Skip to content

Commit 2495f56

Browse files
committed
use complete addition in secp256k1 mul.
1 parent 1c999cb commit 2495f56

File tree

2 files changed

+63
-2
lines changed

2 files changed

+63
-2
lines changed

barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_secp256k1.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,9 @@ element<C, Fq, Fr, G> element<C, Fq, Fr, G>::secp256k1_ecdsa_mul(const element&
108108
const auto& add_1 = endoP1_table[u1_hi_wnaf.least_significant_wnaf_fragment];
109109
const auto& add_2 = endoP2_table[u2_hi_wnaf.least_significant_wnaf_fragment];
110110
const auto& add_3 = P1_table[u1_lo_wnaf.least_significant_wnaf_fragment];
111-
accumulator = element::chain_add_end(
112-
element::chain_add(add_3, element::chain_add(add_2, element::chain_add_start(accumulator, add_1))));
111+
accumulator += add_1;
112+
accumulator += add_2;
113+
accumulator += add_3;
113114

114115
/**
115116
* Handle wNAF skew.

barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_secp256k1.test.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "barretenberg/stdlib/primitives/curves/secp256k1.hpp"
1212
#include "barretenberg/stdlib/primitives/curves/secp256r1.hpp"
1313
#include "barretenberg/transcript/origin_tag.hpp"
14+
#include "gtest/gtest.h"
1415
#include <vector>
1516

1617
using namespace bb;
@@ -166,6 +167,61 @@ template <typename Curve> class stdlibBiggroupSecp256k1 : public testing::Test {
166167

167168
EXPECT_CIRCUIT_CORRECTNESS(builder);
168169
}
170+
171+
static void test_secp256k1_ecdsa_mul_stagger_regression()
172+
{
173+
// This test uses the same idea as the skew handling regression test above.
174+
// However, in this test, we use scalars to ensure that we are correctly handling the stagger offsets before
175+
// adding the skew points. The scalars s1, u1, u2 are chosen such that:
176+
// Public key: P = (s1 * G)
177+
//
178+
// u1 * G + u2 * (s1 * G) = ø
179+
//
180+
// where ø is the point at infinity. For this set of scalars, we have all the skews as 0.
181+
// This means that we will reach the point at infinity while adding the stagger fragments of the scalars.
182+
// Since we compute the wnaf with stagger offsets:
183+
//
184+
// compute_secp256k1_endo_wnaf<8, 2, 3>(u1);
185+
// compute_secp256k1_endo_wnaf<4, 0, 1>(u2);
186+
//
187+
// we have the following stagger offsets:
188+
// u1_low stagger bits: 2 <== add_3 = 2G
189+
// u1_high stagger bits: 3 <== add_1 = 3λG
190+
// u2_low stagger bits: 0
191+
// u2_high stagger bits: 1 <== add_2 = λG
192+
//
193+
// Hence we add these terms to the accumulator using addition chain:
194+
// acc += (((add_1) + add_2) + add_3).
195+
//
196+
// After adding add_2, the x-coordinate of the accumulator is equal to the x-coordinate of add_3.
197+
// Using incomplete addition formulae, we catch a circuit error as the addition is not valid if the
198+
// x-coordinates are equal. To avoid this, we use the complete addition formulae to add add_1, add_2, add_3
199+
// to the accumulator. The increases the circuit size for secp256k1_ecdsa_mul by 730 gates but we accept that
200+
// for now to ensure correctness.
201+
//
202+
const uint256_t scalar_g1("0x9d496650d261d31af6aa4cf41e435ed739d0fe2c34728a21a0df5c66a3504ccd");
203+
const uint256_t scalar_u1("0xf3d9f52f0f55d3da6f902aa842aa604005633f3d165bc800f3a3aa661b18df5f");
204+
const uint256_t scalar_u2("0x1323b0342b1a56a076cbf5e3899156fbf3f439f2c3b0d5a95b9ef74622447f2e");
205+
206+
// Check the assumptions
207+
ASSERT(scalar_g1 < fr::modulus);
208+
ASSERT(scalar_u1 < fr::modulus);
209+
ASSERT(scalar_u2 < fr::modulus);
210+
ASSERT((fr(scalar_g1) * fr(scalar_u2) + fr(scalar_u1)).is_zero());
211+
ASSERT((g1::one * fr(scalar_u1) + (g1::one * fr(scalar_g1)) * fr(scalar_u2)).is_point_at_infinity());
212+
213+
// Create the circuit
214+
Builder builder = Builder();
215+
element_ct P_a = element_ct::from_witness(&builder, g1::one * fr(scalar_g1));
216+
scalar_ct u1 = scalar_ct::from_witness(&builder, fr(scalar_u1));
217+
scalar_ct u2 = scalar_ct::from_witness(&builder, fr(scalar_u2));
218+
auto output = element_ct::secp256k1_ecdsa_mul(P_a, u1, u2);
219+
220+
// Check that the output is the point at infinity
221+
EXPECT_EQ(output.is_point_at_infinity().get_value(), true);
222+
223+
EXPECT_CIRCUIT_CORRECTNESS(builder);
224+
}
169225
};
170226

171227
// Then define the test types
@@ -192,3 +248,7 @@ TYPED_TEST(stdlibBiggroupSecp256k1, EcdsaMulSecp256k1SkewHandlingRegression)
192248
{
193249
TestFixture::test_secp256k1_ecdsa_mul_skew_handling_regression();
194250
}
251+
TYPED_TEST(stdlibBiggroupSecp256k1, EcdsaMulSecp256k1StaggerRegression)
252+
{
253+
TestFixture::test_secp256k1_ecdsa_mul_stagger_regression();
254+
}

0 commit comments

Comments
 (0)