use super::*;
use crate::*;
pub enum TransparentInnerProdBuilderConstraint {
Mul(u64, u64, u64),
Add(u64, u64, u64),
}
#[derive(Default)]
pub struct TransparentInnerProdSystemBuilder<E: RingElement> {
pub wtns: HashMap<u64, Vector<E>>,
pub constraints: Vec<TransparentInnerProdBuilderConstraint>,
}
impl<E: RingElement> TransparentInnerProdSystemBuilder<E> {
pub fn commit(&mut self, vec: Vector<E>) -> u64 {
let wtns_i = {
let mut key = 0;
while self.wtns.contains_key(&key) {
key = rand::random();
}
key
};
self.wtns.insert(wtns_i, vec);
wtns_i
}
pub fn constrain_mul(&mut self, wtns_a: u64, wtns_b: u64, wtns_c: u64) {
self.constraints
.push(TransparentInnerProdBuilderConstraint::Mul(
wtns_a, wtns_b, wtns_c,
));
}
pub fn constrain_add(&mut self, wtns_a: u64, wtns_b: u64, wtns_c: u64) {
self.constraints
.push(TransparentInnerProdBuilderConstraint::Add(
wtns_a, wtns_b, wtns_c,
));
}
pub fn commit_public_mul(&mut self, wtns_a: u64, b: E) -> u64 {
match self.wtns.get(&wtns_a).cloned() {
Some(a) => {
let b: Vector<E> = vec![b; a.len()].into();
let b_wtns_i = self.commit(b.clone());
let c = a * &b;
let c_wtns_i = self.commit(c);
self.constraints
.push(TransparentInnerProdBuilderConstraint::Mul(
wtns_a, b_wtns_i, c_wtns_i,
));
c_wtns_i
}
None => {
panic!()
}
}
}
pub fn wtns(&self, i: &u64) -> Result<&Vector<E>> {
self.wtns
.get(i)
.ok_or(anyhow::anyhow!("wtns value at index {i} does not exist"))
}
pub fn argue(self) -> Result<TransparentInnerProdNIZKArg<E>> {
let mut wtns_args = HashMap::default();
let mut transcript = Transcript::<E>::new();
transcript.domain_separator("innerprod_nizk");
for constraint in self.constraints.iter() {
match constraint {
TransparentInnerProdBuilderConstraint::Mul(a_i, b_i, c_i) => {
if wtns_args.contains_key(c_i) {
anyhow::bail!("duplicate witness write");
}
let a = self.wtns(&a_i)?;
let b = self.wtns(&b_i)?;
let arg = TransparentInnerProd::<10, E>::new(a.clone(), b.clone())?;
transcript.append_bytes(&arg.hash);
wtns_args.insert(*c_i, arg);
}
TransparentInnerProdBuilderConstraint::Add(a_i, b_i, c_i) => {
if wtns_args.contains_key(c_i) {
anyhow::bail!("duplicate witness write");
}
let a = self.wtns(&a_i)?;
let b = self.wtns(&b_i)?;
let c = a.clone() + b;
let arg = TransparentInnerProd::<10, E>::new(
c.clone(),
vec![E::one(); c.len()].into(),
)?;
transcript.append_bytes(&arg.hash);
wtns_args.insert(*c_i, arg);
}
}
}
for wtns_i in self.wtns.keys() {
if !wtns_args.contains_key(wtns_i) {
let i = self.wtns(wtns_i)?;
let arg =
TransparentInnerProd::<10, E>::new(i.clone(), vec![E::one(); i.len()].into())?;
transcript.append_bytes(&arg.hash);
wtns_args.insert(*wtns_i, arg);
}
}
Ok(TransparentInnerProdNIZKArg {
wtns_hash: transcript.random(),
wtns_args,
constraints: self.constraints,
})
}
}