package goldilocks import ( "math" "github.com/consensys/gnark/frontend" ) // The types, structs, and functions in this file were ported over from the gnark library // https://github.com/Consensys/gnark/blob/3421eaa7d544286abf3de8c46282b8d4da6d5da0/std/rangecheck/rangecheck_commit.go type Type int const ( R1CS Type = iota SCS ) type FrontendTyper interface { FrontendType() Type } type checkedVariable struct { v frontend.Variable bits int } func getOptimalBasewidth(api frontend.API, collected []checkedVariable) int { if ft, ok := api.(FrontendTyper); ok { switch ft.FrontendType() { case R1CS: return optimalWidth(nbR1CSConstraints, collected) case SCS: return optimalWidth(nbPLONKConstraints, collected) } } return optimalWidth(nbR1CSConstraints, collected) } func optimalWidth(countFn func(baseLength int, collected []checkedVariable) int, collected []checkedVariable) int { min := math.MaxInt64 minVal := 0 for j := 2; j < 18; j++ { current := countFn(j, collected) if current < min { min = current minVal = j } } return minVal } func decompSize(varSize int, limbSize int) int { return (varSize + limbSize - 1) / limbSize } func nbR1CSConstraints(baseLength int, collected []checkedVariable) int { nbDecomposed := 0 for i := range collected { nbDecomposed += int(decompSize(collected[i].bits, baseLength)) } eqs := len(collected) // correctness of decomposition nbRight := nbDecomposed // inverse per decomposed nbleft := (1 << baseLength) // div per table return nbleft + nbRight + eqs + 1 } func nbPLONKConstraints(baseLength int, collected []checkedVariable) int { nbDecomposed := 0 for i := range collected { nbDecomposed += int(decompSize(collected[i].bits, baseLength)) } eqs := nbDecomposed // check correctness of every decomposition. this is nbDecomp adds + eq cost per collected nbRight := 3 * nbDecomposed // denominator sub, inv and large sum per table entry nbleft := 3 * (1 << baseLength) // denominator sub, div and large sum per table entry return nbleft + nbRight + eqs + 1 // and the final assert } func gnarkRangeCheckerSelector(api frontend.API) RangeCheckerType { // Emulate the logic within rangecheck.New // https://github.com/Consensys/gnark/blob/3421eaa7d544286abf3de8c46282b8d4da6d5da0/std/rangecheck/rangecheck.go#L24 if _, ok := api.(frontend.Rangechecker); ok { return NATIVE_RANGE_CHECKER } else if _, ok := api.(frontend.Committer); ok { return COMMIT_RANGE_CHECKER } else { return BIT_DECOMP_RANGE_CHECKER } }