|
16 | 16 |
|
17 | 17 | namespace bb::stdlib::recursion { |
18 | 18 |
|
| 19 | +// Combined limbs for default pairing points: lo = limb0 + limb1 * 2^68, hi = limb2 + limb3 * 2^68 |
| 20 | +// These are the source of truth, used in set_default_to_public() to avoid expensive bigfield operations. |
| 21 | +static constexpr bb::fr DEFAULT_PP_P0_X_LO = |
| 22 | + bb::fr("0x000000000000000000000000000000b75c020998797da7842ab5d6d1986846cf"); |
| 23 | +static constexpr bb::fr DEFAULT_PP_P0_X_HI = |
| 24 | + bb::fr("0x0000000000000000000000000000000000031e97a575e9d05a107acb64952eca"); |
| 25 | +static constexpr bb::fr DEFAULT_PP_P0_Y_LO = |
| 26 | + bb::fr("0x000000000000000000000000000000c410db10a01750aebb5666547acf8bd5a4"); |
| 27 | +static constexpr bb::fr DEFAULT_PP_P0_Y_HI = |
| 28 | + bb::fr("0x0000000000000000000000000000000000178cbf4206471d722669117f9758a4"); |
| 29 | +static constexpr bb::fr DEFAULT_PP_P1_X_LO = |
| 30 | + bb::fr("0x0000000000000000000000000000007fd51009034b3357f0e91b8a11e7842c38"); |
| 31 | +static constexpr bb::fr DEFAULT_PP_P1_X_HI = |
| 32 | + bb::fr("0x00000000000000000000000000000000000f94656a2ca489889939f81e9c7402"); |
| 33 | +static constexpr bb::fr DEFAULT_PP_P1_Y_LO = |
| 34 | + bb::fr("0x00000000000000000000000000000093fe27776f50224bd6fb128b46c1ddb67f"); |
| 35 | +static constexpr bb::fr DEFAULT_PP_P1_Y_HI = |
| 36 | + bb::fr("0x00000000000000000000000000000000001b52c2020d7464a0c80c0da527a081"); |
| 37 | + |
19 | 38 | // TODO(https://github.com/AztecProtocol/barretenberg/issues/911): These are pairing points extracted from a |
20 | 39 | // valid proof. This is a workaround because we can't represent the point at infinity in biggroup yet. |
| 40 | +// Derived from the combined limbs above: fq = lo + hi * 2^136 |
21 | 41 | static constexpr bb::fq DEFAULT_PAIRING_POINT_P0_X = |
22 | | - bb::fq("0x031e97a575e9d05a107acb64952ecab75c020998797da7842ab5d6d1986846cf"); |
| 42 | + bb::fq(uint256_t(DEFAULT_PP_P0_X_LO) + (uint256_t(DEFAULT_PP_P0_X_HI) << 136)); |
23 | 43 | static constexpr bb::fq DEFAULT_PAIRING_POINT_P0_Y = |
24 | | - bb::fq("0x178cbf4206471d722669117f9758a4c410db10a01750aebb5666547acf8bd5a4"); |
| 44 | + bb::fq(uint256_t(DEFAULT_PP_P0_Y_LO) + (uint256_t(DEFAULT_PP_P0_Y_HI) << 136)); |
25 | 45 | static constexpr bb::fq DEFAULT_PAIRING_POINT_P1_X = |
26 | | - bb::fq("0x0f94656a2ca489889939f81e9c74027fd51009034b3357f0e91b8a11e7842c38"); |
| 46 | + bb::fq(uint256_t(DEFAULT_PP_P1_X_LO) + (uint256_t(DEFAULT_PP_P1_X_HI) << 136)); |
27 | 47 | static constexpr bb::fq DEFAULT_PAIRING_POINT_P1_Y = |
28 | | - bb::fq("0x1b52c2020d7464a0c80c0da527a08193fe27776f50224bd6fb128b46c1ddb67f"); |
| 48 | + bb::fq(uint256_t(DEFAULT_PP_P1_Y_LO) + (uint256_t(DEFAULT_PP_P1_Y_HI) << 136)); |
29 | 49 |
|
30 | 50 | /** |
31 | 51 | * @brief An object storing two EC points that represent the inputs to a pairing check. |
@@ -81,11 +101,21 @@ template <typename Curve> struct PairingPoints { |
81 | 101 | {} |
82 | 102 |
|
83 | 103 | // Array-like accessors for Codec compatibility |
84 | | - Group& operator[](size_t idx) { return idx == 0 ? P0 : P1; } |
| 104 | + // Non-const version sets has_data since it's called during assignment (e.g., by Codec deserialization) |
| 105 | + Group& operator[](size_t idx) |
| 106 | + { |
| 107 | + has_data = true; |
| 108 | + return idx == 0 ? P0 : P1; |
| 109 | + } |
85 | 110 | const Group& operator[](size_t idx) const { return idx == 0 ? P0 : P1; } |
86 | 111 |
|
87 | 112 | // Iterator support for range-based for (required by Codec) |
88 | | - Group* begin() { return &P0; } |
| 113 | + // Non-const begin() sets has_data since it's called during Codec deserialization |
| 114 | + Group* begin() |
| 115 | + { |
| 116 | + has_data = true; |
| 117 | + return &P0; |
| 118 | + } |
89 | 119 | Group* end() { return &P1 + 1; } |
90 | 120 | const Group* begin() const { return &P0; } |
91 | 121 | const Group* end() const { return &P1 + 1; } |
@@ -244,16 +274,34 @@ template <typename Curve> struct PairingPoints { |
244 | 274 |
|
245 | 275 | /** |
246 | 276 | * @brief Set the witness indices for the default limbs of the pairing points to public. |
247 | | - * @details Creates default pairing points as witnesses, then sets them public. |
| 277 | + * @details Optimized version that directly sets precomputed Fr limb values as public inputs, |
| 278 | + * avoiding expensive bigfield operations. The default pairing points satisfy the |
| 279 | + * pairing equation, which is verified at compile time via static assertion. |
248 | 280 | * |
249 | 281 | * @return uint32_t The index into the public inputs array at which the representation is stored |
250 | 282 | */ |
251 | 283 | static uint32_t set_default_to_public(Builder* builder) |
252 | 284 | { |
253 | | - PairingPoints pp = construct_default(); |
254 | | - pp.P0.convert_constant_to_fixed_witness(builder); |
255 | | - pp.P1.convert_constant_to_fixed_witness(builder); |
256 | | - return pp.set_public(); |
| 285 | + // Directly add precomputed combined limbs as public inputs, bypassing bigfield's self_reduce. |
| 286 | + // These values encode the default pairing points in the format used by bigfield::set_public(). |
| 287 | + // Order: P0.x (lo, hi), P0.y (lo, hi), P1.x (lo, hi), P1.y (lo, hi) |
| 288 | + // Each fix_witness call adds 1 gate to constrain the value at the VK level. |
| 289 | + auto add_fixed_public = [&](const bb::fr& value) { |
| 290 | + uint32_t idx = builder->add_public_variable(value); |
| 291 | + builder->fix_witness(idx, value); |
| 292 | + return idx; |
| 293 | + }; |
| 294 | + |
| 295 | + uint32_t start_idx = add_fixed_public(DEFAULT_PP_P0_X_LO); |
| 296 | + add_fixed_public(DEFAULT_PP_P0_X_HI); |
| 297 | + add_fixed_public(DEFAULT_PP_P0_Y_LO); |
| 298 | + add_fixed_public(DEFAULT_PP_P0_Y_HI); |
| 299 | + add_fixed_public(DEFAULT_PP_P1_X_LO); |
| 300 | + add_fixed_public(DEFAULT_PP_P1_X_HI); |
| 301 | + add_fixed_public(DEFAULT_PP_P1_Y_LO); |
| 302 | + add_fixed_public(DEFAULT_PP_P1_Y_HI); |
| 303 | + |
| 304 | + return start_idx; |
257 | 305 | } |
258 | 306 |
|
259 | 307 | /** |
|
0 commit comments