Files
hush3/src/zerocash/PourTransaction.cpp

446 lines
18 KiB
C++

/** @file
*****************************************************************************
Implementation of interfaces for the class PourTransaction.
See PourTransaction.h .
*****************************************************************************
* @author This file is part of libzerocash, developed by the Zerocash
* project and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include "Zerocash.h"
#include "PourTransaction.h"
#include "PourInput.h"
#include "PourOutput.h"
#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp"
#include "zerocash_pour_gadget.hpp"
#include "zerocash_pour_ppzksnark.hpp"
namespace libzerocash {
PourTransaction::PourTransaction(): cm_1(), cm_2() {
}
PourTransaction::PourTransaction(ZerocashParams& params,
const std::vector<unsigned char>& pubkeyHash,
const MerkleRootType& rt,
std::vector<PourInput> inputs,
std::vector<PourOutput> outputs,
uint64_t vpub_old,
uint64_t vpub_new
) :
publicOldValue(ZC_V_SIZE), publicNewValue(ZC_V_SIZE), serialNumber_1(ZC_SN_SIZE), serialNumber_2(ZC_SN_SIZE), MAC_1(ZC_H_SIZE), MAC_2(ZC_H_SIZE)
{
if (inputs.size() > 2 || outputs.size() > 2) {
throw std::length_error("Too many inputs or outputs specified");
}
while (inputs.size() < 2) {
// Push a dummy input of value 0.
inputs.push_back(PourInput(params.getTreeDepth()));
}
while (outputs.size() < 2) {
// Push a dummy output of value 0.
outputs.push_back(PourOutput(0));
}
init(1,
params,
rt,
inputs[0].old_coin,
inputs[1].old_coin,
inputs[0].old_address,
inputs[1].old_address,
inputs[0].merkle_index,
inputs[1].merkle_index,
inputs[0].path,
inputs[1].path,
outputs[0].to_address,
outputs[1].to_address,
vpub_old,
vpub_new,
pubkeyHash,
outputs[0].new_coin,
outputs[1].new_coin);
}
PourTransaction::PourTransaction(uint16_t version_num,
ZerocashParams& params,
const MerkleRootType& rt,
const Coin& c_1_old,
const Coin& c_2_old,
const Address& addr_1_old,
const Address& addr_2_old,
const size_t patMerkleIdx_1,
const size_t patMerkleIdx_2,
const merkle_authentication_path& patMAC_1,
const merkle_authentication_path& patMAC_2,
const PublicAddress& addr_1_new,
const PublicAddress& addr_2_new,
uint64_t v_pub_old,
uint64_t v_pub_new,
const std::vector<unsigned char>& pubkeyHash,
const Coin& c_1_new,
const Coin& c_2_new) :
publicOldValue(ZC_V_SIZE), publicNewValue(ZC_V_SIZE), serialNumber_1(ZC_SN_SIZE), serialNumber_2(ZC_SN_SIZE), MAC_1(ZC_H_SIZE), MAC_2(ZC_H_SIZE)
{
init(version_num, params, rt, c_1_old, c_2_old, addr_1_old, addr_2_old, patMerkleIdx_1, patMerkleIdx_2,
patMAC_1, patMAC_2, addr_1_new, addr_2_new, v_pub_old, v_pub_new, pubkeyHash, c_1_new, c_2_new);
}
std::vector<unsigned char> from_uint256(const uint256 &in)
{
return std::vector<unsigned char>(in.begin(), in.end());
}
void PourTransaction::init(uint16_t version_num,
ZerocashParams& params,
const MerkleRootType& rt,
const Coin& c_1_old,
const Coin& c_2_old,
const Address& addr_1_old,
const Address& addr_2_old,
const size_t patMerkleIdx_1,
const size_t patMerkleIdx_2,
const merkle_authentication_path& patMAC_1,
const merkle_authentication_path& patMAC_2,
const PublicAddress& addr_1_new,
const PublicAddress& addr_2_new,
uint64_t v_pub_old,
uint64_t v_pub_new,
const std::vector<unsigned char>& pubkeyHash,
const Coin& c_1_new,
const Coin& c_2_new)
{
params.loadProvingKey();
this->version = version_num;
convertIntToBytesVector(v_pub_old, this->publicOldValue);
convertIntToBytesVector(v_pub_new, this->publicNewValue);
this->cm_1 = c_1_new.getCoinCommitment();
this->cm_2 = c_2_new.getCoinCommitment();
std::vector<bool> root_bv(ZC_ROOT_SIZE * 8);
std::vector<bool> addr_pk_new_1_bv(ZC_A_PK_SIZE * 8);
std::vector<bool> addr_pk_new_2_bv(ZC_A_PK_SIZE * 8);
std::vector<bool> addr_sk_old_1_bv(ZC_A_SK_SIZE * 8);
std::vector<bool> addr_sk_old_2_bv(ZC_A_SK_SIZE * 8);
std::vector<bool> rand_new_1_bv(ZC_R_SIZE * 8);
std::vector<bool> rand_new_2_bv(ZC_R_SIZE * 8);
std::vector<bool> rand_old_1_bv(ZC_R_SIZE * 8);
std::vector<bool> rand_old_2_bv(ZC_R_SIZE * 8);
std::vector<bool> nonce_new_1_bv(ZC_RHO_SIZE * 8);
std::vector<bool> nonce_new_2_bv(ZC_RHO_SIZE * 8);
std::vector<bool> nonce_old_1_bv(ZC_RHO_SIZE * 8);
std::vector<bool> nonce_old_2_bv(ZC_RHO_SIZE * 8);
std::vector<bool> val_new_1_bv(ZC_V_SIZE * 8);
std::vector<bool> val_new_2_bv(ZC_V_SIZE * 8);
std::vector<bool> val_old_pub_bv(ZC_V_SIZE * 8);
std::vector<bool> val_new_pub_bv(ZC_V_SIZE * 8);
std::vector<bool> val_old_1_bv(ZC_V_SIZE * 8);
std::vector<bool> val_old_2_bv(ZC_V_SIZE * 8);
std::vector<bool> cm_new_1_bv(ZC_CM_SIZE * 8);
std::vector<bool> cm_new_2_bv(ZC_CM_SIZE * 8);
convertBytesVectorToVector(rt, root_bv);
convertBytesVectorToVector(c_1_new.getCoinCommitment().getCommitmentValue(), cm_new_1_bv);
convertBytesVectorToVector(c_2_new.getCoinCommitment().getCommitmentValue(), cm_new_2_bv);
{
auto a = from_uint256(addr_1_old.getPrivateAddress().getAddressSecret());
auto b = from_uint256(addr_2_old.getPrivateAddress().getAddressSecret());
convertBytesVectorToVector(a, addr_sk_old_1_bv);
convertBytesVectorToVector(b, addr_sk_old_2_bv);
}
{
auto a = from_uint256(addr_1_new.getPublicAddressSecret());
auto b = from_uint256(addr_2_new.getPublicAddressSecret());
convertBytesVectorToVector(a, addr_pk_new_1_bv);
convertBytesVectorToVector(b, addr_pk_new_2_bv);
}
convertBytesVectorToVector(c_1_old.getR(), rand_old_1_bv);
convertBytesVectorToVector(c_2_old.getR(), rand_old_2_bv);
convertBytesVectorToVector(c_1_new.getR(), rand_new_1_bv);
convertBytesVectorToVector(c_2_new.getR(), rand_new_2_bv);
convertBytesVectorToVector(c_1_old.getRho(), nonce_old_1_bv);
convertBytesVectorToVector(c_2_old.getRho(), nonce_old_2_bv);
convertBytesVectorToVector(c_1_new.getRho(), nonce_new_1_bv);
convertBytesVectorToVector(c_2_new.getRho(), nonce_new_2_bv);
std::vector<unsigned char> v_old_1_conv(ZC_V_SIZE, 0);
convertIntToBytesVector(c_1_old.getValue(), v_old_1_conv);
libzerocash::convertBytesVectorToVector(v_old_1_conv, val_old_1_bv);
std::vector<unsigned char> v_old_2_conv(ZC_V_SIZE, 0);
convertIntToBytesVector(c_2_old.getValue(), v_old_2_conv);
libzerocash::convertBytesVectorToVector(v_old_2_conv, val_old_2_bv);
std::vector<unsigned char> v_new_1_conv(ZC_V_SIZE, 0);
convertIntToBytesVector(c_1_new.getValue(), v_new_1_conv);
libzerocash::convertBytesVectorToVector(v_new_1_conv, val_new_1_bv);
std::vector<unsigned char> v_new_2_conv(ZC_V_SIZE, 0);
convertIntToBytesVector(c_2_new.getValue(), v_new_2_conv);
libzerocash::convertBytesVectorToVector(v_new_2_conv, val_new_2_bv);
convertBytesVectorToVector(this->publicOldValue, val_old_pub_bv);
convertBytesVectorToVector(this->publicNewValue, val_new_pub_bv);
std::vector<bool> nonce_old_1(ZC_RHO_SIZE * 8);
copy(nonce_old_1_bv.begin(), nonce_old_1_bv.end(), nonce_old_1.begin());
nonce_old_1.erase(nonce_old_1.end()-2, nonce_old_1.end());
nonce_old_1.insert(nonce_old_1.begin(), 1);
nonce_old_1.insert(nonce_old_1.begin(), 0);
std::vector<bool> sn_internal_1;
concatenateVectors(addr_sk_old_1_bv, nonce_old_1, sn_internal_1);
std::vector<bool> sn_old_1_bv(ZC_SN_SIZE * 8);
hashVector(sn_internal_1, sn_old_1_bv);
convertVectorToBytesVector(sn_old_1_bv, this->serialNumber_1);
std::vector<bool> nonce_old_2(ZC_RHO_SIZE * 8);
copy(nonce_old_2_bv.begin(), nonce_old_2_bv.end(), nonce_old_2.begin());
nonce_old_2.erase(nonce_old_2.end()-2, nonce_old_2.end());
nonce_old_2.insert(nonce_old_2.begin(), 1);
nonce_old_2.insert(nonce_old_2.begin(), 0);
std::vector<bool> sn_internal_2;
concatenateVectors(addr_sk_old_2_bv, nonce_old_2, sn_internal_2);
std::vector<bool> sn_old_2_bv(ZC_SN_SIZE * 8);
hashVector(sn_internal_2, sn_old_2_bv);
convertVectorToBytesVector(sn_old_2_bv, this->serialNumber_2);
unsigned char h_S_bytes[ZC_H_SIZE];
unsigned char pubkeyHash_bytes[ZC_H_SIZE];
convertBytesVectorToBytes(pubkeyHash, pubkeyHash_bytes);
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, pubkeyHash_bytes, ZC_H_SIZE);
SHA256_Final(h_S_bytes, &sha256);
std::vector<bool> h_S_bv(ZC_H_SIZE * 8);
convertBytesToVector(h_S_bytes, h_S_bv);
std::vector<bool> h_S_internal1(ZC_H_SIZE * 8);
convertBytesToVector(h_S_bytes, h_S_internal1);
h_S_internal1.erase(h_S_internal1.end()-3, h_S_internal1.end());
std::vector<bool> h_S_internal2 = h_S_internal1;
h_S_internal1.insert(h_S_internal1.begin(), 0);
h_S_internal1.insert(h_S_internal1.begin(), 0);
h_S_internal1.insert(h_S_internal1.begin(), 1);
h_S_internal2.insert(h_S_internal2.begin(), 1);
h_S_internal2.insert(h_S_internal2.begin(), 0);
h_S_internal2.insert(h_S_internal2.begin(), 1);
std::vector<bool> MAC_1_internal;
concatenateVectors(addr_sk_old_1_bv, h_S_internal1, MAC_1_internal);
std::vector<bool> MAC_1_bv(ZC_H_SIZE * 8);
hashVector(MAC_1_internal, MAC_1_bv);
convertVectorToBytesVector(MAC_1_bv, this->MAC_1);
std::vector<bool> MAC_2_internal;
concatenateVectors(addr_sk_old_2_bv, h_S_internal2, MAC_2_internal);
std::vector<bool> MAC_2_bv(ZC_H_SIZE * 8);
hashVector(MAC_2_internal, MAC_2_bv);
convertVectorToBytesVector(MAC_2_bv, this->MAC_2);
if(this->version > 0){
auto proofObj = zerocash_pour_ppzksnark_prover<ZerocashParams::zerocash_pp>(params.getProvingKey(),
{ patMAC_1, patMAC_2 },
{ patMerkleIdx_1, patMerkleIdx_2 },
root_bv,
{ addr_pk_new_1_bv, addr_pk_new_2_bv },
{ addr_sk_old_1_bv, addr_sk_old_2_bv },
{ rand_new_1_bv, rand_new_2_bv },
{ rand_old_1_bv, rand_old_2_bv },
{ nonce_new_1_bv, nonce_new_2_bv },
{ nonce_old_1_bv, nonce_old_2_bv },
{ val_new_1_bv, val_new_2_bv },
val_old_pub_bv,
val_new_pub_bv,
{ val_old_1_bv, val_old_2_bv },
h_S_bv);
std::stringstream ss;
ss << proofObj;
this->zkSNARK = ss.str();
} else {
this->zkSNARK = std::string(1235,'A');
}
// TODO: when h_Sig is constructed properly as per spec
// replace uint256() with it
ZCNoteEncryption encryptor = ZCNoteEncryption(uint256());
{
std::vector<unsigned char> plaintext_internals;
plaintext_internals.insert(plaintext_internals.end(), c_1_new.coinValue.begin(), c_1_new.coinValue.end());
plaintext_internals.insert(plaintext_internals.end(), c_1_new.r.begin(), c_1_new.r.end());
plaintext_internals.insert(plaintext_internals.end(), c_1_new.rho.begin(), c_1_new.rho.end());
std::vector<unsigned char> memo(ZC_MEMO_SIZE, 0x00);
plaintext_internals.insert(plaintext_internals.end(), memo.begin(), memo.end());
// This is all going away.
assert(plaintext_internals.size() >= 201);
boost::array<unsigned char, 201> pt;
memcpy(&pt[0], &plaintext_internals[0], 201);
this->ciphertext_1 = encryptor.encrypt(addr_1_new.getEncryptionPublicKey(),
pt);
}
{
std::vector<unsigned char> plaintext_internals;
plaintext_internals.insert(plaintext_internals.end(), c_2_new.coinValue.begin(), c_2_new.coinValue.end());
plaintext_internals.insert(plaintext_internals.end(), c_2_new.r.begin(), c_2_new.r.end());
plaintext_internals.insert(plaintext_internals.end(), c_2_new.rho.begin(), c_2_new.rho.end());
std::vector<unsigned char> memo(ZC_MEMO_SIZE, 0x00);
plaintext_internals.insert(plaintext_internals.end(), memo.begin(), memo.end());
// This is all going away.
assert(plaintext_internals.size() >= 201);
boost::array<unsigned char, 201> pt;
memcpy(&pt[0], &plaintext_internals[0], 201);
this->ciphertext_2 = encryptor.encrypt(addr_2_new.getEncryptionPublicKey(),
pt);
}
this->ephemeralKey = encryptor.get_epk();
}
bool PourTransaction::verify(ZerocashParams& params,
const std::vector<unsigned char> &pubkeyHash,
const MerkleRootType &merkleRoot) const
{
if(this->version == 0){
return true;
}
zerocash_pour_proof<ZerocashParams::zerocash_pp> proof_SNARK;
std::stringstream ss;
ss.str(this->zkSNARK);
ss >> proof_SNARK;
if (merkleRoot.size() != ZC_ROOT_SIZE) { return false; }
if (pubkeyHash.size() != ZC_H_SIZE) { return false; }
if (this->serialNumber_1.size() != ZC_SN_SIZE) { return false; }
if (this->serialNumber_2.size() != ZC_SN_SIZE) { return false; }
if (this->publicOldValue.size() != ZC_V_SIZE) { return false; }
if (this->publicNewValue.size() != ZC_V_SIZE) { return false; }
if (this->MAC_1.size() != ZC_H_SIZE) { return false; }
if (this->MAC_2.size() != ZC_H_SIZE) { return false; }
std::vector<bool> root_bv(ZC_ROOT_SIZE * 8);
std::vector<bool> sn_old_1_bv(ZC_SN_SIZE * 8);
std::vector<bool> sn_old_2_bv(ZC_SN_SIZE * 8);
std::vector<bool> cm_new_1_bv(ZC_CM_SIZE * 8);
std::vector<bool> cm_new_2_bv(ZC_CM_SIZE * 8);
std::vector<bool> val_old_pub_bv(ZC_V_SIZE * 8);
std::vector<bool> val_new_pub_bv(ZC_V_SIZE * 8);
std::vector<bool> MAC_1_bv(ZC_H_SIZE * 8);
std::vector<bool> MAC_2_bv(ZC_H_SIZE * 8);
convertBytesVectorToVector(merkleRoot, root_bv);
convertBytesVectorToVector(this->serialNumber_1, sn_old_1_bv);
convertBytesVectorToVector(this->serialNumber_2, sn_old_2_bv);
convertBytesVectorToVector(this->cm_1.getCommitmentValue(), cm_new_1_bv);
convertBytesVectorToVector(this->cm_2.getCommitmentValue(), cm_new_2_bv);
convertBytesVectorToVector(this->publicOldValue, val_old_pub_bv);
convertBytesVectorToVector(this->publicNewValue, val_new_pub_bv);
convertBytesVectorToVector(this->MAC_1, MAC_1_bv);
convertBytesVectorToVector(this->MAC_2, MAC_2_bv);
unsigned char h_S_bytes[ZC_H_SIZE];
unsigned char pubkeyHash_bytes[ZC_H_SIZE];
convertBytesVectorToBytes(pubkeyHash, pubkeyHash_bytes);
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, pubkeyHash_bytes, ZC_H_SIZE);
SHA256_Final(h_S_bytes, &sha256);
std::vector<bool> h_S_internal(ZC_H_SIZE * 8);
convertBytesToVector(h_S_bytes, h_S_internal);
h_S_internal.erase(h_S_internal.end()-2, h_S_internal.end());
h_S_internal.insert(h_S_internal.begin(), 0);
h_S_internal.insert(h_S_internal.begin(), 1);
std::vector<bool> h_S_bv(ZC_H_SIZE * 8);
convertBytesToVector(h_S_bytes, h_S_bv);
bool snark_result = zerocash_pour_ppzksnark_verifier<ZerocashParams::zerocash_pp>(params.getVerificationKey(),
root_bv,
{ sn_old_1_bv, sn_old_2_bv },
{ cm_new_1_bv, cm_new_2_bv },
val_old_pub_bv,
val_new_pub_bv,
h_S_bv,
{ MAC_1_bv, MAC_2_bv },
proof_SNARK);
return snark_result;
}
const std::vector<unsigned char>& PourTransaction::getSpentSerial1() const{
return this->serialNumber_1;
}
const std::vector<unsigned char>& PourTransaction::getSpentSerial2() const{
return this->serialNumber_2;
}
const ZCNoteEncryption::Ciphertext& PourTransaction::getCiphertext1() const {
return this->ciphertext_1;
}
const ZCNoteEncryption::Ciphertext& PourTransaction::getCiphertext2() const {
return this->ciphertext_2;
}
/**
* Returns the hash of the first new coin commitment output by this Pour.
*/
const CoinCommitmentValue& PourTransaction::getNewCoinCommitmentValue1() const{
return this->cm_1.getCommitmentValue();
}
/**
* Returns the hash of the second new coin commitment output by this Pour.
*/
const CoinCommitmentValue& PourTransaction::getNewCoinCommitmentValue2() const{
return this->cm_2.getCommitmentValue();
}
uint64_t PourTransaction::getPublicValueIn() const{
return convertBytesVectorToInt(this->publicOldValue);
}
uint64_t PourTransaction::getPublicValueOut() const{
return convertBytesVectorToInt(this->publicNewValue);
}
} /* namespace libzerocash */