plonky2/evm/tests/empty_txn_list.rs
Hamish Ivey-Law c134b59763
Cross-table lookup for arithmetic stark (#905)
* First draft of linking arithmetic Stark into the CTL mechanism.

* Handle {ADD,SUB,MUL}FP254 operations explicitly in `modular.rs`.

* Adjust argument order; add tests.

* Add CTLs for ADD, MUL, SUB, LT and GT.

* Add CTLs for {ADD,MUL,SUB}MOD, DIV and MOD.

* Add CTLs for {ADD,MUL,SUB}FP254 operations.

* Refactor the CPU/arithmetic CTL mapping; add some documentation.

* Minor comment fixes.

* Combine addcy CTLs at the expense of repeated constraint evaluation.

* Combine addcy CTLs at the expense of repeated constraint evaluation.

* Merge `*FP254` CTL into main CTL; rename some registers.

* Connect extra argument from CPU in binary ops to facilitate combining with ternary ops.

* Merge modular ops CTL into main CTL.

* Refactor DIV and MOD code into its own module.

* Merge DIV and MOD into arithmetic CTL.

* Clippy.

* Fixes related to merge.

* Simplify register naming.

* Generate u16 BN254 modulus limbs at compile time.

* Clippy.

* Add degree bits ranges for Arithmetic table.
2023-05-11 03:29:06 +10:00

144 lines
4.9 KiB
Rust

#![allow(clippy::upper_case_acronyms)]
use std::collections::HashMap;
use std::marker::PhantomData;
use std::time::Duration;
use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV};
use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie};
use keccak_hash::keccak;
use log::info;
use plonky2::field::goldilocks_field::GoldilocksField;
use plonky2::plonk::config::PoseidonGoldilocksConfig;
use plonky2::util::serialization::{DefaultGateSerializer, DefaultGeneratorSerializer};
use plonky2::util::timing::TimingTree;
use plonky2_evm::all_stark::AllStark;
use plonky2_evm::config::StarkConfig;
use plonky2_evm::fixed_recursive_verifier::AllRecursiveCircuits;
use plonky2_evm::generation::{GenerationInputs, TrieInputs};
use plonky2_evm::proof::BlockMetadata;
use plonky2_evm::prover::prove;
use plonky2_evm::verifier::verify_proof;
use plonky2_evm::Node;
type F = GoldilocksField;
const D: usize = 2;
type C = PoseidonGoldilocksConfig;
/// Execute the empty list of transactions, i.e. a no-op.
#[test]
#[ignore] // Too slow to run on CI.
fn test_empty_txn_list() -> anyhow::Result<()> {
init_logger();
let all_stark = AllStark::<F, D>::default();
let config = StarkConfig::standard_fast_config();
let block_metadata = BlockMetadata::default();
let state_trie = HashedPartialTrie::from(Node::Empty);
let transactions_trie = HashedPartialTrie::from(Node::Empty);
let receipts_trie = HashedPartialTrie::from(Node::Empty);
let storage_tries = vec![];
let state_trie_root = state_trie.hash();
let txns_trie_root = transactions_trie.hash();
let receipts_trie_root = receipts_trie.hash();
let mut contract_code = HashMap::new();
contract_code.insert(keccak(vec![]), vec![]);
let inputs = GenerationInputs {
signed_txns: vec![],
tries: TrieInputs {
state_trie,
transactions_trie,
receipts_trie,
storage_tries,
},
contract_code,
block_metadata,
addresses: vec![],
};
let mut timing = TimingTree::new("prove", log::Level::Debug);
// TODO: This is redundant; prove_root below calls this prove method internally.
// Just keeping it for now because the root proof returned by prove_root doesn't contain public
// values yet, and we want those for the assertions below.
let proof = prove::<F, C, D>(&all_stark, &config, inputs.clone(), &mut timing)?;
timing.filter(Duration::from_millis(100)).print();
assert_eq!(
proof.public_values.trie_roots_before.state_root,
state_trie_root
);
assert_eq!(
proof.public_values.trie_roots_after.state_root,
state_trie_root
);
assert_eq!(
proof.public_values.trie_roots_before.transactions_root,
txns_trie_root
);
assert_eq!(
proof.public_values.trie_roots_after.transactions_root,
txns_trie_root
);
assert_eq!(
proof.public_values.trie_roots_before.receipts_root,
receipts_trie_root
);
assert_eq!(
proof.public_values.trie_roots_after.receipts_root,
receipts_trie_root
);
verify_proof(&all_stark, proof, &config)?;
let all_circuits = AllRecursiveCircuits::<F, C, D>::new(
&all_stark,
&[9..18, 9..15, 9..15, 9..10, 9..12, 9..18], // Minimal ranges to prove an empty list
&config,
);
{
let gate_serializer = DefaultGateSerializer;
let generator_serializer = DefaultGeneratorSerializer {
_phantom: PhantomData::<C>,
};
let timing = TimingTree::new("serialize AllRecursiveCircuits", log::Level::Info);
let all_circuits_bytes = all_circuits
.to_bytes(&gate_serializer, &generator_serializer)
.map_err(|_| anyhow::Error::msg("AllRecursiveCircuits serialization failed."))?;
timing.filter(Duration::from_millis(100)).print();
info!(
"AllRecursiveCircuits length: {} bytes",
all_circuits_bytes.len()
);
let timing = TimingTree::new("deserialize AllRecursiveCircuits", log::Level::Info);
let all_circuits_from_bytes = AllRecursiveCircuits::<F, C, D>::from_bytes(
&all_circuits_bytes,
&gate_serializer,
&generator_serializer,
)
.map_err(|_| anyhow::Error::msg("AllRecursiveCircuits deserialization failed."))?;
timing.filter(Duration::from_millis(100)).print();
assert_eq!(all_circuits, all_circuits_from_bytes);
}
let mut timing = TimingTree::new("prove", log::Level::Info);
let root_proof = all_circuits.prove_root(&all_stark, &config, inputs, &mut timing)?;
timing.filter(Duration::from_millis(100)).print();
all_circuits.verify_root(root_proof.clone())?;
let agg_proof = all_circuits.prove_aggregation(false, &root_proof, false, &root_proof)?;
all_circuits.verify_aggregation(&agg_proof)
}
fn init_logger() {
let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info"));
}