digest_buffer/
lib.rs

1#![no_std]
2extern crate byte_tools;
3extern crate generic_array;
4use generic_array::{GenericArray, ArrayLength};
5use byte_tools::zero;
6
7type Block<N> = GenericArray<u8, N>;
8
9#[derive(Clone, Copy)]
10pub struct DigestBuffer<N: ArrayLength<u8>> where N::ArrayType: Copy {
11    buffer: GenericArray<u8, N>,
12    pos: usize,
13}
14
15impl <N: ArrayLength<u8>> DigestBuffer<N> where N::ArrayType: Copy {
16    pub fn new() -> DigestBuffer<N> {
17        DigestBuffer::<N> {
18            buffer: Default::default(),
19            pos: 0,
20        }
21    }
22
23    pub fn input<F: FnMut(&Block<N>)>(&mut self, mut input: &[u8], mut func: F) {
24        // If there is already data in the buffer, copy as much as we can
25        // into it and process the data if the buffer becomes full.
26        if self.pos != 0 {
27            let rem = N::to_usize() - self.pos;
28
29            if input.len() >= rem {
30                let (l, r) = input.split_at(rem);
31                input = r;
32                self.buffer[self.pos..].copy_from_slice(l);
33                self.pos = 0;
34                func(&self.buffer);
35            } else {
36                let end = self.pos + input.len();
37                self.buffer[self.pos..end].copy_from_slice(input);
38                self.pos = end;
39                return;
40            }
41        }
42
43        // While we have at least a full buffer size chunks's worth of data,
44        // process that data without copying it into the buffer
45        while input.len() >= N::to_usize() {
46            let (l, r) = input.split_at(N::to_usize());
47            input = r;
48            let block = GenericArray::from_slice(&l);
49            func(block);
50        }
51
52        // Copy any input data into the buffer. At this point in the method,
53        // the ammount of data left in the input vector will be less than
54        // the buffer size and the buffer will be empty.
55        self.buffer[..input.len()].copy_from_slice(input);
56        self.pos += input.len();
57    }
58
59    pub fn reset(&mut self) {
60        self.pos = 0;
61    }
62
63    pub fn zero_until(&mut self, idx: usize) {
64        assert!(idx >= self.pos);
65        zero(&mut self.buffer[self.pos..idx]);
66        self.pos = idx;
67    }
68
69    pub fn next(&mut self, len: usize) -> &mut [u8] {
70        self.pos += len;
71        &mut self.buffer[self.pos - len..self.pos]
72    }
73
74    pub fn full_buffer(& mut self) -> &Block<N> {
75        assert!(self.pos == self.size());
76        self.pos = 0;
77        &self.buffer
78    }
79
80    pub fn current_buffer(&mut self) -> &[u8] {
81        let tmp = self.pos;
82        self.pos = 0;
83        &self.buffer[..tmp]
84    }
85
86    pub fn position(&self) -> usize { self.pos }
87
88    pub fn remaining(&self) -> usize { self.size() - self.pos }
89
90    pub fn standard_padding<F: FnMut(&Block<N>)>(&mut self, rem: usize, mut func: F) {
91        let size = self.size();
92
93        self.next(1)[0] = 128;
94
95        if self.remaining() < rem {
96            self.zero_until(size);
97            func(self.full_buffer());
98        }
99
100        self.zero_until(size - rem);
101    }
102
103    pub fn size(&self) -> usize {
104         N::to_usize()
105    }
106}
107
108impl <N: ArrayLength<u8>> Default for DigestBuffer<N> where N::ArrayType: Copy {
109    fn default() -> Self { Self::new() }
110}