dcrypt_algorithms/ec/p521/
scalar.rs1use crate::ec::p521::constants::P521_SCALAR_SIZE;
4use crate::error::{validate, Error, Result};
5use dcrypt_common::security::SecretBuffer;
6use dcrypt_internal::constant_time::{Choice, ConditionallySelectable};
7use dcrypt_internal::zeroing::{Zeroize, ZeroizeOnDrop, Zeroizing};
8use dcrypt_params::traditional::ecdsa::NIST_P521;
9
10#[derive(Clone, Debug)]
14pub struct Scalar(SecretBuffer<P521_SCALAR_SIZE>);
15
16impl Zeroize for Scalar {
17 fn zeroize(&mut self) {
18 self.0.zeroize();
19 }
20}
21
22impl Drop for Scalar {
23 fn drop(&mut self) {
24 self.zeroize();
25 }
26}
27
28impl ZeroizeOnDrop for Scalar {}
29
30impl Scalar {
31 pub fn new(data: [u8; P521_SCALAR_SIZE]) -> Result<Self> {
36 Self::from_secret_buffer(SecretBuffer::new(data))
37 }
38
39 pub fn from_bytes_reduced(data: [u8; P521_SCALAR_SIZE]) -> Self {
46 let mut protected = SecretBuffer::new(data);
47 Self::reduce_scalar_bytes_allow_zero(&mut protected);
48 Self::from_secret_buffer_unchecked(protected)
49 }
50
51 fn from_secret_buffer_unchecked(buffer: SecretBuffer<P521_SCALAR_SIZE>) -> Self {
55 Scalar(buffer)
56 }
57
58 pub fn from_secret_buffer(buffer: SecretBuffer<P521_SCALAR_SIZE>) -> Result<Self> {
62 Self::validate_canonical_nonzero(buffer.as_ref())?;
63 Ok(Self::from_secret_buffer_unchecked(buffer))
64 }
65
66 pub fn as_secret_buffer(&self) -> &SecretBuffer<P521_SCALAR_SIZE> {
68 &self.0
69 }
70
71 pub fn serialize(&self) -> SecretBuffer<P521_SCALAR_SIZE> {
76 self.0.clone()
77 }
78
79 pub fn deserialize(bytes: &[u8]) -> Result<Self> {
83 validate::length("P-521 Scalar", bytes.len(), P521_SCALAR_SIZE)?;
84
85 let mut protected = SecretBuffer::zeroed();
86 protected.as_mut().copy_from_slice(bytes);
87 Self::from_secret_buffer(protected)
88 }
89
90 pub fn is_zero(&self) -> bool {
94 let mut any = 0u8;
95 for &byte in self.0.as_ref() {
96 any |= byte;
97 }
98 any == 0
99 }
100
101 #[inline(always)]
103 fn to_le_limbs(bytes_be: &[u8]) -> Zeroizing<[u32; 17]> {
104 let mut limbs = Zeroizing::new([0u32; 17]);
105 for i in 0..16 {
106 let offset = P521_SCALAR_SIZE - 4 - i * 4;
107 limbs[i] = ((bytes_be[offset] as u32) << 24)
108 | ((bytes_be[offset + 1] as u32) << 16)
109 | ((bytes_be[offset + 2] as u32) << 8)
110 | bytes_be[offset + 3] as u32;
111 }
112 limbs[16] = (((bytes_be[0] as u32) << 8) | bytes_be[1] as u32) & 0x1ff;
113 limbs
114 }
115
116 #[inline(always)]
118 fn limbs_to_secret_buffer(limbs: &[u32; 17]) -> SecretBuffer<P521_SCALAR_SIZE> {
119 let mut out = SecretBuffer::zeroed();
120 for (i, &limb) in limbs.iter().take(16).enumerate() {
121 let offset = P521_SCALAR_SIZE - 4 - i * 4;
122 out[offset] = (limb >> 24) as u8;
123 out[offset + 1] = (limb >> 16) as u8;
124 out[offset + 2] = (limb >> 8) as u8;
125 out[offset + 3] = limb as u8;
126 }
127 let most_significant = limbs[16] & 0x1ff;
128 out[0] = (most_significant >> 8) as u8;
129 out[1] = most_significant as u8;
130 out
131 }
132
133 pub fn add_mod_n(&self, other: &Self) -> Result<Self> {
135 let a = Self::to_le_limbs(self.0.as_ref());
136 let b = Self::to_le_limbs(other.0.as_ref());
137 let mut r = Zeroizing::new([0u32; 17]);
138 let mut carry = 0u64;
139 for i in 0..17 {
140 let sum = a[i] as u64 + b[i] as u64 + carry;
141 r[i] = sum as u32;
142 carry = sum >> 32;
143 }
144 let unreduced = Self::from_secret_buffer_unchecked(Self::limbs_to_secret_buffer(&r));
145 let borrow = Self::sub_in_place(&mut r, &Self::N_LIMBS);
146 let need_reduce = Choice::from((carry as u8) | ((borrow ^ 1) as u8));
147 let reduced = Self::from_secret_buffer_unchecked(Self::limbs_to_secret_buffer(&r));
148
149 Ok(Self::conditional_select(&unreduced, &reduced, need_reduce))
150 }
151
152 pub fn sub_mod_n(&self, other: &Self) -> Result<Self> {
154 let a = Self::to_le_limbs(self.0.as_ref());
155 let b = Self::to_le_limbs(other.0.as_ref());
156 let mut r = Zeroizing::new([0u32; 17]);
157 let mut borrow = 0u64;
158 for i in 0..17 {
159 let difference = (a[i] as u64).wrapping_sub(b[i] as u64).wrapping_sub(borrow);
160 r[i] = difference as u32;
161 borrow = (difference >> 63) & 1;
162 }
163 let unreduced = Self::from_secret_buffer_unchecked(Self::limbs_to_secret_buffer(&r));
164 let mut carry = 0u64;
165 for i in 0..17 {
166 let sum = r[i] as u64 + Self::N_LIMBS[i] as u64 + carry;
167 r[i] = sum as u32;
168 carry = sum >> 32;
169 }
170 let reduced = Self::from_secret_buffer_unchecked(Self::limbs_to_secret_buffer(&r));
171
172 Ok(Self::conditional_select(
173 &unreduced,
174 &reduced,
175 Choice::from(borrow as u8),
176 ))
177 }
178
179 pub fn mul_mod_n(&self, other: &Self) -> Result<Self> {
183 let mut acc = Self::zero();
185
186 for &byte in other.0.as_ref() {
188 for i in (0..8).rev() {
189 acc = acc.add_mod_n(&acc)?;
192
193 let acc_plus_self = acc.add_mod_n(self)?;
194 let choice = Choice::from((byte >> i) & 1);
195 acc = Self::conditional_select(&acc, &acc_plus_self, choice);
196 }
197 }
198
199 Ok(acc)
200 }
201
202 pub fn inv_mod_n(&self) -> Result<Self> {
205 if self.is_zero() {
207 return Err(Error::param("P-521 Scalar", "Cannot invert zero scalar"));
208 }
209
210 let mut exp = Zeroizing::new(NIST_P521.n); let mut borrow = 2u16;
214 for i in (0..P521_SCALAR_SIZE).rev() {
215 let v = exp[i] as i16 - (borrow as i16);
216 if v < 0 {
217 exp[i] = (v + 256) as u8;
218 borrow = 1;
219 } else {
220 exp[i] = v as u8;
221 borrow = 0;
222 }
223 }
224
225 let mut result = { Self::one() };
227 let base = self.clone();
228
229 for &byte in exp.iter() {
230 for bit in (0..8).rev() {
231 result = result.mul_mod_n(&result)?;
233 if (byte >> bit) & 1 == 1 {
235 result = result.mul_mod_n(&base)?;
236 }
237 }
238 }
239
240 Ok(result)
241 }
242
243 pub fn negate(&self) -> Self {
247 let self_limbs = Self::to_le_limbs(self.0.as_ref());
249 let mut res = Zeroizing::new([0u32; 17]);
250
251 let mut borrow = 0u64;
253 for i in 0..17 {
254 let tmp = (Self::N_LIMBS[i] as u64)
255 .wrapping_sub(self_limbs[i] as u64)
256 .wrapping_sub(borrow);
257 res[i] = tmp as u32;
258 borrow = (tmp >> 63) & 1;
259 }
260 let negated = Self::from_secret_buffer_unchecked(Self::limbs_to_secret_buffer(&res));
261 Self::conditional_select(&negated, &Self::zero(), Choice::from(self.is_zero() as u8))
262 }
263
264 fn validate_canonical_nonzero(bytes: &[u8]) -> Result<()> {
271 let mut any = 0u8;
272 for &byte in bytes {
273 any |= byte;
274 }
275 if any == 0 {
276 return Err(Error::param("P-521 Scalar", "Scalar cannot be zero"));
277 }
278
279 let (_, borrow) = Self::subtract_order(bytes);
280 if borrow == 0 {
281 return Err(Error::param(
282 "P-521 Scalar",
283 "Scalar must be less than the group order",
284 ));
285 }
286
287 Ok(())
288 }
289
290 fn reduce_scalar_bytes_allow_zero(bytes: &mut SecretBuffer<P521_SCALAR_SIZE>) {
292 for _ in 0..128 {
293 let (candidate, borrow) = Self::subtract_order(bytes.as_ref());
294
295 let choice = Choice::from(borrow ^ 1);
296 *bytes = Self::select_secret_buffer(bytes, &candidate, choice);
297 }
298 }
299
300 #[inline(always)]
301 fn subtract_order(bytes: &[u8]) -> (SecretBuffer<P521_SCALAR_SIZE>, u8) {
302 let mut result = SecretBuffer::zeroed();
303 let mut borrow = 0u8;
304 for i in (0..P521_SCALAR_SIZE).rev() {
305 let (difference, borrow_order) = bytes[i].overflowing_sub(NIST_P521.n[i]);
306 let (difference, borrow_previous) = difference.overflowing_sub(borrow);
307 result[i] = difference;
308 borrow = (borrow_order | borrow_previous) as u8;
309 }
310 (result, borrow)
311 }
312
313 const N_LIMBS: [u32; 17] = [
315 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, ];
333
334 #[inline(never)]
335 fn select_secret_buffer(
336 a: &SecretBuffer<P521_SCALAR_SIZE>,
337 b: &SecretBuffer<P521_SCALAR_SIZE>,
338 choice: Choice,
339 ) -> SecretBuffer<P521_SCALAR_SIZE> {
340 let mut out = SecretBuffer::zeroed();
341 for i in 0..P521_SCALAR_SIZE {
342 out[i] = u8::conditional_select(&a[i], &b[i], choice);
343 }
344 out
345 }
346
347 #[inline(always)]
348 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
349 Self::from_secret_buffer_unchecked(Self::select_secret_buffer(&a.0, &b.0, choice))
350 }
351
352 fn zero() -> Self {
353 Self::from_secret_buffer_unchecked(SecretBuffer::zeroed())
354 }
355
356 fn one() -> Self {
357 let mut one = SecretBuffer::zeroed();
358 one[P521_SCALAR_SIZE - 1] = 1;
359 Self::from_secret_buffer_unchecked(one)
360 }
361
362 #[inline(always)]
363 fn sub_in_place(a: &mut [u32; 17], b: &[u32; 17]) -> u64 {
364 let mut borrow = 0u64;
365 for i in 0..17 {
366 let difference = (a[i] as u64).wrapping_sub(b[i] as u64).wrapping_sub(borrow);
367 a[i] = difference as u32;
368 borrow = (difference >> 63) & 1;
369 }
370 borrow
371 }
372}