threshold_crypto/src/mock/mod.rs

326 lines
8.0 KiB
Rust

//! 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 ff::{Field, PrimeField, ScalarEngine};
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
use pairing::{Engine, PairingCurveAffine};
use rand::RngCore;
pub use self::ms8::Mersenne8;
/// The size of a key's representation in bytes.
pub const PK_SIZE: usize = 4;
/// The size of a signature's representation in bytes.
pub const SIG_SIZE: usize = 4;
/// 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 PairingCurveAffine for Ms8Affine {
type Prepared = Ms8Affine;
type Pair = Ms8Affine;
type PairingResult = Mersenne8;
fn prepare(&self) -> Self::Prepared {
*self
}
fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
self.0 * other.0
}
}
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 ScalarEngine for Mocktography {
type Fr = Mersenne8;
}
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;
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
}
fn miller_loop<'a, I>(_i: I) -> Self::Fqk
where
I: IntoIterator<
Item = &'a (
&'a <Self::G1Affine as PairingCurveAffine>::Prepared,
&'a <Self::G2Affine as PairingCurveAffine>::Prepared,
),
>,
{
// Unused?
unimplemented!()
}
fn final_exponentiation(_: &Self::Fqk) -> Option<Self::Fqk> {
// Unused?
unimplemented!()
}
}
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 Uncompressed = Ms8Affine;
type Compressed = Ms8Affine;
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 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 random<R: RngCore + ?std::marker::Sized>(rng: &mut R) -> Self {
Self(Mersenne8::random(rng))
}
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.
#![allow(clippy::unreadable_literal)]
use super::{EncodedPoint, Mersenne8, Mocktography, Ms8Affine, PK_SIZE, SIG_SIZE};
use pairing::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));
}
}
#[test]
fn size() {
assert_eq!(<Ms8Affine as EncodedPoint>::size(), PK_SIZE);
assert_eq!(<Ms8Affine as EncodedPoint>::size(), SIG_SIZE);
}
}