From 8cbec40bec3b9fc4351066ae87a2ee9db216c31b Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 29 Feb 2016 16:44:47 -0800 Subject: [PATCH] bitcoin-tx changes for blinded values --- src/bitcoin-tx.cpp | 76 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 2910ff3a5d..4f74f25e0c 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -7,6 +7,7 @@ #endif #include "base58.h" +#include "blind.h" #include "clientversion.h" #include "coins.h" #include "consensus/consensus.h" @@ -74,7 +75,8 @@ static int AppInitRawTx(int argc, char* argv[]) strUsage = HelpMessageGroup(_("Commands:")); strUsage += HelpMessageOpt("delin=N", _("Delete input N from TX")); strUsage += HelpMessageOpt("delout=N", _("Delete output N from TX")); - strUsage += HelpMessageOpt("in=TXID:VOUT(:SEQUENCE_NUMBER)", _("Add input to TX")); + strUsage += HelpMessageOpt("in=TXID:VOUT:VALUE(:SEQUENCE_NUMBER)", _("Add input to TX")); + strUsage += HelpMessageOpt("blind=B1:B2:B3:...", _("Transaction input blinds")); strUsage += HelpMessageOpt("locktime=N", _("Set TX lock time to N")); strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N")); strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX")); @@ -208,7 +210,7 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu boost::split(vStrInputParts, strInput, boost::is_any_of(":")); // separate TXID:VOUT in string - if (vStrInputParts.size()<2) + if (vStrInputParts.size()<3) throw std::runtime_error("TX input missing separator"); // extract and validate TXID @@ -226,14 +228,21 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu if ((vout < 0) || (vout > (int)maxVout)) throw std::runtime_error("invalid TX input vout"); + // extract and validate VALUE + std::string strValue = vStrInputParts[2]; + CAmount value; + if (!ParseMoney(strValue, value)) + throw std::runtime_error("invalid TX output value"); + // extract the optional sequence number uint32_t nSequenceIn=std::numeric_limits::max(); - if (vStrInputParts.size() > 2) - nSequenceIn = std::stoul(vStrInputParts[2]); + if (vStrInputParts.size() > 3) + nSequenceIn = std::stoul(vStrInputParts[3]); // append to transaction input list CTxIn txin(txid, vout, CScript(), nSequenceIn); tx.vin.push_back(txin); + tx.nTxFee += value; } static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strInput) @@ -258,7 +267,12 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strIn // construct TxOut, append to transaction output list CTxOut txout(value, scriptPubKey); + if (addr.IsBlinded()) { + CPubKey pubkey = addr.GetBlindingKey(); + txout.nValue.vchNonceCommitment = std::vector(pubkey.begin(), pubkey.end()); + } tx.vout.push_back(txout); + tx.nTxFee -= value; } static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& strInput) @@ -397,6 +411,52 @@ static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strIn CTxOut txout(value, CScript() << OP_RETURN << data); tx.vout.push_back(txout); + tx.nTxFee -= value; +} + +static void MutateTxBlind(CMutableTransaction& tx, const std::string& strInput) +{ + std::vector input_blinding_factors; + boost::split(input_blinding_factors, strInput, boost::is_any_of(":")); + + if (input_blinding_factors.size() != tx.vin.size()) + throw std::runtime_error("One input blinding factor required per transaction input"); + + bool fBlindedIns = false; + bool fBlindedOuts = false; + std::vector input_blinds; + std::vector output_blinds; + std::vector output_pubkeys; + for (size_t nIn = 0; nIn < tx.vin.size(); nIn++) { + uint256 blind; + blind.SetHex(input_blinding_factors[nIn]); + if (blind.size() == 0) { + input_blinds.push_back(blind); + } else if (blind.size() == 32) { + input_blinds.push_back(blind); + fBlindedIns = true; + } + } + for (size_t nOut = 0; nOut < tx.vout.size(); nOut++) { + if (!tx.vout[nOut].nValue.IsAmount()) + throw std::runtime_error("Invalid parameter: transaction outputs must be unblinded"); + if (tx.vout[nOut].nValue.vchNonceCommitment.size() == 0) { + output_pubkeys.push_back(CPubKey()); + } else { + CPubKey pubkey(tx.vout[nOut].nValue.vchNonceCommitment); + if (!pubkey.IsValid()) { + throw std::runtime_error("Invalid parameter: invalid confidentiality public key given"); + } + output_pubkeys.push_back(pubkey); + fBlindedOuts = true; + } + output_blinds.push_back(uint256()); + } + + if (fBlindedIns && !fBlindedOuts) { + throw std::runtime_error("Confidential inputs without confidential outputs"); + } + BlindOutputs(input_blinds, output_blinds, output_pubkeys, tx); } static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& strInput) @@ -434,10 +494,13 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& str // construct TxOut, append to transaction output list CTxOut txout(value, scriptPubKey); tx.vout.push_back(txout); + tx.nTxFee -= value; } static void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInIdx) { + // TODO: reduce nTxFee + // parse requested deletion index int inIdx = atoi(strInIdx); if (inIdx < 0 || inIdx >= (int)tx.vin.size()) { @@ -451,6 +514,8 @@ static void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInId static void MutateTxDelOutput(CMutableTransaction& tx, const std::string& strOutIdx) { + // TODO: increase nTxFee + // parse requested deletion index int outIdx = atoi(strOutIdx); if (outIdx < 0 || outIdx >= (int)tx.vout.size()) { @@ -685,6 +750,9 @@ static void MutateTx(CMutableTransaction& tx, const std::string& command, else if (command == "sign") { if (!ecc) { ecc.reset(new Secp256k1Init()); } MutateTxSign(tx, commandVal); + } else if (command == "blind") { + if (!ecc) { ecc.reset(new Secp256k1Init()); } + MutateTxBlind(tx, commandVal); } else if (command == "load")