dcrypt_algorithms/ec/k256/
field.rs

1//! secp256k1 field arithmetic implementation.
2//! Field prime p = 2^256 - 2^32 - 977.
3
4use crate::ec::k256::constants::K256_FIELD_ELEMENT_SIZE;
5use crate::error::{Error, Result};
6use subtle::{Choice, ConditionallySelectable};
7
8/// secp256k1 field element representing values in F_p
9#[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    /// The secp256k1 prime modulus: p = 2^256 - 2^32 - 977
24    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    /// The additive identity element: 0
36    pub fn zero() -> Self {
37        FieldElement([0; 8])
38    }
39
40    /// The multiplicative identity element: 1
41    pub fn one() -> Self {
42        let mut limbs = [0; 8];
43        limbs[0] = 1;
44        FieldElement(limbs)
45    }
46
47    /// Create a field element from its canonical byte representation.
48    ///
49    /// Returns an error if the value is greater than or equal to the field modulus.
50    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    /// Convert this field element to its canonical byte representation.
72    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    /// Check if this field element is less than the field modulus.
83    #[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    /// Check if this field element is zero.
90    pub fn is_zero(&self) -> bool {
91        self.0.iter().all(|&l| l == 0)
92    }
93
94    /// Check if this field element is odd (least significant bit is 1).
95    pub fn is_odd(&self) -> bool {
96        // limbs[0] contains the least significant 32 bits
97        (self.0[0] & 1) == 1
98    }
99
100    /// Add two field elements modulo p.
101    #[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    /// Subtract two field elements modulo p.
110    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    /// Negate a field element modulo p.
117    pub fn negate(&self) -> Self {
118        if self.is_zero() {
119            return *self;
120        }
121        FieldElement(Self::MOD_LIMBS).sub(self)
122    }
123
124    /// Multiply two field elements modulo p.
125    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    /// Square a field element modulo p.
143    #[inline(always)]
144    pub fn square(&self) -> Self {
145        self.mul(self)
146    }
147
148    /// Double a field element (multiply by 2) modulo p.
149    pub fn double(&self) -> Self {
150        self.add(self)
151    }
152
153    /// Compute the multiplicative inverse of a field element.
154    ///
155    /// Returns an error if the element is zero.
156    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    /// Compute the square root of a field element.
172    ///
173    /// Returns None if the element is not a quadratic residue.
174    pub fn sqrt(&self) -> Option<Self> {
175        if self.is_zero() {
176            return Some(Self::zero());
177        }
178        // p mod 4 = 3, so sqrt(a) = a^((p+1)/4)
179        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    /// Reduce a 512-bit number modulo p = 2^256 - 2^32 - 977
237    /// Uses the special form of secp256k1's prime for efficient reduction
238    fn reduce_wide(t: [u32; 16]) -> Self {
239        // For p = 2^256 - 2^32 - 977, we can use the fact that
240        // 2^256 ≡ 2^32 + 977 (mod p)
241        // This allows us to reduce the high 256 bits efficiently
242
243        // Split t into low 256 bits (t_low) and high 256 bits (t_high)
244        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        // We need to compute: t_low + t_high * 2^256
250        // Since 2^256 ≡ 2^32 + 977 (mod p), we compute:
251        // t_low + t_high * (2^32 + 977)
252        // = t_low + (t_high << 32) + t_high * 977
253
254        // First, compute t_high * 977
255        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        // Propagate carries
260        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        // Now add: t_low + (t_high << 32) + t_high_977
266        let mut result = [0u64; 9];
267
268        // Add t_low
269        for i in 0..8 {
270            result[i] += t_low[i] as u64;
271        }
272
273        // Add t_high << 32 (which means t_high[i] goes to position i+1)
274        for i in 0..8 {
275            result[i + 1] += t_high[i] as u64;
276        }
277
278        // Add t_high_977
279        for i in 0..9 {
280            result[i] += t_high_977[i];
281        }
282
283        // Propagate all carries
284        for i in 0..8 {
285            result[i + 1] += result[i] >> 32;
286            result[i] &= 0xFFFF_FFFF;
287        }
288
289        // If result[8] is non-zero, we need another reduction step
290        if result[8] > 0 {
291            // result[8] * 2^256 ≡ result[8] * (2^32 + 977) (mod p)
292            let overflow = result[8];
293            result[8] = 0;
294
295            // Add overflow * 977 to result[0]
296            result[0] += overflow * 977;
297            // Add overflow to result[1] (for the 2^32 part)
298            result[1] += overflow;
299
300            // Propagate carries again
301            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        // Convert back to u32 array
310        let mut r = [0u32; 8];
311        for i in 0..8 {
312            r[i] = result[i] as u32;
313        }
314
315        // Final reduction if r >= p
316        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        // The correct secp256k1 prime in hex:
333        // p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
334
335        // Convert MOD_LIMBS to bytes for comparison
336        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        // Expected prime as bytes
344        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}