liminal_ark_relations/shielder/
deposit.rs1use liminal_ark_relation_macro::snark_relation;
2
3use super::types::{BackendNote, FrontendNote};
4
5#[snark_relation]
10mod relation {
11 #[cfg(feature = "circuit")]
12 use {
13 crate::shielder::note_var::NoteVarBuilder,
14 ark_r1cs_std::alloc::AllocationMode::{Input, Witness},
15 };
16
17 use crate::shielder::{
18 convert_hash,
19 types::{
20 BackendNullifier, BackendTokenAmount, BackendTokenId, BackendTrapdoor,
21 FrontendNullifier, FrontendTokenAmount, FrontendTokenId, FrontendTrapdoor,
22 },
23 };
24
25 #[relation_object_definition]
26 #[derive(Clone, Debug)]
27 struct DepositRelation {
28 #[public_input(frontend_type = "FrontendNote", parse_with = "convert_hash")]
29 pub note: BackendNote,
30 #[public_input(frontend_type = "FrontendTokenId")]
31 pub token_id: BackendTokenId,
32 #[public_input(frontend_type = "FrontendTokenAmount")]
33 pub token_amount: BackendTokenAmount,
34
35 #[private_input(frontend_type = "FrontendTrapdoor", parse_with = "convert_hash")]
36 pub trapdoor: BackendTrapdoor,
37 #[private_input(frontend_type = "FrontendNullifier", parse_with = "convert_hash")]
38 pub nullifier: BackendNullifier,
39 }
40
41 #[cfg(feature = "circuit")]
42 #[circuit_definition]
43 fn generate_constraints() {
44 let _note = NoteVarBuilder::new(cs)
45 .with_note(self.note(), Input)?
46 .with_token_id(self.token_id(), Input)?
47 .with_token_amount(self.token_amount(), Input)?
48 .with_trapdoor(self.trapdoor(), Witness)?
49 .with_nullifier(self.nullifier(), Witness)?
50 .build()?;
51 Ok(())
52 }
53}
54
55#[cfg(all(test, feature = "circuit"))]
56mod tests {
57 use ark_bls12_381::Bls12_381;
58 use ark_groth16::Groth16;
59 use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem};
60 use ark_snark::SNARK;
61
62 use super::{
63 DepositRelationWithFullInput, DepositRelationWithPublicInput, DepositRelationWithoutInput,
64 };
65 use crate::shielder::{
66 note::compute_note,
67 types::{FrontendNullifier, FrontendTokenAmount, FrontendTokenId, FrontendTrapdoor},
68 };
69
70 fn get_circuit_with_full_input() -> DepositRelationWithFullInput {
71 let token_id: FrontendTokenId = 1;
72 let token_amount: FrontendTokenAmount = 100_000_000_000_000_000_000;
73 let trapdoor: FrontendTrapdoor = [17; 4];
74 let nullifier: FrontendNullifier = [19; 4];
75 let note = compute_note(token_id, token_amount, trapdoor, nullifier);
76
77 DepositRelationWithFullInput::new(note, token_id, token_amount, trapdoor, nullifier)
78 }
79
80 #[test]
81 fn deposit_constraints_correctness() {
82 let circuit = get_circuit_with_full_input();
83
84 let cs = ConstraintSystem::new_ref();
85 circuit.generate_constraints(cs.clone()).unwrap();
86
87 let is_satisfied = cs.is_satisfied().unwrap();
88 if !is_satisfied {
89 println!("{:?}", cs.which_is_unsatisfied());
90 }
91
92 assert!(is_satisfied);
93 }
94
95 #[test]
96 fn deposit_proving_procedure() {
97 let circuit_withouth_input = DepositRelationWithoutInput::new();
98
99 let mut rng = ark_std::test_rng();
100 let (pk, vk) =
101 Groth16::<Bls12_381>::circuit_specific_setup(circuit_withouth_input, &mut rng).unwrap();
102
103 let circuit = get_circuit_with_full_input();
104 let proof = Groth16::prove(&pk, circuit, &mut rng).unwrap();
105
106 let circuit: DepositRelationWithPublicInput = get_circuit_with_full_input().into();
107 let input = circuit.serialize_public_input();
108 let valid_proof = Groth16::verify(&vk, &input, &proof).unwrap();
109 assert!(valid_proof);
110 }
111}