1use super::plonk_verifier::*;
10use ark_ec::pairing::Pairing;
11use ark_ff::PrimeField;
12use ark_std::{string::ToString, vec::Vec};
13use core::marker::PhantomData;
14use jf_relation::{
15 gadgets::{
16 ecc::{PointVariable, SWToTEConParam},
17 ultraplonk::mod_arith::FpElemVar,
18 },
19 Circuit,
20 CircuitError::{self, ParameterError},
21 PlonkCircuit, Variable,
22};
23use jf_rescue::{gadgets::RescueNativeGadget, RescueParameter, STATE_SIZE};
24
25pub struct RescueTranscriptVar<F: RescueParameter> {
29 transcript_var: Vec<Variable>,
30 state_var: [Variable; STATE_SIZE],
31 _phantom: PhantomData<F>,
32}
33
34impl<F> RescueTranscriptVar<F>
35where
36 F: RescueParameter + SWToTEConParam,
37{
38 pub(crate) fn new(circuit: &mut PlonkCircuit<F>) -> Self {
40 Self {
41 transcript_var: Vec::new(),
42 state_var: [circuit.zero(); STATE_SIZE],
43 _phantom: PhantomData,
44 }
45 }
46
47 pub(crate) fn append_vk_and_pub_input_vars<E: Pairing<BaseField = F>>(
49 &mut self,
50 circuit: &mut PlonkCircuit<F>,
51 vk_var: &VerifyingKeyVar<E>,
52 pub_input: &[FpElemVar<F>],
53 ) -> Result<(), CircuitError> {
54 for com in vk_var.selector_comms.iter() {
63 self.transcript_var.push(com.get_x());
65 self.transcript_var.push(com.get_y());
66 }
67 for com in vk_var.sigma_comms.iter() {
69 self.transcript_var.push(com.get_x());
71 self.transcript_var.push(com.get_y());
72 }
73 for e in pub_input {
75 let pub_var = e.convert_to_var(circuit)?;
76 self.transcript_var.push(pub_var)
77 }
78 Ok(())
79 }
80
81 pub(crate) fn append_variable(
84 &mut self,
85 _label: &'static [u8],
86 var: &Variable,
87 ) -> Result<(), CircuitError> {
88 self.transcript_var.push(*var);
89
90 Ok(())
91 }
92
93 pub(crate) fn append_message_vars(
96 &mut self,
97 _label: &'static [u8],
98 msg_vars: &[Variable],
99 ) -> Result<(), CircuitError> {
100 for e in msg_vars.iter() {
101 self.append_variable(_label, e)?;
102 }
103
104 Ok(())
105 }
106
107 pub(crate) fn append_commitment_var(
112 &mut self,
113 _label: &'static [u8],
114 poly_comm_var: &PointVariable,
115 ) -> Result<(), CircuitError> {
116 self.transcript_var.push(poly_comm_var.get_x());
118 self.transcript_var.push(poly_comm_var.get_y());
119
120 Ok(())
121 }
122
123 pub(crate) fn append_commitments_vars(
128 &mut self,
129 _label: &'static [u8],
130 poly_comm_vars: &[PointVariable],
131 ) -> Result<(), CircuitError> {
132 for poly_comm_var in poly_comm_vars.iter() {
133 self.transcript_var.push(poly_comm_var.get_x());
135 self.transcript_var.push(poly_comm_var.get_y());
136 }
137 Ok(())
138 }
139
140 pub(crate) fn append_proof_evaluations_vars(
142 &mut self,
143 circuit: &mut PlonkCircuit<F>,
144 evals: &ProofEvaluationsVar<F>,
145 ) -> Result<(), CircuitError> {
146 for e in &evals.wires_evals {
147 let tmp = e.convert_to_var(circuit)?;
148 self.transcript_var.push(tmp);
149 }
150 for e in &evals.wire_sigma_evals {
151 let tmp = e.convert_to_var(circuit)?;
152 self.transcript_var.push(tmp);
153 }
154 let tmp = evals.perm_next_eval.convert_to_var(circuit)?;
155 self.transcript_var.push(tmp);
156 Ok(())
157 }
158
159 pub(crate) fn get_challenge_var<E>(
167 &mut self,
168 _label: &'static [u8],
169 circuit: &mut PlonkCircuit<F>,
170 ) -> Result<Variable, CircuitError>
171 where
172 E: Pairing,
173 {
174 if !circuit.support_lookup() {
175 return Err(ParameterError("does not support range table".to_string()));
176 }
177
178 if E::ScalarField::MODULUS_BIT_SIZE != 253 || E::BaseField::MODULUS_BIT_SIZE != 377 {
179 return Err(ParameterError(
180 "Curve Parameter does not support for rescue transcript circuit".to_string(),
181 ));
182 }
183
184 let input_var = [self.state_var.as_ref(), self.transcript_var.as_ref()].concat();
193 let res_var =
194 RescueNativeGadget::<F>::rescue_sponge_with_padding(circuit, &input_var, STATE_SIZE)
195 .unwrap();
196 let out_var = res_var[0];
197
198 let challenge_var = circuit.truncate(out_var, 248)?;
200
201 self.state_var.copy_from_slice(&res_var[0..STATE_SIZE]);
204 self.transcript_var = Vec::new();
205
206 Ok(challenge_var)
207 }
208}
209
210#[cfg(test)]
211mod tests {
212 use super::*;
213 use crate::{
214 proof_system::structs::VerifyingKey,
215 transcript::{PlonkTranscript, RescueTranscript},
216 };
217 use ark_bls12_377::Bls12_377;
218 use ark_ec::{
219 short_weierstrass::{Affine, SWCurveConfig},
220 AffineRepr, CurveGroup,
221 };
222 use ark_std::{format, vec, UniformRand};
223 use jf_pcs::prelude::{Commitment, UnivariateVerifierParam};
224 use jf_relation::gadgets::ecc::TEPoint;
225 use jf_utils::{bytes_to_field_elements, field_switching, test_rng};
226
227 const RANGE_BIT_LEN_FOR_TEST: usize = 16;
228 #[test]
229 fn test_rescue_transcript_challenge_circuit() {
230 test_rescue_transcript_challenge_circuit_helper::<Bls12_377, _, _>()
231 }
232 fn test_rescue_transcript_challenge_circuit_helper<E, F, P>()
233 where
234 E: Pairing<BaseField = F, G1Affine = Affine<P>>,
235 F: RescueParameter + SWToTEConParam,
236 P: SWCurveConfig<BaseField = F>,
237 {
238 let mut circuit = PlonkCircuit::<F>::new_ultra_plonk(RANGE_BIT_LEN_FOR_TEST);
239
240 let label = "testing".as_ref();
241
242 let mut transcript_var = RescueTranscriptVar::new(&mut circuit);
243 let mut transcript = RescueTranscript::<F>::new(label);
244
245 for _ in 0..10 {
246 for i in 0..10 {
247 let msg = format!("message {}", i);
248 let vals = bytes_to_field_elements(msg.as_bytes());
249 let message_vars: Vec<Variable> = vals
250 .iter()
251 .map(|x| circuit.create_variable(*x).unwrap())
252 .collect();
253
254 transcript.append_message(label, msg.as_bytes()).unwrap();
255
256 transcript_var
257 .append_message_vars(label, &message_vars)
258 .unwrap();
259 }
260
261 let challenge = transcript.get_challenge::<E>(label).unwrap();
262
263 let challenge_var = transcript_var
264 .get_challenge_var::<E>(label, &mut circuit)
265 .unwrap();
266
267 assert_eq!(
268 circuit.witness(challenge_var).unwrap().into_bigint(),
269 field_switching::<_, F>(&challenge).into_bigint()
270 );
271 }
272 }
273
274 #[test]
275 fn test_rescue_transcript_append_vk_and_input_circuit() {
276 test_rescue_transcript_append_vk_and_input_circuit_helper::<Bls12_377, _, _>()
277 }
278 fn test_rescue_transcript_append_vk_and_input_circuit_helper<E, F, P>()
279 where
280 E: Pairing<BaseField = F, G1Affine = Affine<P>>,
281 F: RescueParameter + SWToTEConParam,
282 P: SWCurveConfig<BaseField = F>,
283 {
284 let mut circuit = PlonkCircuit::<F>::new_ultra_plonk(RANGE_BIT_LEN_FOR_TEST);
285
286 let mut rng = test_rng();
287
288 let label = "testing".as_ref();
289
290 let mut transcript_var = RescueTranscriptVar::new(&mut circuit);
291 let mut transcript = RescueTranscript::<F>::new(label);
292
293 let g = E::G1Affine::generator();
294 let h = E::G2Affine::generator();
295 let beta_h = E::G2::rand(&mut rng).into_affine();
296 let open_key: UnivariateVerifierParam<E> = UnivariateVerifierParam {
297 g,
298 h,
299 beta_h,
300 powers_of_h: vec![h, beta_h],
301 powers_of_g: vec![g],
302 };
303
304 let dummy_vk = VerifyingKey {
305 domain_size: 512,
306 num_inputs: 0,
307 sigma_comms: Vec::new(),
308 selector_comms: Vec::new(),
309 k: Vec::new(),
310 open_key: open_key.clone(),
311 is_merged: false,
312 plookup_vk: None,
313 };
314
315 let dummy_vk_var = VerifyingKeyVar::new(&mut circuit, &dummy_vk).unwrap();
316
317 transcript.append_vk_and_pub_input(&dummy_vk, &[]).unwrap();
319 transcript_var
320 .append_vk_and_pub_input_vars::<E>(&mut circuit, &dummy_vk_var, &[])
321 .unwrap();
322
323 let challenge = transcript.get_challenge::<E>(label).unwrap();
324
325 let challenge_var = transcript_var
326 .get_challenge_var::<E>(label, &mut circuit)
327 .unwrap();
328
329 assert_eq!(
330 circuit.witness(challenge_var).unwrap(),
331 field_switching(&challenge)
332 );
333
334 for _ in 0..10 {
335 let input: Vec<E::ScalarField> =
337 (0..16).map(|_| E::ScalarField::rand(&mut rng)).collect();
338
339 let sigma_comms: Vec<Commitment<E>> = (0..42)
341 .map(|_| Commitment(E::G1::rand(&mut rng).into_affine()))
342 .collect();
343 let mut sigma_comms_vars: Vec<PointVariable> = Vec::new();
344 for e in sigma_comms.iter() {
345 let p: TEPoint<F> = e.0.into();
347 sigma_comms_vars.push(circuit.create_point_variable(p).unwrap());
348 }
349
350 let selector_comms: Vec<Commitment<E>> = (0..33)
352 .map(|_| Commitment(E::G1::rand(&mut rng).into_affine()))
353 .collect();
354 let mut selector_comms_vars: Vec<PointVariable> = Vec::new();
355 for e in selector_comms.iter() {
356 let p: TEPoint<F> = e.0.into();
358 selector_comms_vars.push(circuit.create_point_variable(p).unwrap());
359 }
360
361 let k: Vec<E::ScalarField> = (0..5).map(|_| E::ScalarField::rand(&mut rng)).collect();
363
364 let vk = VerifyingKey {
365 domain_size: 512,
366 num_inputs: input.len(),
367 sigma_comms,
368 selector_comms,
369 k,
370 open_key: open_key.clone(),
371 is_merged: false,
372 plookup_vk: None,
373 };
374 let vk_var = VerifyingKeyVar::new(&mut circuit, &vk).unwrap();
375
376 transcript.append_vk_and_pub_input(&vk, &input).unwrap();
378 let m = 128;
379 let input_vars: Vec<Variable> = input
380 .iter()
381 .map(|&x| circuit.create_public_variable(field_switching(&x)).unwrap())
382 .collect();
383
384 let input_fp_elem_vars: Vec<FpElemVar<F>> = input_vars
385 .iter()
386 .map(|&x| FpElemVar::new_unchecked(&mut circuit, x, m, None).unwrap())
387 .collect();
388 transcript_var
389 .append_vk_and_pub_input_vars::<E>(&mut circuit, &vk_var, &input_fp_elem_vars)
390 .unwrap();
391
392 let challenge = transcript.get_challenge::<E>(label).unwrap();
393
394 let challenge_var = transcript_var
395 .get_challenge_var::<E>(label, &mut circuit)
396 .unwrap();
397
398 assert_eq!(
399 circuit.witness(challenge_var).unwrap(),
400 field_switching(&challenge)
401 );
402 }
403 }
404}