use super::params::{HashFamily, MAX_N, Params};
use crate::hash::{Digest, ExtendableOutput, Sha256, Shake128, Shake256};
const MAX_PAD: usize = 32;
const PAD_F: u64 = 0;
const PAD_H: u64 = 1;
const PAD_HASH: u64 = 2;
const PAD_PRF: u64 = 3;
const PAD_PRF_KEYGEN: u64 = 4;
fn to_byte(x: u64, outlen: usize, out: &mut [u8]) {
out[..outlen].fill(0);
let mut v = x;
for i in (0..outlen).rev() {
out[i] = (v & 0xff) as u8;
v >>= 8;
}
}
fn core_hash(p: &Params, parts: &[&[u8]], out: &mut [u8]) {
let n = p.n;
match p.family {
HashFamily::Sha2_256 => {
let mut h = Sha256::new();
for part in parts {
h.update(part);
}
let d = h.finalize();
out[..n].copy_from_slice(&d.as_ref()[..n]);
}
HashFamily::Shake128 => {
let mut h = Shake128::new();
for part in parts {
h.update(part);
}
h.finalize_into(&mut out[..n]);
}
HashFamily::Shake256 => {
let mut h = Shake256::new();
for part in parts {
h.update(part);
}
h.finalize_into(&mut out[..n]);
}
}
}
pub(crate) fn prf(p: &Params, key: &[u8], input: &[u8; 32], out: &mut [u8]) {
let mut pad = [0u8; MAX_PAD];
to_byte(PAD_PRF, p.padding_len, &mut pad);
core_hash(p, &[&pad[..p.padding_len], &key[..p.n], input], out);
}
pub(crate) fn prf_keygen(p: &Params, key: &[u8], input: &[u8], out: &mut [u8]) {
let mut pad = [0u8; MAX_PAD];
to_byte(PAD_PRF_KEYGEN, p.padding_len, &mut pad);
core_hash(p, &[&pad[..p.padding_len], &key[..p.n], input], out);
}
pub(crate) fn prf_base(p: &Params, key: &[u8]) -> Option<Sha256> {
if matches!(p.family, HashFamily::Sha2_256) && p.padding_len + p.n == 64 {
let mut pad = [0u8; MAX_PAD];
to_byte(PAD_PRF, p.padding_len, &mut pad);
let mut h = Sha256::new();
h.update(&pad[..p.padding_len]);
h.update(&key[..p.n]);
Some(h)
} else {
None
}
}
pub(crate) fn prf_with(
p: &Params,
base: &Option<Sha256>,
key: &[u8],
input: &[u8; 32],
out: &mut [u8],
) {
match base {
Some(b) => {
let mut h = b.clone();
h.update(input);
let d = h.finalize();
out[..p.n].copy_from_slice(&d[..p.n]);
}
None => prf(p, key, input, out),
}
}
pub(crate) fn f(p: &Params, key: &[u8], masked: &[u8], out: &mut [u8]) {
let mut pad = [0u8; MAX_PAD];
to_byte(PAD_F, p.padding_len, &mut pad);
core_hash(
p,
&[&pad[..p.padding_len], &key[..p.n], &masked[..p.n]],
out,
);
}
pub(crate) fn h(p: &Params, key: &[u8], masked: &[u8], out: &mut [u8]) {
let mut pad = [0u8; MAX_PAD];
to_byte(PAD_H, p.padding_len, &mut pad);
core_hash(
p,
&[&pad[..p.padding_len], &key[..p.n], &masked[..2 * p.n]],
out,
);
}
pub(crate) fn h_msg(p: &Params, r: &[u8], root: &[u8], idx: u64, msg: &[u8], out: &mut [u8]) {
let mut pad = [0u8; MAX_PAD];
to_byte(PAD_HASH, p.padding_len, &mut pad);
let mut idx_bytes = [0u8; MAX_N];
to_byte(idx, p.n, &mut idx_bytes);
core_hash(
p,
&[
&pad[..p.padding_len],
&r[..p.n],
&root[..p.n],
&idx_bytes[..p.n],
msg,
],
out,
);
}