Skip to content

Commit

Permalink
p384: initial 32-bit support
Browse files Browse the repository at this point in the history
Imports the 32-bit fiat-crypto scalar field implementation generated by
@jedisct1 from this PR:

mit-plv/fiat-crypto#1259

Gates all field backends and precomputed constants on
`target_pointer_width`, substituting 12-limb 32-bit versions for 32-bit
targets where necessary.

Inversions are implemented using 64-bit arithmetic, so for now they are
marked as `todo!()`.
  • Loading branch information
tarcieri committed May 27, 2022
1 parent 1f35666 commit e8c2a7d
Show file tree
Hide file tree
Showing 7 changed files with 11,617 additions and 61 deletions.
5 changes: 2 additions & 3 deletions .github/workflows/p384.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ env:
RUSTFLAGS: "-Dwarnings"

jobs:
# TODO(tarcieri): test arithmetic on 32-bit platforms
build:
runs-on: ubuntu-latest
strategy:
Expand All @@ -37,8 +36,7 @@ jobs:
override: true
profile: minimal
- run: cargo build --target ${{ matrix.target }} --release --no-default-features
# TODO(tarcieri): currently 64-bit only
# - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features arithmetic
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features arithmetic
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features ecdsa-core
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features jwk
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features pem
Expand All @@ -48,6 +46,7 @@ jobs:
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features voprf
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features ecdsa-core,jwk,pem,pkcs8,serde,sha384,voprf

# TODO(tarcieri): test arithmetic on 32-bit platforms
test:
runs-on: ubuntu-latest
strategy:
Expand Down
41 changes: 34 additions & 7 deletions p384/src/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,50 @@ use field::{FieldElement, MODULUS};
use projective::ProjectivePoint;
use scalar::Scalar;

/// Number of limbs used to represent a field element.
#[cfg(target_pointer_width = "32")]
const LIMBS: usize = 12;
/// Number of limbs used to represent a field element.
#[cfg(target_pointer_width = "64")]
const LIMBS: usize = 6;

/// a = -3 (0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc)
/// NOTE: field element has been translated into the Montgomery domain.
#[cfg(target_pointer_width = "32")]
const CURVE_EQUATION_A: FieldElement = FieldElement([
17179869180,
18446744056529682432,
18446744073709551611,
18446744073709551615,
18446744073709551615,
18446744073709551615,
0xfffffffc, 0x00000003, 0x00000000, 0xfffffffc, 0xfffffffb, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
]);

/// a = -3 (0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc)
/// NOTE: field element has been translated into the Montgomery domain.
#[cfg(target_pointer_width = "64")]
const CURVE_EQUATION_A: FieldElement = FieldElement([
0x00000003_fffffffc,
0xfffffffc_00000000,
0xffffffff_fffffffb,
0xffffffff_ffffffff,
0xffffffff_ffffffff,
0xffffffff_ffffffff,
]);

/// b = b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112
/// 0314088f 5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef
///
/// NOTE: field element has been translated into the Montgomery domain.
#[cfg(target_pointer_width = "32")]
const CURVE_EQUATION_B: FieldElement = FieldElement([
0x9d412dcc, 0x08118871, 0x7a4c32ec, 0xf729add8, 0x1920022e, 0x77f2209b, 0x94938ae2, 0xe3374bee,
0x1f022094, 0xb62b21f4, 0x604fbff9, 0xcd08114b,
]);

