Skip to content

Commit

Permalink
bellman: add VerificationError (#254)
Browse files Browse the repository at this point in the history
* bellman: add VerificationError

This adds a distinct VerificationError type to the crate and changes
`verify_proof` to return `Result<(), VerificationError>` rather than
`Result<bool, SynthesisError>`.  This is significantly safer, because it avoids
the need to mix pattern-matching logic with boolean logic (the cause of
RUSTSEC-2019-0004).

* Rename VerificationError variants per review comments.

* Add missing Clone impl to VerificationError.
  • Loading branch information
hdevalence authored and str4d committed Aug 25, 2020
1 parent 701e6cf commit e534f36
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 19 deletions.
4 changes: 2 additions & 2 deletions src/groth16/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -560,8 +560,8 @@ mod test_with_bls12_381 {
let de_proof = Proof::read(&v[..]).unwrap();
assert!(proof == de_proof);

assert!(verify_proof(&pvk, &proof, &[c]).unwrap());
assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
assert!(verify_proof(&pvk, &proof, &[c]).is_ok());
assert!(verify_proof(&pvk, &proof, &[a]).is_err());
}
}
}
2 changes: 1 addition & 1 deletion src/groth16/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,5 +377,5 @@ fn test_xordemo() {
assert_eq!(expected_c, proof.c);
}

assert!(verify_proof(&pvk, &proof, &[Fr::one()]).unwrap());
assert!(verify_proof(&pvk, &proof, &[Fr::one()]).is_ok());
}
25 changes: 15 additions & 10 deletions src/groth16/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::ops::{AddAssign, Neg};

use super::{PreparedVerifyingKey, Proof, VerifyingKey};

use crate::SynthesisError;
use crate::VerificationError;

pub fn prepare_verifying_key<E: MultiMillerLoop>(vk: &VerifyingKey<E>) -> PreparedVerifyingKey<E> {
let gamma = vk.gamma_g2.neg();
Expand All @@ -22,9 +22,9 @@ pub fn verify_proof<'a, E: MultiMillerLoop>(
pvk: &'a PreparedVerifyingKey<E>,
proof: &Proof<E>,
public_inputs: &[E::Fr],
) -> Result<bool, SynthesisError> {
) -> Result<(), VerificationError> {
if (public_inputs.len() + 1) != pvk.ic.len() {
return Err(SynthesisError::MalformedVerifyingKey);
return Err(VerificationError::InvalidVerifyingKey);
}

let mut acc = pvk.ic[0].to_curve();
Expand All @@ -41,11 +41,16 @@ pub fn verify_proof<'a, E: MultiMillerLoop>(
// A * B + inputs * (-gamma) + C * (-delta) = alpha * beta
// which allows us to do a single final exponentiation.

Ok(E::multi_miller_loop(&[
(&proof.a, &proof.b.into()),
(&acc.to_affine(), &pvk.neg_gamma_g2),
(&proof.c, &pvk.neg_delta_g2),
])
.final_exponentiation()
== pvk.alpha_g1_beta_g2)
if pvk.alpha_g1_beta_g2
== E::multi_miller_loop(&[
(&proof.a, &proof.b.into()),
(&acc.to_affine(), &pvk.neg_gamma_g2),
(&proof.c, &pvk.neg_delta_g2),
])
.final_exponentiation()
{
Ok(())
} else {
Err(VerificationError::InvalidProof)
}
}
31 changes: 26 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@
//! let inputs = multipack::compute_multipacking(&hash_bits);
//!
//! // Check the proof!
//! assert!(groth16::verify_proof(&pvk, &proof, &inputs).unwrap());
//! assert!(groth16::verify_proof(&pvk, &proof, &inputs).is_ok());
//! ```
//!
//! # Roadmap
Expand Down Expand Up @@ -314,7 +314,7 @@ impl<'a, Scalar: PrimeField> Sub<(Scalar, &'a LinearCombination<Scalar>)>
}

/// This is an error that could occur during circuit synthesis contexts,
/// such as CRS generation, proving or verification.
/// such as CRS generation or proving.
#[derive(Debug)]
pub enum SynthesisError {
/// During synthesis, we lacked knowledge of a variable assignment.
Expand All @@ -329,8 +329,6 @@ pub enum SynthesisError {
UnexpectedIdentity,
/// During proof generation, we encountered an I/O error with the CRS
IoError(io::Error),
/// During verification, our verifying key was malformed.
MalformedVerifyingKey,
/// During CRS generation, we observed an unconstrained auxiliary variable
UnconstrainedVariable,
}
Expand All @@ -352,7 +350,6 @@ impl Error for SynthesisError {
SynthesisError::PolynomialDegreeTooLarge => "polynomial degree is too large",
SynthesisError::UnexpectedIdentity => "encountered an identity element in the CRS",
SynthesisError::IoError(_) => "encountered an I/O error",
SynthesisError::MalformedVerifyingKey => "malformed verifying key",
SynthesisError::UnconstrainedVariable => "auxiliary variable was unconstrained",
}
}
Expand All @@ -369,6 +366,30 @@ impl fmt::Display for SynthesisError {
}
}

/// An error during verification.
#[derive(Debug, Clone)]
pub enum VerificationError {
/// Verification was attempted with a malformed verifying key.
InvalidVerifyingKey,
/// Proof verification failed.
InvalidProof,
}

impl Error for VerificationError {
fn description(&self) -> &str {
match *self {
VerificationError::InvalidVerifyingKey => "malformed verifying key",
VerificationError::InvalidProof => "proof verification failed",
}
}
}

impl fmt::Display for VerificationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{}", self)
}
}

/// Represents a constraint system which can have new variables
/// allocated and constrains between them formed.
pub trait ConstraintSystem<Scalar: PrimeField>: Sized {
Expand Down
2 changes: 1 addition & 1 deletion tests/mimc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ fn test_mimc() {
let start = Instant::now();
let proof = Proof::read(&proof_vec[..]).unwrap();
// Check the proof
assert!(verify_proof(&pvk, &proof, &[image]).unwrap());
assert!(verify_proof(&pvk, &proof, &[image]).is_ok());
total_verifying += start.elapsed();
}
let proving_avg = total_proving / SAMPLES;
Expand Down

0 comments on commit e534f36

Please sign in to comment.