From cd579d13d211e38b8731f7cc460582915b585147 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Wed, 6 Nov 2024 14:34:39 +0100 Subject: [PATCH 01/20] feat: STARK-based signature scheme --- Cargo.lock | 110 +++++++++++++++ Cargo.toml | 3 + src/dsa/mod.rs | 2 + src/dsa/rpo_stark/mod.rs | 25 ++++ src/dsa/rpo_stark/signature/mod.rs | 156 +++++++++++++++++++++ src/dsa/rpo_stark/stark/air.rs | 217 +++++++++++++++++++++++++++++ src/dsa/rpo_stark/stark/mod.rs | 67 +++++++++ src/dsa/rpo_stark/stark/prover.rs | 116 +++++++++++++++ src/hash/mod.rs | 5 +- src/hash/rescue/mod.rs | 18 +-- 10 files changed, 709 insertions(+), 10 deletions(-) create mode 100644 src/dsa/rpo_stark/mod.rs create mode 100644 src/dsa/rpo_stark/signature/mod.rs create mode 100644 src/dsa/rpo_stark/stark/air.rs create mode 100644 src/dsa/rpo_stark/stark/mod.rs create mode 100644 src/dsa/rpo_stark/stark/prover.rs diff --git a/Cargo.lock b/Cargo.lock index 3e822fb3c..229ed15ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -539,8 +539,11 @@ dependencies = [ "sha3", "winter-crypto", "winter-math", + "winter-prover", "winter-rand-utils", "winter-utils", + "winter-verifier", + "winterfell", ] [[package]] @@ -629,6 +632,12 @@ version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + [[package]] name = "plotters" version = "0.3.7" @@ -932,6 +941,34 @@ dependencies = [ "serde_json", ] +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" + [[package]] name = "typenum" version = "1.17.0" @@ -1143,6 +1180,19 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winter-air" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29bec0b06b741543f43e3a6677b95b200d4cad2daab76e6721e14345345bfd0e" +dependencies = [ + "libm", + "winter-crypto", + "winter-fri", + "winter-math", + "winter-utils", +] + [[package]] name = "winter-crypto" version = "0.10.1" @@ -1155,6 +1205,17 @@ dependencies = [ "winter-utils", ] +[[package]] +name = "winter-fri" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b7b394670d68979a4cc21a37a95ef8ef350cf84be9256c53effe3052df50d26" +dependencies = [ + "winter-crypto", + "winter-math", + "winter-utils", +] + [[package]] name = "winter-math" version = "0.10.1" @@ -1165,6 +1226,31 @@ dependencies = [ "winter-utils", ] +[[package]] +name = "winter-maybe-async" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be43529f43f70306437d2c2c9f9e2b3a4d39b42e86702d8d7577f2357ea32fa6" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "winter-prover" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f55f0153d26691caaf969066a13a824bcf3c98719d71b0f569bf8dc40a06fb9" +dependencies = [ + "tracing", + "winter-air", + "winter-crypto", + "winter-fri", + "winter-math", + "winter-maybe-async", + "winter-utils", +] + [[package]] name = "winter-rand-utils" version = "0.10.1" @@ -1181,6 +1267,30 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76b116c8ade0172506f8bda32dc674cf6b230adc8516e5138a0173ae69158a4f" +[[package]] +name = "winter-verifier" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae1648768f96f5e6321a48a5bff5cc3101d2e51b23a6a095c6c9c9e133ecb61" +dependencies = [ + "winter-air", + "winter-crypto", + "winter-fri", + "winter-math", + "winter-utils", +] + +[[package]] +name = "winterfell" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39c8336dc6a035698780b8cc624f875e479bd6bf6e1846670f3ef4485c125882" +dependencies = [ + "winter-air", + "winter-prover", + "winter-verifier", +] + [[package]] name = "zerocopy" version = "0.7.35" diff --git a/Cargo.toml b/Cargo.toml index 5d124c687..d342f901c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,10 @@ serde = { version = "1.0", default-features = false, optional = true, features = sha3 = { version = "0.10", default-features = false } winter-crypto = { version = "0.10", default-features = false } winter-math = { version = "0.10", default-features = false } +winter-prover = { version = "0.10", default-features = false } winter-utils = { version = "0.10", default-features = false } +winter-verifier = { version = "0.10", default-features = false } +winterfell = { version = "0.10", default-features = false } [dev-dependencies] criterion = { version = "0.5", features = ["html_reports"] } diff --git a/src/dsa/mod.rs b/src/dsa/mod.rs index 9c5c0a5ed..470cde044 100644 --- a/src/dsa/mod.rs +++ b/src/dsa/mod.rs @@ -1,3 +1,5 @@ //! Digital signature schemes supported by default in the Miden VM. pub mod rpo_falcon512; + +pub mod rpo_stark; diff --git a/src/dsa/rpo_stark/mod.rs b/src/dsa/rpo_stark/mod.rs new file mode 100644 index 000000000..00631c7ec --- /dev/null +++ b/src/dsa/rpo_stark/mod.rs @@ -0,0 +1,25 @@ +mod signature; +pub use signature::{PublicKey, SecretKey, Signature}; + +mod stark; + +// TESTS +// ================================================================================================ + +#[cfg(test)] +mod tests { + use super::SecretKey; + + #[test] + fn test_signature() { + use rand_utils::rand_array; + + let sk = SecretKey::new(); + + let message = rand_array(); + let signature = sk.sign(message); + + let pk = sk.compute_public_key(); + assert!(pk.verify(message, &signature)) + } +} diff --git a/src/dsa/rpo_stark/signature/mod.rs b/src/dsa/rpo_stark/signature/mod.rs new file mode 100644 index 000000000..da24d3ba5 --- /dev/null +++ b/src/dsa/rpo_stark/signature/mod.rs @@ -0,0 +1,156 @@ +use rand::Rng; +use winter_math::fields::f64::BaseElement; +use winter_prover::Proof; +use winter_utils::{ + ByteReader, ByteWriter, Deserializable, DeserializationError, Randomizable, Serializable, +}; +use winterfell::{FieldExtension, ProofOptions}; + +use super::stark::compute_rpo_image; +use crate::{dsa::rpo_stark::stark::RpoSignatureScheme, hash::rpo::Rpo256, Word, ZERO}; + +// CONSTANTS +// ================================================================================================ + +/// Specifies the parameters of the STARK underlying the signature scheme. +/// +/// TODO: The number of queries needs to be updated so that it matches the one given in +/// the specification. The reason for choosing such a low number for the number of FRI queries is +/// due to the fact that the number of FRI queries should be smaller than the size of the LDE +/// domain. Since the PR enabling zero-knowledge in Winterfell is yet to be merged, this not +/// case. +pub const PROOF_OPTIONS: ProofOptions = + ProofOptions::new(63, 8, 0, FieldExtension::Quadratic, 8, 31); + +// PUBLIC KEY +// ================================================================================================ + +/// A public key for verifying signatures. +/// +/// The public key is a [Word] (i.e., 4 field elements) that is the hash of the secret key. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct PublicKey(Word); + +impl PublicKey { + /// Verifies the provided signature against provided message and this public key. + pub fn verify(&self, message: Word, signature: &Signature) -> bool { + signature.verify(message, self.0) + } +} + +// SECRET KEY +// ================================================================================================ + +/// A secret key for generating signatures. +/// +/// The secret key is a [Word] (i.e., 4 field elements). +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct SecretKey(Word); + +impl SecretKey { + /// Generates a secret key from OS-provided randomness. + #[cfg(feature = "std")] + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + use rand::{rngs::StdRng, SeedableRng}; + + let mut rng = StdRng::from_entropy(); + Self::with_rng(&mut rng) + } + + /// Generates a secret_key using the provided random number generator `Rng`. + pub fn with_rng(rng: &mut R) -> Self { + let mut sk = [ZERO; 4]; + + let mut dest = vec![0_u8; 8]; + for s in sk.iter_mut() { + rng.fill_bytes(&mut dest); + *s = BaseElement::from_random_bytes(&dest).expect(""); + } + + Self(sk) + } + + /// Computes the public key corresponding to this secret key. + pub fn compute_public_key(&self) -> PublicKey { + let pk = compute_rpo_image(self.0); + PublicKey(pk) + } + + /// Signs a message with this secret key. + pub fn sign(&self, message: Word) -> Signature { + let signature: RpoSignatureScheme = RpoSignatureScheme::new(PROOF_OPTIONS); + let proof = signature.sign(self.0, message); + Signature { proof } + } +} + +// SIGNATURE +// ================================================================================================ + +/// An RPO STARK-based signature over a message. +/// +/// The signature is a STARK proof of knowledge of a pre-image given an image where the map is +/// the RPO permutation, the pre-image is the secret key and the image is the public key. +/// The current implementation follows the description in [1] in the unique decoding regime where +/// it is argued that for the parameter set [PROOF_OPTIONS] the signature achieves $113$ bits of +/// average-case existential unforgeability security against $2^{113}$-query bound adversaries +/// that can obtain up to $2^{64}$ signatures under the same public key. +/// +/// [1]: https://eprint.iacr.org/2024/1553 +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Signature { + proof: Proof, +} + +impl Signature { + /// Returns true if this signature is a valid signature for the specified message generated + /// against the secret key matching the specified public key commitment. + pub fn verify(&self, message: Word, pk: Word) -> bool { + let signature: RpoSignatureScheme = RpoSignatureScheme::new(PROOF_OPTIONS); + + signature.verify(pk, message, self.proof.clone()).is_ok() + } +} + +// SERIALIZATION / DESERIALIZATION +// ================================================================================================ + +impl Serializable for PublicKey { + fn write_into(&self, target: &mut W) { + self.0.write_into(target); + } +} + +impl Deserializable for PublicKey { + fn read_from(source: &mut R) -> Result { + let pk = ::read_from(source)?; + Ok(Self(pk)) + } +} + +impl Serializable for SecretKey { + fn write_into(&self, target: &mut W) { + self.0.write_into(target); + } +} + +impl Deserializable for SecretKey { + fn read_from(source: &mut R) -> Result { + let sk = ::read_from(source)?; + Ok(Self(sk)) + } +} + +impl Serializable for Signature { + fn write_into(&self, target: &mut W) { + self.proof.write_into(target); + } +} + +impl Deserializable for Signature { + fn read_from(source: &mut R) -> Result { + let proof = Proof::read_from(source)?; + Ok(Self { proof }) + } +} diff --git a/src/dsa/rpo_stark/stark/air.rs b/src/dsa/rpo_stark/stark/air.rs new file mode 100644 index 000000000..ccd090f28 --- /dev/null +++ b/src/dsa/rpo_stark/stark/air.rs @@ -0,0 +1,217 @@ +use std::vec::Vec; + +use winter_math::{fields::f64::BaseElement, FieldElement, ToElements}; +use winter_prover::{ + Air, AirContext, Assertion, EvaluationFrame, ProofOptions, TraceInfo, + TransitionConstraintDegree, +}; + +use crate::{ + hash::rpo::{ARK1, ARK2, MDS, STATE_WIDTH}, + Word, ZERO, +}; + +// CONSTANTS +// ================================================================================================ + +pub const HASH_CYCLE_LEN: usize = 8; +pub const TRACE_WIDTH: usize = 12; + +// AIR +// ================================================================================================ + +pub struct RescueAir { + context: AirContext, + pub_key: Word, +} + +impl Air for RescueAir { + type BaseField = BaseElement; + type PublicInputs = PublicInputs; + + type GkrProof = (); + type GkrVerifier = (); + + // CONSTRUCTOR + // -------------------------------------------------------------------------------------------- + fn new(trace_info: TraceInfo, pub_inputs: PublicInputs, options: ProofOptions) -> Self { + let degrees = vec![ + // Apply RPO rounds. + TransitionConstraintDegree::new(7), + TransitionConstraintDegree::new(7), + TransitionConstraintDegree::new(7), + TransitionConstraintDegree::new(7), + TransitionConstraintDegree::new(7), + TransitionConstraintDegree::new(7), + TransitionConstraintDegree::new(7), + TransitionConstraintDegree::new(7), + TransitionConstraintDegree::new(7), + TransitionConstraintDegree::new(7), + TransitionConstraintDegree::new(7), + TransitionConstraintDegree::new(7), + ]; + assert_eq!(TRACE_WIDTH, trace_info.width()); + let context = AirContext::new(trace_info, degrees, 12, options); + let context = context.set_num_transition_exemptions(1); + RescueAir { context, pub_key: pub_inputs.pub_key } + } + + fn context(&self) -> &AirContext { + &self.context + } + + fn evaluate_transition>( + &self, + frame: &EvaluationFrame, + periodic_values: &[E], + result: &mut [E], + ) { + let current = frame.current(); + let next = frame.next(); + // expected state width is 12 field elements + debug_assert_eq!(TRACE_WIDTH, current.len()); + debug_assert_eq!(TRACE_WIDTH, next.len()); + + enforce_rpo_round(frame, result, periodic_values); + } + + fn get_assertions(&self) -> Vec> { + // Assert that the public key is the correct one + let initial_step = 0; + let last_step = self.trace_length() - 1; + vec![ + Assertion::single(0, initial_step, Self::BaseField::ZERO), + Assertion::single(1, initial_step, Self::BaseField::ZERO), + Assertion::single(2, initial_step, Self::BaseField::ZERO), + Assertion::single(3, initial_step, Self::BaseField::ZERO), + Assertion::single(8, initial_step, Self::BaseField::ZERO), + Assertion::single(9, initial_step, Self::BaseField::ZERO), + Assertion::single(10, initial_step, Self::BaseField::ZERO), + Assertion::single(11, initial_step, Self::BaseField::ZERO), + Assertion::single(4, last_step, self.pub_key[0]), + Assertion::single(5, last_step, self.pub_key[1]), + Assertion::single(6, last_step, self.pub_key[2]), + Assertion::single(7, last_step, self.pub_key[3]), + ] + } + + fn get_periodic_column_values(&self) -> Vec> { + get_round_constants() + } +} + +pub struct PublicInputs { + pub(crate) pub_key: Word, + pub(crate) msg: Word, +} + +impl ToElements for PublicInputs { + fn to_elements(&self) -> Vec { + let mut res = self.pub_key.to_vec(); + res.extend_from_slice(self.msg.as_ref()); + res + } +} + +// HELPER EVALUATORS +// ------------------------------------------------------------------------------------------------ + +/// Enforces constraints for a single round of the Rescue Prime Optimized hash functions. +pub fn enforce_rpo_round>( + frame: &EvaluationFrame, + result: &mut [E], + ark: &[E], +) { + // compute the state that should result from applying the first 5 operations of the RPO round to + // the current hash state. + let mut step1 = [E::ZERO; STATE_WIDTH]; + step1.copy_from_slice(frame.current()); + + apply_mds(&mut step1); + // add constants + for i in 0..STATE_WIDTH { + step1[i] += ark[i]; + } + apply_sbox(&mut step1); + apply_mds(&mut step1); + // add constants + for i in 0..STATE_WIDTH { + step1[i] += ark[STATE_WIDTH + i]; + } + + // compute the state that should result from applying the inverse of the last operation of the + // RPO round to the next step of the computation. + let mut step2 = [E::ZERO; STATE_WIDTH]; + step2.copy_from_slice(frame.next()); + apply_sbox(&mut step2); + + // make sure that the results are equal. + for i in 0..STATE_WIDTH { + result.agg_constraint(i, are_equal(step2[i], step1[i])); + } +} + +#[inline(always)] +fn apply_sbox>(state: &mut [E; STATE_WIDTH]) { + state.iter_mut().for_each(|v| { + let t2 = v.square(); + let t4 = t2.square(); + *v *= t2 * t4; + }); +} + +#[inline(always)] +fn apply_mds>(state: &mut [E; STATE_WIDTH]) { + let mut result = [E::ZERO; STATE_WIDTH]; + result.iter_mut().zip(MDS).for_each(|(r, mds_row)| { + state.iter().zip(mds_row).for_each(|(&s, m)| { + *r += E::from(m) * s; + }); + }); + *state = result +} + +/// Returns RPO round constants arranged in column-major form. +pub fn get_round_constants() -> Vec> { + let mut constants = Vec::new(); + for _ in 0..(STATE_WIDTH * 2) { + constants.push(vec![ZERO; HASH_CYCLE_LEN]); + } + + #[allow(clippy::needless_range_loop)] + for i in 0..HASH_CYCLE_LEN - 1 { + for j in 0..STATE_WIDTH { + constants[j][i] = ARK1[i][j]; + constants[j + STATE_WIDTH][i] = ARK2[i][j]; + } + } + + constants +} + +// CONSTRAINT EVALUATION HELPERS +// ================================================================================================ + +/// Returns zero only when a == b. +pub fn are_equal(a: E, b: E) -> E { + a - b +} + +// TRAIT TO SIMPLIFY CONSTRAINT AGGREGATION +// ================================================================================================ + +pub trait EvaluationResult { + fn agg_constraint(&mut self, index: usize, value: E); +} + +impl EvaluationResult for [E] { + fn agg_constraint(&mut self, index: usize, value: E) { + self[index] += value; + } +} + +impl EvaluationResult for Vec { + fn agg_constraint(&mut self, index: usize, value: E) { + self[index] += value; + } +} diff --git a/src/dsa/rpo_stark/stark/mod.rs b/src/dsa/rpo_stark/stark/mod.rs new file mode 100644 index 000000000..67b36bb0c --- /dev/null +++ b/src/dsa/rpo_stark/stark/mod.rs @@ -0,0 +1,67 @@ +use core::marker::PhantomData; + +use air::{PublicInputs, RescueAir}; +use prover::RpoSignatureProver; +use winter_crypto::{DefaultRandomCoin, ElementHasher, MerkleTree}; +use winter_math::{fields::f64::BaseElement, FieldElement}; +use winter_prover::{Proof, ProofOptions}; +use winter_verifier::{verify, AcceptableOptions, VerifierError}; +use winterfell::Prover; + +use crate::hash::rpo::{Rpo256, DIGEST_RANGE, DIGEST_SIZE, NUM_ROUNDS, STATE_WIDTH}; + +mod air; +mod prover; + +/// Represents an abstract STARK-based signature scheme with knowledge of RPO pre-image as +/// the hard relation. +pub struct RpoSignatureScheme { + options: ProofOptions, + _h: PhantomData, +} + +impl + Sync> RpoSignatureScheme { + pub fn new(options: ProofOptions) -> Self { + RpoSignatureScheme { options, _h: PhantomData } + } + + pub fn sign(&self, sk: [BaseElement; DIGEST_SIZE], msg: [BaseElement; DIGEST_SIZE]) -> Proof { + // create a prover + let prover = RpoSignatureProver::::new(self.options.clone()); + + // generate execution trace + let trace = prover.build_trace(sk, msg); + + // generate the proof + prover.prove(trace).expect("failed to generate the signature") + } + + pub fn verify( + &self, + pub_key: [BaseElement; DIGEST_SIZE], + msg: [BaseElement; DIGEST_SIZE], + proof: Proof, + ) -> Result<(), VerifierError> { + let pub_inputs = PublicInputs { pub_key, msg }; + let acceptable_options = AcceptableOptions::OptionSet(vec![proof.options().clone()]); + verify::, MerkleTree>( + proof, + pub_inputs, + &acceptable_options, + ) + } +} + +// HELPER FUNCTIONS +// ================================================================================================ + +pub fn compute_rpo_image(pre_image: [BaseElement; DIGEST_SIZE]) -> [BaseElement; DIGEST_SIZE] { + let mut state = [BaseElement::ZERO; STATE_WIDTH]; + state[DIGEST_RANGE].copy_from_slice(&pre_image); + for i in 0..NUM_ROUNDS { + Rpo256::apply_round(&mut state, i); + } + state[DIGEST_RANGE] + .try_into() + .expect("should not fail given the size of the array") +} diff --git a/src/dsa/rpo_stark/stark/prover.rs b/src/dsa/rpo_stark/stark/prover.rs new file mode 100644 index 000000000..e4148f0e3 --- /dev/null +++ b/src/dsa/rpo_stark/stark/prover.rs @@ -0,0 +1,116 @@ +use core::marker::PhantomData; + +use winter_crypto::{DefaultRandomCoin, ElementHasher, MerkleTree}; +use winter_math::{fields::f64::BaseElement, FieldElement}; +use winter_prover::{ + matrix::ColMatrix, DefaultConstraintEvaluator, DefaultTraceLde, ProofOptions, Prover, + StarkDomain, Trace, TraceInfo, TracePolyTable, TraceTable, +}; +use winter_utils::{Deserializable, Serializable}; +use winterfell::{AuxRandElements, ConstraintCompositionCoefficients, PartitionOptions}; + +use super::air::{PublicInputs, RescueAir, HASH_CYCLE_LEN}; +use crate::{hash::rpo::Rpo256, Word, ZERO}; + +// PROVER +// ================================================================================================ + +pub struct RpoSignatureProver +where + H: Sync, +{ + options: ProofOptions, + _hasher: PhantomData, +} + +impl RpoSignatureProver { + pub fn new(options: ProofOptions) -> Self { + Self { options, _hasher: PhantomData } + } + + pub fn build_trace(&self, sk: Word, msg: Word) -> TraceTable { + let trace_length = HASH_CYCLE_LEN; + let mut target = vec![]; + msg.write_into(&mut target); + let mut trace = TraceTable::with_meta(12, trace_length, target); + + trace.fill( + |state| { + // initialize first state of the computation + state[0] = ZERO; + state[1] = ZERO; + state[2] = ZERO; + state[3] = ZERO; + state[4] = sk[0]; + state[5] = sk[1]; + state[6] = sk[2]; + state[7] = sk[3]; + state[8] = ZERO; + state[9] = ZERO; + state[10] = ZERO; + state[11] = ZERO; + }, + |step, state| { + Rpo256::apply_round( + state.try_into().expect("should not fail given the size of the array"), + step, + ); + }, + ); + trace + } +} + +impl Prover for RpoSignatureProver +where + H: ElementHasher + Sync, +{ + type BaseField = BaseElement; + type Air = RescueAir; + type Trace = TraceTable; + type HashFn = H; + type VC = MerkleTree; + type RandomCoin = DefaultRandomCoin; + type TraceLde> = + DefaultTraceLde; + type ConstraintEvaluator<'a, E: FieldElement> = + DefaultConstraintEvaluator<'a, Self::Air, E>; + + fn get_pub_inputs(&self, trace: &Self::Trace) -> PublicInputs { + let last_step = trace.length() - 1; + let source = trace.info().meta(); + let msg = ::read_from_bytes(source).expect("the message should be a Word"); + PublicInputs { + pub_key: [ + trace.get(4, last_step), + trace.get(5, last_step), + trace.get(6, last_step), + trace.get(7, last_step), + ], + msg, + } + } + + fn options(&self) -> &ProofOptions { + &self.options + } + + fn new_trace_lde>( + &self, + trace_info: &TraceInfo, + main_trace: &ColMatrix, + domain: &StarkDomain, + partition_option: PartitionOptions, + ) -> (Self::TraceLde, TracePolyTable) { + DefaultTraceLde::new(trace_info, main_trace, domain, partition_option) + } + + fn new_evaluator<'a, E: FieldElement>( + &self, + air: &'a Self::Air, + aux_rand_elements: Option>, + composition_coefficients: ConstraintCompositionCoefficients, + ) -> Self::ConstraintEvaluator<'a, E> { + DefaultConstraintEvaluator::new(air, aux_rand_elements, composition_coefficients) + } +} diff --git a/src/hash/mod.rs b/src/hash/mod.rs index e7fd9c721..fd9464ecb 100644 --- a/src/hash/mod.rs +++ b/src/hash/mod.rs @@ -6,7 +6,10 @@ pub mod blake; mod rescue; pub mod rpo { - pub use super::rescue::{Rpo256, RpoDigest, RpoDigestError}; + pub use super::rescue::{ + Rpo256, RpoDigest, RpoDigestError, ARK1, ARK2, DIGEST_RANGE, DIGEST_SIZE, MDS, NUM_ROUNDS, + STATE_WIDTH, + }; } pub mod rpx { diff --git a/src/hash/rescue/mod.rs b/src/hash/rescue/mod.rs index fee20aba6..530f62eac 100644 --- a/src/hash/rescue/mod.rs +++ b/src/hash/rescue/mod.rs @@ -6,7 +6,7 @@ mod arch; pub use arch::optimized::{add_constants_and_apply_inv_sbox, add_constants_and_apply_sbox}; mod mds; -use mds::{apply_mds, MDS}; +pub use mds::{apply_mds, MDS}; mod rpo; pub use rpo::{Rpo256, RpoDigest, RpoDigestError}; @@ -22,11 +22,11 @@ mod tests; /// The number of rounds is set to 7. For the RPO hash functions all rounds are uniform. For the /// RPX hash function, there are 3 different types of rounds. -const NUM_ROUNDS: usize = 7; +pub const NUM_ROUNDS: usize = 7; /// Sponge state is set to 12 field elements or 96 bytes; 8 elements are reserved for rate and /// the remaining 4 elements are reserved for capacity. -const STATE_WIDTH: usize = 12; +pub const STATE_WIDTH: usize = 12; /// The rate portion of the state is located in elements 4 through 11. const RATE_RANGE: Range = 4..12; @@ -42,8 +42,8 @@ const CAPACITY_RANGE: Range = 0..4; /// /// The digest is returned from state elements 4, 5, 6, and 7 (the first four elements of the /// rate portion). -const DIGEST_RANGE: Range = 4..8; -const DIGEST_SIZE: usize = DIGEST_RANGE.end - DIGEST_RANGE.start; +pub const DIGEST_RANGE: Range = 4..8; +pub const DIGEST_SIZE: usize = DIGEST_RANGE.end - DIGEST_RANGE.start; /// The number of bytes needed to encoded a digest const DIGEST_BYTES: usize = 32; @@ -83,7 +83,7 @@ fn apply_sbox(state: &mut [Felt; STATE_WIDTH]) { // ================================================================================================ #[inline(always)] -fn apply_inv_sbox(state: &mut [Felt; STATE_WIDTH]) { +pub fn apply_inv_sbox(state: &mut [Felt; STATE_WIDTH]) { // compute base^10540996611094048183 using 72 multiplications per array element // 10540996611094048183 = b1001001001001001001001001001000110110110110110110110110110110111 @@ -132,7 +132,7 @@ fn apply_inv_sbox(state: &mut [Felt; STATE_WIDTH]) { } #[inline(always)] -fn add_constants(state: &mut [Felt; STATE_WIDTH], ark: &[Felt; STATE_WIDTH]) { +pub fn add_constants(state: &mut [Felt; STATE_WIDTH], ark: &[Felt; STATE_WIDTH]) { state.iter_mut().zip(ark).for_each(|(s, &k)| *s += k); } @@ -144,7 +144,7 @@ fn add_constants(state: &mut [Felt; STATE_WIDTH], ark: &[Felt; STATE_WIDTH]) { /// /// The constants are broken up into two arrays ARK1 and ARK2; ARK1 contains the constants for the /// first half of RPO round, and ARK2 contains constants for the second half of RPO round. -const ARK1: [[Felt; STATE_WIDTH]; NUM_ROUNDS] = [ +pub const ARK1: [[Felt; STATE_WIDTH]; NUM_ROUNDS] = [ [ Felt::new(5789762306288267392), Felt::new(6522564764413701783), @@ -245,7 +245,7 @@ const ARK1: [[Felt; STATE_WIDTH]; NUM_ROUNDS] = [ ], ]; -const ARK2: [[Felt; STATE_WIDTH]; NUM_ROUNDS] = [ +pub const ARK2: [[Felt; STATE_WIDTH]; NUM_ROUNDS] = [ [ Felt::new(6077062762357204287), Felt::new(15277620170502011191), From ec0953985fb2bf62cfc5435284b403a507226476 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Wed, 6 Nov 2024 14:53:58 +0100 Subject: [PATCH 02/20] fix: clippy --- src/dsa/rpo_stark/signature/mod.rs | 2 +- src/dsa/rpo_stark/stark/air.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dsa/rpo_stark/signature/mod.rs b/src/dsa/rpo_stark/signature/mod.rs index da24d3ba5..f073e69b4 100644 --- a/src/dsa/rpo_stark/signature/mod.rs +++ b/src/dsa/rpo_stark/signature/mod.rs @@ -93,7 +93,7 @@ impl SecretKey { /// The signature is a STARK proof of knowledge of a pre-image given an image where the map is /// the RPO permutation, the pre-image is the secret key and the image is the public key. /// The current implementation follows the description in [1] in the unique decoding regime where -/// it is argued that for the parameter set [PROOF_OPTIONS] the signature achieves $113$ bits of +/// it is argued that for the parameter set `PROOF_OPTIONS` the signature achieves $113$ bits of /// average-case existential unforgeability security against $2^{113}$-query bound adversaries /// that can obtain up to $2^{64}$ signatures under the same public key. /// diff --git a/src/dsa/rpo_stark/stark/air.rs b/src/dsa/rpo_stark/stark/air.rs index ccd090f28..64dea565e 100644 --- a/src/dsa/rpo_stark/stark/air.rs +++ b/src/dsa/rpo_stark/stark/air.rs @@ -1,4 +1,4 @@ -use std::vec::Vec; +use alloc::vec::Vec; use winter_math::{fields::f64::BaseElement, FieldElement, ToElements}; use winter_prover::{ From cb15287ce7e3e4766d41f2154b47395d81131d98 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Wed, 6 Nov 2024 15:02:09 +0100 Subject: [PATCH 03/20] fix: clippy --- src/dsa/rpo_stark/mod.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/dsa/rpo_stark/mod.rs b/src/dsa/rpo_stark/mod.rs index 00631c7ec..128200b19 100644 --- a/src/dsa/rpo_stark/mod.rs +++ b/src/dsa/rpo_stark/mod.rs @@ -8,13 +8,18 @@ mod stark; #[cfg(test)] mod tests { + use rand::SeedableRng; + use rand_chacha::ChaCha20Rng; + use super::SecretKey; #[test] fn test_signature() { use rand_utils::rand_array; - let sk = SecretKey::new(); + let seed = [0_u8; 32]; + let mut rng = ChaCha20Rng::from_seed(seed); + let sk = SecretKey::with_rng(&mut rng); let message = rand_array(); let signature = sk.sign(message); From 2fa04229d174fec603a576611f5da9ba88a7c80c Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Mon, 18 Nov 2024 05:47:22 +0100 Subject: [PATCH 04/20] wip --- Cargo.lock | 111 ++++++++++++++--------------- Cargo.toml | 15 ++++ src/dsa/rpo_stark/mod.rs | 6 +- src/dsa/rpo_stark/signature/mod.rs | 17 ++++- src/dsa/rpo_stark/stark/air.rs | 6 ++ src/dsa/rpo_stark/stark/mod.rs | 14 ++-- src/dsa/rpo_stark/stark/prover.rs | 24 +++++-- src/hash/blake/mod.rs | 8 +++ src/hash/rescue/rpo/digest.rs | 25 +++++++ src/hash/rescue/rpx/digest.rs | 12 ++++ src/rand/rpo.rs | 36 +++++++++- src/rand/rpx.rs | 8 +++ 12 files changed, 211 insertions(+), 71 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 229ed15ee..2b7b58429 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.17" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -34,9 +34,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" @@ -147,9 +147,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.1.31" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" +checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" dependencies = [ "jobserver", "libc", @@ -191,9 +191,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -201,9 +201,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -225,9 +225,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "colorchoice" @@ -243,9 +243,9 @@ checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" dependencies = [ "libc", ] @@ -355,9 +355,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "fnv" @@ -489,9 +489,18 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.161" +version = "0.2.162" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" + +[[package]] +name = "libc-print" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "a4a660208db49e35faf57b37484350f1a61072f2a5becf0592af6015d9ddd4b0" +dependencies = [ + "libc", +] [[package]] name = "libm" @@ -537,6 +546,7 @@ dependencies = [ "seq-macro", "serde", "sha3", + "winter-air", "winter-crypto", "winter-math", "winter-prover", @@ -792,9 +802,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -809,9 +819,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustix" -version = "0.38.38" +version = "0.38.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" +checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" dependencies = [ "bitflags", "errno", @@ -855,18 +865,18 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" [[package]] name = "serde" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", @@ -909,9 +919,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.85" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -920,9 +930,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", @@ -1182,9 +1192,7 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winter-air" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bec0b06b741543f43e3a6677b95b200d4cad2daab76e6721e14345345bfd0e" +version = "0.10.0" dependencies = [ "libm", "winter-crypto", @@ -1195,11 +1203,10 @@ dependencies = [ [[package]] name = "winter-crypto" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "163da45f1d4d65cac361b8df4835a6daa95b3399154e16eb0305c178c6f6c1f4" +version = "0.10.0" dependencies = [ "blake3", + "rand", "sha3", "winter-math", "winter-utils", @@ -1207,10 +1214,10 @@ dependencies = [ [[package]] name = "winter-fri" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7b394670d68979a4cc21a37a95ef8ef350cf84be9256c53effe3052df50d26" +version = "0.10.0" dependencies = [ + "rand", + "rand_chacha", "winter-crypto", "winter-math", "winter-utils", @@ -1218,9 +1225,7 @@ dependencies = [ [[package]] name = "winter-math" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a8ba832121679e79b004b0003018c85873956d742a39c348c247f680fe15e00" +version = "0.10.0" dependencies = [ "serde", "winter-utils", @@ -1229,8 +1234,6 @@ dependencies = [ [[package]] name = "winter-maybe-async" version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be43529f43f70306437d2c2c9f9e2b3a4d39b42e86702d8d7577f2357ea32fa6" dependencies = [ "quote", "syn", @@ -1238,24 +1241,24 @@ dependencies = [ [[package]] name = "winter-prover" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f55f0153d26691caaf969066a13a824bcf3c98719d71b0f569bf8dc40a06fb9" +version = "0.10.0" dependencies = [ + "libc-print", + "rand", + "rand_chacha", "tracing", "winter-air", "winter-crypto", "winter-fri", "winter-math", "winter-maybe-async", + "winter-rand-utils", "winter-utils", ] [[package]] name = "winter-rand-utils" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a7616d11fcc26552dada45c803a884ac97c253218835b83a2c63e1c2a988639" +version = "0.10.0" dependencies = [ "rand", "winter-utils", @@ -1263,15 +1266,11 @@ dependencies = [ [[package]] name = "winter-utils" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b116c8ade0172506f8bda32dc674cf6b230adc8516e5138a0173ae69158a4f" +version = "0.10.0" [[package]] name = "winter-verifier" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ae1648768f96f5e6321a48a5bff5cc3101d2e51b23a6a095c6c9c9e133ecb61" +version = "0.10.0" dependencies = [ "winter-air", "winter-crypto", diff --git a/Cargo.toml b/Cargo.toml index d342f901c..de5b5dc1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,12 +55,14 @@ rand_core = { version = "0.6", default-features = false } rand-utils = { version = "0.10", package = "winter-rand-utils", optional = true } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } sha3 = { version = "0.10", default-features = false } +winter-air = { version = "0.10", default-features = false } winter-crypto = { version = "0.10", default-features = false } winter-math = { version = "0.10", default-features = false } winter-prover = { version = "0.10", default-features = false } winter-utils = { version = "0.10", default-features = false } winter-verifier = { version = "0.10", default-features = false } winterfell = { version = "0.10", default-features = false } +rand_chacha = { version = "0.3", default-features = false } [dev-dependencies] criterion = { version = "0.5", features = ["html_reports"] } @@ -74,3 +76,16 @@ seq-macro = { version = "0.3" } [build-dependencies] cc = { version = "1.1", optional = true, features = ["parallel"] } glob = "0.3" + + +[patch.crates-io] +winter-air = {path = "../../training/test_task/winterfell/air" } +winter-crypto = {path = "../../training/test_task/winterfell/crypto" } +winter-prover = {path = "../../training/test_task/winterfell/prover" } +winter-verifier = {path = "../../training/test_task/winterfell/verifier" } +winter-math = {path = "../../training/test_task/winterfell/math" } +winter-fri = {path = "../../training/test_task/winterfell/fri" } +winter-maybe-async = {path = "../../training/test_task/winterfell/utils/maybe_async" } +winter-utils = {path = "../../training/test_task/winterfell/utils/core" } +winter-rand-utils = {path = "../../training/test_task/winterfell/utils/rand" } + diff --git a/src/dsa/rpo_stark/mod.rs b/src/dsa/rpo_stark/mod.rs index 128200b19..b8bb52dff 100644 --- a/src/dsa/rpo_stark/mod.rs +++ b/src/dsa/rpo_stark/mod.rs @@ -2,12 +2,15 @@ mod signature; pub use signature::{PublicKey, SecretKey, Signature}; mod stark; +pub use stark::{PublicInputs, RescueAir}; // TESTS // ================================================================================================ #[cfg(test)] mod tests { + use std::println; + use rand::SeedableRng; use rand_chacha::ChaCha20Rng; @@ -23,8 +26,9 @@ mod tests { let message = rand_array(); let signature = sk.sign(message); - + //println!("signature {:?}", signature); let pk = sk.compute_public_key(); + println!("verify {:?}", pk.verify(message, &signature)); assert!(pk.verify(message, &signature)) } } diff --git a/src/dsa/rpo_stark/signature/mod.rs b/src/dsa/rpo_stark/signature/mod.rs index f073e69b4..515c334e3 100644 --- a/src/dsa/rpo_stark/signature/mod.rs +++ b/src/dsa/rpo_stark/signature/mod.rs @@ -1,3 +1,5 @@ +use std::println; + use rand::Rng; use winter_math::fields::f64::BaseElement; use winter_prover::Proof; @@ -20,7 +22,7 @@ use crate::{dsa::rpo_stark::stark::RpoSignatureScheme, hash::rpo::Rpo256, Word, /// domain. Since the PR enabling zero-knowledge in Winterfell is yet to be merged, this not /// case. pub const PROOF_OPTIONS: ProofOptions = - ProofOptions::new(63, 8, 0, FieldExtension::Quadratic, 8, 31); + ProofOptions::new(3, 8, 0, FieldExtension::Quadratic, 4, 31, true); // PUBLIC KEY // ================================================================================================ @@ -31,6 +33,12 @@ pub const PROOF_OPTIONS: ProofOptions = #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct PublicKey(Word); +impl PublicKey { + pub fn inner(&self) -> Word { + self.0 + } +} + impl PublicKey { /// Verifies the provided signature against provided message and this public key. pub fn verify(&self, message: Word, signature: &Signature) -> bool { @@ -104,12 +112,17 @@ pub struct Signature { } impl Signature { + pub fn inner(&self) -> Proof { + self.proof.clone() + } /// Returns true if this signature is a valid signature for the specified message generated /// against the secret key matching the specified public key commitment. pub fn verify(&self, message: Word, pk: Word) -> bool { let signature: RpoSignatureScheme = RpoSignatureScheme::new(PROOF_OPTIONS); - signature.verify(pk, message, self.proof.clone()).is_ok() + let res = signature.verify(pk, message, self.proof.clone()); + println!("res is {:?}", res); + res.is_ok() } } diff --git a/src/dsa/rpo_stark/stark/air.rs b/src/dsa/rpo_stark/stark/air.rs index 64dea565e..6dd5b7ef8 100644 --- a/src/dsa/rpo_stark/stark/air.rs +++ b/src/dsa/rpo_stark/stark/air.rs @@ -105,6 +105,12 @@ pub struct PublicInputs { pub(crate) msg: Word, } +impl PublicInputs { + pub fn new(pub_key: Word, msg: Word) -> Self { + Self { pub_key, msg } + } +} + impl ToElements for PublicInputs { fn to_elements(&self) -> Vec { let mut res = self.pub_key.to_vec(); diff --git a/src/dsa/rpo_stark/stark/mod.rs b/src/dsa/rpo_stark/stark/mod.rs index 67b36bb0c..32cb25000 100644 --- a/src/dsa/rpo_stark/stark/mod.rs +++ b/src/dsa/rpo_stark/stark/mod.rs @@ -1,16 +1,17 @@ use core::marker::PhantomData; -use air::{PublicInputs, RescueAir}; use prover::RpoSignatureProver; -use winter_crypto::{DefaultRandomCoin, ElementHasher, MerkleTree}; +use rand::{distributions::Standard, prelude::Distribution}; +use winter_crypto::{DefaultRandomCoin, ElementHasher, Hasher, MerkleTree, SaltedMerkleTree}; use winter_math::{fields::f64::BaseElement, FieldElement}; use winter_prover::{Proof, ProofOptions}; use winter_verifier::{verify, AcceptableOptions, VerifierError}; use winterfell::Prover; -use crate::hash::rpo::{Rpo256, DIGEST_RANGE, DIGEST_SIZE, NUM_ROUNDS, STATE_WIDTH}; +use crate::{hash::rpo::{Rpo256, DIGEST_RANGE, DIGEST_SIZE, NUM_ROUNDS, STATE_WIDTH}, rand::RpoRandomCoin}; mod air; +pub use air::{PublicInputs, RescueAir}; mod prover; /// Represents an abstract STARK-based signature scheme with knowledge of RPO pre-image as @@ -20,7 +21,10 @@ pub struct RpoSignatureScheme { _h: PhantomData, } -impl + Sync> RpoSignatureScheme { +impl + Sync> RpoSignatureScheme +where + Standard: Distribution<::Digest>, +{ pub fn new(options: ProofOptions) -> Self { RpoSignatureScheme { options, _h: PhantomData } } @@ -44,7 +48,7 @@ impl + Sync> RpoSignatureScheme { ) -> Result<(), VerifierError> { let pub_inputs = PublicInputs { pub_key, msg }; let acceptable_options = AcceptableOptions::OptionSet(vec![proof.options().clone()]); - verify::, MerkleTree>( + verify::>( proof, pub_inputs, &acceptable_options, diff --git a/src/dsa/rpo_stark/stark/prover.rs b/src/dsa/rpo_stark/stark/prover.rs index e4148f0e3..ac5dab82c 100644 --- a/src/dsa/rpo_stark/stark/prover.rs +++ b/src/dsa/rpo_stark/stark/prover.rs @@ -1,6 +1,9 @@ use core::marker::PhantomData; -use winter_crypto::{DefaultRandomCoin, ElementHasher, MerkleTree}; +use rand::SeedableRng; +use rand_chacha::ChaCha20Rng; +use winter_air::ZkParameters; +use winter_crypto::{DefaultRandomCoin, ElementHasher, MerkleTree, SaltedMerkleTree}; use winter_math::{fields::f64::BaseElement, FieldElement}; use winter_prover::{ matrix::ColMatrix, DefaultConstraintEvaluator, DefaultTraceLde, ProofOptions, Prover, @@ -10,7 +13,7 @@ use winter_utils::{Deserializable, Serializable}; use winterfell::{AuxRandElements, ConstraintCompositionCoefficients, PartitionOptions}; use super::air::{PublicInputs, RescueAir, HASH_CYCLE_LEN}; -use crate::{hash::rpo::Rpo256, Word, ZERO}; +use crate::{hash::rpo::Rpo256, rand::RpoRandomCoin, Word, ZERO}; // PROVER // ================================================================================================ @@ -68,9 +71,9 @@ where type BaseField = BaseElement; type Air = RescueAir; type Trace = TraceTable; - type HashFn = H; - type VC = MerkleTree; - type RandomCoin = DefaultRandomCoin; + type HashFn = Rpo256; + type VC = SaltedMerkleTree; + type RandomCoin = RpoRandomCoin; type TraceLde> = DefaultTraceLde; type ConstraintEvaluator<'a, E: FieldElement> = @@ -101,8 +104,17 @@ where main_trace: &ColMatrix, domain: &StarkDomain, partition_option: PartitionOptions, + zk_parameters: Option, ) -> (Self::TraceLde, TracePolyTable) { - DefaultTraceLde::new(trace_info, main_trace, domain, partition_option) + let mut prng = ChaCha20Rng::from_entropy(); + DefaultTraceLde::new( + trace_info, + main_trace, + domain, + partition_option, + zk_parameters, + &mut prng, + ) } fn new_evaluator<'a, E: FieldElement>( diff --git a/src/hash/blake/mod.rs b/src/hash/blake/mod.rs index 88ffe0897..618bff968 100644 --- a/src/hash/blake/mod.rs +++ b/src/hash/blake/mod.rs @@ -99,6 +99,14 @@ impl Digest for Blake3Digest { assert!(N <= 32, "digest currently supports only 32 bytes!"); expand_bytes(&self.0) } + + fn from_random_bytes(buffer: &[u8]) -> Self { + Self( + buffer + .try_into() + .expect("The size of the buffer with random bytes should be 32"), + ) + } } // BLAKE3 256-BIT OUTPUT diff --git a/src/hash/rescue/rpo/digest.rs b/src/hash/rescue/rpo/digest.rs index 67d73e315..cc23baa52 100644 --- a/src/hash/rescue/rpo/digest.rs +++ b/src/hash/rescue/rpo/digest.rs @@ -1,4 +1,5 @@ use alloc::string::String; +use rand::{distributions::Standard, prelude::Distribution}; use core::{cmp::Ordering, fmt::Display, ops::Deref, slice}; use super::{Digest, Felt, StarkField, DIGEST_BYTES, DIGEST_SIZE, ZERO}; @@ -64,6 +65,18 @@ impl Digest for RpoDigest { result } + + fn from_random_bytes(buffer: &[u8]) -> Self { + let mut digest: [Felt; DIGEST_SIZE] = [ZERO; DIGEST_SIZE]; + + buffer.chunks(8).zip(digest.iter_mut()).for_each(|(chunk, digest)| { + *digest = Felt::new(u64::from_be_bytes( + chunk.try_into().expect("Given the size of the chunk this should not panic"), + )) + }); + + digest.into() + } } impl Deref for RpoDigest { @@ -124,6 +137,18 @@ impl Randomizable for RpoDigest { } } +impl Distribution for Standard { + fn sample(&self, rng: &mut R) -> RpoDigest { + let mut res = [ZERO; DIGEST_SIZE]; + for r in res.iter_mut() { + let mut source = [0_u8; 8]; + rng.fill_bytes(&mut source); + *r = Felt::from_random_bytes(&source).expect("failed to generate element"); + } + RpoDigest::new(res) + } +} + // CONVERSIONS: FROM RPO DIGEST // ================================================================================================ diff --git a/src/hash/rescue/rpx/digest.rs b/src/hash/rescue/rpx/digest.rs index 8f953fc68..b3e76a702 100644 --- a/src/hash/rescue/rpx/digest.rs +++ b/src/hash/rescue/rpx/digest.rs @@ -64,6 +64,18 @@ impl Digest for RpxDigest { result } + + fn from_random_bytes(buffer: &[u8]) -> Self { + let mut digest: [Felt; DIGEST_SIZE] = [ZERO; DIGEST_SIZE]; + + buffer.chunks(8).zip(digest.iter_mut()).for_each(|(chunk, digest)| { + *digest = Felt::new(u64::from_be_bytes( + chunk.try_into().expect("Given the size of the chunk this should not panic"), + )) + }); + + digest.into() + } } impl Deref for RpxDigest { diff --git a/src/rand/rpo.rs b/src/rand/rpo.rs index a6add3935..bb1b0ed5c 100644 --- a/src/rand/rpo.rs +++ b/src/rand/rpo.rs @@ -1,3 +1,5 @@ +use std::println; + use alloc::{string::ToString, vec::Vec}; use rand_core::impls; @@ -146,7 +148,8 @@ impl RandomCoin for RpoRandomCoin { Rpo256::apply_permutation(&mut self.state); // reset the buffer - self.current = RATE_START; + self.current = RATE_START + 1; + println!("here"); // determine how many bits are needed to represent valid values in the domain let v_mask = (domain_size - 1) as u64; @@ -170,8 +173,39 @@ impl RandomCoin for RpoRandomCoin { return Err(RandomCoinError::FailedToDrawIntegers(num_values, values.len(), 1000)); } + println!("rand_integers {:?}", values); Ok(values) } + + fn reseed_with_salt( + &mut self, + data: ::Digest, + salt: Option<::Digest>, + ) { + // Reset buffer + self.current = RATE_START; + + // Add the new seed material to the first half of the rate portion of the RPO state + let data: Word = data.into(); + + self.state[RATE_START] += data[0]; + self.state[RATE_START + 1] += data[1]; + self.state[RATE_START + 2] += data[2]; + self.state[RATE_START + 3] += data[3]; + + if let Some(salt) = salt { + // Add the salt to the second half of the rate portion of the RPO state + let data: Word = salt.into(); + + self.state[RATE_START + 4] += data[0]; + self.state[RATE_START + 5] += data[1]; + self.state[RATE_START + 6] += data[2]; + self.state[RATE_START + 7] += data[3]; + } + + // Absorb + Rpo256::apply_permutation(&mut self.state); + } } // FELT RNG IMPLEMENTATION diff --git a/src/rand/rpx.rs b/src/rand/rpx.rs index 2f91b0cab..fb13600e2 100644 --- a/src/rand/rpx.rs +++ b/src/rand/rpx.rs @@ -172,6 +172,14 @@ impl RandomCoin for RpxRandomCoin { Ok(values) } + + fn reseed_with_salt( + &mut self, + data: ::Digest, + salt: Option<::Digest>, + ) { + todo!() + } } // FELT RNG IMPLEMENTATION From eaa1db66fbef27a2fea35586a425dc29fe421108 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Mon, 2 Dec 2024 15:40:22 +0100 Subject: [PATCH 05/20] fix: updated after Winterfell updates --- Cargo.lock | 27 +++++++++++----------- Cargo.toml | 36 ++++++++++++------------------ src/dsa/rpo_stark/mod.rs | 1 - src/dsa/rpo_stark/signature/mod.rs | 17 ++++---------- src/dsa/rpo_stark/stark/mod.rs | 19 +++++++++++----- src/dsa/rpo_stark/stark/prover.rs | 17 +++++--------- src/hash/rescue/rpo/digest.rs | 3 ++- src/rand/rpo.rs | 4 ---- src/rand/rpx.rs | 26 +++++++++++++++++++-- 9 files changed, 77 insertions(+), 73 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2b7b58429..f312c4e92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -493,15 +493,6 @@ version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" -[[package]] -name = "libc-print" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a660208db49e35faf57b37484350f1a61072f2a5becf0592af6015d9ddd4b0" -dependencies = [ - "libc", -] - [[package]] name = "libm" version = "0.2.11" @@ -548,7 +539,9 @@ dependencies = [ "sha3", "winter-air", "winter-crypto", + "winter-fri", "winter-math", + "winter-maybe-async", "winter-prover", "winter-rand-utils", "winter-utils", @@ -1193,6 +1186,7 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winter-air" version = "0.10.0" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" dependencies = [ "libm", "winter-crypto", @@ -1204,9 +1198,11 @@ dependencies = [ [[package]] name = "winter-crypto" version = "0.10.0" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" dependencies = [ "blake3", "rand", + "rand_chacha", "sha3", "winter-math", "winter-utils", @@ -1215,6 +1211,7 @@ dependencies = [ [[package]] name = "winter-fri" version = "0.10.0" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" dependencies = [ "rand", "rand_chacha", @@ -1226,6 +1223,7 @@ dependencies = [ [[package]] name = "winter-math" version = "0.10.0" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" dependencies = [ "serde", "winter-utils", @@ -1234,6 +1232,7 @@ dependencies = [ [[package]] name = "winter-maybe-async" version = "0.10.1" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" dependencies = [ "quote", "syn", @@ -1242,8 +1241,8 @@ dependencies = [ [[package]] name = "winter-prover" version = "0.10.0" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" dependencies = [ - "libc-print", "rand", "rand_chacha", "tracing", @@ -1259,6 +1258,7 @@ dependencies = [ [[package]] name = "winter-rand-utils" version = "0.10.0" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" dependencies = [ "rand", "winter-utils", @@ -1267,10 +1267,12 @@ dependencies = [ [[package]] name = "winter-utils" version = "0.10.0" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" [[package]] name = "winter-verifier" version = "0.10.0" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" dependencies = [ "winter-air", "winter-crypto", @@ -1281,9 +1283,8 @@ dependencies = [ [[package]] name = "winterfell" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c8336dc6a035698780b8cc624f875e479bd6bf6e1846670f3ef4485c125882" +version = "0.10.0" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" dependencies = [ "winter-air", "winter-prover", diff --git a/Cargo.toml b/Cargo.toml index de5b5dc1a..9f8cf47cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,16 +52,20 @@ num = { version = "0.4", default-features = false, features = ["alloc", "libm"] num-complex = { version = "0.4", default-features = false } rand = { version = "0.8", default-features = false } rand_core = { version = "0.6", default-features = false } -rand-utils = { version = "0.10", package = "winter-rand-utils", optional = true } +#rand-utils = { version = "0.10", package = "winter-rand-utils", optional = true } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } sha3 = { version = "0.10", default-features = false } -winter-air = { version = "0.10", default-features = false } -winter-crypto = { version = "0.10", default-features = false } -winter-math = { version = "0.10", default-features = false } -winter-prover = { version = "0.10", default-features = false } -winter-utils = { version = "0.10", default-features = false } -winter-verifier = { version = "0.10", default-features = false } -winterfell = { version = "0.10", default-features = false } +winter-air = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } +winter-crypto = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } +winter-prover = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } +winter-verifier = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } +winter-math = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } +winter-fri = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } +winter-maybe-async = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } +winter-utils = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk', optional = true } +#winter-rand-utils = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk', optional = true } +rand-utils = {git = 'https://github.com/Al-Kindi-0/winterfell', package = "winter-rand-utils" , branch = 'al-zk', optional = true } +winterfell = {git = 'https://github.com/Al-Kindi-0/winterfell/', branch = 'al-zk' } rand_chacha = { version = "0.3", default-features = false } [dev-dependencies] @@ -70,22 +74,10 @@ getrandom = { version = "0.2", features = ["js"] } hex = { version = "0.4", default-features = false, features = ["alloc"] } proptest = "1.5" rand_chacha = { version = "0.3", default-features = false } -rand-utils = { version = "0.10", package = "winter-rand-utils" } +#rand-utils = { version = "0.10", package = "winter-rand-utils" } +rand-utils = {git = 'https://github.com/Al-Kindi-0/winterfell', package = "winter-rand-utils" , branch = 'al-zk' } seq-macro = { version = "0.3" } [build-dependencies] cc = { version = "1.1", optional = true, features = ["parallel"] } glob = "0.3" - - -[patch.crates-io] -winter-air = {path = "../../training/test_task/winterfell/air" } -winter-crypto = {path = "../../training/test_task/winterfell/crypto" } -winter-prover = {path = "../../training/test_task/winterfell/prover" } -winter-verifier = {path = "../../training/test_task/winterfell/verifier" } -winter-math = {path = "../../training/test_task/winterfell/math" } -winter-fri = {path = "../../training/test_task/winterfell/fri" } -winter-maybe-async = {path = "../../training/test_task/winterfell/utils/maybe_async" } -winter-utils = {path = "../../training/test_task/winterfell/utils/core" } -winter-rand-utils = {path = "../../training/test_task/winterfell/utils/rand" } - diff --git a/src/dsa/rpo_stark/mod.rs b/src/dsa/rpo_stark/mod.rs index b8bb52dff..5600263f7 100644 --- a/src/dsa/rpo_stark/mod.rs +++ b/src/dsa/rpo_stark/mod.rs @@ -26,7 +26,6 @@ mod tests { let message = rand_array(); let signature = sk.sign(message); - //println!("signature {:?}", signature); let pk = sk.compute_public_key(); println!("verify {:?}", pk.verify(message, &signature)); assert!(pk.verify(message, &signature)) diff --git a/src/dsa/rpo_stark/signature/mod.rs b/src/dsa/rpo_stark/signature/mod.rs index 515c334e3..3ebfdba20 100644 --- a/src/dsa/rpo_stark/signature/mod.rs +++ b/src/dsa/rpo_stark/signature/mod.rs @@ -1,5 +1,3 @@ -use std::println; - use rand::Rng; use winter_math::fields::f64::BaseElement; use winter_prover::Proof; @@ -15,14 +13,8 @@ use crate::{dsa::rpo_stark::stark::RpoSignatureScheme, hash::rpo::Rpo256, Word, // ================================================================================================ /// Specifies the parameters of the STARK underlying the signature scheme. -/// -/// TODO: The number of queries needs to be updated so that it matches the one given in -/// the specification. The reason for choosing such a low number for the number of FRI queries is -/// due to the fact that the number of FRI queries should be smaller than the size of the LDE -/// domain. Since the PR enabling zero-knowledge in Winterfell is yet to be merged, this not -/// case. pub const PROOF_OPTIONS: ProofOptions = - ProofOptions::new(3, 8, 0, FieldExtension::Quadratic, 4, 31, true); + ProofOptions::new(30, 8, 12, FieldExtension::Quadratic, 4, 7, true); // PUBLIC KEY // ================================================================================================ @@ -42,7 +34,7 @@ impl PublicKey { impl PublicKey { /// Verifies the provided signature against provided message and this public key. pub fn verify(&self, message: Word, signature: &Signature) -> bool { - signature.verify(message, self.0) + signature.verify(message, *self) } } @@ -117,11 +109,10 @@ impl Signature { } /// Returns true if this signature is a valid signature for the specified message generated /// against the secret key matching the specified public key commitment. - pub fn verify(&self, message: Word, pk: Word) -> bool { + pub fn verify(&self, message: Word, pk: PublicKey) -> bool { let signature: RpoSignatureScheme = RpoSignatureScheme::new(PROOF_OPTIONS); - let res = signature.verify(pk, message, self.proof.clone()); - println!("res is {:?}", res); + let res = signature.verify(pk.inner(), message, self.proof.clone()); res.is_ok() } } diff --git a/src/dsa/rpo_stark/stark/mod.rs b/src/dsa/rpo_stark/stark/mod.rs index 32cb25000..c09e8a0cc 100644 --- a/src/dsa/rpo_stark/stark/mod.rs +++ b/src/dsa/rpo_stark/stark/mod.rs @@ -1,14 +1,18 @@ use core::marker::PhantomData; use prover::RpoSignatureProver; -use rand::{distributions::Standard, prelude::Distribution}; -use winter_crypto::{DefaultRandomCoin, ElementHasher, Hasher, MerkleTree, SaltedMerkleTree}; +use rand::{distributions::Standard, prelude::Distribution, thread_rng, RngCore, SeedableRng}; +use rand_chacha::ChaCha20Rng; +use winter_crypto::{ElementHasher, Hasher, SaltedMerkleTree}; use winter_math::{fields::f64::BaseElement, FieldElement}; use winter_prover::{Proof, ProofOptions}; use winter_verifier::{verify, AcceptableOptions, VerifierError}; use winterfell::Prover; -use crate::{hash::rpo::{Rpo256, DIGEST_RANGE, DIGEST_SIZE, NUM_ROUNDS, STATE_WIDTH}, rand::RpoRandomCoin}; +use crate::{ + hash::rpo::{Rpo256, DIGEST_RANGE, DIGEST_SIZE, NUM_ROUNDS, STATE_WIDTH}, + rand::RpoRandomCoin, +}; mod air; pub use air::{PublicInputs, RescueAir}; @@ -36,8 +40,13 @@ where // generate execution trace let trace = prover.build_trace(sk, msg); + // generate the initial seed for the PRNG used for zero-knowledge + let mut seed = ::Seed::default(); + let mut rng = thread_rng(); + rng.fill_bytes(&mut seed); + // generate the proof - prover.prove(trace).expect("failed to generate the signature") + prover.prove(trace, Some(seed)).expect("failed to generate the signature") } pub fn verify( @@ -48,7 +57,7 @@ where ) -> Result<(), VerifierError> { let pub_inputs = PublicInputs { pub_key, msg }; let acceptable_options = AcceptableOptions::OptionSet(vec![proof.options().clone()]); - verify::>( + verify::>( proof, pub_inputs, &acceptable_options, diff --git a/src/dsa/rpo_stark/stark/prover.rs b/src/dsa/rpo_stark/stark/prover.rs index ac5dab82c..f3659fa09 100644 --- a/src/dsa/rpo_stark/stark/prover.rs +++ b/src/dsa/rpo_stark/stark/prover.rs @@ -1,9 +1,8 @@ use core::marker::PhantomData; -use rand::SeedableRng; use rand_chacha::ChaCha20Rng; use winter_air::ZkParameters; -use winter_crypto::{DefaultRandomCoin, ElementHasher, MerkleTree, SaltedMerkleTree}; +use winter_crypto::{ElementHasher, SaltedMerkleTree}; use winter_math::{fields::f64::BaseElement, FieldElement}; use winter_prover::{ matrix::ColMatrix, DefaultConstraintEvaluator, DefaultTraceLde, ProofOptions, Prover, @@ -72,12 +71,13 @@ where type Air = RescueAir; type Trace = TraceTable; type HashFn = Rpo256; - type VC = SaltedMerkleTree; + type VC = SaltedMerkleTree; type RandomCoin = RpoRandomCoin; type TraceLde> = DefaultTraceLde; type ConstraintEvaluator<'a, E: FieldElement> = DefaultConstraintEvaluator<'a, Self::Air, E>; + type ZkPrng = ChaCha20Rng; fn get_pub_inputs(&self, trace: &Self::Trace) -> PublicInputs { let last_step = trace.length() - 1; @@ -105,16 +105,9 @@ where domain: &StarkDomain, partition_option: PartitionOptions, zk_parameters: Option, + prng: &mut Option, ) -> (Self::TraceLde, TracePolyTable) { - let mut prng = ChaCha20Rng::from_entropy(); - DefaultTraceLde::new( - trace_info, - main_trace, - domain, - partition_option, - zk_parameters, - &mut prng, - ) + DefaultTraceLde::new(trace_info, main_trace, domain, partition_option, zk_parameters, prng) } fn new_evaluator<'a, E: FieldElement>( diff --git a/src/hash/rescue/rpo/digest.rs b/src/hash/rescue/rpo/digest.rs index cc23baa52..21aa507e7 100644 --- a/src/hash/rescue/rpo/digest.rs +++ b/src/hash/rescue/rpo/digest.rs @@ -1,7 +1,8 @@ use alloc::string::String; -use rand::{distributions::Standard, prelude::Distribution}; use core::{cmp::Ordering, fmt::Display, ops::Deref, slice}; +use rand::{distributions::Standard, prelude::Distribution}; + use super::{Digest, Felt, StarkField, DIGEST_BYTES, DIGEST_SIZE, ZERO}; use crate::{ rand::Randomizable, diff --git a/src/rand/rpo.rs b/src/rand/rpo.rs index bb1b0ed5c..fe9ceb6ac 100644 --- a/src/rand/rpo.rs +++ b/src/rand/rpo.rs @@ -1,5 +1,3 @@ -use std::println; - use alloc::{string::ToString, vec::Vec}; use rand_core::impls; @@ -149,7 +147,6 @@ impl RandomCoin for RpoRandomCoin { // reset the buffer self.current = RATE_START + 1; - println!("here"); // determine how many bits are needed to represent valid values in the domain let v_mask = (domain_size - 1) as u64; @@ -173,7 +170,6 @@ impl RandomCoin for RpoRandomCoin { return Err(RandomCoinError::FailedToDrawIntegers(num_values, values.len(), 1000)); } - println!("rand_integers {:?}", values); Ok(values) } diff --git a/src/rand/rpx.rs b/src/rand/rpx.rs index fb13600e2..e2693a032 100644 --- a/src/rand/rpx.rs +++ b/src/rand/rpx.rs @@ -172,13 +172,35 @@ impl RandomCoin for RpxRandomCoin { Ok(values) } - + fn reseed_with_salt( &mut self, data: ::Digest, salt: Option<::Digest>, ) { - todo!() + // Reset buffer + self.current = RATE_START; + + // Add the new seed material to the first half of the rate portion of the RPO state + let data: Word = data.into(); + + self.state[RATE_START] += data[0]; + self.state[RATE_START + 1] += data[1]; + self.state[RATE_START + 2] += data[2]; + self.state[RATE_START + 3] += data[3]; + + if let Some(salt) = salt { + // Add the salt to the second half of the rate portion of the RPO state + let data: Word = salt.into(); + + self.state[RATE_START + 4] += data[0]; + self.state[RATE_START + 5] += data[1]; + self.state[RATE_START + 6] += data[2]; + self.state[RATE_START + 7] += data[3]; + } + + // Absorb + Rpx256::apply_permutation(&mut self.state); } } From 866fda603af0ccdd8534df7d297ca9099bcc660c Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Tue, 3 Dec 2024 06:30:25 +0100 Subject: [PATCH 06/20] chore: update prover --- Cargo.lock | 127 +++++++++++++++--------------- src/dsa/rpo_stark/stark/prover.rs | 26 +++++- 2 files changed, 89 insertions(+), 64 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f312c4e92..3a9a08ff3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,9 +107,9 @@ checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "blake3" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" dependencies = [ "arrayref", "arrayvec", @@ -147,9 +147,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" +checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" dependencies = [ "jobserver", "libc", @@ -243,9 +243,9 @@ checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "cpufeatures" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -345,12 +345,12 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -450,9 +450,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jobserver" @@ -465,10 +465,11 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -489,9 +490,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.162" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] name = "libm" @@ -680,9 +681,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -812,9 +813,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustix" -version = "0.38.40" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ "bitflags", "errno", @@ -878,9 +879,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", @@ -912,9 +913,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.87" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -946,9 +947,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -957,9 +958,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", @@ -968,9 +969,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" [[package]] name = "typenum" @@ -986,9 +987,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "utf8parse" @@ -1029,9 +1030,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" dependencies = [ "cfg-if", "once_cell", @@ -1040,9 +1041,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" dependencies = [ "bumpalo", "log", @@ -1055,9 +1056,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1065,9 +1066,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" dependencies = [ "proc-macro2", "quote", @@ -1078,15 +1079,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "a98bc3c33f0fe7e59ad7cd041b89034fa82a7c2d4365ca538dda6cdaf513863c" dependencies = [ "js-sys", "wasm-bindgen", @@ -1185,8 +1186,8 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winter-air" -version = "0.10.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" +version = "0.11.0" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" dependencies = [ "libm", "winter-crypto", @@ -1197,8 +1198,8 @@ dependencies = [ [[package]] name = "winter-crypto" -version = "0.10.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" +version = "0.11.0" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" dependencies = [ "blake3", "rand", @@ -1210,8 +1211,8 @@ dependencies = [ [[package]] name = "winter-fri" -version = "0.10.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" +version = "0.11.0" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" dependencies = [ "rand", "rand_chacha", @@ -1222,8 +1223,8 @@ dependencies = [ [[package]] name = "winter-math" -version = "0.10.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" +version = "0.11.0" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" dependencies = [ "serde", "winter-utils", @@ -1231,8 +1232,8 @@ dependencies = [ [[package]] name = "winter-maybe-async" -version = "0.10.1" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" +version = "0.11.0" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" dependencies = [ "quote", "syn", @@ -1240,8 +1241,8 @@ dependencies = [ [[package]] name = "winter-prover" -version = "0.10.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" +version = "0.11.0" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" dependencies = [ "rand", "rand_chacha", @@ -1257,8 +1258,8 @@ dependencies = [ [[package]] name = "winter-rand-utils" -version = "0.10.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" +version = "0.11.0" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" dependencies = [ "rand", "winter-utils", @@ -1266,13 +1267,13 @@ dependencies = [ [[package]] name = "winter-utils" -version = "0.10.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" +version = "0.11.0" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" [[package]] name = "winter-verifier" -version = "0.10.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" +version = "0.11.0" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" dependencies = [ "winter-air", "winter-crypto", @@ -1283,8 +1284,8 @@ dependencies = [ [[package]] name = "winterfell" -version = "0.10.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#c6542eb717e73baaeda156dafe0ab187089a995f" +version = "0.11.0" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" dependencies = [ "winter-air", "winter-prover", diff --git a/src/dsa/rpo_stark/stark/prover.rs b/src/dsa/rpo_stark/stark/prover.rs index f3659fa09..66ce031a6 100644 --- a/src/dsa/rpo_stark/stark/prover.rs +++ b/src/dsa/rpo_stark/stark/prover.rs @@ -9,7 +9,10 @@ use winter_prover::{ StarkDomain, Trace, TraceInfo, TracePolyTable, TraceTable, }; use winter_utils::{Deserializable, Serializable}; -use winterfell::{AuxRandElements, ConstraintCompositionCoefficients, PartitionOptions}; +use winterfell::{ + AuxRandElements, CompositionPoly, CompositionPolyTrace, ConstraintCompositionCoefficients, + DefaultConstraintCommitment, PartitionOptions, +}; use super::air::{PublicInputs, RescueAir, HASH_CYCLE_LEN}; use crate::{hash::rpo::Rpo256, rand::RpoRandomCoin, Word, ZERO}; @@ -75,6 +78,8 @@ where type RandomCoin = RpoRandomCoin; type TraceLde> = DefaultTraceLde; + type ConstraintCommitment> = + DefaultConstraintCommitment; type ConstraintEvaluator<'a, E: FieldElement> = DefaultConstraintEvaluator<'a, Self::Air, E>; type ZkPrng = ChaCha20Rng; @@ -118,4 +123,23 @@ where ) -> Self::ConstraintEvaluator<'a, E> { DefaultConstraintEvaluator::new(air, aux_rand_elements, composition_coefficients) } + + fn build_constraint_commitment>( + &self, + composition_poly_trace: CompositionPolyTrace, + num_constraint_composition_columns: usize, + domain: &StarkDomain, + partition_options: PartitionOptions, + zk_parameters: Option, + prng: &mut Option, + ) -> (Self::ConstraintCommitment, CompositionPoly) { + DefaultConstraintCommitment::new( + composition_poly_trace, + num_constraint_composition_columns, + domain, + partition_options, + zk_parameters, + prng, + ) + } } From c41b45f3bda4b31b836a86865861e0b1ad8f31ed Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Tue, 3 Dec 2024 12:08:50 +0100 Subject: [PATCH 07/20] chore: rebased on main --- Cargo.lock | 1 + Cargo.toml | 1 + src/hash/rescue/rpo/digest.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 9f993f243..9d4b79de2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -545,6 +545,7 @@ dependencies = [ "seq-macro", "serde", "sha3", + "thiserror", "winter-air", "winter-crypto", "winter-fri", diff --git a/Cargo.toml b/Cargo.toml index 2429dfef2..76aa42c33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,7 @@ rand_core = { version = "0.6", default-features = false } #rand-utils = { version = "0.10", package = "winter-rand-utils", optional = true } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } sha3 = { version = "0.10", default-features = false } +thiserror = { version = "2.0", default-features = false } winter-air = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } winter-crypto = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } winter-prover = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } diff --git a/src/hash/rescue/rpo/digest.rs b/src/hash/rescue/rpo/digest.rs index 25c8485c3..1e3f1d5cc 100644 --- a/src/hash/rescue/rpo/digest.rs +++ b/src/hash/rescue/rpo/digest.rs @@ -2,6 +2,7 @@ use alloc::string::String; use core::{cmp::Ordering, fmt::Display, ops::Deref, slice}; use rand::{distributions::Standard, prelude::Distribution}; +use thiserror::Error; use super::{Digest, Felt, StarkField, DIGEST_BYTES, DIGEST_SIZE, ZERO}; use crate::{ From e67dc6f042af2a9f1dca2564c07cf06deeb6a56f Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Wed, 4 Dec 2024 08:54:25 +0100 Subject: [PATCH 08/20] feat: add constructor for sk from Word --- src/dsa/rpo_stark/signature/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/dsa/rpo_stark/signature/mod.rs b/src/dsa/rpo_stark/signature/mod.rs index 3ebfdba20..40972f0df 100644 --- a/src/dsa/rpo_stark/signature/mod.rs +++ b/src/dsa/rpo_stark/signature/mod.rs @@ -58,6 +58,11 @@ impl SecretKey { Self::with_rng(&mut rng) } + /// Generates a secret key from a [Word]. + pub fn from_word(sk: Word) -> Self { + Self(sk) + } + /// Generates a secret_key using the provided random number generator `Rng`. pub fn with_rng(rng: &mut R) -> Self { let mut sk = [ZERO; 4]; From 90447924a30baafec0f0eb511c0c9a39d1ebc74f Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:55:21 +0100 Subject: [PATCH 09/20] chore: address feedback --- src/dsa/rpo_stark/mod.rs | 2 +- src/dsa/rpo_stark/signature/mod.rs | 117 +++++++++++++++-------------- src/dsa/rpo_stark/stark/air.rs | 38 ++-------- src/dsa/rpo_stark/stark/mod.rs | 18 +---- src/dsa/rpo_stark/stark/prover.rs | 15 ++-- src/hash/mod.rs | 6 +- src/hash/rescue/mod.rs | 18 ++--- src/hash/rescue/rpo/digest.rs | 15 ++-- src/hash/rescue/rpx/digest.rs | 4 +- 9 files changed, 100 insertions(+), 133 deletions(-) diff --git a/src/dsa/rpo_stark/mod.rs b/src/dsa/rpo_stark/mod.rs index 5600263f7..a7c1f4707 100644 --- a/src/dsa/rpo_stark/mod.rs +++ b/src/dsa/rpo_stark/mod.rs @@ -26,7 +26,7 @@ mod tests { let message = rand_array(); let signature = sk.sign(message); - let pk = sk.compute_public_key(); + let pk = sk.public_key(); println!("verify {:?}", pk.verify(message, &signature)); assert!(pk.verify(message, &signature)) } diff --git a/src/dsa/rpo_stark/signature/mod.rs b/src/dsa/rpo_stark/signature/mod.rs index 40972f0df..a8b0bc876 100644 --- a/src/dsa/rpo_stark/signature/mod.rs +++ b/src/dsa/rpo_stark/signature/mod.rs @@ -1,18 +1,23 @@ -use rand::Rng; -use winter_math::fields::f64::BaseElement; +use rand::{distributions::Uniform, prelude::Distribution, Rng}; +use winter_math::{fields::f64::BaseElement, FieldElement, StarkField}; use winter_prover::Proof; -use winter_utils::{ - ByteReader, ByteWriter, Deserializable, DeserializationError, Randomizable, Serializable, -}; +use winter_utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}; use winterfell::{FieldExtension, ProofOptions}; -use super::stark::compute_rpo_image; -use crate::{dsa::rpo_stark::stark::RpoSignatureScheme, hash::rpo::Rpo256, Word, ZERO}; +use crate::{ + dsa::rpo_stark::stark::RpoSignatureScheme, + hash::{rpo::Rpo256, DIGEST_SIZE}, + Word, ZERO, +}; // CONSTANTS // ================================================================================================ -/// Specifies the parameters of the STARK underlying the signature scheme. +/// Specifies the parameters of the STARK underlying the signature scheme. These parameters provide +/// at least 102 bits of security under the conjectured security of the toy protocol in +/// the ethSTARK paper [1]. +/// +/// [1]: https://eprint.iacr.org/2021/582 pub const PROOF_OPTIONS: ProofOptions = ProofOptions::new(30, 8, 12, FieldExtension::Quadratic, 4, 7, true); @@ -38,6 +43,19 @@ impl PublicKey { } } +impl Serializable for PublicKey { + fn write_into(&self, target: &mut W) { + self.0.write_into(target); + } +} + +impl Deserializable for PublicKey { + fn read_from(source: &mut R) -> Result { + let pk = ::read_from(source)?; + Ok(Self(pk)) + } +} + // SECRET KEY // ================================================================================================ @@ -49,37 +67,39 @@ pub struct SecretKey(Word); impl SecretKey { /// Generates a secret key from OS-provided randomness. + pub fn new(word: Word) -> Self { + Self(word) + } + + /// Generates a secret key from a [Word]. #[cfg(feature = "std")] - #[allow(clippy::new_without_default)] - pub fn new() -> Self { + pub fn random() -> Self { use rand::{rngs::StdRng, SeedableRng}; let mut rng = StdRng::from_entropy(); Self::with_rng(&mut rng) } - /// Generates a secret key from a [Word]. - pub fn from_word(sk: Word) -> Self { - Self(sk) - } - /// Generates a secret_key using the provided random number generator `Rng`. + #[cfg(feature = "std")] pub fn with_rng(rng: &mut R) -> Self { let mut sk = [ZERO; 4]; + let uni_dist = Uniform::from(0..BaseElement::MODULUS); - let mut dest = vec![0_u8; 8]; for s in sk.iter_mut() { - rng.fill_bytes(&mut dest); - *s = BaseElement::from_random_bytes(&dest).expect(""); + let sampled_integer = uni_dist.sample(rng); + *s = BaseElement::new(sampled_integer); } Self(sk) } /// Computes the public key corresponding to this secret key. - pub fn compute_public_key(&self) -> PublicKey { - let pk = compute_rpo_image(self.0); - PublicKey(pk) + pub fn public_key(&self) -> PublicKey { + let mut elements = [BaseElement::ZERO; 8]; + elements[..DIGEST_SIZE].copy_from_slice(&self.0); + let pk = Rpo256::hash_elements(&elements); + PublicKey(pk.into()) } /// Signs a message with this secret key. @@ -90,6 +110,19 @@ impl SecretKey { } } +impl Serializable for SecretKey { + fn write_into(&self, target: &mut W) { + self.0.write_into(target); + } +} + +impl Deserializable for SecretKey { + fn read_from(source: &mut R) -> Result { + let sk = ::read_from(source)?; + Ok(Self(sk)) + } +} + // SIGNATURE // ================================================================================================ @@ -97,12 +130,14 @@ impl SecretKey { /// /// The signature is a STARK proof of knowledge of a pre-image given an image where the map is /// the RPO permutation, the pre-image is the secret key and the image is the public key. -/// The current implementation follows the description in [1] in the unique decoding regime where -/// it is argued that for the parameter set `PROOF_OPTIONS` the signature achieves $113$ bits of -/// average-case existential unforgeability security against $2^{113}$-query bound adversaries -/// that can obtain up to $2^{64}$ signatures under the same public key. +/// The current implementation follows the description in [1] but relies on the conjectured security +/// of the toy protocol in the ethSTARK paper [2], which gives us using the parameter set +/// given in `PROOF_OPTIONS` a signature with $102$ bits of average-case existential unforgeability +/// security against $2^{113}$-query bound adversaries that can obtain up to $2^{64}$ signatures +/// under the same public key. /// /// [1]: https://eprint.iacr.org/2024/1553 +/// [2]: https://eprint.iacr.org/2021/582 #[derive(Debug, Clone, PartialEq, Eq)] pub struct Signature { proof: Proof, @@ -112,8 +147,9 @@ impl Signature { pub fn inner(&self) -> Proof { self.proof.clone() } + /// Returns true if this signature is a valid signature for the specified message generated - /// against the secret key matching the specified public key commitment. + /// against the secret key matching the specified public key. pub fn verify(&self, message: Word, pk: PublicKey) -> bool { let signature: RpoSignatureScheme = RpoSignatureScheme::new(PROOF_OPTIONS); @@ -122,35 +158,6 @@ impl Signature { } } -// SERIALIZATION / DESERIALIZATION -// ================================================================================================ - -impl Serializable for PublicKey { - fn write_into(&self, target: &mut W) { - self.0.write_into(target); - } -} - -impl Deserializable for PublicKey { - fn read_from(source: &mut R) -> Result { - let pk = ::read_from(source)?; - Ok(Self(pk)) - } -} - -impl Serializable for SecretKey { - fn write_into(&self, target: &mut W) { - self.0.write_into(target); - } -} - -impl Deserializable for SecretKey { - fn read_from(source: &mut R) -> Result { - let sk = ::read_from(source)?; - Ok(Self(sk)) - } -} - impl Serializable for Signature { fn write_into(&self, target: &mut W) { self.proof.write_into(target); diff --git a/src/dsa/rpo_stark/stark/air.rs b/src/dsa/rpo_stark/stark/air.rs index 6dd5b7ef8..163829625 100644 --- a/src/dsa/rpo_stark/stark/air.rs +++ b/src/dsa/rpo_stark/stark/air.rs @@ -7,7 +7,7 @@ use winter_prover::{ }; use crate::{ - hash::rpo::{ARK1, ARK2, MDS, STATE_WIDTH}, + hash::{ARK1, ARK2, MDS, STATE_WIDTH}, Word, ZERO, }; @@ -15,7 +15,6 @@ use crate::{ // ================================================================================================ pub const HASH_CYCLE_LEN: usize = 8; -pub const TRACE_WIDTH: usize = 12; // AIR // ================================================================================================ @@ -50,7 +49,7 @@ impl Air for RescueAir { TransitionConstraintDegree::new(7), TransitionConstraintDegree::new(7), ]; - assert_eq!(TRACE_WIDTH, trace_info.width()); + assert_eq!(STATE_WIDTH, trace_info.width()); let context = AirContext::new(trace_info, degrees, 12, options); let context = context.set_num_transition_exemptions(1); RescueAir { context, pub_key: pub_inputs.pub_key } @@ -69,8 +68,8 @@ impl Air for RescueAir { let current = frame.current(); let next = frame.next(); // expected state width is 12 field elements - debug_assert_eq!(TRACE_WIDTH, current.len()); - debug_assert_eq!(TRACE_WIDTH, next.len()); + debug_assert_eq!(STATE_WIDTH, current.len()); + debug_assert_eq!(STATE_WIDTH, next.len()); enforce_rpo_round(frame, result, periodic_values); } @@ -153,7 +152,7 @@ pub fn enforce_rpo_round>( // make sure that the results are equal. for i in 0..STATE_WIDTH { - result.agg_constraint(i, are_equal(step2[i], step1[i])); + result[i] = step2[i] - step1[i] } } @@ -194,30 +193,3 @@ pub fn get_round_constants() -> Vec> { constants } - -// CONSTRAINT EVALUATION HELPERS -// ================================================================================================ - -/// Returns zero only when a == b. -pub fn are_equal(a: E, b: E) -> E { - a - b -} - -// TRAIT TO SIMPLIFY CONSTRAINT AGGREGATION -// ================================================================================================ - -pub trait EvaluationResult { - fn agg_constraint(&mut self, index: usize, value: E); -} - -impl EvaluationResult for [E] { - fn agg_constraint(&mut self, index: usize, value: E) { - self[index] += value; - } -} - -impl EvaluationResult for Vec { - fn agg_constraint(&mut self, index: usize, value: E) { - self[index] += value; - } -} diff --git a/src/dsa/rpo_stark/stark/mod.rs b/src/dsa/rpo_stark/stark/mod.rs index c09e8a0cc..a73c3967e 100644 --- a/src/dsa/rpo_stark/stark/mod.rs +++ b/src/dsa/rpo_stark/stark/mod.rs @@ -4,13 +4,13 @@ use prover::RpoSignatureProver; use rand::{distributions::Standard, prelude::Distribution, thread_rng, RngCore, SeedableRng}; use rand_chacha::ChaCha20Rng; use winter_crypto::{ElementHasher, Hasher, SaltedMerkleTree}; -use winter_math::{fields::f64::BaseElement, FieldElement}; +use winter_math::fields::f64::BaseElement; use winter_prover::{Proof, ProofOptions}; use winter_verifier::{verify, AcceptableOptions, VerifierError}; use winterfell::Prover; use crate::{ - hash::rpo::{Rpo256, DIGEST_RANGE, DIGEST_SIZE, NUM_ROUNDS, STATE_WIDTH}, + hash::{rpo::Rpo256, DIGEST_SIZE}, rand::RpoRandomCoin, }; @@ -64,17 +64,3 @@ where ) } } - -// HELPER FUNCTIONS -// ================================================================================================ - -pub fn compute_rpo_image(pre_image: [BaseElement; DIGEST_SIZE]) -> [BaseElement; DIGEST_SIZE] { - let mut state = [BaseElement::ZERO; STATE_WIDTH]; - state[DIGEST_RANGE].copy_from_slice(&pre_image); - for i in 0..NUM_ROUNDS { - Rpo256::apply_round(&mut state, i); - } - state[DIGEST_RANGE] - .try_into() - .expect("should not fail given the size of the array") -} diff --git a/src/dsa/rpo_stark/stark/prover.rs b/src/dsa/rpo_stark/stark/prover.rs index 66ce031a6..9fc653cd6 100644 --- a/src/dsa/rpo_stark/stark/prover.rs +++ b/src/dsa/rpo_stark/stark/prover.rs @@ -20,20 +20,21 @@ use crate::{hash::rpo::Rpo256, rand::RpoRandomCoin, Word, ZERO}; // PROVER // ================================================================================================ -pub struct RpoSignatureProver -where - H: Sync, -{ +/// A prover for the RPO STARK-based signature scheme. +/// +/// The signature is based on the the one-wayness of the RPO hash function but it is generic over +/// the hash function used for instantiating the random oracle for the BCS transform. +pub(crate) struct RpoSignatureProver { options: ProofOptions, _hasher: PhantomData, } impl RpoSignatureProver { - pub fn new(options: ProofOptions) -> Self { + pub(crate) fn new(options: ProofOptions) -> Self { Self { options, _hasher: PhantomData } } - pub fn build_trace(&self, sk: Word, msg: Word) -> TraceTable { + pub(crate) fn build_trace(&self, sk: Word, msg: Word) -> TraceTable { let trace_length = HASH_CYCLE_LEN; let mut target = vec![]; msg.write_into(&mut target); @@ -41,7 +42,7 @@ impl RpoSignatureProver { trace.fill( |state| { - // initialize first state of the computation + // initialize first half of the rate portion of the state with the secret key state[0] = ZERO; state[1] = ZERO; state[2] = ZERO; diff --git a/src/hash/mod.rs b/src/hash/mod.rs index fd9464ecb..4d11511a4 100644 --- a/src/hash/mod.rs +++ b/src/hash/mod.rs @@ -5,11 +5,9 @@ use super::{CubeExtension, Felt, FieldElement, StarkField, ZERO}; pub mod blake; mod rescue; +pub(crate) use rescue::{ARK1, ARK2, DIGEST_SIZE, MDS, STATE_WIDTH}; pub mod rpo { - pub use super::rescue::{ - Rpo256, RpoDigest, RpoDigestError, ARK1, ARK2, DIGEST_RANGE, DIGEST_SIZE, MDS, NUM_ROUNDS, - STATE_WIDTH, - }; + pub use super::rescue::{Rpo256, RpoDigest, RpoDigestError}; } pub mod rpx { diff --git a/src/hash/rescue/mod.rs b/src/hash/rescue/mod.rs index 530f62eac..42bdb60e5 100644 --- a/src/hash/rescue/mod.rs +++ b/src/hash/rescue/mod.rs @@ -6,7 +6,7 @@ mod arch; pub use arch::optimized::{add_constants_and_apply_inv_sbox, add_constants_and_apply_sbox}; mod mds; -pub use mds::{apply_mds, MDS}; +pub(crate) use mds::{apply_mds, MDS}; mod rpo; pub use rpo::{Rpo256, RpoDigest, RpoDigestError}; @@ -22,11 +22,11 @@ mod tests; /// The number of rounds is set to 7. For the RPO hash functions all rounds are uniform. For the /// RPX hash function, there are 3 different types of rounds. -pub const NUM_ROUNDS: usize = 7; +const NUM_ROUNDS: usize = 7; /// Sponge state is set to 12 field elements or 96 bytes; 8 elements are reserved for rate and /// the remaining 4 elements are reserved for capacity. -pub const STATE_WIDTH: usize = 12; +pub(crate) const STATE_WIDTH: usize = 12; /// The rate portion of the state is located in elements 4 through 11. const RATE_RANGE: Range = 4..12; @@ -42,8 +42,8 @@ const CAPACITY_RANGE: Range = 0..4; /// /// The digest is returned from state elements 4, 5, 6, and 7 (the first four elements of the /// rate portion). -pub const DIGEST_RANGE: Range = 4..8; -pub const DIGEST_SIZE: usize = DIGEST_RANGE.end - DIGEST_RANGE.start; +pub(crate) const DIGEST_RANGE: Range = 4..8; +pub(crate) const DIGEST_SIZE: usize = DIGEST_RANGE.end - DIGEST_RANGE.start; /// The number of bytes needed to encoded a digest const DIGEST_BYTES: usize = 32; @@ -83,7 +83,7 @@ fn apply_sbox(state: &mut [Felt; STATE_WIDTH]) { // ================================================================================================ #[inline(always)] -pub fn apply_inv_sbox(state: &mut [Felt; STATE_WIDTH]) { +fn apply_inv_sbox(state: &mut [Felt; STATE_WIDTH]) { // compute base^10540996611094048183 using 72 multiplications per array element // 10540996611094048183 = b1001001001001001001001001001000110110110110110110110110110110111 @@ -132,7 +132,7 @@ pub fn apply_inv_sbox(state: &mut [Felt; STATE_WIDTH]) { } #[inline(always)] -pub fn add_constants(state: &mut [Felt; STATE_WIDTH], ark: &[Felt; STATE_WIDTH]) { +fn add_constants(state: &mut [Felt; STATE_WIDTH], ark: &[Felt; STATE_WIDTH]) { state.iter_mut().zip(ark).for_each(|(s, &k)| *s += k); } @@ -144,7 +144,7 @@ pub fn add_constants(state: &mut [Felt; STATE_WIDTH], ark: &[Felt; STATE_WIDTH]) /// /// The constants are broken up into two arrays ARK1 and ARK2; ARK1 contains the constants for the /// first half of RPO round, and ARK2 contains constants for the second half of RPO round. -pub const ARK1: [[Felt; STATE_WIDTH]; NUM_ROUNDS] = [ +pub(crate) const ARK1: [[Felt; STATE_WIDTH]; NUM_ROUNDS] = [ [ Felt::new(5789762306288267392), Felt::new(6522564764413701783), @@ -245,7 +245,7 @@ pub const ARK1: [[Felt; STATE_WIDTH]; NUM_ROUNDS] = [ ], ]; -pub const ARK2: [[Felt; STATE_WIDTH]; NUM_ROUNDS] = [ +pub(crate) const ARK2: [[Felt; STATE_WIDTH]; NUM_ROUNDS] = [ [ Felt::new(6077062762357204287), Felt::new(15277620170502011191), diff --git a/src/hash/rescue/rpo/digest.rs b/src/hash/rescue/rpo/digest.rs index 1e3f1d5cc..54fa02f92 100644 --- a/src/hash/rescue/rpo/digest.rs +++ b/src/hash/rescue/rpo/digest.rs @@ -1,7 +1,10 @@ use alloc::string::String; use core::{cmp::Ordering, fmt::Display, ops::Deref, slice}; -use rand::{distributions::Standard, prelude::Distribution}; +use rand::{ + distributions::{Standard, Uniform}, + prelude::Distribution, +}; use thiserror::Error; use super::{Digest, Felt, StarkField, DIGEST_BYTES, DIGEST_SIZE, ZERO}; @@ -71,8 +74,8 @@ impl Digest for RpoDigest { fn from_random_bytes(buffer: &[u8]) -> Self { let mut digest: [Felt; DIGEST_SIZE] = [ZERO; DIGEST_SIZE]; - buffer.chunks(8).zip(digest.iter_mut()).for_each(|(chunk, digest)| { - *digest = Felt::new(u64::from_be_bytes( + buffer.chunks(8).zip(digest.iter_mut()).for_each(|(chunk, element)| { + *element = Felt::new(u64::from_be_bytes( chunk.try_into().expect("Given the size of the chunk this should not panic"), )) }); @@ -142,10 +145,10 @@ impl Randomizable for RpoDigest { impl Distribution for Standard { fn sample(&self, rng: &mut R) -> RpoDigest { let mut res = [ZERO; DIGEST_SIZE]; + let uni_dist = Uniform::from(0..Felt::MODULUS); for r in res.iter_mut() { - let mut source = [0_u8; 8]; - rng.fill_bytes(&mut source); - *r = Felt::from_random_bytes(&source).expect("failed to generate element"); + let sampled_integer = uni_dist.sample(rng); + *r = Felt::new(sampled_integer); } RpoDigest::new(res) } diff --git a/src/hash/rescue/rpx/digest.rs b/src/hash/rescue/rpx/digest.rs index 275ffc661..8a0b8e10c 100644 --- a/src/hash/rescue/rpx/digest.rs +++ b/src/hash/rescue/rpx/digest.rs @@ -70,8 +70,8 @@ impl Digest for RpxDigest { fn from_random_bytes(buffer: &[u8]) -> Self { let mut digest: [Felt; DIGEST_SIZE] = [ZERO; DIGEST_SIZE]; - buffer.chunks(8).zip(digest.iter_mut()).for_each(|(chunk, digest)| { - *digest = Felt::new(u64::from_be_bytes( + buffer.chunks(8).zip(digest.iter_mut()).for_each(|(chunk, element)| { + *element = Felt::new(u64::from_be_bytes( chunk.try_into().expect("Given the size of the chunk this should not panic"), )) }); From f0ef609bf9e15be3ade3be906f39ca0b60ea0192 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Mon, 9 Dec 2024 15:06:43 +0100 Subject: [PATCH 10/20] chore: conflict resolve --- Cargo.lock | 1 + Cargo.toml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 9d4b79de2..200229474 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -542,6 +542,7 @@ dependencies = [ "rand", "rand_chacha", "rand_core", + "rayon", "seq-macro", "serde", "sha3", diff --git a/Cargo.toml b/Cargo.toml index 76aa42c33..7d8410194 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,8 @@ num = { version = "0.4", default-features = false, features = ["alloc", "libm"] num-complex = { version = "0.4", default-features = false } rand = { version = "0.8", default-features = false } rand_core = { version = "0.6", default-features = false } -#rand-utils = { version = "0.10", package = "winter-rand-utils", optional = true } +#rand-utils = { version = "0.11", package = "winter-rand-utils", optional = true } +rayon = { version = "1.10", optional = true } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } sha3 = { version = "0.10", default-features = false } thiserror = { version = "2.0", default-features = false } From 1bbadffe9208c6924713b9ea811aeb7b0213286a Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:50:09 +0100 Subject: [PATCH 11/20] chore: address feedback 2 --- src/dsa/rpo_stark/signature/mod.rs | 2 ++ src/dsa/rpo_stark/stark/air.rs | 5 ++++- src/dsa/rpo_stark/stark/mod.rs | 7 +++++-- src/dsa/rpo_stark/stark/prover.rs | 27 +++++++++++++++------------ 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/dsa/rpo_stark/signature/mod.rs b/src/dsa/rpo_stark/signature/mod.rs index a8b0bc876..63393a9ad 100644 --- a/src/dsa/rpo_stark/signature/mod.rs +++ b/src/dsa/rpo_stark/signature/mod.rs @@ -31,6 +31,7 @@ pub const PROOF_OPTIONS: ProofOptions = pub struct PublicKey(Word); impl PublicKey { + /// Returns the [Word] defining the public key. pub fn inner(&self) -> Word { self.0 } @@ -144,6 +145,7 @@ pub struct Signature { } impl Signature { + /// Returns the STARK proof constituting the signature. pub fn inner(&self) -> Proof { self.proof.clone() } diff --git a/src/dsa/rpo_stark/stark/air.rs b/src/dsa/rpo_stark/stark/air.rs index 163829625..eb7fede3e 100644 --- a/src/dsa/rpo_stark/stark/air.rs +++ b/src/dsa/rpo_stark/stark/air.rs @@ -75,10 +75,12 @@ impl Air for RescueAir { } fn get_assertions(&self) -> Vec> { - // Assert that the public key is the correct one let initial_step = 0; let last_step = self.trace_length() - 1; vec![ + // Assert that the capacity as well as the second half of the rate portion of the state + // are initialized to `ZERO`.The first half of the rate is unconstrained as it will + // contain the secret key Assertion::single(0, initial_step, Self::BaseField::ZERO), Assertion::single(1, initial_step, Self::BaseField::ZERO), Assertion::single(2, initial_step, Self::BaseField::ZERO), @@ -87,6 +89,7 @@ impl Air for RescueAir { Assertion::single(9, initial_step, Self::BaseField::ZERO), Assertion::single(10, initial_step, Self::BaseField::ZERO), Assertion::single(11, initial_step, Self::BaseField::ZERO), + // Assert that the public key is the correct one Assertion::single(4, last_step, self.pub_key[0]), Assertion::single(5, last_step, self.pub_key[1]), Assertion::single(6, last_step, self.pub_key[2]), diff --git a/src/dsa/rpo_stark/stark/mod.rs b/src/dsa/rpo_stark/stark/mod.rs index a73c3967e..51bbde16d 100644 --- a/src/dsa/rpo_stark/stark/mod.rs +++ b/src/dsa/rpo_stark/stark/mod.rs @@ -35,10 +35,10 @@ where pub fn sign(&self, sk: [BaseElement; DIGEST_SIZE], msg: [BaseElement; DIGEST_SIZE]) -> Proof { // create a prover - let prover = RpoSignatureProver::::new(self.options.clone()); + let prover = RpoSignatureProver::::new(msg, self.options.clone()); // generate execution trace - let trace = prover.build_trace(sk, msg); + let trace = prover.build_trace(sk); // generate the initial seed for the PRNG used for zero-knowledge let mut seed = ::Seed::default(); @@ -55,6 +55,9 @@ where msg: [BaseElement; DIGEST_SIZE], proof: Proof, ) -> Result<(), VerifierError> { + if *proof.options() != self.options { + return Err(VerifierError::UnacceptableProofOptions); + } let pub_inputs = PublicInputs { pub_key, msg }; let acceptable_options = AcceptableOptions::OptionSet(vec![proof.options().clone()]); verify::>( diff --git a/src/dsa/rpo_stark/stark/prover.rs b/src/dsa/rpo_stark/stark/prover.rs index 9fc653cd6..ef7e22d41 100644 --- a/src/dsa/rpo_stark/stark/prover.rs +++ b/src/dsa/rpo_stark/stark/prover.rs @@ -8,14 +8,17 @@ use winter_prover::{ matrix::ColMatrix, DefaultConstraintEvaluator, DefaultTraceLde, ProofOptions, Prover, StarkDomain, Trace, TraceInfo, TracePolyTable, TraceTable, }; -use winter_utils::{Deserializable, Serializable}; use winterfell::{ AuxRandElements, CompositionPoly, CompositionPolyTrace, ConstraintCompositionCoefficients, DefaultConstraintCommitment, PartitionOptions, }; use super::air::{PublicInputs, RescueAir, HASH_CYCLE_LEN}; -use crate::{hash::rpo::Rpo256, rand::RpoRandomCoin, Word, ZERO}; +use crate::{ + hash::{rpo::Rpo256, STATE_WIDTH}, + rand::RpoRandomCoin, + Word, ZERO, +}; // PROVER // ================================================================================================ @@ -25,20 +28,18 @@ use crate::{hash::rpo::Rpo256, rand::RpoRandomCoin, Word, ZERO}; /// The signature is based on the the one-wayness of the RPO hash function but it is generic over /// the hash function used for instantiating the random oracle for the BCS transform. pub(crate) struct RpoSignatureProver { + message: Word, options: ProofOptions, _hasher: PhantomData, } impl RpoSignatureProver { - pub(crate) fn new(options: ProofOptions) -> Self { - Self { options, _hasher: PhantomData } + pub(crate) fn new(message: Word, options: ProofOptions) -> Self { + Self { message, options, _hasher: PhantomData } } - pub(crate) fn build_trace(&self, sk: Word, msg: Word) -> TraceTable { - let trace_length = HASH_CYCLE_LEN; - let mut target = vec![]; - msg.write_into(&mut target); - let mut trace = TraceTable::with_meta(12, trace_length, target); + pub(crate) fn build_trace(&self, sk: Word) -> TraceTable { + let mut trace = TraceTable::new(STATE_WIDTH, HASH_CYCLE_LEN); trace.fill( |state| { @@ -87,8 +88,10 @@ where fn get_pub_inputs(&self, trace: &Self::Trace) -> PublicInputs { let last_step = trace.length() - 1; - let source = trace.info().meta(); - let msg = ::read_from_bytes(source).expect("the message should be a Word"); + // Note that the message is not part of the execution trace but is part of the public + // inputs. This is explained in the reference description of the DSA and intuitively + // it is done in order to make sure that the message is part of the Fiat-Shamir + // transcript and hence binds the proof/signature to the message PublicInputs { pub_key: [ trace.get(4, last_step), @@ -96,7 +99,7 @@ where trace.get(6, last_step), trace.get(7, last_step), ], - msg, + msg: self.message, } } From 5854a7044508ff41a00da948fcd2651cfca01e62 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Tue, 10 Dec 2024 13:10:21 +0100 Subject: [PATCH 12/20] chore: remove from random_bytes --- Cargo.lock | 87 +++++++++++++++++------------------ src/hash/blake/mod.rs | 8 ---- src/hash/rescue/rpo/digest.rs | 12 ----- src/hash/rescue/rpx/digest.rs | 12 ----- 4 files changed, 43 insertions(+), 76 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 200229474..052a1ec98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -153,9 +153,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" +checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" dependencies = [ "jobserver", "libc", @@ -197,9 +197,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.21" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ "clap_builder", "clap_derive", @@ -207,9 +207,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.21" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ "anstream", "anstyle", @@ -231,9 +231,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "colorchoice" @@ -361,9 +361,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fnv" @@ -471,9 +471,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.74" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ "once_cell", "wasm-bindgen", @@ -496,9 +496,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.167" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "libm" @@ -822,15 +822,15 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustix" -version = "0.38.41" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -946,18 +946,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.3" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.3" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" dependencies = [ "proc-macro2", "quote", @@ -1059,9 +1059,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", @@ -1070,13 +1070,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", "syn", @@ -1085,9 +1084,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1095,9 +1094,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", @@ -1108,15 +1107,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "web-sys" -version = "0.3.74" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a98bc3c33f0fe7e59ad7cd041b89034fa82a7c2d4365ca538dda6cdaf513863c" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", @@ -1216,7 +1215,7 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winter-air" version = "0.11.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3" dependencies = [ "libm", "winter-crypto", @@ -1228,7 +1227,7 @@ dependencies = [ [[package]] name = "winter-crypto" version = "0.11.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3" dependencies = [ "blake3", "rand", @@ -1241,7 +1240,7 @@ dependencies = [ [[package]] name = "winter-fri" version = "0.11.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3" dependencies = [ "rand", "rand_chacha", @@ -1253,7 +1252,7 @@ dependencies = [ [[package]] name = "winter-math" version = "0.11.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3" dependencies = [ "serde", "winter-utils", @@ -1262,7 +1261,7 @@ dependencies = [ [[package]] name = "winter-maybe-async" version = "0.11.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3" dependencies = [ "quote", "syn", @@ -1271,7 +1270,7 @@ dependencies = [ [[package]] name = "winter-prover" version = "0.11.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3" dependencies = [ "rand", "rand_chacha", @@ -1288,7 +1287,7 @@ dependencies = [ [[package]] name = "winter-rand-utils" version = "0.11.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3" dependencies = [ "rand", "winter-utils", @@ -1297,12 +1296,12 @@ dependencies = [ [[package]] name = "winter-utils" version = "0.11.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3" [[package]] name = "winter-verifier" version = "0.11.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3" dependencies = [ "winter-air", "winter-crypto", @@ -1314,7 +1313,7 @@ dependencies = [ [[package]] name = "winterfell" version = "0.11.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#606ffe7344aa165a5b58053cf678a5fb4f27ebcb" +source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3" dependencies = [ "winter-air", "winter-prover", diff --git a/src/hash/blake/mod.rs b/src/hash/blake/mod.rs index 618bff968..88ffe0897 100644 --- a/src/hash/blake/mod.rs +++ b/src/hash/blake/mod.rs @@ -99,14 +99,6 @@ impl Digest for Blake3Digest { assert!(N <= 32, "digest currently supports only 32 bytes!"); expand_bytes(&self.0) } - - fn from_random_bytes(buffer: &[u8]) -> Self { - Self( - buffer - .try_into() - .expect("The size of the buffer with random bytes should be 32"), - ) - } } // BLAKE3 256-BIT OUTPUT diff --git a/src/hash/rescue/rpo/digest.rs b/src/hash/rescue/rpo/digest.rs index 54fa02f92..c69200e06 100644 --- a/src/hash/rescue/rpo/digest.rs +++ b/src/hash/rescue/rpo/digest.rs @@ -70,18 +70,6 @@ impl Digest for RpoDigest { result } - - fn from_random_bytes(buffer: &[u8]) -> Self { - let mut digest: [Felt; DIGEST_SIZE] = [ZERO; DIGEST_SIZE]; - - buffer.chunks(8).zip(digest.iter_mut()).for_each(|(chunk, element)| { - *element = Felt::new(u64::from_be_bytes( - chunk.try_into().expect("Given the size of the chunk this should not panic"), - )) - }); - - digest.into() - } } impl Deref for RpoDigest { diff --git a/src/hash/rescue/rpx/digest.rs b/src/hash/rescue/rpx/digest.rs index 8a0b8e10c..07ec3c66e 100644 --- a/src/hash/rescue/rpx/digest.rs +++ b/src/hash/rescue/rpx/digest.rs @@ -66,18 +66,6 @@ impl Digest for RpxDigest { result } - - fn from_random_bytes(buffer: &[u8]) -> Self { - let mut digest: [Felt; DIGEST_SIZE] = [ZERO; DIGEST_SIZE]; - - buffer.chunks(8).zip(digest.iter_mut()).for_each(|(chunk, element)| { - *element = Felt::new(u64::from_be_bytes( - chunk.try_into().expect("Given the size of the chunk this should not panic"), - )) - }); - - digest.into() - } } impl Deref for RpxDigest { From d7a23c41f571b35bea4ccd8d2f89ed611658ac36 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Wed, 11 Dec 2024 10:25:52 +0100 Subject: [PATCH 13/20] chore: address feedback --- Cargo.lock | 11 ----------- Cargo.toml | 7 +------ src/dsa/rpo_stark/signature/mod.rs | 2 +- src/dsa/rpo_stark/stark/mod.rs | 4 ++-- src/dsa/rpo_stark/stark/prover.rs | 13 ++++++------- 5 files changed, 10 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 052a1ec98..0970f9fbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -556,7 +556,6 @@ dependencies = [ "winter-rand-utils", "winter-utils", "winter-verifier", - "winterfell", ] [[package]] @@ -1310,16 +1309,6 @@ dependencies = [ "winter-utils", ] -[[package]] -name = "winterfell" -version = "0.11.0" -source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3" -dependencies = [ - "winter-air", - "winter-prover", - "winter-verifier", -] - [[package]] name = "zerocopy" version = "0.7.35" diff --git a/Cargo.toml b/Cargo.toml index 7d8410194..894ac364c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,8 +51,8 @@ clap = { version = "4.5", optional = true, features = ["derive"] } num = { version = "0.4", default-features = false, features = ["alloc", "libm"] } num-complex = { version = "0.4", default-features = false } rand = { version = "0.8", default-features = false } +rand_chacha = { version = "0.3", default-features = false } rand_core = { version = "0.6", default-features = false } -#rand-utils = { version = "0.11", package = "winter-rand-utils", optional = true } rayon = { version = "1.10", optional = true } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } sha3 = { version = "0.10", default-features = false } @@ -65,10 +65,7 @@ winter-math = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk winter-fri = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } winter-maybe-async = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } winter-utils = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk', optional = true } -#winter-rand-utils = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk', optional = true } rand-utils = {git = 'https://github.com/Al-Kindi-0/winterfell', package = "winter-rand-utils" , branch = 'al-zk', optional = true } -winterfell = {git = 'https://github.com/Al-Kindi-0/winterfell/', branch = 'al-zk' } -rand_chacha = { version = "0.3", default-features = false } [dev-dependencies] assert_matches = { version = "1.5", default-features = false } @@ -76,8 +73,6 @@ criterion = { version = "0.5", features = ["html_reports"] } getrandom = { version = "0.2", features = ["js"] } hex = { version = "0.4", default-features = false, features = ["alloc"] } proptest = "1.5" -rand_chacha = { version = "0.3", default-features = false } -#rand-utils = { version = "0.10", package = "winter-rand-utils" } rand-utils = {git = 'https://github.com/Al-Kindi-0/winterfell', package = "winter-rand-utils" , branch = 'al-zk' } seq-macro = { version = "0.3" } diff --git a/src/dsa/rpo_stark/signature/mod.rs b/src/dsa/rpo_stark/signature/mod.rs index 63393a9ad..87d367039 100644 --- a/src/dsa/rpo_stark/signature/mod.rs +++ b/src/dsa/rpo_stark/signature/mod.rs @@ -1,8 +1,8 @@ use rand::{distributions::Uniform, prelude::Distribution, Rng}; +use winter_air::{FieldExtension, ProofOptions}; use winter_math::{fields::f64::BaseElement, FieldElement, StarkField}; use winter_prover::Proof; use winter_utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}; -use winterfell::{FieldExtension, ProofOptions}; use crate::{ dsa::rpo_stark::stark::RpoSignatureScheme, diff --git a/src/dsa/rpo_stark/stark/mod.rs b/src/dsa/rpo_stark/stark/mod.rs index 51bbde16d..80d409cd4 100644 --- a/src/dsa/rpo_stark/stark/mod.rs +++ b/src/dsa/rpo_stark/stark/mod.rs @@ -5,9 +5,8 @@ use rand::{distributions::Standard, prelude::Distribution, thread_rng, RngCore, use rand_chacha::ChaCha20Rng; use winter_crypto::{ElementHasher, Hasher, SaltedMerkleTree}; use winter_math::fields::f64::BaseElement; -use winter_prover::{Proof, ProofOptions}; +use winter_prover::{Proof, ProofOptions, Prover}; use winter_verifier::{verify, AcceptableOptions, VerifierError}; -use winterfell::Prover; use crate::{ hash::{rpo::Rpo256, DIGEST_SIZE}, @@ -55,6 +54,7 @@ where msg: [BaseElement; DIGEST_SIZE], proof: Proof, ) -> Result<(), VerifierError> { + // we make sure that the parameters used in generating the proof match the expected ones if *proof.options() != self.options { return Err(VerifierError::UnacceptableProofOptions); } diff --git a/src/dsa/rpo_stark/stark/prover.rs b/src/dsa/rpo_stark/stark/prover.rs index ef7e22d41..9018dab26 100644 --- a/src/dsa/rpo_stark/stark/prover.rs +++ b/src/dsa/rpo_stark/stark/prover.rs @@ -1,16 +1,15 @@ use core::marker::PhantomData; use rand_chacha::ChaCha20Rng; -use winter_air::ZkParameters; +use winter_air::{ + AuxRandElements, ConstraintCompositionCoefficients, PartitionOptions, ZkParameters, +}; use winter_crypto::{ElementHasher, SaltedMerkleTree}; use winter_math::{fields::f64::BaseElement, FieldElement}; use winter_prover::{ - matrix::ColMatrix, DefaultConstraintEvaluator, DefaultTraceLde, ProofOptions, Prover, - StarkDomain, Trace, TraceInfo, TracePolyTable, TraceTable, -}; -use winterfell::{ - AuxRandElements, CompositionPoly, CompositionPolyTrace, ConstraintCompositionCoefficients, - DefaultConstraintCommitment, PartitionOptions, + matrix::ColMatrix, CompositionPoly, CompositionPolyTrace, DefaultConstraintCommitment, + DefaultConstraintEvaluator, DefaultTraceLde, ProofOptions, Prover, StarkDomain, Trace, + TraceInfo, TracePolyTable, TraceTable, }; use super::air::{PublicInputs, RescueAir, HASH_CYCLE_LEN}; From e30c18d36577c8ef466e0ee895360a47ce47e5d0 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Wed, 11 Dec 2024 10:34:48 +0100 Subject: [PATCH 14/20] chore: add flag --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 69eccef6d..3430731e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,6 +58,7 @@ std = [ "winter-crypto/std", "winter-math/std", "winter-utils/std", + "getrandom/js", ] [dependencies] From b815e03645aa748247a273b54ce95932f0058f60 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Wed, 11 Dec 2024 10:58:49 +0100 Subject: [PATCH 15/20] chore: remove optional --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3430731e4..dbfdd20c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,7 +80,7 @@ winter-verifier = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'a winter-math = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } winter-fri = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } winter-maybe-async = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } -winter-utils = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk', optional = true } +winter-utils = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } rand-utils = {git = 'https://github.com/Al-Kindi-0/winterfell', package = "winter-rand-utils" , branch = 'al-zk', optional = true } [dev-dependencies] From edc3843a361d28d016b2e80cb80412e83ce68bb9 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Wed, 11 Dec 2024 11:01:43 +0100 Subject: [PATCH 16/20] fix: clippy --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index dbfdd20c7..1985616e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,11 +82,11 @@ winter-fri = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' winter-maybe-async = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } winter-utils = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } rand-utils = {git = 'https://github.com/Al-Kindi-0/winterfell', package = "winter-rand-utils" , branch = 'al-zk', optional = true } +getrandom = { version = "0.2", features = ["js"] } [dev-dependencies] assert_matches = { version = "1.5", default-features = false } criterion = { version = "0.5", features = ["html_reports"] } -getrandom = { version = "0.2", features = ["js"] } hex = { version = "0.4", default-features = false, features = ["alloc"] } proptest = "1.5" rand-utils = {git = 'https://github.com/Al-Kindi-0/winterfell', package = "winter-rand-utils" , branch = 'al-zk' } From 8c67eeb0a7432cb631d9bf73668f33d3b8badd74 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Wed, 11 Dec 2024 12:50:03 +0100 Subject: [PATCH 17/20] fix: clippy --- src/dsa/rpo_stark/mod.rs | 15 +++------------ src/dsa/rpo_stark/signature/mod.rs | 7 +++++-- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/dsa/rpo_stark/mod.rs b/src/dsa/rpo_stark/mod.rs index a7c1f4707..599a7fab7 100644 --- a/src/dsa/rpo_stark/mod.rs +++ b/src/dsa/rpo_stark/mod.rs @@ -9,25 +9,16 @@ pub use stark::{PublicInputs, RescueAir}; #[cfg(test)] mod tests { - use std::println; - - use rand::SeedableRng; - use rand_chacha::ChaCha20Rng; - + use crate::Word; use super::SecretKey; #[test] fn test_signature() { - use rand_utils::rand_array; - - let seed = [0_u8; 32]; - let mut rng = ChaCha20Rng::from_seed(seed); - let sk = SecretKey::with_rng(&mut rng); + let sk = SecretKey::new(Word::default()); - let message = rand_array(); + let message = Word::default(); let signature = sk.sign(message); let pk = sk.public_key(); - println!("verify {:?}", pk.verify(message, &signature)); assert!(pk.verify(message, &signature)) } } diff --git a/src/dsa/rpo_stark/signature/mod.rs b/src/dsa/rpo_stark/signature/mod.rs index 87d367039..fe7c0bcfc 100644 --- a/src/dsa/rpo_stark/signature/mod.rs +++ b/src/dsa/rpo_stark/signature/mod.rs @@ -1,15 +1,18 @@ use rand::{distributions::Uniform, prelude::Distribution, Rng}; use winter_air::{FieldExtension, ProofOptions}; -use winter_math::{fields::f64::BaseElement, FieldElement, StarkField}; +use winter_math::{fields::f64::BaseElement, FieldElement}; use winter_prover::Proof; use winter_utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}; use crate::{ dsa::rpo_stark::stark::RpoSignatureScheme, hash::{rpo::Rpo256, DIGEST_SIZE}, - Word, ZERO, + Word, }; +#[cfg(feature = "std")] +use crate::{StarkField, ZERO}; + // CONSTANTS // ================================================================================================ From 4de39ad2d6a21a92207fd2a1d1fe0c30486349f8 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Wed, 11 Dec 2024 12:56:36 +0100 Subject: [PATCH 18/20] fix: add changelog --- CHANGELOG.md | 1 + src/dsa/rpo_stark/mod.rs | 2 +- src/dsa/rpo_stark/signature/mod.rs | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2957f2c97..762a58319 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - Fixed a bug in the implementation of `draw_integers` for `RpoRandomCoin` (#343). - [BREAKING] Refactor error messages and use `thiserror` to derive errors (#344). - [BREAKING] Updated Winterfell dependency to v0.11 (#346). +- Added RPO-STARK based DSA (#349). ## 0.12.0 (2024-10-30) diff --git a/src/dsa/rpo_stark/mod.rs b/src/dsa/rpo_stark/mod.rs index 599a7fab7..f35ef1639 100644 --- a/src/dsa/rpo_stark/mod.rs +++ b/src/dsa/rpo_stark/mod.rs @@ -9,8 +9,8 @@ pub use stark::{PublicInputs, RescueAir}; #[cfg(test)] mod tests { - use crate::Word; use super::SecretKey; + use crate::Word; #[test] fn test_signature() { diff --git a/src/dsa/rpo_stark/signature/mod.rs b/src/dsa/rpo_stark/signature/mod.rs index fe7c0bcfc..cafc6ec00 100644 --- a/src/dsa/rpo_stark/signature/mod.rs +++ b/src/dsa/rpo_stark/signature/mod.rs @@ -9,7 +9,6 @@ use crate::{ hash::{rpo::Rpo256, DIGEST_SIZE}, Word, }; - #[cfg(feature = "std")] use crate::{StarkField, ZERO}; From c4931b60600f0cd92ed32d8e00dad219cca3bbb6 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Thu, 12 Dec 2024 09:38:27 +0100 Subject: [PATCH 19/20] chore: fix std gate --- Cargo.toml | 1 - src/dsa/rpo_stark/signature/mod.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1985616e9..d96566aeb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,7 +58,6 @@ std = [ "winter-crypto/std", "winter-math/std", "winter-utils/std", - "getrandom/js", ] [dependencies] diff --git a/src/dsa/rpo_stark/signature/mod.rs b/src/dsa/rpo_stark/signature/mod.rs index cafc6ec00..8ae9c82e7 100644 --- a/src/dsa/rpo_stark/signature/mod.rs +++ b/src/dsa/rpo_stark/signature/mod.rs @@ -84,7 +84,6 @@ impl SecretKey { } /// Generates a secret_key using the provided random number generator `Rng`. - #[cfg(feature = "std")] pub fn with_rng(rng: &mut R) -> Self { let mut sk = [ZERO; 4]; let uni_dist = Uniform::from(0..BaseElement::MODULUS); From a7e484324498049e2dd3a50348706ba3144835e8 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Thu, 12 Dec 2024 09:43:25 +0100 Subject: [PATCH 20/20] fix: imports --- Cargo.lock | 2 -- Cargo.toml | 2 -- src/dsa/rpo_stark/signature/mod.rs | 4 +--- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0970f9fbf..ea60d0624 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -549,9 +549,7 @@ dependencies = [ "thiserror", "winter-air", "winter-crypto", - "winter-fri", "winter-math", - "winter-maybe-async", "winter-prover", "winter-rand-utils", "winter-utils", diff --git a/Cargo.toml b/Cargo.toml index d96566aeb..2b7b5791a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,8 +77,6 @@ winter-crypto = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al- winter-prover = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } winter-verifier = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } winter-math = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } -winter-fri = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } -winter-maybe-async = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } winter-utils = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' } rand-utils = {git = 'https://github.com/Al-Kindi-0/winterfell', package = "winter-rand-utils" , branch = 'al-zk', optional = true } getrandom = { version = "0.2", features = ["js"] } diff --git a/src/dsa/rpo_stark/signature/mod.rs b/src/dsa/rpo_stark/signature/mod.rs index 8ae9c82e7..c92a33d63 100644 --- a/src/dsa/rpo_stark/signature/mod.rs +++ b/src/dsa/rpo_stark/signature/mod.rs @@ -7,10 +7,8 @@ use winter_utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, use crate::{ dsa::rpo_stark::stark::RpoSignatureScheme, hash::{rpo::Rpo256, DIGEST_SIZE}, - Word, + StarkField, Word, ZERO, }; -#[cfg(feature = "std")] -use crate::{StarkField, ZERO}; // CONSTANTS // ================================================================================================