dcrypt_algorithms/ec/p384/
scalar.rs1use crate::ec::p384::constants::P384_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_P384;
9
10#[derive(Clone, Debug)]
15pub struct Scalar(SecretBuffer<P384_SCALAR_SIZE>);
16
17impl Zeroize for Scalar {
18 fn zeroize(&mut self) {
19 self.0.zeroize();
20 }
21}
22
23impl Drop for Scalar {
24 fn drop(&mut self) {
25 self.zeroize();
26 }
27}
28
29impl ZeroizeOnDrop for Scalar {}
30
31impl Scalar {
32 pub fn new(data: [u8; P384_SCALAR_SIZE]) -> Result<Self> {
37 Self::from_secret_buffer(SecretBuffer::new(data))
38 }
39
40 pub fn from_bytes_reduced(data: [u8; P384_SCALAR_SIZE]) -> Self {
47 let mut protected = SecretBuffer::new(data);
48 Self::reduce_scalar_bytes_allow_zero(&mut protected);
49 Self::from_secret_buffer_unchecked(protected)
50 }
51
52 fn from_secret_buffer_unchecked(buffer: SecretBuffer<P384_SCALAR_SIZE>) -> Self {
57 Scalar(buffer)
58 }
59
60 pub fn from_secret_buffer(buffer: SecretBuffer<P384_SCALAR_SIZE>) -> Result<Self> {
65 Self::validate_canonical_nonzero(buffer.as_ref())?;
66 Ok(Self::from_secret_buffer_unchecked(buffer))
67 }
68
69 pub fn as_secret_buffer(&self) -> &SecretBuffer<P384_SCALAR_SIZE> {
71 &self.0
72 }
73
74 pub fn serialize(&self) -> SecretBuffer<P384_SCALAR_SIZE> {
80 self.0.clone()
81 }
82
83 pub fn deserialize(bytes: &[u8]) -> Result<Self> {
88 validate::length("P-384 Scalar", bytes.len(), P384_SCALAR_SIZE)?;
89
90 let mut protected = SecretBuffer::zeroed();
91 protected.as_mut().copy_from_slice(bytes);
92 Self::from_secret_buffer(protected)
93 }
94
95 pub fn is_zero(&self) -> bool {
100 let mut any = 0u8;
101 for &byte in self.0.as_ref() {
102 any |= byte;
103 }
104 any == 0
105 }
106
107 #[inline(always)]
109 fn to_le_limbs(bytes_be: &[u8]) -> Zeroizing<[u32; 12]> {
110 let mut limbs = Zeroizing::new([0u32; 12]);
111 for (i, limb) in limbs.iter_mut().enumerate() {
112 let start = 44 - i * 4;
114 *limb = ((bytes_be[start] as u32) << 24)
115 | ((bytes_be[start + 1] as u32) << 16)
116 | ((bytes_be[start + 2] as u32) << 8)
117 | bytes_be[start + 3] as u32;
118 }
119 limbs
120 }
121
122 #[inline(always)]
125 fn limbs_to_secret_buffer(limbs: &[u32; 12]) -> SecretBuffer<P384_SCALAR_SIZE> {
126 let mut out = SecretBuffer::zeroed();
127 for (i, &w) in limbs.iter().enumerate() {
128 let start = 44 - i * 4;
129 out[start] = (w >> 24) as u8;
130 out[start + 1] = (w >> 16) as u8;
131 out[start + 2] = (w >> 8) as u8;
132 out[start + 3] = w as u8;
133 }
134 out
135 }
136
137 pub fn add_mod_n(&self, other: &Self) -> Result<Self> {
139 let a = Self::to_le_limbs(self.0.as_ref());
140 let b = Self::to_le_limbs(other.0.as_ref());
141
142 let mut r = Zeroizing::new([0u32; 12]);
143 let mut carry = 0u64;
144
145 for i in 0..12 {
147 let tmp = a[i] as u64 + b[i] as u64 + carry;
148 r[i] = tmp as u32;
149 carry = tmp >> 32;
150 }
151
152 let unreduced = Self::from_secret_buffer_unchecked(Self::limbs_to_secret_buffer(&r));
153 let borrow = Self::sub_in_place(&mut r, &Self::N_LIMBS);
154 let need_reduce = Choice::from((carry as u8) | ((borrow ^ 1) as u8));
155 let reduced = Self::from_secret_buffer_unchecked(Self::limbs_to_secret_buffer(&r));
156
157 Ok(Self::conditional_select(&unreduced, &reduced, need_reduce))
158 }
159
160 pub fn sub_mod_n(&self, other: &Self) -> Result<Self> {
162 let a = Self::to_le_limbs(self.0.as_ref());
163 let b = Self::to_le_limbs(other.0.as_ref());
164
165 let mut r = Zeroizing::new([0u32; 12]);
166 let mut borrow = 0u64;
167
168 for (i, r_limb) in r.iter_mut().enumerate() {
169 let tmp = (a[i] as u64).wrapping_sub(b[i] as u64).wrapping_sub(borrow);
170 *r_limb = tmp as u32;
171 borrow = (tmp >> 63) & 1;
172 }
173
174 let unreduced = Self::from_secret_buffer_unchecked(Self::limbs_to_secret_buffer(&r));
175 let mut carry = 0u64;
176 for (i, r_limb) in r.iter_mut().enumerate() {
177 let tmp = *r_limb as u64 + Self::N_LIMBS[i] as u64 + carry;
178 *r_limb = tmp as u32;
179 carry = tmp >> 32;
180 }
181 let reduced = Self::from_secret_buffer_unchecked(Self::limbs_to_secret_buffer(&r));
182
183 Ok(Self::conditional_select(
184 &unreduced,
185 &reduced,
186 Choice::from(borrow as u8),
187 ))
188 }
189
190 pub fn mul_mod_n(&self, other: &Self) -> Result<Self> {
195 let mut acc = Self::zero();
197
198 for &byte in other.0.as_ref() {
200 for i in (0..8).rev() {
201 acc = acc.add_mod_n(&acc)?;
204
205 let acc_plus_self = acc.add_mod_n(self)?;
206 let choice = Choice::from((byte >> i) & 1);
207 acc = Self::conditional_select(&acc, &acc_plus_self, choice);
208 }
209 }
210
211 Ok(acc)
212 }
213
214 pub fn inv_mod_n(&self) -> Result<Self> {
216 if self.is_zero() {
218 return Err(Error::param("P-384 Scalar", "Cannot invert zero scalar"));
219 }
220
221 const N_MINUS_2: [u8; 48] = [
225 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
226 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0x63, 0x4D, 0x81,
227 0xF4, 0x37, 0x2D, 0xDF, 0x58, 0x1A, 0x0D, 0xB2, 0x48, 0xB0, 0xA7, 0x7A, 0xEC, 0xEC,
228 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x71,
229 ];
230
231 let mut result = Self::one();
232 let base = self.clone();
233
234 for byte in N_MINUS_2 {
235 for bit in (0..8).rev() {
236 result = result.mul_mod_n(&result)?;
237 if (byte >> bit) & 1 == 1 {
238 result = result.mul_mod_n(&base)?;
239 }
240 }
241 }
242
243 Ok(result)
244 }
245
246 pub fn negate(&self) -> Self {
251 let self_limbs = Self::to_le_limbs(self.0.as_ref());
253 let mut res = Zeroizing::new([0u32; 12]);
254
255 let mut borrow = 0u64;
257 for i in 0..12 {
258 let tmp = (Self::N_LIMBS[i] as u64)
259 .wrapping_sub(self_limbs[i] as u64)
260 .wrapping_sub(borrow);
261 res[i] = tmp as u32;
262 borrow = (tmp >> 63) & 1;
263 }
264 let negated = Self::from_secret_buffer_unchecked(Self::limbs_to_secret_buffer(&res));
265 Self::conditional_select(&negated, &Self::zero(), Choice::from(self.is_zero() as u8))
266 }
267
268 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-384 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-384 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<P384_SCALAR_SIZE>) {
292 let (candidate, borrow) = Self::subtract_order(bytes.as_ref());
293 let reduce = Choice::from(borrow ^ 1);
294 *bytes = Self::select_secret_buffer(bytes, &candidate, reduce);
295 }
296
297 #[inline(always)]
298 fn subtract_order(bytes: &[u8]) -> (SecretBuffer<P384_SCALAR_SIZE>, u8) {
299 let mut result = SecretBuffer::zeroed();
300 let mut borrow = 0u8;
301 for i in (0..P384_SCALAR_SIZE).rev() {
302 let (difference, borrow_order) = bytes[i].overflowing_sub(NIST_P384.n[i]);
303 let (difference, borrow_previous) = difference.overflowing_sub(borrow);
304 result[i] = difference;
305 borrow = (borrow_order | borrow_previous) as u8;
306 }
307 (result, borrow)
308 }
309
310 const N_LIMBS: [u32; 12] = [
314 0xCCC5_2973,
315 0xECEC_196A,
316 0x48B0_A77A,
317 0x581A_0DB2,
318 0xF437_2DDF,
319 0xC763_4D81,
320 0xFFFF_FFFF,
321 0xFFFF_FFFF,
322 0xFFFF_FFFF,
323 0xFFFF_FFFF,
324 0xFFFF_FFFF,
325 0xFFFF_FFFF,
326 ];
327
328 #[inline(never)]
329 fn select_secret_buffer(
330 a: &SecretBuffer<P384_SCALAR_SIZE>,
331 b: &SecretBuffer<P384_SCALAR_SIZE>,
332 choice: Choice,
333 ) -> SecretBuffer<P384_SCALAR_SIZE> {
334 let mut out = SecretBuffer::zeroed();
335 for i in 0..P384_SCALAR_SIZE {
336 out[i] = u8::conditional_select(&a[i], &b[i], choice);
337 }
338 out
339 }
340
341 #[inline(always)]
342 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
343 Self::from_secret_buffer_unchecked(Self::select_secret_buffer(&a.0, &b.0, choice))
344 }
345
346 fn zero() -> Self {
347 Self::from_secret_buffer_unchecked(SecretBuffer::zeroed())
348 }
349
350 fn one() -> Self {
351 let mut one = SecretBuffer::zeroed();
352 one[P384_SCALAR_SIZE - 1] = 1;
353 Self::from_secret_buffer_unchecked(one)
354 }
355
356 #[inline(always)]
358 fn sub_in_place(a: &mut [u32; 12], b: &[u32; 12]) -> u64 {
359 let mut borrow = 0u64;
360 for i in 0..12 {
361 let tmp = (a[i] as u64).wrapping_sub(b[i] as u64).wrapping_sub(borrow);
362 a[i] = tmp as u32;
363 borrow = (tmp >> 63) & 1;
364 }
365 borrow
366 }
367}