From 3c382eca5ef3642db02d864c0c6a525b86a279be Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 23 Aug 2024 07:26:34 +0000 Subject: [PATCH 1/4] refactor: move limb composition to package --- std/internal/limbcomposition/composition.go | 54 ++++++++ .../limbcomposition/composition_test.go | 47 +++++++ std/math/emulated/composition.go | 105 --------------- std/math/emulated/composition_test.go | 66 ---------- std/math/emulated/element.go | 3 +- std/math/emulated/element_test.go | 7 +- std/math/emulated/field.go | 3 +- std/math/emulated/field_hint.go | 7 +- std/math/emulated/field_mul.go | 11 +- std/math/emulated/hints.go | 78 ++--------- std/math/emulated/subtraction_padding.go | 123 ++++++++++++++++++ std/math/emulated/subtraction_padding_test.go | 33 +++++ 12 files changed, 283 insertions(+), 254 deletions(-) create mode 100644 std/internal/limbcomposition/composition.go create mode 100644 std/internal/limbcomposition/composition_test.go delete mode 100644 std/math/emulated/composition.go delete mode 100644 std/math/emulated/composition_test.go create mode 100644 std/math/emulated/subtraction_padding.go create mode 100644 std/math/emulated/subtraction_padding_test.go diff --git a/std/internal/limbcomposition/composition.go b/std/internal/limbcomposition/composition.go new file mode 100644 index 0000000000..93d678dec7 --- /dev/null +++ b/std/internal/limbcomposition/composition.go @@ -0,0 +1,54 @@ +package limbs + +import ( + "fmt" + "math/big" +) + +// Recompose takes the limbs in inputs and combines them into res. It errors if +// inputs is uninitialized or zero-length and if the result is uninitialized. +// +// The following holds +// +// res = \sum_{i=0}^{len(inputs)} inputs[i] * 2^{nbBits * i} +func Recompose(inputs []*big.Int, nbBits uint, res *big.Int) error { + if len(inputs) == 0 { + return fmt.Errorf("zero length slice input") + } + if res == nil { + return fmt.Errorf("result not initialized") + } + res.SetUint64(0) + for i := range inputs { + res.Lsh(res, nbBits) + res.Add(res, inputs[len(inputs)-i-1]) + } + // we do not mod-reduce here as the result is mod-reduced by the caller if + // needed. In some places we need non-reduced results. + return nil +} + +// Decompose decomposes the input into res as integers of width nbBits. It +// errors if the decomposition does not fit into res or if res is uninitialized. +// +// The following holds +// +// input = \sum_{i=0}^{len(res)} res[i] * 2^{nbBits * i} +func Decompose(input *big.Int, nbBits uint, res []*big.Int) error { + // limb modulus + if input.BitLen() > len(res)*int(nbBits) { + return fmt.Errorf("decomposed integer does not fit into res") + } + for _, r := range res { + if r == nil { + return fmt.Errorf("result slice element uninitalized") + } + } + base := new(big.Int).Lsh(big.NewInt(1), nbBits) + tmp := new(big.Int).Set(input) + for i := 0; i < len(res); i++ { + res[i].Mod(tmp, base) + tmp.Rsh(tmp, nbBits) + } + return nil +} diff --git a/std/internal/limbcomposition/composition_test.go b/std/internal/limbcomposition/composition_test.go new file mode 100644 index 0000000000..f00044e1b7 --- /dev/null +++ b/std/internal/limbcomposition/composition_test.go @@ -0,0 +1,47 @@ +package limbs_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "reflect" + "testing" + + limbs "github.com/consensys/gnark/std/internal/limbcomposition" + "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/std/math/emulated/emparams" + "github.com/consensys/gnark/test" +) + +func TestComposition(t *testing.T) { + testComposition[emparams.BN254Fp](t) + testComposition[emparams.Secp256k1Fp](t) + testComposition[emparams.BLS12377Fp](t) + testComposition[emparams.Goldilocks](t) +} + +func testComposition[T emulated.FieldParams](t *testing.T) { + t.Helper() + assert := test.NewAssert(t) + var fp T + assert.Run(func(assert *test.Assert) { + n, err := rand.Int(rand.Reader, fp.Modulus()) + if err != nil { + assert.FailNow("rand int", err) + } + res := make([]*big.Int, fp.NbLimbs()) + for i := range res { + res[i] = new(big.Int) + } + if err = limbs.Decompose(n, fp.BitsPerLimb(), res); err != nil { + assert.FailNow("decompose", err) + } + n2 := new(big.Int) + if err = limbs.Recompose(res, fp.BitsPerLimb(), n2); err != nil { + assert.FailNow("recompose", err) + } + if n2.Cmp(n) != 0 { + assert.FailNow("unequal") + } + }, fmt.Sprintf("%s/limb=%d", reflect.TypeOf(fp).Name(), fp.BitsPerLimb())) +} diff --git a/std/math/emulated/composition.go b/std/math/emulated/composition.go deleted file mode 100644 index d94d4f5cca..0000000000 --- a/std/math/emulated/composition.go +++ /dev/null @@ -1,105 +0,0 @@ -package emulated - -import ( - "fmt" - "math/big" -) - -// recompose takes the limbs in inputs and combines them into res. It errors if -// inputs is uninitialized or zero-length and if the result is uninitialized. -// -// The following holds -// -// res = \sum_{i=0}^{len(inputs)} inputs[i] * 2^{nbBits * i} -func recompose(inputs []*big.Int, nbBits uint, res *big.Int) error { - if len(inputs) == 0 { - return fmt.Errorf("zero length slice input") - } - if res == nil { - return fmt.Errorf("result not initialized") - } - res.SetUint64(0) - for i := range inputs { - res.Lsh(res, nbBits) - res.Add(res, inputs[len(inputs)-i-1]) - } - // we do not mod-reduce here as the result is mod-reduced by the caller if - // needed. In some places we need non-reduced results. - return nil -} - -// decompose decomposes the input into res as integers of width nbBits. It -// errors if the decomposition does not fit into res or if res is uninitialized. -// -// The following holds -// -// input = \sum_{i=0}^{len(res)} res[i] * 2^{nbBits * i} -func decompose(input *big.Int, nbBits uint, res []*big.Int) error { - // limb modulus - if input.BitLen() > len(res)*int(nbBits) { - return fmt.Errorf("decomposed integer does not fit into res") - } - for _, r := range res { - if r == nil { - return fmt.Errorf("result slice element uninitalized") - } - } - base := new(big.Int).Lsh(big.NewInt(1), nbBits) - tmp := new(big.Int).Set(input) - for i := 0; i < len(res); i++ { - res[i].Mod(tmp, base) - tmp.Rsh(tmp, nbBits) - } - return nil -} - -// subPadding returns k*p for some k. -// Denote the padding d=(d[0], ..., d[nbLimbs]). When computing the difference -// of a and b by limb-wise subtraction -// -// s = a - b = (a[0]-b[0], ..., a[nbLimbs]-b[nbLimbs]) -// -// it may happen that some limbs underflow the snark scalar field and the limbs -// of s do not represent the actual difference a-b. However, when adding the -// padding d to every limb i.e. -// -// s = a + d - b = (a[0]+d[0]-b[0], ..., a[nbLimbs]+d[nbLimbs]-b[nbLimbs]) -// -// then no such underflow happens and s = a-b (mod p) as the padding is multiple -// of p. -func subPadding(modulus *big.Int, bitsPerLimbs uint, overflow uint, nbLimbs uint) []*big.Int { - if modulus.Cmp(big.NewInt(0)) == 0 { - panic("modulus is zero") - } - // first, we build a number nLimbs, such that nLimbs > b; - // here b is defined by its bounds, that is b is an element with nbLimbs of (bitsPerLimbs+overflow) - // so a number nLimbs > b, is simply taking the next power of 2 over this bound . - nLimbs := make([]*big.Int, nbLimbs) - for i := 0; i < len(nLimbs); i++ { - nLimbs[i] = new(big.Int).SetUint64(1) - nLimbs[i].Lsh(nLimbs[i], overflow+bitsPerLimbs) - } - - // recompose n as the sum of the coefficients weighted by the limbs - n := new(big.Int) - if err := recompose(nLimbs, bitsPerLimbs, n); err != nil { - panic(fmt.Sprintf("recompose: %v", err)) - } - // mod reduce n, and negate it - n.Mod(n, modulus) - n.Sub(modulus, n) - - // construct pad such that: - // pad := n - neg(n mod p) == kp - pad := make([]*big.Int, nbLimbs) - for i := range pad { - pad[i] = new(big.Int) - } - if err := decompose(n, bitsPerLimbs, pad); err != nil { - panic(fmt.Sprintf("decompose: %v", err)) - } - for i := range pad { - pad[i].Add(pad[i], nLimbs[i]) - } - return pad -} diff --git a/std/math/emulated/composition_test.go b/std/math/emulated/composition_test.go deleted file mode 100644 index 25ef0430f9..0000000000 --- a/std/math/emulated/composition_test.go +++ /dev/null @@ -1,66 +0,0 @@ -package emulated - -import ( - "crypto/rand" - "fmt" - "math/big" - "testing" - - "github.com/consensys/gnark/test" -) - -func TestComposition(t *testing.T) { - testComposition[BN254Fp](t) - testComposition[Secp256k1Fp](t) - testComposition[BLS12377Fp](t) - testComposition[Goldilocks](t) -} - -func testComposition[T FieldParams](t *testing.T) { - t.Helper() - assert := test.NewAssert(t) - var fp T - assert.Run(func(assert *test.Assert) { - n, err := rand.Int(rand.Reader, fp.Modulus()) - if err != nil { - assert.FailNow("rand int", err) - } - res := make([]*big.Int, fp.NbLimbs()) - for i := range res { - res[i] = new(big.Int) - } - if err = decompose(n, fp.BitsPerLimb(), res); err != nil { - assert.FailNow("decompose", err) - } - n2 := new(big.Int) - if err = recompose(res, fp.BitsPerLimb(), n2); err != nil { - assert.FailNow("recompose", err) - } - if n2.Cmp(n) != 0 { - assert.FailNow("unequal") - } - }, testName[T]()) -} - -func TestSubPadding(t *testing.T) { - testSubPadding[BN254Fp](t) - testSubPadding[Secp256k1Fp](t) - testSubPadding[BLS12377Fp](t) - testSubPadding[Goldilocks](t) -} - -func testSubPadding[T FieldParams](t *testing.T) { - var fp T - assert := test.NewAssert(t) - for i := fp.NbLimbs(); i < 2*fp.NbLimbs(); i++ { - assert.Run(func(assert *test.Assert) { - limbs := subPadding(fp.Modulus(), fp.BitsPerLimb(), 0, i) - padValue := new(big.Int) - if err := recompose(limbs, fp.BitsPerLimb(), padValue); err != nil { - assert.FailNow("recompose", err) - } - padValue.Mod(padValue, fp.Modulus()) - assert.Zero(padValue.Cmp(big.NewInt(0)), "padding not multiple of order") - }, fmt.Sprintf("%s/nbLimbs=%d", testName[T](), i)) - } -} diff --git a/std/math/emulated/element.go b/std/math/emulated/element.go index 171418d747..bbad40cd2c 100644 --- a/std/math/emulated/element.go +++ b/std/math/emulated/element.go @@ -6,6 +6,7 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/internal/utils" + limbs "github.com/consensys/gnark/std/internal/limbcomposition" ) // Element defines an element in the ring of integers modulo n. The integer @@ -73,7 +74,7 @@ func newConstElement[T FieldParams](v interface{}) *Element[T] { for i := range blimbs { blimbs[i] = new(big.Int) } - if err := decompose(&bValue, fp.BitsPerLimb(), blimbs); err != nil { + if err := limbs.Decompose(&bValue, fp.BitsPerLimb(), blimbs); err != nil { panic(fmt.Errorf("decompose value: %w", err)) } diff --git a/std/math/emulated/element_test.go b/std/math/emulated/element_test.go index 96530c1126..264d0effcd 100644 --- a/std/math/emulated/element_test.go +++ b/std/math/emulated/element_test.go @@ -13,6 +13,7 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/frontend/cs/scs" + limbs "github.com/consensys/gnark/std/internal/limbcomposition" "github.com/consensys/gnark/std/math/emulated/emparams" "github.com/consensys/gnark/test" ) @@ -1136,7 +1137,7 @@ func testReduceStrict[T FieldParams](t *testing.T) { for i := range plimbs { plimbs[i] = new(big.Int) } - err := decompose(p, fp.BitsPerLimb(), plimbs) + err := limbs.Decompose(p, fp.BitsPerLimb(), plimbs) assert.NoError(err) plimbs[0].Add(plimbs[0], big.NewInt(1)) exp := make([]*big.Int, int(fp.NbLimbs())) @@ -1191,7 +1192,7 @@ func testToBitsCanonical[T FieldParams](t *testing.T) { for i := range plimbs { plimbs[i] = new(big.Int) } - err := decompose(p, fp.BitsPerLimb(), plimbs) + err := limbs.Decompose(p, fp.BitsPerLimb(), plimbs) assert.NoError(err) plimbs[0].Add(plimbs[0], big.NewInt(1)) exp := make([]*big.Int, int(nbBits)) @@ -1242,7 +1243,7 @@ func testIsZeroEdgeCases[T FieldParams](t *testing.T) { for i := range plimbs { plimbs[i] = new(big.Int) } - err := decompose(p, fp.BitsPerLimb(), plimbs) + err := limbs.Decompose(p, fp.BitsPerLimb(), plimbs) assert.NoError(err) // limbs are for zero witness1 := &IsZeroEdgeCase[T]{Limbs: make([]frontend.Variable, int(fp.NbLimbs())), Expected: 1} diff --git a/std/math/emulated/field.go b/std/math/emulated/field.go index 96bca2fd79..e33a245570 100644 --- a/std/math/emulated/field.go +++ b/std/math/emulated/field.go @@ -9,6 +9,7 @@ import ( "github.com/consensys/gnark/internal/kvstore" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" + limbs "github.com/consensys/gnark/std/internal/limbcomposition" "github.com/consensys/gnark/std/rangecheck" "github.com/rs/zerolog" "golang.org/x/exp/constraints" @@ -251,7 +252,7 @@ func (f *Field[T]) constantValue(v *Element[T]) (*big.Int, bool) { } res := new(big.Int) - if err := recompose(constLimbs, f.fParams.BitsPerLimb(), res); err != nil { + if err := limbs.Recompose(constLimbs, f.fParams.BitsPerLimb(), res); err != nil { f.log.Error().Err(err).Msg("recomposing constant") return nil, false } diff --git a/std/math/emulated/field_hint.go b/std/math/emulated/field_hint.go index 2c613c5397..826f33c075 100644 --- a/std/math/emulated/field_hint.go +++ b/std/math/emulated/field_hint.go @@ -6,6 +6,7 @@ import ( "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" + limbs "github.com/consensys/gnark/std/internal/limbcomposition" ) func (f *Field[T]) wrapHint(nonnativeInputs ...*Element[T]) []frontend.Variable { @@ -60,7 +61,7 @@ func unwrapHint(isEmulatedInput, isEmulatedOutput bool, nativeInputs, nativeOutp return fmt.Errorf("hint wrapper header is 2+nbLimbs elements") } nonnativeMod := new(big.Int) - if err := recompose(nativeInputs[2:2+nbLimbs], uint(nbBits), nonnativeMod); err != nil { + if err := limbs.Recompose(nativeInputs[2:2+nbLimbs], uint(nbBits), nonnativeMod); err != nil { return fmt.Errorf("cannot recover nonnative mod: %w", err) } var nonnativeInputs []*big.Int @@ -83,7 +84,7 @@ func unwrapHint(isEmulatedInput, isEmulatedOutput bool, nativeInputs, nativeOutp return fmt.Errorf("cannot read %d-th nonnative element", i) } nonnativeInputs[i] = new(big.Int) - if err := recompose(nativeInputs[readPtr+1:readPtr+1+currentInputLen], uint(nbBits), nonnativeInputs[i]); err != nil { + if err := limbs.Recompose(nativeInputs[readPtr+1:readPtr+1+currentInputLen], uint(nbBits), nonnativeInputs[i]); err != nil { return fmt.Errorf("recompose %d-th element: %w", i, err) } readPtr += 1 + currentInputLen @@ -115,7 +116,7 @@ func unwrapHint(isEmulatedInput, isEmulatedOutput bool, nativeInputs, nativeOutp if isEmulatedOutput { for i := range nonnativeOutputs { nonnativeOutputs[i].Mod(nonnativeOutputs[i], nonnativeMod) - if err := decompose(nonnativeOutputs[i], uint(nbBits), nativeOutputs[i*nbLimbs:(i+1)*nbLimbs]); err != nil { + if err := limbs.Decompose(nonnativeOutputs[i], uint(nbBits), nativeOutputs[i*nbLimbs:(i+1)*nbLimbs]); err != nil { return fmt.Errorf("decompose %d-th element: %w", i, err) } } diff --git a/std/math/emulated/field_mul.go b/std/math/emulated/field_mul.go index 278b9a5024..fb2a80e741 100644 --- a/std/math/emulated/field_mul.go +++ b/std/math/emulated/field_mul.go @@ -6,6 +6,7 @@ import ( "math/bits" "github.com/consensys/gnark/frontend" + limbs "github.com/consensys/gnark/std/internal/limbcomposition" "github.com/consensys/gnark/std/multicommit" ) @@ -345,13 +346,13 @@ func mulHint(field *big.Int, inputs, outputs []*big.Int) error { p := new(big.Int) a := new(big.Int) b := new(big.Int) - if err := recompose(plimbs, uint(nbBits), p); err != nil { + if err := limbs.Recompose(plimbs, uint(nbBits), p); err != nil { return fmt.Errorf("recompose p: %w", err) } - if err := recompose(alimbs, uint(nbBits), a); err != nil { + if err := limbs.Recompose(alimbs, uint(nbBits), a); err != nil { return fmt.Errorf("recompose a: %w", err) } - if err := recompose(blimbs, uint(nbBits), b); err != nil { + if err := limbs.Recompose(blimbs, uint(nbBits), b); err != nil { return fmt.Errorf("recompose b: %w", err) } quo := new(big.Int) @@ -360,10 +361,10 @@ func mulHint(field *big.Int, inputs, outputs []*big.Int) error { if p.Cmp(new(big.Int)) != 0 { quo.QuoRem(ab, p, rem) } - if err := decompose(quo, uint(nbBits), quoLimbs); err != nil { + if err := limbs.Decompose(quo, uint(nbBits), quoLimbs); err != nil { return fmt.Errorf("decompose quo: %w", err) } - if err := decompose(rem, uint(nbBits), remLimbs); err != nil { + if err := limbs.Decompose(rem, uint(nbBits), remLimbs); err != nil { return fmt.Errorf("decompose rem: %w", err) } xp := make([]*big.Int, nbMultiplicationResLimbs(nbALen, nbBLen)) diff --git a/std/math/emulated/hints.go b/std/math/emulated/hints.go index 08c56a5f23..7ebdba29ef 100644 --- a/std/math/emulated/hints.go +++ b/std/math/emulated/hints.go @@ -6,6 +6,7 @@ import ( "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" + limbs "github.com/consensys/gnark/std/internal/limbcomposition" ) // TODO @gbotrel hint[T FieldParams] would simplify this . Issue is when registering hint, if QuoRem[T] was declared @@ -63,17 +64,17 @@ func InverseHint(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { return fmt.Errorf("result does not fit into output") } p := new(big.Int) - if err := recompose(inputs[2:2+nbLimbs], nbBits, p); err != nil { + if err := limbs.Recompose(inputs[2:2+nbLimbs], nbBits, p); err != nil { return fmt.Errorf("recompose emulated order: %w", err) } x := new(big.Int) - if err := recompose(inputs[2+nbLimbs:], nbBits, x); err != nil { + if err := limbs.Recompose(inputs[2+nbLimbs:], nbBits, x); err != nil { return fmt.Errorf("recompose value: %w", err) } if x.ModInverse(x, p) == nil { return fmt.Errorf("input and modulus not relatively primes") } - if err := decompose(x, nbBits, outputs); err != nil { + if err := limbs.Decompose(x, nbBits, outputs); err != nil { return fmt.Errorf("decompose: %w", err) } return nil @@ -114,15 +115,15 @@ func DivHint(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { return fmt.Errorf("result does not fit into output") } p := new(big.Int) - if err := recompose(inputs[4:4+nbLimbs], nbBits, p); err != nil { + if err := limbs.Recompose(inputs[4:4+nbLimbs], nbBits, p); err != nil { return fmt.Errorf("recompose emulated order: %w", err) } nominator := new(big.Int) - if err := recompose(inputs[4+nbLimbs:4+nbLimbs+nbNomLimbs], nbBits, nominator); err != nil { + if err := limbs.Recompose(inputs[4+nbLimbs:4+nbLimbs+nbNomLimbs], nbBits, nominator); err != nil { return fmt.Errorf("recompose nominator: %w", err) } denominator := new(big.Int) - if err := recompose(inputs[4+nbLimbs+nbNomLimbs:], nbBits, denominator); err != nil { + if err := limbs.Recompose(inputs[4+nbLimbs+nbNomLimbs:], nbBits, denominator); err != nil { return fmt.Errorf("recompose denominator: %w", err) } res := new(big.Int).ModInverse(denominator, p) @@ -131,7 +132,7 @@ func DivHint(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { } res.Mul(res, nominator) res.Mod(res, p) - if err := decompose(res, nbBits, outputs); err != nil { + if err := limbs.Decompose(res, nbBits, outputs); err != nil { return fmt.Errorf("decompose division: %w", err) } return nil @@ -154,66 +155,3 @@ func SqrtHint(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { return nil }) } - -// subPaddingHint computes the padding for the subtraction of two numbers. It -// ensures that the padding is a multiple of the modulus. Can be used to avoid -// underflow. -// -// In case of fixed modulus use subPadding instead. -func subPaddingHint(mod *big.Int, inputs, outputs []*big.Int) error { - if len(inputs) < 4 { - return fmt.Errorf("input must be at least four elements") - } - nbLimbs := int(inputs[0].Int64()) - bitsPerLimbs := uint(inputs[1].Uint64()) - overflow := uint(inputs[2].Uint64()) - retLimbs := int(inputs[3].Int64()) - if len(inputs[4:]) != nbLimbs { - return fmt.Errorf("input length mismatch") - } - if len(outputs) != retLimbs { - return fmt.Errorf("result does not fit into output") - } - pLimbs := inputs[4 : 4+nbLimbs] - p := new(big.Int) - if err := recompose(pLimbs, bitsPerLimbs, p); err != nil { - return fmt.Errorf("recompose modulus: %w", err) - } - padLimbs := subPadding(p, bitsPerLimbs, overflow, uint(nbLimbs)) - for i := range padLimbs { - outputs[i].Set(padLimbs[i]) - } - - return nil -} - -func (f *Field[T]) computeSubPaddingHint(overflow uint, nbLimbs uint, modulus *Element[T]) *Element[T] { - // we compute the subtraction padding hint in-circuit. The padding has satisfy: - // 1. padding % modulus = 0 - // 2. padding[i] >= (1 << (bits+overflow)) - // 3. padding[i] + a[i] < native_field for all valid a[i] (defined by overflow) - var fp T - inputs := []frontend.Variable{fp.NbLimbs(), fp.BitsPerLimb(), overflow, nbLimbs} - inputs = append(inputs, modulus.Limbs...) - // compute the actual padding value - res, err := f.api.NewHint(subPaddingHint, int(nbLimbs), inputs...) - if err != nil { - panic(fmt.Sprintf("sub padding hint: %v", err)) - } - maxLimb := new(big.Int).Lsh(big.NewInt(1), fp.BitsPerLimb()+overflow) - maxLimb.Sub(maxLimb, big.NewInt(1)) - for i := range res { - // we can check conditions 2 and 3 together by subtracting the maximum - // value which can be subtracted from the padding. The result should not - // underflow (in which case the width of the subtraction result could be - // at least native_width-overflow) and should be nbBits+overflow+1 bits - // wide (as expected padding is one bit wider than the maximum allowed - // subtraction limb). - f.checker.Check(f.api.Sub(res[i], maxLimb), int(fp.BitsPerLimb()+overflow+1)) - } - - // ensure that condition 1 holds - padding := f.newInternalElement(res, overflow+1) - f.checkZero(padding, modulus) - return padding -} diff --git a/std/math/emulated/subtraction_padding.go b/std/math/emulated/subtraction_padding.go new file mode 100644 index 0000000000..e30298e9aa --- /dev/null +++ b/std/math/emulated/subtraction_padding.go @@ -0,0 +1,123 @@ +package emulated + +import ( + "fmt" + "math/big" + + "github.com/consensys/gnark/frontend" + limbs "github.com/consensys/gnark/std/internal/limbcomposition" +) + +// subPadding returns k*p for some k. +// Denote the padding d=(d[0], ..., d[nbLimbs]). When computing the difference +// of a and b by limb-wise subtraction +// +// s = a - b = (a[0]-b[0], ..., a[nbLimbs]-b[nbLimbs]) +// +// it may happen that some limbs underflow the snark scalar field and the limbs +// of s do not represent the actual difference a-b. However, when adding the +// padding d to every limb i.e. +// +// s = a + d - b = (a[0]+d[0]-b[0], ..., a[nbLimbs]+d[nbLimbs]-b[nbLimbs]) +// +// then no such underflow happens and s = a-b (mod p) as the padding is multiple +// of p. +func subPadding(modulus *big.Int, bitsPerLimbs uint, overflow uint, nbLimbs uint) []*big.Int { + if modulus.Cmp(big.NewInt(0)) == 0 { + panic("modulus is zero") + } + // first, we build a number nLimbs, such that nLimbs > b; + // here b is defined by its bounds, that is b is an element with nbLimbs of (bitsPerLimbs+overflow) + // so a number nLimbs > b, is simply taking the next power of 2 over this bound . + nLimbs := make([]*big.Int, nbLimbs) + for i := 0; i < len(nLimbs); i++ { + nLimbs[i] = new(big.Int).SetUint64(1) + nLimbs[i].Lsh(nLimbs[i], overflow+bitsPerLimbs) + } + + // recompose n as the sum of the coefficients weighted by the limbs + n := new(big.Int) + if err := limbs.Recompose(nLimbs, bitsPerLimbs, n); err != nil { + panic(fmt.Sprintf("recompose: %v", err)) + } + // mod reduce n, and negate it + n.Mod(n, modulus) + n.Sub(modulus, n) + + // construct pad such that: + // pad := n - neg(n mod p) == kp + pad := make([]*big.Int, nbLimbs) + for i := range pad { + pad[i] = new(big.Int) + } + if err := limbs.Decompose(n, bitsPerLimbs, pad); err != nil { + panic(fmt.Sprintf("decompose: %v", err)) + } + for i := range pad { + pad[i].Add(pad[i], nLimbs[i]) + } + return pad +} + +// subPaddingHint computes the padding for the subtraction of two numbers. It +// ensures that the padding is a multiple of the modulus. Can be used to avoid +// underflow. +// +// In case of fixed modulus use subPadding instead. +func subPaddingHint(mod *big.Int, inputs, outputs []*big.Int) error { + if len(inputs) < 4 { + return fmt.Errorf("input must be at least four elements") + } + nbLimbs := int(inputs[0].Int64()) + bitsPerLimbs := uint(inputs[1].Uint64()) + overflow := uint(inputs[2].Uint64()) + retLimbs := int(inputs[3].Int64()) + if len(inputs[4:]) != nbLimbs { + return fmt.Errorf("input length mismatch") + } + if len(outputs) != retLimbs { + return fmt.Errorf("result does not fit into output") + } + pLimbs := inputs[4 : 4+nbLimbs] + p := new(big.Int) + if err := limbs.Recompose(pLimbs, bitsPerLimbs, p); err != nil { + return fmt.Errorf("recompose modulus: %w", err) + } + padLimbs := subPadding(p, bitsPerLimbs, overflow, uint(nbLimbs)) + for i := range padLimbs { + outputs[i].Set(padLimbs[i]) + } + + return nil +} + +func (f *Field[T]) computeSubPaddingHint(overflow uint, nbLimbs uint, modulus *Element[T]) *Element[T] { + // we compute the subtraction padding hint in-circuit. The padding has satisfy: + // 1. padding % modulus = 0 + // 2. padding[i] >= (1 << (bits+overflow)) + // 3. padding[i] + a[i] < native_field for all valid a[i] (defined by overflow) + var fp T + inputs := []frontend.Variable{fp.NbLimbs(), fp.BitsPerLimb(), overflow, nbLimbs} + inputs = append(inputs, modulus.Limbs...) + // compute the actual padding value + res, err := f.api.NewHint(subPaddingHint, int(nbLimbs), inputs...) + if err != nil { + panic(fmt.Sprintf("sub padding hint: %v", err)) + } + maxLimb := new(big.Int).Lsh(big.NewInt(1), fp.BitsPerLimb()+overflow) + maxLimb.Sub(maxLimb, big.NewInt(1)) + for i := range res { + // we can check conditions 2 and 3 together by subtracting the maximum + // value which can be subtracted from the padding. The result should not + // underflow (in which case the width of the subtraction result could be + // at least native_width-overflow) and should be nbBits+overflow+1 bits + // wide (as expected padding is one bit wider than the maximum allowed + // subtraction limb). + f.checker.Check(f.api.Sub(res[i], maxLimb), int(fp.BitsPerLimb()+overflow+1)) + } + + // ensure that condition 1 holds + padding := f.newInternalElement(res, overflow+1) + f.checkZero(padding, modulus) + return padding +} diff --git a/std/math/emulated/subtraction_padding_test.go b/std/math/emulated/subtraction_padding_test.go new file mode 100644 index 0000000000..f7d4540111 --- /dev/null +++ b/std/math/emulated/subtraction_padding_test.go @@ -0,0 +1,33 @@ +package emulated + +import ( + "fmt" + "math/big" + "testing" + + limbs "github.com/consensys/gnark/std/internal/limbcomposition" + "github.com/consensys/gnark/test" +) + +func TestSubPadding(t *testing.T) { + testSubPadding[BN254Fp](t) + testSubPadding[Secp256k1Fp](t) + testSubPadding[BLS12377Fp](t) + testSubPadding[Goldilocks](t) +} + +func testSubPadding[T FieldParams](t *testing.T) { + var fp T + assert := test.NewAssert(t) + for i := fp.NbLimbs(); i < 2*fp.NbLimbs(); i++ { + assert.Run(func(assert *test.Assert) { + ls := subPadding(fp.Modulus(), fp.BitsPerLimb(), 0, i) + padValue := new(big.Int) + if err := limbs.Recompose(ls, fp.BitsPerLimb(), padValue); err != nil { + assert.FailNow("recompose", err) + } + padValue.Mod(padValue, fp.Modulus()) + assert.Zero(padValue.Cmp(big.NewInt(0)), "padding not multiple of order") + }, fmt.Sprintf("%s/nbLimbs=%d", testName[T](), i)) + } +} From a719a48379e006949ce60a3a350de8ab04d85df6 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 23 Aug 2024 07:50:01 +0000 Subject: [PATCH 2/4] refactor: use single implementation --- std/evmprecompiles/compose.go | 37 ----------------------------------- std/evmprecompiles/hints.go | 21 +++++++++++++++----- 2 files changed, 16 insertions(+), 42 deletions(-) delete mode 100644 std/evmprecompiles/compose.go diff --git a/std/evmprecompiles/compose.go b/std/evmprecompiles/compose.go deleted file mode 100644 index c1ffaff2aa..0000000000 --- a/std/evmprecompiles/compose.go +++ /dev/null @@ -1,37 +0,0 @@ -package evmprecompiles - -import ( - "fmt" - "math/big" -) - -func recompose(inputs []*big.Int, nbBits uint) *big.Int { - res := new(big.Int) - if len(inputs) == 0 { - return res - } - for i := range inputs { - res.Lsh(res, nbBits) - res.Add(res, inputs[len(inputs)-i-1]) - } - return res -} - -func decompose(input *big.Int, nbBits uint, res []*big.Int) error { - // limb modulus - if input.BitLen() > len(res)*int(nbBits) { - return fmt.Errorf("decomposed integer does not fit into res") - } - for _, r := range res { - if r == nil { - return fmt.Errorf("result slice element uninitalized") - } - } - base := new(big.Int).Lsh(big.NewInt(1), nbBits) - tmp := new(big.Int).Set(input) - for i := 0; i < len(res); i++ { - res[i].Mod(tmp, base) - tmp.Rsh(tmp, nbBits) - } - return nil -} diff --git a/std/evmprecompiles/hints.go b/std/evmprecompiles/hints.go index 15c7e98202..1ff0021ebe 100644 --- a/std/evmprecompiles/hints.go +++ b/std/evmprecompiles/hints.go @@ -8,6 +8,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/secp256k1/ecdsa" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" + limbs "github.com/consensys/gnark/std/internal/limbcomposition" "github.com/consensys/gnark/std/math/emulated" ) @@ -46,10 +47,20 @@ func recoverPublicKeyHint(_ *big.Int, inputs []*big.Int, outputs []*big.Int) err if len(outputs) != 2*int(emfp.NbLimbs())+1 { return fmt.Errorf("expected output %d limbs got %d", 2*emfp.NbLimbs(), len(outputs)) } - msg := recompose(inputs[:emfr.NbLimbs()], emfr.BitsPerLimb()) + msg, r, s := new(big.Int), new(big.Int), new(big.Int) + err := limbs.Recompose(inputs[:emfr.NbLimbs()], emfr.BitsPerLimb(), msg) + if err != nil { + return fmt.Errorf("recompose message: %w", err) + } v := inputs[emfr.NbLimbs()].Uint64() - r := recompose(inputs[emfr.NbLimbs()+1:2*emfr.NbLimbs()+1], emfr.BitsPerLimb()) - s := recompose(inputs[2*emfr.NbLimbs()+1:3*emfr.NbLimbs()+1], emfr.BitsPerLimb()) + err = limbs.Recompose(inputs[emfr.NbLimbs()+1:2*emfr.NbLimbs()+1], emfr.BitsPerLimb(), r) + if err != nil { + return fmt.Errorf("recompose r: %w", err) + } + err = limbs.Recompose(inputs[2*emfr.NbLimbs()+1:3*emfr.NbLimbs()+1], emfr.BitsPerLimb(), s) + if err != nil { + return fmt.Errorf("recompose s: %w", err) + } var pk ecdsa.PublicKey var isQNRFailure int if err := pk.RecoverFrom(msg.Bytes(), uint(v), r, s); err != nil { @@ -62,10 +73,10 @@ func recoverPublicKeyHint(_ *big.Int, inputs []*big.Int, outputs []*big.Int) err } Px := pk.A.X.BigInt(new(big.Int)) Py := pk.A.Y.BigInt(new(big.Int)) - if err := decompose(Px, emfp.BitsPerLimb(), outputs[0:emfp.NbLimbs()]); err != nil { + if err := limbs.Decompose(Px, emfp.BitsPerLimb(), outputs[0:emfp.NbLimbs()]); err != nil { return fmt.Errorf("decompose x: %w", err) } - if err := decompose(Py, emfp.BitsPerLimb(), outputs[emfp.NbLimbs():2*emfp.NbLimbs()]); err != nil { + if err := limbs.Decompose(Py, emfp.BitsPerLimb(), outputs[emfp.NbLimbs():2*emfp.NbLimbs()]); err != nil { return fmt.Errorf("decompose y: %w", err) } // we also return a flag that indicates if the public key is zero but only From 961a11876020cd0200c6ebf242d0a8bd495515a8 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 23 Aug 2024 07:50:10 +0000 Subject: [PATCH 3/4] docs: update reference --- std/math/emulated/doc.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/std/math/emulated/doc.go b/std/math/emulated/doc.go index 6f4685f253..915afea480 100644 --- a/std/math/emulated/doc.go +++ b/std/math/emulated/doc.go @@ -55,8 +55,8 @@ know that the limb values do not overflow 2^w, then we say that the element is in normal form. In the implementation, we have two functions for splitting an element into limbs -and composing an element from limbs -- [decompose] and [recompose]. The -[recompose] function also accepts element in non-normal form. +and composing an element from limbs -- [limbs.Decompose] and [limbs.Recompose]. +The [limbs.Recompose] function also accepts element in non-normal form. # Elements in non-normal form From a1112261517d4de600b965f8078120d1a2e04f17 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 23 Aug 2024 09:23:00 +0000 Subject: [PATCH 4/4] refactor: move utils from std/ to internal --- constraint/bls12-377/gkr.go | 2 +- constraint/bls12-381/gkr.go | 2 +- constraint/bls24-315/gkr.go | 2 +- constraint/bls24-317/gkr.go | 2 +- constraint/bn254/gkr.go | 2 +- constraint/bw6-633/gkr.go | 2 +- constraint/bw6-761/gkr.go | 2 +- constraint/gkr.go | 5 +++-- {std/utils => internal}/algo_utils/algo_utils.go | 0 .../algo_utils/algo_utils_test.go | 0 .../backend/template/representations/gkr.go.tmpl | 2 +- std/compress/internal/io_test.go | 5 +++-- std/compress/internal/plonk/plonk_test.go | 7 ++++--- std/compress/io_test.go | 7 ++++--- std/compress/lzss/snark_test.go | 5 +++-- std/compress/lzss/snark_testing.go | 2 +- std/gkr/api.go | 2 +- std/gkr/api_test.go | 13 +++++++------ std/gkr/compile.go | 2 +- .../test_vectors_utils/test_vector_utils.go | 0 .../test_vectors_utils/test_vector_utils_test.go | 0 21 files changed, 35 insertions(+), 29 deletions(-) rename {std/utils => internal}/algo_utils/algo_utils.go (100%) rename {std/utils => internal}/algo_utils/algo_utils_test.go (100%) rename std/{utils => internal}/test_vectors_utils/test_vector_utils.go (100%) rename std/{utils => internal}/test_vectors_utils/test_vector_utils_test.go (100%) diff --git a/constraint/bls12-377/gkr.go b/constraint/bls12-377/gkr.go index 39f57003a5..ffb369fcac 100644 --- a/constraint/bls12-377/gkr.go +++ b/constraint/bls12-377/gkr.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/utils" "github.com/consensys/gnark/constraint" hint "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/std/utils/algo_utils" + "github.com/consensys/gnark/internal/algo_utils" "hash" "math/big" "sync" diff --git a/constraint/bls12-381/gkr.go b/constraint/bls12-381/gkr.go index 3c8cd75434..8480ebb6e8 100644 --- a/constraint/bls12-381/gkr.go +++ b/constraint/bls12-381/gkr.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/utils" "github.com/consensys/gnark/constraint" hint "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/std/utils/algo_utils" + "github.com/consensys/gnark/internal/algo_utils" "hash" "math/big" "sync" diff --git a/constraint/bls24-315/gkr.go b/constraint/bls24-315/gkr.go index a8d541a275..8205771038 100644 --- a/constraint/bls24-315/gkr.go +++ b/constraint/bls24-315/gkr.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/utils" "github.com/consensys/gnark/constraint" hint "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/std/utils/algo_utils" + "github.com/consensys/gnark/internal/algo_utils" "hash" "math/big" "sync" diff --git a/constraint/bls24-317/gkr.go b/constraint/bls24-317/gkr.go index ffe2ec1627..0894277205 100644 --- a/constraint/bls24-317/gkr.go +++ b/constraint/bls24-317/gkr.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/utils" "github.com/consensys/gnark/constraint" hint "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/std/utils/algo_utils" + "github.com/consensys/gnark/internal/algo_utils" "hash" "math/big" "sync" diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index 8e1ece3ca7..10de1207eb 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/utils" "github.com/consensys/gnark/constraint" hint "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/std/utils/algo_utils" + "github.com/consensys/gnark/internal/algo_utils" "hash" "math/big" "sync" diff --git a/constraint/bw6-633/gkr.go b/constraint/bw6-633/gkr.go index f24ff2cb0b..41d58f19d5 100644 --- a/constraint/bw6-633/gkr.go +++ b/constraint/bw6-633/gkr.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/utils" "github.com/consensys/gnark/constraint" hint "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/std/utils/algo_utils" + "github.com/consensys/gnark/internal/algo_utils" "hash" "math/big" "sync" diff --git a/constraint/bw6-761/gkr.go b/constraint/bw6-761/gkr.go index c665d27dbc..585af422d4 100644 --- a/constraint/bw6-761/gkr.go +++ b/constraint/bw6-761/gkr.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/utils" "github.com/consensys/gnark/constraint" hint "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/std/utils/algo_utils" + "github.com/consensys/gnark/internal/algo_utils" "hash" "math/big" "sync" diff --git a/constraint/gkr.go b/constraint/gkr.go index 4d84a5466d..e1337cb0b9 100644 --- a/constraint/gkr.go +++ b/constraint/gkr.go @@ -2,10 +2,11 @@ package constraint import ( "fmt" + "sort" + "github.com/consensys/gnark-crypto/utils" "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/std/utils/algo_utils" - "sort" + "github.com/consensys/gnark/internal/algo_utils" ) type GkrVariable int // Just an alias to hide implementation details. May be more trouble than worth diff --git a/std/utils/algo_utils/algo_utils.go b/internal/algo_utils/algo_utils.go similarity index 100% rename from std/utils/algo_utils/algo_utils.go rename to internal/algo_utils/algo_utils.go diff --git a/std/utils/algo_utils/algo_utils_test.go b/internal/algo_utils/algo_utils_test.go similarity index 100% rename from std/utils/algo_utils/algo_utils_test.go rename to internal/algo_utils/algo_utils_test.go diff --git a/internal/generator/backend/template/representations/gkr.go.tmpl b/internal/generator/backend/template/representations/gkr.go.tmpl index 3801ce0de5..32ff5da874 100644 --- a/internal/generator/backend/template/representations/gkr.go.tmpl +++ b/internal/generator/backend/template/representations/gkr.go.tmpl @@ -7,7 +7,7 @@ import ( "github.com/consensys/gnark-crypto/utils" "github.com/consensys/gnark/constraint" hint "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/std/utils/algo_utils" + "github.com/consensys/gnark/internal/algo_utils" "hash" "math/big" "sync" diff --git a/std/compress/internal/io_test.go b/std/compress/internal/io_test.go index 1745970bd3..f88b9cc0fa 100644 --- a/std/compress/internal/io_test.go +++ b/std/compress/internal/io_test.go @@ -3,6 +3,8 @@ package internal_test import ( "bytes" "crypto/rand" + "testing" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/frontend" @@ -10,12 +12,11 @@ import ( "github.com/consensys/gnark/std/compress" "github.com/consensys/gnark/std/compress/internal" "github.com/consensys/gnark/std/compress/lzss" + test_vector_utils "github.com/consensys/gnark/std/internal/test_vectors_utils" "github.com/consensys/gnark/std/math/bits" - test_vector_utils "github.com/consensys/gnark/std/utils/test_vectors_utils" "github.com/consensys/gnark/test" "github.com/icza/bitio" "github.com/stretchr/testify/assert" - "testing" ) func TestRecombineBytes(t *testing.T) { diff --git a/std/compress/internal/plonk/plonk_test.go b/std/compress/internal/plonk/plonk_test.go index 1023d1ee2a..7392139f17 100644 --- a/std/compress/internal/plonk/plonk_test.go +++ b/std/compress/internal/plonk/plonk_test.go @@ -4,14 +4,15 @@ import ( "crypto/rand" "encoding/binary" "errors" + "reflect" + "testing" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/frontend" - test_vector_utils "github.com/consensys/gnark/std/utils/test_vectors_utils" + test_vector_utils "github.com/consensys/gnark/std/internal/test_vectors_utils" "github.com/consensys/gnark/test" - "reflect" - "testing" ) func TestCustomConstraint(t *testing.T) { diff --git a/std/compress/io_test.go b/std/compress/io_test.go index cbe17e7a73..ea07eeb1ae 100644 --- a/std/compress/io_test.go +++ b/std/compress/io_test.go @@ -4,6 +4,9 @@ import ( "crypto/rand" "errors" "fmt" + "math/big" + "testing" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark-crypto/hash" @@ -11,11 +14,9 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/profile" - test_vector_utils "github.com/consensys/gnark/std/utils/test_vectors_utils" + test_vector_utils "github.com/consensys/gnark/std/internal/test_vectors_utils" "github.com/consensys/gnark/test" "github.com/stretchr/testify/assert" - "math/big" - "testing" ) func TestShiftLeft(t *testing.T) { diff --git a/std/compress/lzss/snark_test.go b/std/compress/lzss/snark_test.go index ab1fbfc232..34936dd73b 100644 --- a/std/compress/lzss/snark_test.go +++ b/std/compress/lzss/snark_test.go @@ -4,15 +4,16 @@ import ( "crypto/sha256" "encoding/hex" "fmt" - "github.com/consensys/gnark/frontend/cs/scs" "os" "testing" + "github.com/consensys/gnark/frontend/cs/scs" + "github.com/consensys/compress/lzss" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/frontend" - test_vector_utils "github.com/consensys/gnark/std/utils/test_vectors_utils" + test_vector_utils "github.com/consensys/gnark/std/internal/test_vectors_utils" "github.com/consensys/gnark/test" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/std/compress/lzss/snark_testing.go b/std/compress/lzss/snark_testing.go index a224898c86..fc309a3fd8 100644 --- a/std/compress/lzss/snark_testing.go +++ b/std/compress/lzss/snark_testing.go @@ -4,7 +4,7 @@ import ( "github.com/consensys/compress/lzss" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/compress" - test_vector_utils "github.com/consensys/gnark/std/utils/test_vectors_utils" + test_vector_utils "github.com/consensys/gnark/std/internal/test_vectors_utils" ) type DecompressionTestCircuit struct { diff --git a/std/gkr/api.go b/std/gkr/api.go index d13c65e2d0..b46cfad8e5 100644 --- a/std/gkr/api.go +++ b/std/gkr/api.go @@ -2,7 +2,7 @@ package gkr import ( "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/std/utils/algo_utils" + "github.com/consensys/gnark/internal/algo_utils" ) func frontendVarToInt(a constraint.GkrVariable) int { diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 2dead41af5..25fc3c3c1e 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -2,6 +2,12 @@ package gkr import ( "fmt" + "hash" + "math/rand" + "strconv" + "testing" + "time" + bls12377 "github.com/consensys/gnark/constraint/bls12-377" bls12381 "github.com/consensys/gnark/constraint/bls12-381" bls24315 "github.com/consensys/gnark/constraint/bls24-315" @@ -9,11 +15,6 @@ import ( bw6633 "github.com/consensys/gnark/constraint/bw6-633" bw6761 "github.com/consensys/gnark/constraint/bw6-761" "github.com/consensys/gnark/test" - "hash" - "math/rand" - "strconv" - "testing" - "time" "github.com/consensys/gnark-crypto/kzg" "github.com/consensys/gnark/backend/plonk" @@ -32,7 +33,7 @@ import ( "github.com/consensys/gnark/frontend/cs/scs" stdHash "github.com/consensys/gnark/std/hash" "github.com/consensys/gnark/std/hash/mimc" - test_vector_utils "github.com/consensys/gnark/std/utils/test_vectors_utils" + test_vector_utils "github.com/consensys/gnark/std/internal/test_vectors_utils" "github.com/consensys/gnark/test/unsafekzg" ) diff --git a/std/gkr/compile.go b/std/gkr/compile.go index 72a60570ba..dd3ad75ee0 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -7,9 +7,9 @@ import ( "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/internal/algo_utils" fiatshamir "github.com/consensys/gnark/std/fiat-shamir" "github.com/consensys/gnark/std/hash" - "github.com/consensys/gnark/std/utils/algo_utils" ) type circuitDataForSnark struct { diff --git a/std/utils/test_vectors_utils/test_vector_utils.go b/std/internal/test_vectors_utils/test_vector_utils.go similarity index 100% rename from std/utils/test_vectors_utils/test_vector_utils.go rename to std/internal/test_vectors_utils/test_vector_utils.go diff --git a/std/utils/test_vectors_utils/test_vector_utils_test.go b/std/internal/test_vectors_utils/test_vector_utils_test.go similarity index 100% rename from std/utils/test_vectors_utils/test_vector_utils_test.go rename to std/internal/test_vectors_utils/test_vector_utils_test.go