kona_preimage/
key.rs

1//! Contains the [PreimageKey] type, which is used to identify preimages that may be fetched from
2//! the preimage oracle.
3
4use alloy_primitives::{B256, Keccak256, U256};
5#[cfg(feature = "rkyv")]
6use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
7#[cfg(feature = "serde")]
8use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize};
9
10use crate::errors::PreimageOracleError;
11
12/// <https://specs.optimism.io/experimental/fault-proof/index.html#pre-image-key-types>
13#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
14#[repr(u8)]
15#[cfg_attr(
16    feature = "rkyv",
17    derive(Archive, RkyvSerialize, RkyvDeserialize),
18    rkyv(derive(Eq, PartialEq, Ord, PartialOrd, Hash))
19)]
20#[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))]
21pub enum PreimageKeyType {
22    /// Local key types are local to a given instance of a fault-proof and context dependent.
23    /// Commonly these local keys are mapped to bootstrap data for the fault proof program.
24    Local = 1,
25    /// Keccak256 key types are global and context independent. Preimages are mapped from the
26    /// low-order 31 bytes of the preimage's `keccak256` digest to the preimage itself.
27    #[default]
28    Keccak256 = 2,
29    /// GlobalGeneric key types are reserved for future use.
30    GlobalGeneric = 3,
31    /// Sha256 key types are global and context independent. Preimages are mapped from the
32    /// low-order 31 bytes of the preimage's `sha256` digest to the preimage itself.
33    Sha256 = 4,
34    /// Blob key types are global and context independent. Blob keys are constructed as
35    /// `keccak256(commitment ++ z)`, and then the high-order byte of the digest is set to the
36    /// type byte.
37    Blob = 5,
38    /// Precompile key types are global and context independent. Precompile keys are constructed as
39    /// `keccak256(precompile_addr ++ input)`, and then the high-order byte of the digest is set to
40    /// the type byte.
41    Precompile = 6,
42}
43
44impl TryFrom<u8> for PreimageKeyType {
45    type Error = PreimageOracleError;
46
47    fn try_from(value: u8) -> Result<Self, Self::Error> {
48        let key_type = match value {
49            1 => Self::Local,
50            2 => Self::Keccak256,
51            3 => Self::GlobalGeneric,
52            4 => Self::Sha256,
53            5 => Self::Blob,
54            6 => Self::Precompile,
55            _ => return Err(PreimageOracleError::InvalidPreimageKey),
56        };
57        Ok(key_type)
58    }
59}
60
61/// A preimage key is a 32-byte value that identifies a preimage that may be fetched from the
62/// oracle.
63///
64/// **Layout**:
65/// |  Bits   | Description |
66/// |---------|-------------|
67/// | [0, 1)  | Type byte   |
68/// | [1, 32) | Data        |
69#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
70#[cfg_attr(
71    feature = "rkyv",
72    derive(Archive, RkyvSerialize, RkyvDeserialize),
73    rkyv(derive(Eq, PartialEq, Ord, PartialOrd, Hash))
74)]
75#[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))]
76pub struct PreimageKey {
77    data: [u8; 31],
78    key_type: PreimageKeyType,
79}
80
81impl PreimageKey {
82    /// Creates a new [PreimageKey] from a 32-byte value and a [PreimageKeyType]. The 32-byte value
83    /// will be truncated to 31 bytes by taking the low-order 31 bytes.
84    pub fn new(key: [u8; 32], key_type: PreimageKeyType) -> Self {
85        let mut data = [0u8; 31];
86        data.copy_from_slice(&key[1..]);
87        Self { data, key_type }
88    }
89
90    /// Creates a new local [PreimageKey] from a 64-bit local identifier. The local identifier will
91    /// be written into the low-order 8 bytes of the big-endian 31-byte data field.
92    pub fn new_local(local_ident: u64) -> Self {
93        let mut data = [0u8; 31];
94        data[23..].copy_from_slice(&local_ident.to_be_bytes());
95        Self { data, key_type: PreimageKeyType::Local }
96    }
97
98    /// Creates a new keccak256 [PreimageKey] from a 32-byte keccak256 digest. The digest will be
99    /// truncated to 31 bytes by taking the low-order 31 bytes.
100    pub fn new_keccak256(digest: [u8; 32]) -> Self {
101        Self::new(digest, PreimageKeyType::Keccak256)
102    }
103
104    /// Creates a new precompile [PreimageKey] from a precompile address and input. The key will be
105    /// constructed as `keccak256(precompile_addr ++ input)`, and then the high-order byte of the
106    /// digest will be set to the type byte.
107    pub fn new_precompile(precompile_addr: [u8; 20], input: &[u8]) -> Self {
108        let mut data = [0u8; 31];
109
110        let mut hasher = Keccak256::new();
111        hasher.update(precompile_addr);
112        hasher.update(input);
113
114        data.copy_from_slice(&hasher.finalize()[1..]);
115        Self { data, key_type: PreimageKeyType::Precompile }
116    }
117
118    /// Returns the [PreimageKeyType] for the [PreimageKey].
119    pub const fn key_type(&self) -> PreimageKeyType {
120        self.key_type
121    }
122
123    /// Returns the value of the [PreimageKey] as a [U256].
124    pub const fn key_value(&self) -> U256 {
125        U256::from_be_slice(self.data.as_slice())
126    }
127}
128
129impl From<PreimageKey> for [u8; 32] {
130    fn from(key: PreimageKey) -> Self {
131        let mut rendered_key = [0u8; 32];
132        rendered_key[0] = key.key_type as u8;
133        rendered_key[1..].copy_from_slice(&key.data);
134        rendered_key
135    }
136}
137
138impl From<PreimageKey> for B256 {
139    fn from(value: PreimageKey) -> Self {
140        let raw: [u8; 32] = value.into();
141        Self::from(raw)
142    }
143}
144
145impl TryFrom<[u8; 32]> for PreimageKey {
146    type Error = PreimageOracleError;
147
148    fn try_from(value: [u8; 32]) -> Result<Self, Self::Error> {
149        let key_type = PreimageKeyType::try_from(value[0])?;
150        Ok(Self::new(value, key_type))
151    }
152}
153
154impl core::fmt::Display for PreimageKey {
155    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
156        let raw: [u8; 32] = (*self).into();
157        write!(f, "{}", B256::from(raw))
158    }
159}
160
161#[cfg(test)]
162mod test {
163    use super::*;
164
165    #[test]
166    fn test_preimage_key_from_u8() {
167        assert_eq!(PreimageKeyType::try_from(1).unwrap(), PreimageKeyType::Local);
168        assert_eq!(PreimageKeyType::try_from(2).unwrap(), PreimageKeyType::Keccak256);
169        assert_eq!(PreimageKeyType::try_from(3).unwrap(), PreimageKeyType::GlobalGeneric);
170        assert_eq!(PreimageKeyType::try_from(4).unwrap(), PreimageKeyType::Sha256);
171        assert_eq!(PreimageKeyType::try_from(5).unwrap(), PreimageKeyType::Blob);
172        assert_eq!(PreimageKeyType::try_from(6).unwrap(), PreimageKeyType::Precompile);
173        assert!(PreimageKeyType::try_from(0).is_err());
174        assert!(PreimageKeyType::try_from(7).is_err());
175    }
176
177    #[test]
178    fn test_preimage_key_new_local() {
179        let key = PreimageKey::new_local(0xFFu64);
180        assert_eq!(key.key_type(), PreimageKeyType::Local);
181        assert_eq!(key.key_value(), U256::from(0xFFu64));
182    }
183
184    #[test]
185    fn test_preimage_key_value() {
186        let key = PreimageKey::new([0xFFu8; 32], PreimageKeyType::Local);
187        assert_eq!(
188            key.key_value(),
189            alloy_primitives::uint!(
190                452312848583266388373324160190187140051835877600158453279131187530910662655_U256
191            )
192        );
193    }
194
195    #[test]
196    fn test_preimage_key_roundtrip_b256() {
197        let key = PreimageKey::new([0xFFu8; 32], PreimageKeyType::Local);
198        let b256: B256 = key.into();
199        let key2 = PreimageKey::try_from(<[u8; 32]>::from(b256)).unwrap();
200        assert_eq!(key, key2);
201    }
202
203    #[test]
204    fn test_preimage_key_display() {
205        let key = PreimageKey::new([0xFFu8; 32], PreimageKeyType::Local);
206        assert_eq!(
207            key.to_string(),
208            "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
209        );
210    }
211
212    #[test]
213    fn test_preimage_keys() {
214        let types = [
215            PreimageKeyType::Local,
216            PreimageKeyType::Keccak256,
217            PreimageKeyType::GlobalGeneric,
218            PreimageKeyType::Sha256,
219            PreimageKeyType::Blob,
220            PreimageKeyType::Precompile,
221        ];
222
223        for key_type in types {
224            let key = PreimageKey::new([0xFFu8; 32], key_type);
225            assert_eq!(key.key_type(), key_type);
226
227            let mut rendered_key = [0xFFu8; 32];
228            rendered_key[0] = key_type as u8;
229            let actual: [u8; 32] = key.into();
230            assert_eq!(actual, rendered_key);
231        }
232    }
233}