From 607ea8a4f00c0513b627b1cbb8fe3d7efb696fbc Mon Sep 17 00:00:00 2001 From: Denis Varlakov Date: Wed, 3 Feb 2021 16:18:37 +0700 Subject: [PATCH] Ring algorithm support (#103) * Add arithmetic wrapper * Bump version --- Cargo.toml | 5 +- src/arithmetic/big_gmp.rs | 125 +++++++++++++++++++++++++++++++++++++- src/arithmetic/traits.rs | 1 + 3 files changed, 129 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b7db4ff1..35c07131 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "curv" -version = "0.5.5" +version = "0.5.6" edition = "2018" authors = ["Omer Shlomovits"] license = "MIT" @@ -24,6 +24,8 @@ blake2b_simd = "0.5.7" derivative = "2.1.1" pairing-plus = "0.19" ff-zeroize = "0.6.3" +ring-algorithm = "0.2.3" +num-traits = "0.2" [dependencies.rust-gmp-kzen] version = "0.5.0" @@ -60,3 +62,4 @@ version = "0.14" bincode = "1.1" serde_json = "1.0" paste = "1.0.2" +proptest = "0.10" diff --git a/src/arithmetic/big_gmp.rs b/src/arithmetic/big_gmp.rs index 9026f1a2..e9aae51f 100644 --- a/src/arithmetic/big_gmp.rs +++ b/src/arithmetic/big_gmp.rs @@ -22,8 +22,8 @@ use super::traits::{ use gmp::mpz::Mpz; use std::borrow::Borrow; -use std::ptr; use std::sync::atomic; +use std::{ops, ptr}; pub type BigInt = Mpz; @@ -162,6 +162,92 @@ impl ConvertFrom for u64 { } } +/// Wraps BigInt making it compatible with [ring_algorithm] crate +#[derive(Eq, PartialEq, Clone, Debug)] +pub struct Arithmetic(T); + +impl Arithmetic { + pub fn wrap(n: BigInt) -> Self { + Self(n) + } +} + +impl Arithmetic { + pub fn into_inner(self) -> T { + self.0 + } +} + +impl ops::Deref for Arithmetic { + type Target = T; + fn deref(&self) -> &T { + &self.0 + } +} + +impl ops::DerefMut for Arithmetic { + fn deref_mut(&mut self) -> &mut T { + &mut self.0 + } +} + +macro_rules! impl_ops { + ($($op: ident $func:ident ($($t:tt)+)),+$(,)?) => { + $( + impl ops::$op for &Arithmetic { + type Output = Arithmetic; + fn $func(self, rhs: Self) -> Self::Output { + Arithmetic(&self.0 $($t)+ &rhs.0) + } + } + impl ops::$op for Arithmetic { + type Output = Self; + fn $func(self, rhs: Self) -> Self::Output { + Arithmetic(self.0 $($t)+ rhs.0) + } + } + )+ + }; +} + +impl_ops! { + Add add (+), + Sub sub (-), + Mul mul (*), + Div div (/), + Rem rem (%), +} + +impl num_traits::Zero for Arithmetic { + fn zero() -> Self { + Arithmetic(BigInt::zero()) + } + + fn is_zero(&self) -> bool { + self.0 == BigInt::zero() + } +} + +impl num_traits::One for Arithmetic { + fn one() -> Self { + Arithmetic(BigInt::one()) + } +} + +impl ring_algorithm::RingNormalize for Arithmetic { + fn leading_unit(&self) -> Self { + if self.0 >= BigInt::zero() { + Arithmetic(BigInt::one()) + } else { + Arithmetic(-BigInt::one()) + } + } + + fn normalize_mut(&mut self) { + *self = Arithmetic(self.abs()) + } +} + #[cfg(test)] mod tests { use super::Converter; @@ -279,3 +365,40 @@ mod tests { assert_eq!(Mpz::from_hex(&a.to_hex()), a); } } + +/// Tests that ring_algorithm work as expected +#[cfg(test)] +mod ring_algorithm_test { + const PRIME: u32 = u32::MAX - 4; + + use super::*; + use crate::arithmetic::traits::EGCD; + + proptest::proptest! { + #[test] + fn fuzz_inverse(n in 1..PRIME) { + test_inverse(BigInt::from(n)) + } + #[test] + fn fuzz_xgcd(a in 1u32.., b in 1u32..) { + test_xgcd(BigInt::from(a), BigInt::from(b)) + } + } + + fn test_inverse(n: BigInt) { + let prime = BigInt::from(PRIME); + let n_inv_expected = n.invert(&prime).unwrap(); + let n_inv_actual = + ring_algorithm::modulo_inverse(Arithmetic(n), Arithmetic(prime.clone())).unwrap(); + assert_eq!(n_inv_expected, n_inv_actual.into_inner().modulus(&prime)); + } + + fn test_xgcd(a: BigInt, b: BigInt) { + let (s1, p1, q1) = BigInt::egcd(&a, &b); + let (s2, p2, q2) = + ring_algorithm::normalized_extended_euclidian_algorithm(Arithmetic(a), Arithmetic(b)); + assert_eq!(s1, s2.into_inner()); + assert_eq!(p1, p2.into_inner()); + assert_eq!(q1, q2.into_inner()); + } +} diff --git a/src/arithmetic/traits.rs b/src/arithmetic/traits.rs index a04184c9..b2358f2c 100644 --- a/src/arithmetic/traits.rs +++ b/src/arithmetic/traits.rs @@ -62,4 +62,5 @@ pub trait BitManipulation { pub trait ConvertFrom { fn _from(_: &T) -> Self; } + //use std::ops::{Add, Div, Mul, Neg, Rem, Shr, Sub};