Skip to main content

agglayer_primitives/
vkey_hash.rs

1use alloy_primitives::B256;
2use serde::{Deserialize, Serialize};
3
4use crate::Digest;
5
6/// Type alias for a 256-bit hash. When using this alias, ensure that the
7/// array is in fact hashed.
8pub type HashU32 = [u32; 8];
9
10/// Verifying key hash.
11#[derive(Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
12#[serde(from = "B256", into = "B256")]
13pub struct VKeyHash(HashU32);
14
15impl VKeyHash {
16    /// Create a [`VKeyHash`] from a [`HashU32`].
17    pub const fn from_hash_u32(hash: HashU32) -> Self {
18        Self(hash)
19    }
20
21    /// Create a [`VKeyHash`] from a [`B256`]. Assumes the bytes are in
22    /// big-endian order.
23    pub const fn from_bytes(bytes: B256) -> Self {
24        let bytes = bytes.0;
25        let mut hash_u32: HashU32 = [0u32; 8];
26
27        let mut w = 0_usize;
28        while w < 8 {
29            let b0 = bytes[4 * w];
30            let b1 = bytes[4 * w + 1];
31            let b2 = bytes[4 * w + 2];
32            let b3 = bytes[4 * w + 3];
33            hash_u32[w] = u32::from_be_bytes([b0, b1, b2, b3]);
34            w += 1;
35        }
36
37        Self(hash_u32)
38    }
39
40    /// Convert a [`VKeyHash`] to a [`B256`]. The resulting bytes are in
41    /// big-endian order.
42    pub const fn to_bytes(&self) -> B256 {
43        let mut bytes = [0_u8; 32];
44
45        let mut w = 0_usize;
46        while w < 8 {
47            let [b0, b1, b2, b3] = self.0[w].to_be_bytes();
48            bytes[4 * w] = b0;
49            bytes[4 * w + 1] = b1;
50            bytes[4 * w + 2] = b2;
51            bytes[4 * w + 3] = b3;
52            w += 1;
53        }
54
55        B256::new(bytes)
56    }
57
58    /// Convert a [`VKeyHash`] to a [`HashU32`].
59    pub const fn to_hash_u32(&self) -> HashU32 {
60        self.0
61    }
62}
63
64impl From<Digest> for VKeyHash {
65    fn from(digest: Digest) -> Self {
66        Self::from_bytes(B256::from(digest))
67    }
68}
69
70impl From<VKeyHash> for Digest {
71    fn from(hash: VKeyHash) -> Self {
72        Self::from(hash.to_bytes())
73    }
74}
75
76impl From<B256> for VKeyHash {
77    fn from(bytes: B256) -> Self {
78        Self::from_bytes(bytes)
79    }
80}
81
82impl From<VKeyHash> for B256 {
83    fn from(hash: VKeyHash) -> Self {
84        hash.to_bytes()
85    }
86}
87
88impl std::str::FromStr for VKeyHash {
89    type Err = <B256 as std::str::FromStr>::Err;
90
91    fn from_str(s: &str) -> Result<Self, Self::Err> {
92        s.parse().map(Self::from_bytes)
93    }
94}
95
96impl std::fmt::Debug for VKeyHash {
97    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98        self.to_bytes().fmt(f)
99    }
100}
101
102#[cfg(test)]
103mod test {
104    use alloy_primitives::b256;
105
106    use super::*;
107
108    #[test]
109    fn constructors_consistently_be() {
110        let from_hash_u32 = VKeyHash::from_hash_u32([
111            0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f, 0x10111213, 0x14151617, 0x18191a1b,
112            0x1c1d1e1f,
113        ]);
114
115        let from_hex = VKeyHash::from_bytes(b256!(
116            "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
117        ));
118
119        assert_eq!(from_hash_u32, from_hex);
120
121        let roundtrip = VKeyHash::from_bytes(from_hash_u32.to_bytes());
122        assert_eq!(from_hash_u32, roundtrip);
123    }
124}