revm_precompile/
utilities.rs

1use primitives::{b256, Bytes, B256};
2use std::borrow::Cow;
3
4/// Right-pads the given slice at `offset` with zeroes until `LEN`.
5///
6/// Returns the first `LEN` bytes if it does not need padding.
7#[inline]
8pub fn right_pad_with_offset<const LEN: usize>(data: &[u8], offset: usize) -> Cow<'_, [u8; LEN]> {
9    right_pad(data.get(offset..).unwrap_or_default())
10}
11
12/// Right-pads the given slice at `offset` with zeroes until `len`.
13///
14/// Returns the first `len` bytes if it does not need padding.
15#[inline]
16pub fn right_pad_with_offset_vec(data: &[u8], offset: usize, len: usize) -> Cow<'_, [u8]> {
17    right_pad_vec(data.get(offset..).unwrap_or_default(), len)
18}
19
20/// Right-pads the given slice with zeroes until `LEN`.
21///
22/// Returns the first `LEN` bytes if it does not need padding.
23#[inline]
24pub fn right_pad<const LEN: usize>(data: &[u8]) -> Cow<'_, [u8; LEN]> {
25    if let Some(data) = data.get(..LEN) {
26        Cow::Borrowed(data.try_into().unwrap())
27    } else {
28        let mut padded = [0; LEN];
29        padded[..data.len()].copy_from_slice(data);
30        Cow::Owned(padded)
31    }
32}
33
34/// Right-pads the given slice with zeroes until `len`.
35///
36/// Returns the first `len` bytes if it does not need padding.
37#[inline]
38pub fn right_pad_vec(data: &[u8], len: usize) -> Cow<'_, [u8]> {
39    if let Some(data) = data.get(..len) {
40        Cow::Borrowed(data)
41    } else {
42        let mut padded = vec![0; len];
43        padded[..data.len()].copy_from_slice(data);
44        Cow::Owned(padded)
45    }
46}
47
48/// Left-pads the given slice with zeroes until `LEN`.
49///
50/// Returns the first `LEN` bytes if it does not need padding.
51#[inline]
52pub fn left_pad<const LEN: usize>(data: &[u8]) -> Cow<'_, [u8; LEN]> {
53    if let Some(data) = data.get(..LEN) {
54        Cow::Borrowed(data.try_into().unwrap())
55    } else {
56        let mut padded = [0; LEN];
57        padded[LEN - data.len()..].copy_from_slice(data);
58        Cow::Owned(padded)
59    }
60}
61
62/// Left-pads the given slice with zeroes until `len`.
63///
64/// Returns the first `len` bytes if it does not need padding.
65#[inline]
66pub fn left_pad_vec(data: &[u8], len: usize) -> Cow<'_, [u8]> {
67    if let Some(data) = data.get(..len) {
68        Cow::Borrowed(data)
69    } else {
70        let mut padded = vec![0; len];
71        padded[len - data.len()..].copy_from_slice(data);
72        Cow::Owned(padded)
73    }
74}
75
76/// Converts a boolean to a left-padded 32-byte [`Bytes`] value.
77///
78/// This is optimized to not allocate at runtime by using 2 static arrays.
79#[inline]
80pub const fn bool_to_bytes32(value: bool) -> Bytes {
81    Bytes::from_static(&bool_to_b256(value).0)
82}
83
84/// Converts a boolean to a left-padded [`B256`] value.
85///
86/// This is optimized to not allocate at runtime by using 2 static arrays.
87#[inline]
88pub const fn bool_to_b256(value: bool) -> &'static B256 {
89    const TRUE: &B256 =
90        &b256!("0x0000000000000000000000000000000000000000000000000000000000000001");
91    const FALSE: &B256 =
92        &b256!("0x0000000000000000000000000000000000000000000000000000000000000000");
93    if value {
94        TRUE
95    } else {
96        FALSE
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103
104    #[test]
105    fn get_with_right_padding() {
106        let data = [1, 2, 3, 4];
107        let padded = right_pad_with_offset::<8>(&data, 4);
108        assert!(matches!(padded, Cow::Owned(_)));
109        assert_eq!(padded[..], [0, 0, 0, 0, 0, 0, 0, 0]);
110        let padded = right_pad_with_offset_vec(&data, 4, 8);
111        assert!(matches!(padded, Cow::Owned(_)));
112        assert_eq!(padded[..], [0, 0, 0, 0, 0, 0, 0, 0]);
113
114        let data = [1, 2, 3, 4, 5, 6, 7, 8];
115        let padded = right_pad_with_offset::<8>(&data, 0);
116        assert!(matches!(padded, Cow::Borrowed(_)));
117        assert_eq!(padded[..], [1, 2, 3, 4, 5, 6, 7, 8]);
118        let padded = right_pad_with_offset_vec(&data, 0, 8);
119        assert!(matches!(padded, Cow::Borrowed(_)));
120        assert_eq!(padded[..], [1, 2, 3, 4, 5, 6, 7, 8]);
121
122        let data = [1, 2, 3, 4, 5, 6, 7, 8];
123        let padded = right_pad_with_offset::<8>(&data, 4);
124        assert!(matches!(padded, Cow::Owned(_)));
125        assert_eq!(padded[..], [5, 6, 7, 8, 0, 0, 0, 0]);
126        let padded = right_pad_with_offset_vec(&data, 4, 8);
127        assert!(matches!(padded, Cow::Owned(_)));
128        assert_eq!(padded[..], [5, 6, 7, 8, 0, 0, 0, 0]);
129    }
130
131    #[test]
132    fn right_padding() {
133        let data = [1, 2, 3, 4];
134        let padded = right_pad::<8>(&data);
135        assert!(matches!(padded, Cow::Owned(_)));
136        assert_eq!(padded[..], [1, 2, 3, 4, 0, 0, 0, 0]);
137        let padded = right_pad_vec(&data, 8);
138        assert!(matches!(padded, Cow::Owned(_)));
139        assert_eq!(padded[..], [1, 2, 3, 4, 0, 0, 0, 0]);
140
141        let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
142        let padded = right_pad::<8>(&data);
143        assert!(matches!(padded, Cow::Borrowed(_)));
144        assert_eq!(padded[..], [1, 2, 3, 4, 5, 6, 7, 8]);
145        let padded = right_pad_vec(&data, 8);
146        assert!(matches!(padded, Cow::Borrowed(_)));
147        assert_eq!(padded[..], [1, 2, 3, 4, 5, 6, 7, 8]);
148    }
149
150    #[test]
151    fn left_padding() {
152        let data = [1, 2, 3, 4];
153        let padded = left_pad::<8>(&data);
154        assert!(matches!(padded, Cow::Owned(_)));
155        assert_eq!(padded[..], [0, 0, 0, 0, 1, 2, 3, 4]);
156        let padded = left_pad_vec(&data, 8);
157        assert!(matches!(padded, Cow::Owned(_)));
158        assert_eq!(padded[..], [0, 0, 0, 0, 1, 2, 3, 4]);
159
160        let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
161        let padded = left_pad::<8>(&data);
162        assert!(matches!(padded, Cow::Borrowed(_)));
163        assert_eq!(padded[..], [1, 2, 3, 4, 5, 6, 7, 8]);
164        let padded = left_pad_vec(&data, 8);
165        assert!(matches!(padded, Cow::Borrowed(_)));
166        assert_eq!(padded[..], [1, 2, 3, 4, 5, 6, 7, 8]);
167    }
168
169    #[test]
170    fn bool2bytes() {
171        let f = bool_to_bytes32(false);
172        assert_eq!(f[..], [0; 32]);
173        let t = bool_to_bytes32(true);
174        assert_eq!(t.len(), 32);
175        assert_eq!(t[..31], [0; 31]);
176        assert_eq!(t[31], 1);
177    }
178}