dcrypt_algorithms/ec/p521/
field.rs1use crate::ec::p521::constants::{P521_FIELD_ELEMENT_SIZE, P521_LIMBS};
13use crate::error::{Error, Result};
14use dcrypt_internal::constant_time::{Choice, ConditionallySelectable};
15use dcrypt_internal::zeroing::{Zeroize, Zeroizing};
16
17#[derive(Clone, Debug, PartialEq, Eq)]
25pub struct FieldElement(pub(crate) [u32; P521_LIMBS]);
26
27impl Default for FieldElement {
28 fn default() -> Self {
29 Self::zero()
30 }
31}
32
33impl Zeroize for FieldElement {
34 fn zeroize(&mut self) {
35 self.0.zeroize();
36 }
37}
38
39impl FieldElement {
44 pub(crate) const MOD_LIMBS: [u32; P521_LIMBS] = [
46 0xFFFF_FFFF,
47 0xFFFF_FFFF,
48 0xFFFF_FFFF,
49 0xFFFF_FFFF,
50 0xFFFF_FFFF,
51 0xFFFF_FFFF,
52 0xFFFF_FFFF,
53 0xFFFF_FFFF,
54 0xFFFF_FFFF,
55 0xFFFF_FFFF,
56 0xFFFF_FFFF,
57 0xFFFF_FFFF,
58 0xFFFF_FFFF,
59 0xFFFF_FFFF,
60 0xFFFF_FFFF,
61 0xFFFF_FFFF,
62 0x0000_01FF, ];
64
65 pub(crate) const A_M3: [u32; P521_LIMBS] = [
67 0xFFFF_FFFC,
68 0xFFFF_FFFF,
69 0xFFFF_FFFF,
70 0xFFFF_FFFF,
71 0xFFFF_FFFF,
72 0xFFFF_FFFF,
73 0xFFFF_FFFF,
74 0xFFFF_FFFF,
75 0xFFFF_FFFF,
76 0xFFFF_FFFF,
77 0xFFFF_FFFF,
78 0xFFFF_FFFF,
79 0xFFFF_FFFF,
80 0xFFFF_FFFF,
81 0xFFFF_FFFF,
82 0xFFFF_FFFF,
83 0x0000_01FF,
84 ];
85
86 #[inline]
88 pub fn zero() -> Self {
89 FieldElement([0u32; P521_LIMBS])
90 }
91
92 #[inline]
94 pub fn one() -> Self {
95 let mut limbs = Zeroizing::new([0u32; P521_LIMBS]);
96 limbs[0] = 1;
97 Self(*limbs)
98 }
99}
100
101impl FieldElement {
106 pub fn from_bytes(bytes: &[u8; P521_FIELD_ELEMENT_SIZE]) -> Result<Self> {
111 let mut limbs = Zeroizing::new([0u32; P521_LIMBS]);
112 for i in 0..16 {
113 let offset = P521_FIELD_ELEMENT_SIZE - 4 - i * 4;
114 limbs[i] = ((bytes[offset] as u32) << 24)
115 | ((bytes[offset + 1] as u32) << 16)
116 | ((bytes[offset + 2] as u32) << 8)
117 | bytes[offset + 3] as u32;
118 }
119 limbs[16] = ((bytes[0] as u32) << 8) | bytes[1] as u32;
120
121 let fe = Zeroizing::new(FieldElement(*limbs));
122 if !fe.is_valid() {
123 return Err(Error::param("FieldElement P-521", "Value >= modulus"));
124 }
125 Ok(fe.into_inner())
126 }
127
128 pub fn to_bytes(&self) -> [u8; P521_FIELD_ELEMENT_SIZE] {
130 let mut bytes = [0u8; P521_FIELD_ELEMENT_SIZE];
131 self.write_bytes(&mut bytes);
132 bytes
133 }
134
135 pub(crate) fn write_bytes(&self, bytes: &mut [u8]) {
136 debug_assert_eq!(bytes.len(), P521_FIELD_ELEMENT_SIZE);
137 for (i, &limb) in self.0.iter().take(16).enumerate() {
138 let offset = P521_FIELD_ELEMENT_SIZE - 4 - i * 4;
139 bytes[offset] = (limb >> 24) as u8;
140 bytes[offset + 1] = (limb >> 16) as u8;
141 bytes[offset + 2] = (limb >> 8) as u8;
142 bytes[offset + 3] = limb as u8;
143 }
144 let most_significant = self.0[16] & 0x1ff;
145 bytes[0] = (most_significant >> 8) as u8;
146 bytes[1] = most_significant as u8;
147 }
148
149 #[inline(always)]
151 pub fn is_zero(&self) -> bool {
152 let mut any = 0u32;
153 for &limb in &self.0 {
154 any |= limb;
155 }
156 any == 0
157 }
158
159 #[inline(always)]
161 pub fn is_odd(&self) -> bool {
162 (self.0[0] & 1) == 1
163 }
164
165 #[inline(always)]
167 pub fn is_valid(&self) -> bool {
168 let (_difference, borrow) = Self::sbb_n(&self.0, &Self::MOD_LIMBS);
169 borrow == 1 }
171}
172
173impl FieldElement {
178 #[inline(always)]
180 pub(crate) fn adc_n<const N: usize>(a: &[u32; N], b: &[u32; N]) -> (Zeroizing<[u32; N]>, u32) {
181 let mut out = Zeroizing::new([0u32; N]);
182 let mut carry = 0u64;
183 for i in 0..N {
184 let t = a[i] as u64 + b[i] as u64 + carry;
185 out[i] = t as u32;
186 carry = t >> 32;
187 }
188 (out, carry as u32)
189 }
190
191 #[inline(always)]
193 pub(crate) fn sbb_n<const N: usize>(a: &[u32; N], b: &[u32; N]) -> (Zeroizing<[u32; N]>, u32) {
194 let mut out = Zeroizing::new([0u32; N]);
195 let mut borrow = 0i64;
196 for i in 0..N {
197 let t = a[i] as i64 - b[i] as i64 - borrow;
198 out[i] = t as u32;
199 borrow = (t >> 63) & 1; }
201 (out, borrow as u32)
202 }
203
204 #[inline(always)]
206 pub(crate) fn conditional_select(a: &Self, b: &Self, flag: Choice) -> Self {
207 Self::select_limbs(&a.0, &b.0, flag)
208 }
209
210 #[inline(never)]
211 fn select_limbs(a: &[u32; P521_LIMBS], b: &[u32; P521_LIMBS], flag: Choice) -> Self {
212 let mut out = Zeroizing::new([0u32; P521_LIMBS]);
213 for i in 0..P521_LIMBS {
214 out[i] = u32::conditional_select(&a[i], &b[i], flag);
215 }
216 FieldElement(*out)
217 }
218
219 #[inline(always)]
224 pub fn conditional_swap(a: &mut Self, b: &mut Self, choice: Choice) {
225 for i in 0..P521_LIMBS {
226 let mut tmp = u32::conditional_select(&a.0[i], &b.0[i], choice);
227 b.0[i] = u32::conditional_select(&b.0[i], &a.0[i], choice);
228 a.0[i] = tmp;
229 tmp.zeroize();
230 }
231 }
232}
233
234impl FieldElement {
239 fn reduce_wide(t: &[u32; 34]) -> Self {
242 let mut first = Zeroizing::new([0u32; 18]);
245 let mut carry = 0u64;
246 for i in 0..16 {
247 let high = ((t[i + 16] >> 9) | (t[i + 17] << 23)) as u64;
248 let value = t[i] as u64 + high + carry;
249 first[i] = value as u32;
250 carry = value >> 32;
251 }
252 let high_16 = ((t[32] >> 9) | (t[33] << 23)) as u64;
253 let value_16 = (t[16] & 0x1ff) as u64 + high_16 + carry;
254 first[16] = value_16 as u32;
255 carry = value_16 >> 32;
256
257 let value_17 = ((t[33] as u64) >> 9) + carry;
258 first[17] = value_17 as u32;
259
260 let extra = ((first[16] >> 9) as u64) | ((first[17] as u64) << 23);
263 let mut limbs = Zeroizing::new([0u32; P521_LIMBS]);
264 carry = extra;
265 for i in 0..P521_LIMBS {
266 let low = if i == 16 { first[i] & 0x1ff } else { first[i] };
267 let value = low as u64 + carry;
268 limbs[i] = value as u32;
269 carry = value >> 32;
270 }
271
272 let (sub, borrow) = Self::sbb_n(&limbs, &Self::MOD_LIMBS);
276 Self::select_limbs(&limbs, &sub, Choice::from((borrow ^ 1) as u8))
277 }
278}
279
280impl FieldElement {
285 pub fn add(&self, other: &Self) -> Self {
287 let (sum, carry) = Self::adc_n(&self.0, &other.0);
288 let (sub, borrow) = Self::sbb_n(&sum, &Self::MOD_LIMBS);
290 let need_sub = Choice::from(((carry | (borrow ^ 1)) & 1) as u8);
291 Self::select_limbs(&sum, &sub, need_sub)
292 }
293
294 pub fn sub(&self, other: &Self) -> Self {
296 let (diff, borrow) = Self::sbb_n(&self.0, &other.0);
297 let (sum, _carry) = Self::adc_n(&diff, &Self::MOD_LIMBS);
299 Self::select_limbs(&diff, &sum, Choice::from(borrow as u8))
300 }
301
302 pub fn mul(&self, other: &Self) -> Self {
304 let mut wide = Zeroizing::new([0u128; 34]);
306 for i in 0..17 {
307 for j in 0..17 {
308 wide[i + j] += (self.0[i] as u128) * (other.0[j] as u128);
309 }
310 }
311
312 let mut limbs = Zeroizing::new([0u32; 34]);
314 let mut carry: u128 = 0;
315 for i in 0..34 {
316 let v = wide[i] + carry;
317 limbs[i] = (v & 0xFFFF_FFFF) as u32;
318 carry = v >> 32;
319 }
320 let _ = carry;
323
324 Self::reduce_wide(&limbs)
326 }
327
328 #[inline(always)]
330 pub fn square(&self) -> Self {
331 self.mul(self)
332 }
333
334 pub fn invert(&self) -> Result<Self> {
336 if self.is_zero() {
337 return Err(Error::param("FieldElement P-521", "Inverse of zero"));
338 }
339
340 let mut exp = Zeroizing::new([0u8; P521_FIELD_ELEMENT_SIZE]);
343 exp[0] = 0x01;
344 for byte in exp.iter_mut().skip(1) {
345 *byte = 0xFF;
346 }
347 let mut borrow = 2u16;
349 for i in (0..66).rev() {
350 let v = exp[i] as i16 - borrow as i16;
351 exp[i] = if v < 0 { (v + 256) as u8 } else { v as u8 };
352 borrow = if v < 0 { 1 } else { 0 };
353 }
354
355 let mut result = Zeroizing::new(FieldElement::one());
357 let base = Zeroizing::new(self.clone());
358 for byte in exp.iter() {
359 for bit in (0..8).rev() {
360 let squared = Zeroizing::new(result.square());
361 result.zeroize();
362 *result = squared.into_inner();
363 if (byte >> bit) & 1 == 1 {
364 let next = Zeroizing::new(result.mul(&base));
365 result.zeroize();
366 *result = next.into_inner();
367 }
368 }
369 }
370 Ok(result.into_inner())
371 }
372
373 pub fn sqrt(&self) -> Option<Self> {
376 if self.is_zero() {
377 return Some(Self::zero());
378 }
379 let mut res = Zeroizing::new(self.clone());
381 for _ in 0..519 {
382 let squared = Zeroizing::new(res.square());
383 res.zeroize();
384 *res = squared.into_inner();
385 }
386 let verification = Zeroizing::new(res.square());
388 if *verification == *self {
389 Some(res.into_inner())
390 } else {
391 None
392 }
393 }
394
395 pub(crate) fn get_modulus() -> Self {
397 FieldElement(Self::MOD_LIMBS)
398 }
399}