1#[doc(hidden)]
4pub mod proto;
5pub mod types;
6pub mod units;
7
8use bech32::{FromBase32, ToBase32, Variant};
9use primitive_types::H160;
10pub use types::*;
11pub use units::*;
12
13use std::{
14 fmt::Display,
15 ops::{BitAnd, Deref},
16 str::FromStr,
17};
18
19use serde::de::Error as SerdeError;
20use serde::{Deserialize, Deserializer, Serialize};
21use sha2::Digest;
22
23use crate::Error;
24
25fn is_byte_string(str: &str, len: usize) -> bool {
27 let regex = regex::Regex::new(&format!("^[0-9a-fA-F]{{{}}}$", len)).expect("Failed to create the regex for `is_byte_string`");
28 let str = str.replace("0x", "");
29 regex.is_match(&str)
30}
31
32#[derive(Debug, Clone, Deserialize)]
34pub struct TxHash(String);
35
36impl TxHash {
37 pub fn is_valid(tx_hash: &str) -> bool {
45 is_byte_string(tx_hash, 64)
46 }
47}
48
49impl FromStr for TxHash {
50 type Err = Error;
51 fn from_str(tx_hash: &str) -> Result<Self, Self::Err> {
59 if TxHash::is_valid(tx_hash) {
60 Ok(Self(tx_hash.to_string()))
61 } else {
62 Err(Error::InvalidTransactionHash(tx_hash.to_string()))
63 }
64 }
65}
66
67impl Display for TxHash {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 write!(f, "{}", self.0)
70 }
71}
72
73#[derive(Serialize, Debug, Clone, Deserialize, PartialEq)]
75pub struct BNum(String);
76impl BNum {
77 pub fn new(bnum: &str) -> Self {
78 Self(bnum.to_string())
79 }
80}
81
82impl Deref for BNum {
83 type Target = String;
84
85 fn deref(&self) -> &Self::Target {
86 &self.0
87 }
88}
89
90impl FromStr for BNum {
91 type Err = Error;
92
93 fn from_str(s: &str) -> Result<Self, Self::Err> {
95 Ok(Self::new(s))
96 }
97}
98
99#[derive(Debug, Clone)]
100pub struct PrivateKey(k256::SecretKey);
102
103impl PrivateKey {
104 pub fn create_random() -> Self {
112 Self(k256::SecretKey::random(&mut rand::thread_rng()))
113 }
114
115 pub fn from_slice(slice: &[u8]) -> Result<Self, Error> {
117 Ok(Self(k256::SecretKey::from_slice(slice)?))
118 }
119
120 pub fn public_key(&self) -> PublicKey {
122 PublicKey::new(self.0.public_key())
123 }
124}
125
126impl FromStr for PrivateKey {
127 type Err = Error;
128
129 fn from_str(secret_key: &str) -> Result<Self, Self::Err> {
143 let secret_key = match secret_key.strip_prefix("0x") {
144 Some(secret_key) => secret_key,
145 None => secret_key,
146 };
147 Ok(Self(k256::SecretKey::from_slice(&hex::decode(secret_key)?)?))
148 }
149}
150
151impl Deref for PrivateKey {
152 type Target = k256::SecretKey;
153
154 fn deref(&self) -> &Self::Target {
155 &self.0
156 }
157}
158
159impl Display for PrivateKey {
160 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161 write!(f, "{}", hex::encode(self.to_bytes()).to_lowercase())
162 }
163}
164
165impl PartialEq for PrivateKey {
166 fn eq(&self, other: &Self) -> bool {
168 self.to_string() == other.to_string()
169 }
170}
171
172#[derive(Debug, Clone)]
174pub struct PublicKey(k256::PublicKey);
175
176impl PublicKey {
177 pub fn new(pk: k256::PublicKey) -> Self {
179 Self(pk)
180 }
181}
182
183impl FromStr for PublicKey {
184 type Err = Error;
185
186 fn from_str(public_key: &str) -> Result<Self, Self::Err> {
200 let public_key = match public_key.strip_prefix("0x") {
201 Some(public_key) => public_key,
202 None => public_key,
203 };
204
205 Ok(Self(k256::PublicKey::from_sec1_bytes(&hex::decode(public_key)?)?))
206 }
207}
208
209impl PartialEq for PublicKey {
210 fn eq(&self, other: &Self) -> bool {
212 self.to_string() == other.to_string()
213 }
214}
215
216impl Deref for PublicKey {
217 type Target = k256::PublicKey;
218
219 fn deref(&self) -> &Self::Target {
220 &self.0
221 }
222}
223
224impl Display for PublicKey {
225 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
226 write!(f, "{}", hex::encode(self.to_sec1_bytes()).to_lowercase())
227 }
228}
229
230#[derive(Eq, Hash, Debug, PartialEq, Clone, serde::Serialize, Default)]
232pub struct ZilAddress(String);
233
234impl Deref for ZilAddress {
235 type Target = String;
236
237 fn deref(&self) -> &Self::Target {
238 &self.0
239 }
240}
241
242impl TryFrom<&PublicKey> for ZilAddress {
243 type Error = Error;
244
245 fn try_from(value: &PublicKey) -> Result<Self, Self::Error> {
247 let mut hasher = sha2::Sha256::new();
248 hasher.update(value.to_sec1_bytes());
249 Ok(Self(ZilAddress::to_checksum_address(&hex::encode(hasher.finalize())[24..])?))
250 }
251}
252
253impl ZilAddress {
254 fn from_bech32(address: &str) -> Result<Self, Error> {
255 let (_hrp, data, _) = bech32::decode(address)?;
256
257 let address = hex::encode(Vec::<u8>::from_base32(&data)?);
258
259 Ok(Self(ZilAddress::to_checksum_address(&address)?))
260 }
261
262 fn to_checksum_address(address: &str) -> Result<String, Error> {
263 let address = address.replace("0x", "");
264 if !Self::is_address(&address) {
265 return Err(Error::InvalidAddress(address.to_string()));
266 }
267
268 let mut hasher = sha2::Sha256::new();
269 hasher.update(hex::decode(&address)?);
270 let v = primitive_types::U256::from_big_endian(&hasher.finalize());
271 let ret = address
272 .chars()
273 .enumerate()
274 .map(|(i, c)| {
275 if c.is_ascii_digit() {
276 c
277 } else {
278 let cond = v
279 .bitand(primitive_types::U256::from(2).pow(primitive_types::U256::from(255 - 6 * i)))
280 .ge(&primitive_types::U256::one());
281 if cond {
282 c.to_ascii_uppercase()
283 } else {
284 c.to_ascii_lowercase()
285 }
286 }
287 })
288 .collect::<String>();
289
290 Ok(format!("0x{}", ret))
291 }
292
293 pub fn to_bech32(&self) -> Result<String, Error> {
294 let address = self.0.strip_prefix("0x").unwrap(); Ok(bech32::encode("zil", hex::decode(address)?.to_base32(), Variant::Bech32)?)
297 }
298
299 pub fn nil() -> Self {
301 Self("0x0000000000000000000000000000000000000000".to_string())
302 }
303
304 pub fn is_bech32(raw: &str) -> bool {
313 let regex = regex::Regex::new("^zil1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{38}$")
314 .expect("Failed to create the regex for `is_bech32`");
315
316 regex.is_match(raw)
317 }
318
319 pub fn is_address(address: &str) -> bool {
320 is_byte_string(address, 40)
321 }
322}
323
324impl FromStr for ZilAddress {
325 type Err = Error;
326
327 fn from_str(addr: &str) -> Result<Self, Self::Err> {
329 if ZilAddress::is_address(addr) {
330 Ok(Self(ZilAddress::to_checksum_address(addr)?))
331 } else if ZilAddress::is_bech32(addr) {
332 Self::from_bech32(addr)
333 } else {
334 Err(Error::InvalidAddress(addr.to_string()))
335 }
336 }
337}
338
339impl TryFrom<H160> for ZilAddress {
340 type Error = Error;
341
342 fn try_from(value: H160) -> Result<Self, Self::Error> {
343 Self::from_str(&hex::encode(value))
344 }
345}
346
347impl Display for ZilAddress {
348 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
349 write!(f, "{}", self.0)
350 }
351}
352
353impl<'de> Deserialize<'de> for ZilAddress {
354 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
355 where
356 D: Deserializer<'de>,
357 {
358 let s: &str = Deserialize::deserialize(deserializer)?;
359
360 s.parse::<Self>().map_err(D::Error::custom)
361 }
362}
363
364#[cfg(test)]
365mod tests {
366 use claim::assert_ok;
367
368 use super::{is_byte_string, PrivateKey, PublicKey, TxHash, ZilAddress};
369
370 #[test]
371 fn is_byte_string_should_return_true_for_a_valid_byte_string_with_correct_size() {
372 let str = "1234567890";
373 assert!(is_byte_string(str, str.len()))
374 }
375
376 #[test]
377 fn is_byte_string_should_return_true_for_a_valid_byte_string_with_correct_size_even_if_its_prepended_with_0x() {
378 let str = "0x1234567890";
379 assert!(is_byte_string(str, str.len() - 2)) }
381
382 #[test]
383 fn is_byte_string_should_return_true_for_a_valid_byte_string_with_correct_size_when_it_contains_letters_a_f() {
384 let str = "1234567890aabbccddeeff";
385 assert!(is_byte_string(str, str.len()))
386 }
387
388 #[test]
389 fn is_byte_string_should_return_false_if_size_is_incorrect() {
390 let str = "1234567890aabbccddeeff";
391 assert_eq!(is_byte_string(str, str.len() - 2), false);
392 }
393
394 #[test]
395 fn is_byte_string_should_return_false_if_contains_out_of_a_f_characters() {
396 let str = "1234567890aabbccddeeffgg";
397 assert_eq!(is_byte_string(str, str.len()), false);
398 }
399
400 #[test]
401 fn is_tx_hash_should_return_true_for_a_valid_hash() {
402 let hash = "bdadfd994f452df803cc223d1f417b02830ac96dbe5edad1b9f8d58613f95206";
403 assert!(TxHash::is_valid(hash));
404
405 let hash = "bdadfd994f452df803cc223d1f417b02830ac96dbe5edad1b9f8d58613f95206".to_ascii_uppercase();
406 assert!(TxHash::is_valid(&hash));
407 }
408
409 #[test]
410 fn is_tx_hash_should_return_false_for_a_invalid_hash() {
411 let hash = "bdadfd994f452df803cc223d102830ac96dbe5edad1b9f8d58613f95206";
412 assert!(!TxHash::is_valid(hash));
413 }
414
415 #[test]
416 fn should_parse_hex_string_to_private_key() {
417 let pv: PrivateKey = "D96e9eb5b782a80ea153c937fa83e5948485fbfc8b7e7c069d7b914dbc350aba"
418 .parse()
419 .unwrap();
420 assert_eq!(
421 "d96e9eb5b782a80ea153c937fa83e5948485fbfc8b7e7c069d7b914dbc350aba",
422 pv.to_string()
423 );
424
425 assert_eq!(
426 pv.public_key().to_string(),
427 "03bfad0f0b53cff5213b5947f3ddd66acee8906aba3610c111915aecc84092e052"
428 );
429 }
430
431 #[test]
432 fn should_parse_hex_string_to_private_key_if_prefixed_with_0x() {
433 let pv: PrivateKey = "0xD96e9eb5b782a80ea153c937fa83e5948485fbfc8b7e7c069d7b914dbc350aba"
434 .parse()
435 .unwrap();
436 assert_eq!(
437 "d96e9eb5b782a80ea153c937fa83e5948485fbfc8b7e7c069d7b914dbc350aba",
438 pv.to_string()
439 );
440
441 assert_eq!(
442 pv.public_key().to_string(),
443 "03bfad0f0b53cff5213b5947f3ddd66acee8906aba3610c111915aecc84092e052"
444 );
445 }
446
447 #[test]
448 fn should_parse_public_key_from_hexstring() {
449 let public_key: PublicKey = "03bfad0f0b53cff5213b5947f3ddd66acee8906aba3610c111915aecc84092e052"
450 .parse()
451 .unwrap();
452
453 assert_eq!(
454 public_key.to_string(),
455 "03bfad0f0b53cff5213b5947f3ddd66acee8906aba3610c111915aecc84092e052"
456 );
457 }
458
459 #[test]
460 fn valid_address_should_parse_correctly() {
461 let address = "0x381f4008505e940AD7681EC3468a719060caF796";
462 assert_ok!(address.parse::<ZilAddress>());
463 assert_eq!(address.parse::<ZilAddress>().unwrap().to_string(), address);
464
465 assert_ok!(address.strip_prefix("0x").unwrap().parse::<ZilAddress>());
466 assert_eq!(
467 address.strip_prefix("0x").unwrap().parse::<ZilAddress>().unwrap().to_string(),
468 address
469 );
470 }
471
472 #[test]
473 fn valid_bech32_address_should_parse_correctly() {
474 let address = "0x381f4008505e940AD7681EC3468a719060caF796";
475 let bech32_address = "zil18q05qzzst62q44mgrmp5dzn3jpsv4aukxredu2";
476 let zil_addr: ZilAddress = bech32_address.parse().unwrap();
477
478 assert_eq!(zil_addr.to_string(), address);
479 }
480
481 #[test]
482 fn to_bech32_address_should_return_correct_address() {
483 let address = "0x381f4008505e940AD7681EC3468a719060caF796";
484 let bech32_address = "zil18q05qzzst62q44mgrmp5dzn3jpsv4aukxredu2";
485
486 let zil_addr: ZilAddress = address.parse().unwrap();
487 assert_eq!(zil_addr.to_bech32().unwrap(), bech32_address);
488 }
489
490 #[test]
491 fn is_bech32_should_return_true_for_valid_one() {
492 assert!(ZilAddress::is_bech32("zil18q05qzzst62q44mgrmp5dzn3jpsv4aukxredu2"))
493 }
494
495 #[test]
496 fn is_bech32_should_return_false_for_invalid_ones() {
497 assert!(!ZilAddress::is_bech32("liz18q05qzzst62q44mgrmp5dzn3jpsv4aukxredu2"));
498 assert!(!ZilAddress::is_bech32("zil18q05qzzst62q44mgrmp5dzn3jpsv4aukxredu2ssaas"));
499 }
500
501 #[test]
502 fn to_checksum_address_should_return_correct_value_for_valid_input() {
503 let address = "11223344556677889900aabbccddeeff11223344";
504 let checksum = "0x11223344556677889900AabbccdDeefF11223344";
505
506 assert_eq!(checksum, ZilAddress::to_checksum_address(address).unwrap())
507 }
508}