Add tests for Fq operations.
This commit is contained in:
parent
27415d25c3
commit
c8128b692d
241
src/fq.rs
241
src/fq.rs
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue