1use super::{
2 super::{B, N_32, N_64, N_8},
3 fiat,
4};
5
6const N: usize = N_32;
7
8#[derive(Copy, Clone)]
9pub struct Fp(fiat::FpMontgomeryDomainFieldElement);
10
11impl PartialEq for Fp {
12 fn eq(&self, other: &Self) -> bool {
13 let sub = self.sub(other);
14 let mut check_word = 0;
15 fiat::fp_nonzero(&mut check_word, &sub.0 .0);
16 check_word == 0
17 }
18}
19
20impl Eq for Fp {}
21
22impl zeroize::Zeroize for Fp {
23 fn zeroize(&mut self) {
24 self.0 .0.zeroize()
25 }
26}
27
28impl Fp {
29 pub(crate) fn from_le_limbs(limbs: [u64; N_64]) -> Fp {
30 let limbs = {
31 let mut out = [0u32; N];
32 for i in 0..N_64 {
33 out[2 * i] = (limbs[i] & 0xFFFF_FFFF_FFFF_FFFF) as u32;
34 out[2 * i + 1] = (limbs[i] >> 32) as u32;
35 }
36 out
37 };
38 let x_non_monty = fiat::FpNonMontgomeryDomainFieldElement(limbs);
39 let mut x = fiat::FpMontgomeryDomainFieldElement([0; N]);
40 fiat::fp_to_montgomery(&mut x, &x_non_monty);
41 Self(x)
42 }
43
44 pub(crate) fn from_raw_bytes(bytes: &[u8; N_8]) -> Fp {
45 let mut x_non_montgomery = fiat::FpNonMontgomeryDomainFieldElement([0; N]);
46 let mut x = fiat::FpMontgomeryDomainFieldElement([0; N]);
47
48 fiat::fp_from_bytes(&mut x_non_montgomery.0, &bytes);
49 fiat::fp_to_montgomery(&mut x, &x_non_montgomery);
50
51 Self(x)
52 }
53
54 pub(crate) fn to_le_limbs(&self) -> [u64; N_64] {
55 let mut x_non_montgomery = fiat::FpNonMontgomeryDomainFieldElement([0; N]);
56 fiat::fp_from_montgomery(&mut x_non_montgomery, &self.0);
57 let limbs = x_non_montgomery.0;
58 let mut out = [0u64; N_64];
59 for i in 0..N_64 {
60 out[i] = (limbs[2 * i] as u64) | ((limbs[2 * i + 1] as u64) << 32);
61 }
62 out
63 }
64
65 pub fn to_bytes_le(&self) -> [u8; N_8] {
66 let mut bytes = [0u8; N_8];
67 let mut x_non_montgomery = fiat::FpNonMontgomeryDomainFieldElement([0; N]);
68 fiat::fp_from_montgomery(&mut x_non_montgomery, &self.0);
69 fiat::fp_to_bytes(&mut bytes, &x_non_montgomery.0);
70 bytes
71 }
72
73 const fn from_montgomery_limbs_backend(limbs: [u32; N]) -> Fp {
74 Self(fiat::FpMontgomeryDomainFieldElement(limbs))
75 }
76
77 pub(crate) const fn from_montgomery_limbs(limbs: [u64; N_64]) -> Fp {
78 Self(fiat::FpMontgomeryDomainFieldElement([
79 limbs[0] as u32,
80 (limbs[0] >> 32) as u32,
81 limbs[1] as u32,
82 (limbs[1] >> 32) as u32,
83 limbs[2] as u32,
84 (limbs[2] >> 32) as u32,
85 limbs[3] as u32,
86 (limbs[3] >> 32) as u32,
87 limbs[4] as u32,
88 (limbs[4] >> 32) as u32,
89 limbs[5] as u32,
90 (limbs[5] >> 32) as u32,
91 ]))
92 }
93
94 pub const ZERO: Self = Self(fiat::FpMontgomeryDomainFieldElement([0; N]));
95
96 pub const ONE: Self = Self(fiat::FpMontgomeryDomainFieldElement([
97 4294967144, 47054847, 2147483569, 1363189635, 2323464178, 2675815337, 1853645573,
98 2068748215, 2151449832, 1291097535, 3808294042, 9266785,
99 ]));
100
101 pub const QUADRATIC_NON_RESIDUE: Self = Self(fiat::FpMontgomeryDomainFieldElement([
102 762, 4228612096, 3758096779, 2547227894, 3214954564, 544358927, 3648796674, 3418144080,
103 1477704171, 196026051, 3230948050, 10056866,
104 ]));
105
106 pub const MINUS_ONE: Self = Self(fiat::FpMontgomeryDomainFieldElement([
107 153, 2184888320, 2952790095, 3318398400, 797706253, 2138418822, 2457383049, 2664710715,
108 3966026834, 2034659328, 885464144, 18928612,
109 ]));
110
111 pub fn square(&self) -> Fp {
112 let mut result = fiat::FpMontgomeryDomainFieldElement([0; N]);
113 fiat::fp_square(&mut result, &self.0);
114 Self(result)
115 }
116
117 pub fn inverse(&self) -> Option<Self> {
118 if self == &Self::ZERO {
119 return None;
120 }
121
122 const I: usize = (49 * B + 57) / 17;
123
124 let mut a = fiat::FpNonMontgomeryDomainFieldElement([0; N]);
125 fiat::fp_from_montgomery(&mut a, &self.0);
126 let mut d = 1;
127 let mut f: [u32; N + 1] = [0u32; N + 1];
128 fiat::fp_msat(&mut f);
129 let mut g: [u32; N + 1] = [0u32; N + 1];
130 let mut v: [u32; N] = [0u32; N];
131 let mut r: [u32; N] = Self::ONE.0 .0;
132 let mut i = 0;
133 let mut j = 0;
134
135 while j < N {
136 g[j] = a[j];
137 j += 1;
138 }
139
140 let mut out1: u32 = 0;
141 let mut out2: [u32; N + 1] = [0; N + 1];
142 let mut out3: [u32; N + 1] = [0; N + 1];
143 let mut out4: [u32; N] = [0; N];
144 let mut out5: [u32; N] = [0; N];
145 let mut out6: u32 = 0;
146 let mut out7: [u32; N + 1] = [0; N + 1];
147 let mut out8: [u32; N + 1] = [0; N + 1];
148 let mut out9: [u32; N] = [0; N];
149 let mut out10: [u32; N] = [0; N];
150
151 while i < I - I % 2 {
152 fiat::fp_divstep(
153 &mut out1, &mut out2, &mut out3, &mut out4, &mut out5, d, &f, &g, &v, &r,
154 );
155 fiat::fp_divstep(
156 &mut out6, &mut out7, &mut out8, &mut out9, &mut out10, out1, &out2, &out3, &out4,
157 &out5,
158 );
159 d = out6;
160 f = out7;
161 g = out8;
162 v = out9;
163 r = out10;
164 i += 2;
165 }
166
167 if I % 2 != 0 {
168 fiat::fp_divstep(
169 &mut out1, &mut out2, &mut out3, &mut out4, &mut out5, d, &f, &g, &v, &r,
170 );
171 v = out4;
172 f = out2;
173 }
174
175 let s = ((f[f.len() - 1] >> (32 - 1)) & 1) as u8;
176 let mut neg = fiat::FpMontgomeryDomainFieldElement([0; N]);
177 fiat::fp_opp(&mut neg, &fiat::FpMontgomeryDomainFieldElement(v));
178
179 let mut v_prime: [u32; N] = [0u32; N];
180 fiat::fp_selectznz(&mut v_prime, s, &v, &neg.0);
181
182 let mut pre_comp: [u32; N] = [0u32; N];
183 fiat::fp_divstep_precomp(&mut pre_comp);
184
185 let mut result = fiat::FpMontgomeryDomainFieldElement([0; N]);
186 fiat::fp_mul(
187 &mut result,
188 &fiat::FpMontgomeryDomainFieldElement(v_prime),
189 &fiat::FpMontgomeryDomainFieldElement(pre_comp),
190 );
191
192 Some(Fp(result))
193 }
194
195 pub fn add(self, other: &Fp) -> Fp {
196 let mut result = fiat::FpMontgomeryDomainFieldElement([0; N]);
197 fiat::fp_add(&mut result, &self.0, &other.0);
198 Fp(result)
199 }
200
201 pub fn sub(self, other: &Fp) -> Fp {
202 let mut result = fiat::FpMontgomeryDomainFieldElement([0; N]);
203 fiat::fp_sub(&mut result, &self.0, &other.0);
204 Fp(result)
205 }
206
207 pub fn mul(self, other: &Fp) -> Fp {
208 let mut result = fiat::FpMontgomeryDomainFieldElement([0; N]);
209 fiat::fp_mul(&mut result, &self.0, &other.0);
210 Fp(result)
211 }
212
213 pub fn neg(self) -> Fp {
214 let mut result = fiat::FpMontgomeryDomainFieldElement([0; N]);
215 fiat::fp_opp(&mut result, &self.0);
216 Fp(result)
217 }
218}