Skip to content

Commit

Permalink
p384: add FieldElement::{to_canonical, to_montgomery} (#492)
Browse files Browse the repository at this point in the history
Adds wrappers for fiat-crypto's `fiat_p384_from_montgomery` and
`fiat_p384_to_montgomery`, using them to translate field elements into
and out of the Montgomery domain when decoding or encoding them from big
endian-serialized canonical form.

Also ensures field element constants are already in Montgomery form.
  • Loading branch information
tarcieri authored Dec 19, 2021
1 parent c77e0c4 commit 09ae780
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 26 deletions.
6 changes: 3 additions & 3 deletions p256/src/arithmetic/affine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,13 +184,13 @@ impl DecompactPoint<NistP256> for AffinePoint {
let montgomery_y = (x * &x * &x + &(CURVE_EQUATION_A * &x) + &CURVE_EQUATION_B).sqrt();
montgomery_y.map(|montgomery_y| {
// Convert to canonical form for comparisons
let y = montgomery_y.as_canonical();
let y = montgomery_y.to_canonical();
let p_y = MODULUS.subtract(&y);
let (_, borrow) = p_y.informed_subtract(&y);
let recovered_y = if borrow == 0 { y } else { p_y };
AffinePoint {
x,
y: recovered_y.as_montgomery(),
y: recovered_y.to_montgomery(),
infinity: Choice::from(0),
}
})
Expand Down Expand Up @@ -251,7 +251,7 @@ impl ToCompactEncodedPoint<NistP256> for AffinePoint {
/// Serialize this value as a SEC1 compact [`EncodedPoint`]
fn to_compact_encoded_point(&self) -> Option<EncodedPoint> {
// Convert to canonical form for comparisons
let y = self.y.as_canonical();
let y = self.y.to_canonical();
let (p_y, borrow) = MODULUS.informed_subtract(&y);
assert_eq!(borrow, 0);
let (_, borrow) = p_y.informed_subtract(&y);
Expand Down
15 changes: 9 additions & 6 deletions p256/src/arithmetic/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,13 @@ impl FieldElement {
let is_some = (borrow as u8) & 1;

// Convert w to Montgomery form: w * R^2 * R^-1 mod p = wR mod p
CtOption::new(FieldElement(w).as_montgomery(), Choice::from(is_some))
CtOption::new(FieldElement(w).to_montgomery(), Choice::from(is_some))
}

/// Returns the SEC1 encoding of this field element.
pub fn to_bytes(self) -> FieldBytes {
// Convert from Montgomery form to canonical form
let tmp =
FieldElement::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0);
let tmp = self.to_canonical();

let mut ret = FieldBytes::default();
ret[0..8].copy_from_slice(&tmp.0[3].to_be_bytes());
Expand Down Expand Up @@ -333,12 +332,16 @@ impl FieldElement {
result
}

pub(crate) const fn as_canonical(&self) -> Self {
/// Translate a field element out of the Montgomery domain.
#[inline]
pub(crate) const fn to_canonical(self) -> Self {
FieldElement::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0)
}

pub(crate) const fn as_montgomery(&self) -> Self {
self.mul(&R2)
/// Translate a field element into the Montgomery domain.
#[inline]
pub(crate) const fn to_montgomery(self) -> Self {
Self::mul(&self, &R2)
}

/// Returns self * rhs mod p
Expand Down
14 changes: 8 additions & 6 deletions p384/src/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ const CURVE_EQUATION_A: FieldElement = FieldElement([

/// 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([
0x2a85c8ed_d3ec2aef,
0xc656398d_8a2ed19d,
0x0314088f_5013875a,
0x181d9c6e_fe814112,
0x988e056b_e3f82d19,
0xb3312fa7_e23ee7e4,
0x81188719_d412dcc,
0xf729add8_7a4c32ec,
0x77f2209b_1920022e,
0xe3374bee_94938ae2,
0xb62b21f4_1f022094,
0xcd08114b_604fbff9,
]);
41 changes: 30 additions & 11 deletions p384/src/arithmetic/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ mod field_impl;
pub(super) use self::field_impl::fiat_p384_montgomery_domain_field_element as FieldElementImpl;

use self::field_impl::{
fiat_p384_add, fiat_p384_mul, fiat_p384_opp, fiat_p384_square, fiat_p384_sub,
fiat_p384_add, fiat_p384_from_montgomery, fiat_p384_mul, fiat_p384_opp, fiat_p384_square,
fiat_p384_sub, fiat_p384_to_montgomery,
};
use crate::FieldBytes;
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
Expand All @@ -47,6 +48,7 @@ const LIMBS: usize = 6;

/// Constant representing the modulus
/// p = 2^{384} − 2^{128} − 2^{96} + 2^{32} − 1
// TODO(tarcieri): convert to Montgomery form?
pub(crate) const MODULUS: FieldElement = FieldElement([
0x00000000ffffffff,
0xffffffff00000000,
Expand Down Expand Up @@ -99,21 +101,22 @@ impl FieldElement {
let (_, borrow) = sbb(w[5], MODULUS.0[5], borrow);
let is_some = (borrow as u8) & 1;

// TODO(tarcieri): Convert w to Montgomery form: w * R^2 * R^-1 mod p = wR mod p
//CtOption::new(FieldElement(w).as_montgomery(), Choice::from(is_some))
CtOption::new(FieldElement(w), Choice::from(is_some))
// Convert w to Montgomery form: w * R^2 * R^-1 mod p = wR mod p
CtOption::new(FieldElement(w).to_montgomery(), Choice::from(is_some))
}

/// Returns the SEC1 encoding of this field element.
pub fn to_bytes(self) -> FieldBytes {
// TODO(tarcieri): convert from Montgomery form to canonical form
// Convert from Montgomery form to canonical form
let tmp = self.to_canonical();

let mut ret = FieldBytes::default();
ret[0..8].copy_from_slice(&self.0[5].to_be_bytes());
ret[8..16].copy_from_slice(&self.0[4].to_be_bytes());
ret[16..24].copy_from_slice(&self.0[3].to_be_bytes());
ret[24..32].copy_from_slice(&self.0[2].to_be_bytes());
ret[32..40].copy_from_slice(&self.0[1].to_be_bytes());
ret[40..48].copy_from_slice(&self.0[0].to_be_bytes());
ret[0..8].copy_from_slice(&tmp.0[5].to_be_bytes());
ret[8..16].copy_from_slice(&tmp.0[4].to_be_bytes());
ret[16..24].copy_from_slice(&tmp.0[3].to_be_bytes());
ret[24..32].copy_from_slice(&tmp.0[2].to_be_bytes());
ret[32..40].copy_from_slice(&tmp.0[1].to_be_bytes());
ret[40..48].copy_from_slice(&tmp.0[0].to_be_bytes());
ret
}

Expand Down Expand Up @@ -187,6 +190,22 @@ impl FieldElement {
pub fn sqrt(&self) -> CtOption<Self> {
todo!()
}

/// Translate a field element out of the Montgomery domain.
#[inline]
fn to_canonical(self) -> Self {
let mut out = Self::ZERO;
fiat_p384_from_montgomery(&mut out.0, &self.0);
out
}

/// Translate a field element into the Montgomery domain.
#[inline]
fn to_montgomery(self) -> Self {
let mut out = Self::ZERO;
fiat_p384_to_montgomery(&mut out.0, &self.0);
out
}
}

impl PartialEq for FieldElement {
Expand Down

0 comments on commit 09ae780

Please sign in to comment.