eth_valkyoth_primitives/
lib.rs1#![no_std]
2#![forbid(unsafe_code)]
3use subtle::ConstantTimeEq as _;
6
7macro_rules! id_type {
8 ($name:ident, $inner:ty, $doc:literal) => {
9 #[doc = $doc]
10 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
11 pub struct $name($inner);
12
13 impl $name {
14 #[must_use]
16 pub const fn new(value: $inner) -> Self {
17 Self(value)
18 }
19
20 #[must_use]
22 pub const fn get(self) -> $inner {
23 self.0
24 }
25 }
26 };
27}
28
29id_type!(ChainId, u64, "Ethereum chain identifier.");
30id_type!(BlockNumber, u64, "Ethereum execution-layer block number.");
31id_type!(Gas, u64, "Gas quantity.");
32id_type!(Nonce, u64, "Account transaction nonce.");
33id_type!(UnixTimestamp, u64, "Block timestamp as Unix seconds.");
34
35#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
37pub struct Address([u8; 20]);
38
39impl Address {
40 #[must_use]
42 pub const fn from_bytes(bytes: [u8; 20]) -> Self {
43 Self(bytes)
44 }
45
46 #[must_use]
48 pub const fn to_bytes(self) -> [u8; 20] {
49 self.0
50 }
51}
52
53#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
58pub struct B256([u8; 32]);
59
60impl B256 {
61 #[must_use]
63 pub const fn from_bytes(bytes: [u8; 32]) -> Self {
64 Self(bytes)
65 }
66
67 #[must_use]
69 pub const fn to_bytes(self) -> [u8; 32] {
70 self.0
71 }
72
73 #[must_use]
78 pub fn ct_eq(&self, other: &Self) -> bool {
79 self.0.ct_eq(&other.0).into()
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn chain_id_round_trips() {
89 assert_eq!(ChainId::new(1).get(), 1);
90 }
91
92 #[test]
93 fn address_round_trips() {
94 let bytes = [7_u8; 20];
95 assert_eq!(Address::from_bytes(bytes).to_bytes(), bytes);
96 }
97
98 #[test]
99 fn b256_constant_time_equality_result_matches_equality() {
100 let left = B256::from_bytes([1_u8; 32]);
101 let same = B256::from_bytes([1_u8; 32]);
102 let different = B256::from_bytes([2_u8; 32]);
103 assert!(left.ct_eq(&same));
104 assert!(!left.ct_eq(&different));
105 }
106}