/** @file ***************************************************************************** Declaration of interfaces for the Zerocash Pour gadget. The Pour gadget implements the NP statement "Zerocash Pour" described in \[BCGGMTV14]. References: \[BCGGMTV14]: "Zerocash: Decentralized Anonymous Payments from Bitcoin", Eli Ben-Sasson, Alessandro Chiesa, Christina Garman, Matthew Green, Ian Miers, Eran Tromer, Madars Virza, S&P 2014, ***************************************************************************** * @author This file is part of libzerocash, developed by the Zerocash * project and contributors (see AUTHORS). * @copyright MIT license (see LICENSE file) *****************************************************************************/ #ifndef ZEROCASH_POUR_GADGET_HPP_ #define ZEROCASH_POUR_GADGET_HPP_ #include "zerocash_pour_params.hpp" #include "libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" #include "libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp" namespace libzerocash { using namespace libsnark; /** * Gadget for the NP statement Zerocash Pour. * * More precisely, this gadgets checks the following NP statement. * (See Section 4.2 and Section 5.1 of the Zerocash paper for more details.) * * (A) old_coin_commitment_variables[i] appears on path old_coin_authentication_paths[i] to merkle_tree_root_variable * * (B) old_address_public_keys[i] * = PRF_{old_address_secret_key_variables[i]}^{addr}(z) * = H(old_address_secret_key_variables[i] || 00 || z) * where z = 0...0 * * (C) old_coin_serial_number_variables[i] * = PRF_{old_address_secret_key_variables[i]}^{sn}(old_coin_serial_number_nonce_variables[0..254]) * = H(old_address_secret_key_variables[i] || 01 || old_coin_serial_number_nonce_variables[0..254]) * * Properties (D0) and (D1) jointly ensure that * * old_coin_value_commitment_nonces[i] * = COMM_{old_address_commitment_nonce_variables[i]}(old_address_public_key_variables[i] || old_coin_serial_number_nonce_variables[i]) * * as follows: * * (D0) commitments_to_old_address_public_keys[i] * = H(old_address_public_key_variables[i] || old_coin_serial_number_nonce_variables[i]) * * (D1) old_coin_value_commitment_nonces[i] * = H(old_address_commitment_nonce_variables[i] || commitments_to_old_address_public_keys[i] [0..128]) * * Given this, (D2) computes old_coin_commitments: * * (D2) old_coin_commitment_variables[i] * = COMM_s(old_coin_value_variables[i] || old_coin_value_commitment_nonces[i]) * = H(old_coin_value_commitment_nonces[i] || 0^{192} || old_coin_value_variables[i]) * * Here we ignore commitment randomness s, because * k = old_coin_value_commitment_nonces[i] * is an output of a statistically-hiding commitment scheme. * * While (D0) and (D1) check that old coin commitments are well formed, * (E0) and (E1) check the same properties for new coins. * * (F) mac_of_signature_public_key_hash_variables[i] * = PRF_{old_address_secret_key_variables[i]}^{pk}(i || signature_public_key_hash_variable) * = H(old_address_secret_key_variables[i] || 10 || i || signature_public_key_hash_variable) * * Here signature_public_key_hash is truncated so that the entire argument fits inside SHA256 block. * Furthermore, the representation of i is MSB to LSB and is exactly log2(num_old_coins) bits long. */ template class zerocash_pour_gadget : public gadget { public: size_t tree_depth; pb_variable_array input_as_field_elements; /* R1CS input */ pb_variable_array input_as_bits; /* unpacked R1CS input */ std::shared_ptr > unpack_inputs; /* individual components of the unpacked R1CS input */ std::shared_ptr > merkle_tree_root_variable; std::vector > > old_coin_serial_number_variables; pb_variable_array old_coin_enforce_commitment; std::vector > > new_coin_commitment_variables; pb_variable_array public_old_value_variable; pb_variable_array public_new_value_variable; std::shared_ptr > signature_public_key_hash_variable; std::vector > > mac_of_signature_public_key_hash_variables; /* TODO */ pb_variable zero; std::vector > new_address_public_key_variables; std::vector > old_address_secret_key_variables; std::vector > new_address_commitment_nonce_variables; std::vector > old_address_commitment_nonce_variables; std::vector > new_coin_serial_number_nonce_variables; std::vector > old_coin_serial_number_nonce_variables; std::vector > new_coin_value_variables; std::vector > old_coin_value_variables; std::vector > > prf_for_old_coin_serial_number_input_variables; std::vector > > prfs_for_old_coin_serial_numbers; // (C) std::vector > > old_address_public_key_variables; std::vector > > prf_for_old_address_public_key_input_variables; std::vector > > prfs_for_old_address_public_keys; // (B) std::vector > > commitments_to_old_address_public_keys; std::vector > > commit_to_old_address_public_key_input_variables; std::vector > > commit_to_old_address_public_keys; // (D0) std::vector > > old_coin_value_commitment_nonces; std::vector > > commit_to_old_coin_value_commitment_nonce_input_variables; std::vector > > commit_to_old_coin_value_commitment_nonces; // (D1) std::vector > > old_coin_commitment_variables; std::vector > > compute_old_coin_commitment_input_variables; std::vector > > compute_old_coin_commitments; // (D2) std::vector > > commitments_to_new_address_public_keys; std::vector > > commit_to_new_address_public_key_input_variables; std::vector > > commit_to_new_address_public_keys; // (E0) std::vector > > new_coin_value_commitment_nonces; std::vector > > commit_to_new_coin_value_commitment_nonce_input_variables; std::vector > > commit_to_new_coin_value_commitment_nonces; // (E1) std::vector > > compute_new_coin_commitment_input_variables; std::vector > > compute_new_coin_commitments; // (E2) std::vector > > prf_for_macs_of_signature_public_key_hash_input_variables; std::vector > > prfs_for_macs_of_signature_public_key_hash; // (F) std::vector > old_coin_merkle_tree_position_variables; std::vector > > > old_coin_authentication_path_variables; std::vector > > > old_coin_commitments_in_tree; // (A) size_t num_old_coins; size_t num_new_coins; zerocash_pour_gadget(protoboard &pb, const size_t num_old_coins, const size_t num_new_coins, const size_t tree_depth, const std::string &annotation_prefix); void generate_r1cs_constraints(); void generate_r1cs_witness(const std::vector &old_coin_authentication_paths, const std::vector &old_coin_merkle_tree_positions, const bit_vector &merkle_tree_root, const std::vector &new_address_public_keys, const std::vector &old_address_secret_keys, const std::vector &new_address_commitment_nonces, const std::vector &old_address_commitment_nonces, const std::vector &new_coin_serial_number_nonces, const std::vector &old_coin_serial_number_nonces, const std::vector &new_coin_values, const bit_vector &public_old_value, const bit_vector &public_new_value, const std::vector &old_coin_values, const bit_vector &signature_public_key_hash); }; template r1cs_primary_input zerocash_pour_input_map(const size_t num_old_coins, const size_t num_new_coins, const bit_vector &merkle_tree_root, const std::vector &old_coin_serial_numbers, const std::vector &new_coin_commitments, const bit_vector &public_old_value, const bit_vector &public_new_value, const bit_vector &signature_public_key_hash, const std::vector &signature_public_key_hash_macs); } // libzerocash #include "zerocash_pour_gadget.tcc" #endif // ZEROCASH_POUR_GADGET_HPP_