diff --git a/plonk/src/circuit/plonk_verifier/gadgets.rs b/plonk/src/circuit/plonk_verifier/gadgets.rs index b6cbf0d5e..e02ee56c7 100644 --- a/plonk/src/circuit/plonk_verifier/gadgets.rs +++ b/plonk/src/circuit/plonk_verifier/gadgets.rs @@ -6,7 +6,10 @@ //! Circuits for the building blocks in Plonk verifiers. use crate::{ - circuit::{plonk_verifier::*, transcript::RescueTranscriptVar}, + circuit::{ + plonk_verifier::*, + transcript::{RescueTranscriptLabelVar, RescueTranscriptVar}, + }, constants::EXTRA_TRANSCRIPT_MSG_LABEL, errors::PlonkError, }; @@ -205,42 +208,65 @@ where public_inputs.len(), ))); } - let mut transcript_var = RescueTranscriptVar::new(circuit); + let extra_transcript_msg_label_var = + RescueTranscriptLabelVar::new(circuit, EXTRA_TRANSCRIPT_MSG_LABEL)?; + let mut transcript_var = RescueTranscriptVar::new(circuit, &extra_transcript_msg_label_var); if let Some(msg) = extra_transcript_init_msg { let msg_fs = bytes_to_field_elements::<_, F>(msg); let msg_vars = msg_fs .iter() .map(|x| circuit.create_variable(*x)) .collect::, _>>()?; - transcript_var.append_message_vars(EXTRA_TRANSCRIPT_MSG_LABEL, &msg_vars)?; + transcript_var.append_message_vars(&extra_transcript_msg_label_var, &msg_vars)?; } for (&vk, &pi) in verify_keys.iter().zip(public_inputs.iter()) { transcript_var.append_vk_and_pub_input_vars::(circuit, vk, pi)?; } + let witness_poly_comms_label_var = + RescueTranscriptLabelVar::new(circuit, b"witness_poly_comms")?; for wires_poly_comms in batch_proof.wires_poly_comms_vec.iter() { - transcript_var.append_commitments_vars::(b"witness_poly_comms", wires_poly_comms)?; + transcript_var + .append_commitments_vars::(&witness_poly_comms_label_var, wires_poly_comms)?; } - let tau = transcript_var.get_and_append_challenge_var::(b"tau", circuit)?; - - let beta = transcript_var.get_and_append_challenge_var::(b"beta", circuit)?; - let gamma = transcript_var.get_and_append_challenge_var::(b"gamma", circuit)?; + let tau_label_var = RescueTranscriptLabelVar::new(circuit, b"tau")?; + let tau = transcript_var.get_and_append_challenge_var::(&tau_label_var, circuit)?; + + let beta_label_var = RescueTranscriptLabelVar::new(circuit, b"beta")?; + let gamma_label_var = RescueTranscriptLabelVar::new(circuit, b"gamma")?; + let beta = transcript_var.get_and_append_challenge_var::(&beta_label_var, circuit)?; + let gamma = transcript_var.get_and_append_challenge_var::(&gamma_label_var, circuit)?; + let perm_poly_comms_label_var = RescueTranscriptLabelVar::new(circuit, b"perm_poly_comms")?; for prod_perm_poly_comm in batch_proof.prod_perm_poly_comms_vec.iter() { - transcript_var.append_commitment_var::(b"perm_poly_comms", prod_perm_poly_comm)?; + transcript_var + .append_commitment_var::(&perm_poly_comms_label_var, prod_perm_poly_comm)?; } - let alpha = transcript_var.get_and_append_challenge_var::(b"alpha", circuit)?; - transcript_var - .append_commitments_vars::(b"quot_poly_comms", &batch_proof.split_quot_poly_comms)?; - let zeta = transcript_var.get_and_append_challenge_var::(b"zeta", circuit)?; + let alpha_label_var = RescueTranscriptLabelVar::new(circuit, b"alpha")?; + let zeta_label_var = RescueTranscriptLabelVar::new(circuit, b"zeta")?; + let alpha = transcript_var.get_and_append_challenge_var::(&alpha_label_var, circuit)?; + let quot_poly_comms_label_var = RescueTranscriptLabelVar::new(circuit, b"quot_poly_comms")?; + transcript_var.append_commitments_vars::( + "_poly_comms_label_var, + &batch_proof.split_quot_poly_comms, + )?; + let zeta = transcript_var.get_and_append_challenge_var::(&zeta_label_var, circuit)?; for poly_evals in batch_proof.poly_evals_vec.iter() { transcript_var.append_proof_evaluations_vars::(circuit, poly_evals)?; } - let v = transcript_var.get_and_append_challenge_var::(b"v", circuit)?; - transcript_var.append_commitment_var::(b"open_proof", &batch_proof.opening_proof)?; + let v_label_var = RescueTranscriptLabelVar::new(circuit, b"v")?; + let v = transcript_var.get_and_append_challenge_var::(&v_label_var, circuit)?; + let open_proof_label_var = RescueTranscriptLabelVar::new(circuit, b"open_proof")?; + let shifted_open_proof_label_var = + RescueTranscriptLabelVar::new(circuit, b"shifted_open_proof")?; transcript_var - .append_commitment_var::(b"shifted_open_proof", &batch_proof.shifted_opening_proof)?; - let u = transcript_var.get_and_append_challenge_var::(b"u", circuit)?; + .append_commitment_var::(&open_proof_label_var, &batch_proof.opening_proof)?; + transcript_var.append_commitment_var::( + &shifted_open_proof_label_var, + &batch_proof.shifted_opening_proof, + )?; + let u_label_var = RescueTranscriptLabelVar::new(circuit, b"u")?; + let u = transcript_var.get_and_append_challenge_var::(&u_label_var, circuit)?; // convert challenge vars into FpElemVars let challenge_var = ChallengesVar { diff --git a/plonk/src/circuit/transcript.rs b/plonk/src/circuit/transcript.rs index 6e3bb9a07..4c0e26efa 100644 --- a/plonk/src/circuit/transcript.rs +++ b/plonk/src/circuit/transcript.rs @@ -23,6 +23,7 @@ use jf_relation::{ }, Circuit, PlonkCircuit, Variable, }; +use jf_utils::bytes_to_field_elements; /// Struct of variables representing a Rescue transcript type, including /// `STATE_SIZE` variables for the state, and a vector of variables for @@ -33,14 +34,44 @@ pub struct RescueTranscriptVar { _phantom: PhantomData, } +/// Variable for Rescue transcript label +pub struct RescueTranscriptLabelVar { + vars: Vec, + _phantom: PhantomData, +} + +impl AsRef<[Variable]> for RescueTranscriptLabelVar { + fn as_ref(&self) -> &[Variable] { + &self.vars + } +} + +impl RescueTranscriptLabelVar { + /// create a new RescueTranscriptLabelVar for a given circuit + pub(crate) fn new( + circuit: &mut PlonkCircuit, + label: &'static [u8], + ) -> Result { + let vars_result: Result, CircuitError> = bytes_to_field_elements(label) + .into_iter() + .map(|f| circuit.create_public_variable(f)) + .collect(); + let vars = vars_result?; + Ok(Self { + vars, + _phantom: PhantomData::default(), + }) + } +} + impl RescueTranscriptVar where F: RescueParameter + SWToTEConParam, { /// create a new RescueTranscriptVar for a given circuit. - pub(crate) fn new(circuit: &mut PlonkCircuit) -> Self { + pub(crate) fn new(circuit: &mut PlonkCircuit, label: &RescueTranscriptLabelVar) -> Self { Self { - transcript_var: Vec::new(), + transcript_var: label.as_ref().to_vec(), state_var: [circuit.zero(); STATE_SIZE], _phantom: PhantomData::default(), } @@ -84,9 +115,10 @@ where // For efficiency purpose, label is not used for rescue FS. pub(crate) fn append_variable( &mut self, - _label: &'static [u8], + label: &RescueTranscriptLabelVar, var: &Variable, ) -> Result<(), CircuitError> { + self.transcript_var.extend_from_slice(label.as_ref()); self.transcript_var.push(*var); Ok(()) @@ -94,13 +126,14 @@ where // Append the message variables to the transcript. // For efficiency purpose, label is not used for rescue FS. + // TODO(Chengyu): fix the bug here. pub(crate) fn append_message_vars( &mut self, - _label: &'static [u8], + label: &RescueTranscriptLabelVar, msg_vars: &[Variable], ) -> Result<(), CircuitError> { for e in msg_vars.iter() { - self.append_variable(_label, e)?; + self.append_variable(label, e)?; } Ok(()) @@ -112,13 +145,14 @@ where // For efficiency purpose, label is not used for rescue FS. pub(crate) fn append_commitment_var( &mut self, - _label: &'static [u8], + label: &RescueTranscriptLabelVar, poly_comm_var: &PointVariable, ) -> Result<(), CircuitError> where E: PairingEngine>, P: SWModelParameters, { + self.transcript_var.extend_from_slice(label.as_ref()); // push the x and y coordinate of comm to the transcript self.transcript_var.push(poly_comm_var.get_x()); self.transcript_var.push(poly_comm_var.get_y()); @@ -132,13 +166,14 @@ where // transcript For efficiency purpose, label is not used for rescue FS. pub(crate) fn append_commitments_vars( &mut self, - _label: &'static [u8], + label: &RescueTranscriptLabelVar, poly_comm_vars: &[PointVariable], ) -> Result<(), CircuitError> where E: PairingEngine>, P: SWModelParameters, { + self.transcript_var.extend_from_slice(label.as_ref()); for poly_comm_var in poly_comm_vars.iter() { // push the x and y coordinate of comm to the transcript self.transcript_var.push(poly_comm_var.get_x()); @@ -151,10 +186,10 @@ where // For efficiency purpose, label is not used for rescue FS. pub(crate) fn append_challenge_var( &mut self, - _label: &'static [u8], + label: &RescueTranscriptLabelVar, challenge_var: &Variable, ) -> Result<(), CircuitError> { - self.append_variable(_label, challenge_var) + self.append_variable(label, challenge_var) } // Append the proof evaluation to the transcript @@ -183,7 +218,7 @@ where // curve due to its decomposition method. pub(crate) fn get_and_append_challenge_var( &mut self, - _label: &'static [u8], + label: &RescueTranscriptLabelVar, circuit: &mut PlonkCircuit, ) -> Result where @@ -220,7 +255,7 @@ where // finish and update the states self.state_var.copy_from_slice(&res_var[0..STATE_SIZE]); self.transcript_var = Vec::new(); - self.append_challenge_var(_label, &challenge_var)?; + self.append_challenge_var(label, &challenge_var)?; Ok(challenge_var) } @@ -254,8 +289,9 @@ mod tests { let mut circuit = PlonkCircuit::::new_ultra_plonk(RANGE_BIT_LEN_FOR_TEST); let label = "testing".as_ref(); + let label_var = RescueTranscriptLabelVar::new(&mut circuit, &label).unwrap(); - let mut transcipt_var = RescueTranscriptVar::new(&mut circuit); + let mut transcipt_var = RescueTranscriptVar::new(&mut circuit, &label_var); let mut transcript = RescueTranscript::::new(label); for _ in 0..10 { @@ -270,16 +306,18 @@ mod tests { transcript.append_message(label, msg.as_bytes()).unwrap(); transcipt_var - .append_message_vars(label, &message_vars) + .append_message_vars(&label_var, &message_vars) .unwrap(); } let challenge = transcript.get_and_append_challenge::(label).unwrap(); let challenge_var = transcipt_var - .get_and_append_challenge_var::(label, &mut circuit) + .get_and_append_challenge_var::(&label_var, &mut circuit) .unwrap(); + ark_std::println!("{:?}", field_switching::<_, F>(&challenge).into_repr()); + ark_std::println!("{:?}", circuit.witness(challenge_var).unwrap().into_repr()); assert_eq!( circuit.witness(challenge_var).unwrap().into_repr(), field_switching::<_, F>(&challenge).into_repr() @@ -302,8 +340,9 @@ mod tests { let mut rng = test_rng(); let label = "testing".as_ref(); + let label_var = RescueTranscriptLabelVar::new(&mut circuit, label).unwrap(); - let mut transcript_var = RescueTranscriptVar::new(&mut circuit); + let mut transcript_var = RescueTranscriptVar::new(&mut circuit, &label_var); let mut transcript = RescueTranscript::::new(label); let open_key: UnivariateVerifierParam = UnivariateVerifierParam { @@ -334,7 +373,7 @@ mod tests { let challenge = transcript.get_and_append_challenge::(label).unwrap(); let challenge_var = transcript_var - .get_and_append_challenge_var::(label, &mut circuit) + .get_and_append_challenge_var::(&label_var, &mut circuit) .unwrap(); assert_eq!( @@ -402,7 +441,7 @@ mod tests { let challenge = transcript.get_and_append_challenge::(label).unwrap(); let challenge_var = transcript_var - .get_and_append_challenge_var::(label, &mut circuit) + .get_and_append_challenge_var::(&label_var, &mut circuit) .unwrap(); assert_eq!( diff --git a/plonk/src/transcript/rescue.rs b/plonk/src/transcript/rescue.rs index 06e81c9f9..1acb7db1c 100644 --- a/plonk/src/transcript/rescue.rs +++ b/plonk/src/transcript/rescue.rs @@ -47,10 +47,10 @@ impl PlonkTranscript for RescueTranscript where F: RescueParameter + SWToTEConParam, { - /// Create a new plonk transcript. `_label` is omitted for efficiency. - fn new(_label: &'static [u8]) -> Self { + /// Create a new plonk transcript. + fn new(label: &'static [u8]) -> Self { RescueTranscript { - transcript: Vec::new(), + transcript: bytes_to_field_elements(label).to_vec(), state: [F::zero(); STATE_SIZE], } } @@ -93,27 +93,31 @@ where Ok(()) } - /// Append the message to the transcript. `_label` is omitted for - /// efficiency. - fn append_message(&mut self, _label: &'static [u8], msg: &[u8]) -> Result<(), PlonkError> { - // We remove the labels for better efficiency - - let mut f = bytes_to_field_elements(&msg); - self.transcript.append(&mut f); + /// Append the message to the transcript. + /// TODO(Chengyu): fix the bug here, current design brings trouble to the + /// gadget implementation. First, label, msg_len and msg shouldn't be + /// composed together before being converted into field elements. + /// Second, we should either remove the msg_len from transcript or find a + /// way to input it in the gadget design. + fn append_message(&mut self, label: &'static [u8], msg: &[u8]) -> Result<(), PlonkError> { + let bytes = [label, &msg.len().to_le_bytes(), msg].concat(); + self.transcript + .extend_from_slice(&bytes_to_field_elements(&bytes)); Ok(()) } - /// Append a single commitment to the transcript. `_label` is omitted for - /// efficiency. + /// Append a single commitment to the transcript. fn append_commitment( &mut self, - _label: &'static [u8], + label: &'static [u8], comm: &Commitment, ) -> Result<(), PlonkError> where E: PairingEngine>, P: SWParam, { + self.transcript + .extend_from_slice(&bytes_to_field_elements(label)); // convert the SW form commitments into TE form let te_point: Point = (&comm.0).into(); // push the x and y coordinate of comm (in twisted @@ -124,16 +128,17 @@ where Ok(()) } - /// Append a challenge to the transcript. `_label` is omitted for - /// efficiency. + /// Append a challenge to the transcript. fn append_challenge( &mut self, - _label: &'static [u8], + label: &'static [u8], challenge: &E::Fr, ) -> Result<(), PlonkError> where E: PairingEngine, { + self.transcript + .extend_from_slice(bytes_to_field_elements(label).as_ref()); self.transcript.push(field_switching(challenge)); Ok(()) } @@ -166,21 +171,20 @@ where } /// Generate the challenge for the current transcript, - /// and then append it to the transcript. `_label` is omitted for - /// efficiency. - fn get_and_append_challenge(&mut self, _label: &'static [u8]) -> Result + /// and then append it to the transcript. + fn get_and_append_challenge(&mut self, label: &'static [u8]) -> Result where E: PairingEngine, { // 1. state: [F: STATE_SIZE] = hash(state|transcript) // 2. challenge = state[0] in Fr - // 3. transcript = Vec::new() + // 3. transcript = [label] let input = [self.state.as_ref(), self.transcript.as_ref()].concat(); let tmp: [F; STATE_SIZE] = VariableLengthRescueCRHF::evaluate(&input)?; let challenge = fq_to_fr_with_mask::(&tmp[0]); self.state.copy_from_slice(&tmp); - self.transcript = Vec::new(); + self.transcript = bytes_to_field_elements(label).to_vec(); self.transcript.push(field_switching(&challenge)); Ok(challenge) diff --git a/plonk/src/transcript/solidity.rs b/plonk/src/transcript/solidity.rs index 7b864f8a1..44daf63e8 100644 --- a/plonk/src/transcript/solidity.rs +++ b/plonk/src/transcript/solidity.rs @@ -34,29 +34,31 @@ pub struct SolidityTranscript { } impl PlonkTranscript for SolidityTranscript { - /// Create a new plonk transcript. `label` is omitted for efficiency. - fn new(_label: &'static [u8]) -> Self { + /// Create a new plonk transcript. + fn new(label: &'static [u8]) -> Self { SolidityTranscript { - transcript: Vec::new(), + transcript: label.to_vec(), state: [0u8; KECCAK256_STATE_SIZE], } } - /// Append the message to the transcript. `_label` is omitted for - /// efficiency. - fn append_message(&mut self, _label: &'static [u8], msg: &[u8]) -> Result<(), PlonkError> { - // We remove the labels for better efficiency + /// Append the message to the transcript. + fn append_message(&mut self, label: &'static [u8], msg: &[u8]) -> Result<(), PlonkError> { + self.transcript.extend_from_slice(label); + self.transcript + .extend_from_slice(msg.len().to_le_bytes().as_ref()); self.transcript.extend_from_slice(msg); Ok(()) } /// Generate the challenge for the current transcript, - /// and then append it to the transcript. `_label` is omitted for - /// efficiency. - fn get_and_append_challenge(&mut self, _label: &'static [u8]) -> Result + /// and then append it to the transcript. + fn get_and_append_challenge(&mut self, label: &'static [u8]) -> Result where E: PairingEngine, { + self.transcript.extend_from_slice(label); + // 1. state = keccak256(state|transcript|0) || keccak256(state|transcript|1) let input0 = [self.state.as_ref(), self.transcript.as_ref(), &[0u8]].concat(); let input1 = [self.state.as_ref(), self.transcript.as_ref(), &[1u8]].concat();