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
#![no_std]
extern crate byte_tools;
extern crate generic_array;
use generic_array::{GenericArray, ArrayLength};
use byte_tools::{copy_memory, zero};

type Block<N> = GenericArray<u8, N>;

#[derive(Clone, Copy)]
pub struct DigestBuffer<N: ArrayLength<u8>> where N::ArrayType: Copy {
    buffer: GenericArray<u8, N>,
    buffer_idx: usize,
}

impl <N: ArrayLength<u8>> DigestBuffer<N> where N::ArrayType: Copy {
    pub fn new() -> DigestBuffer<N> {
        DigestBuffer::<N> {
            buffer: Default::default(),
            buffer_idx: 0,
        }
    }

    pub fn input<F: FnMut(&Block<N>)>(&mut self, input: &[u8], mut func: F) {
        let mut i = 0;
        let size = self.size();
        // 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.buffer_idx != 0 {
            let buffer_remaining = size - self.buffer_idx;
            if input.len() >= buffer_remaining {
                    copy_memory(
                        &input[..buffer_remaining],
                        &mut self.buffer[self.buffer_idx..size]);
                self.buffer_idx = 0;
                func(&self.buffer);
                i += buffer_remaining;
            } else {
                copy_memory(
                    input,
                    &mut self.buffer[self.buffer_idx..][..input.len()]);
                self.buffer_idx += input.len();
                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() - i >= size {
            let block = GenericArray::from_slice(&input[i..i + size]);
            func(block);
            i += size;
        }

        // 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.
        let input_remaining = input.len() - i;
        copy_memory(
            &input[i..],
            &mut self.buffer[0..input_remaining]);
        self.buffer_idx += input_remaining;
    }

    pub fn reset(&mut self) {
        self.buffer_idx = 0;
    }

    pub fn zero_until(&mut self, idx: usize) {
        assert!(idx >= self.buffer_idx);
        zero(&mut self.buffer[self.buffer_idx..idx]);
        self.buffer_idx = idx;
    }

    pub fn next(&mut self, len: usize) -> &mut [u8] {
        self.buffer_idx += len;
        &mut self.buffer[self.buffer_idx - len..self.buffer_idx]
    }

    pub fn full_buffer(& mut self) -> &Block<N> {
        assert!(self.buffer_idx == self.size());
        self.buffer_idx = 0;
        &self.buffer
    }

    pub fn current_buffer(&mut self) -> &[u8] {
        let tmp = self.buffer_idx;
        self.buffer_idx = 0;
        &self.buffer[..tmp]
    }

    pub fn position(&self) -> usize { self.buffer_idx }

    pub fn remaining(&self) -> usize { self.size() - self.buffer_idx }

    pub fn standard_padding<F: FnMut(&Block<N>)>(&mut self, rem: usize, mut func: F) {
        let size = self.size();

        self.next(1)[0] = 128;

        if self.remaining() < rem {
            self.zero_until(size);
            func(self.full_buffer());
        }

        self.zero_until(size - rem);
    }

    pub fn size(&self) -> usize {
         N::to_usize()
    }
}

impl <N: ArrayLength<u8>> Default for DigestBuffer<N> where N::ArrayType: Copy {
    fn default() -> Self { Self::new() }
}