decaf377/fields/fp/u32/
wrapper.rs

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}