liminal_ark_relations/shielder/
deposit.rs

1use liminal_ark_relation_macro::snark_relation;
2
3use super::types::{BackendNote, FrontendNote};
4
5/// 'Deposit' relation for the Shielder application.
6///
7/// It expresses the fact that `note` is a prefix of the result of hashing together `token_id`,
8/// `token_amount`, `trapdoor` and `nullifier`.
9#[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}