Browse Source

Remove nearly all of libzerocash.

pull/4/head
Sean Bowe 8 years ago
parent
commit
4ec57478c4
  1. 24
      src/Makefile.am
  2. 27
      src/Makefile.zcash.include
  3. 132
      src/zerocash/Address.cpp
  4. 87
      src/zerocash/Address.h
  5. 137
      src/zerocash/Coin.cpp
  6. 76
      src/zerocash/Coin.h
  7. 58
      src/zerocash/CoinCommitment.cpp
  8. 44
      src/zerocash/CoinCommitment.h
  9. 42
      src/zerocash/GenerateParamsForFiles.cpp
  10. 606
      src/zerocash/IncrementalMerkleTree.cpp
  11. 140
      src/zerocash/IncrementalMerkleTree.h
  12. 161
      src/zerocash/Makefile
  13. 75
      src/zerocash/MintTransaction.cpp
  14. 69
      src/zerocash/MintTransaction.h
  15. 39
      src/zerocash/PourInput.cpp
  16. 38
      src/zerocash/PourInput.h
  17. 29
      src/zerocash/PourOutput.cpp
  18. 32
      src/zerocash/PourOutput.h
  19. 12
      src/zerocash/PourProver.cpp
  20. 65
      src/zerocash/PourProver.h
  21. 445
      src/zerocash/PourTransaction.cpp
  22. 204
      src/zerocash/PourTransaction.h
  23. 65
      src/zerocash/Zerocash.h
  24. 191
      src/zerocash/ZerocashParams.cpp
  25. 77
      src/zerocash/ZerocashParams.h
  26. 39
      src/zerocash/profiling/profile_zerocash_pour_gadget.cpp
  27. 325
      src/zerocash/tests/test_zerocash_pour_ppzksnark.cpp
  28. 631
      src/zerocash/tests/zerocashTest.cpp
  29. 188
      src/zerocash/zerocash_pour_gadget.hpp
  30. 503
      src/zerocash/zerocash_pour_gadget.tcc
  31. 34
      src/zerocash/zerocash_pour_params.hpp
  32. 232
      src/zerocash/zerocash_pour_ppzksnark.hpp
  33. 212
      src/zerocash/zerocash_pour_ppzksnark.tcc

24
src/Makefile.am

@ -72,18 +72,6 @@ endif
# TODO: rename to libzcash
LIBZEROCASH_H = \
zcash/IncrementalMerkleTree.h \
zerocash/Address.h \
zerocash/CoinCommitment.h \
zerocash/Coin.h \
zerocash/IncrementalMerkleTree.h \
zerocash/MintTransaction.h \
zerocash/PourInput.h \
zerocash/PourOutput.h \
zerocash/PourProver.h \
zerocash/PourTransaction.h \
zerocash/Zerocash.h \
zerocash/ZerocashParams.h \
zerocash/zerocash_pour_params.hpp \
zerocash/utils/util.h \
zcash/NoteEncryption.hpp \
zcash/Address.hpp \
@ -418,16 +406,6 @@ bitcoin_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
# zerocash protocol primitives #
libzerocash_a_SOURCES = \
zcash/IncrementalMerkleTree.cpp \
zerocash/Address.cpp \
zerocash/CoinCommitment.cpp \
zerocash/Coin.cpp \
zerocash/IncrementalMerkleTree.cpp \
zerocash/MintTransaction.cpp \
zerocash/PourInput.cpp \
zerocash/PourOutput.cpp \
zerocash/PourProver.cpp \
zerocash/PourTransaction.cpp \
zerocash/ZerocashParams.cpp \
zerocash/utils/util.cpp \
zcash/NoteEncryption.cpp \
zcash/Address.cpp \
@ -473,7 +451,7 @@ CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a *.gcda *.gcno
DISTCLEANFILES = obj/build.h
EXTRA_DIST = leveldb libzerocash/Makefile
EXTRA_DIST = leveldb
clean-local:
-$(MAKE) -C leveldb clean

27
src/Makefile.zcash.include

@ -1,8 +1,6 @@
bin_PROGRAMS += \
zcash/GenerateParams \
zerocash/tests/utilTest \
zerocash/tests/zerocashTest \
zerocash/tests/test_zerocash_pour_ppzksnark
zerocash/tests/utilTest
# tool for generating our public parameters
zcash_GenerateParams_SOURCES = zcash/GenerateParams.cpp
@ -21,26 +19,3 @@ zerocash_tests_utilTest_LDADD = \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \
$(LIBZEROCASH_LIBS)
# tests for libzerocash APIs
zerocash_tests_zerocashTest_SOURCES = \
zerocash/tests/zerocashTest.cpp \
zerocash/tests/timer.cpp
zerocash_tests_zerocashTest_LDADD = \
$(BOOST_LIBS) \
$(LIBZEROCASH) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \
$(LIBZEROCASH_LIBS)
# tests for our zkSNARK circuit
zerocash_tests_test_zerocash_pour_ppzksnark_SOURCES = zerocash/tests/test_zerocash_pour_ppzksnark.cpp
zerocash_tests_test_zerocash_pour_ppzksnark_LDADD = \
$(BOOST_LIBS) \
$(LIBZEROCASH) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \
$(LIBZEROCASH_LIBS)

132
src/zerocash/Address.cpp

@ -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 */

87
src/zerocash/Address.h

@ -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_ */

137
src/zerocash/Coin.cpp

@ -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 */

76
src/zerocash/Coin.h

@ -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_ */

58
src/zerocash/CoinCommitment.cpp

@ -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 */

44
src/zerocash/CoinCommitment.h

@ -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_ */

42
src/zerocash/GenerateParamsForFiles.cpp

@ -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;
}

606
src/zerocash/IncrementalMerkleTree.cpp

@ -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 */

140
src/zerocash/IncrementalMerkleTree.h

@ -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_ */

161
src/zerocash/Makefile

@ -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)

75
src/zerocash/MintTransaction.cpp

@ -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 */

69
src/zerocash/MintTransaction.h

@ -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_ */

39
src/zerocash/PourInput.cpp

@ -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 */

38
src/zerocash/PourInput.h

@ -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_ */

29
src/zerocash/PourOutput.cpp

@ -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 */

32
src/zerocash/PourOutput.h

@ -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_ */

12
src/zerocash/PourProver.cpp

@ -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"

65
src/zerocash/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_ */

445
src/zerocash/PourTransaction.cpp

@ -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 */

204
src/zerocash/PourTransaction.h

@ -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_ */

65
src/zerocash/Zerocash.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_ */

191
src/zerocash/ZerocashParams.cpp

@ -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 */

77
src/zerocash/ZerocashParams.h

@ -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_ */

39
src/zerocash/profiling/profile_zerocash_pour_gadget.cpp

@ -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
}

325
src/zerocash/tests/test_zerocash_pour_ppzksnark.cpp

@ -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);
}

631
src/zerocash/tests/zerocashTest.cpp

@ -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);
}

188
src/zerocash/zerocash_pour_gadget.hpp

@ -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_

503
src/zerocash/zerocash_pour_gadget.tcc

@ -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

34
src/zerocash/zerocash_pour_params.hpp

@ -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_

232
src/zerocash/zerocash_pour_ppzksnark.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_

212
src/zerocash/zerocash_pour_ppzksnark.tcc

@ -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…
Cancel
Save