Browse Source

add mimc7

pull/1/head
arnaucube 4 years ago
parent
commit
8e81dc980e
4 changed files with 271 additions and 0 deletions
  1. +3
    -0
      .gitignore
  2. +12
    -0
      Cargo.toml
  3. +8
    -0
      README.md
  4. +248
    -0
      src/lib.rs

+ 3
- 0
.gitignore

@ -0,0 +1,3 @@
/target
**/*.rs.bk
Cargo.lock

+ 12
- 0
Cargo.toml

@ -0,0 +1,12 @@
[package]
name = "mimc-rs"
version = "0.1.0"
authors = ["arnaucube <root@arnaucube.com>"]
edition = "2018"
[dependencies]
num = "0.2.0"
num-bigint = "0.2.2"
num-traits = "0.2.8"
tiny-keccak = "1.5"
rustc-hex = "1.0.0"

+ 8
- 0
README.md

@ -0,0 +1,8 @@
# mimc-rs
MIMC7 hash implementation in Rust
https://eprint.iacr.org/2016/492.pdf
## Warning
Do not use in production

+ 248
- 0
src/lib.rs

@ -0,0 +1,248 @@
extern crate num;
extern crate num_bigint;
extern crate num_traits;
use tiny_keccak::Keccak;
use num_bigint::{BigInt, Sign};
use num_traits::Zero;
const SEED: &str = "mimc";
pub struct Constants {
seed_hash: BigInt,
iv: BigInt,
r: BigInt,
n_rounds: i64,
cts: Vec<BigInt>,
}
pub fn modulus(a: &BigInt, m: &BigInt) -> BigInt {
((a % m) + m) % m
}
pub fn generate_constants() -> Constants {
let r: BigInt = BigInt::parse_bytes(
b"21888242871839275222246405745257275088548364400416034343698204186575808495617",
10,
)
.unwrap();
let mut keccak = Keccak::new_keccak256();
let mut h = [0u8; 32];
keccak.update(SEED.as_bytes());
keccak.finalize(&mut h);
let mut keccak = Keccak::new_keccak256();
let mut h_iv = [0u8; 32];
let seed_iv = format!("{}{}", SEED, "_iv");
keccak.update(seed_iv.as_bytes());
keccak.finalize(&mut h_iv);
let seed_hash: BigInt = BigInt::from_bytes_be(Sign::Plus, &h);
let c: BigInt = BigInt::from_bytes_be(Sign::Plus, &h_iv);
let iv: BigInt = c % &r;
let n_rounds: i64 = 91;
let cts = get_constants(&r, SEED, n_rounds);
Constants {
seed_hash: seed_hash,
iv: iv,
r: r,
n_rounds: n_rounds,
cts: cts,
}
}
pub fn get_constants(r: &BigInt, seed: &str, n_rounds: i64) -> Vec<BigInt> {
let mut cts: Vec<BigInt> = Vec::new();
cts.push(Zero::zero());
let mut keccak = Keccak::new_keccak256();
let mut h = [0u8; 32];
keccak.update(seed.as_bytes());
keccak.finalize(&mut h);
let mut c = BigInt::from_bytes_be(Sign::Plus, &h);
for _ in 1..n_rounds {
let mut keccak = Keccak::new_keccak256();
let mut h = [0u8; 32];
let (_, c_bytes) = c.to_bytes_be();
keccak.update(&c_bytes[..]);
keccak.finalize(&mut h);
c = BigInt::from_bytes_be(Sign::Plus, &h);
let n = modulus(&c, &r);
cts.push(n);
}
cts
}
pub fn mimc7_hash_generic(r: &BigInt, x_in: &BigInt, k: &BigInt, n_rounds: i64) -> BigInt {
let cts = get_constants(r, SEED, n_rounds);
let mut h: BigInt = Zero::zero();
for i in 0..n_rounds as usize {
let mut t: BigInt;
if i == 0 {
t = x_in + k;
} else {
t = h + k + &cts[i];
}
t = modulus(&t, &r);
let t2 = &t * &t;
let t4 = &t2 * &t2;
h = (t4 * t2) * t;
h = modulus(&h, &r);
}
modulus(&(h + k), &r)
}
pub fn hash_generic(iv: BigInt, arr: Vec<BigInt>, r: BigInt, n_rounds: i64) -> BigInt {
let mut h: BigInt = iv;
for i in 0..arr.len() {
h = mimc7_hash_generic(&r, &h, &arr[i], n_rounds);
}
h
}
pub struct Mimc7 {
constants: Constants,
}
impl Mimc7 {
pub fn new() -> Mimc7 {
Mimc7 {
constants: generate_constants(),
}
}
pub fn hash(&self, arr: Vec<BigInt>) -> BigInt {
// TODO check if arr elements are inside the Finite Field over R
let mut h: BigInt = Zero::zero();
for i in 0..arr.len() {
h = &h + &arr[i] + self.mimc7_hash(&arr[i], &h);
h = modulus(&h, &self.constants.r)
}
modulus(&h, &self.constants.r)
}
pub fn mimc7_hash(&self, x_in: &BigInt, k: &BigInt) -> BigInt {
let mut h: BigInt = Zero::zero();
for i in 0..self.constants.n_rounds as usize {
let t: BigInt;
if i == 0 {
t = x_in + k;
} else {
t = h + k + &self.constants.cts[i];
}
let t2 = &t * &t;
let t4 = &t2 * &t2;
h = (t4 * t2) * t;
h = modulus(&h, &self.constants.r);
}
modulus(&(h + k), &self.constants.r)
}
}
#[cfg(test)]
mod tests {
use super::*;
use rustc_hex::ToHex;
#[test]
fn test_sha3() {
let mut keccak = Keccak::new_keccak256();
let mut res = [0u8; 32];
keccak.update(SEED.as_bytes());
keccak.finalize(&mut res);
assert_eq!(
res.to_hex(),
"b6e489e6b37224a50bebfddbe7d89fa8fdcaa84304a70bd13f79b5d9f7951e9e"
);
let mut keccak = Keccak::new_keccak256();
let mut res = [0u8; 32];
keccak.update(SEED.as_bytes());
keccak.finalize(&mut res);
let c = BigInt::from_bytes_be(Sign::Plus, &res);
assert_eq!(
c.to_string(),
"82724731331859054037315113496710413141112897654334566532528783843265082629790"
);
}
#[test]
fn test_generate_constants() {
let constants = generate_constants();
assert_eq!(
"20888961410941983456478427210666206549300505294776164667214940546594746570981",
constants.cts[1].to_string()
);
}
#[test]
fn test_mimc7_generic() {
let b1: BigInt = BigInt::parse_bytes(b"1", 10).unwrap();
let b2: BigInt = BigInt::parse_bytes(b"2", 10).unwrap();
let constants = generate_constants();
let h1 = mimc7_hash_generic(&constants.r, &b1, &b2, 91);
assert_eq!(
h1.to_string(),
"10594780656576967754230020536574539122676596303354946869887184401991294982664"
);
}
#[test]
fn test_mimc7() {
let b12: BigInt = BigInt::parse_bytes(b"12", 10).unwrap();
let b45: BigInt = BigInt::parse_bytes(b"45", 10).unwrap();
let b78: BigInt = BigInt::parse_bytes(b"78", 10).unwrap();
let b41: BigInt = BigInt::parse_bytes(b"41", 10).unwrap();
let mut big_arr1: Vec<BigInt> = Vec::new();
big_arr1.push(b12.clone());
let mimc7 = Mimc7::new();
let h1 = mimc7.hash(big_arr1);
let (_, h1_bytes) = h1.to_bytes_be();
assert_eq!(
h1_bytes.to_hex(),
"237c92644dbddb86d8a259e0e923aaab65a93f1ec5758b8799988894ac0958fd"
);
let mh2 = mimc7.mimc7_hash(&b12, &b45);
let (_, mh2_bytes) = mh2.to_bytes_be();
assert_eq!(
mh2_bytes.to_hex(),
"2ba7ebad3c6b6f5a20bdecba2333c63173ca1a5f2f49d958081d9fa7179c44e4"
);
let mut big_arr2: Vec<BigInt> = Vec::new();
big_arr2.push(b78.clone());
big_arr2.push(b41.clone());
let h2 = mimc7.hash(big_arr2);
let (_, h2_bytes) = h2.to_bytes_be();
assert_eq!(
h2_bytes.to_hex(),
"067f3202335ea256ae6e6aadcd2d5f7f4b06a00b2d1e0de903980d5ab552dc70"
);
let mut big_arr2: Vec<BigInt> = Vec::new();
big_arr2.push(b12.clone());
big_arr2.push(b45.clone());
let h1 = mimc7.hash(big_arr2);
let (_, h1_bytes) = h1.to_bytes_be();
assert_eq!(
h1_bytes.to_hex(),
"15ff7fe9793346a17c3150804bcb36d161c8662b110c50f55ccb7113948d8879"
);
let mut big_arr1: Vec<BigInt> = Vec::new();
big_arr1.push(b12.clone());
big_arr1.push(b45.clone());
big_arr1.push(b78.clone());
big_arr1.push(b41.clone());
let mimc7 = Mimc7::new();
let h1 = mimc7.hash(big_arr1);
let (_, h1_bytes) = h1.to_bytes_be();
assert_eq!(
h1_bytes.to_hex(),
"284bc1f34f335933a23a433b6ff3ee179d682cd5e5e2fcdd2d964afa85104beb"
);
}
}

Loading…
Cancel
Save