dcrypt_algorithms/ec/b283k/
scalar.rs

1//! sect283k1 scalar arithmetic operations
2
3use crate::ec::b283k::constants::B283K_SCALAR_SIZE;
4use crate::error::{Error, Result};
5use dcrypt_common::security::SecretBuffer;
6use zeroize::{Zeroize, ZeroizeOnDrop};
7
8/// sect283k1 scalar value for use in elliptic curve operations
9#[derive(Clone, Zeroize, ZeroizeOnDrop, Debug)]
10pub struct Scalar(SecretBuffer<B283K_SCALAR_SIZE>);
11
12impl Scalar {
13    /// Create a new scalar from raw bytes.
14    ///
15    /// The bytes will be reduced modulo the curve order if necessary.
16    /// The most significant bit is masked to ensure the scalar is < 2^283.
17    /// Returns an error if the resulting scalar would be zero.
18    pub fn new(mut data: [u8; B283K_SCALAR_SIZE]) -> Result<Self> {
19        Self::reduce_scalar_bytes(&mut data)?;
20        Ok(Scalar(SecretBuffer::new(data)))
21    }
22
23    /// Create a scalar from a `SecretBuffer`.
24    ///
25    /// The buffer contents will be reduced modulo the curve order if necessary.
26    /// Returns an error if the resulting scalar would be zero.
27    pub fn from_secret_buffer(buffer: SecretBuffer<B283K_SCALAR_SIZE>) -> Result<Self> {
28        let mut bytes = [0u8; B283K_SCALAR_SIZE];
29        bytes.copy_from_slice(buffer.as_ref());
30        Self::reduce_scalar_bytes(&mut bytes)?;
31        Ok(Scalar(SecretBuffer::new(bytes)))
32    }
33
34    /// Get a reference to the underlying `SecretBuffer`.
35    pub fn as_secret_buffer(&self) -> &SecretBuffer<B283K_SCALAR_SIZE> {
36        &self.0
37    }
38
39    /// Serialize this scalar to bytes.
40    pub fn serialize(&self) -> [u8; B283K_SCALAR_SIZE] {
41        let mut result = [0u8; B283K_SCALAR_SIZE];
42        result.copy_from_slice(self.0.as_ref());
43        result
44    }
45
46    /// Check if this scalar is zero.
47    pub fn is_zero(&self) -> bool {
48        self.0.as_ref().iter().all(|&b| b == 0)
49    }
50
51    fn reduce_scalar_bytes(bytes: &mut [u8; B283K_SCALAR_SIZE]) -> Result<()> {
52        bytes[0] &= 0x01; // Ensure the scalar is < 2^283
53        if bytes.iter().all(|&b| b == 0) {
54            return Err(Error::param("B283k Scalar", "Scalar cannot be zero"));
55        }
56
57        let mut is_ge = false;
58        for (i, (&byte, &order_byte)) in bytes.iter().zip(Self::ORDER.iter()).enumerate() {
59            if byte > order_byte {
60                is_ge = true;
61                break;
62            }
63            if byte < order_byte {
64                break;
65            }
66            if i == B283K_SCALAR_SIZE - 1 {
67                is_ge = true;
68            }
69        }
70
71        if is_ge {
72            let mut borrow = 0i16;
73            for i in (0..B283K_SCALAR_SIZE).rev() {
74                let diff = (bytes[i] as i16) - (Self::ORDER[i] as i16) - borrow;
75                if diff < 0 {
76                    bytes[i] = (diff + 256) as u8;
77                    borrow = 1;
78                } else {
79                    bytes[i] = diff as u8;
80                    borrow = 0;
81                }
82            }
83        }
84
85        if bytes.iter().all(|&b| b == 0) {
86            return Err(Error::param(
87                "B283k Scalar",
88                "Reduction resulted in zero scalar",
89            ));
90        }
91        Ok(())
92    }
93
94    const ORDER: [u8; 36] = [
95        0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
96        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x96, 0xE4, 0x04, 0x28,
97        0x2D, 0xD3, 0x23, 0x22, 0x83, 0xE5,
98    ];
99}