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