Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change Merkle verify asserts to Result Errs #251

Merged
merged 5 commits into from
Aug 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 24 additions & 9 deletions risc0/zkp/rust/src/verify/fri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::{
sha::Sha,
},
field::Elem,
verify::{merkle::MerkleTreeVerifier, read_iop::ReadIOP},
verify::{merkle::MerkleTreeVerifier, read_iop::ReadIOP, VerificationError},
FRI_FOLD, FRI_MIN_DEGREE, INV_RATE, QUERIES,
};

Expand Down Expand Up @@ -65,11 +65,16 @@ impl VerifyRoundInfo {
}
}

pub fn verify_query<S: Sha>(&mut self, iop: &mut ReadIOP<S>, pos: &mut usize, goal: &mut Fp4) {
pub fn verify_query<S: Sha>(
&mut self,
iop: &mut ReadIOP<S>,
pos: &mut usize,
goal: &mut Fp4,
) -> Result<(), VerificationError> {
let quot = *pos / self.domain;
let group = *pos % self.domain;
// Get the column data
let data = self.merkle.verify(iop, group);
let data = self.merkle.verify(iop, group)?;
let mut data4 = vec![];
for i in 0..FRI_FOLD {
data4.push(Fp4::new(
Expand All @@ -80,16 +85,23 @@ impl VerifyRoundInfo {
));
}
// Check the existing goal
assert_eq!(data4[quot], *goal);
if data4[quot] != *goal {
return Err(VerificationError::InvalidProof);
}
// Compute the new goal + pos
*goal = fold_eval(&mut data4, self.mix, self.domain, group);
*pos = group;
Ok(())
}
}

pub fn fri_verify<S: Sha, F>(iop: &mut ReadIOP<S>, mut degree: usize, mut inner: F)
pub fn fri_verify<S: Sha, F>(
iop: &mut ReadIOP<S>,
mut degree: usize,
mut inner: F,
) -> Result<(), VerificationError>
where
F: FnMut(&mut ReadIOP<S>, usize) -> Fp4,
F: FnMut(&mut ReadIOP<S>, usize) -> Result<Fp4, VerificationError>,
{
let orig_domain = INV_RATE * degree;
let mut domain = orig_domain;
Expand All @@ -112,10 +124,10 @@ where
let rng = iop.next_u32();
let mut pos = rng as usize % orig_domain;
// Do the 'inner' verification for this index
let mut goal = inner(iop, pos);
let mut goal = inner(iop, pos)?;
// Verify the per-round proofs
for round in &mut rounds {
round.verify_query(iop, &mut pos, &mut goal);
round.verify_query(iop, &mut pos, &mut goal)?;
}
// Do final verification
let x = gen.pow(pos);
Expand All @@ -131,6 +143,9 @@ where
fx += cur * coeff;
cur *= x;
}
assert_eq!(fx, goal)
if fx != goal {
return Err(VerificationError::InvalidProof);
}
}
Ok(())
}
21 changes: 17 additions & 4 deletions risc0/zkp/rust/src/verify/merkle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use crate::{
field::Elem,
merkle::MerkleTreeParams,
verify::read_iop::ReadIOP,
verify::VerificationError,
};

/// A struct against which we verify merkle branches, consisting of the
Expand Down Expand Up @@ -63,8 +64,17 @@ impl MerkleTreeVerifier {
}

/// Verifies a branch provided by an IOP.
pub fn verify<S: Sha>(&self, iop: &mut ReadIOP<S>, mut idx: usize) -> Vec<Fp> {
assert!(idx < self.params.row_size);
pub fn verify<S: Sha>(
&self,
iop: &mut ReadIOP<S>,
mut idx: usize,
) -> Result<Vec<Fp>, VerificationError> {
if idx >= self.params.row_size {
return Err(VerificationError::MerkleQueryOutOfRange {
idx: idx,
rows: self.params.row_size,
});
}
// Initialize a vector to hold field elements.
let mut out = vec![Fp::ZERO; self.params.col_size];
// Read out field elements from IOP.
Expand All @@ -90,7 +100,10 @@ impl MerkleTreeVerifier {
}
// Once we reduce to an index for which we have the hash, check that it's
// correct.
assert_eq!(self.top[idx], cur);
out
if self.top[idx] == cur {
Ok(out)
} else {
Err(VerificationError::InvalidProof)
}
}
}
76 changes: 45 additions & 31 deletions risc0/zkp/rust/src/verify/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,21 @@ const CHECK_SIZE: usize = INV_RATE * EXT_SIZE;
pub enum VerificationError {
ReceiptFormatError,
MethodVerificationError,
MerkleQueryOutOfRange { idx: usize, rows: usize },
InvalidProof,
}

