1use p3_binary_field::TowerLevel;
4
5#[must_use]
13pub fn domain_point<F: TowerLevel>(index: usize) -> F {
14 let mut point = F::ZERO;
15 let mut remaining = index;
16 let mut r = 0;
17 while remaining != 0 {
18 if remaining & 1 == 1 {
19 point += F::cantor_basis(r);
20 }
21 remaining >>= 1;
22 r += 1;
23 }
24 point
25}
26
27#[must_use]
33pub fn subspace_polynomial<F: TowerLevel>(j: usize, x: F) -> F {
34 let mut value = x;
35 for _ in 0..j {
36 value = value.square() + value;
37 }
38 value
39}
40
41#[cfg(test)]
42mod tests {
43 use p3_binary_field::{BinaryField8, BinaryField16, BinaryField128, TowerLevel};
44 use p3_field::PrimeCharacteristicRing;
45
46 use super::{domain_point, subspace_polynomial};
47
48 #[test]
51 fn domain_point_images_are_the_cantor_basis() {
52 for r in 0..8 {
53 assert_eq!(
54 domain_point::<BinaryField8>(1 << r),
55 BinaryField8::cantor_basis(r),
56 "r={r}"
57 );
58 }
59 for r in 0..usize::BITS as usize {
60 assert_eq!(
61 domain_point::<BinaryField128>(1 << r),
62 BinaryField128::cantor_basis(r),
63 "r={r}"
64 );
65 }
66 }
67
68 #[test]
70 #[should_panic = "Cantor basis index out of range"]
71 fn domain_point_rejects_an_index_past_the_basis() {
72 let _ = domain_point::<BinaryField8>(1 << 8);
73 }
74
75 #[test]
77 fn domain_point_is_linear_in_the_index() {
78 for a in 0..1usize << 8 {
79 for b in 0..1usize << 8 {
80 assert_eq!(
81 domain_point::<BinaryField8>(a ^ b),
82 domain_point::<BinaryField8>(a) + domain_point::<BinaryField8>(b)
83 );
84 }
85 }
86 }
87
88 #[test]
90 fn subspace_polynomial_vanishes_on_its_subspace() {
91 for j in 0..=8 {
92 for m in 0..1usize << 8 {
93 let value = subspace_polynomial::<BinaryField8>(j, domain_point(m));
94 assert_eq!(value == BinaryField8::ZERO, m < 1 << j, "j={j} m={m}");
95 }
96 }
97 }
98
99 #[test]
101 fn subspace_polynomial_shifts_the_basis() {
102 for j in 0..16 {
103 for i in j..16 {
104 assert_eq!(
105 subspace_polynomial::<BinaryField16>(j, BinaryField16::cantor_basis(i)),
106 BinaryField16::cantor_basis(i - j),
107 "j={j} i={i}"
108 );
109 }
110 }
111 }
112
113 #[test]
115 fn domain_points_agree_across_levels() {
116 for m in 0..1usize << 8 {
117 let small: u128 = domain_point::<BinaryField8>(m).to_repr().into();
118 let large: u128 = domain_point::<BinaryField128>(m).to_repr();
119 assert_eq!(small, large, "index {m}");
120 }
121 }
122}