diff --git a/elliptic-curve/src/arithmetic.rs b/elliptic-curve/src/arithmetic.rs index f09e8d728..53654d57e 100644 --- a/elliptic-curve/src/arithmetic.rs +++ b/elliptic-curve/src/arithmetic.rs @@ -1,7 +1,7 @@ //! Elliptic curve arithmetic traits. use crate::{ - ops::{LinearCombination, MulByGenerator, ShrAssign}, + ops::{LinearCombination, MulByGenerator, Reduce, ShrAssign}, point::{AffineXCoordinate, AffineYIsOdd}, scalar::FromUintUnchecked, scalar::IsHigh, @@ -72,6 +72,7 @@ pub trait CurveArithmetic: Curve { + Into + IsHigh + PartialOrd + + Reduce> + ShrAssign + ff::Field + ff::PrimeField>; diff --git a/elliptic-curve/src/dev.rs b/elliptic-curve/src/dev.rs index f63d34b76..2d45bf32f 100644 --- a/elliptic-curve/src/dev.rs +++ b/elliptic-curve/src/dev.rs @@ -325,12 +325,18 @@ impl<'a> Product<&'a Scalar> for Scalar { } impl Reduce for Scalar { + type Bytes = FieldBytes; + fn reduce(w: U256) -> Self { let (r, underflow) = w.sbb(&MockCurve::ORDER, Limb::ZERO); let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8); let reduced = U256::conditional_select(&w, &r, !underflow); Self(ScalarPrimitive::new(reduced).unwrap()) } + + fn reduce_bytes(_: &FieldBytes) -> Self { + todo!() + } } impl From for Scalar { diff --git a/elliptic-curve/src/lib.rs b/elliptic-curve/src/lib.rs index fb14e0df7..cda6ebad7 100644 --- a/elliptic-curve/src/lib.rs +++ b/elliptic-curve/src/lib.rs @@ -72,7 +72,6 @@ extern crate alloc; #[cfg(feature = "std")] extern crate std; -pub mod ops; pub mod point; pub mod scalar; @@ -82,6 +81,8 @@ pub mod dev; pub mod ecdh; #[cfg(feature = "hash2curve")] pub mod hash2curve; +#[cfg(feature = "arithmetic")] +pub mod ops; #[cfg(feature = "sec1")] pub mod sec1; #[cfg(feature = "arithmetic")] diff --git a/elliptic-curve/src/ops.rs b/elliptic-curve/src/ops.rs index aa16ee701..377558a15 100644 --- a/elliptic-curve/src/ops.rs +++ b/elliptic-curve/src/ops.rs @@ -3,8 +3,6 @@ pub use core::ops::{Add, AddAssign, Mul, Neg, Shr, ShrAssign, Sub, SubAssign}; use crypto_bigint::Integer; - -#[cfg(feature = "arithmetic")] use {group::Group, subtle::CtOption}; /// Perform an inversion on a field element (i.e. base field element or scalar) @@ -16,7 +14,6 @@ pub trait Invert { fn invert(&self) -> Self::Output; } -#[cfg(feature = "arithmetic")] impl Invert for F { type Output = CtOption; @@ -31,7 +28,6 @@ impl Invert for F { /// linear combinations (e.g. Shamir's Trick), or otherwise provides a default /// non-optimized implementation. // TODO(tarcieri): replace this with a trait from the `group` crate? (see zkcrypto/group#25) -#[cfg(feature = "arithmetic")] pub trait LinearCombination: Group { /// Calculates `x * k + y * l`. fn lincomb(x: &Self, k: &Self::Scalar, y: &Self, l: &Self::Scalar) -> Self { @@ -43,7 +39,6 @@ pub trait LinearCombination: Group { /// /// May use optimizations (e.g. precomputed tables) when available. // TODO(tarcieri): replace this with `Group::mul_by_generator``? (see zkcrypto/group#44) -#[cfg(feature = "arithmetic")] pub trait MulByGenerator: Group { /// Multiply by the generator of the prime-order subgroup. #[must_use] @@ -54,8 +49,14 @@ pub trait MulByGenerator: Group { /// Modular reduction. pub trait Reduce: Sized { + /// Bytes used as input to [`Reduce::reduce_bytes`]. + type Bytes: AsRef<[u8]>; + /// Perform a modular reduction, returning a field element. fn reduce(n: Uint) -> Self; + + /// Interpret the given bytes as an integer and perform a modular reduction. + fn reduce_bytes(bytes: &Self::Bytes) -> Self; } /// Modular reduction to a non-zero output. @@ -65,7 +66,11 @@ pub trait Reduce: Sized { /// /// End users should use the [`Reduce`] impl on /// [`NonZeroScalar`][`crate::NonZeroScalar`] instead. -pub trait ReduceNonZero: Sized { +pub trait ReduceNonZero: Reduce + Sized { /// Perform a modular reduction, returning a field element. fn reduce_nonzero(n: Uint) -> Self; + + /// Interpret the given bytes as an integer and perform a modular reduction + /// to a non-zero output. + fn reduce_nonzero_bytes(bytes: &Self::Bytes) -> Self; } diff --git a/elliptic-curve/src/scalar/nonzero.rs b/elliptic-curve/src/scalar/nonzero.rs index a4a2dbeca..460d6fc5f 100644 --- a/elliptic-curve/src/scalar/nonzero.rs +++ b/elliptic-curve/src/scalar/nonzero.rs @@ -249,24 +249,36 @@ impl Reduce for NonZeroScalar where C: CurveArithmetic, I: Integer + ArrayEncoding, - Scalar: ReduceNonZero, + Scalar: Reduce> + ReduceNonZero, { + type Bytes = FieldBytes; + fn reduce(n: I) -> Self { Self::reduce_nonzero(n) } + + fn reduce_bytes(bytes: &FieldBytes) -> Self { + Self::reduce_nonzero_bytes(bytes) + } } impl ReduceNonZero for NonZeroScalar where C: CurveArithmetic, I: Integer + ArrayEncoding, - Scalar: ReduceNonZero, + Scalar: Reduce> + ReduceNonZero, { fn reduce_nonzero(n: I) -> Self { let scalar = Scalar::::reduce_nonzero(n); debug_assert!(!bool::from(scalar.is_zero())); Self::new(scalar).unwrap() } + + fn reduce_nonzero_bytes(bytes: &FieldBytes) -> Self { + let scalar = Scalar::::reduce_nonzero_bytes(bytes); + debug_assert!(!bool::from(scalar.is_zero())); + Self::new(scalar).unwrap() + } } impl TryFrom<&[u8]> for NonZeroScalar diff --git a/elliptic-curve/src/scalar/primitive.rs b/elliptic-curve/src/scalar/primitive.rs index d0a78f083..0da18f589 100644 --- a/elliptic-curve/src/scalar/primitive.rs +++ b/elliptic-curve/src/scalar/primitive.rs @@ -2,13 +2,17 @@ use crate::{ bigint::{prelude::*, Limb, NonZero}, - ops::{Add, AddAssign, Neg, ShrAssign, Sub, SubAssign}, scalar::FromUintUnchecked, scalar::IsHigh, Curve, Error, FieldBytes, Result, }; use base16ct::HexDisplay; -use core::{cmp::Ordering, fmt, str}; +use core::{ + cmp::Ordering, + fmt, + ops::{Add, AddAssign, Neg, ShrAssign, Sub, SubAssign}, + str, +}; use generic_array::GenericArray; use rand_core::CryptoRngCore; use subtle::{