stacks_core/crypto/
mod.rs

1pub use bdk::bitcoin::secp256k1;
2use serde::{Deserialize, Serialize};
3
4use crate::{StacksError, StacksResult};
5
6/// Module for Hash160 hashing
7pub mod hash160;
8/// Module for sha256 hashing
9pub mod sha256;
10pub mod wif;
11
12const CHECKSUM_LENGTH: usize = 4;
13
14#[derive(Serialize, Deserialize)]
15#[serde(transparent)]
16struct Hex(String);
17
18/// Hashing trait
19pub trait Hashing<const LENGTH: usize>: Clone + Sized {
20	/// Hash the given data
21	fn hash(data: &[u8]) -> Self;
22	/// Get the bytes of the hash
23	fn as_bytes(&self) -> &[u8];
24	/// Attempt to create a hash from the given bytes
25	fn from_bytes(bytes: &[u8]) -> StacksResult<Self>;
26	/// Create a hash from the given bytes
27	fn new(value: impl AsRef<[u8]>) -> Self {
28		Self::hash(value.as_ref())
29	}
30
31	/// Create a zeroed hash
32	fn zeroes() -> Self {
33		Self::from_bytes(vec![0; LENGTH].as_slice()).unwrap()
34	}
35
36	/// Get the checksum of the hash
37	fn checksum(&self) -> [u8; CHECKSUM_LENGTH] {
38		self.as_bytes()[0..CHECKSUM_LENGTH].try_into().unwrap()
39	}
40
41	/// Attempt to create a hash from the given hex bytes
42	fn from_hex(data: impl AsRef<str>) -> StacksResult<Self> {
43		Self::from_bytes(&hex::decode(data.as_ref().as_bytes())?)
44	}
45
46	/// Get the hex representation of the hash
47	fn to_hex(&self) -> String {
48		hex::encode(self.as_bytes())
49	}
50}
51
52#[derive(
53	Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord,
54)]
55#[serde(try_from = "Hex")]
56#[serde(into = "Hex")]
57/// The hasher type
58pub struct Hasher<T, const LENGTH: usize>(T)
59where
60	T: Hashing<LENGTH>;
61
62impl<T, const LENGTH: usize> Hashing<LENGTH> for Hasher<T, LENGTH>
63where
64	T: Hashing<LENGTH>,
65{
66	fn hash(data: &[u8]) -> Self {
67		Self(T::hash(data))
68	}
69
70	fn as_bytes(&self) -> &[u8] {
71		T::as_bytes(&self.0)
72	}
73
74	fn from_bytes(bytes: &[u8]) -> StacksResult<Self> {
75		Ok(Self(T::from_bytes(bytes)?))
76	}
77}
78
79impl<T, const LENGTH: usize> AsRef<[u8]> for Hasher<T, LENGTH>
80where
81	T: Hashing<LENGTH>,
82{
83	fn as_ref(&self) -> &[u8] {
84		self.as_bytes()
85	}
86}
87
88impl<T, const LENGTH: usize> TryFrom<&[u8]> for Hasher<T, LENGTH>
89where
90	T: Hashing<LENGTH>,
91{
92	type Error = StacksError;
93
94	fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
95		Self::from_bytes(value)
96	}
97}
98
99impl<T, const LENGTH: usize> From<[u8; LENGTH]> for Hasher<T, LENGTH>
100where
101	T: Hashing<LENGTH>,
102{
103	fn from(value: [u8; LENGTH]) -> Self {
104		Self::from_bytes(&value).unwrap()
105	}
106}
107
108impl<T, const LENGTH: usize> Default for Hasher<T, LENGTH>
109where
110	T: Hashing<LENGTH>,
111{
112	fn default() -> Self {
113		Self::zeroes()
114	}
115}
116
117// From conversion is fallible for this type
118#[allow(clippy::from_over_into)]
119impl<T, const LENGTH: usize> Into<Hex> for Hasher<T, LENGTH>
120where
121	T: Hashing<LENGTH>,
122{
123	fn into(self) -> Hex {
124		Hex(hex::encode(self.as_bytes()))
125	}
126}
127
128impl<T, const LENGTH: usize> TryFrom<Hex> for Hasher<T, LENGTH>
129where
130	T: Hashing<LENGTH>,
131{
132	type Error = StacksError;
133
134	fn try_from(value: Hex) -> Result<Self, Self::Error> {
135		Self::from_bytes(&hex::decode(value.0)?)
136	}
137}
138
139/// Stacks private key
140pub type PrivateKey = bdk::bitcoin::secp256k1::SecretKey;
141
142/// Stacks public key
143pub type PublicKey = bdk::bitcoin::secp256k1::PublicKey;