Skip to content

Commit d6e0519

Browse files
committed
primefield: generic MontyFieldElement type
The previous implementation was written entirely in terms of macros. Leveraging types from `crypto-bigint`, this provides a generic field element type with an internal Montgomery form representation.
1 parent 37fbeea commit d6e0519

File tree

8 files changed

+856
-31
lines changed

8 files changed

+856
-31
lines changed

Cargo.lock

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ members = [
2121
opt-level = 2
2222

2323
[patch.crates-io]
24+
crypto-bigint = { git = "https://github.com/RustCrypto/crypto-bigint" }
2425
elliptic-curve = { git = "https://github.com/RustCrypto/traits.git" }
26+
2527
hash2curve = { path = "hash2curve" }
2628
primefield = { path = "primefield" }
2729
primeorder = { path = "primeorder" }

p256/src/arithmetic/field.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ mod field_impl;
99
use crate::{FieldBytes, NistP256};
1010
use core::ops::Mul;
1111
use elliptic_curve::{
12-
FieldBytesEncoding,
1312
bigint::U256,
1413
ff::PrimeField,
1514
subtle::{Choice, ConstantTimeEq, CtOption},
15+
FieldBytesEncoding,
1616
};
1717

1818
const MODULUS_HEX: &str = "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff";
@@ -195,7 +195,7 @@ impl PrimeField for FieldElement {
195195
#[cfg(test)]
196196
mod tests {
197197
use super::FieldElement;
198-
use crate::{FieldBytes, U256, test_vectors::field::DBL_TEST_VECTORS};
198+
use crate::{test_vectors::field::DBL_TEST_VECTORS, FieldBytes, U256};
199199

200200
#[cfg(target_pointer_width = "64")]
201201
use proptest::{num::u64::ANY, prelude::*};

p256/src/arithmetic/scalar.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ use core::{
1212
ops::{Add, AddAssign, Mul, MulAssign, Neg, Shr, ShrAssign, Sub, SubAssign},
1313
};
1414
use elliptic_curve::{
15-
Curve,
16-
bigint::{Limb, U256, prelude::*},
15+
bigint::{prelude::*, Limb, U256},
1716
group::ff::{self, Field, PrimeField},
1817
ops::{Invert, Reduce, ReduceNonZero},
1918
rand_core::TryRngCore,
@@ -23,6 +22,7 @@ use elliptic_curve::{
2322
CtOption,
2423
},
2524
zeroize::DefaultIsZeroes,
25+
Curve,
2626
};
2727

2828
#[cfg(feature = "bits")]
@@ -31,7 +31,7 @@ use {crate::ScalarBits, elliptic_curve::group::ff::PrimeFieldBits};
3131
#[cfg(feature = "serde")]
3232
use {
3333
elliptic_curve::ScalarPrimitive,
34-
serdect::serde::{Deserialize, Serialize, de, ser},
34+
serdect::serde::{de, ser, Deserialize, Serialize},
3535
};
3636

3737
/// Constant representing the modulus
@@ -714,10 +714,10 @@ mod tests {
714714
use super::{Scalar, U256};
715715
use crate::{FieldBytes, NistP256, NonZeroScalar, SecretKey};
716716
use elliptic_curve::{
717-
Curve,
718717
array::Array,
719718
group::ff::{Field, PrimeField},
720719
ops::{BatchInvert, ReduceNonZero},
720+
Curve,
721721
};
722722
use proptest::{prelude::any, prop_compose, proptest};
723723

primefield/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ edition = "2024"
1414
rust-version = "1.85"
1515

1616
[dependencies]
17-
bigint = { package = "crypto-bigint", version = "=0.7.0-pre.7", default-features = false }
17+
bigint = { package = "crypto-bigint", version = "=0.7.0-pre.7", default-features = false, features = ["hybrid-array"] }
1818
ff = { version = "=0.14.0-pre.0", default-features = false }
1919
subtle = { version = "2.6", default-features = false }
2020
rand_core = { version = "0.9", default-features = false }

primefield/src/dev.rs

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,11 @@ macro_rules! test_primefield_constants {
1616
use $crate::ff::PrimeField as _;
1717

1818
/// t = (modulus - 1) >> S
19-
const T: $uint = $uint::from_be_hex($fe::MODULUS)
20-
.wrapping_sub(&$uint::ONE)
21-
.wrapping_shr($fe::S);
22-
23-
/// Helper function to compute the args to `pow_vartime`.
2419
#[cfg(target_pointer_width = "32")]
25-
fn pow_args(n: &$uint) -> [u64; $uint::LIMBS.div_ceil(2)] {
26-
let words = n.as_words();
27-
core::array::from_fn(|i| {
28-
let hi = words.get((2 * i) + 1).copied().unwrap_or_default();
29-
let lo = words[2 * i];
30-
(hi as u64) << 32 | (lo as u64)
31-
})
32-
}
20+
const T: [u64; $uint::LIMBS.div_ceil(2)] =
21+
$crate::compute_t(&$uint::from_be_hex($fe::MODULUS));
3322
#[cfg(target_pointer_width = "64")]
34-
fn pow_args(n: &$uint) -> [u64; $uint::LIMBS] {
35-
*n.as_words()
36-
}
23+
const T: [u64; $uint::LIMBS] = $crate::compute_t(&$uint::from_be_hex($fe::MODULUS));
3724

3825
#[test]
3926
fn two_inv_constant() {
@@ -58,7 +45,7 @@ macro_rules! test_primefield_constants {
5845

5946
// MULTIPLICATIVE_GENERATOR^{t} mod m == ROOT_OF_UNITY
6047
assert_eq!(
61-
$fe::MULTIPLICATIVE_GENERATOR.pow_vartime(&pow_args(&T)),
48+
$fe::MULTIPLICATIVE_GENERATOR.pow_vartime(&T),
6249
$fe::ROOT_OF_UNITY
6350
)
6451
}
@@ -71,7 +58,7 @@ macro_rules! test_primefield_constants {
7158
#[test]
7259
fn delta_constant() {
7360
// DELTA^{t} mod m == 1
74-
assert_eq!($fe::DELTA.pow_vartime(&pow_args(&T)), $fe::ONE);
61+
assert_eq!($fe::DELTA.pow_vartime(&T), $fe::ONE);
7562
}
7663
};
7764
}

primefield/src/lib.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,28 @@
88
#![warn(missing_docs, rust_2018_idioms, unused_qualifications)]
99
#![doc = include_str!("../README.md")]
1010

11+
mod dev;
12+
mod fiat;
13+
mod monty;
14+
15+
pub use crate::monty::{MontyFieldElement, MontyFieldParams, compute_t};
16+
pub use array::typenum::consts;
1117
pub use bigint;
18+
pub use bigint::hybrid_array as array;
1219
pub use ff;
1320
pub use rand_core;
1421
pub use subtle;
1522
pub use zeroize;
1623

17-
mod dev;
18-
mod fiat;
24+
/// Byte order used when encoding/decoding field elements as bytestrings.
25+
#[derive(Debug)]
26+
pub enum ByteOrder {
27+
/// Big endian.
28+
BigEndian,
29+
30+
/// Little endian.
31+
LittleEndian,
32+
}
1933

2034
/// Implements a field element type whose internal representation is in
2135
/// Montgomery form, providing a combination of trait impls and inherent impls
@@ -221,12 +235,10 @@ macro_rules! field_element_type {
221235
Self::ZERO.ct_eq(self)
222236
}
223237

224-
#[must_use]
225238
fn square(&self) -> Self {
226239
self.square()
227240
}
228241

229-
#[must_use]
230242
fn double(&self) -> Self {
231243
self.double()
232244
}

0 commit comments

Comments
 (0)