stacks_core/crypto/
mod.rs1pub use bdk::bitcoin::secp256k1;
2use serde::{Deserialize, Serialize};
3
4use crate::{StacksError, StacksResult};
5
6pub mod hash160;
8pub mod sha256;
10pub mod wif;
11
12const CHECKSUM_LENGTH: usize = 4;
13
14#[derive(Serialize, Deserialize)]
15#[serde(transparent)]
16struct Hex(String);
17
18pub trait Hashing<const LENGTH: usize>: Clone + Sized {
20 fn hash(data: &[u8]) -> Self;
22 fn as_bytes(&self) -> &[u8];
24 fn from_bytes(bytes: &[u8]) -> StacksResult<Self>;
26 fn new(value: impl AsRef<[u8]>) -> Self {
28 Self::hash(value.as_ref())
29 }
30
31 fn zeroes() -> Self {
33 Self::from_bytes(vec![0; LENGTH].as_slice()).unwrap()
34 }
35
36 fn checksum(&self) -> [u8; CHECKSUM_LENGTH] {
38 self.as_bytes()[0..CHECKSUM_LENGTH].try_into().unwrap()
39 }
40
41 fn from_hex(data: impl AsRef<str>) -> StacksResult<Self> {
43 Self::from_bytes(&hex::decode(data.as_ref().as_bytes())?)
44 }
45
46 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")]
57pub 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#[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
139pub type PrivateKey = bdk::bitcoin::secp256k1::SecretKey;
141
142pub type PublicKey = bdk::bitcoin::secp256k1::PublicKey;