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,
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.
builder.connect(pvs.txn_number_before, lhs.txn_number_before);
builder.connect(pvs.txn_number_after, rhs.txn_number_after);
@ -776,6 +781,16 @@ where
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.
let one = builder.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.
Self::connect_final_block_values_to_intermediary(builder, rhs);
// Chack that the genesis block number is 0.
let zero = builder.zero();
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);
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(
@ -981,16 +1006,34 @@ where
block_inputs
.set_proof_with_pis_target(&self.block.parent_block_proof, parent_block_proof);
} else {
// Initialize state_root_after and the block number for correct connection between blocks.
let state_trie_root_keys = 24..32;
let block_number_key = TrieRootsTarget::SIZE * 2 + 6;
// Initialize genesis_state_trie, state_root_after and the block number for correct connection between blocks.
// Initialize `state_root_after`.
let state_trie_root_after_keys = 24..32;
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))
{
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);
block_inputs.set_proof_with_pis_target(
&self.block.parent_block_proof,
&cyclic_base_proof(

View File

@ -48,6 +48,8 @@ pub struct GenerationInputs {
pub tries: TrieInputs,
/// Expected trie roots after the transactions are executed.
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.
/// 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 extra_block_data = ExtraBlockData {
genesis_state_root: inputs.genesis_state_trie_root,
txn_number_before: inputs.txn_number_before,
txn_number_after,
gas_used_before: inputs.gas_used_before,

View File

@ -116,6 +116,7 @@ fn observe_extra_block_data<
challenger: &mut Challenger<F, C::Hasher>,
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_after.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
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_after);
challenger.observe_element(extra_data.gas_used_before);

View File

@ -95,6 +95,7 @@ pub struct BlockMetadata {
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct ExtraBlockData {
pub genesis_state_root: H256,
pub txn_number_before: U256,
pub txn_number_after: U256,
pub gas_used_before: U256,
@ -166,6 +167,7 @@ impl PublicValuesTarget {
buffer.write_target_array(&cur_hash)?;
let ExtraBlockDataTarget {
genesis_state_root,
txn_number_before,
txn_number_after,
gas_used_before,
@ -173,6 +175,7 @@ impl PublicValuesTarget {
block_bloom_before,
block_bloom_after,
} = self.extra_block_data;
buffer.write_target_array(&genesis_state_root)?;
buffer.write_target(txn_number_before)?;
buffer.write_target(txn_number_after)?;
buffer.write_target(gas_used_before)?;
@ -214,6 +217,7 @@ impl PublicValuesTarget {
};
let extra_block_data = ExtraBlockDataTarget {
genesis_state_root: buffer.read_target_array()?,
txn_number_before: buffer.read_target()?,
txn_number_after: buffer.read_target()?,
gas_used_before: buffer.read_target()?,
@ -381,7 +385,7 @@ pub struct BlockMetadataTarget {
}
impl BlockMetadataTarget {
const SIZE: usize = 77;
pub const SIZE: usize = 77;
pub fn from_public_inputs(pis: &[Target]) -> Self {
let block_beneficiary = pis[0..5].try_into().unwrap();
@ -465,7 +469,7 @@ pub struct BlockHashesTarget {
}
impl BlockHashesTarget {
const BLOCK_HASHES_SIZE: usize = 2056;
pub const BLOCK_HASHES_SIZE: usize = 2056;
pub fn from_public_inputs(pis: &[Target]) -> Self {
Self {
prev_hashes: pis[0..2048].try_into().unwrap(),
@ -505,6 +509,7 @@ impl BlockHashesTarget {
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub struct ExtraBlockDataTarget {
pub genesis_state_root: [Target; 8],
pub txn_number_before: Target,
pub txn_number_after: Target,
pub gas_used_before: Target,
@ -514,17 +519,19 @@ pub struct ExtraBlockDataTarget {
}
impl ExtraBlockDataTarget {
const SIZE: usize = 132;
const SIZE: usize = 140;
pub fn from_public_inputs(pis: &[Target]) -> Self {
let txn_number_before = pis[0];
let txn_number_after = pis[1];
let gas_used_before = pis[2];
let gas_used_after = pis[3];
let block_bloom_before = pis[4..68].try_into().unwrap();
let block_bloom_after = pis[68..132].try_into().unwrap();
let genesis_state_root = pis[0..8].try_into().unwrap();
let txn_number_before = pis[8];
let txn_number_after = pis[9];
let gas_used_before = pis[10];
let gas_used_after = pis[11];
let block_bloom_before = pis[12..76].try_into().unwrap();
let block_bloom_after = pis[76..140].try_into().unwrap();
Self {
genesis_state_root,
txn_number_before,
txn_number_after,
gas_used_before,
@ -541,6 +548,13 @@ impl ExtraBlockDataTarget {
ed1: 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(
condition,
ed0.txn_number_before,
@ -571,6 +585,9 @@ impl ExtraBlockDataTarget {
ed0: 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_after, ed1.txn_number_after);
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>(
builder: &mut CircuitBuilder<F, D>,
) -> ExtraBlockDataTarget {
let genesis_state_root = builder.add_virtual_public_input_arr();
let txn_number_before = builder.add_virtual_public_input();
let txn_number_after = 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_after: [Target; 64] = builder.add_virtual_public_input_arr();
ExtraBlockDataTarget {
genesis_state_root,
txn_number_before,
txn_number_after,
gas_used_before,
@ -1070,6 +1072,10 @@ pub(crate) fn set_extra_public_values_target<F, W, const D: usize>(
F: RichField + Extendable<D>,
W: Witness<F>,
{
witness.set_target_arr(
&ed_target.genesis_state_root,
&h256_limbs::<F>(ed.genesis_state_root),
);
witness.set_target(
ed_target.txn_number_before,
F::from_canonical_usize(ed.txn_number_before.as_usize()),

View File

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

View File

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

View File

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

View File

@ -225,6 +225,7 @@ fn test_log_opcodes() -> anyhow::Result<()> {
tries: tries_before,
trie_roots_after,
contract_code,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
block_metadata,
txn_number_before: 0.into(),
gas_used_before: 0.into(),
@ -423,6 +424,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> {
tries: tries_before,
trie_roots_after: tries_after,
contract_code,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
block_metadata: block_metadata.clone(),
txn_number_before: 0.into(),
gas_used_before: 0.into(),
@ -564,6 +566,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> {
tries: tries_before,
trie_roots_after,
contract_code,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
block_metadata,
txn_number_before: 1.into(),
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_after: public_values.trie_roots_after,
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_after: public_values.extra_block_data.txn_number_after,
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,
trie_roots_after,
contract_code,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
block_metadata,
txn_number_before: 0.into(),
gas_used_before: 0.into(),

View File

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

View File

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