From cc13bf4880503eaf5f7f14031ec5546b238f5c17 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 26 Jan 2023 12:34:48 -0600 Subject: [PATCH 01/10] refactor: step 1 clean up api and builder wrapper --- .golangci.yml | 28 +- std/math/emulated/composition_test.go | 1 + .../doc_example_fieldapi_builder_test.go | 62 --- .../emulated/doc_example_fieldapi_test.go | 85 ---- std/math/emulated/element_test.go | 80 ++-- std/math/emulated/field_assert.go | 3 +- std/math/emulated/field_ops.go | 55 +-- std/math/emulated/field_test.go | 219 --------- std/math/emulated/pairing_test.go | 116 ----- std/math/emulated/wrapped_api.go | 428 ------------------ std/math/emulated/wrapped_builder.go | 77 ---- 11 files changed, 71 insertions(+), 1083 deletions(-) delete mode 100644 std/math/emulated/doc_example_fieldapi_builder_test.go delete mode 100644 std/math/emulated/doc_example_fieldapi_test.go delete mode 100644 std/math/emulated/pairing_test.go delete mode 100644 std/math/emulated/wrapped_api.go delete mode 100644 std/math/emulated/wrapped_builder.go diff --git a/.golangci.yml b/.golangci.yml index 3a5f6fca1b..edd055d0f7 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,12 +1,24 @@ linters: - disable-all: true - enable: - - gofmt - - staticcheck - - gosec - - gosimple - - govet - - ineffassign + # disable-all: true + enable-all: true + disable: + - varnamelen + - wrapcheck + - testpackage + - thelper + - paralleltest + - nonamedreturns + - nosnakecase + - nlreturn + - gomnd + - goerr113 + # enable: + # - gofmt + # - staticcheck + # - gosec + # - gosimple + # - govet + # - ineffassign run: issues-exit-code: 1 \ No newline at end of file diff --git a/std/math/emulated/composition_test.go b/std/math/emulated/composition_test.go index 5e2501a01f..d1c59289cc 100644 --- a/std/math/emulated/composition_test.go +++ b/std/math/emulated/composition_test.go @@ -17,6 +17,7 @@ func TestComposition(t *testing.T) { } func testComposition[T FieldParams](t *testing.T) { + t.Helper() assert := test.NewAssert(t) var fp T assert.Run(func(assert *test.Assert) { diff --git a/std/math/emulated/doc_example_fieldapi_builder_test.go b/std/math/emulated/doc_example_fieldapi_builder_test.go deleted file mode 100644 index bffea60b3e..0000000000 --- a/std/math/emulated/doc_example_fieldapi_builder_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package emulated_test - -import ( - "fmt" - - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/math/emulated" - "github.com/consensys/gnark/test" -) - -type ExampleFieldAPIBuilderCircuit struct { - In1 frontend.Variable - In2 frontend.Variable - Res frontend.Variable -} - -func (c *ExampleFieldAPIBuilderCircuit) Define(api frontend.API) error { - // now use API as would use native frontend.API - res := api.Mul(c.In1, c.In2) // native element is converted to non-native on-the-fly - api.AssertIsEqual(res, c.Res) - return nil -} - -// Example of using [FieldAPI] implementing [frontend.Builder] interface. The -// witness elements may be of any type, they are converted to [Element] type -// instance by the built-in hooks of the wrapped builder during parsing. -func ExampleFieldAPI_builder() { - circuit := ExampleFieldAPIBuilderCircuit{} - witness := ExampleFieldAPIBuilderCircuit{ - In1: emulated.NewElement[emulated.BN254Fp](3), - In2: emulated.NewElement[emulated.BN254Fp](5), - Res: emulated.NewElement[emulated.BN254Fp](15), - } - _, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit, frontend.WithBuilderWrapper(func(b frontend.Builder) frontend.Builder { - wb, err := emulated.NewBuilder[emulated.BN254Fp](b) - if err != nil { - panic(err) - } - return wb - })) - if err != nil { - panic(err) - } else { - fmt.Println("compiled using builder wrapper") - } - err = test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField(), test.WithApiWrapper(func(a frontend.API) frontend.API { - wa, err := emulated.NewAPI[emulated.BN254Fp](a) - if err != nil { - panic(err) - } - return wa - })) - if err != nil { - panic(err) - } else { - fmt.Println("solved using test engine") - } - // Output: compiled using builder wrapper - // solved using test engine -} diff --git a/std/math/emulated/doc_example_fieldapi_test.go b/std/math/emulated/doc_example_fieldapi_test.go deleted file mode 100644 index 6b94e8bc89..0000000000 --- a/std/math/emulated/doc_example_fieldapi_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package emulated_test - -import ( - "fmt" - - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/backend" - "github.com/consensys/gnark/backend/groth16" - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/math/emulated" -) - -type ExampleFieldAPICircuit struct { - InNative frontend.Variable // must be integer-like, not [Element] - InNonnative emulated.Element[emulated.BN254Fp] - Res emulated.Element[emulated.BN254Fp] -} - -func (c *ExampleFieldAPICircuit) Define(api frontend.API) error { - api, err := emulated.NewAPI[emulated.BN254Fp](api) - if err != nil { - return fmt.Errorf("new api: %w", err) - } - // now use API as would use native frontend.API - res := api.Mul(c.InNative, c.InNonnative) // native element is converted to non-native on-the-fly - api.AssertIsEqual(res, c.Res) - return nil -} - -// Example of using [FieldAPI] for drop-in replacement of native API. -// -// Witness elements must be [Element] type for successful compiling and parsing -// of the circuit. -func ExampleFieldAPI_api() { - // compiling the circuit - circuit := ExampleFieldAPICircuit{} - witness := ExampleFieldAPICircuit{ - InNative: 3, - InNonnative: emulated.NewElement[emulated.BN254Fp](5), - Res: emulated.NewElement[emulated.BN254Fp](15), - } - ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) - if err != nil { - panic(err) - } else { - fmt.Println("compiled") - } - witnessData, err := frontend.NewWitness(&witness, ecc.BN254.ScalarField()) - if err != nil { - panic(err) - } else { - fmt.Println("secret witness parsed") - } - publicWitnessData, err := witnessData.Public() - if err != nil { - panic(err) - } else { - fmt.Println("public witness parsed") - } - pk, vk, err := groth16.Setup(ccs) - if err != nil { - panic(err) - } else { - fmt.Println("setup done") - } - proof, err := groth16.Prove(ccs, pk, witnessData, backend.WithHints(emulated.GetHints()...)) - if err != nil { - panic(err) - } else { - fmt.Println("proved") - } - err = groth16.Verify(proof, vk, publicWitnessData) - if err != nil { - panic(err) - } else { - fmt.Println("verified") - } - // Output: compiled - // secret witness parsed - // public witness parsed - // setup done - // proved - // verified -} diff --git a/std/math/emulated/element_test.go b/std/math/emulated/element_test.go index 335220e450..4e1351e1eb 100644 --- a/std/math/emulated/element_test.go +++ b/std/math/emulated/element_test.go @@ -130,12 +130,12 @@ type MulNoOverflowCircuit[T FieldParams] struct { } func (c *MulNoOverflowCircuit[T]) Define(api frontend.API) error { - f, err := NewAPI[T](api) + f, err := NewField[T](api) if err != nil { return err } - res := f.Mul(c.A, c.B) - f.AssertIsEqual(res, c.C) + res := f.Mul(&c.A, &c.B) + f.AssertIsEqual(res, &c.C) return nil } @@ -167,12 +167,12 @@ type MulCircuitOverflow[T FieldParams] struct { } func (c *MulCircuitOverflow[T]) Define(api frontend.API) error { - f, err := NewAPI[T](api) + f, err := NewField[T](api) if err != nil { return err } - res := f.Mul(c.A, c.B) - f.AssertIsEqual(res, c.C) + res := f.Mul(&c.A, &c.B) + f.AssertIsEqual(res, &c.C) return nil } @@ -244,12 +244,12 @@ type SubtractCircuit[T FieldParams] struct { } func (c *SubtractCircuit[T]) Define(api frontend.API) error { - f, err := NewAPI[T](api) + f, err := NewField[T](api) if err != nil { return err } - res := f.Sub(c.A, c.B) - f.AssertIsEqual(res, c.C) + res := f.Sub(&c.A, &c.B) + f.AssertIsEqual(res, &c.C) return nil } @@ -301,12 +301,12 @@ type NegationCircuit[T FieldParams] struct { } func (c *NegationCircuit[T]) Define(api frontend.API) error { - f, err := NewAPI[T](api) + f, err := NewField[T](api) if err != nil { return err } - res := f.Neg(c.A) - f.AssertIsEqual(res, c.B) + res := f.Neg(&c.A) + f.AssertIsEqual(res, &c.B) return nil } @@ -335,12 +335,12 @@ type InverseCircuit[T FieldParams] struct { } func (c *InverseCircuit[T]) Define(api frontend.API) error { - f, err := NewAPI[T](api) + f, err := NewField[T](api) if err != nil { return err } - res := f.Inverse(c.A) - f.AssertIsEqual(res, c.B) + res := f.Inverse(&c.A) + f.AssertIsEqual(res, &c.B) return nil } @@ -373,12 +373,12 @@ type DivisionCircuit[T FieldParams] struct { } func (c *DivisionCircuit[T]) Define(api frontend.API) error { - f, err := NewAPI[T](api) + f, err := NewField[T](api) if err != nil { return err } - res := f.Div(c.A, c.B) - f.AssertIsEqual(res, c.C) + res := f.Div(&c.A, &c.B) + f.AssertIsEqual(res, &c.C) return nil } @@ -415,11 +415,11 @@ type ToBinaryCircuit[T FieldParams] struct { } func (c *ToBinaryCircuit[T]) Define(api frontend.API) error { - f, err := NewAPI[T](api) + f, err := NewField[T](api) if err != nil { return err } - bits := f.ToBinary(c.Value) + bits := f.ToBits(&c.Value) if len(bits) != len(c.Bits) { return fmt.Errorf("got %d bits, expected %d", len(bits), len(c.Bits)) } @@ -459,12 +459,12 @@ type FromBinaryCircuit[T FieldParams] struct { } func (c *FromBinaryCircuit[T]) Define(api frontend.API) error { - f, err := NewAPI[T](api) + f, err := NewField[T](api) if err != nil { return err } - res := f.FromBinary(c.Bits...) - f.AssertIsEqual(res, c.Res) + res := f.FromBits(c.Bits...) + f.AssertIsEqual(res, &c.Res) return nil } @@ -500,12 +500,12 @@ type EqualityCheckCircuit[T FieldParams] struct { } func (c *EqualityCheckCircuit[T]) Define(api frontend.API) error { - f, err := NewAPI[T](api) + f, err := NewField[T](api) if err != nil { return err } // res := c.A //f.Set(c.A) TODO @gbotrel fixme - f.AssertIsEqual(c.A, c.B) + f.AssertIsEqual(&c.A, &c.B) return nil } @@ -536,13 +536,13 @@ type SelectCircuit[T FieldParams] struct { } func (c *SelectCircuit[T]) Define(api frontend.API) error { - f, err := NewAPI[T](api) + f, err := NewField[T](api) if err != nil { return err } - l := f.Mul(c.A, c.B) - res := f.Select(c.Selector, l, c.C) - f.AssertIsEqual(res, c.D) + l := f.Mul(&c.A, &c.B) + res := f.Select(c.Selector, l, &c.C) + f.AssertIsEqual(res, &c.D) return nil } @@ -586,12 +586,12 @@ type Lookup2Circuit[T FieldParams] struct { } func (c *Lookup2Circuit[T]) Define(api frontend.API) error { - f, err := NewAPI[T](api) + f, err := NewField[T](api) if err != nil { return err } - res := f.Lookup2(c.Bit0, c.Bit1, c.A, c.B, c.C, c.D) - f.AssertIsEqual(res, c.E) + res := f.Lookup2(c.Bit0, c.Bit1, &c.A, &c.B, &c.C, &c.D) + f.AssertIsEqual(res, &c.E) return nil } @@ -633,26 +633,28 @@ type ComputationCircuit[T FieldParams] struct { } func (c *ComputationCircuit[T]) Define(api frontend.API) error { - f, err := NewAPI[T](api) + f, err := NewField[T](api) if err != nil { return err } // compute x1^3 + 5*x2 + (x3-x4) / (x5+x6) - x13 := f.Mul(c.X1, c.X1) + x13 := f.Mul(&c.X1, &c.X1) if !c.noReduce { x13 = f.Reduce(x13) } - x13 = f.Mul(x13, c.X1) + x13 = f.Mul(x13, &c.X1) if !c.noReduce { x13 = f.Reduce(x13) } - fx2 := f.Mul(5, c.X2) + // TODO @gbotrel better way to deal with constants? + five := NewElement[T](5) + fx2 := f.Mul(&five, &c.X2) fx2 = f.Reduce(fx2) - nom := f.Sub(c.X3, c.X4) + nom := f.Sub(&c.X3, &c.X4) - denom := f.Add(c.X5, c.X6) + denom := f.Add(&c.X5, &c.X6) free := f.Div(nom, denom) @@ -660,7 +662,7 @@ func (c *ComputationCircuit[T]) Define(api frontend.API) error { res := f.Add(x13, fx2) res = f.Add(res, free) - f.AssertIsEqual(res, c.Res) + f.AssertIsEqual(res, &c.Res) return nil } diff --git a/std/math/emulated/field_assert.go b/std/math/emulated/field_assert.go index 3bea317ce8..96311a7f9b 100644 --- a/std/math/emulated/field_assert.go +++ b/std/math/emulated/field_assert.go @@ -118,8 +118,7 @@ func (f *Field[T]) AssertLimbsEquality(a, b *Element[T]) { // than full limb width). Otherwise, every limb is assumed to have same width // (defined by the field parameter). func (f *Field[T]) enforceWidth(a *Element[T], modWidth bool) { - _, aConst := f.constantValue(a) - if aConst { + if _, aConst := f.constantValue(a); aConst { if len(a.Limbs) != int(f.fParams.NbLimbs()) { panic("constant limb width doesn't match parametrized field") } diff --git a/std/math/emulated/field_ops.go b/std/math/emulated/field_ops.go index 2d1c8bb6ec..bf73140554 100644 --- a/std/math/emulated/field_ops.go +++ b/std/math/emulated/field_ops.go @@ -51,18 +51,11 @@ func (f *Field[T]) Add(a, b *Element[T]) *Element[T] { return f.reduceAndOp(f.add, f.addPreCond, a, b) } -// AddMutable is the mutating version of the [Field[T].Add] method. It reduces -// the given inputs a, b if the result wouldn't fit into Element. -func (f *Field[T]) AddMutable(a, b *Element[T]) *Element[T] { - r := f.reduceAndOpMutable(f.add, f.addPreCond, a, b) - return r -} - func (f *Field[T]) addPreCond(a, b *Element[T]) (nextOverflow uint, err error) { reduceRight := a.overflow < b.overflow nextOverflow = max(a.overflow, b.overflow) + 1 if nextOverflow > f.maxOverflow() { - err = errOverflow{op: "add", nextOverflow: nextOverflow, maxOverflow: f.maxOverflow(), reduceRight: reduceRight} + err = overflowError{op: "add", nextOverflow: nextOverflow, maxOverflow: f.maxOverflow(), reduceRight: reduceRight} } return } @@ -113,13 +106,6 @@ func (f *Field[T]) MulMod(a, b *Element[T]) *Element[T] { return f.Reduce(r) } -// MulModMutable is the mutable version of the [Field[T].MulMod] method, -// reducing the inputs if the result wouldn't fit into Element. -func (f *Field[T]) MulModMutable(a, b *Element[T]) *Element[T] { - r := f.reduceAndOpMutable(f.mul, f.mulPreCond, a, b) - return f.Reduce(r) -} - // MulConst multiplies a by a constant c and returns it. We assume that the // input constant is "small", so that we can compute the product by multiplying // all individual limbs with the constant. If it is not small, then use the @@ -151,7 +137,7 @@ func (f *Field[T]) MulConst(a *Element[T], c *big.Int) *Element[T] { func(a, _ *Element[T]) (nextOverflow uint, err error) { nextOverflow = a.overflow + uint(cbl) if nextOverflow > f.maxOverflow() { - err = errOverflow{op: "mulConst", nextOverflow: nextOverflow, maxOverflow: f.maxOverflow()} + err = overflowError{op: "mulConst", nextOverflow: nextOverflow, maxOverflow: f.maxOverflow()} } return }, @@ -164,7 +150,7 @@ func (f *Field[T]) mulPreCond(a, b *Element[T]) (nextOverflow uint, err error) { nbResLimbs := nbMultiplicationResLimbs(len(a.Limbs), len(b.Limbs)) nextOverflow = f.fParams.BitsPerLimb() + uint(math.Log2(float64(2*nbResLimbs-1))) + 1 + a.overflow + b.overflow if nextOverflow > f.maxOverflow() { - err = errOverflow{op: "mul", nextOverflow: nextOverflow, maxOverflow: f.maxOverflow(), reduceRight: reduceRight} + err = overflowError{op: "mul", nextOverflow: nextOverflow, maxOverflow: f.maxOverflow(), reduceRight: reduceRight} } return } @@ -219,8 +205,7 @@ func (f *Field[T]) Reduce(a *Element[T]) *Element[T] { return a } // sanity check - _, aConst := f.constantValue(a) - if aConst { + if _, aConst := f.constantValue(a); aConst { panic("trying to reduce a constant, which happen to have an overflow flag set") } @@ -240,18 +225,11 @@ func (f *Field[T]) Sub(a, b *Element[T]) *Element[T] { return f.reduceAndOp(f.sub, f.subPreCond, a, b) } -// SubMutable is the mutating version of [Field[T].Sub] which modifies the -// inputs when needed. -func (f *Field[T]) SubMutable(a, b *Element[T]) *Element[T] { - r := f.reduceAndOpMutable(f.sub, f.subPreCond, a, b) - return r -} - func (f *Field[T]) subPreCond(a, b *Element[T]) (nextOverflow uint, err error) { reduceRight := a.overflow < b.overflow+2 nextOverflow = max(b.overflow+2, a.overflow) if nextOverflow > f.maxOverflow() { - err = errOverflow{op: "sub", nextOverflow: nextOverflow, maxOverflow: f.maxOverflow(), reduceRight: reduceRight} + err = overflowError{op: "sub", nextOverflow: nextOverflow, maxOverflow: f.maxOverflow(), reduceRight: reduceRight} } return } @@ -358,7 +336,7 @@ func (f *Field[T]) reduceAndOp(op func(*Element[T], *Element[T], uint) *Element[ f.enforceWidthConditional(b) var nextOverflow uint var err error - var target errOverflow + var target overflowError for nextOverflow, err = preCond(a, b); errors.As(err, &target); nextOverflow, err = preCond(a, b) { if !target.reduceRight { @@ -370,30 +348,13 @@ func (f *Field[T]) reduceAndOp(op func(*Element[T], *Element[T], uint) *Element[ return op(a, b, nextOverflow) } -func (f *Field[T]) reduceAndOpMutable(op func(*Element[T], *Element[T], uint) *Element[T], preCond func(*Element[T], *Element[T]) (uint, error), a, b *Element[T]) *Element[T] { - f.enforceWidthConditional(a) - f.enforceWidthConditional(b) - var nextOverflow uint - var err error - var target errOverflow - - for nextOverflow, err = preCond(a, b); errors.As(err, &target); nextOverflow, err = preCond(a, b) { - if !target.reduceRight { - *a = *f.Reduce(a) - } else { - *b = *f.Reduce(b) - } - } - return op(a, b, nextOverflow) -} - -type errOverflow struct { +type overflowError struct { op string nextOverflow uint maxOverflow uint reduceRight bool } -func (e errOverflow) Error() string { +func (e overflowError) Error() string { return fmt.Sprintf("op %s overflow %d exceeds max %d", e.op, e.nextOverflow, e.maxOverflow) } diff --git a/std/math/emulated/field_test.go b/std/math/emulated/field_test.go index 072b5cffdd..186b17c1ef 100644 --- a/std/math/emulated/field_test.go +++ b/std/math/emulated/field_test.go @@ -1,55 +1,17 @@ package emulated import ( - "crypto/rand" "errors" "fmt" - "math/big" - "sort" "testing" bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/internal/backend/circuits" - "github.com/consensys/gnark/std/algebra/fields_bls12377" "github.com/consensys/gnark/std/algebra/sw_bls12377" "github.com/consensys/gnark/test" - "github.com/stretchr/testify/require" ) -func witnessData(q *big.Int) (X1, X2, X3, X4, X5, X6, Res *big.Int) { - x1, _ := rand.Int(rand.Reader, q) - x2, _ := rand.Int(rand.Reader, q) - x3, _ := rand.Int(rand.Reader, q) - x4, _ := rand.Int(rand.Reader, q) - x5, _ := rand.Int(rand.Reader, q) - x6, _ := rand.Int(rand.Reader, q) - - tmp := new(big.Int) - res := new(big.Int) - // res = x1^3 - tmp.Exp(x1, big.NewInt(3), q) - res.Set(tmp) - // res = x1^3 + 5*x2 - tmp.Mul(x2, big.NewInt(5)) - res.Add(res, tmp) - // tmp = (x3-x4) - tmp.Sub(x3, x4) - tmp.Mod(tmp, q) - // tmp2 = (x5+x6) - tmp2 := new(big.Int) - tmp2.Add(x5, x6) - // tmp = (x3-x4)/(x5+x6) - tmp2.ModInverse(tmp2, q) - tmp.Mul(tmp, tmp2) - tmp.Mod(tmp, q) - // res = x1^3 + 5*x2 + (x3-x4)/(x5+x6) - res.Add(res, tmp) - res.Mod(res, q) - return x1, x2, x3, x4, x5, x6, res -} - type WrapperCircuit struct { X1, X2, X3, X4, X5, X6 frontend.Variable Res frontend.Variable @@ -67,130 +29,6 @@ func (c *WrapperCircuit) Define(api frontend.API) error { return nil } -func TestTestEngineWrapper(t *testing.T) { - assert := test.NewAssert(t) - - circuit := WrapperCircuit{ - X1: NewElement[Secp256k1Fp](nil), - X2: NewElement[Secp256k1Fp](nil), - X3: NewElement[Secp256k1Fp](nil), - X4: NewElement[Secp256k1Fp](nil), - X5: NewElement[Secp256k1Fp](nil), - X6: NewElement[Secp256k1Fp](nil), - Res: NewElement[Secp256k1Fp](nil), - } - - x1, x2, x3, x4, x5, x6, res := witnessData(Secp256k1Fp{}.Modulus()) - witness := WrapperCircuit{ - X1: NewElement[Secp256k1Fp](x1), - X2: NewElement[Secp256k1Fp](x2), - X3: NewElement[Secp256k1Fp](x3), - X4: NewElement[Secp256k1Fp](x4), - X5: NewElement[Secp256k1Fp](x5), - X6: NewElement[Secp256k1Fp](x6), - Res: NewElement[Secp256k1Fp](res), - } - wrapperOpt := test.WithApiWrapper(func(api frontend.API) frontend.API { - napi, err := NewAPI[Secp256k1Fp](api) - assert.NoError(err) - return napi - }) - err := test.IsSolved(&circuit, &witness, testCurve.ScalarField(), wrapperOpt) - assert.NoError(err) -} - -func TestCompilerWrapper(t *testing.T) { - assert := test.NewAssert(t) - circuit := WrapperCircuit{ - X1: NewElement[Secp256k1Fp](nil), - X2: NewElement[Secp256k1Fp](nil), - X3: NewElement[Secp256k1Fp](nil), - X4: NewElement[Secp256k1Fp](nil), - X5: NewElement[Secp256k1Fp](nil), - X6: NewElement[Secp256k1Fp](nil), - Res: NewElement[Secp256k1Fp](nil), - } - - x1, x2, x3, x4, x5, x6, res := witnessData(Secp256k1Fp{}.Modulus()) - witness := WrapperCircuit{ - X1: NewElement[Secp256k1Fp](x1), - X2: NewElement[Secp256k1Fp](x2), - X3: NewElement[Secp256k1Fp](x3), - X4: NewElement[Secp256k1Fp](x4), - X5: NewElement[Secp256k1Fp](x5), - X6: NewElement[Secp256k1Fp](x6), - Res: NewElement[Secp256k1Fp](res), - } - ccs, err := frontend.Compile(testCurve.ScalarField(), r1cs.NewBuilder, &circuit, frontend.WithBuilderWrapper(builderWrapper[Secp256k1Fp]())) - assert.NoError(err) - t.Log(ccs.GetNbConstraints()) - // TODO: create proof - _ = witness -} - -func TestIntegrationApi(t *testing.T) { - assert := test.NewAssert(t) - wrapperOpt := test.WithApiWrapper(func(api frontend.API) frontend.API { - napi, err := NewAPI[Secp256k1Fp](api) - assert.NoError(err) - return napi - }) - keys := make([]string, 0, len(circuits.Circuits)) - for k := range circuits.Circuits { - keys = append(keys, k) - } - sort.Strings(keys) - - for i := range keys { - name := keys[i] - if name == "inv" || name == "div" || name == "cmp" { - // TODO @gbotrel thes don't pass when we use emulated field modulus != snark field - continue - } - tData := circuits.Circuits[name] - assert.Run(func(assert *test.Assert) { - _, err := frontend.Compile(testCurve.ScalarField(), r1cs.NewBuilder, tData.Circuit, frontend.WithBuilderWrapper(builderWrapper[Secp256k1Fp]())) - assert.NoError(err) - }, name, "compile") - for i := range tData.ValidAssignments { - assignment := tData.ValidAssignments[i] - assert.Run(func(assert *test.Assert) { - err := test.IsSolved(tData.Circuit, assignment, testCurve.ScalarField(), wrapperOpt) - assert.NoError(err) - }, name, fmt.Sprintf("valid=%d", i)) - } - for i := range tData.InvalidAssignments { - assignment := tData.InvalidAssignments[i] - assert.Run(func(assert *test.Assert) { - err := test.IsSolved(tData.Circuit, assignment, testCurve.ScalarField(), wrapperOpt) - assert.Error(err) - }, name, fmt.Sprintf("invalid=%d", i)) - } - } -} - -func TestVarToElements(t *testing.T) { - assert := require.New(t) - w, _ := NewAPI[BN254Fp](nil) - - { - in := []frontend.Variable{8000, 42} - out1 := w.varsToElements(in...) - out2 := w.varsToElements(in) - - assert.Equal(len(out1), len(out2)) - assert.Equal(len(out1), 2) - } - - defer func() { - if r := recover(); r == nil { - t.Fatal("nil input should panic") - } - }() - in := []frontend.Variable{8000, nil, 3000} - _ = w.varsToElements(in) -} - type pairingBLS377 struct { P sw_bls12377.G1Affine `gnark:",public"` Q sw_bls12377.G2Affine @@ -217,63 +55,6 @@ func (circuit *pairingBLS377) Define(api frontend.API) error { return nil } -func TestPairingBLS377(t *testing.T) { - t.Skip() - assert := test.NewAssert(t) - - _, _, P, Q := bls12377.Generators() - milRes, _ := bls12377.MillerLoop([]bls12377.G1Affine{P}, []bls12377.G2Affine{Q}) - pairingRes := bls12377.FinalExponentiation(&milRes) - - circuit := pairingBLS377{ - pairingRes: pairingRes, - P: sw_bls12377.G1Affine{ - X: NewElement[BLS12377Fp](nil), - Y: NewElement[BLS12377Fp](nil), - }, - Q: sw_bls12377.G2Affine{ - X: fields_bls12377.E2{ - A0: NewElement[BLS12377Fp](nil), - A1: NewElement[BLS12377Fp](nil), - }, - Y: fields_bls12377.E2{ - A0: NewElement[BLS12377Fp](nil), - A1: NewElement[BLS12377Fp](nil), - }, - }, - } - witness := pairingBLS377{ - pairingRes: pairingRes, - P: sw_bls12377.G1Affine{ - X: NewElement[BLS12377Fp](P.X), - Y: NewElement[BLS12377Fp](P.Y), - }, - Q: sw_bls12377.G2Affine{ - X: fields_bls12377.E2{ - A0: NewElement[BLS12377Fp](Q.X.A0), - A1: NewElement[BLS12377Fp](Q.X.A1), - }, - Y: fields_bls12377.E2{ - A0: NewElement[BLS12377Fp](Q.Y.A0), - A1: NewElement[BLS12377Fp](Q.Y.A1), - }, - }, - } - - wrapperOpt := test.WithApiWrapper(func(api frontend.API) frontend.API { - napi, err := NewAPI[BLS12377Fp](api) - assert.NoError(err) - return napi - }) - // TODO @gbotrel test engine when test.SetAllVariablesAsConstants() also consider witness as - // constant. It shouldn't. - err := test.IsSolved(&circuit, &witness, testCurve.ScalarField(), wrapperOpt) //, test.SetAllVariablesAsConstants()) - assert.NoError(err) - // _, err = frontend.Compile(testCurve.ScalarField(), r1cs.NewBuilder, &circuit, frontend.WithBuilderWrapper(builderWrapper[BLS12377Fp]())) - // assert.NoError(err) - // TODO: create proof -} - type ConstantCircuit struct { } diff --git a/std/math/emulated/pairing_test.go b/std/math/emulated/pairing_test.go deleted file mode 100644 index a4bba56968..0000000000 --- a/std/math/emulated/pairing_test.go +++ /dev/null @@ -1,116 +0,0 @@ -package emulated - -import ( - "testing" - - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/fields_bls12377" - "github.com/consensys/gnark/std/algebra/sw_bls12377" - "github.com/consensys/gnark/test" -) - -type mlBLS377 struct { - R sw_bls12377.GT -} - -func (circuit *mlBLS377) Define(api frontend.API) error { - circuit.R, _ = e12Squares(api, circuit.R) - return nil -} - -func TestE12SquareBLS377(t *testing.T) { - if testing.Short() { - t.Skip() - } - assert := test.NewAssert(t) - - circuit := mlBLS377{ - R: sw_bls12377.GT{ - C0: fields_bls12377.E6{ - B0: fields_bls12377.E2{ - A0: NewElement[BLS12377Fp](nil), - A1: NewElement[BLS12377Fp](nil), - }, - B1: fields_bls12377.E2{ - A0: NewElement[BLS12377Fp](nil), - A1: NewElement[BLS12377Fp](nil), - }, - B2: fields_bls12377.E2{ - A0: NewElement[BLS12377Fp](nil), - A1: NewElement[BLS12377Fp](nil), - }, - }, - C1: fields_bls12377.E6{ - B0: fields_bls12377.E2{ - A0: NewElement[BLS12377Fp](nil), - A1: NewElement[BLS12377Fp](nil), - }, - B1: fields_bls12377.E2{ - A0: NewElement[BLS12377Fp](nil), - A1: NewElement[BLS12377Fp](nil), - }, - B2: fields_bls12377.E2{ - A0: NewElement[BLS12377Fp](nil), - A1: NewElement[BLS12377Fp](nil), - }, - }, - }, - } - - witness := mlBLS377{ - R: sw_bls12377.GT{ - C0: fields_bls12377.E6{ - B0: fields_bls12377.E2{ - A0: NewElement[BLS12377Fp](nil), - A1: NewElement[BLS12377Fp](nil), - }, - B1: fields_bls12377.E2{ - A0: NewElement[BLS12377Fp](nil), - A1: NewElement[BLS12377Fp](nil), - }, - B2: fields_bls12377.E2{ - A0: NewElement[BLS12377Fp](nil), - A1: NewElement[BLS12377Fp](nil), - }, - }, - C1: fields_bls12377.E6{ - B0: fields_bls12377.E2{ - A0: NewElement[BLS12377Fp](nil), - A1: NewElement[BLS12377Fp](nil), - }, - B1: fields_bls12377.E2{ - A0: NewElement[BLS12377Fp](nil), - A1: NewElement[BLS12377Fp](nil), - }, - B2: fields_bls12377.E2{ - A0: NewElement[BLS12377Fp](nil), - A1: NewElement[BLS12377Fp](nil), - }, - }, - }, - } - - wrapperOpt := test.WithApiWrapper(func(api frontend.API) frontend.API { - napi, err := NewAPI[BLS12377Fp](api) - assert.NoError(err) - return napi - }) - - err := test.IsSolved(&circuit, &witness, testCurve.ScalarField(), wrapperOpt) //, test.SetAllVariablesAsConstants()) - assert.NoError(err) - - _, err = frontend.Compile(testCurve.ScalarField(), r1cs.NewBuilder, &circuit, frontend.WithBuilderWrapper(builderWrapper[BLS12377Fp]()), frontend.IgnoreUnconstrainedInputs()) - assert.NoError(err) - -} - -// e12Squares -func e12Squares(api frontend.API, R sw_bls12377.GT) (sw_bls12377.GT, error) { - const N = 4 - for i := 0; i < N; i++ { - R.Square(api, R) - } - - return R, nil -} diff --git a/std/math/emulated/wrapped_api.go b/std/math/emulated/wrapped_api.go deleted file mode 100644 index fac6c1eef6..0000000000 --- a/std/math/emulated/wrapped_api.go +++ /dev/null @@ -1,428 +0,0 @@ -package emulated - -import ( - "errors" - "fmt" - "math/big" - - "github.com/consensys/gnark/backend/hint" - "github.com/consensys/gnark/frontend" -) - -// FieldAPI provides the wrapped [frontend.API] / [frontend.Builder] -// implementations over non-native field. The methods defined by -// [frontend.Builder] are available only if the variable is created using -// [NewBuilder]. -type FieldAPI[T FieldParams] struct { - f *Field[T] - b frontend.Builder -} - -// NewAPI wraps the native [frontend.API] to perform operations over non-native -// field defined by [FieldParams]. The [frontend.Variable] variables which are -// taken as inputs and returned as outputs in the methods are usually [*Element] -// type instances. -// -// This method can be used for taking an existing circuit, wrapping the API and -// compiling the result. It doesn't work well with parsing the schema (i.e. how -// to encode) as the parser doesn't know how to represent non-native elements. -// For that, use [NewBuilder] which also wraps the [frontend.Builder]. -// -// For optimising the circuit description, it is better to use [Field] type -// (instantiated using [NewField]), as it provides more methods, performs lazy -// reduction etc. -func NewAPI[T FieldParams](native frontend.API) (*FieldAPI[T], error) { - f, err := NewField[T](native) - if err != nil { - return nil, fmt.Errorf("new field: %w", err) - } - return &FieldAPI[T]{f: f}, nil -} - -func (w *FieldAPI[T]) varToElement(in frontend.Variable) *Element[T] { - if e, ok := in.(Element[T]); ok { - return &e - } else if e, ok := in.(*Element[T]); ok { - return e - } else if frontend.IsCanonical(in) { - r := w.f.PackFullLimbs([]frontend.Variable{in}) - return r - } else if in == nil { - r := newConstElement[T](0) - r.internal = false - return r - } else { - r := newConstElement[T](in) - r.internal = false - return r - } -} - -func (w *FieldAPI[T]) varsToElements(in ...frontend.Variable) []*Element[T] { - var els []*Element[T] - for i := range in { - switch v := in[i].(type) { - case []frontend.Variable: - subels := w.varsToElements(v...) - els = append(els, subels...) - case frontend.Variable: - els = append(els, w.varToElement(v)) - default: - // handle nil value - panic("can't convert to Element[T]") - } - } - return els -} - -func (w *FieldAPI[T]) Add(i1 frontend.Variable, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { - els := w.varsToElements(i1, i2, in) - res := w.f.reduceAndOp(w.f.add, w.f.addPreCond, els[0], els[1]) - for i := 2; i < len(els); i++ { - res = w.f.reduceAndOp(w.f.add, w.f.addPreCond, res, els[i]) // TODO @gbotrel re-use res memory, don't reallocate limbs ! - } - return res -} - -func (w *FieldAPI[T]) MulAcc(a, b, c frontend.Variable) frontend.Variable { - // TODO can we do better here to limit allocations? - return w.Add(a, w.Mul(b, c)) -} - -func (w *FieldAPI[T]) Neg(i1 frontend.Variable) frontend.Variable { - el := w.varToElement(i1) - return w.f.Neg(el) -} - -func (w *FieldAPI[T]) Sub(i1 frontend.Variable, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { - els := w.varsToElements(i1, i2, in) - tmp := els[1] - for i := 2; i < len(els); i++ { - tmp = w.f.reduceAndOp(w.f.add, w.f.addPreCond, tmp, els[i]) - } - res := w.f.Sub(els[0], tmp) - return res -} - -func (w *FieldAPI[T]) Mul(i1 frontend.Variable, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { - els := w.varsToElements(i1, i2, in) - res := w.f.reduceAndOp(w.f.mul, w.f.mulPreCond, els[0], els[1]) - for i := 2; i < len(els); i++ { - res = w.f.reduceAndOp(w.f.mul, w.f.mulPreCond, res, els[i]) - } - res = w.f.Reduce(res) - return res -} - -func (w *FieldAPI[T]) DivUnchecked(i1 frontend.Variable, i2 frontend.Variable) frontend.Variable { - return w.Div(i1, i2) -} - -func (w *FieldAPI[T]) Div(i1 frontend.Variable, i2 frontend.Variable) frontend.Variable { - els := w.varsToElements(i1, i2) - return w.f.Div(els[0], els[1]) -} - -func (w *FieldAPI[T]) Inverse(i1 frontend.Variable) frontend.Variable { - a := w.varToElement(i1) - return w.f.Inverse(a) -} - -func (w *FieldAPI[T]) ToBinary(i1 frontend.Variable, n ...int) []frontend.Variable { - el := w.varToElement(i1) - res := w.f.Reduce(el) - out := w.f.ToBits(res) - switch len(n) { - case 0: - case 1: - // TODO @gbotrel this can unecessarly constraint some bits - // and falsify test results where we only want to "mask" a part of the element - out = out[:n[0]] - default: - panic("only single vararg permitted to ToBinary") - } - return out -} - -func (w *FieldAPI[T]) FromBinary(b ...frontend.Variable) frontend.Variable { - els := w.varsToElements(b) - in := make([]frontend.Variable, len(els)) - for i := range els { - w.AssertIsBoolean(els[i]) - in[i] = els[i].Limbs[0] - } - return w.f.FromBits(in...) -} - -func (w *FieldAPI[T]) Xor(a frontend.Variable, b frontend.Variable) frontend.Variable { - els := w.varsToElements(a, b) - w.AssertIsBoolean(els[0]) - w.AssertIsBoolean(els[1]) - rv := w.f.api.Xor(els[0].Limbs[0], els[1].Limbs[0]) - return w.f.newInternalElement([]frontend.Variable{rv}, 0) -} - -func (w *FieldAPI[T]) Or(a frontend.Variable, b frontend.Variable) frontend.Variable { - els := w.varsToElements(a, b) - w.AssertIsBoolean(els[0]) - w.AssertIsBoolean(els[1]) - rv := w.f.api.Or(els[0].Limbs[0], els[1].Limbs[0]) - return w.f.newInternalElement([]frontend.Variable{rv}, 0) -} - -func (w *FieldAPI[T]) And(a frontend.Variable, b frontend.Variable) frontend.Variable { - els := w.varsToElements(a, b) - w.AssertIsBoolean(els[0]) - w.AssertIsBoolean(els[1]) - rv := w.f.api.And(els[0].Limbs[0], els[1].Limbs[0]) - return w.f.newInternalElement([]frontend.Variable{rv}, 0) -} - -func (w *FieldAPI[T]) Select(b frontend.Variable, i1 frontend.Variable, i2 frontend.Variable) frontend.Variable { - els := w.varsToElements(i1, i2) - switch vv := b.(type) { - case Element[T]: - w.AssertIsBoolean(vv) - b = vv.Limbs[0] - case *Element[T]: - w.AssertIsBoolean(vv) - b = vv.Limbs[0] - } - return w.f.Select(b, els[0], els[1]) -} - -func (w *FieldAPI[T]) Lookup2(b0 frontend.Variable, b1 frontend.Variable, i0 frontend.Variable, i1 frontend.Variable, i2 frontend.Variable, i3 frontend.Variable) frontend.Variable { - els := w.varsToElements(i0, i1, i2, i3) - switch vv := b0.(type) { - case Element[T]: - w.AssertIsBoolean(vv) - b0 = vv.Limbs[0] - case *Element[T]: - w.AssertIsBoolean(vv) - b0 = vv.Limbs[0] - } - switch vv := b1.(type) { - case Element[T]: - w.AssertIsBoolean(vv) - b1 = vv.Limbs[0] - case *Element[T]: - w.AssertIsBoolean(vv) - b1 = vv.Limbs[0] - } - return w.f.Lookup2(b0, b1, els[0], els[1], els[2], els[3]) -} - -func (w *FieldAPI[T]) IsZero(i1 frontend.Variable) frontend.Variable { - el := w.varToElement(i1) - reduced := w.f.Reduce(el) - res := w.f.api.IsZero(reduced.Limbs[0]) - for i := 1; i < len(reduced.Limbs); i++ { - w.f.api.Mul(res, w.f.api.IsZero(reduced.Limbs[i])) - } - return w.f.newInternalElement([]frontend.Variable{res}, 0) -} - -func (w *FieldAPI[T]) Cmp(i1 frontend.Variable, i2 frontend.Variable) frontend.Variable { - els := w.varsToElements(i1, i2) - rls0 := w.f.Reduce(els[0]) - rls1 := w.f.Reduce(els[1]) - var res frontend.Variable = 0 - for i := int(w.f.fParams.NbLimbs() - 1); i >= 0; i-- { - lmbCmp := w.f.api.Cmp(rls0.Limbs[i], rls1.Limbs[i]) - res = w.f.api.Select(w.f.api.IsZero(res), lmbCmp, res) - } - return res -} - -func (w *FieldAPI[T]) AssertIsEqual(i1 frontend.Variable, i2 frontend.Variable) { - els := w.varsToElements(i1, i2) - w.f.reduceAndOp(func(a, b *Element[T], nextOverflow uint) *Element[T] { - w.f.AssertIsEqual(a, b) - return nil - }, - func(e1, e2 *Element[T]) (uint, error) { - nextOverflow, err := w.f.subPreCond(e2, e1) - var target errOverflow - if err != nil && errors.As(err, &target) { - target.reduceRight = !target.reduceRight - return nextOverflow, target - } - return nextOverflow, err - }, els[0], els[1]) -} - -func (w *FieldAPI[T]) AssertIsDifferent(i1 frontend.Variable, i2 frontend.Variable) { - els := w.varsToElements(i1, i2) - rls0 := w.f.Reduce(els[0]) - rls1 := w.f.Reduce(els[1]) - var res frontend.Variable = 0 - for i := 0; i < int(w.f.fParams.NbLimbs()); i++ { - cmp := w.f.api.Cmp(rls0.Limbs[i], rls1.Limbs[i]) - cmpsq := w.f.api.Mul(cmp, cmp) - res = w.f.api.Add(res, cmpsq) - } - w.f.api.AssertIsDifferent(res, 0) -} - -func (w *FieldAPI[T]) AssertIsBoolean(i1 frontend.Variable) { - switch vv := i1.(type) { - case Element[T]: - v := w.f.Reduce(&vv) - w.f.api.AssertIsBoolean(v.Limbs[0]) - for i := 1; i < len(v.Limbs); i++ { - w.f.api.AssertIsEqual(v.Limbs[i], 0) - } - case *Element[T]: - v := w.f.Reduce(vv) - w.f.api.AssertIsBoolean(v.Limbs[0]) - for i := 1; i < len(v.Limbs); i++ { - w.f.api.AssertIsEqual(v.Limbs[i], 0) - } - default: - w.f.api.AssertIsBoolean(vv) - } -} - -func (w *FieldAPI[T]) AssertIsLessOrEqual(v frontend.Variable, bound frontend.Variable) { - els := w.varsToElements(v, bound) - l := w.f.Reduce(els[0]) - r := w.f.Reduce(els[1]) - w.f.AssertIsLessEqualThan(l, r) -} - -func (w *FieldAPI[T]) Println(a ...frontend.Variable) { - els := w.varsToElements(a) - for i := range els { - w.f.api.Println(els[i].Limbs...) - } -} - -func (w *FieldAPI[T]) Compiler() frontend.Compiler { - return w -} - -type typedInput struct { - pos int - nbLimbs int - isElement bool -} - -func (w *FieldAPI[T]) NewHint(hf hint.Function, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { - // this is a trick to allow calling hint functions using non-native - // elements. We use the fact that the hints take as inputs *big.Int values. - // Instead of supplying hf to the solver for calling, we wrap it with - // another function (implementing hint.Function), which takes as inputs the - // "expanded" version of inputs (where instead of Element[T] values we provide - // as inputs the limbs of every Element[T]) and returns nbLimbs*nbOutputs - // number of outputs (i.e. the limbs of non-native Element[T] values). The - // wrapper then recomposes and decomposes the *big.Int values at runtime and - // provides them as input to the initially provided hint function. - var expandedInputs []frontend.Variable - typedInputs := make([]typedInput, len(inputs)) - for i := range inputs { - switch vv := inputs[i].(type) { - case Element[T]: - w.f.enforceWidthConditional(&vv) - expandedInputs = append(expandedInputs, vv.Limbs...) - typedInputs[i] = typedInput{ - pos: len(expandedInputs) - len(vv.Limbs), - nbLimbs: len(vv.Limbs), - isElement: true, - } - case *Element[T]: - w.f.enforceWidthConditional(vv) - expandedInputs = append(expandedInputs, vv.Limbs...) - typedInputs[i] = typedInput{ - pos: len(expandedInputs) - len(vv.Limbs), - nbLimbs: len(vv.Limbs), - isElement: true, - } - default: - expandedInputs = append(expandedInputs, inputs[i]) - typedInputs[i] = typedInput{ - pos: len(expandedInputs) - 1, - nbLimbs: 1, - isElement: false, - } - } - } - nbNativeOutputs := nbOutputs * int(w.f.fParams.NbLimbs()) - wrappedHint := func(_ *big.Int, expandedHintInputs []*big.Int, expandedHintOutputs []*big.Int) error { - hintInputs := make([]*big.Int, len(inputs)) - hintOutputs := make([]*big.Int, nbOutputs) - for i, ti := range typedInputs { - hintInputs[i] = new(big.Int) - if ti.isElement { - if err := recompose(expandedHintInputs[ti.pos:ti.pos+ti.nbLimbs], w.f.fParams.BitsPerLimb(), hintInputs[i]); err != nil { - return fmt.Errorf("recompose: %w", err) - } - } else { - hintInputs[i].Set(expandedHintInputs[ti.pos]) - } - } - for i := range hintOutputs { - hintOutputs[i] = new(big.Int) - } - if err := hf(w.f.fParams.Modulus(), hintInputs, hintOutputs); err != nil { - return fmt.Errorf("call hint: %w", err) - } - for i := range hintOutputs { - if err := decompose(hintOutputs[i], w.f.fParams.BitsPerLimb(), expandedHintOutputs[i*int(w.f.fParams.NbLimbs()):(i+1)*int(w.f.fParams.NbLimbs())]); err != nil { - return fmt.Errorf("decompose: %w", err) - } - } - return nil - } - hintRet, err := w.f.api.Compiler().NewHint(wrappedHint, nbNativeOutputs, expandedInputs...) - if err != nil { - return nil, fmt.Errorf("NewHint: %w", err) - } - ret := make([]frontend.Variable, nbOutputs) - for i := 0; i < nbOutputs; i++ { - limbs := hintRet[i*int(w.f.fParams.NbLimbs()) : (i+1)*int(w.f.fParams.NbLimbs())] - ret[i] = w.f.newInternalElement(limbs, 0) - } - return ret, nil -} - -func (w *FieldAPI[T]) ConstantValue(v frontend.Variable) (*big.Int, bool) { - el := w.varToElement(v) - return w.f.constantValue(el) -} - -func (w *FieldAPI[T]) Field() *big.Int { - return w.f.fParams.Modulus() -} - -func (w *FieldAPI[T]) FieldBitLen() int { - return w.f.fParams.Modulus().BitLen() -} - -func (w *FieldAPI[T]) IsBoolean(v frontend.Variable) bool { - switch vv := v.(type) { - case Element[T]: - return w.f.api.Compiler().IsBoolean(vv.Limbs[0]) - case *Element[T]: - return w.f.api.Compiler().IsBoolean(vv.Limbs[0]) - default: - return w.f.api.Compiler().IsBoolean(vv) - } -} - -func (w *FieldAPI[T]) MarkBoolean(v frontend.Variable) { - switch vv := v.(type) { - case Element[T]: - w.f.api.Compiler().MarkBoolean(vv.Limbs[0]) - case *Element[T]: - w.f.api.Compiler().MarkBoolean(vv.Limbs[0]) - default: - w.f.api.Compiler().MarkBoolean(vv) - } -} - -// --- non-API methods - -func (w *FieldAPI[T]) Reduce(i1 frontend.Variable) frontend.Variable { - el := w.varToElement(i1) - return w.f.Reduce(el) -} diff --git a/std/math/emulated/wrapped_builder.go b/std/math/emulated/wrapped_builder.go deleted file mode 100644 index 1df302c45f..0000000000 --- a/std/math/emulated/wrapped_builder.go +++ /dev/null @@ -1,77 +0,0 @@ -package emulated - -import ( - "fmt" - "reflect" - "strconv" - - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/schema" -) - -// NewBuilder wraps the existing builder to be compatible with frontend builder -// option [frontend.WithBuilderWrapper]. The wrapper builder also wraps the API -// methods (embedded in the [frontend.Builder] definition). -// -// Using wrapped builder allows to take an existing circuit defined over a -// native field (and where all the public/private witness are defined as type -// [frontend.Variable]) and run it over non-native field. -// -// For most of the cases, this leads to sub-optimal performance as dedicated -// operations on the [Field] allow for writing more optimal circuits. -func NewBuilder[T FieldParams](native frontend.Builder) (*FieldAPI[T], error) { - f, err := NewField[T](native) - if err != nil { - return nil, fmt.Errorf("new field: %w", err) - } - return &FieldAPI[T]{f: f, b: native}, nil -} - -// builderWrapper returns a wrapper for the builder which is compatible to use -// as a frontend compile option. When using this wrapper, it is possible to -// extend existing circuits into any emulated field defined by -func builderWrapper[T FieldParams]() frontend.BuilderWrapper { - return func(b frontend.Builder) frontend.Builder { - b, err := NewBuilder[T](b) - if err != nil { - panic(err) - } - return b - } -} - -func (w *FieldAPI[T]) Compile() (constraint.ConstraintSystem, error) { - return w.b.Compile() -} - -func (w *FieldAPI[T]) VariableCount(_ reflect.Type) int { - return int(w.f.fParams.NbLimbs()) -} - -func (w *FieldAPI[T]) addVariable(sf schema.LeafInfo, adder func(schema.LeafInfo) frontend.Variable) frontend.Variable { - limbs := make([]frontend.Variable, w.f.fParams.NbLimbs()) - n := sf.FullName() - for i := 0; i < len(limbs); i++ { - li := sf - li.FullName = func() string { - return n + "_" + strconv.Itoa(i) - } - limbs[i] = adder(li) - } - el := w.f.PackElementLimbs(limbs) - return el -} - -func (w *FieldAPI[T]) PublicVariable(sf schema.LeafInfo) frontend.Variable { - return w.addVariable(sf, w.b.PublicVariable) -} - -func (w *FieldAPI[T]) SecretVariable(sf schema.LeafInfo) frontend.Variable { - return w.addVariable(sf, w.b.SecretVariable) -} - -func (w *FieldAPI[T]) Commit(v ...frontend.Variable) (frontend.Variable, error) { - //TODO implement me - panic("not implemented") -} From d560332012caab67243a8e2f1df62e4440043556 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 26 Jan 2023 13:51:08 -0600 Subject: [PATCH 02/10] refactor: PackElementLimbs PackFull -> packLimbs --- std/math/emulated/field.go | 19 +++++++------------ std/math/emulated/field_ops.go | 4 ++-- std/math/emulated/hints.go | 4 ++-- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/std/math/emulated/field.go b/std/math/emulated/field.go index c59b4d3cc9..2241db3c2a 100644 --- a/std/math/emulated/field.go +++ b/std/math/emulated/field.go @@ -110,19 +110,14 @@ func (f *Field[T]) Modulus() *Element[T] { return f.nConst } -// PackElementLimbs returns an element from the given limbs. The method -// constrains the limbs to have same width as the modulus of the field. -func (f *Field[T]) PackElementLimbs(limbs []frontend.Variable) *Element[T] { +// packLimbs returns an element from the given limbs. +// If strict is false, each limbs is constrained to have width as defined by field parameter. +// If strict is true, the most significant limb will be constrained to have width of the most +// significant limb of the modulus, which may have less bits than the other limbs. In which case, +// less constraints will be generated when strict = true. +func (f *Field[T]) packLimbs(limbs []frontend.Variable, strict bool) *Element[T] { e := f.newInternalElement(limbs, 0) - f.enforceWidth(e, true) - return e -} - -// PackFullLimbs creates an element from the given limbs and enforces every limb -// to have NbBits bits. -func (f *Field[T]) PackFullLimbs(limbs []frontend.Variable) *Element[T] { - e := f.newInternalElement(limbs, 0) - f.enforceWidth(e, false) + f.enforceWidth(e, strict) return e } diff --git a/std/math/emulated/field_ops.go b/std/math/emulated/field_ops.go index bf73140554..c0362ff2d0 100644 --- a/std/math/emulated/field_ops.go +++ b/std/math/emulated/field_ops.go @@ -21,7 +21,7 @@ func (f *Field[T]) Div(a, b *Element[T]) *Element[T] { if err != nil { panic(fmt.Sprintf("compute division: %v", err)) } - e := f.PackElementLimbs(div) + e := f.packLimbs(div, true) res := f.Mul(e, b) f.AssertIsEqual(res, a) return e @@ -37,7 +37,7 @@ func (f *Field[T]) Inverse(a *Element[T]) *Element[T] { if err != nil { panic(fmt.Sprintf("compute inverse: %v", err)) } - e := f.PackElementLimbs(k) + e := f.packLimbs(k, true) res := f.Mul(e, a) one := f.One() f.AssertIsEqual(res, one) diff --git a/std/math/emulated/hints.go b/std/math/emulated/hints.go index 2949c8a187..9e799e4e17 100644 --- a/std/math/emulated/hints.go +++ b/std/math/emulated/hints.go @@ -97,7 +97,7 @@ func (f *Field[T]) computeRemHint(x, y *Element[T]) (z *Element[T], err error) { if err != nil { return nil, err } - return f.PackElementLimbs(limbs), nil + return f.packLimbs(limbs, true), nil } // RemHint sets z to the remainder x%y for y != 0 and returns z. @@ -138,7 +138,7 @@ func (f *Field[T]) computeQuoHint(x *Element[T]) (z *Element[T], err error) { return nil, err } - return f.PackFullLimbs(limbs), nil + return f.packLimbs(limbs, false), nil } // QuoHint sets z to the quotient x/y for y != 0 and returns z. From 719964f7bf84a537caa76954393837c9d26ff2e1 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 26 Jan 2023 14:52:58 -0600 Subject: [PATCH 03/10] refactor: added field.NewElement --- std/algebra/weierstrass/doc_test.go | 8 +- std/algebra/weierstrass/point.go | 6 +- std/algebra/weierstrass/point_test.go | 48 ++++----- std/math/emulated/doc_example_field_test.go | 6 +- std/math/emulated/element.go | 27 ++--- std/math/emulated/element_test.go | 106 ++++++++++---------- std/math/emulated/field.go | 30 +++++- std/math/emulated/field_assert.go | 12 +-- std/math/emulated/field_ops.go | 2 +- std/math/emulated/field_test.go | 14 +-- std/signature/ecdsa/ecdsa_test.go | 20 ++-- 11 files changed, 148 insertions(+), 131 deletions(-) diff --git a/std/algebra/weierstrass/doc_test.go b/std/algebra/weierstrass/doc_test.go index 808652922f..20de03a906 100644 --- a/std/algebra/weierstrass/doc_test.go +++ b/std/algebra/weierstrass/doc_test.go @@ -23,9 +23,9 @@ func (c *ExampleCurveCircuit[B, S]) Define(api frontend.API) error { panic("initalize new curve") } G := curve.Generator() - scalar4 := emulated.NewElement[S](4) + scalar4 := emulated.NewConstant[S](4) g4 := curve.ScalarMul(G, &scalar4) // 4*G - scalar5 := emulated.NewElement[S](5) + scalar5 := emulated.NewConstant[S](5) g5 := curve.ScalarMul(G, &scalar5) // 5*G g9 := curve.Add(g4, g5) // 9*G curve.AssertIsEqual(g9, &c.Res) @@ -41,8 +41,8 @@ func ExampleCurve() { circuit := ExampleCurveCircuit[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := ExampleCurveCircuit[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ Res: weierstrass.AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewElement[emulated.Secp256k1Fp](secpCurve.Gx), - Y: emulated.NewElement[emulated.Secp256k1Fp](secpCurve.Gy), + X: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gx), + Y: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gy), }, } ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) diff --git a/std/algebra/weierstrass/point.go b/std/algebra/weierstrass/point.go index e12677de01..22dab07b69 100644 --- a/std/algebra/weierstrass/point.go +++ b/std/algebra/weierstrass/point.go @@ -21,8 +21,8 @@ func New[Base, Scalars emulated.FieldParams](api frontend.API, params CurveParam if err != nil { return nil, fmt.Errorf("new scalar api: %w", err) } - Gx := emulated.NewElement[Base](params.Gx) - Gy := emulated.NewElement[Base](params.Gy) + Gx := emulated.NewConstant[Base](params.Gx) + Gy := emulated.NewConstant[Base](params.Gy) return &Curve[Base, Scalars]{ params: params, api: api, @@ -32,7 +32,7 @@ func New[Base, Scalars emulated.FieldParams](api frontend.API, params CurveParam X: Gx, Y: Gy, }, - a: emulated.NewElement[Base](params.A), + a: emulated.NewConstant[Base](params.A), addA: params.A.Cmp(big.NewInt(0)) != 0, }, nil } diff --git a/std/algebra/weierstrass/point_test.go b/std/algebra/weierstrass/point_test.go index f6a00e8b56..e3cc777c9c 100644 --- a/std/algebra/weierstrass/point_test.go +++ b/std/algebra/weierstrass/point_test.go @@ -36,12 +36,12 @@ func TestNeg(t *testing.T) { circuit := NegTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := NegTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ P: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewElement[emulated.Secp256k1Fp](secpCurve.Gx), - Y: emulated.NewElement[emulated.Secp256k1Fp](secpCurve.Gy), + X: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gx), + Y: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gy), }, Q: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewElement[emulated.Secp256k1Fp](secpCurve.Gx), - Y: emulated.NewElement[emulated.Secp256k1Fp](yn), + X: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gx), + Y: emulated.NewConstant[emulated.Secp256k1Fp](yn), }, } err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) @@ -70,16 +70,16 @@ func TestAdd(t *testing.T) { circuit := AddTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := AddTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ P: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewElement[emulated.Secp256k1Fp](secpCurve.Gx), - Y: emulated.NewElement[emulated.Secp256k1Fp](secpCurve.Gy), + X: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gx), + Y: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gy), }, Q: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewElement[emulated.Secp256k1Fp](xd), - Y: emulated.NewElement[emulated.Secp256k1Fp](yd), + X: emulated.NewConstant[emulated.Secp256k1Fp](xd), + Y: emulated.NewConstant[emulated.Secp256k1Fp](yd), }, R: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewElement[emulated.Secp256k1Fp](xa), - Y: emulated.NewElement[emulated.Secp256k1Fp](ya), + X: emulated.NewConstant[emulated.Secp256k1Fp](xa), + Y: emulated.NewConstant[emulated.Secp256k1Fp](ya), }, } err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) @@ -107,12 +107,12 @@ func TestDouble(t *testing.T) { circuit := DoubleTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := DoubleTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ P: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewElement[emulated.Secp256k1Fp](secpCurve.Gx), - Y: emulated.NewElement[emulated.Secp256k1Fp](secpCurve.Gy), + X: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gx), + Y: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gy), }, Q: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewElement[emulated.Secp256k1Fp](xd), - Y: emulated.NewElement[emulated.Secp256k1Fp](yd), + X: emulated.NewConstant[emulated.Secp256k1Fp](xd), + Y: emulated.NewConstant[emulated.Secp256k1Fp](yd), }, } err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) @@ -143,14 +143,14 @@ func TestScalarMul(t *testing.T) { circuit := ScalarMulTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := ScalarMulTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ - S: emulated.NewElement[emulated.Secp256k1Fr](s), + S: emulated.NewConstant[emulated.Secp256k1Fr](s), P: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewElement[emulated.Secp256k1Fp](secpCurve.Gx), - Y: emulated.NewElement[emulated.Secp256k1Fp](secpCurve.Gy), + X: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gx), + Y: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gy), }, Q: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewElement[emulated.Secp256k1Fp](sx), - Y: emulated.NewElement[emulated.Secp256k1Fp](sy), + X: emulated.NewConstant[emulated.Secp256k1Fp](sx), + Y: emulated.NewConstant[emulated.Secp256k1Fp](sy), }, } err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) @@ -169,14 +169,14 @@ func TestScalarMul2(t *testing.T) { circuit := ScalarMulTest[emulated.BN254Fp, emulated.BN254Fr]{} witness := ScalarMulTest[emulated.BN254Fp, emulated.BN254Fr]{ - S: emulated.NewElement[emulated.BN254Fr](s), + S: emulated.NewConstant[emulated.BN254Fr](s), P: AffinePoint[emulated.BN254Fp]{ - X: emulated.NewElement[emulated.BN254Fp](gen.X.BigInt(new(big.Int))), - Y: emulated.NewElement[emulated.BN254Fp](gen.Y.BigInt(new(big.Int))), + X: emulated.NewConstant[emulated.BN254Fp](gen.X.BigInt(new(big.Int))), + Y: emulated.NewConstant[emulated.BN254Fp](gen.Y.BigInt(new(big.Int))), }, Q: AffinePoint[emulated.BN254Fp]{ - X: emulated.NewElement[emulated.BN254Fp](res.X.BigInt(new(big.Int))), - Y: emulated.NewElement[emulated.BN254Fp](res.Y.BigInt(new(big.Int))), + X: emulated.NewConstant[emulated.BN254Fp](res.X.BigInt(new(big.Int))), + Y: emulated.NewConstant[emulated.BN254Fp](res.Y.BigInt(new(big.Int))), }, } err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) diff --git a/std/math/emulated/doc_example_field_test.go b/std/math/emulated/doc_example_field_test.go index 2eabc62bca..19451a5090 100644 --- a/std/math/emulated/doc_example_field_test.go +++ b/std/math/emulated/doc_example_field_test.go @@ -33,9 +33,9 @@ func (c *ExampleFieldCircuit[T]) Define(api frontend.API) error { func ExampleField() { circuit := ExampleFieldCircuit[emulated.BN254Fp]{} witness := ExampleFieldCircuit[emulated.BN254Fp]{ - In1: emulated.NewElement[emulated.BN254Fp](3), - In2: emulated.NewElement[emulated.BN254Fp](5), - Res: emulated.NewElement[emulated.BN254Fp](15), + In1: emulated.NewConstant[emulated.BN254Fp](3), + In2: emulated.NewConstant[emulated.BN254Fp](5), + Res: emulated.NewConstant[emulated.BN254Fp](15), } ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) if err != nil { diff --git a/std/math/emulated/element.go b/std/math/emulated/element.go index b780bed037..a518c3f688 100644 --- a/std/math/emulated/element.go +++ b/std/math/emulated/element.go @@ -33,26 +33,17 @@ type Element[T FieldParams] struct { internal bool } -// NewElement builds a new emulated element from input. The inputs can be: -// - of type Element[T] (or a pointer to it). Then, the limbs are cloned and packed into new Element[T], -// - integer-like. Then it is cast to [*big.Int], decomposed into limbs and packed into new Element[T], -func NewElement[T FieldParams](v interface{}) Element[T] { - if e, ok := v.(Element[T]); ok { - return *e.copy() - } else if e, ok := v.(*Element[T]); ok { - return *e.copy() - } else if frontend.IsCanonical(v) { - // We can not force that v is correct width. Better use PackFullLimbs - panic("can not enforec limb width. Use PackLimbs instead") - } else if v == nil { +// NewConstant returns an Element[T] from a constant value. +// The input is converted to *big.Int and decomposed into limbs and packed into new Element[T]. +func NewConstant[T FieldParams](constant interface{}) Element[T] { + if constant == nil { r := newConstElement[T](0) - r.internal = false - return *r - } else { - r := newConstElement[T](v) - r.internal = false + // r.internal = false return *r } + r := newConstElement[T](constant) + // r.internal = false + return *r } // newConstElement is shorthand for initialising new element using NewElement and @@ -100,7 +91,7 @@ func (f *Field[T]) newInternalElement(limbs []frontend.Variable, overflow uint) // GnarkInitHook describes how to initialise the element. func (e *Element[T]) GnarkInitHook() { if e.Limbs == nil { - *e = NewElement[T](0) + *e = NewConstant[T](0) } } diff --git a/std/math/emulated/element_test.go b/std/math/emulated/element_test.go index 4e1351e1eb..7d18d0ef0c 100644 --- a/std/math/emulated/element_test.go +++ b/std/math/emulated/element_test.go @@ -47,8 +47,8 @@ func testAssertLimbEqualityNoOverflow[T FieldParams](t *testing.T) { assert.Run(func(assert *test.Assert) { var circuit, witness AssertLimbEqualityCircuit[T] val, _ := rand.Int(rand.Reader, fp.Modulus()) - witness.A = NewElement[T](val) - witness.B = NewElement[T](val) + witness.A = NewConstant[T](val) + witness.B = NewConstant[T](val) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -64,7 +64,7 @@ func (c *AssertIsLessEqualThanCircuit[T]) Define(api frontend.API) error { if err != nil { return err } - f.AssertIsLessEqualThan(&c.L, &c.R) + f.AssertIsLessOrEqual(&c.L, &c.R) return nil } @@ -81,8 +81,8 @@ func testAssertIsLessEqualThan[T FieldParams](t *testing.T) { var circuit, witness AssertIsLessEqualThanCircuit[T] R, _ := rand.Int(rand.Reader, fp.Modulus()) L, _ := rand.Int(rand.Reader, R) - witness.R = NewElement[T](R) - witness.L = NewElement[T](L) + witness.R = NewConstant[T](R) + witness.L = NewConstant[T](L) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -116,9 +116,9 @@ func testAddCircuitNoOverflow[T FieldParams](t *testing.T) { val1, _ := rand.Int(rand.Reader, bound) val2, _ := rand.Int(rand.Reader, bound) res := new(big.Int).Add(val1, val2) - witness.A = NewElement[T](val1) - witness.B = NewElement[T](val2) - witness.C = NewElement[T](res) + witness.A = NewConstant[T](val1) + witness.B = NewConstant[T](val2) + witness.C = NewConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -153,9 +153,9 @@ func testMulCircuitNoOverflow[T FieldParams](t *testing.T) { val1, _ := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), uint(fp.Modulus().BitLen())/2)) val2, _ := rand.Int(rand.Reader, new(big.Int).Div(fp.Modulus(), val1)) res := new(big.Int).Mul(val1, val2) - witness.A = NewElement[T](val1) - witness.B = NewElement[T](val2) - witness.C = NewElement[T](res) + witness.A = NewConstant[T](val1) + witness.B = NewConstant[T](val2) + witness.C = NewConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16)) }, testName[T]()) } @@ -191,9 +191,9 @@ func testMulCircuitOverflow[T FieldParams](t *testing.T) { val2, _ := rand.Int(rand.Reader, fp.Modulus()) res := new(big.Int).Mul(val1, val2) res.Mod(res, fp.Modulus()) - witness.A = NewElement[T](val1) - witness.B = NewElement[T](val2) - witness.C = NewElement[T](res) + witness.A = NewConstant[T](val1) + witness.B = NewConstant[T](val2) + witness.C = NewConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -230,9 +230,9 @@ func testReduceAfterAdd[T FieldParams](t *testing.T) { val1, _ := rand.Int(rand.Reader, val2) val3 := new(big.Int).Add(val1, fp.Modulus()) val3.Sub(val3, val2) - witness.A = NewElement[T](val3) - witness.B = NewElement[T](val2) - witness.C = NewElement[T](val1) + witness.A = NewConstant[T](val3) + witness.B = NewConstant[T](val2) + witness.C = NewConstant[T](val1) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -271,9 +271,9 @@ func testSubtractNoOverflow[T FieldParams](t *testing.T) { val1, _ := rand.Int(rand.Reader, fp.Modulus()) val2, _ := rand.Int(rand.Reader, val1) res := new(big.Int).Sub(val1, val2) - witness.A = NewElement[T](val1) - witness.B = NewElement[T](val2) - witness.C = NewElement[T](res) + witness.A = NewConstant[T](val1) + witness.B = NewConstant[T](val2) + witness.C = NewConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -288,9 +288,9 @@ func testSubtractOverflow[T FieldParams](t *testing.T) { val2.Add(val2, val1) res := new(big.Int).Sub(val1, val2) res.Mod(res, fp.Modulus()) - witness.A = NewElement[T](val1) - witness.B = NewElement[T](val2) - witness.C = NewElement[T](res) + witness.A = NewConstant[T](val1) + witness.B = NewConstant[T](val2) + witness.C = NewConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -323,8 +323,8 @@ func testNegation[T FieldParams](t *testing.T) { var circuit, witness NegationCircuit[T] val1, _ := rand.Int(rand.Reader, fp.Modulus()) res := new(big.Int).Sub(fp.Modulus(), val1) - witness.A = NewElement[T](val1) - witness.B = NewElement[T](res) + witness.A = NewConstant[T](val1) + witness.B = NewConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -360,8 +360,8 @@ func testInverse[T FieldParams](t *testing.T) { var circuit, witness InverseCircuit[T] val1, _ := rand.Int(rand.Reader, fp.Modulus()) res := new(big.Int).ModInverse(val1, fp.Modulus()) - witness.A = NewElement[T](val1) - witness.B = NewElement[T](res) + witness.A = NewConstant[T](val1) + witness.B = NewConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -402,9 +402,9 @@ func testDivision[T FieldParams](t *testing.T) { res.ModInverse(val2, fp.Modulus()) res.Mul(val1, res) res.Mod(res, fp.Modulus()) - witness.A = NewElement[T](val1) - witness.B = NewElement[T](val2) - witness.C = NewElement[T](res) + witness.A = NewConstant[T](val1) + witness.B = NewConstant[T](val2) + witness.C = NewConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -447,7 +447,7 @@ func testToBinary[T FieldParams](t *testing.T) { for i := 0; i < len(bits); i++ { bits[i] = val1.Bit(i) } - witness.Value = NewElement[T](val1) + witness.Value = NewConstant[T](val1) witness.Bits = bits assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) @@ -488,7 +488,7 @@ func testFromBinary[T FieldParams](t *testing.T) { bits[i] = val1.Bit(i) } - witness.Res = NewElement[T](val1) + witness.Res = NewConstant[T](val1) witness.Bits = bits assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) @@ -521,8 +521,8 @@ func testConstantEqual[T FieldParams](t *testing.T) { assert.Run(func(assert *test.Assert) { var circuit, witness EqualityCheckCircuit[T] val, _ := rand.Int(rand.Reader, fp.Modulus()) - witness.A = NewElement[T](val) - witness.B = NewElement[T](val) + witness.A = NewConstant[T](val) + witness.B = NewConstant[T](val) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -565,10 +565,10 @@ func testSelect[T FieldParams](t *testing.T) { randbit, _ := rand.Int(rand.Reader, big.NewInt(2)) b := randbit.Uint64() - witness.A = NewElement[T](val1) - witness.B = NewElement[T](val2) - witness.C = NewElement[T](val3) - witness.D = NewElement[T]([]*big.Int{l, val3}[1-b]) + witness.A = NewConstant[T](val1) + witness.B = NewConstant[T](val2) + witness.C = NewConstant[T](val3) + witness.D = NewConstant[T]([]*big.Int{l, val3}[1-b]) witness.Selector = b assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) @@ -613,11 +613,11 @@ func testLookup2[T FieldParams](t *testing.T) { val4, _ := rand.Int(rand.Reader, fp.Modulus()) randbit, _ := rand.Int(rand.Reader, big.NewInt(4)) - witness.A = NewElement[T](val1) - witness.B = NewElement[T](val2) - witness.C = NewElement[T](val3) - witness.D = NewElement[T](val4) - witness.E = NewElement[T]([]*big.Int{val1, val2, val3, val4}[randbit.Uint64()]) + witness.A = NewConstant[T](val1) + witness.B = NewConstant[T](val2) + witness.C = NewConstant[T](val3) + witness.D = NewConstant[T](val4) + witness.E = NewConstant[T]([]*big.Int{val1, val2, val3, val4}[randbit.Uint64()]) witness.Bit0 = randbit.Bit(0) witness.Bit1 = randbit.Bit(1) @@ -648,7 +648,7 @@ func (c *ComputationCircuit[T]) Define(api frontend.API) error { } // TODO @gbotrel better way to deal with constants? - five := NewElement[T](5) + five := NewConstant[T](5) fx2 := f.Mul(&five, &c.X2) fx2 = f.Reduce(fx2) @@ -707,13 +707,13 @@ func testComputation[T FieldParams](t *testing.T) { res.Add(res, tmp) res.Mod(res, fp.Modulus()) - witness.X1 = NewElement[T](val1) - witness.X2 = NewElement[T](val2) - witness.X3 = NewElement[T](val3) - witness.X4 = NewElement[T](val4) - witness.X5 = NewElement[T](val5) - witness.X6 = NewElement[T](val6) - witness.Res = NewElement[T](res) + witness.X1 = NewConstant[T](val1) + witness.X2 = NewConstant[T](val2) + witness.X3 = NewConstant[T](val3) + witness.X4 = NewConstant[T](val4) + witness.X5 = NewConstant[T](val5) + witness.X6 = NewConstant[T](val6) + witness.Res = NewConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) @@ -768,8 +768,8 @@ func testFourMuls[T FieldParams](t *testing.T) { res.Mul(res, val1) res.Mod(res, fp.Modulus()) - witness.A = NewElement[T](val1) - witness.Res = NewElement[T](res) + witness.A = NewConstant[T](val1) + witness.Res = NewConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } diff --git a/std/math/emulated/field.go b/std/math/emulated/field.go index 2241db3c2a..e829e269e2 100644 --- a/std/math/emulated/field.go +++ b/std/math/emulated/field.go @@ -86,6 +86,32 @@ func NewField[T FieldParams](native frontend.API) (*Field[T], error) { return f, nil } +// NewElement builds a new Element[T] from input v. +// - if v is a Element[T] or *Element[T] it clones it +// - if v is a constant this is equivalent to calling emulated.NewConstant[T] +// - if this methods interpret v (frontend.Variable or []frontend.Variable) as being the limbs; and constrain the limbs following the parameters of the Field. +func (f *Field[T]) NewElement(v interface{}) *Element[T] { + if e, ok := v.(Element[T]); ok { + return e.copy() + } + if e, ok := v.(*Element[T]); ok { + return e.copy() + } + if frontend.IsCanonical(v) { + return f.packLimbs([]frontend.Variable{v}, true) + } + if e, ok := v.([]frontend.Variable); ok { + for _, sv := range e { + if !frontend.IsCanonical(sv) { + panic("[]frontend.Variable that are not canonical (known to the compiler) is not a valid input") + } + } + return f.packLimbs(e, true) + } + c := NewConstant[T](v) + return &c +} + // Zero returns zero as a constant. func (f *Field[T]) Zero() *Element[T] { f.zeroConstOnce.Do(func() { @@ -111,10 +137,10 @@ func (f *Field[T]) Modulus() *Element[T] { } // packLimbs returns an element from the given limbs. -// If strict is false, each limbs is constrained to have width as defined by field parameter. // If strict is true, the most significant limb will be constrained to have width of the most // significant limb of the modulus, which may have less bits than the other limbs. In which case, -// less constraints will be generated when strict = true. +// less constraints will be generated. +// If strict is false, each limbs is constrained to have width as defined by field parameter. func (f *Field[T]) packLimbs(limbs []frontend.Variable, strict bool) *Element[T] { e := f.newInternalElement(limbs, 0) f.enforceWidth(e, strict) diff --git a/std/math/emulated/field_assert.go b/std/math/emulated/field_assert.go index 96311a7f9b..c8daae2bf5 100644 --- a/std/math/emulated/field_assert.go +++ b/std/math/emulated/field_assert.go @@ -81,9 +81,9 @@ func rsh(api frontend.API, v frontend.Variable, startDigit, endDigit int) fronte } -// AssertLimbsEquality asserts that the limbs represent a same integer value (up -// to overflow). This method does not ensure that the values are equal modulo -// the field order. For strict equality, use AssertIsEqual. +// AssertLimbsEquality asserts that the limbs represent a same integer value. +// This method does not ensure that the values are equal modulo the field order. +// For strict equality, use AssertIsEqual. func (f *Field[T]) AssertLimbsEquality(a, b *Element[T]) { f.enforceWidthConditional(a) f.enforceWidthConditional(b) @@ -98,7 +98,7 @@ func (f *Field[T]) AssertLimbsEquality(a, b *Element[T]) { return } - // first, we check if we can compact the e and other; they could be using 8 limbs of 32bits + // first, we check if we can compact a and b; they could be using 8 limbs of 32bits // but with our snark field, we could express them in 2 limbs of 128bits, which would make bit decomposition // and limbs equality in-circuit (way) cheaper ca, cb, bitsPerLimb := f.compact(a, b) @@ -170,8 +170,8 @@ func (f *Field[T]) AssertIsEqual(a, b *Element[T]) { f.AssertLimbsEquality(diff, kp) } -// AssertIsEqualLessThan ensures that e is less or equal than e. -func (f *Field[T]) AssertIsLessEqualThan(e, a *Element[T]) { +// AssertIsLessOrEqual ensures that e is less or equal than a. +func (f *Field[T]) AssertIsLessOrEqual(e, a *Element[T]) { // we omit conditional width assertion as is done in ToBits below if e.overflow+a.overflow > 0 { panic("inputs must have 0 overflow") diff --git a/std/math/emulated/field_ops.go b/std/math/emulated/field_ops.go index c0362ff2d0..baa7154f5d 100644 --- a/std/math/emulated/field_ops.go +++ b/std/math/emulated/field_ops.go @@ -112,7 +112,7 @@ func (f *Field[T]) MulMod(a, b *Element[T]) *Element[T] { // general [Field[T].Mul] or [Field[T].MulMod] with creating new Element from // the constant on-the-fly. func (f *Field[T]) MulConst(a *Element[T], c *big.Int) *Element[T] { - switch c.Cmp(big.NewInt(0)) { + switch c.Sign() { case -1: f.MulConst(f.Neg(a), new(big.Int).Neg(c)) case 0: diff --git a/std/math/emulated/field_test.go b/std/math/emulated/field_test.go index 186b17c1ef..3d98b3e5ec 100644 --- a/std/math/emulated/field_test.go +++ b/std/math/emulated/field_test.go @@ -64,7 +64,7 @@ func (c *ConstantCircuit) Define(api frontend.API) error { return err } { - c1 := NewElement[Secp256k1Fp](42) + c1 := NewConstant[Secp256k1Fp](42) b1, ok := f.constantValue(&c1) if !ok { return errors.New("42 should be constant") @@ -107,9 +107,9 @@ func (c *MulConstantCircuit) Define(api frontend.API) error { if err != nil { return err } - c0 := NewElement[Secp256k1Fp](0) - c1 := NewElement[Secp256k1Fp](0) - c2 := NewElement[Secp256k1Fp](0) + c0 := NewConstant[Secp256k1Fp](0) + c1 := NewConstant[Secp256k1Fp](0) + c2 := NewConstant[Secp256k1Fp](0) r := f.Mul(&c0, &c1) f.AssertIsEqual(r, &c2) @@ -136,9 +136,9 @@ func (c *SubConstantCircuit) Define(api frontend.API) error { if err != nil { return err } - c0 := NewElement[Secp256k1Fp](0) - c1 := NewElement[Secp256k1Fp](0) - c2 := NewElement[Secp256k1Fp](0) + c0 := NewConstant[Secp256k1Fp](0) + c1 := NewConstant[Secp256k1Fp](0) + c2 := NewConstant[Secp256k1Fp](0) r := f.Sub(&c0, &c1) if r.overflow != 0 { return fmt.Errorf("overflow %d != 0", r.overflow) diff --git a/std/signature/ecdsa/ecdsa_test.go b/std/signature/ecdsa/ecdsa_test.go index 4f5f8474db..3599023e15 100644 --- a/std/signature/ecdsa/ecdsa_test.go +++ b/std/signature/ecdsa/ecdsa_test.go @@ -65,13 +65,13 @@ func TestEcdsa(t *testing.T) { circuit := EcdsaCircuit[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := EcdsaCircuit[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ Sig: Signature[emulated.Secp256k1Fr]{ - R: emulated.NewElement[emulated.Secp256k1Fr](r), - S: emulated.NewElement[emulated.Secp256k1Fr](s), + R: emulated.NewConstant[emulated.Secp256k1Fr](r), + S: emulated.NewConstant[emulated.Secp256k1Fr](s), }, - Msg: emulated.NewElement[emulated.Secp256k1Fr](m), + Msg: emulated.NewConstant[emulated.Secp256k1Fr](m), Pub: PublicKey[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ - X: emulated.NewElement[emulated.Secp256k1Fp](_pub.X), - Y: emulated.NewElement[emulated.Secp256k1Fp](_pub.Y), + X: emulated.NewConstant[emulated.Secp256k1Fp](_pub.X), + Y: emulated.NewConstant[emulated.Secp256k1Fp](_pub.Y), }, } assert := test.NewAssert(t) @@ -90,13 +90,13 @@ func ExamplePublicKey_Verify() { // can be done in or out-circuit. Sig := Signature[emulated.Secp256k1Fr]{ - R: emulated.NewElement[emulated.Secp256k1Fr](r), - S: emulated.NewElement[emulated.Secp256k1Fr](s), + R: emulated.NewConstant[emulated.Secp256k1Fr](r), + S: emulated.NewConstant[emulated.Secp256k1Fr](s), } - Msg := emulated.NewElement[emulated.Secp256k1Fr](m) + Msg := emulated.NewConstant[emulated.Secp256k1Fr](m) Pub := PublicKey[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ - X: emulated.NewElement[emulated.Secp256k1Fp](pubx), - Y: emulated.NewElement[emulated.Secp256k1Fp](puby), + X: emulated.NewConstant[emulated.Secp256k1Fp](pubx), + Y: emulated.NewConstant[emulated.Secp256k1Fp](puby), } // signature verification assertion is done in-circuit Pub.Verify(api, weierstrass.GetCurveParams[emulated.Secp256k1Fp](), &Msg, &Sig) From ba501b43189905aca7e3b51aea0f6f85135080c3 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 26 Jan 2023 15:07:42 -0600 Subject: [PATCH 04/10] refactor: remove deadcode from builder stuff, update stats with constraining inputs --- examples/emulated/emulated_test.go | 6 +++--- frontend/builder.go | 5 ----- frontend/compile.go | 22 +--------------------- frontend/cs/r1cs/builder.go | 5 ----- frontend/cs/scs/builder.go | 4 ---- internal/stats/latest.stats | Bin 2801 -> 2801 bytes internal/stats/snippet.go | 25 +++++++++++++++---------- 7 files changed, 19 insertions(+), 48 deletions(-) diff --git a/examples/emulated/emulated_test.go b/examples/emulated/emulated_test.go index ef8358bac0..75f380ed57 100644 --- a/examples/emulated/emulated_test.go +++ b/examples/emulated/emulated_test.go @@ -16,9 +16,9 @@ func TestEmulatedArithmetic(t *testing.T) { var circuit, witness Circuit - witness.X = emulated.NewElement[emulated.Secp256k1Fp]("26959946673427741531515197488526605382048662297355296634326893985793") - witness.Y = emulated.NewElement[emulated.Secp256k1Fp]("53919893346855483063030394977053210764097324594710593268653787971586") - witness.Res = emulated.NewElement[emulated.Secp256k1Fp]("485279052387156144224396168012515269674445015885648619762653195154800") + witness.X = emulated.NewConstant[emulated.Secp256k1Fp]("26959946673427741531515197488526605382048662297355296634326893985793") + witness.Y = emulated.NewConstant[emulated.Secp256k1Fp]("53919893346855483063030394977053210764097324594710593268653787971586") + witness.Res = emulated.NewConstant[emulated.Secp256k1Fp]("485279052387156144224396168012515269674445015885648619762653195154800") assert.ProverSucceeded(&circuit, &witness, test.WithCurves(ecc.BN254), test.WithBackends(backend.GROTH16), test.NoSerialization()) } diff --git a/frontend/builder.go b/frontend/builder.go index 6a9a048ee8..c15dc1d334 100644 --- a/frontend/builder.go +++ b/frontend/builder.go @@ -2,7 +2,6 @@ package frontend import ( "math/big" - "reflect" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" @@ -66,10 +65,6 @@ type Builder interface { // Compile is called after circuit.Define() to produce a final IR (ConstraintSystem) Compile() (constraint.ConstraintSystem, error) - // VariableCount returns the number of native elements required to represent - // the given reflected type as a witness. - VariableCount(reflect.Type) int - // PublicVariable is called by the compiler when parsing the circuit schema. It panics if // called inside circuit.Define() PublicVariable(schema.LeafInfo) Variable diff --git a/frontend/compile.go b/frontend/compile.go index 87791cedfe..d39ff5dd7b 100644 --- a/frontend/compile.go +++ b/frontend/compile.go @@ -36,7 +36,7 @@ func Compile(field *big.Int, newBuilder NewBuilder, circuit Circuit, opts ...Com log := logger.Logger() log.Info().Msg("compiling circuit") // parse options - opt := CompileConfig{wrapper: func(b Builder) Builder { return b }} + opt := CompileConfig{} for _, o := range opts { if err := o(&opt); err != nil { log.Err(err).Msg("applying compile option") @@ -50,7 +50,6 @@ func Compile(field *big.Int, newBuilder NewBuilder, circuit Circuit, opts ...Com log.Err(err).Msg("instantiating builder") return nil, fmt.Errorf("new compiler: %w", err) } - builder = opt.wrapper(builder) // parse the circuit builds a schema of the circuit // and call circuit.Define() method to initialize a list of constraints in the compiler @@ -75,11 +74,6 @@ func parseCircuit(builder Builder, circuit Circuit) (err error) { return err } - // we scale the number of secret and public variables by n; - // scs and r1cs builder always return 1. Emulated arithmetic returns number of limbs per variable. - n := builder.VariableCount(nil) - s.Public *= n - s.Secret *= n log := logger.Logger() log.Info().Int("nbSecret", s.Secret).Int("nbPublic", s.Public).Msg("parsed circuit inputs") @@ -140,7 +134,6 @@ type CompileOption func(opt *CompileConfig) error type CompileConfig struct { Capacity int IgnoreUnconstrainedInputs bool - wrapper BuilderWrapper CompressThreshold int } @@ -168,19 +161,6 @@ func IgnoreUnconstrainedInputs() CompileOption { } } -// BuilderWrapper wraps existing Builder. -type BuilderWrapper func(Builder) Builder - -// WithBuilderWrapper is a compile option which wraps the builder before parsing -// the schema and calling Define method of the circuit. If not set, then the -// builder returned by the NewBuilder is directly used. -func WithBuilderWrapper(wrapper BuilderWrapper) CompileOption { - return func(opt *CompileConfig) error { - opt.wrapper = wrapper - return nil - } -} - // WithCompressThreshold is a compile option which enforces automatic variable // compression if the length of the linear expression in the variable exceeds // given threshold. diff --git a/frontend/cs/r1cs/builder.go b/frontend/cs/r1cs/builder.go index 5fa4906f58..a811dc2462 100644 --- a/frontend/cs/r1cs/builder.go +++ b/frontend/cs/r1cs/builder.go @@ -125,11 +125,6 @@ func (builder *builder) newInternalVariable() expr.LinearExpression { return expr.NewLinearExpression(idx, builder.tOne) } -func (builder *builder) VariableCount(t reflect.Type) int { - // TODO @gbotrel refactor? - return 1 -} - // PublicVariable creates a new public Variable func (builder *builder) PublicVariable(f schema.LeafInfo) frontend.Variable { idx := builder.cs.AddPublicVariable(f.FullName()) diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index 10d467bfdb..dce80a0aeb 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -145,10 +145,6 @@ func (builder *scs) newInternalVariable() expr.TermToRefactor { return expr.NewTermToRefactor(idx, constraint.CoeffIdOne) } -func (builder *scs) VariableCount(t reflect.Type) int { - return 1 -} - // PublicVariable creates a new Public Variable func (builder *scs) PublicVariable(f schema.LeafInfo) frontend.Variable { idx := builder.cs.AddPublicVariable(f.FullName()) diff --git a/internal/stats/latest.stats b/internal/stats/latest.stats index f94898534b4a492a4755c38adda1692ebaeade91..debd58dfe4c750dca62909a07d87e02dedc2eaa4 100644 GIT binary patch delta 249 zcmew;`cZU3*5o*jmdW$Ef+q8@T%DNpVDcf(yOR&G-kt2l_;9j1^V7-m*)-}cwlV&* zuwnobxEX5S82_ow0;nU*;l&Vg`E( XO_+S23?e5 delta 254 zcmew;`cZU3)?`tp2b0&cJY>|HJdss=au~;x$rD(gPIh3tIysj8;p9uqcPE#!Y1ErO zV*F>C#sDO6Gqh3||7kG+)#%wU{?omHP|U!=_^){f5ZeI7@GugK82=>-0M+C?1L7)# dVg`E(O_*%Kd2?b`%Va^W2a~@t-JSR@2mnYvYV!a9 diff --git a/internal/stats/snippet.go b/internal/stats/snippet.go index 5128a1b20f..c3c8ebd44a 100644 --- a/internal/stats/snippet.go +++ b/internal/stats/snippet.go @@ -80,22 +80,27 @@ func initSnippets() { _ = mimc.Sum() }) registerSnippet("math/emulated/secp256k1_64", func(api frontend.API, newVariable func() frontend.Variable) { - secp256k1, _ := emulated.NewAPI[emulated.Secp256k1Fp](api) + secp256k1, _ := emulated.NewField[emulated.Secp256k1Fp](api) - newElement := func() emulated.Element[emulated.Secp256k1Fp] { - r := emulated.NewElement[emulated.Secp256k1Fp](nil) - for i := 0; i < len(r.Limbs); i++ { - r.Limbs[i] = newVariable() + newElement := func() *emulated.Element[emulated.Secp256k1Fp] { + limbs := make([]frontend.Variable, emulated.Secp256k1Fp{}.NbLimbs()) + for i := 0; i < len(limbs); i++ { + limbs[i] = newVariable() } - return r + return secp256k1.NewElement(limbs) } - x13 := secp256k1.Mul(newElement(), newElement(), newElement()) - fx2 := secp256k1.Mul(5, newElement()) + x13 := secp256k1.Mul(newElement(), newElement()) + x13 = secp256k1.Mul(x13, newElement()) + five := emulated.NewConstant[emulated.Secp256k1Fp](5) + fx2 := secp256k1.Mul(&five, newElement()) nom := secp256k1.Sub(fx2, x13) - denom := secp256k1.Add(newElement(), newElement(), newElement(), newElement()) + denom := secp256k1.Add(newElement(), newElement()) + denom = secp256k1.Add(denom, newElement()) + denom = secp256k1.Add(denom, newElement()) free := secp256k1.Div(nom, denom) - res := secp256k1.Add(x13, fx2, free) + res := secp256k1.Add(x13, fx2) + res = secp256k1.Add(res, free) secp256k1.AssertIsEqual(res, newElement()) }) From 60835dca2a6eaf19fa4bcd00680cd04f0dcbdd44 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 26 Jan 2023 15:10:55 -0600 Subject: [PATCH 05/10] build: restore golangci-lint conf --- .golangci.yml | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index edd055d0f7..3a5f6fca1b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,24 +1,12 @@ linters: - # disable-all: true - enable-all: true - disable: - - varnamelen - - wrapcheck - - testpackage - - thelper - - paralleltest - - nonamedreturns - - nosnakecase - - nlreturn - - gomnd - - goerr113 - # enable: - # - gofmt - # - staticcheck - # - gosec - # - gosimple - # - govet - # - ineffassign + disable-all: true + enable: + - gofmt + - staticcheck + - gosec + - gosimple + - govet + - ineffassign run: issues-exit-code: 1 \ No newline at end of file From 2a7b3fb2b84742c49e2a2cccca1ce730ae10b29e Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 26 Jan 2023 15:28:28 -0600 Subject: [PATCH 06/10] refactor: emulated.NewConstant -> emulated.FromConstant --- examples/emulated/emulated_test.go | 6 +- internal/stats/snippet.go | 2 +- std/algebra/weierstrass/doc_test.go | 8 +- std/algebra/weierstrass/point.go | 6 +- std/algebra/weierstrass/point_test.go | 48 ++++----- std/math/emulated/doc_example_field_test.go | 6 +- std/math/emulated/element.go | 6 +- std/math/emulated/element_test.go | 104 ++++++++++---------- std/math/emulated/field.go | 2 +- std/math/emulated/field_test.go | 14 +-- std/signature/ecdsa/ecdsa_test.go | 20 ++-- 11 files changed, 111 insertions(+), 111 deletions(-) diff --git a/examples/emulated/emulated_test.go b/examples/emulated/emulated_test.go index 75f380ed57..226e1e10c2 100644 --- a/examples/emulated/emulated_test.go +++ b/examples/emulated/emulated_test.go @@ -16,9 +16,9 @@ func TestEmulatedArithmetic(t *testing.T) { var circuit, witness Circuit - witness.X = emulated.NewConstant[emulated.Secp256k1Fp]("26959946673427741531515197488526605382048662297355296634326893985793") - witness.Y = emulated.NewConstant[emulated.Secp256k1Fp]("53919893346855483063030394977053210764097324594710593268653787971586") - witness.Res = emulated.NewConstant[emulated.Secp256k1Fp]("485279052387156144224396168012515269674445015885648619762653195154800") + witness.X = emulated.FromConstant[emulated.Secp256k1Fp]("26959946673427741531515197488526605382048662297355296634326893985793") + witness.Y = emulated.FromConstant[emulated.Secp256k1Fp]("53919893346855483063030394977053210764097324594710593268653787971586") + witness.Res = emulated.FromConstant[emulated.Secp256k1Fp]("485279052387156144224396168012515269674445015885648619762653195154800") assert.ProverSucceeded(&circuit, &witness, test.WithCurves(ecc.BN254), test.WithBackends(backend.GROTH16), test.NoSerialization()) } diff --git a/internal/stats/snippet.go b/internal/stats/snippet.go index c3c8ebd44a..6415b5c9b4 100644 --- a/internal/stats/snippet.go +++ b/internal/stats/snippet.go @@ -92,7 +92,7 @@ func initSnippets() { x13 := secp256k1.Mul(newElement(), newElement()) x13 = secp256k1.Mul(x13, newElement()) - five := emulated.NewConstant[emulated.Secp256k1Fp](5) + five := emulated.FromConstant[emulated.Secp256k1Fp](5) fx2 := secp256k1.Mul(&five, newElement()) nom := secp256k1.Sub(fx2, x13) denom := secp256k1.Add(newElement(), newElement()) diff --git a/std/algebra/weierstrass/doc_test.go b/std/algebra/weierstrass/doc_test.go index 20de03a906..690c8d536b 100644 --- a/std/algebra/weierstrass/doc_test.go +++ b/std/algebra/weierstrass/doc_test.go @@ -23,9 +23,9 @@ func (c *ExampleCurveCircuit[B, S]) Define(api frontend.API) error { panic("initalize new curve") } G := curve.Generator() - scalar4 := emulated.NewConstant[S](4) + scalar4 := emulated.FromConstant[S](4) g4 := curve.ScalarMul(G, &scalar4) // 4*G - scalar5 := emulated.NewConstant[S](5) + scalar5 := emulated.FromConstant[S](5) g5 := curve.ScalarMul(G, &scalar5) // 5*G g9 := curve.Add(g4, g5) // 9*G curve.AssertIsEqual(g9, &c.Res) @@ -41,8 +41,8 @@ func ExampleCurve() { circuit := ExampleCurveCircuit[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := ExampleCurveCircuit[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ Res: weierstrass.AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gx), - Y: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gy), + X: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gx), + Y: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gy), }, } ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) diff --git a/std/algebra/weierstrass/point.go b/std/algebra/weierstrass/point.go index 22dab07b69..425cf185cb 100644 --- a/std/algebra/weierstrass/point.go +++ b/std/algebra/weierstrass/point.go @@ -21,8 +21,8 @@ func New[Base, Scalars emulated.FieldParams](api frontend.API, params CurveParam if err != nil { return nil, fmt.Errorf("new scalar api: %w", err) } - Gx := emulated.NewConstant[Base](params.Gx) - Gy := emulated.NewConstant[Base](params.Gy) + Gx := emulated.FromConstant[Base](params.Gx) + Gy := emulated.FromConstant[Base](params.Gy) return &Curve[Base, Scalars]{ params: params, api: api, @@ -32,7 +32,7 @@ func New[Base, Scalars emulated.FieldParams](api frontend.API, params CurveParam X: Gx, Y: Gy, }, - a: emulated.NewConstant[Base](params.A), + a: emulated.FromConstant[Base](params.A), addA: params.A.Cmp(big.NewInt(0)) != 0, }, nil } diff --git a/std/algebra/weierstrass/point_test.go b/std/algebra/weierstrass/point_test.go index e3cc777c9c..2b66d615c9 100644 --- a/std/algebra/weierstrass/point_test.go +++ b/std/algebra/weierstrass/point_test.go @@ -36,12 +36,12 @@ func TestNeg(t *testing.T) { circuit := NegTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := NegTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ P: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gx), - Y: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gy), + X: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gx), + Y: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gy), }, Q: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gx), - Y: emulated.NewConstant[emulated.Secp256k1Fp](yn), + X: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gx), + Y: emulated.FromConstant[emulated.Secp256k1Fp](yn), }, } err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) @@ -70,16 +70,16 @@ func TestAdd(t *testing.T) { circuit := AddTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := AddTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ P: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gx), - Y: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gy), + X: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gx), + Y: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gy), }, Q: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewConstant[emulated.Secp256k1Fp](xd), - Y: emulated.NewConstant[emulated.Secp256k1Fp](yd), + X: emulated.FromConstant[emulated.Secp256k1Fp](xd), + Y: emulated.FromConstant[emulated.Secp256k1Fp](yd), }, R: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewConstant[emulated.Secp256k1Fp](xa), - Y: emulated.NewConstant[emulated.Secp256k1Fp](ya), + X: emulated.FromConstant[emulated.Secp256k1Fp](xa), + Y: emulated.FromConstant[emulated.Secp256k1Fp](ya), }, } err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) @@ -107,12 +107,12 @@ func TestDouble(t *testing.T) { circuit := DoubleTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := DoubleTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ P: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gx), - Y: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gy), + X: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gx), + Y: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gy), }, Q: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewConstant[emulated.Secp256k1Fp](xd), - Y: emulated.NewConstant[emulated.Secp256k1Fp](yd), + X: emulated.FromConstant[emulated.Secp256k1Fp](xd), + Y: emulated.FromConstant[emulated.Secp256k1Fp](yd), }, } err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) @@ -143,14 +143,14 @@ func TestScalarMul(t *testing.T) { circuit := ScalarMulTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := ScalarMulTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ - S: emulated.NewConstant[emulated.Secp256k1Fr](s), + S: emulated.FromConstant[emulated.Secp256k1Fr](s), P: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gx), - Y: emulated.NewConstant[emulated.Secp256k1Fp](secpCurve.Gy), + X: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gx), + Y: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gy), }, Q: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.NewConstant[emulated.Secp256k1Fp](sx), - Y: emulated.NewConstant[emulated.Secp256k1Fp](sy), + X: emulated.FromConstant[emulated.Secp256k1Fp](sx), + Y: emulated.FromConstant[emulated.Secp256k1Fp](sy), }, } err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) @@ -169,14 +169,14 @@ func TestScalarMul2(t *testing.T) { circuit := ScalarMulTest[emulated.BN254Fp, emulated.BN254Fr]{} witness := ScalarMulTest[emulated.BN254Fp, emulated.BN254Fr]{ - S: emulated.NewConstant[emulated.BN254Fr](s), + S: emulated.FromConstant[emulated.BN254Fr](s), P: AffinePoint[emulated.BN254Fp]{ - X: emulated.NewConstant[emulated.BN254Fp](gen.X.BigInt(new(big.Int))), - Y: emulated.NewConstant[emulated.BN254Fp](gen.Y.BigInt(new(big.Int))), + X: emulated.FromConstant[emulated.BN254Fp](gen.X.BigInt(new(big.Int))), + Y: emulated.FromConstant[emulated.BN254Fp](gen.Y.BigInt(new(big.Int))), }, Q: AffinePoint[emulated.BN254Fp]{ - X: emulated.NewConstant[emulated.BN254Fp](res.X.BigInt(new(big.Int))), - Y: emulated.NewConstant[emulated.BN254Fp](res.Y.BigInt(new(big.Int))), + X: emulated.FromConstant[emulated.BN254Fp](res.X.BigInt(new(big.Int))), + Y: emulated.FromConstant[emulated.BN254Fp](res.Y.BigInt(new(big.Int))), }, } err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) diff --git a/std/math/emulated/doc_example_field_test.go b/std/math/emulated/doc_example_field_test.go index 19451a5090..8a7bf76b10 100644 --- a/std/math/emulated/doc_example_field_test.go +++ b/std/math/emulated/doc_example_field_test.go @@ -33,9 +33,9 @@ func (c *ExampleFieldCircuit[T]) Define(api frontend.API) error { func ExampleField() { circuit := ExampleFieldCircuit[emulated.BN254Fp]{} witness := ExampleFieldCircuit[emulated.BN254Fp]{ - In1: emulated.NewConstant[emulated.BN254Fp](3), - In2: emulated.NewConstant[emulated.BN254Fp](5), - Res: emulated.NewConstant[emulated.BN254Fp](15), + In1: emulated.FromConstant[emulated.BN254Fp](3), + In2: emulated.FromConstant[emulated.BN254Fp](5), + Res: emulated.FromConstant[emulated.BN254Fp](15), } ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) if err != nil { diff --git a/std/math/emulated/element.go b/std/math/emulated/element.go index a518c3f688..dc0c713e22 100644 --- a/std/math/emulated/element.go +++ b/std/math/emulated/element.go @@ -33,9 +33,9 @@ type Element[T FieldParams] struct { internal bool } -// NewConstant returns an Element[T] from a constant value. +// FromConstant returns an Element[T] from a constant value. // The input is converted to *big.Int and decomposed into limbs and packed into new Element[T]. -func NewConstant[T FieldParams](constant interface{}) Element[T] { +func FromConstant[T FieldParams](constant interface{}) Element[T] { if constant == nil { r := newConstElement[T](0) // r.internal = false @@ -91,7 +91,7 @@ func (f *Field[T]) newInternalElement(limbs []frontend.Variable, overflow uint) // GnarkInitHook describes how to initialise the element. func (e *Element[T]) GnarkInitHook() { if e.Limbs == nil { - *e = NewConstant[T](0) + *e = FromConstant[T](0) } } diff --git a/std/math/emulated/element_test.go b/std/math/emulated/element_test.go index 7d18d0ef0c..ce0cffa507 100644 --- a/std/math/emulated/element_test.go +++ b/std/math/emulated/element_test.go @@ -47,8 +47,8 @@ func testAssertLimbEqualityNoOverflow[T FieldParams](t *testing.T) { assert.Run(func(assert *test.Assert) { var circuit, witness AssertLimbEqualityCircuit[T] val, _ := rand.Int(rand.Reader, fp.Modulus()) - witness.A = NewConstant[T](val) - witness.B = NewConstant[T](val) + witness.A = FromConstant[T](val) + witness.B = FromConstant[T](val) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -81,8 +81,8 @@ func testAssertIsLessEqualThan[T FieldParams](t *testing.T) { var circuit, witness AssertIsLessEqualThanCircuit[T] R, _ := rand.Int(rand.Reader, fp.Modulus()) L, _ := rand.Int(rand.Reader, R) - witness.R = NewConstant[T](R) - witness.L = NewConstant[T](L) + witness.R = FromConstant[T](R) + witness.L = FromConstant[T](L) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -116,9 +116,9 @@ func testAddCircuitNoOverflow[T FieldParams](t *testing.T) { val1, _ := rand.Int(rand.Reader, bound) val2, _ := rand.Int(rand.Reader, bound) res := new(big.Int).Add(val1, val2) - witness.A = NewConstant[T](val1) - witness.B = NewConstant[T](val2) - witness.C = NewConstant[T](res) + witness.A = FromConstant[T](val1) + witness.B = FromConstant[T](val2) + witness.C = FromConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -153,9 +153,9 @@ func testMulCircuitNoOverflow[T FieldParams](t *testing.T) { val1, _ := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), uint(fp.Modulus().BitLen())/2)) val2, _ := rand.Int(rand.Reader, new(big.Int).Div(fp.Modulus(), val1)) res := new(big.Int).Mul(val1, val2) - witness.A = NewConstant[T](val1) - witness.B = NewConstant[T](val2) - witness.C = NewConstant[T](res) + witness.A = FromConstant[T](val1) + witness.B = FromConstant[T](val2) + witness.C = FromConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16)) }, testName[T]()) } @@ -191,9 +191,9 @@ func testMulCircuitOverflow[T FieldParams](t *testing.T) { val2, _ := rand.Int(rand.Reader, fp.Modulus()) res := new(big.Int).Mul(val1, val2) res.Mod(res, fp.Modulus()) - witness.A = NewConstant[T](val1) - witness.B = NewConstant[T](val2) - witness.C = NewConstant[T](res) + witness.A = FromConstant[T](val1) + witness.B = FromConstant[T](val2) + witness.C = FromConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -230,9 +230,9 @@ func testReduceAfterAdd[T FieldParams](t *testing.T) { val1, _ := rand.Int(rand.Reader, val2) val3 := new(big.Int).Add(val1, fp.Modulus()) val3.Sub(val3, val2) - witness.A = NewConstant[T](val3) - witness.B = NewConstant[T](val2) - witness.C = NewConstant[T](val1) + witness.A = FromConstant[T](val3) + witness.B = FromConstant[T](val2) + witness.C = FromConstant[T](val1) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -271,9 +271,9 @@ func testSubtractNoOverflow[T FieldParams](t *testing.T) { val1, _ := rand.Int(rand.Reader, fp.Modulus()) val2, _ := rand.Int(rand.Reader, val1) res := new(big.Int).Sub(val1, val2) - witness.A = NewConstant[T](val1) - witness.B = NewConstant[T](val2) - witness.C = NewConstant[T](res) + witness.A = FromConstant[T](val1) + witness.B = FromConstant[T](val2) + witness.C = FromConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -288,9 +288,9 @@ func testSubtractOverflow[T FieldParams](t *testing.T) { val2.Add(val2, val1) res := new(big.Int).Sub(val1, val2) res.Mod(res, fp.Modulus()) - witness.A = NewConstant[T](val1) - witness.B = NewConstant[T](val2) - witness.C = NewConstant[T](res) + witness.A = FromConstant[T](val1) + witness.B = FromConstant[T](val2) + witness.C = FromConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -323,8 +323,8 @@ func testNegation[T FieldParams](t *testing.T) { var circuit, witness NegationCircuit[T] val1, _ := rand.Int(rand.Reader, fp.Modulus()) res := new(big.Int).Sub(fp.Modulus(), val1) - witness.A = NewConstant[T](val1) - witness.B = NewConstant[T](res) + witness.A = FromConstant[T](val1) + witness.B = FromConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -360,8 +360,8 @@ func testInverse[T FieldParams](t *testing.T) { var circuit, witness InverseCircuit[T] val1, _ := rand.Int(rand.Reader, fp.Modulus()) res := new(big.Int).ModInverse(val1, fp.Modulus()) - witness.A = NewConstant[T](val1) - witness.B = NewConstant[T](res) + witness.A = FromConstant[T](val1) + witness.B = FromConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -402,9 +402,9 @@ func testDivision[T FieldParams](t *testing.T) { res.ModInverse(val2, fp.Modulus()) res.Mul(val1, res) res.Mod(res, fp.Modulus()) - witness.A = NewConstant[T](val1) - witness.B = NewConstant[T](val2) - witness.C = NewConstant[T](res) + witness.A = FromConstant[T](val1) + witness.B = FromConstant[T](val2) + witness.C = FromConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -447,7 +447,7 @@ func testToBinary[T FieldParams](t *testing.T) { for i := 0; i < len(bits); i++ { bits[i] = val1.Bit(i) } - witness.Value = NewConstant[T](val1) + witness.Value = FromConstant[T](val1) witness.Bits = bits assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) @@ -488,7 +488,7 @@ func testFromBinary[T FieldParams](t *testing.T) { bits[i] = val1.Bit(i) } - witness.Res = NewConstant[T](val1) + witness.Res = FromConstant[T](val1) witness.Bits = bits assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) @@ -521,8 +521,8 @@ func testConstantEqual[T FieldParams](t *testing.T) { assert.Run(func(assert *test.Assert) { var circuit, witness EqualityCheckCircuit[T] val, _ := rand.Int(rand.Reader, fp.Modulus()) - witness.A = NewConstant[T](val) - witness.B = NewConstant[T](val) + witness.A = FromConstant[T](val) + witness.B = FromConstant[T](val) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -565,10 +565,10 @@ func testSelect[T FieldParams](t *testing.T) { randbit, _ := rand.Int(rand.Reader, big.NewInt(2)) b := randbit.Uint64() - witness.A = NewConstant[T](val1) - witness.B = NewConstant[T](val2) - witness.C = NewConstant[T](val3) - witness.D = NewConstant[T]([]*big.Int{l, val3}[1-b]) + witness.A = FromConstant[T](val1) + witness.B = FromConstant[T](val2) + witness.C = FromConstant[T](val3) + witness.D = FromConstant[T]([]*big.Int{l, val3}[1-b]) witness.Selector = b assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) @@ -613,11 +613,11 @@ func testLookup2[T FieldParams](t *testing.T) { val4, _ := rand.Int(rand.Reader, fp.Modulus()) randbit, _ := rand.Int(rand.Reader, big.NewInt(4)) - witness.A = NewConstant[T](val1) - witness.B = NewConstant[T](val2) - witness.C = NewConstant[T](val3) - witness.D = NewConstant[T](val4) - witness.E = NewConstant[T]([]*big.Int{val1, val2, val3, val4}[randbit.Uint64()]) + witness.A = FromConstant[T](val1) + witness.B = FromConstant[T](val2) + witness.C = FromConstant[T](val3) + witness.D = FromConstant[T](val4) + witness.E = FromConstant[T]([]*big.Int{val1, val2, val3, val4}[randbit.Uint64()]) witness.Bit0 = randbit.Bit(0) witness.Bit1 = randbit.Bit(1) @@ -648,7 +648,7 @@ func (c *ComputationCircuit[T]) Define(api frontend.API) error { } // TODO @gbotrel better way to deal with constants? - five := NewConstant[T](5) + five := FromConstant[T](5) fx2 := f.Mul(&five, &c.X2) fx2 = f.Reduce(fx2) @@ -707,13 +707,13 @@ func testComputation[T FieldParams](t *testing.T) { res.Add(res, tmp) res.Mod(res, fp.Modulus()) - witness.X1 = NewConstant[T](val1) - witness.X2 = NewConstant[T](val2) - witness.X3 = NewConstant[T](val3) - witness.X4 = NewConstant[T](val4) - witness.X5 = NewConstant[T](val5) - witness.X6 = NewConstant[T](val6) - witness.Res = NewConstant[T](res) + witness.X1 = FromConstant[T](val1) + witness.X2 = FromConstant[T](val2) + witness.X3 = FromConstant[T](val3) + witness.X4 = FromConstant[T](val4) + witness.X5 = FromConstant[T](val5) + witness.X6 = FromConstant[T](val6) + witness.Res = FromConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) @@ -768,8 +768,8 @@ func testFourMuls[T FieldParams](t *testing.T) { res.Mul(res, val1) res.Mod(res, fp.Modulus()) - witness.A = NewConstant[T](val1) - witness.Res = NewConstant[T](res) + witness.A = FromConstant[T](val1) + witness.Res = FromConstant[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } diff --git a/std/math/emulated/field.go b/std/math/emulated/field.go index e829e269e2..fcdcf25445 100644 --- a/std/math/emulated/field.go +++ b/std/math/emulated/field.go @@ -108,7 +108,7 @@ func (f *Field[T]) NewElement(v interface{}) *Element[T] { } return f.packLimbs(e, true) } - c := NewConstant[T](v) + c := FromConstant[T](v) return &c } diff --git a/std/math/emulated/field_test.go b/std/math/emulated/field_test.go index 3d98b3e5ec..f66584ae78 100644 --- a/std/math/emulated/field_test.go +++ b/std/math/emulated/field_test.go @@ -64,7 +64,7 @@ func (c *ConstantCircuit) Define(api frontend.API) error { return err } { - c1 := NewConstant[Secp256k1Fp](42) + c1 := FromConstant[Secp256k1Fp](42) b1, ok := f.constantValue(&c1) if !ok { return errors.New("42 should be constant") @@ -107,9 +107,9 @@ func (c *MulConstantCircuit) Define(api frontend.API) error { if err != nil { return err } - c0 := NewConstant[Secp256k1Fp](0) - c1 := NewConstant[Secp256k1Fp](0) - c2 := NewConstant[Secp256k1Fp](0) + c0 := FromConstant[Secp256k1Fp](0) + c1 := FromConstant[Secp256k1Fp](0) + c2 := FromConstant[Secp256k1Fp](0) r := f.Mul(&c0, &c1) f.AssertIsEqual(r, &c2) @@ -136,9 +136,9 @@ func (c *SubConstantCircuit) Define(api frontend.API) error { if err != nil { return err } - c0 := NewConstant[Secp256k1Fp](0) - c1 := NewConstant[Secp256k1Fp](0) - c2 := NewConstant[Secp256k1Fp](0) + c0 := FromConstant[Secp256k1Fp](0) + c1 := FromConstant[Secp256k1Fp](0) + c2 := FromConstant[Secp256k1Fp](0) r := f.Sub(&c0, &c1) if r.overflow != 0 { return fmt.Errorf("overflow %d != 0", r.overflow) diff --git a/std/signature/ecdsa/ecdsa_test.go b/std/signature/ecdsa/ecdsa_test.go index 3599023e15..9d51f9ef52 100644 --- a/std/signature/ecdsa/ecdsa_test.go +++ b/std/signature/ecdsa/ecdsa_test.go @@ -65,13 +65,13 @@ func TestEcdsa(t *testing.T) { circuit := EcdsaCircuit[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := EcdsaCircuit[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ Sig: Signature[emulated.Secp256k1Fr]{ - R: emulated.NewConstant[emulated.Secp256k1Fr](r), - S: emulated.NewConstant[emulated.Secp256k1Fr](s), + R: emulated.FromConstant[emulated.Secp256k1Fr](r), + S: emulated.FromConstant[emulated.Secp256k1Fr](s), }, - Msg: emulated.NewConstant[emulated.Secp256k1Fr](m), + Msg: emulated.FromConstant[emulated.Secp256k1Fr](m), Pub: PublicKey[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ - X: emulated.NewConstant[emulated.Secp256k1Fp](_pub.X), - Y: emulated.NewConstant[emulated.Secp256k1Fp](_pub.Y), + X: emulated.FromConstant[emulated.Secp256k1Fp](_pub.X), + Y: emulated.FromConstant[emulated.Secp256k1Fp](_pub.Y), }, } assert := test.NewAssert(t) @@ -90,13 +90,13 @@ func ExamplePublicKey_Verify() { // can be done in or out-circuit. Sig := Signature[emulated.Secp256k1Fr]{ - R: emulated.NewConstant[emulated.Secp256k1Fr](r), - S: emulated.NewConstant[emulated.Secp256k1Fr](s), + R: emulated.FromConstant[emulated.Secp256k1Fr](r), + S: emulated.FromConstant[emulated.Secp256k1Fr](s), } - Msg := emulated.NewConstant[emulated.Secp256k1Fr](m) + Msg := emulated.FromConstant[emulated.Secp256k1Fr](m) Pub := PublicKey[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ - X: emulated.NewConstant[emulated.Secp256k1Fp](pubx), - Y: emulated.NewConstant[emulated.Secp256k1Fp](puby), + X: emulated.FromConstant[emulated.Secp256k1Fp](pubx), + Y: emulated.FromConstant[emulated.Secp256k1Fp](puby), } // signature verification assertion is done in-circuit Pub.Verify(api, weierstrass.GetCurveParams[emulated.Secp256k1Fp](), &Msg, &Sig) From b0d67be7f83874cc0bc49973710eea94513e9307 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 26 Jan 2023 15:32:40 -0600 Subject: [PATCH 07/10] refactor: emulated.FromConstant -> emulated.ValueOf --- examples/emulated/emulated_test.go | 6 +- internal/stats/snippet.go | 2 +- std/algebra/weierstrass/doc_test.go | 8 +- std/algebra/weierstrass/point.go | 6 +- std/algebra/weierstrass/point_test.go | 48 ++++----- std/math/emulated/doc_example_field_test.go | 6 +- std/math/emulated/element.go | 6 +- std/math/emulated/element_test.go | 104 ++++++++++---------- std/math/emulated/field.go | 2 +- std/math/emulated/field_test.go | 14 +-- std/signature/ecdsa/ecdsa_test.go | 20 ++-- 11 files changed, 111 insertions(+), 111 deletions(-) diff --git a/examples/emulated/emulated_test.go b/examples/emulated/emulated_test.go index 226e1e10c2..64fc4b358e 100644 --- a/examples/emulated/emulated_test.go +++ b/examples/emulated/emulated_test.go @@ -16,9 +16,9 @@ func TestEmulatedArithmetic(t *testing.T) { var circuit, witness Circuit - witness.X = emulated.FromConstant[emulated.Secp256k1Fp]("26959946673427741531515197488526605382048662297355296634326893985793") - witness.Y = emulated.FromConstant[emulated.Secp256k1Fp]("53919893346855483063030394977053210764097324594710593268653787971586") - witness.Res = emulated.FromConstant[emulated.Secp256k1Fp]("485279052387156144224396168012515269674445015885648619762653195154800") + witness.X = emulated.ValueOf[emulated.Secp256k1Fp]("26959946673427741531515197488526605382048662297355296634326893985793") + witness.Y = emulated.ValueOf[emulated.Secp256k1Fp]("53919893346855483063030394977053210764097324594710593268653787971586") + witness.Res = emulated.ValueOf[emulated.Secp256k1Fp]("485279052387156144224396168012515269674445015885648619762653195154800") assert.ProverSucceeded(&circuit, &witness, test.WithCurves(ecc.BN254), test.WithBackends(backend.GROTH16), test.NoSerialization()) } diff --git a/internal/stats/snippet.go b/internal/stats/snippet.go index 6415b5c9b4..1f6ed7764c 100644 --- a/internal/stats/snippet.go +++ b/internal/stats/snippet.go @@ -92,7 +92,7 @@ func initSnippets() { x13 := secp256k1.Mul(newElement(), newElement()) x13 = secp256k1.Mul(x13, newElement()) - five := emulated.FromConstant[emulated.Secp256k1Fp](5) + five := emulated.ValueOf[emulated.Secp256k1Fp](5) fx2 := secp256k1.Mul(&five, newElement()) nom := secp256k1.Sub(fx2, x13) denom := secp256k1.Add(newElement(), newElement()) diff --git a/std/algebra/weierstrass/doc_test.go b/std/algebra/weierstrass/doc_test.go index 690c8d536b..9313745fbd 100644 --- a/std/algebra/weierstrass/doc_test.go +++ b/std/algebra/weierstrass/doc_test.go @@ -23,9 +23,9 @@ func (c *ExampleCurveCircuit[B, S]) Define(api frontend.API) error { panic("initalize new curve") } G := curve.Generator() - scalar4 := emulated.FromConstant[S](4) + scalar4 := emulated.ValueOf[S](4) g4 := curve.ScalarMul(G, &scalar4) // 4*G - scalar5 := emulated.FromConstant[S](5) + scalar5 := emulated.ValueOf[S](5) g5 := curve.ScalarMul(G, &scalar5) // 5*G g9 := curve.Add(g4, g5) // 9*G curve.AssertIsEqual(g9, &c.Res) @@ -41,8 +41,8 @@ func ExampleCurve() { circuit := ExampleCurveCircuit[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := ExampleCurveCircuit[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ Res: weierstrass.AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gx), - Y: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gy), + X: emulated.ValueOf[emulated.Secp256k1Fp](secpCurve.Gx), + Y: emulated.ValueOf[emulated.Secp256k1Fp](secpCurve.Gy), }, } ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) diff --git a/std/algebra/weierstrass/point.go b/std/algebra/weierstrass/point.go index 425cf185cb..8c91ed2761 100644 --- a/std/algebra/weierstrass/point.go +++ b/std/algebra/weierstrass/point.go @@ -21,8 +21,8 @@ func New[Base, Scalars emulated.FieldParams](api frontend.API, params CurveParam if err != nil { return nil, fmt.Errorf("new scalar api: %w", err) } - Gx := emulated.FromConstant[Base](params.Gx) - Gy := emulated.FromConstant[Base](params.Gy) + Gx := emulated.ValueOf[Base](params.Gx) + Gy := emulated.ValueOf[Base](params.Gy) return &Curve[Base, Scalars]{ params: params, api: api, @@ -32,7 +32,7 @@ func New[Base, Scalars emulated.FieldParams](api frontend.API, params CurveParam X: Gx, Y: Gy, }, - a: emulated.FromConstant[Base](params.A), + a: emulated.ValueOf[Base](params.A), addA: params.A.Cmp(big.NewInt(0)) != 0, }, nil } diff --git a/std/algebra/weierstrass/point_test.go b/std/algebra/weierstrass/point_test.go index 2b66d615c9..931f4fd608 100644 --- a/std/algebra/weierstrass/point_test.go +++ b/std/algebra/weierstrass/point_test.go @@ -36,12 +36,12 @@ func TestNeg(t *testing.T) { circuit := NegTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := NegTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ P: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gx), - Y: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gy), + X: emulated.ValueOf[emulated.Secp256k1Fp](secpCurve.Gx), + Y: emulated.ValueOf[emulated.Secp256k1Fp](secpCurve.Gy), }, Q: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gx), - Y: emulated.FromConstant[emulated.Secp256k1Fp](yn), + X: emulated.ValueOf[emulated.Secp256k1Fp](secpCurve.Gx), + Y: emulated.ValueOf[emulated.Secp256k1Fp](yn), }, } err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) @@ -70,16 +70,16 @@ func TestAdd(t *testing.T) { circuit := AddTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := AddTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ P: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gx), - Y: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gy), + X: emulated.ValueOf[emulated.Secp256k1Fp](secpCurve.Gx), + Y: emulated.ValueOf[emulated.Secp256k1Fp](secpCurve.Gy), }, Q: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.FromConstant[emulated.Secp256k1Fp](xd), - Y: emulated.FromConstant[emulated.Secp256k1Fp](yd), + X: emulated.ValueOf[emulated.Secp256k1Fp](xd), + Y: emulated.ValueOf[emulated.Secp256k1Fp](yd), }, R: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.FromConstant[emulated.Secp256k1Fp](xa), - Y: emulated.FromConstant[emulated.Secp256k1Fp](ya), + X: emulated.ValueOf[emulated.Secp256k1Fp](xa), + Y: emulated.ValueOf[emulated.Secp256k1Fp](ya), }, } err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) @@ -107,12 +107,12 @@ func TestDouble(t *testing.T) { circuit := DoubleTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := DoubleTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ P: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gx), - Y: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gy), + X: emulated.ValueOf[emulated.Secp256k1Fp](secpCurve.Gx), + Y: emulated.ValueOf[emulated.Secp256k1Fp](secpCurve.Gy), }, Q: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.FromConstant[emulated.Secp256k1Fp](xd), - Y: emulated.FromConstant[emulated.Secp256k1Fp](yd), + X: emulated.ValueOf[emulated.Secp256k1Fp](xd), + Y: emulated.ValueOf[emulated.Secp256k1Fp](yd), }, } err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) @@ -143,14 +143,14 @@ func TestScalarMul(t *testing.T) { circuit := ScalarMulTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := ScalarMulTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ - S: emulated.FromConstant[emulated.Secp256k1Fr](s), + S: emulated.ValueOf[emulated.Secp256k1Fr](s), P: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gx), - Y: emulated.FromConstant[emulated.Secp256k1Fp](secpCurve.Gy), + X: emulated.ValueOf[emulated.Secp256k1Fp](secpCurve.Gx), + Y: emulated.ValueOf[emulated.Secp256k1Fp](secpCurve.Gy), }, Q: AffinePoint[emulated.Secp256k1Fp]{ - X: emulated.FromConstant[emulated.Secp256k1Fp](sx), - Y: emulated.FromConstant[emulated.Secp256k1Fp](sy), + X: emulated.ValueOf[emulated.Secp256k1Fp](sx), + Y: emulated.ValueOf[emulated.Secp256k1Fp](sy), }, } err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) @@ -169,14 +169,14 @@ func TestScalarMul2(t *testing.T) { circuit := ScalarMulTest[emulated.BN254Fp, emulated.BN254Fr]{} witness := ScalarMulTest[emulated.BN254Fp, emulated.BN254Fr]{ - S: emulated.FromConstant[emulated.BN254Fr](s), + S: emulated.ValueOf[emulated.BN254Fr](s), P: AffinePoint[emulated.BN254Fp]{ - X: emulated.FromConstant[emulated.BN254Fp](gen.X.BigInt(new(big.Int))), - Y: emulated.FromConstant[emulated.BN254Fp](gen.Y.BigInt(new(big.Int))), + X: emulated.ValueOf[emulated.BN254Fp](gen.X.BigInt(new(big.Int))), + Y: emulated.ValueOf[emulated.BN254Fp](gen.Y.BigInt(new(big.Int))), }, Q: AffinePoint[emulated.BN254Fp]{ - X: emulated.FromConstant[emulated.BN254Fp](res.X.BigInt(new(big.Int))), - Y: emulated.FromConstant[emulated.BN254Fp](res.Y.BigInt(new(big.Int))), + X: emulated.ValueOf[emulated.BN254Fp](res.X.BigInt(new(big.Int))), + Y: emulated.ValueOf[emulated.BN254Fp](res.Y.BigInt(new(big.Int))), }, } err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) diff --git a/std/math/emulated/doc_example_field_test.go b/std/math/emulated/doc_example_field_test.go index 8a7bf76b10..b6f3b8a18e 100644 --- a/std/math/emulated/doc_example_field_test.go +++ b/std/math/emulated/doc_example_field_test.go @@ -33,9 +33,9 @@ func (c *ExampleFieldCircuit[T]) Define(api frontend.API) error { func ExampleField() { circuit := ExampleFieldCircuit[emulated.BN254Fp]{} witness := ExampleFieldCircuit[emulated.BN254Fp]{ - In1: emulated.FromConstant[emulated.BN254Fp](3), - In2: emulated.FromConstant[emulated.BN254Fp](5), - Res: emulated.FromConstant[emulated.BN254Fp](15), + In1: emulated.ValueOf[emulated.BN254Fp](3), + In2: emulated.ValueOf[emulated.BN254Fp](5), + Res: emulated.ValueOf[emulated.BN254Fp](15), } ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) if err != nil { diff --git a/std/math/emulated/element.go b/std/math/emulated/element.go index dc0c713e22..0c5ac5c5a8 100644 --- a/std/math/emulated/element.go +++ b/std/math/emulated/element.go @@ -33,9 +33,9 @@ type Element[T FieldParams] struct { internal bool } -// FromConstant returns an Element[T] from a constant value. +// ValueOf returns an Element[T] from a constant value. // The input is converted to *big.Int and decomposed into limbs and packed into new Element[T]. -func FromConstant[T FieldParams](constant interface{}) Element[T] { +func ValueOf[T FieldParams](constant interface{}) Element[T] { if constant == nil { r := newConstElement[T](0) // r.internal = false @@ -91,7 +91,7 @@ func (f *Field[T]) newInternalElement(limbs []frontend.Variable, overflow uint) // GnarkInitHook describes how to initialise the element. func (e *Element[T]) GnarkInitHook() { if e.Limbs == nil { - *e = FromConstant[T](0) + *e = ValueOf[T](0) } } diff --git a/std/math/emulated/element_test.go b/std/math/emulated/element_test.go index ce0cffa507..7c6f71dba7 100644 --- a/std/math/emulated/element_test.go +++ b/std/math/emulated/element_test.go @@ -47,8 +47,8 @@ func testAssertLimbEqualityNoOverflow[T FieldParams](t *testing.T) { assert.Run(func(assert *test.Assert) { var circuit, witness AssertLimbEqualityCircuit[T] val, _ := rand.Int(rand.Reader, fp.Modulus()) - witness.A = FromConstant[T](val) - witness.B = FromConstant[T](val) + witness.A = ValueOf[T](val) + witness.B = ValueOf[T](val) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -81,8 +81,8 @@ func testAssertIsLessEqualThan[T FieldParams](t *testing.T) { var circuit, witness AssertIsLessEqualThanCircuit[T] R, _ := rand.Int(rand.Reader, fp.Modulus()) L, _ := rand.Int(rand.Reader, R) - witness.R = FromConstant[T](R) - witness.L = FromConstant[T](L) + witness.R = ValueOf[T](R) + witness.L = ValueOf[T](L) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -116,9 +116,9 @@ func testAddCircuitNoOverflow[T FieldParams](t *testing.T) { val1, _ := rand.Int(rand.Reader, bound) val2, _ := rand.Int(rand.Reader, bound) res := new(big.Int).Add(val1, val2) - witness.A = FromConstant[T](val1) - witness.B = FromConstant[T](val2) - witness.C = FromConstant[T](res) + witness.A = ValueOf[T](val1) + witness.B = ValueOf[T](val2) + witness.C = ValueOf[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -153,9 +153,9 @@ func testMulCircuitNoOverflow[T FieldParams](t *testing.T) { val1, _ := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), uint(fp.Modulus().BitLen())/2)) val2, _ := rand.Int(rand.Reader, new(big.Int).Div(fp.Modulus(), val1)) res := new(big.Int).Mul(val1, val2) - witness.A = FromConstant[T](val1) - witness.B = FromConstant[T](val2) - witness.C = FromConstant[T](res) + witness.A = ValueOf[T](val1) + witness.B = ValueOf[T](val2) + witness.C = ValueOf[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16)) }, testName[T]()) } @@ -191,9 +191,9 @@ func testMulCircuitOverflow[T FieldParams](t *testing.T) { val2, _ := rand.Int(rand.Reader, fp.Modulus()) res := new(big.Int).Mul(val1, val2) res.Mod(res, fp.Modulus()) - witness.A = FromConstant[T](val1) - witness.B = FromConstant[T](val2) - witness.C = FromConstant[T](res) + witness.A = ValueOf[T](val1) + witness.B = ValueOf[T](val2) + witness.C = ValueOf[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -230,9 +230,9 @@ func testReduceAfterAdd[T FieldParams](t *testing.T) { val1, _ := rand.Int(rand.Reader, val2) val3 := new(big.Int).Add(val1, fp.Modulus()) val3.Sub(val3, val2) - witness.A = FromConstant[T](val3) - witness.B = FromConstant[T](val2) - witness.C = FromConstant[T](val1) + witness.A = ValueOf[T](val3) + witness.B = ValueOf[T](val2) + witness.C = ValueOf[T](val1) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -271,9 +271,9 @@ func testSubtractNoOverflow[T FieldParams](t *testing.T) { val1, _ := rand.Int(rand.Reader, fp.Modulus()) val2, _ := rand.Int(rand.Reader, val1) res := new(big.Int).Sub(val1, val2) - witness.A = FromConstant[T](val1) - witness.B = FromConstant[T](val2) - witness.C = FromConstant[T](res) + witness.A = ValueOf[T](val1) + witness.B = ValueOf[T](val2) + witness.C = ValueOf[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -288,9 +288,9 @@ func testSubtractOverflow[T FieldParams](t *testing.T) { val2.Add(val2, val1) res := new(big.Int).Sub(val1, val2) res.Mod(res, fp.Modulus()) - witness.A = FromConstant[T](val1) - witness.B = FromConstant[T](val2) - witness.C = FromConstant[T](res) + witness.A = ValueOf[T](val1) + witness.B = ValueOf[T](val2) + witness.C = ValueOf[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -323,8 +323,8 @@ func testNegation[T FieldParams](t *testing.T) { var circuit, witness NegationCircuit[T] val1, _ := rand.Int(rand.Reader, fp.Modulus()) res := new(big.Int).Sub(fp.Modulus(), val1) - witness.A = FromConstant[T](val1) - witness.B = FromConstant[T](res) + witness.A = ValueOf[T](val1) + witness.B = ValueOf[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -360,8 +360,8 @@ func testInverse[T FieldParams](t *testing.T) { var circuit, witness InverseCircuit[T] val1, _ := rand.Int(rand.Reader, fp.Modulus()) res := new(big.Int).ModInverse(val1, fp.Modulus()) - witness.A = FromConstant[T](val1) - witness.B = FromConstant[T](res) + witness.A = ValueOf[T](val1) + witness.B = ValueOf[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -402,9 +402,9 @@ func testDivision[T FieldParams](t *testing.T) { res.ModInverse(val2, fp.Modulus()) res.Mul(val1, res) res.Mod(res, fp.Modulus()) - witness.A = FromConstant[T](val1) - witness.B = FromConstant[T](val2) - witness.C = FromConstant[T](res) + witness.A = ValueOf[T](val1) + witness.B = ValueOf[T](val2) + witness.C = ValueOf[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -447,7 +447,7 @@ func testToBinary[T FieldParams](t *testing.T) { for i := 0; i < len(bits); i++ { bits[i] = val1.Bit(i) } - witness.Value = FromConstant[T](val1) + witness.Value = ValueOf[T](val1) witness.Bits = bits assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) @@ -488,7 +488,7 @@ func testFromBinary[T FieldParams](t *testing.T) { bits[i] = val1.Bit(i) } - witness.Res = FromConstant[T](val1) + witness.Res = ValueOf[T](val1) witness.Bits = bits assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) @@ -521,8 +521,8 @@ func testConstantEqual[T FieldParams](t *testing.T) { assert.Run(func(assert *test.Assert) { var circuit, witness EqualityCheckCircuit[T] val, _ := rand.Int(rand.Reader, fp.Modulus()) - witness.A = FromConstant[T](val) - witness.B = FromConstant[T](val) + witness.A = ValueOf[T](val) + witness.B = ValueOf[T](val) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } @@ -565,10 +565,10 @@ func testSelect[T FieldParams](t *testing.T) { randbit, _ := rand.Int(rand.Reader, big.NewInt(2)) b := randbit.Uint64() - witness.A = FromConstant[T](val1) - witness.B = FromConstant[T](val2) - witness.C = FromConstant[T](val3) - witness.D = FromConstant[T]([]*big.Int{l, val3}[1-b]) + witness.A = ValueOf[T](val1) + witness.B = ValueOf[T](val2) + witness.C = ValueOf[T](val3) + witness.D = ValueOf[T]([]*big.Int{l, val3}[1-b]) witness.Selector = b assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) @@ -613,11 +613,11 @@ func testLookup2[T FieldParams](t *testing.T) { val4, _ := rand.Int(rand.Reader, fp.Modulus()) randbit, _ := rand.Int(rand.Reader, big.NewInt(4)) - witness.A = FromConstant[T](val1) - witness.B = FromConstant[T](val2) - witness.C = FromConstant[T](val3) - witness.D = FromConstant[T](val4) - witness.E = FromConstant[T]([]*big.Int{val1, val2, val3, val4}[randbit.Uint64()]) + witness.A = ValueOf[T](val1) + witness.B = ValueOf[T](val2) + witness.C = ValueOf[T](val3) + witness.D = ValueOf[T](val4) + witness.E = ValueOf[T]([]*big.Int{val1, val2, val3, val4}[randbit.Uint64()]) witness.Bit0 = randbit.Bit(0) witness.Bit1 = randbit.Bit(1) @@ -648,7 +648,7 @@ func (c *ComputationCircuit[T]) Define(api frontend.API) error { } // TODO @gbotrel better way to deal with constants? - five := FromConstant[T](5) + five := ValueOf[T](5) fx2 := f.Mul(&five, &c.X2) fx2 = f.Reduce(fx2) @@ -707,13 +707,13 @@ func testComputation[T FieldParams](t *testing.T) { res.Add(res, tmp) res.Mod(res, fp.Modulus()) - witness.X1 = FromConstant[T](val1) - witness.X2 = FromConstant[T](val2) - witness.X3 = FromConstant[T](val3) - witness.X4 = FromConstant[T](val4) - witness.X5 = FromConstant[T](val5) - witness.X6 = FromConstant[T](val6) - witness.Res = FromConstant[T](res) + witness.X1 = ValueOf[T](val1) + witness.X2 = ValueOf[T](val2) + witness.X3 = ValueOf[T](val3) + witness.X4 = ValueOf[T](val4) + witness.X5 = ValueOf[T](val5) + witness.X6 = ValueOf[T](val6) + witness.Res = ValueOf[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) @@ -768,8 +768,8 @@ func testFourMuls[T FieldParams](t *testing.T) { res.Mul(res, val1) res.Mod(res, fp.Modulus()) - witness.A = FromConstant[T](val1) - witness.Res = FromConstant[T](res) + witness.A = ValueOf[T](val1) + witness.Res = ValueOf[T](res) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } diff --git a/std/math/emulated/field.go b/std/math/emulated/field.go index fcdcf25445..166d736df1 100644 --- a/std/math/emulated/field.go +++ b/std/math/emulated/field.go @@ -108,7 +108,7 @@ func (f *Field[T]) NewElement(v interface{}) *Element[T] { } return f.packLimbs(e, true) } - c := FromConstant[T](v) + c := ValueOf[T](v) return &c } diff --git a/std/math/emulated/field_test.go b/std/math/emulated/field_test.go index f66584ae78..927b23bc59 100644 --- a/std/math/emulated/field_test.go +++ b/std/math/emulated/field_test.go @@ -64,7 +64,7 @@ func (c *ConstantCircuit) Define(api frontend.API) error { return err } { - c1 := FromConstant[Secp256k1Fp](42) + c1 := ValueOf[Secp256k1Fp](42) b1, ok := f.constantValue(&c1) if !ok { return errors.New("42 should be constant") @@ -107,9 +107,9 @@ func (c *MulConstantCircuit) Define(api frontend.API) error { if err != nil { return err } - c0 := FromConstant[Secp256k1Fp](0) - c1 := FromConstant[Secp256k1Fp](0) - c2 := FromConstant[Secp256k1Fp](0) + c0 := ValueOf[Secp256k1Fp](0) + c1 := ValueOf[Secp256k1Fp](0) + c2 := ValueOf[Secp256k1Fp](0) r := f.Mul(&c0, &c1) f.AssertIsEqual(r, &c2) @@ -136,9 +136,9 @@ func (c *SubConstantCircuit) Define(api frontend.API) error { if err != nil { return err } - c0 := FromConstant[Secp256k1Fp](0) - c1 := FromConstant[Secp256k1Fp](0) - c2 := FromConstant[Secp256k1Fp](0) + c0 := ValueOf[Secp256k1Fp](0) + c1 := ValueOf[Secp256k1Fp](0) + c2 := ValueOf[Secp256k1Fp](0) r := f.Sub(&c0, &c1) if r.overflow != 0 { return fmt.Errorf("overflow %d != 0", r.overflow) diff --git a/std/signature/ecdsa/ecdsa_test.go b/std/signature/ecdsa/ecdsa_test.go index 9d51f9ef52..ce42942097 100644 --- a/std/signature/ecdsa/ecdsa_test.go +++ b/std/signature/ecdsa/ecdsa_test.go @@ -65,13 +65,13 @@ func TestEcdsa(t *testing.T) { circuit := EcdsaCircuit[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := EcdsaCircuit[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ Sig: Signature[emulated.Secp256k1Fr]{ - R: emulated.FromConstant[emulated.Secp256k1Fr](r), - S: emulated.FromConstant[emulated.Secp256k1Fr](s), + R: emulated.ValueOf[emulated.Secp256k1Fr](r), + S: emulated.ValueOf[emulated.Secp256k1Fr](s), }, - Msg: emulated.FromConstant[emulated.Secp256k1Fr](m), + Msg: emulated.ValueOf[emulated.Secp256k1Fr](m), Pub: PublicKey[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ - X: emulated.FromConstant[emulated.Secp256k1Fp](_pub.X), - Y: emulated.FromConstant[emulated.Secp256k1Fp](_pub.Y), + X: emulated.ValueOf[emulated.Secp256k1Fp](_pub.X), + Y: emulated.ValueOf[emulated.Secp256k1Fp](_pub.Y), }, } assert := test.NewAssert(t) @@ -90,13 +90,13 @@ func ExamplePublicKey_Verify() { // can be done in or out-circuit. Sig := Signature[emulated.Secp256k1Fr]{ - R: emulated.FromConstant[emulated.Secp256k1Fr](r), - S: emulated.FromConstant[emulated.Secp256k1Fr](s), + R: emulated.ValueOf[emulated.Secp256k1Fr](r), + S: emulated.ValueOf[emulated.Secp256k1Fr](s), } - Msg := emulated.FromConstant[emulated.Secp256k1Fr](m) + Msg := emulated.ValueOf[emulated.Secp256k1Fr](m) Pub := PublicKey[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ - X: emulated.FromConstant[emulated.Secp256k1Fp](pubx), - Y: emulated.FromConstant[emulated.Secp256k1Fp](puby), + X: emulated.ValueOf[emulated.Secp256k1Fp](pubx), + Y: emulated.ValueOf[emulated.Secp256k1Fp](puby), } // signature verification assertion is done in-circuit Pub.Verify(api, weierstrass.GetCurveParams[emulated.Secp256k1Fp](), &Msg, &Sig) From 45ef6101f6ff7d4897ba6e1179be6133c8de8c59 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Fri, 27 Jan 2023 08:59:36 -0600 Subject: [PATCH 08/10] fix: ensure we alwways constrain witness limbs --- std/math/emulated/element.go | 3 +-- std/math/emulated/element_test.go | 6 ++---- std/math/emulated/field.go | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/std/math/emulated/element.go b/std/math/emulated/element.go index 0c5ac5c5a8..b75511b7a9 100644 --- a/std/math/emulated/element.go +++ b/std/math/emulated/element.go @@ -38,11 +38,9 @@ type Element[T FieldParams] struct { func ValueOf[T FieldParams](constant interface{}) Element[T] { if constant == nil { r := newConstElement[T](0) - // r.internal = false return *r } r := newConstElement[T](constant) - // r.internal = false return *r } @@ -92,6 +90,7 @@ func (f *Field[T]) newInternalElement(limbs []frontend.Variable, overflow uint) func (e *Element[T]) GnarkInitHook() { if e.Limbs == nil { *e = ValueOf[T](0) + e.internal = false // we need to constrain in later. } } diff --git a/std/math/emulated/element_test.go b/std/math/emulated/element_test.go index 7c6f71dba7..c291737d63 100644 --- a/std/math/emulated/element_test.go +++ b/std/math/emulated/element_test.go @@ -647,9 +647,7 @@ func (c *ComputationCircuit[T]) Define(api frontend.API) error { x13 = f.Reduce(x13) } - // TODO @gbotrel better way to deal with constants? - five := ValueOf[T](5) - fx2 := f.Mul(&five, &c.X2) + fx2 := f.Mul(f.NewElement(5), &c.X2) fx2 = f.Reduce(fx2) nom := f.Sub(&c.X3, &c.X4) @@ -726,7 +724,7 @@ func TestOptimisation(t *testing.T) { } ccs, err := frontend.Compile(testCurve.ScalarField(), r1cs.NewBuilder, &circuit) assert.NoError(err) - assert.LessOrEqual(ccs.GetNbConstraints(), 5577) + assert.LessOrEqual(ccs.GetNbConstraints(), 5945) ccs2, err := frontend.Compile(testCurve.ScalarField(), scs.NewBuilder, &circuit) assert.NoError(err) assert.LessOrEqual(ccs2.GetNbConstraints(), 12977) diff --git a/std/math/emulated/field.go b/std/math/emulated/field.go index 166d736df1..2dccc1c392 100644 --- a/std/math/emulated/field.go +++ b/std/math/emulated/field.go @@ -88,7 +88,7 @@ func NewField[T FieldParams](native frontend.API) (*Field[T], error) { // NewElement builds a new Element[T] from input v. // - if v is a Element[T] or *Element[T] it clones it -// - if v is a constant this is equivalent to calling emulated.NewConstant[T] +// - if v is a constant this is equivalent to calling emulated.ValueOf[T] // - if this methods interpret v (frontend.Variable or []frontend.Variable) as being the limbs; and constrain the limbs following the parameters of the Field. func (f *Field[T]) NewElement(v interface{}) *Element[T] { if e, ok := v.(Element[T]); ok { From 7a0a01b2b7d26cf01419488c725a1549be9a5943 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Fri, 27 Jan 2023 09:10:19 -0600 Subject: [PATCH 09/10] fix: fix optimisation test bound with constrained limbs --- std/math/emulated/element_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/math/emulated/element_test.go b/std/math/emulated/element_test.go index c291737d63..aa7d5f8cd7 100644 --- a/std/math/emulated/element_test.go +++ b/std/math/emulated/element_test.go @@ -727,7 +727,7 @@ func TestOptimisation(t *testing.T) { assert.LessOrEqual(ccs.GetNbConstraints(), 5945) ccs2, err := frontend.Compile(testCurve.ScalarField(), scs.NewBuilder, &circuit) assert.NoError(err) - assert.LessOrEqual(ccs2.GetNbConstraints(), 12977) + assert.LessOrEqual(ccs2.GetNbConstraints(), 14859) } type FourMulsCircuit[T FieldParams] struct { From 3df6a716970bda65e4b82a77245f256e212e40f0 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Fri, 27 Jan 2023 09:12:34 -0600 Subject: [PATCH 10/10] perf: constraint to modulus width the witness limbs --- std/math/emulated/field.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/math/emulated/field.go b/std/math/emulated/field.go index 2dccc1c392..e4c0c3d357 100644 --- a/std/math/emulated/field.go +++ b/std/math/emulated/field.go @@ -185,7 +185,7 @@ func (f *Field[T]) enforceWidthConditional(a *Element[T]) (didConstrain bool) { } } if didConstrain { - f.enforceWidth(a, false) + f.enforceWidth(a, true) } return }