diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/fixed_base_scalar_mul.cpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/fixed_base_scalar_mul.cpp index d54f8a33c98..68895c7c6e2 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/fixed_base_scalar_mul.cpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/fixed_base_scalar_mul.cpp @@ -1,17 +1,42 @@ #include "fixed_base_scalar_mul.hpp" +#include "barretenberg/dsl/types.hpp" +#include "barretenberg/ecc/curves/bn254/fr.hpp" +#include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" +#include "barretenberg/proof_system/arithmetization/gate_data.hpp" namespace acir_format { void create_fixed_base_constraint(Builder& builder, const FixedBaseScalarMul& input) { + // Computes low * G + high * 2^128 * G + // + // Low and high need to be less than 2^128 field_ct low_as_field = field_ct::from_witness_index(&builder, input.low); field_ct high_as_field = field_ct::from_witness_index(&builder, input.high); - (void)high_as_field; - auto public_key = group_ct::fixed_base_scalar_mul_g1<254>(low_as_field); - builder.assert_equal(public_key.x.witness_index, input.pub_key_x); - builder.assert_equal(public_key.y.witness_index, input.pub_key_y); + low_as_field.create_range_constraint(128); + high_as_field.create_range_constraint(128); + + auto low_value = grumpkin::fr(low_as_field.get_value()); + auto high_value = grumpkin::fr(high_as_field.get_value()); + auto pow_128 = grumpkin::fr(2).pow(128); + + grumpkin::g1::element result = grumpkin::g1::one * low_value + grumpkin::g1::one * (high_value * pow_128); + grumpkin::g1::affine_element result_affine = result.normalize(); + + auto x_var = builder.add_variable(result_affine.x); + auto y_var = builder.add_variable(result_affine.y); + builder.create_add_gate({ x_var, + y_var, + x_var, + barretenberg::fr::zero(), + barretenberg::fr::zero(), + barretenberg::fr::zero(), + barretenberg::fr::zero() }); + + builder.assert_equal(x_var, input.pub_key_x); + builder.assert_equal(y_var, input.pub_key_y); } } // namespace acir_format diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/fixed_base_scalar_mul.test.cpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/fixed_base_scalar_mul.test.cpp new file mode 100644 index 00000000000..3bda4b65bef --- /dev/null +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/fixed_base_scalar_mul.test.cpp @@ -0,0 +1,134 @@ +#include "acir_format.hpp" +#include "barretenberg/crypto/ecdsa/ecdsa.hpp" +#include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" +#include "barretenberg/plonk/proof_system/types/proof.hpp" +#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" +#include "fixed_base_scalar_mul.hpp" + +#include +#include +#include + +namespace acir_format::tests { +using group_ct = proof_system::plonk::stdlib::group; + +size_t generate_scalar_mul_constraints(FixedBaseScalarMul& scalar_mul_constraint, + WitnessVector& witness_values, + uint256_t low_value, + uint256_t high_value, + grumpkin::g1::affine_element expected) +{ + uint32_t offset = 1; + + uint32_t low_index = offset; + witness_values.emplace_back(low_value); + offset += 1; + + uint32_t high_index = offset; + witness_values.emplace_back(high_value); + offset += 1; + + uint32_t pub_key_x_index = offset; + witness_values.emplace_back(expected.x); + offset += 1; + + uint32_t pub_key_y_index = offset; + witness_values.emplace_back(expected.y); + offset += 1; + + scalar_mul_constraint = FixedBaseScalarMul{ + .low = low_index, + .high = high_index, + .pub_key_x = pub_key_x_index, + .pub_key_y = pub_key_y_index, + }; + + return offset; +} + +size_t generate_fixed_base_scalar_mul_fixtures(FixedBaseScalarMul& scalar_mul_constraint, + WitnessVector& witness_values, + grumpkin::fr low, + grumpkin::fr high) +{ + + auto two_pow_128 = grumpkin::fr(2).pow(128); + grumpkin::g1::element expected_projective = (grumpkin::g1::one * low) + grumpkin::g1::one * (high * two_pow_128); + grumpkin::g1::affine_element expected = expected_projective.normalize(); + return generate_scalar_mul_constraints(scalar_mul_constraint, witness_values, low, high, expected); +} + +TEST(FixedBaseScalarMul, TestSimpleScalarMul) +{ + FixedBaseScalarMul scalar_mul_constraint; + WitnessVector witness_values; + auto low = grumpkin::fr(1); + auto high = grumpkin::fr(2); + size_t num_variables = generate_fixed_base_scalar_mul_fixtures(scalar_mul_constraint, witness_values, low, high); + acir_format constraint_system{ + .varnum = static_cast(num_variables), + .public_inputs = {}, + .logic_constraints = {}, + .range_constraints = {}, + .sha256_constraints = {}, + .schnorr_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, + .blake2s_constraints = {}, + .keccak_constraints = {}, + .keccak_var_constraints = {}, + .pedersen_constraints = {}, + .hash_to_field_constraints = {}, + .fixed_base_scalar_mul_constraints = { scalar_mul_constraint }, + .recursion_constraints = {}, + .constraints = {}, + .block_constraints = {}, + }; + + auto builder = create_circuit_with_witness(constraint_system, witness_values); + + auto composer = Composer(); + auto prover = composer.create_prover(builder); + + auto proof = prover.construct_proof(); + auto verifier = composer.create_verifier(builder); + EXPECT_EQ(verifier.verify_proof(proof), true); +} +TEST(FixedBaseScalarMul, TestLimbLargerThan2Pow128) +{ + FixedBaseScalarMul scalar_mul_constraint; + WitnessVector witness_values; + grumpkin::fr low = grumpkin::fr(2).pow(129); + grumpkin::fr high = 1; + size_t num_variables = generate_fixed_base_scalar_mul_fixtures(scalar_mul_constraint, witness_values, low, high); + acir_format constraint_system{ + .varnum = static_cast(num_variables), + .public_inputs = {}, + .logic_constraints = {}, + .range_constraints = {}, + .sha256_constraints = {}, + .schnorr_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, + .blake2s_constraints = {}, + .keccak_constraints = {}, + .keccak_var_constraints = {}, + .pedersen_constraints = {}, + .hash_to_field_constraints = {}, + .fixed_base_scalar_mul_constraints = { scalar_mul_constraint }, + .recursion_constraints = {}, + .constraints = {}, + .block_constraints = {}, + }; + + auto builder = create_circuit_with_witness(constraint_system, witness_values); + + auto composer = Composer(); + auto prover = composer.create_prover(builder); + + auto proof = prover.construct_proof(); + auto verifier = composer.create_verifier(builder); + EXPECT_EQ(verifier.verify_proof(proof), false); +} + +} // namespace acir_format::tests