extern crate alloc;
use alloc::vec::Vec;
use crypto_bigint::{Zero, U256};
use rand_core::RngCore;
use crate::error::Error;
use crate::sm9::fields::fp::{fn_from_bytes, fn_inv, fn_mul, fn_to_bytes, Fn, GROUP_ORDER};
use crate::sm9::groups::g1::G1Jacobian;
use super::{bls_sign, BlsKeyShare, BlsPrivKey, BlsSignature};
pub fn bls_threshold_keygen<R: RngCore>(
sk: &BlsPrivKey,
threshold: usize,
total: usize,
rng: &mut R,
) -> Result<Vec<BlsKeyShare>, Error> {
if total < threshold + 1 || threshold == 0 {
return Err(Error::InvalidInput);
}
let sk_fn = fn_from_bytes(&sk.scalar);
let mut coeffs: Vec<Fn> = Vec::with_capacity(threshold + 1);
coeffs.push(sk_fn);
for _ in 0..threshold {
let mut bytes = [0u8; 32];
loop {
rng.fill_bytes(&mut bytes);
let v = U256::from_be_slice(&bytes);
if !bool::from(v.is_zero()) && v < GROUP_ORDER {
coeffs.push(fn_from_bytes(&bytes));
break;
}
}
}
let mut shares = Vec::with_capacity(total);
for i in 1..=total {
let i_fn = fn_from_bytes(&{
let mut b = [0u8; 32];
let i_u256 = U256::from(i as u64);
b.copy_from_slice(&i_u256.to_be_bytes());
b
});
let mut val = coeffs[threshold];
for j in (0..threshold).rev() {
val = fn_mul(&val, &i_fn);
val = crate::sm9::fields::fp::fn_add(&val, &coeffs[j]);
}
shares.push(BlsKeyShare {
index: i,
scalar: fn_to_bytes(&val),
});
}
coeffs.fill(Fn::ZERO);
Ok(shares)
}
fn lagrange_coefficient(i: usize, participants: &[usize]) -> Fn {
let _i_fn = index_to_fn(i);
let mut num = Fn::ONE; let mut den = Fn::ONE;
for &j in participants {
if j != i {
let j_fn = index_to_fn(j);
num = fn_mul(&num, &j_fn);
let diff = if j > i {
index_to_fn(j - i)
} else {
let pos = index_to_fn(i - j);
crate::sm9::fields::fp::fn_neg(&pos)
};
den = fn_mul(&den, &diff);
}
}
let den_inv = fn_inv(&den).expect("Lagrange: 分母不应为零(参与者索引应互不相同)");
fn_mul(&num, &den_inv)
}
fn index_to_fn(i: usize) -> Fn {
let mut b = [0u8; 32];
let u = U256::from(i as u64);
b.copy_from_slice(&u.to_be_bytes());
fn_from_bytes(&b)
}
pub fn bls_partial_sign(share: &BlsKeyShare, msg: &[u8]) -> Result<BlsSignature, Error> {
let sk = BlsPrivKey {
scalar: share.scalar,
};
bls_sign(&sk, msg)
}
pub fn bls_combine_signatures(
partial_sigs: &[(usize, BlsSignature)],
) -> Result<BlsSignature, Error> {
if partial_sigs.is_empty() {
return Err(Error::InvalidInput);
}
let participants: Vec<usize> = partial_sigs.iter().map(|(i, _)| *i).collect();
let mut result = G1Jacobian::INFINITY;
for (i, sig) in partial_sigs {
let lambda = lagrange_coefficient(*i, &participants);
let lambda_u256 = lambda.retrieve();
let sig_jac = G1Jacobian::from_affine(&sig.point);
let scaled = G1Jacobian::scalar_mul(&lambda_u256, &sig_jac);
result = G1Jacobian::add(&result, &scaled);
}
let point = result.to_affine().map_err(|_| Error::PointAtInfinity)?;
Ok(BlsSignature { point })
}
#[cfg(test)]
mod tests {
use super::*;
use crate::bls::{bls_keygen, bls_verify};
use rand_core::OsRng;
#[test]
fn test_threshold_2_of_3() {
let mut rng = OsRng;
let (sk, pk) = bls_keygen(&mut rng);
let msg = b"threshold test message";
let shares = bls_threshold_keygen(&sk, 2, 3, &mut rng).expect("密钥分割应成功");
assert_eq!(shares.len(), 3);
let partial_sigs: Vec<(usize, BlsSignature)> = shares
.iter()
.map(|s| {
let sig = bls_partial_sign(s, msg).expect("部分签名应成功");
(s.index, sig)
})
.collect();
let combined = bls_combine_signatures(&partial_sigs).expect("签名组合应成功");
bls_verify(&pk, msg, &combined).expect("门限签名验证应成功");
}
#[test]
fn test_threshold_1_of_2() {
let mut rng = OsRng;
let (sk, pk) = bls_keygen(&mut rng);
let msg = b"simple threshold";
let shares = bls_threshold_keygen(&sk, 1, 2, &mut rng).expect("密钥分割应成功");
let partial_sigs: Vec<(usize, BlsSignature)> = shares
.iter()
.map(|s| (s.index, bls_partial_sign(s, msg).unwrap()))
.collect();
let combined = bls_combine_signatures(&partial_sigs).unwrap();
bls_verify(&pk, msg, &combined).expect("(1,2) 门限签名验证应成功");
}
#[test]
fn test_invalid_threshold_params() {
let mut rng = OsRng;
let (sk, _pk) = bls_keygen(&mut rng);
assert!(bls_threshold_keygen(&sk, 3, 2, &mut rng).is_err());
assert!(bls_threshold_keygen(&sk, 0, 3, &mut rng).is_err());
}
}