dcrypt_algorithms/ec/p521/
scalar.rs1use crate::ec::p521::constants::{p521_bytes_to_limbs, p521_limbs_to_bytes, P521_SCALAR_SIZE};
4use crate::ec::p521::field::FieldElement;
5use crate::error::{validate, Error, Result};
6use dcrypt_common::security::SecretBuffer;
7use dcrypt_params::traditional::ecdsa::NIST_P521;
8use subtle::{Choice, ConditionallySelectable};
9use zeroize::{Zeroize, ZeroizeOnDrop};
10
11#[derive(Clone, Zeroize, ZeroizeOnDrop, Debug)]
15pub struct Scalar(SecretBuffer<P521_SCALAR_SIZE>);
16
17impl Scalar {
18 pub fn new(mut data: [u8; P521_SCALAR_SIZE]) -> Result<Self> {
23 Self::reduce_scalar_bytes(&mut data)?;
24 Ok(Scalar(SecretBuffer::new(data)))
25 }
26
27 pub(super) fn from_bytes_unchecked(bytes: [u8; P521_SCALAR_SIZE]) -> Self {
31 Scalar(SecretBuffer::new(bytes))
32 }
33
34 pub fn from_secret_buffer(buffer: SecretBuffer<P521_SCALAR_SIZE>) -> Result<Self> {
38 let mut bytes = [0u8; P521_SCALAR_SIZE];
39 bytes.copy_from_slice(buffer.as_ref());
40
41 Self::reduce_scalar_bytes(&mut bytes)?;
42 Ok(Scalar(SecretBuffer::new(bytes)))
43 }
44
45 pub fn as_secret_buffer(&self) -> &SecretBuffer<P521_SCALAR_SIZE> {
47 &self.0
48 }
49
50 pub fn serialize(&self) -> [u8; P521_SCALAR_SIZE] {
54 let mut result = [0u8; P521_SCALAR_SIZE];
55 result.copy_from_slice(self.0.as_ref());
56 result
57 }
58
59 pub fn deserialize(bytes: &[u8]) -> Result<Self> {
63 validate::length("P-521 Scalar", bytes.len(), P521_SCALAR_SIZE)?;
64
65 let mut scalar_bytes = [0u8; P521_SCALAR_SIZE];
66 scalar_bytes.copy_from_slice(bytes);
67
68 Self::new(scalar_bytes)
69 }
70
71 pub fn is_zero(&self) -> bool {
75 self.0.as_ref().iter().all(|&b| b == 0)
76 }
77
78 #[inline(always)]
80 fn to_le_limbs(bytes_be: &[u8; 66]) -> [u32; 17] {
81 p521_bytes_to_limbs(bytes_be)
82 }
83
84 #[inline(always)]
86 fn limbs_to_be(limbs: &[u32; 17]) -> [u8; 66] {
87 p521_limbs_to_bytes(limbs)
88 }
89
90 pub fn add_mod_n(&self, other: &Self) -> Result<Self> {
92 let a = Self::to_le_limbs(&self.serialize());
93 let b = Self::to_le_limbs(&other.serialize());
94
95 let (r, carry) = FieldElement::adc_n(a, b);
96 let unreduced = Self::from_bytes_unchecked(Self::limbs_to_be(&r));
97 let (reduced, borrow) = FieldElement::sbb_n(r, Self::N_LIMBS);
98 let need_reduce = Choice::from((carry as u8) | ((borrow ^ 1) as u8));
99
100 Ok(Self::conditional_select(
101 &unreduced,
102 &Self::from_bytes_unchecked(Self::limbs_to_be(&reduced)),
103 need_reduce,
104 ))
105 }
106
107 pub fn sub_mod_n(&self, other: &Self) -> Result<Self> {
109 let a = Self::to_le_limbs(&self.serialize());
110 let b = Self::to_le_limbs(&other.serialize());
111
112 let (r, borrow) = FieldElement::sbb_n(a, b);
113 let unreduced = Self::from_bytes_unchecked(Self::limbs_to_be(&r));
114 let (reduced, _) = FieldElement::adc_n(r, Self::N_LIMBS);
115
116 Ok(Self::conditional_select(
117 &unreduced,
118 &Self::from_bytes_unchecked(Self::limbs_to_be(&reduced)),
119 Choice::from(borrow as u8),
120 ))
121 }
122
123 pub fn mul_mod_n(&self, other: &Self) -> Result<Self> {
127 let mut acc = Self::from_bytes_unchecked([0u8; P521_SCALAR_SIZE]);
129
130 for byte in other.serialize() {
132 for i in (0..8).rev() {
133 acc = acc.add_mod_n(&acc)?;
136
137 let acc_plus_self = acc.add_mod_n(self)?;
138 let choice = Choice::from((byte >> i) & 1);
139 acc = Self::conditional_select(&acc, &acc_plus_self, choice);
140 }
141 }
142
143 Ok(acc)
144 }
145
146 pub fn inv_mod_n(&self) -> Result<Self> {
149 if self.is_zero() {
151 return Err(Error::param("P-521 Scalar", "Cannot invert zero scalar"));
152 }
153
154 let mut exp = NIST_P521.n; let mut borrow = 2u16;
158 for i in (0..P521_SCALAR_SIZE).rev() {
159 let v = exp[i] as i16 - (borrow as i16);
160 if v < 0 {
161 exp[i] = (v + 256) as u8;
162 borrow = 1;
163 } else {
164 exp[i] = v as u8;
165 borrow = 0;
166 }
167 }
168
169 let mut result = {
171 let mut one = [0u8; P521_SCALAR_SIZE];
172 one[P521_SCALAR_SIZE - 1] = 1;
173 Self::from_bytes_unchecked(one)
174 };
175 let base = self.clone();
176
177 for byte in exp {
178 for bit in (0..8).rev() {
179 result = result.mul_mod_n(&result)?;
181 if (byte >> bit) & 1 == 1 {
183 result = result.mul_mod_n(&base)?;
184 }
185 }
186 }
187
188 Ok(result)
189 }
190
191 pub fn negate(&self) -> Self {
195 if self.is_zero() {
197 return Self::from_bytes_unchecked([0u8; P521_SCALAR_SIZE]);
198 }
199
200 let n_limbs = Self::N_LIMBS;
202 let self_limbs = Self::to_le_limbs(&self.serialize());
203 let mut res = [0u32; 17];
204
205 let mut borrow = 0i64;
207 for i in 0..17 {
208 let tmp = n_limbs[i] as i64 - self_limbs[i] as i64 - borrow;
209 if tmp < 0 {
210 res[i] = (tmp + (1i64 << 32)) as u32;
211 borrow = 1;
212 } else {
213 res[i] = tmp as u32;
214 borrow = 0;
215 }
216 }
217
218 debug_assert_eq!(borrow, 0);
220
221 Self::from_bytes_unchecked(Self::limbs_to_be(&res))
222 }
223
224 fn reduce_scalar_bytes(bytes: &mut [u8; P521_SCALAR_SIZE]) -> Result<()> {
238 let order = &NIST_P521.n;
239
240 if bytes.iter().all(|&b| b == 0) {
242 return Err(Error::param("P-521 Scalar", "Scalar cannot be zero"));
243 }
244
245 let mut reduced = *bytes;
246 for _ in 0..128 {
247 let mut candidate = reduced;
248 let mut borrow = 0u16;
249 for i in (0..P521_SCALAR_SIZE).rev() {
250 let diff = candidate[i] as i16 - order[i] as i16 - borrow as i16;
251 if diff < 0 {
252 candidate[i] = (diff + 256) as u8;
253 borrow = 1;
254 } else {
255 candidate[i] = diff as u8;
256 borrow = 0;
257 }
258 }
259
260 let choice = Choice::from((borrow ^ 1) as u8);
261 for i in 0..P521_SCALAR_SIZE {
262 reduced[i] = u8::conditional_select(&reduced[i], &candidate[i], choice);
263 }
264 }
265
266 *bytes = reduced;
267 Ok(())
268 }
269
270 const N_LIMBS: [u32; 17] = [
272 0x9138_6409, 0xBB6F_B71E, 0x899C_47AE, 0x3BB5_C9B8, 0xF709_A5D0, 0x7FCC_0148, 0xBF2F_966B, 0x5186_8783, 0xFFFF_FFFA, 0xFFFF_FFFF, 0xFFFF_FFFF, 0xFFFF_FFFF, 0xFFFF_FFFF, 0xFFFF_FFFF, 0xFFFF_FFFF, 0xFFFF_FFFF, 0x0000_01FF, ];
290
291 #[inline(always)]
293 fn geq(a: &[u32; 17], b: &[u32; 17]) -> bool {
294 for i in (0..17).rev() {
295 if a[i] > b[i] {
296 return true;
297 }
298 if a[i] < b[i] {
299 return false;
300 }
301 }
302 true }
304
305 #[inline(always)]
307 fn sub_in_place(a: &mut [u32; 17], b: &[u32; 17]) {
308 let mut borrow = 0u64;
309 for i in 0..17 {
310 let tmp = (a[i] as u64).wrapping_sub(b[i] as u64).wrapping_sub(borrow);
311 a[i] = tmp as u32;
312 borrow = (tmp >> 63) & 1; }
314 }
315
316 #[inline(always)]
317 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
318 let a_bytes = a.serialize();
319 let b_bytes = b.serialize();
320 let mut out = [0u8; P521_SCALAR_SIZE];
321 for i in 0..P521_SCALAR_SIZE {
322 out[i] = u8::conditional_select(&a_bytes[i], &b_bytes[i], choice);
323 }
324 Self::from_bytes_unchecked(out)
325 }
326}