Browse Source

NoteEncryption implementation and integration, removal of ECIES and crypto++ dependencies.

metaverse
Sean Bowe 8 years ago
parent
commit
6c36a9fe03
  1. 8
      configure.ac
  2. 20
      depends/packages/crypto++.mk
  3. 2
      depends/packages/packages.mk
  4. 9
      src/Makefile.am
  5. 1
      src/Makefile.test.include
  6. 2
      src/Makefile.zcash.include
  7. 5
      src/primitives/transaction.cpp
  8. 19
      src/primitives/transaction.h
  9. 1002
      src/test/data/sighash.json
  10. 183
      src/test/noteencryption_tests.cpp
  11. 1
      src/test/sighash_tests.cpp
  12. 56
      src/wallet/rpcwallet.cpp
  13. 169
      src/zcash/NoteEncryption.cpp
  14. 79
      src/zcash/NoteEncryption.hpp
  15. 63
      src/zcash/prf.cpp
  16. 17
      src/zcash/prf.h
  17. 63
      src/zerocash/Address.cpp
  18. 21
      src/zerocash/Address.h
  19. 54
      src/zerocash/Coin.cpp
  20. 4
      src/zerocash/Coin.h
  21. 126
      src/zerocash/PourTransaction.cpp
  22. 36
      src/zerocash/PourTransaction.h
  23. 1
      src/zerocash/Zerocash.h

8
configure.ac

