Mocktography (#49)
Added mocktography (feature `use-insecure-test-only-mock-crypto) and factored out CI execution script.master
parent
90f63e34e9
commit
d133bb6d79
@ -0,0 +1,16 @@ |
||||
#!/bin/sh |
||||
|
||||
set -xe |
||||
|
||||
export RUST_BACKTRACE=1 |
||||
|
||||
# Enables additional cpu-specific optimizations. |
||||
export RUSTFLAGS="-D warnings -C target-cpu=native" |
||||
|
||||
cargo clippy --tests --examples --benches -- --deny clippy |
||||
cargo clippy --all-features --tests --examples --benches -- --deny clippy |
||||
cargo fmt -- --check |
||||
cargo test --release |
||||
cargo test --all-features --release |
||||
cargo doc |
||||
cargo deadlinks --dir target/doc/threshold_crypto/ |
@ -0,0 +1,322 @@ |
||||
//! Mock cryptography implementation of a `pairing` engine.
|
||||
//!
|
||||
//! Affectionately known as *mocktography*, the `mock` module implements a valid `pairing::Engine`
|
||||
//! on top of simpler cryptographic primitives; instead of elliptic curves, a simple finite field of
|
||||
//! Mersenne prime order is used. The resulting engine is trivially breakable (the key space is
|
||||
//! smaller than 2^31), but should not produce accidental collisions at an unacceptable rate.
|
||||
//!
|
||||
//! As a result, all "cryptographic" operations can be carried out much faster. This module is
|
||||
//! intended to be used during unit-tests of applications that build on top of `threshold_crypto`;
|
||||
//! enabling this in production code of any application will immediately break its cryptographic
|
||||
//! security.
|
||||
|
||||
pub mod ms8; |
||||
|
||||
use std::{fmt, mem, slice}; |
||||
|
||||
use pairing::{EncodedPoint, Field, GroupDecodingError, PrimeField}; |
||||
use rand; |
||||
|
||||
use super::{CurveAffine, CurveProjective, Engine}; |
||||
|
||||
pub use self::ms8::Mersenne8; |
||||
|
||||
/// A `pairing` Engine based on `Mersenne8` prime fields.
|
||||
#[derive(Clone, Debug)] |
||||
pub struct Mocktography; |
||||
|
||||
/// Affine type for `Mersenne8`.
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd)] |
||||
pub struct Ms8Affine(Mersenne8); |
||||
|
||||
/// Projective type for `Mersenne8`.
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd)] |
||||
pub struct Ms8Projective(Mersenne8); |
||||
|
||||
impl fmt::Display for Ms8Affine { |
||||
#[inline] |
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||
fmt::Display::fmt(&self.0, f) |
||||
} |
||||
} |
||||
|
||||
impl fmt::Display for Ms8Projective { |
||||
#[inline] |
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||
fmt::Display::fmt(&self.0, f) |
||||
} |
||||
} |
||||
|
||||
impl rand::Rand for Ms8Affine { |
||||
#[inline] |
||||
fn rand<R: rand::Rng>(rng: &mut R) -> Self { |
||||
Ms8Affine(rng.gen()) |
||||
} |
||||
} |
||||
|
||||
impl rand::Rand for Ms8Projective { |
||||
#[inline] |
||||
fn rand<R: rand::Rng>(rng: &mut R) -> Self { |
||||
Ms8Projective(rng.gen()) |
||||
} |
||||
} |
||||
|
||||
impl From<Ms8Projective> for Ms8Affine { |
||||
fn from(Ms8Projective(x): Ms8Projective) -> Ms8Affine { |
||||
Ms8Affine(x) |
||||
} |
||||
} |
||||
|
||||
impl From<Ms8Affine> for Ms8Projective { |
||||
fn from(Ms8Affine(x): Ms8Affine) -> Ms8Projective { |
||||
Ms8Projective(x) |
||||
} |
||||
} |
||||
|
||||
impl Engine for Mocktography { |
||||
type G1 = Ms8Projective; |
||||
type G1Affine = Ms8Affine; |
||||
type G2 = Ms8Projective; |
||||
type G2Affine = Ms8Affine; |
||||
type Fq = Mersenne8; |
||||
type Fqe = Mersenne8; |
||||
type Fqk = Mersenne8; |
||||
|
||||
// In newer versions of pairing, this must be moved to `ScalarEngine`:
|
||||
type Fr = Mersenne8; |
||||
|
||||
fn miller_loop<'a, I>(_i: I) -> Self::Fqk |
||||
where |
||||
I: IntoIterator< |
||||
Item = &'a ( |
||||
&'a <Self::G1Affine as CurveAffine>::Prepared, |
||||
&'a <Self::G2Affine as CurveAffine>::Prepared, |
||||
), |
||||
>, |
||||
{ |
||||
// Unused?
|
||||
unimplemented!() |
||||
} |
||||
|
||||
fn final_exponentiation(_: &Self::Fqk) -> Option<Self::Fqk> { |
||||
// Unused?
|
||||
unimplemented!() |
||||
} |
||||
|
||||
fn pairing<G1, G2>(p: G1, q: G2) -> Self::Fqk |
||||
where |
||||
G1: Into<Self::G1Affine>, |
||||
G2: Into<Self::G2Affine>, |
||||
{ |
||||
p.into().0 * q.into().0 |
||||
} |
||||
} |
||||
|
||||
impl AsRef<[u64]> for Mersenne8 { |
||||
#[inline] |
||||
fn as_ref(&self) -> &[u64] { |
||||
panic!("Not supported: AsRef<[u64]>") |
||||
} |
||||
} |
||||
|
||||
impl AsRef<[u8]> for Mersenne8 { |
||||
#[inline] |
||||
fn as_ref(&self) -> &[u8] { |
||||
unsafe { slice::from_raw_parts(&self.0 as *const u32 as *const u8, 4) } |
||||
} |
||||
} |
||||
|
||||
impl AsMut<[u64]> for Mersenne8 { |
||||
#[inline] |
||||
fn as_mut(&mut self) -> &mut [u64] { |
||||
panic!("Not supported: AsMut<[u64]>") |
||||
} |
||||
} |
||||
|
||||
impl AsMut<[u8]> for Mersenne8 { |
||||
#[inline] |
||||
fn as_mut(&mut self) -> &mut [u8] { |
||||
unsafe { slice::from_raw_parts_mut(&mut self.0 as *mut u32 as *mut u8, 4) } |
||||
} |
||||
} |
||||
|
||||
impl AsRef<[u8]> for Ms8Affine { |
||||
#[inline] |
||||
fn as_ref(&self) -> &[u8] { |
||||
self.0.as_ref() |
||||
} |
||||
} |
||||
|
||||
impl AsMut<[u8]> for Ms8Affine { |
||||
#[inline] |
||||
fn as_mut(&mut self) -> &mut [u8] { |
||||
self.0.as_mut() |
||||
} |
||||
} |
||||
|
||||
impl CurveAffine for Ms8Affine { |
||||
type Engine = Mocktography; |
||||
type Scalar = Mersenne8; |
||||
type Base = Mersenne8; |
||||
type Projective = Ms8Projective; |
||||
type Prepared = Ms8Affine; |
||||
type Uncompressed = Ms8Affine; |
||||
type Compressed = Ms8Affine; |
||||
type Pair = Ms8Affine; |
||||
type PairingResult = Mersenne8; |
||||
|
||||
fn zero() -> Self { |
||||
Ms8Affine(Mersenne8::zero()) |
||||
} |
||||
|
||||
fn one() -> Self { |
||||
Ms8Affine(Mersenne8::one()) |
||||
} |
||||
|
||||
fn is_zero(&self) -> bool { |
||||
self.0.is_zero() |
||||
} |
||||
|
||||
fn negate(&mut self) { |
||||
self.0.negate(); |
||||
} |
||||
|
||||
fn mul<S: Into<<Self::Scalar as PrimeField>::Repr>>(&self, other: S) -> Self::Projective { |
||||
// FIXME: Is this correct?
|
||||
let s = other.into(); |
||||
|
||||
Ms8Projective(self.0 * s) |
||||
} |
||||
|
||||
fn prepare(&self) -> Self::Prepared { |
||||
*self |
||||
} |
||||
|
||||
fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult { |
||||
// This is the actual implementation of e: G_1 x G_2 -> G_T.
|
||||
// We have chosen e(P, Q) = PQ.
|
||||
self.0 * other.0 |
||||
} |
||||
|
||||
fn into_projective(&self) -> Self::Projective { |
||||
Ms8Projective(self.0) |
||||
} |
||||
} |
||||
|
||||
impl CurveProjective for Ms8Projective { |
||||
type Engine = Mocktography; |
||||
type Scalar = Mersenne8; |
||||
type Base = Mersenne8; |
||||
type Affine = Ms8Affine; |
||||
|
||||
fn zero() -> Self { |
||||
Ms8Projective(Mersenne8::zero()) |
||||
} |
||||
|
||||
fn one() -> Self { |
||||
Ms8Projective(Mersenne8::one()) |
||||
} |
||||
|
||||
fn is_zero(&self) -> bool { |
||||
self.0.is_zero() |
||||
} |
||||
|
||||
fn batch_normalization(_v: &mut [Self]) { |
||||
// We just assume all values as already normalized. See `is_normalized()`.
|
||||
} |
||||
|
||||
fn is_normalized(&self) -> bool { |
||||
true |
||||
} |
||||
|
||||
fn double(&mut self) { |
||||
self.0.double() |
||||
} |
||||
|
||||
fn add_assign(&mut self, other: &Self) { |
||||
self.0.add_assign(&other.0); |
||||
} |
||||
|
||||
fn add_assign_mixed(&mut self, other: &Self::Affine) { |
||||
self.0.add_assign(&other.0); |
||||
} |
||||
|
||||
fn negate(&mut self) { |
||||
self.0.negate(); |
||||
} |
||||
|
||||
fn mul_assign<S: Into<<Self::Scalar as PrimeField>::Repr>>(&mut self, other: S) { |
||||
self.0 *= other.into(); |
||||
} |
||||
|
||||
fn into_affine(&self) -> Self::Affine { |
||||
Ms8Affine(self.0) |
||||
} |
||||
|
||||
fn recommended_wnaf_for_scalar(_scalar: <Self::Scalar as PrimeField>::Repr) -> usize { |
||||
2 |
||||
} |
||||
|
||||
fn recommended_wnaf_for_num_scalars(_num_scalars: usize) -> usize { |
||||
2 |
||||
} |
||||
} |
||||
|
||||
impl EncodedPoint for Ms8Affine { |
||||
type Affine = Ms8Affine; |
||||
|
||||
fn empty() -> Self { |
||||
// FIXME: Ensure we are not violating any assumptions here.
|
||||
Self::default() |
||||
} |
||||
|
||||
fn size() -> usize { |
||||
mem::size_of::<Self>() |
||||
} |
||||
|
||||
fn into_affine(&self) -> Result<Self::Affine, GroupDecodingError> { |
||||
Ok(*self) |
||||
} |
||||
|
||||
fn into_affine_unchecked(&self) -> Result<Self::Affine, GroupDecodingError> { |
||||
Ok(*self) |
||||
} |
||||
|
||||
fn from_affine(affine: Self::Affine) -> Self { |
||||
affine |
||||
} |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
mod test { |
||||
// There are copy & pasted results of calculations from external programs in these tests.
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))] |
||||
|
||||
use super::{Mersenne8, Mocktography, Ms8Affine}; |
||||
use Engine; |
||||
|
||||
#[test] |
||||
fn example_pairings() { |
||||
let pqs: Vec<(u32, u32, u32)> = vec![ |
||||
(0, 0, 0), |
||||
(123, 0, 0), |
||||
(1, 1, 1), |
||||
(123, 1, 123), |
||||
(4, 5, 20), |
||||
(123456789, 987654321, 2137109934), |
||||
(456789123, 456789123, 1405297315), |
||||
]; |
||||
|
||||
for (p, q, res) in pqs { |
||||
let p = Ms8Affine(p.into()); |
||||
let q = Ms8Affine(q.into()); |
||||
println!("P, Q: {}, {}", p, q); |
||||
println!("Checking e({}, {}) = {}", p, q, res); |
||||
assert_eq!(Mocktography::pairing(p, q), Mersenne8::new(res)); |
||||
|
||||
// Our pairing is bilinear.
|
||||
println!("Checking e({}, {}) = {}", q, p, res); |
||||
assert_eq!(Mocktography::pairing(q, p), Mersenne8::new(res)); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,815 @@ |
||||
//! Eigth Mersenne prime field
|
||||
//!
|
||||
//! The eighth [Mersenne Prime](https://en.wikipedia.org/wiki/Mersenne_prime) (`MS8 := 2^31-1) can
|
||||
//! be used to construct a finite field supporting addition and multiplication. This module provides
|
||||
//! a wrapper type around `u32` to implement this functionality.
|
||||
//!
|
||||
//! The resulting type also implements the `Field`, `PrimeField` and `SqrtField` traits. For
|
||||
//! convenience, `PrimeFieldRepr` is also implemented.
|
||||
|
||||
use std::io::{self, Read, Write}; |
||||
use std::{fmt, mem, ops}; |
||||
|
||||
use byteorder::{BigEndian, ByteOrder}; |
||||
use pairing::{ |
||||
Field, LegendreSymbol, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, SqrtField, |
||||
}; |
||||
use rand; |
||||
|
||||
/// Modular exponentiation
|
||||
///
|
||||
/// Warning: Only tested using bases and exponents `< MS8`.
|
||||
#[inline] |
||||
fn modular_pow(base: u32, mut exp: u32, modulus: u32) -> u32 { |
||||
// Source: https://en.wikipedia.org/wiki/Modular_exponentiation#Right-to-left_binary_method
|
||||
if modulus == 1 { |
||||
return 0; |
||||
} |
||||
|
||||
// Need to use 64 bits to ensure the assert from Schneier's algorithm:
|
||||
// (modulus - 1) * (modulus - 1) does not overflow base
|
||||
let mut result: u64 = 1; |
||||
let md: u64 = u64::from(modulus); |
||||
let mut base = u64::from(base) % md; |
||||
|
||||
while exp > 0 { |
||||
if exp % 2 == 1 { |
||||
result = (result * base) % md; |
||||
} |
||||
exp >>= 1; |
||||
base = (base * base) % md; |
||||
} |
||||
|
||||
result as u32 |
||||
} |
||||
|
||||
/// Eigth Mersenne prime, aka `i32::MAX`.
|
||||
pub const MS8: u32 = 0x7fff_ffff; |
||||
|
||||
/// Eighth Mersenne prime field element
|
||||
///
|
||||
/// Finite field of order `2^31-1`.
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd)] |
||||
pub struct Mersenne8(pub u32); |
||||
|
||||
// We opt to implement the same variants the standard library implements as well:
|
||||
//
|
||||
// FooAssign: `lhs .= rhs, lhs .= &rhs`.
|
||||
// Foo: `lhs . rhs, &lhs . rhs, &lhs . &rhs, lhs . &rhs`
|
||||
macro_rules! generate_op_impls { |
||||
($t:ty, $op_name:ident, $op_name_assign:ident, $op_method:ident, $op_method_assign:ident) => { |
||||
// Supplied by caller: `lhs .= rhs`
|
||||
|
||||
// `lhs . rhs`
|
||||
impl ops::$op_name for $t { |
||||
type Output = Self; |
||||
|
||||
#[inline] |
||||
fn $op_method(mut self, rhs: $t) -> Self { |
||||
self.$op_method_assign(&rhs); |
||||
self |
||||
} |
||||
} |
||||
|
||||
// lhs .= &rhs
|
||||
impl<'a> ops::$op_name_assign<&'a $t> for $t { |
||||
#[inline] |
||||
fn $op_method_assign(&mut self, rhs: &'a $t) { |
||||
ops::$op_name_assign::$op_method_assign(self, *rhs) |
||||
} |
||||
} |
||||
|
||||
// `&lhs . rhs`
|
||||
impl<'a> ops::$op_name<$t> for &'a $t { |
||||
type Output = $t; |
||||
|
||||
#[inline] |
||||
fn $op_method(self, other: $t) -> Self::Output { |
||||
let mut tmp = *self; |
||||
tmp.$op_method_assign(&other); |
||||
tmp |
||||
} |
||||
} |
||||
|
||||
// `&lhs . &rhs`
|
||||
impl<'a, 'b> ops::$op_name<&'b $t> for &'a $t { |
||||
type Output = $t; |
||||
|
||||
#[inline] |
||||
fn $op_method(self, other: &'b $t) -> Self::Output { |
||||
let mut tmp = *self; |
||||
tmp.$op_method_assign(other); |
||||
tmp |
||||
} |
||||
} |
||||
|
||||
// `lhs . &rhs`
|
||||
impl<'a> ops::$op_name<&'a $t> for $t { |
||||
type Output = $t; |
||||
|
||||
#[inline] |
||||
fn $op_method(mut self, other: &'a $t) -> Self::Output { |
||||
self.$op_method_assign(other); |
||||
self |
||||
} |
||||
} |
||||
}; |
||||
} |
||||
|
||||
impl ops::SubAssign<Mersenne8> for Mersenne8 { |
||||
#[inline] |
||||
fn sub_assign(&mut self, rhs: Mersenne8) { |
||||
// Since `self.0` is < 2^31-1, `self.0 + 2^31-1` is still smaller than `u32::MAX`.
|
||||
self.0 = (self.0 + MS8 - rhs.0) % MS8; |
||||
} |
||||
} |
||||
generate_op_impls!(Mersenne8, Sub, SubAssign, sub, sub_assign); |
||||
|
||||
impl ops::AddAssign<Mersenne8> for Mersenne8 { |
||||
#[inline] |
||||
fn add_assign(&mut self, rhs: Mersenne8) { |
||||
self.0 = (self.0 + rhs.0) % MS8; |
||||
} |
||||
} |
||||
generate_op_impls!(Mersenne8, Add, AddAssign, add, add_assign); |
||||
|
||||
impl ops::MulAssign for Mersenne8 { |
||||
#[inline] |
||||
fn mul_assign(&mut self, rhs: Mersenne8) { |
||||
// Usually, Schrage's method would be a good way to implement the multiplication;
|
||||
// however, since we will mostly be running the code on 64-bit machines and
|
||||
// `(2^31-1)^2 < 2^64`, we can cheat and do this fairly fast in 64 bits.
|
||||
self.0 = (u64::from(self.0) * u64::from(rhs.0) % u64::from(MS8)) as u32; |
||||
} |
||||
} |
||||
|
||||
generate_op_impls!(Mersenne8, Mul, MulAssign, mul, mul_assign); |
||||
|
||||
impl Mersenne8 { |
||||
#[inline] |
||||
pub fn new(v: u32) -> Mersenne8 { |
||||
Mersenne8(v % MS8) |
||||
} |
||||
|
||||
#[inline] |
||||
pub fn pow(self, exp: u32) -> Mersenne8 { |
||||
Mersenne8(modular_pow(self.0, exp, MS8)) |
||||
} |
||||
} |
||||
|
||||
impl From<u32> for Mersenne8 { |
||||
#[inline] |
||||
fn from(v: u32) -> Mersenne8 { |
||||
Mersenne8::new(v) |
||||
} |
||||
} |
||||
|
||||
impl From<u64> for Mersenne8 { |
||||
#[inline] |
||||
fn from(v: u64) -> Mersenne8 { |
||||
Mersenne8((v % u64::from(MS8)) as u32) |
||||
} |
||||
} |
||||
|
||||
impl From<Mersenne8> for u32 { |
||||
fn from(v: Mersenne8) -> u32 { |
||||
v.0 |
||||
} |
||||
} |
||||
|
||||
impl PartialEq<u32> for Mersenne8 { |
||||
fn eq(&self, other: &u32) -> bool { |
||||
self.0 == *other |
||||
} |
||||
} |
||||
|
||||
impl fmt::Display for Mersenne8 { |
||||
#[inline] |
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||
fmt::Display::fmt(&self.0, f) |
||||
} |
||||
} |
||||
|
||||
impl rand::Rand for Mersenne8 { |
||||
#[inline] |
||||
fn rand<R: rand::Rng>(rng: &mut R) -> Self { |
||||
Mersenne8::from(<u32 as rand::Rand>::rand(rng)) |
||||
} |
||||
} |
||||
|
||||
impl Field for Mersenne8 { |
||||
#[inline] |
||||
fn zero() -> Self { |
||||
Mersenne8(0) |
||||
} |
||||
|
||||
#[inline] |
||||
fn one() -> Self { |
||||
Mersenne8(1) |
||||
} |
||||
|
||||
#[inline] |
||||
fn is_zero(&self) -> bool { |
||||
self.0 == 0 |
||||
} |
||||
|
||||
#[inline] |
||||
fn square(&mut self) { |
||||
self.0 = (*self * *self).0; |
||||
} |
||||
|
||||
#[inline] |
||||
fn double(&mut self) { |
||||
// MS8 fits at least twice into a single u32.
|
||||
self.0 = (self.0 * 2) % MS8; |
||||
} |
||||
|
||||
#[inline] |
||||
fn negate(&mut self) { |
||||
self.0 = (Self::zero() - *self).0; |
||||
} |
||||
|
||||
#[inline] |
||||
fn add_assign(&mut self, other: &Self) { |
||||
*self += other; |
||||
} |
||||
|
||||
#[inline] |
||||
fn sub_assign(&mut self, other: &Self) { |
||||
*self -= other; |
||||
} |
||||
|
||||
#[inline] |
||||
fn mul_assign(&mut self, other: &Self) { |
||||
*self *= other; |
||||
} |
||||
|
||||
#[inline] |
||||
fn inverse(&self) -> Option<Self> { |
||||
let (d, _s, t) = ext_euclid(MS8, self.0); |
||||
|
||||
// MS8 is prime, so the gcd should always be 1, unless the number itself is 0.
|
||||
if d != 1 { |
||||
debug_assert_eq!(d, MS8); |
||||
return None; |
||||
} |
||||
|
||||
Some(Mersenne8::new( |
||||
((t + i64::from(MS8)) % i64::from(MS8)) as u32, |
||||
)) |
||||
} |
||||
|
||||
#[inline] |
||||
fn frobenius_map(&mut self, _power: usize) { |
||||
// Does nothing, the frobenius endomorphism is the identity function in every finite field
|
||||
// of prime order.
|
||||
} |
||||
} |
||||
|
||||
impl PrimeField for Mersenne8 { |
||||
type Repr = Self; |
||||
|
||||
const NUM_BITS: u32 = 32; |
||||
const CAPACITY: u32 = 30; |
||||
|
||||
// Not actually used.
|
||||
const S: u32 = 0; |
||||
|
||||
#[inline] |
||||
fn from_repr(v: Self::Repr) -> Result<Self, PrimeFieldDecodingError> { |
||||
Ok(v) |
||||
} |
||||
|
||||
#[inline] |
||||
fn into_repr(&self) -> Self::Repr { |
||||
*self |
||||
} |
||||
|
||||
#[inline] |
||||
fn char() -> Self::Repr { |
||||
// Awkward. We cannot return the characteristic itself, since it's not an element of field,
|
||||
// but equal to its order. Instead, we panic.
|
||||
//
|
||||
// Note: The return type of this function should probably be `usize`.
|
||||
panic!("Cannot return characteristic of Mersenne8 as an element of Mersenne8."); |
||||
} |
||||
|
||||
#[inline] |
||||
fn multiplicative_generator() -> Self { |
||||
// Any element of a finite field of prime order is a generator, but 3 is the smallest one
|
||||
// that is a quadratic non-residue.
|
||||
Mersenne8::new(3) |
||||
} |
||||
|
||||
#[inline] |
||||
fn root_of_unity() -> Self { |
||||
// Still unclear what's supposed to be implemented here, missing at least an `n`?.
|
||||
unimplemented!() |
||||
} |
||||
} |
||||
|
||||
impl SqrtField for Mersenne8 { |
||||
fn legendre(&self) -> LegendreSymbol { |
||||
// Uses Euler's criterion: `(a/p) === a^((p-1)/2).
|
||||
let exp = (MS8 - 1) / 2; |
||||
|
||||
match (*self).pow(exp).0 { |
||||
1 => LegendreSymbol::QuadraticResidue, |
||||
n if n == MS8 - 1 => LegendreSymbol::QuadraticNonResidue, |
||||
0 => LegendreSymbol::Zero, |
||||
_ => panic!("Euler's criteria did not return correct Legendre symbol"), |
||||
} |
||||
} |
||||
|
||||
fn sqrt(&self) -> Option<Self> { |
||||
unimplemented!() // FIXME, could use Tonelli-Shanks algorithm
|
||||
} |
||||
} |
||||
|
||||
impl PrimeFieldRepr for Mersenne8 { |
||||
#[inline] |
||||
fn sub_noborrow(&mut self, other: &Self) { |
||||
*self -= other; |
||||
} |
||||
|
||||
#[inline] |
||||
fn add_nocarry(&mut self, other: &Self) { |
||||
*self += other; |
||||
} |
||||
|
||||
#[inline] |
||||
fn num_bits(&self) -> u32 { |
||||
8 * mem::size_of::<Self>() as u32 |
||||
} |
||||
|
||||
#[inline] |
||||
fn is_zero(&self) -> bool { |
||||
self.0 == 0 |
||||
} |
||||
|
||||
#[inline] |
||||
fn is_odd(&self) -> bool { |
||||
self.0 % 2 == 1 |
||||
} |
||||
|
||||
// #[inline]
|
||||
fn is_even(&self) -> bool { |
||||
!self.is_odd() |
||||
} |
||||
|
||||
#[inline] |
||||
fn div2(&mut self) { |
||||
self.shr(1); |
||||
} |
||||
|
||||
#[inline] |
||||
fn shr(&mut self, amt: u32) { |
||||
self.0 >>= amt; |
||||
} |
||||
|
||||
#[inline] |
||||
fn mul2(&mut self) { |
||||
*self *= Mersenne8::new(2); |
||||
} |
||||
|
||||
#[inline] |
||||
fn shl(&mut self, amt: u32) { |
||||
// FIXME: is this correct?
|
||||
self.0 <<= amt; |
||||
self.0 %= MS8; |
||||
} |
||||
|
||||
fn write_be<W: Write>(&self, mut writer: W) -> io::Result<()> { |
||||
let mut buf = [0u8; 4]; |
||||
BigEndian::write_u32(&mut buf, self.0); |
||||
writer.write_all(&buf)?; |
||||
Ok(()) |
||||
} |
||||
|
||||
fn read_be<R: Read>(&mut self, mut reader: R) -> io::Result<()> { |
||||
let mut buf = [0u8; 4]; |
||||
reader.read_exact(&mut buf)?; |
||||
self.0 = BigEndian::read_u32(&buf); |
||||
Ok(()) |
||||
} |
||||
} |
||||
|
||||
/// Extended Euclidean algorithm
|
||||
///
|
||||
/// Returns the `gcd(a,b)`, as well as the
|
||||
/// [Bézout coefficients](https://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity) `s` and `t` (with
|
||||
/// `sa + tb = gcd(a,b)`).
|
||||
///
|
||||
/// The function will neither panic nor overflow; however passing in `0` as either `a` or `b`
|
||||
/// will not give useful results for `s` and `t`.
|
||||
///
|
||||
/// Note: A non-recurring implementation will probably be faster, but the recursion is simpler
|
||||
/// to write.
|
||||
#[inline] |
||||
fn ext_euclid(a: u32, b: u32) -> (u32, i64, i64) { |
||||
// Bézout coefficients (`s` and `t`) are bound by `|s| <= |b/d|` and `|t| <= |a/d|`
|
||||
// (`d` being `gdc(a,b)`). (See https://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity)
|
||||
//
|
||||
// FIXME: Find out of there are any larger than i32::MAX. For now, we are using an `i64` to
|
||||
// avoid problems, at the expense of some runtime performance on 32 bit systems.
|
||||
|
||||
if b == 0 { |
||||
return (a, 1, 0); |
||||
} |
||||
|
||||
let res = ext_euclid(b, a % b); |
||||
let s = res.2; |
||||
let t = res.1 - i64::from(a / b) * res.2; |
||||
(res.0, s, t) |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
mod tests { |
||||
// There are copy & pasted results of calculations from external programs in these tests.
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))] |
||||
#![cfg_attr(feature = "cargo-clippy", allow(op_ref))] |
||||
// We test a few mathematical identities, including `c - c = 0`. Clippy complains about these
|
||||
// otherwise unusual expressions, so the lint is disabled.
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(eq_op))] |
||||
|
||||
use super::{ext_euclid, modular_pow, Mersenne8}; |
||||
use pairing::Field; |
||||
|
||||
#[test] |
||||
fn ext_euclid_simple() { |
||||
assert_eq!(ext_euclid(56, 15), (1, -4, 15)); |
||||
assert_eq!(ext_euclid(128, 44), (4, -1, 3)); |
||||
assert_eq!(ext_euclid(44, 128), (4, 3, -1)); |
||||
assert_eq!(ext_euclid(7, 0), (7, 1, 0)); |
||||
assert_eq!(ext_euclid(0, 7), (7, 0, 1)); |
||||
} |
||||
|
||||
#[test] |
||||
fn modular_pow_simple() { |
||||
assert_eq!(modular_pow(2, 8, 1024), 256); |
||||
|
||||
let mods: &[u64] = &[2, 7, 256, 32000, 4294967295]; |
||||
|
||||
for exp in 0..20u32 { |
||||
for base in 2..8u64 { |
||||
for &m in mods { |
||||
assert_eq!( |
||||
modular_pow(base as u32, exp, m as u32), |
||||
(base.pow(exp) % m) as u32 |
||||
) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
#[test] |
||||
fn construction() { |
||||
let a: Mersenne8 = 0u32.into(); |
||||
let b: Mersenne8 = 1u32.into(); |
||||
let c: Mersenne8 = 2147483649u32.into(); |
||||
let d: Mersenne8 = 1099511627776u64.into(); |
||||
|
||||
assert_eq!(a, 0); |
||||
assert_eq!(b, 1); |
||||
assert_eq!(c, 2); |
||||
assert_eq!(d, 512); |
||||
|
||||
assert_eq!(a, Mersenne8::new(0)); |
||||
assert_eq!(b, Mersenne8::new(1)); |
||||
assert_eq!(c, Mersenne8::new(2)); |
||||
assert_eq!(d, Mersenne8::new(512)); |
||||
} |
||||
|
||||
#[test] |
||||
fn addition() { |
||||
let a = Mersenne8::new(0); |
||||
let b = Mersenne8::new(1); |
||||
let c = Mersenne8::new(127); |
||||
let d = Mersenne8::new(1073741824); |
||||
let e = Mersenne8::new(2147483646); |
||||
|
||||
// lhs . rhs
|
||||
assert_eq!(a + b, Mersenne8::new(1)); |
||||
assert_eq!(c + c, Mersenne8::new(254)); |
||||
assert_eq!(d + c, Mersenne8::new(1073741951)); |
||||
assert_eq!(d + e, Mersenne8::new(3221225470)); |
||||
assert_eq!(d + e, 1073741823); |
||||
assert_eq!(e + e, Mersenne8::new(4294967292)); |
||||
|
||||
// &lhs . rhs
|
||||
assert_eq!(a + &b, Mersenne8::new(1)); |
||||
assert_eq!(c + &c, Mersenne8::new(254)); |
||||
assert_eq!(d + &c, Mersenne8::new(1073741951)); |
||||
assert_eq!(d + &e, Mersenne8::new(3221225470)); |
||||
assert_eq!(e + &e, Mersenne8::new(4294967292)); |
||||
|
||||
// lhs . &rhs
|
||||
assert_eq!(&a + b, Mersenne8::new(1)); |
||||
assert_eq!(&c + c, Mersenne8::new(254)); |
||||
assert_eq!(&d + c, Mersenne8::new(1073741951)); |
||||
assert_eq!(&d + e, Mersenne8::new(3221225470)); |
||||
assert_eq!(&e + e, Mersenne8::new(4294967292)); |
||||
|
||||
// &lhs . &rhs
|
||||
assert_eq!(&a + &b, Mersenne8::new(1)); |
||||
assert_eq!(&c + &c, Mersenne8::new(254)); |
||||
assert_eq!(&d + &c, Mersenne8::new(1073741951)); |
||||
assert_eq!(&d + &e, Mersenne8::new(3221225470)); |
||||
assert_eq!(&e + &e, Mersenne8::new(4294967292)); |
||||
|
||||
// lhs .= rhs
|
||||
let mut x = Mersenne8::new(8); |
||||
assert_eq!(x, Mersenne8::new(8)); |
||||
x += a; |
||||
assert_eq!(x, Mersenne8::new(8)); |
||||
x += b; |
||||
assert_eq!(x, Mersenne8::new(9)); |
||||
x += c; |
||||
assert_eq!(x, Mersenne8::new(136)); |
||||
x += d; |
||||
assert_eq!(x, Mersenne8::new(1073741960)); |
||||
x += e; |
||||
assert_eq!(x, Mersenne8::new(1073741959)); |
||||
|
||||
// lhs .= &rhs
|
||||
let mut y = Mersenne8::new(8); |
||||
assert_eq!(y, Mersenne8::new(8)); |
||||
y += &a; |
||||
assert_eq!(y, Mersenne8::new(8)); |
||||
y += &b; |
||||
assert_eq!(y, Mersenne8::new(9)); |
||||
y += &c; |
||||
assert_eq!(y, Mersenne8::new(136)); |
||||
y += &d; |
||||
assert_eq!(y, Mersenne8::new(1073741960)); |
||||
y += &e; |
||||
assert_eq!(y, Mersenne8::new(1073741959)); |
||||
} |
||||
|
||||
#[test] |
||||
fn subtraction() { |
||||
let a = Mersenne8::new(0); |
||||
let b = Mersenne8::new(1); |
||||
let c = Mersenne8::new(127); |
||||
let d = Mersenne8::new(1073741824); |
||||
let e = Mersenne8::new(2147483646); |
||||
|
||||
// lhs . rhs
|
||||
assert_eq!(a - b, Mersenne8::new(2147483646)); |
||||
assert_eq!(c - c, Mersenne8::new(0)); |
||||
assert_eq!(d - c, Mersenne8::new(1073741697)); |
||||
assert_eq!(d - e, Mersenne8::new(1073741825)); |
||||
|
||||
// &lhs . rhs
|
||||
assert_eq!(&a - b, Mersenne8::new(2147483646)); |
||||
assert_eq!(&c - c, Mersenne8::new(0)); |
||||
assert_eq!(&d - c, Mersenne8::new(1073741697)); |
||||
assert_eq!(&d - e, Mersenne8::new(1073741825)); |
||||
|
||||
// lhs . &rhs
|
||||
assert_eq!(a - &b, Mersenne8::new(2147483646)); |
||||
assert_eq!(c - &c, Mersenne8::new(0)); |
||||
assert_eq!(d - &c, Mersenne8::new(1073741697)); |
||||
assert_eq!(d - &e, Mersenne8::new(1073741825)); |
||||
|
||||
// &lhs . &rhs
|
||||
assert_eq!(&a - &b, Mersenne8::new(2147483646)); |
||||
assert_eq!(&c - &c, Mersenne8::new(0)); |
||||
assert_eq!(&d - &c, Mersenne8::new(1073741697)); |
||||
assert_eq!(&d - &e, Mersenne8::new(1073741825)); |
||||
|
||||
// lhs .= rhs
|
||||
let mut x = Mersenne8::new(17); |
||||
assert_eq!(x, Mersenne8::new(17)); |
||||
x -= a; |
||||
assert_eq!(x, Mersenne8::new(17)); |
||||
x -= b; |
||||
assert_eq!(x, Mersenne8::new(16)); |
||||
x -= c; |
||||
assert_eq!(x, Mersenne8::new(2147483536)); |
||||
x -= d; |
||||
assert_eq!(x, Mersenne8::new(1073741712)); |
||||
x -= e; |
||||
assert_eq!(x, Mersenne8::new(1073741713)); |
||||
|
||||
// lhs .= &rhs
|
||||
let mut y = Mersenne8::new(17); |
||||
assert_eq!(y, Mersenne8::new(17)); |
||||
y -= &a; |
||||
assert_eq!(y, Mersenne8::new(17)); |
||||
y -= &b; |
||||
assert_eq!(y, Mersenne8::new(16)); |
||||
y -= &c; |
||||
assert_eq!(y, Mersenne8::new(2147483536)); |
||||
y -= &d; |
||||
assert_eq!(y, Mersenne8::new(1073741712)); |
||||
y -= &e; |
||||
assert_eq!(y, Mersenne8::new(1073741713)); |
||||
} |
||||
|
||||
#[test] |
||||
fn multiplication() { |
||||
let a = Mersenne8::new(0); |
||||
let b = Mersenne8::new(1); |
||||
let c = Mersenne8::new(127); |
||||
let d = Mersenne8::new(1073741824); |
||||
let e = Mersenne8::new(384792341); |
||||
|
||||
// lhs . rhs
|
||||
assert_eq!(a * a, Mersenne8::new(0)); |
||||
assert_eq!(a * b, Mersenne8::new(0)); |
||||
assert_eq!(b * b, Mersenne8::new(1)); |
||||
assert_eq!(c * c, Mersenne8::new(16129)); |
||||
assert_eq!(d * c, Mersenne8::new(1073741887)); |
||||
assert_eq!(d * e, Mersenne8::new(1266137994)); |
||||
|
||||
// &lhs . rhs
|
||||
assert_eq!(&a * a, Mersenne8::new(0)); |
||||
assert_eq!(&a * b, Mersenne8::new(0)); |
||||
assert_eq!(&b * b, Mersenne8::new(1)); |
||||
assert_eq!(&c * c, Mersenne8::new(16129)); |
||||
assert_eq!(&d * c, Mersenne8::new(1073741887)); |
||||
assert_eq!(&d * e, Mersenne8::new(1266137994)); |
||||
|
||||
// lhs . &rhs
|
||||
assert_eq!(a * &a, Mersenne8::new(0)); |
||||
assert_eq!(a * &b, Mersenne8::new(0)); |
||||
assert_eq!(b * &b, Mersenne8::new(1)); |
||||
assert_eq!(c * &c, Mersenne8::new(16129)); |
||||
assert_eq!(d * &c, Mersenne8::new(1073741887)); |
||||
assert_eq!(d * &e, Mersenne8::new(1266137994)); |
||||
|
||||
// &lhs . &rhs
|
||||
assert_eq!(&a * &a, Mersenne8::new(0)); |
||||
assert_eq!(&a * &b, Mersenne8::new(0)); |
||||
assert_eq!(&b * &b, Mersenne8::new(1)); |
||||
assert_eq!(&c * &c, Mersenne8::new(16129)); |
||||
assert_eq!(&d * &c, Mersenne8::new(1073741887)); |
||||
assert_eq!(&d * &e, Mersenne8::new(1266137994)); |
||||
|
||||
// lhs .= rhs
|
||||
let mut x = Mersenne8::new(17); |
||||
x *= b; |
||||
assert_eq!(x, Mersenne8::new(17)); |
||||
x *= c; |
||||
assert_eq!(x, Mersenne8::new(2159)); |
||||
x *= d; |
||||
assert_eq!(x, Mersenne8::new(1073742903)); |
||||
x *= e; |
||||
assert_eq!(x, Mersenne8::new(1992730062)); |
||||
|
||||
// // lhs .= &rhs
|
||||
let mut y = Mersenne8::new(17); |
||||
y *= &b; |
||||
assert_eq!(y, Mersenne8::new(17)); |
||||
y *= &c; |
||||
assert_eq!(y, Mersenne8::new(2159)); |
||||
y *= &d; |
||||
assert_eq!(y, Mersenne8::new(1073742903)); |
||||
y *= &e; |
||||
assert_eq!(y, Mersenne8::new(1992730062)); |
||||
} |
||||
|
||||
#[test] |
||||
fn square() { |
||||
let a = Mersenne8::new(7); |
||||
let b = Mersenne8::new(1073729479); |
||||
|
||||
let mut a_sq = a; |
||||
a_sq.square(); |
||||
assert_eq!(a_sq, a * a); |
||||
assert_eq!(a_sq, 49); |
||||
|
||||
let mut b_sq = b; |
||||
b_sq.square(); |
||||
assert_eq!(b_sq, b * b); |
||||
assert_eq!(b_sq, 689257592); |
||||
} |
||||
|
||||
#[test] |
||||
fn double() { |
||||
let mut a = Mersenne8::new(0); |
||||
let mut b = Mersenne8::new(1); |
||||
let mut c = Mersenne8::new(9); |
||||
let mut d = Mersenne8::new(2147483646); |
||||
|
||||
a.double(); |
||||
b.double(); |
||||
c.double(); |
||||
d.double(); |
||||
|
||||
assert_eq!(a, 0); |
||||
assert_eq!(b, 2); |
||||
assert_eq!(c, 18); |
||||
assert_eq!(d, 2147483645); |
||||
} |
||||
|
||||
#[test] |
||||
fn negate() { |
||||
let mut a = Mersenne8::new(0); |
||||
let mut b = Mersenne8::new(1); |
||||
let mut c = Mersenne8::new(9); |
||||
let mut d = Mersenne8::new(17); |
||||
let mut e = Mersenne8::new(16441); |
||||
let mut f = Mersenne8::new(1073754169); |
||||
|
||||
a.negate(); |
||||
b.negate(); |
||||
c.negate(); |
||||
d.negate(); |
||||
e.negate(); |
||||
f.negate(); |
||||
|
||||
assert_eq!(a, 0); |
||||
assert_eq!(b, 2147483646); |
||||
assert_eq!(c, 2147483638); |
||||
assert_eq!(d, 2147483630); |
||||
assert_eq!(e, 2147467206); |
||||
assert_eq!(f, 1073729478); |
||||
} |
||||
|
||||
#[test] |
||||
fn inverse() { |
||||
let a = Mersenne8::new(0); |
||||
let b = Mersenne8::new(1); |
||||
let c = Mersenne8::new(2); |
||||
let d = Mersenne8::new(1234); |
||||
let e = Mersenne8::new(1073741823); |
||||
let f = Mersenne8::new(46341); |
||||
let g = Mersenne8::new(2147483646); |
||||
let h = Mersenne8::new(923042); |
||||
|
||||
assert_eq!(a.inverse(), None); |
||||
assert_eq!(b.inverse(), Some(Mersenne8::new(1))); |
||||
assert_eq!(c.inverse(), Some(Mersenne8::new(1073741824))); |
||||
assert_eq!(d.inverse(), Some(Mersenne8::new(158363867))); |
||||
assert_eq!(e.inverse(), Some(Mersenne8::new(2147483645))); |
||||
assert_eq!(f.inverse(), Some(Mersenne8::new(2147020238))); |
||||
assert_eq!(g.inverse(), Some(Mersenne8::new(2147483646))); |
||||
assert_eq!(h.inverse(), Some(Mersenne8::new(1271194309))); |
||||
|
||||
assert_eq!(b.inverse().unwrap().inverse().unwrap(), b); |
||||
assert_eq!(c.inverse().unwrap().inverse().unwrap(), c); |
||||
assert_eq!(d.inverse().unwrap().inverse().unwrap(), d); |
||||
assert_eq!(e.inverse().unwrap().inverse().unwrap(), e); |
||||
assert_eq!(f.inverse().unwrap().inverse().unwrap(), f); |
||||
assert_eq!(g.inverse().unwrap().inverse().unwrap(), g); |
||||
assert_eq!(g.inverse().unwrap().inverse().unwrap(), g); |
||||
assert_eq!(h.inverse().unwrap().inverse().unwrap(), h); |
||||
} |
||||
|
||||
#[test] |
||||
fn frobenius_map() { |
||||
let a = Mersenne8::new(0); |
||||
let b = Mersenne8::new(1); |
||||
let c = Mersenne8::new(2); |
||||
let d = Mersenne8::new(1234); |
||||
let e = Mersenne8::new(1073741823); |
||||
let f = Mersenne8::new(46341); |
||||
let g = Mersenne8::new(2147483646); |
||||
let h = Mersenne8::new(923042); |
||||
|
||||
let mut a_fm = a; |
||||
let mut b_fm = b; |
||||
let mut c_fm = c; |
||||
let mut d_fm = d; |
||||
let mut e_fm = e; |
||||
let mut f_fm = f; |
||||
let mut g_fm = g; |
||||
let mut h_fm = h; |
||||
|
||||
a_fm.frobenius_map(1); |
||||
a_fm.frobenius_map(2); |
||||
a_fm.frobenius_map(3); |
||||
b_fm.frobenius_map(1); |
||||
b_fm.frobenius_map(2); |
||||
b_fm.frobenius_map(3); |
||||
c_fm.frobenius_map(1); |
||||
c_fm.frobenius_map(2); |
||||
c_fm.frobenius_map(3); |
||||
d_fm.frobenius_map(1); |
||||
d_fm.frobenius_map(2); |
||||
d_fm.frobenius_map(3); |
||||
e_fm.frobenius_map(1); |
||||
e_fm.frobenius_map(2); |
||||
e_fm.frobenius_map(3); |
||||
f_fm.frobenius_map(1); |
||||
f_fm.frobenius_map(2); |
||||
f_fm.frobenius_map(3); |
||||
g_fm.frobenius_map(1); |
||||
g_fm.frobenius_map(2); |
||||
g_fm.frobenius_map(3); |
||||
h_fm.frobenius_map(1); |
||||
h_fm.frobenius_map(2); |
||||
h_fm.frobenius_map(3); |
||||
|
||||
assert_eq!(a_fm, a); |
||||
assert_eq!(b_fm, b); |
||||
assert_eq!(c_fm, c); |
||||
assert_eq!(d_fm, d); |
||||
assert_eq!(e_fm, e); |
||||
assert_eq!(f_fm, f); |
||||
assert_eq!(g_fm, g); |
||||
assert_eq!(h_fm, h); |
||||
} |
||||
} |
Loading…
Reference in new issue