use super::plonk_verifier::*;
use ark_ec::pairing::Pairing;
use ark_ff::PrimeField;
use ark_std::{string::ToString, vec::Vec};
use core::marker::PhantomData;
use jf_relation::{
gadgets::{
ecc::{PointVariable, SWToTEConParam},
ultraplonk::mod_arith::FpElemVar,
},
Circuit,
CircuitError::{self, ParameterError},
PlonkCircuit, Variable,
};
use jf_rescue::{gadgets::RescueNativeGadget, RescueParameter, STATE_SIZE};
pub struct RescueTranscriptVar<F: RescueParameter> {
transcript_var: Vec<Variable>,
state_var: [Variable; STATE_SIZE],
_phantom: PhantomData<F>,
}
impl<F> RescueTranscriptVar<F>
where
F: RescueParameter + SWToTEConParam,
{
pub(crate) fn new(circuit: &mut PlonkCircuit<F>) -> Self {
Self {
transcript_var: Vec::new(),
state_var: [circuit.zero(); STATE_SIZE],
_phantom: PhantomData,
}
}
pub(crate) fn append_vk_and_pub_input_vars<E: Pairing<BaseField = F>>(
&mut self,
circuit: &mut PlonkCircuit<F>,
vk_var: &VerifyingKeyVar<E>,
pub_input: &[FpElemVar<F>],
) -> Result<(), CircuitError> {
for com in vk_var.selector_comms.iter() {
self.transcript_var.push(com.get_x());
self.transcript_var.push(com.get_y());
}
for com in vk_var.sigma_comms.iter() {
self.transcript_var.push(com.get_x());
self.transcript_var.push(com.get_y());
}
for e in pub_input {
let pub_var = e.convert_to_var(circuit)?;
self.transcript_var.push(pub_var)
}
Ok(())
}
pub(crate) fn append_variable(
&mut self,
_label: &'static [u8],
var: &Variable,
) -> Result<(), CircuitError> {
self.transcript_var.push(*var);
Ok(())
}
pub(crate) fn append_message_vars(
&mut self,
_label: &'static [u8],
msg_vars: &[Variable],
) -> Result<(), CircuitError> {
for e in msg_vars.iter() {
self.append_variable(_label, e)?;
}
Ok(())
}
pub(crate) fn append_commitment_var(
&mut self,
_label: &'static [u8],
poly_comm_var: &PointVariable,
) -> Result<(), CircuitError> {
self.transcript_var.push(poly_comm_var.get_x());
self.transcript_var.push(poly_comm_var.get_y());
Ok(())
}
pub(crate) fn append_commitments_vars(
&mut self,
_label: &'static [u8],
poly_comm_vars: &[PointVariable],
) -> Result<(), CircuitError> {
for poly_comm_var in poly_comm_vars.iter() {
self.transcript_var.push(poly_comm_var.get_x());
self.transcript_var.push(poly_comm_var.get_y());
}
Ok(())
}
pub(crate) fn append_proof_evaluations_vars(
&mut self,
circuit: &mut PlonkCircuit<F>,
evals: &ProofEvaluationsVar<F>,
) -> Result<(), CircuitError> {
for e in &evals.wires_evals {
let tmp = e.convert_to_var(circuit)?;
self.transcript_var.push(tmp);
}
for e in &evals.wire_sigma_evals {
let tmp = e.convert_to_var(circuit)?;
self.transcript_var.push(tmp);
}
let tmp = evals.perm_next_eval.convert_to_var(circuit)?;
self.transcript_var.push(tmp);
Ok(())
}
pub(crate) fn get_challenge_var<E>(
&mut self,
_label: &'static [u8],
circuit: &mut PlonkCircuit<F>,
) -> Result<Variable, CircuitError>
where
E: Pairing,
{
if !circuit.support_lookup() {
return Err(ParameterError("does not support range table".to_string()));
}
if E::ScalarField::MODULUS_BIT_SIZE != 253 || E::BaseField::MODULUS_BIT_SIZE != 377 {
return Err(ParameterError(
"Curve Parameter does not support for rescue transcript circuit".to_string(),
));
}
let input_var = [self.state_var.as_ref(), self.transcript_var.as_ref()].concat();
let res_var =
RescueNativeGadget::<F>::rescue_sponge_with_padding(circuit, &input_var, STATE_SIZE)
.unwrap();
let out_var = res_var[0];
let challenge_var = circuit.truncate(out_var, 248)?;
self.state_var.copy_from_slice(&res_var[0..STATE_SIZE]);
self.transcript_var = Vec::new();
Ok(challenge_var)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
proof_system::structs::VerifyingKey,
transcript::{PlonkTranscript, RescueTranscript},
};
use ark_bls12_377::Bls12_377;
use ark_ec::{
short_weierstrass::{Affine, SWCurveConfig},
AffineRepr, CurveGroup,
};
use ark_std::{format, vec, UniformRand};
use jf_pcs::prelude::{Commitment, UnivariateVerifierParam};
use jf_relation::gadgets::ecc::TEPoint;
use jf_utils::{bytes_to_field_elements, field_switching, test_rng};
const RANGE_BIT_LEN_FOR_TEST: usize = 16;
#[test]
fn test_rescue_transcript_challenge_circuit() {
test_rescue_transcript_challenge_circuit_helper::<Bls12_377, _, _>()
}
fn test_rescue_transcript_challenge_circuit_helper<E, F, P>()
where
E: Pairing<BaseField = F, G1Affine = Affine<P>>,
F: RescueParameter + SWToTEConParam,
P: SWCurveConfig<BaseField = F>,
{
let mut circuit = PlonkCircuit::<F>::new_ultra_plonk(RANGE_BIT_LEN_FOR_TEST);
let label = "testing".as_ref();
let mut transcript_var = RescueTranscriptVar::new(&mut circuit);
let mut transcript = RescueTranscript::<F>::new(label);
for _ in 0..10 {
for i in 0..10 {
let msg = format!("message {}", i);
let vals = bytes_to_field_elements(msg.as_bytes());
let message_vars: Vec<Variable> = vals
.iter()
.map(|x| circuit.create_variable(*x).unwrap())
.collect();
transcript.append_message(label, msg.as_bytes()).unwrap();
transcript_var
.append_message_vars(label, &message_vars)
.unwrap();
}
let challenge = transcript.get_challenge::<E>(label).unwrap();
let challenge_var = transcript_var
.get_challenge_var::<E>(label, &mut circuit)
.unwrap();
assert_eq!(
circuit.witness(challenge_var).unwrap().into_bigint(),
field_switching::<_, F>(&challenge).into_bigint()
);
}
}
#[test]
fn test_rescue_transcript_append_vk_and_input_circuit() {
test_rescue_transcript_append_vk_and_input_circuit_helper::<Bls12_377, _, _>()
}
fn test_rescue_transcript_append_vk_and_input_circuit_helper<E, F, P>()
where
E: Pairing<BaseField = F, G1Affine = Affine<P>>,
F: RescueParameter + SWToTEConParam,
P: SWCurveConfig<BaseField = F>,
{
let mut circuit = PlonkCircuit::<F>::new_ultra_plonk(RANGE_BIT_LEN_FOR_TEST);
let mut rng = test_rng();
let label = "testing".as_ref();
let mut transcript_var = RescueTranscriptVar::new(&mut circuit);
let mut transcript = RescueTranscript::<F>::new(label);
let g = E::G1Affine::generator();
let h = E::G2Affine::generator();
let beta_h = E::G2::rand(&mut rng).into_affine();
let open_key: UnivariateVerifierParam<E> = UnivariateVerifierParam {
g,
h,
beta_h,
powers_of_h: vec![h, beta_h],
powers_of_g: vec![g],
};
let dummy_vk = VerifyingKey {
domain_size: 512,
num_inputs: 0,
sigma_comms: Vec::new(),
selector_comms: Vec::new(),
k: Vec::new(),
open_key: open_key.clone(),
is_merged: false,
plookup_vk: None,
};
let dummy_vk_var = VerifyingKeyVar::new(&mut circuit, &dummy_vk).unwrap();
transcript.append_vk_and_pub_input(&dummy_vk, &[]).unwrap();
transcript_var
.append_vk_and_pub_input_vars::<E>(&mut circuit, &dummy_vk_var, &[])
.unwrap();
let challenge = transcript.get_challenge::<E>(label).unwrap();
let challenge_var = transcript_var
.get_challenge_var::<E>(label, &mut circuit)
.unwrap();
assert_eq!(
circuit.witness(challenge_var).unwrap(),
field_switching(&challenge)
);
for _ in 0..10 {
let input: Vec<E::ScalarField> =
(0..16).map(|_| E::ScalarField::rand(&mut rng)).collect();
let sigma_comms: Vec<Commitment<E>> = (0..42)
.map(|_| Commitment(E::G1::rand(&mut rng).into_affine()))
.collect();
let mut sigma_comms_vars: Vec<PointVariable> = Vec::new();
for e in sigma_comms.iter() {
let p: TEPoint<F> = e.0.into();
sigma_comms_vars.push(circuit.create_point_variable(p).unwrap());
}
let selector_comms: Vec<Commitment<E>> = (0..33)
.map(|_| Commitment(E::G1::rand(&mut rng).into_affine()))
.collect();
let mut selector_comms_vars: Vec<PointVariable> = Vec::new();
for e in selector_comms.iter() {
let p: TEPoint<F> = e.0.into();
selector_comms_vars.push(circuit.create_point_variable(p).unwrap());
}
let k: Vec<E::ScalarField> = (0..5).map(|_| E::ScalarField::rand(&mut rng)).collect();
let vk = VerifyingKey {
domain_size: 512,
num_inputs: input.len(),
sigma_comms,
selector_comms,
k,
open_key: open_key.clone(),
is_merged: false,
plookup_vk: None,
};
let vk_var = VerifyingKeyVar::new(&mut circuit, &vk).unwrap();
transcript.append_vk_and_pub_input(&vk, &input).unwrap();
let m = 128;
let input_vars: Vec<Variable> = input
.iter()
.map(|&x| circuit.create_public_variable(field_switching(&x)).unwrap())
.collect();
let input_fp_elem_vars: Vec<FpElemVar<F>> = input_vars
.iter()
.map(|&x| FpElemVar::new_unchecked(&mut circuit, x, m, None).unwrap())
.collect();
transcript_var
.append_vk_and_pub_input_vars::<E>(&mut circuit, &vk_var, &input_fp_elem_vars)
.unwrap();
let challenge = transcript.get_challenge::<E>(label).unwrap();
let challenge_var = transcript_var
.get_challenge_var::<E>(label, &mut circuit)
.unwrap();
assert_eq!(
circuit.witness(challenge_var).unwrap(),
field_switching(&challenge)
);
}
}
}