use crate::{
marlin_pc::{Commitment, CommitmentVar},
LabeledCommitment,
String,
ToString,
};
use snarkvm_curves::PairingEngine;
use snarkvm_gadgets::{fields::FpGadget, traits::curves::PairingGadget, utilities::alloc::AllocGadget};
use snarkvm_r1cs::{ConstraintSystem, SynthesisError, ToConstraintField};
use core::borrow::Borrow;
pub struct LabeledCommitmentVar<
TargetCurve: PairingEngine,
BaseCurve: PairingEngine,
PG: PairingGadget<TargetCurve, <BaseCurve as PairingEngine>::Fr>,
> where
<TargetCurve as PairingEngine>::G1Affine: ToConstraintField<<BaseCurve as PairingEngine>::Fr>,
<TargetCurve as PairingEngine>::G2Affine: ToConstraintField<<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>,
<TargetCurve as PairingEngine>::G1Affine: ToConstraintField<<BaseCurve as PairingEngine>::Fr>,
<TargetCurve as PairingEngine>::G2Affine: ToConstraintField<<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>,
<TargetCurve as PairingEngine>::G1Affine: ToConstraintField<<BaseCurve as PairingEngine>::Fr>,
<TargetCurve as PairingEngine>::G2Affine: ToConstraintField<<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,
})
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{marlin_pc::MarlinKZG10, LabeledPolynomial, PolynomialCommitment};
use snarkvm_algorithms::fft::DensePolynomial;
use snarkvm_curves::{
bls12_377::{Bls12_377, Fq, Fr},
bw6_761::BW6_761,
AffineCurve,
};
use snarkvm_gadgets::{
curves::bls12_377::PairingGadget as Bls12_377PairingGadget,
utilities::{eq::EqGadget, ToBytesGadget},
};
use snarkvm_r1cs::TestConstraintSystem;
use snarkvm_utilities::rand::test_rng;
type PC = MarlinKZG10<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().comm.0.into_projective())
})
.unwrap();
commitment_gadget
.commitment
.comm
.enforce_equal(
cs.ns(|| format!("commitment_conditional_enforce_equal_{}", i)),
&expected_commitment_gadget,
)
.unwrap();
assert_eq!(
commitment.commitment().shifted_comm.is_some(),
commitment_gadget.commitment.shifted_comm.is_some()
);
if let (Some(shifted_comm), Some(shifted_comm_gadget)) = (
&commitment.commitment().shifted_comm,
commitment_gadget.commitment.shifted_comm,
) {
let expected_shifted_commitment_gadget = <PG as PairingGadget<_, _>>::G1Gadget::alloc(
cs.ns(|| format!("shifted_commitment_gadget_{}", i)),
|| Ok(shifted_comm.0.into_projective()),
)
.unwrap();
shifted_comm_gadget
.enforce_equal(
cs.ns(|| format!("shifted_commitment_conditional_enforce_equal_{}", i)),
&expected_shifted_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();
}
}
}