1212#include " barretenberg/stdlib/primitives/bool/bool.hpp"
1313#include " barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp"
1414#include " barretenberg/stdlib/primitives/field/field.hpp"
15+ #include " barretenberg/stdlib/primitives/group/cycle_scalar.hpp"
16+ #include " barretenberg/stdlib/primitives/group/straus_lookup_table.hpp"
17+ #include " barretenberg/stdlib/primitives/group/straus_scalar_slice.hpp"
1518#include " barretenberg/stdlib_circuit_builders/plookup_tables/fixed_base/fixed_base_params.hpp"
1619#include " barretenberg/transcript/origin_tag.hpp"
1720#include < optional>
@@ -20,8 +23,6 @@ namespace bb::stdlib {
2023
2124template <typename Builder>
2225concept IsUltraArithmetic = (Builder::CIRCUIT_TYPE == CircuitType::ULTRA);
23- template <typename Builder>
24- concept IsNotUltraArithmetic = (Builder::CIRCUIT_TYPE != CircuitType::ULTRA);
2526
2627/* *
2728 * @brief cycle_group represents a group Element of the proving system's embedded curve
@@ -57,157 +58,9 @@ template <typename Builder> class cycle_group {
5758 // Since the cycle_group base field is the circuit's native field, it can be stored using two public inputs.
5859 static constexpr size_t PUBLIC_INPUTS_SIZE = 2 ;
5960
60- private:
61- public:
62- /* *
63- * @brief cycle_scalar represents a member of the cycle curve SCALAR FIELD.
64- * This is NOT the native circuit field type.
65- * i.e. for a BN254 circuit, cycle_group will be Grumpkin and cycle_scalar will be Grumpkin::ScalarField
66- * (BN254 native field is BN254::ScalarField == Grumpkin::BaseField)
67- *
68- * @details We convert scalar multiplication inputs into cycle_scalars to enable scalar multiplication to be
69- * *complete* i.e. Grumpkin points multiplied by BN254 scalars does not produce a cyclic group
70- * as BN254::ScalarField < Grumpkin::ScalarField
71- * This complexity *should* not leak outside the cycle_group / cycle_scalar implementations, as cycle_scalar
72- * performs all required conversions if the input scalars are stdlib::field_t elements
73- *
74- * @note We opted to create a new class to represent `cycle_scalar` instead of using `bigfield`,
75- * as `bigfield` is inefficient in this context. All required range checks for `cycle_scalar` can be obtained for
76- * free from the `batch_mul` algorithm, making the range checks performed by `bigfield` largely redundant.
77- */
78- struct cycle_scalar {
79- static constexpr size_t LO_BITS = field_t ::native::Params::MAX_BITS_PER_ENDOMORPHISM_SCALAR;
80- static constexpr size_t HI_BITS = NUM_BITS - LO_BITS;
81- field_t lo;
82- field_t hi;
83-
84- private:
85- size_t _num_bits = NUM_BITS;
86- bool _skip_primality_test = false ;
87- // if our scalar multiplier is a bn254 FF scalar (e.g. pedersen hash),
88- // we want to validate the cycle_scalar < bn254::fr::modulus *not* grumpkin::fr::modulus
89- bool _use_bn254_scalar_field_for_primality_test = false ;
90-
91- public:
92- cycle_scalar (const field_t & _lo,
93- const field_t & _hi,
94- const size_t bits,
95- const bool skip_primality_test,
96- const bool use_bn254_scalar_field_for_primality_test)
97- : lo(_lo)
98- , hi(_hi)
99- , _num_bits(bits)
100- , _skip_primality_test(skip_primality_test)
101- , _use_bn254_scalar_field_for_primality_test(use_bn254_scalar_field_for_primality_test) {};
102- cycle_scalar (const ScalarField& _in = 0 );
103- cycle_scalar (const field_t & _lo, const field_t & _hi);
104- cycle_scalar (const field_t & _in);
105- static cycle_scalar from_witness (Builder* context, const ScalarField& value);
106- static cycle_scalar from_witness_bitstring (Builder* context, const uint256_t & bitstring, size_t num_bits);
107- static cycle_scalar create_from_bn254_scalar (const field_t & _in, bool skip_primality_test = false );
108- [[nodiscard]] bool is_constant () const ;
109- ScalarField get_value () const ;
110- Builder* get_context () const { return lo.get_context () != nullptr ? lo.get_context () : hi.get_context (); }
111- [[nodiscard]] size_t num_bits () const { return _num_bits; }
112- [[nodiscard]] bool skip_primality_test () const { return _skip_primality_test; }
113- [[nodiscard]] bool use_bn254_scalar_field_for_primality_test () const
114- {
115- return _use_bn254_scalar_field_for_primality_test;
116- }
117- void validate_scalar_is_in_field () const ;
118-
119- explicit cycle_scalar (BigScalarField&);
120- /* *
121- * @brief Get the origin tag of the cycle_scalar (a merge of the lo and hi tags)
122- *
123- * @return OriginTag
124- */
125- OriginTag get_origin_tag () const { return OriginTag (lo.get_origin_tag (), hi.get_origin_tag ()); }
126- /* *
127- * @brief Set the origin tag of lo and hi members of cycle scalar
128- *
129- * @param tag
130- */
131- void set_origin_tag (const OriginTag& tag) const
132- {
133- lo.set_origin_tag (tag);
134- hi.set_origin_tag (tag);
135- }
136- /* *
137- * @brief Set the free witness flag for the cycle scalar's tags
138- */
139- void set_free_witness_tag ()
140- {
141- lo.set_free_witness_tag ();
142- hi.set_free_witness_tag ();
143- }
144- /* *
145- * @brief Unset the free witness flag for the cycle scalar's tags
146- */
147- void unset_free_witness_tag ()
148- {
149- lo.unset_free_witness_tag ();
150- hi.unset_free_witness_tag ();
151- }
152- };
153-
154- /* *
155- * @brief straus_scalar_slice decomposes an input scalar into `table_bits` bit-slices.
156- * Used in `batch_mul`, which ses the Straus multiscalar multiplication algorithm.
157- *
158- */
159- struct straus_scalar_slice {
160- straus_scalar_slice (Builder* context, const cycle_scalar& scalars, size_t table_bits);
161- std::optional<field_t > read (size_t index);
162- size_t _table_bits;
163- std::vector<field_t > slices;
164- std::vector<uint64_t > slices_native;
165- };
166-
167- /* *
168- * @brief straus_lookup_table computes a lookup table of size 1 << table_bits
169- *
170- * @details for an input base_point [P] and offset_generator point [G], where N = 1 << table_bits, the following is
171- * computed:
172- *
173- * { [G] + 0.[P], [G] + 1.[P], ..., [G] + (N - 1).[P] }
174- *
175- * The point [G] is used to ensure that we do not have to handle the point at infinity associated with 0.[P].
176- *
177- * For an HONEST Prover, the probability of [G] and [P] colliding is equivalent to solving the dlog problem.
178- * This allows us to partially ignore the incomplete addition formula edge-cases for short Weierstrass curves.
179- *
180- * When adding group elements in `batch_mul`, we can constrain+assert the x-coordinates of the operand points do not
181- * match. An honest prover will never trigger the case where x-coordinates match due to the above. Validating
182- * x-coordinates do not match is much cheaper than evaluating the full complete addition formulae for short
183- * Weierstrass curves.
184- *
185- * @note For the case of fixed-base scalar multipliation, all input points are defined at circuit compile.
186- * We can ensure that all Provers cannot create point collisions between the base points and offset generators.
187- * For this restricted case we can skip the x-coordiante collision checks when performing group operations.
188- *
189- * @note straus_lookup_table uses Ultra ROM tables if available. If not, we use simple conditional assignment
190- * constraints and restrict the table size to be 1 bit.
191- */
192- struct straus_lookup_table {
193- public:
194- static std::vector<Element> compute_straus_lookup_table_hints (const Element& base_point,
195- const Element& offset_generator,
196- size_t table_bits);
197-
198- straus_lookup_table () = default ;
199- straus_lookup_table (Builder* context,
200- const cycle_group& base_point,
201- const cycle_group& offset_generator,
202- size_t table_bits,
203- std::optional<std::span<AffineElement>> hints = std::nullopt );
204- cycle_group read (const field_t & index);
205- size_t _table_bits;
206- Builder* _context;
207- std::vector<cycle_group> point_table;
208- size_t rom_id = 0 ;
209- OriginTag tag{};
210- };
61+ using cycle_scalar = ::bb::stdlib::cycle_scalar<Builder>;
62+ using straus_lookup_table = ::bb::stdlib::straus_lookup_table<Builder>;
63+ using straus_scalar_slice = ::bb::stdlib::straus_scalar_slice<Builder>;
21164
21265 private:
21366 /* *
@@ -239,14 +92,9 @@ template <typename Builder> class cycle_group {
23992 void validate_is_on_curve () const ;
24093 cycle_group dbl (const std::optional<AffineElement> hint = std::nullopt ) const
24194 requires IsUltraArithmetic<Builder>;
242- cycle_group dbl (const std::optional<AffineElement> hint = std::nullopt ) const
243- requires IsNotUltraArithmetic<Builder>;
24495 cycle_group unconditional_add (const cycle_group& other,
24596 const std::optional<AffineElement> hint = std::nullopt ) const
24697 requires IsUltraArithmetic<Builder>;
247- cycle_group unconditional_add (const cycle_group& other,
248- const std::optional<AffineElement> hint = std::nullopt ) const
249- requires IsNotUltraArithmetic<Builder>;
25098 cycle_group unconditional_subtract (const cycle_group& other,
25199 const std::optional<AffineElement> hint = std::nullopt ) const ;
252100 cycle_group checked_unconditional_add (const cycle_group& other,
@@ -384,10 +232,6 @@ template <typename Builder> class cycle_group {
384232 std::span<AffineElement> base_points,
385233 std::span<AffineElement const > offset_generators)
386234 requires IsUltraArithmetic<Builder>;
387- static batch_mul_internal_output _fixed_base_batch_mul_internal (std::span<cycle_scalar> scalars,
388- std::span<AffineElement> base_points,
389- std::span<AffineElement const > offset_generators)
390- requires IsNotUltraArithmetic<Builder>;
391235};
392236
393237template <typename Builder> inline std::ostream& operator <<(std::ostream& os, cycle_group<Builder> const & v)
0 commit comments