1use num_bigint::BigUint;
3use num_traits::One;
4use serde::{Deserialize, Serialize};
5use slop_algebra::{
6 AbstractExtensionField, AbstractField, ExtensionField, Field, Packable, PrimeField32,
7};
8use std::{
9 array,
10 fmt::Display,
11 iter::{Product, Sum},
12 ops::{Add, AddAssign, Div, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign},
13};
14
15use crate::air::{SP1AirBuilder, SepticExtensionAirBuilder};
16
17#[derive(
21 Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq, Hash, deepsize2::DeepSizeOf,
22)]
23#[repr(C)]
24pub struct SepticExtension<F>(pub [F; 7]);
25
26impl<F: AbstractField> AbstractField for SepticExtension<F> {
27 type F = SepticExtension<F::F>;
28
29 fn zero() -> Self {
30 SepticExtension([
31 F::zero(),
32 F::zero(),
33 F::zero(),
34 F::zero(),
35 F::zero(),
36 F::zero(),
37 F::zero(),
38 ])
39 }
40
41 fn one() -> Self {
42 SepticExtension([
43 F::one(),
44 F::zero(),
45 F::zero(),
46 F::zero(),
47 F::zero(),
48 F::zero(),
49 F::zero(),
50 ])
51 }
52
53 fn two() -> Self {
54 SepticExtension([
55 F::two(),
56 F::zero(),
57 F::zero(),
58 F::zero(),
59 F::zero(),
60 F::zero(),
61 F::zero(),
62 ])
63 }
64
65 fn neg_one() -> Self {
66 SepticExtension([
67 F::neg_one(),
68 F::zero(),
69 F::zero(),
70 F::zero(),
71 F::zero(),
72 F::zero(),
73 F::zero(),
74 ])
75 }
76
77 fn from_f(f: Self::F) -> Self {
78 SepticExtension([
79 F::from_f(f.0[0]),
80 F::from_f(f.0[1]),
81 F::from_f(f.0[2]),
82 F::from_f(f.0[3]),
83 F::from_f(f.0[4]),
84 F::from_f(f.0[5]),
85 F::from_f(f.0[6]),
86 ])
87 }
88
89 fn from_bool(b: bool) -> Self {
90 SepticExtension([
91 F::from_bool(b),
92 F::zero(),
93 F::zero(),
94 F::zero(),
95 F::zero(),
96 F::zero(),
97 F::zero(),
98 ])
99 }
100
101 fn from_canonical_u8(n: u8) -> Self {
102 SepticExtension([
103 F::from_canonical_u8(n),
104 F::zero(),
105 F::zero(),
106 F::zero(),
107 F::zero(),
108 F::zero(),
109 F::zero(),
110 ])
111 }
112
113 fn from_canonical_u16(n: u16) -> Self {
114 SepticExtension([
115 F::from_canonical_u16(n),
116 F::zero(),
117 F::zero(),
118 F::zero(),
119 F::zero(),
120 F::zero(),
121 F::zero(),
122 ])
123 }
124
125 fn from_canonical_u32(n: u32) -> Self {
126 SepticExtension([
127 F::from_canonical_u32(n),
128 F::zero(),
129 F::zero(),
130 F::zero(),
131 F::zero(),
132 F::zero(),
133 F::zero(),
134 ])
135 }
136
137 fn from_canonical_u64(n: u64) -> Self {
138 SepticExtension([
139 F::from_canonical_u64(n),
140 F::zero(),
141 F::zero(),
142 F::zero(),
143 F::zero(),
144 F::zero(),
145 F::zero(),
146 ])
147 }
148
149 fn from_canonical_usize(n: usize) -> Self {
150 SepticExtension([
151 F::from_canonical_usize(n),
152 F::zero(),
153 F::zero(),
154 F::zero(),
155 F::zero(),
156 F::zero(),
157 F::zero(),
158 ])
159 }
160
161 fn from_wrapped_u32(n: u32) -> Self {
162 SepticExtension([
163 F::from_wrapped_u32(n),
164 F::zero(),
165 F::zero(),
166 F::zero(),
167 F::zero(),
168 F::zero(),
169 F::zero(),
170 ])
171 }
172
173 fn from_wrapped_u64(n: u64) -> Self {
174 SepticExtension([
175 F::from_wrapped_u64(n),
176 F::zero(),
177 F::zero(),
178 F::zero(),
179 F::zero(),
180 F::zero(),
181 F::zero(),
182 ])
183 }
184
185 fn generator() -> Self {
186 SepticExtension([
187 F::zero(),
188 F::one(),
189 F::zero(),
190 F::zero(),
191 F::zero(),
192 F::zero(),
193 F::zero(),
194 ])
195 }
196}
197
198impl<F: Field> Field for SepticExtension<F> {
199 type Packing = Self;
200
201 fn try_inverse(&self) -> Option<Self> {
202 if self.is_zero() {
203 return None;
204 }
205 Some(self.inv())
206 }
207
208 fn order() -> BigUint {
209 F::order().pow(7)
210 }
211}
212
213impl<F: AbstractField> AbstractExtensionField<F> for SepticExtension<F> {
214 const D: usize = 7;
215
216 fn from_base(b: F) -> Self {
217 SepticExtension([b, F::zero(), F::zero(), F::zero(), F::zero(), F::zero(), F::zero()])
218 }
219
220 fn from_base_slice(bs: &[F]) -> Self {
221 SepticExtension([
222 bs[0].clone(),
223 bs[1].clone(),
224 bs[2].clone(),
225 bs[3].clone(),
226 bs[4].clone(),
227 bs[5].clone(),
228 bs[6].clone(),
229 ])
230 }
231
232 fn from_base_fn<G: FnMut(usize) -> F>(f: G) -> Self {
233 Self(array::from_fn(f))
234 }
235
236 fn as_base_slice(&self) -> &[F] {
237 self.0.as_slice()
238 }
239}
240
241impl<F: Field> ExtensionField<F> for SepticExtension<F> {
242 type ExtensionPacking = SepticExtension<F::Packing>;
243}
244
245impl<F: Field> Packable for SepticExtension<F> {}
246
247impl<F: AbstractField> Add for SepticExtension<F> {
248 type Output = Self;
249
250 fn add(self, rhs: Self) -> Self::Output {
251 let mut res = self.0;
252 for (r, rhs_val) in res.iter_mut().zip(rhs.0) {
253 *r = (*r).clone() + rhs_val;
254 }
255 Self(res)
256 }
257}
258
259impl<F: AbstractField> AddAssign for SepticExtension<F> {
260 fn add_assign(&mut self, rhs: Self) {
261 self.0[0] += rhs.0[0].clone();
262 self.0[1] += rhs.0[1].clone();
263 self.0[2] += rhs.0[2].clone();
264 self.0[3] += rhs.0[3].clone();
265 self.0[4] += rhs.0[4].clone();
266 self.0[5] += rhs.0[5].clone();
267 self.0[6] += rhs.0[6].clone();
268 }
269}
270
271impl<F: AbstractField> Sub for SepticExtension<F> {
272 type Output = Self;
273
274 fn sub(self, rhs: Self) -> Self::Output {
275 let mut res = self.0;
276 for (r, rhs_val) in res.iter_mut().zip(rhs.0) {
277 *r = (*r).clone() - rhs_val;
278 }
279 Self(res)
280 }
281}
282
283impl<F: AbstractField> SubAssign for SepticExtension<F> {
284 fn sub_assign(&mut self, rhs: Self) {
285 self.0[0] -= rhs.0[0].clone();
286 self.0[1] -= rhs.0[1].clone();
287 self.0[2] -= rhs.0[2].clone();
288 self.0[3] -= rhs.0[3].clone();
289 self.0[4] -= rhs.0[4].clone();
290 self.0[5] -= rhs.0[5].clone();
291 self.0[6] -= rhs.0[6].clone();
292 }
293}
294
295impl<F: AbstractField> Neg for SepticExtension<F> {
296 type Output = Self;
297
298 fn neg(self) -> Self::Output {
299 let mut res = self.0;
300 for r in res.iter_mut() {
301 *r = -r.clone();
302 }
303 Self(res)
304 }
305}
306
307impl<F: AbstractField> Mul for SepticExtension<F> {
308 type Output = Self;
309
310 fn mul(self, rhs: Self) -> Self::Output {
312 let mut res: [F; 13] = core::array::from_fn(|_| F::zero());
313 for i in 0..7 {
314 for j in 0..7 {
315 res[i + j] = res[i + j].clone() + self.0[i].clone() * rhs.0[j].clone();
316 }
317 }
318 let mut ret: [F; 7] = core::array::from_fn(|i| res[i].clone());
319 for i in 7..13 {
320 ret[i - 7] = ret[i - 7].clone() + res[i].clone() * F::from_canonical_u32(5);
321 ret[i - 6] = ret[i - 6].clone() + res[i].clone() * F::from_canonical_u32(3);
322 }
323 Self(ret)
324 }
325}
326
327impl<F: AbstractField> MulAssign for SepticExtension<F> {
328 fn mul_assign(&mut self, rhs: Self) {
329 let res = self.clone() * rhs;
330 *self = res;
331 }
332}
333
334impl<F: AbstractField> Product for SepticExtension<F> {
335 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
336 let one = Self::one();
337 iter.fold(one, |acc, x| acc * x)
338 }
339}
340
341impl<F: AbstractField> Sum for SepticExtension<F> {
342 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
343 let zero = Self::zero();
344 iter.fold(zero, |acc, x| acc + x)
345 }
346}
347
348impl<F: AbstractField> From<F> for SepticExtension<F> {
349 fn from(f: F) -> Self {
350 SepticExtension([f, F::zero(), F::zero(), F::zero(), F::zero(), F::zero(), F::zero()])
351 }
352}
353
354impl<F: AbstractField> Add<F> for SepticExtension<F> {
355 type Output = Self;
356
357 fn add(self, rhs: F) -> Self::Output {
358 SepticExtension([
359 self.0[0].clone() + rhs,
360 self.0[1].clone(),
361 self.0[2].clone(),
362 self.0[3].clone(),
363 self.0[4].clone(),
364 self.0[5].clone(),
365 self.0[6].clone(),
366 ])
367 }
368}
369
370impl<F: AbstractField> AddAssign<F> for SepticExtension<F> {
371 fn add_assign(&mut self, rhs: F) {
372 self.0[0] += rhs;
373 }
374}
375
376impl<F: AbstractField> Sub<F> for SepticExtension<F> {
377 type Output = Self;
378
379 fn sub(self, rhs: F) -> Self::Output {
380 self + (-rhs)
381 }
382}
383
384impl<F: AbstractField> SubAssign<F> for SepticExtension<F> {
385 fn sub_assign(&mut self, rhs: F) {
386 self.0[0] -= rhs;
387 }
388}
389
390impl<F: AbstractField> Mul<F> for SepticExtension<F> {
391 type Output = Self;
392
393 fn mul(self, rhs: F) -> Self::Output {
394 SepticExtension([
395 self.0[0].clone() * rhs.clone(),
396 self.0[1].clone() * rhs.clone(),
397 self.0[2].clone() * rhs.clone(),
398 self.0[3].clone() * rhs.clone(),
399 self.0[4].clone() * rhs.clone(),
400 self.0[5].clone() * rhs.clone(),
401 self.0[6].clone() * rhs.clone(),
402 ])
403 }
404}
405
406impl<F: AbstractField> MulAssign<F> for SepticExtension<F> {
407 fn mul_assign(&mut self, rhs: F) {
408 for i in 0..7 {
409 self.0[i] *= rhs.clone();
410 }
411 }
412}
413
414impl<F: Field> Div for SepticExtension<F> {
415 type Output = Self;
416
417 #[allow(clippy::suspicious_arithmetic_impl)]
418 fn div(self, rhs: Self) -> Self::Output {
419 self * rhs.inverse()
420 }
421}
422
423impl<F: AbstractField> Display for SepticExtension<F> {
424 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
425 write!(f, "{:?}", self.0)
426 }
427}
428
429impl<F: Field> SepticExtension<F> {
430 fn z_pow_p(index: u32) -> Self {
432 debug_assert_eq!(F::order(), BigUint::from(2130706433u32));
434 if index == 0 {
435 return Self::one();
436 }
437 if index == 1 {
438 return SepticExtension([
439 F::from_canonical_u32(1272123317),
440 F::from_canonical_u32(1950759909),
441 F::from_canonical_u32(1879852731),
442 F::from_canonical_u32(746569225),
443 F::from_canonical_u32(180350946),
444 F::from_canonical_u32(1600835585),
445 F::from_canonical_u32(333893434),
446 ]);
447 }
448 if index == 2 {
449 return SepticExtension([
450 F::from_canonical_u32(129050189),
451 F::from_canonical_u32(1749509219),
452 F::from_canonical_u32(983995729),
453 F::from_canonical_u32(711096547),
454 F::from_canonical_u32(1505254548),
455 F::from_canonical_u32(639452798),
456 F::from_canonical_u32(68186395),
457 ]);
458 }
459 if index == 3 {
460 return SepticExtension([
461 F::from_canonical_u32(1911662442),
462 F::from_canonical_u32(1095215454),
463 F::from_canonical_u32(1794102427),
464 F::from_canonical_u32(1173566779),
465 F::from_canonical_u32(140526665),
466 F::from_canonical_u32(110899104),
467 F::from_canonical_u32(1387282150),
468 ]);
469 }
470 if index == 4 {
471 return SepticExtension([
472 F::from_canonical_u32(1366416596),
473 F::from_canonical_u32(1212861),
474 F::from_canonical_u32(2104391040),
475 F::from_canonical_u32(1447859676),
476 F::from_canonical_u32(308944373),
477 F::from_canonical_u32(106444152),
478 F::from_canonical_u32(1362577042),
479 ]);
480 }
481 if index == 5 {
482 return SepticExtension([
483 F::from_canonical_u32(1411781189),
484 F::from_canonical_u32(1580508159),
485 F::from_canonical_u32(1332301780),
486 F::from_canonical_u32(1528790701),
487 F::from_canonical_u32(380217034),
488 F::from_canonical_u32(1752756730),
489 F::from_canonical_u32(989817517),
490 ]);
491 }
492 if index == 6 {
493 return SepticExtension([
494 F::from_canonical_u32(37669840),
495 F::from_canonical_u32(439102875),
496 F::from_canonical_u32(410223214),
497 F::from_canonical_u32(964813232),
498 F::from_canonical_u32(1250258104),
499 F::from_canonical_u32(877333757),
500 F::from_canonical_u32(222095778),
501 ]);
502 }
503 unreachable!();
504 }
505
506 fn z_pow_p2(index: u32) -> Self {
508 debug_assert_eq!(F::order(), BigUint::from(2130706433u32));
510 if index == 0 {
511 return Self::one();
512 }
513 if index == 1 {
514 return SepticExtension([
515 F::from_canonical_u32(1330073564),
516 F::from_canonical_u32(1724372201),
517 F::from_canonical_u32(942213154),
518 F::from_canonical_u32(258987814),
519 F::from_canonical_u32(1836986639),
520 F::from_canonical_u32(566030553),
521 F::from_canonical_u32(2086945921),
522 ]);
523 }
524 if index == 2 {
525 return SepticExtension([
526 F::from_canonical_u32(473977877),
527 F::from_canonical_u32(99096011),
528 F::from_canonical_u32(1919717963),
529 F::from_canonical_u32(733784355),
530 F::from_canonical_u32(1167998744),
531 F::from_canonical_u32(19619652),
532 F::from_canonical_u32(1354518805),
533 ]);
534 }
535 if index == 3 {
536 return SepticExtension([
537 F::from_canonical_u32(1040563478),
538 F::from_canonical_u32(1866766699),
539 F::from_canonical_u32(1875293643),
540 F::from_canonical_u32(846885082),
541 F::from_canonical_u32(1921678452),
542 F::from_canonical_u32(2127718474),
543 F::from_canonical_u32(1489297699),
544 ]);
545 }
546 if index == 4 {
547 return SepticExtension([
548 F::from_canonical_u32(1350284585),
549 F::from_canonical_u32(1583164394),
550 F::from_canonical_u32(512913106),
551 F::from_canonical_u32(1818487640),
552 F::from_canonical_u32(2116891899),
553 F::from_canonical_u32(318922921),
554 F::from_canonical_u32(1013732863),
555 ]);
556 }
557 if index == 5 {
558 return SepticExtension([
559 F::from_canonical_u32(887772098),
560 F::from_canonical_u32(1971095075),
561 F::from_canonical_u32(843183752),
562 F::from_canonical_u32(711838602),
563 F::from_canonical_u32(1717807390),
564 F::from_canonical_u32(521017530),
565 F::from_canonical_u32(1548716569),
566 ]);
567 }
568 if index == 6 {
569 return SepticExtension([
570 F::from_canonical_u32(372606377),
571 F::from_canonical_u32(357514301),
572 F::from_canonical_u32(335089633),
573 F::from_canonical_u32(330400379),
574 F::from_canonical_u32(1545190367),
575 F::from_canonical_u32(1813349020),
576 F::from_canonical_u32(1393941056),
577 ]);
578 }
579 unreachable!();
580 }
581
582 #[must_use]
583 fn frobenius(&self) -> Self {
584 let mut result = Self::zero();
585 result += self.0[0];
586 result += Self::z_pow_p(1) * self.0[1];
587 result += Self::z_pow_p(2) * self.0[2];
588 result += Self::z_pow_p(3) * self.0[3];
589 result += Self::z_pow_p(4) * self.0[4];
590 result += Self::z_pow_p(5) * self.0[5];
591 result += Self::z_pow_p(6) * self.0[6];
592 result
593 }
594
595 #[must_use]
596 fn double_frobenius(&self) -> Self {
597 let mut result = Self::zero();
598 result += self.0[0];
599 result += Self::z_pow_p2(1) * self.0[1];
600 result += Self::z_pow_p2(2) * self.0[2];
601 result += Self::z_pow_p2(3) * self.0[3];
602 result += Self::z_pow_p2(4) * self.0[4];
603 result += Self::z_pow_p2(5) * self.0[5];
604 result += Self::z_pow_p2(6) * self.0[6];
605 result
606 }
607
608 #[must_use]
609 fn pow_r_1(&self) -> Self {
610 let base = self.frobenius() * self.double_frobenius();
611 let base_p2 = base.double_frobenius();
612 let base_p4 = base_p2.double_frobenius();
613 base * base_p2 * base_p4
614 }
615
616 #[must_use]
617 fn inv(&self) -> Self {
618 let pow_r_1 = self.pow_r_1();
619 let pow_r = pow_r_1 * *self;
620 pow_r_1 * pow_r.0[0].inverse()
621 }
622
623 fn is_square(&self) -> (F, bool) {
624 let pow_r_1 = self.pow_r_1();
625 let pow_r = pow_r_1 * *self;
626 let exp = (F::order() - BigUint::one()) / BigUint::from(2u8);
627 let exp = exp.to_u64_digits()[0];
628
629 (pow_r.0[0], pow_r.0[0].exp_u64(exp) == F::one())
630 }
631
632 pub fn sqrt(&self) -> Option<Self> {
635 let n = *self;
636
637 if n == Self::zero() || n == Self::one() {
638 return Some(n);
639 }
640
641 let (numerator, is_square) = n.is_square();
642
643 if !is_square {
644 return None;
645 }
646
647 let mut n_iter = n;
648 let mut n_power = n;
649 for i in 1..30 {
650 n_iter *= n_iter;
651 if i >= 23 {
652 n_power *= n_iter;
653 }
654 }
655
656 let mut n_frobenius = n_power.frobenius();
657 let mut denominator = n_frobenius;
658
659 n_frobenius = n_frobenius.double_frobenius();
660 denominator *= n_frobenius;
661 n_frobenius = n_frobenius.double_frobenius();
662 denominator *= n_frobenius;
663 denominator *= n;
664
665 let base = numerator.inverse();
666 let g = F::generator();
667 let mut a = F::one();
668 let mut nonresidue = F::one() - base;
669 let legendre_exp = (F::order() - BigUint::one()) / BigUint::from(2u8);
670
671 while nonresidue.exp_u64(legendre_exp.to_u64_digits()[0]) == F::one() {
672 a *= g;
673 nonresidue = a.square() - base;
674 }
675
676 let order = F::order();
677 let cipolla_pow = (&order + BigUint::one()) / BigUint::from(2u8);
678 let mut x = CipollaExtension::new(a, F::one());
679 x = x.pow(&cipolla_pow, nonresidue);
680
681 Some(denominator * x.real)
682 }
683}
684
685impl<F: PrimeField32> SepticExtension<F> {
686 pub fn is_receive(&self) -> bool {
689 1 <= self.0[6].as_canonical_u32() && self.0[6].as_canonical_u32() <= 63 * (1 << 24)
690 }
691
692 pub fn is_send(&self) -> bool {
695 F::ORDER_U32 - 63 * (1 << 24) <= self.0[6].as_canonical_u32()
696 && self.0[6].as_canonical_u32() <= (F::ORDER_U32 - 1)
697 }
698
699 pub fn is_exception(&self) -> bool {
702 self.0[6].as_canonical_u32() == 0
703 || (63 * (1 << 24) < self.0[6].as_canonical_u32()
704 && self.0[6].as_canonical_u32() < F::ORDER_U32 - 63 * (1 << 24))
705 }
706}
707
708#[derive(Clone, Copy, Debug)]
710struct CipollaExtension<F: Field> {
711 real: F,
712 imag: F,
713}
714
715impl<F: Field> CipollaExtension<F> {
716 fn new(real: F, imag: F) -> Self {
717 Self { real, imag }
718 }
719
720 fn one() -> Self {
721 Self::new(F::one(), F::zero())
722 }
723
724 fn mul_ext(&self, other: Self, nonresidue: F) -> Self {
725 Self::new(
726 self.real * other.real + nonresidue * self.imag * other.imag,
727 self.real * other.imag + self.imag * other.real,
728 )
729 }
730
731 fn pow(&self, exp: &BigUint, nonresidue: F) -> Self {
732 let mut result = Self::one();
733 let mut base = *self;
734 let bits = exp.bits();
735
736 for i in 0..bits {
737 if exp.bit(i) {
738 result = result.mul_ext(base, nonresidue);
739 }
740 base = base.mul_ext(base, nonresidue);
741 }
742 result
743 }
744}
745
746#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
748#[repr(C)]
749pub struct SepticBlock<T>(pub [T; 7]);
750
751impl<T> SepticBlock<T> {
752 pub fn map<F, U>(self, f: F) -> SepticBlock<U>
754 where
755 F: FnMut(T) -> U,
756 {
757 SepticBlock(self.0.map(f))
758 }
759
760 pub fn from_base_fn<G: FnMut(usize) -> T>(f: G) -> Self {
762 Self(array::from_fn(f))
763 }
764}
765
766impl<T: Clone> SepticBlock<T> {
767 pub fn as_extension<AB: SepticExtensionAirBuilder<Var = T>>(
769 &self,
770 ) -> SepticExtension<AB::Expr> {
771 let arr: [AB::Expr; 7] = self.0.clone().map(|x| AB::Expr::zero() + x);
772 SepticExtension(arr)
773 }
774
775 pub fn as_extension_from_base<AB: SP1AirBuilder<Var = T>>(
777 &self,
778 base: AB::Expr,
779 ) -> SepticExtension<AB::Expr> {
780 let mut arr: [AB::Expr; 7] = self.0.clone().map(|_| AB::Expr::zero());
781 arr[0] = base;
782
783 SepticExtension(arr)
784 }
785}
786
787impl<T> From<[T; 7]> for SepticBlock<T> {
788 fn from(arr: [T; 7]) -> Self {
789 Self(arr)
790 }
791}
792
793impl<T: AbstractField> From<T> for SepticBlock<T> {
794 fn from(value: T) -> Self {
795 Self([value, T::zero(), T::zero(), T::zero(), T::zero(), T::zero(), T::zero()])
796 }
797}
798
799impl<T: Copy> From<&[T]> for SepticBlock<T> {
800 fn from(slice: &[T]) -> Self {
801 let arr: [T; 7] = slice.try_into().unwrap();
802 Self(arr)
803 }
804}
805
806impl<T, I> Index<I> for SepticBlock<T>
807where
808 [T]: Index<I>,
809{
810 type Output = <[T] as Index<I>>::Output;
811
812 #[inline]
813 fn index(&self, index: I) -> &Self::Output {
814 Index::index(&self.0, index)
815 }
816}
817
818impl<T, I> IndexMut<I> for SepticBlock<T>
819where
820 [T]: IndexMut<I>,
821{
822 #[inline]
823 fn index_mut(&mut self, index: I) -> &mut Self::Output {
824 IndexMut::index_mut(&mut self.0, index)
825 }
826}
827
828impl<T> IntoIterator for SepticBlock<T> {
829 type Item = T;
830 type IntoIter = std::array::IntoIter<T, 7>;
831
832 fn into_iter(self) -> Self::IntoIter {
833 self.0.into_iter()
834 }
835}
836
837#[cfg(test)]
838mod tests {
839 #![allow(clippy::print_stdout)]
840
841 use sp1_primitives::SP1Field;
842
843 use super::*;
844
845 #[test]
846 fn test_mul() {
847 let a: SepticExtension<SP1Field> = SepticExtension::from_canonical_u32(1);
848 let b: SepticExtension<SP1Field> = SepticExtension::from_canonical_u32(2);
849 let c = a * b;
850 println!("{c}");
851 }
852
853 #[test]
854 fn test_inv() {
855 for i in 0..256 {
856 let a: SepticExtension<SP1Field> = SepticExtension([
857 SP1Field::from_canonical_u32(i + 3),
858 SP1Field::from_canonical_u32(2 * i + 6),
859 SP1Field::from_canonical_u32(5 * i + 17),
860 SP1Field::from_canonical_u32(6 * i + 91),
861 SP1Field::from_canonical_u32(8 * i + 37),
862 SP1Field::from_canonical_u32(11 * i + 35),
863 SP1Field::from_canonical_u32(14 * i + 33),
864 ]);
865 let b = a.inv();
866 assert_eq!(a * b, SepticExtension::<SP1Field>::one());
867 }
868 }
869
870 #[test]
871 fn test_legendre() {
872 let a: SepticExtension<SP1Field> = SepticExtension::generator();
873 let mut b = SepticExtension::<SP1Field>::one();
874 for i in 1..256 {
875 b *= a;
876 let (_, c) = b.is_square();
877 assert!(c == (i % 2 == 0));
878 }
879 }
880
881 #[test]
882 fn test_sqrt() {
883 for i in 0..256 {
884 let a: SepticExtension<SP1Field> = SepticExtension([
885 SP1Field::from_canonical_u32(i + 3),
886 SP1Field::from_canonical_u32(2 * i + 6),
887 SP1Field::from_canonical_u32(5 * i + 17),
888 SP1Field::from_canonical_u32(6 * i + 91),
889 SP1Field::from_canonical_u32(8 * i + 37),
890 SP1Field::from_canonical_u32(11 * i + 35),
891 SP1Field::from_canonical_u32(14 * i + 33),
892 ]);
893 let b = a * a;
894 let recovered_a = b.sqrt().unwrap();
895 assert_eq!(recovered_a * recovered_a, b);
896 }
897 let mut b = SepticExtension::<SP1Field>::one();
898 for i in 1..256 {
899 let a: SepticExtension<SP1Field> = SepticExtension::generator();
900 b *= a;
901 let c = b.sqrt();
902 if i % 2 == 1 {
903 assert!(c.is_none());
904 } else {
905 let c = c.unwrap();
906 assert_eq!(c * c, b);
907 }
908 }
909 }
910}