primitives/algebra/elliptic_curve/p384/
mod.rs1use std::{
2 hash::{Hash, Hasher},
3 iter::Sum,
4 mem::MaybeUninit,
5 ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
6};
7
8use elliptic_curve::{
9 bigint::U384,
10 group::{Group, GroupEncoding},
11 hash2curve::{ExpandMsgXmd, GroupDigest},
12 ops::MulByGenerator,
13 sec1::{FromEncodedPoint, ToEncodedPoint},
14 FieldBytesEncoding,
15};
16use ff::Field;
17use hybrid_array::Array;
18use rand::RngCore;
19use sha2::Sha384;
20use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
21use typenum::{U3, U48};
22
23use crate::{
24 algebra::{
25 elliptic_curve::{
26 curve::{FromCoordinates, PointAtInfinityError, ToCoordinates},
27 BaseFieldElement,
28 Curve,
29 },
30 field::{FieldExtension, SubfieldElement},
31 },
32 errors::PrimitiveError,
33 utils::codec::InPlaceCodec,
34};
35
36macro_rules! impl_p384_field {
43 ($field:ident, $repr:ident, $name:literal) => {
44 impl std::hash::Hash for $field {
45 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
46 use crate::algebra::field::FieldExtension;
47 self.to_le_bytes().into_iter().for_each(|x| {
48 x.hash(state);
49 });
50 }
51 }
52
53 impl From<u128> for $field {
54 fn from(value: u128) -> Self {
55 let mut bytes = [0u8; 56];
56 bytes[..16].copy_from_slice(&value.to_le_bytes());
57 <Self as ff::PrimeField>::from_repr($repr(bytes)).unwrap()
58 }
59 }
60
61 impl crate::algebra::uniform_bytes::FromUniformBytes for $field {
62 type UniformBytes = typenum::U64;
63
64 fn from_uniform_bytes(bytes: &hybrid_array::Array<u8, Self::UniformBytes>) -> Self {
65 use ff::PrimeField;
66 let mut lo = [0u8; 56];
69 lo[..32].copy_from_slice(&bytes[..32]);
70 let mut hi = [0u8; 56];
71 hi[..32].copy_from_slice(&bytes[32..]);
72 let mut pow = [0u8; 56];
73 pow[32] = 1;
74 let lo = Self::from_repr($repr(lo)).unwrap();
75 let hi = Self::from_repr($repr(hi)).unwrap();
76 let two_pow_256 = Self::from_repr($repr(pow)).unwrap();
77 hi * two_pow_256 + lo
78 }
79 }
80
81 impl crate::algebra::field::FieldExtension for $field {
82 type Subfield = Self;
83
84 type Degree = typenum::U1;
85 type FieldBitSize = typenum::U384;
86 type FieldBytesSize = typenum::U48;
87
88 fn to_subfield_elements(&self) -> hybrid_array::Array<Self::Subfield, Self::Degree> {
89 hybrid_array::Array([*self])
90 }
91
92 fn from_subfield_elements(
93 elems: hybrid_array::Array<Self::Subfield, Self::Degree>,
94 ) -> Self {
95 elems[0]
96 }
97
98 fn to_le_bytes(&self) -> hybrid_array::Array<u8, Self::FieldBytesSize> {
99 <[u8; 48]>::try_from(&ff::PrimeField::to_repr(self).as_ref()[..48])
101 .unwrap()
102 .into()
103 }
104
105 fn from_le_bytes(bytes: &[u8]) -> Option<Self> {
106 if bytes.len() != 48 {
107 return None;
108 }
109 let mut repr = [0u8; 56];
110 repr[..48].copy_from_slice(bytes);
111 ff::PrimeField::from_repr($repr(repr)).into()
112 }
113
114 fn mul_by_subfield(&self, other: &Self::Subfield) -> Self {
115 *self * other
116 }
117
118 fn generator() -> Self {
119 <Self as ff::PrimeField>::MULTIPLICATIVE_GENERATOR
120 }
121 }
122
123 unsafe impl crate::utils::codec::InPlaceCodec for $field {
128 const ENCODED_SIZE: usize = 48;
129
130 fn write_le_bytes(&self, out: &mut [std::mem::MaybeUninit<u8>]) {
131 let bytes = crate::algebra::field::FieldExtension::to_le_bytes(self);
132 for (slot, &b) in out.iter_mut().zip(bytes.iter()) {
133 slot.write(b);
134 }
135 }
136
137 fn read_le_bytes(bytes: &[u8]) -> Result<Self, crate::errors::PrimitiveError> {
138 <Self as crate::algebra::field::FieldExtension>::from_le_bytes(bytes).ok_or_else(
139 || {
140 crate::errors::PrimitiveError::DeserializationFailed(
141 concat!("non-canonical ", $name, " encoding").into(),
142 )
143 },
144 )
145 }
146 }
147
148 impl crate::random::Random for $field {
149 fn random(rng: impl crate::random::CryptoRngCore) -> Self {
150 <Self as ff::Field>::random(rng)
151 }
152 }
153
154 impl crate::types::identifiers::Named for $field {
155 fn get_name() -> String {
156 $name.to_string()
157 }
158 }
159
160 impl crate::algebra::ops::IntoWide for $field {
163 #[inline]
164 fn to_wide(&self) -> Self {
165 *self
166 }
167
168 #[inline]
169 fn zero_wide() -> Self {
170 <Self as ff::Field>::ZERO
171 }
172 }
173
174 impl crate::algebra::ops::ReduceWide for $field {
175 #[inline]
176 fn reduce_mod_order(a: Self) -> Self {
177 a
178 }
179 }
180
181 impl crate::algebra::ops::MulAccReduce for $field {
182 type WideType = Self;
183
184 #[inline]
185 fn mul_acc(acc: &mut Self, a: Self, b: Self) {
186 *acc += a * b;
187 }
188 }
189
190 impl<'a> crate::algebra::ops::MulAccReduce<Self, &'a Self> for $field {
191 type WideType = Self;
192
193 #[inline]
194 fn mul_acc(acc: &mut Self, a: Self, b: &'a Self) {
195 *acc += a * b;
196 }
197 }
198
199 impl<'a> crate::algebra::ops::MulAccReduce<&'a Self, Self> for $field {
200 type WideType = Self;
201
202 #[inline]
203 fn mul_acc(acc: &mut Self, a: &'a Self, b: Self) {
204 *acc += *a * b;
205 }
206 }
207
208 impl<'a> crate::algebra::ops::MulAccReduce<&'a Self, &'a Self> for $field {
209 type WideType = Self;
210
211 #[inline]
212 fn mul_acc(acc: &mut Self, a: &'a Self, b: &'a Self) {
213 *acc += *a * b;
214 }
215 }
216
217 impl crate::algebra::ops::AccReduce for $field {
218 type WideType = Self;
219
220 #[inline]
221 fn acc(acc: &mut Self, a: Self) {
222 *acc += a;
223 }
224 }
225
226 impl<'a> crate::algebra::ops::AccReduce<&'a Self> for $field {
227 type WideType = Self;
228
229 #[inline]
230 fn acc(acc: &mut Self, a: &'a Self) {
231 *acc += a;
232 }
233 }
234
235 impl crate::algebra::ops::DefaultDotProduct for $field {}
236 impl crate::algebra::ops::DefaultDotProduct<Self, &Self> for $field {}
237 impl<'a> crate::algebra::ops::DefaultDotProduct<&'a Self, &'a Self> for $field {}
238 impl crate::algebra::ops::DefaultDotProduct<&Self, Self> for $field {}
239 };
240}
241
242pub mod base_field;
243pub mod scalar_field;
244
245pub use base_field::BaseFieldP384;
246pub use scalar_field::ScalarP384;
247
248#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
253pub struct P384;
254
255impl elliptic_curve::Curve for P384 {
256 type FieldBytesSize = U48;
257 type Uint = U384;
258
259 const ORDER: U384 = U384::from_be_hex(
260 "ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973",
261 );
262}
263
264impl FieldBytesEncoding<P384> for U384 {}
265
266impl Curve for P384 {
267 const NAME: &'static str = "NIST P-384";
268 const SCALAR_BIG_ENDIAN: bool = false;
269 const POINT_BIG_ENDIAN: bool = true;
270 const BASE_FIELD_BIG_ENDIAN: bool = false;
271
272 type Point = PointP384;
273 type Scalar = ScalarP384;
274 type BaseField = BaseFieldP384;
275
276 fn hash_to_curve(bytes: &[u8]) -> Self::Point {
277 PointP384(
279 ::p384::NistP384::hash_from_bytes::<ExpandMsgXmd<Sha384>>(
280 &[bytes],
281 &[b"P384_XMD:SHA-384_SSWU_RO_"],
282 )
283 .expect("hash-to-curve with a fixed non-empty DST cannot fail"),
284 )
285 }
286}
287
288#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
292#[repr(transparent)]
293pub struct PointP384(pub ::p384::ProjectivePoint);
294
295impl Hash for PointP384 {
296 fn hash<H: Hasher>(&self, state: &mut H) {
297 self.to_bytes().as_slice().hash(state);
299 }
300}
301
302impl ConstantTimeEq for PointP384 {
303 #[inline]
304 fn ct_eq(&self, other: &Self) -> Choice {
305 self.0.ct_eq(&other.0)
306 }
307}
308
309impl ConditionallySelectable for PointP384 {
310 #[inline]
311 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
312 Self(::p384::ProjectivePoint::conditional_select(
313 &a.0, &b.0, choice,
314 ))
315 }
316}
317
318#[macros::op_variants(owned)]
319impl Add<&PointP384> for PointP384 {
320 type Output = PointP384;
321
322 #[inline]
323 fn add(mut self, rhs: &PointP384) -> PointP384 {
324 self.0 += rhs.0;
325 self
326 }
327}
328
329#[macros::op_variants(owned)]
330impl AddAssign<&PointP384> for PointP384 {
331 #[inline]
332 fn add_assign(&mut self, rhs: &PointP384) {
333 self.0 += rhs.0;
334 }
335}
336
337#[macros::op_variants(owned)]
338impl Sub<&PointP384> for PointP384 {
339 type Output = PointP384;
340
341 #[inline]
342 fn sub(mut self, rhs: &PointP384) -> PointP384 {
343 self.0 -= rhs.0;
344 self
345 }
346}
347
348#[macros::op_variants(owned)]
349impl SubAssign<&PointP384> for PointP384 {
350 #[inline]
351 fn sub_assign(&mut self, rhs: &PointP384) {
352 self.0 -= rhs.0;
353 }
354}
355
356impl Neg for PointP384 {
357 type Output = PointP384;
358
359 #[inline]
360 fn neg(self) -> PointP384 {
361 Self(-self.0)
362 }
363}
364
365#[macros::op_variants(owned)]
366impl Mul<&ScalarP384> for PointP384 {
367 type Output = PointP384;
368
369 #[inline]
370 fn mul(self, rhs: &ScalarP384) -> PointP384 {
371 Self(self.0 * rhs.to_p384())
372 }
373}
374
375#[macros::op_variants(owned)]
376impl MulAssign<&ScalarP384> for PointP384 {
377 #[inline]
378 fn mul_assign(&mut self, rhs: &ScalarP384) {
379 self.0 *= rhs.to_p384();
380 }
381}
382
383impl Sum for PointP384 {
384 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
385 iter.fold(Self::identity(), |acc, x| acc + x)
386 }
387}
388
389impl<'a> Sum<&'a PointP384> for PointP384 {
390 fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
391 iter.fold(Self::identity(), |acc, x| acc + x)
392 }
393}
394
395impl Group for PointP384 {
396 type Scalar = ScalarP384;
397
398 fn random(rng: impl RngCore) -> Self {
399 Self(::p384::ProjectivePoint::random(rng))
400 }
401
402 fn identity() -> Self {
403 Self(::p384::ProjectivePoint::IDENTITY)
404 }
405
406 fn generator() -> Self {
407 Self(::p384::ProjectivePoint::GENERATOR)
408 }
409
410 fn is_identity(&self) -> Choice {
411 self.0.is_identity()
412 }
413
414 fn double(&self) -> Self {
415 Self(self.0.double())
416 }
417}
418
419impl MulByGenerator for PointP384 {}
420
421impl GroupEncoding for PointP384 {
422 type Repr = <::p384::ProjectivePoint as GroupEncoding>::Repr;
423
424 fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
425 ::p384::ProjectivePoint::from_bytes(bytes).map(Self)
426 }
427
428 fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
429 ::p384::ProjectivePoint::from_bytes_unchecked(bytes).map(Self)
430 }
431
432 fn to_bytes(&self) -> Self::Repr {
433 self.0.to_bytes()
434 }
435}
436
437unsafe impl InPlaceCodec for PointP384 {
442 const ENCODED_SIZE: usize = size_of::<<Self as GroupEncoding>::Repr>();
443
444 fn write_le_bytes(&self, out: &mut [MaybeUninit<u8>]) {
445 let bytes = self.to_bytes();
446 for (slot, &b) in out.iter_mut().zip(bytes.as_slice()) {
447 slot.write(b);
448 }
449 }
450
451 fn read_le_bytes(bytes: &[u8]) -> Result<Self, PrimitiveError> {
452 let mut repr = <Self as GroupEncoding>::Repr::default();
453 if bytes.len() != repr.len() {
454 return Err(PrimitiveError::InvalidSize(repr.len(), bytes.len()));
455 }
456 repr.as_mut_slice().copy_from_slice(bytes);
457 Option::from(Self::from_bytes(&repr)).ok_or_else(|| {
458 PrimitiveError::DeserializationFailed("invalid curve point encoding".into())
459 })
460 }
461}
462
463fn base_field_to_be_bytes(element: BaseFieldP384) -> ::p384::FieldBytes {
464 let mut bytes: [u8; 48] = element.to_le_bytes().into();
465 bytes.reverse();
466 bytes.into()
467}
468
469fn base_field_from_be_bytes(bytes: &[u8]) -> Option<BaseFieldP384> {
470 let mut bytes: [u8; 48] = bytes.try_into().ok()?;
471 bytes.reverse();
472 BaseFieldP384::from_le_bytes(&bytes)
473}
474
475impl ToCoordinates for PointP384 {
476 type BaseFieldElement = BaseFieldElement<P384>;
477 type NumCoordinates = U3;
478
479 fn to_coordinates(self) -> Result<Array<Self::BaseFieldElement, U3>, PointAtInfinityError> {
482 if self.0.is_identity().into() {
483 return Ok(Array(
484 [BaseFieldP384::ZERO, BaseFieldP384::ONE, BaseFieldP384::ZERO]
485 .map(SubfieldElement::new),
486 ));
487 }
488 let encoded = self.0.to_affine().to_encoded_point(false);
489 let x = base_field_from_be_bytes(encoded.x().unwrap()).unwrap();
490 let y = base_field_from_be_bytes(encoded.y().unwrap()).unwrap();
491 Ok(Array([x, y, BaseFieldP384::ONE].map(SubfieldElement::new)))
492 }
493}
494
495impl FromCoordinates for PointP384 {
496 type BaseFieldElement = BaseFieldElement<P384>;
497 type NumCoordinates = U3;
498
499 #[allow(non_snake_case)]
504 fn from_coordinates(coordinates: Array<Self::BaseFieldElement, U3>) -> Option<Self> {
505 let [X, Y, Z] = coordinates.0.map(|coordinate| coordinate.inner());
506 let Some(z_inv) = Option::<BaseFieldP384>::from(Z.invert()) else {
507 let is_identity = bool::from(X.is_zero()) && !bool::from(Y.is_zero());
508 return is_identity.then_some(Self(::p384::ProjectivePoint::IDENTITY));
509 };
510 let x = X * z_inv;
511 let y = Y * z_inv;
512 let encoded = ::p384::EncodedPoint::from_affine_coordinates(
513 &base_field_to_be_bytes(x),
514 &base_field_to_be_bytes(y),
515 false,
516 );
517 let affine =
518 Option::<::p384::AffinePoint>::from(::p384::AffinePoint::from_encoded_point(&encoded))?;
519 Some(Self(affine.into()))
520 }
521}
522
523#[cfg(test)]
524mod tests {
525 use super::*;
526 use crate::random::{test_rng, Random};
527
528 fn random_scalar(rng: impl crate::random::CryptoRngCore) -> ScalarP384 {
529 Random::random(rng)
530 }
531
532 #[test]
533 fn test_group_law_and_encoding_roundtrip() {
534 let mut rng = test_rng();
535 let point = PointP384::random(&mut rng);
536 assert_eq!(point + point, point.double());
537
538 let bytes = point.to_bytes();
539 let decoded = Option::<PointP384>::from(PointP384::from_bytes(&bytes)).unwrap();
540 assert_eq!(point, decoded);
541
542 let mut bad = bytes;
544 bad.as_mut_slice()[1..].fill(0xFF);
545 assert!(Option::<PointP384>::from(PointP384::from_bytes(&bad)).is_none());
546 }
547
548 #[test]
549 fn test_scalar_mul_matches_p384_crate() {
550 let mut rng = test_rng();
551 for _ in 0..10 {
552 let a = random_scalar(&mut rng);
553 let b = random_scalar(&mut rng);
554 assert_eq!((a * b).to_p384(), a.to_p384() * b.to_p384());
555 assert_eq!((a + b).to_p384(), a.to_p384() + b.to_p384());
556 }
557
558 let scalar = random_scalar(&mut rng);
559 let expected = ::p384::ProjectivePoint::GENERATOR * scalar.to_p384();
560 assert_eq!(PointP384::generator() * scalar, PointP384(expected));
561 }
562
563 #[test]
564 fn test_coordinates_roundtrip() {
565 let mut rng = test_rng();
566 let point = PointP384::random(&mut rng);
567 let coordinates = point.to_coordinates().unwrap();
568 assert_eq!(coordinates[2], SubfieldElement::new(BaseFieldP384::ONE));
569 assert_eq!(PointP384::from_coordinates(coordinates).unwrap(), point);
570
571 let lambda = SubfieldElement::new(BaseFieldP384::from(7u128));
573 let scaled = Array([
574 coordinates[0] * lambda,
575 coordinates[1] * lambda,
576 coordinates[2] * lambda,
577 ]);
578 assert_eq!(PointP384::from_coordinates(scaled).unwrap(), point);
579
580 let identity_coordinates = PointP384::identity().to_coordinates().unwrap();
582 assert_eq!(
583 PointP384::from_coordinates(identity_coordinates).unwrap(),
584 PointP384::identity()
585 );
586
587 let mut bad_infinity = coordinates;
589 bad_infinity[2] = SubfieldElement::new(BaseFieldP384::ZERO);
590 assert!(PointP384::from_coordinates(bad_infinity).is_none());
591
592 let mut off_curve = coordinates;
594 off_curve[1] += SubfieldElement::new(BaseFieldP384::ONE);
595 assert!(PointP384::from_coordinates(off_curve).is_none());
596 }
597
598 #[test]
599 fn test_hash_to_curve() {
600 let point1 = P384::hash_to_curve(b"async-mpc test input");
601 let point2 = P384::hash_to_curve(b"async-mpc test input");
602 let point3 = P384::hash_to_curve(b"different input");
603 assert_eq!(point1, point2);
604 assert_ne!(point1, point3);
605 assert!(!bool::from(point1.is_identity()));
606 }
607
608 #[test]
609 fn test_inplace_roundtrip() {
610 let mut rng = test_rng();
611 let point = PointP384::random(&mut rng);
612 let serialized = point.to_inplace_bytes();
613 assert_eq!(PointP384::from_inplace_bytes(&serialized).unwrap(), point);
614 }
615}