raycrypt 0.3.1

Encrypt at the speed of light
Documentation
use crate::utils::*;
use zeroize::{Zeroize, ZeroizeOnDrop};

#[derive(Zeroize, ZeroizeOnDrop)]
pub struct Poly1305 {
    r: [u32; 5],
    h: [u32; 5],
    pad: [u32; 4],
    buf: [u8; 16],
    leftover: usize,
}

impl Poly1305 {
    fn block(&mut self, m: &[u8], partial: bool) {
        let hibit: u32 = if partial { 0 } else { 1 << 24 };
        let s = [self.r[1] * 5, self.r[2] * 5, self.r[3] * 5, self.r[4] * 5];

        self.h[0] += (from_le_bytes(&m[0..4])) & 0x3ffffff;
        self.h[1] += (from_le_bytes(&m[3..7]) >> 2) & 0x3ffffff;
        self.h[2] += (from_le_bytes(&m[6..10]) >> 4) & 0x3ffffff;
        self.h[3] += (from_le_bytes(&m[9..13]) >> 6) & 0x3ffffff;
        self.h[4] += (from_le_bytes(&m[12..16]) >> 8) | hibit;

        let mut d = [0u64; 5];

        for i in 0..5 {
            for j in 0..5 {
                let num = if j > i { s[4 - (j - i)] } else { self.r[i - j] };
                d[i] += self.h[j] as u64 * num as u64;
            }
        }

        let mut c: u32;

        for i in 0..4 {
            self.h[i] = d[i] as u32 & 0x3ffffff;
            c = (d[i] >> 26) as u32;
            d[i + 1] += c as u64;
        }

        c = (d[4] >> 26) as u32;
        self.h[4] = d[4] as u32 & 0x3ff_ffff;
        self.h[0] += c * 5;

        c = self.h[0] >> 26;
        self.h[0] &= 0x3ff_ffff;
        self.h[1] += c;
    }

    fn finish(&mut self) -> [u8; 16] {
        if self.leftover == 16 {
            self.block(&self.buf.clone(), false);
        }
        else if self.leftover != 0 {
            self.buf[self.leftover] = 1;
            self.block(&self.buf.clone(), true);
        }

        let mut h = self.h.clone();

        let mut c: u32 = 0;

        for i in 1..5 {
            h[i] += c;
            c = h[i] >> 26;
            h[i] &= 0x3ffffff;
        }

        h[0] += c * 5;
        c = h[0] >> 26;
        h[0] = h[0] & 0x3ffffff;
        h[1] += c;

        let mut g = [0u32; 5];

        let mut c = 5u32;

        for i in 0..4 {
            g[i] = h[i].wrapping_add(c);
            c = g[i] >> 26;
            g[i] &= 0x3ffffff;
        }

        g[4] = h[4].wrapping_add(c).wrapping_sub(1 << 26);

        let mut mask = (g[4] >> (32 - 1)).wrapping_sub(1);

        for i in g.iter_mut() {
            *i &= mask;
        }

        mask = !mask;

        for i in 0..5 {
            h[i] = (h[i] & mask) | g[i];
        }

        h[0] |= h[1] << 26;
        h[1] = (h[1] >> 6) | (h[2] << 20);
        h[2] = (h[2] >> 12) | (h[3] << 14);
        h[3] = (h[3] >> 18) | (h[4] << 8);

        let mut f: u64;
        f = h[0] as u64 + self.pad[0] as u64;
        h[0] = f as u32;
        f = h[1] as u64 + self.pad[1] as u64 + (f >> 32);
        h[1] = f as u32;
        f = h[2] as u64 + self.pad[2] as u64 + (f >> 32);
        h[2] = f as u32;
        f = h[3] as u64 + self.pad[3] as u64 + (f >> 32);
        h[3] = f as u32;

        let mut output = [0u8; 16];

        for i in 0..4 {
            output[i * 4..(i + 1) * 4].clone_from_slice(&h[i].to_le_bytes());
        }

        output
    }
}

impl Poly1305 {
    pub fn new(key: [u8; 32]) -> Poly1305 {
        let mut r = [0u32; 5];
        r[0] = (from_le_bytes(&key[0..4])) & 0x3ffffff;
        r[1] = (from_le_bytes(&key[3..7]) >> 2) & 0x3ffff03;
        r[2] = (from_le_bytes(&key[6..10]) >> 4) & 0x3ffc0ff;
        r[3] = (from_le_bytes(&key[9..13]) >> 6) & 0x3f03fff;
        r[4] = (from_le_bytes(&key[12..16]) >> 8) & 0x00fffff;

        let mut pad = [0u32; 4];
        pad[0] = from_le_bytes(&key[16..20]);
        pad[1] = from_le_bytes(&key[20..24]);
        pad[2] = from_le_bytes(&key[24..28]);
        pad[3] = from_le_bytes(&key[28..32]);

        let h = [0u32; 5];
        let buf = [0u8; 16];
        let leftover = 0usize;

        Poly1305 {
            r,
            h,
            pad,
            buf,
            leftover,
        }
    }

    pub fn update(&mut self, data: &[u8]) {
        for chunk in data.chunks(16) {
            let mut m = [0u8; 16];
            m[..chunk.len()].clone_from_slice(chunk);
            self.block(&m, false);
        }
    }

    pub fn update_unpadded(&mut self, data: &[u8]) {
        for chunk in data.chunks(16) {
            if chunk.len() == 16 {
                self.block(chunk, false);
            } else {
                while (16 - self.leftover) < chunk.len() {
                    let x = [&self.buf[self.leftover..], &chunk[..(16 - self.leftover)]].concat();
                    self.block(&x, false);
                    self.leftover = 0;
                    self.buf.zeroize();
                }

                self.buf[self.leftover..self.leftover + (chunk.len() % 16)].copy_from_slice(&chunk[..(chunk.len() % 16)]);
                self.leftover += chunk.len();
            }
        }
    }

    pub fn tag(&mut self) -> [u8; 16] {
        let output = self.finish();
        self.zeroize();

        output
    }

    pub fn verify(&mut self, other: &[u8]) -> bool {
        const_time_eq(&self.tag(), other)
    }
}