snap_coin/crypto/
mod.rs

1use argon2::{Argon2, Params};
2use bincode::{Decode, Encode};
3use ed25519_dalek::SigningKey;
4use ed25519_dalek::ed25519::Error;
5use ed25519_dalek::ed25519::signature::SignerMut;
6use ed25519_dalek::{Signature as DalekSignature, VerifyingKey};
7use num_bigint::BigUint;
8use serde::{Deserialize, Serialize};
9use std::fmt;
10use std::ops::Deref;
11
12use keys::{Private, Public};
13
14/// Public / Private key logic
15pub mod keys;
16
17/// Merkle tree
18pub mod merkle_tree;
19
20/// Address inclusion filter
21pub mod address_inclusion_filter;
22
23/// Argon2 configuration, includes magic bytes (the salt for hashing)
24pub struct Argon2Config {
25    pub memory_cost: u32,
26    pub time_cost: u32,
27    pub parallelism: u32,
28    pub output_length: Option<usize>,
29    pub algorithm: argon2::Algorithm,
30    pub version: argon2::Version,
31    pub magic_bytes: [u8; 10]
32}
33
34/// The currently used, blockchain argon2 config
35pub const ARGON2_CONFIG: Argon2Config = Argon2Config {
36    memory_cost: 8 * 1024,
37    time_cost: 1,
38    parallelism: 2,
39    output_length: Some(32),
40    algorithm: argon2::Algorithm::Argon2id,
41    version: argon2::Version::V0x13,
42    magic_bytes: [0xCD, 0xC6, 0x3B, 0xAF, 0x5E, 0x52, 0xE0, 0x9, 0x72, 0xAD]
43};
44
45// WARNING: SLOW
46pub fn argon2_hash(input: &[u8]) -> [u8; 32] {
47    let params = Params::new(ARGON2_CONFIG.memory_cost, ARGON2_CONFIG.time_cost, ARGON2_CONFIG.parallelism, ARGON2_CONFIG.output_length).unwrap();
48    let argon2 = Argon2::new(ARGON2_CONFIG.algorithm, ARGON2_CONFIG.version, params);
49    let mut hash = [0u8; 32];
50    argon2
51        .hash_password_into(input, &ARGON2_CONFIG.magic_bytes, &mut hash)
52        .unwrap();
53    hash
54}
55
56/// Store and hash Argon2 hashes (compare too)
57/// When used in in hashmaps, the already hashed argon 2 digest gets re-hashed, for speed
58#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, std::hash::Hash)]
59pub struct Hash([u8; 32]);
60
61impl Hash {
62    /// Create a new hash by hashing some data
63    /// WARNING: SLOW
64    pub fn new(data: &[u8]) -> Self {
65        Hash(argon2_hash(data))
66    }
67
68    /// Create a new hash with a buffer of an already existing hash
69    pub const fn new_from_buf(hash_buf: [u8; 32]) -> Self {
70        Hash(hash_buf)
71    }
72
73    /// Compare this hash with some data (check if the data hash is the same)
74    pub fn compare_with_data(&self, other_data: &[u8]) -> bool {
75        let computed = argon2_hash(other_data);
76        computed == self.0
77    }
78
79    /// Create a new hash from a already existing hash encoded in a base36 string
80    pub fn new_from_base36(s: &str) -> Option<Self> {
81        // Convert base36 string to bytes
82        let big_int = BigUint::parse_bytes(s.as_bytes(), 36)?;
83        let mut buf = big_int.to_bytes_be();
84
85        // Ensure the buffer is exactly 32 bytes
86        if buf.len() > 32 {
87            return None;
88        } else if buf.len() < 32 {
89            // Pad with zeros at the front
90            let mut padded = vec![0u8; 32 - buf.len()];
91            padded.extend(buf);
92            buf = padded;
93        }
94
95        // Convert Vec<u8> to [u8; 32]
96        let buf: [u8; 32] = buf.try_into().ok()?;
97
98        Some(Hash(buf))
99    }
100
101    pub fn dump_base36(&self) -> String {
102        let big_int = BigUint::from_bytes_be(&self.0);
103        big_int.to_str_radix(36)
104    }
105
106    pub fn dump_buf(&self) -> [u8; 32] {
107        self.0
108    }
109}
110
111impl Serialize for Hash {
112    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
113    where
114        S: serde::Serializer,
115    {
116        serializer.serialize_str(&self.dump_base36())
117    }
118}
119
120impl<'de> Deserialize<'de> for Hash {
121    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
122    where
123        D: serde::Deserializer<'de>,
124    {
125        let s = String::deserialize(deserializer)?;
126        Self::new_from_base36(&s).ok_or_else(|| serde::de::Error::custom("Invalid base36 hash"))
127    }
128}
129
130impl Deref for Hash {
131    type Target = [u8; 32];
132    fn deref(&self) -> &Self::Target {
133        &self.0
134    }
135}
136
137impl fmt::Debug for Hash {
138    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
139        write!(f, "Hash: {}", self.dump_base36())
140    }
141}
142
143/// Store sign and verify ed25519
144#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy, Hash)]
145pub struct Signature([u8; 64]);
146
147impl Signature {
148    /// Create a signature by signing some data
149    pub fn new_signature(private: &mut Private, data: &[u8]) -> Self {
150        let mut key = SigningKey::from_bytes(private.dump_buf());
151        let signature = key.sign(data);
152        Signature(signature.to_bytes()) // [u8; 64]
153    }
154
155    /// Create a signature with the raw signature bytes (no signing)
156    pub fn new_from_buf(signature: &[u8; 64]) -> Self {
157        Signature(signature.clone())
158    }
159
160    /// Validate a signature and return true if valid
161    pub fn validate_with_public(&self, public: &Public, data: &[u8]) -> Result<bool, Error> {
162        let key = VerifyingKey::from_bytes(public.dump_buf())?;
163        Ok(key
164            .verify_strict(data, &DalekSignature::from_bytes(&self.0))
165            .is_ok())
166    }
167
168    /// Validate a signature and return true if valid
169    pub fn validate_with_private(&self, private: &Private, data: &[u8]) -> Result<bool, Error> {
170        let key = SigningKey::from_bytes(private.dump_buf());
171        Ok(key
172            .verify_strict(data, &DalekSignature::from_bytes(&self.0))
173            .is_ok())
174    }
175
176    /// Create a signature from a base 36 string
177    pub fn new_from_base36(s: &str) -> Option<Self> {
178        // Convert base36 string to bytes
179        let big_int = BigUint::parse_bytes(s.as_bytes(), 36)?;
180        let mut buf = big_int.to_bytes_be();
181
182        // Ensure the buffer is exactly 64 bytes
183        if buf.len() > 64 {
184            return None;
185        } else if buf.len() < 64 {
186            // Pad with zeros at the front
187            let mut padded = vec![0u8; 64 - buf.len()];
188            padded.extend(buf);
189            buf = padded;
190        }
191
192        // Convert Vec<u8> to [u8; 64]
193        let buf: [u8; 64] = buf.try_into().ok()?;
194
195        Some(Self(buf))
196    }
197
198    pub fn dump_base36(&self) -> String {
199        let big_int = BigUint::from_bytes_be(&self.0);
200        big_int.to_str_radix(36)
201    }
202
203    pub fn dump_buf(&self) -> [u8; 64] {
204        self.0
205    }
206}
207
208impl Serialize for Signature {
209    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
210    where
211        S: serde::Serializer,
212    {
213        serializer.serialize_str(&self.dump_base36())
214    }
215}
216
217impl<'de> Deserialize<'de> for Signature {
218    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
219    where
220        D: serde::Deserializer<'de>,
221    {
222        let s = String::deserialize(deserializer)?;
223        Self::new_from_base36(&s).ok_or_else(|| serde::de::Error::custom("Invalid base36 signature"))
224    }
225}
226
227impl Deref for Signature {
228    type Target = [u8; 64]; // match the array size
229    fn deref(&self) -> &Self::Target {
230        &self.0
231    }
232}
233
234impl fmt::Debug for Signature {
235    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
236        write!(f, "Signature: {}", self.dump_base36())
237    }
238}