/// b = b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112
/// 0314088f 5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef
///
/// NOTE: field element has been translated into the Montgomery domain.
#[cfg(target_pointer_width = "64")]
const CURVE_EQUATION_B: FieldElement = FieldElement([
0x81188719_d412dcc,
0x08118871_9d412dcc,
0xf729add8_7a4c32ec,
0x77f2209b_1920022e,
0xe3374bee_94938ae2,
Expand Down
49 changes: 37 additions & 12 deletions p384/src/arithmetic/affine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,25 +63,50 @@ impl AffinePoint {
/// Gᵧ = 3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c
/// e9da3113 b5f0b8c0 0a60b1ce 1d7e819d 7a431d7c 90ea0e5f
/// ```
#[cfg(target_pointer_width = "32")]
pub const GENERATOR: Self = Self {
x: FieldElement([
4454189113653900584,
2369870743683386936,
9771750146904378734,
7229551204834152191,
9308930686126579243,
5564951339003155731,
0x49c0b528, 0x3dd07566, 0xa0d6ce38, 0x20e378e2, 0x541b4d6e, 0x879c3afc, 0x59a30eff,
0x64548684, 0x614ede2b, 0x812ff723, 0x299e1513, 0x4d3aadc2,
]),
y: FieldElement([
2523209505731486974,
11655219901025790380,
10064955099576512592,
14322381509056856025,
15960759442596276288,
3132442392059561449,
0x4b03a4fe, 0x23043dad, 0x7bb4a9ac, 0xa1bfa8bf, 0x2e83b050, 0x8bade756, 0x68f4ffd9,
0xc6c35219, 0x3969a840, 0x3969a840, 0x5a15c5e9, 0x2b78abc2,
]),
infinity: 0,
};

/// Base point of P-384.
///
/// Defined in FIPS 186-4 § D.1.2.4:
///
/// ```text
/// Gₓ = aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98
/// 59f741e0 82542a38 5502f25d bf55296c 3a545e38 72760ab7
/// Gᵧ = 3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c
/// e9da3113 b5f0b8c0 0a60b1ce 1d7e819d 7a431d7c 90ea0e5f
/// ```
#[cfg(target_pointer_width = "64")]
pub const GENERATOR: Self = Self {
x: FieldElement([
0x3dd07566_49c0b528,
0x20e378e2_a0d6ce38,
0x879c3afc_541b4d6e,
0x64548684_59a30eff,
0x812ff723_614ede2b,
0x4d3aadc2_299e1513,
]),
y: FieldElement([
0x23043dad_4b03a4fe,
0xa1bfa8bf_7bb4a9ac,
0x8bade756_2e83b050,
0xc6c35219_68f4ffd9,
0xdd800226_3969a840,
0x2b78abc2_5a15c5e9,
]),
infinity: 0,
};

/// Additive identity of the group: the point at infinity.
pub const IDENTITY: Self = Self {
x: FieldElement::ZERO,
Expand Down
137 changes: 117 additions & 20 deletions p384/src/arithmetic/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,35 +26,41 @@
#[rustfmt::skip]
mod field_impl;

use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
pub(super) use self::field_impl::fiat_p384_montgomery_domain_field_element as FieldElementImpl;

use self::field_impl::*;
use super::LIMBS;
use crate::FieldBytes;
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use elliptic_curve::{
subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption},
zeroize::DefaultIsZeroes,
};

pub(super) use self::field_impl::fiat_p384_montgomery_domain_field_element as FieldElementImpl;
use self::field_impl::*;
use crate::FieldBytes;

/// Type used to represent a limb.
// TODO(tarcieri): hardcoded for 64-bit; add 32-bit support
#[cfg(target_pointer_width = "32")]
type Limb = u32;
/// Type used to represent a limb.
#[cfg(target_pointer_width = "64")]
type Limb = u64;

/// Number of limbs used to represent a field element.
// TODO(tarcieri): hardcoded for 64-bit; add 32-bit support
const LIMBS: usize = 6;

/// Constant representing the modulus
/// p = 2^{384} − 2^{128} − 2^{96} + 2^{32} − 1
// TODO(tarcieri): convert to Montgomery form?
#[cfg(target_pointer_width = "32")]
pub(crate) const MODULUS: FieldElement = FieldElement([
0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
]);
/// Constant representing the modulus
/// p = 2^{384} − 2^{128} − 2^{96} + 2^{32} − 1
#[cfg(target_pointer_width = "64")]
pub(crate) const MODULUS: FieldElement = FieldElement([
0x00000000ffffffff,
0xffffffff00000000,
0xfffffffffffffffe,
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
0x00000000_ffffffff,
0xffffffff_00000000,
0xffffffff_fffffffe,
0xffffffff_ffffffff,
0xffffffff_ffffffff,
0xffffffff_ffffffff,
]);

/// An element in the finite field used for curve coordinates.
Expand All @@ -70,6 +76,7 @@ impl FieldElement {
/// Multiplicative identity.
#[cfg(target_pointer_width = "64")]
pub const ONE: Self = Self([0xffffffff00000001, 0xffffffff, 0x1, 0x0, 0x0, 0x0]);

/// Zero element.
pub const ZERO: Self = Self([0; LIMBS]);

Expand All @@ -79,8 +86,51 @@ impl FieldElement {

/// Attempts to parse the given byte array as an SEC1-encoded field element.
///
/// Returns None if the byte array does not contain a big-endian integer in
/// the range [0, p).
/// Returns `None` if the byte array does not contain a big-endian integer in
/// the range `[0, p)`.
#[cfg(target_pointer_width = "32")]
pub fn from_sec1(bytes: &FieldBytes) -> CtOption<Self> {
let mut w = [Limb::default(); LIMBS];

// Interpret the bytes as a big-endian integer w.
w[11] = u32::from_be_bytes(bytes[0..4].try_into().unwrap());
w[10] = u32::from_be_bytes(bytes[4..8].try_into().unwrap());
w[9] = u32::from_be_bytes(bytes[8..12].try_into().unwrap());
w[8] = u32::from_be_bytes(bytes[12..16].try_into().unwrap());
w[7] = u32::from_be_bytes(bytes[16..20].try_into().unwrap());
w[6] = u32::from_be_bytes(bytes[20..24].try_into().unwrap());
w[5] = u32::from_be_bytes(bytes[24..28].try_into().unwrap());
w[4] = u32::from_be_bytes(bytes[28..32].try_into().unwrap());
w[3] = u32::from_be_bytes(bytes[32..36].try_into().unwrap());
w[2] = u32::from_be_bytes(bytes[36..40].try_into().unwrap());
w[1] = u32::from_be_bytes(bytes[40..44].try_into().unwrap());
w[0] = u32::from_be_bytes(bytes[44..48].try_into().unwrap());

// If w is in the range [0, p) then w - p will overflow, resulting in a borrow
// value of 2^64 - 1.
let (_, borrow) = sbb(w[0], MODULUS.0[0], 0);
let (_, borrow) = sbb(w[1], MODULUS.0[1], borrow);
let (_, borrow) = sbb(w[2], MODULUS.0[2], borrow);
let (_, borrow) = sbb(w[3], MODULUS.0[3], borrow);
let (_, borrow) = sbb(w[4], MODULUS.0[4], borrow);
let (_, borrow) = sbb(w[5], MODULUS.0[5], borrow);
let (_, borrow) = sbb(w[0], MODULUS.0[6], borrow);
let (_, borrow) = sbb(w[1], MODULUS.0[7], borrow);
let (_, borrow) = sbb(w[2], MODULUS.0[8], borrow);
let (_, borrow) = sbb(w[3], MODULUS.0[9], borrow);
let (_, borrow) = sbb(w[4], MODULUS.0[10], borrow);
let (_, borrow) = sbb(w[5], MODULUS.0[11], borrow);
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).to_montgomery(), Choice::from(is_some))
}

/// Attempts to parse the given byte array as an SEC1-encoded field element.
///
/// Returns `None` if the byte array does not contain a big-endian integer in
/// the range `[0, p)`.
#[cfg(target_pointer_width = "64")]
pub fn from_sec1(bytes: &FieldBytes) -> CtOption<Self> {
let mut w = [Limb::default(); LIMBS];

Expand All @@ -107,6 +157,29 @@ impl FieldElement {
}

/// Returns the SEC1 encoding of this field element.
#[cfg(target_pointer_width = "32")]
pub fn to_sec1(self) -> FieldBytes {
// Convert from Montgomery form to canonical form
let tmp = self.to_canonical();

let mut ret = FieldBytes::default();
ret[0..4].copy_from_slice(&tmp.0[11].to_be_bytes());
ret[4..8].copy_from_slice(&tmp.0[10].to_be_bytes());
ret[8..12].copy_from_slice(&tmp.0[9].to_be_bytes());
ret[12..16].copy_from_slice(&tmp.0[8].to_be_bytes());
ret[16..20].copy_from_slice(&tmp.0[7].to_be_bytes());
ret[20..24].copy_from_slice(&tmp.0[6].to_be_bytes());
ret[24..28].copy_from_slice(&tmp.0[5].to_be_bytes());
ret[28..32].copy_from_slice(&tmp.0[4].to_be_bytes());
ret[32..36].copy_from_slice(&tmp.0[3].to_be_bytes());
ret[36..40].copy_from_slice(&tmp.0[2].to_be_bytes());
ret[40..44].copy_from_slice(&tmp.0[1].to_be_bytes());
ret[44..48].copy_from_slice(&tmp.0[0].to_be_bytes());
ret
}

/// Returns the SEC1 encoding of this field element.
#[cfg(target_pointer_width = "64")]
pub fn to_sec1(self) -> FieldBytes {
// Convert from Montgomery form to canonical form
let tmp = self.to_canonical();
Expand Down Expand Up @@ -240,7 +313,14 @@ impl FieldElement {
out
}

/// Inversion
/// Inversion.
#[cfg(target_pointer_width = "32")]
pub fn invert(&self) -> CtOption<Self> {
todo!()
}

/// Inversion.
#[cfg(target_pointer_width = "64")]
pub fn invert(&self) -> CtOption<Self> {
let limbs = &self.0;
type Fe = fiat_p384_montgomery_domain_field_element;
Expand Down Expand Up @@ -376,6 +456,14 @@ impl From<U384> for FieldElement {
}
}

#[cfg(target_pointer_width = "32")]
impl From<[u32; 12]> for FieldElement {
fn from(w: [u32; 12]) -> Self {
FieldElement::from_limbs(w)
}
}

#[cfg(target_pointer_width = "64")]
impl From<[u64; 6]> for FieldElement {
fn from(w: [u64; 6]) -> Self {
FieldElement::from_limbs(w)
Expand Down Expand Up @@ -471,6 +559,15 @@ impl Neg for FieldElement {
}

/// Computes `a - (b + borrow)`, returning the result and the new borrow.
#[cfg(target_pointer_width = "32")]
#[inline(always)]
pub const fn sbb(a: u32, b: u32, borrow: u32) -> (u32, u32) {
let ret = (a as u64).wrapping_sub((b as u64) + ((borrow >> 31) as u64));
(ret as u32, (ret >> 32) as u32)
}

/// Computes `a - (b + borrow)`, returning the result and the new borrow.
#[cfg(target_pointer_width = "64")]
#[inline(always)]
pub const fn sbb(a: u64, b: u64, borrow: u64) -> (u64, u64) {
let ret = (a as u128).wrapping_sub((b as u128) + ((borrow >> 63) as u128));
Expand Down
Loading

0 comments on commit e8c2a7d

Please sign in to comment.