342 lines
9.9 KiB
Rust
342 lines
9.9 KiB
Rust
//! Traits provided by this crate
|
||
|
||
use crate::{Limb, NonZero};
|
||
use core::fmt::Debug;
|
||
use core::ops::{BitAnd, BitOr, BitXor, Div, Not, Rem, Shl, Shr};
|
||
use subtle::{
|
||
Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess,
|
||
CtOption,
|
||
};
|
||
|
||
#[cfg(feature = "rand_core")]
|
||
use rand_core::CryptoRngCore;
|
||
|
||
/// Integer type.
|
||
pub trait Integer:
|
||
'static
|
||
+ AsRef<[Limb]>
|
||
+ BitAnd<Output = Self>
|
||
+ BitOr<Output = Self>
|
||
+ BitXor<Output = Self>
|
||
+ for<'a> CheckedAdd<&'a Self, Output = Self>
|
||
+ for<'a> CheckedSub<&'a Self, Output = Self>
|
||
+ for<'a> CheckedMul<&'a Self, Output = Self>
|
||
+ Copy
|
||
+ ConditionallySelectable
|
||
+ ConstantTimeEq
|
||
+ ConstantTimeGreater
|
||
+ ConstantTimeLess
|
||
+ Debug
|
||
+ Default
|
||
+ Div<NonZero<Self>, Output = Self>
|
||
+ Eq
|
||
+ From<u64>
|
||
+ Not
|
||
+ Ord
|
||
+ Rem<NonZero<Self>, Output = Self>
|
||
+ Send
|
||
+ Sized
|
||
+ Shl<usize, Output = Self>
|
||
+ Shr<usize, Output = Self>
|
||
+ Sync
|
||
+ Zero
|
||
{
|
||
/// The value `1`.
|
||
const ONE: Self;
|
||
|
||
/// Maximum value this integer can express.
|
||
const MAX: Self;
|
||
|
||
/// Total size of the represented integer in bits.
|
||
const BITS: usize;
|
||
|
||
/// Total size of the represented integer in bytes.
|
||
const BYTES: usize;
|
||
|
||
/// The number of limbs used on this platform.
|
||
const LIMBS: usize;
|
||
|
||
/// Is this integer value an odd number?
|
||
///
|
||
/// # Returns
|
||
///
|
||
/// If odd, returns `Choice(1)`. Otherwise, returns `Choice(0)`.
|
||
fn is_odd(&self) -> Choice;
|
||
|
||
/// Is this integer value an even number?
|
||
///
|
||
/// # Returns
|
||
///
|
||
/// If even, returns `Choice(1)`. Otherwise, returns `Choice(0)`.
|
||
fn is_even(&self) -> Choice {
|
||
!self.is_odd()
|
||
}
|
||
}
|
||
|
||
/// Zero values.
|
||
pub trait Zero: ConstantTimeEq + Sized {
|
||
/// The value `0`.
|
||
const ZERO: Self;
|
||
|
||
/// Determine if this value is equal to zero.
|
||
///
|
||
/// # Returns
|
||
///
|
||
/// If zero, returns `Choice(1)`. Otherwise, returns `Choice(0)`.
|
||
fn is_zero(&self) -> Choice {
|
||
self.ct_eq(&Self::ZERO)
|
||
}
|
||
}
|
||
|
||
/// Random number generation support.
|
||
#[cfg(feature = "rand_core")]
|
||
pub trait Random: Sized {
|
||
/// Generate a cryptographically secure random value.
|
||
fn random(rng: &mut impl CryptoRngCore) -> Self;
|
||
}
|
||
|
||
/// Modular random number generation support.
|
||
#[cfg(feature = "rand_core")]
|
||
pub trait RandomMod: Sized + Zero {
|
||
/// Generate a cryptographically secure random number which is less than
|
||
/// a given `modulus`.
|
||
///
|
||
/// This function uses rejection sampling, a method which produces an
|
||
/// unbiased distribution of in-range values provided the underlying
|
||
/// CSRNG is unbiased, but runs in variable-time.
|
||
///
|
||
/// The variable-time nature of the algorithm should not pose a security
|
||
/// issue so long as the underlying random number generator is truly a
|
||
/// CSRNG, where previous outputs are unrelated to subsequent
|
||
/// outputs and do not reveal information about the RNG's internal state.
|
||
fn random_mod(rng: &mut impl CryptoRngCore, modulus: &NonZero<Self>) -> Self;
|
||
}
|
||
|
||
/// Compute `self + rhs mod p`.
|
||
pub trait AddMod<Rhs = Self> {
|
||
/// Output type.
|
||
type Output;
|
||
|
||
/// Compute `self + rhs mod p`.
|
||
///
|
||
/// Assumes `self` and `rhs` are `< p`.
|
||
fn add_mod(&self, rhs: &Rhs, p: &Self) -> Self::Output;
|
||
}
|
||
|
||
/// Compute `self - rhs mod p`.
|
||
pub trait SubMod<Rhs = Self> {
|
||
/// Output type.
|
||
type Output;
|
||
|
||
/// Compute `self - rhs mod p`.
|
||
///
|
||
/// Assumes `self` and `rhs` are `< p`.
|
||
fn sub_mod(&self, rhs: &Rhs, p: &Self) -> Self::Output;
|
||
}
|
||
|
||
/// Compute `-self mod p`.
|
||
pub trait NegMod {
|
||
/// Output type.
|
||
type Output;
|
||
|
||
/// Compute `-self mod p`.
|
||
#[must_use]
|
||
fn neg_mod(&self, p: &Self) -> Self::Output;
|
||
}
|
||
|
||
/// Compute `self * rhs mod p`.
|
||
///
|
||
/// Requires `p_inv = -(p^{-1} mod 2^{BITS}) mod 2^{BITS}` to be provided for efficiency.
|
||
pub trait MulMod<Rhs = Self> {
|
||
/// Output type.
|
||
type Output;
|
||
|
||
/// Compute `self * rhs mod p`.
|
||
///
|
||
/// Requires `p_inv = -(p^{-1} mod 2^{BITS}) mod 2^{BITS}` to be provided for efficiency.
|
||
fn mul_mod(&self, rhs: &Rhs, p: &Self, p_inv: Limb) -> Self::Output;
|
||
}
|
||
|
||
/// Checked addition.
|
||
pub trait CheckedAdd<Rhs = Self>: Sized {
|
||
/// Output type.
|
||
type Output;
|
||
|
||
/// Perform checked subtraction, returning a [`CtOption`] which `is_some`
|
||
/// only if the operation did not overflow.
|
||
fn checked_add(&self, rhs: Rhs) -> CtOption<Self>;
|
||
}
|
||
|
||
/// Checked multiplication.
|
||
pub trait CheckedMul<Rhs = Self>: Sized {
|
||
/// Output type.
|
||
type Output;
|
||
|
||
/// Perform checked multiplication, returning a [`CtOption`] which `is_some`
|
||
/// only if the operation did not overflow.
|
||
fn checked_mul(&self, rhs: Rhs) -> CtOption<Self>;
|
||
}
|
||
|
||
/// Checked subtraction.
|
||
pub trait CheckedSub<Rhs = Self>: Sized {
|
||
/// Output type.
|
||
type Output;
|
||
|
||
/// Perform checked subtraction, returning a [`CtOption`] which `is_some`
|
||
/// only if the operation did not underflow.
|
||
fn checked_sub(&self, rhs: Rhs) -> CtOption<Self>;
|
||
}
|
||
|
||
/// Concatenate two numbers into a "wide" double-width value, using the `lo`
|
||
/// value as the least significant value.
|
||
pub trait Concat: ConcatMixed<Self, MixedOutput = Self::Output> {
|
||
/// Concatenated output: twice the width of `Self`.
|
||
type Output;
|
||
|
||
/// Concatenate the two halves, with `self` as most significant and `lo`
|
||
/// as the least significant.
|
||
fn concat(&self, lo: &Self) -> Self::Output {
|
||
self.concat_mixed(lo)
|
||
}
|
||
}
|
||
|
||
/// Concatenate two numbers into a "wide" combined-width value, using the `lo`
|
||
/// value as the least significant value.
|
||
pub trait ConcatMixed<Lo: ?Sized = Self> {
|
||
/// Concatenated output: combination of `Lo` and `Self`.
|
||
type MixedOutput;
|
||
|
||
/// Concatenate the two values, with `self` as most significant and `lo`
|
||
/// as the least significant.
|
||
fn concat_mixed(&self, lo: &Lo) -> Self::MixedOutput;
|
||
}
|
||
|
||
/// Split a number in half, returning the most significant half followed by
|
||
/// the least significant.
|
||
pub trait Split: SplitMixed<Self::Output, Self::Output> {
|
||
/// Split output: high/low components of the value.
|
||
type Output;
|
||
|
||
/// Split this number in half, returning its high and low components
|
||
/// respectively.
|
||
fn split(&self) -> (Self::Output, Self::Output) {
|
||
self.split_mixed()
|
||
}
|
||
}
|
||
|
||
/// Split a number into parts, returning the most significant part followed by
|
||
/// the least significant.
|
||
pub trait SplitMixed<Hi, Lo> {
|
||
/// Split this number into parts, returning its high and low components
|
||
/// respectively.
|
||
fn split_mixed(&self) -> (Hi, Lo);
|
||
}
|
||
|
||
/// Integers whose representation takes a bounded amount of space.
|
||
pub trait Bounded {
|
||
/// Size of this integer in bits.
|
||
const BITS: usize;
|
||
|
||
/// Size of this integer in bytes.
|
||
const BYTES: usize;
|
||
}
|
||
|
||
/// Encoding support.
|
||
pub trait Encoding: Sized {
|
||
/// Byte array representation.
|
||
type Repr: AsRef<[u8]> + AsMut<[u8]> + Copy + Clone + Sized;
|
||
|
||
/// Decode from big endian bytes.
|
||
fn from_be_bytes(bytes: Self::Repr) -> Self;
|
||
|
||
/// Decode from little endian bytes.
|
||
fn from_le_bytes(bytes: Self::Repr) -> Self;
|
||
|
||
/// Encode to big endian bytes.
|
||
fn to_be_bytes(&self) -> Self::Repr;
|
||
|
||
/// Encode to little endian bytes.
|
||
fn to_le_bytes(&self) -> Self::Repr;
|
||
}
|
||
|
||
/// Support for optimized squaring
|
||
pub trait Square: Sized
|
||
where
|
||
for<'a> &'a Self: core::ops::Mul<&'a Self, Output = Self>,
|
||
{
|
||
/// Computes the same as `self.mul(self)`, but may be more efficient.
|
||
fn square(&self) -> Self {
|
||
self * self
|
||
}
|
||
}
|
||
|
||
/// Constant-time exponentiation.
|
||
pub trait Pow<Exponent> {
|
||
/// Raises to the `exponent` power.
|
||
fn pow(&self, exponent: &Exponent) -> Self;
|
||
}
|
||
|
||
impl<T: PowBoundedExp<Exponent>, Exponent: Bounded> Pow<Exponent> for T {
|
||
fn pow(&self, exponent: &Exponent) -> Self {
|
||
self.pow_bounded_exp(exponent, Exponent::BITS)
|
||
}
|
||
}
|
||
|
||
/// Constant-time exponentiation with exponent of a bounded bit size.
|
||
pub trait PowBoundedExp<Exponent> {
|
||
/// Raises to the `exponent` power,
|
||
/// with `exponent_bits` representing the number of (least significant) bits
|
||
/// to take into account for the exponent.
|
||
///
|
||
/// NOTE: `exponent_bits` may be leaked in the time pattern.
|
||
fn pow_bounded_exp(&self, exponent: &Exponent, exponent_bits: usize) -> Self;
|
||
}
|
||
|
||
/// Performs modular multi-exponentiation using Montgomery's ladder.
|
||
///
|
||
/// See: Straus, E. G. Problems and solutions: Addition chains of vectors. American Mathematical Monthly 71 (1964), 806–808.
|
||
pub trait MultiExponentiate<Exponent, BasesAndExponents>: Pow<Exponent> + Sized
|
||
where
|
||
BasesAndExponents: AsRef<[(Self, Exponent)]> + ?Sized,
|
||
{
|
||
/// Calculates `x1 ^ k1 * ... * xn ^ kn`.
|
||
fn multi_exponentiate(bases_and_exponents: &BasesAndExponents) -> Self;
|
||
}
|
||
|
||
impl<T, Exponent, BasesAndExponents> MultiExponentiate<Exponent, BasesAndExponents> for T
|
||
where
|
||
T: MultiExponentiateBoundedExp<Exponent, BasesAndExponents>,
|
||
Exponent: Bounded,
|
||
BasesAndExponents: AsRef<[(Self, Exponent)]> + ?Sized,
|
||
{
|
||
fn multi_exponentiate(bases_and_exponents: &BasesAndExponents) -> Self {
|
||
Self::multi_exponentiate_bounded_exp(bases_and_exponents, Exponent::BITS)
|
||
}
|
||
}
|
||
|
||
/// Performs modular multi-exponentiation using Montgomery's ladder.
|
||
/// `exponent_bits` represents the number of bits to take into account for the exponent.
|
||
///
|
||
/// See: Straus, E. G. Problems and solutions: Addition chains of vectors. American Mathematical Monthly 71 (1964), 806–808.
|
||
///
|
||
/// NOTE: this value is leaked in the time pattern.
|
||
pub trait MultiExponentiateBoundedExp<Exponent, BasesAndExponents>: Pow<Exponent> + Sized
|
||
where
|
||
BasesAndExponents: AsRef<[(Self, Exponent)]> + ?Sized,
|
||
{
|
||
/// Calculates `x1 ^ k1 * ... * xn ^ kn`.
|
||
fn multi_exponentiate_bounded_exp(
|
||
bases_and_exponents: &BasesAndExponents,
|
||
exponent_bits: usize,
|
||
) -> Self;
|
||
}
|
||
|
||
/// Constant-time inversion.
|
||
pub trait Invert: Sized {
|
||
/// Output of the inversion.
|
||
type Output;
|
||
|
||
/// Computes the inverse.
|
||
fn invert(&self) -> Self::Output;
|
||
}
|