1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
use base58::ToBase58;
use blake3::Hasher;
use ring::digest::{Algorithm, SHA256 as sha256};
pub use secp256k1::{Message, PublicKey, SecretKey, Signature, SECP256K1};
pub static SHA256: &Algorithm = &sha256;
pub use merkle::MerkleTree;

// symmetrical encryption
use aes::Aes128;
use block_modes::block_padding::Pkcs7;
use block_modes::{BlockMode, Cbc};
// create an alias for convenience
type Aes128Cbc = Cbc<Aes128, Pkcs7>;

pub type SaitoHash = [u8; 32];
pub type SaitoUTXOSetKey = [u8; 74];
pub type SaitoPublicKey = [u8; 33];
pub type SaitoPrivateKey = [u8; 32]; // 256-bit key
pub type SaitoSignature = [u8; 64];

pub const PARALLEL_HASH_BYTE_THRESHOLD: usize = 128_000;

pub fn encrypt_with_password(msg: Vec<u8>, password: &str) -> Vec<u8> {
    let hash = hash(&password.as_bytes().to_vec());
    let mut key: [u8; 16] = [0; 16];
    let mut iv: [u8; 16] = [0; 16];
    key.clone_from_slice(&hash[0..16]);
    iv.clone_from_slice(&hash[16..32]);

    let cipher = Aes128Cbc::new_from_slices(&key, &iv).unwrap();
    let encrypt_msg = cipher.encrypt_vec(&msg);

    return encrypt_msg;
}
pub fn decrypt_with_password(msg: Vec<u8>, password: &str) -> Vec<u8> {
    let hash = hash(&password.as_bytes().to_vec());
    let mut key: [u8; 16] = [0; 16];
    let mut iv: [u8; 16] = [0; 16];
    key.clone_from_slice(&hash[0..16]);
    iv.clone_from_slice(&hash[16..32]);

    let cipher = Aes128Cbc::new_from_slices(&key, &iv).unwrap();
    let decrypt_msg = cipher.decrypt_vec(&msg).unwrap();

    return decrypt_msg;
}

pub fn generate_keys() -> (SaitoPublicKey, SaitoPrivateKey) {
    let (mut secret_key, mut public_key) =
        SECP256K1.generate_keypair(&mut secp256k1::rand::thread_rng());
    while public_key.serialize().to_base58().len() != 44 {
        // sometimes secp256k1 address is too big to store in 44 base-58 digits
        let keypair_tuple = SECP256K1.generate_keypair(&mut secp256k1::rand::thread_rng());
        secret_key = keypair_tuple.0;
        public_key = keypair_tuple.1;
    }
    let mut secret_bytes = [0u8; 32];
    for i in 0..32 {
        secret_bytes[i] = secret_key[i];
    }
    (public_key.serialize(), secret_bytes)
}
/// Create and return a keypair with  the given hex u8 array as the private key
pub fn generate_keypair_from_privatekey(slice: &[u8]) -> (SaitoPublicKey, SaitoPrivateKey) {
    let secret_key = SecretKey::from_slice(slice).unwrap();
    let public_key = PublicKey::from_secret_key(&SECP256K1, &secret_key);
    let mut secret_bytes = [0u8; 32];
    for i in 0..32 {
        secret_bytes[i] = secret_key[i];
    }
    (public_key.serialize(), secret_bytes)
}

pub fn sign_blob(vbytes: &mut Vec<u8>, privatekey: SaitoPrivateKey) -> &mut Vec<u8> {
    let sig = sign(&hash(vbytes.as_ref()), privatekey);
    vbytes.extend(&sig);
    vbytes
}

pub fn generate_random_bytes(len: u64) -> Vec<u8> {
    if len == 0 {
        let x: Vec<u8> = vec![];
        return x;
    }
    (0..len).map(|_| rand::random::<u8>()).collect()
}

pub fn hash(data: &Vec<u8>) -> SaitoHash {
    let mut hasher = Hasher::new();
    // Hashing in parallel can be faster if large enough
    // TODO: Blake3 has benchmarked 128 kb as the cutoff,
    // the benchmark should be redone for Saito's needs
    if data.len() > PARALLEL_HASH_BYTE_THRESHOLD {
        hasher.update(data);
    } else {
        hasher.update_rayon(data);
    }
    hasher.finalize().into()
}

pub fn sign(message_bytes: &[u8], privatekey: SaitoPrivateKey) -> SaitoSignature {
    let msg = Message::from_slice(message_bytes).unwrap();
    let secret = SecretKey::from_slice(&privatekey).unwrap();
    let sig = SECP256K1.sign(&msg, &secret);
    sig.serialize_compact()
}

pub fn verify(msg: &[u8], sig: SaitoSignature, publickey: SaitoPublicKey) -> bool {
    let m = Message::from_slice(msg);
    let p = PublicKey::from_slice(&publickey);
    let s = Signature::from_compact(&sig);
    if m.is_err() || p.is_err() || s.is_err() {
        false
    } else {
        SECP256K1
            .verify(&m.unwrap(), &s.unwrap(), &p.unwrap())
            .is_ok()
    }
}

#[cfg(test)]

mod tests {

    use super::*;
    use hex::FromHex;
    use std::str;

    #[test]
    //
    // test symmetrical encryption works properly
    //
    fn symmetrical_encryption_works_test() {
        let text = "This is our unencrypted text";
        let e = encrypt_with_password(text.as_bytes().to_vec(), "asdf");
        let d = decrypt_with_password(e, "asdf");
        let dtext = str::from_utf8(&d).unwrap();

        assert_eq!(text, dtext);
    }

    #[test]
    fn sign_message_test() {
        let msg = <[u8; 32]>::from_hex(
            "dcf6cceb74717f98c3f7239459bb36fdcd8f350eedbfccfbebf7c0b0161fcd8b",
        )
        .unwrap();
        let private_key: SaitoPrivateKey = <[u8; 32]>::from_hex(
            "854702489d49c7fb2334005b903580c7a48fe81121ff16ee6d1a528ad32f235d",
        )
        .unwrap();

        let result = sign(&msg, private_key);
        assert_eq!(result.len(), 64);
        assert_eq!(
            result,
            [
                202, 118, 37, 146, 48, 117, 177, 10, 18, 74, 214, 201, 245, 79, 145, 68, 124, 181,
                129, 43, 91, 128, 75, 189, 34, 121, 244, 108, 214, 106, 46, 155, 54, 226, 157, 1,
                230, 58, 151, 82, 11, 177, 41, 250, 204, 74, 32, 21, 109, 128, 177, 114, 15, 171,
                9, 150, 237, 116, 236, 2, 146, 210, 39, 69
            ]
        );
    }
}