@ -699,11 +699,6 @@ AC_CHECK_LIB([gmp],[[__gmpn_sub_n]],GMP_LIBS=-lgmp, [AC_MSG_ERROR(libgmp missing
AC_CHECK_HEADER([gmpxx.h],,AC_MSG_ERROR(libgmpxx headers missing))
AC_CHECK_LIB([gmpxx],[main],GMPXX_LIBS=-lgmpxx, [AC_MSG_ERROR(libgmpxx missing)])
AC_CHECK_HEADER([cryptopp/eccrypto.h],,AC_MSG_ERROR(libcryptopp headers missing))
# We link against "main" as a stop-gap; crypto++ is full of template
# classes whose library symbols are mangled by some black alchemy.
AC_CHECK_LIB([cryptopp],[main],CRYPTOPP_LIBS=-lcryptopp, [AC_MSG_ERROR(libcryptopp missing)])
# libsnark header layout is broken unless cpp's -I is passed with the
# libsnark directory, so for now we use this hideous workaround:
echo 'Hunting for libsnark include directory...'
@ -720,7 +715,7 @@ CPPFLAGS="-I$LIBSNARK_INCDIR $CPPFLAGS"
AC_CHECK_HEADER([libsnark/gadgetlib1/gadget.hpp],,AC_MSG_ERROR(libsnark headers missing))
AC_CHECK_LIB([snark],[main],LIBSNARK_LIBS=-lsnark, [AC_MSG_ERROR(libsnark missing)], [-lgmpxx])
LIBZEROCASH_LIBS="-lsnark -lcryptopp -lgmp -lgmpxx -lboost_system-mt -lcrypto -lsodium"
LIBZEROCASH_LIBS="-lsnark -lgmp -lgmpxx -lboost_system-mt -lcrypto -lsodium"
AC_CHECK_LIB([crypto],[RAND_egd],[],[
AC_ARG_WITH([libressl],
@ -929,7 +924,6 @@ AC_SUBST(MINIUPNPC_CPPFLAGS)
AC_SUBST(MINIUPNPC_LIBS)
AC_SUBST(GMP_LIBS)
AC_SUBST(GMPXX_LIBS)
AC_SUBST(CRYPTOPP_LIBS)
AC_SUBST(LIBSNARK_LIBS)
AC_SUBST(LIBZEROCASH_LIBS)
AC_CONFIG_FILES([Makefile src/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py])

20
depends/packages/crypto++.mk

@ -1,20 +0,0 @@
package=crypto++
$(package)_version=5.6.2
$(package)_download_path=http://www.cryptopp.com/
$(package)_file_name=cryptopp562.zip
$(package)_sha256_hash=5cbfd2fcb4a6b3aab35902e2e0f3b59d9171fee12b3fc2b363e1801dfec53574
$(package)_dependencies=
# SECURITY BUG: _extract_cmds is responsible for verifying the archive
# hash, but does not do so here:
define $(package)_extract_cmds
unzip $($(package)_source_dir)/$($(package)_file_name)
endef
define $(package)_build_cmds
$(MAKE) static CXXFLAGS='-DNDEBUG -g -O2 -fPIC'
endef
define $(package)_stage_cmds
$(MAKE) install PREFIX=$($(package)_staging_dir)$(host_prefix)
endef

2
depends/packages/packages.mk

@ -1,4 +1,4 @@
zerocash_packages := libsnark crypto++ libgmp libsodium
zerocash_packages := libsnark libgmp libsodium
packages := boost openssl $(zerocash_packages) googletest
native_packages := native_ccache native_comparisontool

9
src/Makefile.am

@ -82,7 +82,9 @@ LIBZEROCASH_H = \
zerocash/Zerocash.h \
zerocash/ZerocashParams.h \
zerocash/zerocash_pour_params.hpp \
zerocash/utils/util.h
zerocash/utils/util.h \
zcash/NoteEncryption.hpp \
zcash/prf.h
.PHONY: FORCE
# bitcoin core #
@ -400,7 +402,6 @@ bitcoin_tx_LDADD = \
$(LIBBITCOIN_UNIVALUE) \
$(LIBBITCOIN_COMMON) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \
$(LIBSECP256K1) \
$(LIBZEROCASH) \
$(LIBBITCOIN_CRYPTO) \
@ -421,7 +422,9 @@ libzerocash_a_SOURCES = \
zerocash/PourProver.cpp \
zerocash/PourTransaction.cpp \
zerocash/ZerocashParams.cpp \
zerocash/utils/util.cpp
zerocash/utils/util.cpp \
zcash/NoteEncryption.cpp \
zcash/prf.cpp
libzerocash_a_CPPFLAGS = -fPIC -DCURVE_ALT_BN128 -DBOOST_SPIRIT_THREADSAFE -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -std=c++11 -pipe -O2 -O0 -g -Wstack-protector -fstack-protector-all -fPIE -fvisibility=hidden -DSTATIC $(BITCOIN_INCLUDES)

1
src/Makefile.test.include

@ -56,6 +56,7 @@ BITCOIN_TESTS =\
test/miner_tests.cpp \
test/mruset_tests.cpp \
test/multisig_tests.cpp \
test/noteencryption_tests.cpp \
test/netbase_tests.cpp \
test/pmt_tests.cpp \
test/policyestimator_tests.cpp \

2
src/Makefile.zcash.include

@ -38,6 +38,7 @@ zerocash_tests_zerocashTest_SOURCES = \
zerocash_tests_zerocashTest_LDADD = \
$(BOOST_LIBS) \
$(LIBZEROCASH) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \
$(LIBZEROCASH_LIBS)
@ -47,6 +48,7 @@ zerocash_tests_test_zerocash_pour_ppzksnark_SOURCES = zerocash/tests/test_zeroca
zerocash_tests_test_zerocash_pour_ppzksnark_LDADD = \
$(BOOST_LIBS) \
$(LIBZEROCASH) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \
$(LIBZEROCASH_LIBS)

5
src/primitives/transaction.cpp

@ -58,14 +58,11 @@ CPourTx::CPourTx(ZerocashParams& params,
boost::array<std::vector<unsigned char>, NUM_POUR_INPUTS> serials_bv;
boost::array<std::vector<unsigned char>, NUM_POUR_OUTPUTS> commitments_bv;
boost::array<std::vector<unsigned char>, NUM_POUR_INPUTS> macs_bv;
boost::array<std::string, NUM_POUR_OUTPUTS> ciphertexts_bv;
proof = pourtx.unpack(serials_bv, commitments_bv, macs_bv, ciphertexts_bv);
proof = pourtx.unpack(serials_bv, commitments_bv, macs_bv, ciphertexts, ephemeralKey);
serials = unsigned_char_vector_array_to_uint256_array(serials_bv);
commitments = unsigned_char_vector_array_to_uint256_array(commitments_bv);
macs = unsigned_char_vector_array_to_uint256_array(macs_bv);
ciphertexts = ciphertexts_bv;
}
bool CPourTx::Verify(ZerocashParams& params) const {

19
src/primitives/transaction.h

@ -17,6 +17,8 @@
#include "zerocash/PourInput.h"
#include "zerocash/PourOutput.h"
#include "zcash/NoteEncryption.hpp"
using namespace libzerocash;
static const unsigned int NUM_POUR_INPUTS = 2;
@ -58,10 +60,13 @@ public:
boost::array<uint256, NUM_POUR_OUTPUTS> commitments;
// Ciphertexts
// These are encrypted using ECIES. They are used to
// transfer metadata and seeds to generate trapdoors
// for the recipient to spend the value.
boost::array<std::string, NUM_POUR_OUTPUTS> ciphertexts;
// These contain trapdoors, values and other information
// that the recipient needs, including a memo field. It
// is encrypted using the scheme implemented in crypto/NoteEncryption.cpp
boost::array<ZCNoteEncryption::Ciphertext, NUM_POUR_OUTPUTS> ciphertexts;
// Ephemeral key
uint256 ephemeralKey;
// MACs
// The verification of the pour requires these MACs
@ -72,9 +77,7 @@ public:
// This is a zk-SNARK which ensures that this pour is valid.
std::string proof;
CPourTx(): vpub_old(0), vpub_new(0), scriptPubKey(), scriptSig(), anchor(), serials(), commitments(), ciphertexts(), macs(), proof() {
}
CPourTx(): vpub_old(0), vpub_new(0) { }
CPourTx(ZerocashParams& params,
const CScript& scriptPubKey,
@ -100,6 +103,7 @@ public:
READWRITE(serials);
READWRITE(commitments);
READWRITE(ciphertexts);
READWRITE(ephemeralKey);
READWRITE(macs);
READWRITE(proof);
}
@ -115,6 +119,7 @@ public:
a.serials == b.serials &&
a.commitments == b.commitments &&
a.ciphertexts == b.ciphertexts &&
a.ephemeralKey == b.ephemeralKey &&
a.macs == b.macs &&
a.proof == b.proof
);

1002
src/test/data/sighash.json

File diff suppressed because one or more lines are too long

183
src/test/noteencryption_tests.cpp

@ -0,0 +1,183 @@
#include "test/test_bitcoin.h"
#include "sodium.h"
#include <stdexcept>
#include "zcash/NoteEncryption.hpp"
#include "zcash/prf.h"
#include <boost/test/unit_test.hpp>
class TestNoteDecryption : public ZCNoteDecryption {
public:
TestNoteDecryption(uint256 sk_enc) : ZCNoteDecryption(sk_enc) {}
void change_pk_enc(uint256 to) {
pk_enc = to;
}
};
BOOST_FIXTURE_TEST_SUITE(noteencryption_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(noteencryption)
{
uint256 sk_enc = ZCNoteEncryption::generate_privkey(uint256S("21035d60bc1983e37950ce4803418a8fb33ea68d5b937ca382ecbae7564d6a77"));
uint256 pk_enc = ZCNoteEncryption::generate_pubkey(sk_enc);
ZCNoteEncryption b = ZCNoteEncryption(uint256());
boost::array<unsigned char, 216> message;
for (unsigned char i = 0; i < 216; i++) {
// Fill the message with dummy data
message[i] = (unsigned char) i;
}
for (int i = 0; i < 255; i++) {
auto ciphertext = b.encrypt(pk_enc, message);
{
ZCNoteDecryption decrypter(sk_enc);
// Test decryption
auto plaintext = decrypter.decrypt(ciphertext, b.get_epk(), uint256(), i);
BOOST_CHECK(plaintext == message);
// Test wrong nonce
BOOST_CHECK_THROW(decrypter.decrypt(ciphertext, b.get_epk(), uint256(), (i == 0) ? 1 : (i - 1)), std::runtime_error);
// Test wrong ephemeral key
BOOST_CHECK_THROW(decrypter.decrypt(ciphertext, ZCNoteEncryption::generate_privkey(uint256()), uint256(), i), std::runtime_error);
// Test wrong seed
BOOST_CHECK_THROW(decrypter.decrypt(ciphertext, b.get_epk(), uint256S("11035d60bc1983e37950ce4803418a8fb33ea68d5b937ca382ecbae7564d6a77"), i), std::runtime_error);
// Test corrupted ciphertext
ciphertext[10] ^= 0xff;
BOOST_CHECK_THROW(decrypter.decrypt(ciphertext, b.get_epk(), uint256(), i), std::runtime_error);
ciphertext[10] ^= 0xff;
}
{
// Test wrong private key
uint256 sk_enc_2 = ZCNoteEncryption::generate_privkey(uint256());
ZCNoteDecryption decrypter(sk_enc_2);
BOOST_CHECK_THROW(decrypter.decrypt(ciphertext, b.get_epk(), uint256(), i), std::runtime_error);
}
{
TestNoteDecryption decrypter(sk_enc);
// Test decryption
auto plaintext = decrypter.decrypt(ciphertext, b.get_epk(), uint256(), i);
BOOST_CHECK(plaintext == message);
// Test wrong public key (test of KDF)
decrypter.change_pk_enc(uint256());
BOOST_CHECK_THROW(decrypter.decrypt(ciphertext, b.get_epk(), uint256(), i), std::runtime_error);
}
}
// Nonce space should run out here
BOOST_CHECK_THROW(b.encrypt(pk_enc, message), std::logic_error);
}
uint256 test_prf(
unsigned char distinguisher,
uint256 x,
uint256 y
) {
*x.begin() &= 0x0f;
*x.begin() |= distinguisher;
CSHA256 hasher;
hasher.Write(x.begin(), 32);
hasher.Write(y.begin(), 32);
uint256 ret;
hasher.FinalizeNoPadding(ret.begin());
return ret;
}
BOOST_AUTO_TEST_CASE(prf_addr)
{
for (size_t i = 0; i < 100; i++) {
uint256 a_sk = libzcash::random_uint256();
uint256 rest;
BOOST_CHECK_MESSAGE(
test_prf(0xc0, a_sk, rest) == PRF_addr_a_pk(a_sk),
a_sk.GetHex()
);
}
for (size_t i = 0; i < 100; i++) {
uint256 a_sk = libzcash::random_uint256();
uint256 rest;
*rest.begin() = 0x01;
BOOST_CHECK_MESSAGE(
test_prf(0xc0, a_sk, rest) == PRF_addr_sk_enc(a_sk),
a_sk.GetHex()
);
}
}
BOOST_AUTO_TEST_CASE(prf_nf)
{
for (size_t i = 0; i < 100; i++) {
uint256 a_sk = libzcash::random_uint256();
uint256 rho = libzcash::random_uint256();
BOOST_CHECK_MESSAGE(
test_prf(0xe0, a_sk, rho) == PRF_nf(a_sk, rho),
a_sk.GetHex() + " and " + rho.GetHex()
);
}
}
BOOST_AUTO_TEST_CASE(prf_pk)
{
for (size_t i = 0; i < 100; i++) {
uint256 a_sk = libzcash::random_uint256();
uint256 h_sig = libzcash::random_uint256();
BOOST_CHECK_MESSAGE(
test_prf(0x00, a_sk, h_sig) == PRF_pk(a_sk, 0, h_sig),
a_sk.GetHex() + " and " + h_sig.GetHex()
);
}
for (size_t i = 0; i < 100; i++) {
uint256 a_sk = libzcash::random_uint256();
uint256 h_sig = libzcash::random_uint256();
BOOST_CHECK_MESSAGE(
test_prf(0x40, a_sk, h_sig) == PRF_pk(a_sk, 1, h_sig),
a_sk.GetHex() + " and " + h_sig.GetHex()
);
}
uint256 dummy;
BOOST_CHECK_THROW(PRF_pk(dummy, 2, dummy), std::domain_error);
}
BOOST_AUTO_TEST_CASE(prf_rho)
{
for (size_t i = 0; i < 100; i++) {
uint256 phi = libzcash::random_uint256();
uint256 h_sig = libzcash::random_uint256();
BOOST_CHECK_MESSAGE(
test_prf(0x20, phi, h_sig) == PRF_rho(phi, 0, h_sig),
phi.GetHex() + " and " + h_sig.GetHex()
);
}
for (size_t i = 0; i < 100; i++) {
uint256 phi = libzcash::random_uint256();
uint256 h_sig = libzcash::random_uint256();
BOOST_CHECK_MESSAGE(
test_prf(0x60, phi, h_sig) == PRF_rho(phi, 1, h_sig),
phi.GetHex() + " and " + h_sig.GetHex()
);
}
uint256 dummy;
BOOST_CHECK_THROW(PRF_rho(dummy, 2, dummy), std::domain_error);
}
BOOST_AUTO_TEST_SUITE_END()

1
src/test/sighash_tests.cpp

@ -129,6 +129,7 @@ void static RandomTransaction(CMutableTransaction &tx, bool fSingle) {
pourtx.anchor = GetRandHash();
pourtx.serials[0] = GetRandHash();
pourtx.serials[1] = GetRandHash();
pourtx.ephemeralKey = GetRandHash();
pourtx.ciphertexts[0] = {insecure_rand() % 100, insecure_rand() % 100};
pourtx.ciphertexts[1] = {insecure_rand() % 100, insecure_rand() % 100};
pourtx.macs[0] = GetRandHash();

56
src/wallet/rpcwallet.cpp

@ -2454,8 +2454,8 @@ Value zc_raw_receive(const json_spirit::Array& params, bool fHelp)
LOCK(cs_main);
std::vector<unsigned char> a_sk;
std::string sk_enc;
uint256 a_sk;
uint256 sk_enc;
{
CDataStream ssData(ParseHexV(params[0], "zcsecretkey"), SER_NETWORK, PROTOCOL_VERSION);
@ -2472,9 +2472,24 @@ Value zc_raw_receive(const json_spirit::Array& params, bool fHelp)
libzerocash::PrivateAddress zcsecretkey(a_sk, sk_enc);
libzerocash::Address zcaddress(zcsecretkey);
auto encrypted_bucket_vec = ParseHexV(params[1], "encrypted_bucket");
std::string encrypted_bucket(encrypted_bucket_vec.begin(), encrypted_bucket_vec.end());
libzerocash::Coin decrypted_bucket(encrypted_bucket, zcaddress);
uint256 epk;
unsigned char nonce;
ZCNoteEncryption::Ciphertext ct;
{
CDataStream ssData(ParseHexV(params[1], "encrypted_bucket"), SER_NETWORK, PROTOCOL_VERSION);
try {
ssData >> nonce;
ssData >> epk;
ssData >> ct;
} catch(const std::exception &) {
throw runtime_error(
"encrypted_bucket could not be decoded"
);
}
}
libzerocash::Coin decrypted_bucket(ct, zcaddress, epk, nonce);
std::vector<unsigned char> commitment_v = decrypted_bucket.getCoinCommitment().getCommitmentValue();
uint256 commitment = uint256(commitment_v);
@ -2565,8 +2580,8 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
ssData >> rho;
ssData >> r;
std::vector<unsigned char> a_sk;
std::string sk_enc;
uint256 a_sk;
uint256 sk_enc;
{
CDataStream ssData2(ParseHexV(s.value_, "zcsecretkey"), SER_NETWORK, PROTOCOL_VERSION);
@ -2608,8 +2623,8 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
{
CDataStream ssData(ParseHexV(s.name_, "to_address"), SER_NETWORK, PROTOCOL_VERSION);
std::vector<unsigned char> pubAddressSecret;
std::string encryptionPublicKey;
uint256 pubAddressSecret;
uint256 encryptionPublicKey;
ssData >> pubAddressSecret;
ssData >> encryptionPublicKey;
@ -2653,9 +2668,28 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << rawTx;
std::string encryptedBucket1;
std::string encryptedBucket2;
{
CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
ss2 << ((unsigned char) 0x00);
ss2 << pourtx.ephemeralKey;
ss2 << pourtx.ciphertexts[0];
encryptedBucket1 = HexStr(ss2.begin(), ss2.end());
}
{
CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
ss2 << ((unsigned char) 0x01);
ss2 << pourtx.ephemeralKey;
ss2 << pourtx.ciphertexts[1];
encryptedBucket2 = HexStr(ss2.begin(), ss2.end());
}
Object result;
result.push_back(Pair("encryptedbucket1", HexStr(pourtx.ciphertexts[0].begin(), pourtx.ciphertexts[0].end())));
result.push_back(Pair("encryptedbucket2", HexStr(pourtx.ciphertexts[1].begin(), pourtx.ciphertexts[1].end())));
result.push_back(Pair("encryptedbucket1", encryptedBucket1));
result.push_back(Pair("encryptedbucket2", encryptedBucket2));
result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
return result;
}

169
src/zcash/NoteEncryption.cpp

@ -0,0 +1,169 @@
#include "NoteEncryption.hpp"
#include <stdexcept>
#include "sodium.h"
#include <boost/static_assert.hpp>
#include "prf.h"
#define NOTEENCRYPTION_CIPHER_KEYSIZE 32
void clamp_curve25519(unsigned char key[crypto_scalarmult_SCALARBYTES])
{
key[0] &= 248;
key[31] &= 127;
key[31] |= 64;
}
void KDF(unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE],
const uint256 &dhsecret,
const uint256 &epk,
const uint256 &pk_enc,
const uint256 &hSig,
unsigned char nonce
)
{
if (nonce == 0xff) {
throw std::logic_error("no additional nonce space for KDF");
}
unsigned char block[128] = {};
memcpy(block+0, hSig.begin(), 32);
memcpy(block+32, dhsecret.begin(), 32);
memcpy(block+64, epk.begin(), 32);
memcpy(block+96, pk_enc.begin(), 32);
unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {};
memcpy(personalization, "ZcashKDF", 8);
memcpy(personalization+8, &nonce, 1);
if (crypto_generichash_blake2b_salt_personal(K, NOTEENCRYPTION_CIPHER_KEYSIZE,
block, 128,
NULL, 0, // No key.
NULL, // No salt.
personalization
) != 0)
{
throw std::logic_error("hash function failure");
}
}
namespace libzcash {
template<size_t MLEN>
NoteEncryption<MLEN>::NoteEncryption(uint256 hSig) : nonce(0), hSig(hSig) {
// All of this code assumes crypto_scalarmult_BYTES is 32
// There's no reason that will _ever_ change, but for
// completeness purposes, let's check anyway.
BOOST_STATIC_ASSERT(32 == crypto_scalarmult_BYTES);
BOOST_STATIC_ASSERT(32 == crypto_scalarmult_SCALARBYTES);
BOOST_STATIC_ASSERT(NOTEENCRYPTION_AUTH_BYTES == crypto_aead_chacha20poly1305_ABYTES);
// Create the ephemeral keypair
esk = random_uint256();
epk = generate_pubkey(esk);
}
template<size_t MLEN>
NoteDecryption<MLEN>::NoteDecryption(uint256 sk_enc) : sk_enc(sk_enc) {
this->pk_enc = NoteEncryption<MLEN>::generate_pubkey(sk_enc);
}
template<size_t MLEN>
typename NoteEncryption<MLEN>::Ciphertext NoteEncryption<MLEN>::encrypt
(const uint256 &pk_enc,
const NoteEncryption<MLEN>::Plaintext &message
)
{
uint256 dhsecret;
if (crypto_scalarmult(dhsecret.begin(), esk.begin(), pk_enc.begin()) != 0) {
throw std::logic_error("Could not create DH secret");
}
// Construct the symmetric key
unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE];
KDF(K, dhsecret, epk, pk_enc, hSig, nonce);
// Increment the number of encryptions we've performed
nonce++;
// The nonce is zero because we never reuse keys
unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {};
NoteEncryption<MLEN>::Ciphertext ciphertext;
crypto_aead_chacha20poly1305_ietf_encrypt(ciphertext.begin(), NULL,
message.begin(), MLEN,
NULL, 0, // no "additional data"
NULL, cipher_nonce, K);
return ciphertext;
}
template<size_t MLEN>
typename NoteDecryption<MLEN>::Plaintext NoteDecryption<MLEN>::decrypt
(const NoteDecryption<MLEN>::Ciphertext &ciphertext,
const uint256 &epk,
const uint256 &hSig,
unsigned char nonce
) const
{
uint256 dhsecret;
if (crypto_scalarmult(dhsecret.begin(), sk_enc.begin(), epk.begin()) != 0) {
throw std::logic_error("Could not create DH secret");
}
unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE];
KDF(K, dhsecret, epk, pk_enc, hSig, nonce);
// The nonce is zero because we never reuse keys
unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {};
NoteDecryption<MLEN>::Plaintext plaintext;
if (crypto_aead_chacha20poly1305_ietf_decrypt(plaintext.begin(), NULL,
NULL,
ciphertext.begin(), NoteDecryption<MLEN>::CLEN,
NULL,
0,
cipher_nonce, K) != 0) {
throw std::runtime_error("Could not decrypt message");
}
return plaintext;
}
template<size_t MLEN>
uint256 NoteEncryption<MLEN>::generate_privkey(const uint256 &a_sk)
{
uint256 sk = PRF_addr_sk_enc(a_sk);
clamp_curve25519(sk.begin());
return sk;
}
template<size_t MLEN>
uint256 NoteEncryption<MLEN>::generate_pubkey(const uint256 &sk_enc)
{
uint256 pk;
if (crypto_scalarmult_base(pk.begin(), sk_enc.begin()) != 0) {
throw std::logic_error("Could not create public key");
}
return pk;
}
uint256 random_uint256()
{
uint256 ret;
randombytes_buf(ret.begin(), 32);
return ret;
}
template class NoteEncryption<ZC_V_SIZE + ZC_RHO_SIZE + ZC_R_SIZE + ZC_MEMO_SIZE>;
template class NoteDecryption<ZC_V_SIZE + ZC_RHO_SIZE + ZC_R_SIZE + ZC_MEMO_SIZE>;
}

79
src/zcash/NoteEncryption.hpp

@ -0,0 +1,79 @@
/*
See the Zcash protocol specification for more information.
https://github.com/zcash/zips/blob/master/protocol/protocol.pdf
*/
#ifndef ZC_NOTE_ENCRYPTION_H_
#define ZC_NOTE_ENCRYPTION_H_
#include <boost/array.hpp>
#include "uint256.h"
#include "zerocash/Zerocash.h"
namespace libzcash {
#define NOTEENCRYPTION_AUTH_BYTES 16
template<size_t MLEN>
class NoteEncryption {
protected:
enum { CLEN=MLEN+NOTEENCRYPTION_AUTH_BYTES };
uint256 epk;
uint256 esk;
unsigned char nonce;
uint256 hSig;
public:
typedef boost::array<unsigned char, CLEN> Ciphertext;
typedef boost::array<unsigned char, MLEN> Plaintext;
NoteEncryption(uint256 hSig);
// Gets the ephemeral public key
uint256 get_epk() {
return epk;
}
// Encrypts `message` with `pk_enc` and returns the ciphertext.
// This can only be called twice for a given instantiation before
// the nonce-space runs out.
Ciphertext encrypt(const uint256 &pk_enc,
const Plaintext &message
);
// Creates a NoteEncryption private key
static uint256 generate_privkey(const uint256 &a_sk);
// Creates a NoteEncryption public key from a private key
static uint256 generate_pubkey(const uint256 &sk_enc);
};
template<size_t MLEN>
class NoteDecryption {
protected:
enum { CLEN=MLEN+NOTEENCRYPTION_AUTH_BYTES };
uint256 sk_enc;
uint256 pk_enc;
public:
typedef boost::array<unsigned char, CLEN> Ciphertext;
typedef boost::array<unsigned char, MLEN> Plaintext;
NoteDecryption(uint256 sk_enc);
Plaintext decrypt(const Ciphertext &ciphertext,
const uint256 &epk,
const uint256 &hSig,
unsigned char nonce
) const;
};
uint256 random_uint256();
}
typedef libzcash::NoteEncryption<ZC_V_SIZE + ZC_RHO_SIZE + ZC_R_SIZE + ZC_MEMO_SIZE> ZCNoteEncryption;
typedef libzcash::NoteDecryption<ZC_V_SIZE + ZC_RHO_SIZE + ZC_R_SIZE + ZC_MEMO_SIZE> ZCNoteDecryption;
#endif /* ZC_NOTE_ENCRYPTION_H_ */

63
src/zcash/prf.cpp

@ -0,0 +1,63 @@
#include "prf.h"
#include "crypto/sha256.h"
uint256 PRF(bool a, bool b, bool c, bool d,
const uint256& x,
const uint256& y)
{
uint256 res;
unsigned char blob[64];
memcpy(&blob[0], x.begin(), 32);
memcpy(&blob[32], y.begin(), 32);
blob[0] &= 0x0F;
blob[0] |= (a ? 1 << 7 : 0) | (b ? 1 << 6 : 0) | (c ? 1 << 5 : 0) | (d ? 1 << 4 : 0);
CSHA256 hasher;
hasher.Write(blob, 64);
hasher.FinalizeNoPadding(res.begin());
return res;
}
uint256 PRF_addr(const uint256& a_sk, unsigned char t)
{
uint256 y;
*(y.begin()) = t;
return PRF(1, 1, 0, 0, a_sk, y);
}
uint256 PRF_addr_a_pk(const uint256& a_sk)
{
return PRF_addr(a_sk, 0);
}
uint256 PRF_addr_sk_enc(const uint256& a_sk)
{
return PRF_addr(a_sk, 1);
}
uint256 PRF_nf(const uint256& a_sk, const uint256& rho)
{
return PRF(1, 1, 1, 0, a_sk, rho);
}
uint256 PRF_pk(const uint256& a_sk, size_t i0, const uint256& h_sig)
{
if ((i0 != 0) && (i0 != 1)) {
throw std::domain_error("PRF_pk invoked with index out of bounds");
}
return PRF(0, i0, 0, 0, a_sk, h_sig);
}
uint256 PRF_rho(const uint256& phi, size_t i0, const uint256& h_sig)
{
if ((i0 != 0) && (i0 != 1)) {
throw std::domain_error("PRF_rho invoked with index out of bounds");
}
return PRF(0, i0, 1, 0, phi, h_sig);
}

17
src/zcash/prf.h

@ -0,0 +1,17 @@
/*
Zcash uses SHA256Compress as a PRF for various components
within the zkSNARK circuit.
*/
#ifndef _PRF_H_
#define _PRF_H_
#include "uint256.h"
uint256 PRF_addr_a_pk(const uint256& a_sk);
uint256 PRF_addr_sk_enc(const uint256& a_sk);
uint256 PRF_nf(const uint256& a_sk, const uint256& rho);
uint256 PRF_pk(const uint256& a_sk, size_t i0, const uint256& h_sig);
uint256 PRF_rho(const uint256& phi, size_t i0, const uint256& h_sig);
#endif // _PRF_H_

63
src/zerocash/Address.cpp

@ -11,26 +11,14 @@
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include <cryptopp/osrng.h>
using CryptoPP::AutoSeededRandomPool;
#include <cryptopp/eccrypto.h>
using CryptoPP::ECP;
using CryptoPP::ECIES;
#include <cryptopp/oids.h>
namespace ASN1 = CryptoPP::ASN1;
#include <cryptopp/filters.h>
using CryptoPP::StringSink;
using CryptoPP::StringStore;
#include "zcash/NoteEncryption.hpp"
#include "Zerocash.h"
#include "Address.h"
namespace libzerocash {
PrivateAddress::PrivateAddress(const std::vector<unsigned char> a_sk, const std::string sk_enc) {
PrivateAddress::PrivateAddress(const uint256 &a_sk, const uint256 &sk_enc) {
this->a_sk = a_sk;
this->sk_enc = sk_enc;
}
@ -47,23 +35,27 @@ bool PrivateAddress::operator!=(const PrivateAddress& rhs) const {
return !(*this == rhs);
}
const std::string PrivateAddress::getEncryptionSecretKey() const {
const uint256& PrivateAddress::getEncryptionSecretKey() const {
return this->sk_enc;
}
const std::vector<unsigned char>& PrivateAddress::getAddressSecret() const {
const uint256& PrivateAddress::getAddressSecret() const {
return this->a_sk;
}
PublicAddress::PublicAddress(): a_pk(ZC_A_PK_SIZE) {
this->pk_enc = "";
PublicAddress::PublicAddress() {
}
PublicAddress::PublicAddress(const std::vector<unsigned char>& a_pk, std::string& pk_enc) : a_pk(a_pk), pk_enc(pk_enc) {}
PublicAddress::PublicAddress(const uint256& a_pk, uint256& pk_enc) : a_pk(a_pk), pk_enc(pk_enc) {}
PublicAddress::PublicAddress(const PrivateAddress& addr_sk): a_pk(ZC_A_PK_SIZE) {
PublicAddress::PublicAddress(const PrivateAddress& addr_sk) {
std::vector<bool> a_sk_bool(ZC_A_SK_SIZE * 8);
convertBytesVectorToVector(addr_sk.getAddressSecret(), a_sk_bool);
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);
@ -73,26 +65,20 @@ PublicAddress::PublicAddress(const PrivateAddress& addr_sk): a_pk(ZC_A_PK_SIZE)
std::vector<bool> a_pk_bool(ZC_A_PK_SIZE * 8);
hashVector(a_pk_internal, a_pk_bool);
convertVectorToBytesVector(a_pk_bool, this->a_pk);
std::vector<unsigned char> a_pk_vv(ZC_A_PK_SIZE);
ECIES<ECP>::PublicKey publicKey;
convertVectorToBytesVector(a_pk_bool, a_pk_vv);
ECIES<ECP>::PrivateKey decodedPrivateKey;
decodedPrivateKey.Load(StringStore(addr_sk.getEncryptionSecretKey()).Ref());
this->a_pk = uint256(a_pk_vv);
decodedPrivateKey.MakePublicKey(publicKey);
std::string encodedPublicKey;
publicKey.Save(StringSink(encodedPublicKey).Ref());
this->pk_enc = encodedPublicKey;
this->pk_enc = ZCNoteEncryption::generate_pubkey(addr_sk.getEncryptionSecretKey());
}
const std::string PublicAddress::getEncryptionPublicKey() const {
const uint256& PublicAddress::getEncryptionPublicKey() const {
return this->pk_enc;
}
const std::vector<unsigned char>& PublicAddress::getPublicAddressSecret() const {
const uint256& PublicAddress::getPublicAddressSecret() const {
return this->a_pk;
}
@ -135,16 +121,11 @@ Address Address::CreateNewRandomAddress() {
getRandBytes(a_sk_bytes, ZC_A_SK_SIZE);
convertBytesToBytesVector(a_sk_bytes, a_sk);
AutoSeededRandomPool prng;
ECIES<ECP>::PrivateKey privateKey;
privateKey.Initialize(prng, ASN1::secp256r1());
std::string encodedPrivateKey;
uint256 a_sk_u(a_sk);
privateKey.Save(StringSink(encodedPrivateKey).Ref());
uint256 sk_enc = ZCNoteEncryption::generate_privkey(a_sk_u);
PrivateAddress addr_sk(a_sk, encodedPrivateKey);
PrivateAddress addr_sk(a_sk_u, sk_enc);
return Address(addr_sk);
}

21
src/zerocash/Address.h

@ -15,6 +15,7 @@
#include <vector>
#include <string>
#include "uint256.h"
namespace libzerocash {
@ -24,17 +25,17 @@ class PrivateAddress {
public:
/* This constructor is to be used ONLY for deserialization. */
PrivateAddress();
PrivateAddress(const std::vector<unsigned char> a_sk, const std::string sk_enc);
PrivateAddress(const uint256 &a_sk, const uint256 &sk_enc);
bool operator==(const PrivateAddress& rhs) const;
bool operator!=(const PrivateAddress& rhs) const;
const std::vector<unsigned char>& getAddressSecret() const;
const std::string getEncryptionSecretKey() const;
const uint256& getAddressSecret() const;
const uint256& getEncryptionSecretKey() const;
private:
std::vector<unsigned char> a_sk;
std::string sk_enc;
uint256 a_sk;
uint256 sk_enc;
};
@ -44,19 +45,19 @@ class PublicAddress {
public:
/* This constructor is to be used ONLY for deserialization. */
PublicAddress();
PublicAddress(const std::vector<unsigned char>& a_pk, std::string& pk_enc);
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 std::vector<unsigned char>& getPublicAddressSecret() const;
const std::string getEncryptionPublicKey() const;
const uint256& getPublicAddressSecret() const;
const uint256& getEncryptionPublicKey() const;
private:
std::vector<unsigned char> a_pk;
std::string pk_enc;
uint256 a_pk;
uint256 pk_enc;
};
/******************************** Address ************************************/

54
src/zerocash/Coin.cpp

@ -11,20 +11,6 @@
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include <cryptopp/osrng.h>
using CryptoPP::AutoSeededRandomPool;
#include <cryptopp/eccrypto.h>
using CryptoPP::ECP;
using CryptoPP::ECIES;
#include <cryptopp/oids.h>
namespace ASN1 = CryptoPP::ASN1;
#include <cryptopp/filters.h>
using CryptoPP::StringSink;
using CryptoPP::StringStore;
#include <stdexcept>
#include "Zerocash.h"
@ -36,29 +22,17 @@ Coin::Coin(): addr_pk(), cm(), rho(ZC_RHO_SIZE), r(ZC_R_SIZE), coinValue(ZC_V_SI
}
Coin::Coin(const std::string bucket, Address& addr): addr_pk(), cm(), rho(ZC_RHO_SIZE), r(ZC_R_SIZE), k(ZC_K_SIZE), coinValue(ZC_V_SIZE) {
// Retreive and decode the private key
ECIES<ECP>::PrivateKey decodedPrivateKey;
decodedPrivateKey.Load(StringStore(addr.getPrivateAddress().getEncryptionSecretKey()).Ref());
// Create the decryption session
AutoSeededRandomPool prng;
ECIES<ECP>::Decryptor decrypt(decodedPrivateKey);
// Convert the input string into a vector of bytes
std::vector<byte> bucket_bytes(bucket.begin(), bucket.end());
// Construct a temporary object to store the plaintext, large enough
// to store the plaintext if it were extended beyond the real size.
std::vector<unsigned char> plaintext;
// Size as needed, filling with zeros.
plaintext.resize(decrypt.MaxPlaintextLength(decrypt.CiphertextLength(ZC_V_SIZE + ZC_R_SIZE + ZC_RHO_SIZE)), 0);
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) {
// Perform the decryption
decrypt.Decrypt(prng,
&bucket_bytes[0],
decrypt.CiphertextLength(ZC_V_SIZE + ZC_R_SIZE + ZC_RHO_SIZE),
&plaintext[0]);
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(),
@ -73,7 +47,8 @@ Coin::Coin(const std::string bucket, Address& addr): addr_pk(), cm(), rho(ZC_RHO
this->rho = rho_v;
this->addr_pk = addr.getPublicAddress();
std::vector<unsigned char> a_pk = addr.getPublicAddress().getPublicAddressSecret();
std::vector<unsigned char> a_pk(addr.getPublicAddress().getPublicAddressSecret().begin(),
addr.getPublicAddress().getPublicAddressSecret().end());
this->computeCommitments(a_pk);
}
@ -82,7 +57,8 @@ Coin::Coin(const PublicAddress& addr, uint64_t value): addr_pk(addr), cm(), rho(
{
convertIntToBytesVector(value, this->coinValue);
std::vector<unsigned char> a_pk = addr.getPublicAddressSecret();
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);
@ -101,7 +77,7 @@ Coin::Coin(const PublicAddress& addr, uint64_t value,
{
convertIntToBytesVector(value, this->coinValue);
std::vector<unsigned char> a_pk = addr.getPublicAddressSecret();
std::vector<unsigned char> a_pk(addr.getPublicAddressSecret().begin(), addr.getPublicAddressSecret().end());
this->computeCommitments(a_pk);
}

4
src/zerocash/Coin.h

@ -17,6 +17,8 @@
#include "Address.h"
#include "CoinCommitment.h"
#include "zcash/NoteEncryption.hpp"
namespace libzerocash {
/********************************* Coin **************************************/
@ -41,7 +43,7 @@ public:
const std::vector<unsigned char>& rho,
const std::vector<unsigned char>& r);
Coin(const std::string bucket, Address& addr);
Coin(const ZCNoteEncryption::Ciphertext&, Address& addr, uint256& epk, unsigned char nonce);
const PublicAddress& getPublicAddress() const;

126
src/zerocash/PourTransaction.cpp

@ -11,25 +11,6 @@
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include <cryptopp/osrng.h>
using CryptoPP::AutoSeededRandomPool;
#include <cryptopp/eccrypto.h>
using CryptoPP::ECP;
using CryptoPP::ECIES;
#include <cryptopp/filters.h>
using CryptoPP::StringSource;
using CryptoPP::StringStore;
using CryptoPP::StringSink;
using CryptoPP::PK_EncryptorFilter;
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
#include <openssl/bn.h>
#include <openssl/sha.h>
#include "Zerocash.h"
#include "PourTransaction.h"
#include "PourInput.h"
@ -113,6 +94,11 @@ PourTransaction::PourTransaction(uint16_t version_num,
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,
@ -168,11 +154,21 @@ void PourTransaction::init(uint16_t version_num,
convertBytesVectorToVector(c_1_new.getCoinCommitment().getCommitmentValue(), cm_new_1_bv);
convertBytesVectorToVector(c_2_new.getCoinCommitment().getCommitmentValue(), cm_new_2_bv);
convertBytesVectorToVector(addr_1_old.getPrivateAddress().getAddressSecret(), addr_sk_old_1_bv);
convertBytesVectorToVector(addr_2_old.getPrivateAddress().getAddressSecret(), addr_sk_old_2_bv);
{
auto a = from_uint256(addr_1_old.getPrivateAddress().getAddressSecret());
auto b = from_uint256(addr_2_old.getPrivateAddress().getAddressSecret());
convertBytesVectorToVector(addr_1_new.getPublicAddressSecret(), addr_pk_new_1_bv);
convertBytesVectorToVector(addr_2_new.getPublicAddressSecret(), addr_pk_new_2_bv);
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);
@ -293,65 +289,45 @@ void PourTransaction::init(uint16_t version_num,
this->zkSNARK = std::string(1235,'A');
}
unsigned char val_new_1_bytes[ZC_V_SIZE];
unsigned char val_new_2_bytes[ZC_V_SIZE];
unsigned char nonce_new_1_bytes[ZC_RHO_SIZE];
unsigned char nonce_new_2_bytes[ZC_RHO_SIZE];
unsigned char rand_new_1_bytes[ZC_R_SIZE];
unsigned char rand_new_2_bytes[ZC_R_SIZE];
convertVectorToBytes(val_new_1_bv, val_new_1_bytes);
convertVectorToBytes(val_new_2_bv, val_new_2_bytes);
convertVectorToBytes(rand_new_1_bv, rand_new_1_bytes);
convertVectorToBytes(rand_new_2_bv, rand_new_2_bytes);
convertVectorToBytes(nonce_new_1_bv, nonce_new_1_bytes);
convertVectorToBytes(nonce_new_2_bv, nonce_new_2_bytes);
std::string val_new_1_string(val_new_1_bytes, val_new_1_bytes + ZC_V_SIZE);
std::string val_new_2_string(val_new_2_bytes, val_new_2_bytes + ZC_V_SIZE);
std::string nonce_new_1_string(nonce_new_1_bytes, nonce_new_1_bytes + ZC_RHO_SIZE);
std::string nonce_new_2_string(nonce_new_2_bytes, nonce_new_2_bytes + ZC_RHO_SIZE);
std::string rand_new_1_string(rand_new_1_bytes, rand_new_1_bytes + ZC_R_SIZE);
std::string rand_new_2_string(rand_new_2_bytes, rand_new_2_bytes + ZC_R_SIZE);
AutoSeededRandomPool prng_1;
AutoSeededRandomPool prng_2;
ECIES<ECP>::PublicKey publicKey_1;
publicKey_1.Load(StringStore(addr_1_new.getEncryptionPublicKey()).Ref());
ECIES<ECP>::Encryptor encryptor_1(publicKey_1);
// 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> ciphertext_1_internals;
ciphertext_1_internals.insert(ciphertext_1_internals.end(), c_1_new.coinValue.begin(), c_1_new.coinValue.end());
ciphertext_1_internals.insert(ciphertext_1_internals.end(), c_1_new.r.begin(), c_1_new.r.end());
ciphertext_1_internals.insert(ciphertext_1_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());
assert(ciphertext_1_internals.size() == (ZC_V_SIZE + ZC_R_SIZE + ZC_RHO_SIZE));
assert(plaintext_internals.size() == 216);
byte gEncryptBuf[encryptor_1.CiphertextLength(ZC_V_SIZE + ZC_R_SIZE + ZC_RHO_SIZE)];
boost::array<unsigned char, 216> pt;
memcpy(&pt[0], &plaintext_internals[0], 216);
encryptor_1.Encrypt(prng_1, &ciphertext_1_internals[0], ZC_V_SIZE + ZC_R_SIZE + ZC_RHO_SIZE, gEncryptBuf);
std::string C_1_string(gEncryptBuf, gEncryptBuf + sizeof gEncryptBuf / sizeof gEncryptBuf[0]);
this->ciphertext_1 = C_1_string;
ECIES<ECP>::PublicKey publicKey_2;
publicKey_2.Load(StringStore(addr_2_new.getEncryptionPublicKey()).Ref());
ECIES<ECP>::Encryptor encryptor_2(publicKey_2);
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> ciphertext_2_internals;
ciphertext_2_internals.insert(ciphertext_2_internals.end(), c_2_new.coinValue.begin(), c_2_new.coinValue.end());
ciphertext_2_internals.insert(ciphertext_2_internals.end(), c_2_new.r.begin(), c_2_new.r.end());
ciphertext_2_internals.insert(ciphertext_2_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());
assert(ciphertext_2_internals.size() == (ZC_V_SIZE + ZC_R_SIZE + ZC_RHO_SIZE));
assert(plaintext_internals.size() == 216);
byte gEncryptBuf_2[encryptor_2.CiphertextLength(ZC_V_SIZE + ZC_R_SIZE + ZC_RHO_SIZE)];
boost::array<unsigned char, 216> pt;
memcpy(&pt[0], &plaintext_internals[0], 216);
encryptor_2.Encrypt(prng_1, &ciphertext_2_internals[0], ZC_V_SIZE + ZC_R_SIZE + ZC_RHO_SIZE, gEncryptBuf_2);
this->ciphertext_2 = encryptor.encrypt(addr_2_new.getEncryptionPublicKey(),
pt);
}
std::string C_2_string(gEncryptBuf_2, gEncryptBuf_2 + sizeof gEncryptBuf_2 / sizeof gEncryptBuf_2[0]);
this->ciphertext_2 = C_2_string;
this->ephemeralKey = encryptor.get_epk();
}
bool PourTransaction::verify(ZerocashParams& params,
@ -434,11 +410,11 @@ const std::vector<unsigned char>& PourTransaction::getSpentSerial2() const{
return this->serialNumber_2;
}
const std::string& PourTransaction::getCiphertext1() const {
const ZCNoteEncryption::Ciphertext& PourTransaction::getCiphertext1() const {
return this->ciphertext_1;
}
const std::string& PourTransaction::getCiphertext2() const {
const ZCNoteEncryption::Ciphertext& PourTransaction::getCiphertext2() const {
return this->ciphertext_2;
}

36
src/zerocash/PourTransaction.h

@ -22,6 +22,9 @@
#include <boost/array.hpp>
#include "uint256.h"
#include "zcash/NoteEncryption.hpp"
typedef std::vector<unsigned char> CoinCommitmentValue;
namespace libzerocash {
@ -113,8 +116,8 @@ public:
const std::vector<unsigned char>& getSpentSerial1() const;
const std::vector<unsigned char>& getSpentSerial2() const;
const std::string& getCiphertext1() const;
const std::string& getCiphertext2() const;
const ZCNoteEncryption::Ciphertext& getCiphertext1() const;
const ZCNoteEncryption::Ciphertext& getCiphertext2() const;
/**
* Returns the hash of the first new coin generated by this Pour.
@ -137,7 +140,8 @@ public:
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<std::string, 2>& ciphertexts
boost::array<ZCNoteEncryption::Ciphertext, 2>& ciphertexts,
uint256& epk
) const {
serials[0] = this->serialNumber_1;
serials[1] = this->serialNumber_2;
@ -147,6 +151,7 @@ public:
macs[1] = this->MAC_2;
ciphertexts[0] = this->ciphertext_1;
ciphertexts[1] = this->ciphertext_2;
epk = this->ephemeralKey;
return this->zkSNARK;
}
@ -179,18 +184,19 @@ public:
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)
std::string ciphertext_1; // ciphertext #1
std::string ciphertext_2; // ciphertext #2
std::string zkSNARK; // contents of the zkSNARK proof itself
uint16_t version; // version for the Pour transaction
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 */

1
src/zerocash/Zerocash.h

@ -33,6 +33,7 @@
#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

Loading…
Cancel
Save