liminal_ark_relations/shielder/
note_var.rs1use ark_r1cs_std::{
2 alloc::{AllocVar, AllocationMode},
3 eq::EqGadget,
4};
5use ark_relations::{
6 ns,
7 r1cs::{ConstraintSystemRef, SynthesisError},
8};
9use paste::paste;
10
11use crate::{
12 environment::{CircuitField, FpVar},
13 shielder::{
14 token_amount_var::TokenAmountVar,
15 types::{
16 BackendNote, BackendNullifier, BackendTokenAmount, BackendTokenId, BackendTrapdoor,
17 },
18 },
19};
20
21#[derive(Clone, Debug)]
22pub struct NoteVar {
23 pub token_id: FpVar,
24 pub token_amount: TokenAmountVar,
25 pub trapdoor: FpVar,
26 pub nullifier: FpVar,
27 pub note: FpVar,
28}
29
30#[derive(Clone, Debug)]
31pub struct NoteVarBuilder<
32 const TOKEN_ID_SET: bool,
33 const TOKEN_AMOUNT_SET: bool,
34 const TRAPDOOR_SET: bool,
35 const NULLIFIER_SET: bool,
36 const NOTE_SET: bool,
37> {
38 token_id: Option<FpVar>,
39 token_amount: Option<TokenAmountVar>,
40 trapdoor: Option<FpVar>,
41 nullifier: Option<FpVar>,
42 note: Option<FpVar>,
43 cs: ConstraintSystemRef<CircuitField>,
44}
45
46impl NoteVarBuilder<false, false, false, false, false> {
47 pub fn new(cs: ConstraintSystemRef<CircuitField>) -> Self {
48 NoteVarBuilder {
49 token_id: None,
50 token_amount: None,
51 trapdoor: None,
52 nullifier: None,
53 note: None,
54 cs,
55 }
56 }
57}
58
59type Result<T> = core::result::Result<T, SynthesisError>;
60
61macro_rules! impl_with_plain_arg {
62 ($item: ident, $item_type: ty, $target_type: ty, $target_item_type: ty) => {
63 paste! {
64 pub fn [<with_ $item>] (self, $item: Result<&$item_type>, mode: AllocationMode) -> Result<$target_type> {
65 let $item = $target_item_type::new_variable(ns!(self.cs, stringify!($item)), || $item, mode)?;
66 Ok(self. [<with_ $item _var>]($item))
67 }
68 }
69 };
70}
71
72macro_rules! impl_with_var_arg {
73 ($item: ident, $target_type: ty, $target_item_type: ty) => {
74 paste! {
75 pub fn [<with_ $item _var>] (self, $item: $target_item_type) -> $target_type {
76 let mut note: $target_type = NoteVarBuilder {
77 token_id: self.token_id,
78 token_amount: self.token_amount,
79 trapdoor: self.trapdoor,
80 nullifier: self.nullifier,
81 note: self.note,
82 cs: self.cs,
83 };
84 note.$item = Some($item);
85 note
86 }
87 }
88 };
89}
90
91macro_rules! impl_builder {
92 ($in_type: ty, $out_type: ty, $item: ident, $item_type: ty) => {
93 impl_builder!($in_type, $out_type, $item, $item_type, FpVar);
94 };
95 ($in_type: ty, $out_type: ty, $item: ident, $item_type: ty, $target_item_type: ty) => {
96 impl<const _1: bool, const _2: bool, const _3: bool, const _4: bool> $in_type {
97 impl_with_plain_arg!($item, $item_type, $out_type, $target_item_type);
98 impl_with_var_arg!($item, $out_type, $target_item_type);
99 }
100 };
101}
102
103impl_builder!(
104 NoteVarBuilder<false, _1, _2, _3, _4>,
105 NoteVarBuilder<true, _1, _2, _3, _4>,
106 token_id, BackendTokenId
107);
108impl_builder!(
109 NoteVarBuilder<_1, false, _2, _3, _4>,
110 NoteVarBuilder<_1, true, _2, _3, _4>,
111 token_amount, BackendTokenAmount, TokenAmountVar
112);
113impl_builder!(
114 NoteVarBuilder<_1, _2, false, _3, _4>,
115 NoteVarBuilder<_1, _2, true, _3, _4>,
116 trapdoor, BackendTrapdoor
117);
118impl_builder!(
119 NoteVarBuilder<_1, _2, _3, false, _4>,
120 NoteVarBuilder<_1, _2, _3, true, _4>,
121 nullifier, BackendNullifier
122);
123impl_builder!(
124 NoteVarBuilder<_1, _2, _3, _4, false>,
125 NoteVarBuilder<_1, _2, _3, _4, true>,
126 note, BackendNote
127);
128
129impl NoteVarBuilder<true, true, true, true, true> {
130 pub fn build(self) -> Result<NoteVar> {
133 let note = NoteVar {
134 token_id: self.token_id.unwrap(),
135 token_amount: self.token_amount.unwrap(),
136 trapdoor: self.trapdoor.unwrap(),
137 nullifier: self.nullifier.unwrap(),
138 note: self.note.unwrap(),
139 };
140
141 let hash = liminal_ark_poseidon::circuit::four_to_one_hash(
142 self.cs,
143 [
144 note.token_id.clone(),
145 note.token_amount.clone().into(),
146 note.trapdoor.clone(),
147 note.nullifier.clone(),
148 ],
149 )?;
150
151 hash.enforce_equal(¬e.note)?;
152
153 Ok(note)
154 }
155}