1 // Copyright (c) 2015-2022 Clearmatics Technologies Ltd
3 // SPDX-License-Identifier: LGPL-3.0+
5 #ifndef __ZETH_CIRCUITS_PRFS_PRF_TCC__
6 #define __ZETH_CIRCUITS_PRFS_PRF_TCC__
8 #include "libzeth/circuits/prfs/prf.hpp"
11 // Content Taken and adapted from Zcash
12 // https://github.com/zcash/zcash/blob/master/src/zcash/circuit/prfs.tcc
17 template<typename FieldT, typename HashT>
18 PRF_gadget<FieldT, HashT>::PRF_gadget(
19 libsnark::protoboard<FieldT> &pb,
20 const libsnark::pb_variable_array<FieldT> &x,
21 const libsnark::pb_variable_array<FieldT> &y,
22 std::shared_ptr<libsnark::digest_variable<FieldT>> result,
23 const std::string &annotation_prefix)
24 : libsnark::gadget<FieldT>(pb, annotation_prefix)
26 , block(pb, {x, y}, FMT(this->annotation_prefix, " block"))
27 , hasher(pb, block, *result, FMT(this->annotation_prefix, " hasher_gadget"))
31 template<typename FieldT, typename HashT>
32 void PRF_gadget<FieldT, HashT>::generate_r1cs_constraints()
34 hasher.generate_r1cs_constraints(true);
37 template<typename FieldT, typename HashT>
38 void PRF_gadget<FieldT, HashT>::generate_r1cs_witness()
40 hasher.generate_r1cs_witness();
43 template<typename FieldT, typename HashT>
44 libsnark::pb_variable_array<FieldT> gen_256_zeroes(
45 const libsnark::pb_variable<FieldT> &ZERO)
47 libsnark::pb_variable_array<FieldT> ret;
48 // We generate half a block of zeroes
49 while (ret.size() < HashT::get_block_len() / 2) {
50 ret.emplace_back(ZERO);
53 // Check that we correctly built a 256-bit (half a block) string since we
54 // use blake2sCompress 256
55 assert(ret.size() == 256);
60 template<typename FieldT>
61 libsnark::pb_variable_array<FieldT> get_tag_addr(
62 const libsnark::pb_variable<FieldT> &ZERO,
63 const libsnark::pb_variable_array<FieldT> &a_sk)
65 libsnark::pb_variable_array<FieldT> tagged_a_sk;
66 tagged_a_sk.emplace_back(ONE); // 1
67 tagged_a_sk.emplace_back(ONE); // 11
68 tagged_a_sk.emplace_back(ZERO); // 110
69 tagged_a_sk.emplace_back(ZERO); // 1100
71 // Should always be satisfied because a_sk
72 // is a 256 bit string. This is just a sanity check
73 // to make sure that the for loop doesn't
74 // go out of the bound of the a_sk vector
75 assert(a_sk.size() > 252);
76 for (size_t i = 0; i < 252; ++i) {
77 tagged_a_sk.emplace_back(a_sk[i]);
80 // Check that we correctly built a 256-bit string
81 assert(tagged_a_sk.size() == 256);
86 template<typename FieldT>
87 libsnark::pb_variable_array<FieldT> get_tag_nf(
88 const libsnark::pb_variable<FieldT> &ZERO,
89 const libsnark::pb_variable_array<FieldT> &a_sk)
91 libsnark::pb_variable_array<FieldT> tagged_a_sk;
92 tagged_a_sk.emplace_back(ONE); // 1
93 tagged_a_sk.emplace_back(ONE); // 11
94 tagged_a_sk.emplace_back(ONE); // 111
95 tagged_a_sk.emplace_back(ZERO); // 1110
97 // Should always be satisfied because a_sk
98 // is a 256 bit string. This is just a sanity check
99 // to make sure that the for loop doesn't
100 // go out of the bound of the a_sk vector
101 assert(a_sk.size() > 252);
102 for (size_t i = 0; i < 252; ++i) {
103 tagged_a_sk.emplace_back(a_sk[i]);
106 // Check that we correctly built a 256-bit string
107 assert(tagged_a_sk.size() == 256);
112 template<typename FieldT>
113 libsnark::pb_variable_array<FieldT> get_tag_pk(
114 const libsnark::pb_variable<FieldT> &ZERO,
115 const libsnark::pb_variable_array<FieldT> &a_sk,
118 libsnark::pb_variable_array<FieldT> tagged_a_sk;
119 tagged_a_sk.emplace_back(ZERO); // 0
121 // Index should either be 0 or 1 since we support
122 // joinsplit with 2 inputs only
123 if (index == 0) { // 0 || index
124 tagged_a_sk.emplace_back(ZERO); // 00
126 tagged_a_sk.emplace_back(ONE); // 01
129 tagged_a_sk.emplace_back(ZERO); // 0 || index || 0
130 tagged_a_sk.emplace_back(ZERO); // 0 || index || 00
132 // Should always be satisfied because a_sk
133 // is a 256 bit string. This is just a sanity check
134 // to make sure that the for loop doesn't
135 // go out of the bound of the a_sk vector
136 assert(a_sk.size() > 252);
137 for (size_t i = 0; i < 252; ++i) {
138 tagged_a_sk.emplace_back(a_sk[i]);
141 // Check that we correctly built a 256-bit string
142 assert(tagged_a_sk.size() == 256);
147 template<typename FieldT>
148 libsnark::pb_variable_array<FieldT> get_tag_rho(
149 const libsnark::pb_variable<FieldT> &ZERO,
150 const libsnark::pb_variable_array<FieldT> &phi,
153 libsnark::pb_variable_array<FieldT> tagged_phi;
154 tagged_phi.emplace_back(ZERO); // 0
156 if (index == 0) { // 0 || index
157 tagged_phi.emplace_back(ZERO); // 00
159 tagged_phi.emplace_back(ONE); // 01
162 tagged_phi.emplace_back(ONE); // 0 || index || 1
163 tagged_phi.emplace_back(ZERO); // 0 || index || 10
165 // Should always be satisfied because phi
166 // is a 256 bit string. This is just a sanity check
167 // to make sure that the for loop doesn't
168 // go out of the bound of the phi vector
169 assert(phi.size() > 252);
170 for (size_t i = 0; i < 252; ++i) {
171 tagged_phi.emplace_back(phi[i]);
174 // Check that we correctly built a 256-bit string
175 assert(tagged_phi.size() == 256);
180 // PRF to generate the public addresses
181 // a_pk = blake2sCompress(1100 || [a_sk]_252 || 0^256): See ZCash protocol
182 // specification paper, page 57
183 template<typename FieldT, typename HashT>
184 PRF_addr_a_pk_gadget<FieldT, HashT>::PRF_addr_a_pk_gadget(
185 libsnark::protoboard<FieldT> &pb,
186 const libsnark::pb_variable<FieldT> &ZERO,
187 const libsnark::pb_variable_array<FieldT> &a_sk,
188 std::shared_ptr<libsnark::digest_variable<FieldT>> result,
189 const std::string &annotation_prefix)
190 : PRF_gadget<FieldT, HashT>(
192 get_tag_addr(ZERO, a_sk),
193 gen_256_zeroes<FieldT, HashT>(ZERO),
200 // PRF to generate the nullifier
201 // nf = blake2sCompress(1110 || [a_sk]_252 || rho): See ZCash protocol
202 // specification paper, page 57
203 template<typename FieldT, typename HashT>
204 PRF_nf_gadget<FieldT, HashT>::PRF_nf_gadget(
205 libsnark::protoboard<FieldT> &pb,
206 const libsnark::pb_variable<FieldT> &ZERO,
207 const libsnark::pb_variable_array<FieldT> &a_sk,
208 const libsnark::pb_variable_array<FieldT> &rho,
209 std::shared_ptr<libsnark::digest_variable<FieldT>> result,
210 const std::string &annotation_prefix)
211 : PRF_gadget<FieldT, HashT>(
212 pb, get_tag_nf(ZERO, a_sk), rho, result, annotation_prefix)
217 // PRF to generate the h_i
218 // h_i = blake2sCompress(0 || i || 00 || [a_sk]_252 || h_sig): See ZCash
219 // protocol specification paper, page 57
220 template<typename FieldT, typename HashT>
221 PRF_pk_gadget<FieldT, HashT>::PRF_pk_gadget(
222 libsnark::protoboard<FieldT> &pb,
223 const libsnark::pb_variable<FieldT> &ZERO,
224 const libsnark::pb_variable_array<FieldT> &a_sk,
225 const libsnark::pb_variable_array<FieldT> &h_sig,
227 std::shared_ptr<libsnark::digest_variable<FieldT>> result,
228 const std::string &annotation_prefix)
229 : PRF_gadget<FieldT, HashT>(
230 pb, get_tag_pk(ZERO, a_sk, index), h_sig, result, annotation_prefix)
235 // PRF to generate rho
236 // rho_i = blake2sCompress(0 || i || 10 || [a_sk]_252 || h_sig): See ZCash
237 // protocol specification paper, page 57
238 template<typename FieldT, typename HashT>
239 PRF_rho_gadget<FieldT, HashT>::PRF_rho_gadget(
240 libsnark::protoboard<FieldT> &pb,
241 const libsnark::pb_variable<FieldT> &ZERO,
242 const libsnark::pb_variable_array<FieldT> &phi,
243 const libsnark::pb_variable_array<FieldT> &h_sig,
245 std::shared_ptr<libsnark::digest_variable<FieldT>> result,
246 const std::string &annotation_prefix)
247 : PRF_gadget<FieldT, HashT>(
248 pb, get_tag_rho(ZERO, phi, index), h_sig, result, annotation_prefix)
253 } // namespace libzeth
255 #endif // __ZETH_CIRCUITS_PRFS_PRF_TCC__