Skip to main content

dcrypt_algorithms/ec/k256/
scalar.rs

1//! secp256k1 scalar arithmetic operations
2
3use crate::ec::k256::constants::K256_SCALAR_SIZE;
4use crate::error::{validate, Error, Result};
5use dcrypt_common::security::SecretBuffer;
6use dcrypt_internal::zeroing::{Zeroize, ZeroizeOnDrop};
7
8/// secp256k1 scalar value for use in elliptic curve operations
9#[derive(Clone, Debug)]
10pub struct Scalar(SecretBuffer<K256_SCALAR_SIZE>);
11
12impl Zeroize for Scalar {
13    fn zeroize(&mut self) {
14        self.0.zeroize();
15    }
16}
17
18impl Drop for Scalar {
19    fn drop(&mut self) {
20        self.zeroize();
21    }
22}
23
24impl ZeroizeOnDrop for Scalar {}
25
26impl Scalar {
27    /// Create a new scalar from raw bytes.
28    ///
29    /// The value must use the canonical big-endian encoding in `1..n`.
30    /// Out-of-range inputs are rejected rather than reduced.
31    pub fn new(data: [u8; K256_SCALAR_SIZE]) -> Result<Self> {
32        Self::from_secret_buffer(SecretBuffer::new(data))
33    }
34
35    /// Create a scalar from a `SecretBuffer`.
36    ///
37    /// The buffer contents must be a canonical non-zero scalar.
38    pub fn from_secret_buffer(buffer: SecretBuffer<K256_SCALAR_SIZE>) -> Result<Self> {
39        Self::validate_canonical_nonzero(buffer.as_ref())?;
40        Ok(Self(buffer))
41    }
42
43    /// Get a reference to the underlying `SecretBuffer`.
44    pub fn as_secret_buffer(&self) -> &SecretBuffer<K256_SCALAR_SIZE> {
45        &self.0
46    }
47
48    /// Serialize this scalar to protected exact-size storage.
49    pub fn serialize(&self) -> SecretBuffer<K256_SCALAR_SIZE> {
50        self.0.clone()
51    }
52
53    /// Deserialize a canonical non-zero scalar.
54    pub fn deserialize(bytes: &[u8]) -> Result<Self> {
55        validate::length("K256 Scalar", bytes.len(), K256_SCALAR_SIZE)?;
56        let mut protected = SecretBuffer::zeroed();
57        protected.as_mut().copy_from_slice(bytes);
58        Self::from_secret_buffer(protected)
59    }
60
61    /// Check if this scalar is zero.
62    pub fn is_zero(&self) -> bool {
63        let mut any = 0u8;
64        for &byte in self.0.as_ref() {
65            any |= byte;
66        }
67        any == 0
68    }
69
70    fn validate_canonical_nonzero(bytes: &[u8]) -> Result<()> {
71        let mut any = 0u8;
72        for &byte in bytes {
73            any |= byte;
74        }
75        if any == 0 {
76            return Err(Error::param("K256 Scalar", "Scalar cannot be zero"));
77        }
78
79        let mut borrow = 0u8;
80        for i in (0..K256_SCALAR_SIZE).rev() {
81            let (difference, borrow_order) = bytes[i].overflowing_sub(Self::ORDER[i]);
82            let (_, borrow_previous) = difference.overflowing_sub(borrow);
83            borrow = (borrow_order | borrow_previous) as u8;
84        }
85        if borrow == 1 {
86            Ok(())
87        } else {
88            Err(Error::param(
89                "K256 Scalar",
90                "Scalar must be less than the group order",
91            ))
92        }
93    }
94
95    const ORDER: [u8; 32] = [
96        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
97        0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36,
98        0x41, 0x41,
99    ];
100}