class_groups/crypto_bigint/element.rs
1use core::{ops::Neg, fmt::Debug};
2
3use zeroize::Zeroize;
4
5use crypto_bigint::{
6 Choice, CtOption, CtEq, CtGt as _, CtSelect, CtAssign as _, BitOps, NonZero, One as _, Limb,
7 UintRef,
8};
9
10use super::I;
11
12use crate::Element;
13#[cfg(feature = "alloc")]
14use crate::Table;
15
16pub(super) trait Limbs:
17 Send
18 + Sync
19 + Debug
20 + Zeroize
21 + CtEq
22 + CtSelect
23 + BitOps
24 + super::composition::Limbs<
25 Wide: Send
26 + Sync
27 + Debug
28 + Zeroize
29 + CtSelect
30 + BitOps
31 + super::c::Limbs
32 + super::reduction::Limbs,
33 > + super::encoding::Limbs
34{
35 type Bytes: AsRef<[u8]> + AsMut<[u8]>;
36
37 /// The maximum amount of bits this value can support.
38 ///
39 /// `None` signifies this value is unbounded.
40 fn max_bits() -> Option<u32>;
41
42 /// Truncate `wide` to a member of `Self`.
43 ///
44 /// `bits`, a bound on the size of the result, is provided. The value in `wide` MUST be less than
45 /// $2^{bits}$. `bits` MUST be less than or equal to `Self::max_bits()` when
46 /// `Self::max_bits().is_some()`.
47 fn truncate(wide: Self::Wide, bits: u32) -> Self;
48
49 /// Widen `thin` to a member of `Self::Wide`.
50 ///
51 /// `wide_bits` is a bound on how big the widened type should be able to support. The value in
52 /// `thin` MUST be less than $2^{wide_bits}$. `wide_bits` MUST be less than or equal to
53 /// `2 * Self::max_bits()` when `Self::max_bits().is_some()`.
54 fn widen(thin: Self, wide_bits: u32) -> Self::Wide;
55
56 /// Convert this number to a sequence of little-endian bytes.
57 ///
58 /// This function MUST run in constant time and yield a result of length constant to the relevant
59 /// bound.
60 fn to_le_bytes(self) -> Self::Bytes;
61
62 /// Convert this wide number to a sequence of little-endian bytes.
63 ///
64 /// This function MUST run in constant time and yield a result of length constant to the relevant
65 /// bound.
66 fn wide_to_le_bytes(wide: Self::Wide) -> impl AsRef<[u8]>;
67
68 /// Load this number from a sequence of little-endian bytes.
69 ///
70 /// The slice MAY be of arbitrary length so long as the encoded value has bits less than or
71 /// equal to `max_bits`. `max_bits` MUST be less than or equal to `Self::max_bits()` when
72 /// `Self::max_bits().is_some()`.
73 fn from_le_slice(bytes: &[u8], max_bits: u32) -> Self;
74
75 /// Load a wide number from a sequence of little-endian bytes.
76 ///
77 /// The slice MAY be of arbitrary length so long as the encoded value has bits less than or
78 /// equal to `max_bits`.`max_bits` MUST be less than or equal to `2 * Self::max_bits()` when
79 /// `Self::max_bits().is_some()`.
80 fn wide_from_le_slice(bytes: &[u8], max_bits: u32) -> Self::Wide;
81
82 /// Stich together two byte sequences into a single container of length `2 * bytes_per_element`.
83 fn stitch(first: Self::Bytes, second: Self::Bytes, bytes_per_element: usize) -> impl AsRef<[u8]>;
84}
85
86/// A constant-time primitive element of a class group, implemented via `crypto-bigint`.
87///
88/// This only supports discriminants `delta` such that $delta < 0, |delta| \cong 1 \mod 2$.
89///
90/// This is implemented in time variable to the discriminant yet constant to the `a, b, c`
91/// coefficients. This prevents timing analysis from leaking the elements being composed. It is
92/// only recommended for provers as it has a significant performance overhead compared to other
93/// backends, which verifiers should take advantage of.
94///
95/// This implementation does not itself allocate and can be used with [`crypto_bigint::Uint`] to
96/// achieve elements which are fixed size and live on the stack, albeit only with support for a
97/// bounded subset of discriminants. Alternatively, [`crypto_bigint::BoxedUint`] may be used to
98/// support all discriminants, at the cost of using the heap.
99#[expect(private_bounds)]
100#[derive(Clone, Debug)]
101pub struct CryptoBigintElement<U: Limbs> {
102 /// The `a` coefficient.
103 ///
104 /// This may not be reduced but is bounded to less than the square root of the discriminant.
105 a: U,
106
107 /// The `b` coefficient.
108 ///
109 /// This may not be reduced but is bounded to have an absolute value less than the square root of
110 /// the discriminant.
111 b: I<U>,
112
113 /// The `c` coefficient.
114 ///
115 /// This may not be reduced but is bounded to be less than the discriminant.
116 /*
117 This `c` coefficient satisfies `b^2 - 4ac = delta`. `b^2` is at most the discriminant itself.
118 This means `4ac` can be at most `2 |delta|` (for a negative discriminant, as we bound). This
119 means `ac` can be at most `2 |delta| / 4`, and therefore `c` itself is within that bound.
120 */
121 c: U::Wide,
122
123 /// The absolute value of the negative discriminant for this form.
124 ///
125 /// This is used to recalculate the `c` coefficient after composition.
126 discriminant_abs: U::Wide,
127}
128
129impl<U: Limbs> CtEq for CryptoBigintElement<U> {
130 /// This MAY return an incorrect result for forms of different discriminants.
131 fn ct_eq(&self, other: &Self) -> Choice {
132 let a = self.clone().reduce();
133 let other = other.clone().reduce();
134
135 /*
136 We do not check the `c` coefficient is equal, as if the `a, b` coefficients are equal, the
137 `c` coefficient will be so long as these forms are of the same discriminant (and if not,
138 we're allowed to return an incorrect result, which is why we don't check the discriminant).
139 */
140 a.a.ct_eq(&other.a) & a.b.0.ct_eq(&other.b.0) & a.b.1.ct_eq(&other.b.1)
141 }
142}
143
144impl<U: Limbs> PartialEq for CryptoBigintElement<U> {
145 fn eq(&self, other: &Self) -> bool {
146 bool::from(self.ct_eq(other))
147 }
148}
149impl<U: Limbs> Eq for CryptoBigintElement<U> {}
150
151#[expect(private_bounds)]
152impl<U: Limbs> CryptoBigintElement<U> {
153 /// This is only valid for forms of negative odd discriminant.
154 fn identity_from_discriminant(discriminant_abs: U::Wide) -> Self {
155 /*
156 The identity element has `a = 1`. As composition sets $a_3 = (a_1 * a_2) / gcd(a_1, a_2)^2$,
157 it's clear how having one $a_1 = 1$ causes $a_3 = a_2$ (or $a_2 = 1$ causes $a_3 = a_1$). As
158 for the `b` coefficient, the only `b` coefficient less than or equal to an `a` coefficient of
159 `1` (as required for a reduced form) is itself `1`. As `|b| == a`, then `b` must be positive.
160 Finally, for the `c` coefficient, we are able to calculate it from the `a, b` coefficients
161 and the discriminant.
162
163 The identity element is primitive as `gcd(a, b, c) = gcd(1, 1, c) = 1`.
164 */
165 let a = &[1];
166 let b = (Choice::TRUE, &[1]);
167
168 /*
169 `b^2 - 4ac = delta`
170 `b^2 - delta = 4ac`
171 `(b^2 - delta) / 4a = c`
172
173 where `b^2 = 1, delta < 0, a = 1` so
174
175 $(1 + |delta|) / 4 = c$
176 */
177 let mut c = discriminant_abs.clone();
178 {
179 let c = AsMut::<[Limb]>::as_mut(&mut c);
180 let mut i = 0;
181 let mut carry = Limb::ONE;
182 while i < c.len() {
183 // `|delta| >> 2`
184 if let Some(j) = i.checked_sub(1) {
185 c[j] |= c[i] << (Limb::BITS - 2);
186 }
187 c[i] >>= 2;
188 /*
189 `+ 1`, as `carry` was initialized to one.
190
191 This technically doesn't calculate $(1 + |delta|) / 4$ but $floor(|delta| / 4) + 1$.
192 These two values are equivalent when $|delta| \cong 3 \mod 4$.
193
194 We only explicitly bound $delta < 0, delta \cong 1 \mod 2$. By $b^2 - 4 a c = delta$, we
195 have $b^2 \cong delta \mod 4$. $3$ is not a square modulo $4$, so if
196 $delta \cong 1 \mod 2$ (as we bound), we MUST have $delta \cong 1 \mod 4$ (and therefore
197 $|delta| \cong 3 \mod 4$).
198 */
199 (c[i], carry) = c[i].carrying_add(Limb::ZERO, carry);
200 i += 1;
201 }
202 }
203
204 // SAFETY: This is well-defined, reduced, and primitive
205 unsafe {
206 <Self as Element>::from_coefficients(
207 a,
208 b,
209 U::wide_to_le_bytes(c),
210 U::wide_to_le_bytes(discriminant_abs),
211 )
212 }
213 }
214}
215
216impl<U: Limbs> Zeroize for CryptoBigintElement<U> {
217 /// This is only valid for forms of negative odd discriminant.
218 ///
219 /// This does not zeroize the discriminant, solely the `a, b, c` coefficients, and will set the
220 /// result to the identity element of the same discriminant.
221 fn zeroize(&mut self) {
222 // Zeroize
223 self.a.zeroize();
224 // Best effort, as `Choice: !Zeroize`
225 self.b.0.ct_assign(&Choice::TRUE, Choice::TRUE);
226 self.b.1.zeroize();
227 self.c.zeroize();
228
229 *self = Self::identity_from_discriminant(self.discriminant_abs.clone());
230 }
231}
232
233impl<U: Limbs> CtSelect for CryptoBigintElement<U> {
234 /// This MAY return an incorrect result for forms of different discriminants.
235 fn ct_select(&self, b: &Self, choice: Choice) -> Self {
236 Self {
237 a: U::ct_select(&self.a, &b.a, choice),
238 b: (<_>::ct_select(&self.b.0, &b.b.0, choice), <_>::ct_select(&self.b.1, &b.b.1, choice)),
239 c: U::Wide::ct_select(&self.c, &b.c, choice),
240 // This is the same when the forms are of the same discriminant, allowing us to simply use
241 // `self`'s without invoking `ct_select`
242 discriminant_abs: self.discriminant_abs.clone(),
243 }
244 }
245}
246
247impl<U: Limbs> Neg for CryptoBigintElement<U> {
248 type Output = Self;
249 /// This is only correct for primitives forms where $delta \cong 1 \mod 2$.
250 fn neg(mut self) -> Self {
251 /*
252 Per Proposition 5.2.5 of A Course in Computational Algebraic Number Theory, a binary
253 quadratic form is only invertible if `(a, b, c)` is primitive, hence why we bound the input
254 to be primitive.
255
256 Proposition 5.2.5 also includes a very academic description of the inverse, which here is
257 implemented as negating the `b` coefficient.
258
259 While `-0` is of unclear validity in this context, we know that this result will _NOT_ be
260 `-0` as $b \cong 1 \mod 2$ for odd discriminants (as we bound).
261 */
262 self.b.0 = !self.b.0;
263 self
264 }
265}
266
267#[expect(private_bounds)]
268impl<U: Limbs> CryptoBigintElement<U> {
269 /// Partially reduce an element.
270 ///
271 /// This assumes the coefficients are the result from composition (either addition or doubling)
272 /// of two well-defined instances of this type.
273 fn partial_reduce(a: U::Wide, b: I<U::Wide>, discriminant_abs: U::Wide) -> Self {
274 /*
275 `partial_reduce` yields `a, b` coefficients which are bounded by the square root of delta, so
276 the `a` from composition will be bounded by delta. The `b` coefficient is bound to be
277 within one bit of twice the resulting `a` coefficient or within one bit of the `b2`
278 coefficient used for composition, whichever is greater. As `b2` was also bounded by the
279 square root of delta, we know the bound from `a` to be the greater (and therefore the
280 relevant) bound.
281 */
282 let (a, b, c) =
283 super::partial_reduce(2 + discriminant_abs.bits_vartime(), a, b, &discriminant_abs);
284
285 /*
286 `partial_reduce` is guaranteed to return `a, b` which are each less then the square root of
287 the discriminant. We need one additional bit for these to be usable with our methods for
288 composition however.
289 */
290 let sqrt_discriminant_bits = discriminant_abs.bits_vartime().div_ceil(2);
291 let a = U::truncate(a, 1 + sqrt_discriminant_bits);
292 let b = (b.0, U::truncate(b.1, 1 + sqrt_discriminant_bits));
293 // These `a, b` coefficients are bounded by the square root of delta, as this type requires
294 // `c`'s bound, that it's bounded by the discriminant, is inherently satisfied from there
295 Self { a, b, c, discriminant_abs }
296 }
297
298 /// Reduce an element.
299 fn reduce(self) -> Self {
300 let discriminant_bits = self.discriminant_abs.bits_vartime();
301 let sqrt_discriminant_bits = discriminant_bits.div_ceil(2);
302 let (a, b, c) = super::reduce(
303 // The documentation on our `struct` require `a, b` satisfy this bound
304 sqrt_discriminant_bits,
305 // Widen these, as `reduce` requires all its arguments have the same capacity
306 U::widen(self.a, self.c.bits_precision()),
307 (self.b.0, U::widen(self.b.1, self.c.bits_precision())),
308 self.c,
309 );
310
311 /*
312 A reduced element has `|b| <= a < sqrt(|delta|)` per
313 Definition 5.3.2 and Lemma 5.3.4 of A Course in Computational Algebraic Number Theory.
314
315 We again keep one extra bit for these to be usable with our methods for composition.
316 */
317 let a = U::truncate(a, 1 + sqrt_discriminant_bits);
318 let b = (b.0, U::truncate(b.1, 1 + sqrt_discriminant_bits));
319 Self { a, b, c, discriminant_abs: self.discriminant_abs.clone() }
320 }
321}
322
323// SAFETY: This reduces the form before yielding it and does return a well-defined form as
324// required.
325unsafe impl<U: Limbs> crate::Coefficients for CryptoBigintElement<U> {
326 /// This function runs in constant time.
327 fn a_b_c_discriminant(
328 self,
329 ) -> (impl AsRef<[u8]>, (Choice, impl AsRef<[u8]>), impl AsRef<[u8]>, impl AsRef<[u8]>) {
330 let reduced = self.reduce();
331 (
332 reduced.a.to_le_bytes(),
333 (reduced.b.0, reduced.b.1.to_le_bytes()),
334 U::wide_to_le_bytes(reduced.c),
335 U::wide_to_le_bytes(reduced.discriminant_abs),
336 )
337 }
338}
339
340impl<U: Limbs> Element for CryptoBigintElement<U> {
341 /// This is only valid for forms of negative odd discriminant.
342 fn identity(discriminant_abs: impl AsRef<[u8]>) -> Self {
343 let discriminant_abs = discriminant_abs.as_ref();
344 assert_eq!(discriminant_abs[0] & 0b11, 0b11, "discriminant was not a valid odd discriminant");
345 Self::identity_from_discriminant(U::wide_from_le_slice(
346 discriminant_abs,
347 8 * u32::try_from(discriminant_abs.len()).expect("4 GB discriminant?"),
348 ))
349 }
350
351 /// This MAY return an incorrect result when the form doesn't have an odd, negative discriminant.
352 fn is_identity(&self) -> Choice {
353 let reduced = self.clone().reduce();
354
355 let a = AsRef::<[Limb]>::as_ref(&reduced.a);
356 let b = AsRef::<[Limb]>::as_ref(&reduced.b.1);
357
358 /*
359 We know the `a, b` coefficients are non-zero due to having a negative odd discriminant. We
360 check both have only the least-significant bit set.
361 */
362 let is_one = a[0] | b[0];
363 let mut is_zero = Limb::ZERO;
364 for limb in &a[1 ..] {
365 is_zero |= *limb;
366 }
367 for limb in &b[1 ..] {
368 is_zero |= *limb;
369 }
370 is_one.is_one() & is_zero.is_zero()
371 }
372
373 /// This is only correct for forms of the same discriminant where at least one form is primitive.
374 fn add(&self, other: &Self) -> Self {
375 let (a3, b3) =
376 super::add(self.a.clone(), self.b.clone(), other.a.clone(), other.b.clone(), other.c.clone());
377 Self::partial_reduce(a3, b3, self.discriminant_abs.clone())
378 }
379
380 /// This is only correct when the form is primitive.
381 fn double(&self) -> Self {
382 let (a3, b3) = super::double(self.a.clone(), self.b.clone(), self.c.clone());
383 Self::partial_reduce(a3, b3, self.discriminant_abs.clone())
384 }
385
386 /// This is only correct for forms of the same discriminant where at least one form is primitive.
387 fn sub(&self, other: Self) -> Self {
388 let (a3, b3) =
389 super::add(self.a.clone(), self.b.clone(), other.a, (!other.b.0, other.b.1), other.c);
390 Self::partial_reduce(a3, b3, self.discriminant_abs.clone())
391 }
392
393 /// This function is only valid for primitive reduced positive definite binary quadratic forms of
394 /// negative odd discriminant where the discriminant fits within `(2 * max_bits) - 2` bits.
395 ///
396 /// This function MAY run in time variable to:
397 /// - the byte-length of the inputs
398 /// - the validity of the inputs
399 /// - the discriminant
400 ///
401 /// This function MAY panic if asked to handle coefficients which exceed the capacity of the
402 /// underlying container(s).
403 unsafe fn from_coefficients(
404 a: impl AsRef<[u8]>,
405 (b_positive, b_abs): (Choice, impl AsRef<[u8]>),
406 c: impl AsRef<[u8]>,
407 discriminant_abs: impl AsRef<[u8]>,
408 ) -> Self {
409 let a = a.as_ref();
410 let b_abs = b_abs.as_ref();
411 let c = c.as_ref();
412 let discriminant_abs = discriminant_abs.as_ref();
413
414 let bit_len = |slice: &[u8]| {
415 if let Some(last) = slice.last() {
416 u32::try_from(8 * (slice.len() - 1))
417 .ok()
418 .and_then(|value| value.checked_add(Limb::from(*last).bits()))
419 .expect("slice exceeded 4 GB")
420 } else {
421 0
422 }
423 };
424
425 // Determine how many bits are actually in the absolute value of the discriminant
426 let discriminant_bits =
427 U::wide_from_le_slice(discriminant_abs, bit_len(discriminant_abs)).bits_vartime();
428 // Ensure our bound on the discriminant is respected
429 if let Some(max_bits) = U::max_bits() {
430 assert!(discriminant_bits <= ((2 * max_bits) - 2));
431 }
432
433 // Load the absolute value of the discriminant with the exact precision required
434 let discriminant_abs = U::wide_from_le_slice(discriminant_abs, discriminant_bits);
435
436 let sqrt_discriminant_bits = discriminant_bits.div_ceil(2);
437 let a = U::from_le_slice(a, 1 + sqrt_discriminant_bits);
438 assert!(bool::from(!a.bits().ct_gt(&sqrt_discriminant_bits)));
439 let b = (b_positive, U::from_le_slice(b_abs, 1 + sqrt_discriminant_bits));
440 assert!(bool::from(!b.1.bits().ct_gt(&sqrt_discriminant_bits)));
441 let c = U::wide_from_le_slice(c, discriminant_bits);
442
443 Self { a, b, c, discriminant_abs }
444 }
445
446 /// This runs in time variable to the size of the discriminant and the size of the underlying
447 /// container.
448 fn uncompressed_encode(self) -> impl AsRef<[u8]> {
449 let bits_per_element = ((self.discriminant_abs.bits() - 1) / 2) + 1;
450 let bytes_per_element = usize::try_from(bits_per_element.div_ceil(8)).unwrap();
451
452 let reduced = self.reduce();
453 let a = reduced.a.to_le_bytes();
454 let mut b = reduced.b.1.to_le_bytes();
455 b.as_mut()[0] ^= u8::from(!reduced.b.0);
456
457 U::stitch(a, b, bytes_per_element)
458 }
459
460 /// This runs in time variable to the size of the discriminant and the size of the underlying
461 /// container. This MAY return `None` for discriminants which fit within the bounds but have
462 /// trailing zero bytes which cause the amount of encoded bits to exceed the bounds.
463 fn uncompressed_decode(
464 buf: impl AsRef<[u8]>,
465 discriminant_abs: impl AsRef<[u8]>,
466 ) -> CtOption<Self> {
467 let discriminant_abs = discriminant_abs.as_ref();
468
469 let invalid_size = CtOption::new(
470 Self {
471 a: U::from_le_slice(&[], 1),
472 b: (Choice::TRUE, U::from_le_slice(&[], 1)),
473 c: U::wide_from_le_slice(&[], 1),
474 discriminant_abs: U::wide_from_le_slice(&[], 1),
475 },
476 Choice::FALSE,
477 );
478 let discriminant_bits = {
479 let Ok(discriminant_bytes) = u32::try_from(discriminant_abs.len()) else {
480 return invalid_size;
481 };
482 let Some(msb) = discriminant_abs.last().copied() else { return invalid_size };
483 /*
484 This is lossy in that it _may_ believe a discriminant is larger than it actually is, but
485 only if the discriminant has trailing zero bytes, which we're allowed to not support.
486 */
487 let Some(discriminant_bits) = 8u32.checked_mul(discriminant_bytes) else {
488 return invalid_size;
489 };
490 let discriminant_bits = discriminant_bits - (8 - Limb::from(msb).bits());
491
492 if let Some(max_bits) = U::max_bits() {
493 if discriminant_bits > (2u32.checked_mul(max_bits).unwrap_or(0).saturating_sub(2)) {
494 return invalid_size;
495 }
496 }
497
498 discriminant_bits
499 };
500
501 let discriminant_bits =
502 UintRef::new(U::wide_from_le_slice(discriminant_abs, discriminant_bits).as_ref()).bits();
503 let discriminant_abs = U::wide_from_le_slice(discriminant_abs, discriminant_bits);
504
505 let bits_per_element = (discriminant_abs.bits() / 2) + 1;
506 let bytes_per_element = usize::try_from(bits_per_element.div_ceil(8)).unwrap();
507
508 let buf = buf.as_ref();
509 if buf.len() != (2 * bytes_per_element) {
510 return invalid_size;
511 }
512
513 let sqrt_discriminant_bits = discriminant_bits.div_ceil(2);
514 let a = U::from_le_slice(&buf[.. bytes_per_element], 1 + sqrt_discriminant_bits);
515 let mut b_abs = U::from_le_slice(&buf[bytes_per_element ..], 1 + sqrt_discriminant_bits);
516
517 let b_positive =
518 (b_abs.as_ref()[0] & Limb::ONE).ct_eq(&(discriminant_abs.as_ref()[0] & Limb::ONE));
519 b_abs.as_mut()[0] ^= Limb::from(u8::from(!b_positive));
520
521 NonZero::new(a).and_then(|a| {
522 super::encoding::validate_binary_quadratic_form(a, (b_positive, b_abs), &discriminant_abs)
523 .map(|(a, b, c)| Self { a: a.get(), b, c, discriminant_abs })
524 })
525 }
526}
527
528// TODO
529#[cfg(feature = "alloc")]
530impl<U: Limbs> crate::ElementExt for CryptoBigintElement<U> {
531 const MAX_TABLE_BITS: u32 = 12;
532
533 /// This is only correct when `identity` is in fact the identity element for the class group the
534 /// elements in the table belong to.
535 fn multiexp(identity: &Self, pairs: &[(&Table<Self>, &[u8])]) -> Self {
536 let mut longest_scalar_bits = 0;
537 for (_table, scalar) in pairs {
538 longest_scalar_bits = longest_scalar_bits.max(scalar.len() * 8);
539 }
540
541 let mut res: Option<Self> = None;
542 for i in 0 .. longest_scalar_bits {
543 // Shift over the existing result by a bit
544 if let Some(res) = res.as_mut() {
545 *res = res.double();
546 }
547
548 for (table, scalar) in pairs {
549 let scalar_bits = scalar.len() * 8;
550 // Transform the index of the bit in our longest scalar to the index of the bit in this one
551 let Some(i) = i.checked_sub(longest_scalar_bits - scalar_bits) else {
552 // If we're indexing a bit which doesn't exist in this scalar, continue
553 continue;
554 };
555
556 // If it's time to add this entry, do so
557 let table_bits = table.bits();
558 if ((i + 1) % table_bits) == 0 {
559 let mut accum = 0usize;
560 debug_assert_eq!(i - (i + 1 - table_bits) + 1, table_bits);
561 for i in (i + 1 - table_bits) ..= i {
562 accum <<= 1;
563 accum |= (usize::from(scalar[i / 8] >> (7 - (i % 8)))) & 1;
564 }
565
566 let mut to_add = Self::ct_select(&table[0], &table[1], 1.ct_eq(&accum));
567 for i in 2 .. table.as_ref().len() {
568 to_add = Self::ct_select(&to_add, &table[i], i.ct_eq(&accum));
569 }
570 res = Some(res.as_ref().map(|res| res.add(&to_add)).unwrap_or_else(|| to_add.clone()));
571 }
572 }
573 }
574
575 // Perform the final step of the accumulator
576 for (table, scalar) in pairs {
577 let scalar_bits = scalar.len() * 8;
578
579 let table_bits = table.bits();
580 let mut accum = 0usize;
581 for i in ((scalar_bits / table_bits) * table_bits) .. scalar_bits {
582 accum <<= 1;
583 accum |= (usize::from(scalar[i / 8] >> (7 - (i % 8)))) & 1;
584 }
585
586 let mut to_add = Self::ct_select(&table[0], &table[1], 1.ct_eq(&accum));
587 for i in 2 .. table.as_ref().len() {
588 to_add = Self::ct_select(&to_add, &table[i], i.ct_eq(&accum));
589 }
590 res = Some(res.as_ref().map(|res| res.add(&to_add)).unwrap_or_else(|| to_add.clone()));
591 }
592
593 res.unwrap_or_else(|| identity.clone())
594 }
595}