Skip to content

Commit

Permalink
p521: CurveArithmetic + PrimeCurveParams (#764)
Browse files Browse the repository at this point in the history
Adds impls of the `CurveArithmetic` and `PrimeCurveArithmetic` traits,
the latter of which defines the coefficients of the curve equation as
well as the coordinates of the generator point.

Constants have been sourced from NIST SP 800-186 § 3.2.1.5: P-521.
  • Loading branch information
tarcieri authored Feb 13, 2023
1 parent 2fde7a0 commit 267e3c3
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 68 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 0 additions & 3 deletions p224/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@ use elliptic_curve::{
FieldBytesEncoding,
};

#[cfg(feature = "wip-arithmetic-do-not-use")]
pub use arithmetic::{scalar::Scalar, AffinePoint, ProjectivePoint};

#[cfg(target_pointer_width = "32")]
pub use elliptic_curve::bigint::U224 as Uint;

Expand Down
5 changes: 4 additions & 1 deletion p521/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ rust-version = "1.61"
[dependencies]
elliptic-curve = { version = "=0.13.0-pre.5", default-features = false, features = ["hazmat", "sec1"] }

# optional dependencies
primeorder = { version = "=0.13.0-pre", optional = true, path = "../primeorder" }

[features]
default = ["pem", "std"]
alloc = ["elliptic-curve/alloc"]
Expand All @@ -26,4 +29,4 @@ std = ["alloc", "elliptic-curve/std"]
jwk = ["elliptic-curve/jwk"]
pem = ["elliptic-curve/pem", "pkcs8"]
pkcs8 = ["elliptic-curve/pkcs8"]
wip-arithmetic-do-not-use = []
wip-arithmetic-do-not-use = ["primeorder"]
81 changes: 54 additions & 27 deletions p521/src/arithmetic.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,66 @@
//! Pure Rust implementation of group operations on secp224r1.
//! Pure Rust implementation of group operations on secp521r1.
//!
//! Curve parameters can be found in [NIST SP 800-186] § G.1.1: Curve P-384.
//! Curve parameters can be found in [NIST SP 800-186] § 3.2.1.5: P-521.
//!
//! [NIST SP 800-186]: https://csrc.nist.gov/publications/detail/sp/800-186/final
pub mod field;
pub mod scalar;
pub(crate) mod field;
pub(crate) mod scalar;
mod util;

/// Convert an 18-element array of `u32` into a 9-element array of `u16`,
/// assuming integer arrays are in little-endian order.
#[cfg(target_pointer_width = "32")]
const fn u32x18_to_u64x9(w: &[u32; 18]) -> [u64; 9] {
let mut ret = [0u64; 9];
let mut i = 0;
pub use self::scalar::Scalar;

while i < 9 {
ret[i] = (w[i * 2] as u64) | ((w[(i * 2) + 1] as u64) << 32);
i += 1;
}
use self::field::FieldElement;
use crate::NistP521;
use elliptic_curve::{CurveArithmetic, PrimeCurveArithmetic};
use primeorder::{point_arithmetic, PrimeCurveParams};

ret
/// Elliptic curve point in affine coordinates.
pub type AffinePoint = primeorder::AffinePoint<NistP521>;

/// Elliptic curve point in projective coordinates.
pub type ProjectivePoint = primeorder::ProjectivePoint<NistP521>;

impl CurveArithmetic for NistP521 {
type AffinePoint = AffinePoint;
type ProjectivePoint = ProjectivePoint;
type Scalar = Scalar;
}

/// Convert a 9-element array of `u64` into an 18-element array of `u32`,
/// assuming integers are in little-endian order.
#[cfg(target_pointer_width = "32")]
const fn u64x9_to_u32x18(w: &[u64; 9]) -> [u32; 18] {
let mut ret = [0u32; 18];
let mut i = 0;
impl PrimeCurveArithmetic for NistP521 {
type CurveGroup = ProjectivePoint;
}

/// Adapted from [NIST SP 800-186] § 3.2.1.5: P-521.
///
/// [NIST SP 800-186]: https://csrc.nist.gov/publications/detail/sp/800-186/final
impl PrimeCurveParams for NistP521 {
type FieldElement = FieldElement;
type PointArithmetic = point_arithmetic::EquationAIsMinusThree;

/// a = -3 (0x1ff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
/// ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
/// ffffffff ffffffff ffffffff fffffffc)
const EQUATION_A: FieldElement = FieldElement::from_u64(3).neg();

while i < 9 {
ret[i * 2] = (w[i] & 0xFFFFFFFF) as u32;
ret[(i * 2) + 1] = (w[i] >> 32) as u32;
i += 1;
}
/// b = 0x051 953eb961 8e1c9a1f 929a21a0 b68540ee a2da725b 99b315f3
/// b8b48991 8ef109e1 56193951 ec7e937b 1652c0bd 3bb1bf07
/// 3573df88 3d2c34f1 ef451fd4 6b503f00
const EQUATION_B: FieldElement =
FieldElement::from_hex("0000000000000051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00");

ret
/// Base point of P-521.
///
/// ```text
/// Gₓ = 0x0c6 858e06b7 0404e9cd 9e3ecb66 2395b442 9c648139 053fb521
/// f828af60 6b4d3dba a14b5e77 efe75928 fe1dc127 a2ffa8de
/// 3348b3c1 856a429b f97e7e31 c2e5bd66
/// Gᵧ = 0x118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9 98f54449 579b4468
/// 17afbd17 273e662c 97ee7299 5ef42640 c550b901 3fad0761
/// 353c7086 a272c240 88be9476 9fd16650
/// ```
const GENERATOR: (FieldElement, FieldElement) = (
FieldElement::from_hex("00000000000000c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66"),
FieldElement::from_hex("000000000000011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650"),
);
}
2 changes: 1 addition & 1 deletion p521/src/arithmetic/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ use elliptic_curve::{
};

#[cfg(target_pointer_width = "32")]
use super::u32x18_to_u64x9;
use super::util::u32x18_to_u64x9;

/// Constant representing the modulus serialized as hex.
/// p = 2^{521} − 1
Expand Down
38 changes: 2 additions & 36 deletions p521/src/arithmetic/scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use elliptic_curve::{
zeroize::DefaultIsZeroes,
Curve as _, Error, FieldBytesEncoding, Result, ScalarPrimitive,
};
use primeorder::impl_field_op;

#[cfg(feature = "bits")]
use {crate::ScalarBits, elliptic_curve::group::ff::PrimeFieldBits};
Expand All @@ -35,7 +36,7 @@ use serdect::serde::{de, ser, Deserialize, Serialize};
use core::ops::{Add, Mul, Sub};

#[cfg(target_pointer_width = "32")]
use super::{u32x18_to_u64x9, u64x9_to_u32x18};
use super::util::{u32x18_to_u64x9, u64x9_to_u32x18};

/// Scalars are elements in the finite field modulo `n`.
///
Expand Down Expand Up @@ -371,41 +372,6 @@ impl Field for Scalar {
}
}

/// Emit impls for a `core::ops` trait for all combinations of reference types,
/// which thunk to the given function.
// TODO(tarcieri): import this macro from `primeorder` when it's a dependency
#[macro_export]
macro_rules! impl_field_op {
($fe:tt, $op:tt, $op_fn:ident, $func:ident) => {
impl ::core::ops::$op for $fe {
type Output = $fe;

#[inline]
fn $op_fn(self, rhs: $fe) -> $fe {
$fe($func(self.as_ref(), rhs.as_ref()).into())
}
}

impl ::core::ops::$op<&$fe> for $fe {
type Output = $fe;

#[inline]
fn $op_fn(self, rhs: &$fe) -> $fe {
$fe($func(self.as_ref(), rhs.as_ref()).into())
}
}

impl ::core::ops::$op<&$fe> for &$fe {
type Output = $fe;

#[inline]
fn $op_fn(self, rhs: &$fe) -> $fe {
$fe($func(self.as_ref(), rhs.as_ref()).into())
}
}
};
}

impl_field_op!(Scalar, Add, add, fiat_p521_scalar_add);
impl_field_op!(Scalar, Sub, sub, fiat_p521_scalar_sub);
impl_field_op!(Scalar, Mul, mul, fiat_p521_scalar_mul);
Expand Down
32 changes: 32 additions & 0 deletions p521/src/arithmetic/util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//! Utility functions.
/// Convert an 18-element array of `u32` into a 9-element array of `u16`,
/// assuming integer arrays are in little-endian order.
#[cfg(target_pointer_width = "32")]
pub(crate) const fn u32x18_to_u64x9(w: &[u32; 18]) -> [u64; 9] {
let mut ret = [0u64; 9];
let mut i = 0;

while i < 9 {
ret[i] = (w[i * 2] as u64) | ((w[(i * 2) + 1] as u64) << 32);
i += 1;
}

ret
}

/// Convert a 9-element array of `u64` into an 18-element array of `u32`,
/// assuming integers are in little-endian order.
#[cfg(target_pointer_width = "32")]
pub(crate) const fn u64x9_to_u32x18(w: &[u64; 9]) -> [u32; 18] {
let mut ret = [0u32; 18];
let mut i = 0;

while i < 9 {
ret[i * 2] = (w[i] & 0xFFFFFFFF) as u32;
ret[(i * 2) + 1] = (w[i] >> 32) as u32;
i += 1;
}

ret
}

0 comments on commit 267e3c3

Please sign in to comment.