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 core::ops::{AddAssign, SubAssign, MulAssign, Neg};
|
||||||
|
|
||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
use subtle::{Choice, ConditionallySelectable, ConditionallyAssignable};
|
use subtle::{Choice, ConditionallySelectable, ConditionallyAssignable, ConstantTimeEq};
|
||||||
|
|
||||||
/// Represents an element of `GF(q)`.
|
/// Represents an element of `GF(q)`.
|
||||||
// The internal representation of this type is four 64-bit unsigned
|
// The internal representation of this type is four 64-bit unsigned
|
||||||
|
@ -10,6 +11,32 @@ use subtle::{Choice, ConditionallySelectable, ConditionallyAssignable};
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Fq([u64; 4]);
|
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 {
|
impl ConditionallySelectable for Fq {
|
||||||
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
|
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
|
||||||
Fq([
|
Fq([
|
||||||
|
@ -221,9 +248,9 @@ impl Fq {
|
||||||
pub fn pow(&self, by: &[u64; 4]) -> Self {
|
pub fn pow(&self, by: &[u64; 4]) -> Self {
|
||||||
let mut res = Self::one();
|
let mut res = Self::one();
|
||||||
for e in by.iter().rev() {
|
for e in by.iter().rev() {
|
||||||
res.square_assign();
|
|
||||||
let mut e = *e;
|
let mut e = *e;
|
||||||
for i in (0..64).rev() {
|
for i in (0..64).rev() {
|
||||||
|
res.square_assign();
|
||||||
let mut tmp = res;
|
let mut tmp = res;
|
||||||
tmp.mul_assign(self);
|
tmp.mul_assign(self);
|
||||||
res.conditional_assign(&tmp, (((e >> i) & 0x1) as u8).into());
|
res.conditional_assign(&tmp, (((e >> i) & 0x1) as u8).into());
|
||||||
|
@ -312,3 +339,213 @@ fn test_inv() {
|
||||||
|
|
||||||
assert_eq!(inv, 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