risc0_steel/beacon/
mod.rs

1// Copyright 2025 RISC Zero, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Types related to commitments to the beacon block root.
16use crate::{merkle, BlockHeaderCommit, Commitment, CommitmentVersion, ComposeInput};
17use alloy_primitives::{Sealed, B256};
18use serde::{Deserialize, Serialize};
19use std::fmt;
20
21#[cfg(feature = "host")]
22pub(crate) mod host;
23
24/// The generalized Merkle tree index of the `state_root` field in the `BeaconBlock`.
25pub const STATE_ROOT_LEAF_INDEX: usize = 6434;
26
27/// The generalized Merkle tree index of the `block_hash` field in the `BeaconBlock`.
28pub const BLOCK_HASH_LEAF_INDEX: usize = 6444;
29
30/// Input committing to the corresponding Beacon Chain block root.
31pub type BeaconInput<F> = ComposeInput<F, BeaconCommit>;
32
33/// A commitment that an execution block hash is included in a specific beacon block on the Ethereum
34/// blockchain.
35///
36/// This type represents a commitment that proves the inclusion of an execution block's hash within
37/// a particular beacon block on the Ethereum beacon chain. It relies on a Merkle proof to establish
38/// this link, ensuring the integrity and verifiability of the connection between the execution
39/// block and the beacon chain.
40///
41/// **Important:** This type currently relies on an underlying implementation that only supports the
42/// Deneb fork of the beacon chain. If the beacon chain undergoes a future upgrade, this type's
43/// functionality may be affected, potentially requiring updates to handle new block structures or
44/// proof generation mechanisms.
45///
46/// Users should monitor for beacon chain upgrades and ensure they are using a compatible version of
47/// this library.
48pub type BeaconCommit = GeneralizedBeaconCommit<BLOCK_HASH_LEAF_INDEX>;
49
50/// A beacon block identifier.
51#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
52pub enum BeaconBlockId {
53    /// Timestamp of the child execution block, to query the beacon block root using the EIP-4788
54    /// beacon roots contract.
55    Eip4788(u64),
56    /// Slot of the beacon block.
57    Slot(u64),
58}
59
60impl fmt::Display for BeaconBlockId {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        match self {
63            BeaconBlockId::Eip4788(timestamp) => {
64                write!(f, "eip4788-timestamp: {timestamp}")
65            }
66            BeaconBlockId::Slot(slot) => write!(f, "slot: {slot}"),
67        }
68    }
69}
70
71impl BeaconBlockId {
72    pub const fn as_version(&self) -> u16 {
73        match self {
74            BeaconBlockId::Eip4788(_) => CommitmentVersion::Beacon as u16,
75            BeaconBlockId::Slot(_) => CommitmentVersion::Consensus as u16,
76        }
77    }
78    pub const fn as_id(&self) -> u64 {
79        match self {
80            BeaconBlockId::Eip4788(ts) => *ts,
81            BeaconBlockId::Slot(slot) => *slot,
82        }
83    }
84}
85
86/// A commitment to a field of the beacon block at a specific index in a Merkle tree, along with a
87/// timestamp.
88///
89/// The constant generic parameter `LEAF_INDEX` specifies the generalized Merkle tree index of the
90/// leaf node in the Merkle tree corresponding to the field.
91#[derive(Clone, Serialize, Deserialize)]
92pub struct GeneralizedBeaconCommit<const LEAF_INDEX: usize> {
93    proof: Vec<B256>,
94    block_id: BeaconBlockId,
95}
96
97impl<const LEAF_INDEX: usize> GeneralizedBeaconCommit<LEAF_INDEX> {
98    /// Creates a new `GeneralizedBeaconCommit`.
99    ///
100    /// It panics if `LEAF_INDEX` is zero, because a Merkle tree cannot have a leaf at index 0.
101    #[must_use]
102    #[inline]
103    pub const fn new(proof: Vec<B256>, block_id: BeaconBlockId) -> Self {
104        assert!(LEAF_INDEX > 0);
105        Self { proof, block_id }
106    }
107
108    /// Disassembles this `GeneralizedBeaconCommit`, returning the underlying Merkle proof and
109    /// beacon block identifier.
110    #[inline]
111    pub fn into_parts(self) -> (Vec<B256>, BeaconBlockId) {
112        (self.proof, self.block_id)
113    }
114
115    /// Calculates the root of the Merkle tree containing the given `leaf` hash at `LEAF_INDEX`,
116    /// using the provided Merkle proof.
117    #[inline]
118    pub fn process_proof(&self, leaf: B256) -> Result<B256, merkle::InvalidProofError> {
119        merkle::process_proof(leaf, &self.proof, LEAF_INDEX)
120    }
121
122    /// Verifies that the given `leaf` hash is present at the `LEAF_INDEX` in the Merkle tree
123    /// represented by the `root` hash.
124    #[inline]
125    pub fn verify(&self, leaf: B256, root: B256) -> Result<(), merkle::InvalidProofError> {
126        merkle::verify(leaf, &self.proof, LEAF_INDEX, root)
127    }
128
129    /// Returns the beacon block identifier (slot or timestamp).
130    pub(crate) fn block_id(&self) -> BeaconBlockId {
131        self.block_id
132    }
133
134    pub(crate) fn into_commit(self, leaf: B256) -> (BeaconBlockId, B256) {
135        let beacon_root = self
136            .process_proof(leaf)
137            .expect("Invalid beacon inclusion proof");
138        (self.block_id(), beacon_root)
139    }
140}
141
142impl<H, const LEAF_INDEX: usize> BlockHeaderCommit<H> for GeneralizedBeaconCommit<LEAF_INDEX> {
143    #[inline]
144    fn commit(self, header: &Sealed<H>, config_id: B256) -> Commitment {
145        let (block_id, beacon_root) = self.into_commit(header.seal());
146        Commitment::new(
147            block_id.as_version(),
148            block_id.as_id(),
149            beacon_root,
150            config_id,
151        )
152    }
153}