impl fmt::Display for VerificationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
VerificationError::ReceiptFormatError => write!(f, "invalid receipt format"),
VerificationError::MethodVerificationError => write!(f, "method verification failed"),
VerificationError::MerkleQueryOutOfRange { idx, rows } => write!(
f,
"Requested Merkle validation on row {}, but only {} rows exist",
idx, rows
),
VerificationError::InvalidProof => write!(f, "Verification indicates proof is invalid"),
}
}
}
Expand Down Expand Up @@ -153,7 +161,9 @@ where
}
check *= (Fp4::from_u32(3) * z).pow(size) - Fp4::ONE;
// debug!("Check = {check:?}");
assert_eq!(check, result);
if check != result {
return Err(VerificationError::InvalidProof);
}

// Set the mix mix value
let mix = Fp4::random(&mut iop);
Expand Down Expand Up @@ -185,37 +195,41 @@ where

let gen = Fp::new(ROU_FWD[log2_ceil(domain)]);
// debug!("FRI-verify, size = {size}");
fri_verify(&mut iop, size, |iop: &mut ReadIOP<S>, idx: usize| -> Fp4 {
let x = Fp4::from_fp(gen.pow(idx));
let mut rows = vec![];
rows.push(accum_merkle.verify(iop, idx));
rows.push(code_merkle.verify(iop, idx));
rows.push(data_merkle.verify(iop, idx));
let check_row = check_merkle.verify(iop, idx);
let mut cur = Fp4::ONE;
let mut tot = vec![Fp4::ZERO; combo_count + 1];
for reg in taps.regs() {
tot[reg.combo_id()] += cur * rows[reg.group() as usize][reg.offset()];
cur *= mix;
}
for i in 0..CHECK_SIZE {
tot[combo_count] += cur * check_row[i];
cur *= mix;
}
let mut ret = Fp4::ZERO;
for i in 0..combo_count {
let num = tot[i] - poly_eval(&combo_u[i], x);
let mut divisor = Fp4::ONE;
for back in taps.get_combo(i).slice() {
divisor *= x - z * back_one.pow(*back as usize);
fri_verify(
&mut iop,
size,
|iop: &mut ReadIOP<S>, idx: usize| -> Result<Fp4, VerificationError> {
let x = Fp4::from_fp(gen.pow(idx));
let mut rows = vec![];
rows.push(accum_merkle.verify(iop, idx)?);
rows.push(code_merkle.verify(iop, idx)?);
rows.push(data_merkle.verify(iop, idx)?);
let check_row = check_merkle.verify(iop, idx)?;
let mut cur = Fp4::ONE;
let mut tot = vec![Fp4::ZERO; combo_count + 1];
for reg in taps.regs() {
tot[reg.combo_id()] += cur * rows[reg.group() as usize][reg.offset()];
cur *= mix;
}
ret += num * divisor.inv();
}
let check_num = tot[combo_count] - combo_u[combo_count][0];
let check_div = x - z.pow(INV_RATE);
ret += check_num * check_div.inv();
ret
});
for i in 0..CHECK_SIZE {
tot[combo_count] += cur * check_row[i];
cur *= mix;
}
let mut ret = Fp4::ZERO;
for i in 0..combo_count {
let num = tot[i] - poly_eval(&combo_u[i], x);
let mut divisor = Fp4::ONE;
for back in taps.get_combo(i).slice() {
divisor *= x - z * back_one.pow(*back as usize);
}
ret += num * divisor.inv();
}
let check_num = tot[combo_count] - combo_u[combo_count][0];
let check_div = x - z.pow(INV_RATE);
ret += check_num * check_div.inv();
Ok(ret)
},
)?;
iop.verify_complete();
Ok(())
}