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