mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
3.5.2 Add more tests to ff-group-tests
The audit recommends checking failure cases for from_bytes, from_bytes_unechecked, and from_repr. This isn't feasible. from_bytes is allowed to have non-canonical values. [0xff; 32] may accordingly be a valid point for non-SEC1-encoded curves. from_bytes_unchecked doesn't have a defined failure mode, and by name, unchecked, shouldn't necessarily fail. The audit acknowledges the tests should test for whatever result is 'appropriate', yet any result which isn't a failure on a valid element is appropriate. from_repr must be canonical, yet for a binary field of 2^n where n % 8 == 0, a [0xff; n / 8] repr would be valid.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
use rand_core::RngCore;
|
||||
use group::ff::Field;
|
||||
|
||||
/// Perform basic tests on equality.
|
||||
@@ -106,8 +107,27 @@ pub fn test_cube<F: Field>() {
|
||||
assert_eq!(two.cube(), two * two * two, "2^3 != 8");
|
||||
}
|
||||
|
||||
/// Test random.
|
||||
pub fn test_random<R: RngCore, F: Field>(rng: &mut R) {
|
||||
let a = F::random(&mut *rng);
|
||||
|
||||
// Run up to 128 times so small fields, which may occasionally return the same element twice,
|
||||
// are statistically unlikely to fail
|
||||
// Field of order 1 will always fail this test due to lack of distinct elements to sample
|
||||
// from
|
||||
let mut pass = false;
|
||||
for _ in 0 .. 128 {
|
||||
let b = F::random(&mut *rng);
|
||||
// This test passes if a distinct element is returned at least once
|
||||
if b != a {
|
||||
pass = true;
|
||||
}
|
||||
}
|
||||
assert!(pass, "random always returned the same value");
|
||||
}
|
||||
|
||||
/// Run all tests on fields implementing Field.
|
||||
pub fn test_field<F: Field>() {
|
||||
pub fn test_field<R: RngCore, F: Field>(rng: &mut R) {
|
||||
test_eq::<F>();
|
||||
test_conditional_select::<F>();
|
||||
test_add::<F>();
|
||||
@@ -119,4 +139,5 @@ pub fn test_field<F: Field>() {
|
||||
test_sqrt::<F>();
|
||||
test_is_zero::<F>();
|
||||
test_cube::<F>();
|
||||
test_random::<R, F>(rng);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use rand_core::RngCore;
|
||||
use group::{
|
||||
ff::{Field, PrimeFieldBits},
|
||||
Group,
|
||||
@@ -69,6 +70,11 @@ pub fn test_sum<G: Group>() {
|
||||
G::generator().double(),
|
||||
"[generator, generator].sum() != two"
|
||||
);
|
||||
assert_eq!(
|
||||
[G::generator().double(), G::generator()].iter().sum::<G>(),
|
||||
G::generator().double() + G::generator(),
|
||||
"[generator.double(), generator].sum() != three"
|
||||
);
|
||||
}
|
||||
|
||||
/// Test negation.
|
||||
@@ -107,9 +113,31 @@ pub fn test_order<G: Group>() {
|
||||
assert_eq!(minus_one + G::generator(), G::identity(), "((modulus - 1) * G) + G wasn't identity");
|
||||
}
|
||||
|
||||
/// Test random.
|
||||
pub fn test_random<R: RngCore, G: Group>(rng: &mut R) {
|
||||
let a = G::random(&mut *rng);
|
||||
assert!(!bool::from(a.is_identity()), "random returned identity");
|
||||
|
||||
// Run up to 128 times so small groups, which may occasionally return the same element twice,
|
||||
// are statistically unlikely to fail
|
||||
// Groups of order <= 2 will always fail this test due to lack of distinct elements to sample
|
||||
// from
|
||||
let mut pass = false;
|
||||
for _ in 0 .. 128 {
|
||||
let b = G::random(&mut *rng);
|
||||
assert!(!bool::from(b.is_identity()), "random returned identity");
|
||||
|
||||
// This test passes if a distinct element is returned at least once
|
||||
if b != a {
|
||||
pass = true;
|
||||
}
|
||||
}
|
||||
assert!(pass, "random always returned the same value");
|
||||
}
|
||||
|
||||
/// Run all tests on groups implementing Group.
|
||||
pub fn test_group<G: Group>() {
|
||||
test_prime_field::<G::Scalar>();
|
||||
pub fn test_group<R: RngCore, G: Group>(rng: &mut R) {
|
||||
test_prime_field::<R, G::Scalar>(rng);
|
||||
|
||||
test_eq::<G>();
|
||||
test_identity::<G>();
|
||||
@@ -121,6 +149,7 @@ pub fn test_group<G: Group>() {
|
||||
test_sub::<G>();
|
||||
test_mul::<G>();
|
||||
test_order::<G>();
|
||||
test_random::<R, G>(rng);
|
||||
}
|
||||
|
||||
/// Test encoding and decoding of group elements.
|
||||
@@ -142,19 +171,19 @@ pub fn test_encoding<G: PrimeGroup>() {
|
||||
}
|
||||
|
||||
/// Run all tests on groups implementing PrimeGroup (Group + GroupEncoding).
|
||||
pub fn test_prime_group<G: PrimeGroup>() {
|
||||
test_group::<G>();
|
||||
pub fn test_prime_group<R: RngCore, G: PrimeGroup>(rng: &mut R) {
|
||||
test_group::<R, G>(rng);
|
||||
|
||||
test_encoding::<G>();
|
||||
}
|
||||
|
||||
/// Run all tests offered by this crate on the group.
|
||||
pub fn test_prime_group_bits<G: PrimeGroup>()
|
||||
pub fn test_prime_group_bits<R: RngCore, G: PrimeGroup>(rng: &mut R)
|
||||
where
|
||||
G::Scalar: PrimeFieldBits,
|
||||
{
|
||||
test_prime_field_bits::<G::Scalar>();
|
||||
test_prime_group::<G>();
|
||||
test_prime_field_bits::<R, G::Scalar>(rng);
|
||||
test_prime_group::<R, G>(rng);
|
||||
}
|
||||
|
||||
// Run these tests against k256/p256
|
||||
@@ -167,10 +196,10 @@ where
|
||||
|
||||
#[test]
|
||||
fn test_k256() {
|
||||
test_prime_group_bits::<k256::ProjectivePoint>();
|
||||
test_prime_group_bits::<_, k256::ProjectivePoint>(&mut rand_core::OsRng);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_p256() {
|
||||
test_prime_group_bits::<p256::ProjectivePoint>();
|
||||
test_prime_group_bits::<_, p256::ProjectivePoint>(&mut rand_core::OsRng);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use rand_core::RngCore;
|
||||
use group::ff::{PrimeField, PrimeFieldBits};
|
||||
|
||||
use crate::field::test_field;
|
||||
@@ -29,6 +30,16 @@ pub fn test_is_odd<F: PrimeField>() {
|
||||
assert_eq!(F::one().is_odd().unwrap_u8(), 1, "1 was even");
|
||||
assert_eq!(F::one().is_even().unwrap_u8(), 0, "1 wasn't odd");
|
||||
|
||||
// Make sure an odd value added to an odd value is even
|
||||
let two = F::one().double();
|
||||
assert_eq!(two.is_odd().unwrap_u8(), 0, "2 was odd");
|
||||
assert_eq!(two.is_even().unwrap_u8(), 1, "2 wasn't even");
|
||||
|
||||
// Make sure an even value added to an even value is even
|
||||
let four = two.double();
|
||||
assert_eq!(four.is_odd().unwrap_u8(), 0, "4 was odd");
|
||||
assert_eq!(four.is_even().unwrap_u8(), 1, "4 wasn't even");
|
||||
|
||||
let neg_one = -F::one();
|
||||
assert_eq!(neg_one.is_odd().unwrap_u8(), 0, "-1 was odd");
|
||||
assert_eq!(neg_one.is_even().unwrap_u8(), 1, "-1 wasn't even");
|
||||
@@ -49,6 +60,11 @@ pub fn test_encoding<F: PrimeField>() {
|
||||
F::from_repr_vartime(repr).unwrap(),
|
||||
"{msg} couldn't be encoded and decoded",
|
||||
);
|
||||
assert_eq!(
|
||||
bytes.as_ref(),
|
||||
F::from_repr(repr).unwrap().to_repr().as_ref(),
|
||||
"canonical encoding decoded produced distinct encoding"
|
||||
);
|
||||
};
|
||||
test(F::zero(), "0");
|
||||
test(F::one(), "1");
|
||||
@@ -57,8 +73,8 @@ pub fn test_encoding<F: PrimeField>() {
|
||||
}
|
||||
|
||||
/// Run all tests on fields implementing PrimeField.
|
||||
pub fn test_prime_field<F: PrimeField>() {
|
||||
test_field::<F>();
|
||||
pub fn test_prime_field<R: RngCore, F: PrimeField>(rng: &mut R) {
|
||||
test_field::<R, F>(rng);
|
||||
|
||||
test_zero::<F>();
|
||||
test_one::<F>();
|
||||
@@ -265,6 +281,7 @@ pub fn test_root_of_unity<F: PrimeFieldBits>() {
|
||||
}
|
||||
bit = bit.double();
|
||||
}
|
||||
assert!(bool::from(t.is_odd()), "t wasn't odd");
|
||||
|
||||
assert_eq!(pow(F::multiplicative_generator(), t), F::root_of_unity(), "incorrect root of unity");
|
||||
assert_eq!(
|
||||
@@ -275,8 +292,8 @@ pub fn test_root_of_unity<F: PrimeFieldBits>() {
|
||||
}
|
||||
|
||||
/// Run all tests on fields implementing PrimeFieldBits.
|
||||
pub fn test_prime_field_bits<F: PrimeFieldBits>() {
|
||||
test_prime_field::<F>();
|
||||
pub fn test_prime_field_bits<R: RngCore, F: PrimeFieldBits>(rng: &mut R) {
|
||||
test_prime_field::<R, F>(rng);
|
||||
|
||||
test_to_le_bits::<F>();
|
||||
test_char_le_bits::<F>();
|
||||
|
||||
Reference in New Issue
Block a user