Skip to content

Commit

Permalink
chore: improve ec addition (#8291)
Browse files Browse the repository at this point in the history
Reduces the gate count for addition in cycle group

I get 37 gates instead of 41.
I improved the equality checks by one gate by removing the boolean gate.
I rewrote a division as one gate instead of 3 thanks to the quotient
being not null.
  • Loading branch information
guipublic authored Sep 3, 2024
1 parent e64b34e commit e8a097c
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,7 @@ TEST_F(join_split_tests, test_0_input_notes_and_detect_circuit_change)
// The below part detects any changes in the join-split circuit
constexpr size_t DYADIC_CIRCUIT_SIZE = 1 << 16;

constexpr uint256_t CIRCUIT_HASH("0x9170317e02f4131b84f6b4efdd3ac23e5f392d815df37750c8f05a94c64797b2");
constexpr uint256_t CIRCUIT_HASH("0x2b30566e4d921ea9b0c76802d86ea5b8381ffa78ef143af1b0d0e3045862cb6b");

const uint256_t circuit_hash = circuit.hash_circuit();
// circuit is finalized now
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -694,18 +694,18 @@ template <typename Builder> bool_t<Builder> field_t<Builder>::operator==(const f
bb::fr fd = fa - fb;
bool is_equal = (fa == fb);
bb::fr fc = is_equal ? bb::fr::one() : fd.invert();
bool_t result(ctx, is_equal);
auto result_witness = witness_t(ctx, is_equal);
result.witness_index = result_witness.witness_index;
result.witness_bool = is_equal;

bool_t result(witness_t(ctx, is_equal));
field_t r(result);
field_t x(witness_t(ctx, fc));

const field_t& a = *this;
const field_t& b = other;
const field_t diff = a - b;

const field_t t1 = r.madd(-x + 1, x);
const field_t t2 = diff.madd(t1, r - 1);
t2.assert_equal(0);
// these constraints ensure that result is a boolean
field_t::evaluate_polynomial_identity(diff, x, result, -field_t(bb::fr::one()));
field_t::evaluate_polynomial_identity(diff, result, field_t(bb::fr::zero()), field_t(bb::fr::zero()));

return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,9 +325,9 @@ template <typename Builder> class stdlib_field : public testing::Test {
// This logic requires on madd in field, which creates a big mul gate.
// This gate is implemented in standard by create 2 actual gates, while in ultra there are 2
if constexpr (std::same_as<Builder, StandardCircuitBuilder>) {
EXPECT_EQ(gates_after - gates_before, 6UL);
EXPECT_EQ(gates_after - gates_before, 5UL);
} else if (std::same_as<Builder, UltraCircuitBuilder>) {
EXPECT_EQ(gates_after - gates_before, 4UL);
EXPECT_EQ(gates_after - gates_before, 3UL);
}

bool result = CircuitChecker::check(builder);
Expand All @@ -353,9 +353,9 @@ template <typename Builder> class stdlib_field : public testing::Test {
// This logic requires on madd in field, which creates a big mul gate.
// This gate is implemented in standard by create 2 actual gates, while in ultra there are 2
if constexpr (std::same_as<Builder, StandardCircuitBuilder>) {
EXPECT_EQ(gates_after - gates_before, 6UL);
EXPECT_EQ(gates_after - gates_before, 5UL);
} else if (std::same_as<Builder, UltraCircuitBuilder>) {
EXPECT_EQ(gates_after - gates_before, 4UL);
EXPECT_EQ(gates_after - gates_before, 3UL);
}

bool result = CircuitChecker::check(builder);
Expand All @@ -382,9 +382,9 @@ template <typename Builder> class stdlib_field : public testing::Test {
// This logic requires on madd in field, which creates a big mul gate.
// This gate is implemented in standard by create 2 actual gates, while in ultra there are 2
if constexpr (std::same_as<Builder, StandardCircuitBuilder>) {
EXPECT_EQ(gates_after - gates_before, 11UL);
EXPECT_EQ(gates_after - gates_before, 9UL);
} else if (std::same_as<Builder, UltraCircuitBuilder>) {
EXPECT_EQ(gates_after - gates_before, 7UL);
EXPECT_EQ(gates_after - gates_before, 5UL);
}

bool result = CircuitChecker::check(builder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,15 @@ template <typename Builder> cycle_group<Builder> cycle_group<Builder>::operator+
// if x_coordinates match, lambda triggers a divide by zero error.
// Adding in `x_coordinates_match` ensures that lambda will always be well-formed
auto x_diff = x2.add_two(-x1, x_coordinates_match);
auto lambda = (y2 - y1) / x_diff;
// Computes lambda = (y2-y1)/x_diff, using the fact that x_diff is never 0
field_t lambda;
if ((y1.is_constant() && y2.is_constant()) || x_diff.is_constant()) {
lambda = (y2 - y1).divide_no_zero_check(x_diff);
} else {
lambda = field_t::from_witness(context, (y2.get_value() - y1.get_value()) / x_diff.get_value());
field_t::evaluate_polynomial_identity(x_diff, lambda, -y2, y1);
}

auto x3 = lambda.madd(lambda, -(x2 + x1));
auto y3 = lambda.madd(x1 - x3, -y1);
cycle_group add_result(x3, y3, x_coordinates_match);
Expand All @@ -473,7 +481,6 @@ template <typename Builder> cycle_group<Builder> cycle_group<Builder>::operator+
// is result point at infinity?
// yes = infinity_predicate && !lhs_infinity && !rhs_infinity
// yes = lhs_infinity && rhs_infinity
// n.b. can likely optimize this
bool_t result_is_infinity = infinity_predicate && (!lhs_infinity && !rhs_infinity);
result_is_infinity = result_is_infinity || (lhs_infinity && rhs_infinity);
result.set_point_at_infinity(result_is_infinity);
Expand Down

0 comments on commit e8a097c

Please sign in to comment.