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
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#![no_std]
#[macro_use]
extern crate arrayref;
extern crate byte_tools;

use byte_tools::{zero, write_u64_le};

mod paddings;

pub use paddings::*;

macro_rules! impl_buffer {
    ($name:ident, $len:expr) => {

        pub struct $name {
            buffer: [u8; $len],
            pos: usize,
        }

        impl Copy for $name {}

        impl Clone for $name {
            fn clone(&self) -> Self {
                *self
            }
        }

        impl Default for $name {
            fn default() -> Self {
                $name {buffer: [0; $len], pos: 0}
            }
        }

        impl $name {
            #[inline]
            pub fn input<F: FnMut(&[u8; $len])>(&mut self, mut input: &[u8], mut func: F) {
                // If there is already data in the buffer, copy as much as we can
                // into it and process the data if the buffer becomes full.
                if self.pos != 0 {
                    let rem = self.remaining();

                    if input.len() >= rem {
                        let (l, r) = input.split_at(rem);
                        input = r;
                        self.buffer[self.pos..].copy_from_slice(l);
                        self.pos = 0;
                        func(&self.buffer);
                    } else {
                        let end = self.pos + input.len();
                        self.buffer[self.pos..end].copy_from_slice(input);
                        self.pos = end;
                        return;
                    }
                }

                // While we have at least a full buffer size chunks's worth of data,
                // process that data without copying it into the buffer
                while input.len() >= self.size() {
                    let (l, r) = input.split_at(self.size());
                    input = r;
                    func(array_ref!(l, 0, $len));
                }

                // Copy any input data into the buffer. At this point in the method,
                // the ammount of data left in the input vector will be less than
                // the buffer size and the buffer will be empty.
                self.buffer[..input.len()].copy_from_slice(input);
                self.pos = input.len();
            }

            #[inline]
            fn digest_pad<F>(&mut self, up_to: usize, mut func: &mut F)
                where F: FnMut(&[u8; $len])
            {
                self.buffer[self.pos] = 0x80;
                self.pos += 1;

                zero(&mut self.buffer[self.pos..]);

                if self.remaining() < up_to {
                    func(&self.buffer);
                    zero(&mut self.buffer[..self.pos]);
                }
            }

            #[inline]
            /// Will pad message with message length in big-endian format
            pub fn len_padding<F>(&mut self, data_len: u64, mut func: F)
                where F: FnMut(&[u8; $len])
            {
                self.digest_pad(8, &mut func);
                let s = self.size();
                write_u64_le(&mut self.buffer[s-8..], data_len);
                func(&self.buffer);
                self.pos = 0;
            }

            #[inline]
            pub fn len_padding_u128<F>(&mut self, hi: u64, lo: u64, mut func: F)
                where F: FnMut(&[u8; $len])
            {
                self.digest_pad(16, &mut func);
                let s = self.size();
                write_u64_le(&mut self.buffer[s-16..s-8], hi);
                write_u64_le(&mut self.buffer[s-8..], lo);
                func(&self.buffer);
                self.pos = 0;
            }

            #[inline]
            pub fn pad_with<P: Padding>(&mut self) -> &mut [u8; $len] {
                P::pad(&mut self.buffer[..], self.pos);
                self.pos = 0;
                &mut self.buffer
            }

            #[inline]
            pub fn size(&self) -> usize {
                $len
            }

            #[inline]
            pub fn position(&self) -> usize {
                self.pos
            }

            #[inline]
            pub fn remaining(&self) -> usize {
                self.size() - self.pos
            }
        }
    }
}

impl_buffer!(BlockBuffer256, 32);
impl_buffer!(BlockBuffer512, 64);
impl_buffer!(BlockBuffer1024, 128);