arcis_compiler/utils/zkp/
transcript.rs1use crate::{
4 core::{
5 circuits::boolean::{
6 boolean_value::{Boolean, BooleanValue},
7 byte::Byte,
8 },
9 global_value::{curve_value::CompressedCurveValue, value::FieldValue},
10 },
11 traits::{FromLeBits, ToLeBytes},
12 utils::{
13 field::ScalarField,
14 zkp::{
15 elgamal::ElGamalCiphertext,
16 grouped_elgamal::{
17 GroupedElGamalCiphertext2Handles,
18 GroupedElGamalCiphertext3Handles,
19 GROUPED_ELGAMAL_CIPHERTEXT_2_HANDLES_LEN,
20 GROUPED_ELGAMAL_CIPHERTEXT_3_HANDLES_LEN,
21 },
22 strobe::Strobe128,
23 },
24 },
25};
26use zk_elgamal_proof::encryption::{
27 DECRYPT_HANDLE_LEN,
28 ELGAMAL_CIPHERTEXT_LEN,
29 PEDERSEN_COMMITMENT_LEN,
30};
31
32pub const MERLIN_PROTOCOL_LABEL: &[u8] = b"Merlin v1.0";
39
40fn encode_u64(x: u64) -> [u8; 8] {
41 use byteorder::{ByteOrder, LittleEndian};
42
43 let mut buf = [0; 8];
44 LittleEndian::write_u64(&mut buf, x);
45 buf
46}
47
48fn encode_usize_as_u32(x: usize) -> [u8; 4] {
49 use byteorder::{ByteOrder, LittleEndian};
50
51 assert!(x <= (u32::MAX as usize));
52
53 let mut buf = [0; 4];
54 LittleEndian::write_u32(&mut buf, x as u32);
55 buf
56}
57
58#[derive(Clone)]
88pub struct Transcript<B: Boolean> {
89 strobe: Strobe128<B>,
90}
91
92impl<B: Boolean> Transcript<B> {
93 pub fn new(label: &'static [u8]) -> Transcript<B> {
104 let mut transcript = Transcript {
105 strobe: Strobe128::new(MERLIN_PROTOCOL_LABEL),
106 };
107 transcript.append_message(
108 b"dom-sep",
109 &label
110 .iter()
111 .copied()
112 .map(Byte::<B>::from)
113 .collect::<Vec<Byte<B>>>(),
114 );
115
116 transcript
117 }
118
119 pub fn append_message(&mut self, label: &'static [u8], message: &[Byte<B>]) {
126 let data_len = encode_usize_as_u32(message.len());
127 self.strobe.meta_ad(label, false);
128 self.strobe.meta_ad(&data_len, true);
129 self.strobe.ad(message, false);
130 }
131
132 fn append_u64(&mut self, label: &'static [u8], x: u64) {
144 self.append_message(
145 label,
146 &encode_u64(x)
147 .into_iter()
148 .map(Byte::<B>::from)
149 .collect::<Vec<Byte<B>>>(),
150 );
151 }
152
153 pub fn challenge_bytes(&mut self, label: &'static [u8], dest: &mut [Byte<B>]) {
160 let data_len = encode_usize_as_u32(dest.len());
161 self.strobe.meta_ad(label, false);
162 self.strobe.meta_ad(&data_len, true);
163 self.strobe.prf(dest, false);
164 }
165
166 pub fn range_proof_domain_separator(&mut self, n: u64) {
167 self.append_message(
168 b"dom-sep",
169 &b"range-proof"
170 .iter()
171 .copied()
172 .map(Byte::<B>::from)
173 .collect::<Vec<Byte<B>>>(),
174 );
175 self.append_u64(b"n", n);
176 }
177
178 pub fn inner_product_proof_domain_separator(&mut self, n: u64) {
179 self.append_message(
180 b"dom-sep",
181 &b"inner-product"
182 .iter()
183 .copied()
184 .map(Byte::<B>::from)
185 .collect::<Vec<Byte<B>>>(),
186 );
187 self.append_u64(b"n", n);
188 }
189
190 pub fn ciphertext_commitment_equality_proof_domain_separator(&mut self) {
191 self.append_message(
192 b"dom-sep",
193 &b"ciphertext-commitment-equality-proof"
194 .iter()
195 .copied()
196 .map(Byte::<B>::from)
197 .collect::<Vec<Byte<B>>>(),
198 )
199 }
200
201 pub fn zero_ciphertext_proof_domain_separator(&mut self) {
202 self.append_message(
203 b"dom-sep",
204 &b"zero-ciphertext-proof"
205 .iter()
206 .copied()
207 .map(Byte::<B>::from)
208 .collect::<Vec<Byte<B>>>(),
209 )
210 }
211
212 pub fn grouped_ciphertext_validity_proof_domain_separator(&mut self, handles: u64) {
213 self.append_message(
214 b"dom-sep",
215 &b"validity-proof"
216 .iter()
217 .copied()
218 .map(Byte::<B>::from)
219 .collect::<Vec<Byte<B>>>(),
220 );
221 self.append_u64(b"handles", handles);
222 }
223
224 pub fn batched_grouped_ciphertext_validity_proof_domain_separator(&mut self, handles: u64) {
225 self.append_message(
226 b"dom-sep",
227 &b"batched-validity-proof"
228 .iter()
229 .copied()
230 .map(Byte::<B>::from)
231 .collect::<Vec<Byte<B>>>(),
232 );
233 self.append_u64(b"handles", handles);
234 }
235
236 pub fn percentage_with_cap_proof_domain_separator(&mut self) {
237 self.append_message(
238 b"dom-sep",
239 &b"percentage-with-cap-proof"
240 .iter()
241 .copied()
242 .map(Byte::<B>::from)
243 .collect::<Vec<Byte<B>>>(),
244 )
245 }
246
247 pub fn pubkey_proof_domain_separator(&mut self) {
248 self.append_message(
249 b"dom-sep",
250 &b"pubkey-proof"
251 .iter()
252 .copied()
253 .map(Byte::<B>::from)
254 .collect::<Vec<Byte<B>>>(),
255 )
256 }
257}
258
259impl Transcript<BooleanValue> {
260 pub fn append_scalar(&mut self, label: &'static [u8], scalar: &FieldValue<ScalarField>) {
261 self.append_message(label, &scalar.to_le_bytes());
262 }
263
264 pub fn append_point(&mut self, label: &'static [u8], point: &CompressedCurveValue) {
265 self.append_message(label, &point.to_bytes());
266 }
267
268 pub fn append_elgamal_ciphertext(
269 &mut self,
270 label: &'static [u8],
271 ciphertext: &ElGamalCiphertext,
272 ) {
273 let mut bytes = [Byte::<BooleanValue>::from(0u8); ELGAMAL_CIPHERTEXT_LEN];
274 bytes[..PEDERSEN_COMMITMENT_LEN]
275 .copy_from_slice(&ciphertext.commitment.get_point().compress().to_bytes());
276 bytes[PEDERSEN_COMMITMENT_LEN..]
277 .copy_from_slice(&ciphertext.handle.get_point().compress().to_bytes());
278 self.append_message(label, &bytes);
279 }
280
281 pub fn append_elgamal_ciphertext_2_handles(
282 &mut self,
283 label: &'static [u8],
284 ciphertext: &GroupedElGamalCiphertext2Handles,
285 ) {
286 let mut bytes = [Byte::<BooleanValue>::from(0u8); GROUPED_ELGAMAL_CIPHERTEXT_2_HANDLES_LEN];
287 bytes[..PEDERSEN_COMMITMENT_LEN]
288 .copy_from_slice(&ciphertext.0.commitment.get_point().compress().to_bytes());
289 let mut offset = PEDERSEN_COMMITMENT_LEN;
290 for i in 0..2 {
291 bytes[offset..offset + DECRYPT_HANDLE_LEN]
292 .copy_from_slice(&ciphertext.0.handles[i].get_point().compress().to_bytes());
293 offset += DECRYPT_HANDLE_LEN;
294 }
295 self.append_message(label, &bytes);
296 }
297
298 pub fn append_elgamal_ciphertext_3_handles(
299 &mut self,
300 label: &'static [u8],
301 ciphertext: &GroupedElGamalCiphertext3Handles,
302 ) {
303 let mut bytes = [Byte::<BooleanValue>::from(0u8); GROUPED_ELGAMAL_CIPHERTEXT_3_HANDLES_LEN];
304 bytes[..PEDERSEN_COMMITMENT_LEN]
305 .copy_from_slice(&ciphertext.0.commitment.get_point().compress().to_bytes());
306 let mut offset = PEDERSEN_COMMITMENT_LEN;
307 for i in 0..3 {
308 bytes[offset..offset + DECRYPT_HANDLE_LEN]
309 .copy_from_slice(&ciphertext.0.handles[i].get_point().compress().to_bytes());
310 offset += DECRYPT_HANDLE_LEN;
311 }
312 self.append_message(label, &bytes);
313 }
314
315 pub fn challenge_scalar(&mut self, label: &'static [u8]) -> FieldValue<ScalarField> {
316 let mut buf = [Byte::from(0u8); 64];
317 self.challenge_bytes(label, &mut buf);
318 let buf_bits = buf
319 .into_iter()
320 .flat_map(|byte| byte.to_vec())
321 .collect::<Vec<BooleanValue>>();
322
323 FieldValue::<ScalarField>::from_le_bits(buf_bits, false)
324 }
325}