diff --git a/go/acir/black_box_func/and.go b/go/acir/black_box_func/and.go index 7849a25..a3ba6b7 100644 --- a/go/acir/black_box_func/and.go +++ b/go/acir/black_box_func/and.go @@ -38,7 +38,7 @@ func (a *And[T, E]) UnmarshalReader(r io.Reader) error { func (a *And[T, E]) Equals(other BlackBoxFunction[E]) bool { value, ok := other.(*And[T, E]) - return ok && a.Lhs.Equals(&value.Lhs) && a.Rhs.Equals(&value.Rhs) && a.Output.Equals(&value.Output) + return ok && a.Lhs.Equals(&value.Lhs) && a.Rhs.Equals(&value.Rhs) && a.Output.Equals(&value.Output) && a.nBits == value.nBits } func (a *And[T, E]) Define(api frontend.Builder[E], witnesses map[shr.Witness]frontend.Variable) error { @@ -77,10 +77,10 @@ func (a *And[T, E]) FillWitnessTree(tree *btree.BTree, index uint32) bool { return false } - if a.Lhs.FunctionInputKind == 1 { + if a.Lhs.IsWitness() { tree.ReplaceOrInsert(*a.Lhs.Witness + shr.Witness(index)) } - if a.Rhs.FunctionInputKind == 1 { + if a.Rhs.IsWitness() { tree.ReplaceOrInsert(*a.Rhs.Witness + shr.Witness(index)) } tree.ReplaceOrInsert(a.Output + shr.Witness(index)) diff --git a/go/acir/black_box_func/and_test.go b/go/acir/black_box_func/and_test.go index bc493f5..7ffaa63 100644 --- a/go/acir/black_box_func/and_test.go +++ b/go/acir/black_box_func/and_test.go @@ -39,6 +39,7 @@ func TestAndUnmarshalReader(t *testing.T) { Witness: &expectedWitnessRhs, }, Output: shr.Witness(3456), + nBits: 5678, }, } diff --git a/go/acir/black_box_func/ecdsa_secp256k1.go b/go/acir/black_box_func/ecdsa_secp256k1.go index fd06103..78853d5 100644 --- a/go/acir/black_box_func/ecdsa_secp256k1.go +++ b/go/acir/black_box_func/ecdsa_secp256k1.go @@ -3,6 +3,7 @@ package blackboxfunc import ( "encoding/binary" "io" + "math/big" shr "sunspot/go/acir/shared" "github.com/consensys/gnark/constraint" @@ -23,7 +24,7 @@ type ECDSASECP256K1[T shr.ACIRField, E constraint.Element] struct { Output shr.Witness } -func (a *ECDSASECP256K1[T, Equals]) UnmarshalReader(r io.Reader) error { +func (a *ECDSASECP256K1[T, E]) UnmarshalReader(r io.Reader) error { for i := 0; i < 32; i++ { if err := a.PublicKeyX[i].UnmarshalReader(r); err != nil { return err @@ -59,7 +60,10 @@ func (a *ECDSASECP256K1[T, Equals]) UnmarshalReader(r io.Reader) error { } func (a *ECDSASECP256K1[T, E]) Equals(other BlackBoxFunction[E]) bool { - value := other.(*ECDSASECP256K1[T, E]) + value, ok := other.(*ECDSASECP256K1[T, E]) + if !ok { + return false + } if len(a.PublicKeyX) != len(value.PublicKeyX) || len(a.PublicKeyY) != len(value.PublicKeyY) || len(a.Signature) != len(value.Signature) || @@ -134,7 +138,18 @@ func (a *ECDSASECP256K1[T, E]) Define(api frontend.Builder[E], witnesses map[shr if err != nil { return err } - api.AssertIsEqual(frontend.Variable(0), api.Mul(pred, api.Sub(witnesses[a.Output], Q.IsValid(api, sw_emulated.GetSecp256k1Params(), msg, &sig)))) + + validSig := Q.IsValid(api, sw_emulated.GetSecp256k1Params(), msg, &sig) + + // Noir's verify_signature rejects signatures with s > n/2 (low-s form) to + // prevent malleability; gnark's IsValid does not, so enforce it here. + halfOrder := new(big.Int).Rsh(emulated.Secp256k1Fr{}.Modulus(), 1) + sBits := scalarField.ToBits(&sig.S) + isLowS := isLessOrEqualConstant(api, sBits, halfOrder) + + result := api.Mul(validSig, isLowS) + + api.AssertIsEqual(frontend.Variable(0), api.Mul(pred, api.Sub(witnesses[a.Output], result))) return nil } @@ -172,7 +187,6 @@ func (a *ECDSASECP256K1[T, E]) FillWitnessTree(tree *btree.BTree, index uint32) // ACIR has signature variables as big endian bytes // but gnark wants them as 4 * 64 but limbs. // See https://pkg.go.dev/github.com/consensys/gnark/std/math/emulated@v0.14.0#hdr-Element_representation - func BytesTo64BitLimbs[T shr.ACIRField]( api frontend.API, vars []FunctionInput[T], diff --git a/go/acir/black_box_func/ecdsa_secp256r1.go b/go/acir/black_box_func/ecdsa_secp256r1.go index bbcfba4..d3aa6dc 100644 --- a/go/acir/black_box_func/ecdsa_secp256r1.go +++ b/go/acir/black_box_func/ecdsa_secp256r1.go @@ -3,6 +3,7 @@ package blackboxfunc import ( "encoding/binary" "io" + "math/big" shr "sunspot/go/acir/shared" "github.com/google/btree" @@ -134,7 +135,16 @@ func (a *ECDSASECP256R1[T, E]) Define(api frontend.Builder[E], witnesses map[shr if err != nil { return err } - api.AssertIsEqual(frontend.Variable(0), api.Mul(pred, api.Sub(witnesses[a.Output], Q.IsValid(api, sw_emulated.GetP256Params(), msg, &sig)))) + + // Noir's verify_signature rejects signatures with s > n/2 (low-s form) to + // prevent malleability; gnark's IsValid does not, so enforce it here. + validSig := Q.IsValid(api, sw_emulated.GetP256Params(), msg, &sig) + halfOrder := new(big.Int).Rsh(emulated.P256Fr{}.Modulus(), 1) + sBits := scalarField.ToBits(&sig.S) + isLowS := isLessOrEqualConstant(api, sBits, halfOrder) + result := api.Mul(validSig, isLowS) + + api.AssertIsEqual(frontend.Variable(0), api.Mul(pred, api.Sub(witnesses[a.Output], result))) return nil } diff --git a/go/acir/black_box_func/embedded_curve_add.go b/go/acir/black_box_func/embedded_curve_add.go index 3c33a1b..a22ee39 100644 --- a/go/acir/black_box_func/embedded_curve_add.go +++ b/go/acir/black_box_func/embedded_curve_add.go @@ -5,8 +5,6 @@ import ( "io" shr "sunspot/go/acir/shared" - grumpkin "sunspot/go/sw-grumpkin" - "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" "github.com/google/btree" @@ -65,44 +63,27 @@ func (a *EmbeddedCurveAdd[T, E]) Equals(other BlackBoxFunction[E]) bool { } func (a *EmbeddedCurveAdd[T, E]) Define(api frontend.Builder[E], witnesses map[shr.Witness]frontend.Variable) error { - // Initialise points and pairs - point1X, err := a.Input1[0].ToVariable(witnesses) + pred, err := a.predicate.ToVariable(witnesses) if err != nil { return err } - point1Y, err := a.Input1[1].ToVariable(witnesses) - if err != nil { - return err - } - point2X, err := a.Input2[0].ToVariable(witnesses) + x, err := EmbeddedPointFromInputs(api, witnesses, pred, a.Input1) if err != nil { return err } - point2Y, err := a.Input2[1].ToVariable(witnesses) + y, err := EmbeddedPointFromInputs(api, witnesses, pred, a.Input2) if err != nil { return err } - x := grumpkin.G1Affine{ - X: point1X, - Y: point1Y, - } - - y := grumpkin.G1Affine{ - X: point2X, - Y: point2Y, - } + output := maskedEmbeddedPoint(api, pred, + witnesses[a.Outputs[0]], witnesses[a.Outputs[1]], witnesses[a.Outputs[2]]) - // Assert that the addition is correct - pred, err := a.predicate.ToVariable(witnesses) - if err != nil { - return err - } constrained_output := x.AddUnified(api, y) // Assert that the addition is correct, ignoring if the predicate is zero - api.AssertIsEqual(frontend.Variable(0), api.Mul(pred, api.Sub(constrained_output.X, witnesses[a.Outputs[0]]))) - api.AssertIsEqual(frontend.Variable(0), api.Mul(pred, api.Sub(constrained_output.Y, witnesses[a.Outputs[1]]))) + api.AssertIsEqual(frontend.Variable(0), api.Mul(pred, api.Sub(constrained_output.X, output.X))) + api.AssertIsEqual(frontend.Variable(0), api.Mul(pred, api.Sub(constrained_output.Y, output.Y))) return nil } diff --git a/go/acir/black_box_func/function_input_test.go b/go/acir/black_box_func/function_input_test.go index 0f9ad1b..0709f77 100644 --- a/go/acir/black_box_func/function_input_test.go +++ b/go/acir/black_box_func/function_input_test.go @@ -1,6 +1,7 @@ package blackboxfunc import ( + "math/big" "os" shr "sunspot/go/acir/shared" "sunspot/go/bn254" @@ -18,7 +19,7 @@ func TestFunctionInputUnmarshalReaderConstant(t *testing.T) { t.Fatalf("Failed to unmarshal FunctionInput: %v", err) } - expectedField := bn254.Zero() + expectedField := &bn254.BN254Field{Value: *big.NewInt(1234)} expected := FunctionInput[*bn254.BN254Field]{ FunctionInputKind: ACIRFunctionInputKindConstant, ConstantInput: &expectedField, diff --git a/go/acir/black_box_func/multi_scalar_mul.go b/go/acir/black_box_func/multi_scalar_mul.go index 21b9d0d..33d9a53 100644 --- a/go/acir/black_box_func/multi_scalar_mul.go +++ b/go/acir/black_box_func/multi_scalar_mul.go @@ -89,44 +89,33 @@ func (a *MultiScalarMul[T, E]) Define(api frontend.Builder[E], witnesses map[shr scalars := make([]interface{}, len(a.Scalars)/2) - for i := 0; i < len(a.Points); i += 3 { - pointX, err := a.Points[i].ToVariable(witnesses) - if err != nil { - return err - } + pred, err := a.predicate.ToVariable(witnesses) + if err != nil { + return err + } - pointY, err := a.Points[i+1].ToVariable(witnesses) + for i := 0; i < len(a.Points); i += 3 { + point, err := EmbeddedPointFromInputs(api, witnesses, pred, + [3]FunctionInput[T]{a.Points[i], a.Points[i+1], a.Points[i+2]}) if err != nil { return err } - - point := grumpkin.G1Affine{ - X: pointX, - Y: pointY, - } points[i/3] = &point } for i := 0; i < len(a.Scalars); i += 2 { - scalar, err := a.Scalars[i].ToVariable(witnesses) + scalar, err := ScalarFromLimbs(api, witnesses, a.Scalars[i], a.Scalars[i+1]) if err != nil { return err } scalars[i/2] = scalar } - output := grumpkin.G1Affine{ - X: witnesses[a.Outputs[0]], - Y: witnesses[a.Outputs[1]], - } + output := maskedEmbeddedPoint(api, pred, + witnesses[a.Outputs[0]], witnesses[a.Outputs[1]], witnesses[a.Outputs[2]]) constrained_output := grumpkin.MultiScalarMul(api, points, scalars) - pred, err := a.predicate.ToVariable(witnesses) - if err != nil { - return err - } - // To assert the two points are the same (and ignore if predicate is zero), we have to split into // its X and Y coordinates api.AssertIsEqual(frontend.Variable(0), api.Mul(pred, api.Sub(constrained_output.X, output.X))) diff --git a/go/acir/black_box_func/range.go b/go/acir/black_box_func/range.go index c631185..b19e1ab 100644 --- a/go/acir/black_box_func/range.go +++ b/go/acir/black_box_func/range.go @@ -29,26 +29,17 @@ func (a *Range[T, E]) UnmarshalReader(r io.Reader) error { func (a Range[T, E]) Equals(other BlackBoxFunction[E]) bool { value, ok := other.(*Range[T, E]) - return ok && a.Input.Equals(&value.Input) + return ok && a.Input.Equals(&value.Input) && a.nBits == value.nBits } func (a Range[T, E]) Define(api frontend.Builder[E], witnesses map[shr.Witness]frontend.Variable) error { - if a.Input.FunctionInputKind == ACIRFunctionInputKindConstant { - return nil - } - - witness := a.Input.Witness - if witness == nil { - return fmt.Errorf("witness is nil for Range function input") - } - - w, ok := witnesses[*witness] - if !ok { - return fmt.Errorf("witness %v not found in witnesses map", *witness) + input, err := a.Input.ToVariable(witnesses) + if err != nil { + return fmt.Errorf("failed to resolve Range function input: %w", err) } rangechecker := rangecheck.New(api) - rangechecker.Check(w, int(a.nBits)) + rangechecker.Check(input, int(a.nBits)) return nil } diff --git a/go/acir/black_box_func/shared_ecdsa.go b/go/acir/black_box_func/shared_ecdsa.go new file mode 100644 index 0000000..777a44c --- /dev/null +++ b/go/acir/black_box_func/shared_ecdsa.go @@ -0,0 +1,28 @@ +package blackboxfunc + +import ( + "math/big" + + "github.com/consensys/gnark/frontend" +) + +// isLessOrEqualConstant returns 1 if the unsigned integer encoded by the +// little-endian bits is ≤ c, otherwise 0. bitsLE must be boolean-constrained +// and c must fit in len(bitsLE) bits. +func isLessOrEqualConstant(api frontend.API, bitsLE []frontend.Variable, c *big.Int) frontend.Variable { + var isLess frontend.Variable = 0 + var isEqual frontend.Variable = 1 + for i := len(bitsLE) - 1; i >= 0; i-- { + sBit := bitsLE[i] + if c.Bit(i) == 1 { + // isEqual*(1-sBit) = isEqual - isEqual*sBit; reuse the product to + // keep this branch at a single multiplication constraint. + newIsEqual := api.Mul(isEqual, sBit) + isLess = api.Add(isLess, api.Sub(isEqual, newIsEqual)) + isEqual = newIsEqual + } else { + isEqual = api.Mul(isEqual, api.Sub(1, sBit)) + } + } + return api.Add(isLess, isEqual) +} diff --git a/go/acir/black_box_func/shared_embedded_curve.go b/go/acir/black_box_func/shared_embedded_curve.go new file mode 100644 index 0000000..4f1d017 --- /dev/null +++ b/go/acir/black_box_func/shared_embedded_curve.go @@ -0,0 +1,74 @@ +package blackboxfunc + +import ( + "math/big" + shr "sunspot/go/acir/shared" + grumpkin "sunspot/go/sw-grumpkin" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/frontend" +) + +var twoTo128 = new(big.Int).Lsh(big.NewInt(1), 128) + +// grumpkinScalarModulusHighLimb is floor(p / 2^128) where p is the grumpkin +// scalar modulus — the upper bound for a scalar's high 128-bit limb. +var grumpkinScalarModulusHighLimb = new(big.Int).Rsh(ecc.GRUMPKIN.ScalarField(), 128) + +// ScalarFromLimbs recomposes a scalar from its (lo, hi) 128-bit limb +// FunctionInputs into lo + hi * 2^128. +func ScalarFromLimbs[T shr.ACIRField, E constraint.Element]( + api frontend.Builder[E], + witnesses map[shr.Witness]frontend.Variable, + lo, hi FunctionInput[T], +) (frontend.Variable, error) { + scalarLo, err := lo.ToVariable(witnesses) + if err != nil { + return nil, err + } + scalarHi, err := hi.ToVariable(witnesses) + if err != nil { + return nil, err + } + api.AssertIsLessOrEqual(scalarHi, grumpkinScalarModulusHighLimb) + return api.Add(scalarLo, api.Mul(scalarHi, twoTo128)), nil +} + +// maskedEmbeddedPoint constrains isInf to a boolean (gated by pred) and returns +// a grumpkin point whose coordinates are masked to (0, 0) when isInf is set. +func maskedEmbeddedPoint[E constraint.Element]( + api frontend.Builder[E], + pred, x, y, isInf frontend.Variable, +) grumpkin.G1Affine { + api.AssertIsEqual(frontend.Variable(0), api.Mul(pred, isInf, api.Sub(frontend.Variable(1), isInf))) + notInf := api.Sub(frontend.Variable(1), isInf) + return grumpkin.G1Affine{ + X: api.Mul(notInf, x), + Y: api.Mul(notInf, y), + } +} + +// EmbeddedPointFromInputs resolves an (x, y, is_infinite) triple of +// FunctionInputs into a grumpkin point whose coordinates are masked to (0, 0) +// when is_infinite is set. +func EmbeddedPointFromInputs[T shr.ACIRField, E constraint.Element]( + api frontend.Builder[E], + witnesses map[shr.Witness]frontend.Variable, + pred frontend.Variable, + in [3]FunctionInput[T], +) (grumpkin.G1Affine, error) { + x, err := in[0].ToVariable(witnesses) + if err != nil { + return grumpkin.G1Affine{}, err + } + y, err := in[1].ToVariable(witnesses) + if err != nil { + return grumpkin.G1Affine{}, err + } + isInf, err := in[2].ToVariable(witnesses) + if err != nil { + return grumpkin.G1Affine{}, err + } + return maskedEmbeddedPoint(api, pred, x, y, isInf), nil +} diff --git a/go/acir/black_box_func/xor.go b/go/acir/black_box_func/xor.go index 5697107..70aadbb 100644 --- a/go/acir/black_box_func/xor.go +++ b/go/acir/black_box_func/xor.go @@ -39,7 +39,7 @@ func (a *Xor[T, E]) UnmarshalReader(r io.Reader) error { func (a *Xor[T, E]) Equals(other BlackBoxFunction[E]) bool { value, ok := other.(*Xor[T, E]) - if !ok || !a.Lhs.Equals(&value.Lhs) || !a.Rhs.Equals(&value.Rhs) { + if !ok || !a.Lhs.Equals(&value.Lhs) || !a.Rhs.Equals(&value.Rhs) || a.nBits != value.nBits { return false } return a.Output == value.Output diff --git a/go/acir/brillig/opcodes/const_test.go b/go/acir/brillig/opcodes/const_test.go index e2c18b0..b8aa237 100644 --- a/go/acir/brillig/opcodes/const_test.go +++ b/go/acir/brillig/opcodes/const_test.go @@ -1,6 +1,7 @@ package opcodes import ( + "math/big" "os" mem "sunspot/go/acir/brillig/memory" "sunspot/go/bn254" @@ -30,7 +31,7 @@ func TestConstUnmarshalReader(t *testing.T) { Kind: mem.BitSizeKindInteger, IntegerBitSize: &expectedIntegerBitSize, }, - Value: bn254.Zero(), + Value: &bn254.BN254Field{Value: *new(big.Int).SetUint64(5678)}, }, } diff --git a/go/acir/brillig/opcodes/indirect_const_test.go b/go/acir/brillig/opcodes/indirect_const_test.go index 7532a6f..c921724 100644 --- a/go/acir/brillig/opcodes/indirect_const_test.go +++ b/go/acir/brillig/opcodes/indirect_const_test.go @@ -1,6 +1,7 @@ package opcodes import ( + "math/big" "os" mem "sunspot/go/acir/brillig/memory" "sunspot/go/bn254" @@ -30,7 +31,7 @@ func TestIndirectConstUnmarshalReader(t *testing.T) { Kind: mem.BitSizeKindInteger, IntegerBitSize: &expectedIntegerBitSize, }, - Value: bn254.Zero(), + Value: &bn254.BN254Field{Value: *new(big.Int).SetUint64(5678)}, }, } diff --git a/go/acir/call/call_test.go b/go/acir/call/call_test.go index 83c4fc3..6bb55ff 100644 --- a/go/acir/call/call_test.go +++ b/go/acir/call/call_test.go @@ -125,7 +125,7 @@ func TestCallUnmarshalReaderWithPredicate(t *testing.T) { Predicate: &exp.Expression[T, E]{ MulTerms: []exp.MulTerm[T]{}, LinearCombinations: []exp.LinearCombination[T]{}, - Constant: bn254.Zero(), + Constant: bn254.One(), }, // Assuming a valid predicate expression } @@ -161,7 +161,7 @@ func TestCallUnmarshalReaderWithInputsAndOutputs(t *testing.T) { Predicate: &exp.Expression[T, E]{ MulTerms: []exp.MulTerm[T]{}, LinearCombinations: []exp.LinearCombination[T]{}, - Constant: bn254.Zero(), + Constant: bn254.One(), }, // Assuming a valid predicate expression } diff --git a/go/acir/expression/expression_test.go b/go/acir/expression/expression_test.go index 7621488..9e4ce9f 100644 --- a/go/acir/expression/expression_test.go +++ b/go/acir/expression/expression_test.go @@ -60,8 +60,8 @@ func TestExpressionUnmarshalReaderWithLinearCombinations(t *testing.T) { MulTerms: []MulTerm[T]{}, LinearCombinations: []LinearCombination[T]{ {Term: bn254.One(), Witness: 0}, - {Term: bn254.One(), Witness: 1234}, - {Term: bn254.One(), Witness: 5678}, + {Term: &bn254.BN254Field{Value: *big.NewInt(2)}, Witness: 1234}, + {Term: &bn254.BN254Field{Value: *big.NewInt(3)}, Witness: 5678}, }, Constant: bn254.Zero(), } @@ -89,8 +89,8 @@ func TestExpressionUnmarshalReaderWithMulTerms(t *testing.T) { expectedExpression := Expression[T, E]{ MulTerms: []MulTerm[T]{ {Term: bn254.One(), WitnessLeft: 0, WitnessRight: 1}, - {Term: bn254.One(), WitnessLeft: 1234, WitnessRight: 5678}, - {Term: bn254.One(), WitnessLeft: 5678, WitnessRight: 1234}, + {Term: &bn254.BN254Field{Value: *big.NewInt(2)}, WitnessLeft: 1234, WitnessRight: 5678}, + {Term: &bn254.BN254Field{Value: *big.NewInt(3)}, WitnessLeft: 5678, WitnessRight: 1234}, }, LinearCombinations: []LinearCombination[T]{}, Constant: bn254.Zero(), @@ -119,13 +119,13 @@ func TestExpressionUnmarshalReaderMulTermsWithLinearCombinations(t *testing.T) { expectedExpression := Expression[T, E]{ MulTerms: []MulTerm[T]{ {Term: bn254.One(), WitnessLeft: 0, WitnessRight: 1}, - {Term: bn254.One(), WitnessLeft: 1234, WitnessRight: 5678}, - {Term: bn254.One(), WitnessLeft: 5678, WitnessRight: 1234}, + {Term: &bn254.BN254Field{Value: *big.NewInt(2)}, WitnessLeft: 1234, WitnessRight: 5678}, + {Term: &bn254.BN254Field{Value: *big.NewInt(3)}, WitnessLeft: 5678, WitnessRight: 1234}, }, LinearCombinations: []LinearCombination[T]{ {Term: bn254.One(), Witness: 0}, - {Term: bn254.One(), Witness: 1234}, - {Term: bn254.One(), Witness: 5678}, + {Term: &bn254.BN254Field{Value: *big.NewInt(2)}, Witness: 1234}, + {Term: &bn254.BN254Field{Value: *big.NewInt(3)}, Witness: 5678}, }, Constant: bn254.Zero(), } diff --git a/go/acir/memory_op/memory_op_test.go b/go/acir/memory_op/memory_op_test.go index acae832..e937f2d 100644 --- a/go/acir/memory_op/memory_op_test.go +++ b/go/acir/memory_op/memory_op_test.go @@ -1,6 +1,7 @@ package memory_op import ( + "math/big" "os" exp "sunspot/go/acir/expression" shr "sunspot/go/acir/shared" @@ -34,17 +35,17 @@ func TestMemoryOpWithoutPredicate(t *testing.T) { Operation: exp.Expression[T, E]{ MulTerms: []exp.MulTerm[*bn254.BN254Field]{}, LinearCombinations: []exp.LinearCombination[*bn254.BN254Field]{}, - Constant: bn254.Zero(), + Constant: &bn254.BN254Field{Value: *new(big.Int).SetUint64(1)}, }, Index: exp.Expression[T, E]{ MulTerms: []exp.MulTerm[T]{}, LinearCombinations: []exp.LinearCombination[T]{}, - Constant: bn254.Zero(), + Constant: &bn254.BN254Field{Value: *new(big.Int).SetUint64(2)}, }, Value: exp.Expression[T, E]{ MulTerms: []exp.MulTerm[T]{}, LinearCombinations: []exp.LinearCombination[T]{}, - Constant: bn254.Zero(), + Constant: &bn254.BN254Field{Value: *new(big.Int).SetUint64(3)}, }, } @@ -78,17 +79,17 @@ func TestMemoryOpWithPredicate(t *testing.T) { Operation: exp.Expression[T, E]{ MulTerms: []exp.MulTerm[T]{}, LinearCombinations: []exp.LinearCombination[T]{}, - Constant: bn254.Zero(), + Constant: &bn254.BN254Field{Value: *new(big.Int).SetUint64(4)}, }, Index: exp.Expression[T, E]{ MulTerms: []exp.MulTerm[T]{}, LinearCombinations: []exp.LinearCombination[T]{}, - Constant: bn254.Zero(), + Constant: &bn254.BN254Field{Value: *new(big.Int).SetUint64(5)}, }, Value: exp.Expression[T, E]{ MulTerms: []exp.MulTerm[T]{}, LinearCombinations: []exp.LinearCombination[T]{}, - Constant: bn254.Zero(), + Constant: &bn254.BN254Field{Value: *new(big.Int).SetUint64(6)}, }, } diff --git a/go/bn254/bn254.go b/go/bn254/bn254.go index d8b08b0..221fea0 100644 --- a/go/bn254/bn254.go +++ b/go/bn254/bn254.go @@ -14,18 +14,18 @@ import ( ) type BN254Field struct { - value big.Int + Value big.Int } func Zero() *BN254Field { return &BN254Field{ - value: *new(big.Int).SetUint64(0), + Value: *new(big.Int).SetUint64(0), } } func One() *BN254Field { return &BN254Field{ - value: *new(big.Int).SetInt64(1), + Value: *new(big.Int).SetInt64(1), } } @@ -41,17 +41,21 @@ func (b *BN254Field) UnmarshalReader(r io.Reader) error { if _, err := io.ReadFull(r, bn254Bytes); err != nil { return fmt.Errorf("failed to read BN254 field bytes: %w", err) } - b.value.SetBytes(bn254Bytes) + b.Value.SetBytes(bn254Bytes) return nil } func (b BN254Field) Equals(other shr.ACIRField) bool { - return true // Implement the equality check logic here + o, ok := other.(*BN254Field) + if !ok { + return false + } + return b.Value.Cmp(&o.Value) == 0 } func (b BN254Field) ToElement() shr.GenericFPElement { var element fp.Element - element.SetBigInt(&b.value) + element.SetBigInt(&b.Value) return shr.GenericFPElement{ Kind: shr.GenericFPElementKindBN254, BN254FpElement: &element, @@ -60,14 +64,14 @@ func (b BN254Field) ToElement() shr.GenericFPElement { func (b BN254Field) ToFrontendVariable() frontend.Variable { var element fr.Element - element.SetBigInt(&b.value) + element.SetBigInt(&b.Value) return element } func (b BN254Field) String() string { - return b.value.String() + return b.Value.String() } func (b BN254Field) ToBigInt() *big.Int { - return new(big.Int).Set(&b.value) + return new(big.Int).Set(&b.Value) } diff --git a/noir-samples/black_box_functions/multiscalar_multiplication/Prover.toml b/noir-samples/black_box_functions/multiscalar_multiplication/Prover.toml index 14b49a1..dcad09f 100644 --- a/noir-samples/black_box_functions/multiscalar_multiplication/Prover.toml +++ b/noir-samples/black_box_functions/multiscalar_multiplication/Prover.toml @@ -1,44 +1,25 @@ -# Sage for generating witness -# -# p = 21888242871839275222246405745257275088548364400416034343698204186575808495617 -# Fp = GF(p) -# a = Fp(0) -# b = Fp(-17) -# Grumpkin = EllipticCurve(Fp, [a, b]) -# X = Grumpkin.random_point() -# Y = Grumpkin.random_point() -# Z = Grumpkin.random_point -# output = 3*x + 5*Y + 7*z - - [output] is_infinite = false -x = "8004440150022240020986334492041793313521542940963138040580207692251810156687" -y= "4869145120798538285781368327208366237469494086788667684933913386340433835925" +x = "0x169b0cc066d51f61371af8476004cc5301d935ccad997d7b2228b396793aee5b" +y= "0x0742cc7bda90efb8453c43b06f8ec7785d3b65c8e5c0930471327dd50c84d123" [[points]] is_infinite = false x = "13457461695866919433821564521619285514105166235431728247720640848441866812394" y = "12239832528093754184015030410952400611363246321141890794076152105619117698331" - [[points]] is_infinite = false x = "5341319855299567283962548376642876605561149191024064097651019541503013001492" y = "8947150551278687521985373522524055960658382661941169433773659017309756569695" - - [[points]] is_infinite = false x = "2119026014721165951606552814421286269668112493167093450523003693549443806567" y = "12520261813199548858744432192769383837819987256498135451689313779647572966656" - [[scalars]] -hi = 0 -lo = 3 - +hi = 3 +lo = 2 [[scalars]] -hi = 0 -lo = 5 - +hi = 2 +lo = 6 [[scalars]] hi = 0 -lo = 7 +lo = 5 \ No newline at end of file