diff --git a/tasm-lib/benchmarks/tasmlib_verifier_fri_verify.json b/tasm-lib/benchmarks/tasmlib_verifier_fri_verify.json index e3cb22aa..1ab5a531 100644 --- a/tasm-lib/benchmarks/tasmlib_verifier_fri_verify.json +++ b/tasm-lib/benchmarks/tasmlib_verifier_fri_verify.json @@ -2,22 +2,22 @@ { "name": "tasmlib_verifier_fri_verify", "benchmark_result": { - "clock_cycle_count": 44905, - "hash_table_height": 14646, - "u32_table_height": 17928, - "op_stack_table_height": 42893, - "ram_table_height": 17534 + "clock_cycle_count": 45087, + "hash_table_height": 14784, + "u32_table_height": 17958, + "op_stack_table_height": 43009, + "ram_table_height": 17567 }, "case": "CommonCase" }, { "name": "tasmlib_verifier_fri_verify", "benchmark_result": { - "clock_cycle_count": 44905, - "hash_table_height": 14646, - "u32_table_height": 17324, - "op_stack_table_height": 42893, - "ram_table_height": 17534 + "clock_cycle_count": 45087, + "hash_table_height": 14784, + "u32_table_height": 17354, + "op_stack_table_height": 43009, + "ram_table_height": 17567 }, "case": "WorstCase" } diff --git a/tasm-lib/benchmarks/tasmlib_verifier_stark_verify_dynamic_inner_padded_height_256_fri_exp_4.json b/tasm-lib/benchmarks/tasmlib_verifier_stark_verify_dynamic_inner_padded_height_256_fri_exp_4.json index 75cbbf94..972979ca 100644 --- a/tasm-lib/benchmarks/tasmlib_verifier_stark_verify_dynamic_inner_padded_height_256_fri_exp_4.json +++ b/tasm-lib/benchmarks/tasmlib_verifier_stark_verify_dynamic_inner_padded_height_256_fri_exp_4.json @@ -2,11 +2,11 @@ { "name": "tasmlib_verifier_stark_verify_dynamic_inner_padded_height_256_fri_exp_4", "benchmark_result": { - "clock_cycle_count": 194859, - "hash_table_height": 142849, - "u32_table_height": 25541, - "op_stack_table_height": 176992, - "ram_table_height": 289182 + "clock_cycle_count": 195215, + "hash_table_height": 143125, + "u32_table_height": 26065, + "op_stack_table_height": 177172, + "ram_table_height": 289262 }, "case": "CommonCase" } diff --git a/tasm-lib/benchmarks/tasmlib_verifier_stark_verify_dynamic_inner_padded_height_512_fri_exp_4.json b/tasm-lib/benchmarks/tasmlib_verifier_stark_verify_dynamic_inner_padded_height_512_fri_exp_4.json index 70614160..ce0ec938 100644 --- a/tasm-lib/benchmarks/tasmlib_verifier_stark_verify_dynamic_inner_padded_height_512_fri_exp_4.json +++ b/tasm-lib/benchmarks/tasmlib_verifier_stark_verify_dynamic_inner_padded_height_512_fri_exp_4.json @@ -2,11 +2,11 @@ { "name": "tasmlib_verifier_stark_verify_dynamic_inner_padded_height_512_fri_exp_4", "benchmark_result": { - "clock_cycle_count": 202884, - "hash_table_height": 150541, - "u32_table_height": 34793, - "op_stack_table_height": 182148, - "ram_table_height": 290360 + "clock_cycle_count": 203285, + "hash_table_height": 150817, + "u32_table_height": 33925, + "op_stack_table_height": 182354, + "ram_table_height": 290449 }, "case": "CommonCase" } diff --git a/tasm-lib/benchmarks/tasmlib_verifier_stark_verify_static_inner_padded_height_256_fri_exp_4.json b/tasm-lib/benchmarks/tasmlib_verifier_stark_verify_static_inner_padded_height_256_fri_exp_4.json index 35b07d96..3743db8c 100644 --- a/tasm-lib/benchmarks/tasmlib_verifier_stark_verify_static_inner_padded_height_256_fri_exp_4.json +++ b/tasm-lib/benchmarks/tasmlib_verifier_stark_verify_static_inner_padded_height_256_fri_exp_4.json @@ -2,11 +2,11 @@ { "name": "tasmlib_verifier_stark_verify_static_inner_padded_height_256_fri_exp_4", "benchmark_result": { - "clock_cycle_count": 183156, - "hash_table_height": 128803, - "u32_table_height": 25891, - "op_stack_table_height": 169186, - "ram_table_height": 285283 + "clock_cycle_count": 183512, + "hash_table_height": 129085, + "u32_table_height": 25825, + "op_stack_table_height": 169366, + "ram_table_height": 285363 }, "case": "CommonCase" } diff --git a/tasm-lib/benchmarks/tasmlib_verifier_stark_verify_static_inner_padded_height_512_fri_exp_4.json b/tasm-lib/benchmarks/tasmlib_verifier_stark_verify_static_inner_padded_height_512_fri_exp_4.json index 90bdd1c4..d1b5a3cb 100644 --- a/tasm-lib/benchmarks/tasmlib_verifier_stark_verify_static_inner_padded_height_512_fri_exp_4.json +++ b/tasm-lib/benchmarks/tasmlib_verifier_stark_verify_static_inner_padded_height_512_fri_exp_4.json @@ -2,11 +2,11 @@ { "name": "tasmlib_verifier_stark_verify_static_inner_padded_height_512_fri_exp_4", "benchmark_result": { - "clock_cycle_count": 191181, - "hash_table_height": 136495, - "u32_table_height": 34185, - "op_stack_table_height": 174342, - "ram_table_height": 286461 + "clock_cycle_count": 191582, + "hash_table_height": 136777, + "u32_table_height": 34566, + "op_stack_table_height": 174548, + "ram_table_height": 286550 }, "case": "CommonCase" } diff --git a/tasm-lib/benchmarks/tasmlib_verifier_vm_proof_iter_drop.json b/tasm-lib/benchmarks/tasmlib_verifier_vm_proof_iter_drop.json new file mode 100644 index 00000000..47117721 --- /dev/null +++ b/tasm-lib/benchmarks/tasmlib_verifier_vm_proof_iter_drop.json @@ -0,0 +1,24 @@ +[ + { + "name": "tasmlib_verifier_vm_proof_iter_drop", + "benchmark_result": { + "clock_cycle_count": 13, + "hash_table_height": 12, + "u32_table_height": 0, + "op_stack_table_height": 11, + "ram_table_height": 5 + }, + "case": "CommonCase" + }, + { + "name": "tasmlib_verifier_vm_proof_iter_drop", + "benchmark_result": { + "clock_cycle_count": 13, + "hash_table_height": 12, + "u32_table_height": 0, + "op_stack_table_height": 11, + "ram_table_height": 5 + }, + "case": "WorstCase" + } +] \ No newline at end of file diff --git a/tasm-lib/src/neptune/neptune_like_types_for_tests.rs b/tasm-lib/src/neptune/neptune_like_types_for_tests.rs index c5529bf6..a1d3bb06 100644 --- a/tasm-lib/src/neptune/neptune_like_types_for_tests.rs +++ b/tasm-lib/src/neptune/neptune_like_types_for_tests.rs @@ -4,15 +4,16 @@ use twenty_first::prelude::MmrMembershipProof; use twenty_first::util_types::mmr::mmr_accumulator::MmrAccumulator; use crate::prelude::TasmObject; +use crate::verifier::proof_for_nd_memory::ProofForNdMemory; #[derive(Debug, Clone, TasmObject, BFieldCodec, Arbitrary)] pub(crate) struct ProofCollectionLookalike { - pub removal_records_integrity: Proof, - pub collect_lock_scripts: Proof, - pub lock_scripts_halt: Vec, - pub kernel_to_outputs: Proof, - pub collect_type_scripts: Proof, - pub type_scripts_halt: Vec, + pub removal_records_integrity: ProofForNdMemory, + pub collect_lock_scripts: ProofForNdMemory, + pub lock_scripts_halt: Vec, + pub kernel_to_outputs: ProofForNdMemory, + pub collect_type_scripts: ProofForNdMemory, + pub type_scripts_halt: Vec, pub lock_script_hashes: Vec, pub type_script_hashes: Vec, pub kernel_mast_hash: Digest, @@ -115,8 +116,8 @@ pub(crate) struct MergeWitnessLookalike { left_kernel: TransactionKernelLookalike, right_kernel: TransactionKernelLookalike, new_kernel: TransactionKernelLookalike, - left_proof: Proof, - right_proof: Proof, + left_proof: ProofForNdMemory, + right_proof: ProofForNdMemory, } #[derive(Debug, Clone, TasmObject, BFieldCodec, Arbitrary)] @@ -153,7 +154,7 @@ pub(crate) struct UpdateWitnessLookalike { new_kernel: TransactionKernelLookalike, old_kernel_mast_hash: Digest, new_kernel_mast_hash: Digest, - old_proof: Proof, + old_proof: ProofForNdMemory, new_swbfi_bagged: Digest, new_aocl: MmrAccumulator, new_swbfa_hash: Digest, diff --git a/tasm-lib/src/structure/auto_generated_tasm_object_implementations.rs b/tasm-lib/src/structure/auto_generated_tasm_object_implementations.rs index abb93d9c..81973c77 100644 --- a/tasm-lib/src/structure/auto_generated_tasm_object_implementations.rs +++ b/tasm-lib/src/structure/auto_generated_tasm_object_implementations.rs @@ -1,5 +1,4 @@ pub mod claim; -pub mod fri_response; pub mod mmr_accumulator; pub mod mmr_membership_proof; pub mod mmr_successor_proof; diff --git a/tasm-lib/src/structure/auto_generated_tasm_object_implementations/fri_response.rs b/tasm-lib/src/structure/auto_generated_tasm_object_implementations/fri_response.rs deleted file mode 100644 index d67e7596..00000000 --- a/tasm-lib/src/structure/auto_generated_tasm_object_implementations/fri_response.rs +++ /dev/null @@ -1,803 +0,0 @@ -use triton_vm::fri::AuthenticationStructure; -use triton_vm::prelude::*; -use triton_vm::proof_item::FriResponse; - -impl crate::tasm_lib::structure::tasm_object::TasmObject for FriResponse { - fn label_friendly_name() -> String { - "FriResponse".to_owned() - } - fn get_field(field_name: &str) -> Vec { - let field_getter = match field_name { - "revealed_leaves" => { - let current = { - if let Some(size) = as crate::twenty_first::math::bfield_codec::BFieldCodec>::static_length() { - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push( - crate::BFieldElement::new(size as u64), - ), - ), - ] - .to_vec() - } else { - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::ReadMem( - crate::triton_vm::isa::op_stack::NumberOfWords::N1, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push( - crate::triton_vm::prelude::BFieldElement::new( - Self::MAX_OFFSET.into(), - ), - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Dup( - crate::triton_vm::isa::op_stack::OpStackElement::ST2, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Lt, - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Assert, - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::AddI( - crate::BFieldElement::new(1u64), - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Swap( - crate::triton_vm::isa::op_stack::OpStackElement::ST1, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::AddI( - crate::BFieldElement::new(1u64), - ), - ), - ] - .to_vec() - } - }; - let getter = { - if as crate::twenty_first::math::bfield_codec::BFieldCodec>::static_length() - .is_some() - { - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Pop( - crate::triton_vm::isa::op_stack::NumberOfWords::N1, - ), - ), - ] - .to_vec() - } else { - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Pop( - crate::triton_vm::isa::op_stack::NumberOfWords::N1, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push( - crate::BFieldElement::new(1u64), - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Add, - ), - ] - .to_vec() - } - }; - [current, getter].concat() - } - "auth_structure" => { - let current = { - [ - Self::get_field_start_with_jump_distance("revealed_leaves"), - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Add, - ), - ] - .to_vec(), - { - if let Some(size) = ::static_length() { - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push( - crate::BFieldElement::new(size as u64), - ), - ), - ] - .to_vec() - } else { - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::ReadMem( - crate::triton_vm::isa::op_stack::NumberOfWords::N1, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push( - crate::triton_vm::prelude::BFieldElement::new( - Self::MAX_OFFSET.into(), - ), - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Dup( - crate::triton_vm::isa::op_stack::OpStackElement::ST2, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Lt, - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Assert, - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::AddI( - crate::BFieldElement::new(1u64), - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Swap( - crate::triton_vm::isa::op_stack::OpStackElement::ST1, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::AddI( - crate::BFieldElement::new(1u64), - ), - ), - ] - .to_vec() - } - }, - ] - .concat() - }; - let getter = { - if ::static_length() - .is_some() - { - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Pop( - crate::triton_vm::isa::op_stack::NumberOfWords::N1, - ), - ), - ] - .to_vec() - } else { - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Pop( - crate::triton_vm::isa::op_stack::NumberOfWords::N1, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push( - crate::BFieldElement::new(1u64), - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Add, - ), - ] - .to_vec() - } - }; - [current, getter].concat() - } - unknown_field_name => { - panic!("Cannot match on field name `{0}`.", unknown_field_name,); - } - }; - let hint_appendix = [ - crate::triton_vm::isa::instruction::LabelledInstruction::TypeHint( - crate::triton_vm::isa::instruction::TypeHint { - starting_index: 0, - length: 1, - type_name: std::option::Option::::None, - variable_name: std::string::String::from(field_name), - }, - ), - ] - .to_vec(); - [field_getter, hint_appendix].concat() - } - fn get_field_with_size( - field_name: &str, - ) -> Vec { - let field_getter = match field_name { - "revealed_leaves" => { - let current = { - if let Some(size) = as crate::twenty_first::math::bfield_codec::BFieldCodec>::static_length() { - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push( - crate::BFieldElement::new(size as u64), - ), - ), - ] - .to_vec() - } else { - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::ReadMem( - crate::triton_vm::isa::op_stack::NumberOfWords::N1, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push( - crate::triton_vm::prelude::BFieldElement::new( - Self::MAX_OFFSET.into(), - ), - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Dup( - crate::triton_vm::isa::op_stack::OpStackElement::ST2, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Lt, - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Assert, - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::AddI( - crate::BFieldElement::new(1u64), - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Swap( - crate::triton_vm::isa::op_stack::OpStackElement::ST1, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::AddI( - crate::BFieldElement::new(1u64), - ), - ), - ] - .to_vec() - } - }; - let getter_sizer = { - if as crate::twenty_first::math::bfield_codec::BFieldCodec>::static_length() - .is_some() - { - ::std::vec::Vec::< - crate::triton_vm::isa::instruction::LabelledInstruction, - >::new() - } else { - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push( - -crate::BFieldElement::new(1u64), - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Add, - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Swap( - crate::triton_vm::isa::op_stack::OpStackElement::ST1, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push( - crate::BFieldElement::new(1u64), - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Add, - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Swap( - crate::triton_vm::isa::op_stack::OpStackElement::ST1, - ), - ), - ] - .to_vec() - } - }; - [current, getter_sizer].concat() - } - "auth_structure" => { - let current = { - [ - Self::get_field_start_with_jump_distance("revealed_leaves"), - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Add, - ), - ] - .to_vec(), - { - if let Some(size) = ::static_length() { - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push( - crate::BFieldElement::new(size as u64), - ), - ), - ] - .to_vec() - } else { - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::ReadMem( - crate::triton_vm::isa::op_stack::NumberOfWords::N1, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push( - crate::triton_vm::prelude::BFieldElement::new( - Self::MAX_OFFSET.into(), - ), - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Dup( - crate::triton_vm::isa::op_stack::OpStackElement::ST2, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Lt, - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Assert, - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::AddI( - crate::BFieldElement::new(1u64), - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Swap( - crate::triton_vm::isa::op_stack::OpStackElement::ST1, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::AddI( - crate::BFieldElement::new(1u64), - ), - ), - ] - .to_vec() - } - }, - ] - .concat() - }; - let getter_sizer = { - if ::static_length() - .is_some() - { - ::std::vec::Vec::< - crate::triton_vm::isa::instruction::LabelledInstruction, - >::new() - } else { - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push( - -crate::BFieldElement::new(1u64), - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Add, - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Swap( - crate::triton_vm::isa::op_stack::OpStackElement::ST1, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push( - crate::BFieldElement::new(1u64), - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Add, - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Swap( - crate::triton_vm::isa::op_stack::OpStackElement::ST1, - ), - ), - ] - .to_vec() - } - }; - [current, getter_sizer].concat() - } - unknown_field_name => { - panic!("Cannot match on field name `{0}`.", unknown_field_name,); - } - }; - let hint_appendix = [ - crate::triton_vm::isa::instruction::LabelledInstruction::TypeHint( - crate::triton_vm::isa::instruction::TypeHint { - starting_index: 0, - length: 1, - type_name: std::option::Option::::Some( - std::string::String::from("u32"), - ), - variable_name: std::string::String::from("size"), - }, - ), - crate::triton_vm::isa::instruction::LabelledInstruction::TypeHint( - crate::triton_vm::isa::instruction::TypeHint { - starting_index: 1, - length: 1, - type_name: std::option::Option::::None, - variable_name: std::string::String::from(field_name), - }, - ), - ] - .to_vec(); - [field_getter, hint_appendix].concat() - } - fn get_field_start_with_jump_distance( - field_name: &str, - ) -> Vec { - match field_name { - "revealed_leaves" => { - if let Some(size) = as crate::twenty_first::math::bfield_codec::BFieldCodec>::static_length() { - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push( - crate::BFieldElement::new(size as u64), - ), - ), - ] - .to_vec() - } else { - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::ReadMem( - crate::triton_vm::isa::op_stack::NumberOfWords::N1, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push( - crate::triton_vm::prelude::BFieldElement::new( - Self::MAX_OFFSET.into(), - ), - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Dup( - crate::triton_vm::isa::op_stack::OpStackElement::ST2, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Lt, - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Assert, - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::AddI( - crate::BFieldElement::new(1u64), - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Swap( - crate::triton_vm::isa::op_stack::OpStackElement::ST1, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::AddI( - crate::BFieldElement::new(1u64), - ), - ), - ] - .to_vec() - } - } - "auth_structure" => { - let prev = [ - Self::get_field_start_with_jump_distance("revealed_leaves"), - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Add, - ), - ] - .to_vec(), - ] - .concat(); - let jumper = { - if let Some(size) = ::static_length() { - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push( - crate::BFieldElement::new(size as u64), - ), - ), - ] - .to_vec() - } else { - [ - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::ReadMem( - crate::triton_vm::isa::op_stack::NumberOfWords::N1, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push( - crate::triton_vm::prelude::BFieldElement::new( - Self::MAX_OFFSET.into(), - ), - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Dup( - crate::triton_vm::isa::op_stack::OpStackElement::ST2, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Lt, - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Assert, - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::AddI( - crate::BFieldElement::new(1u64), - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Swap( - crate::triton_vm::isa::op_stack::OpStackElement::ST1, - ), - ), - crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::AddI( - crate::BFieldElement::new(1u64), - ), - ), - ] - .to_vec() - } - }; - [prev, jumper].concat() - } - unknown_field_name => { - panic!( - "Cannot match on field name `{0}`.", - unknown_field_name, - ); - } - } - } - fn compute_size_and_assert_valid_size_indicator( - library: &mut crate::tasm_lib::Library, - ) -> Vec { - let push0 = crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push(0u64.into()), - ); - let pushmax = crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Push(Self::MAX_OFFSET.into()), - ); - let dup0 = crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Dup( - crate::triton_vm::isa::op_stack::OpStackElement::ST0, - ), - ); - let dup1 = crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Dup( - crate::triton_vm::isa::op_stack::OpStackElement::ST1, - ), - ); - let dup2 = crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Dup( - crate::triton_vm::isa::op_stack::OpStackElement::ST2, - ), - ); - let swap1 = crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Swap( - crate::triton_vm::isa::op_stack::OpStackElement::ST1, - ), - ); - let swap2 = crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Swap( - crate::triton_vm::isa::op_stack::OpStackElement::ST2, - ), - ); - let lt = crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Lt, - ); - let assert = crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Assert, - ); - let eq = crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Eq, - ); - let add = crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Add, - ); - let read_mem1 = crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::ReadMem( - crate::triton_vm::isa::op_stack::NumberOfWords::N1, - ), - ); - let addi1 = crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::AddI(crate::BFieldElement::new( - 1u64, - )), - ); - let addi2 = crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::AddI(crate::BFieldElement::new( - 2u64, - )), - ); - let pop1 = crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::Pop( - crate::triton_vm::isa::op_stack::NumberOfWords::N1, - ), - ); - let hint_acc_size = [ - crate::triton_vm::isa::instruction::LabelledInstruction::TypeHint( - crate::triton_vm::isa::instruction::TypeHint { - starting_index: 1, - length: 1, - type_name: std::option::Option::::None, - variable_name: std::string::String::from("acc_size"), - }, - ), - ] - .to_vec(); - let hint_field_ptr = [ - crate::triton_vm::isa::instruction::LabelledInstruction::TypeHint( - crate::triton_vm::isa::instruction::TypeHint { - starting_index: 0, - length: 1, - type_name: std::option::Option::::None, - variable_name: std::string::String::from("field_ptr"), - }, - ), - ] - .to_vec(); - [ - [push0.clone(), swap1.clone()].to_vec(), - hint_acc_size, - hint_field_ptr, - if let Some(static_length) = as crate::triton_vm::twenty_first::math::bfield_codec::BFieldCodec>::static_length() { - let addi_len = crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::AddI( - crate::BFieldElement::new(static_length as u64), - ), - ); - [addi_len.clone(), swap1.clone(), addi_len.clone(), swap1.clone()] - .to_vec() - } else { - [ - [ - read_mem1.clone(), - pushmax.clone(), - dup2.clone(), - lt.clone(), - assert.clone(), - addi2.clone(), - dup0.clone(), - ] - .to_vec(), - as crate::tasm_lib::structure::tasm_object::TasmObject>::compute_size_and_assert_valid_size_indicator( - library, - ), - [ - dup2.clone(), - eq.clone(), - assert.clone(), - dup1.clone(), - add.clone(), - swap2.clone(), - add.clone(), - addi1.clone(), - swap1.clone(), - ] - .to_vec(), - ] - .concat() - }, - if let Some(static_length) = ::static_length() { - let addi_len = crate::triton_vm::isa::instruction::LabelledInstruction::Instruction( - crate::triton_vm::isa::instruction::AnInstruction::AddI( - crate::BFieldElement::new(static_length as u64), - ), - ); - [addi_len.clone(), swap1.clone(), addi_len.clone(), swap1.clone()] - .to_vec() - } else { - [ - [ - read_mem1.clone(), - pushmax.clone(), - dup2.clone(), - lt.clone(), - assert.clone(), - addi2.clone(), - dup0.clone(), - ] - .to_vec(), - ::compute_size_and_assert_valid_size_indicator( - library, - ), - [ - dup2.clone(), - eq.clone(), - assert.clone(), - dup1.clone(), - add.clone(), - swap2.clone(), - add.clone(), - addi1.clone(), - swap1.clone(), - ] - .to_vec(), - ] - .concat() - }, - [pop1.clone()].to_vec(), - ] - .concat() - } - fn decode_iter>( - iterator: &mut Itr, - ) -> ::std::result::Result< - ::std::boxed::Box, - ::std::boxed::Box, - > { - let length: usize = if let Some(static_length) = as crate::twenty_first::math::bfield_codec::BFieldCodec>::static_length() { - static_length - } else { - iterator.next().unwrap().value() as usize - }; - let sequence = (0..length) - .map(|_| iterator.next().unwrap()) - .collect::>(); - let revealed_leaves: Vec = - *crate::twenty_first::math::bfield_codec::BFieldCodec::decode(&sequence)?; - let length: usize = if let Some(static_length) = ::static_length() { - static_length - } else { - iterator.next().unwrap().value() as usize - }; - let sequence = (0..length) - .map(|_| iterator.next().unwrap()) - .collect::>(); - let auth_structure: AuthenticationStructure = - *crate::twenty_first::math::bfield_codec::BFieldCodec::decode(&sequence)?; - ::std::result::Result::Ok(::std::boxed::Box::new(Self { - revealed_leaves, - auth_structure, - })) - } -} diff --git a/tasm-lib/src/structure/manual_tasm_object_implementations.rs b/tasm-lib/src/structure/manual_tasm_object_implementations.rs index 40d11cdd..6a80bebb 100644 --- a/tasm-lib/src/structure/manual_tasm_object_implementations.rs +++ b/tasm-lib/src/structure/manual_tasm_object_implementations.rs @@ -1,12 +1,15 @@ use itertools::Itertools; use num::Zero; use triton_vm::prelude::*; +use triton_vm::proof_item::FriResponse; use twenty_first::error::BFieldCodecError; use twenty_first::math::x_field_element::EXTENSION_DEGREE; +use twenty_first::prelude::Polynomial; use super::tasm_object::Result; use crate::data_type::DataType; use crate::prelude::TasmObject; +use crate::verifier::proof_for_nd_memory::ProofForNdMemory; impl TasmObject for [T; N] { fn label_friendly_name() -> String { @@ -321,7 +324,7 @@ impl TasmObject for bool { fn compute_size_and_assert_valid_size_indicator( _library: &mut crate::tasm_lib::Library, ) -> Vec { - unreachable!("Size is known statically for u32 encoding") + unreachable!("Size is known statically for bool encoding") } fn decode_iter>(iterator: &mut Itr) -> Result> { @@ -586,9 +589,157 @@ impl TasmObject for (T } } -impl TasmObject for Proof { +impl TasmObject for FriResponse { + fn label_friendly_name() -> String { + "fri_response".to_owned() + } + + fn get_field(field_name: &str) -> Vec { + match field_name { + "revealed_leaves" => triton_asm!(addi 1), + _ => panic!("Only the revealed_leaves field should be accessed in the FriResponse"), + } + } + + fn get_field_with_size(field_name: &str) -> Vec { + match field_name { + "revealed_leaves" => triton_asm!(read_mem 1 addi 2 swap 1), + _ => panic!("Only the revealed_leaves field should be accessed in the FriResponse"), + } + } + + fn get_field_start_with_jump_distance(_field_name: &str) -> Vec { + todo!() + } + + fn compute_size_and_assert_valid_size_indicator( + _library: &mut crate::prelude::Library, + ) -> Vec { + // Assert that all authentication paths have been stripped from memory, + // and that size indicator of `revealed_leaves` matches its length. + triton_asm!( + // _ *fri_response + + addi 1 + read_mem 2 + hint revealed_leafs_size = stack[1] + hint revealed_leafs_len = stack[2] + // _ revealed_leafs_len revealed_leafs_size (*fri_response - 1) + + + /* Assert max size of `revealed_leafs` */ + push {FriResponse::MAX_OFFSET} + dup 2 + lt + assert + // _ revealed_leafs_len revealed_leafs_size (*fri_response - 1) + + + /* Assert revealed_leafs_size matches revealed_leafs_len */ + swap 2 + push {EXTENSION_DEGREE} + mul + addi 1 + dup 1 + eq + assert + // _ (*fri_response - 1) revealed_leafs_size + + swap 1 + // _ revealed_leafs_size (*fri_response - 1) + + addi 3 + dup 1 + add + // _ revealed_leafs_size *auth_structure + + read_mem 2 + pop 1 + // _ revealed_leafs_size auth_struct_si auth_struct_len + + + /* Assert that `auth_struct` field is empty */ + push 1 + eq + assert + + push 0 + eq + assert + // _ revealed_leafs_size + + + /* Account for two size indicators and an empty list */ + addi 3 + // _ fri_response_size + ) + } + + fn decode_iter>(_iterator: &mut Itr) -> Result> { + todo!() + } +} + +impl TasmObject for Polynomial { + fn label_friendly_name() -> String { + "polynomial_xfe".to_owned() + } + + fn get_field(_field_name: &str) -> Vec { + todo!() + } + + fn get_field_with_size(_field_name: &str) -> Vec { + todo!() + } + + fn get_field_start_with_jump_distance(_field_name: &str) -> Vec { + todo!() + } + + fn compute_size_and_assert_valid_size_indicator( + _library: &mut crate::prelude::Library, + ) -> Vec { + triton_asm!( + // _ *field_size + + addi 1 + // _ *list_length + + read_mem 2 + pop 1 + // _ list_length field_size + + push {Polynomial::::MAX_OFFSET} + dup 1 + lt + assert + // _ list_length field_size + + swap 1 + push {EXTENSION_DEGREE} + mul + addi 1 + // _ field_size calculated_field_size + + dup 1 + eq + assert + // _ field_size + + /* Account for a size-indicator */ + addi 1 + ) + } + + fn decode_iter>(_iterator: &mut Itr) -> Result> { + todo!() + } +} + +impl TasmObject for ProofForNdMemory { fn label_friendly_name() -> String { - "tvm_proof".to_owned() + "proof_for_nd_memory".to_owned() } fn get_field(_field_name: &str) -> Vec { diff --git a/tasm-lib/src/structure/tasm_object.rs b/tasm-lib/src/structure/tasm_object.rs index 28bf5665..a2ad7ce8 100644 --- a/tasm-lib/src/structure/tasm_object.rs +++ b/tasm-lib/src/structure/tasm_object.rs @@ -277,6 +277,7 @@ mod test { /// Test derivation of field getters and manual derivations of the `field!` macro mod derive_tests { use num_traits::ConstZero; + use twenty_first::math::other::random_elements; use twenty_first::math::x_field_element::EXTENSION_DEGREE; use super::*; @@ -769,56 +770,106 @@ mod test { assert_eq!(random_object.0.len(), extracted_xfe_count); } - #[test] - fn test_fri_response() { - let mut rng = thread_rng(); - let num_digests = 50; - let num_leafs = 20; - - // generate object - let authentication_structure = - (0..num_digests).map(|_| rng.gen::()).collect_vec(); - let revealed_leafs = (0..num_leafs) - .map(|_| rng.gen::()) - .collect_vec(); - let fri_response = FriResponse { - auth_structure: authentication_structure, - revealed_leaves: revealed_leafs, - }; - - // code snippet to access object's fields + fn fri_response_prop(fri_response: FriResponse) { let mut library = Library::new(); - let get_authentication_structure = field!(FriResponse::auth_structure); - let length_digests = library.import(Box::new(Length { - element_type: DataType::Digest, - })); let get_revealed_leafs = field!(FriResponse::revealed_leaves); + let get_revealed_leafs_with_size = field_with_size!(FriResponse::revealed_leaves); let length_xfes = library.import(Box::new(Length { element_type: DataType::Xfe, })); + + let assert_valid_size_indicators = + FriResponse::compute_size_and_assert_valid_size_indicator(&mut library); let code = triton_asm! { // _ *fri_response - dup 0 // _ *fri_response *fri_response - {&get_authentication_structure} // _ *fri_response *authentication_structure - swap 1 // _ *authentication_structure *fri_response - {&get_revealed_leafs} // _ *authentication_structure *revealed_leafs + dup 0 + // _ *fri_response *fri_response + + {&assert_valid_size_indicators} + // _ *fri_response fri_response_size + + swap 1 + // _ fri_response_size *fri_response + + dup 0 + {&get_revealed_leafs_with_size} + // _ fri_response_size *fri_response *revealed_leafs revealed_leafs_size + + swap 2 + // _ fri_response_size revealed_leafs_size *revealed_leafs *fri_response + + {&get_revealed_leafs} + // _ fri_response_size revealed_leafs_size *revealed_leafs *revealed_leafs + - swap 1 // _ *revealed_leafs *authentication_structure - call {length_digests} // _ *revealed_leafs num_digests - swap 1 // _ num_digests *revealed_leafs - call {length_xfes} // _ num_digests num_leafs + /* Verify that both field-getters agree on field pointer */ + dup 1 + eq + assert + // _ fri_response_size revealed_leafs_size *revealed_leafs + call {length_xfes} + // _ fri_response_size revealed_leafs_size num_revealed_leafs }; - // extract list lengths - let mut stack = get_final_stack(&fri_response, library, code); - let extracted_xfes_length = stack.pop().unwrap().value() as usize; - let extracted_digests_length = stack.pop().unwrap().value() as usize; + let mut memory: HashMap = HashMap::new(); + let random_address: u64 = thread_rng().gen_range(0..(1 << 30)); + let address = random_address.into(); + encode_to_memory(&mut memory, address, &fri_response); + let stack = [empty_stack(), vec![address]].concat(); - // assert correct lengths - assert_eq!(num_digests, extracted_digests_length); - assert_eq!(num_leafs, extracted_xfes_length); + let library_code = library.all_imports(); + let code = triton_asm!( + {&code} + halt + {&library_code} + ); + + let public_input = vec![]; + let sponge = None; + let nondeterminism = NonDeterminism::new(vec![]).with_ram(memory); + + let tvm_result = execute_with_terminal_state( + &Program::new(&code), + &public_input, + &stack, + &nondeterminism, + sponge, + ); + + // Only FriResponse objects with empty `auth_struct` fields are + // allowed since digests are read from the ND digest stream + // instead. + if !fri_response.auth_structure.is_empty() { + let err = tvm_result.unwrap_err(); + assert_eq!(InstructionError::AssertionFailed, err,); + } else { + let mut stack = tvm_result.unwrap().op_stack.stack; + + let extracted_xfes_length = stack.pop().unwrap().value() as usize; + assert_eq!(fri_response.revealed_leaves.len(), extracted_xfes_length); + + let extracted_revealed_leafs_field_size = stack.pop().unwrap().value() as usize; + assert_eq!( + fri_response.revealed_leaves.len() * EXTENSION_DEGREE + 1, + extracted_revealed_leafs_field_size + ); + + let reported_size = stack.pop().unwrap().value() as usize; + assert_eq!(fri_response.encode().len(), reported_size); + } + } + + #[test] + fn test_fri_response_tasm_object_impl() { + for n in 0..10 { + let fri_response = FriResponse { + auth_structure: random_elements(n), + revealed_leaves: random_elements(32), + }; + fri_response_prop(fri_response); + } } /// Helper function for testing field getters. Only returns the final stack. diff --git a/tasm-lib/src/structure/verify_nd_si_integrity.rs b/tasm-lib/src/structure/verify_nd_si_integrity.rs index facbe8f0..0d49f65d 100644 --- a/tasm-lib/src/structure/verify_nd_si_integrity.rs +++ b/tasm-lib/src/structure/verify_nd_si_integrity.rs @@ -96,6 +96,7 @@ mod tests { use crate::traits::accessor::AccessorInitialState; use crate::traits::accessor::ShadowedAccessor; use crate::traits::rust_shadow::RustShadow; + use crate::verifier::proof_for_nd_memory::ProofForNdMemory; impl Arbitrary<'a> + Debug + Clone> VerifyNdSiIntegrity { fn initial_state(&self, address: BFieldElement, t: T) -> AccessorInitialState { @@ -438,7 +439,7 @@ mod tests { #[test] fn test_pbt_proof() { - let snippet: VerifyNdSiIntegrity = VerifyNdSiIntegrity { + let snippet: VerifyNdSiIntegrity = VerifyNdSiIntegrity { _phantom_data: PhantomData, }; ShadowedAccessor::new(snippet).test(); diff --git a/tasm-lib/src/test_helpers.rs b/tasm-lib/src/test_helpers.rs index 3063a670..6622b2e7 100644 --- a/tasm-lib/src/test_helpers.rs +++ b/tasm-lib/src/test_helpers.rs @@ -533,13 +533,13 @@ pub fn negative_test( let rust_failed_successfully = rust_result.is_err(); assert!( rust_failed_successfully, - "Test case: Rust-shadowing must panic in negative test case" + "Failed to fail: Rust-shadowing must panic in negative test case" ); let tvm_failed_successfully = tvm_result.is_err(); assert!( tvm_failed_successfully, - "Test case: TVM-execution must panic in negative test case" + "Failed to fail: TVM-execution must crash in negative test case" ); let err = tvm_result.unwrap_err(); diff --git a/tasm-lib/src/traits/accessor.rs b/tasm-lib/src/traits/accessor.rs index d9f9d838..fe054ed6 100644 --- a/tasm-lib/src/traits/accessor.rs +++ b/tasm-lib/src/traits/accessor.rs @@ -71,9 +71,9 @@ pub struct ShadowedAccessor { } impl ShadowedAccessor { - pub fn new(algorithm: T) -> Self { + pub fn new(accessor: T) -> Self { Self { - accessor: Rc::new(RefCell::new(algorithm)), + accessor: Rc::new(RefCell::new(accessor)), } } } diff --git a/tasm-lib/src/verifier.rs b/tasm-lib/src/verifier.rs index 9893ffee..0ce02995 100644 --- a/tasm-lib/src/verifier.rs +++ b/tasm-lib/src/verifier.rs @@ -5,6 +5,7 @@ pub mod fri; pub mod master_table; pub mod out_of_domain_points; pub mod own_program_digest; +pub mod proof_for_nd_memory; pub mod read_and_verify_own_program_digest_from_std_in; pub mod stark_verify; pub mod vm_proof_iter; diff --git a/tasm-lib/src/verifier/fri/verify.rs b/tasm-lib/src/verifier/fri/verify.rs index 842d3fa2..bb728ec0 100644 --- a/tasm-lib/src/verifier/fri/verify.rs +++ b/tasm-lib/src/verifier/fri/verify.rs @@ -167,6 +167,18 @@ impl BasicSnippet for FriSnippet { let get_xfe_from_list = library.import(Box::new(Get::new(DataType::Xfe))); let get_digest_from_list = library.import(Box::new(Get::new(DataType::Digest))); let sample_indices = library.import(Box::new(SampleIndices)); + + let assert_no_auth_paths_in_memory = triton_asm!( + // _ *fri_response + + dup 0 + {&FriResponse::compute_size_and_assert_valid_size_indicator(library)} + // _ *fri_response fri_response_size + + pop 1 + // _ + ); + let verify_authentication_paths_for_leaf_and_index_list = library.import(Box::new(VerifyFriAuthenticationPaths)); let zip_index_xfe = library.import(Box::new(Zip::new(DataType::U32, DataType::Xfe))); @@ -440,6 +452,9 @@ impl BasicSnippet for FriSnippet { call {vm_proof_iter_dequeue_next_as_fri_response} // _ *vm_proof_iter *fri_verify num_rounds last_round_max_degree *last_codeword *roots *alphas dom_len *indices *fri_response + {&assert_no_auth_paths_in_memory} + // _ *vm_proof_iter *fri_verify num_rounds last_round_max_degree *last_codeword *roots *alphas dom_len *indices *fri_response + // assert correct length of number of leafs {&field!(FriResponse::revealed_leaves)} // _ *vm_proof_iter *fri_verify num_rounds last_round_max_degree *last_codeword *roots *alphas dom_len *indices *a_elements @@ -1193,6 +1208,7 @@ mod test { use crate::traits::procedure::Procedure; use crate::traits::procedure::ProcedureInitialState; use crate::traits::procedure::ShadowedProcedure; + use crate::verifier::proof_for_nd_memory::strip_non_memory_items; impl FriVerify { pub fn new( @@ -1289,8 +1305,9 @@ mod test { // uses highly specific knowledge about `BFieldCodec` let proof_iter_current_item_pointer = vm_proof_iter_pointer + BFieldElement::new(2); + let stripped_proof_stream = strip_non_memory_items(proof_stream); let fri_verify_pointer = - encode_to_memory(&mut memory, vm_proof_iter_pointer, &proof_stream); + encode_to_memory(&mut memory, vm_proof_iter_pointer, &stripped_proof_stream); let proof_iter_pointer = encode_to_memory(&mut memory, fri_verify_pointer, &self.test_instance); encode_to_memory( diff --git a/tasm-lib/src/verifier/proof_for_nd_memory.rs b/tasm-lib/src/verifier/proof_for_nd_memory.rs new file mode 100644 index 00000000..2dfc7137 --- /dev/null +++ b/tasm-lib/src/verifier/proof_for_nd_memory.rs @@ -0,0 +1,72 @@ +use arbitrary::Arbitrary; +use triton_vm::error::ProofStreamError; +use triton_vm::prelude::BFieldCodec; +use triton_vm::prelude::BFieldElement; +use triton_vm::proof::Proof; +use triton_vm::proof_stream::ProofStream; + +/// A proof stripped of proof items that are divined in. +/// +/// Intended to be loaded into the ND-section of memory prior to Triton VM +/// executions involving verification. +#[derive(Debug, Clone, Eq, PartialEq, BFieldCodec, Arbitrary)] +pub struct ProofForNdMemory(pub Vec); + +impl TryFrom for ProofForNdMemory { + type Error = ProofStreamError; + + fn try_from(proof: Proof) -> Result { + (&proof).try_into() + } +} + +/// Strip those parts of the proof stream that are not read from memory by +/// the TASM verifier. +pub(crate) fn strip_non_memory_items(proof_stream: ProofStream) -> ProofStream { + let mut stripped_proof = ProofStream::new(); + for mut proof_item in proof_stream.items.into_iter() { + use triton_vm::proof_item::ProofItem::*; + match &mut proof_item { + AuthenticationStructure(_) => continue, + FriResponse(fri_response) => { + fri_response.auth_structure.clear(); + } + _ => (), + } + + stripped_proof.enqueue(proof_item); + } + + stripped_proof +} + +impl TryFrom<&Proof> for ProofForNdMemory { + type Error = ProofStreamError; + + fn try_from(proof: &Proof) -> Result { + let proof_stream = *ProofStream::decode(&proof.0)?; + let stripped_proof = strip_non_memory_items(proof_stream); + Ok(stripped_proof.into()) + } +} + +impl From for Proof { + fn from(value: ProofForNdMemory) -> Self { + Proof(value.0) + } +} + +impl From for ProofForNdMemory { + fn from(proof_stream: ProofStream) -> Self { + ProofForNdMemory(proof_stream.encode()) + } +} + +impl TryFrom<&ProofForNdMemory> for ProofStream { + type Error = ProofStreamError; + + fn try_from(proof: &ProofForNdMemory) -> Result { + let proof_stream = *ProofStream::decode(&proof.0)?; + Ok(proof_stream) + } +} diff --git a/tasm-lib/src/verifier/stark_verify.rs b/tasm-lib/src/verifier/stark_verify.rs index 810a08ef..31443d4a 100644 --- a/tasm-lib/src/verifier/stark_verify.rs +++ b/tasm-lib/src/verifier/stark_verify.rs @@ -36,6 +36,7 @@ use crate::verifier::master_table::verify_table_rows::VerifyTableRows; use crate::verifier::out_of_domain_points::OodPoint; use crate::verifier::out_of_domain_points::OutOfDomainPoints; use crate::verifier::vm_proof_iter::dequeue_next_as::DequeueNextAs; +use crate::verifier::vm_proof_iter::drop::Drop; use crate::verifier::vm_proof_iter::new::New; /// Verify a STARK proof. @@ -302,6 +303,7 @@ impl BasicSnippet for StarkVerify { let entrypoint = self.entrypoint(); let proof_to_vm_proof_iter = library.import(Box::new(New)); + let drop_vm_proof_iter = library.import(Box::new(Drop)); let ood_curr_row_main_and_aux_value_pointer_alloc = library.kmalloc(EXTENSION_DEGREE.try_into().unwrap()); @@ -332,9 +334,6 @@ impl BasicSnippet for StarkVerify { let next_as_maintablerows = library.import(Box::new(DequeueNextAs { proof_item: ProofItemVariant::MasterMainTableRows, })); - let next_as_authentication_path = library.import(Box::new(DequeueNextAs { - proof_item: ProofItemVariant::AuthenticationStructure, - })); let next_as_auxtablerows = library.import(Box::new(DequeueNextAs { proof_item: ProofItemVariant::MasterAuxTableRows, })); @@ -937,13 +936,6 @@ impl BasicSnippet for StarkVerify { call {verify_main_table_rows} // _ *beqd_ws *p_iter *oodpnts *fri *e_mr *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *btrows - - /* Dequeue and ignore main-table's authentication path */ - dup 10 - call {next_as_authentication_path} - pop 1 - // _ *beqd_ws *p_iter *oodpnts *fri *e_mr *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *btrows - swap 7 // _ *beqd_ws *p_iter *oodpnts *fri *btrows *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *e_mr @@ -976,12 +968,6 @@ impl BasicSnippet for StarkVerify { call {verify_aux_table_rows} // _ *beqd_ws *p_iter *oodpnts *fri *btrows *odd_brow_next *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *etrows - - /* Dequeue and ignore aux-table's authentication path */ - dup 10 - call {next_as_authentication_path} - pop 1 - swap 5 // _ *beqd_ws *p_iter *oodpnts *fri *btrows *odd_brow_next *etrows *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *quot_mr @@ -1055,10 +1041,10 @@ impl BasicSnippet for StarkVerify { assert // _ *beqd_ws *p_iter *oodpnts *fri *btrows *odd_brow_next *etrows *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *qseg_elems num_colli - /* Clean up stack */ + /* Clean up stack and drop p_iter, ensuring that it ends up in a consistent state */ swap 12 swap 11 - pop 1 + call {drop_vm_proof_iter} // _ num_colli *beqd_ws *oodpnts *fri *btrows *odd_brow_next *etrows *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *qseg_elems /* Sum out-of-domain values */ @@ -1229,6 +1215,7 @@ pub mod tests { use crate::test_helpers::maybe_write_tvm_output_to_disk; use crate::verifier::claim::shared::insert_claim_into_static_memory; use crate::verifier::master_table::air_constraint_evaluation::an_integral_but_profane_dynamic_memory_layout; + use crate::verifier::proof_for_nd_memory::ProofForNdMemory; #[ignore = "Used for debugging when comparing two versions of the verifier"] #[test] @@ -1269,7 +1256,7 @@ pub mod tests { ); } - /// Run the (static) verifier, and return the cycle count and inner padded + /// Run the verifier, and return the cycle count and inner padded /// height for crude benchmarking. fn test_verify_and_report_basic_features( inner_nondeterminism: NonDeterminism, @@ -1468,6 +1455,7 @@ pub mod tests { }; stark_verify.update_nondeterminism(&mut nondeterminism, &proof, &claim); + let proof: ProofForNdMemory = proof.try_into().unwrap(); encode_to_memory( &mut nondeterminism.ram, FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS, @@ -1481,9 +1469,9 @@ pub mod tests { fn verify_two_proofs() { #[derive(Debug, Clone, BFieldCodec, TasmObject)] struct TwoProofs { - proof1: Proof, + proof1: ProofForNdMemory, claim1: Claim, - proof2: Proof, + proof2: ProofForNdMemory, claim2: Claim, } @@ -1545,9 +1533,27 @@ pub mod tests { .with_input(inner_input_2.clone()) .with_output(inner_output_2.clone()); let proof_2 = stark.prove(&claim_2, &aet_2).unwrap(); + let padded_height_2 = proof_2.padded_height().unwrap(); println!("padded_height_2: {padded_height_2}"); + let mut outer_nondeterminism = NonDeterminism::new(vec![]); + + let num_nd_digests_before = outer_nondeterminism.digests.len(); + + stark_snippet.update_nondeterminism(&mut outer_nondeterminism, &proof_1, &claim_1); + stark_snippet.update_nondeterminism(&mut outer_nondeterminism, &proof_2, &claim_2); + + let num_nd_digests_after = outer_nondeterminism.digests.len(); + + assert_eq!( + num_nd_digests_after - num_nd_digests_before, + stark_snippet.number_of_nondeterministic_digests_consumed(&proof_1, &claim_1) + + stark_snippet.number_of_nondeterministic_digests_consumed(&proof_2, &claim_2) + ); + + let proof_1: ProofForNdMemory = proof_1.try_into().unwrap(); + let proof_2: ProofForNdMemory = proof_2.try_into().unwrap(); let two_proofs = TwoProofs { proof1: proof_1.clone(), claim1: claim_1.clone(), @@ -1563,21 +1569,7 @@ pub mod tests { &two_proofs, ); - let mut outer_nondeterminism = NonDeterminism::new(vec![]).with_ram(memory); - - let num_nd_digests_before = outer_nondeterminism.digests.len(); - - stark_snippet.update_nondeterminism(&mut outer_nondeterminism, &proof_1, &claim_1); - stark_snippet.update_nondeterminism(&mut outer_nondeterminism, &proof_2, &claim_2); - - let num_nd_digests_after = outer_nondeterminism.digests.len(); - - assert_eq!( - num_nd_digests_after - num_nd_digests_before, - stark_snippet.number_of_nondeterministic_digests_consumed(&proof_1, &claim_1) - + stark_snippet.number_of_nondeterministic_digests_consumed(&proof_2, &claim_2) - ); - + let outer_nondeterminism = outer_nondeterminism.with_ram(memory); let program = Program::new(&verify_two_proofs_program); let vm_state = VMState::new( diff --git a/tasm-lib/src/verifier/vm_proof_iter.rs b/tasm-lib/src/verifier/vm_proof_iter.rs index fa07074f..8e95900c 100644 --- a/tasm-lib/src/verifier/vm_proof_iter.rs +++ b/tasm-lib/src/verifier/vm_proof_iter.rs @@ -1,3 +1,4 @@ pub mod dequeue_next_as; +pub mod drop; pub mod new; pub mod shared; diff --git a/tasm-lib/src/verifier/vm_proof_iter/dequeue_next_as.rs b/tasm-lib/src/verifier/vm_proof_iter/dequeue_next_as.rs index effc3c8a..938123fd 100644 --- a/tasm-lib/src/verifier/vm_proof_iter/dequeue_next_as.rs +++ b/tasm-lib/src/verifier/vm_proof_iter/dequeue_next_as.rs @@ -1,10 +1,17 @@ +use triton_vm::fri::AuthenticationStructure; use triton_vm::prelude::*; +use triton_vm::proof_item::FriResponse; use triton_vm::proof_item::ProofItemVariant; +use triton_vm::table::AuxiliaryRow; +use triton_vm::table::MainRow; +use triton_vm::table::QuotientSegments; use triton_vm::twenty_first::math::x_field_element::EXTENSION_DEGREE; +use twenty_first::prelude::Polynomial; use crate::data_type::DataType; use crate::hashing::sponge_hasher::pad_and_absorb_all::PadAndAbsorbAll; use crate::library::Library; +use crate::structure::tasm_object::TasmObject; use crate::traits::basic_snippet::BasicSnippet; const MAX_SIZE_FOR_DYNAMICALLY_SIZED_PROOF_ITEMS: u32 = 1u32 << 22; @@ -28,6 +35,116 @@ impl DequeueNextAs { self.proof_item.to_string().to_lowercase() } + fn proof_item_calculate_size(&self, library: &mut Library) -> Vec { + match self.proof_item { + ProofItemVariant::MasterMainTableRows => { + Vec::>::compute_size_and_assert_valid_size_indicator(library) + } + ProofItemVariant::MasterAuxTableRows => { + Vec::::compute_size_and_assert_valid_size_indicator(library) + } + ProofItemVariant::QuotientSegmentsElements => { + Vec::::compute_size_and_assert_valid_size_indicator(library) + } + ProofItemVariant::FriCodeword => { + Vec::::compute_size_and_assert_valid_size_indicator(library) + } + ProofItemVariant::FriPolynomial => { + Polynomial::::compute_size_and_assert_valid_size_indicator(library) + } + ProofItemVariant::FriResponse => { + FriResponse::compute_size_and_assert_valid_size_indicator(library) + } + ProofItemVariant::AuthenticationStructure => { + // All authentication structures should be stripped from loaded proofs, but for + // more complete tests, we support it here anyway. + AuthenticationStructure::compute_size_and_assert_valid_size_indicator(library) + } + _ => unreachable!(), + } + } + + /// Increment the counter of proof items already dequeued. + /// + /// ```text + /// BEFORE: _ *vm_proof_iter + /// AFTER: _ *vm_proof_iter + /// ``` + fn increment_current_item_count(&self) -> Vec { + const CURRENT_ITEM_COUNT_OFFSET: BFieldElement = BFieldElement::new(4); + + triton_asm!( + // _ *proof_item_iter + + dup 0 + addi {CURRENT_ITEM_COUNT_OFFSET} + // _ *proof_item_iter *current_item_count + + read_mem 1 + addi 1 + // _ *proof_item_iter current_item_count *current_item_count + + pick 1 + addi 1 + pick 1 + // _ *proof_item_iter (current_item_count + 1) *current_item_count + + write_mem 1 + pop 1 + // _ *proof_item_iter + ) + } + + /// ```text + /// BEFORE: _ *proof_item_size + /// AFTER: _ *proof_item_size + /// ``` + fn assert_consistent_size_indicators(&self, library: &mut Library) -> Vec { + if self.proof_item.payload_static_length().is_some() { + return vec![]; + } + + let calculate_own_size = self.proof_item_calculate_size(library); + + triton_asm! { + // _ *proof_item_size + + dup 0 + addi 3 + {&calculate_own_size} + hint calculated_payload_size = stack[0] + // _ *proof_item_size calculated_payload_size + + dup 1 + addi 2 + read_mem 1 + pop 1 + hint indicated_payload_size = stack[0] + // _ *proof_item_size calculated_payload_size reported_field_size + + dup 1 + eq + assert + hint payload_size = stack[0] + // _ *proof_item_size payload_size + + + /* Account for discriminant and size-indicator */ + addi 2 + hint calculated_item_size = stack[0] + // _ *proof_item_size calculated_item_size + + dup 1 + read_mem 1 + pop 1 + // _ *proof_item_size calculated_own_size indicated_item_size + + eq + assert + // _ *proof_item_size + } + } + /// ```text /// BEFORE: _ *proof_item_size /// AFTER: _ *proof_item_size @@ -203,45 +320,51 @@ impl BasicSnippet for DequeueNextAs { } /// ```text - /// BEFORE: _ *proof_item_iter + /// BEFORE: _ *vm_proof_iter /// AFTER: _ *proof_item_payload /// ``` fn code(&self, library: &mut Library) -> Vec { let final_hint = format!("hint {}_pointer: Pointer = stack[0]", self.item_name()); triton_asm! { {self.entrypoint()}: - read_mem 1 - hint proof_item_list_element_size_pointer = stack[1] + {&self.increment_current_item_count()} + // _ *vm_proof_iter + + read_mem 1 + hint proof_item_list_element_size_pointer = stack[1] - push 1 add - swap 1 // _ *proof_item_iter *proof_item_size + addi 1 + swap 1 // _ *proof_item_iter *proof_item_size - push 1 add - hint proof_item_discriminant_pointer = stack[0] + addi 1 + hint proof_item_discriminant_pointer = stack[0] - read_mem 1 // _ *proof_item_iter discriminant *proof_item_size - hint proof_item_list_element_size_pointer = stack[0] - hint proof_item_discriminant = stack[1] + read_mem 1 // _ *proof_item_iter discriminant *proof_item_size + hint proof_item_list_element_size_pointer = stack[0] + hint proof_item_discriminant = stack[1] + + swap 1 + push {self.proof_item.bfield_codec_discriminant()} + hint expected_proof_item_discriminant = stack[0] - swap 1 - push {self.proof_item.bfield_codec_discriminant()} - hint expected_proof_item_discriminant = stack[0] + eq assert // _ *proof_item_iter *proof_item_size - eq assert // _ *proof_item_iter *proof_item_size + {&self.assert_consistent_size_indicators(library)} + // _ *proof_item_iter *proof_item_size - {&self.fiat_shamir_absorb_snippet(library)} - // _ *proof_item_iter *proof_item_size + {&self.fiat_shamir_absorb_snippet(library)} + // _ *proof_item_iter *proof_item_size - {&self.update_proof_item_iter_to_next_proof_item()} - // _ *proof_item_size + {&self.update_proof_item_iter_to_next_proof_item()} + // _ *proof_item_size - {&self.advance_list_element_pointer_to_proof_item_payload()} - {final_hint} // _ *proof_item_payload + {&self.advance_list_element_pointer_to_proof_item_payload()} + {final_hint} // _ *proof_item_payload - {&self.verify_last_xfe_is_non_zero_if_payload_is_polynomial()} - {final_hint} // _ *proof_item_payload + {&self.verify_last_xfe_is_non_zero_if_payload_is_polynomial()} + {final_hint} // _ *proof_item_payload - return + return } } } @@ -273,12 +396,14 @@ mod test { use crate::execute_with_terminal_state; use crate::linker::link_for_isolated_run; use crate::memory::encode_to_memory; + use crate::rust_shadowing_helper_functions::dyn_malloc::dynamic_allocator; use crate::snippet_bencher::BenchmarkCase; use crate::structure::tasm_object::decode_from_memory_with_size; use crate::test_helpers::test_rust_equivalence_given_complete_state; use crate::traits::procedure::Procedure; use crate::traits::procedure::ProcedureInitialState; use crate::traits::procedure::ShadowedProcedure; + use crate::verifier::vm_proof_iter::shared::vm_proof_iter_struct::VmProofIter; #[derive(Debug)] struct RustShadowForDequeueNextAs<'a> { @@ -297,6 +422,7 @@ mod test { self.maybe_alter_fiat_shamir_heuristic_with_proof_item(); self.update_stack_using_current_proof_item(); self.update_proof_item_iter(); + self.update_current_item_count(); self.public_output() } @@ -383,6 +509,14 @@ mod test { .insert(self.proof_iter_pointer, next_item_pointer); } + fn update_current_item_count(&mut self) { + let count = self + .memory + .get_mut(&(self.proof_iter_pointer + bfe!(4))) + .unwrap(); + count.increment(); + } + fn public_output(&self) -> Vec { vec![] } @@ -414,31 +548,30 @@ mod test { ) -> ProcedureInitialState { let mut rng = StdRng::from_seed(seed); let mut proof_stream = ProofStream::new(); - proof_stream.enqueue(self.pseudorandom_proof_item(rng.gen())); + proof_stream.enqueue(Self::pseudorandom_proof_item(self.proof_item, rng.gen())); let other_item_type = ProofItemVariant::iter().choose(&mut rng).unwrap(); - let other_dequeue_next_as = DequeueNextAs::new(other_item_type); - proof_stream.enqueue(other_dequeue_next_as.pseudorandom_proof_item(rng.gen())); + proof_stream.enqueue(Self::pseudorandom_proof_item(other_item_type, rng.gen())); - Self::initial_state_from_proof_stream_and_address(proof_stream, rng.gen()) + self.initial_state_from_proof_and_address(proof_stream.into(), rng.gen()) } } impl DequeueNextAs { - fn initial_state_from_proof_stream_and_address( - proof_stream: ProofStream, - address: BFieldElement, + fn initial_state_from_proof_and_address( + &self, + proof: Proof, + proof_address: BFieldElement, ) -> ProcedureInitialState { let mut ram = HashMap::new(); - encode_to_memory(&mut ram, address, &proof_stream); + encode_to_memory(&mut ram, proof_address, &proof); - // uses highly specific knowledge of `BFieldCodec` - let address_of_first_element = address + BFieldElement::new(2); - let proof_iter_address = address - BFieldElement::one(); - ram.insert(proof_iter_address, address_of_first_element); + let proof_iter_address = dynamic_allocator(&mut ram); + let vm_proof_iter_init_state = VmProofIter::new(proof_address, &proof); + encode_to_memory(&mut ram, proof_iter_address, &vm_proof_iter_init_state); ProcedureInitialState { - stack: [empty_stack(), vec![proof_iter_address]].concat(), + stack: [self.init_stack_for_isolated_run(), vec![proof_iter_address]].concat(), nondeterminism: NonDeterminism::default().with_ram(ram), public_input: vec![], sponge: Some(Tip5::init()), @@ -452,50 +585,71 @@ mod test { Self { proof_item } } - /// An item to be `Dequeued`, matching the variant in `self`. - fn pseudorandom_proof_item(&self, seed: [u8; 32]) -> ProofItem { + pub(crate) fn pseudorandom_proof_stream( + proof_items_variants: Vec, + seed: [u8; 32], + ) -> ProofStream { + let mut rng: StdRng = SeedableRng::from_seed(seed); + + let mut proof_stream = ProofStream::new(); + for &proof_item in &proof_items_variants { + let item = DequeueNextAs::pseudorandom_proof_item(proof_item, rng.gen()); + proof_stream.enqueue(item); + } + + proof_stream + } + + fn pseudorandom_proof_item( + proof_item_variant: ProofItemVariant, + seed: [u8; 32], + ) -> ProofItem { let mut rng = StdRng::from_seed(seed); - let proof_stream_seed: [u8; 100] = rng.gen(); + let proof_stream_seed: [u8; 10000] = rng.gen(); let mut unstructured = Unstructured::new(&proof_stream_seed); - match &self.proof_item { - ProofItemVariant::MerkleRoot => { + use ProofItemVariant::*; + match proof_item_variant { + MerkleRoot => { ProofItem::MerkleRoot(Arbitrary::arbitrary(&mut unstructured).unwrap()) } - ProofItemVariant::OutOfDomainMainRow => { + OutOfDomainMainRow => { ProofItem::OutOfDomainMainRow(Arbitrary::arbitrary(&mut unstructured).unwrap()) } - ProofItemVariant::OutOfDomainAuxRow => { + OutOfDomainAuxRow => { ProofItem::OutOfDomainAuxRow(Arbitrary::arbitrary(&mut unstructured).unwrap()) } - ProofItemVariant::OutOfDomainQuotientSegments => { - ProofItem::OutOfDomainQuotientSegments( - Arbitrary::arbitrary(&mut unstructured).unwrap(), - ) - } - ProofItemVariant::AuthenticationStructure => ProofItem::AuthenticationStructure( + OutOfDomainQuotientSegments => ProofItem::OutOfDomainQuotientSegments( Arbitrary::arbitrary(&mut unstructured).unwrap(), ), - ProofItemVariant::MasterMainTableRows => { + AuthenticationStructure => ProofItem::AuthenticationStructure( + Arbitrary::arbitrary(&mut unstructured).unwrap(), + ), + MasterMainTableRows => { ProofItem::MasterMainTableRows(Arbitrary::arbitrary(&mut unstructured).unwrap()) } - ProofItemVariant::MasterAuxTableRows => { + MasterAuxTableRows => { ProofItem::MasterAuxTableRows(Arbitrary::arbitrary(&mut unstructured).unwrap()) } - ProofItemVariant::Log2PaddedHeight => { + Log2PaddedHeight => { ProofItem::Log2PaddedHeight(Arbitrary::arbitrary(&mut unstructured).unwrap()) } - ProofItemVariant::QuotientSegmentsElements => ProofItem::QuotientSegmentsElements( + QuotientSegmentsElements => ProofItem::QuotientSegmentsElements( Arbitrary::arbitrary(&mut unstructured).unwrap(), ), - ProofItemVariant::FriCodeword => { + FriCodeword => { ProofItem::FriCodeword(Arbitrary::arbitrary(&mut unstructured).unwrap()) } - ProofItemVariant::FriPolynomial => { + FriPolynomial => { ProofItem::FriPolynomial(Arbitrary::arbitrary(&mut unstructured).unwrap()) } - ProofItemVariant::FriResponse => { - ProofItem::FriResponse(Arbitrary::arbitrary(&mut unstructured).unwrap()) + FriResponse => { + // This code requires the authentication paths field to be empty + let fri_response = triton_vm::proof_item::FriResponse { + auth_structure: vec![], + revealed_leaves: Arbitrary::arbitrary(&mut unstructured).unwrap(), + }; + ProofItem::FriResponse(fri_response) } } } @@ -551,8 +705,9 @@ mod test { let proof_item = ProofItem::MasterMainTableRows(dummy_master_table_rows); let mut proof_stream = ProofStream::new(); proof_stream.enqueue(proof_item); - let address = BFieldElement::zero(); - DequeueNextAs::initial_state_from_proof_stream_and_address(proof_stream, address) + let proof_ptr = BFieldElement::zero(); + DequeueNextAs::new(ProofItemVariant::MasterMainTableRows) + .initial_state_from_proof_and_address(proof_stream.into(), proof_ptr) } #[test] @@ -636,21 +791,23 @@ mod test { } } - #[test] - fn dequeueing_a_merkle_root_is_equivalent_in_rust_and_tasm() { - let dequeue_next_as = DequeueNextAs::new(ProofItemVariant::MerkleRoot); - dequeue_next_as.test_rust_equivalence(small_merkle_root_initial_state()); - } - - fn small_merkle_root_initial_state() -> ProcedureInitialState { - let dummy_digest = Digest::new([42, 43, 44, 45, 46].map(BFieldElement::new)); - let proof_item = ProofItem::MerkleRoot(dummy_digest); + fn dequeueing_is_equivalent_in_rust_and_tasm_prop(proof_item_variant: ProofItemVariant) { let mut proof_stream = ProofStream::new(); - proof_stream.enqueue(proof_item.clone()); + let proof_item = DequeueNextAs::pseudorandom_proof_item(proof_item_variant, random()); proof_stream.enqueue(proof_item); - let address = BFieldElement::zero(); - DequeueNextAs::initial_state_from_proof_stream_and_address(proof_stream, address) + let dequeue_next_as = DequeueNextAs::new(proof_item_variant); + let proof_ptr = BFieldElement::new(14); + let init_state = + dequeue_next_as.initial_state_from_proof_and_address(proof_stream.into(), proof_ptr); + dequeue_next_as.test_rust_equivalence(init_state); + } + + #[test] + fn dequeueing_all_proof_items_individually_is_equivalent_in_rust_and_tasm() { + for variant in ProofItemVariant::iter() { + dequeueing_is_equivalent_in_rust_and_tasm_prop(variant); + } } #[proptest] @@ -720,13 +877,15 @@ mod test { _: Option, ) -> ProcedureInitialState { let mut rng = StdRng::from_seed(seed); - let mut proof_stream = ProofStream::new(); - for &proof_item in &self.proof_items { - let dequeue_next_as = DequeueNextAs { proof_item }; - let item = dequeue_next_as.pseudorandom_proof_item(rng.gen()); - proof_stream.enqueue(item); - } - DequeueNextAs::initial_state_from_proof_stream_and_address(proof_stream, rng.gen()) + let proof_stream = + DequeueNextAs::pseudorandom_proof_stream(self.proof_items.clone(), rng.gen()); + + // We just use the state-initialization method from the `[DequeueNextAs]` snippet. + // This is OK as long as we don't read the program hash which we don't do in this + // snippet. + let dummy_snippet_for_state_init = DequeueNextAs::new(ProofItemVariant::MerkleRoot); + dummy_snippet_for_state_init + .initial_state_from_proof_and_address(proof_stream.into(), rng.gen()) } } diff --git a/tasm-lib/src/verifier/vm_proof_iter/drop.rs b/tasm-lib/src/verifier/vm_proof_iter/drop.rs new file mode 100644 index 00000000..e5016640 --- /dev/null +++ b/tasm-lib/src/verifier/vm_proof_iter/drop.rs @@ -0,0 +1,220 @@ +use triton_vm::isa::triton_asm; +use triton_vm::prelude::LabelledInstruction; + +use crate::data_type::DataType; +use crate::library::Library; +use crate::prelude::BasicSnippet; +use crate::verifier::vm_proof_iter::shared::vm_proof_iter_type; + +/// Signals the end of the lifetime of a VmProofIter +/// +/// This snippet crashes the VM if the VmProofIter does not end up in a sane +/// state after a verification. +pub struct Drop; + +impl BasicSnippet for Drop { + fn inputs(&self) -> Vec<(DataType, String)> { + vec![( + DataType::StructRef(vm_proof_iter_type()), + "vm_proof_iter".to_owned(), + )] + } + + fn outputs(&self) -> Vec<(DataType, String)> { + vec![] + } + + fn entrypoint(&self) -> String { + "tasmlib_verifier_vm_proof_iter_drop".to_owned() + } + + fn code(&self, _library: &mut Library) -> Vec { + let entrypoint = self.entrypoint(); + + triton_asm!( + {entrypoint}: + // _ *vm_proof_iter + + /* Assert that item count matches indicated number of items */ + addi 4 + read_mem 5 + pop 1 + + // _ current_item_count total_item_count proof_start_pointer proof_length current_item_pointer + + place 2 + // _ current_item_count total_item_count current_item_pointer proof_start_pointer proof_length + + add + addi 1 + eq + // _ current_item_count total_item_count (current_item_pointer == proof_start_pointer + proof_length + 1) + + assert + // _ current_item_count total_item_count + + eq + assert + // _ + + return + ) + } +} + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + + use arbitrary::Arbitrary; + use arbitrary::Unstructured; + use rand::rngs::StdRng; + use rand::Rng; + use rand::SeedableRng; + use triton_vm::error::InstructionError; + use triton_vm::prelude::bfe; + use triton_vm::prelude::BFieldElement; + use triton_vm::proof_item::ProofItemVariant; + use triton_vm::proof_stream::ProofStream; + + use super::*; + use crate::memory::encode_to_memory; + use crate::snippet_bencher::BenchmarkCase; + use crate::structure::tasm_object::TasmObject; + use crate::test_helpers::negative_test; + use crate::traits::accessor::Accessor; + use crate::traits::accessor::AccessorInitialState; + use crate::traits::accessor::ShadowedAccessor; + use crate::traits::rust_shadow::RustShadow; + use crate::verifier::vm_proof_iter::dequeue_next_as::DequeueNextAs; + use crate::verifier::vm_proof_iter::shared::vm_proof_iter_struct::VmProofIter; + + #[test] + fn drop_prop() { + ShadowedAccessor::new(Drop).test(); + } + + #[test] + fn negative_test_proof_len_mismatch() { + let proof_ptr = bfe!(450); + let proof_len = 10_000u32; + let correct_proof_end = proof_ptr + bfe!(proof_len); + let bad_proof_length = VmProofIter { + current_item_count: 12, + total_item_count: 12, + proof_start_pointer: proof_ptr, + proof_length: proof_len, + current_item_pointer: correct_proof_end + bfe!(4), + }; + + let bad_init_state = Drop.init_state(bad_proof_length); + negative_test( + &ShadowedAccessor::new(Drop), + bad_init_state.into(), + &[InstructionError::AssertionFailed], + ); + } + + #[test] + fn negative_test_proof_item_count_mismatch() { + let proof_ptr = bfe!(450); + let proof_len = 10_000u32; + let correct_proof_end = proof_ptr + bfe!(proof_len); + let bad_proof_length = VmProofIter { + current_item_count: 16, + total_item_count: 12, + proof_start_pointer: proof_ptr, + proof_length: proof_len, + current_item_pointer: correct_proof_end, + }; + + let bad_init_state = Drop.init_state(bad_proof_length); + negative_test( + &ShadowedAccessor::new(Drop), + bad_init_state.into(), + &[InstructionError::AssertionFailed], + ); + } + + impl Drop { + fn init_state(&self, vm_proof_iter: VmProofIter) -> AccessorInitialState { + let mut memory = HashMap::default(); + let vm_iter_ptr = bfe!(1u64 << 32); + encode_to_memory(&mut memory, vm_iter_ptr, &vm_proof_iter); + + let stack = [self.init_stack_for_isolated_run(), vec![vm_iter_ptr]].concat(); + AccessorInitialState { stack, memory } + } + } + + impl Accessor for Drop { + fn rust_shadow( + &self, + stack: &mut Vec, + memory: &HashMap, + ) { + let vm_proof_iter_ptr = stack.pop().unwrap(); + let vm_proof_iter = + *VmProofIter::decode_from_memory(memory, vm_proof_iter_ptr).unwrap(); + assert_eq!( + vm_proof_iter.current_item_count, + vm_proof_iter.total_item_count + ); + + assert_eq!( + vm_proof_iter.proof_start_pointer + bfe!(vm_proof_iter.proof_length + 1), + vm_proof_iter.current_item_pointer, + "{} + {} and {} must match", + vm_proof_iter.proof_start_pointer, + vm_proof_iter.proof_length, + vm_proof_iter.current_item_pointer + ); + } + + fn pseudorandom_initial_state( + &self, + seed: [u8; 32], + bench_case: Option, + ) -> AccessorInitialState { + let mut rng: StdRng = SeedableRng::from_seed(seed); + + let fake_proof_stream = match bench_case { + Some(BenchmarkCase::CommonCase) => { + let proof_item_variants = vec![ProofItemVariant::MerkleRoot; 20]; + DequeueNextAs::pseudorandom_proof_stream(proof_item_variants, seed) + } + Some(BenchmarkCase::WorstCase) => { + let proof_item_variants = vec![ProofItemVariant::MerkleRoot; 40]; + DequeueNextAs::pseudorandom_proof_stream(proof_item_variants, seed) + } + None => { + let bigger_seed: Vec = (0..1_000_000).map(|_| rng.gen()).collect(); + let unstructured = Unstructured::new(bigger_seed.as_ref()); + ProofStream::arbitrary_take_rest(unstructured).unwrap() + } + }; + + let proof_ptr = bfe!(rng.gen_range(0..20u32)); + let fake_proof = fake_proof_stream.clone().into(); + + // Construct `VmProofIter` as we expect to see it after verifying proof + let mut vm_proof_iter = VmProofIter::new(proof_ptr, &fake_proof); + vm_proof_iter.current_item_count = fake_proof_stream.items.len().try_into().unwrap(); + vm_proof_iter.current_item_pointer = proof_ptr + bfe!(fake_proof.0.len() as u64 + 2); + + self.init_state(vm_proof_iter) + } + } +} + +#[cfg(test)] +mod benches { + use super::*; + use crate::traits::accessor::ShadowedAccessor; + use crate::traits::rust_shadow::RustShadow; + + #[test] + fn drop_bench() { + ShadowedAccessor::new(Drop).bench(); + } +} diff --git a/tasm-lib/src/verifier/vm_proof_iter/new.rs b/tasm-lib/src/verifier/vm_proof_iter/new.rs index a5c77ea5..b18dfc29 100644 --- a/tasm-lib/src/verifier/vm_proof_iter/new.rs +++ b/tasm-lib/src/verifier/vm_proof_iter/new.rs @@ -5,10 +5,24 @@ use crate::memory::dyn_malloc::DynMalloc; use crate::traits::basic_snippet::BasicSnippet; use crate::verifier::vm_proof_iter::shared::vm_proof_iter_type; +/// Create a new `VmProofIter` instance. +/// +/// A `VmProofIter` points to the next proof item in memory to be read in +/// verifying a proof. It also counts how many proof items have been read and +/// records the starting point and indicated length of the proof. pub struct New; impl New { pub const FIRST_PROOF_ITEM_OFFSET: u64 = 4; + pub const MAX_PROOF_SIZE: usize = 1 << 26; + + const MAX_NUMBER_OF_FRI_ROUNDS: usize = 24; + const NUM_PROOF_ITEMS_PER_FRI_ROUND: usize = 2; + const PROOF_ITEMS_EXCLUDING_FRI: usize = 15; + const SAFETY_MARGIN_PER_FRI_ROUND: usize = 1; + pub const MAX_NUM_PROOF_ITEMS: usize = Self::MAX_NUMBER_OF_FRI_ROUNDS + * (Self::NUM_PROOF_ITEMS_PER_FRI_ROUND + Self::SAFETY_MARGIN_PER_FRI_ROUND) + + Self::PROOF_ITEMS_EXCLUDING_FRI; } impl BasicSnippet for New { @@ -33,19 +47,86 @@ impl BasicSnippet for New { triton_asm!( {entrypoint}: - // *proof + // _ *proof + + addi {Self::FIRST_PROOF_ITEM_OFFSET} + dup 0 + addi -1 + read_mem {Self::FIRST_PROOF_ITEM_OFFSET} + addi 1 + push 0 + place 5 + hint first_proof_item: u32 = stack[6] + hint current_proof_item: u32 = stack[5] + hint num_proof_items: u32 = stack[4] + hint proof_len: u32 = stack[1] + // _ *first_proof_item current_proof_item num_proof_items (proof_len - 2) (proof_len - 1) proof_len *proof + + + /* Verify consistent size-indicators */ + place 3 + place 2 + // _ *first_proof_item current_proof_item num_proof_items *proof proof_len (proof_len - 2) (proof_len - 1) + + addi 1 + dup 2 + eq + assert + // _ *first_proof_item current_proof_item num_proof_items *proof proof_len (proof_len - 2) + + addi 2 + dup 1 + eq + assert + // _ *first_proof_item current_proof_item num_proof_items *proof proof_len + + + /* Verify sane sizes */ + push {Self::MAX_PROOF_SIZE} + dup 1 + lt + // _ *first_proof_item current_proof_item num_proof_items *proof proof_len (proof_len < MAX_SIZE) + + assert + + push {Self::MAX_NUM_PROOF_ITEMS} + dup 3 + lt + // _ *first_proof_item current_proof_item num_proof_items *proof proof_len (num_proof_items < MAX_NUM_ITEMS) + + assert + // _ *first_proof_item current_proof_item num_proof_items *proof proof_len + + + /* Verify that all of Proof lives in ND memory */ + dup 1 + pop_count + pop 1 + // _ *first_proof_item current_proof_item num_proof_items *proof proof_len + + dup 0 + pop_count + pop 1 + // _ *first_proof_item current_proof_item num_proof_items *proof proof_len + + dup 1 + dup 1 + add + pop_count + pop 1 + - push {Self::FIRST_PROOF_ITEM_OFFSET} add - // _ *first_proof_item + /* Write proof information to memory */ + pick 4 + // _ current_proof_item num_proof_items *proof proof_len *first_proof_item call {dyn_malloc} - // _ *first_proof_item *vm_proof_iter + // _ current_proof_item num_proof_items *proof proof_len *first_proof_item *vm_proof_iter - write_mem 1 - // _ (*vm_proof_iter + 1) + write_mem 5 + // _ (*vm_proof_iter + 5) - push -1 - add + addi -5 // _ *vm_proof_iter return @@ -57,19 +138,52 @@ impl BasicSnippet for New { mod tests { use std::collections::HashMap; + use rand::rngs::StdRng; + use rand::Rng; + use rand::SeedableRng; + use triton_vm::proof_item::ProofItem; + use triton_vm::proof_stream::ProofStream; + use super::*; + use crate::memory::encode_to_memory; + use crate::prelude::TasmObject; use crate::rust_shadowing_helper_functions; use crate::snippet_bencher::BenchmarkCase; use crate::traits::function::Function; use crate::traits::function::FunctionInitialState; use crate::traits::function::ShadowedFunction; use crate::traits::rust_shadow::RustShadow; + use crate::verifier::proof_for_nd_memory::ProofForNdMemory; + use crate::verifier::vm_proof_iter::shared::vm_proof_iter_struct::VmProofIter; #[test] fn vm_proof_iter_new_pbt() { ShadowedFunction::new(New).test() } + impl New { + fn init_state( + &self, + proof_items: Vec, + proof_pointer: BFieldElement, + ) -> FunctionInitialState { + let mut proof_stream = ProofStream::default(); + for proof_item in proof_items { + proof_stream.enqueue(proof_item); + } + + let proof: Proof = proof_stream.into(); + let proof: ProofForNdMemory = proof.try_into().unwrap(); + let mut memory = HashMap::default(); + encode_to_memory(&mut memory, proof_pointer, &proof); + + FunctionInitialState { + stack: [self.init_stack_for_isolated_run(), vec![proof_pointer]].concat(), + memory, + } + } + } + impl Function for New { fn rust_shadow( &self, @@ -77,22 +191,25 @@ mod tests { memory: &mut HashMap, ) { let pointer_to_proof = stack.pop().unwrap(); - let pointer_to_first_element = pointer_to_proof + bfe!(Self::FIRST_PROOF_ITEM_OFFSET); + let proof = *ProofForNdMemory::decode_from_memory(memory, pointer_to_proof).unwrap(); let pointer_to_vm_proof_iter = rust_shadowing_helper_functions::dyn_malloc::dynamic_allocator(memory); - memory.insert(pointer_to_vm_proof_iter, pointer_to_first_element); + let vm_proof_iter = VmProofIter::new(pointer_to_proof, &proof.into()); + encode_to_memory(memory, pointer_to_vm_proof_iter, &vm_proof_iter); stack.push(pointer_to_vm_proof_iter); } fn pseudorandom_initial_state( &self, - _seed: [u8; 32], + seed: [u8; 32], _bench_case: Option, ) -> FunctionInitialState { - FunctionInitialState { - stack: self.init_stack_for_isolated_run(), - memory: HashMap::default(), - } + let mut rng: StdRng = SeedableRng::from_seed(seed); + let proof_pointer = bfe!(rng.gen_range(0..(1 << 20))); + + let proof_items = vec![ProofItem::MerkleRoot(rng.gen())]; + + self.init_state(proof_items, proof_pointer) } } } diff --git a/tasm-lib/src/verifier/vm_proof_iter/shared.rs b/tasm-lib/src/verifier/vm_proof_iter/shared.rs index eea0c841..a8cd154f 100644 --- a/tasm-lib/src/verifier/vm_proof_iter/shared.rs +++ b/tasm-lib/src/verifier/vm_proof_iter/shared.rs @@ -3,7 +3,56 @@ use crate::data_type::StructType; pub fn vm_proof_iter_type() -> StructType { let name = "VmProofIter".to_string(); - let fields = vec![("current_item_pointer".to_string(), DataType::Bfe)]; + let current_item_pointer = ("current_item_pointer".to_string(), DataType::Bfe); + let current_item_count = ("current_item_count".to_string(), DataType::U32); + let total_item_count = ("total_item_count".to_string(), DataType::U32); + let proof_start_pointer = ("proof_start_pointer".to_string(), DataType::Bfe); + let proof_length = ("proof_length".to_string(), DataType::U32); + + let fields = vec![ + current_item_count, + total_item_count, + proof_start_pointer, + proof_length, + current_item_pointer, + ]; StructType { name, fields } } + +#[cfg(test)] +pub(super) mod vm_proof_iter_struct { + use triton_vm::prelude::bfe; + use triton_vm::prelude::BFieldCodec; + use triton_vm::prelude::BFieldElement; + use triton_vm::proof::Proof; + use triton_vm::proof_stream::ProofStream; + + use crate::prelude::TasmObject; + + /// Represent Triton VM's knowledge about a proof. + #[derive(Debug, Clone, Copy, Eq, PartialEq, BFieldCodec, TasmObject)] + pub(crate) struct VmProofIter { + pub(crate) current_item_count: u32, + pub(crate) total_item_count: u32, + pub(crate) proof_start_pointer: BFieldElement, + pub(crate) proof_length: u32, + pub(crate) current_item_pointer: BFieldElement, + } + + impl VmProofIter { + pub(crate) fn new(proof_pointer: BFieldElement, proof: &Proof) -> Self { + let proof_length = proof.0.len() + 1; + let proof_stream: ProofStream = proof.try_into().unwrap(); + VmProofIter { + current_item_count: 0, + total_item_count: proof_stream.items.len().try_into().unwrap(), + proof_start_pointer: proof_pointer, + proof_length: proof_length.try_into().unwrap(), + + // uses highly specific knowledge of `BFieldCodec` + current_item_pointer: proof_pointer + bfe!(4), + } + } + } +}