saito_core/core/util/
crypto.rs

1use crate::core::defs::{PrintForLog, SaitoHash, SaitoPrivateKey, SaitoPublicKey, SaitoSignature};
2use blake3::Hasher;
3use block_modes::BlockMode;
4pub use merkle::MerkleTree;
5use rand::{thread_rng, Rng, SeedableRng};
6use secp256k1::ecdsa;
7pub use secp256k1::{Message, PublicKey, SecretKey, SECP256K1};
8
9// type Aes128Cbc = Cbc<Aes128, Pkcs7>;
10
11pub const PARALLEL_HASH_BYTE_THRESHOLD: usize = 128_000;
12
13// pub fn encrypt_with_password(msg: &[u8], password: &[u8]) -> Vec<u8> {
14//     let hash = hash(password);
15//     let mut key: [u8; 16] = [0; 16];
16//     let mut iv: [u8; 16] = [0; 16];
17//     key.clone_from_slice(&hash[0..16]);
18//     iv.clone_from_slice(&hash[16..32]);
19//
20//     let cipher = Aes128Cbc::new_from_slices(&key, &iv).unwrap();
21//     let encrypt_msg = cipher.encrypt_vec(msg);
22//
23//     return encrypt_msg;
24// }
25
26// pub fn decrypt_with_password(msg: &[u8], password: &str) -> Vec<u8> {
27//     let hash = hash(password.as_bytes());
28//     let mut key: [u8; 16] = [0; 16];
29//     let mut iv: [u8; 16] = [0; 16];
30//     key.clone_from_slice(&hash[0..16]);
31//     iv.clone_from_slice(&hash[16..32]);
32//
33//     let cipher = Aes128Cbc::new_from_slices(&key, &iv).unwrap();
34//     let decrypt_msg = cipher.decrypt_vec(msg).unwrap();
35//
36//     return decrypt_msg;
37// }
38
39pub fn generate_keys() -> (SaitoPublicKey, SaitoPrivateKey) {
40    let (mut secret_key, mut public_key) =
41        SECP256K1.generate_keypair(&mut secp256k1::rand::thread_rng());
42    while public_key.serialize().to_base58().len() != 44 {
43        // sometimes secp256k1 address is too big to store in 44 base-58 digits
44        let keypair_tuple = SECP256K1.generate_keypair(&mut secp256k1::rand::thread_rng());
45        secret_key = keypair_tuple.0;
46        public_key = keypair_tuple.1;
47    }
48    let mut secret_bytes = [0u8; 32];
49    for i in 0..32 {
50        secret_bytes[i] = secret_key[i];
51    }
52    (public_key.serialize(), secret_bytes)
53}
54
55/// Create and return a keypair with  the given hex u8 array as the private key
56pub fn generate_keypair_from_private_key(slice: &[u8]) -> (SaitoPublicKey, SaitoPrivateKey) {
57    let secret_key = SecretKey::from_slice(slice).unwrap();
58    let public_key = PublicKey::from_secret_key(SECP256K1, &secret_key);
59    let mut secret_bytes = [0u8; 32];
60    for i in 0..32 {
61        secret_bytes[i] = secret_key[i];
62    }
63    (public_key.serialize(), secret_bytes)
64}
65
66pub fn sign_blob<'a>(vbytes: &'a mut Vec<u8>, private_key: &SaitoPrivateKey) -> &'a mut Vec<u8> {
67    let sig = sign(&hash(vbytes.as_ref()), private_key);
68    vbytes.extend(&sig);
69    vbytes
70}
71#[cfg(test)]
72lazy_static::lazy_static! {
73    pub static ref TEST_RNG: tokio::sync::Mutex<rand::rngs::StdRng>  = tokio::sync::Mutex::new(create_test_rng());
74}
75
76fn create_test_rng() -> rand::rngs::StdRng {
77    rand::rngs::StdRng::from_seed([0; 32])
78}
79
80pub async fn generate_random_bytes(len: u64) -> Vec<u8> {
81    if len == 0 {
82        let x: Vec<u8> = vec![];
83        return x;
84    }
85    // Don't have to be cryptographically secure, since we only need a random hash and only check the signature of that in return
86
87    #[cfg(not(test))]
88    {
89        let mut rng = thread_rng();
90        (0..len).map(|_| rng.gen::<u8>()).collect()
91    }
92    #[cfg(test)]
93    {
94        // let mut rng = TEST_RNG.clone();
95        let mut rng = TEST_RNG.lock().await;
96        (0..len).map(|_| rng.gen::<u8>()).collect()
97    }
98}
99
100pub fn hash(data: &[u8]) -> SaitoHash {
101    let mut hasher = Hasher::new();
102    // Hashing in parallel can be faster if large enough
103    // TODO: Blake3 has benchmarked 128 kb as the cutoff,
104    //  the benchmark should be redone for Saito's needs
105
106    #[cfg(feature = "with-rayon")]
107    {
108        if data.len() > PARALLEL_HASH_BYTE_THRESHOLD {
109            hasher.update_rayon(data);
110        } else {
111            hasher.update(data);
112        }
113    }
114    #[cfg(not(feature = "with-rayon"))]
115    {
116        hasher.update(data);
117    }
118
119    hasher.finalize().into()
120}
121
122pub fn sign(message_bytes: &[u8], private_key: &SaitoPrivateKey) -> SaitoSignature {
123    let hash = hash(message_bytes);
124    let msg = Message::from_slice(&hash).unwrap();
125    let secret = SecretKey::from_slice(private_key).unwrap();
126    let sig = SECP256K1.sign_ecdsa(&msg, &secret);
127    sig.serialize_compact()
128}
129
130pub fn verify(msg: &[u8], sig: &SaitoSignature, public_key: &SaitoPublicKey) -> bool {
131    let hash = hash(msg);
132    verify_signature(&hash, sig, public_key)
133}
134
135pub fn verify_signature(
136    hash: &SaitoHash,
137    sig: &SaitoSignature,
138    public_key: &SaitoPublicKey,
139) -> bool {
140    let m = Message::from_slice(hash);
141    let p = PublicKey::from_slice(public_key);
142    let s = ecdsa::Signature::from_compact(sig);
143    if m.is_err() || p.is_err() || s.is_err() {
144        false
145    } else {
146        SECP256K1
147            .verify_ecdsa(&m.unwrap(), &s.unwrap(), &p.unwrap())
148            .is_ok()
149    }
150}
151
152pub fn is_valid_public_key(key: &SaitoPublicKey) -> bool {
153    let result = PublicKey::from_slice(key);
154    result.is_ok()
155}
156
157#[cfg(test)]
158mod tests {
159
160    use crate::core::defs::SaitoPrivateKey;
161
162    use super::*;
163
164    // #[test]
165    // //
166    // // test symmetrical encryption works properly
167    // //
168    // fn symmetrical_encryption_test() {
169    //     let text = "This is our unencrypted text";
170    //     let e = encrypt_with_password(text.as_bytes(), "asdf");
171    //     let d = decrypt_with_password(e.as_slice(), "asdf");
172    //     let dtext = str::from_utf8(&d).unwrap();
173    //     assert_eq!(text, dtext);
174    // }
175
176    #[test]
177    fn keypair_restoration_from_private_key_test() {
178        let (public_key, private_key) = generate_keys();
179        let (public_key2, private_key2) = generate_keypair_from_private_key(&private_key);
180        assert_eq!(public_key, public_key2);
181        assert_eq!(private_key, private_key2);
182    }
183
184    #[test]
185    fn sign_message_test() {
186        let msg = <[u8; 32]>::from_hex(
187            "5a16ffa08e5fc440772ee962c1d730041f12c7008a6e5c704d13dfd3d1906e0d",
188        )
189        .unwrap();
190
191        let hex = hash(msg.as_slice());
192
193        let hex_str = hex.to_hex();
194        assert_eq!(
195            hex_str,
196            "f8b1f22222bdbd2e0bce06707a51f5fffa0753b11483c330e3bfddaf5bacabd6"
197        );
198
199        let private_key: SaitoPrivateKey = <[u8; 32]>::from_hex(
200            "4a16ffa08e5fc440772ee962c1d730041f12c7008a6e5c704d13dfd3d1905e0d",
201        )
202        .unwrap();
203
204        let (public, _) = generate_keypair_from_private_key(&private_key);
205
206        let signature = sign(&msg, &private_key);
207        assert_eq!(signature.len(), 64);
208        let hex_str = signature.to_hex();
209        assert_eq!(hex_str, "11c0e19856726c42c8ac3ec8e469057f5f8a882f7206377525db00899835b03f6ec3010d19534a5703dd9b1004b4f0e31d19582cdd5aec794541d0d0f339db7c");
210
211        let result = verify(&msg, &signature, &public);
212        assert!(result);
213    }
214
215    #[test]
216    fn verify_message_test() {
217        let msg = <[u8; 32]>::from_hex(
218            "dcf6cceb74717f98c3f7239459bb36fdcd8f350eedbfccfbebf7c0b0161fcd8b",
219        )
220        .unwrap();
221
222        let (public_key, private_key) = generate_keys();
223        let (public_key2, private_key2) = generate_keys();
224
225        assert_eq!(verify(&msg, &sign(&msg, &private_key), &public_key), true);
226        assert_eq!(verify(&msg, &sign(&msg, &private_key2), &public_key2), true);
227        assert_eq!(verify(&msg, &sign(&msg, &private_key), &public_key2), false);
228        assert_eq!(verify(&msg, &sign(&msg, &private_key2), &public_key), false);
229    }
230
231    #[test]
232    fn is_valid_public_key_test() {
233        let (public_key, _) = generate_keys();
234        assert!(is_valid_public_key(&public_key));
235
236        let public_key: SaitoPublicKey = [0; 33];
237        assert!(!is_valid_public_key(&public_key));
238
239        let public_key: SaitoPublicKey = [u8::try_from('a').unwrap(); 33];
240        assert!(!is_valid_public_key(&public_key));
241    }
242}