Skip to main content

thruput_xdr/
impls.rs

1use crate::*;
2use core::ops::*;
3
4impl From<SHA256Hash> for StorageKey {
5    fn from(hash: SHA256Hash) -> Self {
6        Self::ContractData {
7            contract_data_key: hash.into_inner().into(),
8        }
9    }
10}
11
12impl From<SHA256Hash> for StorageKeyContractData {
13    fn from(hash: SHA256Hash) -> Self {
14        hash.into_inner().into()
15    }
16}
17
18impl From<ContractAddress> for StorageKeyContractData {
19    fn from(addr: ContractAddress) -> Self {
20        addr.into_inner().into()
21    }
22}
23
24impl From<SHA256Hash> for ContractAddress {
25    fn from(hash: SHA256Hash) -> Self {
26        hash.into_inner().into()
27    }
28}
29
30impl BitXor for SHA256Hash {
31    type Output = Self;
32
33    fn bitxor(mut self, rhs: Self) -> Self::Output {
34        self ^= &rhs.into_inner();
35
36        self
37    }
38}
39
40impl BitXor<&Self> for SHA256Hash {
41    type Output = Self;
42
43    fn bitxor(mut self, rhs: &Self) -> Self::Output {
44        let rhs: &[u8; 32] = rhs;
45
46        self ^= rhs;
47
48        self
49    }
50}
51
52impl BitXorAssign<&[u8; 32]> for SHA256Hash {
53    fn bitxor_assign(&mut self, rhs: &[u8; 32]) {
54        bitxor_assign_bytes(&mut *self, rhs);
55    }
56}
57
58impl BitXor for StorageKeyContractData {
59    type Output = Self;
60
61    fn bitxor(mut self, rhs: Self) -> Self::Output {
62        self ^= &rhs.into_inner();
63
64        self
65    }
66}
67
68impl BitXor<&Self> for StorageKeyContractData {
69    type Output = Self;
70
71    fn bitxor(mut self, rhs: &Self) -> Self::Output {
72        let rhs: &[u8; 32] = rhs;
73
74        self ^= rhs;
75
76        self
77    }
78}
79
80impl BitXorAssign<&[u8; 32]> for StorageKeyContractData {
81    fn bitxor_assign(&mut self, rhs: &[u8; 32]) {
82        bitxor_assign_bytes(&mut *self, rhs);
83    }
84}
85
86fn bitxor_assign_bytes<const N: usize>(lhs: &mut [u8; N], rhs: &[u8; N]) {
87    let (lchunks, []) = lhs.as_chunks_mut::<4>() else {
88        unreachable!()
89    };
90    let (rchunks, []) = rhs.as_chunks::<4>() else {
91        unreachable!()
92    };
93    lchunks
94        .iter_mut()
95        .zip(rchunks.iter())
96        .for_each(|(lbytes, rbytes)| {
97            let l = u32::from_le_bytes(*lbytes);
98            let r = u32::from_le_bytes(*rbytes);
99            *lbytes = (l ^ r).to_le_bytes();
100        });
101}
102
103// arrays with size above 32 don't implement Default, so we can't derive it
104impl Default for Ed25519Signature {
105    fn default() -> Self {
106        Self::from([0; 64])
107    }
108}
109
110impl Default for Signature {
111    fn default() -> Self {
112        Signature::Ed25519 {
113            ed25519: Ed25519Signature::default(),
114        }
115    }
116}
117
118impl Default for StorageKey {
119    fn default() -> Self {
120        Self::ContractData {
121            contract_data_key: StorageKeyContractData::default(),
122        }
123    }
124}
125
126impl ContractAddress {
127    /// Returns the all-zero address, useful as a placeholder where no
128    /// real contract address exists yet.
129    pub const fn zero() -> Self {
130        Self::new([0; 32])
131    }
132}
133
134// These types carry `#[rust(no_debug)]` in types.x. Wrappers inherit this
135// readable identifier form through their derived Debug implementations.
136macro_rules! base58_debug {
137    ($($t:ty),+ $(,)?) => {$(
138        impl core::fmt::Debug for $t {
139            fn fmt(
140                &self,
141                f: &mut core::fmt::Formatter<'_>,
142            ) -> core::fmt::Result {
143                write!(f, "{}", crate::base58::base58_encode(self))
144            }
145        }
146    )+};
147}
148
149base58_debug!(ContractAddress, SHA256Hash);
150
151// The secret key types also carry `#[rust(no_debug)]`: SecretKey and
152// ValidatorPrivateInfo derive Debug, and a derived impl here would print the
153// private key into any log that formats them.
154macro_rules! redacted_debug {
155    ($($t:ident),+ $(,)?) => {$(
156        impl core::fmt::Debug for $t {
157            fn fmt(
158                &self,
159                f: &mut core::fmt::Formatter<'_>,
160            ) -> core::fmt::Result {
161                f.write_str(concat!(stringify!($t), "(<redacted>)"))
162            }
163        }
164    )+};
165}
166
167redacted_debug!(Ed25519SecretKey, MlDsa65SecretKey);
168
169impl ContractEntrypointID {
170    /// Builds an entrypoint ID from its numeric form, storing `n` as
171    /// the ID's 8 big-endian bytes.
172    pub const fn from_u64(n: u64) -> Self {
173        Self::new(n.to_be_bytes())
174    }
175
176    /// Returns the numeric form of this ID, reading its 8 bytes as a
177    /// big-endian `u64`. Inverse of [`Self::from_u64`].
178    pub fn into_u64(self) -> u64 {
179        u64::from_be_bytes(self.into_inner())
180    }
181}
182
183impl From<uint128_xdr> for u128 {
184    fn from(u: uint128_xdr) -> Self {
185        ((u.highbits as u128) << 64) | (u.lowbits as u128)
186    }
187}
188
189impl From<u128> for uint128_xdr {
190    fn from(n: u128) -> Self {
191        uint128_xdr {
192            lowbits: (n & 0xffff_ffff_ffff_ffff) as u64,
193            highbits: (n >> 64) as u64,
194        }
195    }
196}
197
198impl From<int128_xdr> for i128 {
199    fn from(i: int128_xdr) -> Self {
200        ((i.highbits as i128) << 64) | (i.lowbits as i128)
201    }
202}
203
204impl From<i128> for int128_xdr {
205    fn from(n: i128) -> Self {
206        int128_xdr {
207            lowbits: (n & 0xffff_ffff_ffff_ffff) as u64,
208            highbits: (n >> 64) as i64,
209        }
210    }
211}
212
213impl Default for StorageLongHash {
214    fn default() -> Self {
215        Self::new([0; 2048])
216    }
217}
218
219#[cfg(test)]
220mod xor_test {
221    use super::*;
222    use std::vec::Vec;
223
224    #[test]
225    fn sk_bit_xor() {
226        let l: Vec<u8> = (0..32).collect();
227        let l: &[u8; 32] = l.as_slice().try_into().unwrap();
228        let l: StorageKeyContractData = (*l).into();
229
230        let rv: Vec<u8> = (107..139).rev().collect();
231        let rs: &[u8; 32] = rv.as_slice().try_into().unwrap();
232        let r: StorageKeyContractData = (*rs).into();
233
234        let expected = xor_arrays(&l, &r);
235
236        let x: StorageKeyContractData = l ^ r;
237        assert_eq!(*x, expected);
238
239        // Exercise the by-reference operator impl on purpose.
240        #[allow(clippy::op_ref)]
241        let x: StorageKeyContractData = l ^ &r;
242        assert_eq!(*x, expected);
243
244        let mut x: StorageKeyContractData = l;
245        x ^= rs;
246        assert_eq!(*x, expected);
247    }
248
249    fn xor_arrays(a: &[u8; 32], b: &[u8; 32]) -> [u8; 32] {
250        let out: Vec<_> =
251            a.iter().zip(b.iter()).map(|(a, b)| *a ^ *b).collect();
252        let out: &[u8; 32] = out.as_slice().try_into().unwrap();
253        *out
254    }
255}