use digest::Digest;
use num_bigint::BigUint;
use crate::group::Group;
pub fn compute_k<D: Digest>(group: &Group) -> BigUint {
let n_bytes = group.n.to_bytes_be();
let g_bytes = group.g.to_bytes_be();
let padding_g_bytes = zero_pad(g_bytes, group.length_n / 8);
let mut hasher = D::new();
hasher.update(&n_bytes);
hasher.update(&padding_g_bytes);
let hash = hasher.finalize();
BigUint::from_bytes_be(&hash)
}
pub fn zero_pad(mut source: Vec<u8>, length: usize) -> Vec<u8> {
if source.len() >= length {
source
} else {
let mut padded = vec![0u8; length - source.len()];
padded.append(&mut source);
padded
}
}
pub fn compute_client_proof<D: Digest>(
group: &Group,
username: &[u8],
salt: &[u8],
public_client_key: &BigUint,
public_server_key: &BigUint,
session_key: &BigUint,
) -> Vec<u8> {
let n_hash = D::digest(group.n.to_bytes_be());
let g_hash = D::digest(group.g.to_bytes_be());
let xor_hash: Vec<u8> = n_hash
.iter()
.zip(g_hash.iter())
.map(|(a, b)| a ^ b)
.collect();
let i_hash = D::digest(username);
let mut hasher = D::new();
hasher.update(&xor_hash);
hasher.update(&i_hash);
hasher.update(salt);
hasher.update(public_client_key.to_bytes_be());
hasher.update(public_server_key.to_bytes_be());
hasher.update(session_key.to_bytes_be());
hasher.finalize().to_vec()
}
pub fn compute_server_proof<D: Digest>(
public_client_key: &BigUint,
client_proof: &[u8],
session_key: &BigUint,
) -> Vec<u8> {
let mut hasher = D::new();
hasher.update(public_client_key.to_bytes_be());
hasher.update(client_proof);
hasher.update(session_key.to_bytes_be());
hasher.finalize().to_vec()
}