Constrain genesis block's state trie.

This commit is contained in:
Linda Guiga 2023-09-11 15:47:33 +01:00
parent 3571f09707
commit 4d7d9ffa3c
No known key found for this signature in database
11 changed files with 96 additions and 15 deletions

View File

@ -640,6 +640,11 @@ where
lhs: &ExtraBlockDataTarget, lhs: &ExtraBlockDataTarget,
rhs: &ExtraBlockDataTarget, rhs: &ExtraBlockDataTarget,
) { ) {
// Connect genesis state root values.
for (&limb0, &limb1) in pvs.genesis_state_root.iter().zip(&rhs.genesis_state_root) {
builder.connect(limb0, limb1);
}
// Connect the transaction number in public values to the lhs and rhs values correctly. // Connect the transaction number in public values to the lhs and rhs values correctly.
builder.connect(pvs.txn_number_before, lhs.txn_number_before); builder.connect(pvs.txn_number_before, lhs.txn_number_before);
builder.connect(pvs.txn_number_after, rhs.txn_number_after); builder.connect(pvs.txn_number_after, rhs.txn_number_after);
@ -776,6 +781,16 @@ where
builder.connect(limb0, limb1); builder.connect(limb0, limb1);
} }
// Between blocks, the genesis state trie remains unchanged.
for (&limb0, limb1) in lhs
.extra_block_data
.genesis_state_root
.iter()
.zip(rhs.extra_block_data.genesis_state_root)
{
builder.connect(limb0, limb1);
}
// Connect block numbers. // Connect block numbers.
let one = builder.one(); let one = builder.one();
let prev_block_nb = builder.sub(rhs.block_metadata.block_number, one); let prev_block_nb = builder.sub(rhs.block_metadata.block_number, one);
@ -787,13 +802,23 @@ where
// Connect intermediary values for gas_used and bloom filters to the block's final values. We only plug on the right, so there is no need to check the left-handside block. // Connect intermediary values for gas_used and bloom filters to the block's final values. We only plug on the right, so there is no need to check the left-handside block.
Self::connect_final_block_values_to_intermediary(builder, rhs); Self::connect_final_block_values_to_intermediary(builder, rhs);
// Chack that the genesis block number is 0.
let zero = builder.zero(); let zero = builder.zero();
let has_not_parent_block = builder.sub(one, has_parent_block.target); let has_not_parent_block = builder.sub(one, has_parent_block.target);
// Chack that the genesis block number is 0.
let gen_block_constr = builder.mul(has_not_parent_block, rhs.block_metadata.block_number); let gen_block_constr = builder.mul(has_not_parent_block, rhs.block_metadata.block_number);
builder.connect(gen_block_constr, zero); builder.connect(gen_block_constr, zero);
// TODO: Check that the genesis block has a predetermined state trie root. // Check that the genesis block has a predetermined state trie root.
for (&limb0, limb1) in rhs
.trie_roots_before
.state_root
.iter()
.zip(rhs.extra_block_data.genesis_state_root)
{
let mut constr = builder.sub(limb0, limb1);
constr = builder.mul(has_not_parent_block, constr);
builder.connect(constr, zero);
}
} }
fn connect_final_block_values_to_intermediary( fn connect_final_block_values_to_intermediary(
@ -981,16 +1006,34 @@ where
block_inputs block_inputs
.set_proof_with_pis_target(&self.block.parent_block_proof, parent_block_proof); .set_proof_with_pis_target(&self.block.parent_block_proof, parent_block_proof);
} else { } else {
// Initialize state_root_after and the block number for correct connection between blocks. // Initialize genesis_state_trie, state_root_after and the block number for correct connection between blocks.
let state_trie_root_keys = 24..32; // Initialize `state_root_after`.
let block_number_key = TrieRootsTarget::SIZE * 2 + 6; let state_trie_root_after_keys = 24..32;
let mut nonzero_pis = HashMap::new(); let mut nonzero_pis = HashMap::new();
for (key, &value) in state_trie_root_keys for (key, &value) in state_trie_root_after_keys
.zip_eq(&h256_limbs::<F>(public_values.trie_roots_before.state_root)) .zip_eq(&h256_limbs::<F>(public_values.trie_roots_before.state_root))
{ {
nonzero_pis.insert(key, value); nonzero_pis.insert(key, value);
} }
// Initialize the genesis state trie digest.
let genesis_state_trie_keys = TrieRootsTarget::SIZE * 2
+ BlockMetadataTarget::SIZE
+ BlockHashesTarget::BLOCK_HASHES_SIZE
..TrieRootsTarget::SIZE * 2
+ BlockMetadataTarget::SIZE
+ BlockHashesTarget::BLOCK_HASHES_SIZE
+ 8;
for (key, &value) in genesis_state_trie_keys.zip_eq(&h256_limbs::<F>(
public_values.extra_block_data.genesis_state_root,
)) {
nonzero_pis.insert(key, value);
}
// Initialize the block number.
let block_number_key = TrieRootsTarget::SIZE * 2 + 6;
nonzero_pis.insert(block_number_key, F::NEG_ONE); nonzero_pis.insert(block_number_key, F::NEG_ONE);
block_inputs.set_proof_with_pis_target( block_inputs.set_proof_with_pis_target(
&self.block.parent_block_proof, &self.block.parent_block_proof,
&cyclic_base_proof( &cyclic_base_proof(

View File

@ -48,6 +48,8 @@ pub struct GenerationInputs {
pub tries: TrieInputs, pub tries: TrieInputs,
/// Expected trie roots after the transactions are executed. /// Expected trie roots after the transactions are executed.
pub trie_roots_after: TrieRoots, pub trie_roots_after: TrieRoots,
/// State trie root of the genesis block.
pub genesis_state_trie_root: H256,
/// Mapping between smart contract code hashes and the contract byte code. /// Mapping between smart contract code hashes and the contract byte code.
/// All account smart contracts that are invoked will have an entry present. /// All account smart contracts that are invoked will have an entry present.
@ -251,6 +253,7 @@ pub fn generate_traces<F: RichField + Extendable<D>, const D: usize>(
let txn_number_after = read_metadata(GlobalMetadata::TxnNumberAfter); let txn_number_after = read_metadata(GlobalMetadata::TxnNumberAfter);
let extra_block_data = ExtraBlockData { let extra_block_data = ExtraBlockData {
genesis_state_root: inputs.genesis_state_trie_root,
txn_number_before: inputs.txn_number_before, txn_number_before: inputs.txn_number_before,
txn_number_after, txn_number_after,
gas_used_before: inputs.gas_used_before, gas_used_before: inputs.gas_used_before,

View File

@ -116,6 +116,7 @@ fn observe_extra_block_data<
challenger: &mut Challenger<F, C::Hasher>, challenger: &mut Challenger<F, C::Hasher>,
extra_data: &ExtraBlockData, extra_data: &ExtraBlockData,
) { ) {
challenger.observe_elements(&h256_limbs(extra_data.genesis_state_root));
challenger.observe_element(F::from_canonical_u32(extra_data.txn_number_before.as_u32())); challenger.observe_element(F::from_canonical_u32(extra_data.txn_number_before.as_u32()));
challenger.observe_element(F::from_canonical_u32(extra_data.txn_number_after.as_u32())); challenger.observe_element(F::from_canonical_u32(extra_data.txn_number_after.as_u32()));
challenger.observe_element(F::from_canonical_u32(extra_data.gas_used_before.as_u32())); challenger.observe_element(F::from_canonical_u32(extra_data.gas_used_before.as_u32()));
@ -138,6 +139,7 @@ fn observe_extra_block_data_target<
) where ) where
C::Hasher: AlgebraicHasher<F>, C::Hasher: AlgebraicHasher<F>,
{ {
challenger.observe_elements(&extra_data.genesis_state_root);
challenger.observe_element(extra_data.txn_number_before); challenger.observe_element(extra_data.txn_number_before);
challenger.observe_element(extra_data.txn_number_after); challenger.observe_element(extra_data.txn_number_after);
challenger.observe_element(extra_data.gas_used_before); challenger.observe_element(extra_data.gas_used_before);

View File

@ -95,6 +95,7 @@ pub struct BlockMetadata {
#[derive(Debug, Clone, Default, Deserialize, Serialize)] #[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct ExtraBlockData { pub struct ExtraBlockData {
pub genesis_state_root: H256,
pub txn_number_before: U256, pub txn_number_before: U256,
pub txn_number_after: U256, pub txn_number_after: U256,
pub gas_used_before: U256, pub gas_used_before: U256,
@ -166,6 +167,7 @@ impl PublicValuesTarget {
buffer.write_target_array(&cur_hash)?; buffer.write_target_array(&cur_hash)?;
let ExtraBlockDataTarget { let ExtraBlockDataTarget {
genesis_state_root,
txn_number_before, txn_number_before,
txn_number_after, txn_number_after,
gas_used_before, gas_used_before,
@ -173,6 +175,7 @@ impl PublicValuesTarget {
block_bloom_before, block_bloom_before,
block_bloom_after, block_bloom_after,
} = self.extra_block_data; } = self.extra_block_data;
buffer.write_target_array(&genesis_state_root)?;
buffer.write_target(txn_number_before)?; buffer.write_target(txn_number_before)?;
buffer.write_target(txn_number_after)?; buffer.write_target(txn_number_after)?;
buffer.write_target(gas_used_before)?; buffer.write_target(gas_used_before)?;
@ -214,6 +217,7 @@ impl PublicValuesTarget {
}; };
let extra_block_data = ExtraBlockDataTarget { let extra_block_data = ExtraBlockDataTarget {
genesis_state_root: buffer.read_target_array()?,
txn_number_before: buffer.read_target()?, txn_number_before: buffer.read_target()?,
txn_number_after: buffer.read_target()?, txn_number_after: buffer.read_target()?,
gas_used_before: buffer.read_target()?, gas_used_before: buffer.read_target()?,
@ -381,7 +385,7 @@ pub struct BlockMetadataTarget {
} }
impl BlockMetadataTarget { impl BlockMetadataTarget {
const SIZE: usize = 77; pub const SIZE: usize = 77;
pub fn from_public_inputs(pis: &[Target]) -> Self { pub fn from_public_inputs(pis: &[Target]) -> Self {
let block_beneficiary = pis[0..5].try_into().unwrap(); let block_beneficiary = pis[0..5].try_into().unwrap();
@ -465,7 +469,7 @@ pub struct BlockHashesTarget {
} }
impl BlockHashesTarget { impl BlockHashesTarget {
const BLOCK_HASHES_SIZE: usize = 2056; pub const BLOCK_HASHES_SIZE: usize = 2056;
pub fn from_public_inputs(pis: &[Target]) -> Self { pub fn from_public_inputs(pis: &[Target]) -> Self {
Self { Self {
prev_hashes: pis[0..2048].try_into().unwrap(), prev_hashes: pis[0..2048].try_into().unwrap(),
@ -505,6 +509,7 @@ impl BlockHashesTarget {
#[derive(Eq, PartialEq, Debug, Copy, Clone)] #[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub struct ExtraBlockDataTarget { pub struct ExtraBlockDataTarget {
pub genesis_state_root: [Target; 8],
pub txn_number_before: Target, pub txn_number_before: Target,
pub txn_number_after: Target, pub txn_number_after: Target,
pub gas_used_before: Target, pub gas_used_before: Target,
@ -514,17 +519,19 @@ pub struct ExtraBlockDataTarget {
} }
impl ExtraBlockDataTarget { impl ExtraBlockDataTarget {
const SIZE: usize = 132; const SIZE: usize = 140;
pub fn from_public_inputs(pis: &[Target]) -> Self { pub fn from_public_inputs(pis: &[Target]) -> Self {
let txn_number_before = pis[0]; let genesis_state_root = pis[0..8].try_into().unwrap();
let txn_number_after = pis[1]; let txn_number_before = pis[8];
let gas_used_before = pis[2]; let txn_number_after = pis[9];
let gas_used_after = pis[3]; let gas_used_before = pis[10];
let block_bloom_before = pis[4..68].try_into().unwrap(); let gas_used_after = pis[11];
let block_bloom_after = pis[68..132].try_into().unwrap(); let block_bloom_before = pis[12..76].try_into().unwrap();
let block_bloom_after = pis[76..140].try_into().unwrap();
Self { Self {
genesis_state_root,
txn_number_before, txn_number_before,
txn_number_after, txn_number_after,
gas_used_before, gas_used_before,
@ -541,6 +548,13 @@ impl ExtraBlockDataTarget {
ed1: Self, ed1: Self,
) -> Self { ) -> Self {
Self { Self {
genesis_state_root: core::array::from_fn(|i| {
builder.select(
condition,
ed0.genesis_state_root[i],
ed1.genesis_state_root[i],
)
}),
txn_number_before: builder.select( txn_number_before: builder.select(
condition, condition,
ed0.txn_number_before, ed0.txn_number_before,
@ -571,6 +585,9 @@ impl ExtraBlockDataTarget {
ed0: Self, ed0: Self,
ed1: Self, ed1: Self,
) { ) {
for i in 0..8 {
builder.connect(ed0.genesis_state_root[i], ed1.genesis_state_root[i]);
}
builder.connect(ed0.txn_number_before, ed1.txn_number_before); builder.connect(ed0.txn_number_before, ed1.txn_number_before);
builder.connect(ed0.txn_number_after, ed1.txn_number_after); builder.connect(ed0.txn_number_after, ed1.txn_number_after);
builder.connect(ed0.gas_used_before, ed1.gas_used_before); builder.connect(ed0.gas_used_before, ed1.gas_used_before);

View File

@ -808,6 +808,7 @@ pub(crate) fn add_virtual_block_hashes<F: RichField + Extendable<D>, const D: us
pub(crate) fn add_virtual_extra_block_data<F: RichField + Extendable<D>, const D: usize>( pub(crate) fn add_virtual_extra_block_data<F: RichField + Extendable<D>, const D: usize>(
builder: &mut CircuitBuilder<F, D>, builder: &mut CircuitBuilder<F, D>,
) -> ExtraBlockDataTarget { ) -> ExtraBlockDataTarget {
let genesis_state_root = builder.add_virtual_public_input_arr();
let txn_number_before = builder.add_virtual_public_input(); let txn_number_before = builder.add_virtual_public_input();
let txn_number_after = builder.add_virtual_public_input(); let txn_number_after = builder.add_virtual_public_input();
let gas_used_before = builder.add_virtual_public_input(); let gas_used_before = builder.add_virtual_public_input();
@ -815,6 +816,7 @@ pub(crate) fn add_virtual_extra_block_data<F: RichField + Extendable<D>, const D
let block_bloom_before: [Target; 64] = builder.add_virtual_public_input_arr(); let block_bloom_before: [Target; 64] = builder.add_virtual_public_input_arr();
let block_bloom_after: [Target; 64] = builder.add_virtual_public_input_arr(); let block_bloom_after: [Target; 64] = builder.add_virtual_public_input_arr();
ExtraBlockDataTarget { ExtraBlockDataTarget {
genesis_state_root,
txn_number_before, txn_number_before,
txn_number_after, txn_number_after,
gas_used_before, gas_used_before,
@ -1070,6 +1072,10 @@ pub(crate) fn set_extra_public_values_target<F, W, const D: usize>(
F: RichField + Extendable<D>, F: RichField + Extendable<D>,
W: Witness<F>, W: Witness<F>,
{ {
witness.set_target_arr(
&ed_target.genesis_state_root,
&h256_limbs::<F>(ed.genesis_state_root),
);
witness.set_target( witness.set_target(
ed_target.txn_number_before, ed_target.txn_number_before,
F::from_canonical_usize(ed.txn_number_before.as_usize()), F::from_canonical_usize(ed.txn_number_before.as_usize()),

View File

@ -149,6 +149,7 @@ fn add11_yml() -> anyhow::Result<()> {
trie_roots_after, trie_roots_after,
contract_code, contract_code,
block_metadata, block_metadata,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
txn_number_before: 0.into(), txn_number_before: 0.into(),
gas_used_before: 0.into(), gas_used_before: 0.into(),
gas_used_after: 0xa868u64.into(), gas_used_after: 0xa868u64.into(),

View File

@ -165,6 +165,7 @@ fn test_basic_smart_contract() -> anyhow::Result<()> {
tries: tries_before, tries: tries_before,
trie_roots_after, trie_roots_after,
contract_code, contract_code,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
block_metadata, block_metadata,
txn_number_before: 0.into(), txn_number_before: 0.into(),
gas_used_before: 0.into(), gas_used_before: 0.into(),

View File

@ -57,6 +57,7 @@ fn test_empty_txn_list() -> anyhow::Result<()> {
}, },
trie_roots_after, trie_roots_after,
contract_code, contract_code,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
block_metadata, block_metadata,
txn_number_before: 0.into(), txn_number_before: 0.into(),
gas_used_before: 0.into(), gas_used_before: 0.into(),

View File

@ -225,6 +225,7 @@ fn test_log_opcodes() -> anyhow::Result<()> {
tries: tries_before, tries: tries_before,
trie_roots_after, trie_roots_after,
contract_code, contract_code,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
block_metadata, block_metadata,
txn_number_before: 0.into(), txn_number_before: 0.into(),
gas_used_before: 0.into(), gas_used_before: 0.into(),
@ -423,6 +424,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> {
tries: tries_before, tries: tries_before,
trie_roots_after: tries_after, trie_roots_after: tries_after,
contract_code, contract_code,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
block_metadata: block_metadata.clone(), block_metadata: block_metadata.clone(),
txn_number_before: 0.into(), txn_number_before: 0.into(),
gas_used_before: 0.into(), gas_used_before: 0.into(),
@ -564,6 +566,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> {
tries: tries_before, tries: tries_before,
trie_roots_after, trie_roots_after,
contract_code, contract_code,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
block_metadata, block_metadata,
txn_number_before: 1.into(), txn_number_before: 1.into(),
gas_used_before: gas_used_second, gas_used_before: gas_used_second,
@ -589,6 +592,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> {
trie_roots_before: first_public_values.trie_roots_before, trie_roots_before: first_public_values.trie_roots_before,
trie_roots_after: public_values.trie_roots_after, trie_roots_after: public_values.trie_roots_after,
extra_block_data: ExtraBlockData { extra_block_data: ExtraBlockData {
genesis_state_root: first_public_values.extra_block_data.genesis_state_root,
txn_number_before: first_public_values.extra_block_data.txn_number_before, txn_number_before: first_public_values.extra_block_data.txn_number_before,
txn_number_after: public_values.extra_block_data.txn_number_after, txn_number_after: public_values.extra_block_data.txn_number_after,
gas_used_before: first_public_values.extra_block_data.gas_used_before, gas_used_before: first_public_values.extra_block_data.gas_used_before,
@ -864,6 +868,7 @@ fn test_two_txn() -> anyhow::Result<()> {
tries: tries_before, tries: tries_before,
trie_roots_after, trie_roots_after,
contract_code, contract_code,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
block_metadata, block_metadata,
txn_number_before: 0.into(), txn_number_before: 0.into(),
gas_used_before: 0.into(), gas_used_before: 0.into(),

View File

@ -154,6 +154,7 @@ fn self_balance_gas_cost() -> anyhow::Result<()> {
tries: tries_before, tries: tries_before,
trie_roots_after, trie_roots_after,
contract_code, contract_code,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
block_metadata, block_metadata,
txn_number_before: 0.into(), txn_number_before: 0.into(),
gas_used_before: 0.into(), gas_used_before: 0.into(),

View File

@ -135,6 +135,7 @@ fn test_simple_transfer() -> anyhow::Result<()> {
tries: tries_before, tries: tries_before,
trie_roots_after, trie_roots_after,
contract_code, contract_code,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
block_metadata, block_metadata,
txn_number_before: 0.into(), txn_number_before: 0.into(),
gas_used_before: 0.into(), gas_used_before: 0.into(),