From 157bba0d6afc073a1854900deeace6b5788a7f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michele=20Orr=C3=B9?= Date: Tue, 30 Jan 2024 15:52:53 +0100 Subject: [PATCH] Adding tests. Spotted a bug in the use of leftovers, investigating more. Created some basic tests for poseidon. --- src/hash/legacy.rs | 5 +- src/iopattern.rs | 2 +- src/lib.rs | 36 +-- src/plugins/ark/mod.rs | 8 + src/plugins/ark/poseidon.rs | 526 ++---------------------------------- src/plugins/traits.rs | 5 + src/safe.rs | 24 +- src/tests.rs | 99 ++++++- 8 files changed, 159 insertions(+), 546 deletions(-) diff --git a/src/hash/legacy.rs b/src/hash/legacy.rs index c1f7372..9594b4c 100644 --- a/src/hash/legacy.rs +++ b/src/hash/legacy.rs @@ -163,9 +163,10 @@ impl DuplexHash for Di // If we still have some digest not yet squeezed // from previous invocations, write it to the output. } else if !self.leftovers.is_empty() { + println!("Here we are, with leftovers {:?}", self.leftovers); let len = usize::min(output.len(), self.leftovers.len()); - self.leftovers[..len].copy_from_slice(&output[..len]); - self.leftovers.drain(..len); + output[..len].copy_from_slice(&self.leftovers[..len]); + self.leftovers.drain(len..); self.squeeze_unchecked(&mut output[len..]) // Squeeze another digest } else if let Mode::Squeeze(i) = self.mode { diff --git a/src/iopattern.rs b/src/iopattern.rs index 00d8c0c..50f9c52 100644 --- a/src/iopattern.rs +++ b/src/iopattern.rs @@ -65,7 +65,7 @@ impl Op { /// Denotes a protocol absorbing 32 native elements, squeezing 64 native elements, /// and finally absorbing 64 native elements. #[derive(Clone)] -pub struct IOPattern +pub struct IOPattern where U: Unit, H: DuplexHash, diff --git a/src/lib.rs b/src/lib.rs index fabb4ae..32be13b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,36 +4,35 @@ //! Nimue helps performing Fiat-Shamir on any public-coin protocol. //! It enables secure provision of randomness for the prover and secure generation //! of random coins for the verifier. -//! It is inspired by the [SAFE] API with minor variations. -//! -//! This allows for the implementation of non-interactive protocols in a readable manner, -//! in a unified framework for sponge functions. +//! It is inspired by the [SAFE] API, with minor variations. //! //! # Features //! -//! Nimue supports multi-round protocols, domain separation, and protocol composition. -//! Inspired from [Merlin], it tries to address some of its core design limitations: +//! Nimue facilitates the writing of multi-round public coin protocols. +//! It provides the following features: +//! - **Automatic transcript generation**: nimue comes with batteries included for serializing/deserializing algebraic elements such as field/group elements in [Arkworks](https://github.com/arkworks-rs/algebra) and [Zkcrypto](https://github.com/zkcrypto/group). Users can build the top of it via extension trait. //! - **Support custom hash function**, including algebraic hashes. //! To build a secure Fiat-Shamir transform, the minimal requirement is a permutation function over some field, //! be it $\mathbb{F}_{2^8}$ or any large-characteristic prime field $\mathbb{F}_p$. //! - **Retro-compatibility** with MD hashes. -//! We have a legacy interface for Sha2, Blake2, and any hash function that satisfies the [`digest::Digest`] trait. +//! We have a legacy interface for [`sha2``], [`blake2`], and any hash function that satisfies the [`digest::Digest`] trait. //! - **Preprocessing**. //! In recursive SNARKs, minimizing the number of hash invocations //! while maintaining security is crucial. We offer tools for preprocessing the Transcript (i.e., the state of the Fiat-Shamir transform) to achieve this goal. //! - **Private randomness generation**. //! It is vital to avoid providing two different challenges for the same prover message. We do our best to avoid it by tying down the prover randomness to the protocol transcript, without making the proof deterministic. -//! # IO Patterns //! -//! The basic idea behind Nimue is that prover and verifier both commit to the entire sequence of absorb -//! and squeeze done throughout the protocol. -//! Once the IO Pattern is fixed, the rest of the protocol can just proceed with concatenation, without ever worrying -//! about encoding length and special flags in a protocol transcript. +//! # Intuition +//! +//! The basic idea behind Nimue is that prover and verifier "commit" to the protocol before running the actual protocol. +//! This preprocessing step, where the input/output of the prover, generates an "IV" that is used to initialize the hash function for the Fiat-Shamir heuristic. +//! From here, prover just proceeds with concatenation, without ever worrying +//! about encoding length and special flags to embed in the hash function. //! This allows for //! better preprocessing, //! friendliness with algebraic hashes, //! static composition of protocol (and prevention of composition during the execution of a protocol), -//! easy inspection of the Fiat-Shamir transform. +//! easy an easier inspection of the Fiat-Shamir transform. //! //! ``` //! use nimue::IOPattern; @@ -104,12 +103,15 @@ //! let chal = merlin.challenge_bytes::<16>().expect("Squeezing 128 bits"); //! ``` //! -//! # Contributing +//! # Acknowledgements +//! +//! This work is heavily inspired from: +//! - Libsignal's [shosha256], by Trevor Perrin. It provides an absorb/squeeze interface over legacy hash functions. +//! - the [SAFE] API, by Dmitry Khovratovich, JP Aumasson, Porçu Quine, Bart Mennink. To my knowledge they are the first to introduce this idea of using an IO Pattern to build a transcript. +//! - [Merlin], by Henry de Valence. To my knowledge it introduced this idea of a `Transcript` object carrying over the state of the hash function throughout the protocol. //! -//! This work is still in early development! -//! If you would like to contribute, adopt it in your project, or simply tell us about your use-case, -//! reach out to us! //! +//! [shosha256]: https://github.com/signalapp/libsignal/blob/main/rust/poksho/src/shosha256.rs //! [SAFE]: https://eprint.iacr.org/2023/522 //! [Merlin]: https://github.com/dalek-cryptography/merlin //! [`digest::Digest`]: https://docs.rs/digest/latest/digest/trait.Digest.html diff --git a/src/plugins/ark/mod.rs b/src/plugins/ark/mod.rs index 70c5c5a..b446332 100644 --- a/src/plugins/ark/mod.rs +++ b/src/plugins/ark/mod.rs @@ -1,3 +1,7 @@ +//! This module contains utilities for working with Arkworks types +//! and aid in the Fiat-Shamir heuristic for protocols dealing with +//! field elements and group elements. + /// Common utilities for adding public elements to the protocol transcript. mod common; /// IO Pattern utilities. @@ -9,6 +13,10 @@ mod reader; /// Prover's utilities for encoding into a transcript. mod writer; +#[cfg(test)] +/// Tests for arkworks. +mod tests; + #[cfg(feature = "anemoi")] pub mod anemoi; diff --git a/src/plugins/ark/poseidon.rs b/src/plugins/ark/poseidon.rs index 6aeb278..d35cf65 100644 --- a/src/plugins/ark/poseidon.rs +++ b/src/plugins/ark/poseidon.rs @@ -3,8 +3,9 @@ use ark_ff::PrimeField; use crate::hash::sponge::Sponge; use crate::hash::Unit; -#[derive(Clone, Debug)] -pub struct PoseidonConfig { +#[derive(Clone)] +pub struct PoseidonSponge { + /// Number of rounds in a full-round operation. pub full_rounds: usize, /// Number of rounds in a partial-round operation. @@ -13,53 +14,32 @@ pub struct PoseidonConfig = { -// let alpha = 17; -// let full_rounds = 8; -// let total_rounds = 37; -// let partial_rounds = total_rounds - full_rounds; -// PoseidonConfig { -// full_rounds, -// partial_rounds, -// alpha, -// ark: ARK, -// mds: MDS, -// } -// }; - -#[derive(Clone)] -pub struct PoseidonSponge { - /// Sponge Config - pub parameters: PoseidonConfig, + pub mds: &'static [[F; N]], // Sponge State /// Current sponge's state (current elements in the permutation block) - pub state: Vec, + pub state: [F; N], } -impl PoseidonSponge { +impl PoseidonSponge { fn apply_s_box(&self, state: &mut [F], is_full_round: bool) { // Full rounds apply the S Box (x^alpha) to every element of state if is_full_round { for elem in state { - *elem = elem.pow(&[self.parameters.alpha]); + *elem = elem.pow(&[self.alpha]); } } // Partial rounds apply the S Box (x^alpha) to just the first element of state else { - state[0] = state[0].pow(&[self.parameters.alpha]); + state[0] = state[0].pow(&[self.alpha]); } } fn apply_ark(&self, state: &mut [F], round_number: usize) { for (i, state_elem) in state.iter_mut().enumerate() { - state_elem.add_assign(&self.parameters.ark[round_number][i]); + state_elem.add_assign(&self.ark[round_number][i]); } } @@ -68,7 +48,7 @@ impl PoseidonSponge PoseidonSponge Default for PoseidonSponge -where - PoseidonConfig: Default, - F: PrimeField + Unit, -{ - fn default() -> Self { - PoseidonSponge { - parameters: PoseidonConfig::default(), - state: vec![F::zero(); RATE+CAPACITY], - } - } -} +crate::hash::index::impl_indexing!(PoseidonSponge, state, Output = F, Params = [F: PrimeField], Constants = [R, N]); -crate::hash::index::impl_indexing!(PoseidonSponge, state, Output = F, Params = [F: PrimeField], Constants = [RATE, CAPACITY]); - -impl zeroize::Zeroize - for PoseidonSponge -{ +impl zeroize::Zeroize for PoseidonSponge { fn zeroize(&mut self) { self.state.zeroize(); } } -impl Sponge for PoseidonSponge +impl Sponge for PoseidonSponge where - PoseidonSponge: Default, + PoseidonSponge: Default, F: PrimeField + Unit, { type U = F; - const CAPACITY: usize = CAPACITY; - const RATE: usize = RATE; + const CAPACITY: usize = N - R; + const RATE: usize = R; fn new(iv: [u8; 32]) -> Self { - assert!(Self::CAPACITY >= 1); + assert!(N >= 1); let mut ark_sponge = Self::default(); - ark_sponge.state[Self::RATE] = F::from_be_bytes_mod_order(&iv); + ark_sponge.state[R] = F::from_be_bytes_mod_order(&iv); ark_sponge } fn permute(&mut self) { - let full_rounds_over_2 = self.parameters.full_rounds / 2; + let full_rounds_over_2 = self.full_rounds / 2; let mut state = self.state.clone(); for i in 0..full_rounds_over_2 { self.apply_ark(&mut state, i); @@ -125,14 +90,14 @@ where self.apply_mds(&mut state); } - for i in full_rounds_over_2..(full_rounds_over_2 + self.parameters.partial_rounds) { + for i in full_rounds_over_2..(full_rounds_over_2 + self.partial_rounds) { self.apply_ark(&mut state, i); self.apply_s_box(&mut state, false); self.apply_mds(&mut state); } - for i in (full_rounds_over_2 + self.parameters.partial_rounds) - ..(self.parameters.partial_rounds + self.parameters.full_rounds) + for i in (full_rounds_over_2 + self.partial_rounds) + ..(self.partial_rounds + self.full_rounds) { self.apply_ark(&mut state, i); self.apply_s_box(&mut state, true); @@ -141,448 +106,3 @@ where self.state = state; } } - -// const MDS: &'static [[FF; 3]] = &[ -// [ -// ark_ff::MontFp!( -// "43228725308391137369947362226390319299014033584574058394339561338097152657858" -// ), -// ark_ff::MontFp!( -// "20729134655727743386784826341366384914431326428651109729494295849276339718592" -// ), -// ark_ff::MontFp!( -// "14275792724825301816674509766636153429127896752891673527373812580216824074377" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "3039440043015681380498693766234886011876841428799441709991632635031851609481" -// ), -// ark_ff::MontFp!( -// "6678863357926068615342013496680930722082156498064457711885464611323928471101" -// ), -// ark_ff::MontFp!( -// "37355038393562575053091209735467454314247378274125943833499651442997254948957" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "26481612700543967643159862864328231943993263806649000633819754663276818191580" -// ), -// ark_ff::MontFp!( -// "30103264397473155564098369644643015994024192377175707604277831692111219371047" -// ), -// ark_ff::MontFp!( -// "5712721806190262694719203887224391960978962995663881615739647362444059585747" -// ), -// ], -// ]; -// const ARK: &'static [[FF; 3]] = &[ -// [ -// ark_ff::MontFp!( -// "44595993092652566245296379427906271087754779418564084732265552598173323099784" -// ), -// ark_ff::MontFp!( -// "23298463296221002559050231199021122673158929708101049474262017406235785365706" -// ), -// ark_ff::MontFp!( -// "34212491019164671611180318500074499609633402631511849759183986060951187784466" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "19098051134080182375553680073525644187968170656591203562523489333616681350367" -// ), -// ark_ff::MontFp!( -// "7027675418691353855077049716619550622043312043660992344940177187528247727783" -// ), -// ark_ff::MontFp!( -// "47642753235356257928619065424282314733361764347085604019867862722762702755609" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "24281836129477728386327945482863886685457469794572168729834072693507088619997" -// ), -// ark_ff::MontFp!( -// "12624893078331920791384400430193929292743809612452779381349824703573823883410" -// ), -// ark_ff::MontFp!( -// "22654862987689323504199204643771547606936339944127455903448909090318619188561" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "27229172992560143399715985732065737093562061782414043625359531774550940662372" -// ), -// ark_ff::MontFp!( -// "13224952063922250960936823741448973692264041750100990569445192064567307041002" -// ), -// ark_ff::MontFp!( -// "40380869235216625717296601204704413215735530626882135230693823362552484855508" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "4245751157938905689397184705633683893932492370323323780371834663438472308145" -// ), -// ark_ff::MontFp!( -// "8252156875535418429533049587170755750275631534314711502253775796882240991261" -// ), -// ark_ff::MontFp!( -// "32910829712934971129644416249914075073083903821282503505466324428991624789936" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "49412601297460128335642438246716127241669915737656789613664349252868389975962" -// ), -// ark_ff::MontFp!( -// "841661305510340459373323516098909074520942972558284146843779636353111592117" -// ), -// ark_ff::MontFp!( -// "37926489020263024391336570420006226544461516787280929232555625742588667303947" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "18433043696013996573551852847056868761017170818820490351056924728720017242180" -// ), -// ark_ff::MontFp!( -// "45376910275288438312773930242803223482318753992595269901397542214841496212310" -// ), -// ark_ff::MontFp!( -// "47854349410014339708332226068958253098964727682486278458389508597930796651514" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "32638426693771251366613055506166587312642876874690861030672730491779486904360" -// ), -// ark_ff::MontFp!( -// "19105439281696418043426755774110765432959446684037017837894045255490581318047" -// ), -// ark_ff::MontFp!( -// "13484299981373196201166722380389594773562113262309564134825386266765751213853" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "63360321133852659797114062808297090090814531427710842859827725871241144161" -// ), -// ark_ff::MontFp!( -// "42427543035537409467993338717379268954936885184662765745740070438835506287271" -// ), -// ark_ff::MontFp!( -// "149101987103211771991327927827692640556911620408176100290586418839323044234" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "8341764062226826803887898710015561861526081583071950015446833446251359696930" -// ), -// ark_ff::MontFp!( -// "45635980415044299013530304465786867101223925975971912073759959440335364441441" -// ), -// ark_ff::MontFp!( -// "49833261156201520743834327917353893365097424877680239796845398698940689734850" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "26764715016591436228000634284249890185894507497739511725029482580508707525029" -// ), -// ark_ff::MontFp!( -// "25054530812095491217523557726611612265064441619646263299990388543372685322499" -// ), -// ark_ff::MontFp!( -// "47654590955096246997622155031169641628093104787883934397920286718814889326452" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "16463825890556752307085325855351334996898686633642574805918056141310194135796" -// ), -// ark_ff::MontFp!( -// "17473961341633494489168064889016732306117097771640351649096482400214968053040" -// ), -// ark_ff::MontFp!( -// "49914603434867854893558366922996753035832008639512305549839666311012232077468" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "17122578514152308432111470949473865420090463026624297565504381163777697818362" -// ), -// ark_ff::MontFp!( -// "34870689836420861427379101859113225049736283485335674111421609473028315711541" -// ), -// ark_ff::MontFp!( -// "4622082908476410083286670201138165773322781640914243047922441301693321472984" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "6079244375752010013798561155333454682564824861645642293573415833483620500976" -// ), -// ark_ff::MontFp!( -// "2635090520059500019661864086615522409798872905401305311748231832709078452746" -// ), -// ark_ff::MontFp!( -// "19070766579582338321241892986615538320421651429118757507174186491084617237586" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "12622420533971517050761060317049369208980632120901481436392835424625664738526" -// ), -// ark_ff::MontFp!( -// "8965101225657199137904506150282256568170501907667138404080397024857524386266" -// ), -// ark_ff::MontFp!( -// "27085091008069524593196374148553176565775450537072498305327481366756159319838" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "45929056591150668409624595495643698205830429971690813312608217341940499221218" -// ), -// ark_ff::MontFp!( -// "50361689160518167880500080025023064746137161030119436080957023803101861300846" -// ), -// ark_ff::MontFp!( -// "6722586346537620732668048024627882970582133613352245923413730968378696371065" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "7340485916200743279276570085958556798507770452421357119145466906520506506342" -// ), -// ark_ff::MontFp!( -// "25946733168219652706630789514519162148860502996914241011500280690204368174083" -// ), -// ark_ff::MontFp!( -// "9962367658743163006517635070396368828381757404628822422306438427554934645464" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "7221669722700687417346373353960536661883467014204005276831020252277657076044" -// ), -// ark_ff::MontFp!( -// "21487980358388383563030903293359140836304488103090321183948009095669344637431" -// ), -// ark_ff::MontFp!( -// "44389482047246878765773958430749333249729101516826571588063797358040130313157" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "32887270862917330820874162842519225370447850172085449103568878409533683733185" -// ), -// ark_ff::MontFp!( -// "15453393396765207016379045014101989306173462885430532298601655955681532648226" -// ), -// ark_ff::MontFp!( -// "5478929644476681096437469958231489102974161353940993351588559414552523375472" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "41981370411247590312677561209178363054744730805951096631186178388981705304138" -// ), -// ark_ff::MontFp!( -// "3474136981645476955784428843999869229067282976757744542648188369810577298585" -// ), -// ark_ff::MontFp!( -// "26251477770740399889956219915654371915771248171098220204692699710414817081869" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "51916561889718854106125837319509539220778634838409949714061033196765117231752" -// ), -// ark_ff::MontFp!( -// "25355145802812435959748831835587713214179184608408449220418373832038339021974" -// ), -// ark_ff::MontFp!( -// "31950684570730625275416731570246297947385359051792335826965013637877068017530" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "40966378914980473680181850710703295982197782082391794594149984057481543436879" -// ), -// ark_ff::MontFp!( -// "1141315130963422417761731263662398620858625339733452795772225916965481730059" -// ), -// ark_ff::MontFp!( -// "9812100862165422922235757591915383485338044715409891361026651619010947646011" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "25276091996614379065765602410190790163396484122487585763380676888280427744737" -// ), -// ark_ff::MontFp!( -// "18512694312063606403196469408971540495273694846641903978723927656359350642619" -// ), -// ark_ff::MontFp!( -// "5791584766415439694303685437881192048262049244830616851865505314899699012588" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "34501536331706470927069149344450300773777486993504673779438188495686129846168" -// ), -// ark_ff::MontFp!( -// "10797737565565774079718466476236831116206064650762676383469703413649447678207" -// ), -// ark_ff::MontFp!( -// "42599392747310354323136214835734307933597896695637215127297036595538235868368" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "1336670998775417133322626564820911986969949054454812685145275612519924150700" -// ), -// ark_ff::MontFp!( -// "2630141283339761901081411552890260088516693208402906795133548756078952896770" -// ), -// ark_ff::MontFp!( -// "5206688943117414740600380377278238268309952400341418217132724749372435975215" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "10739264253827005683370721104077252560524362323422172665530191908848354339715" -// ), -// ark_ff::MontFp!( -// "48010640624945719826344492755710886355389194986527731603685956726907395779674" -// ), -// ark_ff::MontFp!( -// "47880724693177306044229143357252697148359033158394459365791331000715957339701" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "51658938856669444737833983076793759752280196674149218924101718974926964118996" -// ), -// ark_ff::MontFp!( -// "27558055650076329657496888512074319504342606463881203707330358472954748913263" -// ), -// ark_ff::MontFp!( -// "38886981777859313701520424626728402175860609948757992393598285291689196608037" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "17152756165118461969542990684402410297675979513690903033350206658079448802479" -// ), -// ark_ff::MontFp!( -// "43766946932033687220387514221943418338304186408056458476301583041390483707207" -// ), -// ark_ff::MontFp!( -// "24324495647041812436929170644873622904287038078113808264580396461953421400343" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "6935839211798937659784055008131602708847374430164859822530563797964932598700" -// ), -// ark_ff::MontFp!( -// "42126767398190942911395299419182514513368023621144776598842282267908712110039" -// ), -// ark_ff::MontFp!( -// "5702364486091252903915715761606014714345316580946072019346660327857498603375" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "28184981699552917714085740963279595942132561155181044254318202220270242523053" -// ), -// ark_ff::MontFp!( -// "27078204494010940048327822707224393686245007379331357330801926151074766130790" -// ), -// ark_ff::MontFp!( -// "5004172841233947987988267535285080365124079140142987718231874743202918551203" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "7974360962120296064882769128577382489451060235999590492215336103105134345602" -// ), -// ark_ff::MontFp!( -// "48062035869818179910046292951628308709251170031813126950740044942870578526376" -// ), -// ark_ff::MontFp!( -// "26361151154829600651603985995297072258262605598910254660032612019129606811983" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "46973867849986280770641828877435510444176572688208439836496241838832695841519" -// ), -// ark_ff::MontFp!( -// "1219439673853113792340300173186247996249367102884530407862469123523013083971" -// ), -// ark_ff::MontFp!( -// "8063356002935671186275773257019749639571745240775941450161086349727882957042" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "8815571992701260640209942886673939234666734294275300852283020522390608544536" -// ), -// ark_ff::MontFp!( -// "36384568984671043678320545346945893232044626942887414733675890845013312931948" -// ), -// ark_ff::MontFp!( -// "7493936589040764830842760521372106574503511314427857201860148571929278344956" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "26516538878265871822073279450474977673130300973488209984756372331392531193948" -// ), -// ark_ff::MontFp!( -// "3872858659373466814413243601289105962248870842202907364656526273784217311104" -// ), -// ark_ff::MontFp!( -// "8291822807524000248589997648893671538524566700364221355689839490238724479848" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "32842548776827046388198955038089826231531188946525483251252938248379132381248" -// ), -// ark_ff::MontFp!( -// "10749428410907700061565796335489079278748501945557710351216806276547834974736" -// ), -// ark_ff::MontFp!( -// "43342287917341177925402357903832370099402579088513884654598017447701677948416" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "29658571352070370791360499299098360881857072189358092237807807261478461425147" -// ), -// ark_ff::MontFp!( -// "7805182565862454238315452208989152534554369855020544477885853141626690738363" -// ), -// ark_ff::MontFp!( -// "30699555847500141715826240743138908521140760599479365867708690318477369178275" -// ), -// ], -// [ -// ark_ff::MontFp!( -// "1231951350103545216624376889222508148537733140742167414518514908719103925687" -// ), -// ark_ff::MontFp!( -// "24784260089125933876714702247471508077514206350883487938806451152907502751770" -// ), -// ark_ff::MontFp!( -// "36563542611079418454711392295126742705798573252480028863133394504154697924536" -// ), -// ], -// ]; diff --git a/src/plugins/traits.rs b/src/plugins/traits.rs index 523917c..190c3bc 100644 --- a/src/plugins/traits.rs +++ b/src/plugins/traits.rs @@ -1,11 +1,13 @@ macro_rules! field_traits { ($Field:path) => { + /// Absorb and squeeze field elements to the IO pattern. pub trait FieldIOPattern { fn add_scalars(self, count: usize, label: &str) -> Self; fn challenge_scalars(self, count: usize, label: &str) -> Self; } + /// Interpret verifier messages as uniformly distributed field elements. pub trait FieldChallenges { fn fill_challenge_scalars(&mut self, output: &mut [F]) -> $crate::ProofResult<()>; @@ -15,15 +17,18 @@ macro_rules! field_traits { } } + /// Add field elements as shared public information. pub trait FieldPublic { type Repr; fn public_scalars(&mut self, input: &[F]) -> crate::ProofResult; } + /// Add field elements to the protocol transcript. pub trait FieldWriter: FieldPublic { fn add_scalars(&mut self, input: &[F]) -> crate::ProofResult<()>; } + /// Retrieve field elements from the protocol trainscript. pub trait FieldReader: FieldPublic { fn fill_next_scalars(&mut self, output: &mut [F]) -> crate::ProofResult<()>; diff --git a/src/safe.rs b/src/safe.rs index 6f9a530..118f515 100644 --- a/src/safe.rs +++ b/src/safe.rs @@ -1,3 +1,4 @@ +use core::fmt; use core::marker::PhantomData; use std::collections::vec_deque::VecDeque; @@ -133,8 +134,11 @@ impl> Safe { impl> Drop for Safe { /// Destroy the sponge state. fn drop(&mut self) { - // assert!(self.stack.is_empty()); - if self.stack.is_empty() { + // it's a bit violent to panic here, + // because any other issue in the protocol transcript causing `Safe` to get out of scope + // (like another panic) will pollute the traceback. + // debug_assert!(self.stack.is_empty()); + if !self.stack.is_empty() { log::error!("Unfinished operations:\n {:?}", self.stack) } // XXX. is the compiler going to optimize this out? @@ -142,8 +146,8 @@ impl> Drop for Safe { } } -impl> ::core::fmt::Debug for Safe { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { +impl> fmt::Debug for Safe { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Ensure that the state isn't accidentally logged, // but provide the remaining IO Pattern for debugging. write!(f, "SAFE sponge with IO: {:?}", self.stack) @@ -155,15 +159,3 @@ impl, B: core::borrow::Borrow>> From> Safe { - #[inline(always)] - pub fn absorb_bytes(&mut self, input: &[u8]) -> Result<(), IOPatternError> { - self.absorb(input) - } - - #[inline(always)] - pub fn squeeze_bytes(&mut self, output: &mut [u8]) -> Result<(), IOPatternError> { - self.squeeze(output) - } -} diff --git a/src/tests.rs b/src/tests.rs index 862c877..355a0d1 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,5 +1,9 @@ use crate::hash::keccak::Keccak; -use crate::{Arthur, ByteChallenges, IOPattern, Merlin, Safe}; +use crate::hash::legacy::DigestBridge; +use crate::{Arthur, ByteChallenges, ByteWriter, DuplexHash, IOPattern, Safe}; + +type Sha2 = DigestBridge; +type Blake2 = DigestBridge; /// How should a protocol without IOPattern be handled? #[test] @@ -70,20 +74,101 @@ fn test_statistics() { } #[test] -fn test_merlin() { - let io = IOPattern::new("domain separator") +fn test_transcript_readwrite() { + let io = IOPattern::::new("domain separator") .absorb(10, "hello") - .squeeze(10, "bye bye"); + .squeeze(10, "world"); - let mut arthur = Arthur::::from(&io); + let mut arthur = io.to_arthur(); arthur.add_units(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]).unwrap(); - arthur.fill_challenge_bytes(&mut [0u8; 10]).unwrap(); + let arthur_challenges = arthur.challenge_bytes::<10>().unwrap(); let transcript = arthur.transcript(); - let mut merlin = Merlin::::new(&io, transcript); + let mut merlin = io.to_merlin(transcript); let mut input = [0u8; 5]; merlin.fill_next_units(&mut input).unwrap(); assert_eq!(input, [0, 1, 2, 3, 4]); merlin.fill_next_units(&mut input).unwrap(); assert_eq!(input, [5, 6, 7, 8, 9]); + let merlin_challenges = merlin.challenge_bytes::<10>().unwrap(); + assert_eq!(merlin_challenges, arthur_challenges); +} + +/// An IO that is not fully finished should fail. +#[test] +#[should_panic] +fn test_incomplete_io() { + let io = IOPattern::::new("domain separator") + .absorb(10, "hello") + .squeeze(1, "nop"); + + let mut arthur = io.to_arthur(); + arthur.add_units(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]).unwrap(); + arthur.fill_challenge_bytes(&mut [0u8; 10]).unwrap(); +} + +/// The user should respect the IO pattern even with empty length. +#[test] +#[should_panic] +fn test_empty_absorb() { + let io = IOPattern::::new("domain separator") + .absorb(0, "nothing") + .squeeze(1, "something"); + + let mut arthur = io.to_arthur(); + arthur.fill_challenge_bytes(&mut [0u8; 1]).unwrap(); +} + +/// Absorbs and squeeze over byte-Units should be streamable. +fn test_streaming_absorb_and_squeeze() +where + Arthur: ByteWriter + ByteChallenges, +{ + let bytes = b"yellow submarine"; + + let io = IOPattern::::new("domain separator") + .absorb(16, "some bytes") + .squeeze(16, "control challenge") + .absorb(1, "level 2: use this as a prng stream") + .squeeze(1024, "that's a long challenge"); + + let mut arthur = io.to_arthur(); + arthur.add_bytes(bytes).unwrap(); + let control_chal = arthur.challenge_bytes::<16>().unwrap(); + let control_transcript = arthur.transcript(); + + let mut stream_arthur = io.to_arthur(); + stream_arthur.add_bytes(&bytes[..10]).unwrap(); + stream_arthur.add_bytes(&bytes[10..]).unwrap(); + let first_chal = stream_arthur.challenge_bytes::<8>().unwrap(); + let second_chal = stream_arthur.challenge_bytes::<8>().unwrap(); + let transcript = stream_arthur.transcript(); + + assert_eq!(transcript, control_transcript); + assert_eq!(&first_chal[..], &control_chal[..8]); + assert_eq!(&second_chal[..], &control_chal[8..]); + + arthur.add_bytes(&[0x42]).unwrap(); + stream_arthur.add_bytes(&[0x42]).unwrap(); + + let control_chal = arthur.challenge_bytes::<1024>().unwrap(); + for control_chunk in control_chal.chunks(16) { + let chunk = stream_arthur.challenge_bytes::<16>().unwrap(); + assert_eq!(control_chunk, &chunk[..]); + } +} + +#[test] +fn test_streaming_sha2() { + test_streaming_absorb_and_squeeze::(); +} + +#[test] +fn test_streaming_blake2() { + test_streaming_absorb_and_squeeze::(); +} + +#[test] +fn test_streaming_keccak() { + test_streaming_absorb_and_squeeze::(); }