arnaucube
arnaucube/gnark-plonky2-verifierPublic Self-hosted repository
gnark-plonky2-verifier/sha512/binsum.go
sha512/binsum.goRaw
  1package sha512
  2
  3import (
  4	"math/big"
  5    "github.com/consensys/gnark/backend/hint"
  6    "github.com/consensys/gnark/frontend"
  7)
  8
  9
 10func padToSameLength(args [][]frontend.Variable) ([][]frontend.Variable, int) {
 11	maxLength := 0
 12	for _, v := range args {
 13		if len(v) > maxLength {
 14			maxLength = len(v)
 15		}
 16	}
 17	result := make([][]frontend.Variable, len(args))
 18	for i := 0; i < len(args); i++ {
 19		if len(args[i]) < maxLength {
 20			arr := make([]frontend.Variable, maxLength)
 21			for j := 0; j < maxLength; j++ {
 22				if j < len(args[i]) {
 23					arr[j] = args[i][j]
 24				} else {
 25					arr[j] = 0
 26				}
 27			}
 28			result[i] = arr
 29		} else {
 30			result[i] = args[i]
 31		}
 32	}
 33	return result, maxLength
 34}
 35
 36func log2(n int) int {
 37	if n <= 0 { panic("undefined") }
 38	result := 0
 39	n -= 1
 40	for n > 0 {
 41		n >>= 1
 42		result += 1
 43	}
 44	return result
 45}
 46
 47func extractBit(n big.Int) bool {
 48	if !n.IsInt64() {
 49		panic("not bit")
 50	}
 51	val := n.Int64()
 52	if val == 0 {
 53		return false
 54	} else if val == 1 {
 55		return true
 56	} else {
 57		panic("not bit")
 58	}
 59}
 60
 61func flatten(arr [][]frontend.Variable) ([]frontend.Variable) {
 62	totalLength := 0
 63	for _, v := range arr {
 64		totalLength += len(v)
 65	}
 66	result := make([]frontend.Variable, totalLength)
 67	i := 0
 68	for _, v := range arr {
 69		for _, u := range v {
 70			result[i] = u
 71			i += 1
 72		}
 73	}
 74	return result
 75}
 76
 77func BinSum(api frontend.API, args ...[]frontend.Variable) ([]frontend.Variable) {
 78	ops := len(args)
 79	in, n := padToSameLength(args)
 80	nout := n + log2(ops)
 81//     var nout = nbits((2**n -1)*ops);
 82//     signal input in[ops][n];
 83//     signal output out[nout];
 84
 85	var hintFn hint.Function = func(field *big.Int, inputs []*big.Int, outputs []*big.Int) error {
 86		if len(inputs) != ops*n { panic("bad length") }
 87		if len(outputs) != nout { panic("bad length") }
 88
 89		maxOutputValue := big.NewInt(1)
 90		maxOutputValue.Lsh(maxOutputValue, uint(nout))
 91		if maxOutputValue.Cmp(field) != -1 { panic("overflow") }
 92
 93		result := big.NewInt(0)
 94		for i := 0; i < ops; i++ {
 95			placeValue := big.NewInt(1)
 96			for j := 0; j < n; j++ {
 97				if extractBit(*inputs[i*n+j]) {
 98					result.Add(result, placeValue)
 99				}
100				placeValue.Add(placeValue, placeValue)
101			}
102		}
103		for i := 0; i < nout; i++ {
104			v := new(big.Int).Rsh(result, uint(i))
105			v.And(v, big.NewInt(1))
106			outputs[i] = v
107		}
108		return nil
109	}
110
111	out, err := api.NewHint(hintFn, nout, flatten(in)...)
112	if err != nil {
113		panic(err)
114	}
115
116	var lhs frontend.Variable = 0
117	var rhs frontend.Variable = 0
118
119	placeValue := big.NewInt(1)
120	for i := 0; i < nout; i++ {
121		for j := 0; j < ops; j++ {
122			if i < n {
123				lhs = api.Add(lhs, api.Mul(placeValue, in[j][i]))
124			}
125		}
126		rhs = api.Add(rhs, api.Mul(placeValue, out[i]))
127		api.AssertIsBoolean(out[i])
128		placeValue.Add(placeValue, placeValue)
129	}
130	api.AssertIsEqual(lhs, rhs)
131
132	return out
133}