use core::borrow::Borrow;
use snarkvm_curves::PairingEngine;
use snarkvm_gadgets::{
fields::FpGadget,
traits::{alloc::AllocGadget, curves::PairingGadget},
};
use snarkvm_r1cs::{ConstraintSystem, SynthesisError};
use crate::{
sonic_pc::{gadgets::verifier_key::VerifierKeyVar, PreparedVerifierKey, VerifierKey},
Vec,
};
use snarkvm_algorithms::Prepare;
#[allow(clippy::type_complexity)]
pub struct PreparedVerifierKeyVar<
TargetCurve: PairingEngine,
BaseCurve: PairingEngine,
PG: PairingGadget<TargetCurve, <BaseCurve as PairingEngine>::Fr>,
> {
pub prepared_g: Vec<PG::G1Gadget>,
pub prepared_gamma_g: Vec<PG::G1Gadget>,
pub prepared_h: PG::G2PreparedGadget,
pub prepared_beta_h: PG::G2PreparedGadget,
pub origin_vk: Option<VerifierKeyVar<TargetCurve, BaseCurve, PG>>,
}
impl<TargetCurve, BaseCurve, PG> PreparedVerifierKeyVar<TargetCurve, BaseCurve, PG>
where
TargetCurve: PairingEngine,
BaseCurve: PairingEngine,
PG: PairingGadget<TargetCurve, <BaseCurve as PairingEngine>::Fr>,
{
pub fn get_prepared_shift_power<CS: ConstraintSystem<<BaseCurve as PairingEngine>::Fr>>(
&self,
mut cs: CS,
bound: &FpGadget<<BaseCurve as PairingEngine>::Fr>,
) -> Result<PG::G2PreparedGadget, SynthesisError> {
let vk = self.origin_vk.as_ref().ok_or(SynthesisError::AssignmentMissing)?;
let shift_power = vk.get_shift_power(cs.ns(|| "get unprepared shift_power"), bound)?;
PG::prepare_g2(cs.ns(|| "prepare shift power"), shift_power)
}
}
impl<TargetCurve, BaseCurve, PG> Clone for PreparedVerifierKeyVar<TargetCurve, BaseCurve, PG>
where
TargetCurve: PairingEngine,
BaseCurve: PairingEngine,
PG: PairingGadget<TargetCurve, <BaseCurve as PairingEngine>::Fr>,
{
fn clone(&self) -> Self {
Self {
prepared_g: self.prepared_g.clone(),
prepared_gamma_g: self.prepared_gamma_g.clone(),
prepared_h: self.prepared_h.clone(),
prepared_beta_h: self.prepared_beta_h.clone(),
origin_vk: self.origin_vk.clone(),
}
}
}
#[allow(clippy::from_over_into)]
impl<TargetCurve, BaseCurve, PG> Into<VerifierKeyVar<TargetCurve, BaseCurve, PG>>
for PreparedVerifierKeyVar<TargetCurve, BaseCurve, PG>
where
TargetCurve: PairingEngine,
BaseCurve: PairingEngine,
PG: PairingGadget<TargetCurve, <BaseCurve as PairingEngine>::Fr>,
{
fn into(self) -> VerifierKeyVar<TargetCurve, BaseCurve, PG> {
match self.origin_vk {
Some(vk) => vk,
None => {
eprintln!("Missing original vk");
panic!()
}
}
}
}
impl<TargetCurve, BaseCurve, PG> AllocGadget<PreparedVerifierKey<TargetCurve>, <BaseCurve as PairingEngine>::Fr>
for PreparedVerifierKeyVar<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<PreparedVerifierKey<TargetCurve>>,
CS: ConstraintSystem<<BaseCurve as PairingEngine>::Fr>,
>(
_cs: CS,
_value_gen: Fn,
) -> Result<Self, SynthesisError> {
unimplemented!()
}
fn alloc<
Fn: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<PreparedVerifierKey<TargetCurve>>,
CS: ConstraintSystem<<BaseCurve as PairingEngine>::Fr>,
>(
_cs: CS,
_value_gen: Fn,
) -> Result<Self, SynthesisError> {
unimplemented!()
}
fn alloc_input<
Fn: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<PreparedVerifierKey<TargetCurve>>,
CS: ConstraintSystem<<BaseCurve as PairingEngine>::Fr>,
>(
_cs: CS,
_value_gen: Fn,
) -> Result<Self, SynthesisError> {
unimplemented!()
}
}
impl<TargetCurve, BaseCurve, PG> AllocGadget<VerifierKey<TargetCurve>, <BaseCurve as PairingEngine>::Fr>
for PreparedVerifierKeyVar<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<VerifierKey<TargetCurve>>,
CS: ConstraintSystem<<BaseCurve as PairingEngine>::Fr>,
>(
cs: CS,
value_gen: Fn,
) -> Result<Self, SynthesisError> {
let obj = value_gen()?.borrow().clone();
let pvk = VerifierKey::<TargetCurve>::prepare(&obj);
<Self as AllocGadget<PreparedVerifierKey<TargetCurve>, <BaseCurve as PairingEngine>::Fr>>::alloc_constant(
cs,
|| Ok(pvk),
)
}
fn alloc<
Fn: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<VerifierKey<TargetCurve>>,
CS: ConstraintSystem<<BaseCurve as PairingEngine>::Fr>,
>(
_cs: CS,
_value_gen: Fn,
) -> Result<Self, SynthesisError> {
unimplemented!()
}
fn alloc_input<
Fn: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<VerifierKey<TargetCurve>>,
CS: ConstraintSystem<<BaseCurve as PairingEngine>::Fr>,
>(
_cs: CS,
_value_gen: Fn,
) -> Result<Self, SynthesisError> {
unimplemented!()
}
}
#[cfg(test)]
mod tests {
use snarkvm_curves::{
bls12_377::{Bls12_377, Fq},
bw6_761::BW6_761,
};
use snarkvm_gadgets::{
curves::bls12_377::PairingGadget as Bls12_377PairingGadget,
traits::eq::EqGadget,
PrepareGadget,
};
use snarkvm_r1cs::TestConstraintSystem;
use snarkvm_utilities::rand::test_rng;
use crate::{sonic_pc::SonicKZG10, PCUniversalParams, PolynomialCommitment};
use super::*;
use rand::Rng;
use snarkvm_algorithms::Prepare;
use snarkvm_fields::PrimeField;
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_get_prepared_shift_power() {
let rng = &mut test_rng();
let cs = &mut TestConstraintSystem::<Fq>::new();
let pp = PC::setup(MAX_DEGREE, rng).unwrap();
let supported_degree_bounds = pp.supported_degree_bounds();
let bound = supported_degree_bounds[rng.gen_range(0..supported_degree_bounds.len())];
let bound_field = <BaseCurve as PairingEngine>::Fr::from_repr(
<<BaseCurve as PairingEngine>::Fr as PrimeField>::BigInteger::from(bound as u64),
)
.unwrap();
let bound_gadget = FpGadget::alloc(cs.ns(|| "alloc_bound"), || Ok(bound_field)).unwrap();
let (_committer_key, vk) = PC::trim(&pp, SUPPORTED_DEGREE, SUPPORTED_HIDING_BOUND, Some(&[bound])).unwrap();
let pvk = vk.prepare();
let pvk_gadget = {
let vk =
VerifierKeyVar::<_, BaseCurve, PG>::alloc_constant(cs.ns(|| "alloc_vk"), || Ok(vk.clone())).unwrap();
vk.prepare(cs.ns(|| "Prepare vk")).unwrap()
};
assert!(pvk.degree_bounds_and_prepared_neg_powers_of_h.is_some());
let prepared_shift_power = pvk_gadget
.get_prepared_shift_power(cs.ns(|| "get_shift_power"), &bound_gadget)
.unwrap();
let expected_shift_power =
<PG as PairingGadget<_, _>>::G2PreparedGadget::alloc(cs.ns(|| "allocate_native_shift_power"), || {
Ok(pvk.get_prepared_shift_power(bound).unwrap())
})
.unwrap();
prepared_shift_power
.enforce_equal(cs.ns(|| "enforce_equals_shift_power"), &expected_shift_power)
.unwrap();
assert!(cs.is_satisfied());
}
}