diff --git a/tasm-lib/Cargo.toml b/tasm-lib/Cargo.toml index 58f64886..91b02014 100644 --- a/tasm-lib/Cargo.toml +++ b/tasm-lib/Cargo.toml @@ -32,13 +32,16 @@ itertools = "0" ndarray = { version = "0.16" } num = "0" num-traits = "0" -rand = "0.9.0" +rand = "0.9.1" serde = { version = "1", features = ["derive"] } serde_json = "1" strum = { version = "0.27", features = ["derive"] } tasm-object-derive.workspace = true triton-vm = { version = "0.48.0", default-features = false } +# revision "8b372a513c5b0c91578b62c902219818f5d76d2d" is tip of tip of PR branch asz/merkle-tree-index-types on 2025-05-06 +twenty-first = { git = "https://github.com/Neptune-Crypto/twenty-first", rev = "8b372a513c5b0c91578b62c902219818f5d76d2d" } + [dev-dependencies.cargo-husky] version = "1" default-features = false diff --git a/tasm-lib/benchmarks/tasmlib_mmr_authentication_struct_derive_challenges.json b/tasm-lib/benchmarks/tasmlib_mmr_authentication_struct_derive_challenges.json new file mode 100644 index 00000000..a6cb3ac1 --- /dev/null +++ b/tasm-lib/benchmarks/tasmlib_mmr_authentication_struct_derive_challenges.json @@ -0,0 +1,24 @@ +[ + { + "name": "tasmlib_mmr_authentication_struct_derive_challenges", + "benchmark_result": { + "clock_cycle_count": 1118, + "hash_table_height": 955, + "u32_table_height": 30, + "op_stack_table_height": 777, + "ram_table_height": 1439 + }, + "case": "CommonCase" + }, + { + "name": "tasmlib_mmr_authentication_struct_derive_challenges", + "benchmark_result": { + "clock_cycle_count": 2042, + "hash_table_height": 1879, + "u32_table_height": 26, + "op_stack_table_height": 1393, + "ram_table_height": 2974 + }, + "case": "WorstCase" + } +] \ No newline at end of file diff --git a/tasm-lib/benchmarks/tasmlib_mmr_root_from_authentication_struct.json b/tasm-lib/benchmarks/tasmlib_mmr_root_from_authentication_struct.json new file mode 100644 index 00000000..dd1afaad --- /dev/null +++ b/tasm-lib/benchmarks/tasmlib_mmr_root_from_authentication_struct.json @@ -0,0 +1,24 @@ +[ + { + "name": "tasmlib_mmr_root_from_authentication_struct", + "benchmark_result": { + "clock_cycle_count": 21481, + "hash_table_height": 1759, + "u32_table_height": 3034, + "op_stack_table_height": 33368, + "ram_table_height": 9732 + }, + "case": "CommonCase" + }, + { + "name": "tasmlib_mmr_root_from_authentication_struct", + "benchmark_result": { + "clock_cycle_count": 25081, + "hash_table_height": 1975, + "u32_table_height": 1805, + "op_stack_table_height": 38936, + "ram_table_height": 11316 + }, + "case": "WorstCase" + } +] \ No newline at end of file diff --git a/tasm-lib/src/arithmetic/bfe/primitive_root_of_unity.rs b/tasm-lib/src/arithmetic/bfe/primitive_root_of_unity.rs index efa4954f..3469adc5 100644 --- a/tasm-lib/src/arithmetic/bfe/primitive_root_of_unity.rs +++ b/tasm-lib/src/arithmetic/bfe/primitive_root_of_unity.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; +use triton_vm::prelude::twenty_first::math::traits::PrimitiveRootOfUnity as PRU; use triton_vm::prelude::*; -use twenty_first::math::traits::PrimitiveRootOfUnity as PRU; use crate::prelude::*; use crate::traits::basic_snippet::Reviewer; diff --git a/tasm-lib/src/arithmetic/xfe/mod_pow_u32.rs b/tasm-lib/src/arithmetic/xfe/mod_pow_u32.rs index 0098b289..e4ae2b37 100644 --- a/tasm-lib/src/arithmetic/xfe/mod_pow_u32.rs +++ b/tasm-lib/src/arithmetic/xfe/mod_pow_u32.rs @@ -142,7 +142,7 @@ impl BasicSnippet for XfeModPowU32 { #[cfg(test)] pub mod tests { - use twenty_first::math::traits::ModPowU32; + use triton_vm::prelude::twenty_first::math::traits::ModPowU32; use super::*; use crate::empty_stack; diff --git a/tasm-lib/src/arithmetic/xfe/to_the_power_of_power_of_2.rs b/tasm-lib/src/arithmetic/xfe/to_the_power_of_power_of_2.rs index 5399e107..ef34f71e 100644 --- a/tasm-lib/src/arithmetic/xfe/to_the_power_of_power_of_2.rs +++ b/tasm-lib/src/arithmetic/xfe/to_the_power_of_power_of_2.rs @@ -90,7 +90,7 @@ impl BasicSnippet for ToThePowerOfPowerOf2 { #[cfg(test)] mod tests { - use twenty_first::math::traits::ModPowU32; + use triton_vm::prelude::twenty_first::math::traits::ModPowU32; use super::*; use crate::arithmetic::xfe::mod_pow_u32::XfeModPowU32; diff --git a/tasm-lib/src/array/sum_of_xfes.rs b/tasm-lib/src/array/sum_of_xfes.rs index 52aae39e..c7fbd216 100644 --- a/tasm-lib/src/array/sum_of_xfes.rs +++ b/tasm-lib/src/array/sum_of_xfes.rs @@ -1,6 +1,6 @@ use num::Zero; +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use triton_vm::prelude::*; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; use crate::data_type::ArrayType; use crate::memory::load_words_from_memory_pop_pointer; diff --git a/tasm-lib/src/hashing/absorb_multiple.rs b/tasm-lib/src/hashing/absorb_multiple.rs index 8c777c34..8e43467f 100644 --- a/tasm-lib/src/hashing/absorb_multiple.rs +++ b/tasm-lib/src/hashing/absorb_multiple.rs @@ -146,7 +146,7 @@ impl BasicSnippet for AbsorbMultiple { mod tests { use std::collections::VecDeque; - use twenty_first::prelude::Sponge; + use triton_vm::prelude::twenty_first::prelude::Sponge; use super::*; use crate::empty_stack; diff --git a/tasm-lib/src/hashing/absorb_multiple_static_size.rs b/tasm-lib/src/hashing/absorb_multiple_static_size.rs index a7962c5e..ffa8e6b5 100644 --- a/tasm-lib/src/hashing/absorb_multiple_static_size.rs +++ b/tasm-lib/src/hashing/absorb_multiple_static_size.rs @@ -1,5 +1,5 @@ +use triton_vm::prelude::twenty_first::math::tip5::RATE; use triton_vm::prelude::*; -use twenty_first::math::tip5::RATE; use crate::memory::load_words_from_memory_pop_pointer; use crate::prelude::*; @@ -102,7 +102,7 @@ impl BasicSnippet for AbsorbMultipleStaticSize { #[cfg(test)] mod tests { - use twenty_first::prelude::Sponge; + use triton_vm::prelude::twenty_first::prelude::Sponge; use super::*; use crate::test_prelude::*; diff --git a/tasm-lib/src/hashing/algebraic_hasher/hash_static_size.rs b/tasm-lib/src/hashing/algebraic_hasher/hash_static_size.rs index 870b09f7..68019bec 100644 --- a/tasm-lib/src/hashing/algebraic_hasher/hash_static_size.rs +++ b/tasm-lib/src/hashing/algebraic_hasher/hash_static_size.rs @@ -53,7 +53,7 @@ impl BasicSnippet for HashStaticSize { #[cfg(test)] mod tests { - use twenty_first::prelude::*; + use triton_vm::prelude::twenty_first::prelude::*; use super::*; use crate::test_prelude::*; diff --git a/tasm-lib/src/hashing/algebraic_hasher/hash_varlen.rs b/tasm-lib/src/hashing/algebraic_hasher/hash_varlen.rs index ab659827..4da808dc 100644 --- a/tasm-lib/src/hashing/algebraic_hasher/hash_varlen.rs +++ b/tasm-lib/src/hashing/algebraic_hasher/hash_varlen.rs @@ -73,7 +73,7 @@ impl BasicSnippet for HashVarlen { mod tests { use std::collections::VecDeque; - use twenty_first::prelude::*; + use triton_vm::prelude::twenty_first::prelude::*; use super::*; use crate::empty_stack; diff --git a/tasm-lib/src/hashing/algebraic_hasher/sample_scalar_one.rs b/tasm-lib/src/hashing/algebraic_hasher/sample_scalar_one.rs index 98b3d87a..1416e6b7 100644 --- a/tasm-lib/src/hashing/algebraic_hasher/sample_scalar_one.rs +++ b/tasm-lib/src/hashing/algebraic_hasher/sample_scalar_one.rs @@ -46,8 +46,8 @@ impl BasicSnippet for SampleScalarOne { #[cfg(test)] mod tests { - use twenty_first::math::x_field_element::EXTENSION_DEGREE; - use twenty_first::util_types::sponge::Sponge; + use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; + use triton_vm::prelude::twenty_first::util_types::sponge::Sponge; use super::*; use crate::test_prelude::*; diff --git a/tasm-lib/src/hashing/algebraic_hasher/sample_scalars.rs b/tasm-lib/src/hashing/algebraic_hasher/sample_scalars.rs index ade4859c..d7f8b96a 100644 --- a/tasm-lib/src/hashing/algebraic_hasher/sample_scalars.rs +++ b/tasm-lib/src/hashing/algebraic_hasher/sample_scalars.rs @@ -1,5 +1,5 @@ +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use triton_vm::prelude::*; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; use crate::hashing::squeeze_repeatedly::SqueezeRepeatedly; use crate::list::new::New; @@ -80,7 +80,7 @@ impl BasicSnippet for SampleScalars { #[cfg(test)] mod tests { - use twenty_first::prelude::*; + use triton_vm::prelude::twenty_first::prelude::*; use super::*; use crate::empty_stack; diff --git a/tasm-lib/src/hashing/algebraic_hasher/sample_scalars_static_length_dyn_malloc.rs b/tasm-lib/src/hashing/algebraic_hasher/sample_scalars_static_length_dyn_malloc.rs index 0109bb1e..bd4c5ea7 100644 --- a/tasm-lib/src/hashing/algebraic_hasher/sample_scalars_static_length_dyn_malloc.rs +++ b/tasm-lib/src/hashing/algebraic_hasher/sample_scalars_static_length_dyn_malloc.rs @@ -1,6 +1,6 @@ +use triton_vm::prelude::twenty_first::math::tip5::RATE; +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use triton_vm::prelude::*; -use twenty_first::math::tip5::RATE; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; use crate::data_type::ArrayType; use crate::hashing::squeeze_repeatedly_static_number::SqueezeRepeatedlyStaticNumber; @@ -79,7 +79,7 @@ impl BasicSnippet for SampleScalarsStaticLengthDynMalloc { #[cfg(test)] mod tests { - use twenty_first::prelude::*; + use triton_vm::prelude::twenty_first::prelude::*; use super::*; use crate::memory::dyn_malloc::DYN_MALLOC_FIRST_ADDRESS; diff --git a/tasm-lib/src/hashing/algebraic_hasher/sample_scalars_static_length_kmalloc.rs b/tasm-lib/src/hashing/algebraic_hasher/sample_scalars_static_length_kmalloc.rs index d265401b..69ed6854 100644 --- a/tasm-lib/src/hashing/algebraic_hasher/sample_scalars_static_length_kmalloc.rs +++ b/tasm-lib/src/hashing/algebraic_hasher/sample_scalars_static_length_kmalloc.rs @@ -1,6 +1,6 @@ +use triton_vm::prelude::twenty_first::math::tip5::RATE; +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use triton_vm::prelude::*; -use twenty_first::math::tip5::RATE; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; use crate::hashing::algebraic_hasher::sample_scalars_static_length_dyn_malloc::SampleScalarsStaticLengthDynMalloc; use crate::hashing::squeeze_repeatedly_static_number::SqueezeRepeatedlyStaticNumber; @@ -84,7 +84,7 @@ impl BasicSnippet for SampleScalarsStaticLengthKMalloc { pub(crate) mod tests { use std::ops::Neg; - use twenty_first::util_types::sponge::Sponge; + use triton_vm::prelude::twenty_first::util_types::sponge::Sponge; use super::*; use crate::rust_shadowing_helper_functions::array::array_get; diff --git a/tasm-lib/src/hashing/algebraic_hasher/sample_scalars_static_length_static_pointer.rs b/tasm-lib/src/hashing/algebraic_hasher/sample_scalars_static_length_static_pointer.rs index 49ee137c..25a759a6 100644 --- a/tasm-lib/src/hashing/algebraic_hasher/sample_scalars_static_length_static_pointer.rs +++ b/tasm-lib/src/hashing/algebraic_hasher/sample_scalars_static_length_static_pointer.rs @@ -1,6 +1,6 @@ +use triton_vm::prelude::twenty_first::math::tip5::RATE; +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use triton_vm::prelude::*; -use twenty_first::math::tip5::RATE; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; use crate::hashing::algebraic_hasher::sample_scalars_static_length_dyn_malloc::SampleScalarsStaticLengthDynMalloc; use crate::hashing::squeeze_repeatedly_static_number::SqueezeRepeatedlyStaticNumber; @@ -72,7 +72,7 @@ impl BasicSnippet for SampleScalarsStaticLengthStaticPointer { #[cfg(test)] pub(crate) mod tests { - use twenty_first::util_types::sponge::Sponge; + use triton_vm::prelude::twenty_first::util_types::sponge::Sponge; use super::*; use crate::prelude::Tip5; diff --git a/tasm-lib/src/hashing/hash_from_stack.rs b/tasm-lib/src/hashing/hash_from_stack.rs index cd265831..d7385e9d 100644 --- a/tasm-lib/src/hashing/hash_from_stack.rs +++ b/tasm-lib/src/hashing/hash_from_stack.rs @@ -1,5 +1,5 @@ +use triton_vm::prelude::twenty_first::prelude::*; use triton_vm::prelude::*; -use twenty_first::prelude::*; use crate::prelude::*; diff --git a/tasm-lib/src/hashing/merkle_root.rs b/tasm-lib/src/hashing/merkle_root.rs index 3f2872d7..507cce91 100644 --- a/tasm-lib/src/hashing/merkle_root.rs +++ b/tasm-lib/src/hashing/merkle_root.rs @@ -205,8 +205,8 @@ impl BasicSnippet for MerkleRoot { #[cfg(test)] mod tests { + use ::twenty_first::util_types::merkle_tree::MerkleTree; use proptest::collection::vec; - use twenty_first::util_types::merkle_tree::MerkleTree; use super::*; use crate::rust_shadowing_helper_functions::dyn_malloc::dynamic_allocator; @@ -234,19 +234,31 @@ mod tests { memory: &mut HashMap, ) { let leafs_pointer = stack.pop().unwrap(); - let leafs = *Vec::decode_from_memory(memory, leafs_pointer).unwrap(); - let mt = MerkleTree::par_new(&leafs).unwrap(); + let leafs = *Vec::::decode_from_memory(memory, leafs_pointer).unwrap(); + let leafs_compatible = leafs + .iter() + .map(|d| { + d.values() + .map(|b| ::twenty_first::prelude::BFieldElement::new(b.value())) + }) + .map(::twenty_first::prelude::Digest) + .collect_vec(); + let mt = MerkleTree::par_new(&leafs_compatible).unwrap(); // mimic snippet: write internal nodes to memory, skipping (dummy) node 0 let tree_pointer = dynamic_allocator(memory); let num_internal_nodes = leafs.len(); - for (node_index, node) in (0..num_internal_nodes).zip(mt.nodes()).skip(1) { - let node_address = tree_pointer + bfe!(node_index * Digest::LEN); - encode_to_memory(memory, node_address, node); + for node_index in 1_u64..(num_internal_nodes as u64) { + let node = mt.node(node_index).unwrap(); + let node_address = tree_pointer + bfe!(node_index * (Digest::LEN as u64)); + let node_compatible = Digest(node.values().map(|b| BFieldElement::new(b.value()))); + encode_to_memory(memory, node_address, &node_compatible); } - stack.extend(mt.root().reversed().values()); + let root = mt.root().reversed().values(); + let root_compatible = root.map(|b| BFieldElement::new(b.value())); + stack.extend(root_compatible); } fn pseudorandom_initial_state( diff --git a/tasm-lib/src/hashing/merkle_root_from_xfes.rs b/tasm-lib/src/hashing/merkle_root_from_xfes.rs index 63f2b6a3..d9f82b73 100644 --- a/tasm-lib/src/hashing/merkle_root_from_xfes.rs +++ b/tasm-lib/src/hashing/merkle_root_from_xfes.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use triton_vm::prelude::*; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; use crate::hashing::merkle_root::MerkleRoot; use crate::prelude::*; @@ -209,8 +209,8 @@ impl BasicSnippet for MerkleRootFromXfes { #[cfg(test)] mod tests { + use ::twenty_first::prelude::MerkleTree; use proptest::collection::vec; - use twenty_first::util_types::merkle_tree::MerkleTree; use super::*; use crate::rust_shadowing_helper_functions::dyn_malloc::dynamic_allocator; @@ -244,10 +244,21 @@ mod tests { let leafs_pointer = stack.pop().unwrap(); let leafs = *Vec::::decode_from_memory(memory, leafs_pointer).unwrap(); let leafs = leafs.into_iter().map(Digest::from).collect_vec(); - let mt = MerkleTree::par_new(&leafs).unwrap(); + let leafs_compatible = leafs + .iter() + .map(|d| { + d.values() + .map(|v| v.value()) + .map(::twenty_first::prelude::BFieldElement::from) + }) + .map(::twenty_first::prelude::Digest) + .collect_vec(); + let mt = MerkleTree::par_new(&leafs_compatible).unwrap(); if leafs.len() == 1 { - stack.extend(mt.root().reversed().values()); + let root = mt.root().reversed().values(); + let root_compatible = root.map(|v| BFieldElement::new(v.value())); + stack.extend(root_compatible); return; } @@ -255,22 +266,31 @@ mod tests { let first_layer_pointer = dynamic_allocator(memory); list_new(first_layer_pointer, memory); for node_count in 0..(leafs.len() >> 1) { - let node_index = node_count + (1 << (mt.height() - 1)); + let node_index = (node_count as u64) + (1 << (mt.height() - 1)); let node = mt.node(node_index).unwrap(); - list_push(first_layer_pointer, node.values().to_vec(), memory) + let node_values = node.values().to_vec(); + let node_values_compatible = node_values + .into_iter() + .map(|b| BFieldElement::new(b.value())) + .collect_vec(); + list_push(first_layer_pointer, node_values_compatible, memory) } let rest_of_tree_pointer = dynamic_allocator(memory); for layer in 2..=mt.height() { for node_count in 0..(leafs.len() >> layer) { - let node_index = node_count + (1 << (mt.height() - layer)); + let node_index = (node_count as u64) + (1 << (mt.height() - layer)); let node = mt.node(node_index).unwrap(); - let pointer = rest_of_tree_pointer + bfe!(node_index * Digest::LEN); - encode_to_memory(memory, pointer, &node); + let pointer = rest_of_tree_pointer + bfe!(node_index * (Digest::LEN as u64)); + let node_compatible = + Digest(node.values().map(|b| BFieldElement::new(b.value()))); + encode_to_memory(memory, pointer, &node_compatible); } } - stack.extend(mt.root().reversed().values()); + let root = mt.root().reversed().values(); + let root_compatible = root.map(|b| BFieldElement::new(b.value())); + stack.extend(root_compatible); } fn pseudorandom_initial_state( diff --git a/tasm-lib/src/hashing/sponge_hasher/absorb.rs b/tasm-lib/src/hashing/sponge_hasher/absorb.rs index 6ce2ebcb..78beee63 100644 --- a/tasm-lib/src/hashing/sponge_hasher/absorb.rs +++ b/tasm-lib/src/hashing/sponge_hasher/absorb.rs @@ -1,5 +1,5 @@ +use triton_vm::prelude::twenty_first::math::tip5::RATE; use triton_vm::prelude::*; -use twenty_first::math::tip5::RATE; use crate::data_type::ArrayType; use crate::prelude::*; @@ -76,8 +76,8 @@ impl BasicSnippet for Absorb { mod tests { use arbitrary::Arbitrary; use arbitrary::Unstructured; - use twenty_first::math::other::random_elements; - use twenty_first::prelude::Sponge; + use triton_vm::prelude::twenty_first::math::other::random_elements; + use triton_vm::prelude::twenty_first::prelude::Sponge; use super::*; use crate::empty_stack; diff --git a/tasm-lib/src/hashing/sponge_hasher/init.rs b/tasm-lib/src/hashing/sponge_hasher/init.rs index 4b862343..e61f7476 100644 --- a/tasm-lib/src/hashing/sponge_hasher/init.rs +++ b/tasm-lib/src/hashing/sponge_hasher/init.rs @@ -32,7 +32,7 @@ impl BasicSnippet for Init { mod tests { use arbitrary::Arbitrary; use arbitrary::Unstructured; - use twenty_first::prelude::Sponge; + use triton_vm::prelude::twenty_first::prelude::Sponge; use super::*; use crate::empty_stack; diff --git a/tasm-lib/src/hashing/sponge_hasher/pad_and_absorb_all.rs b/tasm-lib/src/hashing/sponge_hasher/pad_and_absorb_all.rs index d5760e2b..2a99b33b 100644 --- a/tasm-lib/src/hashing/sponge_hasher/pad_and_absorb_all.rs +++ b/tasm-lib/src/hashing/sponge_hasher/pad_and_absorb_all.rs @@ -48,8 +48,8 @@ impl BasicSnippet for PadAndAbsorbAll { mod tests { use arbitrary::Arbitrary; use arbitrary::Unstructured; + use triton_vm::prelude::twenty_first::prelude::Sponge; use triton_vm::prelude::*; - use twenty_first::prelude::Sponge; use super::*; use crate::empty_stack; diff --git a/tasm-lib/src/hashing/sponge_hasher/squeeze.rs b/tasm-lib/src/hashing/sponge_hasher/squeeze.rs index 738a8b9d..a151df61 100644 --- a/tasm-lib/src/hashing/sponge_hasher/squeeze.rs +++ b/tasm-lib/src/hashing/sponge_hasher/squeeze.rs @@ -1,5 +1,5 @@ +use triton_vm::prelude::twenty_first::math::tip5::RATE; use triton_vm::prelude::*; -use twenty_first::math::tip5::RATE; use crate::data_type::ArrayType; use crate::prelude::*; @@ -66,7 +66,7 @@ impl BasicSnippet for Squeeze { mod tests { use arbitrary::Arbitrary; use arbitrary::Unstructured; - use twenty_first::prelude::Sponge; + use triton_vm::prelude::twenty_first::prelude::Sponge; use super::*; use crate::empty_stack; diff --git a/tasm-lib/src/hashing/squeeze_repeatedly.rs b/tasm-lib/src/hashing/squeeze_repeatedly.rs index a697c199..9dc51d2f 100644 --- a/tasm-lib/src/hashing/squeeze_repeatedly.rs +++ b/tasm-lib/src/hashing/squeeze_repeatedly.rs @@ -55,7 +55,7 @@ impl BasicSnippet for SqueezeRepeatedly { #[cfg(test)] mod tests { - use twenty_first::prelude::Sponge; + use triton_vm::prelude::twenty_first::prelude::Sponge; use super::*; use crate::empty_stack; diff --git a/tasm-lib/src/hashing/squeeze_repeatedly_static_number.rs b/tasm-lib/src/hashing/squeeze_repeatedly_static_number.rs index 79f6c2cc..841b8476 100644 --- a/tasm-lib/src/hashing/squeeze_repeatedly_static_number.rs +++ b/tasm-lib/src/hashing/squeeze_repeatedly_static_number.rs @@ -1,5 +1,5 @@ +use triton_vm::prelude::twenty_first::math::tip5::RATE; use triton_vm::prelude::*; -use twenty_first::math::tip5::RATE; use crate::prelude::*; diff --git a/tasm-lib/src/list/horner_evaluation_dynamic_length.rs b/tasm-lib/src/list/horner_evaluation_dynamic_length.rs index 2ea8564f..73fb8061 100644 --- a/tasm-lib/src/list/horner_evaluation_dynamic_length.rs +++ b/tasm-lib/src/list/horner_evaluation_dynamic_length.rs @@ -99,7 +99,7 @@ impl BasicSnippet for HornerEvaluationDynamicLength { #[cfg(test)] mod tests { use itertools::Itertools; - use twenty_first::math::polynomial::Polynomial; + use triton_vm::prelude::twenty_first::math::polynomial::Polynomial; use super::*; use crate::test_prelude::*; diff --git a/tasm-lib/src/list/multiset_equality_digests.rs b/tasm-lib/src/list/multiset_equality_digests.rs index ecf690e9..6a406a7d 100644 --- a/tasm-lib/src/list/multiset_equality_digests.rs +++ b/tasm-lib/src/list/multiset_equality_digests.rs @@ -227,7 +227,7 @@ impl BasicSnippet for MultisetEqualityDigests { #[cfg(test)] mod tests { use num::One; - use twenty_first::math::other::random_elements; + use triton_vm::prelude::twenty_first::math::other::random_elements; use super::*; use crate::empty_stack; diff --git a/tasm-lib/src/list/multiset_equality_u64s.rs b/tasm-lib/src/list/multiset_equality_u64s.rs index 7e3eaa4f..29c4b725 100644 --- a/tasm-lib/src/list/multiset_equality_u64s.rs +++ b/tasm-lib/src/list/multiset_equality_u64s.rs @@ -1,5 +1,5 @@ +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use triton_vm::prelude::*; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; use crate::hashing::algebraic_hasher::hash_varlen::HashVarlen; use crate::prelude::*; diff --git a/tasm-lib/src/list/sum_xfes.rs b/tasm-lib/src/list/sum_xfes.rs index 15b4496f..9d33318d 100644 --- a/tasm-lib/src/list/sum_xfes.rs +++ b/tasm-lib/src/list/sum_xfes.rs @@ -1,5 +1,5 @@ +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use triton_vm::prelude::*; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; use crate::prelude::*; @@ -181,7 +181,7 @@ impl BasicSnippet for SumOfXfes { #[cfg(test)] mod tests { - use twenty_first::math::x_field_element::EXTENSION_DEGREE; + use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use super::*; use crate::rust_shadowing_helper_functions::list::insert_random_list; diff --git a/tasm-lib/src/mmr.rs b/tasm-lib/src/mmr.rs index cf240a9d..803819ec 100644 --- a/tasm-lib/src/mmr.rs +++ b/tasm-lib/src/mmr.rs @@ -1,3 +1,4 @@ +pub mod authentication_struct; pub mod bag_peaks; pub mod calculate_new_peaks_from_append; pub mod calculate_new_peaks_from_leaf_mutation; diff --git a/tasm-lib/src/mmr/authentication_struct.rs b/tasm-lib/src/mmr/authentication_struct.rs new file mode 100644 index 00000000..2406a8f5 --- /dev/null +++ b/tasm-lib/src/mmr/authentication_struct.rs @@ -0,0 +1,3 @@ +pub mod derive_challenges; +pub mod root_from_authentication_struct; +pub mod shared; diff --git a/tasm-lib/src/mmr/authentication_struct/derive_challenges.rs b/tasm-lib/src/mmr/authentication_struct/derive_challenges.rs new file mode 100644 index 00000000..93e2a1e1 --- /dev/null +++ b/tasm-lib/src/mmr/authentication_struct/derive_challenges.rs @@ -0,0 +1,245 @@ +use triton_vm::prelude::*; + +use crate::data_type::DataType; +use crate::hashing::absorb_multiple::AbsorbMultiple; +use crate::mmr::authentication_struct::shared; +use crate::prelude::BasicSnippet; +use crate::prelude::Library; + +/// Derive and return the challenges that the authentication structure verification +/// program uses. +pub struct DeriveChallenges; + +impl BasicSnippet for DeriveChallenges { + fn inputs(&self) -> Vec<(DataType, String)> { + vec![ + ( + DataType::List(Box::new(DataType::Digest)), + "auth_struct".to_owned(), + ), + ( + DataType::List(Box::new(shared::indexed_leaf_element_type())), + "indexed_leafs".to_owned(), + ), + ] + } + + fn outputs(&self) -> Vec<(DataType, String)> { + vec![ + (DataType::Xfe, "alpha".to_owned()), + (DataType::Xfe, "-beta".to_owned()), + (DataType::Xfe, "gamma".to_owned()), + ] + } + + fn entrypoint(&self) -> String { + "tasmlib_mmr_authentication_struct_derive_challenges".to_owned() + } + + fn code(&self, library: &mut Library) -> Vec { + let absorb_multiple = library.import(Box::new(AbsorbMultiple)); + + let entrypoint = self.entrypoint(); + + let indexed_leaf_element_size = shared::indexed_leaf_element_type().stack_size(); + triton_asm!( + {entrypoint}: + // _ *auth_struct *indexed_leafs + + sponge_init + // _ *auth_struct *indexed_leafs + + read_mem 1 + addi 1 + // _ *auth_struct indexed_leafs_len *indexed_leafs + + swap 1 + // _ *auth_struct *indexed_leafs indexed_leafs_len + + push {indexed_leaf_element_size} + mul + addi 1 + // _ *auth_struct *indexed_leafs indexed_leafs_size + + call {absorb_multiple} + // _ *auth_struct + + read_mem 1 + addi 1 + // _ auth_struct_len *auth_struct + + swap 1 + push {Digest::LEN} + mul + addi 1 + // _ *auth_struct auth_struct_size + + call {absorb_multiple} + // _ + + sponge_squeeze + // _ w9 w8 w7 w6 w5 w4 w3 w2 w1 w0 + + pop 1 + // _ w9 w8 w7 w6 w5 w4 w3 w2 w1 + // _ [gamma] [-beta] [alpha] <- rename + + return + ) + } +} + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + use std::collections::VecDeque; + + use itertools::Itertools; + use num::One; + use rand::Rng; + use rand::SeedableRng; + use rand::rngs::StdRng; + use shared::AuthenticatedMerkleAuthStruct; + use triton_vm::prelude::twenty_first::prelude::Sponge; + use triton_vm::prelude::twenty_first::util_types::mmr::mmr_accumulator::util::mmra_with_mps; + + use crate::mmr::authentication_struct::shared::AuthStructIntegrityProof; + use crate::rust_shadowing_helper_functions::list::list_insert; + use crate::rust_shadowing_helper_functions::list::load_list_with_copy_elements; + use crate::snippet_bencher::BenchmarkCase; + use crate::test_prelude::MemPreserver; + use crate::test_prelude::MemPreserverInitialState; + use crate::test_prelude::ShadowedMemPreserver; + use crate::traits::rust_shadow::RustShadow; + + use super::*; + + const SIZE_OF_INDEXED_LEAFS_ELEMENT: usize = Digest::LEN + 2; + + #[test] + fn test() { + ShadowedMemPreserver::new(DeriveChallenges).test(); + } + + impl MemPreserver for DeriveChallenges { + fn rust_shadow( + &self, + stack: &mut Vec, + memory: &HashMap, + _nd_tokens: VecDeque, + _nd_digests: VecDeque, + _stdin: VecDeque, + sponge: &mut Option, + ) -> Vec { + let indexed_leafs_pointer = stack.pop().unwrap(); + let auth_struct_pointer = stack.pop().unwrap(); + let bfes_to_indexed_leaf = + |bfes: [BFieldElement; SIZE_OF_INDEXED_LEAFS_ELEMENT]| -> (u64, Digest) { + *<(u64, Digest)>::decode(&bfes).unwrap() + }; + let bfes_to_digest = |bfes: [BFieldElement; Digest::LEN]| -> Digest { + *Digest::decode(&bfes[0..Digest::LEN]).unwrap() + }; + let indexed_leafs: Vec<[BFieldElement; SIZE_OF_INDEXED_LEAFS_ELEMENT]> = + load_list_with_copy_elements(indexed_leafs_pointer, memory); + let indexed_leafs = indexed_leafs + .into_iter() + .map(bfes_to_indexed_leaf) + .collect_vec(); + let auth_struct: Vec<[BFieldElement; Digest::LEN]> = + load_list_with_copy_elements(auth_struct_pointer, memory); + let auth_struct = auth_struct.into_iter().map(bfes_to_digest).collect_vec(); + + let sponge = sponge.as_mut().expect("sponge must be initialized"); + + sponge.pad_and_absorb_all(&indexed_leafs.encode()); + sponge.pad_and_absorb_all(&auth_struct.encode()); + + let sponge_output = sponge.squeeze(); + for elem in sponge_output.into_iter().skip(1).rev() { + stack.push(elem); + } + + vec![] + } + + fn pseudorandom_initial_state( + &self, + seed: [u8; 32], + bench_case: Option, + ) -> MemPreserverInitialState { + let mut rng: StdRng = SeedableRng::from_seed(seed); + + let (tree_height, num_revealed_leafs) = match bench_case { + Some(BenchmarkCase::CommonCase) => (32, 10), + Some(BenchmarkCase::WorstCase) => (62, 10), + None => (rng.random_range(0..62), 10), + }; + + let leaf_count = 1 << tree_height; + let revealed_leaf_indices = (0..num_revealed_leafs) + .map(|_| rng.random_range(0..leaf_count)) + .unique() + .collect_vec(); + let indexed_leafs = revealed_leaf_indices + .into_iter() + .map(|leaf_idx: u64| (leaf_idx, rng.random())) + .collect_vec(); + let (mmra, mps) = mmra_with_mps(leaf_count, indexed_leafs.clone()); + let indexed_mmr_mps = indexed_leafs + .into_iter() + .zip_eq(mps) + .map(|((leaf_idx, leaf), mp)| (leaf_idx, leaf, mp)) + .collect_vec(); + let authenticity_witnesses = + AuthStructIntegrityProof::new_from_mmr_membership_proofs(&mmra, indexed_mmr_mps); + assert!( + authenticity_witnesses.len().is_one(), + "All indices belong to first peak" + ); + let AuthenticatedMerkleAuthStruct { + auth_struct, + indexed_leafs, + .. + } = &authenticity_witnesses[&0]; + + let mut memory = HashMap::new(); + let authentication_structure_ptr = rng.random(); + let indexed_leafs_ptr = rng.random(); + + list_insert( + authentication_structure_ptr, + auth_struct.to_owned(), + &mut memory, + ); + list_insert(indexed_leafs_ptr, indexed_leafs.to_owned(), &mut memory); + + let stack = [ + self.init_stack_for_isolated_run(), + vec![authentication_structure_ptr, indexed_leafs_ptr], + ] + .concat(); + + let nondeterminism = NonDeterminism::default().with_ram(memory); + MemPreserverInitialState { + stack, + nondeterminism, + public_input: vec![].into(), + sponge_state: Some(Tip5::init()), + } + } + } +} + +#[cfg(test)] +mod benches { + use crate::test_prelude::ShadowedMemPreserver; + use crate::traits::rust_shadow::RustShadow; + + use super::*; + + #[test] + fn bag_peaks_benchmark() { + ShadowedMemPreserver::new(DeriveChallenges).bench(); + } +} diff --git a/tasm-lib/src/mmr/authentication_struct/root_from_authentication_struct.rs b/tasm-lib/src/mmr/authentication_struct/root_from_authentication_struct.rs new file mode 100644 index 00000000..9054d018 --- /dev/null +++ b/tasm-lib/src/mmr/authentication_struct/root_from_authentication_struct.rs @@ -0,0 +1,1044 @@ +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; +use triton_vm::prelude::*; + +use crate::data_type::DataType; +use crate::library::Library; +use crate::mmr::authentication_struct::derive_challenges::DeriveChallenges; +use crate::prelude::BasicSnippet; + +pub struct RootFromAuthenticationStruct; + +impl RootFromAuthenticationStruct { + fn indexed_leaf_element_type() -> DataType { + DataType::Tuple(vec![DataType::U64, DataType::Digest]) + } +} + +impl BasicSnippet for RootFromAuthenticationStruct { + fn inputs(&self) -> Vec<(DataType, String)> { + vec![ + (DataType::U32, "tree_height".to_owned()), + ( + DataType::List(Box::new(DataType::Digest)), + "auth_struct".to_owned(), + ), + ( + DataType::List(Box::new(Self::indexed_leaf_element_type())), + "indexed_leafs".to_owned(), + ), + ] + } + + fn outputs(&self) -> Vec<(DataType, String)> { + vec![(DataType::Digest, "root".to_owned())] + } + + fn entrypoint(&self) -> String { + "tasmlib_mmr_root_from_authentication_struct".to_owned() + } + + fn code(&self, library: &mut Library) -> Vec { + let alpha_challenge_allocation = library.kmalloc(EXTENSION_DEGREE as u32); + let beta_challenge_allocation = library.kmalloc(EXTENSION_DEGREE as u32); + let beta_challenge_read_address = beta_challenge_allocation.read_address(); + let gamma_challenge_allocation = library.kmalloc(EXTENSION_DEGREE as u32); + let gamma_challenge_read_address = gamma_challenge_allocation.read_address(); + let t_digest_allocation = library.kmalloc(Digest::LEN as u32); + let t_digest_write_address = t_digest_allocation.write_address(); + let t_digest_read_address = t_digest_allocation.read_address(); + let right_digest_allocation = library.kmalloc(Digest::LEN as u32); + let left_digest_allocation = library.kmalloc(Digest::LEN as u32); + + let indexed_leaf_element_size = Self::indexed_leaf_element_type().stack_size(); + let derive_challenges = library.import(Box::new(DeriveChallenges)); + let calculate_and_store_challenges = triton_asm!( + // _ *auth_struct *indexed_leafs + + call {derive_challenges} + hint alpha: XFieldElement = stack[0..3] + hint minus_beta: XFieldElement = stack[3..6] + hint gamma: XFieldElement = stack[6..9] + // _ [gamma] [-beta] [alpha] <- rename + + push {alpha_challenge_allocation.write_address()} + write_mem {EXTENSION_DEGREE} + pop 1 + // _ [gamma] [-beta] + + push {beta_challenge_allocation.write_address()} + write_mem {EXTENSION_DEGREE} + pop 1 + // _ [gamma] + + push {gamma_challenge_allocation.write_address()} + write_mem {EXTENSION_DEGREE} + pop 1 + // _ + ); + + let u64_size = DataType::U64.stack_size(); + const TWO_POW_32: u64 = 1 << 32; + let u64_to_bfe = triton_asm!( + // _ leaf_idx_hi leaf_idx_lo + + swap 1 + push {TWO_POW_32} + mul + // _ leaf_idx_lo (leaf_idx_hi << 32) + + add + + // _ leaf_idx_as_bfe + ); + + let digest_to_xfe = triton_asm!( + // _ [digest] + + push 1 + push {alpha_challenge_allocation.read_address()} + read_mem {EXTENSION_DEGREE} + pop 1 + // _ l4 l3 l2 l1 l0 1 [α; 3] + + xx_mul + // _ l4 l3 l2 [(l1 l0 1) * α] + + xx_add + // _ xfe + ); + + let entrypoint = self.entrypoint(); + let accumulate_indexed_leafs_loop_label = format!("{entrypoint}_acc_indexed_leafs"); + let accumulated_indexed_leafs_loop = triton_asm!( + // INVARIANT: _ num_leafs *auth_struct *idx_leafs *idx_leafs[n]_lw [0; 2] [p; 3] + {accumulate_indexed_leafs_loop_label}: + // _ num_leafs *auth_struct *idx_leafs *idx_leafs[n]_lw [0; 2] [p; 3] + + /* Read leaf-index, convert it to BFE, and multiply it with `gamma` challenge */ + push {gamma_challenge_read_address} + read_mem {EXTENSION_DEGREE} + pop 1 + // _ num_leafs *auth_struct *idx_leafs *idx_leafs[n]_lw [0; 2] [p; 3] [gamma] + // _ num_leafs *auth_struct *idx_leafs *idx_leafs[n]_lw [0; 2] [p; 3] [γ] <-- rename + + dup 8 + read_mem {u64_size} + swap 11 + pop 1 + // _ num_leafs *auth_struct *idx_leafs (*idx_leafs[n]_lw - 2) [0; 2] [p; 3] [γ] [leaf_idx; 2] + + // TODO: Assert that `leaf_idx < num_leafs`? + + {&u64_to_bfe} + // _ num_leafs *auth_struct *idx_leafs (*idx_leafs[n]_lw - 2) [0; 2] [p; 3] [γ] leaf_idx_bfe + + dup 12 + add + // _ num_leafs *auth_struct *idx_leafs (*idx_leafs[n]_lw - 2) [0; 2] [p; 3] [γ] node_idx_bfe + + xb_mul + // _ num_leafs *auth_struct *idx_leafs (*idx_leafs[n]_lw - 2) [0; 2] [p; 3] [γ * node_idx; 3] + + dup 8 + read_mem {Digest::LEN} + swap 14 + pop 1 + // _ num_leafs *auth_struct *idx_leafs *idx_leafs[n-1]_lw [0; 2] [p; 3] [γ * node_idx; 3] [leaf; 5] + // _ num_leafs *auth_struct *idx_leafs *idx_leafs[n-1]_lw [0; 2] [p; 3] [γ * node_idx; 3] l4 l3 l2 l1 l0 + + /* Convert `leaf` to XFE, using challenge */ + {&digest_to_xfe} + hint leaf_as_xfe: XFieldElement = stack[0..2] + // _ num_leafs *auth_struct *idx_leafs *idx_leafs[n-1]_lw [0; 2] [p; 3] [γ * node_idx; 3] [(l1 l0 1) * α + (l4 l3 l2)] + // _ num_leafs *auth_struct *idx_leafs *idx_leafs[n-1]_lw [0; 2] [p; 3] [γ * node_idx; 3] [leaf_as_xfe] <-- rename + + push {beta_challenge_read_address} + read_mem {EXTENSION_DEGREE} + pop 1 + // _ num_leafs *auth_struct *idx_leafs *idx_leafs[n-1]_lw [0; 2] [p; 3] [γ * node_idx; 3] [leaf_as_xfe] [-beta] + + xx_add + // _ num_leafs *auth_struct *idx_leafs *idx_leafs[n-1]_lw [0; 2] [p; 3] [γ * node_idx; 3] [leaf_as_xfe - beta] + + xx_add + // _ num_leafs *auth_struct *idx_leafs *idx_leafs[n-1]_lw [0; 2] [p; 3] [γ * node_idx + leaf_as_xfe - beta] + + xx_mul + // _ num_leafs *auth_struct *idx_leafs *idx_leafs[n-1]_lw [0; 2] [p'; 3] + + recurse_or_return + ); + let accumulate_indexed_leafs_from_public_data = triton_asm!( + // _ num_leafs *auth_struct *indexed_leafs + + dup 0 + read_mem 1 + push 1 + add + swap 1 + // _ num_leafs *auth_struct *indexed_leafs *indexed_leafs indexed_leafs_len + + /* Disallow empty list of indexed leafs */ + dup 0 + push 0 + eq + push 0 + eq + assert + // _ num_leafs *auth_struct *indexed_leafs *indexed_leafs indexed_leafs_len + + push {indexed_leaf_element_size} + mul + // _ num_leafs *auth_struct *indexed_leafs *indexed_leafs (indexed_leafs_size - 1) + + add + // _ num_leafs *auth_struct *indexed_leafs *indexed_leafs_last_word + + push 0 + push 0 + push 0 + push 0 + push 1 + hint prev = stack[3..5] + hint p: XFieldElement = stack[0..3] + // _ num_leafs *auth_struct *indexed_leafs *indexed_leafs_last_word [0u64; 2] [p; 3] + + dup 6 + dup 6 + eq + push 0 + eq + skiz + call {accumulate_indexed_leafs_loop_label} + // _ num_leafs *auth_struct *indexed_leafs *indexed_leafs [0u64; 2] [p; 3] + ); + + let accumulate_auth_struct_leafs_from_public_data_label = + format!("{entrypoint}_auth_struct_loop"); + + // let u64_lt = library.import(Box::new(LtU64PreserveArgs)); + let u64_lt = triton_asm!( + // _ lhs_hi lhs_lo rhs_hi rhs_lo + + /* calculate rhs_hi < lhs_hi || rhs_hi == lhs_hi && rhs_lo < lhs_lo */ + dup 2 + swap 1 + // _ lhs_hi lhs_lo rhs_hi lhs_lo rhs_lo + + lt + // _ lhs_hi lhs_lo rhs_hi (lhs_lo > rhs_lo) + // _ lhs_hi lhs_lo rhs_hi (rhs_lo < lhs_lo) + + dup 1 + dup 4 + eq + // _ lhs_hi lhs_lo rhs_hi (rhs_lo < lhs_lo) (rhs_hi == lhs_hi) + + mul + // _ lhs_hi lhs_lo rhs_hi (rhs_lo < lhs_lo && rhs_hi == lhs_hi) + + dup 3 + swap 1 + swap 2 + // _ lhs_hi lhs_lo (rhs_lo < lhs_lo && rhs_hi == lhs_hi) lhs_hi rhs_hi + + lt + // _ lhs_hi lhs_lo (rhs_lo < lhs_lo && rhs_hi == lhs_hi) (lhs_hi > rhs_hi) + // _ lhs_hi lhs_lo (rhs_lo < lhs_lo && rhs_hi == lhs_hi) (rhs_hi < lhs_hi) + + add + // _ lhs_hi lhs_lo (rhs_lo < lhs_lo && rhs_hi == lhs_hi || rhs_hi < lhs_hi) + ); + + let accumulate_auth_struct_leafs_from_public_data = triton_asm!( + // INVARIANT: _ *auth_struct *auth_struct[n]_lw [prev; 2] [p] + {accumulate_auth_struct_leafs_from_public_data_label}: + /* Divine in auth-struct node-index and verify ordering */ + + divine 2 + hint auth_struct_elem_node_index: u64 = stack[0..2] + // _ *auth_struct *auth_struct[n]_lw [prev; 2] [p] [node_index] + + + /* Notice that the u64-lt snippet crashes if divined node-index + words are not valid u32s. So no need to check explicitly. */ + dup 6 + dup 6 + {&u64_lt} + // _ *auth_struct *auth_struct[n]_lw [prev; 2] [p] [node_index] (prev < nodex_index) + + assert + // _ *auth_struct *auth_struct[n]_lw [prev; 2] [p] [node_index] + // _ *auth_struct *auth_struct[n]_lw prev_hi prev_lo p2 p1 p0 node_index_hi node_index_lo + + swap 5 + pop 1 + swap 5 + pop 1 + // _ *auth_struct *auth_struct[n]_lw [node_index] [p] + + /* Calculate `node_index * challenge` */ + push {gamma_challenge_read_address} + read_mem {EXTENSION_DEGREE} + pop 1 + // _ *auth_struct *auth_struct[n]_lw [node_index] [p] [γ] + + dup 7 + push {TWO_POW_32} + mul + dup 7 + add + // _ *auth_struct *auth_struct[n]_lw [node_index] [p] [γ] node_index_bfe + + xb_mul + // _ *auth_struct *auth_struct[n]_lw [node_index] [p] [node_index * γ] + + /* Read auth-struct element and convert to XFE */ + dup 8 + read_mem {Digest::LEN} + swap 14 + pop 1 + // _ *auth_struct *auth_struct[n]_lw [node_index] [p] [node_index * γ] [auth_struct_digest] + + {&digest_to_xfe} + // _ *auth_struct *auth_struct[n]_lw [node_index] [p] [node_index * γ] [auth_struct_xfe] + + push {beta_challenge_read_address} + read_mem {EXTENSION_DEGREE} + pop 1 + xx_add + // _ *auth_struct *auth_struct[n]_lw [node_index] [p] [node_index * γ] [auth_struct_xfe - beta] + + xx_add + // _ *auth_struct *auth_struct[n]_lw [node_index] [p] [node_index * γ + auth_struct_xfe - beta] + + xx_mul + // _ *auth_struct *auth_struct[n]_lw [node_index] [p * (node_index * γ + auth_struct_xfe - beta)] + // _ *auth_struct *auth_struct[n]_lw [prev] [p'] <-- rename + + recurse_or_return + ); + + let dup_top_digest = triton_asm![dup 4; Digest::LEN]; + let store_t_digest_in_memory_label = format!("{entrypoint}_store_t_digest"); + let store_t_digest_in_memory = triton_asm!( + {store_t_digest_in_memory_label}: + // _ [t] + + {&dup_top_digest} + push {t_digest_write_address} + write_mem {Digest::LEN} + pop 1 + // _ [t] + + return + ); + + let nd_loop_label = format!("{entrypoint}_nd_loop"); + let one_half = BFieldElement::new(2).inverse(); + let nd_loop = triton_asm!( + // _ INVARIANT: _ [p] + {nd_loop_label}: + divine 2 + // _ [p] left_index right_index + + dup 1 + push 1 + add + eq + // _ [p] l_index_bfe (left_index + 1 == right_index) + + assert + hint left_index: BFieldElement = stack[0..1] + // _ [p] l_index_bfe + + swap 3 + swap 2 + swap 1 + // _ l_index_bfe [p] + + /* Calculate parent digest, preserving child digests */ + divine {Digest::LEN} + hint right: Digest = stack[0..5] + // _ l_index_bfe [p] [right] + + {&dup_top_digest} + push {right_digest_allocation.write_address()} + write_mem {Digest::LEN} + pop 1 + // _ l_index_bfe [p] [right] + + {&digest_to_xfe} + // _ l_index_bfe [p] [right_xfe] + + push {beta_challenge_read_address} + read_mem {EXTENSION_DEGREE} + pop 1 + xx_add + // _ l_index_bfe [p] [right_xfe - β] + + push {gamma_challenge_read_address} + read_mem {EXTENSION_DEGREE} + pop 1 + // _ l_index_bfe [p] [right_xfe - β] [γ] + + dup 9 + push 1 + add + // _ l_index_bfe [p] [right_xfe - β] [γ] r_index_bfe + + xb_mul + // _ l_index_bfe [p] [right_xfe - β] [γ * r_index_bfe] + + xx_add + // _ l_index_bfe [p] [t_xfe - β + γ * parent_index] + // _ l_index_bfe [p] [fact_right] + + divine {Digest::LEN} + hint left: Digest = stack[0..5] + // _ l_index_bfe [p] [fact_right] [left] + + {&dup_top_digest} + push {left_digest_allocation.write_address()} + write_mem {Digest::LEN} + pop 1 + // _ l_index_bfe [p] [fact_right] [left] + + {&digest_to_xfe} + // _ l_index_bfe [p] [fact_right] [left_xfe] + + push {beta_challenge_read_address} + read_mem {EXTENSION_DEGREE} + pop 1 + xx_add + // _ l_index_bfe [p] [fact_right] [left_xfe - β] + + push {gamma_challenge_read_address} + read_mem {EXTENSION_DEGREE} + pop 1 + // _ l_index_bfe [p] [fact_right] [left_xfe - β] [γ] + + dup 12 + xb_mul + // _ l_index_bfe [p] [fact_right] [left_xfe - β] [l_index_bfe * γ] + + xx_add + // _ l_index_bfe [p] [fact_right] [fact_left] + + xx_mul + // _ l_index_bfe [p] [fact_right * fact_left] + + x_invert + // _ l_index_bfe [p] [(fact_right*fact_left)^{-1}] + + xx_mul + // _ l_index_bfe [p * (fact_right*fact_left)^{-1}] + + /* Calculate t = hash(left, right) */ + push {right_digest_allocation.read_address()} + read_mem {Digest::LEN} + pop 1 + push {left_digest_allocation.read_address()} + read_mem {Digest::LEN} + pop 1 + hash + // _ l_index_bfe [p * (fact_right*fact_left)^{-1}] [t] + + /* Store [t] digest in memory if this is last loop iteration */ + dup 8 + push 2 + eq + skiz + call {store_t_digest_in_memory_label} + // _ l_index_bfe [p * (fact_right*fact_left)^{-1}] [t] + + {&digest_to_xfe} + // _ l_index_bfe [p * (fact_right*fact_left)^{-1}] [t_xfe] + + push {beta_challenge_read_address} + read_mem {EXTENSION_DEGREE} + pop 1 + xx_add + // _ l_index_bfe [p * (fact_right*fact_left)^{-1}] [t_xfe - β] + + push {gamma_challenge_read_address} + read_mem {EXTENSION_DEGREE} + pop 1 + // _ l_index_bfe [p * (fact_right*fact_left)^{-1}] [t_xfe - β] [γ] + + dup 9 + push {one_half} + mul + // _ l_index_bfe [p * (fact_right*fact_left)^{-1}] [t_xfe - β] [γ] parent_index + + xb_mul + // _ l_index_bfe [p * (fact_right*fact_left)^{-1}] [t_xfe - β] [parent_index * γ] + + xx_add + // _ l_index_bfe [p * (fact_right*fact_left)^{-1}] [fact_parent] + + xx_mul + // _ l_index_bfe [p * (fact_right*fact_left)^{-1} * fact_parent] + // _ l_index_bfe [p'] + + swap 1 + swap 2 + swap 3 + // _ [p'] l_index_bfe + + /* Terminate loop when left_index == 2 <=> parent_index == 1 */ + push 2 + eq + skiz + return + // _ [p'] + + recurse + ); + + let compare_xfes = DataType::Xfe.compare(); + triton_asm!( + {entrypoint}: + // _ tree_height *auth_struct *indexed_leafs + + dup 1 + dup 1 + // _ tree_height *auth_struct *indexed_leafs *auth_struct *indexed_leafs + + {&calculate_and_store_challenges} + // _ tree_height *auth_struct *indexed_leafs + + /* Calculate number of leafs in Merkle tree + Notice that `tree_num_leafs` is not necessarily a u32, but is a + BFE and a power of two whose log_2 value is in the range + [0,63] */ + swap 2 + push 2 + pow + swap 2 + hint tree_num_leafs: BFieldElement = stack[2] + // _ tree_num_leafs *auth_struct *indexed_leafs + + {&accumulate_indexed_leafs_from_public_data} + // _ tree_num_leafs *auth_struct *indexed_leafs *indexed_leafs [garbage; 2] [p; 3] + // _ tree_num_leafs *auth_struct *indexed_leafs *indexed_leafs [garbage; 2] p2 p1 p0 <-- rename + + /* Prepare for next loop, absorption of auth-struct digests into accumulator */ + swap 7 + swap 6 + pop 1 + // _ tree_num_leafs p0 *auth_struct *indexed_leafs [0; 2] p2 p1 + + dup 5 + read_mem 1 + push 1 + add + swap 1 + // _ tree_num_leafs p0 *auth_struct *indexed_leafs [0; 2] p2 p1 *auth_struct auth_struct_len + + push {Digest::LEN} + mul + add + // _ tree_num_leafs p0 *auth_struct *indexed_leafs [0; 2] p2 p1 *auth_struct_last_word + + swap 5 + swap 7 + // _ tree_num_leafs *indexed_leafs *auth_struct *auth_struct_last_word [0; 2] p2 p1 p0 + // _ tree_num_leafs *indexed_leafs *auth_struct *auth_struct_last_word [prev; 2] [p] <-- rename + + dup 6 + dup 6 + eq + push 0 + eq + // _ tree_num_leafs *indexed_leafs *auth_struct *auth_struct_last_word [prev; 2] [p] (*auth_struct_last_word != *auth_struct) + + skiz + call {accumulate_auth_struct_leafs_from_public_data_label} + // _ tree_num_leafs *indexed_leafs *auth_struct *auth_struct_last_word [prev; 2] [p] + + /* Cleanup stack before next loop */ + swap 4 + pop 1 + swap 4 + pop 1 + swap 4 + pop 2 + // _ tree_num_leafs *indexed_leafs [p] + + /* Set initial t values, from indexed_leafs[0] */ + dup 3 + push {Digest::LEN} + add + read_mem {Digest::LEN} + pop 1 + // _ tree_num_leafs *indexed_leafs [p] [t; 5] + + /* Write t value (in case we're not entering the loop) */ + push {t_digest_write_address} + write_mem {Digest::LEN} + pop 1 + // _ tree_num_leafs *indexed_leafs [p] + + // _ tree_num_leafs *indexed_leafs p2 p1 p0 + swap 2 + swap 4 + swap 1 + swap 3 + pop 1 + // _ [p] tree_num_leafs + + /* Call the ND-loop if tree_num_leafs != 1 */ + push 1 + eq + push 0 + eq + // [p] (tree_num_leafs != 1) + + skiz + call {nd_loop_label} + // _ [p] + + /* Assert that p == t_xfe - beta + gamma */ + push {t_digest_read_address} + read_mem {Digest::LEN} + pop 1 + {&digest_to_xfe} + // _ [p] [t_xfe] + + push {beta_challenge_read_address} + read_mem {EXTENSION_DEGREE} + pop 1 + xx_add + // _ [p] [t_xfe - β] + + push {gamma_challenge_read_address} + read_mem {EXTENSION_DEGREE} + pop 1 + xx_add + // _ [p] [t_xfe - β + γ] + + {&compare_xfes} + // _ (p == t_xfe - β + γ) + + assert + // _ + + /* Return `t` (digest) */ + push {t_digest_read_address} + read_mem {Digest::LEN} + pop 1 + // _ [t] + + return + + {&accumulated_indexed_leafs_loop} + {&accumulate_auth_struct_leafs_from_public_data} + {&nd_loop} + {&store_t_digest_in_memory} + ) + } +} + +#[cfg(test)] +mod tests { + use std::cmp::min; + use std::collections::HashMap; + use std::collections::VecDeque; + + use itertools::Itertools; + use num::One; + use num::Zero; + use rand::Rng; + use rand::SeedableRng; + use rand::rngs::StdRng; + + use triton_vm::prelude::twenty_first::prelude::Sponge; + use triton_vm::prelude::twenty_first::util_types::mmr::mmr_accumulator::util::mmra_with_mps; + + use crate::memory::encode_to_memory; + use crate::mmr::authentication_struct::shared::AuthStructIntegrityProof; + use crate::rust_shadowing_helper_functions::list::list_insert; + use crate::rust_shadowing_helper_functions::list::load_list_with_copy_elements; + use crate::snippet_bencher::BenchmarkCase; + use crate::traits::procedure::Procedure; + use crate::traits::procedure::ProcedureInitialState; + use crate::traits::procedure::ShadowedProcedure; + use crate::traits::rust_shadow::RustShadow; + + use super::*; + + /// Read and consume a digest from an input source, either public input or + /// secret input. Returns the digest. + pub(crate) fn read_digest_from_input(secret_in: &mut VecDeque) -> Digest { + let mut values = [BFieldElement::zero(); Digest::LEN]; + let mut i = 0; + while i < Digest::LEN { + values[Digest::LEN - 1 - i] = secret_in.pop_front().unwrap(); + i += 1; + } + + Digest::new(values) + } + + const SIZE_OF_INDEXED_LEAFS_ELEMENT: usize = Digest::LEN + 2; + + #[test] + fn test() { + ShadowedProcedure::new(RootFromAuthenticationStruct).test(); + } + + impl Procedure for RootFromAuthenticationStruct { + fn rust_shadow( + &self, + stack: &mut Vec, + memory: &mut std::collections::HashMap, + nondeterminism: &NonDeterminism, + _public_input: &[BFieldElement], + sponge: &mut Option, + ) -> Vec { + fn digest_to_xfe(digest: Digest, challenge: XFieldElement) -> XFieldElement { + let [l0, l1, l2, l3, l4] = digest.0; + let leaf_xfe_lo = XFieldElement::new([BFieldElement::new(1), l0, l1]); + let leaf_xfe_hi = XFieldElement::new([l2, l3, l4]); + + challenge * leaf_xfe_lo + leaf_xfe_hi + } + + fn mimic_use_of_static_memory( + memory: &mut HashMap, + alpha: XFieldElement, + beta: XFieldElement, + gamma: XFieldElement, + t: Digest, + right: Digest, + left: Digest, + ) { + const ALPHA_POINTER_WRITE: BFieldElement = BFieldElement::new(BFieldElement::P - 4); + const BETA_POINTER_WRITE: BFieldElement = BFieldElement::new(BFieldElement::P - 7); + const GAMMA_POINTER_WRITE: BFieldElement = + BFieldElement::new(BFieldElement::P - 10); + const T_DIGEST_POINTER_WRITE: BFieldElement = + BFieldElement::new(BFieldElement::P - 15); + const RIGHT_DIGEST_POINTER_WRITE: BFieldElement = + BFieldElement::new(BFieldElement::P - 20); + const LEFT_DIGEST_POINTER_WRITE: BFieldElement = + BFieldElement::new(BFieldElement::P - 25); + + encode_to_memory(memory, ALPHA_POINTER_WRITE, &alpha); + encode_to_memory(memory, BETA_POINTER_WRITE, &beta); + encode_to_memory(memory, GAMMA_POINTER_WRITE, &gamma); + encode_to_memory(memory, T_DIGEST_POINTER_WRITE, &t); + encode_to_memory(memory, RIGHT_DIGEST_POINTER_WRITE, &right); + encode_to_memory(memory, LEFT_DIGEST_POINTER_WRITE, &left); + } + + fn accumulate_indexed_leafs( + indexed_leafs: &[(u64, Digest)], + alpha: XFieldElement, + beta: XFieldElement, + gamma: XFieldElement, + tree_num_leafs: u64, + ) -> XFieldElement { + let mut p = XFieldElement::one(); + for (leaf_idx, leaf) in indexed_leafs.iter().copied().rev() { + let leaf_idx_as_bfe = bfe!(leaf_idx); + let node_idx_as_bfe = leaf_idx_as_bfe + bfe!(tree_num_leafs); + let leaf_as_xfe = digest_to_xfe(leaf, alpha); + let fact = leaf_as_xfe - beta + gamma * node_idx_as_bfe; + p *= fact; + } + + p + } + + fn accumulate_auth_struct( + mut p: XFieldElement, + auth_struct: Vec, + individual_tokens: &mut VecDeque, + alpha: XFieldElement, + beta: XFieldElement, + gamma: XFieldElement, + ) -> XFieldElement { + let mut prev = 0u64; + + for auth_struct_elem in auth_struct.iter().copied().rev() { + let auth_struct_elem_node_index_hi: u32 = + individual_tokens.pop_front().unwrap().try_into().unwrap(); + let auth_struct_elem_node_index_lo: u32 = + individual_tokens.pop_front().unwrap().try_into().unwrap(); + let auth_struct_elem_node_index = ((auth_struct_elem_node_index_hi as u64) + << 32) + + auth_struct_elem_node_index_lo as u64; + assert!(auth_struct_elem_node_index > prev); + prev = auth_struct_elem_node_index; + + let auth_struct_index_as_bfe = bfe!(auth_struct_elem_node_index); + + let auth_struct_elem_xfe = digest_to_xfe(auth_struct_elem, alpha); + let fact = auth_struct_elem_xfe - beta + gamma * auth_struct_index_as_bfe; + + p *= fact; + } + + p + } + + assert_eq!( + SIZE_OF_INDEXED_LEAFS_ELEMENT, + Self::indexed_leaf_element_type().stack_size() + ); + + // declare input-arguments + let indexed_leafs_pointer = stack.pop().unwrap(); + let auth_struct_pointer = stack.pop().unwrap(); + let tree_height: u32 = stack.pop().unwrap().try_into().unwrap(); + + let bfes_to_indexed_leaf = + |bfes: [BFieldElement; SIZE_OF_INDEXED_LEAFS_ELEMENT]| -> (u64, Digest) { + *<(u64, Digest)>::decode(&bfes).unwrap() + }; + let bfes_to_digest = |bfes: [BFieldElement; Digest::LEN]| -> Digest { + *Digest::decode(&bfes[0..Digest::LEN]).unwrap() + }; + + let indexed_leafs: Vec<[BFieldElement; SIZE_OF_INDEXED_LEAFS_ELEMENT]> = + load_list_with_copy_elements(indexed_leafs_pointer, memory); + let indexed_leafs = indexed_leafs + .into_iter() + .map(bfes_to_indexed_leaf) + .collect_vec(); + let auth_struct: Vec<[BFieldElement; Digest::LEN]> = + load_list_with_copy_elements(auth_struct_pointer, memory); + let auth_struct = auth_struct.into_iter().map(bfes_to_digest).collect_vec(); + + // Calculate challenges + let sponge = sponge.as_mut().expect("sponge must be initialized"); + sponge.pad_and_absorb_all(&indexed_leafs.encode()); + sponge.pad_and_absorb_all(&auth_struct.encode()); + + let sponge_output = sponge.squeeze(); + let alpha = XFieldElement::new([sponge_output[1], sponge_output[2], sponge_output[3]]); + let beta = -XFieldElement::new([sponge_output[4], sponge_output[5], sponge_output[6]]); + let gamma = XFieldElement::new([sponge_output[7], sponge_output[8], sponge_output[9]]); + + let tree_num_leafs = 1u64 << tree_height; + + // Accumulate into `p` from public data + let mut p = + accumulate_indexed_leafs(&indexed_leafs, alpha, beta, gamma, tree_num_leafs); + + let mut individual_tokens: VecDeque = + nondeterminism.individual_tokens.to_owned().into(); + p = accumulate_auth_struct(p, auth_struct, &mut individual_tokens, alpha, beta, gamma); + + // "Unaccumulate" into `p` from secret data, and calculate Merkle root + let mut t = indexed_leafs[0].1; + let mut t_xfe = digest_to_xfe(t, alpha); + let mut right = Digest::default(); + let mut left = Digest::default(); + if tree_num_leafs != 1 { + loop { + let left_index = individual_tokens.pop_front().unwrap(); + let right_index = individual_tokens.pop_front().unwrap(); + assert_eq!(left_index + bfe!(1), right_index); + + let parent_index = left_index / bfe!(2); + + right = read_digest_from_input(&mut individual_tokens); + left = read_digest_from_input(&mut individual_tokens); + + t = Tip5::hash_pair(left, right); + t_xfe = digest_to_xfe(t, alpha); + let l_xfe = digest_to_xfe(left, alpha); + let r_xfe = digest_to_xfe(right, alpha); + let fact1 = l_xfe - beta + gamma * left_index; + let fact2 = r_xfe - beta + gamma * right_index; + let fact_parent = t_xfe - beta + gamma * parent_index; + + p *= fact1.inverse() * fact2.inverse() * fact_parent; + + if parent_index.is_one() { + break; + } + } + } + + assert_eq!(t_xfe - beta + gamma, p); + + // Return the Merkle root on the stack + for elem in t.encode().into_iter().rev() { + stack.push(elem); + } + + mimic_use_of_static_memory(memory, alpha, -beta, gamma, t, right, left); + + vec![] + } + + fn pseudorandom_initial_state( + &self, + seed: [u8; 32], + bench_case: Option, + ) -> ProcedureInitialState { + let mut rng: StdRng = SeedableRng::from_seed(seed); + + let num_chunks = 45; + let num_accessible_chunk_indices = 1 << 8; + let (tree_height, revealed_leaf_indices) = match bench_case { + None => { + let tree_height = rng.random_range(0..62); + let num_leafs_in_merkle_tree = 1 << tree_height; + let num_revealed_leafs = + rng.random_range(1..=min(num_leafs_in_merkle_tree, num_chunks)); + + let revealed_leaf_indices = (0..num_revealed_leafs) + .map(|_| { + rng.random_range( + 0..min(num_accessible_chunk_indices, num_leafs_in_merkle_tree), + ) + }) + .unique() + .collect_vec(); + + (tree_height, revealed_leaf_indices) + } + + // In both benchmarks, we leafs from the middle of the Merkle + // tree. Were we pick the indices is not so relevant for + // performance, as long as they're grouped together in a + // realistic way for the mutator set. + Some(BenchmarkCase::CommonCase) => { + let tree_height = 32; + let midpoint = 1 << (tree_height - 1); + let revealed_leaf_indices = (0..num_chunks) + .map(|_| { + rng.random_range(midpoint..num_accessible_chunk_indices + midpoint) + }) + .unique() + .collect_vec(); + + (tree_height, revealed_leaf_indices) + } + Some(BenchmarkCase::WorstCase) => { + let tree_height = 62; + let midpoint = 1 << (tree_height - 1); + let revealed_leaf_indices = (0..num_chunks) + .map(|_| { + rng.random_range(midpoint..num_accessible_chunk_indices + midpoint) + }) + .unique() + .collect_vec(); + + (tree_height, revealed_leaf_indices) + } + }; + let num_leafs_in_merkle_tree = 1 << tree_height; + + // This picks leaf-indices with low values but I don't think that + // matters for performance. + + let num_revealed_leafs = revealed_leaf_indices.len(); + assert!(!num_revealed_leafs.is_zero()); + + let revealed_leafs: Vec = + (0..num_revealed_leafs).map(|_| rng.random()).collect_vec(); + let indexed_leafs = revealed_leaf_indices + .into_iter() + .zip_eq(revealed_leafs) + .collect_vec(); + + let (mmra, mps) = mmra_with_mps(num_leafs_in_merkle_tree, indexed_leafs.clone()); + let indexed_mmr_mps = indexed_leafs + .into_iter() + .zip_eq(mps) + .map(|((idx, leaf), mp)| (idx, leaf, mp)) + .collect_vec(); + + let mmr_authentication_struct = + AuthStructIntegrityProof::new_from_mmr_membership_proofs(&mmra, indexed_mmr_mps); + assert!(mmr_authentication_struct.len().is_one()); + let mmr_authentication_struct = &mmr_authentication_struct[&0]; + + let mut memory = HashMap::new(); + let authentication_structure_ptr = rng.random(); + let indexed_leafs_ptr = rng.random(); + + list_insert( + authentication_structure_ptr, + mmr_authentication_struct.auth_struct.clone(), + &mut memory, + ); + list_insert( + indexed_leafs_ptr, + mmr_authentication_struct.indexed_leafs.clone(), + &mut memory, + ); + + let stack = [ + self.init_stack_for_isolated_run(), + vec![ + bfe!(tree_height), + authentication_structure_ptr, + indexed_leafs_ptr, + ], + ] + .concat(); + + let nd_auth_struct_indices = mmr_authentication_struct + .witness + .nd_auth_struct_indices + .iter() + .rev() + .flat_map(|node_index| node_index.encode().into_iter().rev().collect_vec()) + .collect_vec(); + let nd_loop_nd = mmr_authentication_struct + .witness + .nd_sibling_indices + .iter() + .copied() + .zip_eq( + mmr_authentication_struct + .witness + .nd_siblings + .iter() + .copied(), + ) + .flat_map(|((left_index, right_index), (left_node, right_node))| { + [ + vec![bfe!(left_index), bfe!(right_index)], + right_node.encode().into_iter().rev().collect_vec(), + left_node.encode().into_iter().rev().collect_vec(), + ] + .concat() + }) + .collect_vec(); + + let individual_tokens = [nd_auth_struct_indices, nd_loop_nd].concat(); + let nondeterminism = NonDeterminism::new(individual_tokens).with_ram(memory); + ProcedureInitialState { + stack, + nondeterminism, + public_input: vec![], + sponge: Some(Tip5::init()), + } + } + + fn corner_case_initial_states(&self) -> Vec { + vec![] + } + } +} + +#[cfg(test)] +mod benches { + use crate::traits::procedure::ShadowedProcedure; + use crate::traits::rust_shadow::RustShadow; + + use super::*; + + #[test] + fn bench_root_from_auth_struct() { + ShadowedProcedure::new(RootFromAuthenticationStruct).bench(); + } +} diff --git a/tasm-lib/src/mmr/authentication_struct/shared.rs b/tasm-lib/src/mmr/authentication_struct/shared.rs new file mode 100644 index 00000000..c1eba8a9 --- /dev/null +++ b/tasm-lib/src/mmr/authentication_struct/shared.rs @@ -0,0 +1,692 @@ +use std::collections::HashMap; +use std::collections::HashSet; + +use itertools::Itertools; +use num_traits::One; + +use crate::data_type::DataType; +use crate::twenty_first::bfe; +use crate::twenty_first::prelude::*; +use crate::twenty_first::util_types::mmr::mmr_accumulator::MmrAccumulator; +use crate::twenty_first::util_types::mmr::shared_advanced::get_peak_heights; +use crate::twenty_first::util_types::mmr::shared_basic::leaf_index_to_mt_index_and_peak_index; + +const ROOT_MT_INDEX: u64 = 1; + +pub(super) fn indexed_leaf_element_type() -> DataType { + DataType::Tuple(vec![DataType::U64, DataType::Digest]) +} + +/// A witness to facilitate the proving of the authenticity of a Merkle +/// authentication struct. +#[derive(Debug, Clone)] +pub struct AuthStructIntegrityProof { + // All indices are Merkle tree node indices + pub nd_auth_struct_indices: Vec, + pub nd_sibling_indices: Vec<(u64, u64)>, + pub nd_siblings: Vec<(Digest, Digest)>, +} + +/// An authentication structure that can be used to prove membership of a list +/// of leaves in a Merkle tree, along with the indexed leaves in question, and +/// the witness necessary to prove membership in a ZK program. +#[derive(Debug, Clone)] +pub struct AuthenticatedMerkleAuthStruct { + pub auth_struct: Vec, + pub indexed_leafs: Vec<(u64, Digest)>, + pub witness: AuthStructIntegrityProof, +} + +impl AuthStructIntegrityProof { + /// Return the Merkle tree node indices of the digests required to prove + /// membership for the specified leaf indices, as well as the node indices + /// that can be derived from the leaf indices and their authentication + /// path. + fn auth_struct_and_nd_indices( + num_leafs: u64, + leaf_indices: &[u64], + ) -> (Vec, Vec<(u64, u64)>) { + // The set of indices of nodes that need to be included in the authentications + // structure. In principle, every node of every authentication path is needed. + // The root is never needed. Hence, it is not considered below. + let mut node_is_needed = HashSet::new(); + + // The set of indices of nodes that can be computed from other nodes in the + // authentication structure or the leafs that are explicitly supplied during + // verification. Every node on the direct path from the leaf to the root can + // be computed by the very nature of “authentication path”. + let mut node_can_be_computed = HashSet::new(); + + for &leaf_index in leaf_indices { + assert!( + num_leafs > leaf_index, + "Leaf index must be less than number of leafs. Got leaf_index = {leaf_index}; num_leafs = {num_leafs}" + ); + + let mut node_index = leaf_index + num_leafs; + while node_index > ROOT_MT_INDEX { + let sibling_index = node_index ^ 1; + node_can_be_computed.insert(node_index); + node_is_needed.insert(sibling_index); + node_index /= 2; + } + } + + let set_difference = node_is_needed.difference(&node_can_be_computed).copied(); + let set_union = node_is_needed + .union(&node_can_be_computed) + .sorted_unstable() + .rev(); + + let mut set_union = set_union.peekable(); + + let mut set_union_as_ordered_pairs = Vec::new(); + while set_union.peek().is_some() { + let right_index = *set_union.next().unwrap(); + + // Crashes on odd-length of input list, which is what we want, as + // this acts as a sanity check. + let left_index = *set_union.next().unwrap(); + set_union_as_ordered_pairs.push((left_index, right_index)); + } + + ( + set_difference.sorted_unstable().rev().collect(), + set_union_as_ordered_pairs, + ) + } + + /// Calculate a root from an authentication structure, indexed leafs, and + /// additional witness data on `self`. Crashes if the witness data is + /// incorrect and if the list of indexed leafs is empty. + pub fn root_from_authentication_struct( + &self, + tree_height: u32, + auth_struct: Vec, + indexed_leafs: Vec<(u64, Digest)>, + ) -> Digest { + fn digest_to_xfe(digest: Digest, challenge: XFieldElement) -> XFieldElement { + let leaf_xfe_lo = XFieldElement::new([digest.0[0], digest.0[1], digest.0[2]]); + let leaf_xfe_hi = + challenge * XFieldElement::new([digest.0[3], digest.0[4], BFieldElement::one()]); + + leaf_xfe_lo + leaf_xfe_hi + } + + fn node_index_to_bfe(node_index: u64) -> BFieldElement { + BFieldElement::new(node_index) + } + + // Sanity check + assert_eq!( + self.nd_auth_struct_indices.len(), + auth_struct.len(), + "Provided auth struct length must match that specified in receiver" + ); + + // Get challenges + let (alpha, beta, gamma) = { + let mut sponge = Tip5::init(); + sponge.pad_and_absorb_all(&indexed_leafs.encode()); + sponge.pad_and_absorb_all(&auth_struct.encode()); + let challenges = sponge.sample_scalars(3); + (challenges[0], challenges[1], challenges[2]) + }; + + // Accumulate `p` from public data + let mut p = XFieldElement::one(); + for i in (0..indexed_leafs.len()).rev() { + let node_index_as_bfe = node_index_to_bfe((1 << tree_height) ^ indexed_leafs[i].0); + let leaf_as_xfe = digest_to_xfe(indexed_leafs[i].1, alpha); + let fact = leaf_as_xfe - beta + gamma * node_index_as_bfe; + p *= fact; + } + + let mut prev = 0; + for i in (0..auth_struct.len()).rev() { + let auth_struct_index = self.nd_auth_struct_indices[i]; + + // `auth_struct` must be sorted high-to-low by node-index. But since + // we're traversing in reverse order, the inequality is flipped. + assert!(auth_struct_index > prev); + prev = auth_struct_index; + + let auth_struct_index_as_bfe = node_index_to_bfe(auth_struct_index); + + let auth_str_elem_as_xfe = digest_to_xfe(auth_struct[i], alpha); + let fact = auth_str_elem_as_xfe - beta + gamma * auth_struct_index_as_bfe; + p *= fact; + } + + // Use secret data to invert `p` back and to calculate the root + let mut t = indexed_leafs.first().unwrap().1; + let mut t_xfe = digest_to_xfe(t, alpha); + let mut parent_index_bfe = BFieldElement::one(); + for ((l, r), (left_index, right_index)) in self + .nd_siblings + .iter() + .zip_eq(self.nd_sibling_indices.clone()) + { + let left_index_bfe = node_index_to_bfe(left_index); + let right_index_bfe = node_index_to_bfe(right_index); + assert_eq!(left_index + 1, right_index); + parent_index_bfe = left_index_bfe / bfe!(2); + + t = Tip5::hash_pair(*l, *r); + + let l_xfe = digest_to_xfe(*l, alpha); + let r_xfe = digest_to_xfe(*r, alpha); + t_xfe = digest_to_xfe(t, alpha); + + let fact_left = l_xfe - beta + gamma * left_index_bfe; + let fact_right = r_xfe - beta + gamma * right_index_bfe; + let fact_parent = t_xfe - beta + gamma * parent_index_bfe; + + p *= fact_left.inverse() * fact_right.inverse() * fact_parent; + } + + assert_eq!(t_xfe - beta + gamma, p); + + assert!(parent_index_bfe.is_one()); + + t + } + + /// Return the authentication structure authenticity witness, + /// authentication structure, and the (leaf-index, leaf-digest) pairs + /// from a list of MMR membership proofs. All MMR membership proofs must + /// belong under the same peak, i.e., be part of the same Merkle tree in + /// the list of Merkle trees that the MMR contains. + /// + /// Panics if the input list of MMR-membership proofs is empty, or if they + /// do not all belong under the same peak. + pub fn new_from_mmr_membership_proofs( + mmra: &MmrAccumulator, + indexed_mmr_mps: Vec<(u64, Digest, MmrMembershipProof)>, + ) -> HashMap { + #[derive(Clone, Debug)] + struct IndexedAuthenticatedMmrLeaf { + merkle_tree_node_index: u64, + merkle_tree_leaf_index: u64, + leaf_digest: Digest, + membership_proof: MmrMembershipProof, + } + + // Split indexed MMR-mps into a hashmap with one entry for each + // referenced peak in the MMR. + let num_mmr_leafs = mmra.num_leafs(); + let mut peak_index_to_indexed_mmr_mp: HashMap> = + HashMap::default(); + let peak_heights = get_peak_heights(num_mmr_leafs); + for (mmr_leaf_index, leaf, mmr_mp) in indexed_mmr_mps { + let (mt_index, peak_index) = + leaf_index_to_mt_index_and_peak_index(mmr_leaf_index, num_mmr_leafs); + let peak_index_as_usize: usize = peak_index.try_into().unwrap(); + let num_leafs_local_mt = 1 << peak_heights[peak_index_as_usize]; + let mt_leaf_index = mt_index - num_leafs_local_mt; + peak_index_to_indexed_mmr_mp + .entry(peak_index) + .or_default() + .push(IndexedAuthenticatedMmrLeaf { + merkle_tree_node_index: mt_index, + merkle_tree_leaf_index: mt_leaf_index, + leaf_digest: leaf, + membership_proof: mmr_mp, + }); + } + + // Loop over all peaks and collect an authentication witness struct + // for each peak. + let mut peak_index_to_authenticated_auth_struct = HashMap::default(); + for (peak_index, indexed_mmr_mp_structs) in peak_index_to_indexed_mmr_mp { + let peak_index_as_usize: usize = peak_index.try_into().unwrap(); + let num_leafs_in_local_mt = 1 << peak_heights[peak_index_as_usize]; + let local_mt_leaf_indices = indexed_mmr_mp_structs + .iter() + .map(|x| x.merkle_tree_leaf_index) + .collect_vec(); + + let (nd_auth_struct_indices, nd_sibling_indices) = + Self::auth_struct_and_nd_indices(num_leafs_in_local_mt, &local_mt_leaf_indices); + let peak = mmra.peaks()[peak_index_as_usize]; + + let mut node_digests: HashMap = HashMap::default(); + node_digests.insert(ROOT_MT_INDEX, peak); + + // Loop over all indexed leafs for this peak + for indexed_mmr_mp in indexed_mmr_mp_structs.iter() { + let mut mt_node_index = indexed_mmr_mp.merkle_tree_node_index; + let mut node = indexed_mmr_mp.leaf_digest; + + // Loop over all authentication path elements for this indexed leaf + for ap_elem in indexed_mmr_mp.membership_proof.authentication_path.iter() { + node_digests.insert(mt_node_index, node); + node_digests.insert(mt_node_index ^ 1, *ap_elem); + node = if mt_node_index & 1 == 0 { + Tip5::hash_pair(node, *ap_elem) + } else { + Tip5::hash_pair(*ap_elem, node) + }; + + mt_node_index /= 2; + } + + // Sanity check that MMR-MPs are valid + assert_eq!(peak, node, "Derived peak must match provided peak"); + } + let nd_siblings = nd_sibling_indices + .iter() + .map(|(left_idx, right_idx)| (node_digests[left_idx], node_digests[right_idx])) + .collect_vec(); + let auth_struct = nd_auth_struct_indices + .iter() + .map(|idx| node_digests[idx]) + .collect_vec(); + let indexed_leafs = indexed_mmr_mp_structs + .into_iter() + .map(|indexed_mmr_mp| { + ( + indexed_mmr_mp.merkle_tree_leaf_index, + indexed_mmr_mp.leaf_digest, + ) + }) + .collect_vec(); + + let witness = Self { + nd_auth_struct_indices, + nd_sibling_indices, + nd_siblings, + }; + + peak_index_to_authenticated_auth_struct.insert( + peak_index, + AuthenticatedMerkleAuthStruct { + auth_struct, + indexed_leafs, + witness, + }, + ); + } + + peak_index_to_authenticated_auth_struct + } + + /// Return the authentication structure witness, authentication structure, + /// and the (leaf-index, leaf-digest) pairs. + pub fn new_from_merkle_tree( + tree: &MerkleTree, + mut revealed_leaf_indices: Vec, + ) -> AuthenticatedMerkleAuthStruct { + revealed_leaf_indices.sort_unstable(); + revealed_leaf_indices.dedup(); + revealed_leaf_indices.reverse(); + let num_leafs: u64 = tree.num_leafs() as u64; + + let (nd_auth_struct_indices, nd_sibling_indices) = + Self::auth_struct_and_nd_indices(num_leafs, &revealed_leaf_indices); + + let nd_siblings = nd_sibling_indices + .iter() + .map(|&(l, r)| { + let l: usize = l.try_into().unwrap(); + let r: usize = r.try_into().unwrap(); + (tree.node(l).unwrap(), tree.node(r).unwrap()) + }) + .collect_vec(); + + let revealed_leafs = revealed_leaf_indices + .iter() + .map(|j| tree.node((*j + num_leafs) as usize).unwrap()) + .collect_vec(); + let indexed_leafs = revealed_leaf_indices + .clone() + .into_iter() + .zip_eq(revealed_leafs) + .collect_vec(); + + let auth_struct = nd_auth_struct_indices + .iter() + .map(|node_index| tree.node(*node_index as usize).unwrap()) + .collect_vec(); + + let witness = Self { + nd_auth_struct_indices, + nd_sibling_indices, + nd_siblings, + }; + + AuthenticatedMerkleAuthStruct { + auth_struct, + indexed_leafs, + witness, + } + } +} + +#[cfg(test)] +mod tests { + use proptest::collection::vec; + use proptest::prop_assert_eq; + use rand::random; + use test_strategy::proptest; + + use crate::twenty_first::math::other::random_elements; + use crate::twenty_first::util_types::mmr::mmr_accumulator::util::mmra_with_mps; + + use super::*; + + #[proptest(cases = 20)] + fn root_from_authentication_struct_mmr_prop_test( + #[strategy(0..u64::MAX / 2)] mmr_leaf_count: u64, + #[strategy(0usize..20)] _num_revealed_leafs: usize, + #[strategy(vec(0u64..#mmr_leaf_count, #_num_revealed_leafs))] + mmr_revealed_leaf_indices: Vec, + ) { + let indexed_leafs_input: Vec<(u64, Digest)> = mmr_revealed_leaf_indices + .iter() + .map(|idx| (*idx, random())) + .collect_vec(); + let (mmra, mmr_mps) = mmra_with_mps(mmr_leaf_count, indexed_leafs_input.clone()); + let indexed_mmr_mps = mmr_mps + .into_iter() + .zip_eq(indexed_leafs_input) + .map(|(mmr_mp, (idx, leaf))| (idx, leaf, mmr_mp)) + .collect_vec(); + + let authenticated_auth_structs = + AuthStructIntegrityProof::new_from_mmr_membership_proofs(&mmra, indexed_mmr_mps); + + let peak_heights = get_peak_heights(mmr_leaf_count); + for (peak_index, authentication_auth_struct) in authenticated_auth_structs { + let AuthenticatedMerkleAuthStruct { + auth_struct, + indexed_leafs, + witness, + } = &authentication_auth_struct; + let tree_height: u32 = peak_heights[peak_index as usize]; + let computed_root = witness.root_from_authentication_struct( + tree_height, + auth_struct.to_owned(), + indexed_leafs.to_owned(), + ); + + prop_assert_eq!(mmra.peaks()[peak_index as usize], computed_root); + } + } + + #[test] + fn auth_struct_on_empty_mmr() { + let empty_mmra = MmrAccumulator::init(vec![], 0); + let authenticated_auth_structs = + AuthStructIntegrityProof::new_from_mmr_membership_proofs(&empty_mmra, vec![]); + assert!(authenticated_auth_structs.is_empty()); + } + + #[test] + fn auth_struct_non_empty_mmr_empty_leaf_list() { + let mmra_10_leafs = MmrAccumulator::new_from_leafs(vec![Digest::default(); 10]); + let authenticated_auth_structs = + AuthStructIntegrityProof::new_from_mmr_membership_proofs(&mmra_10_leafs, vec![]); + assert!(authenticated_auth_structs.is_empty()); + } + + #[should_panic] + #[test] + fn panics_on_missing_nd_digests() { + let tree_height = 3u32; + let num_leafs = 1u64 << tree_height; + let leafs: Vec = random_elements(num_leafs.try_into().unwrap()); + let tree = MerkleTree::par_new(&leafs).unwrap(); + + let authenticated_auth_struct = + AuthStructIntegrityProof::new_from_merkle_tree(&tree, vec![0]); + let AuthenticatedMerkleAuthStruct { + auth_struct, + indexed_leafs, + mut witness, + } = authenticated_auth_struct; + witness.nd_sibling_indices.clear(); + witness.nd_siblings.clear(); + + witness.root_from_authentication_struct(tree_height, auth_struct, indexed_leafs); + } + + #[test] + fn auth_struct_from_mmr_mps_test_height_5_9_indices() { + let local_tree_height = 5; + let mmr_leaf_indices = [0, 1, 2, 16, 17, 18, 27, 29, 31]; + let indexed_leafs_input: Vec<(u64, Digest)> = mmr_leaf_indices + .iter() + .map(|idx| (*idx, random())) + .collect_vec(); + let (mmra, mmr_mps) = mmra_with_mps(1 << local_tree_height, indexed_leafs_input.clone()); + let indexed_mmr_mps = mmr_mps + .into_iter() + .zip_eq(indexed_leafs_input) + .map(|(mmr_mp, (idx, leaf))| (idx, leaf, mmr_mp)) + .collect_vec(); + + let authenticity_witnesses = + AuthStructIntegrityProof::new_from_mmr_membership_proofs(&mmra, indexed_mmr_mps); + assert!( + authenticity_witnesses.len().is_one(), + "All indices belong to first peak" + ); + let AuthenticatedMerkleAuthStruct { + auth_struct, + indexed_leafs, + witness, + } = &authenticity_witnesses[&0]; + + let tree_height: u32 = local_tree_height.try_into().unwrap(); + let computed_root = witness.root_from_authentication_struct( + tree_height, + auth_struct.to_owned(), + indexed_leafs.to_owned(), + ); + + let peak_index = 0; + let expected_root = mmra.peaks()[peak_index]; + assert_eq!(expected_root, computed_root); + } + + #[test] + fn auth_struct_from_mmr_mps_test_height_4_2_indices() { + let local_tree_height = 4; + let mmr_leaf_indices = [0, 1]; + let indexed_leafs_input: Vec<(u64, Digest)> = mmr_leaf_indices + .iter() + .map(|idx| (*idx, random())) + .collect_vec(); + let (mmra, mmr_mps) = mmra_with_mps(1 << local_tree_height, indexed_leafs_input.clone()); + let indexed_mmr_mps = mmr_mps + .into_iter() + .zip_eq(indexed_leafs_input) + .map(|(mmr_mp, (idx, leaf))| (idx, leaf, mmr_mp)) + .collect_vec(); + + let authenticity_witnesses = + AuthStructIntegrityProof::new_from_mmr_membership_proofs(&mmra, indexed_mmr_mps); + assert!( + authenticity_witnesses.len().is_one(), + "All indices belong to first peak" + ); + let AuthenticatedMerkleAuthStruct { + auth_struct, + indexed_leafs, + witness, + } = &authenticity_witnesses[&0]; + + let tree_height: u32 = local_tree_height.try_into().unwrap(); + let computed_root = witness.root_from_authentication_struct( + tree_height, + auth_struct.to_owned(), + indexed_leafs.to_owned(), + ); + + let peak_index = 0; + let expected_root = mmra.peaks()[peak_index]; + assert_eq!(expected_root, computed_root); + } + + #[proptest(cases = 20)] + fn root_from_authentication_struct_prop_test( + #[strategy(0..12u64)] tree_height: u64, + #[strategy(1usize..100)] _num_revealed_leafs: usize, + #[strategy(vec(0u64..1<<#tree_height, #_num_revealed_leafs))] revealed_leaf_indices: Vec< + u64, + >, + ) { + let num_leafs = 1u64 << tree_height; + let leafs: Vec = random_elements(num_leafs.try_into().unwrap()); + let tree = MerkleTree::par_new(&leafs).unwrap(); + + let authenticated_auth_struct = + AuthStructIntegrityProof::new_from_merkle_tree(&tree, revealed_leaf_indices); + let AuthenticatedMerkleAuthStruct { + auth_struct, + indexed_leafs, + witness, + } = authenticated_auth_struct; + + let tree_height: u32 = tree_height.try_into().unwrap(); + let computed_root = + witness.root_from_authentication_struct(tree_height, auth_struct, indexed_leafs); + let expected_root = tree.root(); + prop_assert_eq!(expected_root, computed_root); + } + + fn prop_from_merkle_tree( + tree_height: usize, + leaf_indices: Vec, + nd_auth_struct_indices: Vec, + nd_sibling_indices: Vec<(u64, u64)>, + ) { + let leafs: Vec = random_elements(1 << tree_height); + let tree = MerkleTree::par_new(&leafs).unwrap(); + + let auth_struct = nd_auth_struct_indices + .iter() + .map(|i| tree.node(*i as usize).unwrap()) + .collect_vec(); + let revealed_leafs = leaf_indices + .iter() + .map(|i| tree.leaf(*i as usize).unwrap()) + .collect_vec(); + let revealed_leafs = leaf_indices + .into_iter() + .zip_eq(revealed_leafs) + .collect_vec(); + let nd_siblings = nd_sibling_indices + .iter() + .map(|(left_idx, right_idx)| { + ( + tree.node(*left_idx as usize).unwrap(), + tree.node(*right_idx as usize).unwrap(), + ) + }) + .collect_vec(); + + let mmr_auth_struct = AuthStructIntegrityProof { + nd_auth_struct_indices, + nd_sibling_indices, + nd_siblings, + }; + let tree_height: u32 = tree_height.try_into().unwrap(); + let calculated_root = mmr_auth_struct.root_from_authentication_struct( + tree_height, + auth_struct, + revealed_leafs, + ); + assert_eq!(tree.root(), calculated_root); + } + + #[test] + fn root_from_authentication_struct_tree_height_0_1_revealed() { + let tree_height = 0; + let leaf_indices = vec![0]; + let nd_auth_struct_indices = vec![]; + let nd_sibling_indices = vec![]; + prop_from_merkle_tree( + tree_height, + leaf_indices, + nd_auth_struct_indices, + nd_sibling_indices, + ) + } + + #[test] + fn root_from_authentication_struct_tree_height_1_1_revealed() { + let tree_height = 1; + let leaf_indices = vec![0u64]; + let nd_auth_struct_indices = vec![3]; + let nd_sibling_indices = vec![(2u64, 3u64)]; + prop_from_merkle_tree( + tree_height, + leaf_indices, + nd_auth_struct_indices, + nd_sibling_indices, + ) + } + + #[test] + fn root_from_authentication_struct_tree_height_1_2_revealed() { + let tree_height = 1; + let leaf_indices = vec![0u64, 1]; + let nd_auth_struct_indices = vec![]; + let nd_sibling_indices = vec![(2u64, 3u64)]; + prop_from_merkle_tree( + tree_height, + leaf_indices, + nd_auth_struct_indices, + nd_sibling_indices, + ) + } + + #[test] + fn root_from_authentication_struct_tree_height_2_2_revealed() { + let tree_height = 2; + let leaf_indices = vec![0u64, 1]; + let auth_struct_indices = vec![3]; + let nd_sibling_indices = vec![(4u64, 5u64), (2, 3)]; + prop_from_merkle_tree( + tree_height, + leaf_indices, + auth_struct_indices, + nd_sibling_indices, + ) + } + + #[test] + fn root_from_authentication_struct_tree_height_4_4_revealed() { + let tree_height = 4; + let leaf_indices = vec![14u64, 12, 10, 8]; + let num_leafs = 1 << tree_height; + let auth_struct_indices = vec![ + num_leafs + 15, + num_leafs + 13, + num_leafs + 11, + num_leafs + 9, + 2, + ]; + let nd_sibling_indices_layer_height_0 = [(14u64, 15u64), (12, 13), (10, 11), (8, 9)] + .map(|(l, r)| (l + num_leafs, r + num_leafs)); + let nd_sibling_indices_layer_height_1 = [(14u64, 15u64), (12u64, 13u64)]; + let nd_sibling_indices_layer_height_2 = [(6u64, 7u64)]; + let nd_sibling_indices_layer_height_3 = [(2u64, 3u64)]; + let nd_sibling_indices = [ + nd_sibling_indices_layer_height_0.to_vec(), + nd_sibling_indices_layer_height_1.to_vec(), + nd_sibling_indices_layer_height_2.to_vec(), + nd_sibling_indices_layer_height_3.to_vec(), + ] + .concat(); + + prop_from_merkle_tree( + tree_height, + leaf_indices, + auth_struct_indices, + nd_sibling_indices, + ) + } +} diff --git a/tasm-lib/src/mmr/bag_peaks.rs b/tasm-lib/src/mmr/bag_peaks.rs index 79f6aa90..64e3d0f0 100644 --- a/tasm-lib/src/mmr/bag_peaks.rs +++ b/tasm-lib/src/mmr/bag_peaks.rs @@ -154,8 +154,8 @@ impl BasicSnippet for BagPeaks { mod tests { use std::collections::HashMap; + use triton_vm::prelude::twenty_first::math::other::random_elements; use triton_vm::twenty_first::prelude::Mmr; - use twenty_first::math::other::random_elements; use super::*; use crate::test_prelude::*; diff --git a/tasm-lib/src/mmr/calculate_new_peaks_from_append.rs b/tasm-lib/src/mmr/calculate_new_peaks_from_append.rs index 5249f96f..cad464ab 100644 --- a/tasm-lib/src/mmr/calculate_new_peaks_from_append.rs +++ b/tasm-lib/src/mmr/calculate_new_peaks_from_append.rs @@ -114,7 +114,7 @@ impl BasicSnippet for CalculateNewPeaksFromAppend { #[cfg(test)] mod tests { - use twenty_first::util_types::mmr::mmr_accumulator::MmrAccumulator; + use triton_vm::prelude::twenty_first::util_types::mmr::mmr_accumulator::MmrAccumulator; use super::*; use crate::memory::FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS; diff --git a/tasm-lib/src/mmr/leaf_index_to_mt_index_and_peak_index.rs b/tasm-lib/src/mmr/leaf_index_to_mt_index_and_peak_index.rs index 7fbfeaad..a737bfa4 100644 --- a/tasm-lib/src/mmr/leaf_index_to_mt_index_and_peak_index.rs +++ b/tasm-lib/src/mmr/leaf_index_to_mt_index_and_peak_index.rs @@ -141,7 +141,7 @@ impl BasicSnippet for MmrLeafIndexToMtIndexAndPeakIndex { #[cfg(test)] pub(crate) mod tests { - use twenty_first::util_types::mmr::shared_basic::leaf_index_to_mt_index_and_peak_index; + use triton_vm::prelude::twenty_first::util_types::mmr::shared_basic::leaf_index_to_mt_index_and_peak_index; use super::*; use crate::test_prelude::*; diff --git a/tasm-lib/src/mmr/verify_from_memory.rs b/tasm-lib/src/mmr/verify_from_memory.rs index d0745be2..92e56c07 100644 --- a/tasm-lib/src/mmr/verify_from_memory.rs +++ b/tasm-lib/src/mmr/verify_from_memory.rs @@ -133,8 +133,8 @@ impl BasicSnippet for MmrVerifyFromMemory { mod tests { use itertools::Itertools; use rand::prelude::*; - use twenty_first::math::other::random_elements; - use twenty_first::util_types::mmr::mmr_accumulator::util::mmra_with_mps; + use triton_vm::prelude::twenty_first::math::other::random_elements; + use triton_vm::prelude::twenty_first::util_types::mmr::mmr_accumulator::util::mmra_with_mps; use super::*; use crate::empty_stack; diff --git a/tasm-lib/src/mmr/verify_from_secret_in_leaf_index_on_stack.rs b/tasm-lib/src/mmr/verify_from_secret_in_leaf_index_on_stack.rs index fdae7e5b..ba695f77 100644 --- a/tasm-lib/src/mmr/verify_from_secret_in_leaf_index_on_stack.rs +++ b/tasm-lib/src/mmr/verify_from_secret_in_leaf_index_on_stack.rs @@ -88,12 +88,12 @@ impl BasicSnippet for MmrVerifyFromSecretInLeafIndexOnStack { #[cfg(test)] mod tests { - use twenty_first::math::other::random_elements; - use twenty_first::util_types::mmr::mmr_accumulator::MmrAccumulator; - use twenty_first::util_types::mmr::mmr_accumulator::util::mmra_with_mps; - use twenty_first::util_types::mmr::mmr_membership_proof::MmrMembershipProof; - use twenty_first::util_types::mmr::mmr_trait::Mmr; - use twenty_first::util_types::mmr::shared_basic::leaf_index_to_mt_index_and_peak_index; + use triton_vm::prelude::twenty_first::math::other::random_elements; + use triton_vm::prelude::twenty_first::util_types::mmr::mmr_accumulator::MmrAccumulator; + use triton_vm::prelude::twenty_first::util_types::mmr::mmr_accumulator::util::mmra_with_mps; + use triton_vm::prelude::twenty_first::util_types::mmr::mmr_membership_proof::MmrMembershipProof; + use triton_vm::prelude::twenty_first::util_types::mmr::mmr_trait::Mmr; + use triton_vm::prelude::twenty_first::util_types::mmr::shared_basic::leaf_index_to_mt_index_and_peak_index; use super::*; use crate::rust_shadowing_helper_functions; diff --git a/tasm-lib/src/mmr/verify_from_secret_in_secret_leaf_index.rs b/tasm-lib/src/mmr/verify_from_secret_in_secret_leaf_index.rs index cba48dd3..bf704ad3 100644 --- a/tasm-lib/src/mmr/verify_from_secret_in_secret_leaf_index.rs +++ b/tasm-lib/src/mmr/verify_from_secret_in_secret_leaf_index.rs @@ -104,12 +104,12 @@ impl BasicSnippet for MmrVerifyFromSecretInSecretLeafIndex { mod tests { use num::One; use tasm_lib::test_helpers::test_assertion_failure; - use twenty_first::math::other::random_elements; - use twenty_first::util_types::mmr::mmr_accumulator::MmrAccumulator; - use twenty_first::util_types::mmr::mmr_accumulator::util::mmra_with_mps; - use twenty_first::util_types::mmr::mmr_membership_proof::MmrMembershipProof; - use twenty_first::util_types::mmr::mmr_trait::Mmr; - use twenty_first::util_types::mmr::shared_basic::leaf_index_to_mt_index_and_peak_index; + use triton_vm::prelude::twenty_first::math::other::random_elements; + use triton_vm::prelude::twenty_first::util_types::mmr::mmr_accumulator::MmrAccumulator; + use triton_vm::prelude::twenty_first::util_types::mmr::mmr_accumulator::util::mmra_with_mps; + use triton_vm::prelude::twenty_first::util_types::mmr::mmr_membership_proof::MmrMembershipProof; + use triton_vm::prelude::twenty_first::util_types::mmr::mmr_trait::Mmr; + use triton_vm::prelude::twenty_first::util_types::mmr::shared_basic::leaf_index_to_mt_index_and_peak_index; use super::*; use crate::rust_shadowing_helper_functions; diff --git a/tasm-lib/src/mmr/verify_mmr_successor.rs b/tasm-lib/src/mmr/verify_mmr_successor.rs index af463cd0..b20623f0 100644 --- a/tasm-lib/src/mmr/verify_mmr_successor.rs +++ b/tasm-lib/src/mmr/verify_mmr_successor.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; +use triton_vm::prelude::twenty_first::util_types::mmr::mmr_accumulator::MmrAccumulator; +use triton_vm::prelude::twenty_first::util_types::mmr::mmr_successor_proof::MmrSuccessorProof; use triton_vm::prelude::*; -use twenty_first::util_types::mmr::mmr_accumulator::MmrAccumulator; -use twenty_first::util_types::mmr::mmr_successor_proof::MmrSuccessorProof; use crate::arithmetic::u64 as u64_lib; use crate::hashing::merkle_step_mem_u64_index::MerkleStepMemU64Index; @@ -411,8 +411,8 @@ impl VerifyMmrSuccessor { mod tests { use std::collections::VecDeque; - use twenty_first::util_types::mmr::mmr_accumulator::MmrAccumulator; - use twenty_first::util_types::mmr::mmr_successor_proof::MmrSuccessorProof; + use triton_vm::prelude::twenty_first::util_types::mmr::mmr_accumulator::MmrAccumulator; + use triton_vm::prelude::twenty_first::util_types::mmr::mmr_successor_proof::MmrSuccessorProof; use super::*; use crate::empty_stack; diff --git a/tasm-lib/src/neptune/mutator_set/get_swbf_indices.rs b/tasm-lib/src/neptune/mutator_set/get_swbf_indices.rs index 3a073188..1017f6b9 100644 --- a/tasm-lib/src/neptune/mutator_set/get_swbf_indices.rs +++ b/tasm-lib/src/neptune/mutator_set/get_swbf_indices.rs @@ -151,7 +151,7 @@ pub(crate) fn u32_to_u128_add_another_u128() -> RawCode { #[cfg(test)] mod tests { - use twenty_first::prelude::Sponge; + use triton_vm::prelude::twenty_first::prelude::Sponge; use super::*; use crate::empty_stack; 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 04076888..fa77855c 100644 --- a/tasm-lib/src/neptune/neptune_like_types_for_tests.rs +++ b/tasm-lib/src/neptune/neptune_like_types_for_tests.rs @@ -1,7 +1,7 @@ use arbitrary::Arbitrary; +use triton_vm::prelude::twenty_first::prelude::MmrMembershipProof; +use triton_vm::prelude::twenty_first::util_types::mmr::mmr_accumulator::MmrAccumulator; use triton_vm::prelude::*; -use twenty_first::prelude::MmrMembershipProof; -use twenty_first::util_types::mmr::mmr_accumulator::MmrAccumulator; use crate::prelude::TasmObject; diff --git a/tasm-lib/src/rust_shadowing_helper_functions.rs b/tasm-lib/src/rust_shadowing_helper_functions.rs index bfe6f833..3dc001dd 100644 --- a/tasm-lib/src/rust_shadowing_helper_functions.rs +++ b/tasm-lib/src/rust_shadowing_helper_functions.rs @@ -2,3 +2,29 @@ pub mod array; pub mod claim; pub mod dyn_malloc; pub mod list; + +/// Count the number of non-leaf nodes that were inserted *prior* to +/// the insertion of this leaf. +pub fn non_leaf_nodes_left(leaf_index: u64) -> u64 { + // This formula is derived as follows: + // To get the heights of peaks before this leaf index was inserted, bit-decompose + // the number of leaves before it was inserted. + // Number of leaves in tree of height h = 2^h + // Number of nodes in tree of height h = 2^(h + 1) - 1 + // Number of non-leaves is `#(nodes) - #(leaves)`. + // Thus: f(x) = sum_{h}(2^h - 1) + + // An upper limit for the loop iterator is the log_2_floor(leaf_index) + let log_2_floor_plus_one = u64::BITS - leaf_index.leading_zeros(); + let mut h = 0; + let mut ret = 0; + while h != log_2_floor_plus_one { + let pow = (1 << h) & leaf_index; + if pow != 0 { + ret += pow - 1; + } + h += 1; + } + + ret +} diff --git a/tasm-lib/src/rust_shadowing_helper_functions/array.rs b/tasm-lib/src/rust_shadowing_helper_functions/array.rs index 6f15600f..a6adb329 100644 --- a/tasm-lib/src/rust_shadowing_helper_functions/array.rs +++ b/tasm-lib/src/rust_shadowing_helper_functions/array.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use num::Zero; -use twenty_first::prelude::*; +use triton_vm::prelude::twenty_first::prelude::*; use crate::prelude::*; diff --git a/tasm-lib/src/rust_shadowing_helper_functions/list.rs b/tasm-lib/src/rust_shadowing_helper_functions/list.rs index 2a98a7d8..ed42d633 100644 --- a/tasm-lib/src/rust_shadowing_helper_functions/list.rs +++ b/tasm-lib/src/rust_shadowing_helper_functions/list.rs @@ -2,8 +2,8 @@ use std::collections::HashMap; use num::Zero; use num_traits::ConstOne; +use triton_vm::prelude::twenty_first::math::other::random_elements; use triton_vm::prelude::*; -use twenty_first::math::other::random_elements; use crate::U32_TO_USIZE_ERR; use crate::USIZE_TO_U64_ERR; diff --git a/tasm-lib/src/structure/manual_tasm_object_implementations.rs b/tasm-lib/src/structure/manual_tasm_object_implementations.rs index 4e802e9f..4d262846 100644 --- a/tasm-lib/src/structure/manual_tasm_object_implementations.rs +++ b/tasm-lib/src/structure/manual_tasm_object_implementations.rs @@ -1,10 +1,10 @@ use itertools::Itertools; use num_traits::Zero; +use triton_vm::prelude::twenty_first::error::BFieldCodecError; +use triton_vm::prelude::twenty_first::error::PolynomialBFieldCodecError; +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; +use triton_vm::prelude::twenty_first::prelude::*; use triton_vm::prelude::*; -use twenty_first::error::BFieldCodecError; -use twenty_first::error::PolynomialBFieldCodecError; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; -use twenty_first::prelude::*; use super::tasm_object::Result; use crate::prelude::*; diff --git a/tasm-lib/src/structure/tasm_object.rs b/tasm-lib/src/structure/tasm_object.rs index de9adf18..e8d4940c 100644 --- a/tasm-lib/src/structure/tasm_object.rs +++ b/tasm-lib/src/structure/tasm_object.rs @@ -330,7 +330,7 @@ mod tests { /// Test derivation of field getters and manual derivations of the `field!` macro mod derive_tests { use num_traits::ConstZero; - use twenty_first::math::x_field_element::EXTENSION_DEGREE; + use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use super::*; use crate::maybe_write_debuggable_vm_state_to_disk; diff --git a/tasm-lib/src/structure/verify_nd_si_integrity.rs b/tasm-lib/src/structure/verify_nd_si_integrity.rs index 7136ff86..f270755b 100644 --- a/tasm-lib/src/structure/verify_nd_si_integrity.rs +++ b/tasm-lib/src/structure/verify_nd_si_integrity.rs @@ -77,7 +77,7 @@ mod tests { use arbitrary::Arbitrary; use arbitrary::Unstructured; use num_traits::ConstZero; - use twenty_first::util_types::mmr::mmr_successor_proof::MmrSuccessorProof; + use triton_vm::prelude::twenty_first::util_types::mmr::mmr_successor_proof::MmrSuccessorProof; use super::*; use crate::memory::encode_to_memory; diff --git a/tasm-lib/src/verifier/challenges/new_empty_input_and_output.rs b/tasm-lib/src/verifier/challenges/new_empty_input_and_output.rs index f914ce08..792a0002 100644 --- a/tasm-lib/src/verifier/challenges/new_empty_input_and_output.rs +++ b/tasm-lib/src/verifier/challenges/new_empty_input_and_output.rs @@ -2,8 +2,8 @@ use num::One; use triton_vm::air::challenge_id::ChallengeId; use triton_vm::air::cross_table_argument::CrossTableArg; use triton_vm::air::cross_table_argument::EvalArg; +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use triton_vm::prelude::*; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; use crate::hashing::algebraic_hasher::sample_scalars_static_length_static_pointer::SampleScalarsStaticLengthStaticPointer; use crate::prelude::*; diff --git a/tasm-lib/src/verifier/challenges/new_generic_dyn_claim.rs b/tasm-lib/src/verifier/challenges/new_generic_dyn_claim.rs index 247450db..dddb1cba 100644 --- a/tasm-lib/src/verifier/challenges/new_generic_dyn_claim.rs +++ b/tasm-lib/src/verifier/challenges/new_generic_dyn_claim.rs @@ -3,8 +3,8 @@ use triton_vm::air::challenge_id::ChallengeId; use triton_vm::air::cross_table_argument::CrossTableArg; use triton_vm::air::cross_table_argument::EvalArg; use triton_vm::challenges::Challenges; +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use triton_vm::prelude::*; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; use crate::hashing::algebraic_hasher::sample_scalars_static_length_static_pointer::SampleScalarsStaticLengthStaticPointer; use crate::prelude::*; @@ -215,7 +215,7 @@ impl BasicSnippet for NewGenericDynClaim { #[cfg(test)] mod tests { use triton_vm::challenges::Challenges; - use twenty_first::math::other::random_elements; + use triton_vm::prelude::twenty_first::math::other::random_elements; use super::*; use crate::rust_shadowing_helper_functions::array::insert_as_array; diff --git a/tasm-lib/src/verifier/claim/instantiate_fiat_shamir_with_claim.rs b/tasm-lib/src/verifier/claim/instantiate_fiat_shamir_with_claim.rs index 0d1d04ec..c87885d7 100644 --- a/tasm-lib/src/verifier/claim/instantiate_fiat_shamir_with_claim.rs +++ b/tasm-lib/src/verifier/claim/instantiate_fiat_shamir_with_claim.rs @@ -69,8 +69,8 @@ impl BasicSnippet for InstantiateFiatShamirWithClaim { #[cfg(test)] mod tests { - use twenty_first::math::other::random_elements; - use twenty_first::prelude::Sponge; + use triton_vm::prelude::twenty_first::math::other::random_elements; + use triton_vm::prelude::twenty_first::prelude::Sponge; use super::*; use crate::rust_shadowing_helper_functions::claim::load_claim_from_memory; diff --git a/tasm-lib/src/verifier/fri/barycentric_evaluation.rs b/tasm-lib/src/verifier/fri/barycentric_evaluation.rs index 48a9213b..5f6f6f6f 100644 --- a/tasm-lib/src/verifier/fri/barycentric_evaluation.rs +++ b/tasm-lib/src/verifier/fri/barycentric_evaluation.rs @@ -1,5 +1,5 @@ +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use triton_vm::prelude::*; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; use crate::arithmetic::bfe::primitive_root_of_unity::PrimitiveRootOfUnity; use crate::prelude::*; @@ -222,9 +222,9 @@ impl BasicSnippet for BarycentricEvaluation { #[cfg(test)] mod tests { - use twenty_first::math::other::random_elements; - use twenty_first::math::polynomial::barycentric_evaluate; - use twenty_first::math::traits::PrimitiveRootOfUnity; + use triton_vm::prelude::twenty_first::math::other::random_elements; + use triton_vm::prelude::twenty_first::math::polynomial::barycentric_evaluate; + use triton_vm::prelude::twenty_first::math::traits::PrimitiveRootOfUnity; use super::*; use crate::library::STATIC_MEMORY_FIRST_ADDRESS; diff --git a/tasm-lib/src/verifier/fri/collinear_y.rs b/tasm-lib/src/verifier/fri/collinear_y.rs index 2df74992..34a40cd4 100644 --- a/tasm-lib/src/verifier/fri/collinear_y.rs +++ b/tasm-lib/src/verifier/fri/collinear_y.rs @@ -115,7 +115,7 @@ impl BasicSnippet for CollinearYXfe { #[cfg(test)] mod tests { - use twenty_first::math::polynomial::Polynomial; + use triton_vm::prelude::twenty_first::math::polynomial::Polynomial; use super::*; use crate::test_prelude::*; diff --git a/tasm-lib/src/verifier/fri/number_of_rounds.rs b/tasm-lib/src/verifier/fri/number_of_rounds.rs index bb9a202c..c122553d 100644 --- a/tasm-lib/src/verifier/fri/number_of_rounds.rs +++ b/tasm-lib/src/verifier/fri/number_of_rounds.rs @@ -65,7 +65,7 @@ impl BasicSnippet for NumberOfRounds { mod tests { use triton_vm::arithmetic_domain::ArithmeticDomain; use triton_vm::fri::Fri; - use twenty_first::math::traits::PrimitiveRootOfUnity; + use triton_vm::prelude::twenty_first::math::traits::PrimitiveRootOfUnity; use super::*; use crate::memory::dyn_malloc::DYN_MALLOC_ADDRESS; diff --git a/tasm-lib/src/verifier/fri/test_helpers.rs b/tasm-lib/src/verifier/fri/test_helpers.rs index f3a4358e..7aaf6f7f 100644 --- a/tasm-lib/src/verifier/fri/test_helpers.rs +++ b/tasm-lib/src/verifier/fri/test_helpers.rs @@ -1,12 +1,12 @@ use itertools::Itertools; use triton_vm::challenges::Challenges; +use triton_vm::prelude::twenty_first::prelude::*; use triton_vm::prelude::*; use triton_vm::proof_stream::ProofStream; use triton_vm::table::NUM_QUOTIENT_SEGMENTS; use triton_vm::table::master_table::MasterAuxTable; use triton_vm::table::master_table::MasterMainTable; use triton_vm::table::master_table::MasterTable; -use twenty_first::prelude::*; use crate::prelude::Digest; diff --git a/tasm-lib/src/verifier/fri/verify.rs b/tasm-lib/src/verifier/fri/verify.rs index 860db599..9648371a 100644 --- a/tasm-lib/src/verifier/fri/verify.rs +++ b/tasm-lib/src/verifier/fri/verify.rs @@ -1,19 +1,19 @@ +use ::twenty_first::util_types::merkle_tree::MerkleTree; +use ::twenty_first::util_types::merkle_tree::MerkleTreeInclusionProof; use anyhow::bail; use itertools::Itertools; use num::Zero; use triton_vm::arithmetic_domain::ArithmeticDomain; use triton_vm::error::FriValidationError; use triton_vm::fri::Fri; +use triton_vm::prelude::twenty_first::math::polynomial::Polynomial; +use triton_vm::prelude::twenty_first::math::polynomial::barycentric_evaluate; +use triton_vm::prelude::twenty_first::math::traits::ModPowU32; +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use triton_vm::prelude::*; use triton_vm::proof_item::FriResponse; use triton_vm::proof_item::ProofItemVariant; use triton_vm::proof_stream::ProofStream; -use twenty_first::math::polynomial::Polynomial; -use twenty_first::math::polynomial::barycentric_evaluate; -use twenty_first::math::traits::ModPowU32; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; -use twenty_first::util_types::merkle_tree::MerkleTree; -use twenty_first::util_types::merkle_tree::MerkleTreeInclusionProof; use crate::data_type::StructType; use crate::field; @@ -928,7 +928,7 @@ impl FriVerify { let num_collinearity_check = self.num_collinearity_checks as usize; let mut a_indices = proof_stream.sample_indices(domain_length, num_collinearity_check); - let tree_height = self.domain_length.ilog2() as usize; + let tree_height = self.domain_length.ilog2(); let fri_response = proof_stream .dequeue() .unwrap() @@ -942,11 +942,25 @@ impl FriVerify { // Check if last codeword matches the given root let codeword_digests = Self::map_convert_xfe_to_digest(&last_codeword); - let mt: MerkleTree = MerkleTree::par_new(&codeword_digests).unwrap(); + let codeword_digests_compatible = codeword_digests + .into_iter() + .map(|d| { + ::twenty_first::prelude::Digest( + d.values() + .map(|b| ::twenty_first::prelude::BFieldElement::new(b.value())), + ) + }) + .collect_vec(); + let mt: MerkleTree = MerkleTree::par_new(&codeword_digests_compatible).unwrap(); let last_codeword_merkle_root = mt.root(); let last_root = roots.last().unwrap(); - if *last_root != last_codeword_merkle_root { + let last_root_compatible = ::twenty_first::prelude::Digest( + last_root + .values() + .map(|b| ::twenty_first::prelude::BFieldElement::new(b.value())), + ); + if last_root_compatible != last_codeword_merkle_root { bail!(FriValidationError::BadMerkleRootForLastCodeword); } @@ -965,18 +979,53 @@ impl FriVerify { } // reduplicate authentication structures if necessary + let indexed_a_leafs_compatible = indexed_a_leaves + .iter() + .map(|(index, leaf)| { + ( + *index as u64, + ::twenty_first::prelude::Digest( + leaf.values() + .map(|b| ::twenty_first::prelude::BFieldElement::new(b.value())), + ), + ) + }) + .collect_vec(); + let fri_response_auth_structure_compatible = fri_response + .auth_structure + .iter() + .map(|d| { + ::twenty_first::prelude::Digest( + d.values() + .map(|b| ::twenty_first::prelude::BFieldElement::new(b.value())), + ) + }) + .collect_vec(); if num_nondeterministic_digests_read >= nondeterministic_digests.len() { let inclusion_proof = MerkleTreeInclusionProof { tree_height, - indexed_leafs: indexed_a_leaves.clone(), - authentication_structure: fri_response.auth_structure, + indexed_leafs: indexed_a_leafs_compatible, + authentication_structure: fri_response_auth_structure_compatible, }; // sanity check: the authentication structure was valid, right? - assert!(inclusion_proof.clone().verify(roots[0])); + let root_zero_compatible = ::twenty_first::prelude::Digest( + roots[0] + .values() + .map(|b| ::twenty_first::prelude::BFieldElement::new(b.value())), + ); + assert!(inclusion_proof.clone().verify(root_zero_compatible)); let reduplicated_authentication_paths = inclusion_proof.into_authentication_paths()?; + let reduplicated_authentication_paths_compatible = reduplicated_authentication_paths + .into_iter() + .map(|path| { + path.into_iter() + .map(|n| Digest(n.values().map(|b| BFieldElement::new(b.value())))) + .collect_vec() + }) + .collect_vec(); nondeterministic_digests.extend( - reduplicated_authentication_paths + reduplicated_authentication_paths_compatible .into_iter() .rev() .flatten(), @@ -984,16 +1033,37 @@ impl FriVerify { } // verify authentication paths for A leafs - for indexed_leaf in indexed_a_leaves.iter().rev() { + for (index, leaf) in indexed_a_leaves.iter().rev() { + let indexed_leaf = ( + *index as u64, + ::twenty_first::prelude::Digest( + leaf.values() + .map(|b| ::twenty_first::prelude::BFieldElement::new(b.value())), + ), + ); let authentication_path = &nondeterministic_digests[num_nondeterministic_digests_read - ..(num_nondeterministic_digests_read + tree_height)]; - num_nondeterministic_digests_read += tree_height; + ..(num_nondeterministic_digests_read + (tree_height as usize))]; + let authentication_path_compatible = authentication_path + .iter() + .map(|d| { + ::twenty_first::prelude::Digest( + d.values() + .map(|b| ::twenty_first::prelude::BFieldElement::new(b.value())), + ) + }) + .collect_vec(); + num_nondeterministic_digests_read += tree_height as usize; let inclusion_proof = MerkleTreeInclusionProof { tree_height, - indexed_leafs: vec![*indexed_leaf], - authentication_structure: authentication_path.to_vec(), + indexed_leafs: vec![indexed_leaf], + authentication_structure: authentication_path_compatible, }; - assert!(inclusion_proof.verify(roots[0])); + let root_zero_compatible = ::twenty_first::prelude::Digest( + roots[0] + .values() + .map(|b| ::twenty_first::prelude::BFieldElement::new(b.value())), + ); + assert!(inclusion_proof.verify(root_zero_compatible)); } // save indices and revealed leafs of first round's codeword for returning @@ -1028,18 +1098,54 @@ impl FriVerify { // reduplicate authentication structures if necessary if num_nondeterministic_digests_read >= nondeterministic_digests.len() { + let indexed_b_leafs_compatible = + indexed_b_leaves + .iter() + .map(|(index, leaf)| { + ( + *index as u64, + ::twenty_first::prelude::Digest(leaf.values().map(|b| { + ::twenty_first::prelude::BFieldElement::new(b.value()) + })), + ) + }) + .collect_vec(); + let fri_response_auth_structure_compatible = fri_response + .auth_structure + .iter() + .map(|d| { + ::twenty_first::prelude::Digest( + d.values() + .map(|b| ::twenty_first::prelude::BFieldElement::new(b.value())), + ) + }) + .collect_vec(); let inclusion_proof = MerkleTreeInclusionProof { tree_height: current_tree_height, - indexed_leafs: indexed_b_leaves.clone(), - authentication_structure: fri_response.auth_structure, + indexed_leafs: indexed_b_leafs_compatible, + authentication_structure: fri_response_auth_structure_compatible, }; // sanity check: the auth structure was valid, right? - assert!(inclusion_proof.clone().verify(roots[r])); + let root_r_compatible = ::twenty_first::prelude::Digest( + roots[r] + .values() + .map(|b| ::twenty_first::prelude::BFieldElement::new(b.value())), + ); + assert!(inclusion_proof.clone().verify(root_r_compatible)); let reduplicated_authentication_paths = inclusion_proof.into_authentication_paths()?; - nondeterministic_digests.extend( + let reduplicated_authentication_paths_compatible = reduplicated_authentication_paths + .into_iter() + .map(|path| { + path.into_iter() + .map(|d| Digest(d.values().map(|b| BFieldElement::new(b.value())))) + .collect_vec() + }) + .collect_vec(); + nondeterministic_digests.extend( + reduplicated_authentication_paths_compatible .into_iter() .rev() .flatten(), @@ -1047,17 +1153,38 @@ impl FriVerify { } // verify authentication paths for B leafs - for indexed_leaf in indexed_b_leaves.iter().rev() { + for (index, leaf) in indexed_b_leaves.iter().rev() { + let indexed_leaf_compatible = ( + *index as u64, + ::twenty_first::prelude::Digest( + leaf.values() + .map(|b| ::twenty_first::prelude::BFieldElement::new(b.value())), + ), + ); let authentication_path = &nondeterministic_digests [num_nondeterministic_digests_read - ..(num_nondeterministic_digests_read + current_tree_height)]; - num_nondeterministic_digests_read += current_tree_height; + ..(num_nondeterministic_digests_read + (current_tree_height as usize))]; + let authentication_path_compatible = authentication_path + .iter() + .map(|d| { + ::twenty_first::prelude::Digest( + d.values() + .map(|b| ::twenty_first::prelude::BFieldElement::new(b.value())), + ) + }) + .collect_vec(); + num_nondeterministic_digests_read += current_tree_height as usize; let inclusion_proof = MerkleTreeInclusionProof { tree_height: current_tree_height, - indexed_leafs: vec![*indexed_leaf], - authentication_structure: authentication_path.to_vec(), + indexed_leafs: vec![indexed_leaf_compatible], + authentication_structure: authentication_path_compatible, }; - if !inclusion_proof.verify(roots[r]) { + let root_r_compatible = ::twenty_first::prelude::Digest( + roots[r] + .values() + .map(|b| ::twenty_first::prelude::BFieldElement::new(b.value())), + ); + if !inclusion_proof.verify(root_r_compatible) { bail!(FriValidationError::BadMerkleAuthenticationPath); } } @@ -1150,9 +1277,9 @@ mod tests { use num_traits::Zero; use proptest::collection::vec; use rayon::prelude::*; + use triton_vm::prelude::twenty_first::math::ntt::ntt; + use triton_vm::prelude::twenty_first::util_types::sponge::Sponge; use triton_vm::proof_item::ProofItem; - use twenty_first::math::ntt::ntt; - use twenty_first::util_types::sponge::Sponge; use super::*; use crate::empty_stack; diff --git a/tasm-lib/src/verifier/fri/verify_fri_authentication_paths.rs b/tasm-lib/src/verifier/fri/verify_fri_authentication_paths.rs index a8cdefe3..275ba900 100644 --- a/tasm-lib/src/verifier/fri/verify_fri_authentication_paths.rs +++ b/tasm-lib/src/verifier/fri/verify_fri_authentication_paths.rs @@ -1,5 +1,5 @@ +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use triton_vm::prelude::*; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; use crate::prelude::*; @@ -131,7 +131,7 @@ mod tests { use rand::distr::StandardUniform; use strum::EnumIter; use strum::IntoEnumIterator; - use twenty_first::prelude::*; + use triton_vm::prelude::twenty_first::prelude::*; use super::*; use crate::rust_shadowing_helper_functions; diff --git a/tasm-lib/src/verifier/master_table/air_constraint_evaluation.rs b/tasm-lib/src/verifier/master_table/air_constraint_evaluation.rs index e0ab6300..ff0a9494 100644 --- a/tasm-lib/src/verifier/master_table/air_constraint_evaluation.rs +++ b/tasm-lib/src/verifier/master_table/air_constraint_evaluation.rs @@ -5,12 +5,12 @@ use triton_vm::constraints::static_air_constraint_evaluation_tasm; use triton_vm::memory_layout::DynamicTasmConstraintEvaluationMemoryLayout; use triton_vm::memory_layout::IntegralMemoryLayout; use triton_vm::memory_layout::StaticTasmConstraintEvaluationMemoryLayout; +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use triton_vm::prelude::*; use triton_vm::table::auxiliary_table::Evaluable; use triton_vm::table::master_table::MasterAuxTable; use triton_vm::table::master_table::MasterMainTable; use triton_vm::table::master_table::MasterTable; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; use crate::data_type::ArrayType; use crate::memory::dyn_malloc::DYN_MALLOC_ADDRESS; @@ -296,10 +296,10 @@ mod tests { use arbitrary::Unstructured; use num_traits::ConstZero; use rand::distr::StandardUniform; + use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use triton_vm::proof_stream::ProofStream; use triton_vm::table::master_table::MasterMainTable; use triton_vm::table::master_table::MasterTable; - use twenty_first::math::x_field_element::EXTENSION_DEGREE; use super::*; use crate::execute_test; diff --git a/tasm-lib/src/verifier/master_table/divide_out_zerofiers.rs b/tasm-lib/src/verifier/master_table/divide_out_zerofiers.rs index 53b4970a..f5d4982d 100644 --- a/tasm-lib/src/verifier/master_table/divide_out_zerofiers.rs +++ b/tasm-lib/src/verifier/master_table/divide_out_zerofiers.rs @@ -1,8 +1,8 @@ use triton_vm::prelude::LabelledInstruction; +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use triton_vm::prelude::*; use triton_vm::table::ConstraintType; use triton_vm::table::master_table::MasterAuxTable; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; use crate::prelude::*; use crate::verifier::master_table::air_constraint_evaluation::AirConstraintEvaluation; @@ -151,8 +151,8 @@ mod tests { use itertools::Itertools; use rand::prelude::*; - use twenty_first::math::traits::ModPowU32; - use twenty_first::math::traits::PrimitiveRootOfUnity; + use triton_vm::prelude::twenty_first::math::traits::ModPowU32; + use triton_vm::prelude::twenty_first::math::traits::PrimitiveRootOfUnity; use super::*; use crate::empty_stack; @@ -330,7 +330,7 @@ mod bench { use std::collections::HashMap; use itertools::Itertools; - use twenty_first::math::traits::PrimitiveRootOfUnity; + use triton_vm::prelude::twenty_first::math::traits::PrimitiveRootOfUnity; use super::*; use crate::empty_stack; diff --git a/tasm-lib/src/verifier/master_table/verify_table_rows.rs b/tasm-lib/src/verifier/master_table/verify_table_rows.rs index 3be57428..3e2c9fba 100644 --- a/tasm-lib/src/verifier/master_table/verify_table_rows.rs +++ b/tasm-lib/src/verifier/master_table/verify_table_rows.rs @@ -1,11 +1,11 @@ use strum::Display; use strum::EnumIter; +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use triton_vm::prelude::*; use triton_vm::table::NUM_QUOTIENT_SEGMENTS; use triton_vm::table::master_table::MasterAuxTable; use triton_vm::table::master_table::MasterMainTable; use triton_vm::table::master_table::MasterTable; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; use crate::hashing::algebraic_hasher::hash_static_size::HashStaticSize; use crate::prelude::*; @@ -203,9 +203,9 @@ impl BasicSnippet for VerifyTableRows { #[cfg(test)] mod tests { - use twenty_first::math::other::random_elements; - use twenty_first::math::tip5::RATE; - use twenty_first::prelude::*; + use triton_vm::prelude::twenty_first::math::other::random_elements; + use triton_vm::prelude::twenty_first::math::tip5::RATE; + use triton_vm::prelude::twenty_first::prelude::*; use super::*; use crate::memory::encode_to_memory; diff --git a/tasm-lib/src/verifier/master_table/zerofiers_inverse.rs b/tasm-lib/src/verifier/master_table/zerofiers_inverse.rs index 2af55068..c0c6d166 100644 --- a/tasm-lib/src/verifier/master_table/zerofiers_inverse.rs +++ b/tasm-lib/src/verifier/master_table/zerofiers_inverse.rs @@ -1,7 +1,7 @@ use strum::EnumCount; +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use triton_vm::prelude::*; use triton_vm::table::ConstraintType; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; use crate::arithmetic::xfe::to_the_power_of_power_of_2::ToThePowerOfPowerOf2; use crate::prelude::*; @@ -175,8 +175,8 @@ impl BasicSnippet for ZerofiersInverse { #[cfg(test)] mod tests { use num::One; - use twenty_first::math::traits::ModPowU32; - use twenty_first::math::traits::PrimitiveRootOfUnity; + use triton_vm::prelude::twenty_first::math::traits::ModPowU32; + use triton_vm::prelude::twenty_first::math::traits::PrimitiveRootOfUnity; use super::*; use crate::rust_shadowing_helper_functions::array::insert_as_array; diff --git a/tasm-lib/src/verifier/out_of_domain_points.rs b/tasm-lib/src/verifier/out_of_domain_points.rs index b6d927d3..3a6bb170 100644 --- a/tasm-lib/src/verifier/out_of_domain_points.rs +++ b/tasm-lib/src/verifier/out_of_domain_points.rs @@ -1,5 +1,5 @@ +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; use triton_vm::prelude::*; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; use crate::data_type::ArrayType; use crate::prelude::*; @@ -124,9 +124,9 @@ impl BasicSnippet for OutOfDomainPoints { #[cfg(test)] mod tests { + use triton_vm::prelude::twenty_first::math::traits::ModPowU32; + use triton_vm::prelude::twenty_first::math::traits::PrimitiveRootOfUnity; use triton_vm::table::NUM_QUOTIENT_SEGMENTS; - use twenty_first::math::traits::ModPowU32; - use twenty_first::math::traits::PrimitiveRootOfUnity; use super::*; use crate::rust_shadowing_helper_functions::array::insert_as_array; diff --git a/tasm-lib/src/verifier/stark_verify.rs b/tasm-lib/src/verifier/stark_verify.rs index 7c2c327f..67275075 100644 --- a/tasm-lib/src/verifier/stark_verify.rs +++ b/tasm-lib/src/verifier/stark_verify.rs @@ -1,5 +1,7 @@ use itertools::Itertools; use triton_vm::challenges::Challenges; +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; +use triton_vm::prelude::twenty_first::prelude::MerkleTreeInclusionProof; use triton_vm::prelude::*; use triton_vm::proof_item::ProofItemVariant; use triton_vm::proof_stream::ProofStream; @@ -7,8 +9,6 @@ use triton_vm::table::NUM_QUOTIENT_SEGMENTS; use triton_vm::table::master_table::MasterAuxTable; use triton_vm::table::master_table::MasterMainTable; use triton_vm::table::master_table::MasterTable; -use twenty_first::math::x_field_element::EXTENSION_DEGREE; -use twenty_first::prelude::MerkleTreeInclusionProof; use super::master_table::air_constraint_evaluation::AirConstraintEvaluation; use super::master_table::air_constraint_evaluation::MemoryLayout; 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 b9c2427d..58792f23 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,12 +1,12 @@ use triton_vm::fri::AuthenticationStructure; +use triton_vm::prelude::twenty_first::math::x_field_element::EXTENSION_DEGREE; +use triton_vm::prelude::twenty_first::prelude::Polynomial; 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 twenty_first::math::x_field_element::EXTENSION_DEGREE; -use twenty_first::prelude::Polynomial; use crate::hashing::sponge_hasher::pad_and_absorb_all::PadAndAbsorbAll; use crate::prelude::*; @@ -374,11 +374,11 @@ mod tests { use num_traits::One; use num_traits::Zero; use strum::IntoEnumIterator; + use triton_vm::prelude::twenty_first::prelude::*; use triton_vm::proof_item::ProofItem; use triton_vm::proof_stream::ProofStream; use triton_vm::table::master_table::MasterMainTable; use triton_vm::table::master_table::MasterTable; - use twenty_first::prelude::*; use super::*; use crate::empty_stack; diff --git a/tasm-lib/src/verifier/xfe_ntt.rs b/tasm-lib/src/verifier/xfe_ntt.rs index 9db8f5db..114defc3 100644 --- a/tasm-lib/src/verifier/xfe_ntt.rs +++ b/tasm-lib/src/verifier/xfe_ntt.rs @@ -462,8 +462,8 @@ impl BasicSnippet for XfeNtt { #[cfg(test)] mod tests { - use twenty_first::math::ntt::ntt; - use twenty_first::math::traits::PrimitiveRootOfUnity; + use triton_vm::prelude::twenty_first::math::ntt::ntt; + use triton_vm::prelude::twenty_first::math::traits::PrimitiveRootOfUnity; use super::*; use crate::empty_stack;