use super::Error;
use super::params::{MAX_PARTIES, ThresholdParams44, sharing_pattern};
use purecrypto::mldsa::hazmat::{self, Poly};
use std::collections::HashMap;
const K: usize = 4; const L: usize = 4;
#[derive(Clone)]
pub struct Share44 {
pub s1: [Poly; L],
pub s2: [Poly; K],
pub s1h: [Poly; L],
pub s2h: [Poly; K],
}
#[derive(Clone)]
pub struct Key44 {
pub id: u8,
pub rho: [u8; 32],
pub tr: [u8; 64],
pub t1: [Poly; K],
pub shares: HashMap<u8, Share44>,
}
impl Key44 {
pub fn matrix(&self) -> Vec<Poly> {
expand_matrix(&self.rho)
}
pub fn validate(&self) -> Result<(), Error> {
if self.shares.is_empty() {
return Err(Error::Validation("key has no shares".into()));
}
for &mask in self.shares.keys() {
if mask & (1 << self.id) == 0 {
return Err(Error::Validation("share mask excludes own id".into()));
}
}
Ok(())
}
pub fn recover_share(
&self,
act: u8,
params: &ThresholdParams44,
) -> Result<([Poly; L], [Poly; K]), Error> {
let mut s1h = [Poly::zero(); L];
let mut s2h = [Poly::zero(); K];
if params.t == params.n {
let sh = self
.shares
.values()
.next()
.ok_or_else(|| Error::Validation("recover_share(t==n): no shares".into()))?;
return Ok((sh.s1h, sh.s2h));
}
let pattern = sharing_pattern(params.t, params.n)
.ok_or_else(|| Error::Validation("no sharing pattern for (t,n)".into()))?;
let mut perm = [0u8; MAX_PARTIES];
let (mut i1, mut i2) = (0u8, params.t);
let mut currenti: i32 = -1;
for j in 0..params.n {
if j == self.id {
currenti = i1 as i32;
}
if act & (1 << j) != 0 {
perm[i1 as usize] = j;
i1 += 1;
} else {
perm[i2 as usize] = j;
i2 += 1;
}
}
if currenti < 0 || currenti >= params.t as i32 {
return Err(Error::Validation(
"this key is not in the signing set".into(),
));
}
let pattern_for_me = pattern[currenti as usize];
for &u in pattern_for_me {
let mut u_real = 0u8;
for i in 0..params.n {
if u & (1 << i) != 0 {
u_real |= 1 << perm[i as usize];
}
}
let share = self
.shares
.get(&u_real)
.ok_or_else(|| Error::Validation("missing share in sharing pattern".into()))?;
for j in 0..L {
s1h[j] = s1h[j].add(&share.s1h[j]);
}
for j in 0..K {
s2h[j] = s2h[j].add(&share.s2h[j]);
}
}
Ok((s1h, s2h))
}
}
pub fn expand_matrix(rho: &[u8; 32]) -> Vec<Poly> {
let mut a = Vec::with_capacity(K * L);
for i in 0..K {
for j in 0..L {
a.push(hazmat::sample_ntt_poly(rho, j as u8, i as u8));
}
}
a
}