dcrypt_algorithms/ec/k256/
field.rs1use crate::ec::k256::constants::K256_FIELD_ELEMENT_SIZE;
5use crate::error::{Error, Result};
6use subtle::{Choice, ConditionallySelectable};
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub struct FieldElement(pub(crate) [u32; 8]);
11
12impl ConditionallySelectable for FieldElement {
13 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
14 let mut out = [0u32; 8];
15 for i in 0..8 {
16 out[i] = u32::conditional_select(&a.0[i], &b.0[i], choice);
17 }
18 FieldElement(out)
19 }
20}
21
22impl FieldElement {
23 pub(crate) const MOD_LIMBS: [u32; 8] = [
25 0xFFFF_FC2F,
26 0xFFFF_FFFE,
27 0xFFFF_FFFF,
28 0xFFFF_FFFF,
29 0xFFFF_FFFF,
30 0xFFFF_FFFF,
31 0xFFFF_FFFF,
32 0xFFFF_FFFF,
33 ];
34
35 pub fn zero() -> Self {
37 FieldElement([0; 8])
38 }
39
40 pub fn one() -> Self {
42 let mut limbs = [0; 8];
43 limbs[0] = 1;
44 FieldElement(limbs)
45 }
46
47 pub fn from_bytes(bytes: &[u8; K256_FIELD_ELEMENT_SIZE]) -> Result<Self> {
51 let mut limbs = [0u32; 8];
52 for (i, limb) in limbs.iter_mut().enumerate() {
53 let offset = (7 - i) * 4;
54 *limb = u32::from_be_bytes([
55 bytes[offset],
56 bytes[offset + 1],
57 bytes[offset + 2],
58 bytes[offset + 3],
59 ]);
60 }
61 let fe = FieldElement(limbs);
62 if !fe.is_valid() {
63 return Err(Error::param(
64 "FieldElement K256",
65 "Value must be less than the field modulus",
66 ));
67 }
68 Ok(fe)
69 }
70
71 pub fn to_bytes(&self) -> [u8; K256_FIELD_ELEMENT_SIZE] {
73 let mut bytes = [0u8; K256_FIELD_ELEMENT_SIZE];
74 for i in 0..8 {
75 let limb_bytes = self.0[i].to_be_bytes();
76 let offset = (7 - i) * 4;
77 bytes[offset..offset + 4].copy_from_slice(&limb_bytes);
78 }
79 bytes
80 }
81
82 #[inline(always)]
84 pub fn is_valid(&self) -> bool {
85 let (_, borrow) = Self::sbb8(self.0, Self::MOD_LIMBS);
86 borrow == 1
87 }
88
89 pub fn is_zero(&self) -> bool {
91 self.0.iter().all(|&l| l == 0)
92 }
93
94 pub fn is_odd(&self) -> bool {
96 (self.0[0] & 1) == 1
98 }
99
100 #[inline(always)]
102 pub fn add(&self, other: &Self) -> Self {
103 let (sum, carry) = Self::adc8(self.0, other.0);
104 let (sum_minus_p, borrow) = Self::sbb8(sum, Self::MOD_LIMBS);
105 let needs_reduce = (carry | (borrow ^ 1)) & 1;
106 Self::conditional_select(&sum, &sum_minus_p, Choice::from(needs_reduce as u8))
107 }
108
109 pub fn sub(&self, other: &Self) -> Self {
111 let (diff, borrow) = Self::sbb8(self.0, other.0);
112 let (candidate, _) = Self::adc8(diff, Self::MOD_LIMBS);
113 Self::conditional_select(&diff, &candidate, Choice::from(borrow as u8))
114 }
115
116 pub fn negate(&self) -> Self {
118 if self.is_zero() {
119 return *self;
120 }
121 FieldElement(Self::MOD_LIMBS).sub(self)
122 }
123
124 pub fn mul(&self, other: &Self) -> Self {
126 let mut t = [0u128; 16];
127 for i in 0..8 {
128 for j in 0..8 {
129 t[i + j] += (self.0[i] as u128) * (other.0[j] as u128);
130 }
131 }
132 let mut prod = [0u32; 16];
133 let mut carry: u128 = 0;
134 for i in 0..16 {
135 let v = t[i] + carry;
136 prod[i] = (v & 0xffff_ffff) as u32;
137 carry = v >> 32;
138 }
139 Self::reduce_wide(prod)
140 }
141
142 #[inline(always)]
144 pub fn square(&self) -> Self {
145 self.mul(self)
146 }
147
148 pub fn double(&self) -> Self {
150 self.add(self)
151 }
152
153 pub fn invert(&self) -> Result<Self> {
157 if self.is_zero() {
158 return Err(Error::param(
159 "FieldElement K256",
160 "Inversion of zero is undefined",
161 ));
162 }
163 const P_MINUS_2: [u8; 32] = [
164 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
165 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
166 0xFF, 0xFF, 0xFC, 0x2D,
167 ];
168 self.pow(&P_MINUS_2)
169 }
170
171 pub fn sqrt(&self) -> Option<Self> {
175 if self.is_zero() {
176 return Some(Self::zero());
177 }
178 const P_PLUS_1_DIV_4: [u8; 32] = [
180 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
181 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
182 0xBF, 0xFF, 0xFF, 0x0C,
183 ];
184 let root = self.pow(&P_PLUS_1_DIV_4).ok()?;
185 if root.square() == *self {
186 Some(root)
187 } else {
188 None
189 }
190 }
191
192 fn pow(&self, exp_be: &[u8]) -> Result<Self> {
193 let mut result = Self::one();
194 let base = *self;
195 for &byte in exp_be.iter() {
196 for i in (0..8).rev() {
197 result = result.square();
198 if (byte >> i) & 1 == 1 {
199 result = result.mul(&base);
200 }
201 }
202 }
203 Ok(result)
204 }
205
206 fn conditional_select(a: &[u32; 8], b: &[u32; 8], flag: Choice) -> Self {
207 let mut out = [0u32; 8];
208 for i in 0..8 {
209 out[i] = u32::conditional_select(&a[i], &b[i], flag);
210 }
211 FieldElement(out)
212 }
213
214 fn adc8(a: [u32; 8], b: [u32; 8]) -> ([u32; 8], u32) {
215 let mut r = [0u32; 8];
216 let mut carry: u64 = 0;
217 for i in 0..8 {
218 let tmp = (a[i] as u64) + (b[i] as u64) + carry;
219 r[i] = tmp as u32;
220 carry = tmp >> 32;
221 }
222 (r, carry as u32)
223 }
224
225 fn sbb8(a: [u32; 8], b: [u32; 8]) -> ([u32; 8], u32) {
226 let mut r = [0u32; 8];
227 let mut borrow: i64 = 0;
228 for i in 0..8 {
229 let tmp = (a[i] as i64) - (b[i] as i64) - borrow;
230 r[i] = tmp as u32;
231 borrow = (tmp >> 63) & 1;
232 }
233 (r, borrow as u32)
234 }
235
236 fn reduce_wide(t: [u32; 16]) -> Self {
239 let mut t_low = [0u32; 8];
245 let mut t_high = [0u32; 8];
246 t_low.copy_from_slice(&t[..8]);
247 t_high.copy_from_slice(&t[8..]);
248
249 let mut t_high_977 = [0u64; 9];
256 for i in 0..8 {
257 t_high_977[i] += (t_high[i] as u64) * 977u64;
258 }
259 for i in 0..8 {
261 t_high_977[i + 1] += t_high_977[i] >> 32;
262 t_high_977[i] &= 0xFFFF_FFFF;
263 }
264
265 let mut result = [0u64; 9];
267
268 for i in 0..8 {
270 result[i] += t_low[i] as u64;
271 }
272
273 for i in 0..8 {
275 result[i + 1] += t_high[i] as u64;
276 }
277
278 for i in 0..9 {
280 result[i] += t_high_977[i];
281 }
282
283 for i in 0..8 {
285 result[i + 1] += result[i] >> 32;
286 result[i] &= 0xFFFF_FFFF;
287 }
288
289 if result[8] > 0 {
291 let overflow = result[8];
293 result[8] = 0;
294
295 result[0] += overflow * 977;
297 result[1] += overflow;
299
300 for i in 0..8 {
302 if i < 7 {
303 result[i + 1] += result[i] >> 32;
304 }
305 result[i] &= 0xFFFF_FFFF;
306 }
307 }
308
309 let mut r = [0u32; 8];
311 for i in 0..8 {
312 r[i] = result[i] as u32;
313 }
314
315 let fe = FieldElement(r);
317 if !fe.is_valid() {
318 let (reduced, _) = Self::sbb8(r, Self::MOD_LIMBS);
319 FieldElement(reduced)
320 } else {
321 fe
322 }
323 }
324}
325
326#[cfg(test)]
327mod field_constants_tests {
328 use super::*;
329
330 #[test]
331 fn test_modulus_is_correct() {
332 let mut mod_bytes = [0u8; 32];
337 for (i, &limb) in FieldElement::MOD_LIMBS.iter().enumerate() {
338 let limb_bytes = limb.to_be_bytes();
339 let offset = (7 - i) * 4;
340 mod_bytes[offset..offset + 4].copy_from_slice(&limb_bytes);
341 }
342
343 let expected_bytes: [u8; 32] = [
345 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
346 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
347 0xFF, 0xFF, 0xFC, 0x2F,
348 ];
349
350 assert_eq!(
351 mod_bytes, expected_bytes,
352 "MOD_LIMBS does not encode the correct secp256k1 prime"
353 );
354 }
355}