#![allow(non_snake_case)]
#![deny(missing_docs)]
#![no_std]
#[cfg(feature = "plonk")]
mod circuit_impl;
#[cfg(feature = "plonk")]
mod sender_enc;
use dusk_bls12_381::BlsScalar;
use dusk_bytes::{DeserializableSlice, Error as BytesError, Serializable};
use dusk_jubjub::{JubJubAffine, JubJubScalar};
use jubjub_schnorr::{Signature as SchnorrSignature, SignatureDouble};
use poseidon_merkle::{Item, Opening, Tree, ARITY};
#[cfg(feature = "rkyv-impl")]
use rkyv::{Archive, Deserialize, Serialize};
use phoenix_core::{Note, PublicKey, SecretKey, OUTPUT_NOTES};
extern crate alloc;
use alloc::vec::Vec;
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(
feature = "rkyv-impl",
derive(Archive, Serialize, Deserialize),
archive_attr(derive(bytecheck::CheckBytes))
)]
pub struct TxCircuit<const H: usize, const I: usize> {
pub input_notes_info: [InputNoteInfo<H>; I],
pub output_notes_info: [OutputNoteInfo; OUTPUT_NOTES],
pub payload_hash: BlsScalar,
pub root: BlsScalar,
pub deposit: u64,
pub max_fee: u64,
pub sender_pk: PublicKey,
pub signatures: (SchnorrSignature, SchnorrSignature),
}
impl<const H: usize, const I: usize> TxCircuit<H, I> {
pub const SIZE: usize = I * InputNoteInfo::<H>::SIZE
+ OUTPUT_NOTES * OutputNoteInfo::SIZE
+ 2 * BlsScalar::SIZE
+ 2 * u64::SIZE
+ PublicKey::SIZE
+ 2 * SchnorrSignature::SIZE;
pub fn to_var_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::with_capacity(Self::SIZE);
for info in self.input_notes_info.iter() {
bytes.extend(info.to_var_bytes());
}
for info in self.output_notes_info.iter() {
bytes.extend(info.to_bytes());
}
bytes.extend(self.payload_hash.to_bytes());
bytes.extend(self.root.to_bytes());
bytes.extend(self.deposit.to_bytes());
bytes.extend(self.max_fee.to_bytes());
bytes.extend(self.sender_pk.to_bytes());
bytes.extend(self.signatures.0.to_bytes());
bytes.extend(self.signatures.1.to_bytes());
bytes
}
pub fn from_slice(bytes: &[u8]) -> Result<Self, BytesError> {
if bytes.len() < Self::SIZE {
return Err(BytesError::BadLength {
found: bytes.len(),
expected: Self::SIZE,
});
}
let mut input_notes_info = Vec::new();
for i in 0..I {
let start = i * InputNoteInfo::<H>::SIZE;
input_notes_info.push(InputNoteInfo::from_slice(&bytes[start..])?);
}
let mut reader = &bytes[I * InputNoteInfo::<H>::SIZE..];
let output_notes_info = [
OutputNoteInfo::from_reader(&mut reader)?,
OutputNoteInfo::from_reader(&mut reader)?,
];
let payload_hash = BlsScalar::from_reader(&mut reader)?;
let root = BlsScalar::from_reader(&mut reader)?;
let deposit = u64::from_reader(&mut reader)?;
let max_fee = u64::from_reader(&mut reader)?;
let sender_pk = PublicKey::from_reader(&mut reader)?;
let signature_0 = SchnorrSignature::from_reader(&mut reader)?;
let signature_1 = SchnorrSignature::from_reader(&mut reader)?;
Ok(Self {
input_notes_info: input_notes_info
.try_into()
.expect("The vector has exactly I elements"),
output_notes_info,
payload_hash,
root,
deposit,
max_fee,
sender_pk,
signatures: (signature_0, signature_1),
})
}
}
impl<const H: usize, const I: usize> Default for TxCircuit<H, I> {
fn default() -> Self {
let sk =
SecretKey::new(JubJubScalar::default(), JubJubScalar::default());
let mut tree = Tree::<(), H>::new();
let payload_hash = BlsScalar::default();
let mut input_notes_info = Vec::new();
let note = Note::empty();
let item = Item {
hash: note.hash(),
data: (),
};
tree.insert(*note.pos(), item);
for _ in 0..I {
let merkle_opening = tree.opening(*note.pos()).expect("Tree read.");
input_notes_info.push(InputNoteInfo {
merkle_opening,
note: note.clone(),
note_pk_p: JubJubAffine::default(),
value: 0u64,
value_blinder: JubJubScalar::default(),
nullifier: BlsScalar::default(),
signature: SignatureDouble::default(),
});
}
let output_note_info_0 = OutputNoteInfo {
value: 0,
value_commitment: JubJubAffine::default(),
value_blinder: JubJubScalar::default(),
note_pk: JubJubAffine::default(),
sender_enc: [(JubJubAffine::default(), JubJubAffine::default()); 2],
sender_blinder: [JubJubScalar::default(), JubJubScalar::default()],
};
let output_note_info_1 = output_note_info_0.clone();
let output_notes_info = [output_note_info_0, output_note_info_1];
let root = BlsScalar::default();
let deposit = u64::default();
let max_fee = u64::default();
let signatures =
(SchnorrSignature::default(), SchnorrSignature::default());
Self {
input_notes_info: input_notes_info.try_into().unwrap(),
output_notes_info,
payload_hash,
root,
deposit,
max_fee,
sender_pk: PublicKey::from(&sk),
signatures,
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(
feature = "rkyv-impl",
derive(Archive, Serialize, Deserialize),
archive_attr(derive(bytecheck::CheckBytes))
)]
pub struct InputNoteInfo<const H: usize> {
pub merkle_opening: Opening<(), H>,
pub note: Note,
pub note_pk_p: JubJubAffine,
pub value: u64,
pub value_blinder: JubJubScalar,
pub nullifier: BlsScalar,
pub signature: SignatureDouble,
}
impl<const H: usize> InputNoteInfo<H> {
pub const SIZE: usize = (1 + H * ARITY) * Item::SIZE
+ H * (u32::BITS as usize / 8)
+ Note::SIZE
+ JubJubAffine::SIZE
+ u64::SIZE
+ JubJubScalar::SIZE
+ BlsScalar::SIZE
+ SignatureDouble::SIZE;
pub fn to_var_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::with_capacity(Self::SIZE);
bytes.extend(self.merkle_opening.to_var_bytes());
bytes.extend(self.note.to_bytes());
bytes.extend(self.note_pk_p.to_bytes());
bytes.extend(self.value.to_bytes());
bytes.extend(self.value_blinder.to_bytes());
bytes.extend(self.nullifier.to_bytes());
bytes.extend(self.signature.to_bytes());
bytes
}
pub fn from_slice(bytes: &[u8]) -> Result<Self, BytesError> {
if bytes.len() < Self::SIZE {
return Err(BytesError::BadLength {
found: bytes.len(),
expected: Self::SIZE,
});
}
let merkle_opening_size =
(1 + H * ARITY) * Item::SIZE + H * (u32::BITS as usize / 8);
let merkle_opening =
Opening::<(), H>::from_slice(&bytes[..merkle_opening_size])?;
let mut buf = &bytes[merkle_opening_size..];
let note = Note::from_reader(&mut buf)?;
let note_pk_p = JubJubAffine::from_reader(&mut buf)?;
let value = u64::from_reader(&mut buf)?;
let value_blinder = JubJubScalar::from_reader(&mut buf)?;
let nullifier = BlsScalar::from_reader(&mut buf)?;
let signature = SignatureDouble::from_reader(&mut buf)?;
Ok(Self {
merkle_opening,
note,
note_pk_p,
value,
value_blinder,
nullifier,
signature,
})
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(
feature = "rkyv-impl",
derive(Archive, Serialize, Deserialize),
archive_attr(derive(bytecheck::CheckBytes))
)]
pub struct OutputNoteInfo {
pub value: u64,
pub value_commitment: JubJubAffine,
pub value_blinder: JubJubScalar,
pub note_pk: JubJubAffine,
pub sender_enc: [(JubJubAffine, JubJubAffine); 2],
pub sender_blinder: [JubJubScalar; 2],
}
const OUTPUT_NOTE_INFO_SIZE: usize = u64::SIZE
+ JubJubAffine::SIZE
+ JubJubScalar::SIZE
+ JubJubAffine::SIZE
+ 4 * JubJubAffine::SIZE
+ 2 * JubJubScalar::SIZE;
impl Serializable<OUTPUT_NOTE_INFO_SIZE> for OutputNoteInfo {
type Error = BytesError;
fn to_bytes(&self) -> [u8; Self::SIZE] {
let mut bytes = [0u8; Self::SIZE];
let mut offset = 0;
bytes[..u64::SIZE].copy_from_slice(&self.value.to_bytes());
offset += u64::SIZE;
bytes[offset..offset + JubJubAffine::SIZE]
.copy_from_slice(&self.value_commitment.to_bytes());
offset += JubJubAffine::SIZE;
bytes[offset..offset + JubJubScalar::SIZE]
.copy_from_slice(&self.value_blinder.to_bytes());
offset += JubJubScalar::SIZE;
bytes[offset..offset + JubJubAffine::SIZE]
.copy_from_slice(&self.note_pk.to_bytes());
offset += JubJubAffine::SIZE;
bytes[offset..offset + JubJubAffine::SIZE]
.copy_from_slice(&self.sender_enc[0].0.to_bytes());
offset += JubJubAffine::SIZE;
bytes[offset..offset + JubJubAffine::SIZE]
.copy_from_slice(&self.sender_enc[0].1.to_bytes());
offset += JubJubAffine::SIZE;
bytes[offset..offset + JubJubAffine::SIZE]
.copy_from_slice(&self.sender_enc[1].0.to_bytes());
offset += JubJubAffine::SIZE;
bytes[offset..offset + JubJubAffine::SIZE]
.copy_from_slice(&self.sender_enc[1].1.to_bytes());
offset += JubJubAffine::SIZE;
bytes[offset..offset + JubJubScalar::SIZE]
.copy_from_slice(&self.sender_blinder[0].to_bytes());
offset += JubJubScalar::SIZE;
bytes[offset..offset + JubJubScalar::SIZE]
.copy_from_slice(&self.sender_blinder[1].to_bytes());
bytes
}
fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result<Self, Self::Error> {
let mut reader = &bytes[..];
let value = u64::from_reader(&mut reader)?;
let value_commitment = JubJubAffine::from_reader(&mut reader)?;
let value_blinder = JubJubScalar::from_reader(&mut reader)?;
let note_pk = JubJubAffine::from_reader(&mut reader)?;
let sender_enc_0_0 = JubJubAffine::from_reader(&mut reader)?;
let sender_enc_0_1 = JubJubAffine::from_reader(&mut reader)?;
let sender_enc_1_0 = JubJubAffine::from_reader(&mut reader)?;
let sender_enc_1_1 = JubJubAffine::from_reader(&mut reader)?;
let sender_blinder_0 = JubJubScalar::from_reader(&mut reader)?;
let sender_blinder_1 = JubJubScalar::from_reader(&mut reader)?;
Ok(Self {
value,
value_commitment,
value_blinder,
note_pk,
sender_enc: [
(sender_enc_0_0, sender_enc_0_1),
(sender_enc_1_0, sender_enc_1_1),
],
sender_blinder: [sender_blinder_0, sender_blinder_1],
})
}
}