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__