mod core;
pub use core::{
apply_poly1305_mod_p, apply_poly1305_pad, calculate_poly1305_d_values,
calculate_poly1305_h_values, finalize_poly1305_hash, poly1305_hash_to_tag,
};
use crate::AEADAlgorithm;
use super::{AlgorithmKeyInit, AlgorithmProcess};
#[derive(Default)]
pub struct Poly1305 {
r: [u32; 5],
h: [u32; 5],
pad: [u32; 4],
}
impl Poly1305 {
pub fn new() -> Self {
Self::default()
}
fn compute_block(&mut self, block: [u8; 16], partial: bool) {
let hibit = if partial { 0 } else { 1 << 24 };
let (r0, r1, r2, r3, r4) = (self.r[0], self.r[1], self.r[2], self.r[3], self.r[4]);
let (s1, s2, s3, s4) = (r1 * 5, r2 * 5, r3 * 5, r4 * 5);
let (h0, h1, h2, h3, h4) = calculate_poly1305_h_values(&block, hibit);
let (mut d0, mut d1, mut d2, mut d3, mut d4) =
calculate_poly1305_d_values(h0, h1, h2, h3, h4, r0, r1, r2, r3, r4, s1, s2, s3, s4);
apply_poly1305_mod_p(&mut self.h, &mut d0, &mut d1, &mut d2, &mut d3, &mut d4)
}
fn finalize(&mut self) -> [u8; 16] {
finalize_poly1305_hash(&mut self.h);
apply_poly1305_pad(&mut self.h, self.pad);
poly1305_hash_to_tag(&self.h)
}
}
impl AlgorithmKeyInit for Poly1305 {
fn init(&mut self, key: &[u8]) {
self.r[0] = u32::from_le_bytes([key[0], key[1], key[2], key[3]]) & 0x3ff_ffff;
self.r[1] = u32::from_le_bytes([key[3], key[4], key[5], key[6]]) & 0x3ff_ff03;
self.r[2] = u32::from_le_bytes([key[6], key[7], key[8], key[9]]) & 0x3ff_c0ff;
self.r[3] = u32::from_le_bytes([key[9], key[10], key[11], key[12]]) & 0x3f0_3fff;
self.r[4] = u32::from_le_bytes([key[12], key[13], key[14], key[15]]) & 0x00f_ffff;
self.pad[0] = u32::from_le_bytes([key[16], key[17], key[18], key[19]]);
self.pad[1] = u32::from_le_bytes([key[20], key[21], key[22], key[23]]);
self.pad[2] = u32::from_le_bytes([key[24], key[25], key[26], key[27]]);
self.pad[3] = u32::from_le_bytes([key[28], key[29], key[30], key[31]]);
}
}
impl AlgorithmProcess for Poly1305 {
fn process(&mut self, data: &[u8]) -> Vec<u8> {
let blocks = data.chunks_exact(16);
let partial = blocks.remainder();
for block in blocks {
self.compute_block(block.try_into().unwrap(), false);
}
if !partial.is_empty() {
let mut block = [0u8; 16];
block[..partial.len()].copy_from_slice(partial);
block[partial.len()] = 1;
self.compute_block(block, true);
}
self.finalize().to_vec()
}
}
impl AEADAlgorithm for Poly1305 {}
pub struct SignedEnvelope {
pub header: Vec<u8>,
pub data: Vec<u8>,
pub mac: Vec<u8>,
}
impl SignedEnvelope {
pub fn new(header: Vec<u8>, data: Vec<u8>, mac: Vec<u8>) -> Self {
Self { header, data, mac }
}
}
impl From<Vec<u8>> for SignedEnvelope {
fn from(bytes: Vec<u8>) -> Self {
let mut offset = 0;
let header_len = u32::from_be_bytes(bytes[offset..offset + 4].try_into().unwrap()) as usize;
offset += 4;
let header = bytes[offset..offset + header_len].to_vec();
offset += header_len;
let data_len = u32::from_be_bytes(bytes[offset..offset + 4].try_into().unwrap()) as usize;
offset += 4;
let data = bytes[offset..offset + data_len].to_vec();
offset += data_len;
let mac = bytes[offset..offset + 16].to_vec();
if mac.len() != 16 {
panic!("Unexpected bytes length");
}
Self::new(header, data, mac)
}
}
impl From<SignedEnvelope> for Vec<u8> {
fn from(envelope: SignedEnvelope) -> Self {
let mut bytes = Vec::new();
bytes.extend(&(envelope.header.len() as u32).to_be_bytes());
bytes.extend(&envelope.header);
bytes.extend(&(envelope.data.len() as u32).to_be_bytes());
bytes.extend(&envelope.data);
bytes.extend(&envelope.mac);
bytes
}
}