ark_ff/fields/field_hashers/expander/
mod.rs1use ark_std::vec::Vec;
5use digest::{DynDigest, ExtendableOutput, Update};
6pub trait Expander {
7 fn construct_dst_prime(&self) -> Vec<u8>;
8 fn expand(&self, msg: &[u8], length: usize) -> Vec<u8>;
9}
10const MAX_DST_LENGTH: usize = 255;
11
12const LONG_DST_PREFIX: [u8; 17] = [
13 0x48, 0x32, 0x43, 0x2d, 0x4f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x5a, 0x45, 0x2d, 0x44, 0x53, 0x54,
15 0x2d,
16];
17
18pub(super) struct ExpanderXof<T: Update + Clone + ExtendableOutput> {
19 pub(super) xofer: T,
20 pub(super) dst: Vec<u8>,
21 pub(super) k: usize,
22}
23
24impl<T: Update + Clone + ExtendableOutput> Expander for ExpanderXof<T> {
25 fn construct_dst_prime(&self) -> Vec<u8> {
26 let mut dst_prime = if self.dst.len() > MAX_DST_LENGTH {
27 let mut xofer = self.xofer.clone();
28 xofer.update(&LONG_DST_PREFIX.clone());
29 xofer.update(&self.dst);
30 xofer.finalize_boxed((2 * self.k + 7) >> 3).to_vec()
31 } else {
32 self.dst.clone()
33 };
34 dst_prime.push(dst_prime.len() as u8);
35 dst_prime
36 }
37 fn expand(&self, msg: &[u8], n: usize) -> Vec<u8> {
38 let dst_prime = self.construct_dst_prime();
39 let lib_str = &[((n >> 8) & 0xFF) as u8, (n & 0xFF) as u8];
40
41 let mut xofer = self.xofer.clone();
42 xofer.update(msg);
43 xofer.update(lib_str);
44 xofer.update(&dst_prime);
45 xofer.finalize_boxed(n).to_vec()
46 }
47}
48
49pub(super) struct ExpanderXmd<T: DynDigest + Clone> {
50 pub(super) hasher: T,
51 pub(super) dst: Vec<u8>,
52 pub(super) block_size: usize,
53}
54
55impl<T: DynDigest + Clone> Expander for ExpanderXmd<T> {
56 fn construct_dst_prime(&self) -> Vec<u8> {
57 let mut dst_prime = if self.dst.len() > MAX_DST_LENGTH {
58 let mut hasher = self.hasher.clone();
59 hasher.update(&LONG_DST_PREFIX);
60 hasher.update(&self.dst);
61 hasher.finalize_reset().to_vec()
62 } else {
63 self.dst.clone()
64 };
65 dst_prime.push(dst_prime.len() as u8);
66 dst_prime
67 }
68 fn expand(&self, msg: &[u8], n: usize) -> Vec<u8> {
69 let mut hasher = self.hasher.clone();
70 let b_len = hasher.output_size();
72 let ell = (n + (b_len - 1)) / b_len;
73 assert!(
74 ell <= 255,
75 "The ratio of desired output to the output size of hash function is too large!"
76 );
77
78 let dst_prime = self.construct_dst_prime();
79 let z_pad: Vec<u8> = vec![0; self.block_size];
80 assert!(n < (1 << 16), "Length should be smaller than 2^16");
84 let lib_str: [u8; 2] = (n as u16).to_be_bytes();
85
86 hasher.update(&z_pad);
87 hasher.update(msg);
88 hasher.update(&lib_str);
89 hasher.update(&[0u8]);
90 hasher.update(&dst_prime);
91 let b0 = hasher.finalize_reset();
92
93 hasher.update(&b0);
94 hasher.update(&[1u8]);
95 hasher.update(&dst_prime);
96 let mut bi = hasher.finalize_reset();
97
98 let mut uniform_bytes: Vec<u8> = Vec::with_capacity(n);
99 uniform_bytes.extend_from_slice(&bi);
100 for i in 2..=ell {
101 for (l, r) in b0.iter().zip(bi.iter()) {
103 hasher.update(&[*l ^ *r]);
104 }
105 hasher.update(&[i as u8]);
106 hasher.update(&dst_prime);
107 bi = hasher.finalize_reset();
108 uniform_bytes.extend_from_slice(&bi);
109 }
110 uniform_bytes[0..n].to_vec()
111 }
112}
113
114#[cfg(all(test, feature = "std"))]
115mod tests;