use crate::*;
use core::fmt::{Display, Formatter, Result as FmtResult};
use core::iter::{Product, Sum};
use core::ops::{
Add, AddAssign, Index, IndexMut, Mul, MulAssign, Neg, Shr, ShrAssign, Sub, SubAssign,
};
use crypto_bigint::{Encoding, Zero};
use elliptic_curve::{
bigint::{Limb, NonZero, U448, U704, U896},
ff::{helpers, Field, FieldBits, PrimeFieldBits},
generic_array::{
typenum::{U114, U57, U84, U88},
GenericArray as Array,
},
hash2curve::{ExpandMsg, Expander, FromOkm},
ops::{Invert, Reduce, ReduceNonZero},
scalar::{FromUintUnchecked, IsHigh, ScalarPrimitive},
PrimeField,
};
use rand_core::{CryptoRng, RngCore};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, CtOption};
#[derive(Debug, Copy, Clone, PartialOrd, Ord)]
pub struct Scalar(pub(crate) U448);
pub type ScalarBytes = Array<u8, U57>;
pub type WideScalarBytes = Array<u8, U114>;
pub const ORDER: U448 = U448::from_be_hex("3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3");
pub const NZ_ORDER: NonZero<U448> = NonZero::<U448>::const_new(ORDER).0;
const ORDER_MINUS_ONE: U448 = ORDER.wrapping_sub(&U448::ONE);
const HALF_ORDER: U448 = ORDER.shr_vartime(1);
pub const WIDE_ORDER: U896 = U896::from_be_hex("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3");
const WIDE_ORDER_MINUS_ONE: U896 = WIDE_ORDER.wrapping_sub(&U896::ONE);
pub const MODULUS_LIMBS: [u32; 14] = [
0xab5844f3, 0x2378c292, 0x8dc58f55, 0x216cc272, 0xaed63690, 0xc44edb49, 0x7cca23e9, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3fffffff,
];
impl Display for Scalar {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
let bytes = self.to_bytes_rfc_8032();
for b in &bytes {
write!(f, "{:02x}", b)?;
}
Ok(())
}
}
impl ConstantTimeEq for Scalar {
fn ct_eq(&self, other: &Self) -> Choice {
self.to_bytes().ct_eq(&other.to_bytes())
}
}
impl ConditionallySelectable for Scalar {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Self(U448::conditional_select(&a.0, &b.0, choice))
}
}
impl PartialEq for Scalar {
fn eq(&self, other: &Scalar) -> bool {
self.ct_eq(other).into()
}
}
impl Eq for Scalar {}
impl From<u8> for Scalar {
fn from(a: u8) -> Self {
Scalar(U448::from_u8(a))
}
}
impl From<u16> for Scalar {
fn from(a: u16) -> Self {
Scalar(U448::from_u16(a))
}
}
impl From<u32> for Scalar {
fn from(a: u32) -> Scalar {
Scalar(U448::from_u32(a))
}
}
impl From<u64> for Scalar {
fn from(a: u64) -> Self {
Scalar(U448::from_u64(a))
}
}
impl From<u128> for Scalar {
fn from(a: u128) -> Self {
Scalar(U448::from_u128(a))
}
}
impl Index<usize> for Scalar {
type Output = crypto_bigint::Word;
fn index(&self, index: usize) -> &Self::Output {
&self.0.as_words()[index]
}
}
impl IndexMut<usize> for Scalar {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.0.as_words_mut()[index]
}
}
impl Add<&Scalar> for &Scalar {
type Output = Scalar;
fn add(self, rhs: &Scalar) -> Self::Output {
self.addition(rhs)
}
}
define_add_variants!(LHS = Scalar, RHS = Scalar, Output = Scalar);
impl AddAssign for Scalar {
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs
}
}
impl AddAssign<&Scalar> for Scalar {
fn add_assign(&mut self, rhs: &Scalar) {
*self = *self + rhs
}
}
impl Mul<&Scalar> for &Scalar {
type Output = Scalar;
fn mul(self, rhs: &Scalar) -> Self::Output {
self.multiply(rhs)
}
}
define_mul_variants!(LHS = Scalar, RHS = Scalar, Output = Scalar);
impl MulAssign for Scalar {
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs
}
}
impl MulAssign<&Scalar> for Scalar {
fn mul_assign(&mut self, rhs: &Scalar) {
*self = *self * rhs
}
}
impl Sub<&Scalar> for &Scalar {
type Output = Scalar;
fn sub(self, rhs: &Scalar) -> Self::Output {
self.subtract(rhs)
}
}
define_sub_variants!(LHS = Scalar, RHS = Scalar, Output = Scalar);
impl SubAssign for Scalar {
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs
}
}
impl SubAssign<&Scalar> for Scalar {
fn sub_assign(&mut self, rhs: &Scalar) {
*self = *self - rhs
}
}
impl Neg for Scalar {
type Output = Scalar;
fn neg(self) -> Self::Output {
-&self
}
}
impl Neg for &Scalar {
type Output = Scalar;
fn neg(self) -> Self::Output {
Scalar::ZERO - self
}
}
impl Default for Scalar {
fn default() -> Scalar {
Scalar::ZERO
}
}
impl Sum for Scalar {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
let mut acc = Scalar::ZERO;
for s in iter {
acc += s;
}
acc
}
}
impl<'a> Sum<&'a Scalar> for Scalar {
fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
let mut acc = Scalar::ZERO;
for s in iter {
acc += s;
}
acc
}
}
impl Product for Scalar {
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
let mut acc = Scalar::ONE;
for s in iter {
acc *= s;
}
acc
}
}
impl<'a> Product<&'a Scalar> for Scalar {
fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
let mut acc = Scalar::ONE;
for s in iter {
acc *= s;
}
acc
}
}
impl Field for Scalar {
const ZERO: Self = Self::ZERO;
const ONE: Self = Self::ONE;
fn random(mut rng: impl RngCore) -> Self {
let mut seed = WideScalarBytes::default();
rng.fill_bytes(&mut seed);
Scalar::from_bytes_mod_order_wide(&seed)
}
fn square(&self) -> Self {
self.square()
}
fn double(&self) -> Self {
self + self
}
fn invert(&self) -> CtOption<Self> {
CtOption::new(self.invert(), !self.ct_eq(&Self::ZERO))
}
fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
helpers::sqrt_ratio_generic(num, div)
}
}
impl PrimeField for Scalar {
type Repr = ScalarBytes;
fn from_repr(repr: Self::Repr) -> CtOption<Self> {
Self::from_canonical_bytes(&repr)
}
fn to_repr(&self) -> Self::Repr {
self.to_bytes_rfc_8032()
}
fn is_odd(&self) -> Choice {
Choice::from((self.0.to_words()[0] & 1) as u8)
}
const MODULUS: &'static str = "3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3";
const NUM_BITS: u32 = 448;
const CAPACITY: u32 = Self::NUM_BITS - 1;
const TWO_INV: Self = Self(U448::from_be_hex("1fffffffffffffffffffffffffffffffffffffffffffffffffffffffbe6511f4e2276da4d76b1b4810b6613946e2c7aa91bc614955ac227a"));
const MULTIPLICATIVE_GENERATOR: Self = Self(U448::from_u8(7));
const S: u32 = 1;
const ROOT_OF_UNITY: Self = Self(U448::from_be_hex("3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f2"));
const ROOT_OF_UNITY_INV: Self = Self(U448::from_be_hex("3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f2"));
const DELTA: Self = Self(U448::from_u8(49));
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl From<Scalar> for Vec<u8> {
fn from(scalar: Scalar) -> Vec<u8> {
Self::from(&scalar)
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl From<&Scalar> for Vec<u8> {
fn from(scalar: &Scalar) -> Vec<u8> {
scalar.to_bytes_rfc_8032().to_vec()
}
}
impl From<Scalar> for ScalarBytes {
fn from(scalar: Scalar) -> ScalarBytes {
Self::from(&scalar)
}
}
impl From<&Scalar> for ScalarBytes {
fn from(scalar: &Scalar) -> ScalarBytes {
scalar.to_bytes_rfc_8032()
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl TryFrom<Vec<u8>> for Scalar {
type Error = &'static str;
fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
Self::try_from(&bytes[..])
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl TryFrom<&Vec<u8>> for Scalar {
type Error = &'static str;
fn try_from(bytes: &Vec<u8>) -> Result<Self, Self::Error> {
Self::try_from(&bytes[..])
}
}
impl TryFrom<&[u8]> for Scalar {
type Error = &'static str;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
if bytes.len() != 57 {
return Err("invalid byte length");
}
let scalar_bytes = ScalarBytes::from_slice(bytes);
Option::<Scalar>::from(Scalar::from_canonical_bytes(scalar_bytes))
.ok_or("scalar was not canonically encoded")
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl TryFrom<Box<[u8]>> for Scalar {
type Error = &'static str;
fn try_from(bytes: Box<[u8]>) -> Result<Self, Self::Error> {
Self::try_from(bytes.as_ref())
}
}
#[cfg(feature = "serde")]
impl serdect::serde::Serialize for Scalar {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
S: serdect::serde::Serializer,
{
serdect::slice::serialize_hex_lower_or_bin(&self.to_bytes(), s)
}
}
#[cfg(feature = "serde")]
impl<'de> serdect::serde::Deserialize<'de> for Scalar {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
where
D: serdect::serde::Deserializer<'de>,
{
let mut buffer = ScalarBytes::default();
serdect::array::deserialize_hex_or_bin(&mut buffer[..56], d)?;
Option::from(Self::from_canonical_bytes(&buffer)).ok_or(serdect::serde::de::Error::custom(
"scalar was not canonically encoded",
))
}
}
#[cfg(feature = "zeroize")]
impl zeroize::DefaultIsZeroes for Scalar {}
impl core::fmt::LowerHex for Scalar {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
let tmp = self.to_bytes_rfc_8032();
for &b in tmp.iter() {
write!(f, "{:02x}", b)?;
}
Ok(())
}
}
impl core::fmt::UpperHex for Scalar {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
let tmp = self.to_bytes_rfc_8032();
for &b in tmp.iter() {
write!(f, "{:02X}", b)?;
}
Ok(())
}
}
impl FromOkm for Scalar {
type Length = U84;
fn from_okm(data: &Array<u8, Self::Length>) -> Self {
const SEMI_WIDE_MODULUS: NonZero<U704> = NonZero::<U704>::const_new(U704::from_be_hex("00000000000000000000000000000000000000000000000000000000000000003fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3")).0;
let mut tmp = Array::<u8, U88>::default();
tmp[4..].copy_from_slice(&data[..]);
let mut num = U704::from_be_slice(&tmp[..]);
num %= SEMI_WIDE_MODULUS;
let mut words = [0; U448::LIMBS];
words.copy_from_slice(&num.to_words()[..U448::LIMBS]);
Scalar(U448::from_words(words))
}
}
impl Reduce<U448> for Scalar {
type Bytes = ScalarBytes;
fn reduce(bytes: U448) -> Self {
let (r, underflow) = bytes.sbb(&ORDER, Limb::ZERO);
let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8);
Self(U448::conditional_select(&bytes, &r, !underflow))
}
fn reduce_bytes(bytes: &Self::Bytes) -> Self {
Self::reduce(U448::from_le_slice(bytes))
}
}
impl Reduce<U896> for Scalar {
type Bytes = WideScalarBytes;
fn reduce(bytes: U896) -> Self {
let (r, underflow) = bytes.sbb(&WIDE_ORDER, Limb::ZERO);
let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8);
Self(U896::conditional_select(&bytes, &r, !underflow).split().1)
}
fn reduce_bytes(bytes: &Self::Bytes) -> Self {
Self::from_bytes_mod_order_wide(bytes)
}
}
impl ReduceNonZero<U448> for Scalar {
fn reduce_nonzero(bytes: U448) -> Self {
let (r, underflow) = bytes.sbb(&ORDER_MINUS_ONE, Limb::ZERO);
let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8);
Self(U448::conditional_select(&bytes, &r, !underflow).wrapping_add(&U448::ONE))
}
fn reduce_nonzero_bytes(bytes: &Self::Bytes) -> Self {
Self::reduce_nonzero(U448::from_le_slice(bytes))
}
}
impl ReduceNonZero<U896> for Scalar {
fn reduce_nonzero(bytes: U896) -> Self {
let (r, underflow) = bytes.sbb(&WIDE_ORDER_MINUS_ONE, Limb::ZERO);
let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8);
Self(
U896::conditional_select(&bytes, &r, !underflow)
.split()
.1
.wrapping_add(&U448::ONE),
)
}
fn reduce_nonzero_bytes(bytes: &Self::Bytes) -> Self {
Self::reduce_nonzero(U896::from_le_slice(bytes))
}
}
impl PrimeFieldBits for Scalar {
type ReprBits = [crypto_bigint::Word; U448::LIMBS];
fn to_le_bits(&self) -> FieldBits<Self::ReprBits> {
self.0.to_words().into()
}
fn char_le_bits() -> FieldBits<Self::ReprBits> {
ORDER.to_words().into()
}
}
impl From<ScalarPrimitive<Ed448>> for Scalar {
fn from(scalar: ScalarPrimitive<Ed448>) -> Self {
Self(*scalar.as_uint())
}
}
impl From<&ScalarPrimitive<Ed448>> for Scalar {
fn from(scalar: &ScalarPrimitive<Ed448>) -> Self {
let uint = *scalar.as_uint();
uint.into()
}
}
impl From<Scalar> for ScalarPrimitive<Ed448> {
fn from(scalar: Scalar) -> Self {
let uint: U448 = scalar.into();
Self::from_uint_unchecked(uint)
}
}
impl From<&Scalar> for ScalarPrimitive<Ed448> {
fn from(scalar: &Scalar) -> Self {
let uint: U448 = scalar.into();
ScalarPrimitive::from_uint_unchecked(uint)
}
}
impl From<ScalarPrimitive<Decaf448>> for Scalar {
fn from(scalar: ScalarPrimitive<Decaf448>) -> Self {
Self(*scalar.as_uint())
}
}
impl From<&ScalarPrimitive<Decaf448>> for Scalar {
fn from(scalar: &ScalarPrimitive<Decaf448>) -> Self {
let uint = *scalar.as_uint();
uint.into()
}
}
impl From<Scalar> for ScalarPrimitive<Decaf448> {
fn from(scalar: Scalar) -> Self {
let uint: U448 = scalar.into();
Self::from_uint_unchecked(uint)
}
}
impl From<&Scalar> for ScalarPrimitive<Decaf448> {
fn from(scalar: &Scalar) -> Self {
let uint: U448 = scalar.into();
ScalarPrimitive::from_uint_unchecked(uint)
}
}
impl From<U448> for Scalar {
fn from(uint: U448) -> Self {
<Self as Reduce<U448>>::reduce(uint)
}
}
impl From<&U448> for Scalar {
fn from(uint: &U448) -> Self {
Self::from(*uint)
}
}
impl From<Scalar> for U448 {
fn from(scalar: Scalar) -> Self {
scalar.0
}
}
impl From<&Scalar> for U448 {
fn from(scalar: &Scalar) -> Self {
Self::from(*scalar)
}
}
impl FromUintUnchecked for Scalar {
type Uint = U448;
fn from_uint_unchecked(uint: U448) -> Self {
Self(uint)
}
}
impl Invert for Scalar {
type Output = CtOption<Self>;
fn invert(&self) -> CtOption<Self> {
CtOption::new(self.invert(), !self.ct_eq(&Self::ZERO))
}
}
impl IsHigh for Scalar {
fn is_high(&self) -> Choice {
self.0.ct_gt(&HALF_ORDER)
}
}
impl AsRef<Scalar> for Scalar {
fn as_ref(&self) -> &Scalar {
self
}
}
impl Shr<usize> for Scalar {
type Output = Self;
fn shr(self, rhs: usize) -> Self::Output {
let mut cp = self;
cp.shr_assign(rhs);
cp
}
}
impl Shr<usize> for &Scalar {
type Output = Scalar;
fn shr(self, rhs: usize) -> Self::Output {
let mut cp = *self;
cp.shr_assign(rhs);
cp
}
}
impl ShrAssign<usize> for Scalar {
fn shr_assign(&mut self, shift: usize) {
self.0 >>= shift;
}
}
#[cfg(feature = "zeroize")]
impl From<&Scalar> for Ed448ScalarBits {
fn from(scalar: &Scalar) -> Self {
scalar.0.to_words().into()
}
}
impl Scalar {
pub const ONE: Scalar = Scalar(U448::ONE);
pub const TWO: Scalar = Scalar(U448::from_u8(2));
pub const ZERO: Scalar = Scalar(U448::ZERO);
pub const fn addition(&self, rhs: &Self) -> Self {
Self(self.0.add_mod(&rhs.0, &ORDER))
}
pub const fn double(&self) -> Self {
self.addition(self)
}
pub const fn subtract(&self, rhs: &Self) -> Self {
Self(self.0.sub_mod(&rhs.0, &ORDER))
}
pub const fn multiply(&self, rhs: &Self) -> Self {
let wide_value = self.0.mul_wide(&rhs.0);
Self(U448::const_rem_wide(wide_value, &ORDER).0)
}
pub const fn square(&self) -> Self {
let value = self.0.square_wide();
Self(U448::const_rem_wide(value, &ORDER).0)
}
pub fn is_zero(&self) -> Choice {
self.0.is_zero()
}
pub(crate) fn div_by_four(&mut self) {
self.0 >>= 2;
}
pub(crate) fn to_radix_16(self) -> [i8; 113] {
let bytes = self.to_bytes();
let mut output = [0i8; 113];
#[inline(always)]
fn bot_half(x: u8) -> u8 {
x & 15
}
#[inline(always)]
fn top_half(x: u8) -> u8 {
(x >> 4) & 15
}
for i in 0..56 {
output[2 * i] = bot_half(bytes[i]) as i8;
output[2 * i + 1] = top_half(bytes[i]) as i8;
}
for i in 0..112 {
let carry = (output[i] + 8) >> 4;
output[i] -= carry << 4;
output[i + 1] += carry;
}
output
}
pub fn bits(&self) -> [bool; 448] {
let mut bits = [false; 448];
let mut i = 0;
for limb in self.to_bytes().iter() {
for j in 0..8 {
bits[i] = limb & (1 << j) != 0;
i += 1;
}
}
bits
}
pub fn from_bytes(bytes: &[u8; 56]) -> Scalar {
Self(U448::from_le_slice(bytes))
}
pub fn to_bytes(&self) -> [u8; 56] {
let bytes = self.0.to_le_bytes();
let output: [u8; 56] = core::array::from_fn(|i| bytes[i]);
output
}
pub fn invert(&self) -> Self {
Self::conditional_select(
&self.exp_vartime(&[
0x2378c292ab5844f1,
0x216cc2728dc58f55,
0xc44edb49aed63690,
0xffffffff7cca23e9,
0xffffffffffffffff,
0xffffffffffffffff,
0x3fffffffffffffff,
]),
&Self::ZERO,
self.is_zero(),
)
}
pub const fn exp_vartime(&self, exp: &[u64]) -> Self {
let mut res = Self::ONE;
let mut i = exp.len();
while i > 0 {
i -= 1;
let mut j = 64;
while j > 0 {
j -= 1;
res = res.square();
if ((exp[i] >> j) & 1) == 1 {
res = res.multiply(self);
}
}
}
res
}
pub fn sqrt(&self) -> CtOption<Self> {
let ss = self.pow([
0x48de30a4aad6113d,
0x085b309ca37163d5,
0x7113b6d26bb58da4,
0xffffffffdf3288fa,
0xffffffffffffffff,
0xffffffffffffffff,
0x0fffffffffffffff,
]);
CtOption::new(ss, ss.square().ct_eq(self))
}
pub const fn halve(&self) -> Self {
Self(self.0.shr_vartime(1))
}
pub fn from_canonical_bytes(bytes: &ScalarBytes) -> CtOption<Self> {
let is_valid = is_zero(bytes[56]) | is_zero(bytes[55] >> 6);
let bytes: [u8; 56] = core::array::from_fn(|i| bytes[i]);
let candidate = Scalar::from_bytes(&bytes);
let (_, underflow) = candidate.0.sbb(&ORDER, Limb::ZERO);
let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8);
CtOption::new(candidate, underflow & is_valid)
}
pub fn to_bytes_rfc_8032(&self) -> ScalarBytes {
let mut bytes = ScalarBytes::default();
bytes[..56].copy_from_slice(&self.to_bytes());
bytes
}
pub fn from_bytes_mod_order_wide(input: &WideScalarBytes) -> Scalar {
const TOP_MULTIPLIER: U448 = U448::from_be_hex("3402a939f823b7292052bcb7e4d070af1a9cc14ba3c47c44ae17cf725ee4d8380d66de2388ea18597af32c4bc1b195d9e3539257049b9b60");
let value = (
U448::from_le_slice(&input[..56]),
U448::from_le_slice(&input[56..112]),
);
let mut top = [0u8; 56];
top[..2].copy_from_slice(&input[112..]);
let top = {
let lo_hi = U448::from_le_slice(&top).mul_wide(&TOP_MULTIPLIER);
U448::const_rem_wide(lo_hi, &ORDER).0
};
let bottom = U448::const_rem_wide(value, &NZ_ORDER).0;
Self(bottom.add_mod(&top, &ORDER))
}
pub fn from_bytes_mod_order(input: &ScalarBytes) -> Scalar {
let value = U448::from_le_slice(&input[..56]);
Self(U448::const_rem(&value, &NZ_ORDER).0)
}
pub fn random<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
let mut scalar_bytes = WideScalarBytes::default();
rng.fill_bytes(&mut scalar_bytes);
Scalar::from_bytes_mod_order_wide(&scalar_bytes)
}
pub fn hash<X>(msg: &[u8], dst: &[u8]) -> Self
where
X: for<'a> ExpandMsg<'a>,
{
let mut random_bytes = Array::<u8, U84>::default();
let dst = [dst];
let mut expander =
X::expand_message(&[msg], &dst, random_bytes.len()).expect("invalid dst");
expander.fill_bytes(&mut random_bytes);
Self::from_okm(&random_bytes)
}
}
fn is_zero(b: u8) -> Choice {
let res = b as i8;
Choice::from((((res | -res) >> 7) + 1) as u8)
}
#[cfg(test)]
mod test {
use super::*;
use hex_literal::hex;
#[test]
fn test_basic_add() {
let five = Scalar::from(5u8);
let six = Scalar::from(6u8);
assert_eq!(five + six, Scalar::from(11u8))
}
#[test]
fn test_basic_sub() {
let ten = Scalar::from(10u8);
let five = Scalar::from(5u8);
assert_eq!(ten - five, Scalar::from(5u8))
}
#[test]
fn test_basic_mul() {
let ten = Scalar::from(10u8);
let five = Scalar::from(5u8);
assert_eq!(ten * five, Scalar::from(50u8))
}
#[test]
fn test_mul() {
let a = Scalar(U448::from_be_hex(
"1e63e8073b089f0747cf8cac2c3dc2732aae8688a8fa552ba8cb0ae8c0be082e74d657641d9ac30a087b8fb97f8ed27dc96a3c35ffb823a3"
));
let b = Scalar(U448::from_be_hex(
"16c5450acae1cb680a92de2d8e59b30824e8d4991adaa0e7bc343bcbd099595b188c6b1a1e30b38b17aa6d9be416b899686eb329d8bedc42"
));
let exp = Scalar(U448::from_be_hex(
"31e055c14ca389edfccd61b3203d424bb9036ff6f2d89c1e07bcd93174e9335f36a1492008a3a0e46abd26f5994c9c2b1f5b3197a18d010a"
));
assert_eq!(a * b, exp)
}
#[test]
fn test_basic_square() {
let a = Scalar(U448::from_be_hex(
"3162081604b3273b930392e5d2391f9d21cc3078f22c69514bb395e08dccc4866f08f3311370f8b83fa50692f640922b7e56a34bcf5fac3d",
));
let expected_a_squared = Scalar(U448::from_be_hex(
"1c1e32fc66b21c9c42d6e8e20487193cf6d49916421b290098f30de3713006cfe8ee9d21eeef7427f82a1fe036630c74b9acc2c2ede40f04",
));
assert_eq!(a.square(), expected_a_squared)
}
#[test]
fn test_sanity_check_index_mut() {
let mut x = Scalar::ONE;
x[0] = 2;
assert_eq!(x, Scalar::from(2u8))
}
#[test]
fn test_basic_halving() {
let eight = Scalar::from(8u8);
let four = Scalar::from(4u8);
let two = Scalar::from(2u8);
assert_eq!(eight.halve(), four);
assert_eq!(four.halve(), two);
assert_eq!(two.halve(), Scalar::ONE);
}
#[test]
fn test_equals() {
let a = Scalar::from(5u8);
let b = Scalar::from(5u8);
let c = Scalar::from(10u8);
assert_eq!(a, b);
assert_ne!(a, c);
}
#[test]
fn test_basic_inversion() {
for i in 1..=100u8 {
let x = Scalar::from(i);
let x_inv = x.invert();
assert_eq!(x_inv * x, Scalar::ONE)
}
let zero = Scalar::ZERO;
let expected_zero = zero.invert();
assert_eq!(expected_zero, zero)
}
#[test]
fn test_serialise() {
let scalar = Scalar(U448::from_be_hex(
"0d79f6e375d3395ed9a6c4c3c49a1433fd7c58aa38363f74e9ab2c22a22347d79988f8e01e8a309f862a9f1052fcd042b9b1ed7115598f62",
));
let got = Scalar::from_bytes(&scalar.to_bytes());
assert_eq!(scalar, got)
}
#[test]
fn test_from_canonical_bytes() {
let mut bytes = ScalarBytes::from(hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
bytes.reverse();
let s = Scalar::from_canonical_bytes(&bytes);
assert!(<Choice as Into<bool>>::into(s.is_none()));
let mut bytes = ScalarBytes::from(hex!("003fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3"));
bytes.reverse();
let s = Scalar::from_canonical_bytes(&bytes);
assert!(<Choice as Into<bool>>::into(s.is_none()));
let mut bytes = ScalarBytes::from(hex!("003fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f2"));
bytes.reverse();
let s = Scalar::from_canonical_bytes(&bytes);
match Option::<Scalar>::from(s) {
Some(s) => assert_eq!(s, Scalar::ZERO - Scalar::ONE),
None => panic!("should not return None"),
};
}
#[test]
fn test_from_bytes_mod_order_wide() {
let mut bytes = WideScalarBytes::clone_from_slice(&hex!("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3"));
bytes.reverse();
let s = Scalar::from_bytes_mod_order_wide(&bytes);
assert_eq!(s, Scalar::ZERO);
let mut bytes = WideScalarBytes::clone_from_slice(&hex!("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f2"));
bytes.reverse();
let s = Scalar::from_bytes_mod_order_wide(&bytes);
assert_eq!(s, Scalar::ZERO - Scalar::ONE);
let mut bytes = WideScalarBytes::clone_from_slice(&hex!("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f4"));
bytes.reverse();
let s = Scalar::from_bytes_mod_order_wide(&bytes);
assert_eq!(s, Scalar::ONE);
let bytes = WideScalarBytes::from_slice(&hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
let s = Scalar::from_bytes_mod_order_wide(bytes);
let mut bytes = ScalarBytes::from(hex!("002939f823b7292052bcb7e4d070af1a9cc14ba3c47c44ae17cf72c985bb24b6c520e319fb37a63e29800f160787ad1d2e11883fa931e7de81"));
bytes.reverse();
let reduced = Scalar::from_canonical_bytes(&bytes).unwrap();
assert_eq!(s, reduced);
}
#[test]
fn test_to_bytes_rfc8032() {
let mut bytes: [u8; 57] = hex!("003fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f2");
bytes.reverse();
let x = Scalar::ZERO - Scalar::ONE;
let candidate = x.to_bytes_rfc_8032();
assert_eq!(&bytes[..], &candidate[..]);
}
#[cfg(all(any(feature = "alloc", feature = "std"), feature = "serde"))]
#[test]
fn serde() {
let res = serde_json::to_string(&Scalar::TWO_INV);
assert!(res.is_ok());
let sj = res.unwrap();
let res = serde_json::from_str::<Scalar>(&sj);
assert!(res.is_ok());
assert_eq!(res.unwrap(), Scalar::TWO_INV);
let res = serde_bare::to_vec(&Scalar::TWO_INV);
assert!(res.is_ok());
let sb = res.unwrap();
assert_eq!(sb.len(), 57);
let res = serde_bare::from_slice::<Scalar>(&sb);
assert!(res.is_ok());
assert_eq!(res.unwrap(), Scalar::TWO_INV);
}
#[test]
fn scalar_hash() {
let msg = b"hello world";
let dst = b"edwards448_XOF:SHAKE256_ELL2_RO_";
let res =
Scalar::hash::<elliptic_curve::hash2curve::ExpandMsgXof<sha3::Shake256>>(msg, dst);
let expected: [u8; 57] = hex_literal::hex!("2d32a08f09b88275cc5f437e625696b18de718ed94559e17e4d64aafd143a8527705132178b5ce7395ea6214735387398a35913656b4951300");
assert_eq!(res.to_bytes_rfc_8032(), Array::from(expected));
}
}