Zeth - Zerocash on Ethereum  0.8
Reference implementation of the Zeth protocol by Clearmatics
prf.tcc
Go to the documentation of this file.
1 // Copyright (c) 2015-2022 Clearmatics Technologies Ltd
2 //
3 // SPDX-License-Identifier: LGPL-3.0+
4 
5 #ifndef __ZETH_CIRCUITS_PRFS_PRF_TCC__
6 #define __ZETH_CIRCUITS_PRFS_PRF_TCC__
7 
8 #include "libzeth/circuits/prfs/prf.hpp"
9 
10 // DISCLAIMER:
11 // Content Taken and adapted from Zcash
12 // https://github.com/zcash/zcash/blob/master/src/zcash/circuit/prfs.tcc
13 
14 namespace libzeth
15 {
16 
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)
25  , result(result)
26  , block(pb, {x, y}, FMT(this->annotation_prefix, " block"))
27  , hasher(pb, block, *result, FMT(this->annotation_prefix, " hasher_gadget"))
28 {
29 }
30 
31 template<typename FieldT, typename HashT>
32 void PRF_gadget<FieldT, HashT>::generate_r1cs_constraints()
33 {
34  hasher.generate_r1cs_constraints(true);
35 }
36 
37 template<typename FieldT, typename HashT>
38 void PRF_gadget<FieldT, HashT>::generate_r1cs_witness()
39 {
40  hasher.generate_r1cs_witness();
41 }
42 
43 template<typename FieldT, typename HashT>
44 libsnark::pb_variable_array<FieldT> gen_256_zeroes(
45  const libsnark::pb_variable<FieldT> &ZERO)
46 {
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);
51  }
52 
53  // Check that we correctly built a 256-bit (half a block) string since we
54  // use blake2sCompress 256
55  assert(ret.size() == 256);
56 
57  return ret;
58 }
59 
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)
64 {
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
70 
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]);
78  }
79 
80  // Check that we correctly built a 256-bit string
81  assert(tagged_a_sk.size() == 256);
82 
83  return tagged_a_sk;
84 }
85 
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)
90 {
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
96 
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]);
104  }
105 
106  // Check that we correctly built a 256-bit string
107  assert(tagged_a_sk.size() == 256);
108 
109  return tagged_a_sk;
110 }
111 
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,
116  size_t index)
117 {
118  libsnark::pb_variable_array<FieldT> tagged_a_sk;
119  tagged_a_sk.emplace_back(ZERO); // 0
120 
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
125  } else {
126  tagged_a_sk.emplace_back(ONE); // 01
127  }
128 
129  tagged_a_sk.emplace_back(ZERO); // 0 || index || 0
130  tagged_a_sk.emplace_back(ZERO); // 0 || index || 00
131 
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]);
139  }
140 
141  // Check that we correctly built a 256-bit string
142  assert(tagged_a_sk.size() == 256);
143 
144  return tagged_a_sk;
145 }
146 
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,
151  size_t index)
152 {
153  libsnark::pb_variable_array<FieldT> tagged_phi;
154  tagged_phi.emplace_back(ZERO); // 0
155 
156  if (index == 0) { // 0 || index
157  tagged_phi.emplace_back(ZERO); // 00
158  } else {
159  tagged_phi.emplace_back(ONE); // 01
160  }
161 
162  tagged_phi.emplace_back(ONE); // 0 || index || 1
163  tagged_phi.emplace_back(ZERO); // 0 || index || 10
164 
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]);
172  }
173 
174  // Check that we correctly built a 256-bit string
175  assert(tagged_phi.size() == 256);
176 
177  return tagged_phi;
178 }
179 
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>(
191  pb,
192  get_tag_addr(ZERO, a_sk),
193  gen_256_zeroes<FieldT, HashT>(ZERO),
194  result,
195  annotation_prefix)
196 {
197  // Nothing
198 }
199 
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)
213 {
214  // Nothing
215 }
216 
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,
226  size_t index,
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)
231 {
232  // Nothing
233 }
234 
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,
244  size_t index,
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)
249 {
250  // Nothing
251 }
252 
253 } // namespace libzeth
254 
255 #endif // __ZETH_CIRCUITS_PRFS_PRF_TCC__