#![allow(non_snake_case)]
use mohan::{
dalek::{
ristretto::{
CompressedRistretto,
RistrettoPoint
},
scalar::Scalar,
traits::MultiscalarMul
},
mohan_rand
};
use crate::proofs::bulletproofs::{
BulletproofGens,
util
};
use rand;
use std::iter;
use super::messages::*;
use zeroize::Zeroize;
use crate::{
PedersenGens,
errors::{
ZeiError,
MPCError
}
};
pub struct Party {}
impl Party {
pub fn new<'a>(
bp_gens: &'a BulletproofGens,
pc_gens: &'a PedersenGens,
v: u64,
v_blinding: Scalar,
n: usize,
) -> Result<PartyAwaitingPosition<'a>, ZeiError> {
if !(n == 8 || n == 16 || n == 32 || n == 64) {
return Err(ZeiError::from(MPCError::InvalidBitsize));
}
if bp_gens.gens_capacity < n {
return Err(ZeiError::from(MPCError::InvalidGeneratorsLength));
}
let V = pc_gens.commit(&v.into(), &v_blinding).compress();
Ok(PartyAwaitingPosition {
bp_gens,
pc_gens,
n,
v,
v_blinding,
V,
})
}
}
pub struct PartyAwaitingPosition<'a> {
bp_gens: &'a BulletproofGens,
pc_gens: &'a PedersenGens,
n: usize,
v: u64,
v_blinding: Scalar,
V: CompressedRistretto,
}
impl<'a> PartyAwaitingPosition<'a> {
pub fn assign_position(
self,
j: usize,
) -> Result<(PartyAwaitingBitChallenge<'a>, BitCommitment), ZeiError> {
let mut rng = mohan_rand();
if self.bp_gens.party_capacity <= j {
return Err(ZeiError::from(MPCError::InvalidGeneratorsLength));
}
let bp_share = self.bp_gens.share(j);
let a_blinding = Scalar::random(&mut rng);
let mut A = self.pc_gens.B_blinding * a_blinding;
use subtle::{Choice, ConditionallySelectable};
let mut i = 0;
for (G_i, H_i) in bp_share.G(self.n).zip(bp_share.H(self.n)) {
let v_i = Choice::from(((self.v >> i) & 1) as u8);
let mut point = -H_i;
point.conditional_assign(G_i, v_i);
A += point;
i += 1;
}
let s_blinding = Scalar::random(&mut rng);
let s_L: Vec<Scalar> = (0..self.n).map(|_| Scalar::random(&mut rng)).collect();
let s_R: Vec<Scalar> = (0..self.n).map(|_| Scalar::random(&mut rng)).collect();
let S = RistrettoPoint::multiscalar_mul(
iter::once(&s_blinding).chain(s_L.iter()).chain(s_R.iter()),
iter::once(&self.pc_gens.B_blinding)
.chain(bp_share.G(self.n))
.chain(bp_share.H(self.n)),
);
let bit_commitment = BitCommitment {
V_j: self.V,
A_j: A,
S_j: S,
};
let next_state = PartyAwaitingBitChallenge {
n: self.n,
v: self.v,
v_blinding: self.v_blinding,
pc_gens: self.pc_gens,
j,
a_blinding,
s_blinding,
s_L,
s_R,
};
Ok((next_state, bit_commitment))
}
}
impl<'a> Drop for PartyAwaitingPosition<'a> {
fn drop(&mut self) {
self.v.zeroize();
mohan::zeroize_hack(&mut self.v_blinding);
}
}
pub struct PartyAwaitingBitChallenge<'a> {
n: usize,
v: u64,
v_blinding: Scalar,
j: usize,
pc_gens: &'a PedersenGens,
a_blinding: Scalar,
s_blinding: Scalar,
s_L: Vec<Scalar>,
s_R: Vec<Scalar>,
}
impl<'a> PartyAwaitingBitChallenge<'a> {
pub fn apply_challenge(
self,
vc: &BitChallenge,
) -> (PartyAwaitingPolyChallenge, PolyCommitment) {
let mut rng = rand::thread_rng();
let n = self.n;
let offset_y = util::scalar_exp_vartime(&vc.y, (self.j * n) as u64);
let offset_z = util::scalar_exp_vartime(&vc.z, self.j as u64);
let mut l_poly = util::VecPoly1::zero(n);
let mut r_poly = util::VecPoly1::zero(n);
let zz = vc.z * vc.z;
let mut exp_y = offset_y;
let mut exp_2 = Scalar::one();
for i in 0..n {
let a_L_i = Scalar::from((self.v >> i) & 1);
let a_R_i = a_L_i - Scalar::one();
l_poly.0[i] = a_L_i - vc.z;
l_poly.1[i] = self.s_L[i];
r_poly.0[i] = exp_y * (a_R_i + vc.z) + zz * offset_z * exp_2;
r_poly.1[i] = exp_y * self.s_R[i];
exp_y *= vc.y;
exp_2 = exp_2 + exp_2;
}
let t_poly = l_poly.inner_product(&r_poly);
let t_1_blinding = Scalar::random(&mut rng);
let t_2_blinding = Scalar::random(&mut rng);
let T_1 = self.pc_gens.commit(&t_poly.1, &t_1_blinding);
let T_2 = self.pc_gens.commit(&t_poly.2, &t_2_blinding);
let poly_commitment = PolyCommitment {
T_1_j: T_1,
T_2_j: T_2,
};
let papc = PartyAwaitingPolyChallenge {
v_blinding: self.v_blinding,
a_blinding: self.a_blinding,
s_blinding: self.s_blinding,
z: vc.z,
offset_z,
l_poly,
r_poly,
t_poly,
t_1_blinding,
t_2_blinding,
};
(papc, poly_commitment)
}
}
impl<'a> Drop for PartyAwaitingBitChallenge<'a> {
fn drop(&mut self) {
mohan::zeroize_hack(&mut self.v);
mohan::zeroize_hack(&mut self.v_blinding);
mohan::zeroize_hack(&mut self.a_blinding);
mohan::zeroize_hack(&mut self.s_blinding);
for e in self.s_L.iter_mut() {
mohan::zeroize_hack(e);
}
for e in self.s_R.iter_mut() {
mohan::zeroize_hack(e);
}
}
}
pub struct PartyAwaitingPolyChallenge {
z: Scalar,
offset_z: Scalar,
l_poly: util::VecPoly1,
r_poly: util::VecPoly1,
t_poly: util::Poly2,
v_blinding: Scalar,
a_blinding: Scalar,
s_blinding: Scalar,
t_1_blinding: Scalar,
t_2_blinding: Scalar,
}
impl PartyAwaitingPolyChallenge {
pub fn apply_challenge(self, pc: &PolyChallenge) -> Result<ProofShare, ZeiError> {
if pc.x == Scalar::zero() {
return Err(ZeiError::from(MPCError::MaliciousDealer));
}
let t_blinding_poly = util::Poly2(
self.z * self.z * self.offset_z * self.v_blinding,
self.t_1_blinding,
self.t_2_blinding,
);
let t_x = self.t_poly.eval(pc.x);
let t_x_blinding = t_blinding_poly.eval(pc.x);
let e_blinding = self.a_blinding + self.s_blinding * &pc.x;
let l_vec = self.l_poly.eval(pc.x);
let r_vec = self.r_poly.eval(pc.x);
Ok(ProofShare {
t_x_blinding,
t_x,
e_blinding,
l_vec,
r_vec,
})
}
}
impl Drop for PartyAwaitingPolyChallenge {
fn drop(&mut self) {
mohan::zeroize_hack(&mut self.v_blinding);
mohan::zeroize_hack(&mut self.a_blinding);
mohan::zeroize_hack(&mut self.s_blinding);
mohan::zeroize_hack(&mut self.t_1_blinding);
mohan::zeroize_hack(&mut self.t_2_blinding);
}
}