snarkvm_console_algorithms/blake2xs/
mod.rs1mod hash_to_curve;
21
22pub struct Blake2Xs;
23
24impl Blake2Xs {
25 fn evaluate(input: &[u8], xof_digest_length: u16, persona: &[u8]) -> Vec<u8> {
30 assert!(xof_digest_length > 0, "Output digest must be of non-zero length");
31 assert!(persona.len() <= 8, "Personalization may be at most 8 characters");
32
33 let xof_digest_length_node_offset = (xof_digest_length as u64) << 32;
35 let input_digest = blake2s_simd::Params::new()
36 .hash_length(32)
37 .node_offset(xof_digest_length_node_offset)
38 .personal(persona)
39 .hash(input);
40
41 let mut output = vec![];
42
43 let num_rounds = xof_digest_length.saturating_add(31) / 32;
44 for node_offset in 0..num_rounds {
45 let is_final_round = node_offset == num_rounds - 1;
47 let has_remainder = xof_digest_length % 32 != 0;
48 let digest_length = match is_final_round && has_remainder {
49 true => (xof_digest_length % 32) as usize,
50 false => 32,
51 };
52
53 output.extend_from_slice(
55 blake2s_simd::Params::new()
56 .hash_length(digest_length)
57 .fanout(0)
58 .max_depth(0)
59 .max_leaf_length(32)
60 .node_offset(xof_digest_length_node_offset | (node_offset as u64))
61 .inner_hash_length(32)
62 .personal(persona)
63 .hash(input_digest.as_bytes())
64 .as_bytes(),
65 );
66 }
67
68 output
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use crate::Blake2Xs;
75 use serde::Deserialize;
76
77 #[derive(Deserialize)]
78 struct Case {
79 hash: String,
80 #[serde(rename = "in")]
81 input: String,
82 key: String,
83 #[serde(rename = "out")]
84 output: String,
85 }
86
87 #[test]
88 fn test_blake2xs() {
89 let vectors: Vec<Case> = serde_json::from_str(include_str!("./resources/blake2-kat.json")).unwrap();
91 for case in vectors.iter().filter(|v| &v.hash == "blake2xs" && v.key.is_empty()) {
92 let input = hex::decode(case.input.as_bytes()).unwrap();
93 let xof_digest_length = u16::try_from(case.output.len()).unwrap() / 2;
94 let output = hex::encode(Blake2Xs::evaluate(&input, xof_digest_length, "".as_bytes()));
95 assert_eq!(output, case.output);
96 }
97 }
98
99 #[test]
100 fn test_blake2s() {
101 let vectors: Vec<Case> = serde_json::from_str(include_str!("./resources/blake2-kat.json")).unwrap();
103 for case in vectors.iter().filter(|v| &v.hash == "blake2s" && v.key.is_empty()) {
104 let input = hex::decode(case.input.as_bytes()).unwrap();
105 let output = hex::encode(blake2s_simd::Params::new().personal(&0u64.to_le_bytes()).hash(&input).as_bytes());
106 assert_eq!(output, case.output);
107 }
108 }
109}