mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Add a dedicated crate for testing ff/group implementors
Provides extensive testing for dalek-ff-group and ed448. Also includes a fix for an observed bug in ed448.
This commit is contained in:
@@ -32,3 +32,5 @@ dalek-ff-group = { path = "../dalek-ff-group", version = "^0.1.2" }
|
||||
[dev-dependencies]
|
||||
hex-literal = "0.3"
|
||||
hex = "0.4"
|
||||
|
||||
ff-group-tests = { path = "../ff-group-tests" }
|
||||
|
||||
@@ -38,7 +38,7 @@ macro_rules! field {
|
||||
impl Neg for $FieldName {
|
||||
type Output = $FieldName;
|
||||
fn neg(self) -> $FieldName {
|
||||
$MODULUS - self
|
||||
Self(self.0.neg_mod(&$MODULUS.0))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,29 +104,10 @@ macro_rules! field {
|
||||
}
|
||||
|
||||
fn sqrt(&self) -> CtOption<Self> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> Choice {
|
||||
self.0.ct_eq(&U512::ZERO)
|
||||
}
|
||||
fn cube(&self) -> Self {
|
||||
self.square() * self
|
||||
}
|
||||
fn pow_vartime<S: AsRef<[u64]>>(&self, exp: S) -> Self {
|
||||
let mut sum = Self::one();
|
||||
let mut accum = *self;
|
||||
for (_, num) in exp.as_ref().iter().enumerate() {
|
||||
let mut num = *num;
|
||||
for _ in 0 .. 64 {
|
||||
if (num & 1) == 1 {
|
||||
sum *= accum;
|
||||
}
|
||||
num >>= 1;
|
||||
accum *= accum;
|
||||
}
|
||||
}
|
||||
sum
|
||||
const MOD_1_4: $FieldName =
|
||||
Self($MODULUS.0.saturating_add(&U512::from_u8(1)).wrapping_div(&U512::from_u8(4)));
|
||||
let res = self.pow(MOD_1_4);
|
||||
CtOption::new(res, res.square().ct_eq(self))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,30 +30,7 @@ pub(crate) const Q_4: FieldElement =
|
||||
field!(FieldElement, MODULUS, WIDE_MODULUS, 448);
|
||||
|
||||
#[test]
|
||||
fn repr() {
|
||||
assert_eq!(FieldElement::from_repr(FieldElement::one().to_repr()).unwrap(), FieldElement::one());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_two() {
|
||||
assert_eq!(FieldElement::one() * FieldElement::one().double(), FieldElement::from(2u8));
|
||||
assert_eq!(
|
||||
FieldElement::from_repr(FieldElement::from(2u8).to_repr()).unwrap(),
|
||||
FieldElement::from(2u8)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pow() {
|
||||
assert_eq!(FieldElement::one().pow(FieldElement::one()), FieldElement::one());
|
||||
let two = FieldElement::one().double();
|
||||
assert_eq!(two.pow(two), two.double());
|
||||
|
||||
let three = two + FieldElement::one();
|
||||
assert_eq!(three.pow(three), three * three * three);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invert() {
|
||||
assert_eq!(FieldElement::one().invert().unwrap(), FieldElement::one());
|
||||
fn test_field() {
|
||||
// TODO: Move to test_prime_field_bits once the impl is finished
|
||||
ff_group_tests::prime_field::test_prime_field::<FieldElement>();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![no_std]
|
||||
|
||||
mod backend;
|
||||
|
||||
@@ -309,31 +309,38 @@ impl GroupEncoding for Point {
|
||||
impl PrimeGroup for Point {}
|
||||
|
||||
#[test]
|
||||
fn identity() {
|
||||
assert_eq!(Point::from_bytes(&Point::identity().to_bytes()).unwrap(), Point::identity());
|
||||
assert_eq!(Point::identity() + Point::identity(), Point::identity());
|
||||
fn test_group() {
|
||||
// TODO: Move to test_prime_group_bits once the impl is finished
|
||||
use ff_group_tests::group::*;
|
||||
|
||||
test_eq::<Point>();
|
||||
test_identity::<Point>();
|
||||
test_generator::<Point>();
|
||||
test_double::<Point>();
|
||||
test_add::<Point>();
|
||||
test_sum::<Point>();
|
||||
test_neg::<Point>();
|
||||
test_sub::<Point>();
|
||||
test_mul::<Point>();
|
||||
test_order::<Point>();
|
||||
|
||||
test_encoding::<Point>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn addition_multiplication_serialization() {
|
||||
let mut accum = Point::identity();
|
||||
for x in 1 .. 10 {
|
||||
accum += Point::generator();
|
||||
let mul = Point::generator() * Scalar::from(u8::try_from(x).unwrap());
|
||||
assert_eq!(accum, mul);
|
||||
assert_eq!(Point::from_bytes(&mul.to_bytes()).unwrap(), mul);
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn torsion() {
|
||||
use generic_array::GenericArray;
|
||||
|
||||
// Uses the originally suggested generator which had torsion
|
||||
let old_y = FieldElement::from_repr(
|
||||
hex_literal::hex!(
|
||||
"12796c1532041525945f322e414d434467cfd5c57c9a9af2473b27758c921c4828b277ca5f2891fc4f3d79afdf29a64c72fb28b59c16fa5100"
|
||||
).into(),
|
||||
)
|
||||
let old_y = FieldElement::from_repr(*GenericArray::from_slice(
|
||||
&hex::decode(
|
||||
"\
|
||||
12796c1532041525945f322e414d434467cfd5c57c9a9af2473b2775\
|
||||
8c921c4828b277ca5f2891fc4f3d79afdf29a64c72fb28b59c16fa51\
|
||||
00",
|
||||
)
|
||||
.unwrap(),
|
||||
))
|
||||
.unwrap();
|
||||
let old = Point { x: -recover_x(old_y).unwrap(), y: old_y, z: FieldElement::one() };
|
||||
assert!(bool::from(!old.is_torsion_free()));
|
||||
@@ -382,6 +389,7 @@ a401cd9df24632adfe6b418dc942d8a091817dd8bd70e1c72ba52f3c\
|
||||
);
|
||||
}
|
||||
|
||||
// Checks random won't infinitely loop
|
||||
#[test]
|
||||
fn random() {
|
||||
Point::random(&mut rand_core::OsRng);
|
||||
|
||||
@@ -33,6 +33,7 @@ impl Scalar {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invert() {
|
||||
assert_eq!(Scalar::one().invert().unwrap(), Scalar::one());
|
||||
fn test_scalar_field() {
|
||||
// TODO: Move to test_prime_field_bits once the impl is finished
|
||||
ff_group_tests::prime_field::test_prime_field::<Scalar>();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user