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

const HASH_SIZE: usize = 243;
const STATE_SIZE: usize = HASH_SIZE * 3;

const T: [i8; 11] = [1, 0, -1, 0, 1, -1, 0, 0, -1, 1, 0];

pub type State = [i8; STATE_SIZE];
pub type Hash = [i8; HASH_SIZE];

pub struct Curl {
    idx: [i16; STATE_SIZE + 1],
    state: State,
}

impl Curl {
    /// Constructs a new `Curl`.
    ///
    /// # Examples
    /// ```
    /// use rcurl::Curl;
    ///
    /// let mut c = Curl::new();
    /// ```
    pub fn new() -> Self {
        let mut idx = [0 as i16; STATE_SIZE + 1];
        for i in 0..idx.len() {
            idx[i] = ((i * 364) % 729) as i16;
        }

        Curl { 
            idx: idx, 
            state: [0; STATE_SIZE],
        }
    }

    /// Load the input slice, which should contain trits, and transform it.
    pub fn absorb(&mut self, input: &[i8], offset: usize, size: usize) {
        assert!(offset+size <= input.len());
        for c in input[offset..offset+size].chunks(HASH_SIZE) {
            self.fill_state_array_with_slice(c);
            self.transform();
        }
    }

    pub fn transform(&mut self) {
        let mut state_copy = &mut [0; STATE_SIZE + 1];
        self.fill_state_copy_array(&mut state_copy);

        for _ in 0..27 {
            for i in 0..STATE_SIZE {
                let i = i as usize;
                self.state[i] = T[(state_copy[self.idx[i] as usize] + (state_copy[self.idx[i + 1] as usize] << 2) + 5) as usize];
            }
            self.fill_state_copy_array(&mut state_copy);
        }
    }

    /// Fill the `out` slice, starting at `offset`, with `HASH_SIZE` trits.
    pub fn squeeze_into(&mut self, out: &mut [i8], offset: usize) {
        assert!(offset+HASH_SIZE <= out.len());
        &mut out[offset..offset+HASH_SIZE].copy_from_slice(&self.state[0..HASH_SIZE]);
        self.transform();
    }

    pub fn state(&self) -> State {
        self.state
    }

    pub fn indices(&self) -> [i16; STATE_SIZE + 1] {
        self.idx
    }

    fn fill_state_array_with_slice(&mut self, input: &[i8]) {
        assert!(input.len() <= STATE_SIZE);
        &mut self.state[..input.len()].copy_from_slice(input);
    }

    fn fill_state_copy_array(&mut self, dst: &mut [i8; STATE_SIZE + 1]) {
        &mut dst[..STATE_SIZE].copy_from_slice(&self.state);
    }
}