use core::borrow::Borrow;
use snarkvm_curves::PairingEngine;
use snarkvm_gadgets::{
fields::FpGadget,
traits::{alloc::AllocGadget, curves::PairingGadget},
PrepareGadget,
};
use snarkvm_r1cs::{ConstraintSystem, SynthesisError};
use crate::{
sonic_pc::{Commitment, CommitmentVar, PreparedLabeledCommitmentVar},
LabeledCommitment,
String,
ToString,
};
pub struct LabeledCommitmentVar<
TargetCurve: PairingEngine,
BaseCurve: PairingEngine,
PG: PairingGadget<TargetCurve, <BaseCurve as PairingEngine>::Fr>,
> {
pub label: String,
pub commitment: CommitmentVar<TargetCurve, BaseCurve, PG>,
pub degree_bound: Option<FpGadget<<BaseCurve as PairingEngine>::Fr>>,
}
impl<TargetCurve, BaseCurve, PG> Clone for LabeledCommitmentVar<TargetCurve, BaseCurve, PG>
where
TargetCurve: PairingEngine,
BaseCurve: PairingEngine,
PG: PairingGadget<TargetCurve, <BaseCurve as PairingEngine>::Fr>,
{
fn clone(&self) -> Self {
LabeledCommitmentVar {
label: self.label.clone(),
commitment: self.commitment.clone(),
degree_bound: self.degree_bound.clone(),
}
}
}
impl<TargetCurve, BaseCurve, PG>
AllocGadget<LabeledCommitment<Commitment<TargetCurve>>, <BaseCurve as PairingEngine>::Fr>
for LabeledCommitmentVar<TargetCurve, BaseCurve, PG>
where
TargetCurve: PairingEngine,
BaseCurve: PairingEngine,
PG: PairingGadget<TargetCurve, <BaseCurve as PairingEngine>::Fr>,
{
fn alloc_constant<
Fn: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<LabeledCommitment<Commitment<TargetCurve>>>,
CS: ConstraintSystem<<BaseCurve as PairingEngine>::Fr>,
>(
mut cs: CS,
value_gen: Fn,
) -> Result<Self, SynthesisError> {
value_gen().and_then(|labeled_commitment| {
let labeled_commitment = labeled_commitment.borrow().clone();
let label = labeled_commitment.label().to_string();
let commitment = labeled_commitment.commitment();
let degree_bound = labeled_commitment.degree_bound();
let commitment = CommitmentVar::alloc_constant(cs.ns(|| "commitment"), || Ok(commitment))?;
let degree_bound = if let Some(degree_bound) = degree_bound {
FpGadget::<<BaseCurve as PairingEngine>::Fr>::alloc_constant(cs.ns(|| "degree_bound"), || {
Ok(<<BaseCurve as PairingEngine>::Fr as From<u128>>::from(
degree_bound as u128,
))
})
.ok()
} else {
None
};
Ok(Self {
label,
commitment,
degree_bound,
})
})
}
fn alloc<
Fn: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<LabeledCommitment<Commitment<TargetCurve>>>,
CS: ConstraintSystem<<BaseCurve as PairingEngine>::Fr>,
>(
mut cs: CS,
value_gen: Fn,
) -> Result<Self, SynthesisError> {
value_gen().and_then(|labeled_commitment| {
let labeled_commitment = labeled_commitment.borrow().clone();
let label = labeled_commitment.label().to_string();
let commitment = labeled_commitment.commitment();
let degree_bound = labeled_commitment.degree_bound();
let commitment = CommitmentVar::alloc(cs.ns(|| "commitment"), || Ok(commitment))?;
let degree_bound = if let Some(degree_bound) = degree_bound {
FpGadget::<<BaseCurve as PairingEngine>::Fr>::alloc(cs.ns(|| "degree_bound"), || {
Ok(<<BaseCurve as PairingEngine>::Fr as From<u128>>::from(
degree_bound as u128,
))
})
.ok()
} else {
None
};
Ok(Self {
label,
commitment,
degree_bound,
})
})
}
fn alloc_input<
Fn: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<LabeledCommitment<Commitment<TargetCurve>>>,
CS: ConstraintSystem<<BaseCurve as PairingEngine>::Fr>,
>(
mut cs: CS,
value_gen: Fn,
) -> Result<Self, SynthesisError> {
value_gen().and_then(|labeled_commitment| {
let labeled_commitment = labeled_commitment.borrow().clone();
let label = labeled_commitment.label().to_string();
let commitment = labeled_commitment.commitment();
let degree_bound = labeled_commitment.degree_bound();
let commitment = CommitmentVar::alloc_input(cs.ns(|| "commitment"), || Ok(commitment))?;
let degree_bound = if let Some(degree_bound) = degree_bound {
FpGadget::<<BaseCurve as PairingEngine>::Fr>::alloc_input(cs.ns(|| "degree_bound"), || {
Ok(<<BaseCurve as PairingEngine>::Fr as From<u128>>::from(
degree_bound as u128,
))
})
.ok()
} else {
None
};
Ok(Self {
label,
commitment,
degree_bound,
})
})
}
}
impl<TargetCurve, BaseCurve, PG>
PrepareGadget<PreparedLabeledCommitmentVar<TargetCurve, BaseCurve, PG>, <BaseCurve as PairingEngine>::Fr>
for LabeledCommitmentVar<TargetCurve, BaseCurve, PG>
where
TargetCurve: PairingEngine,
BaseCurve: PairingEngine,
PG: PairingGadget<TargetCurve, <BaseCurve as PairingEngine>::Fr>,
{
fn prepare<CS: ConstraintSystem<<BaseCurve as PairingEngine>::Fr>>(
&self,
cs: CS,
) -> Result<PreparedLabeledCommitmentVar<TargetCurve, BaseCurve, PG>, SynthesisError> {
Ok(PreparedLabeledCommitmentVar::<TargetCurve, BaseCurve, PG> {
label: self.label.clone(),
prepared_commitment: self.commitment.prepare(cs)?,
degree_bound: self.degree_bound.clone(),
})
}
}
#[cfg(test)]
mod tests {
use snarkvm_algorithms::fft::DensePolynomial;
use snarkvm_curves::{
bls12_377::{Bls12_377, Fq, Fr},
bw6_761::BW6_761,
AffineCurve,
};
use snarkvm_gadgets::{
bits::ToBytesGadget,
curves::bls12_377::PairingGadget as Bls12_377PairingGadget,
traits::eq::EqGadget,
};
use snarkvm_r1cs::TestConstraintSystem;
use snarkvm_utilities::rand::test_rng;
use crate::{sonic_pc::SonicKZG10, LabeledPolynomial, PolynomialCommitment};
use super::*;
type PC = SonicKZG10<Bls12_377>;
type PG = Bls12_377PairingGadget;
type BaseCurve = BW6_761;
const MAX_DEGREE: usize = 383;
const SUPPORTED_DEGREE: usize = 300;
const SUPPORTED_HIDING_BOUND: usize = 1;
#[test]
fn test_alloc() {
let rng = &mut test_rng();
let cs = &mut TestConstraintSystem::<Fq>::new();
let pp = PC::setup(MAX_DEGREE, rng).unwrap();
let (committer_key, _vk) = PC::trim(&pp, SUPPORTED_DEGREE, SUPPORTED_HIDING_BOUND, None).unwrap();
let random_polynomial = DensePolynomial::<Fr>::rand(SUPPORTED_DEGREE - 1, rng);
let labeled_polynomial = LabeledPolynomial::new("test_polynomial".to_string(), random_polynomial, None, None);
let (commitments, _randomness) = PC::commit(&committer_key, vec![&labeled_polynomial], Some(rng)).unwrap();
for (i, commitment) in commitments.iter().enumerate() {
let commitment_gadget =
LabeledCommitmentVar::<_, BaseCurve, PG>::alloc(cs.ns(|| format!("commitment_{}", i)), || {
Ok(commitment)
})
.unwrap();
assert_eq!(commitment.label(), &commitment_gadget.label);
assert_eq!(
commitment.degree_bound().is_some(),
commitment_gadget.degree_bound.is_some()
);
if let (Some(degree_bound), Some(degree_bound_gadget)) =
(commitment.degree_bound(), commitment_gadget.degree_bound)
{
let expected_degree_bound = FpGadget::alloc(cs.ns(|| format!("degree_bound_{}", i)), || {
Ok(Fq::from(degree_bound as u32))
})
.unwrap();
expected_degree_bound
.enforce_equal(
cs.ns(|| format!("degree_bound_enforce_equal_{}", i)),
°ree_bound_gadget,
)
.unwrap();
}
let expected_commitment_gadget =
<PG as PairingGadget<_, _>>::G1Gadget::alloc(cs.ns(|| format!("commitment_gadget_{}", i)), || {
Ok(commitment.commitment().0.into_projective())
})
.unwrap();
commitment_gadget
.commitment
.comm
.enforce_equal(
cs.ns(|| format!("commitment_conditional_enforce_equal_{}", i)),
&expected_commitment_gadget,
)
.unwrap();
}
assert!(cs.is_satisfied());
}
#[test]
fn test_to_bytes() {
let rng = &mut test_rng();
let cs = &mut TestConstraintSystem::<Fq>::new();
let pp = PC::setup(MAX_DEGREE, rng).unwrap();
let (committer_key, _vk) = PC::trim(&pp, SUPPORTED_DEGREE, SUPPORTED_HIDING_BOUND, None).unwrap();
let random_polynomial = DensePolynomial::<Fr>::rand(SUPPORTED_DEGREE - 1, rng);
let labeled_polynomial = LabeledPolynomial::new("test_polynomial".to_string(), random_polynomial, None, None);
let (commitments, _randomness) = PC::commit(&committer_key, vec![&labeled_polynomial], Some(rng)).unwrap();
for (i, commitment) in commitments.iter().enumerate() {
let commitment_gadget =
LabeledCommitmentVar::<_, BaseCurve, PG>::alloc(cs.ns(|| format!("commitment_{}", i)), || {
Ok(commitment)
})
.unwrap();
let _commitment_gadget_bytes = commitment_gadget
.commitment
.to_bytes(cs.ns(|| format!("commitment_to_bytes_{}", i)))
.unwrap();
}
}
}