use super::crypto::*;
use super::dleq;
use super::math;
use super::pdleq;
use super::types::*;
pub type Secret<C> = Point<C>;
#[derive(Clone)]
pub struct Escrow<C: EcOperation> {
pub threshold: Threshold,
pub extra_generator: Point<C>,
pub polynomial: math::Polynomial<C>,
pub secret: Secret<C>,
pub proof: dleq::Proof<C>,
}
#[derive(Clone)]
pub struct PublicShares<C: EcOperation> {
pub threshold: Threshold,
pub extra_generator: Point<C>,
pub secret_proof: dleq::Proof<C>,
pub encrypted_shares: Vec<EncryptedShare<C>>,
pub commitments: Vec<Commitment<C>>,
pub proofs: pdleq::Proof<C>,
}
#[derive(Clone)]
pub struct Commitment<C: EcOperation> {
point: Point<C>,
}
#[derive(Clone)]
pub struct EncryptedShare<C: EcOperation> {
pub id: ShareId,
encrypted_val: Point<C>,
}
#[derive(Clone)]
pub struct DecryptedShare<C: EcOperation> {
pub id: ShareId,
decrypted_val: Point<C>,
proof: dleq::Proof<C>,
}
pub fn escrow<C: EcOperation>(drg: &mut Drg, t: Threshold) -> Escrow<C> {
assert!(t >= 1, "threshold is invalid; < 1");
let poly = math::Polynomial::generate(drg, t - 1);
let generator = Point::random_generator(drg);
let secret = poly.at_zero();
let g_s = Point::from_scalar(&secret);
let challenge = Scalar::generate(drg);
let dleq = dleq::DLEQ {
g1: &Point::generator(),
h1: &g_s,
g2: &generator,
h2: &generator.mul(&secret),
};
let proof = dleq::Proof::create(&challenge, &secret, &dleq);
Escrow {
threshold: t,
extra_generator: generator,
polynomial: poly,
secret: g_s,
proof,
}
}
pub fn create_shares<C: EcOperation>(
drg: &mut Drg,
escrow: &Escrow<C>,
pubs: &[PublicKey<C>],
) -> PublicShares<C> {
let n = pubs.len();
let mut shares = Vec::with_capacity(n);
let mut commitments = Vec::with_capacity(n);
let mut sis = Vec::with_capacity(n);
let mut pparams = Vec::with_capacity(n);
for (i, public) in ShareIdsSequence::new().zip(pubs.iter()) {
let si = escrow.polynomial.evaluate(i.to_scalar());
let esi = public.point.mul(&si);
let vi = escrow.extra_generator.mul(&si);
shares.push(EncryptedShare {
id: i,
encrypted_val: esi,
});
commitments.push(Commitment { point: vi });
sis.push(si);
}
for (((s, c), public), si) in shares
.iter()
.zip(commitments.iter())
.zip(pubs.iter())
.zip(sis.iter())
{
{
let w = Scalar::generate(drg);
let dleq = dleq::DLEQ {
g1: &escrow.extra_generator,
h1: &c.point,
g2: &public.point,
h2: &s.encrypted_val,
};
pparams.push((w, si, dleq));
}
}
let pdleq = pdleq::Proof::create(pparams.as_slice());
PublicShares {
threshold: escrow.threshold,
extra_generator: escrow.extra_generator.clone(),
secret_proof: escrow.proof.clone(),
encrypted_shares: shares,
commitments,
proofs: pdleq,
}
}
impl<C: EcOperation> PublicShares<C> {
pub fn number_participants(&self) -> u32 {
self.commitments.len() as u32
}
pub fn verify(&self, drg: &mut Drg, publics: &[PublicKey<C>]) -> bool {
let mut dleqs = Vec::with_capacity(publics.len());
for (i, public) in publics.iter().enumerate() {
let vi = &self.commitments[i].point;
let esi = &self.encrypted_shares[i].encrypted_val;
let dleq = dleq::DLEQ {
g1: &self.extra_generator,
h1: &vi,
g2: &public.point,
h2: &esi,
};
dleqs.push(dleq);
}
if !self.proofs.verify(dleqs.as_slice()) {
return false;
}
let n = self.number_participants();
let poly = math::Polynomial::generate(drg, n - self.threshold - 1);
let mut v = Point::infinity();
for i in 0..n {
let idx = i as usize;
let mut cperp = poly.evaluate(Scalar::from_u32(i));
for j in 0..n {
if i != j {
cperp = cperp * (Scalar::from_u32(i) - Scalar::from_u32(j)).inverse();
}
}
let commitment = &self.commitments[idx];
v = v + commitment.point.mul(&cperp);
}
v == Point::infinity()
}
}
impl<C: EcOperation> DecryptedShare<C> {
pub fn verify(&self, public: &PublicKey<C>, eshare: &EncryptedShare<C>) -> bool {
let dleq = dleq::DLEQ {
g1: &Point::generator(),
h1: &public.point,
g2: &self.decrypted_val,
h2: &eshare.encrypted_val,
};
self.proof.verify(&dleq)
}
}
pub fn decrypt_share<C: EcOperation>(
drg: &mut Drg,
private: &PrivateKey<C>,
public: &PublicKey<C>,
share: &EncryptedShare<C>,
) -> DecryptedShare<C> {
let challenge = Scalar::generate(drg);
let xi = &private.scalar;
let yi = &public.point;
let lifted_yi = &share.encrypted_val;
let si = lifted_yi.mul(&xi.inverse());
let dleq = dleq::DLEQ {
g1: &Point::generator(),
h1: &yi,
g2: &si,
h2: &lifted_yi,
};
let proof = dleq::Proof::create(&challenge, &xi, &dleq);
DecryptedShare {
id: share.id,
decrypted_val: si,
proof,
}
}
fn interpolate_one<C: EcOperation>(
t: Threshold,
sid: usize,
shares: &[DecryptedShare<C>],
) -> Scalar<C> {
let mut v = Scalar::multiplicative_identity();
for j in 0..(t as usize) {
if j != sid {
let sj = shares[j].id.to_scalar();
let si = shares[sid].id.to_scalar();
let d = &sj - &si;
v = v * sj * d.inverse();
}
}
v
}
pub fn recover<C: EcOperation>(
t: Threshold,
shares: &[DecryptedShare<C>],
) -> Result<Secret<C>, ()> {
if t as usize > shares.len() {
return Err(());
};
let mut result = Point::infinity();
for i in 0..(t as usize) {
let v = interpolate_one(t, i, shares);
result = result + shares[i].decrypted_val.mul(&v);
}
Ok(result)
}
pub fn verify_secret<C: EcOperation>(secret: Secret<C>, public_shares: &PublicShares<C>) -> bool {
let mut commitment_interpolate = Point::infinity();
for i in 0..(public_shares.threshold as usize) {
let x = &public_shares.commitments[i].point;
let li = {
let mut v = Scalar::multiplicative_identity();
for j in 0..(public_shares.threshold as usize) {
if j != i {
let sj = Scalar::from_u32((j + 1) as u32);
let si = Scalar::from_u32((i + 1) as u32);
let d = &sj - &si;
v = v * sj * d.inverse();
}
}
v
};
commitment_interpolate = commitment_interpolate + x.mul(&li);
}
let dleq = dleq::DLEQ {
g1: &Point::generator(),
h1: &secret,
g2: &public_shares.extra_generator,
h2: &commitment_interpolate,
};
public_shares.secret_proof.verify(&dleq)
}