diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp index 9388f59ae10..f73d389cab0 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp @@ -297,6 +297,7 @@ template class element { bool_ct is_point_at_infinity() const { return _is_infinity; } void set_point_at_infinity(const bool_ct& is_infinity) { _is_infinity = is_infinity; } + element get_standard_form() const; Fq x; Fq y; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.test.cpp index f01cc3c1849..02c2cf12859 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.test.cpp @@ -122,7 +122,35 @@ template class stdlib_biggroup : public testing::Test { EXPECT_CIRCUIT_CORRECTNESS(builder); } + static void test_standard_form_of_point_at_infinity() + { + Builder builder; + size_t num_repetitions = 5; + for (size_t i = 0; i < num_repetitions; ++i) { + element_ct input_a(element::random_element()); + element_ct input_b(element::random_element()); + input_b.set_point_at_infinity(true); + auto standard_a = input_a.get_standard_form(); + auto standard_b = input_b.get_standard_form(); + EXPECT_EQ(standard_a.is_point_at_infinity().get_value(), false); + EXPECT_EQ(standard_b.is_point_at_infinity().get_value(), true); + fq input_a_x = input_a.x.get_value().lo; + fq input_a_y = input_a.y.get_value().lo; + + fq standard_a_x = standard_a.x.get_value().lo; + fq standard_a_y = standard_a.y.get_value().lo; + + fq standard_b_x = standard_b.x.get_value().lo; + fq standard_b_y = standard_b.y.get_value().lo; + + EXPECT_EQ(input_a_x, standard_a_x); + EXPECT_EQ(input_a_y, standard_a_y); + EXPECT_EQ(standard_b_x, 0); + EXPECT_EQ(standard_b_y, 0); + } + EXPECT_CIRCUIT_CORRECTNESS(builder); + } static void test_sub() { Builder builder; @@ -1173,6 +1201,10 @@ TYPED_TEST(stdlib_biggroup, add_points_at_infinity) { TestFixture::test_add_points_at_infinity(); } +TYPED_TEST(stdlib_biggroup, standard_form_of_point_at_infinity) +{ + TestFixture::test_standard_form_of_point_at_infinity(); +} TYPED_TEST(stdlib_biggroup, sub) { TestFixture::test_sub(); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_impl.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_impl.hpp index 6aa04a80223..38d2c020c04 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_impl.hpp @@ -127,6 +127,25 @@ element element::operator+(const element& other) con return result; } +/** + * @brief Enforce x and y coordinates of a point to be (0,0) in the case of point at infinity + * + * @details We need to have a standard witness in Noir and the point at infinity can have non-zero random coefficients + * when we get it as output from our optimised algorithms. This function returns a (0,0) point, if it is a point at + * infinity + */ +template +element element::get_standard_form() const +{ + + const bool_ct is_infinity = is_point_at_infinity(); + element result(*this); + const Fq zero = Fq::zero(); + result.x = Fq::conditional_assign(is_infinity, zero, this->x); + result.y = Fq::conditional_assign(is_infinity, zero, this->y); + return result; +} + template element element::operator-(const element& other) const {