neo3/neo_types/
bytes.rs

1use std::ops::BitXor;
2
3use bs58::encode as bs58_encode;
4use derive_more::{AsRef, Deref, Index, IndexMut, IntoIterator};
5use hex::encode as hex_encode;
6use num_bigint::BigInt;
7use num_traits::FromPrimitive;
8use serde::{Deserialize, Serialize};
9use sha2::{Digest, Sha256};
10
11/// `Bytes` is a wrapper around a vector of bytes (`Vec<u8>`) providing utility methods
12/// for encoding, decoding, and other common operations on byte arrays.
13#[derive(Debug, Serialize, Deserialize, AsRef, Deref, IntoIterator, Index, IndexMut)]
14struct Bytes(Vec<u8>);
15
16impl Bytes {
17	fn b_int(&self) -> Result<BigInt, &'static str> {
18		let bytes = self.0.as_slice().try_into().map_err(|_| "Failed to convert bytes to i128")?;
19
20		let i128_value = i128::from_be_bytes(bytes);
21		BigInt::from_i128(i128_value).ok_or("Failed to convert i128 to BigInt")
22	}
23
24	fn base64_encoded(&self) -> String {
25		base64::encode(&self.0)
26	}
27
28	fn base58_encoded(&self) -> String {
29		bs58_encode(self.0.as_slice()).into_string()
30	}
31
32	fn base58_check_encoded(&self) -> String {
33		let checksum = &Sha256::digest(&Sha256::digest(&self.0))[..4];
34		let mut bytes = self.0.clone();
35		bytes.extend_from_slice(checksum);
36		bs58_encode(&bytes).into_string()
37	}
38
39	fn no_prefix_hex(&self) -> String {
40		hex_encode(self.0.as_slice()).trim_start_matches("0x").to_string()
41	}
42
43	fn var_size(&self) -> usize {
44		std::mem::size_of::<usize>() + self.0.len()
45	}
46
47	fn scripthash_to_address(&self) -> String {
48		let mut script = vec![0x17];
49		script.extend_from_slice(&self.0.iter().rev().copied().collect::<Vec<_>>());
50
51		let mut hasher = Sha256::new();
52		hasher.update(&script);
53		let checksum = &hasher.finalize()[..4];
54
55		let mut address = script;
56		address.extend_from_slice(checksum);
57
58		bs58_encode(&address).into_string()
59	}
60
61	fn to_padded(&self, length: usize, trailing: bool) -> Result<Bytes, &'static str> {
62		let bytes_len = self.0.len();
63		if bytes_len > length {
64			return Err("Input is too large");
65		}
66
67		let mut padded = vec![0u8; length];
68		let offset = if self.0.first() == Some(&0) { 1 } else { 0 };
69
70		if trailing {
71			padded[..bytes_len - offset].copy_from_slice(&self.0[offset..]);
72		} else {
73			padded[length - bytes_len + offset..].copy_from_slice(&self.0[offset..]);
74		}
75
76		Ok(Bytes(padded))
77	}
78
79	fn trim_trailing_bytes(&mut self, byte: u8) {
80		while self.0.last() == Some(&byte) {
81			self.0.pop();
82		}
83	}
84}
85
86impl BitXor for Bytes {
87	type Output = Result<Self, &'static str>;
88
89	fn bitxor(self, rhs: Self) -> Self::Output {
90		if self.0.len() != rhs.0.len() {
91			return Err("Arrays do not have the same length");
92		}
93
94		let bytes = self.0.iter().zip(rhs.0.iter()).map(|(x, y)| x ^ y).collect();
95
96		Ok(Bytes(bytes))
97	}
98}
99
100pub trait ReverseTrait {
101	fn reverse(&self) -> Self;
102}
103
104impl ReverseTrait for Vec<u8> {
105	fn reverse(&self) -> Self {
106		self.iter().rev().copied().collect()
107	}
108}