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 GroupedElGamalCiphertext3Handles,
18 GROUPED_ELGAMAL_CIPHERTEXT_3_HANDLES_LEN,
19 },
20 strobe::Strobe128,
21 },
22 },
23};
24use zk_elgamal_proof::encryption::{
25 DECRYPT_HANDLE_LEN,
26 ELGAMAL_CIPHERTEXT_LEN,
27 PEDERSEN_COMMITMENT_LEN,
28};
29
30pub const MERLIN_PROTOCOL_LABEL: &[u8] = b"Merlin v1.0";
37
38fn encode_u64(x: u64) -> [u8; 8] {
39 use byteorder::{ByteOrder, LittleEndian};
40
41 let mut buf = [0; 8];
42 LittleEndian::write_u64(&mut buf, x);
43 buf
44}
45
46fn encode_usize_as_u32(x: usize) -> [u8; 4] {
47 use byteorder::{ByteOrder, LittleEndian};
48
49 assert!(x <= (u32::MAX as usize));
50
51 let mut buf = [0; 4];
52 LittleEndian::write_u32(&mut buf, x as u32);
53 buf
54}
55
56#[derive(Clone)]
86pub struct Transcript<B: Boolean> {
87 strobe: Strobe128<B>,
88}
89
90impl<B: Boolean> Transcript<B> {
91 pub fn new(label: &'static [u8]) -> Transcript<B> {
102 let mut transcript = Transcript {
103 strobe: Strobe128::new(MERLIN_PROTOCOL_LABEL),
104 };
105 transcript.append_message(
106 b"dom-sep",
107 &label
108 .iter()
109 .copied()
110 .map(Byte::<B>::from)
111 .collect::<Vec<Byte<B>>>(),
112 );
113
114 transcript
115 }
116
117 pub fn append_message(&mut self, label: &'static [u8], message: &[Byte<B>]) {
124 let data_len = encode_usize_as_u32(message.len());
125 self.strobe.meta_ad(label, false);
126 self.strobe.meta_ad(&data_len, true);
127 self.strobe.ad(message, false);
128 }
129
130 fn append_u64(&mut self, label: &'static [u8], x: u64) {
142 self.append_message(
143 label,
144 &encode_u64(x)
145 .into_iter()
146 .map(Byte::<B>::from)
147 .collect::<Vec<Byte<B>>>(),
148 );
149 }
150
151 pub fn challenge_bytes(&mut self, label: &'static [u8], dest: &mut [Byte<B>]) {
158 let data_len = encode_usize_as_u32(dest.len());
159 self.strobe.meta_ad(label, false);
160 self.strobe.meta_ad(&data_len, true);
161 self.strobe.prf(dest, false);
162 }
163
164 pub fn range_proof_domain_separator(&mut self, n: u64) {
165 self.append_message(
166 b"dom-sep",
167 &b"range-proof"
168 .iter()
169 .copied()
170 .map(Byte::<B>::from)
171 .collect::<Vec<Byte<B>>>(),
172 );
173 self.append_u64(b"n", n);
174 }
175
176 pub fn inner_product_proof_domain_separator(&mut self, n: u64) {
177 self.append_message(
178 b"dom-sep",
179 &b"inner-product"
180 .iter()
181 .copied()
182 .map(Byte::<B>::from)
183 .collect::<Vec<Byte<B>>>(),
184 );
185 self.append_u64(b"n", n);
186 }
187
188 pub fn ciphertext_commitment_equality_proof_domain_separator(&mut self) {
189 self.append_message(
190 b"dom-sep",
191 &b"ciphertext-commitment-equality-proof"
192 .iter()
193 .copied()
194 .map(Byte::<B>::from)
195 .collect::<Vec<Byte<B>>>(),
196 )
197 }
198
199 pub fn zero_ciphertext_proof_domain_separator(&mut self) {
200 self.append_message(
201 b"dom-sep",
202 &b"zero-ciphertext-proof"
203 .iter()
204 .copied()
205 .map(Byte::<B>::from)
206 .collect::<Vec<Byte<B>>>(),
207 )
208 }
209
210 pub fn grouped_ciphertext_validity_proof_domain_separator(&mut self, handles: u64) {
211 self.append_message(
212 b"dom-sep",
213 &b"validity-proof"
214 .iter()
215 .copied()
216 .map(Byte::<B>::from)
217 .collect::<Vec<Byte<B>>>(),
218 );
219 self.append_u64(b"handles", handles);
220 }
221
222 pub fn batched_grouped_ciphertext_validity_proof_domain_separator(&mut self, handles: u64) {
223 self.append_message(
224 b"dom-sep",
225 &b"batched-validity-proof"
226 .iter()
227 .copied()
228 .map(Byte::<B>::from)
229 .collect::<Vec<Byte<B>>>(),
230 );
231 self.append_u64(b"handles", handles);
232 }
233
234 pub fn pubkey_proof_domain_separator(&mut self) {
235 self.append_message(
236 b"dom-sep",
237 &b"pubkey-proof"
238 .iter()
239 .copied()
240 .map(Byte::<B>::from)
241 .collect::<Vec<Byte<B>>>(),
242 )
243 }
244}
245
246impl Transcript<BooleanValue> {
247 pub fn append_scalar(&mut self, label: &'static [u8], scalar: &FieldValue<ScalarField>) {
248 self.append_message(label, &scalar.to_le_bytes());
249 }
250
251 pub fn append_point(&mut self, label: &'static [u8], point: &CompressedCurveValue) {
252 self.append_message(label, &point.to_bytes());
253 }
254
255 pub fn append_elgamal_ciphertext(
256 &mut self,
257 label: &'static [u8],
258 ciphertext: &ElGamalCiphertext,
259 ) {
260 let mut bytes = [Byte::<BooleanValue>::from(0u8); ELGAMAL_CIPHERTEXT_LEN];
261 bytes[..PEDERSEN_COMMITMENT_LEN]
262 .copy_from_slice(&ciphertext.commitment.get_point().compress().to_bytes());
263 bytes[PEDERSEN_COMMITMENT_LEN..]
264 .copy_from_slice(&ciphertext.handle.get_point().compress().to_bytes());
265 self.append_message(label, &bytes);
266 }
267
268 pub fn append_elgamal_ciphertext_3_handles(
269 &mut self,
270 label: &'static [u8],
271 ciphertext: &GroupedElGamalCiphertext3Handles,
272 ) {
273 let mut bytes = [Byte::<BooleanValue>::from(0u8); GROUPED_ELGAMAL_CIPHERTEXT_3_HANDLES_LEN];
274 bytes[..PEDERSEN_COMMITMENT_LEN]
275 .copy_from_slice(&ciphertext.0.commitment.get_point().compress().to_bytes());
276 let mut offset = PEDERSEN_COMMITMENT_LEN;
277 for i in 0..3 {
278 bytes[offset..offset + DECRYPT_HANDLE_LEN]
279 .copy_from_slice(&ciphertext.0.handles[i].get_point().compress().to_bytes());
280 offset += DECRYPT_HANDLE_LEN;
281 }
282 self.append_message(label, &bytes);
283 }
284
285 pub fn challenge_scalar(&mut self, label: &'static [u8]) -> FieldValue<ScalarField> {
286 let mut buf = [Byte::from(0u8); 64];
287 self.challenge_bytes(label, &mut buf);
288 let buf_bits = buf
289 .into_iter()
290 .flat_map(|byte| byte.to_vec())
291 .collect::<Vec<BooleanValue>>();
292
293 FieldValue::<ScalarField>::from_le_bits(buf_bits, false)
294 }
295}