use dusk_bls12_381::BlsScalar;
use dusk_jubjub::{GENERATOR, GENERATOR_NUMS};
use dusk_plonk::prelude::{
Circuit, Composer, Constraint, Error as PlonkError, Witness, WitnessPoint,
};
use dusk_poseidon::{Domain, HashGadget};
use jubjub_schnorr::gadgets;
use poseidon_merkle::zk::opening_gadget;
use crate::{InputNoteInfo, TxCircuit, sender_enc};
impl<const H: usize, const I: usize> Circuit for TxCircuit<H, I> {
fn circuit(&self, composer: &mut Composer) -> Result<(), PlonkError> {
let payload_hash = composer.append_public(self.payload_hash);
let root_pi = composer.append_public(self.root);
let mut input_notes_sum = Composer::ZERO;
for input_note_info in &self.input_notes_info {
let (
note_pk,
note_pk_p,
note_type,
pos,
value,
value_blinder,
nullifier,
signature_u,
signature_r,
signature_r_p,
) = input_note_info.append_to_circuit(composer);
gadgets::verify_signature_double(
composer,
signature_u,
signature_r,
signature_r_p,
note_pk,
note_pk_p,
payload_hash,
)?;
let computed_nullifier = HashGadget::digest(
composer,
Domain::Other,
&[*note_pk_p.x(), *note_pk_p.y(), pos],
)[0];
composer.assert_equal(computed_nullifier, nullifier);
composer.component_range::<32>(value);
let constraint = Constraint::new()
.left(1)
.a(input_notes_sum)
.right(1)
.b(value);
input_notes_sum = composer.gate_add(constraint);
let pc_1 = composer.component_mul_generator(value, GENERATOR)?;
let pc_2 = composer
.component_mul_generator(value_blinder, GENERATOR_NUMS)?;
let value_commitment = composer.component_add_point(pc_1, pc_2);
let note_hash = HashGadget::digest(
composer,
Domain::Other,
&[
note_type,
*value_commitment.x(),
*value_commitment.y(),
*note_pk.x(),
*note_pk.y(),
pos,
],
)[0];
let root = opening_gadget(
composer,
&input_note_info.merkle_opening,
note_hash,
);
composer.assert_equal(root, root_pi);
}
let mut tx_output_sum = Composer::ZERO;
for output_note_info in &self.output_notes_info {
let value = composer.append_witness(output_note_info.value);
let expected_value_commitment =
composer.append_public_point(output_note_info.value_commitment);
let value_blinder =
composer.append_witness(output_note_info.value_blinder);
composer.component_range::<32>(value);
let constraint =
Constraint::new().left(1).a(tx_output_sum).right(1).b(value);
tx_output_sum = composer.gate_add(constraint);
let pc_1 = composer.component_mul_generator(value, GENERATOR)?;
let pc_2 = composer
.component_mul_generator(value_blinder, GENERATOR_NUMS)?;
let computed_value_commitment =
composer.component_add_point(pc_1, pc_2);
composer.assert_equal_point(
expected_value_commitment,
computed_value_commitment,
);
}
let max_fee = composer.append_public(self.max_fee);
let deposit = composer.append_public(self.deposit);
let constraint = Constraint::new()
.left(1)
.a(tx_output_sum)
.right(1)
.b(max_fee)
.fourth(1)
.d(deposit);
tx_output_sum = composer.gate_add(constraint);
composer.assert_equal(input_notes_sum, tx_output_sum);
sender_enc::gadget(
composer,
self.sender_pk,
self.signatures,
[
self.output_notes_info[0].note_pk,
self.output_notes_info[1].note_pk,
],
[
self.output_notes_info[0].sender_blinder,
self.output_notes_info[1].sender_blinder,
],
self.output_notes_info[0].sender_enc,
self.output_notes_info[1].sender_enc,
payload_hash,
)?;
Ok(())
}
}
impl<const H: usize> InputNoteInfo<H> {
fn append_to_circuit(
&self,
composer: &mut Composer,
) -> (
WitnessPoint,
WitnessPoint,
Witness,
Witness,
Witness,
Witness,
Witness,
Witness,
WitnessPoint,
WitnessPoint,
) {
let nullifier = composer.append_public(self.nullifier);
let note_pk = composer
.append_point(*self.note.stealth_address().note_pk().as_ref());
let note_pk_p = composer.append_point(self.note_pk_p);
let note_type = composer
.append_witness(BlsScalar::from(self.note.note_type() as u64));
let pos = composer.append_witness(BlsScalar::from(*self.note.pos()));
let value = composer.append_witness(self.value);
let value_blinder = composer.append_witness(self.value_blinder);
let signature_u = composer.append_witness(*self.signature.u());
let signature_r = composer.append_point(self.signature.R());
let signature_r_p = composer.append_point(self.signature.R_prime());
(
note_pk,
note_pk_p,
note_type,
pos,
value,
value_blinder,
nullifier,
signature_u,
signature_r,
signature_r_p,
)
}
}