Remove crypto-bigint from the public API of prime-field

This commit is contained in:
Luke Parker
2025-09-03 06:41:42 -04:00
parent 974bc82387
commit 41c34d7f11
6 changed files with 101 additions and 24 deletions

2
Cargo.lock generated
View File

@@ -2458,6 +2458,7 @@ version = "0.4.6"
dependencies = [ dependencies = [
"ciphersuite 0.4.2", "ciphersuite 0.4.2",
"crypto-bigint 0.5.5", "crypto-bigint 0.5.5",
"crypto-bigint 0.6.1",
"curve25519-dalek", "curve25519-dalek",
"digest 0.10.7", "digest 0.10.7",
"ff-group-tests", "ff-group-tests",
@@ -6005,6 +6006,7 @@ name = "minimal-ed448"
version = "0.4.2" version = "0.4.2"
dependencies = [ dependencies = [
"ciphersuite 0.4.2", "ciphersuite 0.4.2",
"crypto-bigint 0.6.1",
"ff-group-tests", "ff-group-tests",
"hex", "hex",
"prime-field", "prime-field",

View File

@@ -28,7 +28,8 @@ sha2 = { version = "0.11.0-rc.0", default-features = false }
prime-field = { path = "../prime-field", default-features = false } prime-field = { path = "../prime-field", default-features = false }
ciphersuite = { version = "0.4.2", path = "../ciphersuite", default-features = false } ciphersuite = { version = "0.4.2", path = "../ciphersuite", default-features = false }
crypto-bigint = { version = "0.5", default-features = false, features = ["zeroize"] } crypto-bigint-05 = { package = "crypto-bigint", version = "0.5", default-features = false, features = ["zeroize"] }
crypto-bigint = { version = "0.6", default-features = false, features = ["zeroize"] }
curve25519-dalek = { version = ">= 4.0, < 4.2", default-features = false, features = ["zeroize", "digest", "group", "precomputed-tables"] } curve25519-dalek = { version = ">= 4.0, < 4.2", default-features = false, features = ["zeroize", "digest", "group", "precomputed-tables"] }

View File

@@ -500,8 +500,18 @@ impl FieldElement {
/// ///
/// This will reduce the `U256` by the modulus, into a member of the field. /// This will reduce the `U256` by the modulus, into a member of the field.
#[deprecated] #[deprecated]
pub const fn from_u256(u256: &crypto_bigint::U256) -> Self { pub const fn from_u256(u256: &crypto_bigint_05::U256) -> Self {
FieldElement::from(&prime_field::crypto_bigint::U256::from_words(*u256.as_words())) const MODULUS: crypto_bigint::U256 = crypto_bigint::U256::from_be_hex(
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed",
);
let mut u256 = crypto_bigint::U256::from_words(*u256.as_words());
loop {
let result = FieldElement::from_bytes(&u256.to_le_bytes());
if let Some(result) = result {
return result;
}
u256 = u256.wrapping_sub(&MODULUS);
}
} }
/// Create a `FieldElement` from the reduction of a 512-bit number. /// Create a `FieldElement` from the reduction of a 512-bit number.

View File

@@ -21,6 +21,7 @@ zeroize = { version = "1", default-features = false, features = ["zeroize_derive
sha3 = { version = "0.11.0-rc.0", default-features = false } sha3 = { version = "0.11.0-rc.0", default-features = false }
crypto-bigint = { version = "0.6", default-features = false, features = ["zeroize"] }
prime-field = { path = "../prime-field", default-features = false } prime-field = { path = "../prime-field", default-features = false }
ciphersuite = { path = "../ciphersuite", default-features = false } ciphersuite = { path = "../ciphersuite", default-features = false }
@@ -32,6 +33,6 @@ rand_core = { version = "0.6", default-features = false, features = ["std"] }
ff-group-tests = { path = "../ff-group-tests" } ff-group-tests = { path = "../ff-group-tests" }
[features] [features]
alloc = ["zeroize/alloc", "sha3/alloc", "prime-field/alloc", "ciphersuite/alloc"] alloc = ["zeroize/alloc", "sha3/alloc", "crypto-bigint/alloc", "prime-field/alloc", "ciphersuite/alloc"]
std = ["alloc", "zeroize/std", "prime-field/std", "ciphersuite/std"] std = ["alloc", "zeroize/std", "prime-field/std", "ciphersuite/std"]
default = ["std"] default = ["std"]

View File

@@ -7,8 +7,8 @@ use prime_field::{
subtle::{Choice, CtOption, ConstantTimeEq, ConditionallySelectable, ConditionallyNegatable}, subtle::{Choice, CtOption, ConstantTimeEq, ConditionallySelectable, ConditionallyNegatable},
zeroize::Zeroize, zeroize::Zeroize,
rand_core::RngCore, rand_core::RngCore,
crypto_bigint::U512,
}; };
use crypto_bigint::U512;
use ciphersuite::group::{ use ciphersuite::group::{
ff::{Field, PrimeField, PrimeFieldBits}, ff::{Field, PrimeField, PrimeFieldBits},
@@ -18,17 +18,37 @@ use ciphersuite::group::{
use crate::{u8_from_bool, Scalar, FieldElement}; use crate::{u8_from_bool, Scalar, FieldElement};
const G_Y: FieldElement = FieldElement::from(&U512::from_be_hex(concat!( const G_Y: FieldElement = {
let bytes = U512::from_be_hex(concat!(
"0000000000000000", "0000000000000000",
"693f46716eb6bc248876203756c9c7624bea73736ca3984087789c1e", "693f46716eb6bc248876203756c9c7624bea73736ca3984087789c1e",
"05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14", "05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14",
))); ))
.to_le_bytes();
let mut dest = [0; 57];
let mut i = 0;
while i < dest.len() {
dest[i] = bytes[i];
i += 1;
}
FieldElement::from_bytes(&dest).unwrap()
};
const G_X: FieldElement = FieldElement::from(&U512::from_be_hex(concat!( const G_X: FieldElement = {
let bytes = U512::from_be_hex(concat!(
"0000000000000000", "0000000000000000",
"4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324", "4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324",
"a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05e", "a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05e",
))); ))
.to_le_bytes();
let mut dest = [0; 57];
let mut i = 0;
while i < dest.len() {
dest[i] = bytes[i];
i += 1;
}
FieldElement::from_bytes(&dest).unwrap()
};
fn recover_x(y: FieldElement) -> CtOption<FieldElement> { fn recover_x(y: FieldElement) -> CtOption<FieldElement> {
#[allow(non_snake_case)] #[allow(non_snake_case)]

View File

@@ -5,11 +5,11 @@
pub use subtle; pub use subtle;
pub use zeroize; pub use zeroize;
pub use rand_core; pub use rand_core;
pub use crypto_bigint;
pub use ff; pub use ff;
#[doc(hidden)] #[doc(hidden)]
pub mod __prime_field_private { pub mod __prime_field_private {
pub use crypto_bigint;
pub use paste; pub use paste;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use ff_group_tests; pub use ff_group_tests;
@@ -94,6 +94,8 @@ pub mod __prime_field_private {
/// less than `modulus_as_be_hex`. /// less than `modulus_as_be_hex`.
/// ///
/// `big_endian` controls if the encoded representation will be big-endian or not. /// `big_endian` controls if the encoded representation will be big-endian or not.
///
/// `repr` must satisfy the requirements for `PrimeField::Repr`.
#[doc(hidden)] #[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! odd_prime_field_with_specific_repr { macro_rules! odd_prime_field_with_specific_repr {
@@ -116,13 +118,15 @@ macro_rules! odd_prime_field_with_specific_repr {
}, },
zeroize::Zeroize, zeroize::Zeroize,
rand_core::RngCore, rand_core::RngCore,
ff::*,
__prime_field_private::{
crypto_bigint::{ crypto_bigint::{
Limb, Encoding, Integer, Uint, Limb, Encoding, Integer, Uint,
modular::{ConstMontyParams, ConstMontyForm}, modular::{ConstMontyParams, ConstMontyForm},
impl_modulus, impl_modulus,
}, },
ff::*, *,
__prime_field_private::*, },
}; };
const MODULUS_WITHOUT_PREFIX: &str = hex_str_without_prefix($modulus_as_be_hex); const MODULUS_WITHOUT_PREFIX: &str = hex_str_without_prefix($modulus_as_be_hex);
@@ -180,7 +184,7 @@ macro_rules! odd_prime_field_with_specific_repr {
const MODULUS_MINUS_TWO: UnderlyingUint = MODULUS.wrapping_sub(&UnderlyingUint::from_u8(2)); const MODULUS_MINUS_TWO: UnderlyingUint = MODULUS.wrapping_sub(&UnderlyingUint::from_u8(2));
const T: UnderlyingUint = MODULUS_MINUS_ONE.shr_vartime($name::S); const T: UnderlyingUint = MODULUS_MINUS_ONE.shr_vartime($name::S);
/// A field automatically generated with `short-weierstrass`. /// A field automatically generated with `prime-field`.
#[derive(Clone, Copy, Eq, Debug)] #[derive(Clone, Copy, Eq, Debug)]
pub struct $name(Underlying); pub struct $name(Underlying);
@@ -192,9 +196,47 @@ macro_rules! odd_prime_field_with_specific_repr {
impl $name { impl $name {
/// Create a `$name` from the `Uint` type underlying it. /// Create a `$name` from the `Uint` type underlying it.
pub const fn from(value: &UnderlyingUint) -> Self { const fn from(value: &UnderlyingUint) -> Self {
$name(Underlying::new(value)) $name(Underlying::new(value))
} }
/// Create a `$name` from bytes within a `const` context.
///
/// This function executes in variable time. `<$name as PrimeField>::from_repr` SHOULD
/// be used instead.
pub const fn from_bytes(value: &[u8; MODULUS_BYTES]) -> Option<Self> {
let mut expanded_repr = [0; UnderlyingUint::BYTES];
let repr: &[u8] = value.as_slice();
let (uint, repr) = if $big_endian {
let start = UnderlyingUint::BYTES - MODULUS_BYTES;
let mut i = 0;
while i < repr.len() {
expanded_repr[start + i] = repr[i];
i += 1;
}
let uint = Underlying::new(&UnderlyingUint::from_be_slice(&expanded_repr));
(uint, uint.retrieve().to_be_bytes())
} else {
let mut i = 0;
while i < repr.len() {
expanded_repr[i] = repr[i];
i += 1;
}
let uint = Underlying::new(&UnderlyingUint::from_le_slice(&expanded_repr));
(uint, uint.retrieve().to_le_bytes())
};
// Ensure the representations match
let mut i = 0;
while i < expanded_repr.len() {
if repr[i] != expanded_repr[i] {
return None;
}
i += 1;
}
Some(Self(uint))
}
} }
impl From<u8> for $name { impl From<u8> for $name {
fn from(value: u8) -> Self { fn from(value: u8) -> Self {
@@ -416,6 +458,7 @@ macro_rules! odd_prime_field_with_specific_repr {
} }
/// The encoded representation of a `$name`. /// The encoded representation of a `$name`.
// This is required to be bespoke to satisfy `Default`.
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct Repr([u8; MODULUS_BYTES]); pub struct Repr([u8; MODULUS_BYTES]);
impl Default for Repr { impl Default for Repr {