bc_crypto/
scrypt.rs

1use scrypt::scrypt as scrypt_hash;
2
3/// Computes the scrypt key derivation function using recommended parameters.
4///
5/// # Arguments
6///
7/// * `pass` - The password or passphrase as a byte slice.
8/// * `salt` - The salt as a byte slice.
9/// * `output_len` - The desired length of the derived key in bytes. Must be greater than 9 and less than or equal to 64.
10///
11/// # Returns
12///
13/// A `Vec<u8>` containing the derived key of the specified length.
14///
15/// # Panics
16///
17/// Panics if the scrypt function fails or if the output length is invalid.
18///
19/// # Examples
20///
21/// ```
22/// use bc_crypto::scrypt;
23/// let key = scrypt(b"password", b"salt", 32);
24/// assert_eq!(key.len(), 32);
25/// ```
26pub fn scrypt(
27    pass: impl AsRef<[u8]>,
28    salt: impl AsRef<[u8]>,
29    output_len: usize, // Must be greater than `9` and less than or equal to `64`
30) -> Vec<u8> {
31    let params = scrypt::Params::recommended();
32    let mut output = vec![0u8; output_len];
33    scrypt_hash(pass.as_ref(), salt.as_ref(), &params, &mut output)
34        .expect("scrypt failed");
35    output
36}
37
38pub fn scrypt_opt(
39    pass: impl AsRef<[u8]>,
40    salt: impl AsRef<[u8]>,
41    output_len: usize, // Must be greater than `9` and less than or equal to `64`
42    log_n: u8, // Must be less than `64`
43    r: u32, // Must be greater than 0 and less than or equal to `4294967295`
44    p: u32, // Must be greater than 0 and less than `4294967295`
45) -> Vec<u8> {
46    let params = scrypt::Params::new(log_n, r, p, output_len)
47        .expect("Invalid Scrypt parameters");
48    let mut output = vec![0u8; output_len];
49    scrypt_hash(pass.as_ref(), salt.as_ref(), &params, &mut output)
50        .expect("scrypt failed");
51    output
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    #[test]
59    fn test_scrypt_basic() {
60        let pass = b"password";
61        let salt = b"salt";
62        let output = scrypt(pass, salt, 32);
63        assert_eq!(output.len(), 32);
64        // Scrypt should be deterministic for same input
65        let output2 = scrypt(pass, salt, 32);
66        assert_eq!(output, output2);
67    }
68
69    #[test]
70    fn test_scrypt_different_salt() {
71        let pass = b"password";
72        let salt1 = b"salt1";
73        let salt2 = b"salt2";
74        let out1 = scrypt(pass, salt1, 32);
75        let out2 = scrypt(pass, salt2, 32);
76        assert_ne!(out1, out2);
77    }
78
79    #[test]
80    fn test_scrypt_opt_basic() {
81        let pass = b"password";
82        let salt = b"salt";
83        let output = scrypt_opt(pass, salt, 32, 15, 8, 1);
84        assert_eq!(output.len(), 32);
85    }
86
87    #[test]
88    fn test_scrypt_output_length() {
89        let pass = b"password";
90        let salt = b"salt";
91        for len in [16, 24, 32, 64] {
92            let output = scrypt(pass, salt, len);
93            assert_eq!(output.len(), len);
94        }
95    }
96}