From 2b0e2faa3ea469871bd9b5fbf5113bd3df79b150 Mon Sep 17 00:00:00 2001 From: arnaucube Date: Sun, 19 Jul 2020 12:00:52 +0200 Subject: [PATCH 1/4] gen_constants crate appart --- gen_constants/.gitignore | 3 + gen_constants/Cargo.toml | 13 ++++ gen_constants/src/main.rs | 154 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 gen_constants/.gitignore create mode 100644 gen_constants/Cargo.toml create mode 100644 gen_constants/src/main.rs diff --git a/gen_constants/.gitignore b/gen_constants/.gitignore new file mode 100644 index 0000000..6936990 --- /dev/null +++ b/gen_constants/.gitignore @@ -0,0 +1,3 @@ +/target +**/*.rs.bk +Cargo.lock diff --git a/gen_constants/Cargo.toml b/gen_constants/Cargo.toml new file mode 100644 index 0000000..cb51b80 --- /dev/null +++ b/gen_constants/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "gen_constants" +version = "0.0.1" +authors = ["arnaucube "] +edition = "2018" +license = "GPL-3.0" + +[dependencies] +num = "0.2.0" +num-bigint = "0.2.2" +num-traits = "0.2.8" +blake2 = "0.8" +rustc-hex = "1.0.0" diff --git a/gen_constants/src/main.rs b/gen_constants/src/main.rs new file mode 100644 index 0000000..085ecf3 --- /dev/null +++ b/gen_constants/src/main.rs @@ -0,0 +1,154 @@ +use blake2::digest::{Input, VariableOutput}; +use blake2::VarBlake2b; + +extern crate num; +extern crate num_bigint; +extern crate num_traits; +use num_bigint::{BigInt, Sign}; +use num_traits::{One, Zero}; + +const SEED: &str = "poseidon"; +const NROUNDSF: usize = 8; +const NROUNDSP: usize = 57; +const T: usize = 6; + +#[derive(Debug)] +pub struct Constants { + c: Vec, + m: Vec>, +} + +pub fn generate_constants() -> Constants { + let r: BigInt = BigInt::parse_bytes( + b"21888242871839275222246405745257275088548364400416034343698204186575808495617", + 10, + ) + .unwrap(); + + let c = get_pseudo_random(&r, format!("{}{}", SEED, "_constants"), NROUNDSF + NROUNDSP); + let m = get_mds(&r); + Constants { c: c, m: m } +} + +pub fn get_pseudo_random(r: &BigInt, seed: String, n: usize) -> Vec { + let mut hasher = VarBlake2b::new(32).unwrap(); + hasher.input(seed.as_bytes()); + let mut h = hasher.vec_result(); + + let mut res: Vec = Vec::new(); + while res.len() < n { + let new_n: BigInt = modulus(&BigInt::from_bytes_le(Sign::Plus, &h), &r); + res.push(new_n); + let mut hasher = VarBlake2b::new(32).unwrap(); + hasher.input(h); + h = hasher.vec_result(); + } + res +} + +pub fn nonce_to_string(n: usize) -> String { + let mut r = format!("{}", n); + while r.len() < 4 { + r = format!("0{}", r); + } + r +} + +pub fn get_mds(r: &BigInt) -> Vec> { + let mut nonce = 0; + let mut cauchy_matrix = get_pseudo_random( + r, + format!("{}_matrix_{}", SEED, nonce_to_string(nonce)), + T * 2, + ); + while !check_all_different(&cauchy_matrix) { + nonce = nonce + 1; + cauchy_matrix = get_pseudo_random( + r, + format!("{}_matrix_{}", SEED, nonce_to_string(nonce)), + T * 2, + ); + } + let mut m: Vec> = Vec::new(); + for i in 0..T { + let mut mi: Vec = Vec::new(); + for j in 0..T { + mi.push(modinv( + &modulus(&(&cauchy_matrix[i] - &cauchy_matrix[T + j]), &r), + &r, + )); + } + m.push(mi); + } + m +} + +pub fn check_all_different(v: &Vec) -> bool { + let zero: BigInt = Zero::zero(); + for i in 0..v.len() { + if v[i] == zero { + return false; + } + for j in i + 1..v.len() { + if v[i] == v[j] { + return false; + } + } + } + true +} + +pub fn modulus(a: &BigInt, m: &BigInt) -> BigInt { + ((a % m) + m) % m +} + +pub fn modinv(a: &BigInt, q: &BigInt) -> BigInt { + let mut mn = (q.clone(), a.clone()); + let mut xy: (BigInt, BigInt) = (Zero::zero(), One::one()); + + let big_zero: BigInt = Zero::zero(); + while mn.1 != big_zero { + xy = (xy.1.clone(), xy.0 - (mn.0.clone() / mn.1.clone()) * xy.1); + mn = (mn.1.clone(), modulus(&mn.0, &mn.1)); + } + + while xy.0 < Zero::zero() { + xy.0 = modulus(&xy.0, q); + } + xy.0 +} + +fn main() { + let c = generate_constants(); + println!("let c_str: Vec<&str> = vec!["); + for i in 0..c.c.len() { + println!(" {:?},", c.c[i].to_string()); + } + println!("];\n"); + println!("let m_str: Vec> = vec!["); + for i in 0..c.m.len() { + println!(" vec!["); + for j in 0..c.m[i].len() { + println!(" {:?},", c.m[i][j].to_string()); + } + println!(" ],"); + } + println!("];\n"); +} + +#[cfg(test)] +mod tests { + use super::*; + use rustc_hex::ToHex; + + #[test] + fn test_blake2_version() { + let mut hasher = VarBlake2b::new(32).unwrap(); + hasher.input(b"poseidon_constants"); + let h = hasher.vec_result(); + assert_eq!( + h.to_hex(), + "e57ba154fb2c47811dc1a2369b27e25a44915b4e4ece4eb8ec74850cb78e01b1" + ); + } +} From 89792330c7faaf2b19b040c3cba46f49544773ee Mon Sep 17 00:00:00 2001 From: arnaucube Date: Sun, 19 Jul 2020 12:08:27 +0200 Subject: [PATCH 2/4] Add initial migration from BigInt to ff::Fr --- Cargo.toml | 10 +- src/lib.rs | 493 ++++++++++++++++++++++------------------------------- 2 files changed, 204 insertions(+), 299 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 824e242..6bbe2da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "poseidon-rs" -version = "0.0.1" +version = "0.0.3" authors = ["arnaucube "] edition = "2018" license = "GPL-3.0" @@ -9,8 +9,6 @@ repository = "https://github.com/arnaucube/poseidon-rs" readme = "README.md" [dependencies] -num = "0.2.0" -num-bigint = "0.2.2" -num-traits = "0.2.8" -blake2 = "0.8" -rustc-hex = "1.0.0" +ff = {package="ff_ce" , version="0.11", features = ["derive"]} +rand = "0.4" + diff --git a/src/lib.rs b/src/lib.rs index 337fe30..2953210 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,136 +1,158 @@ -extern crate num; -extern crate num_bigint; -extern crate num_traits; +extern crate rand; +#[macro_use] +extern crate ff; +use ff::*; -use blake2::digest::{Input, VariableOutput}; -use blake2::VarBlake2b; +#[derive(PrimeField)] +#[PrimeFieldModulus = "21888242871839275222246405745257275088548364400416034343698204186575808495617"] +#[PrimeFieldGenerator = "7"] +pub struct Fr(FrRepr); -use num_bigint::{BigInt, Sign}; -use num_traits::{One, Zero}; - -const SEED: &str = "poseidon"; const NROUNDSF: usize = 8; const NROUNDSP: usize = 57; const T: usize = 6; +#[derive(Debug)] pub struct Constants { - r: BigInt, - c: Vec, - m: Vec>, -} - -pub fn generate_constants() -> Constants { - let r: BigInt = BigInt::parse_bytes( - b"21888242871839275222246405745257275088548364400416034343698204186575808495617", - 10, - ) - .unwrap(); - let c = get_pseudo_random(&r, format!("{}{}", SEED, "_constants"), NROUNDSF + NROUNDSP); - let m = get_mds(&r); - Constants { r: r, c: c, m: m } -} - -pub fn get_pseudo_random(r: &BigInt, seed: String, n: usize) -> Vec { - let mut hasher = VarBlake2b::new(32).unwrap(); - hasher.input(seed.as_bytes()); - let mut h = hasher.vec_result(); - - let mut res: Vec = Vec::new(); - while res.len() < n { - let new_n: BigInt = modulus(&BigInt::from_bytes_le(Sign::Plus, &h), &r); - res.push(new_n); - let mut hasher = VarBlake2b::new(32).unwrap(); - hasher.input(h); - h = hasher.vec_result(); - } - res + c: Vec, + m: Vec>, } -pub fn nonce_to_string(n: usize) -> String { - let mut r = format!("{}", n); - while r.len() < 4 { - r = format!("0{}", r); - } - r -} -pub fn get_mds(r: &BigInt) -> Vec> { - let mut nonce = 0; - let mut cauchy_matrix = get_pseudo_random( - r, - format!("{}_matrix_{}", SEED, nonce_to_string(nonce)), - T * 2, - ); - while !check_all_different(&cauchy_matrix) { - nonce = nonce + 1; - cauchy_matrix = get_pseudo_random( - r, - format!("{}_matrix_{}", SEED, nonce_to_string(nonce)), - T * 2, - ); +pub fn load_constants() -> Constants { + let c_str: Vec<&str> = vec![ + "14397397413755236225575615486459253198602422701513067526754101844196324375522", + "10405129301473404666785234951972711717481302463898292859783056520670200613128", + "5179144822360023508491245509308555580251733042407187134628755730783052214509", + "9132640374240188374542843306219594180154739721841249568925550236430986592615", + "20360807315276763881209958738450444293273549928693737723235350358403012458514", + "17933600965499023212689924809448543050840131883187652471064418452962948061619", + "3636213416533737411392076250708419981662897009810345015164671602334517041153", + "2008540005368330234524962342006691994500273283000229509835662097352946198608", + "16018407964853379535338740313053768402596521780991140819786560130595652651567", + "20653139667070586705378398435856186172195806027708437373983929336015162186471", + "17887713874711369695406927657694993484804203950786446055999405564652412116765", + "4852706232225925756777361208698488277369799648067343227630786518486608711772", + "8969172011633935669771678412400911310465619639756845342775631896478908389850", + "20570199545627577691240476121888846460936245025392381957866134167601058684375", + "16442329894745639881165035015179028112772410105963688121820543219662832524136", + "20060625627350485876280451423010593928172611031611836167979515653463693899374", + "16637282689940520290130302519163090147511023430395200895953984829546679599107", + "15599196921909732993082127725908821049411366914683565306060493533569088698214", + "16894591341213863947423904025624185991098788054337051624251730868231322135455", + "1197934381747032348421303489683932612752526046745577259575778515005162320212", + "6172482022646932735745595886795230725225293469762393889050804649558459236626", + "21004037394166516054140386756510609698837211370585899203851827276330669555417", + "15262034989144652068456967541137853724140836132717012646544737680069032573006", + "15017690682054366744270630371095785995296470601172793770224691982518041139766", + "15159744167842240513848638419303545693472533086570469712794583342699782519832", + "11178069035565459212220861899558526502477231302924961773582350246646450941231", + "21154888769130549957415912997229564077486639529994598560737238811887296922114", + "20162517328110570500010831422938033120419484532231241180224283481905744633719", + "2777362604871784250419758188173029886707024739806641263170345377816177052018", + "15732290486829619144634131656503993123618032247178179298922551820261215487562", + "6024433414579583476444635447152826813568595303270846875177844482142230009826", + "17677827682004946431939402157761289497221048154630238117709539216286149983245", + "10716307389353583413755237303156291454109852751296156900963208377067748518748", + "14925386988604173087143546225719076187055229908444910452781922028996524347508", + "8940878636401797005293482068100797531020505636124892198091491586778667442523", + "18911747154199663060505302806894425160044925686870165583944475880789706164410", + "8821532432394939099312235292271438180996556457308429936910969094255825456935", + "20632576502437623790366878538516326728436616723089049415538037018093616927643", + "71447649211767888770311304010816315780740050029903404046389165015534756512", + "2781996465394730190470582631099299305677291329609718650018200531245670229393", + "12441376330954323535872906380510501637773629931719508864016287320488688345525", + "2558302139544901035700544058046419714227464650146159803703499681139469546006", + "10087036781939179132584550273563255199577525914374285705149349445480649057058", + "4267692623754666261749551533667592242661271409704769363166965280715887854739", + "4945579503584457514844595640661884835097077318604083061152997449742124905548", + "17742335354489274412669987990603079185096280484072783973732137326144230832311", + "6266270088302506215402996795500854910256503071464802875821837403486057988208", + "2716062168542520412498610856550519519760063668165561277991771577403400784706", + "19118392018538203167410421493487769944462015419023083813301166096764262134232", + "9386595745626044000666050847309903206827901310677406022353307960932745699524", + "9121640807890366356465620448383131419933298563527245687958865317869840082266", + "3078975275808111706229899605611544294904276390490742680006005661017864583210", + "7157404299437167354719786626667769956233708887934477609633504801472827442743", + "14056248655941725362944552761799461694550787028230120190862133165195793034373", + "14124396743304355958915937804966111851843703158171757752158388556919187839849", + "11851254356749068692552943732920045260402277343008629727465773766468466181076", + "9799099446406796696742256539758943483211846559715874347178722060519817626047", + "10156146186214948683880719664738535455146137901666656566575307300522957959544", + "19908645952733301583346063785055921934459499091029406575311417879963332475861", + "11766105336238068471342414351862472329437473380853789942065610694000443387471", + "11002137593249972174092192767251572171769044073555430468487809799220351297047", + "284136377911685911941431040940403846843630064858778505937392780738953624163", + "19448733709802908339787967270452055364068697565906862913410983275341804035680", + "14423660424692802524250720264041003098290275890428483723270346403986712981505", + "10635360132728137321700090133109897687122647659471659996419791842933639708516", + ]; + + let m_str: Vec> = vec![ + vec![ + "19167410339349846567561662441069598364702008768579734801591448511131028229281", + "14183033936038168803360723133013092560869148726790180682363054735190196956789", + "9067734253445064890734144122526450279189023719890032859456830213166173619761", + "16378664841697311562845443097199265623838619398287411428110917414833007677155", + "12968540216479938138647596899147650021419273189336843725176422194136033835172", + "3636162562566338420490575570584278737093584021456168183289112789616069756675", + ], + vec![ + "17034139127218860091985397764514160131253018178110701196935786874261236172431", + "2799255644797227968811798608332314218966179365168250111693473252876996230317", + "2482058150180648511543788012634934806465808146786082148795902594096349483974", + "16563522740626180338295201738437974404892092704059676533096069531044355099628", + "10468644849657689537028565510142839489302836569811003546969773105463051947124", + "3328913364598498171733622353010907641674136720305714432354138807013088636408", + ], + vec![ + "18985203040268814769637347880759846911264240088034262814847924884273017355969", + "8652975463545710606098548415650457376967119951977109072274595329619335974180", + "970943815872417895015626519859542525373809485973005165410533315057253476903", + "19406667490568134101658669326517700199745817783746545889094238643063688871948", + "17049854690034965250221386317058877242629221002521630573756355118745574274967", + "4964394613021008685803675656098849539153699842663541444414978877928878266244", + ], + vec![ + "19025623051770008118343718096455821045904242602531062247152770448380880817517", + "9077319817220936628089890431129759976815127354480867310384708941479362824016", + "4770370314098695913091200576539533727214143013236894216582648993741910829490", + "4298564056297802123194408918029088169104276109138370115401819933600955259473", + "6905514380186323693285869145872115273350947784558995755916362330070690839131", + "4783343257810358393326889022942241108539824540285247795235499223017138301952", + ], + vec![ + "16205238342129310687768799056463408647672389183328001070715567975181364448609", + "8303849270045876854140023508764676765932043944545416856530551331270859502246", + "20218246699596954048529384569730026273241102596326201163062133863539137060414", + "1712845821388089905746651754894206522004527237615042226559791118162382909269", + "13001155522144542028910638547179410124467185319212645031214919884423841839406", + "16037892369576300958623292723740289861626299352695838577330319504984091062115", + ], + vec![ + "15162889384227198851506890526431746552868519326873025085114621698588781611738", + "13272957914179340594010910867091459756043436017766464331915862093201960540910", + "9416416589114508529880440146952102328470363729880726115521103179442988482948", + "8035240799672199706102747147502951589635001418759394863664434079699838251138", + "21642389080762222565487157652540372010968704000567605990102641816691459811717", + "20261355950827657195644012399234591122288573679402601053407151083849785332516", + ], + ]; + + let mut c: Vec = Vec::new(); + for i in 0..c_str.len() { + let n: Fr = Fr::from_str(c_str[i]).unwrap(); + c.push(n); } - let mut m: Vec> = Vec::new(); - for i in 0..T { - let mut mi: Vec = Vec::new(); - for j in 0..T { - mi.push(modinv( - &modulus(&(&cauchy_matrix[i] - &cauchy_matrix[T + j]), &r), - &r, - )); + let mut m: Vec> = Vec::new(); + for i in 0..m_str.len() { + let mut mj: Vec = Vec::new(); + for j in 0..m_str[i].len() { + let n: Fr = Fr::from_str(m_str[i][j]).unwrap(); + mj.push(n); } - m.push(mi); + m.push(mj); } - m -} - -pub fn check_all_different(v: &Vec) -> bool { - let zero: BigInt = Zero::zero(); - for i in 0..v.len() { - if v[i] == zero { - return false; - } - for j in i + 1..v.len() { - if v[i] == v[j] { - return false; - } - } - } - true -} - -pub fn modulus(a: &BigInt, m: &BigInt) -> BigInt { - ((a % m) + m) % m -} - -pub fn modinv(a: &BigInt, q: &BigInt) -> BigInt { - let mut mn = (q.clone(), a.clone()); - let mut xy: (BigInt, BigInt) = (Zero::zero(), One::one()); - - let big_zero: BigInt = Zero::zero(); - while mn.1 != big_zero { - xy = (xy.1.clone(), xy.0 - (mn.0.clone() / mn.1.clone()) * xy.1); - mn = (mn.1.clone(), modulus(&mn.0, &mn.1)); - } - - while xy.0 < Zero::zero() { - xy.0 = modulus(&xy.0, q); - } - xy.0 -} - -pub fn check_bigint_in_field(a: &BigInt, q: &BigInt) -> bool { - if a >= q { - return false; - } - true -} - -pub fn check_bigint_array_in_field(arr: &Vec, q: &BigInt) -> bool { - for a in arr { - if !check_bigint_in_field(a, &q) { - return false; - } - } - true + Constants { c: c, m: m } } pub struct Poseidon { @@ -139,60 +161,58 @@ pub struct Poseidon { impl Poseidon { pub fn new() -> Poseidon { Poseidon { - constants: generate_constants(), + constants: load_constants(), } } - pub fn ark(&self, state: &Vec, c: &BigInt) -> Vec { - let mut new_state: Vec = state.clone(); + pub fn ark(&self, state: &Vec, c: &Fr) -> Vec { + let mut new_state: Vec = state.clone(); for i in 0..state.len() { - new_state[i] = modulus(&(&state[i] + c), &self.constants.r); + new_state[i] = state[i]; + new_state[i].add_assign(c); } new_state } - pub fn cubic(&self, a: &BigInt) -> BigInt { - modulus(&(a * a * a * a * a), &self.constants.r) - } - - pub fn sbox(&self, state: &Vec, i: usize) -> Vec { - let mut new_state: Vec = state.clone(); + pub fn sbox(&self, state: &Vec, i: usize) -> Vec { + let mut new_state: Vec = state.clone(); if i < NROUNDSF / 2 || i >= NROUNDSF / 2 + NROUNDSP { for j in 0..T { - new_state[j] = self.cubic(&state[j]); + new_state[j] = state[j]; + new_state[j].square(); + new_state[j].square(); + new_state[j].mul_assign(&state[j]); } } else { - new_state[0] = self.cubic(&state[0]); + new_state[0] = state[0]; + new_state[0].square(); + new_state[0].square(); + new_state[0].mul_assign(&state[0]); } new_state } - pub fn mix(&self, state: &Vec, m: &Vec>) -> Vec { - let mut new_state: Vec = Vec::new(); + pub fn mix(&self, state: &Vec, m: &Vec>) -> Vec { + let mut new_state: Vec = Vec::new(); for i in 0..state.len() { - new_state.push(Zero::zero()); + new_state.push(Fr::zero()); for j in 0..state.len() { - new_state[i] = modulus( - &(&new_state[i] + modulus(&(&m[i][j] * &state[j]), &self.constants.r)), - &self.constants.r, - ) + let mut mij = m[i][j]; + mij.mul_assign(&state[j]); + new_state[i].add_assign(&mij); } } - new_state + new_state.clone() } - pub fn poseidon_hash(&self, inp: Vec) -> Result { + pub fn hash(&self, inp: Vec) -> Result { if inp.len() == 0 || inp.len() > T { return Err("Wrong inputs length".to_string()); } - // check if arr elements are inside the finite field over R - if !check_bigint_array_in_field(&inp, &self.constants.r) { - return Err("elements not inside the finite field over R".to_string()); - } let mut state = inp.clone(); for _ in inp.len()..T { - state.push(Zero::zero()); + state.push(Fr::zero()); } for i in 0..(NROUNDSF + NROUNDSP) { @@ -201,182 +221,69 @@ impl Poseidon { state = self.mix(&state, &self.constants.m); } - Ok(state[0].clone()) - } - - pub fn hash(&self, inp: Vec) -> Result { - // check if arr elements are inside the finite field over R - if !check_bigint_array_in_field(&inp, &self.constants.r) { - return Err("elements not inside the finite field over R".to_string()); - } - let mut r: BigInt = One::one(); - for i in (0..inp.len()).step_by(T - 1) { - let mut to_hash: Vec = Vec::new(); - let mut p = 0; - for j in 0..T - 1 { - p = j.clone(); - if i + j < inp.len() { - to_hash.push(inp[i + j].clone()); - } else { - p = j.clone(); - break; - } - } - to_hash.push(r.clone()); - for _ in p + 1..T - 1 { - to_hash.push(Zero::zero()); - } - let ph = &self.poseidon_hash(to_hash); - match ph { - Result::Err(err) => return Err(err.to_string()), - Result::Ok(res) => { - r = modulus(&(r + res), &self.constants.r); - } - } - } - Ok(r) - } - - pub fn hash_bytes(&self, b: Vec) -> Result { - let n = 31; - let mut ints: Vec = Vec::new(); - for i in 0..b.len() / n { - let v: BigInt = BigInt::from_bytes_le(Sign::Plus, &b[n * i..n * (i + 1)]); - ints.push(v); - } - if b.len() % n != 0 { - let v: BigInt = BigInt::from_bytes_le(Sign::Plus, &b[(b.len() / n) * n..]); - ints.push(v); - } - self.hash(ints) + Ok(state[0]) } } #[cfg(test)] mod tests { use super::*; - use rustc_hex::ToHex; #[test] - fn test_blake2_version() { - let mut hasher = VarBlake2b::new(32).unwrap(); - hasher.input(b"poseidon_constants"); - let h = hasher.vec_result(); + fn test_ff() { + let a = Fr::from_repr(FrRepr::from(2)).unwrap(); assert_eq!( - h.to_hex(), - "e57ba154fb2c47811dc1a2369b27e25a44915b4e4ece4eb8ec74850cb78e01b1" + "0000000000000000000000000000000000000000000000000000000000000002", + to_hex(&a) ); + println!("`2` into hex = {}", to_hex(&a)); } #[test] - fn test_poseidon_hash() { - let b1: BigInt = BigInt::parse_bytes(b"1", 10).unwrap(); - let b2: BigInt = BigInt::parse_bytes(b"2", 10).unwrap(); - let mut big_arr: Vec = Vec::new(); - big_arr.push(b1.clone()); - big_arr.push(b2.clone()); - let poseidon = Poseidon::new(); - let h = poseidon.poseidon_hash(big_arr.clone()).unwrap(); + fn test_load_constants() { + let constants = load_constants(); + println!("{:?}", constants.c[0].to_string()); assert_eq!( - h.to_string(), - "12242166908188651009877250812424843524687801523336557272219921456462821518061" + constants.c[0].to_string(), + "Fr(0x1fd4a35e68f0946f8f5dfd2ac9d7882ce2466ec1c9766f69b5a14c3f84a17be2)" ); - let h = poseidon.hash(big_arr).unwrap(); assert_eq!( - h.to_string(), - "4932297968297298434239270129193057052722409868268166443802652458940273154855" + constants.c[constants.c.len() - 1].to_string(), + "Fr(0x1783668830df79d79707da6a0e7c023c5f54a112be7ee3f7d49b420213ab7f64)" ); - - let b3: BigInt = BigInt::parse_bytes(b"3", 10).unwrap(); - let b4: BigInt = BigInt::parse_bytes(b"4", 10).unwrap(); - let mut big_arr34: Vec = Vec::new(); - big_arr34.push(b3.clone()); - big_arr34.push(b4.clone()); - let h34 = poseidon.poseidon_hash(big_arr34.clone()).unwrap(); assert_eq!( - h34.to_string(), - "17185195740979599334254027721507328033796809509313949281114643312710535000993" + constants.m[0][0].to_string(), + "Fr(0x2a605eab3c12c29701b9a8944a16ff3d64c199efa7c857c65e4c0560ab3b0ca1)" ); - let h34 = poseidon.hash(big_arr34).unwrap(); assert_eq!( - h34.to_string(), - "4635491972858758537477743930622086396911540895966845494943021655521913507504" + constants.m[constants.m.len() - 1][0].to_string(), + "Fr(0x2185e429a96435c62e21e7091f4262685769e43fa49c9d40f88c41016c588ada)" ); } #[test] - fn test_hash_bytes() { - let msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; + fn test_hash() { + let b1: Fr = Fr::from_str("1").unwrap(); + let b2: Fr = Fr::from_str("2").unwrap(); + let mut big_arr: Vec = Vec::new(); + big_arr.push(b1.clone()); + big_arr.push(b2.clone()); let poseidon = Poseidon::new(); - let h = poseidon.hash_bytes(msg.as_bytes().to_vec()).unwrap(); + let h = poseidon.hash(big_arr.clone()).unwrap(); assert_eq!( h.to_string(), - "16019700159595764790637132363672701294192939959594423814006267756172551741065" + "Fr(0x1b10d227ef9aa736dc05bba919a8462ce45bc5b7d632e8ff9bfe6874a002eaed)" // "12242166908188651009877250812424843524687801523336557272219921456462821518061" ); - let msg2 = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet."; - let h2 = poseidon.hash_bytes(msg2.as_bytes().to_vec()).unwrap(); + let b3: Fr = Fr::from_str("3").unwrap(); + let b4: Fr = Fr::from_str("4").unwrap(); + let mut big_arr34: Vec = Vec::new(); + big_arr34.push(b3.clone()); + big_arr34.push(b4.clone()); + let h34 = poseidon.hash(big_arr34.clone()).unwrap(); assert_eq!( - h2.to_string(), - "2978613163687734485261639854325792381691890647104372645321246092227111432722" + h34.to_string(), + "Fr(0x25fe79e16e9d530a400584ffe556b1fe69acda374065860c43698cab1c16b3a1)" // "17185195740979599334254027721507328033796809509313949281114643312710535000993" ); } - - #[test] - fn test_chunks() { - let b0: BigInt = BigInt::parse_bytes(b"0", 10).unwrap(); - let b1: BigInt = BigInt::parse_bytes(b"1", 10).unwrap(); - let b2: BigInt = BigInt::parse_bytes(b"2", 10).unwrap(); - let b3: BigInt = BigInt::parse_bytes(b"3", 10).unwrap(); - let b4: BigInt = BigInt::parse_bytes(b"4", 10).unwrap(); - let b5: BigInt = BigInt::parse_bytes(b"5", 10).unwrap(); - let b6: BigInt = BigInt::parse_bytes(b"6", 10).unwrap(); - let b7: BigInt = BigInt::parse_bytes(b"7", 10).unwrap(); - let b8: BigInt = BigInt::parse_bytes(b"8", 10).unwrap(); - let b9: BigInt = BigInt::parse_bytes(b"9", 10).unwrap(); - let big_arr: Vec = vec![ - b0.clone(), - b1.clone(), - b2.clone(), - b3.clone(), - b4.clone(), - b5.clone(), - b6.clone(), - b7.clone(), - b8.clone(), - b9.clone(), - ]; - - let poseidon = Poseidon::new(); - let h = poseidon.hash(big_arr).unwrap(); - - let big_arr2: Vec = vec![ - b5.clone(), - b6.clone(), - b7.clone(), - b8.clone(), - b9.clone(), - b0.clone(), - b1.clone(), - b2.clone(), - b3.clone(), - b4.clone(), - ]; - let h2 = poseidon.hash(big_arr2).unwrap(); - assert_ne!(h, h2); - } - - #[test] - fn test_padding() { - let b0: BigInt = BigInt::parse_bytes(b"0", 10).unwrap(); - let b1: BigInt = BigInt::parse_bytes(b"1", 10).unwrap(); - let big_arr: Vec = vec![b1.clone()]; - - let poseidon = Poseidon::new(); - let h = poseidon.hash(big_arr).unwrap(); - - let big_arr2: Vec = vec![b1.clone(), b0.clone()]; - let h2 = poseidon.hash(big_arr2).unwrap(); - assert_ne!(h, h2); - } } From 32cf0558fa8f5f67b251b9ff6c1e8cf94f0d2f3e Mon Sep 17 00:00:00 2001 From: arnaucube Date: Sun, 19 Jul 2020 12:12:39 +0200 Subject: [PATCH 3/4] Add benchmarks (49x improvement with ff) Tested on a Intel(R) Core(TM) i5-6300U CPU @ 2.40GHz, with 16GB of RAM. - Old (using nnum-bigint): hash time: [5.9258 ms 5.9407 ms 5.9587 ms] - New (using ff): hash time: [120.12 us 121.08 us 122.30 us] --- Cargo.toml | 6 ++++++ README.md | 5 +++++ benches/bench_poseidon_hash.rs | 30 ++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 benches/bench_poseidon_hash.rs diff --git a/Cargo.toml b/Cargo.toml index 6bbe2da..7049207 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,9 @@ readme = "README.md" ff = {package="ff_ce" , version="0.11", features = ["derive"]} rand = "0.4" +[dev-dependencies] +criterion = "0.3" + +[[bench]] +name = "bench_poseidon_hash" +harness = false diff --git a/README.md b/README.md index 33ddf33..651d35c 100644 --- a/README.md +++ b/README.md @@ -7,3 +7,8 @@ Compatible with the Poseidon Go implementation done in https://github.com/iden3/ ## Warning Do not use in production + +## Benchmarks +``` +hash time: [120.12 us 121.08 us 122.30 us] +``` diff --git a/benches/bench_poseidon_hash.rs b/benches/bench_poseidon_hash.rs new file mode 100644 index 0000000..6420ce2 --- /dev/null +++ b/benches/bench_poseidon_hash.rs @@ -0,0 +1,30 @@ +use criterion::{black_box, criterion_group, criterion_main, Criterion}; + +extern crate rand; +#[macro_use] +extern crate ff; +use ff::*; + +use poseidon_rs::Poseidon; + +fn criterion_benchmark(c: &mut Criterion) { + let b1: poseidon_rs::Fr = poseidon_rs::Fr::from_str( + "12242166908188651009877250812424843524687801523336557272219921456462821518061", + ) + .unwrap(); + let b2: poseidon_rs::Fr = poseidon_rs::Fr::from_str( + "12242166908188651009877250812424843524687801523336557272219921456462821518061", + ) + .unwrap(); + let mut big_arr: Vec = Vec::new(); + big_arr.push(b1.clone()); + big_arr.push(b2.clone()); + let poseidon = Poseidon::new(); + + c.bench_function("hash", |b| { + b.iter(|| poseidon.hash(big_arr.clone()).unwrap()) + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); From 725d6397b8572d3fc7b96bdcb674475550ecaa96 Mon Sep 17 00:00:00 2001 From: arnaucube Date: Wed, 22 Jul 2020 19:53:00 +0200 Subject: [PATCH 4/4] Update methods to more efficient usage of ff On a Intel(R) Core(TM) i5-6300U CPU @ 2.40GHz, with 16GB of RAM: - Old (using num-bigint): hash time: [5.9258 ms 5.9407 ms 5.9587 ms] - New (using ff): hash time: [120.12 us 121.08 us 122.30 us] On a Intel(R) Core(TM) i7-8705G CPU @ 3.10GHz, with 32 GB of RAM: - Old (using num-bigint): hash time: [4.1192 ms 4.1318 ms 4.1461 ms] - In the previous commit (using ff): hash time: [91.394 us 91.430 us 91.476 us] - In this commit (using ff): hash time: [85.517 us 85.545 us 85.574 us] --- README.md | 4 ---- benches/bench_poseidon_hash.rs | 2 +- src/lib.rs | 44 ++++++++++++++++++---------------- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 651d35c..3b0ba06 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,3 @@ Compatible with the Poseidon Go implementation done in https://github.com/iden3/ ## Warning Do not use in production -## Benchmarks -``` -hash time: [120.12 us 121.08 us 122.30 us] -``` diff --git a/benches/bench_poseidon_hash.rs b/benches/bench_poseidon_hash.rs index 6420ce2..958acaf 100644 --- a/benches/bench_poseidon_hash.rs +++ b/benches/bench_poseidon_hash.rs @@ -1,4 +1,4 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use criterion::{criterion_group, criterion_main, Criterion}; extern crate rand; #[macro_use] diff --git a/src/lib.rs b/src/lib.rs index 2953210..a79480c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -164,32 +164,26 @@ impl Poseidon { constants: load_constants(), } } - pub fn ark(&self, state: &Vec, c: &Fr) -> Vec { - let mut new_state: Vec = state.clone(); + pub fn ark(&self, state: &mut Vec, c: &Fr) { for i in 0..state.len() { - new_state[i] = state[i]; - new_state[i].add_assign(c); + state[i].add_assign(c); } - - new_state } - pub fn sbox(&self, state: &Vec, i: usize) -> Vec { - let mut new_state: Vec = state.clone(); + pub fn sbox(&self, state: &mut Vec, i: usize) { if i < NROUNDSF / 2 || i >= NROUNDSF / 2 + NROUNDSP { for j in 0..T { - new_state[j] = state[j]; - new_state[j].square(); - new_state[j].square(); - new_state[j].mul_assign(&state[j]); + let aux = state[j]; + state[j].square(); + state[j].square(); + state[j].mul_assign(&aux); } } else { - new_state[0] = state[0]; - new_state[0].square(); - new_state[0].square(); - new_state[0].mul_assign(&state[0]); + let aux = state[0]; + state[0].square(); + state[0].square(); + state[0].mul_assign(&aux); } - new_state } pub fn mix(&self, state: &Vec, m: &Vec>) -> Vec { @@ -216,8 +210,8 @@ impl Poseidon { } for i in 0..(NROUNDSF + NROUNDSP) { - state = self.ark(&state, &self.constants.c[i]); - state = self.sbox(&state, i); + self.ark(&mut state, &self.constants.c[i]); + self.sbox(&mut state, i); state = self.mix(&state, &self.constants.m); } @@ -236,13 +230,21 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000002", to_hex(&a) ); - println!("`2` into hex = {}", to_hex(&a)); + + let b: Fr = Fr::from_str( + "21888242871839275222246405745257275088548364400416034343698204186575808495619", + ) + .unwrap(); + assert_eq!( + "0000000000000000000000000000000000000000000000000000000000000002", + to_hex(&b) + ); + assert_eq!(&a, &b); } #[test] fn test_load_constants() { let constants = load_constants(); - println!("{:?}", constants.c[0].to_string()); assert_eq!( constants.c[0].to_string(), "Fr(0x1fd4a35e68f0946f8f5dfd2ac9d7882ce2466ec1c9766f69b5a14c3f84a17be2)"