jf_plonk/transcript/
solidity.rs1use super::PlonkTranscript;
9use crate::{
10 constants::KECCAK256_STATE_SIZE, errors::PlonkError, proof_system::structs::VerifyingKey,
11};
12use ark_ec::{
13 pairing::Pairing,
14 short_weierstrass::{Affine, SWCurveConfig},
15 AffineRepr,
16};
17use ark_ff::{BigInteger, PrimeField};
18use ark_std::vec::Vec;
19use jf_pcs::prelude::Commitment;
20use jf_utils::to_bytes;
21use sha3::{Digest, Keccak256};
22
23pub struct SolidityTranscript {
33 pub(crate) state: [u8; KECCAK256_STATE_SIZE],
34 pub(crate) transcript: Vec<u8>,
35}
36
37impl<F: PrimeField> PlonkTranscript<F> for SolidityTranscript {
38 fn new(_label: &'static [u8]) -> Self {
40 SolidityTranscript {
41 state: [0u8; KECCAK256_STATE_SIZE],
42 transcript: Vec::new(),
43 }
44 }
45 fn append_message(&mut self, _label: &'static [u8], msg: &[u8]) -> Result<(), PlonkError> {
48 self.transcript.extend_from_slice(msg);
50 Ok(())
51 }
52
53 fn append_commitment<E, P>(
55 &mut self,
56 label: &'static [u8],
57 comm: &Commitment<E>,
58 ) -> Result<(), PlonkError>
59 where
60 E: Pairing<BaseField = F, G1Affine = Affine<P>>,
61 P: SWCurveConfig<BaseField = F>,
62 {
63 let zero = F::zero();
64 let (x, y) = if comm.0.is_zero() {
65 (&zero, &zero)
67 } else {
68 comm.0.xy().unwrap()
69 };
70
71 <Self as PlonkTranscript<F>>::append_message(
72 self,
73 label,
74 &[x.into_bigint().to_bytes_be(), y.into_bigint().to_bytes_be()].concat(),
75 )
76 }
77
78 fn append_field_elem<E>(
80 &mut self,
81 label: &'static [u8],
82 challenge: &E::ScalarField,
83 ) -> Result<(), PlonkError>
84 where
85 E: Pairing<BaseField = F>,
86 {
87 <Self as PlonkTranscript<F>>::append_message(
88 self,
89 label,
90 &challenge.into_bigint().to_bytes_be(),
91 )
92 }
93
94 fn append_vk_and_pub_input<E, P>(
95 &mut self,
96 vk: &VerifyingKey<E>,
97 pub_input: &[E::ScalarField],
98 ) -> Result<(), PlonkError>
99 where
100 E: Pairing<BaseField = F, G1Affine = Affine<P>>,
101 E::ScalarField: PrimeField,
102 P: SWCurveConfig<BaseField = F>,
103 {
104 <Self as PlonkTranscript<F>>::append_message(
105 self,
106 b"field size in bits",
107 E::ScalarField::MODULUS_BIT_SIZE.to_be_bytes().as_ref(),
108 )?;
109 <Self as PlonkTranscript<F>>::append_message(
110 self,
111 b"domain size",
112 vk.domain_size.to_be_bytes().as_ref(),
113 )?;
114 <Self as PlonkTranscript<F>>::append_message(
115 self,
116 b"input size",
117 vk.num_inputs.to_be_bytes().as_ref(),
118 )?;
119 <Self as PlonkTranscript<F>>::append_message(
123 self,
124 b"EVM word alignment padding",
125 &[0u8; 12],
126 )?;
127
128 <Self as PlonkTranscript<F>>::append_message(
137 self,
138 b"SRS G2 element",
139 &to_bytes!(&vk.open_key.powers_of_h[1])?,
140 )?;
141
142 self.append_field_elems::<E>(b"wire subsets separators", &vk.k)?;
143 self.append_commitments(b"selector commitments", &vk.selector_comms)?;
144 self.append_commitments(b"sigma commitments", &vk.sigma_comms)?;
145 self.append_field_elems::<E>(b"public input", pub_input)
146 }
147
148 fn get_challenge<E>(&mut self, _label: &'static [u8]) -> Result<E::ScalarField, PlonkError>
149 where
150 E: Pairing<BaseField = F>,
151 E::ScalarField: PrimeField,
152 {
153 let mut hasher = Keccak256::new();
155 hasher.update(self.state);
156 hasher.update(&self.transcript);
157 let buf = hasher.finalize();
158 self.state.copy_from_slice(&buf);
159
160 self.transcript = Vec::new();
162
163 Ok(E::ScalarField::from_be_bytes_mod_order(&buf))
165 }
166}
167
168#[test]
169fn test_solidity_keccak() {
170 use hex::FromHex;
171 use sha3::{Digest, Keccak256};
172 let message = "the quick brown fox jumps over the lazy dog".as_bytes();
173
174 let mut hasher = Keccak256::new();
175 hasher.update(message);
176 let output = hasher.finalize();
177
178 assert_eq!(
180 output[..],
181 <[u8; 32]>::from_hex("865bf05cca7ba26fb8051e8366c6d19e21cadeebe3ee6bfa462b5c72275414ec")
182 .unwrap()
183 );
184}