From 7a006720507499bb00c78a9f16f2183a80ae5c99 Mon Sep 17 00:00:00 2001 From: zac-williamson Date: Thu, 7 Mar 2024 12:44:26 +0000 Subject: [PATCH 01/19] wip --- .../commitment_schemes/commitment_key.hpp | 32 +++- .../scalar_multiplication.cpp | 170 ++++++++++++++++++ .../scalar_multiplication.hpp | 13 ++ .../srs/scalar_multiplication.test.cpp | 55 ++++++ .../stdlib/encryption/aes128/aes128.test.cpp | 5 +- 5 files changed, 273 insertions(+), 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/commitment_key.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/commitment_key.hpp index 934b6dae9de..ef0a259ebf6 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/commitment_key.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/commitment_key.hpp @@ -18,8 +18,8 @@ #include #include +#include #include - namespace bb { /** @@ -33,6 +33,7 @@ namespace bb { template class CommitmentKey { using Fr = typename Curve::ScalarField; + using Fq = typename Curve::BaseField; using Commitment = typename Curve::AffineElement; public: @@ -75,6 +76,35 @@ template class CommitmentKey { return scalar_multiplication::pippenger_unsafe( const_cast(polynomial.data()), srs->get_monomial_points(), degree, pippenger_runtime_state); }; + + using G1 = typename Curve::AffineElement; + struct AddGroup { + G1* source; + G1* destination_origin; + size_t num_points; + }; + + struct AffineAddTemporaries { + Fq lambda_denominator_accumulator; + Fq lambda_numerator; + }; + + // void parallel_add_4( + // const MultipleAdditionSequences addition_sequences, Fq* scratch_space, G1* result + // ) + // { + // // const auto& num_independent_additions = addition_sequences.num_independent_additions; + // auto& sequence_counts = addition_sequences.sequence_counts; + + // const size_t num_independent_additions = 0; + // if (!addition_sequences.num_independent_additions.has_value()) + // { + // for (auto& num : sequence_counts) + // { + // num_independent_additions += (num >> 1);n + // } + // } + // } }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.cpp index 22e2c72f405..7a1200fc3de 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.cpp @@ -1060,6 +1060,176 @@ template curve::Grumpkin::Element pippenger_without_endomorphism_basis_points& state); +template void batched_affine_add_in_place(MultipleAdditionSequences addition_sequences) +{ + using G1 = typename Curve::AffineElement; + using Fq = typename Curve::BaseField; + std::cout << "enter" << std::endl; + const size_t num_points = addition_sequences.points.size(); + if (num_points == 0 || num_points == 1) { // nothing to do + return; + } + + std::vector reserved_batch_inverse_space; + Fq* scratch_space; + if (!addition_sequences.scratch_space.has_value()) { + reserved_batch_inverse_space.resize(num_points); + scratch_space = &reserved_batch_inverse_space[0]; + } else { + scratch_space = &addition_sequences.scratch_space.value()[0]; + } + + auto points = addition_sequences.points; + auto sequence_counts = addition_sequences.sequence_counts; + + const size_t num_sequences = sequence_counts.size(); + + Fq accumulator = 1; + G1* point_ptr = &points[num_points - 2]; + size_t cc = 0; + for (size_t i = 0; i < num_sequences; ++i) { + const size_t num_sequence_additions = sequence_counts[num_sequences - 1 - i] >> 1; + for (size_t j = 0; j < num_sequence_additions; ++j) { + const auto& x1 = point_ptr[0].x; + const auto& x2 = point_ptr[1].x; + // std::cout << "t0 = " << accumulator << std::endl; + // ASSERT(accumulator != 0); + *scratch_space = accumulator; + // std::cout << "t1 = " << accumulator << std::endl; + // ASSERT(accumulator != 0); + accumulator *= (x2 - x1); + // std::cout << "t2 = " << accumulator << std::endl; + if (accumulator == 0) { + std::cout << "cc " << cc << std::endl; + std::cout << "diff = " << std::ptrdiff_t(&points[num_points - 2] - point_ptr) << std::endl; + ; + } + ASSERT(accumulator != 0); + point_ptr -= 2; + scratch_space += 1; + ++cc; + } + point_ptr += (sequence_counts[num_sequences - 1 - i] & 0x01ULL); + } + + Fq inverse = accumulator.invert(); + + point_ptr = &points[0]; + size_t output_point_count = 0; + size_t output_sequence_count = 0; + bool more_additions = false; + for (size_t i = 0; i < num_sequences; ++i) { + const size_t num_sequence_points = sequence_counts[i]; + const size_t num_sequence_additions = num_sequence_points >> 1; + const bool overflow = static_cast(num_sequence_points & 0x01ULL); + if (overflow) { + points[output_point_count] = *point_ptr; + output_point_count += 1; + point_ptr += 1; + } + for (size_t j = 0; j < num_sequence_additions; ++j) { + const auto& x1 = point_ptr[0].x; + const auto& y1 = point_ptr[0].x; + const auto& x2 = point_ptr[1].x; + const auto& y2 = point_ptr[1].x; + + const Fq denominator = inverse * (*scratch_space); + inverse *= (x2 - x1); + + const Fq lambda = denominator * (y2 - y1); + Fq x3 = lambda.sqr() - x2 - x1; + Fq y3 = lambda * (x1 - x3) - y1; + points[output_point_count] = { x3, y3 }; + scratch_space -= 1; + point_ptr += 2; + output_point_count += 1; + } + sequence_counts[output_sequence_count] = + static_cast(num_sequence_additions) + static_cast(overflow); + output_sequence_count++; + + more_additions = more_additions || (sequence_counts[output_sequence_count] > 1); + } + + std::cout << "output sequence count = " << output_sequence_count << std::endl; + if (more_additions) { + std::span next_points(&points[0], output_point_count); + std::span next_sequences(&sequence_counts[0], output_sequence_count); + return batched_affine_add_in_place(MultipleAdditionSequences{ + sequence_counts = next_sequences, points = next_points, addition_sequences.scratch_space }); + } +} + +// template void batched_affine_add_in_place(MultipleAdditionSequences addition_sequences) + +template void batched_affine_add_in_place( + MultipleAdditionSequences addition_sequences); +template void batched_affine_add_in_place(MultipleAdditionSequences addition_sequences); + +template +void remove_duplicates(std::span polynomial, + std::span base_points, + pippenger_runtime_state& pippenger_runtime_state) +{ + using G1 = typename Curve::AffineElement; + using Fq = typename Curve::BaseField; + using Fr = typename Curve::ScalarField; + + size_t* index_ptr = (size_t*)(pippenger_runtime_state.point_schedule); + std::span index(index_ptr, polynomial.size()); + std::iota(index.begin(), index.end(), 0); + // "Sort" the index array according to the value in the vector of doubles + std::sort(index.begin(), index.end(), [&](size_t n1, size_t n2) { return polynomial[n1] < polynomial[n2]; }); + + // we can store input points in point_pairs_1, and our final "result points" (the points we will be performing + // an MSM over) in state.point_pairs_2 the pippenger algo will map the input point data into state.point_pairs_2 + // before performing computation + G1* mutable_base_points = pippenger_runtime_state.point_pairs_2; + + // we can store our unique polynomial data in point_pairs_1 (point_pairs is twice as large as base_points). + // Disgusting! `compute_wnaf_state` will convert the input scalars into wnafs in wnaf_state prior to + // point_pairs_1 or point_pairs_2 being used + Fr* unique_polynomial_coefficients = (Fr*)(pippenger_runtime_state.point_pairs_2 + polynomial.size()); + + // we can re-use the point schedule to store our sequence count data + uint64_t* sequence_counts = pippenger_runtime_state.point_schedule; + + unique_polynomial_coefficients[0] = polynomial[index[0]]; + // sequence_counts[index[0]] = 1; + mutable_base_points[0] = base_points[index[0]]; + std::cout << "indexes = " << index[0] << " : " << index[1] << std::endl; + std::cout << "p0, p1 = " << base_points[index[0]] << " : " << base_points[index[1]] << std::endl; + size_t count = 0; + sequence_counts[count] = 1; + for (size_t i = 1; i < polynomial.size(); ++i) { + if (polynomial[index[i]] == polynomial[index[i - 1]]) { + sequence_counts[count] += 1; + } else { + count++; + sequence_counts[count] = 1; + unique_polynomial_coefficients[count] = polynomial[index[i]]; + } + mutable_base_points[i] = base_points[index[i]]; + } + + std::span unique_points(mutable_base_points, polynomial.size()); + std::span scratch_space(pippenger_runtime_state.scratch_space, polynomial.size()); + + std::cout << "initial sequence count = " << count << std::endl; + MultipleAdditionSequences sequences{ .sequence_counts = std::span(&sequence_counts[0], count), + .points = unique_points, + .scratch_space = scratch_space }; + batched_affine_add_in_place(sequences); +} + +template void remove_duplicates(std::span polynomial, + std::span base_points, + pippenger_runtime_state& state); + +template void remove_duplicates(std::span polynomial, + std::span base_points, + pippenger_runtime_state& state); + } // namespace bb::scalar_multiplication // NOLINTEND(cppcoreguidelines-avoid-c-arrays, google-readability-casting) diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp index c93b602bfe1..77fc7a2fb0e 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp @@ -170,6 +170,19 @@ typename Curve::Element pippenger_without_endomorphism_basis_points(typename Cur size_t num_initial_points, pippenger_runtime_state& state); +template struct MultipleAdditionSequences { + std::span sequence_counts; + std::span points; + std::optional> scratch_space; +}; + +template void batched_affine_add_in_place(MultipleAdditionSequences addition_sequences); + +template +void remove_duplicates(std::span polynomial, + std::span base_points, + pippenger_runtime_state& pippenger_runtime_state); + // Explicit instantiation // BN254 diff --git a/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp b/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp index d66641157a5..ff1eda1bcd1 100644 --- a/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp +++ b/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp @@ -247,6 +247,61 @@ TYPED_TEST(ScalarMultiplicationTests, ReduceBucketsSimple) } } +TYPED_TEST(ScalarMultiplicationTests, RemoveDuplicates) +{ + using Curve = TypeParam; + using Element = typename Curve::Element; + using AffineElement = typename Curve::AffineElement; + using Fr = typename Curve::ScalarField; + + constexpr size_t num_points = 8192; + + Fr* scalars = (Fr*)aligned_alloc(32, sizeof(Fr) * num_points); + + AffineElement* points = (AffineElement*)aligned_alloc(32, sizeof(AffineElement) * (num_points * 2 + 1)); + + std::vector expected; + bool filling_scalars = true; + size_t num_filled_scalars = 0; + while (filling_scalars) { + size_t num_identical_scalars = static_cast(engine.get_random_uint64()) % 32 + 1; + if (num_filled_scalars + num_identical_scalars > num_points) { + num_identical_scalars = num_points - num_filled_scalars; + } + auto scalar = Fr::random_element(); + Element accumulator; + accumulator.self_set_infinity(); + for (size_t i = 0; i < num_identical_scalars; ++i) { + Element point = Element::random_element(); + scalars[num_filled_scalars + i] = scalar; + points[num_filled_scalars + i] = point; + accumulator += point; + } + expected.push_back(accumulator); + num_filled_scalars += num_identical_scalars; + if (num_filled_scalars == num_points) { + filling_scalars = false; + } + } + + // for (size_t i = 0; i < num_points; ++i) { + // scalars[i] = Fr::random_element(); + // points[i] = AffineElement(Element::random_element()); + // } + + scalar_multiplication::generate_pippenger_point_table(points, points, num_points); + scalar_multiplication::pippenger_runtime_state state(num_points); + + scalar_multiplication::remove_duplicates( + std::span(scalars, num_points), std::span(points, num_points), state); + + AffineElement* result = state.point_pairs_2; + + for (size_t i = 0; i < expected.size(); ++i) { + EXPECT_EQ(result[i], expected[i]); + } +} + TYPED_TEST(ScalarMultiplicationTests, ReduceBuckets) { using Curve = TypeParam; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/encryption/aes128/aes128.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/encryption/aes128/aes128.test.cpp index 90959ee9ccc..f256f54085b 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/encryption/aes128/aes128.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/encryption/aes128/aes128.test.cpp @@ -49,7 +49,10 @@ TEST(stdlib_aes128, encrypt_64_bytes) }; const auto result = stdlib::aes128::encrypt_buffer_cbc(in_field, iv_field, key_field); - + stdlib::aes128::encrypt_buffer_cbc(in_field, iv_field, key_field); + stdlib::aes128::encrypt_buffer_cbc(in_field, iv_field, key_field); + // 4229 + // 12685 for (size_t i = 0; i < 4; ++i) { EXPECT_EQ(result[i].get_value(), expected[i]); } From 33f90e2b139c8c4ae6e2bbb54ba6c0a803a7bdcf Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 3 Jul 2024 03:41:08 +0000 Subject: [PATCH 02/19] batched denominators method and WiP batched add --- .../scalar_multiplication.cpp | 316 ++++++++++++------ .../scalar_multiplication.hpp | 4 + .../srs/scalar_multiplication.test.cpp | 30 ++ 3 files changed, 251 insertions(+), 99 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.cpp index 7a1200fc3de..f510d2ad299 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.cpp @@ -1060,105 +1060,105 @@ template curve::Grumpkin::Element pippenger_without_endomorphism_basis_points& state); -template void batched_affine_add_in_place(MultipleAdditionSequences addition_sequences) -{ - using G1 = typename Curve::AffineElement; - using Fq = typename Curve::BaseField; - std::cout << "enter" << std::endl; - const size_t num_points = addition_sequences.points.size(); - if (num_points == 0 || num_points == 1) { // nothing to do - return; - } - - std::vector reserved_batch_inverse_space; - Fq* scratch_space; - if (!addition_sequences.scratch_space.has_value()) { - reserved_batch_inverse_space.resize(num_points); - scratch_space = &reserved_batch_inverse_space[0]; - } else { - scratch_space = &addition_sequences.scratch_space.value()[0]; - } - - auto points = addition_sequences.points; - auto sequence_counts = addition_sequences.sequence_counts; - - const size_t num_sequences = sequence_counts.size(); - - Fq accumulator = 1; - G1* point_ptr = &points[num_points - 2]; - size_t cc = 0; - for (size_t i = 0; i < num_sequences; ++i) { - const size_t num_sequence_additions = sequence_counts[num_sequences - 1 - i] >> 1; - for (size_t j = 0; j < num_sequence_additions; ++j) { - const auto& x1 = point_ptr[0].x; - const auto& x2 = point_ptr[1].x; - // std::cout << "t0 = " << accumulator << std::endl; - // ASSERT(accumulator != 0); - *scratch_space = accumulator; - // std::cout << "t1 = " << accumulator << std::endl; - // ASSERT(accumulator != 0); - accumulator *= (x2 - x1); - // std::cout << "t2 = " << accumulator << std::endl; - if (accumulator == 0) { - std::cout << "cc " << cc << std::endl; - std::cout << "diff = " << std::ptrdiff_t(&points[num_points - 2] - point_ptr) << std::endl; - ; - } - ASSERT(accumulator != 0); - point_ptr -= 2; - scratch_space += 1; - ++cc; - } - point_ptr += (sequence_counts[num_sequences - 1 - i] & 0x01ULL); - } - - Fq inverse = accumulator.invert(); - - point_ptr = &points[0]; - size_t output_point_count = 0; - size_t output_sequence_count = 0; - bool more_additions = false; - for (size_t i = 0; i < num_sequences; ++i) { - const size_t num_sequence_points = sequence_counts[i]; - const size_t num_sequence_additions = num_sequence_points >> 1; - const bool overflow = static_cast(num_sequence_points & 0x01ULL); - if (overflow) { - points[output_point_count] = *point_ptr; - output_point_count += 1; - point_ptr += 1; - } - for (size_t j = 0; j < num_sequence_additions; ++j) { - const auto& x1 = point_ptr[0].x; - const auto& y1 = point_ptr[0].x; - const auto& x2 = point_ptr[1].x; - const auto& y2 = point_ptr[1].x; - - const Fq denominator = inverse * (*scratch_space); - inverse *= (x2 - x1); - - const Fq lambda = denominator * (y2 - y1); - Fq x3 = lambda.sqr() - x2 - x1; - Fq y3 = lambda * (x1 - x3) - y1; - points[output_point_count] = { x3, y3 }; - scratch_space -= 1; - point_ptr += 2; - output_point_count += 1; - } - sequence_counts[output_sequence_count] = - static_cast(num_sequence_additions) + static_cast(overflow); - output_sequence_count++; - - more_additions = more_additions || (sequence_counts[output_sequence_count] > 1); - } - - std::cout << "output sequence count = " << output_sequence_count << std::endl; - if (more_additions) { - std::span next_points(&points[0], output_point_count); - std::span next_sequences(&sequence_counts[0], output_sequence_count); - return batched_affine_add_in_place(MultipleAdditionSequences{ - sequence_counts = next_sequences, points = next_points, addition_sequences.scratch_space }); - } -} +// template void batched_affine_add_in_place(MultipleAdditionSequences addition_sequences) +// { +// using G1 = typename Curve::AffineElement; +// using Fq = typename Curve::BaseField; +// std::cout << "enter" << std::endl; +// const size_t num_points = addition_sequences.points.size(); +// if (num_points == 0 || num_points == 1) { // nothing to do +// return; +// } + +// std::vector reserved_batch_inverse_space; +// Fq* scratch_space; +// if (!addition_sequences.scratch_space.has_value()) { +// reserved_batch_inverse_space.resize(num_points); +// scratch_space = &reserved_batch_inverse_space[0]; +// } else { +// scratch_space = &addition_sequences.scratch_space.value()[0]; +// } + +// auto points = addition_sequences.points; +// auto sequence_counts = addition_sequences.sequence_counts; + +// const size_t num_sequences = sequence_counts.size(); + +// Fq accumulator = 1; +// G1* point_ptr = &points[num_points - 2]; +// size_t cc = 0; +// for (size_t i = 0; i < num_sequences; ++i) { +// const size_t num_sequence_additions = sequence_counts[num_sequences - 1 - i] >> 1; +// for (size_t j = 0; j < num_sequence_additions; ++j) { +// const auto& x1 = point_ptr[0].x; +// const auto& x2 = point_ptr[1].x; +// // std::cout << "t0 = " << accumulator << std::endl; +// // ASSERT(accumulator != 0); +// *scratch_space = accumulator; +// // std::cout << "t1 = " << accumulator << std::endl; +// // ASSERT(accumulator != 0); +// accumulator *= (x2 - x1); +// // std::cout << "t2 = " << accumulator << std::endl; +// if (accumulator == 0) { +// std::cout << "cc " << cc << std::endl; +// std::cout << "diff = " << std::ptrdiff_t(&points[num_points - 2] - point_ptr) << std::endl; +// ; +// } +// ASSERT(accumulator != 0); +// point_ptr -= 2; +// scratch_space += 1; +// ++cc; +// } +// point_ptr += (sequence_counts[num_sequences - 1 - i] & 0x01ULL); +// } + +// Fq inverse = accumulator.invert(); + +// point_ptr = &points[0]; +// size_t output_point_count = 0; +// size_t output_sequence_count = 0; +// bool more_additions = false; +// for (size_t i = 0; i < num_sequences; ++i) { +// const size_t num_sequence_points = sequence_counts[i]; +// const size_t num_sequence_additions = num_sequence_points >> 1; +// const bool overflow = static_cast(num_sequence_points & 0x01ULL); +// if (overflow) { +// points[output_point_count] = *point_ptr; +// output_point_count += 1; +// point_ptr += 1; +// } +// for (size_t j = 0; j < num_sequence_additions; ++j) { +// const auto& x1 = point_ptr[0].x; +// const auto& y1 = point_ptr[0].x; +// const auto& x2 = point_ptr[1].x; +// const auto& y2 = point_ptr[1].x; + +// const Fq denominator = inverse * (*scratch_space); +// inverse *= (x2 - x1); + +// const Fq lambda = denominator * (y2 - y1); +// Fq x3 = lambda.sqr() - x2 - x1; +// Fq y3 = lambda * (x1 - x3) - y1; +// points[output_point_count] = { x3, y3 }; +// scratch_space -= 1; +// point_ptr += 2; +// output_point_count += 1; +// } +// sequence_counts[output_sequence_count] = +// static_cast(num_sequence_additions) + static_cast(overflow); +// output_sequence_count++; + +// more_additions = more_additions || (sequence_counts[output_sequence_count] > 1); +// } + +// std::cout << "output sequence count = " << output_sequence_count << std::endl; +// if (more_additions) { +// std::span next_points(&points[0], output_point_count); +// std::span next_sequences(&sequence_counts[0], output_sequence_count); +// return batched_affine_add_in_place(MultipleAdditionSequences{ +// sequence_counts = next_sequences, points = next_points, addition_sequences.scratch_space }); +// } +// } // template void batched_affine_add_in_place(MultipleAdditionSequences addition_sequences) @@ -1222,6 +1222,124 @@ void remove_duplicates(std::span polynomial, batched_affine_add_in_place(sequences); } +template +void compute_point_addition_denominators(MultipleAdditionSequences& addition_sequences, + std::span denominators) +{ + using Fq = typename Curve::BaseField; + + auto points = addition_sequences.points; + auto sequence_counts = addition_sequences.sequence_counts; + + // Count the total number of pairs across all addition sequences + size_t total_num_pairs{ 0 }; + for (auto& count : sequence_counts) { + total_num_pairs += count >> 1; + } + + auto scratch_space = denominators; + std::vector differences; + // scratch_space.resize(total_num_pairs); // can both be num_points/2 + differences.resize(total_num_pairs); + + Fq accumulator = 1; + size_t point_idx = 0; + size_t pair_idx = 0; + for (auto& count : sequence_counts) { + const size_t num_pairs = count >> 1; + for (size_t j = 0; j < num_pairs; ++j) { + const auto& x1 = points[point_idx++].x; + const auto& x2 = points[point_idx++].x; + + ASSERT(x1 != x2); + + auto diff = x2 - x1; + differences[pair_idx] = diff; + + scratch_space[pair_idx++] = accumulator; + accumulator *= diff; + } + // If number of points in the sequence is odd, we skip the last one since it has no pair + point_idx += (count & 0x01ULL); + } + + Fq inverse = accumulator.invert(); + + // Compute the point addition denominators 1/(x2 - x1) in place + for (size_t i = 0; i < total_num_pairs; ++i) { + size_t idx = total_num_pairs - 1 - i; + scratch_space[idx] *= inverse; + inverse *= differences[idx]; + } +} + +template void batched_affine_add_in_place(MultipleAdditionSequences addition_sequences) +{ + using G1 = typename Curve::AffineElement; + using Fq = typename Curve::BaseField; + // std::cout << "enter" << std::endl; + const size_t num_points = addition_sequences.points.size(); + if (num_points == 0 || num_points == 1) { // nothing to do + return; + } + + std::vector reserved_batch_inverse_space; + Fq* denominators; + if (!addition_sequences.scratch_space.has_value()) { + reserved_batch_inverse_space.resize(num_points); // WORKTODO: num_pairs + scratch_space = &reserved_batch_inverse_space[0]; + } else { + denominators = &addition_sequences.scratch_space.value()[0]; + } + + scalar_multiplication::compute_point_addition_denominators(addition_sequences, denominators); + + auto points = addition_sequences.points; + auto sequence_counts = addition_sequences.sequence_counts; + + size_t point_idx = 0; + size_t result_point_idx = 0; + size_t result_sequence_idx = 0; + size_t pair_idx = 0; + bool more_additions = false; + for (auto& count : sequence_counts) { + const size_t num_pairs = count >> 1; + const bool overflow = static_cast(count & 0x01ULL); + if (overflow) { + points[result_point_idx++] = points[point_idx++]; + } + for (size_t j = 0; j < num_pairs; ++j) { + const auto& x1 = points[point_idx].x; + const auto& y1 = points[point_idx++].y; + const auto& x2 = points[point_idx].x; + const auto& y2 = points[point_idx++].y; + + const Fq lambda = denominator[pair_idx++] * (y2 - y1); + Fq x3 = lambda.sqr() - x2 - x1; + Fq y3 = lambda * (x1 - x3) - y1; + points[result_point_idx++] = { x3, y3 }; + } + const uint64_t result_sequence_count = static_cast(num_pairs) + static_cast(overflow); + sequence_counts[result_sequence_idx++] = result_sequence_count; + + more_additions = more_additions || (result_sequence_count > 1); + } + + // std::cout << "output sequence count = " << output_sequence_count << std::endl; + // if (more_additions) { + // std::span next_points(&points[0], output_point_count); + // std::span next_sequences(&sequence_counts[0], output_sequence_count); + // return batched_affine_add_in_place(MultipleAdditionSequences{ + // sequence_counts = next_sequences, points = next_points, addition_sequences.scratch_space }); + // } +} + +template void compute_point_addition_denominators( + MultipleAdditionSequences& addition_sequences, std::span denominators); + +template void compute_point_addition_denominators( + MultipleAdditionSequences& addition_sequences, std::span denominators); + template void remove_duplicates(std::span polynomial, std::span base_points, pippenger_runtime_state& state); diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp index 77fc7a2fb0e..250e0527168 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp @@ -183,6 +183,10 @@ void remove_duplicates(std::span polynomial, std::span base_points, pippenger_runtime_state& pippenger_runtime_state); +template +void compute_point_addition_denominators(MultipleAdditionSequences& add_sequences, + std::span denominators); + // Explicit instantiation // BN254 diff --git a/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp b/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp index ff1eda1bcd1..7df387b11d6 100644 --- a/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp +++ b/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp @@ -12,6 +12,7 @@ #include "barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp" #include "barretenberg/common/mem.hpp" #include "barretenberg/common/test.hpp" +#include "barretenberg/common/zip_view.hpp" #include "barretenberg/ecc/scalar_multiplication/point_table.hpp" #include "barretenberg/numeric/random/engine.hpp" #include "barretenberg/srs/factories/file_crs_factory.hpp" @@ -247,6 +248,35 @@ TYPED_TEST(ScalarMultiplicationTests, ReduceBucketsSimple) } } +TYPED_TEST(ScalarMultiplicationTests, ComputePointAdditionDenominators) +{ + using Curve = TypeParam; + using Element = typename Curve::Element; + using AffineElement = typename Curve::AffineElement; + using Fq = typename Curve::BaseField; + + const size_t num_points = 5; + std::array points; + for (auto& point : points) { + point = Element::random_element(); + } + std::array sequence_counts{ 3, 2 }; + + scalar_multiplication::MultipleAdditionSequences addition_sequences{ sequence_counts, points, {} }; + + const size_t num_pairs = 2; + std::array denominators_expected; + denominators_expected[0] = (points[1].x - points[0].x).invert(); + denominators_expected[1] = (points[4].x - points[3].x).invert(); + + std::array denominators; + scalar_multiplication::compute_point_addition_denominators(addition_sequences, denominators); + + for (auto [result, expected] : zip_view(denominators, denominators_expected)) { + EXPECT_EQ(result, expected); + } +} + TYPED_TEST(ScalarMultiplicationTests, RemoveDuplicates) { using Curve = TypeParam; From de4905d268f02ac6b026ffe644163bfee002fac4 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 3 Jul 2024 20:46:47 +0000 Subject: [PATCH 03/19] batched affine add test is passing --- .../scalar_multiplication.cpp | 195 ++++++------------ .../scalar_multiplication.hpp | 5 + .../srs/scalar_multiplication.test.cpp | 81 +++++++- 3 files changed, 143 insertions(+), 138 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.cpp index f510d2ad299..2a53b3c1ab3 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.cpp @@ -1060,112 +1060,6 @@ template curve::Grumpkin::Element pippenger_without_endomorphism_basis_points& state); -// template void batched_affine_add_in_place(MultipleAdditionSequences addition_sequences) -// { -// using G1 = typename Curve::AffineElement; -// using Fq = typename Curve::BaseField; -// std::cout << "enter" << std::endl; -// const size_t num_points = addition_sequences.points.size(); -// if (num_points == 0 || num_points == 1) { // nothing to do -// return; -// } - -// std::vector reserved_batch_inverse_space; -// Fq* scratch_space; -// if (!addition_sequences.scratch_space.has_value()) { -// reserved_batch_inverse_space.resize(num_points); -// scratch_space = &reserved_batch_inverse_space[0]; -// } else { -// scratch_space = &addition_sequences.scratch_space.value()[0]; -// } - -// auto points = addition_sequences.points; -// auto sequence_counts = addition_sequences.sequence_counts; - -// const size_t num_sequences = sequence_counts.size(); - -// Fq accumulator = 1; -// G1* point_ptr = &points[num_points - 2]; -// size_t cc = 0; -// for (size_t i = 0; i < num_sequences; ++i) { -// const size_t num_sequence_additions = sequence_counts[num_sequences - 1 - i] >> 1; -// for (size_t j = 0; j < num_sequence_additions; ++j) { -// const auto& x1 = point_ptr[0].x; -// const auto& x2 = point_ptr[1].x; -// // std::cout << "t0 = " << accumulator << std::endl; -// // ASSERT(accumulator != 0); -// *scratch_space = accumulator; -// // std::cout << "t1 = " << accumulator << std::endl; -// // ASSERT(accumulator != 0); -// accumulator *= (x2 - x1); -// // std::cout << "t2 = " << accumulator << std::endl; -// if (accumulator == 0) { -// std::cout << "cc " << cc << std::endl; -// std::cout << "diff = " << std::ptrdiff_t(&points[num_points - 2] - point_ptr) << std::endl; -// ; -// } -// ASSERT(accumulator != 0); -// point_ptr -= 2; -// scratch_space += 1; -// ++cc; -// } -// point_ptr += (sequence_counts[num_sequences - 1 - i] & 0x01ULL); -// } - -// Fq inverse = accumulator.invert(); - -// point_ptr = &points[0]; -// size_t output_point_count = 0; -// size_t output_sequence_count = 0; -// bool more_additions = false; -// for (size_t i = 0; i < num_sequences; ++i) { -// const size_t num_sequence_points = sequence_counts[i]; -// const size_t num_sequence_additions = num_sequence_points >> 1; -// const bool overflow = static_cast(num_sequence_points & 0x01ULL); -// if (overflow) { -// points[output_point_count] = *point_ptr; -// output_point_count += 1; -// point_ptr += 1; -// } -// for (size_t j = 0; j < num_sequence_additions; ++j) { -// const auto& x1 = point_ptr[0].x; -// const auto& y1 = point_ptr[0].x; -// const auto& x2 = point_ptr[1].x; -// const auto& y2 = point_ptr[1].x; - -// const Fq denominator = inverse * (*scratch_space); -// inverse *= (x2 - x1); - -// const Fq lambda = denominator * (y2 - y1); -// Fq x3 = lambda.sqr() - x2 - x1; -// Fq y3 = lambda * (x1 - x3) - y1; -// points[output_point_count] = { x3, y3 }; -// scratch_space -= 1; -// point_ptr += 2; -// output_point_count += 1; -// } -// sequence_counts[output_sequence_count] = -// static_cast(num_sequence_additions) + static_cast(overflow); -// output_sequence_count++; - -// more_additions = more_additions || (sequence_counts[output_sequence_count] > 1); -// } - -// std::cout << "output sequence count = " << output_sequence_count << std::endl; -// if (more_additions) { -// std::span next_points(&points[0], output_point_count); -// std::span next_sequences(&sequence_counts[0], output_sequence_count); -// return batched_affine_add_in_place(MultipleAdditionSequences{ -// sequence_counts = next_sequences, points = next_points, addition_sequences.scratch_space }); -// } -// } - -// template void batched_affine_add_in_place(MultipleAdditionSequences addition_sequences) - -template void batched_affine_add_in_place( - MultipleAdditionSequences addition_sequences); -template void batched_affine_add_in_place(MultipleAdditionSequences addition_sequences); - template void remove_duplicates(std::span polynomial, std::span base_points, @@ -1277,20 +1171,23 @@ template void batched_affine_add_in_place(MultipleAdditionSeque { using G1 = typename Curve::AffineElement; using Fq = typename Curve::BaseField; - // std::cout << "enter" << std::endl; const size_t num_points = addition_sequences.points.size(); if (num_points == 0 || num_points == 1) { // nothing to do return; } - std::vector reserved_batch_inverse_space; - Fq* denominators; - if (!addition_sequences.scratch_space.has_value()) { - reserved_batch_inverse_space.resize(num_points); // WORKTODO: num_pairs - scratch_space = &reserved_batch_inverse_space[0]; - } else { - denominators = &addition_sequences.scratch_space.value()[0]; - } + std::vector denominators(num_points); + + // std::vector reserved_batch_inverse_space; + // std::span denominators; + // if (!addition_sequences.scratch_space.has_value()) { + // info("Using local scratch space."); + // reserved_batch_inverse_space.resize(num_points); // WORKTODO: num_pairs + // denominators = &reserved_batch_inverse_space[0]; + // } else { + // info("Using PROVIDED scratch space."); + // denominators = &addition_sequences.scratch_space.value()[0]; + // } scalar_multiplication::compute_point_addition_denominators(addition_sequences, denominators); @@ -1299,41 +1196,65 @@ template void batched_affine_add_in_place(MultipleAdditionSeque size_t point_idx = 0; size_t result_point_idx = 0; - size_t result_sequence_idx = 0; size_t pair_idx = 0; bool more_additions = false; for (auto& count : sequence_counts) { const size_t num_pairs = count >> 1; const bool overflow = static_cast(count & 0x01ULL); + // Compute the sum of all pairs in the sequence and store the result in the points array + for (size_t j = 0; j < num_pairs; ++j) { + const auto& point_1 = points[point_idx++]; // first summand + const auto& point_2 = points[point_idx++]; // second summand + const auto& denominator = denominators[pair_idx++]; // denominator needed in add formula + auto& result = points[result_point_idx++]; // target for addition result + + result = scalar_multiplication::affine_add_with_denominator(point_1, point_2, denominator); + } if (overflow) { points[result_point_idx++] = points[point_idx++]; } - for (size_t j = 0; j < num_pairs; ++j) { - const auto& x1 = points[point_idx].x; - const auto& y1 = points[point_idx++].y; - const auto& x2 = points[point_idx].x; - const auto& y2 = points[point_idx++].y; - - const Fq lambda = denominator[pair_idx++] * (y2 - y1); - Fq x3 = lambda.sqr() - x2 - x1; - Fq y3 = lambda * (x1 - x3) - y1; - points[result_point_idx++] = { x3, y3 }; - } - const uint64_t result_sequence_count = static_cast(num_pairs) + static_cast(overflow); - sequence_counts[result_sequence_idx++] = result_sequence_count; + const uint64_t updated_sequence_count = static_cast(num_pairs) + static_cast(overflow); + count = updated_sequence_count; - more_additions = more_additions || (result_sequence_count > 1); + more_additions = more_additions || (updated_sequence_count > 1); } - // std::cout << "output sequence count = " << output_sequence_count << std::endl; - // if (more_additions) { - // std::span next_points(&points[0], output_point_count); - // std::span next_sequences(&sequence_counts[0], output_sequence_count); - // return batched_affine_add_in_place(MultipleAdditionSequences{ - // sequence_counts = next_sequences, points = next_points, addition_sequences.scratch_space }); - // } + if (more_additions) { + const size_t updated_point_count = result_point_idx; + std::span updated_points(&points[0], updated_point_count); + return batched_affine_add_in_place( + MultipleAdditionSequences{ sequence_counts, updated_points, addition_sequences.scratch_space }); + } } +template +typename Curve::AffineElement affine_add_with_denominator(const typename Curve::AffineElement& point_1, + const typename Curve::AffineElement& point_2, + const typename Curve::BaseField& denominator) +{ + using Fq = typename Curve::BaseField; + + const auto& x1 = point_1.x; + const auto& y1 = point_1.y; + const auto& x2 = point_2.x; + const auto& y2 = point_2.y; + + const Fq lambda = denominator * (y2 - y1); + Fq x3 = lambda.sqr() - x2 - x1; + Fq y3 = lambda * (x1 - x3) - y1; + return { x3, y3 }; +} + +template curve::Grumpkin::AffineElement affine_add_with_denominator( + const curve::Grumpkin::AffineElement&, const curve::Grumpkin::AffineElement&, const curve::Grumpkin::BaseField&); +template curve::BN254::AffineElement affine_add_with_denominator(const curve::BN254::AffineElement&, + const curve::BN254::AffineElement&, + const curve::BN254::BaseField&); + +template void batched_affine_add_in_place( + MultipleAdditionSequences addition_sequences); +template void batched_affine_add_in_place(MultipleAdditionSequences addition_sequences); + template void compute_point_addition_denominators( MultipleAdditionSequences& addition_sequences, std::span denominators); diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp index 250e0527168..d6c81cea7d3 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp @@ -178,6 +178,11 @@ template struct MultipleAdditionSequences { template void batched_affine_add_in_place(MultipleAdditionSequences addition_sequences); +template +typename Curve::AffineElement affine_add_with_denominator(const typename Curve::AffineElement&, + const typename Curve::AffineElement&, + const typename Curve::BaseField& denominator); + template void remove_duplicates(std::span polynomial, std::span base_points, diff --git a/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp b/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp index 7df387b11d6..621dbab0d43 100644 --- a/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp +++ b/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp @@ -277,6 +277,84 @@ TYPED_TEST(ScalarMultiplicationTests, ComputePointAdditionDenominators) } } +TYPED_TEST(ScalarMultiplicationTests, AffineAddWithDenominator) +{ + using Curve = TypeParam; + using Element = typename Curve::Element; + using AffineElement = typename Curve::AffineElement; + using Fq = typename Curve::BaseField; + + AffineElement point_1 = Element::random_element(); + AffineElement point_2 = Element::random_element(); + Fq denominator = (point_2.x - point_1.x).invert(); + + AffineElement expected = point_1 + point_2; + + AffineElement result = scalar_multiplication::affine_add_with_denominator(point_1, point_2, denominator); + + EXPECT_EQ(result, expected); +} + +TYPED_TEST(ScalarMultiplicationTests, BatchedAffineAddInPlaceSimple) +{ + using Curve = TypeParam; + using Element = typename Curve::Element; + using AffineElement = typename Curve::AffineElement; + + const size_t num_points = 2; + std::array points; + for (auto& point : points) { + point = Element::random_element(); + } + std::array sequence_counts{ 2 }; + + scalar_multiplication::MultipleAdditionSequences addition_sequences{ sequence_counts, points, {} }; + + std::array expected_points{ points[0] + points[1] }; + + scalar_multiplication::batched_affine_add_in_place(addition_sequences); + + for (size_t idx = 0; idx < expected_points.size(); ++idx) { + // info("expected = ", expected_points[idx]); + // info("result = ", points[idx]); + EXPECT_EQ(expected_points[idx], points[idx]); + } +} + +TYPED_TEST(ScalarMultiplicationTests, BatchedAffineAddInPlace) +{ + using Curve = TypeParam; + using Element = typename Curve::Element; + using G1 = typename Curve::AffineElement; + + const size_t num_points = 10; + std::array points; + for (auto& point : points) { + point = Element::random_element(); + } + std::array sequence_counts{ 5, 2, 3 }; + + scalar_multiplication::MultipleAdditionSequences addition_sequences{ sequence_counts, points, {} }; + + std::vector expected_points; + size_t point_idx = 0; + for (auto count : sequence_counts) { + G1 sum = points[point_idx++]; + for (size_t i = 1; i < count; ++i) { + sum = sum + points[point_idx++]; + } + expected_points.emplace_back(sum); + } + + scalar_multiplication::batched_affine_add_in_place(addition_sequences); + + for (size_t idx = 0; idx < expected_points.size(); ++idx) { + // info("expected = ", expected_points[idx]); + // info("result = ", points[idx]); + EXPECT_EQ(expected_points[idx], points[idx]); + } +} + TYPED_TEST(ScalarMultiplicationTests, RemoveDuplicates) { using Curve = TypeParam; @@ -656,7 +734,8 @@ TYPED_TEST(ScalarMultiplicationTests, EndomorphismSplit) Element expected = Group::one * scalar; - // we want to test that we can split a scalar into two half-length components, using the same location in memory. + // we want to test that we can split a scalar into two half-length components, using the same location in + // memory. Fr* k1_t = &scalar; Fr* k2_t = (Fr*)&scalar.data[2]; From d8d5f0d6dfca6fe7ba30e57fc05d2192eba0a404 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 3 Jul 2024 22:27:03 +0000 Subject: [PATCH 04/19] move logic and tests to new class --- .../ecc/scalar_multiplication/sorted_msm.cpp | 130 ++++++++++++ .../ecc/scalar_multiplication/sorted_msm.hpp | 29 +++ .../scalar_multiplication/sorted_msm.test.cpp | 187 ++++++++++++++++++ 3 files changed, 346 insertions(+) create mode 100644 barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp create mode 100644 barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp create mode 100644 barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp new file mode 100644 index 00000000000..a2cb2681450 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp @@ -0,0 +1,130 @@ +#include "barretenberg/ecc/scalar_multiplication/sorted_msm.hpp" + +namespace bb { + +template +void SortedMsmManager::compute_point_addition_denominators(AdditionSequences& add_sequences, + std::span denominators) +{ + auto points = add_sequences.points; + auto sequence_counts = add_sequences.sequence_counts; + + // Count the total number of pairs across all addition sequences + size_t total_num_pairs{ 0 }; + for (auto& count : sequence_counts) { + total_num_pairs += count >> 1; + } + + auto scratch_space = denominators; + std::vector differences; + differences.resize(total_num_pairs); + + Fq accumulator = 1; + size_t point_idx = 0; + size_t pair_idx = 0; + for (auto& count : sequence_counts) { + const size_t num_pairs = count >> 1; + for (size_t j = 0; j < num_pairs; ++j) { + const auto& x1 = points[point_idx++].x; + const auto& x2 = points[point_idx++].x; + + ASSERT(x1 != x2); + + auto diff = x2 - x1; + differences[pair_idx] = diff; + + scratch_space[pair_idx++] = accumulator; + accumulator *= diff; + } + // If number of points in the sequence is odd, we skip the last one since it has no pair + point_idx += (count & 0x01ULL); + } + + Fq inverse = accumulator.invert(); + + // Compute the point addition denominators 1/(x2 - x1) in place + for (size_t i = 0; i < total_num_pairs; ++i) { + size_t idx = total_num_pairs - 1 - i; + scratch_space[idx] *= inverse; + inverse *= differences[idx]; + } +} + +template +typename Curve::AffineElement SortedMsmManager::affine_add_with_denominator(const G1& point_1, + const G1& point_2, + const Fq& denominator) +{ + const auto& x1 = point_1.x; + const auto& y1 = point_1.y; + const auto& x2 = point_2.x; + const auto& y2 = point_2.y; + + const Fq lambda = denominator * (y2 - y1); + Fq x3 = lambda.sqr() - x2 - x1; + Fq y3 = lambda * (x1 - x3) - y1; + return { x3, y3 }; +} + +template +void SortedMsmManager::batched_affine_add_in_place(AdditionSequences addition_sequences) +{ + const size_t num_points = addition_sequences.points.size(); + if (num_points == 0 || num_points == 1) { // nothing to do + return; + } + + std::vector denominators(num_points); + + // std::vector reserved_batch_inverse_space; + // std::span denominators; + // if (!addition_sequences.scratch_space.has_value()) { + // info("Using local scratch space."); + // reserved_batch_inverse_space.resize(num_points); // WORKTODO: num_pairs + // denominators = &reserved_batch_inverse_space[0]; + // } else { + // info("Using PROVIDED scratch space."); + // denominators = &addition_sequences.scratch_space.value()[0]; + // } + + compute_point_addition_denominators(addition_sequences, denominators); + + auto points = addition_sequences.points; + auto sequence_counts = addition_sequences.sequence_counts; + + size_t point_idx = 0; + size_t result_point_idx = 0; + size_t pair_idx = 0; + bool more_additions = false; + for (auto& count : sequence_counts) { + const size_t num_pairs = count >> 1; + const bool overflow = static_cast(count & 0x01ULL); + // Compute the sum of all pairs in the sequence and store the result in the points array + for (size_t j = 0; j < num_pairs; ++j) { + const auto& point_1 = points[point_idx++]; // first summand + const auto& point_2 = points[point_idx++]; // second summand + const auto& denominator = denominators[pair_idx++]; // denominator needed in add formula + auto& result = points[result_point_idx++]; // target for addition result + + result = affine_add_with_denominator(point_1, point_2, denominator); + } + if (overflow) { + points[result_point_idx++] = points[point_idx++]; + } + const uint64_t updated_sequence_count = static_cast(num_pairs) + static_cast(overflow); + count = updated_sequence_count; + + more_additions = more_additions || (updated_sequence_count > 1); + } + + if (more_additions) { + const size_t updated_point_count = result_point_idx; + std::span updated_points(&points[0], updated_point_count); + return batched_affine_add_in_place( + AdditionSequences{ sequence_counts, updated_points, addition_sequences.scratch_space }); + } +} + +template class SortedMsmManager; +template class SortedMsmManager; +} // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp new file mode 100644 index 00000000000..5a1a97bffd6 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "./runtime_states.hpp" +#include "barretenberg/ecc/curves/bn254/bn254.hpp" +#include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" +#include +#include + +namespace bb { +template class SortedMsmManager { + public: + using G1 = typename Curve::AffineElement; + using Fq = typename Curve::BaseField; + + // Storage for a set of points to be sorted and reduced + struct AdditionSequences { + std::span sequence_counts; + std::span points; + std::optional> scratch_space; + }; + + static G1 affine_add_with_denominator(const G1&, const G1&, const Fq& denominator); + + static void compute_point_addition_denominators(AdditionSequences& add_sequences, std::span denominators); + + static void batched_affine_add_in_place(AdditionSequences addition_sequences); +}; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp new file mode 100644 index 00000000000..b3055b48ae0 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp @@ -0,0 +1,187 @@ +#include "barretenberg/ecc/scalar_multiplication/sorted_msm.hpp" +#include "barretenberg/common/mem.hpp" +#include "barretenberg/common/test.hpp" +#include "barretenberg/common/zip_view.hpp" +#include "barretenberg/ecc/scalar_multiplication/point_table.hpp" +#include "barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp" +#include "barretenberg/numeric/random/engine.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" +#include "barretenberg/srs/io.hpp" + +#include +#include + +using namespace bb; + +namespace { +auto& engine = numeric::get_debug_randomness(); +} + +template class SortedMsmTests : public ::testing::Test { + public: +}; + +using Curves = ::testing::Types; + +TYPED_TEST_SUITE(SortedMsmTests, Curves); + +TYPED_TEST(SortedMsmTests, ComputePointAdditionDenominators) +{ + using Curve = TypeParam; + using G1 = typename Curve::AffineElement; + using Fq = typename Curve::BaseField; + using MsmManager = SortedMsmManager; + using AdditionSequences = typename MsmManager::AdditionSequences; + + const size_t num_points = 5; + std::array points; + for (auto& point : points) { + point = G1::random_element(); + } + std::array sequence_counts{ 3, 2 }; + + AdditionSequences addition_sequences{ sequence_counts, points, {} }; + + const size_t num_pairs = 2; + std::array denominators_expected; + denominators_expected[0] = (points[1].x - points[0].x).invert(); + denominators_expected[1] = (points[4].x - points[3].x).invert(); + + std::array denominators; + MsmManager::compute_point_addition_denominators(addition_sequences, denominators); + + for (auto [result, expected] : zip_view(denominators, denominators_expected)) { + EXPECT_EQ(result, expected); + } +} + +TYPED_TEST(SortedMsmTests, AffineAddWithDenominator) +{ + using Curve = TypeParam; + using G1 = typename Curve::AffineElement; + using Fq = typename Curve::BaseField; + using MsmManager = SortedMsmManager; + + G1 point_1 = G1::random_element(); + G1 point_2 = G1::random_element(); + Fq denominator = (point_2.x - point_1.x).invert(); + + G1 expected = point_1 + point_2; + + G1 result = MsmManager::affine_add_with_denominator(point_1, point_2, denominator); + + EXPECT_EQ(result, expected); +} + +TYPED_TEST(SortedMsmTests, BatchedAffineAddInPlaceSimple) +{ + using Curve = TypeParam; + using G1 = typename Curve::AffineElement; + using MsmManager = SortedMsmManager; + using AdditionSequences = typename MsmManager::AdditionSequences; + + const size_t num_points = 2; + std::array points; + for (auto& point : points) { + point = G1::random_element(); + } + std::array sequence_counts{ 2 }; + + AdditionSequences addition_sequences{ sequence_counts, points, {} }; + + std::array expected_points{ points[0] + points[1] }; + + MsmManager::batched_affine_add_in_place(addition_sequences); + + for (size_t idx = 0; idx < expected_points.size(); ++idx) { + EXPECT_EQ(expected_points[idx], points[idx]); + } +} + +TYPED_TEST(SortedMsmTests, BatchedAffineAddInPlace) +{ + using Curve = TypeParam; + using G1 = typename Curve::AffineElement; + using MsmManager = SortedMsmManager; + using AdditionSequences = typename MsmManager::AdditionSequences; + + const size_t num_points = 10; + std::array points; + for (auto& point : points) { + point = G1::random_element(); + } + std::array sequence_counts{ 5, 2, 3 }; + + AdditionSequences addition_sequences{ sequence_counts, points, {} }; + + std::vector expected_points; + size_t point_idx = 0; + for (auto count : sequence_counts) { + G1 sum = points[point_idx++]; + for (size_t i = 1; i < count; ++i) { + sum = sum + points[point_idx++]; + } + expected_points.emplace_back(sum); + } + + MsmManager::batched_affine_add_in_place(addition_sequences); + + for (size_t idx = 0; idx < expected_points.size(); ++idx) { + EXPECT_EQ(expected_points[idx], points[idx]); + } +} + +// TYPED_TEST(ScalarMultiplicationTests, RemoveDuplicates) +// { +// using Curve = TypeParam; +// using Element = typename Curve::Element; +// using AffineElement = typename Curve::AffineElement; +// using Fr = typename Curve::ScalarField; + +// constexpr size_t num_points = 8192; + +// Fr* scalars = (Fr*)aligned_alloc(32, sizeof(Fr) * num_points); + +// AffineElement* points = (AffineElement*)aligned_alloc(32, sizeof(AffineElement) * (num_points * 2 + 1)); + +// std::vector expected; +// bool filling_scalars = true; +// size_t num_filled_scalars = 0; +// while (filling_scalars) { +// size_t num_identical_scalars = static_cast(engine.get_random_uint64()) % 32 + 1; +// if (num_filled_scalars + num_identical_scalars > num_points) { +// num_identical_scalars = num_points - num_filled_scalars; +// } +// auto scalar = Fr::random_element(); +// Element accumulator; +// accumulator.self_set_infinity(); +// for (size_t i = 0; i < num_identical_scalars; ++i) { +// Element point = G1::random_element(); +// scalars[num_filled_scalars + i] = scalar; +// points[num_filled_scalars + i] = point; +// accumulator += point; +// } +// expected.push_back(accumulator); +// num_filled_scalars += num_identical_scalars; +// if (num_filled_scalars == num_points) { +// filling_scalars = false; +// } +// } + +// // for (size_t i = 0; i < num_points; ++i) { +// // scalars[i] = Fr::random_element(); +// // points[i] = AffineElement(G1::random_element()); +// // } + +// scalar_multiplication::generate_pippenger_point_table(points, points, num_points); +// scalar_multiplication::pippenger_runtime_state state(num_points); + +// scalar_multiplication::remove_duplicates( +// std::span(scalars, num_points), std::span(points, num_points), state); + +// AffineElement* result = state.point_pairs_2; + +// for (size_t i = 0; i < expected.size(); ++i) { +// EXPECT_EQ(result[i], expected[i]); +// } +// } From 1adaa41172ab0700fb922446ac74ac7fbaa3932b Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Thu, 4 Jul 2024 19:07:57 +0000 Subject: [PATCH 05/19] reduce inputs functionality complete and passing tests --- .../ecc/scalar_multiplication/sorted_msm.cpp | 45 +++++++ .../ecc/scalar_multiplication/sorted_msm.hpp | 23 +++- .../scalar_multiplication/sorted_msm.test.cpp | 120 +++++++++++++++++- 3 files changed, 181 insertions(+), 7 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp index a2cb2681450..69bf217cc15 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp @@ -2,6 +2,51 @@ namespace bb { +template void SortedMsmManager::reduce_msm_inputs(std::span scalars, std::span points) +{ + // generate the addition sequences + AdditionSequences addition_sequences = generate_addition_sequences(scalars, points); + + // call batched affine add in place until the sequences have been fully reduced + batched_affine_add_in_place(addition_sequences); + + // the reduced inputs are the unique scalrs and the reduced points +} + +template +SortedMsmManager::AdditionSequences SortedMsmManager::generate_addition_sequences(std::span scalars, + std::span points) +{ + const size_t num_points = points.size(); + std::vector index(num_points); + std::iota(index.begin(), index.end(), 0); + std::sort(index.begin(), index.end(), [&](size_t idx_1, size_t idx_2) { return scalars[idx_1] < scalars[idx_2]; }); + + unique_scalars[0] = scalars[index[0]]; + updated_points[0] = points[index[0]]; + size_t seq_idx = 0; + sequence_counts[seq_idx] = 1; + for (size_t i = 1; i < scalars.size(); ++i) { + const Fr& current_scalar = scalars[index[i]]; + const Fr& prev_scalar = scalars[index[i - 1]]; + + if (current_scalar == prev_scalar) { + sequence_counts[seq_idx]++; + } else { + seq_idx++; + sequence_counts[seq_idx]++; + unique_scalars[seq_idx] = current_scalar; + } + + updated_points[i] = points[index[i]]; + } + + num_unique_scalars = seq_idx + 1; + std::span seq_counts(sequence_counts.data(), num_unique_scalars); + std::span sorted_points(updated_points.data(), num_points); + return AdditionSequences{ seq_counts, sorted_points, {} }; +} + template void SortedMsmManager::compute_point_addition_denominators(AdditionSequences& add_sequences, std::span denominators) diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp index 5a1a97bffd6..b6017a19037 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp @@ -10,6 +10,7 @@ namespace bb { template class SortedMsmManager { public: using G1 = typename Curve::AffineElement; + using Fr = typename Curve::ScalarField; using Fq = typename Curve::BaseField; // Storage for a set of points to be sorted and reduced @@ -19,11 +20,27 @@ template class SortedMsmManager { std::optional> scratch_space; }; - static G1 affine_add_with_denominator(const G1&, const G1&, const Fq& denominator); + size_t num_unique_scalars = 0; + std::vector sequence_counts; + std::vector unique_scalars; + std::vector updated_points; - static void compute_point_addition_denominators(AdditionSequences& add_sequences, std::span denominators); + SortedMsmManager(const size_t num_scalars = 0) + { + sequence_counts.resize(num_scalars); + unique_scalars.resize(num_scalars); + updated_points.resize(num_scalars); + } - static void batched_affine_add_in_place(AdditionSequences addition_sequences); + G1 affine_add_with_denominator(const G1&, const G1&, const Fq& denominator); + + void compute_point_addition_denominators(AdditionSequences& add_sequences, std::span denominators); + + void batched_affine_add_in_place(AdditionSequences addition_sequences); + + AdditionSequences generate_addition_sequences(std::span scalars, std::span points); + + void reduce_msm_inputs(std::span scalars, std::span points); }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp index b3055b48ae0..2473981f07f 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp @@ -33,6 +33,8 @@ TYPED_TEST(SortedMsmTests, ComputePointAdditionDenominators) using MsmManager = SortedMsmManager; using AdditionSequences = typename MsmManager::AdditionSequences; + MsmManager msm_manager; + const size_t num_points = 5; std::array points; for (auto& point : points) { @@ -48,7 +50,7 @@ TYPED_TEST(SortedMsmTests, ComputePointAdditionDenominators) denominators_expected[1] = (points[4].x - points[3].x).invert(); std::array denominators; - MsmManager::compute_point_addition_denominators(addition_sequences, denominators); + msm_manager.compute_point_addition_denominators(addition_sequences, denominators); for (auto [result, expected] : zip_view(denominators, denominators_expected)) { EXPECT_EQ(result, expected); @@ -62,13 +64,15 @@ TYPED_TEST(SortedMsmTests, AffineAddWithDenominator) using Fq = typename Curve::BaseField; using MsmManager = SortedMsmManager; + MsmManager msm_manager; + G1 point_1 = G1::random_element(); G1 point_2 = G1::random_element(); Fq denominator = (point_2.x - point_1.x).invert(); G1 expected = point_1 + point_2; - G1 result = MsmManager::affine_add_with_denominator(point_1, point_2, denominator); + G1 result = msm_manager.affine_add_with_denominator(point_1, point_2, denominator); EXPECT_EQ(result, expected); } @@ -80,6 +84,8 @@ TYPED_TEST(SortedMsmTests, BatchedAffineAddInPlaceSimple) using MsmManager = SortedMsmManager; using AdditionSequences = typename MsmManager::AdditionSequences; + MsmManager msm_manager; + const size_t num_points = 2; std::array points; for (auto& point : points) { @@ -91,7 +97,7 @@ TYPED_TEST(SortedMsmTests, BatchedAffineAddInPlaceSimple) std::array expected_points{ points[0] + points[1] }; - MsmManager::batched_affine_add_in_place(addition_sequences); + msm_manager.batched_affine_add_in_place(addition_sequences); for (size_t idx = 0; idx < expected_points.size(); ++idx) { EXPECT_EQ(expected_points[idx], points[idx]); @@ -105,6 +111,8 @@ TYPED_TEST(SortedMsmTests, BatchedAffineAddInPlace) using MsmManager = SortedMsmManager; using AdditionSequences = typename MsmManager::AdditionSequences; + MsmManager msm_manager; + const size_t num_points = 10; std::array points; for (auto& point : points) { @@ -124,13 +132,117 @@ TYPED_TEST(SortedMsmTests, BatchedAffineAddInPlace) expected_points.emplace_back(sum); } - MsmManager::batched_affine_add_in_place(addition_sequences); + msm_manager.batched_affine_add_in_place(addition_sequences); for (size_t idx = 0; idx < expected_points.size(); ++idx) { EXPECT_EQ(expected_points[idx], points[idx]); } } +TYPED_TEST(SortedMsmTests, GenerateAdditionSequences) +{ + using Curve = TypeParam; + using G1 = typename Curve::AffineElement; + using Fr = typename Curve::ScalarField; + using MsmManager = SortedMsmManager; + using AdditionSequences = typename MsmManager::AdditionSequences; + + const size_t num_points = 10; + std::array points; + for (auto& point : points) { + point = G1::random_element(); + } + std::array sequence_counts{ 5, 2, 3 }; + std::vector scalars; + std::vector unique_scalars; + for (auto& count : sequence_counts) { + Fr repeated_scalar = Fr::random_element(); + for (size_t i = 0; i < count; ++i) { + scalars.emplace_back(repeated_scalar); + } + unique_scalars.emplace_back(repeated_scalar); + } + + // Randomly shuffle the scalars so duplicates are no longer grouped together + std::random_device rd; + std::shuffle(scalars.begin(), scalars.end(), std::default_random_engine(rd())); + + MsmManager msm_manager{ num_points }; + AdditionSequences result = msm_manager.generate_addition_sequences(scalars, points); + + // The resulting sequence counts should match expectation but only as multisets + std::multiset expected_sequence_counts(sequence_counts.begin(), sequence_counts.end()); + std::multiset result_sequence_counts(result.sequence_counts.begin(), result.sequence_counts.end()); + EXPECT_EQ(expected_sequence_counts, result_sequence_counts); + + // The result points will be sorted but should match the original as multisets + std::multiset expected_points(points.begin(), points.end()); + std::multiset result_points(result.points.begin(), result.points.end()); + EXPECT_EQ(expected_points, result_points); + + G1 expected_msm_result = points[0] * scalars[0]; + for (size_t i = 1; i < num_points; ++i) { + expected_msm_result = expected_msm_result + points[i] * scalars[i]; + } + + G1 msm_result; + msm_result.self_set_infinity(); + size_t scalar_idx = 0; + size_t point_idx = 0; + for (auto count : result.sequence_counts) { + for (size_t i = 0; i < count; ++i) { + msm_result = msm_result + result.points[point_idx] * msm_manager.unique_scalars[scalar_idx]; + point_idx++; + } + scalar_idx++; + } + + EXPECT_EQ(msm_result, expected_msm_result); +} + +TYPED_TEST(SortedMsmTests, ReduceMsmInputsSimple) +{ + using Curve = TypeParam; + using G1 = typename Curve::AffineElement; + using Fr = typename Curve::ScalarField; + using MsmManager = SortedMsmManager; + + const size_t num_points = 10; + std::array points; + for (auto& point : points) { + point = G1::random_element(); + } + std::array sequence_counts{ 5, 2, 3 }; + std::vector scalars; + for (auto& count : sequence_counts) { + Fr repeated_scalar = Fr::random_element(); + for (size_t i = 0; i < count; ++i) { + scalars.emplace_back(repeated_scalar); + } + } + + // Randomly shuffle the scalars so duplicates are no longer grouped together + std::random_device rd; + std::shuffle(scalars.begin(), scalars.end(), std::default_random_engine(rd())); + + MsmManager msm_manager{ num_points }; + msm_manager.reduce_msm_inputs(scalars, points); + + G1 expected_msm_result = points[0] * scalars[0]; + for (size_t i = 1; i < num_points; ++i) { + expected_msm_result = expected_msm_result + points[i] * scalars[i]; + } + + auto& updated_points = msm_manager.updated_points; + auto& unique_scalars = msm_manager.unique_scalars; + G1 msm_result = updated_points[0] * unique_scalars[0]; + for (size_t i = 1; i < msm_manager.num_unique_scalars; ++i) { + msm_result = msm_result + updated_points[i] * unique_scalars[i]; + } + + EXPECT_EQ(msm_result, expected_msm_result); +} + // TYPED_TEST(ScalarMultiplicationTests, RemoveDuplicates) // { // using Curve = TypeParam; From a235afe7c28a14b68ce12338414d9fcf59c6ba81 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Thu, 4 Jul 2024 19:58:53 +0000 Subject: [PATCH 06/19] memory is owned by the class --- .../ecc/scalar_multiplication/sorted_msm.cpp | 23 ++++--------------- .../ecc/scalar_multiplication/sorted_msm.hpp | 6 ++++- .../scalar_multiplication/sorted_msm.test.cpp | 16 ++++++------- 3 files changed, 17 insertions(+), 28 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp index 69bf217cc15..0cec14ab5b6 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp @@ -18,7 +18,6 @@ SortedMsmManager::AdditionSequences SortedMsmManager::generate_add std::span points) { const size_t num_points = points.size(); - std::vector index(num_points); std::iota(index.begin(), index.end(), 0); std::sort(index.begin(), index.end(), [&](size_t idx_1, size_t idx_2) { return scalars[idx_1] < scalars[idx_2]; }); @@ -42,14 +41,14 @@ SortedMsmManager::AdditionSequences SortedMsmManager::generate_add } num_unique_scalars = seq_idx + 1; + std::span seq_counts(sequence_counts.data(), num_unique_scalars); std::span sorted_points(updated_points.data(), num_points); return AdditionSequences{ seq_counts, sorted_points, {} }; } template -void SortedMsmManager::compute_point_addition_denominators(AdditionSequences& add_sequences, - std::span denominators) +void SortedMsmManager::compute_point_addition_denominators(AdditionSequences& add_sequences) { auto points = add_sequences.points; auto sequence_counts = add_sequences.sequence_counts; @@ -60,7 +59,7 @@ void SortedMsmManager::compute_point_addition_denominators(AdditionSequen total_num_pairs += count >> 1; } - auto scratch_space = denominators; + std::span scratch_space(denominators.data(), total_num_pairs); std::vector differences; differences.resize(total_num_pairs); @@ -73,6 +72,7 @@ void SortedMsmManager::compute_point_addition_denominators(AdditionSequen const auto& x1 = points[point_idx++].x; const auto& x2 = points[point_idx++].x; + // WORKTODO: what is the risk of a collision here? ASSERT(x1 != x2); auto diff = x2 - x1; @@ -119,20 +119,7 @@ void SortedMsmManager::batched_affine_add_in_place(AdditionSequences addi return; } - std::vector denominators(num_points); - - // std::vector reserved_batch_inverse_space; - // std::span denominators; - // if (!addition_sequences.scratch_space.has_value()) { - // info("Using local scratch space."); - // reserved_batch_inverse_space.resize(num_points); // WORKTODO: num_pairs - // denominators = &reserved_batch_inverse_space[0]; - // } else { - // info("Using PROVIDED scratch space."); - // denominators = &addition_sequences.scratch_space.value()[0]; - // } - - compute_point_addition_denominators(addition_sequences, denominators); + compute_point_addition_denominators(addition_sequences); auto points = addition_sequences.points; auto sequence_counts = addition_sequences.sequence_counts; diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp index b6017a19037..0ee5dd45608 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp @@ -24,17 +24,21 @@ template class SortedMsmManager { std::vector sequence_counts; std::vector unique_scalars; std::vector updated_points; + std::vector index; + std::vector denominators; SortedMsmManager(const size_t num_scalars = 0) { sequence_counts.resize(num_scalars); unique_scalars.resize(num_scalars); updated_points.resize(num_scalars); + index.resize(num_scalars); + denominators.resize(num_scalars); } G1 affine_add_with_denominator(const G1&, const G1&, const Fq& denominator); - void compute_point_addition_denominators(AdditionSequences& add_sequences, std::span denominators); + void compute_point_addition_denominators(AdditionSequences& add_sequences); void batched_affine_add_in_place(AdditionSequences addition_sequences); diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp index 2473981f07f..4777e092b14 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp @@ -33,8 +33,6 @@ TYPED_TEST(SortedMsmTests, ComputePointAdditionDenominators) using MsmManager = SortedMsmManager; using AdditionSequences = typename MsmManager::AdditionSequences; - MsmManager msm_manager; - const size_t num_points = 5; std::array points; for (auto& point : points) { @@ -49,10 +47,12 @@ TYPED_TEST(SortedMsmTests, ComputePointAdditionDenominators) denominators_expected[0] = (points[1].x - points[0].x).invert(); denominators_expected[1] = (points[4].x - points[3].x).invert(); - std::array denominators; - msm_manager.compute_point_addition_denominators(addition_sequences, denominators); + MsmManager msm_manager(num_points); + msm_manager.compute_point_addition_denominators(addition_sequences); - for (auto [result, expected] : zip_view(denominators, denominators_expected)) { + for (size_t i = 0; i < num_pairs; ++i) { + Fq result = msm_manager.denominators[i]; + Fq expected = denominators_expected[i]; EXPECT_EQ(result, expected); } } @@ -84,8 +84,6 @@ TYPED_TEST(SortedMsmTests, BatchedAffineAddInPlaceSimple) using MsmManager = SortedMsmManager; using AdditionSequences = typename MsmManager::AdditionSequences; - MsmManager msm_manager; - const size_t num_points = 2; std::array points; for (auto& point : points) { @@ -97,6 +95,7 @@ TYPED_TEST(SortedMsmTests, BatchedAffineAddInPlaceSimple) std::array expected_points{ points[0] + points[1] }; + MsmManager msm_manager(num_points); msm_manager.batched_affine_add_in_place(addition_sequences); for (size_t idx = 0; idx < expected_points.size(); ++idx) { @@ -111,8 +110,6 @@ TYPED_TEST(SortedMsmTests, BatchedAffineAddInPlace) using MsmManager = SortedMsmManager; using AdditionSequences = typename MsmManager::AdditionSequences; - MsmManager msm_manager; - const size_t num_points = 10; std::array points; for (auto& point : points) { @@ -132,6 +129,7 @@ TYPED_TEST(SortedMsmTests, BatchedAffineAddInPlace) expected_points.emplace_back(sum); } + MsmManager msm_manager(num_points); msm_manager.batched_affine_add_in_place(addition_sequences); for (size_t idx = 0; idx < expected_points.size(); ++idx) { From 38d59ccdce29403d026e9f712fedb6dd720ebed5 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Thu, 4 Jul 2024 20:31:01 +0000 Subject: [PATCH 07/19] crs comment --- .../src/barretenberg/srs/factories/file_crs_factory.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/barretenberg/cpp/src/barretenberg/srs/factories/file_crs_factory.hpp b/barretenberg/cpp/src/barretenberg/srs/factories/file_crs_factory.hpp index 149d9794098..cf6b524d6f1 100644 --- a/barretenberg/cpp/src/barretenberg/srs/factories/file_crs_factory.hpp +++ b/barretenberg/cpp/src/barretenberg/srs/factories/file_crs_factory.hpp @@ -31,6 +31,15 @@ template class FileCrsFactory : public CrsFactory { template class FileProverCrs : public ProverCrs { public: + /** + * @brief Construct a prover CRS populated with a pippenger point table based on the SRS elements + * @details Allocates space in monomials_ for 2 * num_points affine elements, populates the first num_points with + * the raw SRS elements P_i, then overwrites the same memory with the 'pippenger point table' which contains the raw + * elements P_i at even indices and the endomorphism point (\beta * P_i.x, -P_i.y) at odd indices. + * + * @param num_points + * @param path + */ FileProverCrs(const size_t num_points, std::string const& path) : num_points(num_points) { From 9f79c442cf43ee3d57bcd4788bb8aa5ac834ba90 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Thu, 4 Jul 2024 22:39:33 +0000 Subject: [PATCH 08/19] cleanup and remove old versions of methods --- .../scalar_multiplication.cpp | 209 ------------------ .../scalar_multiplication.hpp | 22 -- .../ecc/scalar_multiplication/sorted_msm.cpp | 7 +- .../ecc/scalar_multiplication/sorted_msm.hpp | 7 +- .../scalar_multiplication/sorted_msm.test.cpp | 14 +- .../srs/scalar_multiplication.test.cpp | 162 -------------- 6 files changed, 18 insertions(+), 403 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.cpp index 2a53b3c1ab3..22e2c72f405 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.cpp @@ -1060,215 +1060,6 @@ template curve::Grumpkin::Element pippenger_without_endomorphism_basis_points& state); -template -void remove_duplicates(std::span polynomial, - std::span base_points, - pippenger_runtime_state& pippenger_runtime_state) -{ - using G1 = typename Curve::AffineElement; - using Fq = typename Curve::BaseField; - using Fr = typename Curve::ScalarField; - - size_t* index_ptr = (size_t*)(pippenger_runtime_state.point_schedule); - std::span index(index_ptr, polynomial.size()); - std::iota(index.begin(), index.end(), 0); - // "Sort" the index array according to the value in the vector of doubles - std::sort(index.begin(), index.end(), [&](size_t n1, size_t n2) { return polynomial[n1] < polynomial[n2]; }); - - // we can store input points in point_pairs_1, and our final "result points" (the points we will be performing - // an MSM over) in state.point_pairs_2 the pippenger algo will map the input point data into state.point_pairs_2 - // before performing computation - G1* mutable_base_points = pippenger_runtime_state.point_pairs_2; - - // we can store our unique polynomial data in point_pairs_1 (point_pairs is twice as large as base_points). - // Disgusting! `compute_wnaf_state` will convert the input scalars into wnafs in wnaf_state prior to - // point_pairs_1 or point_pairs_2 being used - Fr* unique_polynomial_coefficients = (Fr*)(pippenger_runtime_state.point_pairs_2 + polynomial.size()); - - // we can re-use the point schedule to store our sequence count data - uint64_t* sequence_counts = pippenger_runtime_state.point_schedule; - - unique_polynomial_coefficients[0] = polynomial[index[0]]; - // sequence_counts[index[0]] = 1; - mutable_base_points[0] = base_points[index[0]]; - std::cout << "indexes = " << index[0] << " : " << index[1] << std::endl; - std::cout << "p0, p1 = " << base_points[index[0]] << " : " << base_points[index[1]] << std::endl; - size_t count = 0; - sequence_counts[count] = 1; - for (size_t i = 1; i < polynomial.size(); ++i) { - if (polynomial[index[i]] == polynomial[index[i - 1]]) { - sequence_counts[count] += 1; - } else { - count++; - sequence_counts[count] = 1; - unique_polynomial_coefficients[count] = polynomial[index[i]]; - } - mutable_base_points[i] = base_points[index[i]]; - } - - std::span unique_points(mutable_base_points, polynomial.size()); - std::span scratch_space(pippenger_runtime_state.scratch_space, polynomial.size()); - - std::cout << "initial sequence count = " << count << std::endl; - MultipleAdditionSequences sequences{ .sequence_counts = std::span(&sequence_counts[0], count), - .points = unique_points, - .scratch_space = scratch_space }; - batched_affine_add_in_place(sequences); -} - -template -void compute_point_addition_denominators(MultipleAdditionSequences& addition_sequences, - std::span denominators) -{ - using Fq = typename Curve::BaseField; - - auto points = addition_sequences.points; - auto sequence_counts = addition_sequences.sequence_counts; - - // Count the total number of pairs across all addition sequences - size_t total_num_pairs{ 0 }; - for (auto& count : sequence_counts) { - total_num_pairs += count >> 1; - } - - auto scratch_space = denominators; - std::vector differences; - // scratch_space.resize(total_num_pairs); // can both be num_points/2 - differences.resize(total_num_pairs); - - Fq accumulator = 1; - size_t point_idx = 0; - size_t pair_idx = 0; - for (auto& count : sequence_counts) { - const size_t num_pairs = count >> 1; - for (size_t j = 0; j < num_pairs; ++j) { - const auto& x1 = points[point_idx++].x; - const auto& x2 = points[point_idx++].x; - - ASSERT(x1 != x2); - - auto diff = x2 - x1; - differences[pair_idx] = diff; - - scratch_space[pair_idx++] = accumulator; - accumulator *= diff; - } - // If number of points in the sequence is odd, we skip the last one since it has no pair - point_idx += (count & 0x01ULL); - } - - Fq inverse = accumulator.invert(); - - // Compute the point addition denominators 1/(x2 - x1) in place - for (size_t i = 0; i < total_num_pairs; ++i) { - size_t idx = total_num_pairs - 1 - i; - scratch_space[idx] *= inverse; - inverse *= differences[idx]; - } -} - -template void batched_affine_add_in_place(MultipleAdditionSequences addition_sequences) -{ - using G1 = typename Curve::AffineElement; - using Fq = typename Curve::BaseField; - const size_t num_points = addition_sequences.points.size(); - if (num_points == 0 || num_points == 1) { // nothing to do - return; - } - - std::vector denominators(num_points); - - // std::vector reserved_batch_inverse_space; - // std::span denominators; - // if (!addition_sequences.scratch_space.has_value()) { - // info("Using local scratch space."); - // reserved_batch_inverse_space.resize(num_points); // WORKTODO: num_pairs - // denominators = &reserved_batch_inverse_space[0]; - // } else { - // info("Using PROVIDED scratch space."); - // denominators = &addition_sequences.scratch_space.value()[0]; - // } - - scalar_multiplication::compute_point_addition_denominators(addition_sequences, denominators); - - auto points = addition_sequences.points; - auto sequence_counts = addition_sequences.sequence_counts; - - size_t point_idx = 0; - size_t result_point_idx = 0; - size_t pair_idx = 0; - bool more_additions = false; - for (auto& count : sequence_counts) { - const size_t num_pairs = count >> 1; - const bool overflow = static_cast(count & 0x01ULL); - // Compute the sum of all pairs in the sequence and store the result in the points array - for (size_t j = 0; j < num_pairs; ++j) { - const auto& point_1 = points[point_idx++]; // first summand - const auto& point_2 = points[point_idx++]; // second summand - const auto& denominator = denominators[pair_idx++]; // denominator needed in add formula - auto& result = points[result_point_idx++]; // target for addition result - - result = scalar_multiplication::affine_add_with_denominator(point_1, point_2, denominator); - } - if (overflow) { - points[result_point_idx++] = points[point_idx++]; - } - const uint64_t updated_sequence_count = static_cast(num_pairs) + static_cast(overflow); - count = updated_sequence_count; - - more_additions = more_additions || (updated_sequence_count > 1); - } - - if (more_additions) { - const size_t updated_point_count = result_point_idx; - std::span updated_points(&points[0], updated_point_count); - return batched_affine_add_in_place( - MultipleAdditionSequences{ sequence_counts, updated_points, addition_sequences.scratch_space }); - } -} - -template -typename Curve::AffineElement affine_add_with_denominator(const typename Curve::AffineElement& point_1, - const typename Curve::AffineElement& point_2, - const typename Curve::BaseField& denominator) -{ - using Fq = typename Curve::BaseField; - - const auto& x1 = point_1.x; - const auto& y1 = point_1.y; - const auto& x2 = point_2.x; - const auto& y2 = point_2.y; - - const Fq lambda = denominator * (y2 - y1); - Fq x3 = lambda.sqr() - x2 - x1; - Fq y3 = lambda * (x1 - x3) - y1; - return { x3, y3 }; -} - -template curve::Grumpkin::AffineElement affine_add_with_denominator( - const curve::Grumpkin::AffineElement&, const curve::Grumpkin::AffineElement&, const curve::Grumpkin::BaseField&); -template curve::BN254::AffineElement affine_add_with_denominator(const curve::BN254::AffineElement&, - const curve::BN254::AffineElement&, - const curve::BN254::BaseField&); - -template void batched_affine_add_in_place( - MultipleAdditionSequences addition_sequences); -template void batched_affine_add_in_place(MultipleAdditionSequences addition_sequences); - -template void compute_point_addition_denominators( - MultipleAdditionSequences& addition_sequences, std::span denominators); - -template void compute_point_addition_denominators( - MultipleAdditionSequences& addition_sequences, std::span denominators); - -template void remove_duplicates(std::span polynomial, - std::span base_points, - pippenger_runtime_state& state); - -template void remove_duplicates(std::span polynomial, - std::span base_points, - pippenger_runtime_state& state); - } // namespace bb::scalar_multiplication // NOLINTEND(cppcoreguidelines-avoid-c-arrays, google-readability-casting) diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp index d6c81cea7d3..c93b602bfe1 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp @@ -170,28 +170,6 @@ typename Curve::Element pippenger_without_endomorphism_basis_points(typename Cur size_t num_initial_points, pippenger_runtime_state& state); -template struct MultipleAdditionSequences { - std::span sequence_counts; - std::span points; - std::optional> scratch_space; -}; - -template void batched_affine_add_in_place(MultipleAdditionSequences addition_sequences); - -template -typename Curve::AffineElement affine_add_with_denominator(const typename Curve::AffineElement&, - const typename Curve::AffineElement&, - const typename Curve::BaseField& denominator); - -template -void remove_duplicates(std::span polynomial, - std::span base_points, - pippenger_runtime_state& pippenger_runtime_state); - -template -void compute_point_addition_denominators(MultipleAdditionSequences& add_sequences, - std::span denominators); - // Explicit instantiation // BN254 diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp index 0cec14ab5b6..19672929388 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp @@ -2,7 +2,9 @@ namespace bb { -template void SortedMsmManager::reduce_msm_inputs(std::span scalars, std::span points) +template +SortedMsmManager::ReducedMsmInputs SortedMsmManager::reduce_msm_inputs(std::span scalars, + std::span points) { // generate the addition sequences AdditionSequences addition_sequences = generate_addition_sequences(scalars, points); @@ -11,6 +13,9 @@ template void SortedMsmManager::reduce_msm_inputs(std::s batched_affine_add_in_place(addition_sequences); // the reduced inputs are the unique scalrs and the reduced points + std::span output_scalars(unique_scalars.data(), num_unique_scalars); + std::span output_points(updated_points.data(), num_unique_scalars); + return { output_scalars, output_points }; } template diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp index 0ee5dd45608..32edc126413 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp @@ -20,6 +20,11 @@ template class SortedMsmManager { std::optional> scratch_space; }; + struct ReducedMsmInputs { + std::span scalars; + std::span points; + }; + size_t num_unique_scalars = 0; std::vector sequence_counts; std::vector unique_scalars; @@ -44,7 +49,7 @@ template class SortedMsmManager { AdditionSequences generate_addition_sequences(std::span scalars, std::span points); - void reduce_msm_inputs(std::span scalars, std::span points); + ReducedMsmInputs reduce_msm_inputs(std::span scalars, std::span points); }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp index 4777e092b14..9deaa99b626 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp @@ -223,19 +223,17 @@ TYPED_TEST(SortedMsmTests, ReduceMsmInputsSimple) std::random_device rd; std::shuffle(scalars.begin(), scalars.end(), std::default_random_engine(rd())); - MsmManager msm_manager{ num_points }; - msm_manager.reduce_msm_inputs(scalars, points); - G1 expected_msm_result = points[0] * scalars[0]; for (size_t i = 1; i < num_points; ++i) { expected_msm_result = expected_msm_result + points[i] * scalars[i]; } - auto& updated_points = msm_manager.updated_points; - auto& unique_scalars = msm_manager.unique_scalars; - G1 msm_result = updated_points[0] * unique_scalars[0]; - for (size_t i = 1; i < msm_manager.num_unique_scalars; ++i) { - msm_result = msm_result + updated_points[i] * unique_scalars[i]; + MsmManager msm_manager{ num_points }; + auto [result_scalars, result_points] = msm_manager.reduce_msm_inputs(scalars, points); + + G1 msm_result = result_points[0] * result_scalars[0]; + for (size_t i = 1; i < result_points.size(); ++i) { + msm_result = msm_result + result_points[i] * result_scalars[i]; } EXPECT_EQ(msm_result, expected_msm_result); diff --git a/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp b/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp index 621dbab0d43..d9b7195f921 100644 --- a/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp +++ b/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp @@ -248,168 +248,6 @@ TYPED_TEST(ScalarMultiplicationTests, ReduceBucketsSimple) } } -TYPED_TEST(ScalarMultiplicationTests, ComputePointAdditionDenominators) -{ - using Curve = TypeParam; - using Element = typename Curve::Element; - using AffineElement = typename Curve::AffineElement; - using Fq = typename Curve::BaseField; - - const size_t num_points = 5; - std::array points; - for (auto& point : points) { - point = Element::random_element(); - } - std::array sequence_counts{ 3, 2 }; - - scalar_multiplication::MultipleAdditionSequences addition_sequences{ sequence_counts, points, {} }; - - const size_t num_pairs = 2; - std::array denominators_expected; - denominators_expected[0] = (points[1].x - points[0].x).invert(); - denominators_expected[1] = (points[4].x - points[3].x).invert(); - - std::array denominators; - scalar_multiplication::compute_point_addition_denominators(addition_sequences, denominators); - - for (auto [result, expected] : zip_view(denominators, denominators_expected)) { - EXPECT_EQ(result, expected); - } -} - -TYPED_TEST(ScalarMultiplicationTests, AffineAddWithDenominator) -{ - using Curve = TypeParam; - using Element = typename Curve::Element; - using AffineElement = typename Curve::AffineElement; - using Fq = typename Curve::BaseField; - - AffineElement point_1 = Element::random_element(); - AffineElement point_2 = Element::random_element(); - Fq denominator = (point_2.x - point_1.x).invert(); - - AffineElement expected = point_1 + point_2; - - AffineElement result = scalar_multiplication::affine_add_with_denominator(point_1, point_2, denominator); - - EXPECT_EQ(result, expected); -} - -TYPED_TEST(ScalarMultiplicationTests, BatchedAffineAddInPlaceSimple) -{ - using Curve = TypeParam; - using Element = typename Curve::Element; - using AffineElement = typename Curve::AffineElement; - - const size_t num_points = 2; - std::array points; - for (auto& point : points) { - point = Element::random_element(); - } - std::array sequence_counts{ 2 }; - - scalar_multiplication::MultipleAdditionSequences addition_sequences{ sequence_counts, points, {} }; - - std::array expected_points{ points[0] + points[1] }; - - scalar_multiplication::batched_affine_add_in_place(addition_sequences); - - for (size_t idx = 0; idx < expected_points.size(); ++idx) { - // info("expected = ", expected_points[idx]); - // info("result = ", points[idx]); - EXPECT_EQ(expected_points[idx], points[idx]); - } -} - -TYPED_TEST(ScalarMultiplicationTests, BatchedAffineAddInPlace) -{ - using Curve = TypeParam; - using Element = typename Curve::Element; - using G1 = typename Curve::AffineElement; - - const size_t num_points = 10; - std::array points; - for (auto& point : points) { - point = Element::random_element(); - } - std::array sequence_counts{ 5, 2, 3 }; - - scalar_multiplication::MultipleAdditionSequences addition_sequences{ sequence_counts, points, {} }; - - std::vector expected_points; - size_t point_idx = 0; - for (auto count : sequence_counts) { - G1 sum = points[point_idx++]; - for (size_t i = 1; i < count; ++i) { - sum = sum + points[point_idx++]; - } - expected_points.emplace_back(sum); - } - - scalar_multiplication::batched_affine_add_in_place(addition_sequences); - - for (size_t idx = 0; idx < expected_points.size(); ++idx) { - // info("expected = ", expected_points[idx]); - // info("result = ", points[idx]); - EXPECT_EQ(expected_points[idx], points[idx]); - } -} - -TYPED_TEST(ScalarMultiplicationTests, RemoveDuplicates) -{ - using Curve = TypeParam; - using Element = typename Curve::Element; - using AffineElement = typename Curve::AffineElement; - using Fr = typename Curve::ScalarField; - - constexpr size_t num_points = 8192; - - Fr* scalars = (Fr*)aligned_alloc(32, sizeof(Fr) * num_points); - - AffineElement* points = (AffineElement*)aligned_alloc(32, sizeof(AffineElement) * (num_points * 2 + 1)); - - std::vector expected; - bool filling_scalars = true; - size_t num_filled_scalars = 0; - while (filling_scalars) { - size_t num_identical_scalars = static_cast(engine.get_random_uint64()) % 32 + 1; - if (num_filled_scalars + num_identical_scalars > num_points) { - num_identical_scalars = num_points - num_filled_scalars; - } - auto scalar = Fr::random_element(); - Element accumulator; - accumulator.self_set_infinity(); - for (size_t i = 0; i < num_identical_scalars; ++i) { - Element point = Element::random_element(); - scalars[num_filled_scalars + i] = scalar; - points[num_filled_scalars + i] = point; - accumulator += point; - } - expected.push_back(accumulator); - num_filled_scalars += num_identical_scalars; - if (num_filled_scalars == num_points) { - filling_scalars = false; - } - } - - // for (size_t i = 0; i < num_points; ++i) { - // scalars[i] = Fr::random_element(); - // points[i] = AffineElement(Element::random_element()); - // } - - scalar_multiplication::generate_pippenger_point_table(points, points, num_points); - scalar_multiplication::pippenger_runtime_state state(num_points); - - scalar_multiplication::remove_duplicates( - std::span(scalars, num_points), std::span(points, num_points), state); - - AffineElement* result = state.point_pairs_2; - - for (size_t i = 0; i < expected.size(); ++i) { - EXPECT_EQ(result[i], expected[i]); - } -} - TYPED_TEST(ScalarMultiplicationTests, ReduceBuckets) { using Curve = TypeParam; From 584df9d01c8b82d90822fa919554f6a339f32738 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Thu, 4 Jul 2024 22:49:18 +0000 Subject: [PATCH 09/19] cleanup --- .../commitment_schemes/commitment_key.hpp | 32 +------------------ .../srs/scalar_multiplication.test.cpp | 4 +-- .../stdlib/encryption/aes128/aes128.test.cpp | 5 +-- 3 files changed, 3 insertions(+), 38 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/commitment_key.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/commitment_key.hpp index ef0a259ebf6..934b6dae9de 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/commitment_key.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/commitment_key.hpp @@ -18,8 +18,8 @@ #include #include -#include #include + namespace bb { /** @@ -33,7 +33,6 @@ namespace bb { template class CommitmentKey { using Fr = typename Curve::ScalarField; - using Fq = typename Curve::BaseField; using Commitment = typename Curve::AffineElement; public: @@ -76,35 +75,6 @@ template class CommitmentKey { return scalar_multiplication::pippenger_unsafe( const_cast(polynomial.data()), srs->get_monomial_points(), degree, pippenger_runtime_state); }; - - using G1 = typename Curve::AffineElement; - struct AddGroup { - G1* source; - G1* destination_origin; - size_t num_points; - }; - - struct AffineAddTemporaries { - Fq lambda_denominator_accumulator; - Fq lambda_numerator; - }; - - // void parallel_add_4( - // const MultipleAdditionSequences addition_sequences, Fq* scratch_space, G1* result - // ) - // { - // // const auto& num_independent_additions = addition_sequences.num_independent_additions; - // auto& sequence_counts = addition_sequences.sequence_counts; - - // const size_t num_independent_additions = 0; - // if (!addition_sequences.num_independent_additions.has_value()) - // { - // for (auto& num : sequence_counts) - // { - // num_independent_additions += (num >> 1);n - // } - // } - // } }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp b/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp index d9b7195f921..d66641157a5 100644 --- a/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp +++ b/barretenberg/cpp/src/barretenberg/srs/scalar_multiplication.test.cpp @@ -12,7 +12,6 @@ #include "barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp" #include "barretenberg/common/mem.hpp" #include "barretenberg/common/test.hpp" -#include "barretenberg/common/zip_view.hpp" #include "barretenberg/ecc/scalar_multiplication/point_table.hpp" #include "barretenberg/numeric/random/engine.hpp" #include "barretenberg/srs/factories/file_crs_factory.hpp" @@ -572,8 +571,7 @@ TYPED_TEST(ScalarMultiplicationTests, EndomorphismSplit) Element expected = Group::one * scalar; - // we want to test that we can split a scalar into two half-length components, using the same location in - // memory. + // we want to test that we can split a scalar into two half-length components, using the same location in memory. Fr* k1_t = &scalar; Fr* k2_t = (Fr*)&scalar.data[2]; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/encryption/aes128/aes128.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/encryption/aes128/aes128.test.cpp index f256f54085b..90959ee9ccc 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/encryption/aes128/aes128.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/encryption/aes128/aes128.test.cpp @@ -49,10 +49,7 @@ TEST(stdlib_aes128, encrypt_64_bytes) }; const auto result = stdlib::aes128::encrypt_buffer_cbc(in_field, iv_field, key_field); - stdlib::aes128::encrypt_buffer_cbc(in_field, iv_field, key_field); - stdlib::aes128::encrypt_buffer_cbc(in_field, iv_field, key_field); - // 4229 - // 12685 + for (size_t i = 0; i < 4; ++i) { EXPECT_EQ(result[i].get_value(), expected[i]); } From ced9f7913c95be196d78240669a8798f3d0eca9f Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Fri, 5 Jul 2024 19:24:44 +0000 Subject: [PATCH 10/19] comments and naming --- .../ecc/scalar_multiplication/sorted_msm.cpp | 74 ++++++++++++++++--- .../ecc/scalar_multiplication/sorted_msm.hpp | 4 +- .../scalar_multiplication/sorted_msm.test.cpp | 4 +- 3 files changed, 67 insertions(+), 15 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp index 19672929388..b9ed26c4074 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp @@ -7,7 +7,7 @@ SortedMsmManager::ReducedMsmInputs SortedMsmManager::reduce_msm_in std::span points) { // generate the addition sequences - AdditionSequences addition_sequences = generate_addition_sequences(scalars, points); + AdditionSequences addition_sequences = construct_addition_sequences(scalars, points); // call batched affine add in place until the sequences have been fully reduced batched_affine_add_in_place(addition_sequences); @@ -18,14 +18,25 @@ SortedMsmManager::ReducedMsmInputs SortedMsmManager::reduce_msm_in return { output_scalars, output_points }; } +/** + * @brief Sort the MSM points by scalar so that points sharing a scalar can be summed prior to performing MSM + * + * @tparam Curve + * @param scalars + * @param points + * @return SortedMsmManager::AdditionSequences + */ template -SortedMsmManager::AdditionSequences SortedMsmManager::generate_addition_sequences(std::span scalars, - std::span points) +SortedMsmManager::AdditionSequences SortedMsmManager::construct_addition_sequences(std::span scalars, + std::span points) { + // Create the array containing the indices of the scalars and points sorted by scalar value const size_t num_points = points.size(); std::iota(index.begin(), index.end(), 0); std::sort(index.begin(), index.end(), [&](size_t idx_1, size_t idx_2) { return scalars[idx_1] < scalars[idx_2]; }); + // Store the unique scalar values, the input points sorted by scalar value, and the number of occurences of each + // unique scalar (i.e. the size of each addition sequence) unique_scalars[0] = scalars[index[0]]; updated_points[0] = points[index[0]]; size_t seq_idx = 0; @@ -34,9 +45,10 @@ SortedMsmManager::AdditionSequences SortedMsmManager::generate_add const Fr& current_scalar = scalars[index[i]]; const Fr& prev_scalar = scalars[index[i - 1]]; + // if the current scalar matches the previous, increment the count for this sequence if (current_scalar == prev_scalar) { sequence_counts[seq_idx]++; - } else { + } else { // otherwise, a new sequence begins seq_idx++; sequence_counts[seq_idx]++; unique_scalars[seq_idx] = current_scalar; @@ -47,18 +59,27 @@ SortedMsmManager::AdditionSequences SortedMsmManager::generate_add num_unique_scalars = seq_idx + 1; + // Return the sorted points and the counts for each addition sequence std::span seq_counts(sequence_counts.data(), num_unique_scalars); std::span sorted_points(updated_points.data(), num_points); return AdditionSequences{ seq_counts, sorted_points, {} }; } +/** + * @brief Batch compute inverses needed for a set of point addition sequences + * @details Addition of points P_1, P_2 requires computation of a term of the form 1/(P_2.x - P_1.x). For efficiency, + * these terms are computed all at once for a full set of addition sequences using batch inversion. + * + * @tparam Curve + * @param add_sequences + */ template -void SortedMsmManager::compute_point_addition_denominators(AdditionSequences& add_sequences) +void SortedMsmManager::batch_compute_point_addition_slope_inverses(AdditionSequences& add_sequences) { auto points = add_sequences.points; auto sequence_counts = add_sequences.sequence_counts; - // Count the total number of pairs across all addition sequences + // Count the total number of point pairs to be added across all addition sequences size_t total_num_pairs{ 0 }; for (auto& count : sequence_counts) { total_num_pairs += count >> 1; @@ -68,6 +89,7 @@ void SortedMsmManager::compute_point_addition_denominators(AdditionSequen std::vector differences; differences.resize(total_num_pairs); + // Compute and store successive products of differences (x_2 - x_1) Fq accumulator = 1; size_t point_idx = 0; size_t pair_idx = 0; @@ -90,9 +112,10 @@ void SortedMsmManager::compute_point_addition_denominators(AdditionSequen point_idx += (count & 0x01ULL); } + // Invert the full product of differences Fq inverse = accumulator.invert(); - // Compute the point addition denominators 1/(x2 - x1) in place + // Compute the individual point-pair addition denominators 1/(x2 - x1) for (size_t i = 0; i < total_num_pairs; ++i) { size_t idx = total_num_pairs - 1 - i; scratch_space[idx] *= inverse; @@ -100,6 +123,18 @@ void SortedMsmManager::compute_point_addition_denominators(AdditionSequen } } +/** + * @brief Add two affine elements with the inverse in the slope term \lambda provided as input + * @details The sum of two points (x1, y1), (x2, y2) is given by x3 = \lambda^2 - x1 - x2, y3 = \lambda*(x1 - x3) - y1, + * where \lambda = (y2 - y1)/(x2 - x1). When performing many additions at once, it is more efficient to batch compute + * the inverse component of \lambda for each pair of points. This gives rise to the need for a method like this one. + * + * @tparam Curve + * @param point_1 (x1, y1) + * @param point_2 (x2, y2) + * @param denominator 1/(x2 - x1) + * @return Curve::AffineElement + */ template typename Curve::AffineElement SortedMsmManager::affine_add_with_denominator(const G1& point_1, const G1& point_2, @@ -116,6 +151,17 @@ typename Curve::AffineElement SortedMsmManager::affine_add_with_denominat return { x3, y3 }; } +/** + * @brief In-place summation to reduce a set of addition sequences to a single point for each sequence + * @details At each round, the set of points in each addition sequence is roughly halved by performing pairwise + * additions. For sequences with odd length, the unpaired point is simply carried over to the next round. For + * efficiency, the inverses needed in the point addition slope \lambda are batch computed for the full set of pairwise + * additions in each round. The method is called recursively until the sequences have all been reduced to a single + * point. + * + * @tparam Curve + * @param addition_sequences Set of points and counts indicating number of points in each addition chain + */ template void SortedMsmManager::batched_affine_add_in_place(AdditionSequences addition_sequences) { @@ -124,14 +170,15 @@ void SortedMsmManager::batched_affine_add_in_place(AdditionSequences addi return; } - compute_point_addition_denominators(addition_sequences); + // Batch compute terms of the form 1/(x2 -x1) for each pair to be added in this round + batch_compute_point_addition_slope_inverses(addition_sequences); auto points = addition_sequences.points; auto sequence_counts = addition_sequences.sequence_counts; - size_t point_idx = 0; - size_t result_point_idx = 0; - size_t pair_idx = 0; + size_t point_idx = 0; // index for points to be summed + size_t result_point_idx = 0; // index for result points + size_t pair_idx = 0; // index into array of denominators for each pair bool more_additions = false; for (auto& count : sequence_counts) { const size_t num_pairs = count >> 1; @@ -145,15 +192,20 @@ void SortedMsmManager::batched_affine_add_in_place(AdditionSequences addi result = affine_add_with_denominator(point_1, point_2, denominator); } + // If the sequence had an odd number of points, simply maintain the unpaired point in the sequence if (overflow) { points[result_point_idx++] = points[point_idx++]; } + + // Update the sequence counts in place for the next round const uint64_t updated_sequence_count = static_cast(num_pairs) + static_cast(overflow); count = updated_sequence_count; + // More additions are required if any sequence has not yet been reduced to a single point more_additions = more_additions || (updated_sequence_count > 1); } + // Recursively perform additions until all sequences have been reduced to a single point if (more_additions) { const size_t updated_point_count = result_point_idx; std::span updated_points(&points[0], updated_point_count); diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp index 32edc126413..462a7faf050 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp @@ -43,11 +43,11 @@ template class SortedMsmManager { G1 affine_add_with_denominator(const G1&, const G1&, const Fq& denominator); - void compute_point_addition_denominators(AdditionSequences& add_sequences); + void batch_compute_point_addition_slope_inverses(AdditionSequences& add_sequences); void batched_affine_add_in_place(AdditionSequences addition_sequences); - AdditionSequences generate_addition_sequences(std::span scalars, std::span points); + AdditionSequences construct_addition_sequences(std::span scalars, std::span points); ReducedMsmInputs reduce_msm_inputs(std::span scalars, std::span points); }; diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp index 9deaa99b626..83e9529a73b 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp @@ -48,7 +48,7 @@ TYPED_TEST(SortedMsmTests, ComputePointAdditionDenominators) denominators_expected[1] = (points[4].x - points[3].x).invert(); MsmManager msm_manager(num_points); - msm_manager.compute_point_addition_denominators(addition_sequences); + msm_manager.batch_compute_point_addition_slope_inverses(addition_sequences); for (size_t i = 0; i < num_pairs; ++i) { Fq result = msm_manager.denominators[i]; @@ -166,7 +166,7 @@ TYPED_TEST(SortedMsmTests, GenerateAdditionSequences) std::shuffle(scalars.begin(), scalars.end(), std::default_random_engine(rd())); MsmManager msm_manager{ num_points }; - AdditionSequences result = msm_manager.generate_addition_sequences(scalars, points); + AdditionSequences result = msm_manager.construct_addition_sequences(scalars, points); // The resulting sequence counts should match expectation but only as multisets std::multiset expected_sequence_counts(sequence_counts.begin(), sequence_counts.end()); From 2ecea89a6828b0877662907d14d50b2daf60f234 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Fri, 5 Jul 2024 19:54:55 +0000 Subject: [PATCH 11/19] test simplification --- .../scalar_multiplication/sorted_msm.test.cpp | 146 +++++++++--------- 1 file changed, 72 insertions(+), 74 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp index 83e9529a73b..46cd915b430 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp @@ -19,28 +19,81 @@ auto& engine = numeric::get_debug_randomness(); template class SortedMsmTests : public ::testing::Test { public: + using G1 = typename Curve::AffineElement; + using Fr = typename Curve::ScalarField; + // using Fq = typename Curve::BaseField; + + struct TestData { + size_t num_points; + std::vector points; + std::vector scalars; + G1 msm_result; + }; + + TestData generate_test_data_from_sequence_counts(std::span sequence_counts) + { + size_t num_points{ 0 }; + std::vector scalars; + for (auto& count : sequence_counts) { + Fr repeated_scalar = Fr::random_element(); + for (size_t i = 0; i < count; ++i) { + scalars.emplace_back(repeated_scalar); + num_points++; + } + } + + std::vector points; + for (size_t i = 0; i < num_points; ++i) { + points.emplace_back(G1::random_element()); + } + + G1 msm_result = points[0] * scalars[0]; + for (size_t i = 1; i < num_points; ++i) { + msm_result = msm_result + points[i] * scalars[i]; + } + + return { num_points, points, scalars, msm_result }; + } }; using Curves = ::testing::Types; TYPED_TEST_SUITE(SortedMsmTests, Curves); -TYPED_TEST(SortedMsmTests, ComputePointAdditionDenominators) +TYPED_TEST(SortedMsmTests, AffineAddWithDenominator) { using Curve = TypeParam; using G1 = typename Curve::AffineElement; using Fq = typename Curve::BaseField; using MsmManager = SortedMsmManager; + + MsmManager msm_manager; + + G1 point_1 = G1::random_element(); + G1 point_2 = G1::random_element(); + Fq denominator = (point_2.x - point_1.x).invert(); + + G1 expected = point_1 + point_2; + + G1 result = msm_manager.affine_add_with_denominator(point_1, point_2, denominator); + + EXPECT_EQ(result, expected); +} + +TYPED_TEST(SortedMsmTests, ComputePointAdditionDenominators) +{ + using Curve = TypeParam; + using Fq = typename Curve::BaseField; + using MsmManager = SortedMsmManager; using AdditionSequences = typename MsmManager::AdditionSequences; - const size_t num_points = 5; - std::array points; - for (auto& point : points) { - point = G1::random_element(); - } + // Generate random MSM inputs based on a set of sequence counts std::array sequence_counts{ 3, 2 }; + auto test_data = TestFixture::generate_test_data_from_sequence_counts(sequence_counts); + size_t num_points = test_data.num_points; + auto& points = test_data.points; - AdditionSequences addition_sequences{ sequence_counts, points, {} }; + AdditionSequences addition_sequences{ sequence_counts, test_data.points, {} }; const size_t num_pairs = 2; std::array denominators_expected; @@ -57,26 +110,6 @@ TYPED_TEST(SortedMsmTests, ComputePointAdditionDenominators) } } -TYPED_TEST(SortedMsmTests, AffineAddWithDenominator) -{ - using Curve = TypeParam; - using G1 = typename Curve::AffineElement; - using Fq = typename Curve::BaseField; - using MsmManager = SortedMsmManager; - - MsmManager msm_manager; - - G1 point_1 = G1::random_element(); - G1 point_2 = G1::random_element(); - Fq denominator = (point_2.x - point_1.x).invert(); - - G1 expected = point_1 + point_2; - - G1 result = msm_manager.affine_add_with_denominator(point_1, point_2, denominator); - - EXPECT_EQ(result, expected); -} - TYPED_TEST(SortedMsmTests, BatchedAffineAddInPlaceSimple) { using Curve = TypeParam; @@ -84,12 +117,10 @@ TYPED_TEST(SortedMsmTests, BatchedAffineAddInPlaceSimple) using MsmManager = SortedMsmManager; using AdditionSequences = typename MsmManager::AdditionSequences; - const size_t num_points = 2; - std::array points; - for (auto& point : points) { - point = G1::random_element(); - } + // Generate random MSM inputs based on a set of sequence counts std::array sequence_counts{ 2 }; + auto [num_points, points, scalars, msm_result] = + TestFixture::generate_test_data_from_sequence_counts(sequence_counts); AdditionSequences addition_sequences{ sequence_counts, points, {} }; @@ -110,12 +141,10 @@ TYPED_TEST(SortedMsmTests, BatchedAffineAddInPlace) using MsmManager = SortedMsmManager; using AdditionSequences = typename MsmManager::AdditionSequences; - const size_t num_points = 10; - std::array points; - for (auto& point : points) { - point = G1::random_element(); - } + // Generate random MSM inputs based on a set of sequence counts std::array sequence_counts{ 5, 2, 3 }; + auto [num_points, points, scalars, msm_result] = + TestFixture::generate_test_data_from_sequence_counts(sequence_counts); AdditionSequences addition_sequences{ sequence_counts, points, {} }; @@ -145,21 +174,10 @@ TYPED_TEST(SortedMsmTests, GenerateAdditionSequences) using MsmManager = SortedMsmManager; using AdditionSequences = typename MsmManager::AdditionSequences; - const size_t num_points = 10; - std::array points; - for (auto& point : points) { - point = G1::random_element(); - } + // Generate random MSM inputs based on a set of sequence counts std::array sequence_counts{ 5, 2, 3 }; - std::vector scalars; - std::vector unique_scalars; - for (auto& count : sequence_counts) { - Fr repeated_scalar = Fr::random_element(); - for (size_t i = 0; i < count; ++i) { - scalars.emplace_back(repeated_scalar); - } - unique_scalars.emplace_back(repeated_scalar); - } + auto [num_points, points, scalars, expected_msm_result] = + TestFixture::generate_test_data_from_sequence_counts(sequence_counts); // Randomly shuffle the scalars so duplicates are no longer grouped together std::random_device rd; @@ -178,11 +196,6 @@ TYPED_TEST(SortedMsmTests, GenerateAdditionSequences) std::multiset result_points(result.points.begin(), result.points.end()); EXPECT_EQ(expected_points, result_points); - G1 expected_msm_result = points[0] * scalars[0]; - for (size_t i = 1; i < num_points; ++i) { - expected_msm_result = expected_msm_result + points[i] * scalars[i]; - } - G1 msm_result; msm_result.self_set_infinity(); size_t scalar_idx = 0; @@ -202,32 +215,17 @@ TYPED_TEST(SortedMsmTests, ReduceMsmInputsSimple) { using Curve = TypeParam; using G1 = typename Curve::AffineElement; - using Fr = typename Curve::ScalarField; using MsmManager = SortedMsmManager; - const size_t num_points = 10; - std::array points; - for (auto& point : points) { - point = G1::random_element(); - } + // Generate random MSM inputs based on a set of sequence counts std::array sequence_counts{ 5, 2, 3 }; - std::vector scalars; - for (auto& count : sequence_counts) { - Fr repeated_scalar = Fr::random_element(); - for (size_t i = 0; i < count; ++i) { - scalars.emplace_back(repeated_scalar); - } - } + auto [num_points, points, scalars, expected_msm_result] = + TestFixture::generate_test_data_from_sequence_counts(sequence_counts); // Randomly shuffle the scalars so duplicates are no longer grouped together std::random_device rd; std::shuffle(scalars.begin(), scalars.end(), std::default_random_engine(rd())); - G1 expected_msm_result = points[0] * scalars[0]; - for (size_t i = 1; i < num_points; ++i) { - expected_msm_result = expected_msm_result + points[i] * scalars[i]; - } - MsmManager msm_manager{ num_points }; auto [result_scalars, result_points] = msm_manager.reduce_msm_inputs(scalars, points); From 1772b64a3717b540e1e855b95e2c96f5d6b52793 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Fri, 5 Jul 2024 22:32:52 +0000 Subject: [PATCH 12/19] larger test --- .../scalar_multiplication/sorted_msm.test.cpp | 127 ++++++------------ 1 file changed, 41 insertions(+), 86 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp index 46cd915b430..fa345c57aed 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp @@ -30,8 +30,18 @@ template class SortedMsmTests : public ::testing::Test { G1 msm_result; }; + /** + * @brief Generate a set of random points and scalars based on an input sequence_counts + * @details E.g. given sequence counts {7, 2, 9}, generate a set of random points an scalars with only 3 unique + * scalar values repeated according to the sequence counts. Also compute the result of the corresponding MSM for + * test comparisons. + * + * @param sequence_counts + * @return TestData + */ TestData generate_test_data_from_sequence_counts(std::span sequence_counts) { + // Generate duplicate scalars corresponding to the sequence counts size_t num_points{ 0 }; std::vector scalars; for (auto& count : sequence_counts) { @@ -42,11 +52,17 @@ template class SortedMsmTests : public ::testing::Test { } } + // Randomly shuffle the scalars so duplicates are no longer grouped together + std::random_device rd; + std::shuffle(scalars.begin(), scalars.end(), std::default_random_engine(rd())); + + // Randomly generate as many points as scalars std::vector points; for (size_t i = 0; i < num_points; ++i) { points.emplace_back(G1::random_element()); } + // Compute the result of the MSM G1 msm_result = points[0] * scalars[0]; for (size_t i = 1; i < num_points; ++i) { msm_result = msm_result + points[i] * scalars[i]; @@ -60,6 +76,7 @@ using Curves = ::testing::Types; TYPED_TEST_SUITE(SortedMsmTests, Curves); +// Test method for a single affine addition with provided slope denominator TYPED_TEST(SortedMsmTests, AffineAddWithDenominator) { using Curve = TypeParam; @@ -80,6 +97,7 @@ TYPED_TEST(SortedMsmTests, AffineAddWithDenominator) EXPECT_EQ(result, expected); } +// Test method for batch computing slope denominators for a set of point addition sequences TYPED_TEST(SortedMsmTests, ComputePointAdditionDenominators) { using Curve = TypeParam; @@ -110,30 +128,7 @@ TYPED_TEST(SortedMsmTests, ComputePointAdditionDenominators) } } -TYPED_TEST(SortedMsmTests, BatchedAffineAddInPlaceSimple) -{ - using Curve = TypeParam; - using G1 = typename Curve::AffineElement; - using MsmManager = SortedMsmManager; - using AdditionSequences = typename MsmManager::AdditionSequences; - - // Generate random MSM inputs based on a set of sequence counts - std::array sequence_counts{ 2 }; - auto [num_points, points, scalars, msm_result] = - TestFixture::generate_test_data_from_sequence_counts(sequence_counts); - - AdditionSequences addition_sequences{ sequence_counts, points, {} }; - - std::array expected_points{ points[0] + points[1] }; - - MsmManager msm_manager(num_points); - msm_manager.batched_affine_add_in_place(addition_sequences); - - for (size_t idx = 0; idx < expected_points.size(); ++idx) { - EXPECT_EQ(expected_points[idx], points[idx]); - } -} - +// Test method for batched addition of point addition sequences in place TYPED_TEST(SortedMsmTests, BatchedAffineAddInPlace) { using Curve = TypeParam; @@ -166,6 +161,7 @@ TYPED_TEST(SortedMsmTests, BatchedAffineAddInPlace) } } +// Test generation of point addition sequences from an arbitrary set of points and scalars TYPED_TEST(SortedMsmTests, GenerateAdditionSequences) { using Curve = TypeParam; @@ -179,10 +175,6 @@ TYPED_TEST(SortedMsmTests, GenerateAdditionSequences) auto [num_points, points, scalars, expected_msm_result] = TestFixture::generate_test_data_from_sequence_counts(sequence_counts); - // Randomly shuffle the scalars so duplicates are no longer grouped together - std::random_device rd; - std::shuffle(scalars.begin(), scalars.end(), std::default_random_engine(rd())); - MsmManager msm_manager{ num_points }; AdditionSequences result = msm_manager.construct_addition_sequences(scalars, points); @@ -222,10 +214,6 @@ TYPED_TEST(SortedMsmTests, ReduceMsmInputsSimple) auto [num_points, points, scalars, expected_msm_result] = TestFixture::generate_test_data_from_sequence_counts(sequence_counts); - // Randomly shuffle the scalars so duplicates are no longer grouped together - std::random_device rd; - std::shuffle(scalars.begin(), scalars.end(), std::default_random_engine(rd())); - MsmManager msm_manager{ num_points }; auto [result_scalars, result_points] = msm_manager.reduce_msm_inputs(scalars, points); @@ -237,57 +225,24 @@ TYPED_TEST(SortedMsmTests, ReduceMsmInputsSimple) EXPECT_EQ(msm_result, expected_msm_result); } -// TYPED_TEST(ScalarMultiplicationTests, RemoveDuplicates) -// { -// using Curve = TypeParam; -// using Element = typename Curve::Element; -// using AffineElement = typename Curve::AffineElement; -// using Fr = typename Curve::ScalarField; - -// constexpr size_t num_points = 8192; - -// Fr* scalars = (Fr*)aligned_alloc(32, sizeof(Fr) * num_points); - -// AffineElement* points = (AffineElement*)aligned_alloc(32, sizeof(AffineElement) * (num_points * 2 + 1)); - -// std::vector expected; -// bool filling_scalars = true; -// size_t num_filled_scalars = 0; -// while (filling_scalars) { -// size_t num_identical_scalars = static_cast(engine.get_random_uint64()) % 32 + 1; -// if (num_filled_scalars + num_identical_scalars > num_points) { -// num_identical_scalars = num_points - num_filled_scalars; -// } -// auto scalar = Fr::random_element(); -// Element accumulator; -// accumulator.self_set_infinity(); -// for (size_t i = 0; i < num_identical_scalars; ++i) { -// Element point = G1::random_element(); -// scalars[num_filled_scalars + i] = scalar; -// points[num_filled_scalars + i] = point; -// accumulator += point; -// } -// expected.push_back(accumulator); -// num_filled_scalars += num_identical_scalars; -// if (num_filled_scalars == num_points) { -// filling_scalars = false; -// } -// } - -// // for (size_t i = 0; i < num_points; ++i) { -// // scalars[i] = Fr::random_element(); -// // points[i] = AffineElement(G1::random_element()); -// // } - -// scalar_multiplication::generate_pippenger_point_table(points, points, num_points); -// scalar_multiplication::pippenger_runtime_state state(num_points); - -// scalar_multiplication::remove_duplicates( -// std::span(scalars, num_points), std::span(points, num_points), state); - -// AffineElement* result = state.point_pairs_2; - -// for (size_t i = 0; i < expected.size(); ++i) { -// EXPECT_EQ(result[i], expected[i]); -// } -// } +TYPED_TEST(SortedMsmTests, ReduceMsmInputs) +{ + using Curve = TypeParam; + using G1 = typename Curve::AffineElement; + using MsmManager = SortedMsmManager; + + // Generate random MSM inputs based on a set of sequence counts + std::array sequence_counts{ 75, 1, 28, 382, 3 }; + auto [num_points, points, scalars, expected_msm_result] = + TestFixture::generate_test_data_from_sequence_counts(sequence_counts); + + MsmManager msm_manager{ num_points }; + auto [result_scalars, result_points] = msm_manager.reduce_msm_inputs(scalars, points); + + G1 msm_result = result_points[0] * result_scalars[0]; + for (size_t i = 1; i < result_points.size(); ++i) { + msm_result = msm_result + result_points[i] * result_scalars[i]; + } + + EXPECT_EQ(msm_result, expected_msm_result); +} \ No newline at end of file From a2967f3ba84af570998dce96a6ebc21905df490d Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Sun, 7 Jul 2024 16:02:19 +0000 Subject: [PATCH 13/19] mas cleanup --- .../ecc/scalar_multiplication/sorted_msm.cpp | 24 +++++----- .../ecc/scalar_multiplication/sorted_msm.hpp | 4 +- .../scalar_multiplication/sorted_msm.test.cpp | 47 +++++++++---------- 3 files changed, 36 insertions(+), 39 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp index b9ed26c4074..f81f13492c3 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp @@ -3,8 +3,7 @@ namespace bb { template -SortedMsmManager::ReducedMsmInputs SortedMsmManager::reduce_msm_inputs(std::span scalars, - std::span points) +MsmSorter::ReducedMsmInputs MsmSorter::reduce_msm_inputs(std::span scalars, std::span points) { // generate the addition sequences AdditionSequences addition_sequences = construct_addition_sequences(scalars, points); @@ -24,11 +23,11 @@ SortedMsmManager::ReducedMsmInputs SortedMsmManager::reduce_msm_in * @tparam Curve * @param scalars * @param points - * @return SortedMsmManager::AdditionSequences + * @return MsmSorter::AdditionSequences */ template -SortedMsmManager::AdditionSequences SortedMsmManager::construct_addition_sequences(std::span scalars, - std::span points) +MsmSorter::AdditionSequences MsmSorter::construct_addition_sequences(std::span scalars, + std::span points) { // Create the array containing the indices of the scalars and points sorted by scalar value const size_t num_points = points.size(); @@ -74,7 +73,7 @@ SortedMsmManager::AdditionSequences SortedMsmManager::construct_ad * @param add_sequences */ template -void SortedMsmManager::batch_compute_point_addition_slope_inverses(AdditionSequences& add_sequences) +void MsmSorter::batch_compute_point_addition_slope_inverses(AdditionSequences& add_sequences) { auto points = add_sequences.points; auto sequence_counts = add_sequences.sequence_counts; @@ -136,9 +135,9 @@ void SortedMsmManager::batch_compute_point_addition_slope_inverses(Additi * @return Curve::AffineElement */ template -typename Curve::AffineElement SortedMsmManager::affine_add_with_denominator(const G1& point_1, - const G1& point_2, - const Fq& denominator) +typename Curve::AffineElement MsmSorter::affine_add_with_denominator(const G1& point_1, + const G1& point_2, + const Fq& denominator) { const auto& x1 = point_1.x; const auto& y1 = point_1.y; @@ -162,8 +161,7 @@ typename Curve::AffineElement SortedMsmManager::affine_add_with_denominat * @tparam Curve * @param addition_sequences Set of points and counts indicating number of points in each addition chain */ -template -void SortedMsmManager::batched_affine_add_in_place(AdditionSequences addition_sequences) +template void MsmSorter::batched_affine_add_in_place(AdditionSequences addition_sequences) { const size_t num_points = addition_sequences.points.size(); if (num_points == 0 || num_points == 1) { // nothing to do @@ -214,6 +212,6 @@ void SortedMsmManager::batched_affine_add_in_place(AdditionSequences addi } } -template class SortedMsmManager; -template class SortedMsmManager; +template class MsmSorter; +template class MsmSorter; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp index 462a7faf050..7ec478985b0 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp @@ -7,7 +7,7 @@ #include namespace bb { -template class SortedMsmManager { +template class MsmSorter { public: using G1 = typename Curve::AffineElement; using Fr = typename Curve::ScalarField; @@ -32,7 +32,7 @@ template class SortedMsmManager { std::vector index; std::vector denominators; - SortedMsmManager(const size_t num_scalars = 0) + MsmSorter(const size_t num_scalars = 0) { sequence_counts.resize(num_scalars); unique_scalars.resize(num_scalars); diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp index fa345c57aed..1ad7dc2701f 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp @@ -21,7 +21,6 @@ template class SortedMsmTests : public ::testing::Test { public: using G1 = typename Curve::AffineElement; using Fr = typename Curve::ScalarField; - // using Fq = typename Curve::BaseField; struct TestData { size_t num_points; @@ -82,9 +81,9 @@ TYPED_TEST(SortedMsmTests, AffineAddWithDenominator) using Curve = TypeParam; using G1 = typename Curve::AffineElement; using Fq = typename Curve::BaseField; - using MsmManager = SortedMsmManager; + using Sorter = MsmSorter; - MsmManager msm_manager; + Sorter msm_sorter; G1 point_1 = G1::random_element(); G1 point_2 = G1::random_element(); @@ -92,7 +91,7 @@ TYPED_TEST(SortedMsmTests, AffineAddWithDenominator) G1 expected = point_1 + point_2; - G1 result = msm_manager.affine_add_with_denominator(point_1, point_2, denominator); + G1 result = msm_sorter.affine_add_with_denominator(point_1, point_2, denominator); EXPECT_EQ(result, expected); } @@ -102,8 +101,8 @@ TYPED_TEST(SortedMsmTests, ComputePointAdditionDenominators) { using Curve = TypeParam; using Fq = typename Curve::BaseField; - using MsmManager = SortedMsmManager; - using AdditionSequences = typename MsmManager::AdditionSequences; + using Sorter = MsmSorter; + using AdditionSequences = typename Sorter::AdditionSequences; // Generate random MSM inputs based on a set of sequence counts std::array sequence_counts{ 3, 2 }; @@ -118,11 +117,11 @@ TYPED_TEST(SortedMsmTests, ComputePointAdditionDenominators) denominators_expected[0] = (points[1].x - points[0].x).invert(); denominators_expected[1] = (points[4].x - points[3].x).invert(); - MsmManager msm_manager(num_points); - msm_manager.batch_compute_point_addition_slope_inverses(addition_sequences); + Sorter msm_sorter(num_points); + msm_sorter.batch_compute_point_addition_slope_inverses(addition_sequences); for (size_t i = 0; i < num_pairs; ++i) { - Fq result = msm_manager.denominators[i]; + Fq result = msm_sorter.denominators[i]; Fq expected = denominators_expected[i]; EXPECT_EQ(result, expected); } @@ -133,8 +132,8 @@ TYPED_TEST(SortedMsmTests, BatchedAffineAddInPlace) { using Curve = TypeParam; using G1 = typename Curve::AffineElement; - using MsmManager = SortedMsmManager; - using AdditionSequences = typename MsmManager::AdditionSequences; + using Sorter = MsmSorter; + using AdditionSequences = typename Sorter::AdditionSequences; // Generate random MSM inputs based on a set of sequence counts std::array sequence_counts{ 5, 2, 3 }; @@ -153,8 +152,8 @@ TYPED_TEST(SortedMsmTests, BatchedAffineAddInPlace) expected_points.emplace_back(sum); } - MsmManager msm_manager(num_points); - msm_manager.batched_affine_add_in_place(addition_sequences); + Sorter msm_sorter(num_points); + msm_sorter.batched_affine_add_in_place(addition_sequences); for (size_t idx = 0; idx < expected_points.size(); ++idx) { EXPECT_EQ(expected_points[idx], points[idx]); @@ -167,16 +166,16 @@ TYPED_TEST(SortedMsmTests, GenerateAdditionSequences) using Curve = TypeParam; using G1 = typename Curve::AffineElement; using Fr = typename Curve::ScalarField; - using MsmManager = SortedMsmManager; - using AdditionSequences = typename MsmManager::AdditionSequences; + using Sorter = MsmSorter; + using AdditionSequences = typename Sorter::AdditionSequences; // Generate random MSM inputs based on a set of sequence counts std::array sequence_counts{ 5, 2, 3 }; auto [num_points, points, scalars, expected_msm_result] = TestFixture::generate_test_data_from_sequence_counts(sequence_counts); - MsmManager msm_manager{ num_points }; - AdditionSequences result = msm_manager.construct_addition_sequences(scalars, points); + Sorter msm_sorter{ num_points }; + AdditionSequences result = msm_sorter.construct_addition_sequences(scalars, points); // The resulting sequence counts should match expectation but only as multisets std::multiset expected_sequence_counts(sequence_counts.begin(), sequence_counts.end()); @@ -194,7 +193,7 @@ TYPED_TEST(SortedMsmTests, GenerateAdditionSequences) size_t point_idx = 0; for (auto count : result.sequence_counts) { for (size_t i = 0; i < count; ++i) { - msm_result = msm_result + result.points[point_idx] * msm_manager.unique_scalars[scalar_idx]; + msm_result = msm_result + result.points[point_idx] * msm_sorter.unique_scalars[scalar_idx]; point_idx++; } scalar_idx++; @@ -207,15 +206,15 @@ TYPED_TEST(SortedMsmTests, ReduceMsmInputsSimple) { using Curve = TypeParam; using G1 = typename Curve::AffineElement; - using MsmManager = SortedMsmManager; + using Sorter = MsmSorter; // Generate random MSM inputs based on a set of sequence counts std::array sequence_counts{ 5, 2, 3 }; auto [num_points, points, scalars, expected_msm_result] = TestFixture::generate_test_data_from_sequence_counts(sequence_counts); - MsmManager msm_manager{ num_points }; - auto [result_scalars, result_points] = msm_manager.reduce_msm_inputs(scalars, points); + Sorter msm_sorter{ num_points }; + auto [result_scalars, result_points] = msm_sorter.reduce_msm_inputs(scalars, points); G1 msm_result = result_points[0] * result_scalars[0]; for (size_t i = 1; i < result_points.size(); ++i) { @@ -229,15 +228,15 @@ TYPED_TEST(SortedMsmTests, ReduceMsmInputs) { using Curve = TypeParam; using G1 = typename Curve::AffineElement; - using MsmManager = SortedMsmManager; + using Sorter = MsmSorter; // Generate random MSM inputs based on a set of sequence counts std::array sequence_counts{ 75, 1, 28, 382, 3 }; auto [num_points, points, scalars, expected_msm_result] = TestFixture::generate_test_data_from_sequence_counts(sequence_counts); - MsmManager msm_manager{ num_points }; - auto [result_scalars, result_points] = msm_manager.reduce_msm_inputs(scalars, points); + Sorter msm_sorter{ num_points }; + auto [result_scalars, result_points] = msm_sorter.reduce_msm_inputs(scalars, points); G1 msm_result = result_points[0] * result_scalars[0]; for (size_t i = 1; i < result_points.size(); ++i) { From 6fb1e7d954b1df4f67510a8827d3912ac7a77f06 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Sun, 7 Jul 2024 16:50:53 +0000 Subject: [PATCH 14/19] class description --- .../ecc/scalar_multiplication/sorted_msm.hpp | 23 +++++++++++++++++-- .../scalar_multiplication/sorted_msm.test.cpp | 6 +++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp index 7ec478985b0..5e09ec88eda 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp @@ -7,7 +7,26 @@ #include namespace bb { + +/** + * @brief Reduce MSM inputs such that the set of scalars contains no duplicates by summing points which share a scalar. + * @details Since point addition is substantially cheaper than scalar multiplication, it is more efficient in some cases + * to first sum all points which share a scalar then perform the MSM on the reduced set of inputs. This is achieved via + * the following procedure: + * + * 1) Sort the input {points, scalars} by scalar in order to group points into 'addition sequences' i.e. sets of points + * to be added together prior to performing the MSM. + * + * 2) For each sequence, perform pairwise addition on all points. (If the length of the sequence is odd, the unpaired + * point is simply carried over to the next round). The inverses needed in the addition formula are batch computed in a + * single go for all additions to be performed across all sequences in a given round. + * + * 3) Perform rounds of pair-wise addition until each sequence is reduced to a single point. + * + * @tparam Curve + */ template class MsmSorter { + public: using G1 = typename Curve::AffineElement; using Fr = typename Curve::ScalarField; @@ -41,6 +60,8 @@ template class MsmSorter { denominators.resize(num_scalars); } + ReducedMsmInputs reduce_msm_inputs(std::span scalars, std::span points); + G1 affine_add_with_denominator(const G1&, const G1&, const Fq& denominator); void batch_compute_point_addition_slope_inverses(AdditionSequences& add_sequences); @@ -48,8 +69,6 @@ template class MsmSorter { void batched_affine_add_in_place(AdditionSequences addition_sequences); AdditionSequences construct_addition_sequences(std::span scalars, std::span points); - - ReducedMsmInputs reduce_msm_inputs(std::span scalars, std::span points); }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp index 1ad7dc2701f..854c3819af5 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp @@ -11,13 +11,14 @@ #include #include -using namespace bb; +namespace bb { namespace { auto& engine = numeric::get_debug_randomness(); } template class SortedMsmTests : public ::testing::Test { + public: using G1 = typename Curve::AffineElement; using Fr = typename Curve::ScalarField; @@ -244,4 +245,5 @@ TYPED_TEST(SortedMsmTests, ReduceMsmInputs) } EXPECT_EQ(msm_result, expected_msm_result); -} \ No newline at end of file +} +} // namespace bb \ No newline at end of file From 853ba1461f594b6dc51c7b98b526b5eae19ee7e2 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 8 Jul 2024 14:10:52 +0000 Subject: [PATCH 15/19] more comments --- .../ecc/scalar_multiplication/sorted_msm.cpp | 3 ++- .../ecc/scalar_multiplication/sorted_msm.hpp | 4 ++++ .../ecc/scalar_multiplication/sorted_msm.test.cpp | 11 ++++++++--- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp index f81f13492c3..3f1ea85cf2b 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp @@ -98,12 +98,13 @@ void MsmSorter::batch_compute_point_addition_slope_inverses(AdditionSeque const auto& x1 = points[point_idx++].x; const auto& x2 = points[point_idx++].x; - // WORKTODO: what is the risk of a collision here? + // It is assumed that the input points are random and thus w/h/p do not share an x-coordinate ASSERT(x1 != x2); auto diff = x2 - x1; differences[pair_idx] = diff; + // Store and update the running product of differences at each stage scratch_space[pair_idx++] = accumulator; accumulator *= diff; } diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp index 5e09ec88eda..90dbde74a1b 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp @@ -23,6 +23,10 @@ namespace bb { * * 3) Perform rounds of pair-wise addition until each sequence is reduced to a single point. * + * @warning This class is intended to reduce MSMs with EC points that are fully random, e.g. those from an SRS. It does + * not necessarily handle the case where two adjacent points are equal or the inverse of one another (i.e. where x_i == + * x_{i+1}) + * * @tparam Curve */ template class MsmSorter { diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp index 854c3819af5..6c3845bc591 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp @@ -32,7 +32,7 @@ template class SortedMsmTests : public ::testing::Test { /** * @brief Generate a set of random points and scalars based on an input sequence_counts - * @details E.g. given sequence counts {7, 2, 9}, generate a set of random points an scalars with only 3 unique + * @details E.g. given sequence counts {7, 2, 9}, generate a set of random points and scalars with only 3 unique * scalar values repeated according to the sequence counts. Also compute the result of the corresponding MSM for * test comparisons. * @@ -232,18 +232,23 @@ TYPED_TEST(SortedMsmTests, ReduceMsmInputs) using Sorter = MsmSorter; // Generate random MSM inputs based on a set of sequence counts - std::array sequence_counts{ 75, 1, 28, 382, 3 }; + const size_t num_unique_scalars = 5; + std::array sequence_counts{ 75, 1, 28, 382, 3 }; auto [num_points, points, scalars, expected_msm_result] = TestFixture::generate_test_data_from_sequence_counts(sequence_counts); Sorter msm_sorter{ num_points }; auto [result_scalars, result_points] = msm_sorter.reduce_msm_inputs(scalars, points); + // Points and scalars should both be reduced to the number of unique scalars + EXPECT_EQ(result_scalars.size(), num_unique_scalars); + EXPECT_EQ(result_points.size(), num_unique_scalars); + + // Performing the MSM over the reduced inputs should yield the same result as the original G1 msm_result = result_points[0] * result_scalars[0]; for (size_t i = 1; i < result_points.size(); ++i) { msm_result = msm_result + result_points[i] * result_scalars[i]; } - EXPECT_EQ(msm_result, expected_msm_result); } } // namespace bb \ No newline at end of file From 1132695362b6270ec417e132780a8ca6657da564 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 8 Jul 2024 14:25:07 +0000 Subject: [PATCH 16/19] and more comments --- .../ecc/scalar_multiplication/sorted_msm.cpp | 36 +++++++++++++++---- .../ecc/scalar_multiplication/sorted_msm.hpp | 13 +------ 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp index 3f1ea85cf2b..c7afbd2fde2 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp @@ -2,16 +2,36 @@ namespace bb { +/** + * @brief Reduce MSM inputs such that the set of scalars contains no duplicates by summing points which share a scalar. + * @details Since point addition is substantially cheaper than scalar multiplication, it is more efficient in some cases + * to first sum all points which share a scalar then perform the MSM on the reduced set of inputs. This is achieved via + * the following procedure: + * + * 1) Sort the input {points, scalars} by scalar in order to group points into 'addition sequences' i.e. sets of points + * to be added together prior to performing the MSM. + * + * 2) For each sequence, perform pairwise addition on all points. (If the length of the sequence is odd, the unpaired + * point is simply carried over to the next round). The inverses needed in the addition formula are batch computed in a + * single go for all additions to be performed across all sequences in a given round. + * + * 3) Perform rounds of pair-wise addition until each sequence is reduced to a single point. + * + * @tparam Curve + * @param scalars + * @param points + * @return MsmSorter::ReducedMsmInputs + */ template MsmSorter::ReducedMsmInputs MsmSorter::reduce_msm_inputs(std::span scalars, std::span points) { - // generate the addition sequences + // Generate the addition sequences (sets of points sharing a scalar) AdditionSequences addition_sequences = construct_addition_sequences(scalars, points); - // call batched affine add in place until the sequences have been fully reduced + // Perform rounds of pairwise addition until all sets of points sharing a scalar have been reduced to a single point batched_affine_add_in_place(addition_sequences); - // the reduced inputs are the unique scalrs and the reduced points + // The reduced MSM inputs are the unique scalars and the reduced points std::span output_scalars(unique_scalars.data(), num_unique_scalars); std::span output_points(updated_points.data(), num_unique_scalars); return { output_scalars, output_points }; @@ -84,6 +104,7 @@ void MsmSorter::batch_compute_point_addition_slope_inverses(AdditionSeque total_num_pairs += count >> 1; } + // Define scratch space for batched inverse computations and eventual storage of denominators std::span scratch_space(denominators.data(), total_num_pairs); std::vector differences; differences.resize(total_num_pairs); @@ -175,6 +196,7 @@ template void MsmSorter::batched_affine_add_in_place(Add auto points = addition_sequences.points; auto sequence_counts = addition_sequences.sequence_counts; + // Compute pairwise in-place additions for all sequences with more than 1 point size_t point_idx = 0; // index for points to be summed size_t result_point_idx = 0; // index for result points size_t pair_idx = 0; // index into array of denominators for each pair @@ -182,7 +204,7 @@ template void MsmSorter::batched_affine_add_in_place(Add for (auto& count : sequence_counts) { const size_t num_pairs = count >> 1; const bool overflow = static_cast(count & 0x01ULL); - // Compute the sum of all pairs in the sequence and store the result in the points array + // Compute the sum of all pairs in the sequence and store the result in the same points array for (size_t j = 0; j < num_pairs; ++j) { const auto& point_1 = points[point_idx++]; // first summand const auto& point_2 = points[point_idx++]; // second summand @@ -191,7 +213,7 @@ template void MsmSorter::batched_affine_add_in_place(Add result = affine_add_with_denominator(point_1, point_2, denominator); } - // If the sequence had an odd number of points, simply maintain the unpaired point in the sequence + // If the sequence had an odd number of points, simply carry the unpaired point over to the next round if (overflow) { points[result_point_idx++] = points[point_idx++]; } @@ -201,10 +223,10 @@ template void MsmSorter::batched_affine_add_in_place(Add count = updated_sequence_count; // More additions are required if any sequence has not yet been reduced to a single point - more_additions = more_additions || (updated_sequence_count > 1); + more_additions = more_additions || updated_sequence_count > 1; } - // Recursively perform additions until all sequences have been reduced to a single point + // Recursively perform pairwise additions until all sequences have been reduced to a single point if (more_additions) { const size_t updated_point_count = result_point_idx; std::span updated_points(&points[0], updated_point_count); diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp index 90dbde74a1b..0c5d07823a5 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp @@ -10,18 +10,6 @@ namespace bb { /** * @brief Reduce MSM inputs such that the set of scalars contains no duplicates by summing points which share a scalar. - * @details Since point addition is substantially cheaper than scalar multiplication, it is more efficient in some cases - * to first sum all points which share a scalar then perform the MSM on the reduced set of inputs. This is achieved via - * the following procedure: - * - * 1) Sort the input {points, scalars} by scalar in order to group points into 'addition sequences' i.e. sets of points - * to be added together prior to performing the MSM. - * - * 2) For each sequence, perform pairwise addition on all points. (If the length of the sequence is odd, the unpaired - * point is simply carried over to the next round). The inverses needed in the addition formula are batch computed in a - * single go for all additions to be performed across all sequences in a given round. - * - * 3) Perform rounds of pair-wise addition until each sequence is reduced to a single point. * * @warning This class is intended to reduce MSMs with EC points that are fully random, e.g. those from an SRS. It does * not necessarily handle the case where two adjacent points are equal or the inverse of one another (i.e. where x_i == @@ -43,6 +31,7 @@ template class MsmSorter { std::optional> scratch_space; }; + // Set of reduced MSM inputs where all scalars are unique struct ReducedMsmInputs { std::span scalars; std::span points; From adfcd9b63e710402a176c4bc314a7f1c7c35aec1 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 8 Jul 2024 17:36:25 +0000 Subject: [PATCH 17/19] fix build --- .../src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp index c7afbd2fde2..adc97599519 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp @@ -114,7 +114,7 @@ void MsmSorter::batch_compute_point_addition_slope_inverses(AdditionSeque size_t point_idx = 0; size_t pair_idx = 0; for (auto& count : sequence_counts) { - const size_t num_pairs = count >> 1; + const auto num_pairs = count >> 1; for (size_t j = 0; j < num_pairs; ++j) { const auto& x1 = points[point_idx++].x; const auto& x2 = points[point_idx++].x; From 6a2c1d7f83f0d73e2b80d90bea3de622747a4023 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 8 Jul 2024 17:42:19 +0000 Subject: [PATCH 18/19] one more --- .../src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp index adc97599519..28a81cfc33e 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp @@ -202,7 +202,7 @@ template void MsmSorter::batched_affine_add_in_place(Add size_t pair_idx = 0; // index into array of denominators for each pair bool more_additions = false; for (auto& count : sequence_counts) { - const size_t num_pairs = count >> 1; + const auto num_pairs = count >> 1; const bool overflow = static_cast(count & 0x01ULL); // Compute the sum of all pairs in the sequence and store the result in the same points array for (size_t j = 0; j < num_pairs; ++j) { From 1341c62c6a5574a84b2c99b04a4840cdc2bf3e28 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Thu, 11 Jul 2024 03:24:38 +0000 Subject: [PATCH 19/19] comments, multithreading sort, and inlining add method --- .../ecc/scalar_multiplication/sorted_msm.cpp | 34 ++++--------------- .../ecc/scalar_multiplication/sorted_msm.hpp | 28 +++++++++++++-- .../scalar_multiplication/sorted_msm.test.cpp | 6 ++++ 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp index 28a81cfc33e..9c51d6125c8 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.cpp @@ -52,7 +52,13 @@ MsmSorter::AdditionSequences MsmSorter::construct_addition_sequenc // Create the array containing the indices of the scalars and points sorted by scalar value const size_t num_points = points.size(); std::iota(index.begin(), index.end(), 0); +#ifdef NO_TBB std::sort(index.begin(), index.end(), [&](size_t idx_1, size_t idx_2) { return scalars[idx_1] < scalars[idx_2]; }); +#else + std::sort(std::execution::par_unseq, index.begin(), index.end(), [&](size_t idx_1, size_t idx_2) { + return scalars[idx_1] < scalars[idx_2]; + }); +#endif // Store the unique scalar values, the input points sorted by scalar value, and the number of occurences of each // unique scalar (i.e. the size of each addition sequence) @@ -144,34 +150,6 @@ void MsmSorter::batch_compute_point_addition_slope_inverses(AdditionSeque } } -/** - * @brief Add two affine elements with the inverse in the slope term \lambda provided as input - * @details The sum of two points (x1, y1), (x2, y2) is given by x3 = \lambda^2 - x1 - x2, y3 = \lambda*(x1 - x3) - y1, - * where \lambda = (y2 - y1)/(x2 - x1). When performing many additions at once, it is more efficient to batch compute - * the inverse component of \lambda for each pair of points. This gives rise to the need for a method like this one. - * - * @tparam Curve - * @param point_1 (x1, y1) - * @param point_2 (x2, y2) - * @param denominator 1/(x2 - x1) - * @return Curve::AffineElement - */ -template -typename Curve::AffineElement MsmSorter::affine_add_with_denominator(const G1& point_1, - const G1& point_2, - const Fq& denominator) -{ - const auto& x1 = point_1.x; - const auto& y1 = point_1.y; - const auto& x2 = point_2.x; - const auto& y2 = point_2.y; - - const Fq lambda = denominator * (y2 - y1); - Fq x3 = lambda.sqr() - x2 - x1; - Fq y3 = lambda * (x1 - x3) - y1; - return { x3, y3 }; -} - /** * @brief In-place summation to reduce a set of addition sequences to a single point for each sequence * @details At each round, the set of points in each addition sequence is roughly halved by performing pairwise diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp index 0c5d07823a5..5022cfd3836 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.hpp @@ -55,13 +55,37 @@ template class MsmSorter { ReducedMsmInputs reduce_msm_inputs(std::span scalars, std::span points); - G1 affine_add_with_denominator(const G1&, const G1&, const Fq& denominator); - void batch_compute_point_addition_slope_inverses(AdditionSequences& add_sequences); void batched_affine_add_in_place(AdditionSequences addition_sequences); AdditionSequences construct_addition_sequences(std::span scalars, std::span points); + + /** + * @brief Add two affine elements with the inverse in the slope term \lambda provided as input + * @details The sum of two points (x1, y1), (x2, y2) is given by x3 = \lambda^2 - x1 - x2, y3 = \lambda*(x1 - x3) - + * y1, where \lambda = (y2 - y1)/(x2 - x1). When performing many additions at once, it is more efficient to batch + * compute the inverse component of \lambda for each pair of points. This gives rise to the need for a method like + * this one. + * + * @tparam Curve + * @param point_1 (x1, y1) + * @param point_2 (x2, y2) + * @param denominator 1/(x2 - x1) + * @return Curve::AffineElement + */ + inline G1 affine_add_with_denominator(const G1& point_1, const G1& point_2, const Fq& denominator) + { + const auto& x1 = point_1.x; + const auto& y1 = point_1.y; + const auto& x2 = point_2.x; + const auto& y2 = point_2.y; + + const Fq lambda = denominator * (y2 - y1); + Fq x3 = lambda.sqr() - x2 - x1; + Fq y3 = lambda * (x1 - x3) - y1; + return { x3, y3 }; + } }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp index 6c3845bc591..baed46e780b 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/scalar_multiplication/sorted_msm.test.cpp @@ -203,6 +203,9 @@ TYPED_TEST(SortedMsmTests, GenerateAdditionSequences) EXPECT_EQ(msm_result, expected_msm_result); } +// Test that the method reduce_msm_inputs can reduce a set of {points, scalars} with duplicate scalars to a reduced set +// of inputs {points', scalars'} such that all scalars in scalars' are unique and that perfoming the MSM on the reduced +// inputs yields the same result as with the original inputs TYPED_TEST(SortedMsmTests, ReduceMsmInputsSimple) { using Curve = TypeParam; @@ -225,6 +228,9 @@ TYPED_TEST(SortedMsmTests, ReduceMsmInputsSimple) EXPECT_EQ(msm_result, expected_msm_result); } +// Test that the method reduce_msm_inputs can reduce a set of {points, scalars} with duplicate scalars to a reduced set +// of inputs {points', scalars'} such that all scalars in scalars' are unique and that perfoming the MSM on the reduced +// inputs yields the same result as with the original inputs TYPED_TEST(SortedMsmTests, ReduceMsmInputs) { using Curve = TypeParam;