Skip to content

Commit

Permalink
WIP: First pass at PSBT for Confidential Assets
Browse files Browse the repository at this point in the history
  • Loading branch information
gwillen committed May 2, 2019
1 parent 506f57b commit d7a44e5
Show file tree
Hide file tree
Showing 10 changed files with 1,004 additions and 137 deletions.
1 change: 1 addition & 0 deletions src/core_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,6 @@ std::string SighashToStr(unsigned char sighash_type);
void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
void ScriptToUniv(const CScript& script, UniValue& out, bool include_address);
void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0);
std::string EncodePSBT(const PartiallySignedTransaction& psbt);

#endif // BITCOIN_CORE_IO_H
30 changes: 22 additions & 8 deletions src/core_write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <issuance.h>
#include <key_io.h>
#include <script/script.h>
#include <script/sign.h>
#include <script/standard.h>
#include <serialize.h>
#include <streams.h>
Expand Down Expand Up @@ -327,15 +328,21 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
uint64_t minv;
uint64_t maxv;
const CTxOutWitness* ptxoutwit = tx.witness.vtxoutwit.size() <= i? NULL: &tx.witness.vtxoutwit[i];
if (ptxoutwit && secp256k1_rangeproof_info(secp256k1_blind_context, &exp, &mantissa, &minv, &maxv, &ptxoutwit->vchRangeproof[0], ptxoutwit->vchRangeproof.size())) {
if (exp == -1) {
out.pushKV("value", ValueFromAmount((CAmount)minv));
} else {
out.pushKV("value-minimum", ValueFromAmount((CAmount)minv));
out.pushKV("value-maximum", ValueFromAmount((CAmount)maxv));
if (ptxoutwit) {
if (ptxoutwit->vchRangeproof.size() && secp256k1_rangeproof_info(secp256k1_blind_context, &exp, &mantissa, &minv, &maxv, &ptxoutwit->vchRangeproof[0], ptxoutwit->vchRangeproof.size())) {
if (exp == -1) {
out.pushKV("value", ValueFromAmount((CAmount)minv));
} else {
out.pushKV("value-minimum", ValueFromAmount((CAmount)minv));
out.pushKV("value-maximum", ValueFromAmount((CAmount)maxv));
}
out.pushKV("ct-exponent", exp);
out.pushKV("ct-bits", mantissa);
}

if (ptxoutwit->vchSurjectionproof.size()) {
out.pushKV("surjectionproof", HexStr(ptxoutwit->vchSurjectionproof));
}
out.pushKV("ct-exponent", exp);
out.pushKV("ct-bits", mantissa);
}
out.pushKV("valuecommitment", txout.nValue.GetHex());
}
Expand Down Expand Up @@ -366,3 +373,10 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
entry.pushKV("hex", EncodeHexTx(tx, serialize_flags)); // The hex-encoded transaction. Used the name "hex" to be consistent with the verbose output of "getrawtransaction".
}
}

std::string EncodePSBT(const PartiallySignedTransaction& psbt)
{
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << psbt;
return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size());
}
288 changes: 255 additions & 33 deletions src/rpc/rawtransaction.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/rpc/rawtransaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ class UniValue;
UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxs, CBasicKeyStore *keystore, bool tempKeystore, const UniValue& hashType);

/** Create a transaction from univalue parameters */
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf, const UniValue& assets_in);
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf, const UniValue& assets_in, std::vector<CPubKey>* output_pubkeys_out = nullptr);

#endif // BITCOIN_RPC_RAWTRANSACTION_H
51 changes: 37 additions & 14 deletions src/script/sign.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <script/sign.h>

#include <confidential_validation.h>
#include <key.h>
#include <policy/policy.h>
#include <primitives/transaction.h>
Expand Down Expand Up @@ -241,27 +242,31 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
return sigdata.complete;
}

bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, int index, int sighash)
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, int sighash)
{
fprintf(stderr, "signpsbtinput called!\n");
const CMutableTransaction& tx = *psbt.tx;
PSBTInput& input = psbt.inputs[index];

// if this input has a final scriptsig or scriptwitness, don't do anything with it
if (!input.final_script_sig.empty() || !input.final_script_witness.IsNull()) {
fprintf(stderr, "already signed, though\n");
return true;
}

// Fill SignatureData with input info
SignatureData sigdata;
input.FillSignatureData(sigdata);

// Get UTXO
// Get UTXO for this input
bool require_witness_sig = false;
CTxOut utxo;

if (input.non_witness_utxo) {
// If we're taking our information from a non-witness UTXO, verify that it matches the prevout.
if (input.non_witness_utxo->GetHash() != tx.vin[index].prevout.hash) return false;
// If both witness and non-witness UTXO are provided, verify that they match. This check shouldn't
// matter, as the PSBT deserializer enforces only one of both is provided, and the only way both
// can be present is when they're added simultaneously by FillPSBT (in which case they always match).
// Still, check in order to not rely on callers to enforce this.
// If both witness and non-witness UTXO are provided, verify that they match. This should not
// actually be possible.
if (!input.witness_utxo.IsNull() && input.non_witness_utxo->vout[tx.vin[index].prevout.n] != input.witness_utxo) return false;
utxo = input.non_witness_utxo->vout[tx.vin[index].prevout.n];
} else if (!input.witness_utxo.IsNull()) {
Expand All @@ -275,20 +280,24 @@ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& t
return false;
}

fprintf(stderr, "gathering utxos\n");

MutableTransactionSignatureCreator creator(&tx, index, utxo.nValue, sighash);
sigdata.witness = false;
fprintf(stderr, "about to produce signature\n");
bool sig_complete = ProduceSignature(provider, creator, utxo.scriptPubKey, sigdata);
fprintf(stderr, "sig complete: %d\n", sig_complete);
// Verify that a witness signature was produced in case one was required.
if (require_witness_sig && !sigdata.witness) return false;
if (require_witness_sig && !sigdata.witness) {
fprintf(stderr, "oh no, witness problem\n");
return false;
}
input.FromSignatureData(sigdata);

// If both UTXO types are present, drop the unnecessary one.
if (input.non_witness_utxo && !input.witness_utxo.IsNull()) {
if (sigdata.witness) {
input.non_witness_utxo = nullptr;
} else {
input.witness_utxo.SetNull();
}
// If we have a witness signature, use the smaller witness UTXO.
if (sigdata.witness) {
input.witness_utxo = utxo;
input.non_witness_utxo = nullptr;
}

return sig_complete;
Expand Down Expand Up @@ -614,6 +623,11 @@ void PSBTInput::Merge(const PSBTInput& input)
if (witness_script.empty() && !input.witness_script.empty()) witness_script = input.witness_script;
if (final_script_sig.empty() && !input.final_script_sig.empty()) final_script_sig = input.final_script_sig;
if (final_script_witness.IsNull() && !input.final_script_witness.IsNull()) final_script_witness = input.final_script_witness;

if (!value && input.value) value = input.value;
if (value_blinding_factor.IsNull() && !input.value_blinding_factor.IsNull()) value_blinding_factor = input.value_blinding_factor;
if (asset.IsNull() && !input.asset.IsNull()) asset = input.asset;
if (asset_blinding_factor.IsNull() && !input.asset_blinding_factor.IsNull()) asset_blinding_factor = input.asset_blinding_factor;
}

bool PSBTInput::IsSane() const
Expand Down Expand Up @@ -666,6 +680,15 @@ void PSBTOutput::Merge(const PSBTOutput& output)

if (redeem_script.empty() && !output.redeem_script.empty()) redeem_script = output.redeem_script;
if (witness_script.empty() && !output.witness_script.empty()) witness_script = output.witness_script;

if (!blinding_pubkey.IsValid() && output.blinding_pubkey.IsValid()) blinding_pubkey = output.blinding_pubkey;
if (value_commitment.IsNull() && !output.value_commitment.IsNull()) value_commitment = output.value_commitment;
if (value_blinding_factor.IsNull() && !output.value_blinding_factor.IsNull()) value_blinding_factor = output.value_blinding_factor;
if (asset_commitment.IsNull() && !output.asset_commitment.IsNull()) asset_commitment = output.asset_commitment;
if (asset_blinding_factor.IsNull() && !output.asset_blinding_factor.IsNull()) asset_blinding_factor = output.asset_blinding_factor;
if (nonce_commitment.IsNull() && !output.nonce_commitment.IsNull()) nonce_commitment = output.nonce_commitment;
if (range_proof.empty() && !output.range_proof.empty()) range_proof = output.range_proof;
if (surjection_proof.empty() && !output.surjection_proof.empty()) surjection_proof = output.surjection_proof;
}

bool HidingSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const
Expand Down
Loading

0 comments on commit d7a44e5

Please sign in to comment.