Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: add is_infinite to curve addition opcode #6384

Merged
merged 47 commits into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
e19e07c
Add is_infinite to curve addition opcode
guipublic May 14, 2024
7cabf86
Merge branch 'master' into gd/noir_issue_4978
guipublic May 14, 2024
f3192b2
fix build
guipublic May 14, 2024
92600e0
nargo fmt
guipublic May 14, 2024
242d91b
cargo format
guipublic May 14, 2024
11a0ebf
Merge branch 'master' into gd/noir_issue_4978
guipublic May 14, 2024
33625c5
update serialisation
guipublic May 14, 2024
f6300ad
Merge branch 'master' into gd/noir_issue_4978
guipublic May 14, 2024
e72cd1d
fix build
guipublic May 14, 2024
4121187
fix build (2)
guipublic May 14, 2024
0ea6ff2
Merge branch 'master' into gd/noir_issue_4978
guipublic May 14, 2024
59b58cc
use proper constructor for bool_t
guipublic May 14, 2024
7fdad1d
Merge branch 'master' into gd/noir_issue_4978
guipublic May 14, 2024
91ff542
revert to .yarn master
guipublic May 14, 2024
02ef713
Merge branch 'master' into gd/noir_issue_4978
guipublic May 14, 2024
c038a5e
Merge branch 'master' into gd/noir_issue_4978
guipublic May 14, 2024
7756155
Merge branch 'master' into gd/noir_issue_4978
guipublic May 15, 2024
6d9be9b
Merge branch 'master' into gd/noir_issue_4978
guipublic May 15, 2024
19aa50d
Merge branch 'master' into gd/noir_issue_4978
guipublic May 15, 2024
8b1bb52
code review
guipublic May 15, 2024
4a6e305
support point at infinity for scalar mul opcode
guipublic May 16, 2024
52d6d8a
Merge branch 'master' into gd/noir_issue_4978
guipublic May 16, 2024
ae8b846
format
guipublic May 16, 2024
ce78853
Merge branch 'master' into gd/noir_issue_4978
guipublic May 16, 2024
fd8e015
nargo fmt
guipublic May 16, 2024
9d9b203
update noir project
guipublic May 16, 2024
a83d446
fix aztec-nr update
guipublic May 16, 2024
492aad5
Merge branch 'master' into gd/noir_issue_4978
guipublic May 16, 2024
0984b87
nargo fmt
guipublic May 16, 2024
48f88c9
nargo fmt
guipublic May 16, 2024
65fafa3
update serialisation test
guipublic May 16, 2024
f608ad8
update serialisation tests
guipublic May 16, 2024
b521e0f
Merge branch 'master' into gd/noir_issue_4978
guipublic May 16, 2024
b669b00
fix unit test
guipublic May 16, 2024
7131fb9
try to fix serialisation test
guipublic May 16, 2024
6f3bef8
Merge branch 'master' into gd/noir_issue_4978
guipublic May 16, 2024
bb9c575
fix msm and adds a unit test
guipublic May 17, 2024
22ee9da
Merge branch 'master' into gd/noir_issue_4978
guipublic May 17, 2024
9de9e50
add unit tests
guipublic May 17, 2024
eb67a8b
add Eq trait to embeddedCurvePoint
guipublic May 17, 2024
24be6dc
Add struct for scalars
guipublic May 17, 2024
501c9bd
Merge branch 'master' into gd/noir_issue_4978
guipublic May 17, 2024
db6b940
update serialisation
guipublic May 17, 2024
538411e
update aztec.nr
guipublic May 17, 2024
6ad818d
nargo fmt
guipublic May 17, 2024
01a53c6
Move test out-of std_lib
guipublic May 17, 2024
e72255a
Merge branch 'master' into gd/noir_issue_4978
guipublic May 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -342,15 +342,19 @@ void handle_blackbox_func_call(Program::Opcode::BlackBoxFuncCall const& arg, Aci
.scalars = map(arg.scalars, [](auto& e) { return e.witness.value; }),
.out_point_x = arg.outputs[0].value,
.out_point_y = arg.outputs[1].value,
.out_point_is_infinite = arg.outputs[2].value,
});
} else if constexpr (std::is_same_v<T, Program::BlackBoxFuncCall::EmbeddedCurveAdd>) {
af.ec_add_constraints.push_back(EcAdd{
.input1_x = arg.input1_x.witness.value,
.input1_y = arg.input1_y.witness.value,
.input2_x = arg.input2_x.witness.value,
.input2_y = arg.input2_y.witness.value,
.input1_x = arg.input1[0].witness.value,
.input1_y = arg.input1[1].witness.value,
.input1_infinite = arg.input1[2].witness.value,
.input2_x = arg.input2[0].witness.value,
.input2_y = arg.input2[1].witness.value,
.input2_infinite = arg.input2[2].witness.value,
.result_x = arg.outputs[0].value,
.result_y = arg.outputs[1].value,
.result_infinite = arg.outputs[2].value,
});
} else if constexpr (std::is_same_v<T, Program::BlackBoxFuncCall::Keccak256>) {
af.keccak_constraints.push_back(KeccakConstraint{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,35 @@ void create_ec_add_constraint(Builder& builder, const EcAdd& input, bool has_val
// Input to cycle_group points
using cycle_group_ct = bb::stdlib::cycle_group<Builder>;
using field_ct = bb::stdlib::field_t<Builder>;
using bool_ct = bb::stdlib::bool_t<Builder>;

auto x1 = field_ct::from_witness_index(&builder, input.input1_x);
auto y1 = field_ct::from_witness_index(&builder, input.input1_y);
auto x2 = field_ct::from_witness_index(&builder, input.input2_x);
auto y2 = field_ct::from_witness_index(&builder, input.input2_y);
auto infinite1 = bool_ct(field_ct::from_witness_index(&builder, input.input1_infinite));
auto infinite2 = bool_ct(field_ct::from_witness_index(&builder, input.input2_infinite));
if (!has_valid_witness_assignments) {
auto g1 = grumpkin::g1::affine_one;
// We need to have correct values representing points on the curve
builder.variables[input.input1_x] = g1.x;
builder.variables[input.input1_y] = g1.y;
builder.variables[input.input1_infinite] = fr(0);
builder.variables[input.input2_x] = g1.x;
builder.variables[input.input2_y] = g1.y;
builder.variables[input.input2_infinite] = fr(0);
}

cycle_group_ct input1_point(x1, y1, false);
cycle_group_ct input2_point(x2, y2, false);

cycle_group_ct input1_point(x1, y1, infinite1);
cycle_group_ct input2_point(x2, y2, infinite2);
// Addition
cycle_group_ct result = input1_point + input2_point;

auto x_normalized = result.x.normalize();
auto y_normalized = result.y.normalize();
auto infinite = result.is_point_at_infinity().normalize();
builder.assert_equal(x_normalized.witness_index, input.result_x);
builder.assert_equal(y_normalized.witness_index, input.result_y);
builder.assert_equal(infinite.witness_index, input.result_infinite);
}

template void create_ec_add_constraint<UltraCircuitBuilder>(UltraCircuitBuilder& builder,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ namespace acir_format {
struct EcAdd {
uint32_t input1_x;
uint32_t input1_y;
uint32_t input1_infinite;
uint32_t input2_x;
uint32_t input2_y;
uint32_t input2_infinite;
uint32_t result_x;
uint32_t result_y;
uint32_t result_infinite;

// for serialization, update with any new fields
MSGPACK_FIELDS(input1_x, input1_y, input2_x, input2_y, result_x, result_y);
MSGPACK_FIELDS(
input1_x, input1_y, input1_infinite, input2_x, input2_y, input2_infinite, result_x, result_y, result_infinite);
friend bool operator==(EcAdd const& lhs, EcAdd const& rhs) = default;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,18 @@ size_t generate_ec_add_constraint(EcAdd& ec_add_constraint, WitnessVector& witne
witness_values.push_back(g1.y);
witness_values.push_back(result.x.get_value());
witness_values.push_back(result.y.get_value());
witness_values.push_back(fr(0));
witness_values.push_back(fr(0));
ec_add_constraint = EcAdd{
.input1_x = 1,
.input1_y = 2,
.input1_infinite = 7,
.input2_x = 3,
.input2_y = 4,
.input2_infinite = 7,
.result_x = 5,
.result_y = 6,
.result_infinite = 8,
};
return witness_values.size();
}
Expand Down Expand Up @@ -85,6 +90,92 @@ TEST_F(EcOperations, TestECOperations)
auto prover = composer.create_prover(builder);

auto proof = prover.construct_proof();

EXPECT_TRUE(CircuitChecker::check(builder));
auto verifier = composer.create_verifier(builder);
EXPECT_EQ(verifier.verify_proof(proof), true);
}

TEST_F(EcOperations, TestECMultiScalarMul)
{
MultiScalarMul msm_constrain;

WitnessVector witness_values;
witness_values.emplace_back(fr(0));

witness_values = {
// dummy
fr(0),
// g1: x,y,infinite
fr(1),
fr("0x0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c"),
fr(0),
// low, high scalars
fr(1),
fr(0),
// result
fr("0x06ce1b0827aafa85ddeb49cdaa36306d19a74caa311e13d46d8bc688cdbffffe"),
fr("0x1c122f81a3a14964909ede0ba2a6855fc93faf6fa1a788bf467be7e7a43f80ac"),
fr(0),
};
msm_constrain = MultiScalarMul{
.points = { 1, 2, 3, 1, 2, 3 },
.scalars = { 4, 5, 4, 5 },
.out_point_x = 6,
.out_point_y = 7,
.out_point_is_infinite = 0,
};
auto res_x = fr("0x06ce1b0827aafa85ddeb49cdaa36306d19a74caa311e13d46d8bc688cdbffffe");
auto assert_equal = poly_triple{
.a = 6,
.b = 0,
.c = 0,
.q_m = 0,
.q_l = fr::neg_one(),
.q_r = 0,
.q_o = 0,
.q_c = res_x,
};

size_t num_variables = witness_values.size();
AcirFormat constraint_system{
.varnum = static_cast<uint32_t>(num_variables + 1),
.recursive = false,
.num_acir_opcodes = 1,
.public_inputs = {},
.logic_constraints = {},
.range_constraints = {},
.aes128_constraints = {},
.sha256_constraints = {},
.sha256_compression = {},
.schnorr_constraints = {},
.ecdsa_k1_constraints = {},
.ecdsa_r1_constraints = {},
.blake2s_constraints = {},
.blake3_constraints = {},
.keccak_constraints = {},
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.multi_scalar_mul_constraints = { msm_constrain },
.ec_add_constraints = {},
.recursion_constraints = {},
.bigint_from_le_bytes_constraints = {},
.bigint_to_le_bytes_constraints = {},
.bigint_operations = {},
.poly_triple_constraints = { assert_equal },
.quad_constraints = {},
.block_constraints = {},
};

auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness_values);

auto composer = Composer();
auto prover = composer.create_prover(builder);

auto proof = prover.construct_proof();

EXPECT_TRUE(CircuitChecker::check(builder));
auto verifier = composer.create_verifier(builder);
EXPECT_EQ(verifier.verify_proof(proof), true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,20 @@ template <typename Builder> void create_multi_scalar_mul_constraint(Builder& bui
using cycle_group_ct = bb::stdlib::cycle_group<Builder>;
using cycle_scalar_ct = typename bb::stdlib::cycle_group<Builder>::cycle_scalar;
using field_ct = bb::stdlib::field_t<Builder>;
using bool_ct = bb::stdlib::bool_t<Builder>;

std::vector<cycle_group_ct> points;
std::vector<cycle_scalar_ct> scalars;

for (size_t i = 0; i < input.points.size(); i += 2) {
for (size_t i = 0; i < input.points.size(); i += 3) {
// Instantiate the input point/variable base as `cycle_group_ct`
auto point_x = field_ct::from_witness_index(&builder, input.points[i]);
auto point_y = field_ct::from_witness_index(&builder, input.points[i + 1]);
cycle_group_ct input_point(point_x, point_y, false);

auto infinite = bool_ct(field_ct::from_witness_index(&builder, input.points[i + 2]));
cycle_group_ct input_point(point_x, point_y, infinite);
// Reconstruct the scalar from the low and high limbs
field_ct scalar_low_as_field = field_ct::from_witness_index(&builder, input.scalars[i]);
field_ct scalar_high_as_field = field_ct::from_witness_index(&builder, input.scalars[i + 1]);
field_ct scalar_low_as_field = field_ct::from_witness_index(&builder, input.scalars[2 * (i / 3)]);
field_ct scalar_high_as_field = field_ct::from_witness_index(&builder, input.scalars[2 * (i / 3) + 1]);
cycle_scalar_ct scalar(scalar_low_as_field, scalar_high_as_field);

// Add the point and scalar to the vectors
Expand All @@ -38,6 +39,7 @@ template <typename Builder> void create_multi_scalar_mul_constraint(Builder& bui
// Add the constraints
builder.assert_equal(output_point.x.get_witness_index(), input.out_point_x);
builder.assert_equal(output_point.y.get_witness_index(), input.out_point_y);
builder.assert_equal(output_point.is_point_at_infinity().witness_index, input.out_point_is_infinite);
}

template void create_multi_scalar_mul_constraint<UltraCircuitBuilder>(UltraCircuitBuilder& builder,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ struct MultiScalarMul {
std::vector<uint32_t> scalars;
uint32_t out_point_x;
uint32_t out_point_y;
uint32_t out_point_is_infinite;

// for serialization, update with any new fields
MSGPACK_FIELDS(points, scalars, out_point_x, out_point_y);
MSGPACK_FIELDS(points, scalars, out_point_x, out_point_y, out_point_is_infinite);
friend bool operator==(MultiScalarMul const& lhs, MultiScalarMul const& rhs) = default;
};

Expand Down
44 changes: 22 additions & 22 deletions barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,19 +149,17 @@ struct BlackBoxFuncCall {
struct MultiScalarMul {
std::vector<Program::FunctionInput> points;
std::vector<Program::FunctionInput> scalars;
std::array<Program::Witness, 2> outputs;
std::array<Program::Witness, 3> outputs;

friend bool operator==(const MultiScalarMul&, const MultiScalarMul&);
std::vector<uint8_t> bincodeSerialize() const;
static MultiScalarMul bincodeDeserialize(std::vector<uint8_t>);
};

struct EmbeddedCurveAdd {
Program::FunctionInput input1_x;
Program::FunctionInput input1_y;
Program::FunctionInput input2_x;
Program::FunctionInput input2_y;
std::array<Program::Witness, 2> outputs;
std::array<Program::FunctionInput, 3> input1;
std::array<Program::FunctionInput, 3> input2;
std::array<Program::Witness, 3> outputs;

friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&);
std::vector<uint8_t> bincodeSerialize() const;
Expand Down Expand Up @@ -807,8 +805,10 @@ struct BlackBoxOp {
struct EmbeddedCurveAdd {
Program::MemoryAddress input1_x;
Program::MemoryAddress input1_y;
Program::MemoryAddress input1_infinite;
Program::MemoryAddress input2_x;
Program::MemoryAddress input2_y;
Program::MemoryAddress input2_infinite;
Program::HeapArray result;

friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&);
Expand Down Expand Up @@ -3194,16 +3194,10 @@ namespace Program {

inline bool operator==(const BlackBoxFuncCall::EmbeddedCurveAdd& lhs, const BlackBoxFuncCall::EmbeddedCurveAdd& rhs)
{
if (!(lhs.input1_x == rhs.input1_x)) {
if (!(lhs.input1 == rhs.input1)) {
return false;
}
if (!(lhs.input1_y == rhs.input1_y)) {
return false;
}
if (!(lhs.input2_x == rhs.input2_x)) {
return false;
}
if (!(lhs.input2_y == rhs.input2_y)) {
if (!(lhs.input2 == rhs.input2)) {
return false;
}
if (!(lhs.outputs == rhs.outputs)) {
Expand Down Expand Up @@ -3237,10 +3231,8 @@ template <typename Serializer>
void serde::Serializable<Program::BlackBoxFuncCall::EmbeddedCurveAdd>::serialize(
const Program::BlackBoxFuncCall::EmbeddedCurveAdd& obj, Serializer& serializer)
{
serde::Serializable<decltype(obj.input1_x)>::serialize(obj.input1_x, serializer);
serde::Serializable<decltype(obj.input1_y)>::serialize(obj.input1_y, serializer);
serde::Serializable<decltype(obj.input2_x)>::serialize(obj.input2_x, serializer);
serde::Serializable<decltype(obj.input2_y)>::serialize(obj.input2_y, serializer);
serde::Serializable<decltype(obj.input1)>::serialize(obj.input1, serializer);
serde::Serializable<decltype(obj.input2)>::serialize(obj.input2, serializer);
serde::Serializable<decltype(obj.outputs)>::serialize(obj.outputs, serializer);
}

Expand All @@ -3250,10 +3242,8 @@ Program::BlackBoxFuncCall::EmbeddedCurveAdd serde::Deserializable<
Program::BlackBoxFuncCall::EmbeddedCurveAdd>::deserialize(Deserializer& deserializer)
{
Program::BlackBoxFuncCall::EmbeddedCurveAdd obj;
obj.input1_x = serde::Deserializable<decltype(obj.input1_x)>::deserialize(deserializer);
obj.input1_y = serde::Deserializable<decltype(obj.input1_y)>::deserialize(deserializer);
obj.input2_x = serde::Deserializable<decltype(obj.input2_x)>::deserialize(deserializer);
obj.input2_y = serde::Deserializable<decltype(obj.input2_y)>::deserialize(deserializer);
obj.input1 = serde::Deserializable<decltype(obj.input1)>::deserialize(deserializer);
obj.input2 = serde::Deserializable<decltype(obj.input2)>::deserialize(deserializer);
obj.outputs = serde::Deserializable<decltype(obj.outputs)>::deserialize(deserializer);
return obj;
}
Expand Down Expand Up @@ -4638,12 +4628,18 @@ inline bool operator==(const BlackBoxOp::EmbeddedCurveAdd& lhs, const BlackBoxOp
if (!(lhs.input1_y == rhs.input1_y)) {
return false;
}
if (!(lhs.input1_infinite == rhs.input1_infinite)) {
return false;
}
if (!(lhs.input2_x == rhs.input2_x)) {
return false;
}
if (!(lhs.input2_y == rhs.input2_y)) {
return false;
}
if (!(lhs.input2_infinite == rhs.input2_infinite)) {
return false;
}
if (!(lhs.result == rhs.result)) {
return false;
}
Expand Down Expand Up @@ -4676,8 +4672,10 @@ void serde::Serializable<Program::BlackBoxOp::EmbeddedCurveAdd>::serialize(
{
serde::Serializable<decltype(obj.input1_x)>::serialize(obj.input1_x, serializer);
serde::Serializable<decltype(obj.input1_y)>::serialize(obj.input1_y, serializer);
serde::Serializable<decltype(obj.input1_infinite)>::serialize(obj.input1_infinite, serializer);
serde::Serializable<decltype(obj.input2_x)>::serialize(obj.input2_x, serializer);
serde::Serializable<decltype(obj.input2_y)>::serialize(obj.input2_y, serializer);
serde::Serializable<decltype(obj.input2_infinite)>::serialize(obj.input2_infinite, serializer);
serde::Serializable<decltype(obj.result)>::serialize(obj.result, serializer);
}

Expand All @@ -4689,8 +4687,10 @@ Program::BlackBoxOp::EmbeddedCurveAdd serde::Deserializable<Program::BlackBoxOp:
Program::BlackBoxOp::EmbeddedCurveAdd obj;
obj.input1_x = serde::Deserializable<decltype(obj.input1_x)>::deserialize(deserializer);
obj.input1_y = serde::Deserializable<decltype(obj.input1_y)>::deserialize(deserializer);
obj.input1_infinite = serde::Deserializable<decltype(obj.input1_infinite)>::deserialize(deserializer);
obj.input2_x = serde::Deserializable<decltype(obj.input2_x)>::deserialize(deserializer);
obj.input2_y = serde::Deserializable<decltype(obj.input2_y)>::deserialize(deserializer);
obj.input2_infinite = serde::Deserializable<decltype(obj.input2_infinite)>::deserialize(deserializer);
obj.result = serde::Deserializable<decltype(obj.result)>::deserialize(deserializer);
return obj;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ use dep::protocol_types::{
constants::GENERATOR_INDEX__SYMMETRIC_KEY, grumpkin_private_key::GrumpkinPrivateKey,
grumpkin_point::GrumpkinPoint, utils::arr_copy_slice
};
use dep::std::{hash::sha256, embedded_curve_ops::multi_scalar_mul};
use dep::std::{hash::sha256, embedded_curve_ops::{EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul}};

// TODO(#5726): This function is called deriveAESSecret in TS. I don't like point_to_symmetric_key name much since
// point is not the only input of the function. Unify naming with TS once we have a better name.
pub fn point_to_symmetric_key(secret: GrumpkinPrivateKey, point: GrumpkinPoint) -> [u8; 32] {
let shared_secret_fields = multi_scalar_mul([point.x, point.y], [secret.low, secret.high]);
let shared_secret_fields = multi_scalar_mul(
[EmbeddedCurvePoint { x: point.x, y: point.y, is_infinite: false }],
[EmbeddedCurveScalar { lo: secret.low, hi: secret.high }]
);
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/6061): make the func return Point struct directly
let shared_secret = GrumpkinPoint::new(shared_secret_fields[0], shared_secret_fields[1]);
let mut shared_secret_bytes_with_separator = [0 as u8; 65];
Expand Down
Loading
Loading