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

p384: use canonical form constants #592

Merged
merged 1 commit into from Jun 3, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 6 additions & 7 deletions p384/src/arithmetic.rs
Expand Up @@ -19,15 +19,14 @@ use self::{
projective::ProjectivePoint,
scalar::Scalar,
};
use crate::U384;

/// a = -3 (0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc)
///
/// NOTE: field element has been translated into the Montgomery domain.
const CURVE_EQUATION_A: FieldElement = FieldElement(U384::from_be_hex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffc0000000000000003fffffffc"));
const CURVE_EQUATION_A: FieldElement = FieldElement::ZERO
.sub(&FieldElement::ONE)
.sub(&FieldElement::ONE)
.sub(&FieldElement::ONE);

/// b = b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112
/// 0314088f 5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef
///
/// NOTE: field element has been translated into the Montgomery domain.
const CURVE_EQUATION_B: FieldElement = FieldElement(U384::from_be_hex("cd08114b604fbff9b62b21f41f022094e3374bee94938ae277f2209b1920022ef729add87a4c32ec081188719d412dcc"));
const CURVE_EQUATION_B: FieldElement =
FieldElement::from_be_hex("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef");
6 changes: 3 additions & 3 deletions p384/src/arithmetic/affine.rs
Expand Up @@ -5,7 +5,7 @@
use core::ops::{Mul, Neg};

use super::{FieldElement, ProjectivePoint, CURVE_EQUATION_A, CURVE_EQUATION_B, MODULUS};
use crate::{CompressedPoint, EncodedPoint, FieldBytes, NistP384, PublicKey, Scalar, U384};
use crate::{CompressedPoint, EncodedPoint, FieldBytes, NistP384, PublicKey, Scalar};
use elliptic_curve::{
group::{prime::PrimeCurveAffine, GroupEncoding},
sec1::{self, FromEncodedPoint, ToEncodedPoint},
Expand Down Expand Up @@ -66,8 +66,8 @@ impl AffinePoint {
/// NOTE: coordinate field elements have been translated into the Montgomery
/// domain.
pub const GENERATOR: Self = Self {
x: FieldElement(U384::from_be_hex("4d3aadc2299e1513812ff723614ede2b6454868459a30eff879c3afc541b4d6e20e378e2a0d6ce383dd0756649c0b528")),
y: FieldElement(U384::from_be_hex("2b78abc25a15c5e9dd8002263969a840c6c3521968f4ffd98bade7562e83b050a1bfa8bf7bb4a9ac23043dad4b03a4fe")),
x: FieldElement::from_be_hex("aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7"),
y: FieldElement::from_be_hex("3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f"),
infinity: 0,
};

Expand Down
16 changes: 4 additions & 12 deletions p384/src/arithmetic/field.rs
Expand Up @@ -40,10 +40,11 @@ pub(crate) const MODULUS: U384 = U384::from_be_hex("ffffffffffffffffffffffffffff
#[derive(Clone, Copy, Debug)]
pub struct FieldElement(pub(super) U384);

impl_sec1_field_element!(
impl_field_element!(
FieldElement,
U384,
FieldBytes,
U384,
MODULUS,
fiat_p384_montgomery_domain_field_element,
fiat_p384_from_montgomery,
fiat_p384_to_montgomery,
Expand All @@ -55,8 +56,6 @@ impl_sec1_field_element!(
fiat_p384_divstep_precomp,
fiat_p384_divstep,
fiat_p384_msat,
MODULUS,
"000000000000000000000000000000000000000000000000000000000000000100000000ffffffffffffffff00000001"
);

impl FieldElement {
Expand Down Expand Up @@ -111,14 +110,7 @@ impl FieldElement {

#[cfg(test)]
mod tests {
use super::{fiat_p384_to_montgomery, FieldElement, U384};

/// Test that the precomputed `FieldElement::ONE` constant is correct.
#[test]
fn one() {
let one_mont = fiat_p384_to_montgomery(U384::ONE.as_ref());
assert_eq!(FieldElement(one_mont.into()), FieldElement::ONE);
}
use super::FieldElement;

/// Basic tests that field inversion works.
#[test]
Expand Down
48 changes: 33 additions & 15 deletions p384/src/arithmetic/macros.rs
Expand Up @@ -45,11 +45,12 @@
/// - `Mul`
/// - `MulAssign`
/// - `Neg`
macro_rules! impl_sec1_field_element {
macro_rules! impl_field_element {
(
$fe:tt,
$uint:ty,
$bytes:ty,
$uint:ty,
$modulus:expr,
$arr:ty,
$from_mont:ident,
$to_mont:ident,
Expand All @@ -61,15 +62,13 @@ macro_rules! impl_sec1_field_element {
$divstep_precomp:ident,
$divstep:ident,
$msat:ident,
$mod:expr,
$one:expr
) => {
impl $fe {
/// Zero element.
pub const ZERO: Self = Self(<$uint>::ZERO);

/// Multiplicative identity.
pub const ONE: Self = Self(<$uint>::from_be_hex($one));
pub const ONE: Self = Self::from_uint_unchecked(<$uint>::ONE);

/// Create a [`
#[doc = stringify!($fe)]
Expand Down Expand Up @@ -116,17 +115,41 @@ macro_rules! impl_sec1_field_element {
/// w * R^2 * R^-1 mod p = wR mod p
/// ```
pub fn from_uint(uint: $uint) -> ::elliptic_curve::subtle::CtOption<Self> {
let is_some = uint.ct_lt(&$mod);
let is_some = uint.ct_lt(&$modulus);
::elliptic_curve::subtle::CtOption::new(Self::from_uint_unchecked(uint), is_some)
}

/// Parse a [`
#[doc = stringify!($fe)]
/// `] from big endian hex-encoded bytes.
///
/// Does *not* perform a check that the field element does not overflow the order.
///
/// This method is primarily intended for defining internal constants.
#[allow(dead_code)]
pub(crate) const fn from_be_hex(hex: &str) -> Self {
Self::from_uint_unchecked(<$uint>::from_be_hex(hex))
}

/// Parse a [`
#[doc = stringify!($fe)]
/// `] from little endian hex-encoded bytes.
///
/// Does *not* perform a check that the field element does not overflow the order.
///
/// This method is primarily intended for defining internal constants.
#[allow(dead_code)]
pub(crate) const fn from_le_hex(hex: &str) -> Self {
Self::from_uint_unchecked(<$uint>::from_le_hex(hex))
}

/// Decode [`
#[doc = stringify!($fe)]
/// `] from [`
#[doc = stringify!($uint)]
/// `] converting it into Montgomery form.
///
/// Does not perform a check that the field element does not overflow the order.
/// Does *not* perform a check that the field element does not overflow the order.
///
/// Used incorrectly this can lead to invalid results!
const fn from_uint_unchecked(w: $uint) -> Self {
Expand Down Expand Up @@ -225,18 +248,13 @@ macro_rules! impl_sec1_field_element {

const LIMBS: usize = ::elliptic_curve::bigint::nlimbs!(<$uint>::BIT_SIZE);
const ITERATIONS: usize = (49 * <$uint>::BIT_SIZE + 57) / 17;
type XLimbs = [Word; LIMBS + 1];

let mut d: Word = 1;
let mut d = 1;
let mut f = $msat();

let mut g = XLimbs::default();
let mut g: [Word; LIMBS + 1] = Default::default();
g[..LIMBS].copy_from_slice(&$from_mont(self.as_ref()));

let mut r = <$arr>::from(Self::ONE.0);
let mut v = <$arr>::default();
let precomp = $divstep_precomp();

let mut i: usize = 0;

while i < ITERATIONS - ITERATIONS % 2 {
Expand Down Expand Up @@ -264,7 +282,7 @@ macro_rules! impl_sec1_field_element {
);

let v = <$uint>::conditional_select(&v, &v_opp, s);
let ret = $mul(v.as_ref(), &precomp);
let ret = $mul(v.as_ref(), &$divstep_precomp());
::elliptic_curve::subtle::CtOption::new(Self(ret.into()), !self.is_zero())
}

Expand Down
30 changes: 9 additions & 21 deletions p384/src/arithmetic/scalar.rs
Expand Up @@ -17,7 +17,6 @@ use core::ops::{AddAssign, MulAssign, Neg, SubAssign};
use elliptic_curve::{
bigint::{ArrayEncoding, Encoding, Integer, Limb},
ff::PrimeField,
generic_array::arr,
ops::Reduce,
subtle::{
Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess,
Expand All @@ -38,10 +37,11 @@ impl ScalarArithmetic for NistP384 {
#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
pub struct Scalar(U384);

impl_sec1_field_element!(
impl_field_element!(
Scalar,
U384,
FieldBytes,
U384,
NistP384::ORDER,
fiat_p384_scalar_montgomery_domain_field_element,
fiat_p384_scalar_from_montgomery,
fiat_p384_scalar_to_montgomery,
Expand All @@ -53,11 +53,12 @@ impl_sec1_field_element!(
fiat_p384_scalar_divstep_precomp,
fiat_p384_scalar_divstep,
fiat_p384_scalar_msat,
NistP384::ORDER,
"000000000000000000000000000000000000000000000000389cb27e0bc8d220a7e5f24db74f58851313e695333ad68d"
);

impl Scalar {
/// `2^s` root of unity.
pub const ROOT_OF_UNITY: Self = Self::from_be_hex("ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52972");

/// Compute modular square root.
pub fn sqrt(&self) -> CtOption<Self> {
// p mod 4 = 3 -> compute sqrt(x) using x^((p+1)/4) =
Expand Down Expand Up @@ -139,21 +140,15 @@ impl PrimeField for Scalar {
}

fn is_odd(&self) -> Choice {
self.to_canonical().is_odd()
self.is_odd()
}

fn multiplicative_generator() -> Self {
2u64.into()
}

fn root_of_unity() -> Self {
Scalar::from_repr(arr![u8;
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37, 0x2d, 0xdf, 0x58, 0x1a, 0x0d, 0xb2,
0x48, 0xb0, 0xa7, 0x7a, 0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5, 0x29, 0x72
])
.unwrap()
Self::ROOT_OF_UNITY
}
}

Expand Down Expand Up @@ -249,17 +244,10 @@ impl TryFrom<U384> for Scalar {

#[cfg(test)]
mod tests {
use super::{fiat_p384_scalar_to_montgomery, Scalar, U384};
use super::Scalar;
use crate::FieldBytes;
use elliptic_curve::ff::{Field, PrimeField};

/// Test that the precomputed `Scalar::ONE` constant is correct.
#[test]
fn one() {
let one_mont = fiat_p384_scalar_to_montgomery(U384::ONE.as_ref());
assert_eq!(Scalar(one_mont.into()), Scalar::ONE);
}

#[test]
fn from_to_bytes_roundtrip() {
let k: u64 = 42;
Expand Down