From f664654355581ea2ca9f4f067e8da41f40459d47 Mon Sep 17 00:00:00 2001 From: Thorkil Vaerge Date: Mon, 18 Mar 2024 15:42:16 +0100 Subject: [PATCH] dequeue, hash and verify quotient segments Co-authored-by: Alan Szepieniec --- src/libraries/recufy.rs | 11 +++ .../ozk/programs/recufier/fri_verify.rs | 91 ++++++++++++------- .../ozk/programs/recufier/verify.rs | 41 ++++++++- 3 files changed, 106 insertions(+), 37 deletions(-) diff --git a/src/libraries/recufy.rs b/src/libraries/recufy.rs index 080aa60d..b77467e9 100644 --- a/src/libraries/recufy.rs +++ b/src/libraries/recufy.rs @@ -4,6 +4,7 @@ use syn::parse_quote; use syn::PathArguments; use tasm_lib::triton_vm::table::NUM_BASE_COLUMNS; use tasm_lib::triton_vm::table::NUM_EXT_COLUMNS; +use tasm_lib::triton_vm::table::NUM_QUOTIENT_SEGMENTS; use crate::ast; use crate::ast_types; @@ -20,6 +21,7 @@ use super::Library; const BASE_ROW_TYPE_NAME: &str = "BaseRow"; const EXT_ROW_TYPE_NAME: &str = "ExtensionRow"; +const QUOT_SEGMENTS_TYPE_NAME: &str = "QuotientSegments"; #[derive(Debug)] pub(crate) struct RecufyLib; @@ -35,6 +37,7 @@ impl Library for RecufyLib { VM_PROOF_ITER_TYPE_NAME => Some(graft_vm_proof_iter(graft)), BASE_ROW_TYPE_NAME => Some(Self::graft_base_row(path_args, graft)), EXT_ROW_TYPE_NAME => Some(Self::graft_ext_row(path_args)), + QUOT_SEGMENTS_TYPE_NAME => Some(Self::graft_quot_segments(path_args)), _ => None, } } @@ -135,6 +138,14 @@ impl RecufyLib { }) } + fn graft_quot_segments(arguments: &PathArguments) -> ast_types::DataType { + assert!(matches!(arguments, PathArguments::None)); + ast_types::DataType::Array(ast_types::ArrayType { + element_type: Box::new(ast_types::DataType::Xfe), + length: NUM_QUOTIENT_SEGMENTS, + }) + } + fn graft_base_row(arguments: &PathArguments, graft: &mut Graft) -> ast_types::DataType { match arguments { syn::PathArguments::AngleBracketed(ab) => { diff --git a/src/tests_and_benchmarks/ozk/programs/recufier/fri_verify.rs b/src/tests_and_benchmarks/ozk/programs/recufier/fri_verify.rs index 520caf8a..f96a6cfe 100644 --- a/src/tests_and_benchmarks/ozk/programs/recufier/fri_verify.rs +++ b/src/tests_and_benchmarks/ozk/programs/recufier/fri_verify.rs @@ -105,7 +105,7 @@ pub(crate) mod test { pub(crate) fri_proof_stream: StarkProofStream, pub(crate) base_tree_authentication_paths: Vec>, pub(crate) ext_tree_authentication_paths: Vec>, - // quot_tree_authentication_paths: Vec>, + pub(crate) quot_tree_authentication_paths: Vec>, } /// Extracts a proof stream that will work for FRI verification from a proof stream that works for @@ -124,7 +124,7 @@ pub(crate) mod test { proof_stream.alter_fiat_shamir_state_with(claim); // Base-table Merkle root - proof_stream + let base_table_root = proof_stream .dequeue() .unwrap() .try_into_merkle_root() @@ -144,7 +144,7 @@ pub(crate) mod test { proof_stream.sample_scalars(MasterExtTable::NUM_CONSTRAINTS); // Quotient codeword Merkle root - proof_stream + let quotient_root = proof_stream .dequeue() .unwrap() .try_into_merkle_root() @@ -191,68 +191,89 @@ pub(crate) mod test { let fri: triton_vm::fri::Fri = stark.derive_fri(padded_height).unwrap(); let fri_proof_stream = proof_stream.clone(); let fri_verify_result = fri.verify(&mut proof_stream, &mut None).unwrap(); + let indices = fri_verify_result.iter().map(|(i, _)| *i).collect_vec(); + let tree_height = fri.domain.length.ilog2() as usize; + // base let base_table_rows = proof_stream .dequeue() .unwrap() .try_into_master_base_table_rows() .unwrap(); - let base_table_leaf_digests = base_table_rows.iter().map(|x| Tip5::hash_varlen(x)); let base_authentication_structure = proof_stream .dequeue() .unwrap() .try_into_authentication_structure() .unwrap(); - let fri_indexed_base_leaves = fri_verify_result - .iter() - .map(|(index, _)| *index) - .zip(base_table_leaf_digests) - .collect_vec(); - let tree_height = fri.domain.length.ilog2() as usize; - let base_tree_inclusion_proof = MerkleTreeInclusionProof:: { + let base_tree_auth_paths = extract_paths( + base_table_root, + &indices, + &base_table_rows, + &base_authentication_structure, tree_height, - indexed_leaves: fri_indexed_base_leaves, - authentication_structure: base_authentication_structure, - _hasher: std::marker::PhantomData, - }; - let base_tree_auth_paths = base_tree_inclusion_proof.into_authentication_paths(); - if let Err(err) = base_tree_auth_paths { - println!("base_tree_auth_paths: {}", err); - } - let base_tree_auth_paths = base_tree_auth_paths.unwrap(); + ); + // extension let ext_table_rows = proof_stream .dequeue() .unwrap() .try_into_master_ext_table_rows() .unwrap(); - let ext_table_leaf_digests = ext_table_rows.iter().map(Tip5::hash).collect_vec(); let ext_authentication_structure = proof_stream .dequeue() .unwrap() .try_into_authentication_structure() .unwrap(); - let fri_indexed_ext_leafs = fri_verify_result - .iter() - .map(|(index, _)| *index) - .zip(ext_table_leaf_digests) - .collect_vec(); - let ext_tree_inclusion_proof = MerkleTreeInclusionProof:: { + let ext_tree_auth_paths = extract_paths( + ext_mt_root, + &indices, + &ext_table_rows, + &ext_authentication_structure, tree_height, - indexed_leaves: fri_indexed_ext_leafs, - authentication_structure: ext_authentication_structure, - _hasher: std::marker::PhantomData, - }; - assert!(ext_tree_inclusion_proof.clone().verify(ext_mt_root)); - let ext_tree_auth_paths = ext_tree_inclusion_proof - .into_authentication_paths() + ); + + // quotient + let quot_table_rows = proof_stream + .dequeue() + .unwrap() + .try_into_quot_segments_elements() + .unwrap(); + let quot_authentication_structure = proof_stream + .dequeue() + .unwrap() + .try_into_authentication_structure() .unwrap(); + let quot_tree_auth_paths = extract_paths( + quotient_root, + &indices, + "_table_rows, + "_authentication_structure, + tree_height, + ); StarkProofExtraction { fri_proof_stream, base_tree_authentication_paths: base_tree_auth_paths, ext_tree_authentication_paths: ext_tree_auth_paths, - // quot_tree_authentication_paths: todo!(), + quot_tree_authentication_paths: quot_tree_auth_paths, } } + + fn extract_paths( + root: Digest, + indices: &[usize], + rows: &[[T; N]], + authentication_structure: &[Digest], + tree_height: usize, + ) -> Vec> { + let leafs = rows.iter().map(Tip5::hash).collect_vec(); + let inclusion_proof = MerkleTreeInclusionProof:: { + tree_height, + indexed_leaves: indices.iter().cloned().zip(leafs).collect_vec(), + authentication_structure: authentication_structure.to_vec(), + _hasher: std::marker::PhantomData, + }; + assert!(inclusion_proof.clone().verify(root)); + inclusion_proof.into_authentication_paths().unwrap() + } } diff --git a/src/tests_and_benchmarks/ozk/programs/recufier/verify.rs b/src/tests_and_benchmarks/ozk/programs/recufier/verify.rs index d33928fd..23377bd9 100644 --- a/src/tests_and_benchmarks/ozk/programs/recufier/verify.rs +++ b/src/tests_and_benchmarks/ozk/programs/recufier/verify.rs @@ -5,6 +5,7 @@ use serde_derive::Serialize; use tasm_lib::triton_vm::table::extension_table::Quotientable; use tasm_lib::triton_vm::table::master_table::MasterExtTable; use tasm_lib::triton_vm::table::ExtensionRow; +use tasm_lib::triton_vm::table::QuotientSegments; use crate::tests_and_benchmarks::ozk::rust_shadows as tasm; use crate::tests_and_benchmarks::ozk::rust_shadows::Tip5WithState; @@ -344,9 +345,9 @@ fn recufy() { .unwrap(); // println!("quot_codeword_weights: {quot_codeword_weights:?}"); RecufyDebug::dump_xfes("_codeword_weights.to_vec()); - let quotient_codeword_merkle_root: Box = proof_iter.next_as_merkleroot(); + let quotient_tree_merkle_root: Box = proof_iter.next_as_merkleroot(); // println!("quotient_codeword_merkle_root: {quotient_codeword_merkle_root:?}"); - RecufyDebug::dump_digest(*quotient_codeword_merkle_root); + RecufyDebug::dump_digest(*quotient_tree_merkle_root); let trace_domain_generator: BFieldElement = ArithmeticDomain::generator_for_length(padded_height as u64); @@ -535,6 +536,37 @@ fn recufy() { } } + // dequeue quotient segments + let quotient_segment_elements: Box> = + proof_iter.next_as_quotientsegmentselements(); + + // hash rows + let mut leaf_digests_quot: Vec = Vec::::default(); + { + let mut i: usize = 0; + while i < 2 * fri.num_colinearity_checks as usize { + leaf_digests_quot.push(tasm::tasm_hashing_algebraic_hasher_hash_varlen( + "ient_segment_elements[i], + 4 * 3, + )); + i += 1; + } + } + + // Merkle verify (quotient tree) + { + let mut i: usize = 0; + while i < 2 * fri.num_colinearity_checks as usize { + tasm::tasm_hashing_merkle_verify( + *quotient_tree_merkle_root, + revealed_fri_indices_and_elements[i].0, + leaf_digests_quot[i], + merkle_tree_height, + ); + i += 1; + } + } + // Ensure that sponge-states are in sync RecufyDebug::sponge_state(Tip5WithState::squeeze()); return; @@ -619,6 +651,11 @@ mod tests { .into_iter() .flatten() .collect_vec(), + proof_extraction + .quot_tree_authentication_paths + .into_iter() + .flatten() + .collect_vec(), ] .concat(); NonDeterminism::default()