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
86
87
88
use crate::Vec;
use ark_std::convert::TryFrom;
use blake2::{Blake2s as B2s, VarBlake2s};
use digest::Digest;

use super::PRF;
use crate::CryptoError;

#[cfg(feature = "r1cs")]
pub mod constraints;

#[derive(Clone)]
pub struct Blake2s;

impl PRF for Blake2s {
    type Input = [u8; 32];
    type Output = [u8; 32];
    type Seed = [u8; 32];

    fn evaluate(seed: &Self::Seed, input: &Self::Input) -> Result<Self::Output, CryptoError> {
        let eval_time = start_timer!(|| "Blake2s::Eval");
        let mut h = B2s::new();
        h.update(seed.as_ref());
        h.update(input.as_ref());
        let mut result = [0u8; 32];
        result.copy_from_slice(&h.finalize());
        end_timer!(eval_time);
        Ok(result)
    }
}

#[derive(Clone)]
pub struct Blake2sWithParameterBlock {
    pub digest_length: u8,
    pub key_length: u8,
    pub fan_out: u8,
    pub depth: u8,
    pub leaf_length: u32,
    pub node_offset: u32,
    pub xof_digest_length: u16,
    pub node_depth: u8,
    pub inner_length: u8,
    pub salt: [u8; 8],
    pub personalization: [u8; 8],
}

impl Blake2sWithParameterBlock {
    pub fn parameters(&self) -> [u32; 8] {
        let mut parameters = [0; 8];
        parameters[0] = u32::from_le_bytes([
            self.digest_length,
            self.key_length,
            self.fan_out,
            self.depth,
        ]);
        parameters[1] = self.leaf_length;
        parameters[2] = self.node_offset;
        parameters[3] = u32::from_le_bytes([
            self.xof_digest_length as u8,
            (self.xof_digest_length >> 8) as u8,
            self.node_depth,
            self.inner_length,
        ]);

        let salt_bytes_1 = <[u8; 4]>::try_from(&self.salt[0..4]).unwrap();
        let salt_bytes_2 = <[u8; 4]>::try_from(&self.salt[4..8]).unwrap();
        let personalization_bytes_1 = <[u8; 4]>::try_from(&self.personalization[0..4]).unwrap();
        let personalization_bytes_2 = <[u8; 4]>::try_from(&self.personalization[4..8]).unwrap();

        parameters[4] = u32::from_le_bytes(salt_bytes_1);
        parameters[5] = u32::from_le_bytes(salt_bytes_2);
        parameters[6] = u32::from_le_bytes(personalization_bytes_1);
        parameters[7] = u32::from_le_bytes(personalization_bytes_2);

        parameters
    }

    pub fn evaluate(&self, input: &[u8]) -> Vec<u8> {
        use digest::*;
        let eval_time = start_timer!(|| "Blake2sWithParameterBlock::Eval");
        let mut h = VarBlake2s::with_parameter_block(&self.parameters());
        h.update(input.as_ref());
        end_timer!(eval_time);
        let mut buf = Vec::with_capacity(digest::VariableOutput::output_size(&h));
        h.finalize_variable(|res| buf.extend_from_slice(res));
        buf
    }
}