@@ -30,7 +30,7 @@ unconstrained fn __batch_invert_impl<let N: u32>(mut x: [F; N]) -> [F; N] {
30
30
}
31
31
32
32
accumulator = accumulator .__invmod ();
33
- let mut T0 : F = BigNum ::new ();
33
+ let mut T0 : F = BigNum ::zero ();
34
34
for i in 0 ..N {
35
35
let idx = N - 1 - i ;
36
36
if (x [idx ].__is_zero () == false ) {
@@ -83,7 +83,7 @@ fn field_to_bignum(x: Field) -> F {
83
83
}
84
84
85
85
fn convert_blob_fields (blob_as_fields : [Field ; FIELDS_PER_BLOB ]) -> [F ; FIELDS_PER_BLOB ] {
86
- let mut blob : [F ; FIELDS_PER_BLOB ] = [BigNum ::new (); FIELDS_PER_BLOB ];
86
+ let mut blob : [F ; FIELDS_PER_BLOB ] = [BigNum ::zero (); FIELDS_PER_BLOB ];
87
87
for i in 0 ..FIELDS_PER_BLOB {
88
88
blob [i ] = field_to_bignum (blob_as_fields [i ]);
89
89
}
@@ -203,25 +203,27 @@ fn barycentric_evaluate_blob_at_z(z: F, ys: [F; FIELDS_PER_BLOB]) -> F {
203
203
// perhaps because all the omega^i terms are constant witnesses?
204
204
let fracs = compute_fracs (z , ys );
205
205
206
- // OK so...we can add multiple product terms into a sum...but I am not sure how many!
207
- // we are computing 254 * 254 bit products and we need to ensure each product limb doesn't overflow
208
- // each limb is 120 bits => 120 * 120 = 240 bits.
209
- // however when computing a mul we add up to 5 product terms into a single field element => 243 bits (ish)
210
- // when we do a modular reduction we validate that a field element >> 120 bits is less than 2^{126} which implies we have 246 bits to play with
211
- // which implies...we can accommodate up to EIGHT additions of product terms before we risk overflowing
212
- // (this is really messy! I never considered the case of giant linear sequences of products)
206
+ let sum = if !std::runtime:: is_unconstrained () {
207
+ // OK so...we can add multiple product terms into a sum...but I am not sure how many!
208
+ // we are computing 254 * 254 bit products and we need to ensure each product limb doesn't overflow
209
+ // each limb is 120 bits => 120 * 120 = 240 bits.
210
+ // however when computing a mul we add up to 5 product terms into a single field element => 243 bits (ish)
211
+ // when we do a modular reduction we validate that a field element >> 120 bits is less than 2^{126} which implies we have 246 bits to play with
212
+ // which implies...we can accommodate up to EIGHT additions of product terms before we risk overflowing
213
+ // (this is really messy! I never considered the case of giant linear sequences of products)
213
214
214
- // Seeking:
215
- // ___d-1
216
- // \ omega^i
217
- // sum = / y_i . ---------
218
- // /____ z - omega^i
219
- // i=0
220
- let NUM_PARTIAL_SUMS = FIELDS_PER_BLOB / 8 ;
221
- /// Safety: This sum is checked by the following `BigNum::evaluate_quadratic_expression` calls.
222
- let partial_sums : [F ; FIELDS_PER_BLOB / 8 ] = unsafe { __compute_partial_sums (fracs , ROOTS ) };
215
+ // Seeking:
216
+ // ___d-1
217
+ // \ omega^i
218
+ // sum = / y_i . ---------
219
+ // /____ z - omega^i
220
+ // i=0
221
+
222
+ let NUM_PARTIAL_SUMS = FIELDS_PER_BLOB / 8 ;
223
+ /// Safety: This sum is checked by the following `BigNum::evaluate_quadratic_expression` calls.
224
+ let partial_sums : [F ; FIELDS_PER_BLOB / 8 ] =
225
+ unsafe { __compute_partial_sums (fracs , ROOTS ) };
223
226
224
- if !std::runtime:: is_unconstrained () {
225
227
// We split off the first term to check the initial sum
226
228
227
229
// partial_sums[0] <- (lhs[0] * rhs[0] + ... + lhs[7] * rhs[7])
@@ -295,10 +297,20 @@ fn barycentric_evaluate_blob_at_z(z: F, ys: [F; FIELDS_PER_BLOB]) -> F {
295
297
[false , true ],
296
298
);
297
299
}
298
- }
300
+
301
+ // The final term in `partial_sums` is then the full sum.
302
+ partial_sums [FIELDS_PER_BLOB / 8 - 1 ]
303
+ } else {
304
+ // There's no need to jump through hoops to check partial sums if we don't need to constrain the result.
305
+ // We can just calculate the final sum.
306
+
307
+ /// Safety: We're running under the condition that `std::runtime::is_unconstrained()` is true.
308
+ unsafe {
309
+ __compute_sum (fracs , ROOTS )
310
+ }
311
+ };
299
312
300
313
let factor = compute_factor (z );
301
- let sum = partial_sums [FIELDS_PER_BLOB / 8 - 1 ];
302
314
factor .mul (sum )
303
315
}
304
316
@@ -352,7 +364,7 @@ unconstrained fn __compute_fracs(
352
364
ys : [F ; FIELDS_PER_BLOB ],
353
365
unconstrained_roots : [F ; FIELDS_PER_BLOB ],
354
366
) -> [F ; FIELDS_PER_BLOB ] {
355
- let mut denoms = [BigNum ::new (); FIELDS_PER_BLOB ];
367
+ let mut denoms = [BigNum ::zero (); FIELDS_PER_BLOB ];
356
368
for i in 0 ..FIELDS_PER_BLOB {
357
369
denoms [i ] = z .__sub (unconstrained_roots [i ]); // (z - omega^i)
358
370
}
@@ -407,7 +419,7 @@ unconstrained fn __compute_partial_sums(
407
419
// k=i*8 + 0
408
420
409
421
// Need to split off the first iteration.
410
- let mut partial_sum : F = BigNum ::new ();
422
+ let mut partial_sum : F = BigNum ::zero ();
411
423
for i in 0 ..8 {
412
424
// y_k * ( omega^k / (z - omega^k) )
413
425
let summand = unconstrained_roots [i ].__mul (fracs [i ]);
@@ -439,6 +451,28 @@ unconstrained fn __compute_partial_sums(
439
451
partial_sums
440
452
}
441
453
454
+ unconstrained fn __compute_sum (
455
+ fracs : [F ; FIELDS_PER_BLOB ],
456
+ unconstrained_roots : [F ; FIELDS_PER_BLOB ],
457
+ ) -> F {
458
+ // Seeking:
459
+ // ___d-1
460
+ // \ omega^i
461
+ // sum = / y_i . ---------
462
+ // /____ z - omega^i
463
+ // i=0
464
+
465
+ let mut sum : F = BigNum ::zero ();
466
+ for i in 0 ..FIELDS_PER_BLOB {
467
+ // y_k * ( omega^k / (z - omega^k) )
468
+ let summand = unconstrained_roots [i ].__mul (fracs [i ]);
469
+
470
+ // partial_sum + ( y_k * ( omega^k / (z - omega^k) ) -> partial_sum
471
+ sum = sum .__add (summand );
472
+ }
473
+ sum
474
+ }
475
+
442
476
mod tests {
443
477
// TODO(#9982): Replace unconstrained_config with config and import ROOTS - calculating ROOTS in unconstrained is insecure.
444
478
use crate:: {
@@ -447,8 +481,9 @@ mod tests {
447
481
field_to_bignum ,
448
482
},
449
483
blob_public_inputs::BlobCommitment ,
450
- config ::{D , D_INV , F },
484
+ config ::{D , D_INV , F , ROOTS },
451
485
};
486
+ use super:: {__compute_partial_sums , __compute_sum };
452
487
use bigint:: {BigNum , fields::bls12_381Fr::BLS12_381_Fr_Params };
453
488
use bigint::bignum::BigNumTrait ;
454
489
use types:: {
@@ -632,7 +667,7 @@ mod tests {
632
667
let z : F = BigNum { limbs : [2 , 0 , 0 ] };
633
668
634
669
// many y's form a blob:
635
- let mut ys : [F ; FIELDS_PER_BLOB ] = [BigNum ::new (); FIELDS_PER_BLOB ];
670
+ let mut ys : [F ; FIELDS_PER_BLOB ] = [BigNum ::zero (); FIELDS_PER_BLOB ];
636
671
637
672
ys [0 ] = BigNum { limbs : [0x1234 , 0 , 0 ] };
638
673
ys [1 ] = BigNum { limbs : [0xabcd , 0 , 0 ] };
@@ -683,5 +718,19 @@ mod tests {
683
718
let d_inversed = D .__invmod ();
684
719
assert_eq (d_inversed , D_INV );
685
720
}
721
+
722
+ #[test]
723
+ fn compute_sum_and_compute_partial_sums_agree () {
724
+ let mut fields = [BigNum ::zero (); FIELDS_PER_BLOB ];
725
+ for i in 0 ..FIELDS_PER_BLOB {
726
+ fields [i ] = field_to_bignum (i as Field );
727
+ }
728
+ unsafe {
729
+ let partial_sums = __compute_partial_sums (fields , ROOTS );
730
+ let sum = __compute_sum (fields , ROOTS );
731
+
732
+ assert_eq (partial_sums [FIELDS_PER_BLOB / 8 - 1 ], sum );
733
+ }
734
+ }
686
735
}
687
736
0 commit comments