1#![allow(non_snake_case)]
10#![deny(missing_docs)]
11#![no_std]
12
13#[cfg(feature = "plonk")]
14mod circuit_impl;
15#[cfg(feature = "plonk")]
16mod sender_enc;
17
18use dusk_bls12_381::BlsScalar;
19use dusk_bytes::{DeserializableSlice, Error as BytesError, Serializable};
20use dusk_jubjub::{JubJubAffine, JubJubScalar};
21use jubjub_schnorr::{Signature as SchnorrSignature, SignatureDouble};
22use phoenix_core::{Note, OUTPUT_NOTES, PublicKey, SecretKey};
23use poseidon_merkle::{ARITY, Item, Opening, Tree};
24#[cfg(feature = "rkyv-impl")]
25use rkyv::{Archive, Deserialize, Serialize};
26
27extern crate alloc;
28use alloc::vec::Vec;
29
30#[derive(Debug, Clone, PartialEq)]
32#[cfg_attr(
33 feature = "rkyv-impl",
34 derive(Archive, Serialize, Deserialize),
35 archive_attr(derive(bytecheck::CheckBytes))
36)]
37pub struct TxCircuit<const H: usize, const I: usize> {
38 pub input_notes_info: [InputNoteInfo<H>; I],
40 pub output_notes_info: [OutputNoteInfo; OUTPUT_NOTES],
42 pub payload_hash: BlsScalar,
44 pub root: BlsScalar,
46 pub deposit: u64,
48 pub max_fee: u64,
50 pub sender_pk: PublicKey,
52 pub signatures: (SchnorrSignature, SchnorrSignature),
54}
55
56impl<const H: usize, const I: usize> TxCircuit<H, I> {
57 pub const SIZE: usize = I * InputNoteInfo::<H>::SIZE
59 + OUTPUT_NOTES * OutputNoteInfo::SIZE
60 + 2 * BlsScalar::SIZE
61 + 2 * u64::SIZE
62 + PublicKey::SIZE
63 + 2 * SchnorrSignature::SIZE;
64
65 pub fn to_var_bytes(&self) -> Vec<u8> {
70 let mut bytes = Vec::with_capacity(Self::SIZE);
71
72 for info in self.input_notes_info.iter() {
73 bytes.extend(info.to_var_bytes());
74 }
75 for info in self.output_notes_info.iter() {
76 bytes.extend(info.to_bytes());
77 }
78 bytes.extend(self.payload_hash.to_bytes());
79 bytes.extend(self.root.to_bytes());
80 bytes.extend(self.deposit.to_bytes());
81 bytes.extend(self.max_fee.to_bytes());
82 bytes.extend(self.sender_pk.to_bytes());
83 bytes.extend(self.signatures.0.to_bytes());
84 bytes.extend(self.signatures.1.to_bytes());
85
86 bytes
87 }
88
89 pub fn from_slice(bytes: &[u8]) -> Result<Self, BytesError> {
98 if bytes.len() < Self::SIZE {
99 return Err(BytesError::BadLength {
100 found: bytes.len(),
101 expected: Self::SIZE,
102 });
103 }
104
105 let mut input_notes_info = Vec::new();
106 for i in 0..I {
107 let start = i * InputNoteInfo::<H>::SIZE;
108 input_notes_info.push(InputNoteInfo::from_slice(&bytes[start..])?);
109 }
110
111 let mut reader = &bytes[I * InputNoteInfo::<H>::SIZE..];
112
113 let output_notes_info = [
114 OutputNoteInfo::from_reader(&mut reader)?,
115 OutputNoteInfo::from_reader(&mut reader)?,
116 ];
117 let payload_hash = BlsScalar::from_reader(&mut reader)?;
118 let root = BlsScalar::from_reader(&mut reader)?;
119 let deposit = u64::from_reader(&mut reader)?;
120 let max_fee = u64::from_reader(&mut reader)?;
121 let sender_pk = PublicKey::from_reader(&mut reader)?;
122 let signature_0 = SchnorrSignature::from_reader(&mut reader)?;
123 let signature_1 = SchnorrSignature::from_reader(&mut reader)?;
124
125 Ok(Self {
126 input_notes_info: input_notes_info
127 .try_into()
128 .expect("The vector has exactly I elements"),
129 output_notes_info,
130 payload_hash,
131 root,
132 deposit,
133 max_fee,
134 sender_pk,
135 signatures: (signature_0, signature_1),
136 })
137 }
138}
139
140impl<const H: usize, const I: usize> Default for TxCircuit<H, I> {
141 fn default() -> Self {
142 let sk =
143 SecretKey::new(JubJubScalar::default(), JubJubScalar::default());
144
145 let mut tree = Tree::<(), H>::new();
146 let payload_hash = BlsScalar::default();
147
148 let mut input_notes_info = Vec::new();
149 let note = Note::empty();
150 let item = Item {
151 hash: note.hash(),
152 data: (),
153 };
154 tree.insert(*note.pos(), item);
155
156 for _ in 0..I {
157 let merkle_opening = tree.opening(*note.pos()).expect("Tree read.");
158 input_notes_info.push(InputNoteInfo {
159 merkle_opening,
160 note: note.clone(),
161 note_pk_p: JubJubAffine::default(),
162 value: 0u64,
163 value_blinder: JubJubScalar::default(),
164 nullifier: BlsScalar::default(),
165 signature: SignatureDouble::default(),
166 });
167 }
168
169 let output_note_info_0 = OutputNoteInfo {
170 value: 0,
171 value_commitment: JubJubAffine::default(),
172 value_blinder: JubJubScalar::default(),
173 note_pk: JubJubAffine::default(),
174 sender_enc: [(JubJubAffine::default(), JubJubAffine::default()); 2],
175 sender_blinder: [JubJubScalar::default(), JubJubScalar::default()],
176 };
177 let output_note_info_1 = output_note_info_0.clone();
178
179 let output_notes_info = [output_note_info_0, output_note_info_1];
180
181 let root = BlsScalar::default();
182 let deposit = u64::default();
183 let max_fee = u64::default();
184
185 let signatures =
186 (SchnorrSignature::default(), SchnorrSignature::default());
187
188 Self {
189 input_notes_info: input_notes_info.try_into().unwrap(),
190 output_notes_info,
191 payload_hash,
192 root,
193 deposit,
194 max_fee,
195 sender_pk: PublicKey::from(&sk),
196 signatures,
197 }
198 }
199}
200
201#[derive(Debug, Clone, PartialEq)]
204#[cfg_attr(
205 feature = "rkyv-impl",
206 derive(Archive, Serialize, Deserialize),
207 archive_attr(derive(bytecheck::CheckBytes))
208)]
209pub struct InputNoteInfo<const H: usize> {
210 pub merkle_opening: Opening<(), H>,
212 pub note: Note,
214 pub note_pk_p: JubJubAffine,
216 pub value: u64,
218 pub value_blinder: JubJubScalar,
220 pub nullifier: BlsScalar,
222 pub signature: SignatureDouble,
224}
225
226impl<const H: usize> InputNoteInfo<H> {
227 pub const SIZE: usize = (1 + H * ARITY) * Item::SIZE
229 + H * (u32::BITS as usize / 8)
230 + Note::SIZE
231 + JubJubAffine::SIZE
232 + u64::SIZE
233 + JubJubScalar::SIZE
234 + BlsScalar::SIZE
235 + SignatureDouble::SIZE;
236
237 pub fn to_var_bytes(&self) -> Vec<u8> {
242 let mut bytes = Vec::with_capacity(Self::SIZE);
243
244 bytes.extend(self.merkle_opening.to_var_bytes());
245 bytes.extend(self.note.to_bytes());
246 bytes.extend(self.note_pk_p.to_bytes());
247 bytes.extend(self.value.to_bytes());
248 bytes.extend(self.value_blinder.to_bytes());
249 bytes.extend(self.nullifier.to_bytes());
250 bytes.extend(self.signature.to_bytes());
251
252 bytes
253 }
254
255 pub fn from_slice(bytes: &[u8]) -> Result<Self, BytesError> {
264 if bytes.len() < Self::SIZE {
265 return Err(BytesError::BadLength {
266 found: bytes.len(),
267 expected: Self::SIZE,
268 });
269 }
270
271 let merkle_opening_size =
272 (1 + H * ARITY) * Item::SIZE + H * (u32::BITS as usize / 8);
273 let merkle_opening =
274 Opening::<(), H>::from_slice(&bytes[..merkle_opening_size])?;
275
276 let mut buf = &bytes[merkle_opening_size..];
277 let note = Note::from_reader(&mut buf)?;
278 let note_pk_p = JubJubAffine::from_reader(&mut buf)?;
279 let value = u64::from_reader(&mut buf)?;
280 let value_blinder = JubJubScalar::from_reader(&mut buf)?;
281 let nullifier = BlsScalar::from_reader(&mut buf)?;
282 let signature = SignatureDouble::from_reader(&mut buf)?;
283
284 Ok(Self {
285 merkle_opening,
286 note,
287 note_pk_p,
288 value,
289 value_blinder,
290 nullifier,
291 signature,
292 })
293 }
294}
295
296#[derive(Debug, Clone, PartialEq)]
299#[cfg_attr(
300 feature = "rkyv-impl",
301 derive(Archive, Serialize, Deserialize),
302 archive_attr(derive(bytecheck::CheckBytes))
303)]
304pub struct OutputNoteInfo {
305 pub value: u64,
307 pub value_commitment: JubJubAffine,
309 pub value_blinder: JubJubScalar,
311 pub note_pk: JubJubAffine,
313 pub sender_enc: [(JubJubAffine, JubJubAffine); 2],
315 pub sender_blinder: [JubJubScalar; 2],
317}
318
319const OUTPUT_NOTE_INFO_SIZE: usize = u64::SIZE
320 + JubJubAffine::SIZE
321 + JubJubScalar::SIZE
322 + JubJubAffine::SIZE
323 + 4 * JubJubAffine::SIZE
324 + 2 * JubJubScalar::SIZE;
325
326impl Serializable<OUTPUT_NOTE_INFO_SIZE> for OutputNoteInfo {
327 type Error = BytesError;
328
329 fn to_bytes(&self) -> [u8; Self::SIZE] {
330 let mut bytes = [0u8; Self::SIZE];
331 let mut offset = 0;
332
333 bytes[..u64::SIZE].copy_from_slice(&self.value.to_bytes());
334 offset += u64::SIZE;
335 bytes[offset..offset + JubJubAffine::SIZE]
336 .copy_from_slice(&self.value_commitment.to_bytes());
337 offset += JubJubAffine::SIZE;
338 bytes[offset..offset + JubJubScalar::SIZE]
339 .copy_from_slice(&self.value_blinder.to_bytes());
340 offset += JubJubScalar::SIZE;
341 bytes[offset..offset + JubJubAffine::SIZE]
342 .copy_from_slice(&self.note_pk.to_bytes());
343 offset += JubJubAffine::SIZE;
344 bytes[offset..offset + JubJubAffine::SIZE]
345 .copy_from_slice(&self.sender_enc[0].0.to_bytes());
346 offset += JubJubAffine::SIZE;
347 bytes[offset..offset + JubJubAffine::SIZE]
348 .copy_from_slice(&self.sender_enc[0].1.to_bytes());
349 offset += JubJubAffine::SIZE;
350 bytes[offset..offset + JubJubAffine::SIZE]
351 .copy_from_slice(&self.sender_enc[1].0.to_bytes());
352 offset += JubJubAffine::SIZE;
353 bytes[offset..offset + JubJubAffine::SIZE]
354 .copy_from_slice(&self.sender_enc[1].1.to_bytes());
355 offset += JubJubAffine::SIZE;
356 bytes[offset..offset + JubJubScalar::SIZE]
357 .copy_from_slice(&self.sender_blinder[0].to_bytes());
358 offset += JubJubScalar::SIZE;
359 bytes[offset..offset + JubJubScalar::SIZE]
360 .copy_from_slice(&self.sender_blinder[1].to_bytes());
361
362 bytes
363 }
364
365 fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result<Self, Self::Error> {
366 let mut reader = &bytes[..];
367
368 let value = u64::from_reader(&mut reader)?;
369 let value_commitment = JubJubAffine::from_reader(&mut reader)?;
370 let value_blinder = JubJubScalar::from_reader(&mut reader)?;
371 let note_pk = JubJubAffine::from_reader(&mut reader)?;
372 let sender_enc_0_0 = JubJubAffine::from_reader(&mut reader)?;
373 let sender_enc_0_1 = JubJubAffine::from_reader(&mut reader)?;
374 let sender_enc_1_0 = JubJubAffine::from_reader(&mut reader)?;
375 let sender_enc_1_1 = JubJubAffine::from_reader(&mut reader)?;
376 let sender_blinder_0 = JubJubScalar::from_reader(&mut reader)?;
377 let sender_blinder_1 = JubJubScalar::from_reader(&mut reader)?;
378
379 Ok(Self {
380 value,
381 value_commitment,
382 value_blinder,
383 note_pk,
384 sender_enc: [
385 (sender_enc_0_0, sender_enc_0_1),
386 (sender_enc_1_0, sender_enc_1_1),
387 ],
388 sender_blinder: [sender_blinder_0, sender_blinder_1],
389 })
390 }
391}