Sean Bowe
8 years ago
33 changed files with 2 additions and 5037 deletions
@ -1,132 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Implementation of interfaces for the classes Address and PublicAddress. |
|||
|
|||
See Address.h . |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#include "zcash/NoteEncryption.hpp" |
|||
|
|||
#include "Zerocash.h" |
|||
#include "Address.h" |
|||
|
|||
namespace libzerocash { |
|||
|
|||
PrivateAddress::PrivateAddress(const uint256 &a_sk, const uint256 &sk_enc) { |
|||
this->a_sk = a_sk; |
|||
this->sk_enc = sk_enc; |
|||
} |
|||
|
|||
PrivateAddress::PrivateAddress() { |
|||
|
|||
} |
|||
|
|||
bool PrivateAddress::operator==(const PrivateAddress& rhs) const { |
|||
return ((this->a_sk == rhs.a_sk) && (this->sk_enc == rhs.sk_enc)); |
|||
} |
|||
|
|||
bool PrivateAddress::operator!=(const PrivateAddress& rhs) const { |
|||
return !(*this == rhs); |
|||
} |
|||
|
|||
const uint256& PrivateAddress::getEncryptionSecretKey() const { |
|||
return this->sk_enc; |
|||
} |
|||
|
|||
const uint256& PrivateAddress::getAddressSecret() const { |
|||
return this->a_sk; |
|||
} |
|||
|
|||
PublicAddress::PublicAddress() { |
|||
|
|||
} |
|||
|
|||
PublicAddress::PublicAddress(const uint256& a_pk, uint256& pk_enc) : a_pk(a_pk), pk_enc(pk_enc) {} |
|||
|
|||
PublicAddress::PublicAddress(const PrivateAddress& addr_sk) { |
|||
std::vector<bool> a_sk_bool(ZC_A_SK_SIZE * 8); |
|||
|
|||
std::vector<unsigned char> a_sk_v(addr_sk.getAddressSecret().begin(), |
|||
addr_sk.getAddressSecret().end()); |
|||
|
|||
convertBytesVectorToVector(a_sk_v, a_sk_bool); |
|||
|
|||
std::vector<bool> zeros_256(256, 0); |
|||
|
|||
std::vector<bool> a_pk_internal; |
|||
concatenateVectors(a_sk_bool, zeros_256, a_pk_internal); |
|||
|
|||
std::vector<bool> a_pk_bool(ZC_A_PK_SIZE * 8); |
|||
hashVector(a_pk_internal, a_pk_bool); |
|||
|
|||
std::vector<unsigned char> a_pk_vv(ZC_A_PK_SIZE); |
|||
|
|||
convertVectorToBytesVector(a_pk_bool, a_pk_vv); |
|||
|
|||
this->a_pk = uint256(a_pk_vv); |
|||
|
|||
this->pk_enc = ZCNoteEncryption::generate_pubkey(addr_sk.getEncryptionSecretKey()); |
|||
} |
|||
|
|||
const uint256& PublicAddress::getEncryptionPublicKey() const { |
|||
return this->pk_enc; |
|||
} |
|||
|
|||
const uint256& PublicAddress::getPublicAddressSecret() const { |
|||
return this->a_pk; |
|||
} |
|||
|
|||
bool PublicAddress::operator==(const PublicAddress& rhs) const { |
|||
return ((this->a_pk == rhs.a_pk) && (this->pk_enc == rhs.pk_enc)); |
|||
} |
|||
|
|||
bool PublicAddress::operator!=(const PublicAddress& rhs) const { |
|||
return !(*this == rhs); |
|||
} |
|||
|
|||
Address::Address(PrivateAddress& priv) : addr_pk(priv), addr_sk(priv) { |
|||
|
|||
} |
|||
|
|||
Address::Address() : addr_pk(), addr_sk() { |
|||
|
|||
} |
|||
|
|||
const PublicAddress& Address::getPublicAddress() const { |
|||
return this->addr_pk; |
|||
} |
|||
|
|||
const PrivateAddress& Address::getPrivateAddress() const { |
|||
return this->addr_sk; |
|||
} |
|||
|
|||
bool Address::operator==(const Address& rhs) const { |
|||
return ((this->addr_sk == rhs.addr_sk) && (this->addr_pk == rhs.addr_pk)); |
|||
} |
|||
|
|||
bool Address::operator!=(const Address& rhs) const { |
|||
return !(*this == rhs); |
|||
} |
|||
|
|||
Address Address::CreateNewRandomAddress() { |
|||
std::vector<unsigned char> a_sk(ZC_A_SK_SIZE); |
|||
|
|||
unsigned char a_sk_bytes[ZC_A_SK_SIZE]; |
|||
getRandBytes(a_sk_bytes, ZC_A_SK_SIZE); |
|||
convertBytesToBytesVector(a_sk_bytes, a_sk); |
|||
|
|||
uint256 a_sk_u(a_sk); |
|||
|
|||
uint256 sk_enc = ZCNoteEncryption::generate_privkey(a_sk_u); |
|||
|
|||
PrivateAddress addr_sk(a_sk_u, sk_enc); |
|||
return Address(addr_sk); |
|||
} |
|||
|
|||
} /* namespace libzerocash */ |
@ -1,87 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Declaration of interfaces for the classes Address and PublicAddress. |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef ADDRESS_H_ |
|||
#define ADDRESS_H_ |
|||
|
|||
#include <vector> |
|||
#include <string> |
|||
|
|||
#include "uint256.h" |
|||
|
|||
namespace libzerocash { |
|||
|
|||
/***************************** Private address ********************************/ |
|||
|
|||
class PrivateAddress { |
|||
public: |
|||
/* This constructor is to be used ONLY for deserialization. */ |
|||
PrivateAddress(); |
|||
PrivateAddress(const uint256 &a_sk, const uint256 &sk_enc); |
|||
|
|||
bool operator==(const PrivateAddress& rhs) const; |
|||
bool operator!=(const PrivateAddress& rhs) const; |
|||
|
|||
const uint256& getAddressSecret() const; |
|||
const uint256& getEncryptionSecretKey() const; |
|||
|
|||
private: |
|||
uint256 a_sk; |
|||
uint256 sk_enc; |
|||
|
|||
}; |
|||
|
|||
/***************************** Public address ********************************/ |
|||
|
|||
class PublicAddress { |
|||
public: |
|||
/* This constructor is to be used ONLY for deserialization. */ |
|||
PublicAddress(); |
|||
PublicAddress(const uint256& a_pk, uint256& pk_enc); |
|||
PublicAddress(const PrivateAddress& addr_sk); |
|||
|
|||
bool operator==(const PublicAddress& rhs) const; |
|||
bool operator!=(const PublicAddress& rhs) const; |
|||
|
|||
|
|||
const uint256& getPublicAddressSecret() const; |
|||
const uint256& getEncryptionPublicKey() const; |
|||
|
|||
private: |
|||
uint256 a_pk; |
|||
uint256 pk_enc; |
|||
}; |
|||
|
|||
/******************************** Address ************************************/ |
|||
|
|||
class Address { |
|||
public: |
|||
/* This constructor is to be used ONLY for deserialization. */ |
|||
Address(); |
|||
Address(PrivateAddress&); |
|||
|
|||
const PublicAddress& getPublicAddress() const; |
|||
const PrivateAddress& getPrivateAddress() const; |
|||
|
|||
bool operator==(const Address& rhs) const; |
|||
bool operator!=(const Address& rhs) const; |
|||
|
|||
|
|||
static Address CreateNewRandomAddress(); |
|||
|
|||
private: |
|||
PublicAddress addr_pk; |
|||
PrivateAddress addr_sk; |
|||
}; |
|||
|
|||
} /* namespace libzerocash */ |
|||
|
|||
#endif /* ADDRESS_H_ */ |
@ -1,137 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Implementation of interfaces for the class Coin. |
|||
|
|||
See coin.h . |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#include <stdexcept> |
|||
|
|||
#include "Zerocash.h" |
|||
#include "Coin.h" |
|||
|
|||
namespace libzerocash { |
|||
|
|||
Coin::Coin(): addr_pk(), cm(), rho(ZC_RHO_SIZE), r(ZC_R_SIZE), coinValue(ZC_V_SIZE) { |
|||
|
|||
} |
|||
|
|||
Coin::Coin(const ZCNoteEncryption::Ciphertext& bucket, |
|||
Address& addr, |
|||
uint256& epk, |
|||
unsigned char nonce |
|||
): addr_pk(), cm(), rho(ZC_RHO_SIZE), r(ZC_R_SIZE), k(ZC_K_SIZE), coinValue(ZC_V_SIZE) { |
|||
|
|||
ZCNoteDecryption decrypter(addr.getPrivateAddress().getEncryptionSecretKey()); |
|||
auto plaintext = decrypter.decrypt(bucket, |
|||
epk, |
|||
uint256(), |
|||
nonce); |
|||
|
|||
// Grab the byte vectors
|
|||
std::vector<unsigned char> value_v(plaintext.begin(), |
|||
plaintext.begin() + ZC_V_SIZE); |
|||
std::vector<unsigned char> r_v(plaintext.begin() + ZC_V_SIZE, |
|||
plaintext.begin() + ZC_V_SIZE + ZC_R_SIZE); |
|||
std::vector<unsigned char> rho_v(plaintext.begin() + ZC_V_SIZE + ZC_R_SIZE, |
|||
plaintext.begin() + ZC_V_SIZE + ZC_R_SIZE + ZC_RHO_SIZE); |
|||
|
|||
this->coinValue = value_v; |
|||
this->r = r_v; |
|||
this->rho = rho_v; |
|||
this->addr_pk = addr.getPublicAddress(); |
|||
|
|||
std::vector<unsigned char> a_pk(addr.getPublicAddress().getPublicAddressSecret().begin(), |
|||
addr.getPublicAddress().getPublicAddressSecret().end()); |
|||
|
|||
this->computeCommitments(a_pk); |
|||
} |
|||
|
|||
Coin::Coin(const PublicAddress& addr, uint64_t value): addr_pk(addr), cm(), rho(ZC_RHO_SIZE), r(ZC_R_SIZE), k(ZC_K_SIZE), coinValue(ZC_V_SIZE) |
|||
{ |
|||
convertIntToBytesVector(value, this->coinValue); |
|||
|
|||
std::vector<unsigned char> a_pk(addr.getPublicAddressSecret().begin(), |
|||
addr.getPublicAddressSecret().end()); |
|||
|
|||
unsigned char rho_bytes[ZC_RHO_SIZE]; |
|||
getRandBytes(rho_bytes, ZC_RHO_SIZE); |
|||
convertBytesToBytesVector(rho_bytes, this->rho); |
|||
|
|||
unsigned char r_bytes[ZC_R_SIZE]; |
|||
getRandBytes(r_bytes, ZC_R_SIZE); |
|||
convertBytesToBytesVector(r_bytes, this->r); |
|||
|
|||
this->computeCommitments(a_pk); |
|||
} |
|||
|
|||
|
|||
Coin::Coin(const PublicAddress& addr, uint64_t value, |
|||
const std::vector<unsigned char>& rho, const std::vector<unsigned char>& r): addr_pk(addr), rho(rho), r(r), k(ZC_K_SIZE), coinValue(ZC_V_SIZE) |
|||
{ |
|||
convertIntToBytesVector(value, this->coinValue); |
|||
|
|||
std::vector<unsigned char> a_pk(addr.getPublicAddressSecret().begin(), addr.getPublicAddressSecret().end()); |
|||
|
|||
this->computeCommitments(a_pk); |
|||
} |
|||
|
|||
void |
|||
Coin::computeCommitments(std::vector<unsigned char>& a_pk) |
|||
{ |
|||
std::vector<unsigned char> k_internal; |
|||
std::vector<unsigned char> k_internalhash_trunc(16); |
|||
|
|||
std::vector<unsigned char> k_internalhash_internal; |
|||
concatenateVectors(a_pk, this->rho, k_internalhash_internal); |
|||
|
|||
std::vector<unsigned char> k_internalhash(ZC_K_SIZE); |
|||
hashVector(k_internalhash_internal, k_internalhash); |
|||
|
|||
copy(k_internalhash.begin(), k_internalhash.begin()+16, k_internalhash_trunc.begin()); |
|||
concatenateVectors(this->r, k_internalhash_trunc, k_internal); |
|||
hashVector(k_internal, this->k); |
|||
|
|||
CoinCommitment com(this->coinValue, this->k); |
|||
this->cm = com; |
|||
} |
|||
|
|||
bool Coin::operator==(const Coin& rhs) const { |
|||
return ((this->cm == rhs.cm) && (this->rho == rhs.rho) && (this->r == rhs.r) && (this->k == rhs.k) && (this->coinValue == rhs.coinValue) && (this->addr_pk == rhs.addr_pk)); |
|||
} |
|||
|
|||
bool Coin::operator!=(const Coin& rhs) const { |
|||
return !(*this == rhs); |
|||
} |
|||
|
|||
const PublicAddress& Coin::getPublicAddress() const { |
|||
return this->addr_pk; |
|||
} |
|||
|
|||
const CoinCommitment& Coin::getCoinCommitment() const { |
|||
return this->cm; |
|||
} |
|||
|
|||
const std::vector<unsigned char>& Coin::getInternalCommitment() const { |
|||
return this->k; |
|||
} |
|||
|
|||
const std::vector<unsigned char>& Coin::getRho() const { |
|||
return this->rho; |
|||
} |
|||
|
|||
const std::vector<unsigned char>& Coin::getR() const { |
|||
return this->r; |
|||
} |
|||
|
|||
uint64_t Coin::getValue() const { |
|||
return convertBytesVectorToInt(this->coinValue); |
|||
} |
|||
|
|||
} /* namespace libzerocash */ |
@ -1,76 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Declaration of interfaces for the class Coin. |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef COIN_H_ |
|||
#define COIN_H_ |
|||
|
|||
#include <vector> |
|||
|
|||
#include "Address.h" |
|||
#include "CoinCommitment.h" |
|||
|
|||
#include "zcash/NoteEncryption.hpp" |
|||
|
|||
namespace libzerocash { |
|||
|
|||
/********************************* Coin **************************************/ |
|||
|
|||
class Coin { |
|||
|
|||
friend class MintTransaction; |
|||
friend class PourTransaction; |
|||
|
|||
public: |
|||
/* This constructor is to be used ONLY for deserialization. */ |
|||
Coin(); |
|||
/**
|
|||
* @param addr the address the coin will belong to when minted or poured into |
|||
* @param value the monetary value of the coin |
|||
*/ |
|||
Coin(const PublicAddress& addr, |
|||
uint64_t value); |
|||
|
|||
Coin(const PublicAddress& addr, |
|||
uint64_t value, |
|||
const std::vector<unsigned char>& rho, |
|||
const std::vector<unsigned char>& r); |
|||
|
|||
Coin(const ZCNoteEncryption::Ciphertext&, Address& addr, uint256& epk, unsigned char nonce); |
|||
|
|||
const PublicAddress& getPublicAddress() const; |
|||
|
|||
const CoinCommitment& getCoinCommitment() const; |
|||
|
|||
bool operator==(const Coin& rhs) const; |
|||
bool operator!=(const Coin& rhs) const; |
|||
|
|||
uint64_t getValue() const; |
|||
|
|||
const std::vector<unsigned char>& getRho() const; |
|||
|
|||
const std::vector<unsigned char>& getR() const; |
|||
|
|||
private: |
|||
PublicAddress addr_pk; |
|||
CoinCommitment cm; |
|||
std::vector<unsigned char> rho; |
|||
std::vector<unsigned char> r; |
|||
std::vector<unsigned char> k; |
|||
std::vector<unsigned char> coinValue; |
|||
|
|||
const std::vector<unsigned char>& getInternalCommitment() const; |
|||
|
|||
void computeCommitments(std::vector<unsigned char>& a_pk); |
|||
}; |
|||
|
|||
} /* namespace libzerocash */ |
|||
|
|||
#endif /* COIN_H_ */ |
@ -1,58 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Implementation of interfaces for the class CoinCommitment. |
|||
|
|||
See CoinCommitment.h . |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#include <stdexcept> |
|||
#include <stdint.h> |
|||
|
|||
#include "Zerocash.h" |
|||
#include "CoinCommitment.h" |
|||
|
|||
namespace libzerocash { |
|||
|
|||
CoinCommitment::CoinCommitment() : commitmentValue(ZC_CM_SIZE) |
|||
{ } |
|||
|
|||
CoinCommitment::CoinCommitment(const std::vector<unsigned char>& val, |
|||
const std::vector<unsigned char>& k) : commitmentValue(ZC_CM_SIZE) |
|||
{ |
|||
std::vector<bool> zeros_192(192, 0); |
|||
std::vector<bool> cm_internal; |
|||
std::vector<bool> value_bool(ZC_V_SIZE * 8, 0); |
|||
std::vector<bool> k_bool(ZC_K_SIZE * 8, 0); |
|||
|
|||
if (val.size() > ZC_V_SIZE || k.size() > ZC_K_SIZE) { |
|||
throw std::runtime_error("CoinCommitment: inputs are too large"); |
|||
} |
|||
|
|||
libzerocash::convertBytesVectorToVector(val, value_bool); |
|||
libzerocash::convertBytesVectorToVector(k, k_bool); |
|||
|
|||
libzerocash::concatenateVectors(k_bool, zeros_192, value_bool, cm_internal); |
|||
std::vector<bool> cm_bool(ZC_CM_SIZE * 8); |
|||
libzerocash::hashVector(cm_internal, cm_bool); |
|||
libzerocash::convertVectorToBytesVector(cm_bool, this->commitmentValue); |
|||
} |
|||
|
|||
bool CoinCommitment::operator==(const CoinCommitment& rhs) const { |
|||
return (this->commitmentValue == rhs.commitmentValue); |
|||
} |
|||
|
|||
bool CoinCommitment::operator!=(const CoinCommitment& rhs) const { |
|||
return !(*this == rhs); |
|||
} |
|||
|
|||
const std::vector<unsigned char>& CoinCommitment::getCommitmentValue() const { |
|||
return this->commitmentValue; |
|||
} |
|||
|
|||
} /* namespace libzerocash */ |
@ -1,44 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Declaration of interfaces for the class CoinCommitment. |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef COINCOMMITMENT_H_ |
|||
#define COINCOMMITMENT_H_ |
|||
|
|||
#include <vector> |
|||
|
|||
namespace libzerocash { |
|||
|
|||
/****************************** Coin commitment ******************************/ |
|||
|
|||
class CoinCommitment { |
|||
|
|||
friend class PourTransaction; |
|||
friend class PourProver; |
|||
|
|||
public: |
|||
CoinCommitment(); |
|||
|
|||
CoinCommitment(const std::vector<unsigned char>& val, |
|||
const std::vector<unsigned char>& k); |
|||
|
|||
const std::vector<unsigned char>& getCommitmentValue() const; |
|||
|
|||
bool operator==(const CoinCommitment& rhs) const; |
|||
bool operator!=(const CoinCommitment& rhs) const; |
|||
|
|||
|
|||
private: |
|||
std::vector<unsigned char> commitmentValue; |
|||
}; |
|||
|
|||
} /* namespace libzerocash */ |
|||
|
|||
#endif /* COINCOMMITMENT_H_ */ |
@ -1,42 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Functionality to generate files containing the Zerocash public parameters. |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#include <fstream> |
|||
|
|||
#include "Zerocash.h" |
|||
#include "ZerocashParams.h" |
|||
#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp" |
|||
#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" |
|||
|
|||
using namespace libzerocash; |
|||
|
|||
int main(int argc, char **argv) |
|||
{ |
|||
if(argc != 4) { |
|||
std::cerr << "Usage: " << argv[0] << " treeDepth provingKeyFileName verificationKeyFileName" << std::endl; |
|||
return 1; |
|||
} |
|||
|
|||
unsigned int tree_depth = atoi(argv[1]); |
|||
std::string pkFile = argv[2]; |
|||
std::string vkFile = argv[3]; |
|||
|
|||
auto keypair = libzerocash::ZerocashParams::GenerateNewKeyPair(tree_depth); |
|||
libzerocash::ZerocashParams p( |
|||
tree_depth, |
|||
&keypair |
|||
); |
|||
|
|||
libzerocash::ZerocashParams::SaveProvingKeyToFile(&p.getProvingKey(), pkFile); |
|||
libzerocash::ZerocashParams::SaveVerificationKeyToFile(&p.getVerificationKey(), vkFile); |
|||
|
|||
return 0; |
|||
} |
@ -1,606 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Implementation of interfaces for the classes IncrementalMerkleTreeCompact, |
|||
IncrementalMerkleNode, and IncrementalMerkleTree. |
|||
|
|||
See IncrementalMerkleTree.h . |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#include "IncrementalMerkleTree.h" |
|||
#include "Zerocash.h" |
|||
|
|||
#include <cmath> |
|||
#include <iostream> |
|||
#include <vector> |
|||
|
|||
namespace libzerocash { |
|||
|
|||
/////////////////////////////////////////////
|
|||
// IncrementalMerkleTreeCompact class
|
|||
/////////////////////////////////////////////
|
|||
|
|||
std::vector<unsigned char> IncrementalMerkleTreeCompact::serialize() const { |
|||
/* Serialization format:
|
|||
* treeHeight (4 bytes, big endian) |
|||
* hashList (ceil(treeHeight / 8) bytes) |
|||
* hashVec (32 bytes for every 1 bit in hashList) |
|||
*/ |
|||
std::vector<unsigned char> serialized; |
|||
|
|||
/* treeHeight (4 bytes, big endian) */ |
|||
std::vector<unsigned char> treeHeightBytes(4); |
|||
convertIntToBytesVector((uint64_t)this->treeHeight, treeHeightBytes); |
|||
serialized.insert(serialized.end(), treeHeightBytes.begin(), treeHeightBytes.end()); |
|||
|
|||
/* hashList */ |
|||
assert(this->hashList.size() == this->treeHeight); |
|||
|
|||
/* Pad it out to a multiple of 8 bits. */ |
|||
std::vector<bool> hashList = this->hashList; |
|||
if (hashList.size() % 8 != 0) { |
|||
hashList.insert(hashList.begin(), 8 - (hashList.size() % 8), false); |
|||
} |
|||
assert(hashList.size() % 8 == 0); |
|||
|
|||
/* Convert it to a byte vector. */ |
|||
std::vector<unsigned char> hashListBytes(hashList.size() / 8); |
|||
convertVectorToBytesVector(hashList, hashListBytes); |
|||
serialized.insert(serialized.end(), hashListBytes.begin(), hashListBytes.end()); |
|||
|
|||
/* hashVec */ |
|||
assert(this->hashVec.size() == countOnes(this->hashList)); |
|||
for (uint32_t i = 0; i < this->hashVec.size(); i++) { |
|||
assert(this->hashVec.at(i).size() == 32); |
|||
serialized.insert(serialized.end(), this->hashVec.at(i).begin(), this->hashVec.at(i).end()); |
|||
} |
|||
|
|||
return serialized; |
|||
} |
|||
|
|||
IncrementalMerkleTreeCompact IncrementalMerkleTreeCompact::deserialize(const std::vector<unsigned char>& serialized) { |
|||
IncrementalMerkleTreeCompact deserialized; |
|||
|
|||
size_t currentPos = 0; |
|||
|
|||
|
|||
/* treeHeight */ |
|||
std::vector<unsigned char> treeHeightBytes = vectorSlice(serialized, 0, 4); |
|||
currentPos += 4; |
|||
deserialized.treeHeight = convertBytesVectorToInt(treeHeightBytes); |
|||
|
|||
/* hashList */ |
|||
uint32_t hashListBytesLength = ceil(deserialized.treeHeight / 8.0); |
|||
std::vector<unsigned char> hashListBytes = vectorSlice(serialized, currentPos, hashListBytesLength); |
|||
currentPos += hashListBytesLength; |
|||
convertBytesVectorToVector(hashListBytes, deserialized.hashList); |
|||
/* Remove the multiple-of-8-bits padding. */ |
|||
deserialized.hashList.erase(deserialized.hashList.begin(), |
|||
deserialized.hashList.end() - deserialized.treeHeight |
|||
); |
|||
|
|||
/* hashVec */ |
|||
size_t hashVecSize = countOnes(deserialized.hashList); |
|||
for (size_t i = 0; i < hashVecSize; i++) { |
|||
std::vector<unsigned char> hashVecElement = vectorSlice(serialized, currentPos, 32); |
|||
currentPos += 32; |
|||
deserialized.hashVec.push_back(hashVecElement); |
|||
} |
|||
|
|||
if (currentPos != serialized.size()) { |
|||
throw std::runtime_error("Serialized vector is longer than expected."); |
|||
} |
|||
|
|||
return deserialized; |
|||
} |
|||
|
|||
/////////////////////////////////////////////
|
|||
// IncrementalMerkleTree class
|
|||
/////////////////////////////////////////////
|
|||
|
|||
// Custom tree constructor (initialize tree of specified height)
|
|||
IncrementalMerkleTree::IncrementalMerkleTree(uint32_t height) : root(0, height) { |
|||
treeHeight = height; |
|||
} |
|||
|
|||
// Vector constructor. Initializes and inserts a list of elements.
|
|||
IncrementalMerkleTree::IncrementalMerkleTree(std::vector< std::vector<bool> > &valueVector, uint32_t height) : root(0, height) |
|||
{ |
|||
// Initialize the tree
|
|||
treeHeight = height; |
|||
|
|||
// Load the tree with all the given values
|
|||
if (this->insertVector(valueVector) == false) { |
|||
throw std::runtime_error("Could not insert vector into Merkle Tree: too many elements"); |
|||
} |
|||
} |
|||
|
|||
// Custom tree constructor (initialize tree from compact representation)
|
|||
//
|
|||
IncrementalMerkleTree::IncrementalMerkleTree(IncrementalMerkleTreeCompact &compact) : root(0, 0) |
|||
{ |
|||
// Initialize the tree
|
|||
this->treeHeight = compact.getHeight(); |
|||
root.treeHeight = treeHeight; |
|||
|
|||
// Reconstitute tree from compact representation
|
|||
this->fromCompactRepresentation(compact); |
|||
} |
|||
|
|||
bool |
|||
IncrementalMerkleTree::insertElement(const std::vector<bool> &hashV, std::vector<bool> &index) { |
|||
|
|||
// Resize the index vector
|
|||
index.resize(this->treeHeight); |
|||
|
|||
// Insert the element
|
|||
return this->root.insertElement(hashV, index); |
|||
} |
|||
|
|||
bool |
|||
IncrementalMerkleTree::insertElement(const std::vector<unsigned char> &hashV, std::vector<unsigned char> &index) { |
|||
|
|||
// Create a temporary vector to hold hashV
|
|||
std::vector<bool> hashVBool(hashV.size() * 8); |
|||
convertBytesVectorToVector(hashV, hashVBool); |
|||
|
|||
// Create a temporary vector to hold the index
|
|||
std::vector<bool> indexBool(this->treeHeight, 0); |
|||
|
|||
// Insert the element
|
|||
bool result = this->insertElement(hashVBool, indexBool); |
|||
|
|||
// Convert the returned vector
|
|||
index.resize(index.size() / 8); // this might need to include a ceil
|
|||
convertVectorToBytesVector(indexBool, index); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
bool |
|||
IncrementalMerkleTree::getWitness(const std::vector<bool> &index, merkle_authentication_path &witness) { |
|||
|
|||
// Resize the witness if necessary
|
|||
if (witness.size() < this->treeHeight) { |
|||
witness.resize(treeHeight); |
|||
} |
|||
|
|||
std::vector<bool> indexPadded = index; |
|||
|
|||
// Discard leading bits of the index if necessary
|
|||
if (indexPadded.size() > this->treeHeight) { |
|||
indexPadded.erase(indexPadded.begin(), indexPadded.begin() + (indexPadded.size() - this->treeHeight)); |
|||
} |
|||
|
|||
// If the index vector is less than 'treeHeight' bits, pad the leftmost bits with 0 (false)
|
|||
// This is to deal with the situation where somebody encodes e.g., a 32-bit integer as an index
|
|||
// into a 64 height tree and does not explicitly pad to length.
|
|||
if (indexPadded.size() < this->treeHeight) { |
|||
indexPadded.insert(indexPadded.begin(), (this->treeHeight - 1) - indexPadded.size(), false); |
|||
} |
|||
|
|||
return this->root.getWitness(indexPadded, witness); |
|||
} |
|||
|
|||
bool |
|||
IncrementalMerkleTree::insertVector(std::vector< std::vector<bool> > &valueVector) |
|||
{ |
|||
std::vector<bool> index; |
|||
|
|||
for (std::vector< std::vector<bool> >::iterator iter = valueVector.begin(); |
|||
iter != valueVector.end(); ++iter) { |
|||
|
|||
if (this->insertElement(*iter, index) == false) { |
|||
return false; |
|||
} |
|||
|
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
bool |
|||
IncrementalMerkleTree::getRootValue(std::vector<bool>& r) const { |
|||
|
|||
// Query the root for its hash
|
|||
this->root.getValue(r); |
|||
return true; |
|||
} |
|||
|
|||
bool |
|||
IncrementalMerkleTree::getRootValue(std::vector<unsigned char>& r) const { |
|||
|
|||
// Create a temporary byte vector
|
|||
std::vector<bool> tempR(r.size() * 8, 0); |
|||
|
|||
// Query the root for its hash
|
|||
this->root.getValue(tempR); |
|||
|
|||
// Convert the result back into the given vector
|
|||
convertVectorToBytesVector(tempR, r); |
|||
|
|||
return true; |
|||
} |
|||
std::vector<unsigned char> |
|||
IncrementalMerkleTree::getRoot(){ |
|||
std::vector<unsigned char> temp(8); |
|||
this->getRootValue(temp); |
|||
return temp; |
|||
} |
|||
|
|||
bool |
|||
IncrementalMerkleTree::prune() |
|||
{ |
|||
return this->root.prune(); |
|||
} |
|||
|
|||
IncrementalMerkleTreeCompact |
|||
IncrementalMerkleTree::getCompactRepresentation() const |
|||
{ |
|||
IncrementalMerkleTreeCompact rep; |
|||
rep.hashList.resize(this->treeHeight); |
|||
rep.treeHeight = this->treeHeight; |
|||
std::fill (rep.hashList.begin(), rep.hashList.end(), false); |
|||
|
|||
this->root.getCompactRepresentation(rep); |
|||
return rep; |
|||
} |
|||
|
|||
bool |
|||
IncrementalMerkleTree::fromCompactRepresentation(IncrementalMerkleTreeCompact &rep) |
|||
{ |
|||
return this->root.fromCompactRepresentation(rep, 0); |
|||
} |
|||
|
|||
/////////////////////////////////////////////
|
|||
// IncrementalMerkleNode class
|
|||
/////////////////////////////////////////////
|
|||
|
|||
// Standard constructor
|
|||
//
|
|||
IncrementalMerkleNode::IncrementalMerkleNode(uint32_t depth, uint32_t height) : left(NULL), right(NULL), value(CSHA256::OUTPUT_SIZE * 8, 0), nodeDepth(depth), treeHeight(height), |
|||
subtreeFull(false), subtreePruned(false) |
|||
{ |
|||
|
|||
} |
|||
|
|||
// Copy constructor
|
|||
//
|
|||
IncrementalMerkleNode::IncrementalMerkleNode(const IncrementalMerkleNode& toCopy) : left(NULL), right(NULL), value(CSHA256::OUTPUT_SIZE * 8, 0) |
|||
{ |
|||
this->nodeDepth = toCopy.nodeDepth; |
|||
this->subtreePruned = toCopy.subtreePruned; |
|||
this->subtreeFull = toCopy.subtreeFull; |
|||
this->value = toCopy.value; |
|||
this->treeHeight = toCopy.treeHeight; |
|||
|
|||
// Recursively copy the subtrees
|
|||
if (toCopy.left) { |
|||
this->left = new IncrementalMerkleNode(toCopy.left->nodeDepth, toCopy.left->treeHeight); |
|||
*(this->left) = *(toCopy.left); |
|||
} |
|||
|
|||
if (toCopy.right) { |
|||
this->right = new IncrementalMerkleNode(toCopy.right->nodeDepth, toCopy.right->treeHeight); |
|||
*(this->right) = *(toCopy.right); |
|||
} |
|||
} |
|||
|
|||
IncrementalMerkleNode::~IncrementalMerkleNode() |
|||
{ |
|||
if (this->left) { |
|||
delete this->left; |
|||
this->left = NULL; |
|||
} |
|||
|
|||
if (this->right) { |
|||
delete this->right; |
|||
this->right = NULL; |
|||
} |
|||
} |
|||
|
|||
bool |
|||
IncrementalMerkleNode::insertElement(const std::vector<bool> &hashV, std::vector<bool> &index) |
|||
{ |
|||
bool result = false; |
|||
|
|||
// Check if we have any free leaves. If not, bail.
|
|||
if (this->subtreeFull == true) { |
|||
return false; |
|||
} |
|||
|
|||
// Are we a leaf? If so, store the hash value.
|
|||
if (this->isLeaf()) { |
|||
// Store the given hash value here and return success.
|
|||
this->value = hashV; |
|||
this->subtreeFull = true; |
|||
return true; |
|||
} |
|||
|
|||
// We're not a leaf. Try to insert into subtrees, creating them if necessary.
|
|||
// Try to recurse on left subtree
|
|||
if (!this->left) { |
|||
this->left = new IncrementalMerkleNode(this->nodeDepth + 1, this->treeHeight); |
|||
} |
|||
result = this->left->insertElement(hashV, index); |
|||
if (result == true) { |
|||
// Update the index value to indicate where the new node went
|
|||
index.at(this->nodeDepth) = false; |
|||
} |
|||
|
|||
// If that failed, try to recurse on right subtree.
|
|||
if (result == false) { |
|||
if (!this->right) { |
|||
this->right = new IncrementalMerkleNode(this->nodeDepth + 1, this->treeHeight); |
|||
} |
|||
result = this->right->insertElement(hashV, index); |
|||
if (result == true) { |
|||
index.at(this->nodeDepth) = true; |
|||
} |
|||
} |
|||
|
|||
// If one of the inserts succeeded, update our 'fullness' status.
|
|||
if (result == true) { |
|||
this->updateHashValue(); |
|||
if (this->isLeaf()) { this->subtreeFull = true; } |
|||
else { |
|||
this->subtreeFull = this->checkIfNodeFull(); |
|||
} |
|||
} |
|||
|
|||
// Return the result
|
|||
return result; |
|||
} |
|||
|
|||
bool |
|||
IncrementalMerkleNode::getWitness(const std::vector<bool> &index, merkle_authentication_path &witness) |
|||
{ |
|||
bool result = false; |
|||
|
|||
// If this node is a leaf: do nothing and return success
|
|||
if (this->isLeaf()) { |
|||
return true; |
|||
} |
|||
|
|||
// If this node is pruned, we can't fetch a witness. Return failure.
|
|||
if (this->isPruned()) { |
|||
return false; |
|||
} |
|||
|
|||
// If the index path leads to the left, we grab the hash value on the
|
|||
// right -- then recurse on the left node.
|
|||
if (index.at(nodeDepth) == false) { |
|||
|
|||
// Make sure there is a value on the right. If not we put the 'null' hash (0) into that element.
|
|||
if (this->right == NULL) { |
|||
witness.at(nodeDepth).resize(CSHA256::OUTPUT_SIZE * 8); |
|||
std::fill (witness.at(nodeDepth).begin(), witness.at(nodeDepth).end(), false); |
|||
} else { |
|||
this->right->getValue(witness.at(nodeDepth)); |
|||
//printVectorAsHex(witness.at(nodeDepth));
|
|||
} |
|||
|
|||
// Recurse on the left node
|
|||
if (this->left) { |
|||
result = this->left->getWitness(index, witness); |
|||
} |
|||
} |
|||
|
|||
// If the index path leads to the right, we grab the hash value on the
|
|||
// left -- then recurse on the right node.
|
|||
if (index.at(nodeDepth) == true) { |
|||
this->left->getValue(witness.at(nodeDepth)); |
|||
|
|||
// Recurse on the right node
|
|||
if (this->right) { |
|||
result = this->right->getWitness(index, witness); |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
bool |
|||
IncrementalMerkleNode::prune() |
|||
{ |
|||
bool result = true; |
|||
|
|||
// If we're already pruned, return.
|
|||
if (this->isPruned() == true) { |
|||
return true; |
|||
} |
|||
|
|||
// Check to see if this node is full. If so, delete the subtrees.
|
|||
if (this->subtreeFull == true) { |
|||
if (this->left) { |
|||
delete this->left; |
|||
this->left = NULL; |
|||
} |
|||
|
|||
if (this->right) { |
|||
delete this->right; |
|||
this->right = NULL; |
|||
} |
|||
|
|||
this->subtreePruned = true; |
|||
} else { |
|||
// Node is not full. Recurse on left and right.
|
|||
if (this->left) { |
|||
result &= this->left->prune(); |
|||
} |
|||
|
|||
if (this->right) { |
|||
result &= this->right->prune(); |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
void |
|||
IncrementalMerkleNode::updateHashValue() |
|||
{ |
|||
// Take no action on leaves or pruned nodes.
|
|||
if (this->isLeaf() || this->isPruned()) { |
|||
return; |
|||
} |
|||
|
|||
// Obtain the hash of the two subtrees and hash the
|
|||
// concatenation of the two.
|
|||
std::vector<bool> hash(CSHA256::OUTPUT_SIZE * 8); |
|||
std::vector<bool> zero(CSHA256::OUTPUT_SIZE * 8); |
|||
std::fill (zero.begin(), zero.end(), false); |
|||
|
|||
// The following code is ugly and should be refactored. It runs
|
|||
// four special cases depending on whether left/right is NULL.
|
|||
// It also ensures that the "hash" of (0 || 0) is 0.
|
|||
if (this->left && !(this->right)) { |
|||
if (VectorIsZero(this->left->getValue())) { |
|||
hash = zero; |
|||
} else { |
|||
hashVectors(this->left->getValue(), zero, hash); |
|||
} |
|||
} else if (!(this->left) && this->right) { |
|||
if (VectorIsZero(this->right->getValue())) { |
|||
hash = zero; |
|||
} else { |
|||
hashVectors(zero, this->left->getValue(), hash); |
|||
} |
|||
} else if (this->left && this->right) { |
|||
if (VectorIsZero(this->left->getValue()) && VectorIsZero(this->right->getValue())) { |
|||
hash = zero; |
|||
} else { |
|||
hashVectors(this->left->getValue(), this->right->getValue(), hash); |
|||
} |
|||
} else { |
|||
hash = zero; |
|||
} |
|||
|
|||
this->value = hash; |
|||
} |
|||
|
|||
bool |
|||
IncrementalMerkleNode::checkIfNodeFull() |
|||
{ |
|||
if (this->isPruned()) { |
|||
return true; |
|||
} |
|||
|
|||
if (this->left == NULL || this->right == NULL) { |
|||
return false; |
|||
} |
|||
|
|||
return (this->left->subtreeFull && this->right->subtreeFull); |
|||
} |
|||
|
|||
void |
|||
IncrementalMerkleNode::getCompactRepresentation(IncrementalMerkleTreeCompact &rep) const |
|||
{ |
|||
// Do nothing at the bottom level
|
|||
if (this->isLeaf()) { |
|||
return; |
|||
} |
|||
|
|||
// There's no content below us. We're done
|
|||
if (!this->left) { |
|||
return; |
|||
} |
|||
|
|||
// If we have no right elements, don't include any hashes. Recurse to the left.
|
|||
if (this->hasRightChildren() == false && this->left->isLeaf() == false && this->left->subtreeFull == false) { |
|||
rep.hashList.at(this->nodeDepth) = false; |
|||
this->left->getCompactRepresentation(rep); |
|||
return; |
|||
} |
|||
|
|||
// Otherwise: Add our left child hash to the tree.
|
|||
rep.hashList.at(this->nodeDepth) = true; |
|||
std::vector<unsigned char> hash(CSHA256::OUTPUT_SIZE, 0); |
|||
convertVectorToBytesVector(this->left->getValue(), hash); |
|||
rep.hashVec.push_back(hash); |
|||
|
|||
// If we have a right child, recurse to the right
|
|||
if (this->hasRightChildren()) { |
|||
this->right->getCompactRepresentation(rep); |
|||
return; |
|||
} |
|||
|
|||
// We get here in one of the following cases:
|
|||
// 1. Our left child is a leaf, and there's no right child.
|
|||
// 2. Our left child is a full tree, and there's no right child.
|
|||
|
|||
// We've gone right for the last time, now we go left until we reach the
|
|||
// bottom.
|
|||
for (uint32_t i = this->nodeDepth + 1; i < this->treeHeight; i++) { |
|||
rep.hashList.at(i) = false; |
|||
} |
|||
} |
|||
|
|||
bool |
|||
IncrementalMerkleNode::fromCompactRepresentation(IncrementalMerkleTreeCompact &rep, uint32_t pos) |
|||
{ |
|||
bool result = false; |
|||
|
|||
// Do nothing at the bottom level
|
|||
if (this->isLeaf()) { |
|||
return true; |
|||
} |
|||
|
|||
// If we have any subtrees (or this tree already has stuff in it), clean it out.
|
|||
if (this->left) { |
|||
// XXX memory leak: left might have the only pointers to its heap
|
|||
// allocated children!
|
|||
delete this->left; |
|||
this->left = NULL; |
|||
} |
|||
if (this->right) { |
|||
// XXX memory leak: right might have the only pointers to its heap
|
|||
// allocated children!
|
|||
delete this->right; |
|||
this->right = NULL; |
|||
} |
|||
this->subtreeFull = this->subtreePruned = false; |
|||
|
|||
// If the hashList[nodeDepth] is true, insert the next hash into the left tree
|
|||
// and mark it full AND pruned. Then recurse to the right.
|
|||
if (rep.hashList.at(this->nodeDepth) == true) { |
|||
// Create a left node
|
|||
this->left = new IncrementalMerkleNode(this->nodeDepth + 1, this->treeHeight); |
|||
|
|||
// Fill the left node with the value and mark it full/pruned
|
|||
std::vector<bool> hash(CSHA256::OUTPUT_SIZE * 8, 0); |
|||
convertBytesVectorToVector(rep.hashVec.at(pos), hash); |
|||
this->left->value = hash; |
|||
this->left->subtreePruned = this->left->subtreeFull = true; |
|||
|
|||
// Create a right node and recurse on it (incrementing pos)
|
|||
this->right = new IncrementalMerkleNode(this->nodeDepth + 1, this->treeHeight); |
|||
result = this->right->fromCompactRepresentation(rep, pos + 1); |
|||
} else if (this->nodeDepth < (this->treeHeight - 1)) { |
|||
// Otherwise --
|
|||
// * If we're about to create a leaf level, do nothing.
|
|||
// * Else create a left node and recurse on it.
|
|||
this->left = new IncrementalMerkleNode(this->nodeDepth + 1, this->treeHeight); |
|||
|
|||
// Otherwise recurse on the left node. Do not increment pos.
|
|||
result = this->left->fromCompactRepresentation(rep, pos); |
|||
} |
|||
|
|||
// Update the hash value of this node
|
|||
this->updateHashValue(); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
IncrementalMerkleNode |
|||
IncrementalMerkleNode::operator=(const IncrementalMerkleNode &rhs) { |
|||
IncrementalMerkleNode dup(rhs); |
|||
return dup; |
|||
} |
|||
|
|||
} /* namespace libzerocash */ |
@ -1,140 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Declaration of interfaces for the classes IncrementalMerkleTreeCompact, |
|||
IncrementalMerkleNode, and IncrementalMerkleTree. |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef INCREMENTALMERKLETREE_H_ |
|||
#define INCREMENTALMERKLETREE_H_ |
|||
|
|||
#include "crypto/sha256.h" |
|||
|
|||
#include "Zerocash.h" |
|||
#include <vector> |
|||
#include <iostream> |
|||
#include <map> |
|||
#include <cstring> |
|||
|
|||
#include "libsnark/common/data_structures/merkle_tree.hpp" |
|||
|
|||
namespace libzerocash { |
|||
|
|||
/******************* Incremental Merkle tree compact *************************/ |
|||
|
|||
/* This is a comapct way to represent an incremental merkle tree, where all full
|
|||
* subtrees are replaced by their hashes. It contains just enough information |
|||
* that you can continue addding elements to the tree. |
|||
* |
|||
* This class can only be constructed by IncrementalMerkleTree, and after that, |
|||
* it is immutable. To act on a compact representation, it must first be |
|||
* de-compactified by loading it into an IncrementalMerkleTree. |
|||
*/ |
|||
class IncrementalMerkleTreeCompact { |
|||
friend class IncrementalMerkleTree; |
|||
friend class IncrementalMerkleNode; |
|||
public: |
|||
uint32_t getHeight() { return this->treeHeight; } |
|||
|
|||
uint32_t getTreeHeight() { return treeHeight; } |
|||
std::vector< std::vector<unsigned char> > const& getHashVec() { return hashVec; } |
|||
std::vector< bool > const& getHashList() { return hashList; } |
|||
|
|||
std::vector<unsigned char> serialize() const; |
|||
static IncrementalMerkleTreeCompact deserialize(const std::vector<unsigned char>& serialized); |
|||
|
|||
private: |
|||
IncrementalMerkleTreeCompact() : treeHeight(0) {} |
|||
uint32_t treeHeight; |
|||
std::vector< std::vector<unsigned char> > hashVec; |
|||
std::vector< bool > hashList; |
|||
}; |
|||
|
|||
/********************* Incremental Merkle tree node **************************/ |
|||
|
|||
class IncrementalMerkleNode { |
|||
public: |
|||
CSHA256 ctx256; |
|||
IncrementalMerkleNode* left; |
|||
IncrementalMerkleNode* right; |
|||
std::vector<bool> value; |
|||
uint32_t nodeDepth; |
|||
uint32_t treeHeight; |
|||
bool subtreeFull; |
|||
bool subtreePruned; |
|||
|
|||
IncrementalMerkleNode(uint32_t depth, uint32_t height); |
|||
IncrementalMerkleNode(const IncrementalMerkleNode& toCopy); |
|||
~IncrementalMerkleNode(); |
|||
|
|||
// Methods
|
|||
bool insertElement(const std::vector<bool> &hashV, std::vector<bool> &index); |
|||
bool getWitness(const std::vector<bool> &index, merkle_authentication_path &witness); |
|||
bool prune(); |
|||
void getCompactRepresentation(IncrementalMerkleTreeCompact &rep) const; |
|||
bool fromCompactRepresentation(IncrementalMerkleTreeCompact &rep, uint32_t pos); |
|||
|
|||
// Utility methods
|
|||
bool isLeaf() const { return (nodeDepth == treeHeight); } |
|||
bool isPruned() const { return subtreePruned; } |
|||
bool hasFreeLeaves() const { return (!subtreeFull); } |
|||
bool hasRightChildren() const { if (!right) return false; return true; } |
|||
void getValue(std::vector<bool> &r) const { r = value; } |
|||
const std::vector<bool>& getValue() const { return value; } |
|||
|
|||
bool checkIfNodeFull(); |
|||
void updateHashValue(); |
|||
|
|||
IncrementalMerkleNode operator=(const IncrementalMerkleNode &rhs); |
|||
}; |
|||
|
|||
/************************ Incremental Merkle tree ****************************/ |
|||
|
|||
class IncrementalMerkleTree { |
|||
protected: |
|||
|
|||
IncrementalMerkleNode root; |
|||
uint32_t treeHeight; |
|||
|
|||
public: |
|||
IncrementalMerkleTree(uint32_t height = ZEROCASH_DEFAULT_TREE_SIZE); |
|||
IncrementalMerkleTree(std::vector< std::vector<bool> > &valueVector, uint32_t height); |
|||
IncrementalMerkleTree(IncrementalMerkleTreeCompact &compact); |
|||
|
|||
void setTo(const IncrementalMerkleTree &other) { |
|||
auto compact = other.getCompactRepresentation(); |
|||
fromCompactRepresentation(compact); |
|||
} |
|||
|
|||
bool insertElement(const std::vector<bool> &hashV, std::vector<bool> &index); |
|||
bool insertElement(const std::vector<unsigned char> &hashV, std::vector<unsigned char> &index); |
|||
bool insertVector(std::vector< std::vector<bool> > &valueVector); |
|||
bool getWitness(const std::vector<bool> &index, merkle_authentication_path &witness); |
|||
bool getRootValue(std::vector<bool>& r) const; |
|||
bool getRootValue(std::vector<unsigned char>& r) const; |
|||
std::vector<unsigned char>getRoot(); |
|||
bool prune(); |
|||
IncrementalMerkleTreeCompact getCompactRepresentation() const; |
|||
std::vector<unsigned char> serialize() const { |
|||
auto compact = getCompactRepresentation(); |
|||
return compact.serialize(); |
|||
} |
|||
|
|||
static IncrementalMerkleTree deserialize(const std::vector<unsigned char>& serialized) { |
|||
auto deserialized = IncrementalMerkleTreeCompact::deserialize(serialized); |
|||
return IncrementalMerkleTree(deserialized); |
|||
} |
|||
|
|||
bool fromCompactRepresentation(IncrementalMerkleTreeCompact &rep); |
|||
|
|||
}; |
|||
|
|||
} /* namespace libzerocash */ |
|||
|
|||
#endif /* INCREMENTALMERKLETREE_H_ */ |
|||
|
@ -1,161 +0,0 @@ |
|||
OPTFLAGS = -march=native -mtune=native -O2 |
|||
CXXFLAGS += -g -Wall -Wextra -Wno-unused-parameter -std=c++11 -fPIC -Wno-unused-variable |
|||
LDFLAGS += -flto |
|||
|
|||
DEPSRC=depsrc |
|||
DEPINST=depinst |
|||
|
|||
LIBZEROCASH=libzerocash |
|||
UTILS=$(LIBZEROCASH)/utils |
|||
TESTUTILS=tests |
|||
LDLIBS += -L $(DEPINST)/lib -Wl,-rpath $(DEPINST)/lib -L . -lsnark -lgmpxx -lgmp |
|||
|
|||
ifeq ($(USE_MT),1) |
|||
LDLIBS += -lboost_system-mt |
|||
LDLIBS += -lboost_unit_test_framework-mt |
|||
else |
|||
LDLIBS += -lboost_system |
|||
LDLIBS += -lboost_unit_test_framework |
|||
endif |
|||
|
|||
LDLIBS += -lcrypto -lcryptopp -lz -ldl |
|||
|
|||
ifeq ($(LINK_RT),1) |
|||
LDLIBS += -lrt |
|||
endif |
|||
|
|||
|
|||
CXXFLAGS += -I $(DEPINST)/include -I $(DEPINST)/include/libsnark -I . -DUSE_ASM -DCURVE_ALT_BN128 |
|||
|
|||
LIBPATH = /usr/local/lib |
|||
|
|||
SRCS= \
|
|||
$(UTILS)/sha256.cpp \
|
|||
$(UTILS)/util.cpp \
|
|||
$(LIBZEROCASH)/IncrementalMerkleTree.cpp \
|
|||
$(LIBZEROCASH)/Address.cpp \
|
|||
$(LIBZEROCASH)/CoinCommitment.cpp \
|
|||
$(LIBZEROCASH)/Coin.cpp \
|
|||
$(LIBZEROCASH)/MintTransaction.cpp \
|
|||
$(LIBZEROCASH)/PourInput.cpp \
|
|||
$(LIBZEROCASH)/PourOutput.cpp \
|
|||
$(LIBZEROCASH)/PourProver.cpp \
|
|||
$(LIBZEROCASH)/PourTransaction.cpp \
|
|||
$(LIBZEROCASH)/ZerocashParams.cpp \
|
|||
$(TESTUTILS)/timer.cpp |
|||
|
|||
EXECUTABLES= \
|
|||
zerocash_pour_ppzksnark/tests/test_zerocash_pour_ppzksnark \
|
|||
zerocash_pour_ppzksnark/profiling/profile_zerocash_pour_gadget \
|
|||
tests/zerocashTest \
|
|||
tests/utilTest \
|
|||
tests/merkleTest \
|
|||
libzerocash/GenerateParamsForFiles |
|||
|
|||
OBJS=$(patsubst %.cpp,%.o,$(SRCS)) |
|||
|
|||
ifeq ($(MINDEPS),1) |
|||
CXXFLAGS += -DMINDEPS |
|||
else |
|||
LDLIBS += -lboost_program_options |
|||
LDLIBS += -lprocps |
|||
endif |
|||
|
|||
ifeq ($(LOWMEM),1) |
|||
CXXFLAGS += -DLOWMEM |
|||
endif |
|||
|
|||
ifeq ($(STATIC),1) |
|||
CXXFLAGS += -static -DSTATIC |
|||
endif |
|||
|
|||
ifeq ($(PROFILE_CURVE),1) |
|||
CXXFLAGS += -static -DPROFILE_CURVE |
|||
endif |
|||
|
|||
ifeq ($(MULTICORE),1) |
|||
# When running ./get-libsnark to prepare for this build, use: |
|||
# $ LIBSNARK_FLAGS='MULTICORE=1 STATIC=1' ./get-libsnark. |
|||
# If you're missing some static libraries, it may help to also add |
|||
# $ NO_PROCPS=1 ... ./get-libsnark |
|||
# and pass MINDEPS=1 to this makefile |
|||
# and run ./get-cryptopp to build the static cryptopp library. |
|||
CXXFLAGS += -static -fopenmp -DMULTICORE |
|||
endif |
|||
|
|||
all: $(EXECUTABLES) libzerocash.a |
|||
|
|||
cppdebug: CXXFLAGS += -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC |
|||
cppdebug: debug |
|||
|
|||
debug: CXXFLAGS += -DDEBUG -g -ggdb3 |
|||
debug: all |
|||
|
|||
noasserts: CXXFLAGS += -DNDEBUG -Wno-unused-variable -Wno-unused-but-set-variable |
|||
noasserts: all |
|||
|
|||
# In order to detect changes to #include dependencies. -MMD below generates a .d file for .cpp file. Include the .d file.
|
|||
-include $(SRCS:.cpp=.d) |
|||
|
|||
$(OBJS) ${patsubst %,%.o,${EXECUTABLES}}: %.o: %.cpp |
|||
$(CXX) -o $@ $< -c -MMD $(CXXFLAGS) |
|||
|
|||
$(EXECUTABLES): %: %.o $(OBJS) |
|||
$(CXX) -o $@ $^ $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) |
|||
|
|||
libzerocash: $(OBJS) $(USER_OBJS) |
|||
@echo 'Building target: $@' |
|||
@echo 'Invoking: Cross G++ Linker' |
|||
$(CXX) -shared -o "libzerocash.so" $(OBJS) $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) |
|||
@echo 'Finished building target: $@' |
|||
@echo 'Copying libzerocash.so' |
|||
sudo cp libzerocash.so $(LIBPATH)/libzerocash.so |
|||
sudo ldconfig |
|||
@echo 'Finished copying libzerocash.so' |
|||
@echo ' ' |
|||
|
|||
libzerocash.a: $(OBJS) $(USER_OBJS) |
|||
@echo 'Building target: $@' |
|||
@echo 'Invoking: Cross G++ Linker' |
|||
$(AR) rcvs $@ $(OBJS) |
|||
@echo 'Finished building target: $@' |
|||
#@echo 'Copying libzerocash.a' |
|||
#sudo cp libzerocash.a $(LIBPATH)/libzerocash.a |
|||
#sudo ldconfig |
|||
#@echo 'Finished copying libzerocash.a' |
|||
@echo ' ' |
|||
|
|||
test_library: %: tests/zerocashTest.o $(OBJS) |
|||
$(CXX) -o tests/$@ $^ $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) -lzerocash |
|||
|
|||
banktest_library: %: bankTest.o $(OBJS) |
|||
$(CXX) -o $@ $^ $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) -lzerocash |
|||
|
|||
merkletest_library: %: merkleTest.o $(OBJS) |
|||
$(CXX) -o $@ $^ $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) -lzerocash |
|||
|
|||
.PHONY: clean install |
|||
|
|||
clean: |
|||
$(RM) \
|
|||
$(OBJS) \
|
|||
$(EXECUTABLES) \
|
|||
${patsubst %,%.o,${EXECUTABLES}} \
|
|||
${patsubst %,%.d,${EXECUTABLES}} \
|
|||
${patsubst %.cpp,%.d,${SRCS}} \
|
|||
libzerocash.a \
|
|||
tests/test_library |
|||
|
|||
|
|||
HEADERS_SRC=$(shell find . -name '*.hpp' -o -name '*.tcc' -o -name '*.h') |
|||
HEADERS_DEST=$(patsubst %,$(PREFIX)/include/libzerocash/%,$(HEADERS_SRC)) |
|||
|
|||
$(HEADERS_DEST): $(PREFIX)/include/libzerocash/%: % |
|||
mkdir -p $(shell dirname $@) |
|||
cp $< $@ |
|||
|
|||
install: all $(HEADERS_DEST) |
|||
mkdir -p $(PREFIX)/lib |
|||
install -m 0755 libzerocash.a $(PREFIX)/lib/ |
|||
mkdir -p $(PREFIX)/bin |
|||
install -m 0755 -t $(PREFIX)/bin/ $(EXECUTABLES) |
@ -1,75 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Implementation of interfaces for the class MintTransaction. |
|||
|
|||
See MintTransaction.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 "MintTransaction.h" |
|||
|
|||
namespace libzerocash { |
|||
|
|||
MintTransaction::MintTransaction(): coinValue(0), internalCommitment(), externalCommitment() |
|||
{ } |
|||
|
|||
/**
|
|||
* Creates a transaction minting the coin c. |
|||
* |
|||
* @param c the coin to mint. |
|||
*/ |
|||
MintTransaction::MintTransaction(const Coin& c): coinValue(ZC_V_SIZE) |
|||
{ |
|||
convertIntToBytesVector(c.getValue(), this->coinValue); |
|||
|
|||
internalCommitment = c.getInternalCommitment(); |
|||
externalCommitment = c.getCoinCommitment(); |
|||
} |
|||
|
|||
/**
|
|||
* Verify the correctness of a Mint transaction. |
|||
* |
|||
* @return true if correct, false otherwise. |
|||
*/ |
|||
bool MintTransaction::verify() const{ |
|||
|
|||
// Check that the internal commitment is the right size
|
|||
if (this->internalCommitment.size() != ZC_K_SIZE) { |
|||
return false; |
|||
} |
|||
|
|||
// The external commitment should formulated as:
|
|||
// H( internalCommitment || 0^192 || coinValue)
|
|||
//
|
|||
// To check the structure of our proof we simply reconstruct
|
|||
// a version of the external commitment and check that it's
|
|||
// equal to the value we store.
|
|||
//
|
|||
// We use the constructor for CoinCommitment to do this.
|
|||
|
|||
try { |
|||
CoinCommitment comp(this->coinValue, this->internalCommitment); |
|||
|
|||
return (comp == this->externalCommitment); |
|||
} catch (std::runtime_error) { |
|||
return false; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
const CoinCommitmentValue& MintTransaction::getMintedCoinCommitmentValue() const{ |
|||
return this->externalCommitment.getCommitmentValue(); |
|||
} |
|||
|
|||
uint64_t MintTransaction::getMonetaryValue() const { |
|||
return convertBytesVectorToInt(this->coinValue); |
|||
} |
|||
|
|||
} /* namespace libzerocash */ |
@ -1,69 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Declaration of interfaces for the class MintTransaction. |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef MINTTRANSACTION_H_ |
|||
#define MINTTRANSACTION_H_ |
|||
|
|||
#include "CoinCommitment.h" |
|||
#include "Coin.h" |
|||
|
|||
typedef std::vector<unsigned char> CoinCommitmentValue; |
|||
|
|||
namespace libzerocash{ |
|||
|
|||
/***************************** Mint transaction ******************************/ |
|||
|
|||
class MintTransaction { |
|||
public: |
|||
MintTransaction(); |
|||
|
|||
/**
|
|||
* Creates a transaction minting the provided coin. |
|||
* |
|||
* @param c the coin to mint. |
|||
*/ |
|||
MintTransaction(const Coin& c); |
|||
|
|||
/**
|
|||
* Verifies the MintTransaction. |
|||
* In particular, this checks that output coin commitment |
|||
* actually is to a coin of the claimed value. |
|||
* |
|||
* @return true if valid, false otherwise. |
|||
*/ |
|||
bool verify() const; |
|||
|
|||
/**
|
|||
*Gets the commitment to the coin that was minted by this transaction. |
|||
* |
|||
* @return the commitment |
|||
*/ |
|||
const CoinCommitmentValue& getMintedCoinCommitmentValue() const; |
|||
|
|||
/**
|
|||
* Gets the monetary value of the minted coin. |
|||
* |
|||
* @return the value |
|||
*/ |
|||
uint64_t getMonetaryValue() const; |
|||
|
|||
|
|||
private: |
|||
std::vector<unsigned char> coinValue; // coin value
|
|||
std::vector<unsigned char> internalCommitment; // "k" in paper notation
|
|||
CoinCommitment externalCommitment; // "cm" in paper notation
|
|||
|
|||
const CoinCommitment& getCoinCommitment() const { return this->externalCommitment; } |
|||
}; |
|||
|
|||
} /* namespace libzerocash */ |
|||
|
|||
#endif /* MINTTRANSACTION_H_ */ |
@ -1,39 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Implementation of interfaces for the class PourInput. |
|||
|
|||
See PourInput.h . |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#include "PourInput.h" |
|||
|
|||
namespace libzerocash { |
|||
|
|||
PourInput::PourInput(int tree_depth): old_coin(), merkle_index(), path() { |
|||
this->old_address = Address::CreateNewRandomAddress(); |
|||
|
|||
this->old_coin = Coin(this->old_address.getPublicAddress(), 0); |
|||
|
|||
ZCIncrementalMerkleTree merkleTree; |
|||
merkleTree.append(uint256(this->old_coin.getCoinCommitment().getCommitmentValue())); |
|||
|
|||
auto witness = merkleTree.witness(); |
|||
auto merkle_path = witness.path(); |
|||
|
|||
this->path = merkle_path.authentication_path; |
|||
this->merkle_index = convertVectorToInt(merkle_path.index); |
|||
} |
|||
|
|||
PourInput::PourInput(Coin old_coin, |
|||
Address old_address, |
|||
const libzcash::MerklePath &path) : old_address(old_address), old_coin(old_coin), path(path.authentication_path) { |
|||
this->merkle_index = convertVectorToInt(path.index); |
|||
}; |
|||
|
|||
} /* namespace libzerocash */ |
@ -1,38 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Declaration of interfaces for the class PourInput. |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef POURINPUT_H_ |
|||
#define POURINPUT_H_ |
|||
|
|||
#include "Coin.h" |
|||
#include "ZerocashParams.h" |
|||
|
|||
#include "zcash/IncrementalMerkleTree.hpp" |
|||
|
|||
namespace libzerocash { |
|||
|
|||
class PourInput { |
|||
public: |
|||
PourInput(int tree_depth); |
|||
|
|||
PourInput(Coin old_coin, |
|||
Address old_address, |
|||
const libzcash::MerklePath& path); |
|||
|
|||
Coin old_coin; |
|||
Address old_address; |
|||
size_t merkle_index; |
|||
merkle_authentication_path path; |
|||
}; |
|||
|
|||
} /* namespace libzerocash */ |
|||
|
|||
#endif /* POURINPUT_H_ */ |
@ -1,29 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Implementation of interfaces for the class PourOutput. |
|||
|
|||
See PourOutput.h . |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#include "PourOutput.h" |
|||
|
|||
namespace libzerocash { |
|||
|
|||
PourOutput::PourOutput(uint64_t val) { |
|||
Address dummy_to_address = Address::CreateNewRandomAddress(); |
|||
|
|||
this->to_address = dummy_to_address.getPublicAddress(); |
|||
this->new_coin = Coin(dummy_to_address.getPublicAddress(), val); |
|||
} |
|||
|
|||
PourOutput::PourOutput(const Coin new_coin, |
|||
const PublicAddress to_address) : new_coin(new_coin), to_address(to_address) { |
|||
} |
|||
|
|||
} /* namespace libzerocash */ |
@ -1,32 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Declaration of interfaces for the class PourOutput. |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef POUROUTPUT_H_ |
|||
#define POUROUTPUT_H_ |
|||
|
|||
#include "Coin.h" |
|||
#include "ZerocashParams.h" |
|||
|
|||
namespace libzerocash { |
|||
|
|||
class PourOutput { |
|||
public: |
|||
PourOutput(uint64_t val); |
|||
PourOutput(const Coin new_coin, |
|||
const PublicAddress to_address); |
|||
|
|||
Coin new_coin; |
|||
PublicAddress to_address; |
|||
}; |
|||
|
|||
} /* namespace libzerocash */ |
|||
|
|||
#endif /* POUROUTPUT_H_ */ |
@ -1,12 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Implementation of interfaces for the class PourProver. |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#include "PourProver.h" |
@ -1,65 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Declaration of interfaces for the class PourProver. |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef POURPROVER_H_ |
|||
#define POURPROVER_H_ |
|||
|
|||
#include "ZerocashParams.h" |
|||
#include "boost/array.hpp" |
|||
#include "PourTransaction.h" |
|||
#include "CoinCommitment.h" |
|||
|
|||
namespace libzerocash { |
|||
|
|||
class PourProver { |
|||
public: |
|||
static bool VerifyProof( |
|||
ZerocashParams& params, |
|||
const std::vector<unsigned char>& pubkeyHash, |
|||
const std::vector<unsigned char>& rt, |
|||
const uint64_t vpub_old, |
|||
const uint64_t vpub_new, |
|||
const boost::array<std::vector<unsigned char>, 2> serials, |
|||
const boost::array<std::vector<unsigned char>, 2> commitments, |
|||
const boost::array<std::vector<unsigned char>, 2> macs, |
|||
const std::string &zkSNARK |
|||
) { |
|||
PourTransaction pourtx; |
|||
|
|||
pourtx.version = 1; |
|||
pourtx.publicOldValue.resize(8); |
|||
pourtx.publicNewValue.resize(8); |
|||
convertIntToBytesVector(vpub_old, pourtx.publicOldValue); |
|||
convertIntToBytesVector(vpub_new, pourtx.publicNewValue); |
|||
pourtx.serialNumber_1 = serials[0]; |
|||
pourtx.serialNumber_2 = serials[1]; |
|||
{ |
|||
CoinCommitment cm; |
|||
cm.commitmentValue = commitments[0]; |
|||
pourtx.cm_1 = cm; |
|||
} |
|||
{ |
|||
CoinCommitment cm; |
|||
cm.commitmentValue = commitments[1]; |
|||
pourtx.cm_2 = cm; |
|||
} |
|||
pourtx.MAC_1 = macs[0]; |
|||
pourtx.MAC_2 = macs[1]; |
|||
pourtx.zkSNARK = zkSNARK; |
|||
|
|||
return pourtx.verify(params, pubkeyHash, rt); |
|||
} |
|||
}; |
|||
|
|||
|
|||
} |
|||
|
|||
#endif /* POURPROVER_H_ */ |
@ -1,445 +0,0 @@ |
|||
/** @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 */ |
@ -1,204 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Declaration of interfaces for the class PourTransaction. |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef POURTRANSACTION_H_ |
|||
#define POURTRANSACTION_H_ |
|||
|
|||
#include "Coin.h" |
|||
#include "ZerocashParams.h" |
|||
#include "Zerocash.h" |
|||
#include "PourInput.h" |
|||
#include "PourOutput.h" |
|||
#include <stdexcept> |
|||
#include <bitset> |
|||
|
|||
#include <boost/array.hpp> |
|||
|
|||
#include "uint256.h" |
|||
#include "zcash/NoteEncryption.hpp" |
|||
|
|||
typedef std::vector<unsigned char> CoinCommitmentValue; |
|||
|
|||
namespace libzerocash { |
|||
|
|||
/***************************** Pour transaction ******************************/ |
|||
|
|||
class PourTransaction { |
|||
friend class PourProver; |
|||
public: |
|||
PourTransaction(); |
|||
PourTransaction(ZerocashParams& params, |
|||
const std::vector<unsigned char>& pubkeyHash, |
|||
const MerkleRootType& rt, |
|||
const std::vector<PourInput> inputs, |
|||
const std::vector<PourOutput> outputs, |
|||
uint64_t vpub_old, |
|||
uint64_t vpub_new |
|||
); |
|||
/**
|
|||
* Generates a transaction pouring the funds in two existing coins into two new coins and optionally |
|||
* converting some of those funds back into the base currency. |
|||
* |
|||
* |
|||
* @param version_num the version of the transaction to create |
|||
* @param params the cryptographic parameters used to generate the proofs. |
|||
* @param root the root of the merkle tree containing the two existing coins |
|||
* @param c_1_old the first existing coin |
|||
* @param c_2_old the second existing coin |
|||
* @param addr_1_old the address the first coin was paid to |
|||
* @param addr_2_old the address the second coin was paid to |
|||
* @param path_1 path showing that first coin is in the merkle tree rooted at root |
|||
* @param path_2 path showing that the second coin is n the merkle tree rooted at root |
|||
* @param addr_1_new the public address to pay the first new coin to |
|||
* @param addr_2_new the public address to pay the second new coin to |
|||
* @param v_pub the amount of funds to convert back to the base currency |
|||
* @param pubkeyHash the hash of a public key to bind into the transaction |
|||
* @param c_1_new the first of the new coins the funds are being poured into |
|||
* @param c_2_new the second of the new coins the funds are being poured into |
|||
*/ |
|||
PourTransaction(uint16_t version_num, |
|||
ZerocashParams& params, |
|||
const MerkleRootType& roott, |
|||
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& path_1, |
|||
const merkle_authentication_path& path_2, |
|||
const PublicAddress& addr_1_new, |
|||
const PublicAddress& addr_2_new, |
|||
uint64_t v_pub_in, |
|||
uint64_t v_pub_out, |
|||
const std::vector<unsigned char>& pubkeyHash, |
|||
const Coin& c_1_new, |
|||
const Coin& c_2_new); |
|||
|
|||
void init(uint16_t version_num, |
|||
ZerocashParams& params, |
|||
const MerkleRootType& roott, |
|||
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& path_1, |
|||
const merkle_authentication_path& path_2, |
|||
const PublicAddress& addr_1_new, |
|||
const PublicAddress& addr_2_new, |
|||
uint64_t v_pub_in, |
|||
uint64_t v_pub_out, |
|||
const std::vector<unsigned char>& pubkeyHash, |
|||
const Coin& c_1_new, |
|||
const Coin& c_2_new); |
|||
|
|||
/**
|
|||
* Verifies the pour transaction. |
|||
* |
|||
* @param params the cryptographic parameters used to verify the proofs. |
|||
* @param pubkeyHash the hash of a public key that we verify is bound to the transaction |
|||
* @param merkleRoot the root of the merkle tree the coins were in. |
|||
* @return ture if correct, false otherwise. |
|||
*/ |
|||
bool verify(ZerocashParams& params, |
|||
const std::vector<unsigned char> &pubkeyHash, |
|||
const MerkleRootType &merkleRoot) const; |
|||
|
|||
const std::vector<unsigned char>& getSpentSerial1() const; |
|||
const std::vector<unsigned char>& getSpentSerial2() const; |
|||
const ZCNoteEncryption::Ciphertext& getCiphertext1() const; |
|||
const ZCNoteEncryption::Ciphertext& getCiphertext2() const; |
|||
|
|||
/**
|
|||
* Returns the hash of the first new coin generated by this Pour. |
|||
* |
|||
* @return the coin hash |
|||
*/ |
|||
const CoinCommitmentValue& getNewCoinCommitmentValue1() const; |
|||
|
|||
/**
|
|||
* Returns the hash of the second new coin generated by this Pour. |
|||
* |
|||
* @return the coin hash |
|||
*/ |
|||
const CoinCommitmentValue& getNewCoinCommitmentValue2() const; |
|||
|
|||
uint64_t getPublicValueIn() const; |
|||
|
|||
uint64_t getPublicValueOut() const; |
|||
|
|||
std::string unpack(boost::array<std::vector<unsigned char>, 2>& serials, |
|||
boost::array<std::vector<unsigned char>, 2>& commitments, |
|||
boost::array<std::vector<unsigned char>, 2>& macs, |
|||
boost::array<ZCNoteEncryption::Ciphertext, 2>& ciphertexts, |
|||
uint256& epk |
|||
) const { |
|||
serials[0] = this->serialNumber_1; |
|||
serials[1] = this->serialNumber_2; |
|||
commitments[0] = this->cm_1.getCommitmentValue(); |
|||
commitments[1] = this->cm_2.getCommitmentValue(); |
|||
macs[0] = this->MAC_1; |
|||
macs[1] = this->MAC_2; |
|||
ciphertexts[0] = this->ciphertext_1; |
|||
ciphertexts[1] = this->ciphertext_2; |
|||
epk = this->ephemeralKey; |
|||
|
|||
return this->zkSNARK; |
|||
} |
|||
|
|||
// just hashes a few fields to see if integrity is correct.
|
|||
// useful for debugging since there's such bad error handling
|
|||
// currently
|
|||
void debug_print() { |
|||
#define DEBUG_PRINT_POUR_FIELD(X, NAME) {\ |
|||
std::hash<std::string> h; \ |
|||
std::cout << NAME << ": " << h(std::string(X.begin(), X.end())) << std::endl;\ |
|||
} |
|||
|
|||
DEBUG_PRINT_POUR_FIELD(publicOldValue, "publicOldValue"); |
|||
DEBUG_PRINT_POUR_FIELD(publicNewValue, "publicNewValue"); |
|||
DEBUG_PRINT_POUR_FIELD(serialNumber_1, "serialNumber_1"); |
|||
DEBUG_PRINT_POUR_FIELD(serialNumber_2, "serialNumber_2"); |
|||
{ |
|||
auto v = cm_1.getCommitmentValue(); |
|||
DEBUG_PRINT_POUR_FIELD(v, "cm_1"); |
|||
} |
|||
{ |
|||
auto v = cm_2.getCommitmentValue(); |
|||
DEBUG_PRINT_POUR_FIELD(v, "cm_2"); |
|||
} |
|||
DEBUG_PRINT_POUR_FIELD(MAC_1, "MAC_1"); |
|||
DEBUG_PRINT_POUR_FIELD(MAC_2, "MAC_2"); |
|||
|
|||
} |
|||
|
|||
private: |
|||
|
|||
std::vector<unsigned char> publicOldValue; // public input value of the Pour transaction
|
|||
std::vector<unsigned char> publicNewValue; // public output value of the Pour transaction
|
|||
std::vector<unsigned char> serialNumber_1; // serial number of input (old) coin #1
|
|||
std::vector<unsigned char> serialNumber_2; // serial number of input (old) coin #1
|
|||
CoinCommitment cm_1; // coin commitment for output coin #1
|
|||
CoinCommitment cm_2; // coin commitment for output coin #2
|
|||
std::vector<unsigned char> MAC_1; // first MAC (h_1 in paper notation)
|
|||
std::vector<unsigned char> MAC_2; // second MAC (h_2 in paper notation)
|
|||
ZCNoteEncryption::Ciphertext ciphertext_1; // ciphertext #1
|
|||
ZCNoteEncryption::Ciphertext ciphertext_2; // ciphertext #2
|
|||
uint256 ephemeralKey; // epk
|
|||
std::string zkSNARK; // contents of the zkSNARK proof itself
|
|||
uint16_t version; // version for the Pour transaction
|
|||
}; |
|||
|
|||
} /* namespace libzerocash */ |
|||
|
|||
#endif /* POURTRANSACTION_H_ */ |
@ -1,65 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Declaration of exceptions and constants for Zerocash. |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef ZEROCASH_H_ |
|||
#define ZEROCASH_H_ |
|||
|
|||
#include <stdexcept> |
|||
#include <vector> |
|||
|
|||
/* The version of this library. */ |
|||
#define ZEROCASH_VERSION_STRING "0.1" |
|||
#define ZEROCASH_VERSION_INT 1 |
|||
#define ZEROCASH_PROTOCOL_VERSION "1" |
|||
#define ZEROCASH_DEFAULT_TREE_SIZE 64 |
|||
|
|||
#define ZC_A_PK_SIZE 32 |
|||
#define ZC_PK_ENC_SIZE 311 |
|||
#define ZC_SIG_PK_SIZE 32 |
|||
#define ZC_ADDR_PK_SIZE (ZC_A_PK_SIZE+ZC_PK_ENC_SIZE) |
|||
|
|||
#define ZC_A_SK_SIZE 32 |
|||
#define ZC_SK_ENC_SIZE 287 |
|||
#define ZC_ADDR_SK_SIZE (ZC_A_SK_SIZE+ZC_SK_ENC_SIZE) |
|||
|
|||
#define ZC_V_SIZE 8 |
|||
#define ZC_RHO_SIZE 32 |
|||
#define ZC_R_SIZE 48 |
|||
#define ZC_MEMO_SIZE 128 |
|||
#define ZC_S_SIZE 0 |
|||
#define ZC_K_SIZE 32 |
|||
#define ZC_CM_SIZE 32 |
|||
#define ZC_COIN_SIZE (ZC_ADDR_PK_SIZE+ZC_V_SIZE+ZC_RHO_SIZE+ZC_R_SIZE+ZC_S_SIZE+ZC_CM_SIZE) |
|||
#define ZC_TX_MINT_SIZE (ZC_CM_SIZE+ZC_V_SIZE+ZC_K_SIZE+ZC_S_SIZE) |
|||
|
|||
#define ZC_ROOT_SIZE 32 |
|||
#define ZC_SN_SIZE 32 |
|||
#define ZC_PK_SIG_SIZE 66 |
|||
#define ZC_H_SIZE 32 |
|||
#define ZC_POUR_PROOF_SIZE 288 |
|||
#define ZC_C_SIZE 173 |
|||
#define ZC_SIGMA_SIZE 72 |
|||
#define ZC_TX_POUR_SIZE (ZC_ROOT_SIZE+(2*ZC_SN_SIZE)+(2*ZC_CM_SIZE)+ZC_V_SIZE+ZC_PK_SIG_SIZE+(2*ZC_H_SIZE)+ZC_POUR_PROOF_SIZE+(2*ZC_C_SIZE)+ZC_SIGMA_SIZE) |
|||
|
|||
#define SNARK |
|||
|
|||
typedef std::vector<unsigned char> MerkleRootType; |
|||
|
|||
namespace libsnark { |
|||
}; |
|||
|
|||
namespace libzerocash { |
|||
using namespace libsnark; |
|||
}; |
|||
|
|||
#include "zerocash/utils/util.h" |
|||
|
|||
#endif /* ZEROCASH_H_ */ |
@ -1,191 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Implementation of interfaces for the class ZerocashParams. |
|||
|
|||
See ZerocashParams.h . |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#include <fstream> |
|||
#include <boost/format.hpp> |
|||
|
|||
#include "Zerocash.h" |
|||
#include "ZerocashParams.h" |
|||
|
|||
static void throw_missing_param_file_exception(std::string paramtype, std::string path) { |
|||
/* paramtype should be either "proving" or "verifying". */ |
|||
const char* tmpl = ("Could not open %s key file: %s\n" |
|||
"Please refer to user documentation for installing this file."); |
|||
throw std::runtime_error((boost::format(tmpl) % paramtype % path).str()); |
|||
} |
|||
|
|||
namespace libzerocash { |
|||
|
|||
int ZerocashParams::getTreeDepth() |
|||
{ |
|||
return treeDepth; |
|||
} |
|||
|
|||
zerocash_pour_keypair<ZerocashParams::zerocash_pp> ZerocashParams::GenerateNewKeyPair(const unsigned int tree_depth) |
|||
{ |
|||
libzerocash::ZerocashParams::zerocash_pp::init_public_params(); |
|||
libzerocash::zerocash_pour_keypair<libzerocash::ZerocashParams::zerocash_pp> kp_v1 = |
|||
libzerocash::zerocash_pour_ppzksnark_generator<libzerocash::ZerocashParams::zerocash_pp>( |
|||
libzerocash::ZerocashParams::numPourInputs, |
|||
libzerocash::ZerocashParams::numPourOutputs, |
|||
tree_depth |
|||
); |
|||
return kp_v1; |
|||
} |
|||
|
|||
void ZerocashParams::SaveProvingKeyToFile(const zerocash_pour_proving_key<ZerocashParams::zerocash_pp>* p_pk_1, std::string path) |
|||
{ |
|||
std::stringstream ssProving; |
|||
ssProving << p_pk_1->r1cs_pk; |
|||
std::ofstream pkFilePtr; |
|||
pkFilePtr.open(path, std::ios::binary); |
|||
ssProving.rdbuf()->pubseekpos(0, std::ios_base::out); |
|||
pkFilePtr << ssProving.rdbuf(); |
|||
pkFilePtr.flush(); |
|||
pkFilePtr.close(); |
|||
} |
|||
|
|||
|
|||
void ZerocashParams::SaveVerificationKeyToFile(const zerocash_pour_verification_key<ZerocashParams::zerocash_pp>* p_vk_1, std::string path) |
|||
{ |
|||
std::stringstream ssVerification; |
|||
ssVerification << p_vk_1->r1cs_vk; |
|||
std::ofstream vkFilePtr; |
|||
vkFilePtr.open(path, std::ios::binary); |
|||
ssVerification.rdbuf()->pubseekpos(0, std::ios_base::out); |
|||
vkFilePtr << ssVerification.rdbuf(); |
|||
vkFilePtr.flush(); |
|||
vkFilePtr.close(); |
|||
} |
|||
|
|||
zerocash_pour_proving_key<ZerocashParams::zerocash_pp> ZerocashParams::LoadProvingKeyFromFile(std::string path, const unsigned int tree_depth) |
|||
{ |
|||
std::stringstream ssProving; |
|||
std::ifstream fileProving(path, std::ios::binary); |
|||
|
|||
if(!fileProving.is_open()) { |
|||
throw_missing_param_file_exception("proving", path); |
|||
} |
|||
|
|||
ssProving << fileProving.rdbuf(); |
|||
fileProving.close(); |
|||
|
|||
ssProving.rdbuf()->pubseekpos(0, std::ios_base::in); |
|||
|
|||
r1cs_ppzksnark_proving_key<ZerocashParams::zerocash_pp> pk_temp; |
|||
ssProving >> pk_temp; |
|||
|
|||
return zerocash_pour_proving_key<ZerocashParams::zerocash_pp>( |
|||
libzerocash::ZerocashParams::numPourInputs, |
|||
libzerocash::ZerocashParams::numPourOutputs, |
|||
tree_depth, |
|||
std::move(pk_temp) |
|||
); |
|||
} |
|||
|
|||
zerocash_pour_verification_key<ZerocashParams::zerocash_pp> ZerocashParams::LoadVerificationKeyFromFile(std::string path, const unsigned int tree_depth) |
|||
{ |
|||
std::stringstream ssVerification; |
|||
std::ifstream fileVerification(path, std::ios::binary); |
|||
|
|||
if(!fileVerification.is_open()) { |
|||
throw_missing_param_file_exception("verification", path); |
|||
} |
|||
|
|||
ssVerification << fileVerification.rdbuf(); |
|||
fileVerification.close(); |
|||
|
|||
ssVerification.rdbuf()->pubseekpos(0, std::ios_base::in); |
|||
|
|||
r1cs_ppzksnark_verification_key<ZerocashParams::zerocash_pp> vk_temp; |
|||
ssVerification >> vk_temp; |
|||
|
|||
return zerocash_pour_verification_key<ZerocashParams::zerocash_pp>( |
|||
libzerocash::ZerocashParams::numPourInputs, |
|||
libzerocash::ZerocashParams::numPourOutputs, |
|||
std::move(vk_temp) |
|||
); |
|||
} |
|||
|
|||
ZerocashParams::ZerocashParams( |
|||
const unsigned int tree_depth, |
|||
zerocash_pour_keypair<ZerocashParams::zerocash_pp> *keypair |
|||
) : |
|||
treeDepth(tree_depth) |
|||
{ |
|||
params_pk_v1 = new zerocash_pour_proving_key<ZerocashParams::zerocash_pp>(keypair->pk); |
|||
params_vk_v1 = new zerocash_pour_verification_key<ZerocashParams::zerocash_pp>(keypair->vk); |
|||
} |
|||
|
|||
ZerocashParams::ZerocashParams( |
|||
const unsigned int tree_depth, |
|||
std::string proving_key_path, |
|||
zerocash_pour_verification_key<ZerocashParams::zerocash_pp>* p_vk_1 |
|||
) : |
|||
treeDepth(tree_depth), provingKeyPath(proving_key_path) |
|||
{ |
|||
params_vk_v1 = new zerocash_pour_verification_key<ZerocashParams::zerocash_pp>(*p_vk_1); |
|||
params_pk_v1 = NULL; |
|||
} |
|||
|
|||
ZerocashParams::ZerocashParams( |
|||
const unsigned int tree_depth, |
|||
zerocash_pour_proving_key<ZerocashParams::zerocash_pp>* p_pk_1, |
|||
zerocash_pour_verification_key<ZerocashParams::zerocash_pp>* p_vk_1 |
|||
) : |
|||
treeDepth(tree_depth) |
|||
{ |
|||
assert(p_pk_1 != NULL || p_vk_1 != NULL); |
|||
|
|||
if (p_pk_1 == NULL) { |
|||
params_pk_v1 = NULL; |
|||
} else { |
|||
params_pk_v1 = new zerocash_pour_proving_key<ZerocashParams::zerocash_pp>(*p_pk_1); |
|||
} |
|||
|
|||
if (p_vk_1 == NULL) { |
|||
params_vk_v1 = NULL; |
|||
} else { |
|||
params_vk_v1 = new zerocash_pour_verification_key<ZerocashParams::zerocash_pp>(*p_vk_1); |
|||
} |
|||
} |
|||
|
|||
ZerocashParams::~ZerocashParams() |
|||
{ |
|||
if (params_pk_v1 != NULL) { |
|||
delete params_pk_v1; |
|||
} |
|||
if (params_vk_v1 != NULL) { |
|||
delete params_vk_v1; |
|||
} |
|||
} |
|||
|
|||
const zerocash_pour_proving_key<ZerocashParams::zerocash_pp>& ZerocashParams::getProvingKey() |
|||
{ |
|||
if (params_pk_v1 != NULL) { |
|||
return *params_pk_v1; |
|||
} else { |
|||
throw std::runtime_error("Pour proving key not set."); |
|||
} |
|||
} |
|||
|
|||
const zerocash_pour_verification_key<ZerocashParams::zerocash_pp>& ZerocashParams::getVerificationKey() |
|||
{ |
|||
if (params_vk_v1 != NULL) { |
|||
return *params_vk_v1; |
|||
} else { |
|||
throw std::runtime_error("Pour verification key not set."); |
|||
} |
|||
} |
|||
|
|||
} /* namespace libzerocash */ |
@ -1,77 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Declaration of interfaces for the class ZerocashParams. |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef PARAMS_H_ |
|||
#define PARAMS_H_ |
|||
|
|||
#include "Zerocash.h" |
|||
#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp" |
|||
#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" |
|||
#include "zerocash_pour_ppzksnark.hpp" |
|||
|
|||
namespace libzerocash { |
|||
|
|||
class ZerocashParams { |
|||
|
|||
public: |
|||
typedef default_r1cs_ppzksnark_pp zerocash_pp; |
|||
|
|||
ZerocashParams( |
|||
const unsigned int tree_depth, |
|||
zerocash_pour_keypair<ZerocashParams::zerocash_pp> *keypair |
|||
); |
|||
|
|||
ZerocashParams( |
|||
const unsigned int tree_depth, |
|||
zerocash_pour_proving_key<ZerocashParams::zerocash_pp>* p_pk_1, |
|||
zerocash_pour_verification_key<ZerocashParams::zerocash_pp>* p_vk_1 |
|||
); |
|||
|
|||
ZerocashParams( |
|||
const unsigned int tree_depth, |
|||
std::string proving_key_path, |
|||
zerocash_pour_verification_key<ZerocashParams::zerocash_pp>* p_vk_1 |
|||
); |
|||
|
|||
const zerocash_pour_proving_key<zerocash_pp>& getProvingKey(); |
|||
const zerocash_pour_verification_key<zerocash_pp>& getVerificationKey(); |
|||
int getTreeDepth(); |
|||
~ZerocashParams(); |
|||
|
|||
static const size_t numPourInputs = 2; |
|||
static const size_t numPourOutputs = 2; |
|||
|
|||
static zerocash_pour_keypair<ZerocashParams::zerocash_pp> GenerateNewKeyPair(const unsigned int tree_depth); |
|||
|
|||
static void SaveProvingKeyToFile(const zerocash_pour_proving_key<ZerocashParams::zerocash_pp>* p_pk_1, std::string path); |
|||
static void SaveVerificationKeyToFile(const zerocash_pour_verification_key<ZerocashParams::zerocash_pp>* p_vk_1, std::string path); |
|||
static zerocash_pour_proving_key<ZerocashParams::zerocash_pp> LoadProvingKeyFromFile(std::string path, const unsigned int tree_depth); |
|||
static zerocash_pour_verification_key<ZerocashParams::zerocash_pp> LoadVerificationKeyFromFile(std::string path, const unsigned int tree_depth); |
|||
|
|||
void loadProvingKey() |
|||
{ |
|||
if (params_pk_v1 == NULL) { |
|||
std::cout << "loading proving key from path: " << provingKeyPath << std::endl; |
|||
params_pk_v1 = new zerocash_pour_proving_key<ZerocashParams::zerocash_pp>( |
|||
LoadProvingKeyFromFile(provingKeyPath, treeDepth)); |
|||
std::cout << "done loading proving key!" << std::endl; |
|||
} |
|||
} |
|||
private: |
|||
int treeDepth; |
|||
zerocash_pour_proving_key<ZerocashParams::zerocash_pp>* params_pk_v1; |
|||
zerocash_pour_verification_key<ZerocashParams::zerocash_pp>* params_vk_v1; |
|||
std::string provingKeyPath; |
|||
}; |
|||
|
|||
} /* namespace libzerocash */ |
|||
|
|||
#endif /* PARAMS_H_ */ |
@ -1,39 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp" |
|||
#include "libsnark/common/profiling.hpp" |
|||
#include "zerocash_pour_ppzksnark/zerocash_pour_gadget.hpp" |
|||
|
|||
using namespace libsnark; |
|||
|
|||
int main(int argc, const char* argv[]) |
|||
{ |
|||
start_profiling(); |
|||
default_r1cs_ppzksnark_pp::init_public_params(); |
|||
#ifndef DEBUG |
|||
printf("this program needs to be compiled with constraint annotations (make debug/make cppdebug)\n"); |
|||
return 2; |
|||
#else |
|||
if (argc != 4) |
|||
{ |
|||
printf("usage: %s num_old_coins num_new_coins tree_depth\n", argv[0]); |
|||
return 1; |
|||
} |
|||
|
|||
|
|||
int num_old_coins = atoi(argv[1]); |
|||
int num_new_coins = atoi(argv[2]); |
|||
int tree_depth = atoi(argv[3]); |
|||
protoboard<Fr<default_r1cs_ppzksnark_pp> > pb; |
|||
libzerocash::zerocash_pour_gadget<Fr<default_r1cs_ppzksnark_pp> > g(pb, num_old_coins, num_new_coins, tree_depth, "pour"); |
|||
g.generate_r1cs_constraints(); |
|||
for (auto it : pb.get_constraint_system().constraint_annotations) |
|||
{ |
|||
printf("%s\n", it.second.c_str()); |
|||
} |
|||
#endif |
|||
} |
@ -1,325 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#include <algorithm> |
|||
#include <random> |
|||
#include <set> |
|||
#include <vector> |
|||
|
|||
#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp" |
|||
#include "libsnark/common/data_structures/merkle_tree.hpp" |
|||
#include "libsnark/common/utils.hpp" |
|||
#include "libsnark/common/profiling.hpp" |
|||
#include "libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" |
|||
#include "zerocash/zerocash_pour_gadget.hpp" |
|||
#include "zerocash/zerocash_pour_ppzksnark.hpp" |
|||
|
|||
using namespace libzerocash; |
|||
|
|||
bit_vector int_to_bit_vector(const size_t value, const size_t length) |
|||
{ |
|||
/* the returned result will have 0-th position equal to MSB of
|
|||
`value`, when written as `length`-bit integer */ |
|||
|
|||
assert(log2(value) < length); |
|||
bit_vector result(length, false); |
|||
|
|||
for (size_t i = 0; i < length; ++i) |
|||
{ |
|||
result[length-1-i] = ((value >> i) & 1) ? true : false; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
bit_vector get_random_bit_vector(const size_t length) |
|||
{ |
|||
bit_vector result(length); |
|||
std::generate(result.begin(), result.end(), [] { return std::rand() % 2; }); |
|||
return result; |
|||
} |
|||
|
|||
std::vector<size_t> sample_random_positions(const size_t num_positions, const size_t log2_universe_size) |
|||
{ |
|||
/* not asymptotically optimal, but likely not to be a problem in
|
|||
practice, where num_positions is much smaller than |
|||
universe_size */ |
|||
assert(log2(num_positions) <= log2_universe_size); |
|||
assert(log2_universe_size <= 8 * sizeof(size_t)); |
|||
std::set<size_t> positions; |
|||
std::vector<size_t> result; |
|||
while (positions.size() != num_positions) |
|||
{ |
|||
size_t new_pos = std::rand(); |
|||
if (log2_universe_size < 8 * sizeof(size_t)) |
|||
{ |
|||
new_pos &= ((1ul << log2_universe_size) - 1); /* clear higher bits appropriately */ |
|||
} |
|||
if (positions.find(new_pos) == positions.end()) |
|||
{ |
|||
positions.insert(new_pos); |
|||
result.emplace_back(new_pos); |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
bit_vector compute_coin_commitment(const bit_vector &address_public_key, |
|||
const bit_vector &coin_value, |
|||
const bit_vector &serial_number_nonce, |
|||
const bit_vector &address_commitment_nonce) |
|||
{ |
|||
/* commitment_to_address_public_key = H(address_public_key || serial_number_nonce) */ |
|||
bit_vector commitment_to_address_public_key_hash_input; |
|||
commitment_to_address_public_key_hash_input.insert(commitment_to_address_public_key_hash_input.end(), |
|||
address_public_key.begin(), |
|||
address_public_key.end()); |
|||
commitment_to_address_public_key_hash_input.insert(commitment_to_address_public_key_hash_input.end(), |
|||
serial_number_nonce.begin(), |
|||
serial_number_nonce.end()); |
|||
const bit_vector commitment_to_address_public_key = sha256_two_to_one_hash_gadget<FieldT>::get_hash(commitment_to_address_public_key_hash_input); |
|||
|
|||
/* coin_value_commitment_nonce = H(address_commitment_nonce || commitment_to_address_public_key[0..128]) */ |
|||
bit_vector coin_value_commitment_nonce_hash_input; |
|||
coin_value_commitment_nonce_hash_input.insert(coin_value_commitment_nonce_hash_input.end(), |
|||
address_commitment_nonce.begin(), |
|||
address_commitment_nonce.end()); |
|||
coin_value_commitment_nonce_hash_input.insert(coin_value_commitment_nonce_hash_input.end(), |
|||
commitment_to_address_public_key.begin(), |
|||
commitment_to_address_public_key.begin() + truncated_coin_commitment_length); |
|||
|
|||
const bit_vector coin_value_commitment_nonce = sha256_two_to_one_hash_gadget<FieldT>::get_hash(coin_value_commitment_nonce_hash_input); |
|||
|
|||
/* coin_commitment = H(coin_value_commitment_nonce || 0^{192} || coin_value) */ |
|||
bit_vector coin_commitment_hash_input; |
|||
coin_commitment_hash_input.insert(coin_commitment_hash_input.end(), |
|||
coin_value_commitment_nonce.begin(), |
|||
coin_value_commitment_nonce.end()); |
|||
coin_commitment_hash_input.resize(coin_commitment_hash_input.size() + coin_commitment_padding_length, false); |
|||
coin_commitment_hash_input.insert(coin_commitment_hash_input.end(), |
|||
coin_value.begin(), |
|||
coin_value.end()); |
|||
const bit_vector coin_commitment = sha256_two_to_one_hash_gadget<FieldT>::get_hash(coin_commitment_hash_input); |
|||
|
|||
return coin_commitment; |
|||
} |
|||
|
|||
std::vector<size_t> randomly_split_up_value(const size_t value, const size_t num_parts) |
|||
{ |
|||
std::vector<size_t> points(num_parts-1); |
|||
std::generate(points.begin(), points.end(), [value] { return std::rand() % value; }); |
|||
points.emplace_back(0); |
|||
points.emplace_back(value); |
|||
std::sort(points.begin(), points.end()); /* now points is a num_parts+1-length vector with endpoints of 0 and value */ |
|||
|
|||
std::vector<size_t> result(num_parts); |
|||
for (size_t i = 0; i < num_parts; ++i) |
|||
{ |
|||
result[i] = points[i+1] - points[i]; |
|||
} |
|||
/* the resulting sum telescopes to value-0 = value */ |
|||
|
|||
return result; |
|||
} |
|||
|
|||
template<typename ppT> |
|||
void test_zerocash_pour_ppzksnark(const size_t num_old_coins, const size_t num_new_coins, const size_t tree_depth) |
|||
{ |
|||
typedef Fr<ppT> FieldT; |
|||
|
|||
assert(log2(num_old_coins) <= tree_depth); |
|||
|
|||
/* information used by the prover in the witness map */ |
|||
std::vector<merkle_authentication_path> old_coin_authentication_paths(num_old_coins); //
|
|||
std::vector<size_t> old_coin_merkle_tree_positions; //
|
|||
bit_vector merkle_tree_root; //
|
|||
std::vector<bit_vector> new_address_public_keys(num_new_coins); //
|
|||
std::vector<bit_vector> old_address_secret_keys(num_old_coins); //
|
|||
std::vector<bit_vector> new_address_commitment_nonces(num_new_coins); //
|
|||
std::vector<bit_vector> old_address_commitment_nonces(num_old_coins); //
|
|||
std::vector<bit_vector> new_coin_serial_number_nonces(num_new_coins); //
|
|||
std::vector<bit_vector> old_coin_serial_number_nonces(num_old_coins); //
|
|||
std::vector<bit_vector> new_coin_values(num_new_coins); //
|
|||
bit_vector public_in_value; //
|
|||
bit_vector public_out_value; //
|
|||
std::vector<bit_vector> old_coin_values(num_old_coins); //
|
|||
bit_vector signature_public_key_hash; //
|
|||
|
|||
/* generate split for the money */ |
|||
std::vector<size_t> old_coin_values_as_integers(num_old_coins); |
|||
std::generate(old_coin_values_as_integers.begin(), old_coin_values_as_integers.end(), [] { return std::rand() % 10000; }); |
|||
const size_t total_value_as_integer = std::accumulate(old_coin_values_as_integers.begin(), old_coin_values_as_integers.end(), 0); |
|||
std::vector<size_t> all_new_values_as_integers = randomly_split_up_value(total_value_as_integer, num_new_coins + 1); |
|||
|
|||
std::transform(old_coin_values_as_integers.begin(), old_coin_values_as_integers.end(), |
|||
old_coin_values.begin(), |
|||
[] (const size_t value) { return int_to_bit_vector(value, coin_value_length); }); |
|||
public_in_value = int_to_bit_vector(0, coin_value_length); |
|||
public_out_value = int_to_bit_vector(all_new_values_as_integers[0], coin_value_length); |
|||
std::transform(all_new_values_as_integers.begin() + 1, all_new_values_as_integers.end(), |
|||
new_coin_values.begin(), |
|||
[] (const size_t value) { return int_to_bit_vector(value, coin_value_length); }); |
|||
|
|||
/* generate random private values for the prover */ |
|||
old_coin_merkle_tree_positions = sample_random_positions(num_old_coins, tree_depth); |
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
old_address_secret_keys[i] = get_random_bit_vector(address_secret_key_length); |
|||
old_address_commitment_nonces[i] = get_random_bit_vector(address_commitment_nonce_length); |
|||
old_coin_serial_number_nonces[i] = get_random_bit_vector(serial_number_nonce_length); |
|||
} |
|||
|
|||
for (size_t i = 0; i < num_new_coins; ++i) |
|||
{ |
|||
new_address_public_keys[i] = get_random_bit_vector(address_public_key_length); |
|||
new_address_commitment_nonces[i] = get_random_bit_vector(address_commitment_nonce_length); |
|||
new_coin_serial_number_nonces[i] = get_random_bit_vector(serial_number_nonce_length); |
|||
} |
|||
|
|||
merkle_tree<sha256_two_to_one_hash_gadget<FieldT> > tree(tree_depth, coin_commitment_length); |
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
/* calculate old coin and place it in the Merkle tree */ |
|||
|
|||
/* old_address_public_key = H(old_address_secret_key || 00...) */ |
|||
bit_vector old_address_public_key_hash_input = old_address_secret_keys[i]; |
|||
old_address_public_key_hash_input.resize(sha256_block_len); |
|||
const bit_vector old_address_public_key = sha256_two_to_one_hash_gadget<FieldT>::get_hash(old_address_public_key_hash_input); |
|||
|
|||
const bit_vector old_coin = compute_coin_commitment<FieldT>(old_address_public_key, |
|||
old_coin_values[i], |
|||
old_coin_serial_number_nonces[i], |
|||
old_address_commitment_nonces[i]); |
|||
tree.set_value(old_coin_merkle_tree_positions[i], old_coin); |
|||
} |
|||
|
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
/* get the corresponding authentication paths */ |
|||
old_coin_authentication_paths[i] = tree.get_path(old_coin_merkle_tree_positions[i]); |
|||
} |
|||
|
|||
merkle_tree_root = tree.get_root(); |
|||
signature_public_key_hash = get_random_bit_vector(sha256_digest_len); |
|||
|
|||
/* calculate the values used by the verifier */ |
|||
std::vector<bit_vector> old_coin_serial_numbers(num_old_coins); //
|
|||
std::vector<bit_vector> new_coin_commitments(num_new_coins); //
|
|||
std::vector<bit_vector> signature_public_key_hash_macs(num_old_coins); //
|
|||
|
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
/* serial_number = H(address_secret_key || 01 || serial_number_nonce[0..254]) */ |
|||
bit_vector old_coin_serial_number_hash_input; |
|||
old_coin_serial_number_hash_input.insert(old_coin_serial_number_hash_input.end(), |
|||
old_address_secret_keys[i].begin(), |
|||
old_address_secret_keys[i].end()); |
|||
old_coin_serial_number_hash_input.push_back(false); |
|||
old_coin_serial_number_hash_input.push_back(true); |
|||
old_coin_serial_number_hash_input.insert(old_coin_serial_number_hash_input.end(), |
|||
old_coin_serial_number_nonces[i].begin(), |
|||
old_coin_serial_number_nonces[i].begin() + truncated_serial_number_length); |
|||
|
|||
old_coin_serial_numbers[i] = sha256_two_to_one_hash_gadget<FieldT>::get_hash(old_coin_serial_number_hash_input); |
|||
|
|||
/* signature_public_key_hash_macs[i] = H(old_address_secret_keys[i] || 10 || i || signature_public_key_hash) */ |
|||
const size_t truncated_signature_public_key_hash_length = indexed_signature_public_key_hash_length - log2(num_old_coins); |
|||
|
|||
bit_vector signature_public_key_hash_macs_hash_input; |
|||
signature_public_key_hash_macs_hash_input.insert(signature_public_key_hash_macs_hash_input.end(), |
|||
old_address_secret_keys[i].begin(), |
|||
old_address_secret_keys[i].end()); |
|||
signature_public_key_hash_macs_hash_input.push_back(true); |
|||
signature_public_key_hash_macs_hash_input.push_back(false); |
|||
const bit_vector i_as_bits = int_to_bit_vector(i, log2(num_old_coins)); |
|||
signature_public_key_hash_macs_hash_input.insert(signature_public_key_hash_macs_hash_input.end(), |
|||
i_as_bits.begin(), |
|||
i_as_bits.end()); |
|||
signature_public_key_hash_macs_hash_input.insert(signature_public_key_hash_macs_hash_input.end(), |
|||
signature_public_key_hash.begin(), |
|||
signature_public_key_hash.begin() + truncated_signature_public_key_hash_length); |
|||
signature_public_key_hash_macs[i] = sha256_two_to_one_hash_gadget<FieldT>::get_hash(signature_public_key_hash_macs_hash_input); |
|||
} |
|||
|
|||
for (size_t i = 0; i < num_new_coins; ++i) |
|||
{ |
|||
new_coin_commitments[i] = compute_coin_commitment<FieldT>(new_address_public_keys[i], |
|||
new_coin_values[i], |
|||
new_coin_serial_number_nonces[i], |
|||
new_address_commitment_nonces[i]); |
|||
} |
|||
|
|||
/* perform basic sanity checks */ |
|||
{ |
|||
protoboard<FieldT> pb; |
|||
zerocash_pour_gadget<FieldT> pour(pb, num_old_coins, num_new_coins, tree_depth, "pour"); |
|||
pour.generate_r1cs_constraints(); |
|||
pour.generate_r1cs_witness(old_coin_authentication_paths, |
|||
old_coin_merkle_tree_positions, |
|||
merkle_tree_root, |
|||
new_address_public_keys, |
|||
old_address_secret_keys, |
|||
new_address_commitment_nonces, |
|||
old_address_commitment_nonces, |
|||
new_coin_serial_number_nonces, |
|||
old_coin_serial_number_nonces, |
|||
new_coin_values, |
|||
public_in_value, |
|||
public_out_value, |
|||
old_coin_values, |
|||
signature_public_key_hash); |
|||
assert(pb.is_satisfied()); |
|||
printf("gadget test OK for num_old_coins = %zu, num_new_coins = %zu, tree_depth = %zu\n", |
|||
num_old_coins, num_new_coins, tree_depth); |
|||
} |
|||
|
|||
/* do the end-to-end test */ |
|||
zerocash_pour_keypair<ppT> keypair = zerocash_pour_ppzksnark_generator<ppT>(num_old_coins, num_new_coins, tree_depth); |
|||
keypair = reserialize<zerocash_pour_keypair<ppT> >(keypair); |
|||
|
|||
zerocash_pour_proof<ppT> proof = zerocash_pour_ppzksnark_prover<ppT>(keypair.pk, |
|||
old_coin_authentication_paths, |
|||
old_coin_merkle_tree_positions, |
|||
merkle_tree_root, |
|||
new_address_public_keys, |
|||
old_address_secret_keys, |
|||
new_address_commitment_nonces, |
|||
old_address_commitment_nonces, |
|||
new_coin_serial_number_nonces, |
|||
old_coin_serial_number_nonces, |
|||
new_coin_values, |
|||
public_in_value, |
|||
public_out_value, |
|||
old_coin_values, |
|||
signature_public_key_hash); |
|||
proof = reserialize<zerocash_pour_proof<ppT> >(proof); |
|||
|
|||
const bool verification_result = zerocash_pour_ppzksnark_verifier<ppT>(keypair.vk, |
|||
merkle_tree_root, |
|||
old_coin_serial_numbers, |
|||
new_coin_commitments, |
|||
public_in_value, |
|||
public_out_value, |
|||
signature_public_key_hash, |
|||
signature_public_key_hash_macs, |
|||
proof); |
|||
printf("Verification result: %s\n", verification_result ? "pass" : "FAIL"); |
|||
assert(verification_result); |
|||
} |
|||
|
|||
int main(int argc, const char * argv[]) |
|||
{ |
|||
start_profiling(); |
|||
default_r1cs_ppzksnark_pp::init_public_params(); |
|||
test_zerocash_pour_ppzksnark<default_r1cs_ppzksnark_pp>(2, 2, 4); |
|||
test_zerocash_pour_ppzksnark<default_r1cs_ppzksnark_pp>(2, 3, 4); |
|||
test_zerocash_pour_ppzksnark<default_r1cs_ppzksnark_pp>(3, 2, 4); |
|||
test_zerocash_pour_ppzksnark<default_r1cs_ppzksnark_pp>(3, 3, 4); |
|||
test_zerocash_pour_ppzksnark<default_r1cs_ppzksnark_pp>(2, 2, 32); |
|||
} |
@ -1,631 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
A test for Zerocash. |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#include <stdlib.h> |
|||
#include <iostream> |
|||
|
|||
#define BOOST_TEST_MODULE zerocashTest |
|||
#include <boost/test/included/unit_test.hpp> |
|||
|
|||
#include "timer.h" |
|||
|
|||
#include "zerocash/Zerocash.h" |
|||
#include "zerocash/ZerocashParams.h" |
|||
#include "zerocash/Address.h" |
|||
#include "zerocash/CoinCommitment.h" |
|||
#include "zerocash/Coin.h" |
|||
#include "zerocash/IncrementalMerkleTree.h" |
|||
#include "zerocash/MintTransaction.h" |
|||
#include "zerocash/PourTransaction.h" |
|||
#include "zerocash/PourInput.h" |
|||
#include "zerocash/PourOutput.h" |
|||
#include "zerocash/utils/util.h" |
|||
|
|||
#include "uint256.h" |
|||
|
|||
using namespace std; |
|||
using namespace libsnark; |
|||
|
|||
BOOST_AUTO_TEST_CASE( SaveAndLoadKeysFromFiles ) { |
|||
cout << "\nSaveAndLoadKeysFromFiles TEST\n" << endl; |
|||
|
|||
cout << "Creating Params...\n" << endl; |
|||
|
|||
libzerocash::timer_start("Param Generation"); |
|||
auto keypair = libzerocash::ZerocashParams::GenerateNewKeyPair(INCREMENTAL_MERKLE_TREE_DEPTH); |
|||
libzerocash::ZerocashParams p( |
|||
INCREMENTAL_MERKLE_TREE_DEPTH, |
|||
&keypair |
|||
); |
|||
libzerocash::timer_stop("Param Generation"); |
|||
print_mem("after param generation"); |
|||
|
|||
cout << "Successfully created Params.\n" << endl; |
|||
|
|||
std::string vk_path = "./zerocashTest-verification-key"; |
|||
std::string pk_path = "./zerocashTest-proving-key"; |
|||
|
|||
libzerocash::timer_start("Saving Proving Key"); |
|||
|
|||
libzerocash::ZerocashParams::SaveProvingKeyToFile( |
|||
&p.getProvingKey(), |
|||
pk_path |
|||
); |
|||
|
|||
libzerocash::timer_stop("Saving Proving Key"); |
|||
|
|||
libzerocash::timer_start("Saving Verification Key"); |
|||
|
|||
libzerocash::ZerocashParams::SaveVerificationKeyToFile( |
|||
&p.getVerificationKey(), |
|||
vk_path |
|||
); |
|||
|
|||
libzerocash::timer_stop("Saving Verification Key"); |
|||
|
|||
libzerocash::timer_start("Loading Proving Key"); |
|||
auto pk_loaded = libzerocash::ZerocashParams::LoadProvingKeyFromFile(pk_path, INCREMENTAL_MERKLE_TREE_DEPTH); |
|||
libzerocash::timer_stop("Loading Proving Key"); |
|||
|
|||
libzerocash::timer_start("Loading Verification Key"); |
|||
auto vk_loaded = libzerocash::ZerocashParams::LoadVerificationKeyFromFile(vk_path, INCREMENTAL_MERKLE_TREE_DEPTH); |
|||
libzerocash::timer_stop("Loading Verification Key"); |
|||
|
|||
cout << "Comparing Proving and Verification key.\n" << endl; |
|||
|
|||
if ( !( p.getProvingKey() == pk_loaded && p.getVerificationKey() == vk_loaded) ) { |
|||
BOOST_ERROR("Proving and verification key are not equal."); |
|||
} |
|||
|
|||
vector<libzerocash::Coin> coins; |
|||
vector<libzerocash::Address> addrs; |
|||
|
|||
cout << "Creating Addresses and Coins...\n" << endl; |
|||
for(size_t i = 0; i < 5; i++) { |
|||
addrs.push_back(libzerocash::Address::CreateNewRandomAddress()); |
|||
coins.push_back(libzerocash::Coin(addrs.at(i).getPublicAddress(), i)); |
|||
} |
|||
cout << "Successfully created address and coins.\n" << endl; |
|||
|
|||
cout << "Creating a Mint Transaction...\n" << endl; |
|||
libzerocash::MintTransaction minttx(coins.at(0)); |
|||
cout << "Successfully created a Mint Transaction.\n" << endl; |
|||
|
|||
vector<std::vector<bool>> coinValues(5); |
|||
vector<bool> temp_comVal(ZC_CM_SIZE * 8); |
|||
for(size_t i = 0; i < coinValues.size(); i++) { |
|||
libzerocash::convertBytesVectorToVector(coins.at(i).getCoinCommitment().getCommitmentValue(), temp_comVal); |
|||
coinValues.at(i) = temp_comVal; |
|||
} |
|||
|
|||
cout << "Creating Merkle Tree...\n" << endl; |
|||
libzerocash::IncrementalMerkleTree merkleTree(coinValues, INCREMENTAL_MERKLE_TREE_DEPTH); |
|||
cout << "Successfully created Merkle Tree.\n" << endl; |
|||
|
|||
std::vector<bool> index; |
|||
|
|||
cout << "Creating Witness 1...\n" << endl; |
|||
merkle_authentication_path witness_1(INCREMENTAL_MERKLE_TREE_DEPTH); |
|||
libzerocash::convertIntToVector(1, index); |
|||
merkleTree.getWitness(index, witness_1); |
|||
cout << "Successfully created Witness 1.\n" << endl; |
|||
|
|||
cout << "Creating Witness 2...\n" << endl; |
|||
merkle_authentication_path witness_2(INCREMENTAL_MERKLE_TREE_DEPTH); |
|||
libzerocash::convertIntToVector(3, index); |
|||
merkleTree.getWitness(index, witness_2); |
|||
cout << "Successfully created Witness 2.\n" << endl; |
|||
|
|||
cout << "Creating coins to spend...\n" << endl; |
|||
libzerocash::Address newAddress3 = libzerocash::Address::CreateNewRandomAddress(); |
|||
libzerocash::PublicAddress pubAddress3 = newAddress3.getPublicAddress(); |
|||
|
|||
libzerocash::Address newAddress4 = libzerocash::Address::CreateNewRandomAddress(); |
|||
libzerocash::PublicAddress pubAddress4 = newAddress4.getPublicAddress(); |
|||
|
|||
libzerocash::Coin c_1_new(pubAddress3, 2); |
|||
libzerocash::Coin c_2_new(pubAddress4, 2); |
|||
cout << "Successfully created coins to spend.\n" << endl; |
|||
|
|||
vector<unsigned char> rt(ZC_ROOT_SIZE); |
|||
merkleTree.getRootValue(rt); |
|||
|
|||
// XXX: debugging
|
|||
std::cout << "Root: " << rt.size() << endl; |
|||
std::cout << "wit1: " << witness_1.size() << endl; |
|||
std::cout << "wit2: " << witness_1.size() << endl; |
|||
|
|||
vector<unsigned char> as(ZC_SIG_PK_SIZE, 'a'); |
|||
|
|||
cout << "Creating a pour transaction...\n" << endl; |
|||
libzerocash::PourTransaction pourtx(1, p, |
|||
rt, |
|||
coins.at(1), coins.at(3), |
|||
addrs.at(1), addrs.at(3), |
|||
1, 3, |
|||
witness_1, witness_2, |
|||
pubAddress3, pubAddress4, |
|||
0, |
|||
0, |
|||
as, |
|||
c_1_new, c_2_new); |
|||
cout << "Successfully created a pour transaction.\n" << endl; |
|||
|
|||
std::vector<unsigned char> pubkeyHash(ZC_SIG_PK_SIZE, 'a'); |
|||
|
|||
cout << "Verifying a pour transaction...\n" << endl; |
|||
bool pourtx_res = pourtx.verify(p, pubkeyHash, rt); |
|||
|
|||
BOOST_CHECK(pourtx_res); |
|||
} |
|||
|
|||
BOOST_AUTO_TEST_CASE( PourInputOutputTest ) { |
|||
// dummy input
|
|||
{ |
|||
libzerocash::PourInput input(INCREMENTAL_MERKLE_TREE_DEPTH); |
|||
|
|||
BOOST_CHECK(input.old_coin.getValue() == 0); |
|||
BOOST_CHECK(input.old_address.getPublicAddress() == input.old_coin.getPublicAddress()); |
|||
} |
|||
|
|||
// dummy output
|
|||
{ |
|||
libzerocash::PourOutput output(0); |
|||
|
|||
BOOST_CHECK(output.new_coin.getValue() == 0); |
|||
BOOST_CHECK(output.to_address == output.new_coin.getPublicAddress()); |
|||
} |
|||
} |
|||
|
|||
// testing with general situational setup
|
|||
void test_pour(libzerocash::ZerocashParams& p, |
|||
uint64_t vpub_in, |
|||
uint64_t vpub_out, |
|||
std::vector<uint64_t> inputs, // values of the inputs (max 2)
|
|||
std::vector<uint64_t> outputs) // values of the outputs (max 2)
|
|||
{ |
|||
using pour_input_state = std::tuple<libzerocash::Address, libzerocash::Coin, ZCIncrementalWitness>; |
|||
|
|||
// Construct incremental merkle tree
|
|||
ZCIncrementalMerkleTree merkleTree; |
|||
|
|||
// Dummy sig_pk
|
|||
vector<unsigned char> as(ZC_SIG_PK_SIZE, 'a'); |
|||
|
|||
vector<libzerocash::PourInput> pour_inputs; |
|||
vector<libzerocash::PourOutput> pour_outputs; |
|||
|
|||
vector<pour_input_state> input_state; |
|||
|
|||
for(std::vector<uint64_t>::iterator it = inputs.begin(); it != inputs.end(); ++it) { |
|||
libzerocash::Address addr = libzerocash::Address::CreateNewRandomAddress(); |
|||
libzerocash::Coin coin(addr.getPublicAddress(), *it); |
|||
|
|||
// commitment from coin
|
|||
uint256 commitment(coin.getCoinCommitment().getCommitmentValue()); |
|||
|
|||
// insert commitment into the merkle tree
|
|||
merkleTree.append(commitment); |
|||
|
|||
// and append to any witnesses
|
|||
for(vector<pour_input_state>::iterator wit = input_state.begin(); wit != input_state.end(); ++wit) { |
|||
std::get<2>(*wit).append(commitment); |
|||
} |
|||
|
|||
// store the state temporarily
|
|||
input_state.push_back(std::make_tuple(addr, coin, merkleTree.witness())); |
|||
} |
|||
|
|||
// compute the merkle root we will be working with
|
|||
auto rt_u = merkleTree.root(); |
|||
std::vector<unsigned char> rt(rt_u.begin(), rt_u.end()); |
|||
|
|||
// get witnesses for all the input coins and construct the pours
|
|||
for(vector<pour_input_state>::iterator it = input_state.begin(); it != input_state.end(); ++it) { |
|||
auto witness = std::get<2>(*it); |
|||
auto path = witness.path(); |
|||
|
|||
pour_inputs.push_back(libzerocash::PourInput(std::get<1>(*it), std::get<0>(*it), path)); |
|||
} |
|||
|
|||
// construct dummy outputs with the given values
|
|||
for(vector<uint64_t>::iterator it = outputs.begin(); it != outputs.end(); ++it) { |
|||
pour_outputs.push_back(libzerocash::PourOutput(*it)); |
|||
} |
|||
|
|||
libzerocash::PourTransaction pourtx(p, as, rt, pour_inputs, pour_outputs, vpub_in, vpub_out); |
|||
|
|||
BOOST_CHECK(pourtx.verify(p, as, rt)); |
|||
} |
|||
|
|||
BOOST_AUTO_TEST_CASE( PourVpubInTest ) { |
|||
auto keypair = libzerocash::ZerocashParams::GenerateNewKeyPair(INCREMENTAL_MERKLE_TREE_DEPTH); |
|||
libzerocash::ZerocashParams p( |
|||
INCREMENTAL_MERKLE_TREE_DEPTH, |
|||
&keypair |
|||
); |
|||
|
|||
// Things that should work..
|
|||
test_pour(p, 0, 0, {1}, {1}); |
|||
test_pour(p, 0, 0, {2}, {1, 1}); |
|||
test_pour(p, 0, 0, {2, 2}, {3, 1}); |
|||
test_pour(p, 0, 1, {1}, {}); |
|||
test_pour(p, 0, 1, {2}, {1}); |
|||
test_pour(p, 0, 1, {2, 2}, {2, 1}); |
|||
test_pour(p, 1, 0, {}, {1}); |
|||
test_pour(p, 1, 0, {1}, {1, 1}); |
|||
test_pour(p, 1, 0, {2, 2}, {2, 3}); |
|||
|
|||
// Things that should not work...
|
|||
BOOST_CHECK_THROW(test_pour(p, 0, 1, {1}, {1}), std::invalid_argument); |
|||
BOOST_CHECK_THROW(test_pour(p, 0, 1, {2}, {1, 1}), std::invalid_argument); |
|||
BOOST_CHECK_THROW(test_pour(p, 0, 1, {2, 2}, {3, 1}), std::invalid_argument); |
|||
BOOST_CHECK_THROW(test_pour(p, 0, 2, {1}, {}), std::invalid_argument); |
|||
BOOST_CHECK_THROW(test_pour(p, 0, 2, {2}, {1}), std::invalid_argument); |
|||
BOOST_CHECK_THROW(test_pour(p, 0, 2, {2, 2}, {2, 1}), std::invalid_argument); |
|||
BOOST_CHECK_THROW(test_pour(p, 1, 1, {}, {1}), std::invalid_argument); |
|||
BOOST_CHECK_THROW(test_pour(p, 1, 1, {1}, {1, 1}), std::invalid_argument); |
|||
BOOST_CHECK_THROW(test_pour(p, 1, 1, {2, 2}, {2, 3}), std::invalid_argument); |
|||
|
|||
BOOST_CHECK_THROW(test_pour(p, 0, 0, {2, 2}, {2, 3}), std::invalid_argument); |
|||
} |
|||
|
|||
BOOST_AUTO_TEST_CASE( CoinTest ) { |
|||
cout << "\nCOIN TEST\n" << endl; |
|||
|
|||
libzerocash::Address newAddress = libzerocash::Address::CreateNewRandomAddress(); |
|||
libzerocash::PublicAddress pubAddress = newAddress.getPublicAddress(); |
|||
|
|||
libzerocash::Coin coin(pubAddress, 0); |
|||
|
|||
cout << "Successfully created a coin.\n" << endl; |
|||
|
|||
///////////////////////////////////////////////////////////////////////////
|
|||
|
|||
libzerocash::timer_start("Coin"); |
|||
libzerocash::Coin coin2(pubAddress, 0); |
|||
libzerocash::timer_stop("Coin"); |
|||
|
|||
cout << "Successfully created a coin.\n" << endl; |
|||
} |
|||
|
|||
BOOST_AUTO_TEST_CASE( MintTxTest ) { |
|||
cout << "\nMINT TRANSACTION TEST\n" << endl; |
|||
|
|||
libzerocash::Address newAddress = libzerocash::Address::CreateNewRandomAddress(); |
|||
libzerocash::PublicAddress pubAddress = newAddress.getPublicAddress(); |
|||
|
|||
vector<unsigned char> value(ZC_V_SIZE, 0); |
|||
|
|||
libzerocash::timer_start("Coin"); |
|||
const libzerocash::Coin coin(pubAddress, 0); |
|||
libzerocash::timer_stop("Coin"); |
|||
|
|||
libzerocash::timer_start("Mint Transaction"); |
|||
libzerocash::MintTransaction minttx(coin); |
|||
libzerocash::timer_stop("Mint Transaction"); |
|||
|
|||
cout << "Successfully created a mint transaction.\n" << endl; |
|||
|
|||
libzerocash::timer_start("Mint Transaction Verify"); |
|||
bool minttx_res = minttx.verify(); |
|||
libzerocash::timer_stop("Mint Transaction Verify"); |
|||
|
|||
BOOST_CHECK(minttx_res); |
|||
} |
|||
|
|||
BOOST_AUTO_TEST_CASE( PourTxTest ) { |
|||
cout << "\nPOUR TRANSACTION TEST\n" << endl; |
|||
|
|||
cout << "Creating Params...\n" << endl; |
|||
|
|||
libzerocash::timer_start("Param Generation"); |
|||
auto keypair = libzerocash::ZerocashParams::GenerateNewKeyPair(INCREMENTAL_MERKLE_TREE_DEPTH); |
|||
libzerocash::ZerocashParams p( |
|||
INCREMENTAL_MERKLE_TREE_DEPTH, |
|||
&keypair |
|||
); |
|||
libzerocash::timer_stop("Param Generation"); |
|||
print_mem("after param generation"); |
|||
|
|||
cout << "Successfully created Params.\n" << endl; |
|||
|
|||
vector<libzerocash::Coin> coins; |
|||
vector<libzerocash::Address> addrs; |
|||
|
|||
for(size_t i = 0; i < 5; i++) { |
|||
addrs.push_back(libzerocash::Address::CreateNewRandomAddress()); |
|||
coins.push_back(libzerocash::Coin(addrs.at(i).getPublicAddress(), i)); |
|||
} |
|||
|
|||
cout << "Successfully created coins.\n" << endl; |
|||
|
|||
vector<std::vector<bool>> coinValues(5); |
|||
|
|||
vector<bool> temp_comVal(ZC_CM_SIZE * 8); |
|||
for(size_t i = 0; i < coinValues.size(); i++) { |
|||
libzerocash::convertBytesVectorToVector(coins.at(i).getCoinCommitment().getCommitmentValue(), temp_comVal); |
|||
coinValues.at(i) = temp_comVal; |
|||
libzerocash::printVectorAsHex("Coin => ", coinValues.at(i)); |
|||
} |
|||
|
|||
cout << "Creating Merkle Tree...\n" << endl; |
|||
|
|||
libzerocash::timer_start("Merkle Tree"); |
|||
libzerocash::IncrementalMerkleTree merkleTree(coinValues, INCREMENTAL_MERKLE_TREE_DEPTH); |
|||
libzerocash::timer_stop("Merkle Tree"); |
|||
|
|||
cout << "Successfully created Merkle Tree.\n" << endl; |
|||
|
|||
merkle_authentication_path witness_1(INCREMENTAL_MERKLE_TREE_DEPTH); |
|||
|
|||
libzerocash::timer_start("Witness"); |
|||
std::vector<bool> index; |
|||
libzerocash::convertIntToVector(1, index); |
|||
if (merkleTree.getWitness(index, witness_1) == false) { |
|||
BOOST_ERROR("Could not get witness"); |
|||
} |
|||
libzerocash::timer_stop("Witness"); |
|||
|
|||
cout << "Witness 1: " << endl; |
|||
for(size_t i = 0; i < witness_1.size(); i++) { |
|||
libzerocash::printVectorAsHex(witness_1.at(i)); |
|||
} |
|||
cout << "\n" << endl; |
|||
|
|||
merkle_authentication_path witness_2(INCREMENTAL_MERKLE_TREE_DEPTH); |
|||
libzerocash::convertIntToVector(3, index); |
|||
if (merkleTree.getWitness(index, witness_2) == false) { |
|||
cout << "Could not get witness" << endl; |
|||
} |
|||
|
|||
cout << "Witness 2: " << endl; |
|||
for(size_t i = 0; i < witness_2.size(); i++) { |
|||
libzerocash::printVectorAsHex(witness_2.at(i)); |
|||
} |
|||
cout << "\n" << endl; |
|||
|
|||
libzerocash::Address newAddress3 = libzerocash::Address::CreateNewRandomAddress(); |
|||
libzerocash::PublicAddress pubAddress3 = newAddress3.getPublicAddress(); |
|||
|
|||
libzerocash::Address newAddress4 = libzerocash::Address::CreateNewRandomAddress(); |
|||
libzerocash::PublicAddress pubAddress4 = newAddress4.getPublicAddress(); |
|||
|
|||
libzerocash::Coin c_1_new(pubAddress3, 2); |
|||
libzerocash::Coin c_2_new(pubAddress4, 2); |
|||
|
|||
vector<bool> root_bv(ZC_ROOT_SIZE * 8); |
|||
merkleTree.getRootValue(root_bv); |
|||
vector<unsigned char> rt(ZC_ROOT_SIZE); |
|||
libzerocash::convertVectorToBytesVector(root_bv, rt); |
|||
|
|||
vector<unsigned char> ones(ZC_V_SIZE, 1); |
|||
vector<unsigned char> twos(ZC_V_SIZE, 2); |
|||
vector<unsigned char> as(ZC_SIG_PK_SIZE, 'a'); |
|||
|
|||
cout << "Creating a pour transaction...\n" << endl; |
|||
|
|||
libzerocash::timer_start("Pour Transaction"); |
|||
libzerocash::PourTransaction pourtx(1, p, rt, coins.at(1), coins.at(3), addrs.at(1), addrs.at(3), 1, 3, witness_1, witness_2, pubAddress3, pubAddress4, 0, 0, as, c_1_new, c_2_new); |
|||
libzerocash::timer_stop("Pour Transaction"); |
|||
print_mem("after pour transaction"); |
|||
|
|||
cout << "Successfully created a pour transaction.\n" << endl; |
|||
|
|||
std::vector<unsigned char> pubkeyHash(ZC_SIG_PK_SIZE, 'a'); |
|||
|
|||
libzerocash::timer_start("Pour Transaction Verify"); |
|||
bool pourtx_res = pourtx.verify(p, pubkeyHash, rt); |
|||
libzerocash::timer_stop("Pour Transaction Verify"); |
|||
|
|||
BOOST_CHECK(pourtx_res); |
|||
} |
|||
|
|||
BOOST_AUTO_TEST_CASE( MerkleTreeSimpleTest ) { |
|||
cout << "\nMERKLE TREE SIMPLE TEST\n" << endl; |
|||
|
|||
vector<libzerocash::Coin> coins; |
|||
vector<libzerocash::Address> addrs; |
|||
|
|||
cout << "Creating coins...\n" << endl; |
|||
|
|||
for(size_t i = 0; i < 5; i++) { |
|||
addrs.push_back(libzerocash::Address::CreateNewRandomAddress()); |
|||
coins.push_back(libzerocash::Coin(addrs.at(i).getPublicAddress(), i)); |
|||
} |
|||
|
|||
cout << "Successfully created coins.\n" << endl; |
|||
|
|||
vector<std::vector<bool>> coinValues(coins.size()); |
|||
|
|||
vector<bool> temp_comVal(ZC_CM_SIZE * 8); |
|||
for(size_t i = 0; i < coinValues.size(); i++) { |
|||
libzerocash::convertBytesVectorToVector(coins.at(i).getCoinCommitment().getCommitmentValue(), temp_comVal); |
|||
coinValues.at(i) = temp_comVal; |
|||
libzerocash::printVectorAsHex(coinValues.at(i)); |
|||
} |
|||
|
|||
cout << "Creating Merkle Tree...\n" << endl; |
|||
|
|||
libzerocash::IncrementalMerkleTree merkleTree(64); |
|||
vector<bool> root; |
|||
merkleTree.getRootValue(root); |
|||
cout << "Root: "; |
|||
libzerocash::printVectorAsHex(root); |
|||
cout << endl; |
|||
|
|||
cout << "Successfully created Merkle Tree.\n" << endl; |
|||
|
|||
cout << "Copying and pruning Merkle Tree...\n" << endl; |
|||
libzerocash::IncrementalMerkleTree copyTree = merkleTree; |
|||
copyTree.prune(); |
|||
|
|||
cout << "Obtaining compact representation and reconstituting tree...\n" << endl; |
|||
libzerocash::IncrementalMerkleTreeCompact compactTree = merkleTree.getCompactRepresentation(); |
|||
|
|||
cout << "Compact representation vector: "; |
|||
libzerocash::printVector(compactTree.getHashList()); |
|||
|
|||
libzerocash::IncrementalMerkleTree reconstitutedTree(compactTree); |
|||
reconstitutedTree.getRootValue(root); |
|||
cout << "New root: "; |
|||
libzerocash::printVectorAsHex(root); |
|||
cout << endl; |
|||
|
|||
reconstitutedTree.insertVector(coinValues); |
|||
merkleTree.insertVector(coinValues); |
|||
|
|||
reconstitutedTree.getRootValue(root); |
|||
cout << "New root (added a bunch more): "; |
|||
libzerocash::printVectorAsHex(root); |
|||
cout << endl; |
|||
|
|||
merkleTree.getRootValue(root); |
|||
cout << "Old root (added a bunch more): "; |
|||
libzerocash::printVectorAsHex(root); |
|||
cout << endl; |
|||
|
|||
merkle_authentication_path witness(16); |
|||
std::vector<bool> index; |
|||
libzerocash::convertIntToVector(3, index); |
|||
if (merkleTree.getWitness(index, witness) == false) { |
|||
BOOST_ERROR("Witness generation failed."); |
|||
} |
|||
|
|||
cout << "Successfully created witness.\n" << endl; |
|||
|
|||
cout << "Witness: " << endl; |
|||
for(size_t i = 0; i < witness.size(); i++) { |
|||
libzerocash::printVectorAsHex(witness.at(i)); |
|||
} |
|||
cout << "\n" << endl; |
|||
|
|||
vector<bool> wit1(CSHA256::OUTPUT_SIZE * 8); |
|||
vector<bool> wit2(CSHA256::OUTPUT_SIZE * 8); |
|||
vector<bool> wit3(CSHA256::OUTPUT_SIZE * 8); |
|||
vector<bool> inter_1(CSHA256::OUTPUT_SIZE * 8); |
|||
vector<bool> inter_2(CSHA256::OUTPUT_SIZE * 8); |
|||
std::vector<bool> zeros(CSHA256::OUTPUT_SIZE * 8, 0); |
|||
|
|||
wit1 = coinValues.at(2); |
|||
libzerocash::hashVectors(coinValues.at(0), coinValues.at(1), wit2); |
|||
libzerocash::hashVectors(coinValues.at(4), zeros, inter_1); |
|||
inter_2 = zeros; |
|||
libzerocash::hashVectors(inter_1, inter_2, wit3); |
|||
|
|||
BOOST_CHECK(witness.size() == 64); |
|||
for (size_t i = 0; i < 61; i++) { |
|||
BOOST_CHECK(witness.at(i) == zeros); |
|||
} |
|||
BOOST_CHECK( |
|||
(witness.at(61) == wit3) && |
|||
(witness.at(62) == wit2) && |
|||
(witness.at(63) == wit1) |
|||
); |
|||
} |
|||
|
|||
BOOST_AUTO_TEST_CASE( SimpleTxTest ) { |
|||
cout << "\nSIMPLE TRANSACTION TEST\n" << endl; |
|||
|
|||
libzerocash::timer_start("Param Generation"); |
|||
auto keypair = libzerocash::ZerocashParams::GenerateNewKeyPair(INCREMENTAL_MERKLE_TREE_DEPTH); |
|||
libzerocash::ZerocashParams p( |
|||
INCREMENTAL_MERKLE_TREE_DEPTH, |
|||
&keypair |
|||
); |
|||
libzerocash::timer_stop("Param Generation"); |
|||
|
|||
vector<libzerocash::Coin> coins; |
|||
vector<libzerocash::Address> addrs; |
|||
|
|||
cout << "Creating Addresses and Coins...\n" << endl; |
|||
for(size_t i = 0; i < 5; i++) { |
|||
addrs.push_back(libzerocash::Address::CreateNewRandomAddress()); |
|||
coins.push_back(libzerocash::Coin(addrs.at(i).getPublicAddress(), i)); |
|||
} |
|||
cout << "Successfully created address and coins.\n" << endl; |
|||
|
|||
cout << "Creating a Mint Transaction...\n" << endl; |
|||
libzerocash::MintTransaction minttx(coins.at(0)); |
|||
cout << "Successfully created a Mint Transaction.\n" << endl; |
|||
|
|||
cout << "Verifying a Mint Transaction...\n" << endl; |
|||
bool minttx_res = minttx.verify(); |
|||
|
|||
vector<std::vector<bool>> coinValues(5); |
|||
vector<bool> temp_comVal(ZC_CM_SIZE * 8); |
|||
for(size_t i = 0; i < coinValues.size(); i++) { |
|||
libzerocash::convertBytesVectorToVector(coins.at(i).getCoinCommitment().getCommitmentValue(), temp_comVal); |
|||
coinValues.at(i) = temp_comVal; |
|||
} |
|||
|
|||
cout << "Creating Merkle Tree...\n" << endl; |
|||
libzerocash::IncrementalMerkleTree merkleTree(coinValues, INCREMENTAL_MERKLE_TREE_DEPTH); |
|||
cout << "Successfully created Merkle Tree.\n" << endl; |
|||
|
|||
std::vector<bool> index; |
|||
|
|||
cout << "Creating Witness 1...\n" << endl; |
|||
merkle_authentication_path witness_1(INCREMENTAL_MERKLE_TREE_DEPTH); |
|||
libzerocash::convertIntToVector(1, index); |
|||
if (merkleTree.getWitness(index, witness_1) == false) { |
|||
BOOST_ERROR("Could not get witness"); |
|||
} |
|||
cout << "Successfully created Witness 1.\n" << endl; |
|||
|
|||
cout << "Creating Witness 2...\n" << endl; |
|||
merkle_authentication_path witness_2(INCREMENTAL_MERKLE_TREE_DEPTH); |
|||
libzerocash::convertIntToVector(3, index); |
|||
if (merkleTree.getWitness(index, witness_2) == false) { |
|||
cout << "Could not get witness" << endl; |
|||
} |
|||
cout << "Successfully created Witness 2.\n" << endl; |
|||
|
|||
cout << "Creating coins to spend...\n" << endl; |
|||
libzerocash::Address newAddress3 = libzerocash::Address::CreateNewRandomAddress(); |
|||
libzerocash::PublicAddress pubAddress3 = newAddress3.getPublicAddress(); |
|||
|
|||
libzerocash::Address newAddress4 = libzerocash::Address::CreateNewRandomAddress(); |
|||
libzerocash::PublicAddress pubAddress4 = newAddress4.getPublicAddress(); |
|||
|
|||
libzerocash::Coin c_1_new(pubAddress3, 2); |
|||
libzerocash::Coin c_2_new(pubAddress4, 2); |
|||
cout << "Successfully created coins to spend.\n" << endl; |
|||
|
|||
vector<bool> root_bv(ZC_ROOT_SIZE * 8); |
|||
merkleTree.getRootValue(root_bv); |
|||
vector<unsigned char> rt(ZC_ROOT_SIZE); |
|||
libzerocash::convertVectorToBytesVector(root_bv, rt); |
|||
|
|||
|
|||
vector<unsigned char> as(ZC_SIG_PK_SIZE, 'a'); |
|||
|
|||
cout << "Creating a pour transaction...\n" << endl; |
|||
libzerocash::PourTransaction pourtx(1, p, |
|||
rt, |
|||
coins.at(1), coins.at(3), |
|||
addrs.at(1), addrs.at(3), |
|||
1, 3, |
|||
witness_1, witness_2, |
|||
pubAddress3, pubAddress4, |
|||
0, |
|||
0, |
|||
as, |
|||
c_1_new, c_2_new); |
|||
cout << "Successfully created a pour transaction.\n" << endl; |
|||
|
|||
std::vector<unsigned char> pubkeyHash(ZC_SIG_PK_SIZE, 'a'); |
|||
|
|||
cout << "Verifying a pour transaction...\n" << endl; |
|||
bool pourtx_res = pourtx.verify(p, pubkeyHash, rt); |
|||
|
|||
BOOST_CHECK(minttx_res && pourtx_res); |
|||
} |
@ -1,188 +0,0 @@ |
|||
/** @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, |
|||
<https://eprint.iacr.org/2014/349>
|
|||
|
|||
***************************************************************************** |
|||
* @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<typename FieldT> |
|||
class zerocash_pour_gadget : public gadget<FieldT> { |
|||
public: |
|||
size_t tree_depth; |
|||
|
|||
pb_variable_array<FieldT> input_as_field_elements; /* R1CS input */ |
|||
pb_variable_array<FieldT> input_as_bits; /* unpacked R1CS input */ |
|||
std::shared_ptr<multipacking_gadget<FieldT> > unpack_inputs; |
|||
|
|||
/* individual components of the unpacked R1CS input */ |
|||
std::shared_ptr<digest_variable<FieldT> > merkle_tree_root_variable; |
|||
std::vector<std::shared_ptr<digest_variable<FieldT> > > old_coin_serial_number_variables; |
|||
pb_variable_array<FieldT> old_coin_enforce_commitment; |
|||
std::vector<std::shared_ptr<digest_variable<FieldT> > > new_coin_commitment_variables; |
|||
pb_variable_array<FieldT> public_old_value_variable; |
|||
pb_variable_array<FieldT> public_new_value_variable; |
|||
std::shared_ptr<digest_variable<FieldT> > signature_public_key_hash_variable; |
|||
std::vector<std::shared_ptr<digest_variable<FieldT> > > mac_of_signature_public_key_hash_variables; |
|||
|
|||
/* TODO */ |
|||
pb_variable<FieldT> zero; |
|||
|
|||
std::vector<pb_variable_array<FieldT> > new_address_public_key_variables; |
|||
std::vector<pb_variable_array<FieldT> > old_address_secret_key_variables; |
|||
std::vector<pb_variable_array<FieldT> > new_address_commitment_nonce_variables; |
|||
std::vector<pb_variable_array<FieldT> > old_address_commitment_nonce_variables; |
|||
std::vector<pb_variable_array<FieldT> > new_coin_serial_number_nonce_variables; |
|||
std::vector<pb_variable_array<FieldT> > old_coin_serial_number_nonce_variables; |
|||
std::vector<pb_variable_array<FieldT> > new_coin_value_variables; |
|||
std::vector<pb_variable_array<FieldT> > old_coin_value_variables; |
|||
|
|||
std::vector<std::shared_ptr<block_variable<FieldT> > > prf_for_old_coin_serial_number_input_variables; |
|||
std::vector<std::shared_ptr<sha256_compression_function_gadget<FieldT> > > prfs_for_old_coin_serial_numbers; // (C)
|
|||
|
|||
std::vector<std::shared_ptr<digest_variable<FieldT> > > old_address_public_key_variables; |
|||
std::vector<std::shared_ptr<block_variable<FieldT> > > prf_for_old_address_public_key_input_variables; |
|||
std::vector<std::shared_ptr<sha256_compression_function_gadget<FieldT> > > prfs_for_old_address_public_keys; // (B)
|
|||
|
|||
std::vector<std::shared_ptr<digest_variable<FieldT> > > commitments_to_old_address_public_keys; |
|||
std::vector<std::shared_ptr<block_variable<FieldT> > > commit_to_old_address_public_key_input_variables; |
|||
std::vector<std::shared_ptr<sha256_compression_function_gadget<FieldT> > > commit_to_old_address_public_keys; // (D0)
|
|||
|
|||
std::vector<std::shared_ptr<digest_variable<FieldT> > > old_coin_value_commitment_nonces; |
|||
std::vector<std::shared_ptr<block_variable<FieldT> > > commit_to_old_coin_value_commitment_nonce_input_variables; |
|||
std::vector<std::shared_ptr<sha256_compression_function_gadget<FieldT> > > commit_to_old_coin_value_commitment_nonces; // (D1)
|
|||
|
|||
std::vector<std::shared_ptr<digest_variable<FieldT> > > old_coin_commitment_variables; |
|||
std::vector<std::shared_ptr<block_variable<FieldT> > > compute_old_coin_commitment_input_variables; |
|||
std::vector<std::shared_ptr<sha256_compression_function_gadget<FieldT> > > compute_old_coin_commitments; // (D2)
|
|||
|
|||
std::vector<std::shared_ptr<digest_variable<FieldT> > > commitments_to_new_address_public_keys; |
|||
std::vector<std::shared_ptr<block_variable<FieldT> > > commit_to_new_address_public_key_input_variables; |
|||
std::vector<std::shared_ptr<sha256_compression_function_gadget<FieldT> > > commit_to_new_address_public_keys; // (E0)
|
|||
|
|||
std::vector<std::shared_ptr<digest_variable<FieldT> > > new_coin_value_commitment_nonces; |
|||
std::vector<std::shared_ptr<block_variable<FieldT> > > commit_to_new_coin_value_commitment_nonce_input_variables; |
|||
std::vector<std::shared_ptr<sha256_compression_function_gadget<FieldT> > > commit_to_new_coin_value_commitment_nonces; // (E1)
|
|||
|
|||
std::vector<std::shared_ptr<block_variable<FieldT> > > compute_new_coin_commitment_input_variables; |
|||
std::vector<std::shared_ptr<sha256_compression_function_gadget<FieldT> > > compute_new_coin_commitments; // (E2)
|
|||
|
|||
std::vector<std::shared_ptr<block_variable<FieldT> > > prf_for_macs_of_signature_public_key_hash_input_variables; |
|||
std::vector<std::shared_ptr<sha256_compression_function_gadget<FieldT> > > prfs_for_macs_of_signature_public_key_hash; // (F)
|
|||
|
|||
std::vector<pb_variable_array<FieldT> > old_coin_merkle_tree_position_variables; |
|||
std::vector<std::shared_ptr<merkle_authentication_path_variable<FieldT, sha256_two_to_one_hash_gadget<FieldT> > > > old_coin_authentication_path_variables; |
|||
std::vector<std::shared_ptr<merkle_tree_check_read_gadget<FieldT, sha256_two_to_one_hash_gadget<FieldT> > > > old_coin_commitments_in_tree; // (A)
|
|||
|
|||
size_t num_old_coins; |
|||
size_t num_new_coins; |
|||
|
|||
zerocash_pour_gadget(protoboard<FieldT> &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<merkle_authentication_path> &old_coin_authentication_paths, |
|||
const std::vector<size_t> &old_coin_merkle_tree_positions, |
|||
const bit_vector &merkle_tree_root, |
|||
const std::vector<bit_vector> &new_address_public_keys, |
|||
const std::vector<bit_vector> &old_address_secret_keys, |
|||
const std::vector<bit_vector> &new_address_commitment_nonces, |
|||
const std::vector<bit_vector> &old_address_commitment_nonces, |
|||
const std::vector<bit_vector> &new_coin_serial_number_nonces, |
|||
const std::vector<bit_vector> &old_coin_serial_number_nonces, |
|||
const std::vector<bit_vector> &new_coin_values, |
|||
const bit_vector &public_old_value, |
|||
const bit_vector &public_new_value, |
|||
const std::vector<bit_vector> &old_coin_values, |
|||
const bit_vector &signature_public_key_hash); |
|||
}; |
|||
|
|||
template<typename FieldT> |
|||
r1cs_primary_input<FieldT> 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<bit_vector> &old_coin_serial_numbers, |
|||
const std::vector<bit_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<bit_vector> &signature_public_key_hash_macs); |
|||
|
|||
} // libzerocash
|
|||
|
|||
#include "zerocash_pour_gadget.tcc" |
|||
|
|||
#endif // ZEROCASH_POUR_GADGET_HPP_
|
@ -1,503 +0,0 @@ |
|||
/** @file |
|||
***************************************************************************** |
|||
|
|||
Implementation of interfaces for the Zerocash Pour gadget. |
|||
|
|||
See zerocash_pour_gadget.hpp . |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libzerocash, developed by the Zerocash |
|||
* project and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#include "algebra/fields/field_utils.hpp" |
|||
|
|||
namespace libzerocash { |
|||
|
|||
template<typename FieldT> |
|||
zerocash_pour_gadget<FieldT>::zerocash_pour_gadget(protoboard<FieldT> &pb, |
|||
const size_t num_old_coins, |
|||
const size_t num_new_coins, |
|||
const size_t tree_depth, |
|||
const std::string &annotation_prefix) : |
|||
gadget<FieldT>(pb, FMT(annotation_prefix, " zerocash_pour_gadget")), |
|||
tree_depth(tree_depth), |
|||
num_old_coins(num_old_coins), |
|||
num_new_coins(num_new_coins) |
|||
{ |
|||
/* allocate packed inputs */ |
|||
const size_t input_size_in_bits = sha256_digest_len + num_old_coins*sha256_digest_len + num_new_coins*sha256_digest_len + (coin_value_length * 2) + (num_old_coins + 1) * sha256_digest_len; |
|||
const size_t input_size_in_field_elements = div_ceil(input_size_in_bits, FieldT::capacity()); |
|||
input_as_field_elements.allocate(pb, input_size_in_field_elements, FMT(annotation_prefix, " input_as_field_elements")); |
|||
this->pb.set_input_sizes(input_size_in_field_elements); |
|||
|
|||
/* allocate inputs */ |
|||
merkle_tree_root_variable.reset(new digest_variable<FieldT>(pb, sha256_digest_len, FMT(annotation_prefix, " merkle_tree_root_variable"))); |
|||
|
|||
old_coin_enforce_commitment.allocate(pb, num_old_coins, FMT(annotation_prefix, " old_coin_enforce_commitment")); |
|||
old_coin_serial_number_variables.resize(num_old_coins); |
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
old_coin_serial_number_variables[i].reset(new digest_variable<FieldT>(pb, sha256_digest_len, FMT(annotation_prefix, " old_coin_serial_number_variables_%zu", i))); |
|||
} |
|||
|
|||
new_coin_commitment_variables.resize(num_new_coins); |
|||
for (size_t i = 0; i < num_new_coins; ++i) |
|||
{ |
|||
new_coin_commitment_variables[i].reset(new digest_variable<FieldT>(pb, sha256_digest_len, FMT(annotation_prefix, " new_coin_commitment_variables_%zu", i))); |
|||
} |
|||
|
|||
public_old_value_variable.allocate(pb, coin_value_length, FMT(annotation_prefix, " public_old_value_variable")); |
|||
public_new_value_variable.allocate(pb, coin_value_length, FMT(annotation_prefix, " public_new_value_variable")); |
|||
signature_public_key_hash_variable.reset(new digest_variable<FieldT>(pb, sha256_digest_len, FMT(annotation_prefix, " signature_public_key_hash"))); |
|||
|
|||
mac_of_signature_public_key_hash_variables.resize(num_old_coins); |
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
mac_of_signature_public_key_hash_variables[i].reset(new digest_variable<FieldT>(pb, sha256_digest_len, FMT(annotation_prefix, " mac_of_signature_public_key_hash_variables_%zu", i))); |
|||
} |
|||
|
|||
/* do the multipacking */ |
|||
input_as_bits.insert(input_as_bits.end(), merkle_tree_root_variable->bits.begin(), merkle_tree_root_variable->bits.end()); |
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
input_as_bits.insert(input_as_bits.end(), old_coin_serial_number_variables[i]->bits.begin(), old_coin_serial_number_variables[i]->bits.end()); |
|||
} |
|||
for (size_t i = 0; i < num_new_coins; ++i) |
|||
{ |
|||
input_as_bits.insert(input_as_bits.end(), new_coin_commitment_variables[i]->bits.begin(), new_coin_commitment_variables[i]->bits.end()); |
|||
} |
|||
input_as_bits.insert(input_as_bits.end(), public_old_value_variable.begin(), public_old_value_variable.end()); |
|||
input_as_bits.insert(input_as_bits.end(), public_new_value_variable.begin(), public_new_value_variable.end()); |
|||
input_as_bits.insert(input_as_bits.end(), signature_public_key_hash_variable->bits.begin(), signature_public_key_hash_variable->bits.end()); |
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
input_as_bits.insert(input_as_bits.end(), mac_of_signature_public_key_hash_variables[i]->bits.begin(), mac_of_signature_public_key_hash_variables[i]->bits.end()); |
|||
} |
|||
assert(input_as_bits.size() == input_size_in_bits); |
|||
unpack_inputs.reset(new multipacking_gadget<FieldT>(this->pb, input_as_bits, input_as_field_elements, FieldT::capacity(), FMT(this->annotation_prefix, " unpack_inputs"))); |
|||
|
|||
pb_linear_combination_array<FieldT> IV = SHA256_default_IV(pb); |
|||
zero.allocate(this->pb, FMT(this->annotation_prefix, " zero")); /* TODO */ |
|||
|
|||
/* allocate witness */ |
|||
new_address_public_key_variables.resize(num_new_coins); |
|||
new_address_commitment_nonce_variables.resize(num_new_coins); |
|||
new_coin_serial_number_nonce_variables.resize(num_new_coins); |
|||
new_coin_value_variables.resize(num_new_coins); |
|||
for (size_t i = 0; i < num_new_coins; ++i) |
|||
{ |
|||
new_address_public_key_variables[i].allocate(pb, address_public_key_length, FMT(annotation_prefix, " new_address_public_key_variables_%zu", i)); |
|||
new_address_commitment_nonce_variables[i].allocate(pb, address_commitment_nonce_length, FMT(annotation_prefix, " new_address_commitment_nonce_variables_%zu", i)); |
|||
new_coin_serial_number_nonce_variables[i].allocate(pb, serial_number_nonce_length, FMT(annotation_prefix, " new_coin_serial_number_nonce_variables_%zu", i)); |
|||
new_coin_value_variables[i].allocate(pb, coin_value_length, FMT(annotation_prefix, " new_coin_value_variables_%zu", i)); |
|||
} |
|||
|
|||
old_address_secret_key_variables.resize(num_old_coins); |
|||
old_address_commitment_nonce_variables.resize(num_old_coins); |
|||
old_coin_serial_number_nonce_variables.resize(num_old_coins); |
|||
old_coin_value_variables.resize(num_old_coins); |
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
old_address_secret_key_variables[i].allocate(pb, address_secret_key_length, FMT(annotation_prefix, " old_address_secret_key_variables_%zu", i)); |
|||
old_address_commitment_nonce_variables[i].allocate(pb, address_commitment_nonce_length, FMT(annotation_prefix, " old_address_commitment_nonce_variables_%zu", i)); |
|||
old_coin_serial_number_nonce_variables[i].allocate(pb, serial_number_nonce_length, FMT(annotation_prefix, " old_coin_serial_number_nonce_variables_%zu", i)); |
|||
old_coin_value_variables[i].allocate(pb, coin_value_length, FMT(annotation_prefix, " old_coin_value_variables_%zu", i)); |
|||
} |
|||
|
|||
/* do the actual hashing */ |
|||
pb_variable_array<FieldT> zero_one; |
|||
zero_one.emplace_back(zero); |
|||
zero_one.emplace_back(ONE); |
|||
|
|||
prf_for_old_coin_serial_number_input_variables.resize(num_old_coins); |
|||
prfs_for_old_coin_serial_numbers.resize(num_old_coins); |
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
/* (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]) */ |
|||
prf_for_old_coin_serial_number_input_variables[i].reset(new block_variable<FieldT>(pb, { |
|||
old_address_secret_key_variables[i], |
|||
zero_one, |
|||
pb_variable_array<FieldT>(old_coin_serial_number_nonce_variables[i].begin(), |
|||
old_coin_serial_number_nonce_variables[i].begin() + truncated_serial_number_length) }, |
|||
FMT(annotation_prefix, " prf_for_old_coin_serial_number_input_variables_%zu", i))); |
|||
prfs_for_old_coin_serial_numbers[i].reset(new sha256_compression_function_gadget<FieldT>(pb, IV, prf_for_old_coin_serial_number_input_variables[i]->bits, *old_coin_serial_number_variables[i], FMT(annotation_prefix, " prfs_for_old_coin_serial_numbers_%zu", i))); |
|||
} |
|||
|
|||
old_address_public_key_variables.resize(num_old_coins); |
|||
prf_for_old_address_public_key_input_variables.resize(num_old_coins); |
|||
prfs_for_old_address_public_keys.resize(num_old_coins); |
|||
|
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
old_address_public_key_variables[i].reset(new digest_variable<FieldT>(pb, sha256_digest_len, FMT(annotation_prefix, " old_address_public_key_variables_%zu", i))); |
|||
|
|||
/* (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 */ |
|||
pb_variable_array<FieldT> addr_pk_pad(address_public_key_padding_length, zero); |
|||
prf_for_old_address_public_key_input_variables[i].reset(new block_variable<FieldT>(pb, |
|||
{ old_address_secret_key_variables[i], addr_pk_pad }, |
|||
FMT(annotation_prefix, " prf_for_old_address_public_key_input_variables_%zu", i))); |
|||
prfs_for_old_address_public_keys[i].reset(new sha256_compression_function_gadget<FieldT>(pb, |
|||
IV, |
|||
prf_for_old_address_public_key_input_variables[i]->bits, |
|||
*old_address_public_key_variables[i], |
|||
FMT(annotation_prefix, " prfs_for_old_address_public_keys_%zu", i))); |
|||
} |
|||
|
|||
commitments_to_old_address_public_keys.resize(num_old_coins); |
|||
commit_to_old_address_public_key_input_variables.resize(num_old_coins); |
|||
commit_to_old_address_public_keys.resize(num_old_coins); |
|||
|
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
/* (D0) commitments_to_old_address_public_keys[i] = H(old_address_public_key_variables[i] || old_coin_serial_number_nonce_variables[i]) */ |
|||
commitments_to_old_address_public_keys[i].reset(new digest_variable<FieldT>(pb, sha256_digest_len, FMT(annotation_prefix, " commitments_to_old_address_public_keys_%zu", i))); |
|||
commit_to_old_address_public_key_input_variables[i].reset(new block_variable<FieldT>(pb, { old_address_public_key_variables[i]->bits, old_coin_serial_number_nonce_variables[i] }, FMT(annotation_prefix, " commit_to_old_address_public_key_input_variables_%zu", i))); |
|||
commit_to_old_address_public_keys[i].reset(new sha256_compression_function_gadget<FieldT>(pb, IV, commit_to_old_address_public_key_input_variables[i]->bits, *commitments_to_old_address_public_keys[i], FMT(annotation_prefix, " commit_to_old_address_public_keys_%zu", i))); |
|||
} |
|||
|
|||
old_coin_value_commitment_nonces.resize(num_old_coins); |
|||
commit_to_old_coin_value_commitment_nonce_input_variables.resize(num_old_coins); |
|||
commit_to_old_coin_value_commitment_nonces.resize(num_old_coins); |
|||
|
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
/* (D1) old_coin_value_commitment_nonces[i] = |
|||
H(old_address_commitment_nonce_variables[i] || commitments_to_old_address_public_keys[i] [0..128]) */ |
|||
old_coin_value_commitment_nonces[i].reset(new digest_variable<FieldT>(pb, sha256_digest_len, FMT(annotation_prefix, " old_coin_value_commitment_nonces_%zu", i))); |
|||
commit_to_old_coin_value_commitment_nonce_input_variables[i].reset(new block_variable<FieldT>(pb, { old_address_commitment_nonce_variables[i], pb_variable_array<FieldT>(commitments_to_old_address_public_keys[i]->bits.begin(), commitments_to_old_address_public_keys[i]->bits.begin()+ truncated_coin_commitment_length) }, FMT(annotation_prefix, " commit_to_old_coin_value_commitment_nonce_input_variables_%zu", i))); |
|||
commit_to_old_coin_value_commitment_nonces[i].reset(new sha256_compression_function_gadget<FieldT>(pb, IV, commit_to_old_coin_value_commitment_nonce_input_variables[i]->bits, *old_coin_value_commitment_nonces[i], FMT(annotation_prefix, " commit_to_old_coin_value_commitment_nonces_%zu", i))); |
|||
} |
|||
|
|||
pb_variable_array<FieldT> coincomm_pad(coin_commitment_padding_length, zero); |
|||
old_coin_commitment_variables.resize(num_old_coins); |
|||
compute_old_coin_commitment_input_variables.resize(num_old_coins); |
|||
compute_old_coin_commitments.resize(num_old_coins); |
|||
|
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
/* (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, as k = old_coin_value_commitment_nonces[i] is an output of a |
|||
statistically hiding commitment scheme. */ |
|||
old_coin_commitment_variables[i].reset(new digest_variable<FieldT>(pb, sha256_digest_len, FMT(annotation_prefix, " old_coin_commitment_variables_%zu", i))); |
|||
compute_old_coin_commitment_input_variables[i].reset(new block_variable<FieldT>(pb, { old_coin_value_commitment_nonces[i]->bits, coincomm_pad, old_coin_value_variables[i] }, FMT(annotation_prefix, " compute_old_coin_commitment_input_variables_%zu", i))); |
|||
compute_old_coin_commitments[i].reset(new sha256_compression_function_gadget<FieldT>(pb, IV, compute_old_coin_commitment_input_variables[i]->bits, *old_coin_commitment_variables[i], FMT(annotation_prefix, " compute_old_coin_commitment_%zu", i))); |
|||
} |
|||
|
|||
commitments_to_new_address_public_keys.resize(num_new_coins); |
|||
commit_to_new_address_public_key_input_variables.resize(num_new_coins); |
|||
commit_to_new_address_public_keys.resize(num_new_coins); |
|||
|
|||
for (size_t i = 0; i < num_new_coins; ++i) |
|||
{ |
|||
/* (E0) commitments_to_new_address_public_keys[i] = H(new_address_public_key_variables[i] || new_coin_serial_number_nonce_variables[i]) */ |
|||
commitments_to_new_address_public_keys[i].reset(new digest_variable<FieldT>(pb, sha256_digest_len, FMT(annotation_prefix, " commitments_to_new_address_public_keys_%zu", i))); |
|||
commit_to_new_address_public_key_input_variables[i].reset(new block_variable<FieldT>(pb, { new_address_public_key_variables[i], new_coin_serial_number_nonce_variables[i] }, FMT(annotation_prefix, " commit_to_new_address_public_key_input_variables_%zu", i))); |
|||
commit_to_new_address_public_keys[i].reset(new sha256_compression_function_gadget<FieldT>(pb, IV, commit_to_new_address_public_key_input_variables[i]->bits, *commitments_to_new_address_public_keys[i], FMT(annotation_prefix, " commit_to_new_address_public_keys_%zu", i))); |
|||
} |
|||
|
|||
new_coin_value_commitment_nonces.resize(num_new_coins); |
|||
commit_to_new_coin_value_commitment_nonce_input_variables.resize(num_new_coins); |
|||
commit_to_new_coin_value_commitment_nonces.resize(num_new_coins); |
|||
for (size_t i = 0; i < num_new_coins; ++i) |
|||
{ |
|||
/* (E1) new_coin_value_commitment_nonces[i] = |
|||
H(new_address_commitment_nonce_variables[i] || commitments_to_new_address_public_keys[i] [0..128]) */ |
|||
new_coin_value_commitment_nonces[i].reset(new digest_variable<FieldT>(pb, sha256_digest_len, FMT(annotation_prefix, " new_coin_value_commitment_nonces_%zu", i))); |
|||
commit_to_new_coin_value_commitment_nonce_input_variables[i].reset(new block_variable<FieldT>(pb, { new_address_commitment_nonce_variables[i], pb_variable_array<FieldT>(commitments_to_new_address_public_keys[i]->bits.begin(), commitments_to_new_address_public_keys[i]->bits.begin()+ truncated_coin_commitment_length) }, FMT(annotation_prefix, " commit_to_new_coin_value_commitment_nonce_input_variables_%zu", i))); |
|||
commit_to_new_coin_value_commitment_nonces[i].reset(new sha256_compression_function_gadget<FieldT>(pb, IV, commit_to_new_coin_value_commitment_nonce_input_variables[i]->bits, *new_coin_value_commitment_nonces[i], FMT(annotation_prefix, " commit_to_new_coin_value_commitment_nonces_%zu", i))); |
|||
} |
|||
|
|||
compute_new_coin_commitment_input_variables.resize(num_new_coins); |
|||
compute_new_coin_commitments.resize(num_new_coins); |
|||
|
|||
for (size_t i = 0; i < num_new_coins; ++i) |
|||
{ |
|||
/* (E2) new_coin_commitment_variables[i] = COMM_s(new_coin_value_variables[i] || new_coin_value_commitment_nonces[i]) |
|||
H(new_coin_value_commitment_nonces[i] || 0^{192} || new_coin_value_variables[i]) */ |
|||
compute_new_coin_commitment_input_variables[i].reset(new block_variable<FieldT>(pb, { new_coin_value_commitment_nonces[i]->bits, coincomm_pad, new_coin_value_variables[i] }, FMT(annotation_prefix, " compute_new_coin_commitment_input_variables_%zu", i))); |
|||
compute_new_coin_commitments[i].reset(new sha256_compression_function_gadget<FieldT>(pb, IV, compute_new_coin_commitment_input_variables[i]->bits, *new_coin_commitment_variables[i], FMT(annotation_prefix, " compute_new_coin_commitment_%zu", i))); |
|||
} |
|||
|
|||
/* compute signature public key macs */ |
|||
prf_for_macs_of_signature_public_key_hash_input_variables.resize(num_old_coins); |
|||
prfs_for_macs_of_signature_public_key_hash.resize(num_old_coins); |
|||
const size_t truncated_signature_public_key_hash_length = indexed_signature_public_key_hash_length - log2(num_old_coins); |
|||
|
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
/* (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. */ |
|||
pb_variable_array<FieldT> prf_padding; |
|||
prf_padding.emplace_back(ONE); |
|||
prf_padding.emplace_back(zero); |
|||
|
|||
for (size_t j = 0; j < log2(num_old_coins); ++j) |
|||
{ |
|||
prf_padding.emplace_back((i >> (log2(num_old_coins) - j - 1)) & 1 ? ONE : zero); |
|||
} |
|||
|
|||
prf_for_macs_of_signature_public_key_hash_input_variables[i].reset(new block_variable<FieldT>(pb, { old_address_secret_key_variables[i], prf_padding, pb_variable_array<FieldT>(signature_public_key_hash_variable->bits.begin(), signature_public_key_hash_variable->bits.begin()+truncated_signature_public_key_hash_length) }, FMT(annotation_prefix, " prf_for_macs_of_signature_public_key_hash_input_variables_%zu", i))); |
|||
prfs_for_macs_of_signature_public_key_hash[i].reset(new sha256_compression_function_gadget<FieldT>(pb, IV, prf_for_macs_of_signature_public_key_hash_input_variables[i]->bits, *mac_of_signature_public_key_hash_variables[i], FMT(annotation_prefix, " prfs_for_macs_of_signature_public_key_hash_%zu", i))); |
|||
} |
|||
|
|||
/* prove membership in the Merkle tree*/ |
|||
old_coin_merkle_tree_position_variables.resize(num_old_coins); |
|||
old_coin_authentication_path_variables.resize(num_old_coins); |
|||
old_coin_commitments_in_tree.resize(num_old_coins); |
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
/* (A) old_coin_commitment_variables[i] appears on path old_coin_authentication_paths[i] |
|||
to merkle_tree_root_variable */ |
|||
old_coin_merkle_tree_position_variables[i].allocate(pb, tree_depth, FMT(annotation_prefix, " old_coin_merkle_tree_position_variables_%zu", i)); |
|||
old_coin_authentication_path_variables[i].reset(new merkle_authentication_path_variable<FieldT, sha256_two_to_one_hash_gadget<FieldT> >(pb, tree_depth, FMT(annotation_prefix, " old_coin_authentication_path_variables_%zu", i))); |
|||
old_coin_commitments_in_tree[i].reset(new merkle_tree_check_read_gadget<FieldT, sha256_two_to_one_hash_gadget<FieldT> >( |
|||
pb, tree_depth, old_coin_merkle_tree_position_variables[i], *old_coin_commitment_variables[i], *merkle_tree_root_variable, |
|||
*old_coin_authentication_path_variables[i], old_coin_enforce_commitment[i], FMT(annotation_prefix, " old_coin_commitments_in_tree_%zu", i))); |
|||
} |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void zerocash_pour_gadget<FieldT>::generate_r1cs_constraints() |
|||
{ |
|||
generate_r1cs_equals_const_constraint<FieldT>(this->pb, zero, FieldT::zero(), FMT(this->annotation_prefix, " zero")); |
|||
|
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
prfs_for_old_coin_serial_numbers[i]->generate_r1cs_constraints(); |
|||
prfs_for_old_address_public_keys[i]->generate_r1cs_constraints(); |
|||
commit_to_old_address_public_keys[i]->generate_r1cs_constraints(); |
|||
commit_to_old_coin_value_commitment_nonces[i]->generate_r1cs_constraints(); |
|||
compute_old_coin_commitments[i]->generate_r1cs_constraints(); |
|||
old_coin_commitments_in_tree[i]->generate_r1cs_constraints(); |
|||
prfs_for_macs_of_signature_public_key_hash[i]->generate_r1cs_constraints(); |
|||
|
|||
for (size_t j = 0; j < tree_depth; ++j) |
|||
{ |
|||
generate_boolean_r1cs_constraint<FieldT>(this->pb, old_coin_merkle_tree_position_variables[i][j], FMT(this->annotation_prefix, " old_coin_merkle_tree_position_variables_%zu_%zu", i, j)); |
|||
} |
|||
} |
|||
|
|||
for (size_t i = 0; i < num_new_coins; ++i) |
|||
{ |
|||
commit_to_new_address_public_keys[i]->generate_r1cs_constraints(); |
|||
commit_to_new_coin_value_commitment_nonces[i]->generate_r1cs_constraints(); |
|||
compute_new_coin_commitments[i]->generate_r1cs_constraints(); |
|||
} |
|||
|
|||
unpack_inputs->generate_r1cs_constraints(true); |
|||
|
|||
/* ensure bitness of all values */ |
|||
for (size_t j = 0; j < coin_value_length; ++j) |
|||
{ |
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
generate_boolean_r1cs_constraint<FieldT>(this->pb, old_coin_value_variables[i][j], FMT(this->annotation_prefix, " old_coin_value_variables_%zu_%zu", i, j)); |
|||
} |
|||
for (size_t i = 0; i < num_new_coins; ++i) |
|||
{ |
|||
generate_boolean_r1cs_constraint<FieldT>(this->pb, new_coin_value_variables[i][j], FMT(this->annotation_prefix, " new_coin_value_variables_%zu_%zu", i, j)); |
|||
} |
|||
} |
|||
|
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
generate_boolean_r1cs_constraint<FieldT>(this->pb, old_coin_enforce_commitment[i], FMT(this->annotation_prefix, " old_coin_enforce_commitment_%zu", i)); |
|||
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>( |
|||
pb_packing_sum<FieldT>(pb_variable_array<FieldT>(old_coin_value_variables[i].rbegin(), old_coin_value_variables[i].rend())), |
|||
1 - old_coin_enforce_commitment[i], |
|||
0), FMT(this->annotation_prefix, " enforce_%zu", i)); |
|||
} |
|||
|
|||
/* check the balance equation */ |
|||
linear_combination<FieldT> old_packed_value; |
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
old_packed_value = old_packed_value + pb_packing_sum<FieldT>(pb_variable_array<FieldT>(old_coin_value_variables[i].rbegin(), old_coin_value_variables[i].rend())); |
|||
} |
|||
old_packed_value = old_packed_value + pb_packing_sum<FieldT>(pb_variable_array<FieldT>(public_old_value_variable.rbegin(), public_old_value_variable.rend())); |
|||
|
|||
linear_combination<FieldT> new_packed_value; |
|||
for (size_t i = 0; i < num_new_coins; ++i) |
|||
{ |
|||
new_packed_value = new_packed_value + pb_packing_sum<FieldT>(pb_variable_array<FieldT>(new_coin_value_variables[i].rbegin(), new_coin_value_variables[i].rend())); |
|||
} |
|||
new_packed_value = new_packed_value + pb_packing_sum<FieldT>(pb_variable_array<FieldT>(public_new_value_variable.rbegin(), public_new_value_variable.rend())); |
|||
|
|||
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(1, old_packed_value, new_packed_value), FMT(this->annotation_prefix, " balance")); |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void zerocash_pour_gadget<FieldT>::generate_r1cs_witness(const std::vector<merkle_authentication_path> &old_coin_authentication_paths, |
|||
const std::vector<size_t> &old_coin_merkle_tree_positions, |
|||
const bit_vector &merkle_tree_root, |
|||
const std::vector<bit_vector> &new_address_public_keys, |
|||
const std::vector<bit_vector> &old_address_secret_keys, |
|||
const std::vector<bit_vector> &new_address_commitment_nonces, |
|||
const std::vector<bit_vector> &old_address_commitment_nonces, |
|||
const std::vector<bit_vector> &new_coin_serial_number_nonces, |
|||
const std::vector<bit_vector> &old_coin_serial_number_nonces, |
|||
const std::vector<bit_vector> &new_coin_values, |
|||
const bit_vector &public_old_value, |
|||
const bit_vector &public_new_value, |
|||
const std::vector<bit_vector> &old_coin_values, |
|||
const bit_vector &signature_public_key_hash) |
|||
{ |
|||
/* fill in the auxiliary variables */ |
|||
this->pb.val(zero) = FieldT::zero(); |
|||
|
|||
/* fill in the witness */ |
|||
for (size_t i = 0; i < num_new_coins; ++i) |
|||
{ |
|||
new_address_public_key_variables[i].fill_with_bits(this->pb, new_address_public_keys[i]); |
|||
new_address_commitment_nonce_variables[i].fill_with_bits(this->pb, new_address_commitment_nonces[i]); |
|||
} |
|||
|
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
old_address_secret_key_variables[i].fill_with_bits(this->pb, old_address_secret_keys[i]); |
|||
old_address_commitment_nonce_variables[i].fill_with_bits(this->pb, old_address_commitment_nonces[i]); |
|||
} |
|||
|
|||
for (size_t i = 0; i < num_new_coins; ++i) |
|||
{ |
|||
new_coin_serial_number_nonce_variables[i].fill_with_bits(this->pb, new_coin_serial_number_nonces[i]); |
|||
new_coin_value_variables[i].fill_with_bits(this->pb, new_coin_values[i]); |
|||
} |
|||
|
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
this->pb.val(old_coin_enforce_commitment[i]) = FieldT::zero(); |
|||
old_coin_serial_number_nonce_variables[i].fill_with_bits(this->pb, old_coin_serial_number_nonces[i]); |
|||
old_coin_value_variables[i].fill_with_bits(this->pb, old_coin_values[i]); |
|||
|
|||
for (size_t j = 0; j < coin_value_length; ++j) |
|||
{ |
|||
if (old_coin_values[i][j]) { |
|||
// If any bit in the value is nonzero, the value is nonzero. |
|||
// Thus, the old coin must be committed in the tree. |
|||
this->pb.val(old_coin_enforce_commitment[i]) = FieldT::one(); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public_old_value_variable.fill_with_bits(this->pb, public_old_value); |
|||
public_new_value_variable.fill_with_bits(this->pb, public_new_value); |
|||
signature_public_key_hash_variable->generate_r1cs_witness(signature_public_key_hash); |
|||
|
|||
/* do the hashing */ |
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
prfs_for_old_coin_serial_numbers[i]->generate_r1cs_witness(); |
|||
prfs_for_old_address_public_keys[i]->generate_r1cs_witness(); |
|||
commit_to_old_address_public_keys[i]->generate_r1cs_witness(); |
|||
commit_to_old_coin_value_commitment_nonces[i]->generate_r1cs_witness(); |
|||
compute_old_coin_commitments[i]->generate_r1cs_witness(); |
|||
prfs_for_macs_of_signature_public_key_hash[i]->generate_r1cs_witness(); |
|||
} |
|||
|
|||
for (size_t i = 0; i < num_new_coins; ++i) |
|||
{ |
|||
commit_to_new_address_public_keys[i]->generate_r1cs_witness(); |
|||
commit_to_new_coin_value_commitment_nonces[i]->generate_r1cs_witness(); |
|||
compute_new_coin_commitments[i]->generate_r1cs_witness(); |
|||
} |
|||
|
|||
/* prove the membership in the Merkle tree */ |
|||
for (size_t i = 0; i < num_old_coins; ++i) |
|||
{ |
|||
/* (A) old_coin_commitment_variables[i] appears on path old_coin_authentication_paths[i] |
|||
to merkle_tree_root_variable */ |
|||
old_coin_merkle_tree_position_variables[i].fill_with_bits_of_ulong(this->pb, old_coin_merkle_tree_positions[i]); |
|||
old_coin_authentication_path_variables[i]->generate_r1cs_witness(old_coin_merkle_tree_positions[i], old_coin_authentication_paths[i]); |
|||
old_coin_commitments_in_tree[i]->generate_r1cs_witness(); |
|||
} |
|||
|
|||
/* pack the input */ |
|||
unpack_inputs->generate_r1cs_witness_from_bits(); |
|||
|
|||
#ifdef DEBUG |
|||
printf("input_as_field_elements according to witness map:\n"); |
|||
for (size_t i = 0; i < input_as_field_elements.size(); ++i) |
|||
{ |
|||
this->pb.val(input_as_field_elements[i]).print(); |
|||
} |
|||
#endif |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
r1cs_primary_input<FieldT> 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<bit_vector> &old_coin_serial_numbers, |
|||
const std::vector<bit_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<bit_vector> &signature_public_key_hash_macs) |
|||
{ |
|||
enter_block("Call to zerocash_pour_input_map"); |
|||
assert(merkle_tree_root.size() == sha256_digest_len); |
|||
assert(old_coin_serial_numbers.size() == num_old_coins); |
|||
for (auto &old_coin_serial_number : old_coin_serial_numbers) |
|||
{ |
|||
assert(old_coin_serial_number.size() == serial_number_length); |
|||
} |
|||
assert(new_coin_commitments.size() == num_new_coins); |
|||
for (auto &new_coin_commitment : new_coin_commitments) |
|||
{ |
|||
assert(new_coin_commitment.size() == coin_commitment_length); |
|||
} |
|||
assert(public_old_value.size() == coin_value_length); |
|||
assert(public_new_value.size() == coin_value_length); |
|||
assert(signature_public_key_hash.size() == sha256_digest_len); |
|||
assert(signature_public_key_hash_macs.size() == num_old_coins); |
|||
for (auto &signature_public_key_hash_mac : signature_public_key_hash_macs) |
|||
{ |
|||
assert(signature_public_key_hash_mac.size() == sha256_digest_len); |
|||
} |
|||
|
|||
bit_vector input_as_bits; |
|||
|
|||
input_as_bits.insert(input_as_bits.end(), merkle_tree_root.begin(), merkle_tree_root.end()); |
|||
for (auto &old_coin_serial_number : old_coin_serial_numbers) |
|||
{ |
|||
input_as_bits.insert(input_as_bits.end(), old_coin_serial_number.begin(), old_coin_serial_number.end()); |
|||
} |
|||
for (auto &new_coin_commitment : new_coin_commitments) |
|||
{ |
|||
input_as_bits.insert(input_as_bits.end(), new_coin_commitment.begin(), new_coin_commitment.end()); |
|||
} |
|||
input_as_bits.insert(input_as_bits.end(), public_old_value.begin(), public_old_value.end()); |
|||
input_as_bits.insert(input_as_bits.end(), public_new_value.begin(), public_new_value.end()); |
|||
input_as_bits.insert(input_as_bits.end(), signature_public_key_hash.begin(), signature_public_key_hash.end()); |
|||
for (auto &signature_public_key_hash_mac : signature_public_key_hash_macs) |
|||
{ |
|||
input_as_bits.insert(input_as_bits.end(), signature_public_key_hash_mac.begin(), signature_public_key_hash_mac.end()); |
|||
} |
|||
std::vector<FieldT> input_as_field_elements = pack_bit_vector_into_field_element_vector<FieldT>(input_as_bits); |
|||
|
|||
#ifdef DEBUG |
|||
printf("input_as_field_elements from zerocash_pour_input_map:\n"); |
|||
for (size_t i = 0; i < input_as_field_elements.size(); ++i) |
|||
{ |
|||
input_as_field_elements[i].print(); |
|||
} |
|||
#endif |
|||
leave_block("Call to zerocash_pour_input_map"); |
|||
|
|||
return input_as_field_elements; |
|||
} |
|||
|
|||
} // libzerocash |
@ -1,34 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Declaration of various parameters used by the Pour gadget and Pour ppzkSNARK. |
|||
|
|||
***************************************************************************** |
|||
* @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_PARAMS_HPP_ |
|||
#define ZEROCASH_POUR_PARAMS_HPP_ |
|||
|
|||
namespace libzerocash { |
|||
|
|||
const size_t sha256_block_len = 512; |
|||
const size_t sha256_digest_len = 256; |
|||
const size_t address_public_key_length = sha256_digest_len; |
|||
const size_t address_public_key_padding_length = 256; |
|||
const size_t address_secret_key_length = 256; |
|||
const size_t coin_commitment_length = sha256_digest_len; |
|||
const size_t coin_commitment_padding_length = 192; |
|||
const size_t truncated_coin_commitment_length = 128; |
|||
const size_t truncated_serial_number_length = 254; |
|||
const size_t serial_number_length = sha256_digest_len; |
|||
const size_t address_commitment_nonce_length = 384; |
|||
const size_t serial_number_nonce_length = 256; |
|||
const size_t coin_value_length = 64; |
|||
const size_t indexed_signature_public_key_hash_length = 254; |
|||
|
|||
} // libzerocash
|
|||
|
|||
#endif // ZEROCASH_POUR_PARAMS_HPP_
|
@ -1,232 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Declaration of interfaces for a ppzkSNARK for the NP statement "Pour". |
|||
|
|||
This includes: |
|||
- class for proving key |
|||
- class for verification key |
|||
- class for key pair (proving key & verification key) |
|||
- class for proof |
|||
- generator algorithm |
|||
- prover algorithm |
|||
- verifier algorithm |
|||
|
|||
The ppzkSNARK is obtained by using an R1CS ppzkSNARK relative to an R1CS |
|||
realization of the NP statement "Pour". The implementation follows, extends, |
|||
and optimizes the approach described in \[BCGGMTV14]. |
|||
|
|||
|
|||
Acronyms: |
|||
|
|||
- R1CS = "Rank-1 Constraint Systems" |
|||
- ppzkSNARK = "PreProcessing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" |
|||
|
|||
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, |
|||
<https://eprint.iacr.org/2014/349>
|
|||
|
|||
***************************************************************************** |
|||
* @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_PPZKSNARK_HPP_ |
|||
#define ZEROCASH_POUR_PPZKSNARK_HPP_ |
|||
|
|||
#include "libsnark/common/data_structures/merkle_tree.hpp" |
|||
#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" |
|||
#include <stdexcept> |
|||
|
|||
namespace libzerocash { |
|||
|
|||
/******************************** Proving key ********************************/ |
|||
|
|||
/**
|
|||
* A proving key for the Pour ppzkSNARK. |
|||
*/ |
|||
template<typename ppzksnark_ppT> |
|||
class zerocash_pour_proving_key; |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
std::ostream& operator<<(std::ostream &out, const zerocash_pour_proving_key<ppzksnark_ppT> &pk); |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
std::istream& operator>>(std::istream &in, zerocash_pour_proving_key<ppzksnark_ppT> &pk); |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
class zerocash_pour_proving_key { |
|||
public: |
|||
size_t num_old_coins; |
|||
size_t num_new_coins; |
|||
size_t tree_depth; |
|||
r1cs_ppzksnark_proving_key<ppzksnark_ppT> r1cs_pk; |
|||
|
|||
zerocash_pour_proving_key() = default; |
|||
zerocash_pour_proving_key(const zerocash_pour_proving_key<ppzksnark_ppT> &other) = default; |
|||
zerocash_pour_proving_key(zerocash_pour_proving_key<ppzksnark_ppT> &&other) = default; |
|||
zerocash_pour_proving_key(const size_t num_old_coins, |
|||
const size_t num_new_coins, |
|||
const size_t tree_depth, |
|||
const r1cs_ppzksnark_proving_key<ppzksnark_ppT> &r1cs_pk) : |
|||
num_old_coins(num_old_coins), num_new_coins(num_new_coins), |
|||
tree_depth(tree_depth), r1cs_pk(r1cs_pk) {} |
|||
zerocash_pour_proving_key(const size_t num_old_coins, |
|||
const size_t num_new_coins, |
|||
const size_t tree_depth, |
|||
r1cs_ppzksnark_proving_key<ppzksnark_ppT> &&r1cs_pk) : |
|||
num_old_coins(num_old_coins), num_new_coins(num_new_coins), |
|||
tree_depth(tree_depth), r1cs_pk(std::move(r1cs_pk)) {} |
|||
zerocash_pour_proving_key<ppzksnark_ppT>& operator=(const zerocash_pour_proving_key<ppzksnark_ppT> &other) = default; |
|||
|
|||
bool operator==(const zerocash_pour_proving_key<ppzksnark_ppT> &other) const; |
|||
friend std::ostream& operator<< <ppzksnark_ppT>(std::ostream &out, const zerocash_pour_proving_key<ppzksnark_ppT> &pk); |
|||
friend std::istream& operator>> <ppzksnark_ppT>(std::istream &in, zerocash_pour_proving_key<ppzksnark_ppT> &pk); |
|||
}; |
|||
|
|||
/******************************* Verification key ****************************/ |
|||
|
|||
/**
|
|||
* A verification key for the Pour ppzkSNARK. |
|||
*/ |
|||
template<typename ppzksnark_ppT> |
|||
class zerocash_pour_verification_key; |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
std::ostream& operator<<(std::ostream &out, const zerocash_pour_verification_key<ppzksnark_ppT> &pk); |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
std::istream& operator>>(std::istream &in, zerocash_pour_verification_key<ppzksnark_ppT> &pk); |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
class zerocash_pour_verification_key { |
|||
public: |
|||
size_t num_old_coins; |
|||
size_t num_new_coins; |
|||
r1cs_ppzksnark_verification_key<ppzksnark_ppT> r1cs_vk; |
|||
|
|||
zerocash_pour_verification_key() = default; |
|||
zerocash_pour_verification_key(const zerocash_pour_verification_key<ppzksnark_ppT> &other) = default; |
|||
zerocash_pour_verification_key(zerocash_pour_verification_key<ppzksnark_ppT> &&other) = default; |
|||
zerocash_pour_verification_key(const size_t num_old_coins, |
|||
const size_t num_new_coins, |
|||
const r1cs_ppzksnark_verification_key<ppzksnark_ppT> &r1cs_vk) : |
|||
num_old_coins(num_old_coins), num_new_coins(num_new_coins), |
|||
r1cs_vk(r1cs_vk) {} |
|||
zerocash_pour_verification_key(const size_t num_old_coins, |
|||
const size_t num_new_coins, |
|||
r1cs_ppzksnark_verification_key<ppzksnark_ppT> &&r1cs_vk) : |
|||
num_old_coins(num_old_coins), num_new_coins(num_new_coins), |
|||
r1cs_vk(std::move(r1cs_vk)) {} |
|||
zerocash_pour_verification_key<ppzksnark_ppT>& operator=(const zerocash_pour_verification_key<ppzksnark_ppT> &other) = default; |
|||
|
|||
bool operator==(const zerocash_pour_verification_key<ppzksnark_ppT> &other) const; |
|||
friend std::ostream& operator<< <ppzksnark_ppT>(std::ostream &out, const zerocash_pour_verification_key<ppzksnark_ppT> &pk); |
|||
friend std::istream& operator>> <ppzksnark_ppT>(std::istream &in, zerocash_pour_verification_key<ppzksnark_ppT> &pk); |
|||
}; |
|||
|
|||
/********************************** Key pair *********************************/ |
|||
|
|||
/**
|
|||
* A key pair for the Pour ppzkSNARK, which consists of a proving key and a verification key. |
|||
*/ |
|||
template<typename ppzksnark_ppT> |
|||
class zerocash_pour_keypair; |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
std::ostream& operator<<(std::ostream &out, const zerocash_pour_keypair<ppzksnark_ppT> &pk); |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
std::istream& operator>>(std::istream &in, zerocash_pour_keypair<ppzksnark_ppT> &pk); |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
class zerocash_pour_keypair { |
|||
public: |
|||
zerocash_pour_proving_key<ppzksnark_ppT> pk; |
|||
zerocash_pour_verification_key<ppzksnark_ppT> vk; |
|||
|
|||
zerocash_pour_keypair() = default; |
|||
zerocash_pour_keypair(const zerocash_pour_keypair<ppzksnark_ppT> &other) = default; |
|||
zerocash_pour_keypair(zerocash_pour_keypair<ppzksnark_ppT> &&other) = default; |
|||
zerocash_pour_keypair(const zerocash_pour_proving_key<ppzksnark_ppT> &pk, |
|||
const zerocash_pour_verification_key<ppzksnark_ppT> &vk) : |
|||
pk(pk), vk(vk) {} |
|||
zerocash_pour_keypair(zerocash_pour_proving_key<ppzksnark_ppT> &&pk, |
|||
zerocash_pour_verification_key<ppzksnark_ppT> &&vk) : |
|||
pk(std::move(pk)), |
|||
vk(std::move(vk)) {} |
|||
zerocash_pour_keypair<ppzksnark_ppT>& operator=(const zerocash_pour_keypair<ppzksnark_ppT> &other) = default; |
|||
|
|||
bool operator==(const zerocash_pour_keypair<ppzksnark_ppT> &other) const; |
|||
friend std::ostream& operator<< <ppzksnark_ppT>(std::ostream &out, const zerocash_pour_keypair<ppzksnark_ppT> &pk); |
|||
friend std::istream& operator>> <ppzksnark_ppT>(std::istream &in, zerocash_pour_keypair<ppzksnark_ppT> &pk); |
|||
}; |
|||
|
|||
/*********************************** Proof ***********************************/ |
|||
|
|||
/**
|
|||
* A proof for the Pour ppzkSNARK. |
|||
*/ |
|||
template<typename ppzksnark_ppT> |
|||
using zerocash_pour_proof = r1cs_ppzksnark_proof<ppzksnark_ppT>; |
|||
|
|||
|
|||
/***************************** Main algorithms *******************************/ |
|||
|
|||
/**
|
|||
* A generator algorithm for the Pour ppzkSNARK. |
|||
* |
|||
* Given a tree depth d, this algorithm produces proving and verification keys |
|||
* for Pour relative to a Merkle tree of depth d. |
|||
*/ |
|||
template<typename ppzksnark_ppT> |
|||
zerocash_pour_keypair<ppzksnark_ppT> zerocash_pour_ppzksnark_generator(const size_t num_old_coins, |
|||
const size_t num_new_coins, |
|||
const size_t tree_depth); |
|||
|
|||
/**
|
|||
* A prover algorithm for the Pour ppzkSNARK. |
|||
* |
|||
* TODO: add description |
|||
*/ |
|||
template<typename ppzksnark_ppT> |
|||
zerocash_pour_proof<ppzksnark_ppT> zerocash_pour_ppzksnark_prover(const zerocash_pour_proving_key<ppzksnark_ppT> &pk, |
|||
const std::vector<merkle_authentication_path> &old_coin_authentication_paths, |
|||
const std::vector<size_t> &old_coin_merkle_tree_positions, |
|||
const bit_vector &merkle_tree_root, |
|||
const std::vector<bit_vector> &new_address_public_keys, |
|||
const std::vector<bit_vector> &old_address_secret_keys, |
|||
const std::vector<bit_vector> &new_address_commitment_nonces, |
|||
const std::vector<bit_vector> &old_address_commitment_nonces, |
|||
const std::vector<bit_vector> &new_coin_serial_number_nonces, |
|||
const std::vector<bit_vector> &old_coin_serial_number_nonces, |
|||
const std::vector<bit_vector> &new_coin_values, |
|||
const bit_vector &public_old_value, |
|||
const bit_vector &public_new_value, |
|||
const std::vector<bit_vector> &old_coin_values, |
|||
const bit_vector &signature_public_key_hash); |
|||
|
|||
/**
|
|||
* A verifier algorithm for the Pour ppzkSNARK. |
|||
*/ |
|||
template<typename ppzksnark_ppT> |
|||
bool zerocash_pour_ppzksnark_verifier(const zerocash_pour_verification_key<ppzksnark_ppT> &vk, |
|||
const bit_vector &merkle_tree_root, |
|||
const std::vector<bit_vector> &old_coin_serial_numbers, |
|||
const std::vector<bit_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<bit_vector> &signature_public_key_hash_macs, |
|||
const zerocash_pour_proof<ppzksnark_ppT> &proof); |
|||
|
|||
} // libzerocash
|
|||
|
|||
#include "zerocash_pour_ppzksnark.tcc" |
|||
|
|||
#endif // ZEROCASH_POUR_PPZKSNARK_HPP_
|
@ -1,212 +0,0 @@ |
|||
/** @file |
|||
***************************************************************************** |
|||
|
|||
Implementation of interfaces for a ppzkSNARK for the NP statement "Pour". |
|||
|
|||
See zerocash_pour_ppzksnark.hpp . |
|||
|
|||
***************************************************************************** |
|||
* @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_PPZKSNARK_TCC_ |
|||
#define ZEROCASH_POUR_PPZKSNARK_TCC_ |
|||
|
|||
#include "zerocash_pour_gadget.hpp" |
|||
#include "common/profiling.hpp" |
|||
|
|||
namespace libzerocash { |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
bool zerocash_pour_proving_key<ppzksnark_ppT>::operator==(const zerocash_pour_proving_key<ppzksnark_ppT> &other) const |
|||
{ |
|||
return (this->num_old_coins == other.num_old_coins && |
|||
this->num_new_coins == other.num_new_coins && |
|||
this->tree_depth == other.tree_depth && |
|||
this->r1cs_pk == other.r1cs_pk); |
|||
} |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
std::ostream& operator<<(std::ostream &out, const zerocash_pour_proving_key<ppzksnark_ppT> &pk) |
|||
{ |
|||
out << pk.num_old_coins << "\n"; |
|||
out << pk.num_new_coins << "\n"; |
|||
out << pk.tree_depth << "\n"; |
|||
out << pk.r1cs_pk; |
|||
|
|||
return out; |
|||
} |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
std::istream& operator>>(std::istream &in, zerocash_pour_proving_key<ppzksnark_ppT> &pk) |
|||
{ |
|||
in >> pk.num_old_coins; |
|||
consume_newline(in); |
|||
in >> pk.num_new_coins; |
|||
consume_newline(in); |
|||
in >> pk.tree_depth; |
|||
consume_newline(in); |
|||
in >> pk.r1cs_pk; |
|||
|
|||
return in; |
|||
} |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
bool zerocash_pour_verification_key<ppzksnark_ppT>::operator==(const zerocash_pour_verification_key<ppzksnark_ppT> &other) const |
|||
{ |
|||
return (this->num_old_coins == other.num_old_coins && |
|||
this->num_new_coins == other.num_new_coins && |
|||
this->r1cs_vk == other.r1cs_vk); |
|||
} |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
std::ostream& operator<<(std::ostream &out, const zerocash_pour_verification_key<ppzksnark_ppT> &vk) |
|||
{ |
|||
out << vk.num_old_coins << "\n"; |
|||
out << vk.num_new_coins << "\n"; |
|||
out << vk.r1cs_vk; |
|||
|
|||
return out; |
|||
} |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
std::istream& operator>>(std::istream &in, zerocash_pour_verification_key<ppzksnark_ppT> &vk) |
|||
{ |
|||
in >> vk.num_old_coins; |
|||
consume_newline(in); |
|||
in >> vk.num_new_coins; |
|||
consume_newline(in); |
|||
in >> vk.r1cs_vk; |
|||
|
|||
return in; |
|||
} |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
bool zerocash_pour_keypair<ppzksnark_ppT>::operator==(const zerocash_pour_keypair<ppzksnark_ppT> &other) const |
|||
{ |
|||
return (this->pk == other.pk && |
|||
this->vk == other.vk); |
|||
} |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
std::ostream& operator<<(std::ostream &out, const zerocash_pour_keypair<ppzksnark_ppT> &kp) |
|||
{ |
|||
out << kp.pk; |
|||
out << kp.vk; |
|||
|
|||
return out; |
|||
} |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
std::istream& operator>>(std::istream &in, zerocash_pour_keypair<ppzksnark_ppT> &kp) |
|||
{ |
|||
in >> kp.pk; |
|||
in >> kp.vk; |
|||
|
|||
return in; |
|||
} |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
zerocash_pour_keypair<ppzksnark_ppT> zerocash_pour_ppzksnark_generator(const size_t num_old_coins, |
|||
const size_t num_new_coins, |
|||
const size_t tree_depth) |
|||
{ |
|||
typedef Fr<ppzksnark_ppT> FieldT; |
|||
enter_block("Call to zerocash_pour_ppzksnark_generator"); |
|||
|
|||
protoboard<FieldT> pb; |
|||
zerocash_pour_gadget<FieldT> g(pb, num_old_coins, num_new_coins, tree_depth, "zerocash_pour"); |
|||
g.generate_r1cs_constraints(); |
|||
const r1cs_constraint_system<FieldT> constraint_system = pb.get_constraint_system(); |
|||
r1cs_ppzksnark_keypair<ppzksnark_ppT> ppzksnark_keypair = r1cs_ppzksnark_generator<ppzksnark_ppT>(constraint_system); |
|||
leave_block("Call to zerocash_pour_ppzksnark_generator"); |
|||
|
|||
zerocash_pour_proving_key<ppzksnark_ppT> zerocash_pour_pk(num_old_coins, num_new_coins, tree_depth, std::move(ppzksnark_keypair.pk)); |
|||
zerocash_pour_verification_key<ppzksnark_ppT> zerocash_pour_vk(num_old_coins, num_new_coins, std::move(ppzksnark_keypair.vk)); |
|||
return zerocash_pour_keypair<ppzksnark_ppT>(std::move(zerocash_pour_pk), std::move(zerocash_pour_vk)); |
|||
} |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
zerocash_pour_proof<ppzksnark_ppT> zerocash_pour_ppzksnark_prover(const zerocash_pour_proving_key<ppzksnark_ppT> &pk, |
|||
const std::vector<merkle_authentication_path> &old_coin_authentication_paths, |
|||
const std::vector<size_t> &old_coin_merkle_tree_positions, |
|||
const bit_vector &merkle_tree_root, |
|||
const std::vector<bit_vector> &new_address_public_keys, |
|||
const std::vector<bit_vector> &old_address_secret_keys, |
|||
const std::vector<bit_vector> &new_address_commitment_nonces, |
|||
const std::vector<bit_vector> &old_address_commitment_nonces, |
|||
const std::vector<bit_vector> &new_coin_serial_number_nonces, |
|||
const std::vector<bit_vector> &old_coin_serial_number_nonces, |
|||
const std::vector<bit_vector> &new_coin_values, |
|||
const bit_vector &public_old_value, |
|||
const bit_vector &public_new_value, |
|||
const std::vector<bit_vector> &old_coin_values, |
|||
const bit_vector &signature_public_key_hash) |
|||
{ |
|||
typedef Fr<ppzksnark_ppT> FieldT; |
|||
|
|||
enter_block("Call to zerocash_pour_ppzksnark_prover"); |
|||
|
|||
protoboard<FieldT> pb; |
|||
zerocash_pour_gadget<FieldT > g(pb, pk.num_old_coins, pk.num_new_coins, pk.tree_depth, "zerocash_pour"); |
|||
g.generate_r1cs_constraints(); |
|||
g.generate_r1cs_witness(old_coin_authentication_paths, |
|||
old_coin_merkle_tree_positions, |
|||
merkle_tree_root, |
|||
new_address_public_keys, |
|||
old_address_secret_keys, |
|||
new_address_commitment_nonces, |
|||
old_address_commitment_nonces, |
|||
new_coin_serial_number_nonces, |
|||
old_coin_serial_number_nonces, |
|||
new_coin_values, |
|||
public_old_value, |
|||
public_new_value, |
|||
old_coin_values, |
|||
signature_public_key_hash); |
|||
if (!pb.is_satisfied()) { |
|||
leave_block("Call to zerocash_pour_ppzksnark_prover"); |
|||
throw std::invalid_argument("Constraints not satisfied by inputs"); |
|||
} |
|||
|
|||
zerocash_pour_proof<ppzksnark_ppT> proof = r1cs_ppzksnark_prover<ppzksnark_ppT>(pk.r1cs_pk, pb.primary_input(), pb.auxiliary_input()); |
|||
|
|||
leave_block("Call to zerocash_pour_ppzksnark_prover"); |
|||
|
|||
return proof; |
|||
} |
|||
|
|||
template<typename ppzksnark_ppT> |
|||
bool zerocash_pour_ppzksnark_verifier(const zerocash_pour_verification_key<ppzksnark_ppT> &vk, |
|||
const bit_vector &merkle_tree_root, |
|||
const std::vector<bit_vector> &old_coin_serial_numbers, |
|||
const std::vector<bit_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<bit_vector> &signature_public_key_hash_macs, |
|||
const zerocash_pour_proof<ppzksnark_ppT> &proof) |
|||
{ |
|||
typedef Fr<ppzksnark_ppT> FieldT; |
|||
|
|||
enter_block("Call to zerocash_pour_ppzksnark_verifier"); |
|||
const r1cs_primary_input<FieldT> input = zerocash_pour_input_map<FieldT>(vk.num_old_coins, |
|||
vk.num_new_coins, |
|||
merkle_tree_root, |
|||
old_coin_serial_numbers, |
|||
new_coin_commitments, |
|||
public_old_value, |
|||
public_new_value, |
|||
signature_public_key_hash, |
|||
signature_public_key_hash_macs); |
|||
const bool ans = r1cs_ppzksnark_verifier_strong_IC<ppzksnark_ppT>(vk.r1cs_vk, input, proof); |
|||
leave_block("Call to zerocash_pour_ppzksnark_verifier"); |
|||
|
|||
return ans; |
|||
} |
|||
|
|||
} // libzerocash |
|||
|
|||
#endif // ZEROCASH_POUR_PPZKSNARK_TCC_ |
Loading…
Reference in new issue