Files
agrarian/src/test/tutorial_zerocoin.cpp
T
2022-02-03 23:45:47 -08:00

285 lines
13 KiB
C++

/**
* @file tutorial.cpp
*
* @brief Simple tutorial program to illustrate Zerocoin usage.
*
* @author Ian Miers, Christina Garman and Matthew Green
* @date June 2013
*
* @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green
* @license This project is released under the MIT license.
**/
// Copyright (c) 2017-2018 The PIVX developers
#include <boost/test/unit_test.hpp>
#include <string>
#include <iostream>
#include <fstream>
// #include <curses.h>
#include <exception>
#include "streams.h"
#include "libzerocoin/bignum.h"
#include "libzerocoin/ParamGeneration.h"
#include "libzerocoin/Denominations.h"
#include "libzerocoin/Coin.h"
#include "libzerocoin/CoinSpend.h"
#include "libzerocoin/Accumulator.h"
#include "test_agrarian.h"
using namespace std;
#define COINS_TO_ACCUMULATE 5
#define DUMMY_TRANSACTION_HASH 0 // in real life these would be uint256 hashes
#define DUMMY_ACCUMULATOR_ID 0 // in real life these would be uint256 hashes
//
// We generated this for testing only. Don't use it in production!
//
#define TUTORIAL_TEST_MODULUS "a8852ebf7c49f01cd196e35394f3b74dd86283a07f57e0a262928e7493d4a3961d93d93c90ea3369719641d626d28b9cddc6d9307b9aabdbffc40b6d6da2e329d079b4187ff784b2893d9f53e9ab913a04ff02668114695b07d8ce877c4c8cac1b12b9beff3c51294ebe349eca41c24cd32a6d09dd1579d3947e5c4dcc30b2090b0454edb98c6336e7571db09e0fdafbd68d8f0470223836e90666a5b143b73b9cd71547c917bf24c0efc86af2eba046ed781d9acb05c80f007ef5a0a5dfca23236f37e698e8728def12554bc80f294f71c040a88eff144d130b24211016a97ce0f5fe520f477e555c9997683d762aff8bd1402ae6938dd5c994780b1bf6aa7239e9d8101630ecfeaa730d2bbc97d39beb057f016db2e28bf12fab4989c0170c2593383fd04660b5229adcd8486ba78f6cc1b558bcd92f344100dff239a8c00dbc4c2825277f24bdd04475bcc9a8c39fd895eff97c1967e434effcb9bd394e0577f4cf98c30d9e6b54cd47d6e447dcf34d67e48e4421691dbe4a7d9bd503abb9"
//
// The following routine exercises most of the core functions of
// the library. We've commented it as well as possible to give
// you the flavor of how libzerocoin works.
//
// For details on Zerocoin integration, see the libzerocoin wiki
// at: https://github.com/Zerocoin/libzerocoin/wiki
//
bool
ZerocoinTutorial()
{
// The following simple code illustrates the call flow for Zerocoin
// applications. In a real currency network these operations would
// be split between individual payers/payees, network nodes and miners.
//
// For each call we specify the participant who would use it.
// Zerocoin uses exceptions (based on the runtime_error class)
// to indicate all sorts of problems. Always remember to catch them!
try {
/********************************************************************/
// What is it: Parameter loading
// Who does it: ALL ZEROCOIN PARTICIPANTS
// What it does: Loads a trusted Zerocoin modulus "N" and
// generates all associated parameters from it.
// We use a hardcoded "N" that we generated using
// the included 'paramgen' utility.
/********************************************************************/
// Load a test modulus from our hardcoded string (above)
CBigNum testModulus;
testModulus.SetHex(std::string(TUTORIAL_TEST_MODULUS));
// Set up the Zerocoin Params object
libzerocoin::ZerocoinParams* params = new libzerocoin::ZerocoinParams(testModulus);
cout << "Successfully loaded parameters." << endl;
/********************************************************************/
// What is it: Coin generation
// Who does it: ZEROCOIN CLIENTS
// What it does: Generates a new 'zerocoin' coin using the
// public parameters. Once generated, the client
// will transmit the public portion of this coin
// in a ZEROCOIN_MINT transaction. The inputs
// to this transaction must add up to the zerocoin
// denomination plus any transaction fees.
/********************************************************************/
// The following constructor does all the work of minting a brand
// new zerocoin. It stores all the private values inside the
// PrivateCoin object. This includes the coin secrets, which must be
// stored in a secure location (wallet) at the client.
libzerocoin::PrivateCoin newCoin(params, libzerocoin::CoinDenomination::ZQ_ONE);
// Get a copy of the 'public' portion of the coin. You should
// embed this into a Zerocoin 'MINT' transaction along with a series
// of currency inputs totaling the assigned value of one zerocoin.
libzerocoin::PublicCoin pubCoin = newCoin.getPublicCoin();
cout << "Successfully minted a zerocoin." << endl;
// Serialize the public coin to a CDataStream object.
CDataStream serializedCoin(SER_NETWORK, PROTOCOL_VERSION);
serializedCoin << pubCoin;
/********************************************************************/
// What is it: Coin verification
// Who does it: TRANSACTION VERIFIERS
// What it does: Verifies the structure of a zerocoin obtained from
// a ZEROCOIN_MINT transaction. All coins must be
// verified before you operate on them.
// Note that this is only part of the transaction
// verification process! The client must also check
// that (1) the inputs to the transaction are valid
// and add up to the value of one zerocoin, (2) that
// this particular zerocoin has not been minted before.
/********************************************************************/
// Deserialize the public coin into a fresh object.
libzerocoin::PublicCoin pubCoinNew(params, serializedCoin);
// Now make sure the coin is valid.
if (!pubCoinNew.validate()) {
// If this returns false, don't accept the coin for any purpose!
// Any ZEROCOIN_MINT with an invalid coin should NOT be
// accepted as a valid transaction in the block chain.
cout << "Error: coin is not valid!";
}
cout << "Deserialized and verified the coin." << endl;
/********************************************************************/
// What is it: Accumulator computation
// Who does it: ZEROCOIN CLIENTS & TRANSACTION VERIFIERS
// What it does: Collects a number of PublicCoin values drawn from
// the block chain and calculates an accumulator.
// This accumulator is incrementally computable;
// you can stop and serialize it at any point
// then continue accumulating new transactions.
// The accumulator is also order-independent, so
// the same coins can be accumulated in any order
// to give the same result.
// WARNING: do not accumulate the same coin twice!
/********************************************************************/
// Create an empty accumulator object
libzerocoin::Accumulator accumulator(params,libzerocoin::CoinDenomination::ZQ_ONE);
// Add several coins to it (we'll generate them here on the fly).
for (uint32_t i = 0; i < COINS_TO_ACCUMULATE; i++) {
libzerocoin::PrivateCoin testCoin(params, libzerocoin::CoinDenomination::ZQ_ONE);
accumulator += testCoin.getPublicCoin();
}
// Serialize the accumulator object.
//
// If you're using Accumulator Checkpoints, each miner would
// start by deserializing the accumulator checkpoint from the
// previous block (or creating a new Accumulator if no previous
// block exists). It will then add all the coins in the new block,
// then serialize the resulting Accumulator object to obtain the
// new checkpoint. All block verifiers should do the same thing
// to check their work.
CDataStream serializedAccumulator(SER_NETWORK, PROTOCOL_VERSION);
serializedAccumulator << accumulator;
// Deserialize the accumulator object
libzerocoin::Accumulator newAccumulator(params, serializedAccumulator);
// We can now continue accumulating things into the accumulator
// we just deserialized. For example, let's put in the coin
// we generated up above.
newAccumulator += pubCoinNew;
cout << "Successfully accumulated coins." << endl;
/********************************************************************/
// What is it: Coin spend
// Who does it: ZEROCOIN CLIENTS
// What it does: Create a new transaction that spends a Zerocoin.
// The user first authors a transaction specifying
// a set of destination addresses (outputs). They
// next compute an Accumulator over all coins in the
// block chain (see above) and a Witness based on the
// coin to be spent. Finally they instantiate a CoinSpend
// object that 'signs' the transaction with a special
// zero knowledge signature of knowledge over the coin
// data, Witness and Accumulator.
/********************************************************************/
// We are going to spend the coin "newCoin" that we generated at the
// top of this function.
//
// We'll use the accumulator we constructed above. This contains
// a set of coins, but does NOT include the coin "newCoin".
//
// To generate the witness, we start with this accumulator and
// add the public half of the coin we want to spend.
libzerocoin::AccumulatorWitness witness(params, accumulator, newCoin.getPublicCoin());
// Add the public half of "newCoin" to the Accumulator itself.
accumulator += newCoin.getPublicCoin();
// At this point we should generate a ZEROCOIN_SPEND transaction to
// send to the network. This network should include a set of outputs
// totalling to the value of one zerocoin (minus transaction fees).
// Construct the CoinSpend object. This acts like a signature on the
// transaction.
libzerocoin::CoinSpend spend(params, params, newCoin, accumulator, 0, witness, 0, libzerocoin::SpendType::SPEND);//(0) - Presstab
// This is a sanity check. The CoinSpend object should always verify,
// but why not check before we put it onto the wire?
if (!spend.Verify(accumulator)) {
cout << "ERROR: Our new CoinSpend transaction did not verify!" << endl;
return false;
}
// Serialize the CoinSpend object into a buffer.
CDataStream serializedCoinSpend(SER_NETWORK, PROTOCOL_VERSION);
serializedCoinSpend << spend;
cout << "Successfully generated a coin spend transaction." << endl;
/********************************************************************/
// What is it: Coin spend verification
// Who does it: ALL PARTIES
// What it does: Verifies that a CoinSpend signature is correct
// with respect to a ZEROCOIN_SPEND transaction hash.
// The client must also extract the serial number from
// the CoinSpend and verify that this serial number has
// not previously appeared in another ZEROCOIN_SPEND
// transaction.
/********************************************************************/
// Deserialize the CoinSpend intro a fresh object
libzerocoin::CoinSpend newSpend(params, params, serializedCoinSpend);
// Create a new metadata object to contain the hash of the received
// ZEROCOIN_SPEND transaction. If we were a real client we'd actually
// compute the hash of the received transaction here.
// If we were a real client we would now re-compute the Accumulator
// from the information given in the ZEROCOIN_SPEND transaction.
// For our purposes we'll just use the one we calculated above.
//
// Verify that the spend is valid with respect to the Accumulator
// and the Metadata
if (!newSpend.Verify(accumulator)) {
cout << "ERROR: The CoinSpend transaction did not verify!" << endl;
return false;
}
// Pull the serial number out of the CoinSpend object. If we
// were a real Zerocoin client we would now check that the serial number
// has not been spent before (in another ZEROCOIN_SPEND) transaction.
// The serial number is stored as a CBigNum.
CBigNum serialNumber = newSpend.getCoinSerialNumber();
cout << "Successfully verified a coin spend transaction." << endl;
cout << endl << "Coin serial number is:" << endl << serialNumber << endl;
// We're done
return true;
} catch (runtime_error &e) {
cout << e.what() << endl;
return false;
}
return false;
}
BOOST_FIXTURE_TEST_SUITE(tutorial_libzerocoin, TestingSetup)
BOOST_AUTO_TEST_CASE(tutorial_libzerocoin_tests)
{
cout << "libzerocoin v" << ZEROCOIN_VERSION_STRING << " tutorial." << endl << endl;
ZerocoinTutorial();
}
BOOST_AUTO_TEST_SUITE_END()