Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

p521: CurveArithmetic + PrimeCurveParams #764

Merged
merged 1 commit into from
Feb 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}