mirror of
https://github.com/saymrwulf/pasta_curves-source.git
synced 2026-09-04 20:03:39 +00:00
fields: Ensure that trait impl dependencies match trait bounds
The `FieldExt` trait was originally the only trait implemented in this
crate. When we added `ff` support, we reworked `FieldExt` to be an
extension trait on top of `ff::PrimeField`, but left the existing impls
in `FieldExt`. This resulted in some circular dependencies that prevent
us from making `FieldExt` conditional (e.g. for no-std support).
This commit removes the cycles like so:
- `ff::PrimeField::{from_repr, to_repr}` were implemented as calls to
`FieldExt::{from_bytes, to_bytes}`. The field encoding/decoding logic
is moved into the `ff::PrimeField` trait impl, and `FieldExt` now
calls into `ff::PrimeField`.
- `ff::Field::sqrt` was implemented in terms of `FieldExt::sqrt_alt`.
Given that the latter is a trivial wrapper around the `SqrtTables`
implementation, we duplicate the call to eliminate the cycle.
- `ff::Field::random` used `FieldExt::from_bytes_wide`, which wraps
either `Fp::from_u512` or `Fq::from_u512`. We now use these internal
methods directly.
This commit is contained in:
parent
87488ec1f6
commit
6a47700b1d
2 changed files with 98 additions and 94 deletions
|
|
@ -466,10 +466,16 @@ impl Group for Fp {
|
|||
|
||||
impl ff::Field for Fp {
|
||||
fn random(mut rng: impl RngCore) -> Self {
|
||||
let mut random_bytes = [0; 64];
|
||||
rng.fill_bytes(&mut random_bytes[..]);
|
||||
|
||||
Self::from_bytes_wide(&random_bytes)
|
||||
Self::from_u512([
|
||||
rng.next_u64(),
|
||||
rng.next_u64(),
|
||||
rng.next_u64(),
|
||||
rng.next_u64(),
|
||||
rng.next_u64(),
|
||||
rng.next_u64(),
|
||||
rng.next_u64(),
|
||||
rng.next_u64(),
|
||||
])
|
||||
}
|
||||
|
||||
fn zero() -> Self {
|
||||
|
|
@ -491,7 +497,7 @@ impl ff::Field for Fp {
|
|||
|
||||
/// Computes the square root of this element, if it exists.
|
||||
fn sqrt(&self) -> CtOption<Self> {
|
||||
let (is_square, res) = self.sqrt_alt();
|
||||
let (is_square, res) = FP_TABLES.sqrt_alt(self);
|
||||
CtOption::new(res, is_square)
|
||||
}
|
||||
|
||||
|
|
@ -535,15 +541,47 @@ impl ff::PrimeField for Fp {
|
|||
const S: u32 = S;
|
||||
|
||||
fn from_repr(repr: Self::Repr) -> CtOption<Self> {
|
||||
Self::from_bytes(&repr)
|
||||
let mut tmp = Fp([0, 0, 0, 0]);
|
||||
|
||||
tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap());
|
||||
tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap());
|
||||
tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap());
|
||||
tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap());
|
||||
|
||||
// Try to subtract the modulus
|
||||
let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0);
|
||||
let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow);
|
||||
let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow);
|
||||
let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow);
|
||||
|
||||
// If the element is smaller than MODULUS then the
|
||||
// subtraction will underflow, producing a borrow value
|
||||
// of 0xffff...ffff. Otherwise, it'll be zero.
|
||||
let is_some = (borrow as u8) & 1;
|
||||
|
||||
// Convert to Montgomery form by computing
|
||||
// (a.R^0 * R^2) / R = a.R
|
||||
tmp *= &R2;
|
||||
|
||||
CtOption::new(tmp, Choice::from(is_some))
|
||||
}
|
||||
|
||||
fn to_repr(&self) -> Self::Repr {
|
||||
self.to_bytes()
|
||||
// Turn into canonical form by computing
|
||||
// (a.R) / R = a
|
||||
let tmp = Fp::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0);
|
||||
|
||||
let mut res = [0; 32];
|
||||
res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes());
|
||||
res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes());
|
||||
res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes());
|
||||
res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes());
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
fn is_odd(&self) -> Choice {
|
||||
Choice::from(self.to_bytes()[0] & 1)
|
||||
Choice::from(self.to_repr()[0] & 1)
|
||||
}
|
||||
|
||||
fn multiplicative_generator() -> Self {
|
||||
|
|
@ -551,7 +589,7 @@ impl ff::PrimeField for Fp {
|
|||
}
|
||||
|
||||
fn root_of_unity() -> Self {
|
||||
Self::ROOT_OF_UNITY
|
||||
ROOT_OF_UNITY
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -660,48 +698,12 @@ impl FieldExt for Fp {
|
|||
Fp::from_raw([v as u64, (v >> 64) as u64, 0, 0])
|
||||
}
|
||||
|
||||
/// Attempts to convert a little-endian byte representation of
|
||||
/// a scalar into a `Fp`, failing if the input is not canonical.
|
||||
fn from_bytes(bytes: &[u8; 32]) -> CtOption<Fp> {
|
||||
let mut tmp = Fp([0, 0, 0, 0]);
|
||||
|
||||
tmp.0[0] = u64::from_le_bytes(bytes[0..8].try_into().unwrap());
|
||||
tmp.0[1] = u64::from_le_bytes(bytes[8..16].try_into().unwrap());
|
||||
tmp.0[2] = u64::from_le_bytes(bytes[16..24].try_into().unwrap());
|
||||
tmp.0[3] = u64::from_le_bytes(bytes[24..32].try_into().unwrap());
|
||||
|
||||
// Try to subtract the modulus
|
||||
let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0);
|
||||
let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow);
|
||||
let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow);
|
||||
let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow);
|
||||
|
||||
// If the element is smaller than MODULUS then the
|
||||
// subtraction will underflow, producing a borrow value
|
||||
// of 0xffff...ffff. Otherwise, it'll be zero.
|
||||
let is_some = (borrow as u8) & 1;
|
||||
|
||||
// Convert to Montgomery form by computing
|
||||
// (a.R^0 * R^2) / R = a.R
|
||||
tmp *= &R2;
|
||||
|
||||
CtOption::new(tmp, Choice::from(is_some))
|
||||
<Self as ff::PrimeField>::from_repr(*bytes)
|
||||
}
|
||||
|
||||
/// Converts an element of `Fp` into a byte representation in
|
||||
/// little-endian byte order.
|
||||
fn to_bytes(&self) -> [u8; 32] {
|
||||
// Turn into canonical form by computing
|
||||
// (a.R) / R = a
|
||||
let tmp = Fp::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0);
|
||||
|
||||
let mut res = [0; 32];
|
||||
res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes());
|
||||
res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes());
|
||||
res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes());
|
||||
res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes());
|
||||
|
||||
res
|
||||
<Self as ff::PrimeField>::to_repr(self)
|
||||
}
|
||||
|
||||
/// Converts a 512-bit little endian integer into
|
||||
|
|
|
|||
|
|
@ -466,10 +466,16 @@ impl Group for Fq {
|
|||
|
||||
impl ff::Field for Fq {
|
||||
fn random(mut rng: impl RngCore) -> Self {
|
||||
let mut random_bytes = [0; 64];
|
||||
rng.fill_bytes(&mut random_bytes[..]);
|
||||
|
||||
Self::from_bytes_wide(&random_bytes)
|
||||
Self::from_u512([
|
||||
rng.next_u64(),
|
||||
rng.next_u64(),
|
||||
rng.next_u64(),
|
||||
rng.next_u64(),
|
||||
rng.next_u64(),
|
||||
rng.next_u64(),
|
||||
rng.next_u64(),
|
||||
rng.next_u64(),
|
||||
])
|
||||
}
|
||||
|
||||
fn zero() -> Self {
|
||||
|
|
@ -491,7 +497,7 @@ impl ff::Field for Fq {
|
|||
|
||||
/// Computes the square root of this element, if it exists.
|
||||
fn sqrt(&self) -> CtOption<Self> {
|
||||
let (is_square, res) = self.sqrt_alt();
|
||||
let (is_square, res) = FQ_TABLES.sqrt_alt(self);
|
||||
CtOption::new(res, is_square)
|
||||
}
|
||||
|
||||
|
|
@ -535,15 +541,47 @@ impl ff::PrimeField for Fq {
|
|||
const S: u32 = S;
|
||||
|
||||
fn from_repr(repr: Self::Repr) -> CtOption<Self> {
|
||||
Self::from_bytes(&repr)
|
||||
let mut tmp = Fq([0, 0, 0, 0]);
|
||||
|
||||
tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap());
|
||||
tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap());
|
||||
tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap());
|
||||
tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap());
|
||||
|
||||
// Try to subtract the modulus
|
||||
let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0);
|
||||
let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow);
|
||||
let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow);
|
||||
let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow);
|
||||
|
||||
// If the element is smaller than MODULUS then the
|
||||
// subtraction will underflow, producing a borrow value
|
||||
// of 0xffff...ffff. Otherwise, it'll be zero.
|
||||
let is_some = (borrow as u8) & 1;
|
||||
|
||||
// Convert to Montgomery form by computing
|
||||
// (a.R^0 * R^2) / R = a.R
|
||||
tmp *= &R2;
|
||||
|
||||
CtOption::new(tmp, Choice::from(is_some))
|
||||
}
|
||||
|
||||
fn to_repr(&self) -> Self::Repr {
|
||||
self.to_bytes()
|
||||
// Turn into canonical form by computing
|
||||
// (a.R) / R = a
|
||||
let tmp = Fq::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0);
|
||||
|
||||
let mut res = [0; 32];
|
||||
res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes());
|
||||
res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes());
|
||||
res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes());
|
||||
res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes());
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
fn is_odd(&self) -> Choice {
|
||||
Choice::from(self.to_bytes()[0] & 1)
|
||||
Choice::from(self.to_repr()[0] & 1)
|
||||
}
|
||||
|
||||
fn multiplicative_generator() -> Self {
|
||||
|
|
@ -551,7 +589,7 @@ impl ff::PrimeField for Fq {
|
|||
}
|
||||
|
||||
fn root_of_unity() -> Self {
|
||||
Self::ROOT_OF_UNITY
|
||||
ROOT_OF_UNITY
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -660,48 +698,12 @@ impl FieldExt for Fq {
|
|||
Fq::from_raw([v as u64, (v >> 64) as u64, 0, 0])
|
||||
}
|
||||
|
||||
/// Attempts to convert a little-endian byte representation of
|
||||
/// a scalar into a `Fq`, failing if the input is not canonical.
|
||||
fn from_bytes(bytes: &[u8; 32]) -> CtOption<Fq> {
|
||||
let mut tmp = Fq([0, 0, 0, 0]);
|
||||
|
||||
tmp.0[0] = u64::from_le_bytes(bytes[0..8].try_into().unwrap());
|
||||
tmp.0[1] = u64::from_le_bytes(bytes[8..16].try_into().unwrap());
|
||||
tmp.0[2] = u64::from_le_bytes(bytes[16..24].try_into().unwrap());
|
||||
tmp.0[3] = u64::from_le_bytes(bytes[24..32].try_into().unwrap());
|
||||
|
||||
// Try to subtract the modulus
|
||||
let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0);
|
||||
let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow);
|
||||
let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow);
|
||||
let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow);
|
||||
|
||||
// If the element is smaller than MODULUS then the
|
||||
// subtraction will underflow, producing a borrow value
|
||||
// of 0xffff...ffff. Otherwise, it'll be zero.
|
||||
let is_some = (borrow as u8) & 1;
|
||||
|
||||
// Convert to Montgomery form by computing
|
||||
// (a.R^0 * R^2) / R = a.R
|
||||
tmp *= &R2;
|
||||
|
||||
CtOption::new(tmp, Choice::from(is_some))
|
||||
<Self as ff::PrimeField>::from_repr(*bytes)
|
||||
}
|
||||
|
||||
/// Converts an element of `Fq` into a byte representation in
|
||||
/// little-endian byte order.
|
||||
fn to_bytes(&self) -> [u8; 32] {
|
||||
// Turn into canonical form by computing
|
||||
// (a.R) / R = a
|
||||
let tmp = Fq::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0);
|
||||
|
||||
let mut res = [0; 32];
|
||||
res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes());
|
||||
res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes());
|
||||
res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes());
|
||||
res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes());
|
||||
|
||||
res
|
||||
<Self as ff::PrimeField>::to_repr(self)
|
||||
}
|
||||
|
||||
/// Converts a 512-bit little endian integer into
|
||||
|
|
|
|||
Loading…
Reference in a new issue