Add tests for Fq operations.

This commit is contained in:
Sean Bowe 2018-09-01 14:04:48 -06:00
parent 27415d25c3
commit c8128b692d
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
1 changed files with 239 additions and 2 deletions

241
src/fq.rs
View File

@ -1,7 +1,8 @@
use core::fmt;
use core::ops::{AddAssign, SubAssign, MulAssign, Neg};
use byteorder::{ByteOrder, LittleEndian};
use subtle::{Choice, ConditionallySelectable, ConditionallyAssignable};
use subtle::{Choice, ConditionallySelectable, ConditionallyAssignable, ConstantTimeEq};
/// Represents an element of `GF(q)`.
// The internal representation of this type is four 64-bit unsigned
@ -10,6 +11,32 @@ use subtle::{Choice, ConditionallySelectable, ConditionallyAssignable};
#[derive(Clone, Copy)]
pub struct Fq([u64; 4]);
impl fmt::Debug for Fq {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let tmp = self.into_bytes();
write!(f, "0x")?;
for &b in tmp.iter().rev() {
write!(f, "{:02x}", b)?;
}
Ok(())
}
}
impl ConstantTimeEq for Fq {
fn ct_eq(&self, other: &Self) -> Choice {
self.0[0].ct_eq(&other.0[0]) &
self.0[1].ct_eq(&other.0[1]) &
self.0[2].ct_eq(&other.0[2]) &
self.0[3].ct_eq(&other.0[3])
}
}
impl PartialEq for Fq {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).unwrap_u8() == 1
}
}
impl ConditionallySelectable for Fq {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Fq([
@ -221,9 +248,9 @@ impl Fq {
pub fn pow(&self, by: &[u64; 4]) -> Self {
let mut res = Self::one();
for e in by.iter().rev() {
res.square_assign();
let mut e = *e;
for i in (0..64).rev() {
res.square_assign();
let mut tmp = res;
tmp.mul_assign(self);
res.conditional_assign(&tmp, (((e >> i) & 0x1) as u8).into());
@ -312,3 +339,213 @@ fn test_inv() {
assert_eq!(inv, INV);
}
#[test]
fn test_debug() {
assert_eq!(format!("{:?}", Fq::zero()), "0x0000000000000000000000000000000000000000000000000000000000000000");
assert_eq!(format!("{:?}", Fq::one()), "0x0000000000000000000000000000000000000000000000000000000000000001");
assert_eq!(format!("{:?}", R2), "0x1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffe");
}
#[test]
fn test_equality() {
assert_eq!(Fq::zero(), Fq::zero());
assert_eq!(Fq::one(), Fq::one());
assert_eq!(R2, R2);
assert!(Fq::zero() != Fq::one());
assert!(Fq::one() != R2);
}
#[test]
fn test_into_bytes() {
assert_eq!(
Fq::zero().into_bytes(),
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
);
assert_eq!(
Fq::one().into_bytes(),
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
);
assert_eq!(
R2.into_bytes(),
[254, 255, 255, 255, 1, 0, 0, 0, 2, 72, 3, 0, 250, 183, 132, 88, 245, 79, 188, 236, 239, 79, 140, 153, 111, 5, 197, 172, 89, 177, 36, 24]
);
assert_eq!(
(-Fq::one()).into_bytes(),
[0, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115]
);
assert_eq!(
(-Fq::one()).into_bytes(),
[0, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115]
);
}
#[test]
fn test_from_bytes_var() {
assert_eq!(
Fq::from_bytes_var([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
Fq::zero()
);
assert_eq!(
Fq::from_bytes_var([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
Fq::one()
);
assert_eq!(
Fq::from_bytes_var([254, 255, 255, 255, 1, 0, 0, 0, 2, 72, 3, 0, 250, 183, 132, 88, 245, 79, 188, 236, 239, 79, 140, 153, 111, 5, 197, 172, 89, 177, 36, 24]).unwrap(),
R2
);
// -1 should work
assert!(Fq::from_bytes_var(
[0, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115]
).is_some());
// modulus is invalid
assert!(Fq::from_bytes_var(
[1, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115]
).is_none());
// Anything larger than the modulus is invalid
assert!(Fq::from_bytes_var(
[2, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115]
).is_none());
assert!(Fq::from_bytes_var(
[1, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, 216, 58, 51, 72, 125, 157, 41, 83, 167, 237, 115]
).is_none());
assert!(Fq::from_bytes_var(
[1, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 116]
).is_none());
}
#[cfg(test)]
const LARGEST: Fq = Fq([
0xffffffff00000000, 0x53bda402fffe5bfe, 0x3339d80809a1d805, 0x73eda753299d7d48
]);
#[test]
fn test_addition() {
let mut tmp = LARGEST;
tmp += &LARGEST;
assert_eq!(
tmp,
Fq([
0xfffffffeffffffff, 0x53bda402fffe5bfe, 0x3339d80809a1d805, 0x73eda753299d7d48
])
);
let mut tmp = LARGEST;
tmp += &Fq([
1, 0, 0, 0
]);
assert_eq!(tmp, Fq::zero());
}
#[test]
fn test_negation() {
let tmp = -LARGEST;
assert_eq!(
tmp,
Fq([
1, 0, 0, 0
])
);
let tmp = -Fq::zero();
assert_eq!(tmp, Fq::zero());
let tmp = -Fq([1, 0, 0, 0]);
assert_eq!(tmp, LARGEST);
}
#[test]
fn test_subtraction() {
let mut tmp = LARGEST;
tmp -= &LARGEST;
assert_eq!(
tmp,
Fq::zero()
);
let mut tmp = Fq::zero();
tmp -= &LARGEST;
let mut tmp2 = MODULUS;
tmp2 -= &LARGEST;
assert_eq!(tmp, tmp2);
}
#[test]
fn test_multiplication() {
let mut cur = LARGEST;
for _ in 0..100 {
let mut tmp = cur;
tmp *= &cur;
let mut tmp2 = Fq::zero();
for b in cur.into_bytes().iter().rev().flat_map(|byte| (0..8).rev().map(move |i| ((byte >> i) & 1u8) == 1u8)) {
let tmp3 = tmp2;
tmp2.add_assign(&tmp3);
if b {
tmp2.add_assign(&cur);
}
}
assert_eq!(tmp, tmp2);
cur.add_assign(&LARGEST);
}
}
#[test]
fn test_squaring() {
let mut cur = LARGEST;
for _ in 0..100 {
let mut tmp = cur;
tmp.square_assign();
let mut tmp2 = Fq::zero();
for b in cur.into_bytes().iter().rev().flat_map(|byte| (0..8).rev().map(move |i| ((byte >> i) & 1u8) == 1u8)) {
let tmp3 = tmp2;
tmp2.add_assign(&tmp3);
if b {
tmp2.add_assign(&cur);
}
}
assert_eq!(tmp, tmp2);
cur.add_assign(&LARGEST);
}
}
#[test]
fn test_inversion() {
assert_eq!(Fq::one().pow_q_minus_2(), Fq::one());
assert_eq!((-Fq::one()).pow_q_minus_2(), -Fq::one());
let mut tmp = R2;
for _ in 0..100 {
let mut tmp2 = tmp.pow_q_minus_2();
tmp2.mul_assign(&tmp);
assert_eq!(tmp2, Fq::one());
tmp.add_assign(&R2);
}
}