use alloc::vec::Vec;
use bigint::{
BoxedUint, Resize,
modular::{BoxedMontyForm, BoxedMontyParams},
};
use digest::{Digest, Output};
#[must_use]
pub fn compute_u<D: Digest>(a_pub: &[u8], b_pub: &[u8]) -> BoxedUint {
let mut u = D::new();
u.update(a_pub);
u.update(b_pub);
BoxedUint::from_be_slice_vartime(&u.finalize())
}
#[must_use]
pub fn compute_u_padded<D: Digest>(g: &BoxedMontyForm, a_pub: &[u8], b_pub: &[u8]) -> BoxedUint {
let n = g.params().modulus().to_be_bytes();
let mut buf_a = vec![0u8; n.len()];
let mut buf_b = vec![0u8; n.len()];
let l_a = n.len() - a_pub.len();
let l_b = n.len() - b_pub.len();
buf_a[l_a..].copy_from_slice(a_pub);
buf_b[l_b..].copy_from_slice(b_pub);
let mut u = D::new();
u.update(&buf_a);
u.update(&buf_b);
BoxedUint::from_be_slice_vartime(&u.finalize())
}
#[must_use]
pub fn compute_k<D: Digest>(g: &BoxedMontyForm) -> BoxedUint {
let n = g.params().modulus().to_be_bytes();
let g_bytes = g.retrieve().to_be_bytes();
let mut buf = vec![0u8; n.len()];
let l = n.len() - g_bytes.len();
buf[l..].copy_from_slice(&g_bytes);
let mut d = D::new();
d.update(&n);
d.update(&buf);
BoxedUint::from_be_slice_vartime(d.finalize().as_slice())
}
#[must_use]
pub fn compute_hash_n_xor_hash_pad_g<D: Digest>(g: &BoxedMontyForm) -> Vec<u8> {
let n = g.params().modulus().to_be_bytes();
let g_bytes = g.retrieve().to_be_bytes();
let mut buf = vec![0u8; n.len()];
let l = n.len() - g_bytes.len();
buf[l..].copy_from_slice(&g_bytes);
let h_n = compute_hash::<D>(&n).to_vec();
let h_g = compute_hash::<D>(&buf).to_vec();
h_n.iter()
.zip(h_g.iter())
.map(|(&x1, &x2)| x1 ^ x2)
.collect()
}
#[must_use]
pub fn compute_hash_n_xor_hash_g<D: Digest>(g: &BoxedMontyForm) -> Vec<u8> {
let n = g.params().modulus().to_be_bytes();
let g_bytes = g.retrieve().to_be_bytes();
let first = g_bytes
.iter()
.position(|&b| b != 0)
.unwrap_or(g_bytes.len().saturating_sub(1));
let g_bytes = &g_bytes[first..];
let h_n = compute_hash::<D>(&n);
let h_g = compute_hash::<D>(g_bytes);
h_n.iter().zip(h_g.iter()).map(|(&a, &b)| a ^ b).collect()
}
#[must_use]
pub fn compute_hash<D: Digest>(data: &[u8]) -> Output<D> {
let mut d = D::new();
d.update(data);
d.finalize()
}
#[must_use]
pub fn compute_m1_rfc5054<D: Digest>(
g: &BoxedMontyForm,
g_no_pad: bool,
username: &[u8],
salt: &[u8],
a_pub: &[u8],
b_pub: &[u8],
key: &[u8],
) -> Output<D> {
let mut d = D::new();
if g_no_pad {
d.update(compute_hash_n_xor_hash_g::<D>(g));
} else {
d.update(compute_hash_n_xor_hash_pad_g::<D>(g));
}
d.update(compute_hash::<D>(username));
d.update(salt);
d.update(a_pub);
d.update(b_pub);
d.update(key);
d.finalize()
}
#[must_use]
pub fn compute_m1_legacy<D: Digest>(a_pub: &[u8], b_pub: &[u8], key: &[u8]) -> Output<D> {
let mut d = D::new();
d.update(a_pub);
d.update(b_pub);
d.update(key);
d.finalize()
}
#[must_use]
pub fn compute_m2<D: Digest>(a_pub: &[u8], m1: &Output<D>, key: &[u8]) -> Output<D> {
let mut d = D::new();
d.update(a_pub);
d.update(m1);
d.update(key);
d.finalize()
}
pub(crate) fn monty_form(x: &BoxedUint, n: &BoxedMontyParams) -> BoxedMontyForm {
let precision = n.modulus().bits_precision();
BoxedMontyForm::new(x.resize(precision), n)
}