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