2022-06-28 08:02:56 +00:00
|
|
|
#![no_std]
|
|
|
|
|
2022-04-22 01:36:18 +00:00
|
|
|
use core::{
|
|
|
|
ops::{Deref, Add, AddAssign, Sub, SubAssign, Neg, Mul, MulAssign},
|
|
|
|
borrow::Borrow,
|
|
|
|
iter::{Iterator, Sum}
|
|
|
|
};
|
|
|
|
|
|
|
|
use rand_core::RngCore;
|
2022-04-27 04:09:05 +00:00
|
|
|
use digest::{consts::U64, Digest};
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-04-23 07:49:30 +00:00
|
|
|
use subtle::{Choice, CtOption, ConstantTimeEq, ConditionallySelectable};
|
2022-04-22 01:36:18 +00:00
|
|
|
|
|
|
|
pub use curve25519_dalek as dalek;
|
|
|
|
|
|
|
|
use dalek::{
|
|
|
|
constants,
|
2022-06-03 19:35:42 +00:00
|
|
|
traits::Identity,
|
2022-04-22 01:36:18 +00:00
|
|
|
scalar::Scalar as DScalar,
|
|
|
|
edwards::{
|
2022-06-06 08:22:49 +00:00
|
|
|
EdwardsPoint as DEdwardsPoint,
|
|
|
|
EdwardsBasepointTable as DEdwardsBasepointTable,
|
|
|
|
CompressedEdwardsY as DCompressedEdwards
|
|
|
|
},
|
|
|
|
ristretto::{
|
|
|
|
RistrettoPoint as DRistrettoPoint,
|
|
|
|
RistrettoBasepointTable as DRistrettoBasepointTable,
|
|
|
|
CompressedRistretto as DCompressedRistretto
|
2022-04-22 01:36:18 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-06-30 07:17:15 +00:00
|
|
|
use ff::{Field, PrimeField, FieldBits, PrimeFieldBits};
|
|
|
|
use group::{Group, GroupEncoding, prime::PrimeGroup};
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-07-09 06:01:22 +00:00
|
|
|
// Convert a boolean to a Choice in a *presumably* constant time manner
|
2022-07-08 19:30:56 +00:00
|
|
|
fn choice(value: bool) -> Choice {
|
|
|
|
let bit = value as u8;
|
|
|
|
debug_assert_eq!(bit | 1, 1);
|
|
|
|
Choice::from(bit)
|
|
|
|
}
|
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
macro_rules! deref_borrow {
|
|
|
|
($Source: ident, $Target: ident) => {
|
|
|
|
impl Deref for $Source {
|
|
|
|
type Target = $Target;
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
impl Borrow<$Target> for $Source {
|
|
|
|
fn borrow(&self) -> &$Target {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
impl Borrow<$Target> for &$Source {
|
|
|
|
fn borrow(&self) -> &$Target {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
2022-04-22 01:36:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
macro_rules! math {
|
|
|
|
($Value: ident, $Factor: ident, $Product: ident) => {
|
|
|
|
impl Add<$Value> for $Value {
|
|
|
|
type Output = Self;
|
|
|
|
fn add(self, other: $Value) -> Self::Output { Self(self.0 + other.0) }
|
|
|
|
}
|
|
|
|
impl AddAssign for $Value {
|
|
|
|
fn add_assign(&mut self, other: $Value) { self.0 += other.0 }
|
|
|
|
}
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
impl<'a> Add<&'a $Value> for $Value {
|
|
|
|
type Output = Self;
|
|
|
|
fn add(self, other: &'a $Value) -> Self::Output { Self(self.0 + other.0) }
|
|
|
|
}
|
|
|
|
impl<'a> AddAssign<&'a $Value> for $Value {
|
|
|
|
fn add_assign(&mut self, other: &'a $Value) { self.0 += other.0 }
|
|
|
|
}
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
impl Sub<$Value> for $Value {
|
|
|
|
type Output = Self;
|
|
|
|
fn sub(self, other: $Value) -> Self::Output { Self(self.0 - other.0) }
|
|
|
|
}
|
|
|
|
impl SubAssign for $Value {
|
|
|
|
fn sub_assign(&mut self, other: $Value) { self.0 -= other.0 }
|
|
|
|
}
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
impl<'a> Sub<&'a $Value> for $Value {
|
|
|
|
type Output = Self;
|
|
|
|
fn sub(self, other: &'a $Value) -> Self::Output { Self(self.0 - other.0) }
|
|
|
|
}
|
|
|
|
impl<'a> SubAssign<&'a $Value> for $Value {
|
|
|
|
fn sub_assign(&mut self, other: &'a $Value) { self.0 -= other.0 }
|
|
|
|
}
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
impl Neg for $Value {
|
|
|
|
type Output = Self;
|
|
|
|
fn neg(self) -> Self::Output { Self(-self.0) }
|
|
|
|
}
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
impl Mul<$Factor> for $Value {
|
|
|
|
type Output = $Product;
|
|
|
|
fn mul(self, other: $Factor) -> Self::Output { Self(self.0 * other.0) }
|
|
|
|
}
|
|
|
|
impl MulAssign<$Factor> for $Value {
|
|
|
|
fn mul_assign(&mut self, other: $Factor) { self.0 *= other.0 }
|
|
|
|
}
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
impl<'a> Mul<&'a $Factor> for $Value {
|
|
|
|
type Output = Self;
|
|
|
|
fn mul(self, b: &'a $Factor) -> $Product { Self(b.0 * self.0) }
|
|
|
|
}
|
|
|
|
impl<'a> MulAssign<&'a $Factor> for $Value {
|
|
|
|
fn mul_assign(&mut self, other: &'a $Factor) { self.0 *= other.0 }
|
|
|
|
}
|
|
|
|
}
|
2022-04-22 01:36:18 +00:00
|
|
|
}
|
|
|
|
|
2022-07-09 06:01:22 +00:00
|
|
|
/// Wrapper around the dalek Scalar type
|
2022-06-06 08:22:49 +00:00
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
|
|
|
|
pub struct Scalar(pub DScalar);
|
|
|
|
deref_borrow!(Scalar, DScalar);
|
|
|
|
math!(Scalar, Scalar, Scalar);
|
|
|
|
|
|
|
|
impl Scalar {
|
2022-07-09 06:01:22 +00:00
|
|
|
/// Perform wide reduction on a 64-byte array to create a Scalar without bias
|
2022-06-06 08:22:49 +00:00
|
|
|
pub fn from_bytes_mod_order_wide(bytes: &[u8; 64]) -> Scalar {
|
|
|
|
Self(DScalar::from_bytes_mod_order_wide(bytes))
|
|
|
|
}
|
|
|
|
|
2022-07-09 06:01:22 +00:00
|
|
|
/// Derive a Scalar without bias from a digest via wide reduction
|
2022-06-06 08:22:49 +00:00
|
|
|
pub fn from_hash<D: Digest<OutputSize = U64>>(hash: D) -> Scalar {
|
|
|
|
let mut output = [0u8; 64];
|
|
|
|
output.copy_from_slice(&hash.finalize());
|
|
|
|
Scalar(DScalar::from_bytes_mod_order_wide(&output))
|
|
|
|
}
|
2022-04-22 01:36:18 +00:00
|
|
|
}
|
|
|
|
|
2022-04-23 07:49:30 +00:00
|
|
|
impl ConstantTimeEq for Scalar {
|
2022-06-03 19:35:42 +00:00
|
|
|
fn ct_eq(&self, other: &Self) -> Choice { self.0.ct_eq(&other.0) }
|
2022-04-23 07:49:30 +00:00
|
|
|
}
|
|
|
|
|
2022-04-22 01:36:18 +00:00
|
|
|
impl ConditionallySelectable for Scalar {
|
2022-06-03 19:35:42 +00:00
|
|
|
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
|
|
|
|
Scalar(DScalar::conditional_select(a, b, choice))
|
|
|
|
}
|
2022-04-22 01:36:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Field for Scalar {
|
|
|
|
fn random(mut rng: impl RngCore) -> Self {
|
|
|
|
let mut r = [0; 64];
|
|
|
|
rng.fill_bytes(&mut r);
|
|
|
|
Self(DScalar::from_bytes_mod_order_wide(&r))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn zero() -> Self { Self(DScalar::zero()) }
|
|
|
|
fn one() -> Self { Self(DScalar::one()) }
|
|
|
|
fn square(&self) -> Self { *self * self }
|
|
|
|
fn double(&self) -> Self { *self + self }
|
2022-05-03 12:49:46 +00:00
|
|
|
fn invert(&self) -> CtOption<Self> {
|
2022-07-08 20:05:17 +00:00
|
|
|
CtOption::new(Self(self.0.invert()), !self.is_zero())
|
2022-05-03 12:49:46 +00:00
|
|
|
}
|
2022-04-22 01:36:18 +00:00
|
|
|
fn sqrt(&self) -> CtOption<Self> { unimplemented!() }
|
2022-06-03 19:35:42 +00:00
|
|
|
fn is_zero(&self) -> Choice { self.0.ct_eq(&DScalar::zero()) }
|
2022-04-22 01:36:18 +00:00
|
|
|
fn cube(&self) -> Self { *self * self * self }
|
|
|
|
fn pow_vartime<S: AsRef<[u64]>>(&self, _exp: S) -> Self { unimplemented!() }
|
|
|
|
}
|
|
|
|
|
2022-07-09 06:01:22 +00:00
|
|
|
impl From<u8> for Scalar {
|
|
|
|
fn from(a: u8) -> Scalar { Self(DScalar::from(a)) }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<u16> for Scalar {
|
|
|
|
fn from(a: u16) -> Scalar { Self(DScalar::from(a)) }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<u32> for Scalar {
|
|
|
|
fn from(a: u32) -> Scalar { Self(DScalar::from(a)) }
|
|
|
|
}
|
|
|
|
|
2022-04-22 01:36:18 +00:00
|
|
|
impl From<u64> for Scalar {
|
|
|
|
fn from(a: u64) -> Scalar { Self(DScalar::from(a)) }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PrimeField for Scalar {
|
|
|
|
type Repr = [u8; 32];
|
|
|
|
const NUM_BITS: u32 = 253;
|
|
|
|
const CAPACITY: u32 = 252;
|
2022-04-23 07:49:30 +00:00
|
|
|
fn from_repr(bytes: [u8; 32]) -> CtOption<Self> {
|
2022-07-08 19:30:56 +00:00
|
|
|
let scalar = DScalar::from_canonical_bytes(bytes);
|
|
|
|
// TODO: This unwrap_or isn't constant time, yet do we have an alternative?
|
|
|
|
CtOption::new(Scalar(scalar.unwrap_or(DScalar::zero())), choice(scalar.is_some()))
|
2022-04-23 07:49:30 +00:00
|
|
|
}
|
2022-04-22 01:36:18 +00:00
|
|
|
fn to_repr(&self) -> [u8; 32] { self.0.to_bytes() }
|
|
|
|
|
2022-06-03 19:35:42 +00:00
|
|
|
const S: u32 = 2;
|
2022-04-23 07:49:30 +00:00
|
|
|
fn is_odd(&self) -> Choice { unimplemented!() }
|
2022-06-03 19:35:42 +00:00
|
|
|
fn multiplicative_generator() -> Self { 2u64.into() }
|
2022-04-22 01:36:18 +00:00
|
|
|
fn root_of_unity() -> Self { unimplemented!() }
|
|
|
|
}
|
|
|
|
|
2022-06-30 07:17:15 +00:00
|
|
|
impl PrimeFieldBits for Scalar {
|
|
|
|
type ReprBits = [u8; 32];
|
|
|
|
|
|
|
|
fn to_le_bits(&self) -> FieldBits<Self::ReprBits> {
|
|
|
|
self.to_repr().into()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn char_le_bits() -> FieldBits<Self::ReprBits> {
|
|
|
|
let mut bytes = (Scalar::zero() - Scalar::one()).to_repr();
|
|
|
|
bytes[0] += 1;
|
2022-07-09 06:01:22 +00:00
|
|
|
debug_assert_eq!(DScalar::from_bytes_mod_order(bytes), DScalar::zero());
|
2022-06-30 07:17:15 +00:00
|
|
|
bytes.into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
macro_rules! dalek_group {
|
|
|
|
(
|
|
|
|
$Point: ident,
|
|
|
|
$DPoint: ident,
|
2022-06-28 05:25:26 +00:00
|
|
|
$torsion_free: expr,
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
$Table: ident,
|
|
|
|
$DTable: ident,
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
$DCompressed: ident,
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
$BASEPOINT_POINT: ident,
|
|
|
|
$BASEPOINT_TABLE: ident
|
|
|
|
) => {
|
2022-07-09 06:01:22 +00:00
|
|
|
/// Wrapper around the dalek Point type. For Ed25519, this is restricted to the prime subgroup
|
2022-06-06 08:22:49 +00:00
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
|
|
pub struct $Point(pub $DPoint);
|
|
|
|
deref_borrow!($Point, $DPoint);
|
|
|
|
math!($Point, Scalar, $Point);
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
pub const $BASEPOINT_POINT: $Point = $Point(constants::$BASEPOINT_POINT);
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
impl Sum<$Point> for $Point {
|
|
|
|
fn sum<I: Iterator<Item = $Point>>(iter: I) -> $Point { Self($DPoint::sum(iter)) }
|
|
|
|
}
|
|
|
|
impl<'a> Sum<&'a $Point> for $Point {
|
|
|
|
fn sum<I: Iterator<Item = &'a $Point>>(iter: I) -> $Point { Self($DPoint::sum(iter)) }
|
|
|
|
}
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
impl Group for $Point {
|
|
|
|
type Scalar = Scalar;
|
2022-07-08 19:30:56 +00:00
|
|
|
// Ideally, this would be cryptographically secure, yet that's not a bound on the trait
|
|
|
|
// k256 also does this
|
2022-06-06 08:22:49 +00:00
|
|
|
fn random(rng: impl RngCore) -> Self { &$BASEPOINT_TABLE * Scalar::random(rng) }
|
|
|
|
fn identity() -> Self { Self($DPoint::identity()) }
|
|
|
|
fn generator() -> Self { $BASEPOINT_POINT }
|
|
|
|
fn is_identity(&self) -> Choice { self.0.ct_eq(&$DPoint::identity()) }
|
|
|
|
fn double(&self) -> Self { *self + self }
|
|
|
|
}
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-28 05:25:26 +00:00
|
|
|
impl GroupEncoding for $Point {
|
|
|
|
type Repr = [u8; 32];
|
|
|
|
|
|
|
|
fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
|
2022-07-08 19:30:56 +00:00
|
|
|
let decompressed = $DCompressed(*bytes).decompress();
|
|
|
|
// TODO: Same note on unwrap_or as above
|
|
|
|
let point = decompressed.unwrap_or($DPoint::identity());
|
|
|
|
CtOption::new($Point(point), choice(decompressed.is_some()) & choice($torsion_free(point)))
|
2022-06-28 05:25:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
|
|
|
|
$Point::from_bytes(bytes)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_bytes(&self) -> Self::Repr {
|
|
|
|
self.0.compress().to_bytes()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PrimeGroup for $Point {}
|
|
|
|
|
2022-07-09 06:01:22 +00:00
|
|
|
/// Wrapper around the dalek Table type, offering efficient multiplication against the
|
|
|
|
/// basepoint
|
2022-06-06 08:22:49 +00:00
|
|
|
pub struct $Table(pub $DTable);
|
|
|
|
deref_borrow!($Table, $DTable);
|
|
|
|
pub const $BASEPOINT_TABLE: $Table = $Table(constants::$BASEPOINT_TABLE);
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
impl Mul<Scalar> for &$Table {
|
|
|
|
type Output = $Point;
|
|
|
|
fn mul(self, b: Scalar) -> $Point { $Point(&b.0 * &self.0) }
|
|
|
|
}
|
|
|
|
};
|
2022-04-22 01:36:18 +00:00
|
|
|
}
|
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
dalek_group!(
|
|
|
|
EdwardsPoint,
|
|
|
|
DEdwardsPoint,
|
2022-06-28 05:25:26 +00:00
|
|
|
|point: DEdwardsPoint| point.is_torsion_free(),
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
EdwardsBasepointTable,
|
|
|
|
DEdwardsBasepointTable,
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
DCompressedEdwards,
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
ED25519_BASEPOINT_POINT,
|
|
|
|
ED25519_BASEPOINT_TABLE
|
|
|
|
);
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
dalek_group!(
|
|
|
|
RistrettoPoint,
|
|
|
|
DRistrettoPoint,
|
2022-06-28 05:25:26 +00:00
|
|
|
|_| true,
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
RistrettoBasepointTable,
|
|
|
|
DRistrettoBasepointTable,
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
DCompressedRistretto,
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-06-06 08:22:49 +00:00
|
|
|
RISTRETTO_BASEPOINT_POINT,
|
|
|
|
RISTRETTO_BASEPOINT_TABLE
|
|
|
|
);
|