From 28bf2b1ab3564ea1747fb5d32c134fd59048cdb8 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Fri, 13 Oct 2023 18:30:37 +0200 Subject: [PATCH] feat: add acceptable options to verification fix: minor nits and refactorings fix: minor nits and refactorings --- examples/src/fibonacci/fib2/mod.rs | 17 ++++++- examples/src/fibonacci/fib8/mod.rs | 11 ++++- examples/src/fibonacci/fib_small/mod.rs | 11 ++++- examples/src/fibonacci/mulfib2/mod.rs | 11 ++++- examples/src/fibonacci/mulfib8/mod.rs | 11 ++++- examples/src/lamport/aggregate/mod.rs | 16 ++++++- examples/src/lamport/threshold/mod.rs | 16 ++++++- examples/src/merkle/mod.rs | 16 ++++++- examples/src/rescue/mod.rs | 16 ++++++- examples/src/rescue_raps/mod.rs | 16 ++++++- examples/src/vdf/exempt/mod.rs | 16 ++++++- examples/src/vdf/regular/mod.rs | 16 ++++++- verifier/src/errors.rs | 18 ++++++++ verifier/src/lib.rs | 61 +++++++++++++++++++++++-- winterfell/src/lib.rs | 5 +- 15 files changed, 230 insertions(+), 27 deletions(-) diff --git a/examples/src/fibonacci/fib2/mod.rs b/examples/src/fibonacci/fib2/mod.rs index a695862e8..c30cb3c4f 100644 --- a/examples/src/fibonacci/fib2/mod.rs +++ b/examples/src/fibonacci/fib2/mod.rs @@ -116,10 +116,23 @@ where } fn verify(&self, proof: StarkProof) -> Result<(), VerifierError> { - winterfell::verify::>(proof, self.result) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + + winterfell::verify::>( + proof, + self.result, + &acceptable_options, + ) } fn verify_with_wrong_inputs(&self, proof: StarkProof) -> Result<(), VerifierError> { - winterfell::verify::>(proof, self.result + BaseElement::ONE) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + winterfell::verify::>( + proof, + self.result + BaseElement::ONE, + &acceptable_options, + ) } } diff --git a/examples/src/fibonacci/fib8/mod.rs b/examples/src/fibonacci/fib8/mod.rs index 33064a02d..694765044 100644 --- a/examples/src/fibonacci/fib8/mod.rs +++ b/examples/src/fibonacci/fib8/mod.rs @@ -115,13 +115,22 @@ where } fn verify(&self, proof: StarkProof) -> Result<(), VerifierError> { - winterfell::verify::>(proof, self.result) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + winterfell::verify::>( + proof, + self.result, + &acceptable_options, + ) } fn verify_with_wrong_inputs(&self, proof: StarkProof) -> Result<(), VerifierError> { + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); winterfell::verify::>( proof, self.result + BaseElement::ONE, + &acceptable_options, ) } } diff --git a/examples/src/fibonacci/fib_small/mod.rs b/examples/src/fibonacci/fib_small/mod.rs index d6b3deb70..f6f9cd2bc 100644 --- a/examples/src/fibonacci/fib_small/mod.rs +++ b/examples/src/fibonacci/fib_small/mod.rs @@ -131,13 +131,22 @@ where } fn verify(&self, proof: StarkProof) -> Result<(), VerifierError> { - winterfell::verify::>(proof, self.result) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + winterfell::verify::>( + proof, + self.result, + &acceptable_options, + ) } fn verify_with_wrong_inputs(&self, proof: StarkProof) -> Result<(), VerifierError> { + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); winterfell::verify::>( proof, self.result + BaseElement::ONE, + &acceptable_options, ) } } diff --git a/examples/src/fibonacci/mulfib2/mod.rs b/examples/src/fibonacci/mulfib2/mod.rs index ece2d16dc..4d2d6a520 100644 --- a/examples/src/fibonacci/mulfib2/mod.rs +++ b/examples/src/fibonacci/mulfib2/mod.rs @@ -110,13 +110,22 @@ where } fn verify(&self, proof: StarkProof) -> Result<(), VerifierError> { - winterfell::verify::>(proof, self.result) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + winterfell::verify::>( + proof, + self.result, + &acceptable_options, + ) } fn verify_with_wrong_inputs(&self, proof: StarkProof) -> Result<(), VerifierError> { + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); winterfell::verify::>( proof, self.result + BaseElement::ONE, + &acceptable_options, ) } } diff --git a/examples/src/fibonacci/mulfib8/mod.rs b/examples/src/fibonacci/mulfib8/mod.rs index 27bee62c6..c763fa124 100644 --- a/examples/src/fibonacci/mulfib8/mod.rs +++ b/examples/src/fibonacci/mulfib8/mod.rs @@ -111,13 +111,22 @@ where } fn verify(&self, proof: StarkProof) -> Result<(), VerifierError> { - winterfell::verify::>(proof, self.result) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + winterfell::verify::>( + proof, + self.result, + &acceptable_options, + ) } fn verify_with_wrong_inputs(&self, proof: StarkProof) -> Result<(), VerifierError> { + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); winterfell::verify::>( proof, self.result + BaseElement::ONE, + &acceptable_options, ) } } diff --git a/examples/src/lamport/aggregate/mod.rs b/examples/src/lamport/aggregate/mod.rs index a9509f6ad..4917960bf 100644 --- a/examples/src/lamport/aggregate/mod.rs +++ b/examples/src/lamport/aggregate/mod.rs @@ -146,7 +146,13 @@ where pub_keys: self.pub_keys.clone(), messages: self.messages.clone(), }; - winterfell::verify::>(proof, pub_inputs) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + winterfell::verify::>( + proof, + pub_inputs, + &acceptable_options, + ) } fn verify_with_wrong_inputs(&self, proof: StarkProof) -> Result<(), VerifierError> { @@ -156,6 +162,12 @@ where pub_keys, messages: self.messages.clone(), }; - winterfell::verify::>(proof, pub_inputs) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + winterfell::verify::>( + proof, + pub_inputs, + &acceptable_options, + ) } } diff --git a/examples/src/lamport/threshold/mod.rs b/examples/src/lamport/threshold/mod.rs index 2b409efa1..db12f43e0 100644 --- a/examples/src/lamport/threshold/mod.rs +++ b/examples/src/lamport/threshold/mod.rs @@ -152,7 +152,13 @@ where num_signatures: self.signatures.len(), message: self.message, }; - winterfell::verify::>(proof, pub_inputs) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + winterfell::verify::>( + proof, + pub_inputs, + &acceptable_options, + ) } fn verify_with_wrong_inputs(&self, proof: StarkProof) -> Result<(), VerifierError> { @@ -162,7 +168,13 @@ where num_signatures: self.signatures.len() + 1, message: self.message, }; - winterfell::verify::>(proof, pub_inputs) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + winterfell::verify::>( + proof, + pub_inputs, + &acceptable_options, + ) } } diff --git a/examples/src/merkle/mod.rs b/examples/src/merkle/mod.rs index 3b143dba8..0e7488560 100644 --- a/examples/src/merkle/mod.rs +++ b/examples/src/merkle/mod.rs @@ -137,7 +137,13 @@ where let pub_inputs = PublicInputs { tree_root: self.tree_root.to_elements(), }; - winterfell::verify::>(proof, pub_inputs) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + winterfell::verify::>( + proof, + pub_inputs, + &acceptable_options, + ) } fn verify_with_wrong_inputs(&self, proof: StarkProof) -> Result<(), VerifierError> { @@ -145,7 +151,13 @@ where let pub_inputs = PublicInputs { tree_root: [tree_root[1], tree_root[0]], }; - winterfell::verify::>(proof, pub_inputs) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + winterfell::verify::>( + proof, + pub_inputs, + &acceptable_options, + ) } } diff --git a/examples/src/rescue/mod.rs b/examples/src/rescue/mod.rs index bf3391e4d..0663d67bd 100644 --- a/examples/src/rescue/mod.rs +++ b/examples/src/rescue/mod.rs @@ -126,7 +126,13 @@ where seed: self.seed, result: self.result, }; - winterfell::verify::>(proof, pub_inputs) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + winterfell::verify::>( + proof, + pub_inputs, + &acceptable_options, + ) } fn verify_with_wrong_inputs(&self, proof: StarkProof) -> Result<(), VerifierError> { @@ -134,7 +140,13 @@ where seed: self.seed, result: [self.result[0], self.result[1] + BaseElement::ONE], }; - winterfell::verify::>(proof, pub_inputs) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + winterfell::verify::>( + proof, + pub_inputs, + &acceptable_options, + ) } } diff --git a/examples/src/rescue_raps/mod.rs b/examples/src/rescue_raps/mod.rs index 5ad260699..8ba1809c6 100644 --- a/examples/src/rescue_raps/mod.rs +++ b/examples/src/rescue_raps/mod.rs @@ -138,14 +138,26 @@ where let pub_inputs = PublicInputs { result: self.result, }; - winterfell::verify::>(proof, pub_inputs) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + winterfell::verify::>( + proof, + pub_inputs, + &acceptable_options, + ) } fn verify_with_wrong_inputs(&self, proof: StarkProof) -> Result<(), VerifierError> { let pub_inputs = PublicInputs { result: [self.result[1], self.result[0]], }; - winterfell::verify::>(proof, pub_inputs) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + winterfell::verify::>( + proof, + pub_inputs, + &acceptable_options, + ) } } diff --git a/examples/src/vdf/exempt/mod.rs b/examples/src/vdf/exempt/mod.rs index bb6e7a096..03f22d5f3 100644 --- a/examples/src/vdf/exempt/mod.rs +++ b/examples/src/vdf/exempt/mod.rs @@ -118,7 +118,13 @@ where seed: self.seed, result: self.result, }; - winterfell::verify::>(proof, pub_inputs) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + winterfell::verify::>( + proof, + pub_inputs, + &acceptable_options, + ) } fn verify_with_wrong_inputs(&self, proof: StarkProof) -> Result<(), VerifierError> { @@ -126,7 +132,13 @@ where seed: self.seed, result: self.result + BaseElement::ONE, }; - winterfell::verify::>(proof, pub_inputs) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + winterfell::verify::>( + proof, + pub_inputs, + &acceptable_options, + ) } } diff --git a/examples/src/vdf/regular/mod.rs b/examples/src/vdf/regular/mod.rs index 3a303c2f3..e7bbf6105 100644 --- a/examples/src/vdf/regular/mod.rs +++ b/examples/src/vdf/regular/mod.rs @@ -115,7 +115,13 @@ where seed: self.seed, result: self.result, }; - winterfell::verify::>(proof, pub_inputs) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + winterfell::verify::>( + proof, + pub_inputs, + &acceptable_options, + ) } fn verify_with_wrong_inputs(&self, proof: StarkProof) -> Result<(), VerifierError> { @@ -123,7 +129,13 @@ where seed: self.seed, result: self.result + BaseElement::ONE, }; - winterfell::verify::>(proof, pub_inputs) + let acceptable_options = + winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); + winterfell::verify::>( + proof, + pub_inputs, + &acceptable_options, + ) } } diff --git a/verifier/src/errors.rs b/verifier/src/errors.rs index 45723723a..47850c13f 100644 --- a/verifier/src/errors.rs +++ b/verifier/src/errors.rs @@ -41,6 +41,17 @@ pub enum VerifierError { /// constraint evaluation queries do not represent a polynomial of the degree expected by the /// verifier. FriVerificationFailed(fri::VerifierError), + /// This error occurs when the parameters, that were used to generate the proof, do not provide + /// a conjectured security level greater than or equal to the conjectured security level + /// expected by the verifier. + InsufficientConjecturedSecurity(u32, u32), + /// This error occurs when the parameters, that were used to generate the proof, do not provide + /// a proven security level greater than or equal to the proven security level expected by + /// the verifier. + InsufficientProvenSecurity(u32, u32), + /// This error occurs when the parameters, that were used to generate the proof, do not match + /// any of the set of parameters expected by the verifier. + UnacceptableProofOptions, } impl fmt::Display for VerifierError { @@ -74,6 +85,13 @@ impl fmt::Display for VerifierError { Self::FriVerificationFailed(err) => { write!(f, "verification of low-degree proof failed: {err}") } + Self::InsufficientConjecturedSecurity(minimal_security, proof_security)=> { + write!(f, "insufficient proof security level: expected at least {minimal_security} bits of conjectured security, but was {proof_security} bits") + } + Self::InsufficientProvenSecurity(minimal_security, proof_security)=> { + write!(f, "insufficient proof security level: expected at least {minimal_security} bits of proven security, but was {proof_security} bits") + } + Self::UnacceptableProofOptions => {write!(f, "invalid proof options: security parameters do not match the acceptable parameter set")} } } } diff --git a/verifier/src/lib.rs b/verifier/src/lib.rs index 4dbee6ce2..3330f9dbb 100644 --- a/verifier/src/lib.rs +++ b/verifier/src/lib.rs @@ -46,11 +46,12 @@ use math::{ }; pub use utils::{ - ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, SliceReader, + collections::Vec, ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, + SliceReader, }; pub use crypto; -use crypto::{ElementHasher, RandomCoin}; +use crypto::{ElementHasher, Hasher, RandomCoin}; use fri::FriVerifier; @@ -70,25 +71,31 @@ pub use errors::VerifierError; // ================================================================================================ /// Verifies that the specified computation was executed correctly against the specified inputs. /// -/// Specifically, for a computation specified by `AIR` and `HashFn` type parameter, verifies that the provided -/// `proof` attests to the correct execution of the computation against public inputs specified -/// by `pub_inputs`. If the verification is successful, `Ok(())` is returned. +/// Specifically, for a computation specified by `AIR` and `HashFn` type parameter, verifies that +/// the provided `proof` attests to the correct execution of the computation against public inputs +/// specified by `pub_inputs`. If the verification is successful, `Ok(())` is returned. /// /// # Errors /// Returns an error if combination of the provided proof and public inputs does not attest to /// a correct execution of the computation. This could happen for many various reasons, including: /// - The specified proof was generated for a different computation. /// - The specified proof was generated for this computation but for different public inputs. +/// - The specified proof was generated with parameters not providing an acceptable security level. #[rustfmt::skip] pub fn verify( proof: StarkProof, pub_inputs: AIR::PublicInputs, + acceptable_options: &AcceptableOptions, ) -> Result<(), VerifierError> where AIR: Air, HashFn: ElementHasher, RandCoin: RandomCoin, { + // check that `proof` was generated with an acceptable set of parameters from the point of view + // of the verifier + let _ = acceptable_options.validate::(&proof); + // build a seed for the public coin; the initial seed is a hash of the proof context and the // public inputs, but as the protocol progresses, the coin will be reseeded with the info // received from the prover @@ -287,3 +294,47 @@ where .verify(&mut channel, &deep_evaluations, &query_positions) .map_err(VerifierError::FriVerificationFailed) } + +// ACCEPTABLE OPTIONS +// ================================================================================================ +// Specifies either the minimal, conjectured or proven, security level or a set of +// `ProofOptions` that are acceptable by the verification procedure. +pub enum AcceptableOptions { + /// Minimal acceptable conjectured security level + MinConjecturedSecurity(u32), + /// Minimal acceptable proven security level + MinProvenSecurity(u32), + /// Set of acceptable proof parameters + OptionSet(Vec), +} + +impl AcceptableOptions { + pub fn validate(&self, proof: &StarkProof) -> Result<(), VerifierError> { + match self { + AcceptableOptions::MinConjecturedSecurity(minimal_security) => { + let proof_security = proof.security_level::(true); + if proof_security < *minimal_security { + return Err(VerifierError::InsufficientConjecturedSecurity( + *minimal_security, + proof_security, + )); + } + } + AcceptableOptions::MinProvenSecurity(minimal_security) => { + let proof_security = proof.security_level::(false); + if proof_security < *minimal_security { + return Err(VerifierError::InsufficientProvenSecurity( + *minimal_security, + proof_security, + )); + } + } + AcceptableOptions::OptionSet(options) => { + if !options.iter().any(|opt| opt == proof.options()) { + return Err(VerifierError::UnacceptableProofOptions); + } + } + } + Ok(()) + } +} diff --git a/winterfell/src/lib.rs b/winterfell/src/lib.rs index 341fb7215..bc6b9ee42 100644 --- a/winterfell/src/lib.rs +++ b/winterfell/src/lib.rs @@ -527,10 +527,11 @@ //! // Verify the proof. The number of steps and options are encoded in the proof itself, //! // so we don't need to pass them explicitly to the verifier. //! let pub_inputs = PublicInputs { start, result }; +//! let acceptable_opt = winterfell::AcceptableOptions::OptionSet(vec![proof.options().clone()]); //! assert!(winterfell::verify::, //! DefaultRandomCoin> -//! >(proof, pub_inputs).is_ok()); +//! >(proof, pub_inputs, &acceptable_opt).is_ok()); //! ``` //! //! That's all there is to it! @@ -567,4 +568,4 @@ pub use prover::{ StarkProof, Trace, TraceInfo, TraceLayout, TraceLde, TraceTable, TraceTableFragment, TransitionConstraintDegree, }; -pub use verifier::{verify, VerifierError}; +pub use verifier::{verify, AcceptableOptions, VerifierError};