decaf377/fields/fr/u32/
wrapper.rs1use 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 Fr(fiat::FrMontgomeryDomainFieldElement);
10
11impl PartialEq for Fr {
12 fn eq(&self, other: &Self) -> bool {
13 let sub = self.sub(other);
14 let mut check_word = 0;
15 fiat::fr_nonzero(&mut check_word, &sub.0 .0);
16 check_word == 0
17 }
18}
19
20impl Eq for Fr {}
21
22impl zeroize::Zeroize for Fr {
23 fn zeroize(&mut self) {
24 self.0 .0.zeroize()
25 }
26}
27
28impl Fr {
29 pub(crate) fn from_le_limbs(limbs: [u64; N_64]) -> Fr {
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::FrNonMontgomeryDomainFieldElement(limbs);
39 let mut x = fiat::FrMontgomeryDomainFieldElement([0; N]);
40 fiat::fr_to_montgomery(&mut x, &x_non_monty);
41 Self(x)
42 }
43
44 pub(crate) fn from_raw_bytes(bytes: &[u8; N_8]) -> Fr {
45 let mut x_non_montgomery = fiat::FrNonMontgomeryDomainFieldElement([0; N]);
46 let mut x = fiat::FrMontgomeryDomainFieldElement([0; N]);
47
48 fiat::fr_from_bytes(&mut x_non_montgomery.0, &bytes);
49 fiat::fr_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::FrNonMontgomeryDomainFieldElement([0; N]);
56 fiat::fr_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::FrNonMontgomeryDomainFieldElement([0; N]);
68 fiat::fr_from_montgomery(&mut x_non_montgomery, &self.0);
69 fiat::fr_to_bytes(&mut bytes, &x_non_montgomery.0);
70 bytes
71 }
72
73 const fn from_montgomery_limbs_backend(limbs: [u32; N]) -> Fr {
74 Self(fiat::FrMontgomeryDomainFieldElement(limbs))
75 }
76
77 pub(crate) const fn from_montgomery_limbs(limbs: [u64; N_64]) -> Fr {
78 Self::from_montgomery_limbs_backend([
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 ])
88 }
89
90 pub const ZERO: Fr = Self(fiat::FrMontgomeryDomainFieldElement([0; N]));
91
92 pub const ONE: Fr = Self(fiat::FrMontgomeryDomainFieldElement([
93 3498574902, 3872500570, 2604314180, 2497411308, 588265454, 3867012838, 3735373809, 66463618,
94 ]));
95
96 pub fn square(&self) -> Fr {
97 let mut result = fiat::FrMontgomeryDomainFieldElement([0; N]);
98 fiat::fr_square(&mut result, &self.0);
99 Self(result)
100 }
101
102 pub fn inverse(&self) -> Option<Self> {
103 if self == &Self::ZERO {
104 return None;
105 }
106
107 const I: usize = (49 * B + 57) / 17;
108
109 let mut a = fiat::FrNonMontgomeryDomainFieldElement([0; N]);
110 fiat::fr_from_montgomery(&mut a, &self.0);
111 let mut d = 1;
112 let mut f: [u32; N + 1] = [0u32; N + 1];
113 fiat::fr_msat(&mut f);
114 let mut g: [u32; N + 1] = [0u32; N + 1];
115 let mut v: [u32; N] = [0u32; N];
116 let mut r: [u32; N] = Self::ONE.0 .0;
117 let mut i = 0;
118 let mut j = 0;
119
120 while j < N {
121 g[j] = a[j];
122 j += 1;
123 }
124
125 let mut out1: u32 = 0;
126 let mut out2: [u32; N + 1] = [0; N + 1];
127 let mut out3: [u32; N + 1] = [0; N + 1];
128 let mut out4: [u32; N] = [0; N];
129 let mut out5: [u32; N] = [0; N];
130 let mut out6: u32 = 0;
131 let mut out7: [u32; N + 1] = [0; N + 1];
132 let mut out8: [u32; N + 1] = [0; N + 1];
133 let mut out9: [u32; N] = [0; N];
134 let mut out10: [u32; N] = [0; N];
135
136 while i < I - I % 2 {
137 fiat::fr_divstep(
138 &mut out1, &mut out2, &mut out3, &mut out4, &mut out5, d, &f, &g, &v, &r,
139 );
140 fiat::fr_divstep(
141 &mut out6, &mut out7, &mut out8, &mut out9, &mut out10, out1, &out2, &out3, &out4,
142 &out5,
143 );
144 d = out6;
145 f = out7;
146 g = out8;
147 v = out9;
148 r = out10;
149 i += 2;
150 }
151
152 if I % 2 != 0 {
153 fiat::fr_divstep(
154 &mut out1, &mut out2, &mut out3, &mut out4, &mut out5, d, &f, &g, &v, &r,
155 );
156 v = out4;
157 f = out2;
158 }
159
160 let s = ((f[f.len() - 1] >> (32 - 1)) & 1) as u8;
161 let mut neg = fiat::FrMontgomeryDomainFieldElement([0; N]);
162 fiat::fr_opp(&mut neg, &fiat::FrMontgomeryDomainFieldElement(v));
163
164 let mut v_prime: [u32; N] = [0u32; N];
165 fiat::fr_selectznz(&mut v_prime, s, &v, &neg.0);
166
167 let mut pre_comp: [u32; N] = [0u32; N];
168 fiat::fr_divstep_precomp(&mut pre_comp);
169
170 let mut result = fiat::FrMontgomeryDomainFieldElement([0; N]);
171 fiat::fr_mul(
172 &mut result,
173 &fiat::FrMontgomeryDomainFieldElement(v_prime),
174 &fiat::FrMontgomeryDomainFieldElement(pre_comp),
175 );
176
177 Some(Fr(result))
178 }
179
180 pub fn add(self, other: &Fr) -> Fr {
181 let mut result = fiat::FrMontgomeryDomainFieldElement([0; N]);
182 fiat::fr_add(&mut result, &self.0, &other.0);
183 Fr(result)
184 }
185
186 pub fn sub(self, other: &Fr) -> Fr {
187 let mut result = fiat::FrMontgomeryDomainFieldElement([0; N]);
188 fiat::fr_sub(&mut result, &self.0, &other.0);
189 Fr(result)
190 }
191
192 pub fn mul(self, other: &Fr) -> Fr {
193 let mut result = fiat::FrMontgomeryDomainFieldElement([0; N]);
194 fiat::fr_mul(&mut result, &self.0, &other.0);
195 Fr(result)
196 }
197
198 pub fn neg(self) -> Fr {
199 let mut result = fiat::FrMontgomeryDomainFieldElement([0; N]);
200 fiat::fr_opp(&mut result, &self.0);
201 Fr(result)
202 }
203}