use thiserror::Error;
use crate::poly::{Eval, Poly};
use crate::sig::tbls::Share;
use crate::sig::{BlindScheme, BlindThresholdScheme, Partial, ThresholdScheme};
#[derive(Debug, Error)]
pub enum BlindThresholdError<E: 'static + std::error::Error> {
#[error(transparent)]
BlindError(E),
#[error(transparent)]
BincodeError(#[from] bincode::Error),
}
impl<T> BlindThresholdScheme for T
where
T: 'static + ThresholdScheme + BlindScheme,
{
type Error = BlindThresholdError<<T as BlindScheme>::Error>;
fn sign_blind_partial(
private: &Share<Self::Private>,
blinded_msg: &[u8],
) -> Result<Partial, <Self as BlindThresholdScheme>::Error> {
let sig = Self::blind_sign(&private.private, blinded_msg)
.map_err(BlindThresholdError::BlindError)?;
let partial = Eval {
value: sig,
index: private.index,
};
bincode::serialize(&partial).map_err(BlindThresholdError::BincodeError)
}
fn unblind_partial_sig(
t: &Self::Token,
partial: &[u8],
) -> Result<Partial, <Self as BlindThresholdScheme>::Error> {
let partial: Eval<Vec<u8>> = bincode::deserialize(partial)?;
let partially_unblinded =
Self::unblind_sig(t, &partial.value).map_err(BlindThresholdError::BlindError)?;
let partially_unblinded = Eval {
index: partial.index,
value: partially_unblinded,
};
bincode::serialize(&partially_unblinded).map_err(BlindThresholdError::BincodeError)
}
fn verify_blind_partial(
public: &Poly<Self::Public>,
blind_msg: &[u8],
blind_partial: &[u8],
) -> Result<(), <Self as BlindThresholdScheme>::Error> {
let blinded_partial: Eval<Vec<u8>> = bincode::deserialize(blind_partial)?;
let public_i = public.eval(blinded_partial.index);
Self::blind_verify(&public_i.value, blind_msg, &blinded_partial.value)
.map_err(BlindThresholdError::BlindError)
}
}
#[cfg(test)]
mod tests {
use rand::thread_rng;
#[cfg(feature = "bls12_381")]
use crate::curve::bls12381::PairingCurve as PCurve;
use crate::poly::Idx;
use crate::sig::{
bls::{G1Scheme, G2Scheme},
SignatureScheme,
};
use super::*;
fn shares<B: BlindThresholdScheme>(
n: usize,
t: usize,
) -> (Vec<Share<B::Private>>, Poly<B::Public>) {
let private = Poly::<B::Private>::new(t - 1);
let shares = (0..n)
.map(|i| private.eval(i as Idx))
.map(|e| Share {
index: e.index,
private: e.value,
})
.collect();
(shares, private.commit())
}
#[cfg(feature = "bls12_381")]
#[test]
fn tblind_g1_bellman_unblind() {
tblind_test::<G1Scheme<PCurve>>();
}
#[cfg(feature = "bls12_381")]
#[test]
fn tblind_g2_bellman_unblind() {
tblind_test::<G2Scheme<PCurve>>();
}
fn tblind_test<B>()
where
B: BlindThresholdScheme + SignatureScheme + ThresholdScheme,
{
let n = 5;
let thr = 4;
let (shares, public) = shares::<B>(n, thr);
let msg = vec![1, 9, 6, 9];
let (token, blinded) = B::blind_msg(&msg, &mut thread_rng());
let partials: Vec<_> = shares
.iter()
.map(|share| B::sign_blind_partial(share, &blinded).unwrap())
.collect();
assert_eq!(
false,
partials
.iter()
.any(|p| B::verify_blind_partial(&public, &blinded, p).is_err())
);
let unblindeds_partials: Vec<_> = partials
.iter()
.map(|p| B::unblind_partial_sig(&token, p).unwrap())
.collect();
let final_sig1 = B::aggregate(thr, &unblindeds_partials).unwrap();
B::verify(&public.public_key(), &msg, &final_sig1).unwrap();
let blinded_final = B::aggregate(thr, &partials).unwrap();
let final_sig2 = B::unblind_sig(&token, &blinded_final).unwrap();
B::verify(&public.public_key(), &msg, &final_sig2).unwrap();
assert_eq!(final_sig1, final_sig2);
}
}