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
//! # Short-input hashing
//!
//! This module implements libsodium's short input hashing, based on
//! SipHash-2-4.
//!
//! You may want to use short input hashing when:
//!
//! * you need to construct hash tables in a fashion that is collision resistant
//!   (i.e., it's hard for other parties to guess when there may be a hash key
//!   collision, which could lead to DoS or timing attacks)
//! * you want to construct probabilistic data structures, such as bloom filters
//! * you want to perform basic integrity checks on data
//! * you have relatively short inputs
//!
//! The key used with this function should be treated as a secret. If used for
//! constructing hash tables, it's recommended the table size be a prime number
//! to ensure all bits from the output are used.
//!
//! For details, refer to [libsodium docs](https://libsodium.gitbook.io/doc/hashing/short-input_hashing).
//!
//! ## Classic API example
//!
//! ```
//! use dryoc::classic::crypto_shorthash::*;
//! use dryoc::rng::copy_randombytes;
//!
//! // Generate a random key
//! let key = crypto_shorthash_keygen();
//!
//! // Generate some random input data
//! let mut input = vec![0u8; 69];
//! copy_randombytes(&mut input);
//!
//! // Compute the hash, put result into `output`
//! let mut output = Hash::default();
//! crypto_shorthash(&mut output, &input, &key);
//! ```
use crate::constants::{CRYPTO_SHORTHASH_BYTES, CRYPTO_SHORTHASH_KEYBYTES};
use crate::rng::copy_randombytes;
use crate::siphash24::siphash24;

/// Hash type alias for short input hashing.
pub type Hash = [u8; CRYPTO_SHORTHASH_BYTES];
/// Key type alias for short input hashing.
pub type Key = [u8; CRYPTO_SHORTHASH_KEYBYTES];

/// Generates a random key for short input hashing.
pub fn crypto_shorthash_keygen() -> Key {
    let mut key = Key::default();
    copy_randombytes(&mut key);
    key
}

/// Computes a short input hash for `input` and `key`, placing the result into
/// `output`, using SipHash-2-4.
pub fn crypto_shorthash(output: &mut Hash, input: &[u8], key: &Key) {
    siphash24(output, input, key)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_shorthash() {
        use rand_core::{OsRng, RngCore};
        use sodiumoxide::crypto::shorthash;

        for _ in 0..20 {
            let key = crypto_shorthash_keygen();
            let mut input = vec![0u8; (OsRng.next_u32() % 69) as usize];
            copy_randombytes(&mut input);
            let mut output = Hash::default();

            crypto_shorthash(&mut output, &input, &key);

            let so_output = shorthash::shorthash(
                &input,
                &shorthash::Key::from_slice(&key).expect("so key failed"),
            );

            assert_eq!(output, so_output.0);
        }
    }
}