Skip to content

Commit

Permalink
de-dupe calculate_contract code
Browse files Browse the repository at this point in the history
  • Loading branch information
instagibbs committed Nov 6, 2017
1 parent 6534bd3 commit 13c3dad
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 105 deletions.
105 changes: 68 additions & 37 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2294,6 +2294,72 @@ bool BitcoindRPCCheck(const bool init)
return true;
}

/* Takes federation redeeem script and adds HMAC_SHA256(pubkey, witnessProgram) as a tweak to each pubkey */
CScript calculate_contract(const CScript& federationRedeemScript, const CScript& witnessProgram) {
CScript scriptDestination(federationRedeemScript);
int version;
std::vector<unsigned char> program;
if (!witnessProgram.IsWitnessProgram(version, program)) {
assert(false);
}
txnouttype type;
std::vector<std::vector<unsigned char> > solutions;
// Sanity check fedRedeemScript
if (!Solver(federationRedeemScript, type, solutions) || (type != TX_MULTISIG && type != TX_TRUE)) {
assert(false);
}

{
CScript::iterator sdpc = scriptDestination.begin();
std::vector<unsigned char> vch;
opcodetype opcodeTmp;
while (scriptDestination.GetOp(sdpc, opcodeTmp, vch))
{
if (vch.size() == 33)
{

unsigned char tweak[32];
size_t pub_len = 33;
int ret;
unsigned char *pub_start = &(*(sdpc - pub_len));
CHMAC_SHA256(pub_start, pub_len).Write(witnessProgram.data(), witnessProgram.size()).Finalize(tweak);
secp256k1_pubkey watchman;
secp256k1_pubkey tweaked;
ret = secp256k1_ec_pubkey_parse(secp256k1_ctx_verify_amounts, &watchman, pub_start, pub_len);
assert(ret == 1);
ret = secp256k1_ec_pubkey_parse(secp256k1_ctx_verify_amounts, &tweaked, pub_start, pub_len);
assert(ret == 1);
// If someone creates a tweak that makes this fail, they broke SHA256
ret = secp256k1_ec_pubkey_tweak_add(secp256k1_ctx_verify_amounts, &tweaked, tweak);
assert(ret == 1);
ret = secp256k1_ec_pubkey_serialize(secp256k1_ctx_verify_amounts, pub_start, &pub_len, &tweaked, SECP256K1_EC_COMPRESSED);
assert(ret == 1);
assert(pub_len == 33);

// Sanity checks to reduce pegin risk. If the tweaked
// value flips a bit, we may lose pegin funds irretrievably.
// We take the tweak, derive its pubkey and check that
// `tweaked - watchman = tweak` to check the computation
// two different ways
secp256k1_pubkey tweaked2;
ret = secp256k1_ec_pubkey_create(secp256k1_ctx_verify_amounts, &tweaked2, tweak);
assert(ret);
ret = secp256k1_ec_pubkey_negate(secp256k1_ctx_verify_amounts, &watchman);
assert(ret);
secp256k1_pubkey* pubkey_combined[2];
pubkey_combined[0] = &watchman;
pubkey_combined[1] = &tweaked;
secp256k1_pubkey maybe_tweaked2;
ret = secp256k1_ec_pubkey_combine(secp256k1_ctx_verify_amounts, &maybe_tweaked2, pubkey_combined, 2);
assert(ret);
assert(!memcmp(&maybe_tweaked2, &tweaked2, 64));
}
}
}

return scriptDestination;
}

bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& prevout) {

// Format on stack is as follows:
Expand Down Expand Up @@ -2395,45 +2461,10 @@ bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& p
}

// Check that the witness program matches the p2ch on the transaction output
opcodetype opcodeTmp;
CScript fedpegscript = Params().GetConsensus().fedpegScript;

// fedpegscript should be multisig or OP_TRUE
// When set to OP_TRUE, the witness program can be any valid witness program
// as there are no pubkeys to tweak. This means typically in regtest there
// is no spending authorization for peg-in inputs.
txnouttype type;
std::vector<std::vector<unsigned char> > solutions;
if (!Solver(fedpegscript, type, solutions) || (type != TX_MULTISIG && type != TX_TRUE)) {
assert(false);
}
{
CScript::iterator sdpc = fedpegscript.begin();
std::vector<unsigned char> vch;
while (fedpegscript.GetOp(sdpc, opcodeTmp, vch))
{
if (vch.size() == 33)
{
unsigned char tweak[32];
size_t pub_len = 33;
int ret;
unsigned char *pub_start = &(*(sdpc - pub_len));
CHMAC_SHA256(pub_start, pub_len).Write(witness_program.data(), witness_program.size()).Finalize(tweak);
secp256k1_pubkey pubkey;
ret = secp256k1_ec_pubkey_parse(secp256k1_ctx_verify_amounts, &pubkey, pub_start, pub_len);
assert(ret == 1);
// If someone creates a tweak that makes this fail, they broke SHA256
ret = secp256k1_ec_pubkey_tweak_add(secp256k1_ctx_verify_amounts, &pubkey, tweak);
assert(ret == 1);
ret = secp256k1_ec_pubkey_serialize(secp256k1_ctx_verify_amounts, pub_start, &pub_len, &pubkey, SECP256K1_EC_COMPRESSED);
assert(ret == 1);
assert(pub_len == 33);
}
}
}
CScript tweaked_fedpegscript = calculate_contract(Params().GetConsensus().fedpegScript, witness_program);

// Check against expected p2sh output
CScriptID expectedP2SH(fedpegscript);
CScriptID expectedP2SH(tweaked_fedpegscript);
CScript expected_script(CScript() << OP_HASH160 << ToByteVector(expectedP2SH) << OP_EQUAL);
if (pegtx->vout[prevout.n].scriptPubKey != expected_script) {
return false;
Expand Down
3 changes: 3 additions & 0 deletions src/validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,9 @@ void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPr
/** Produce the necessary coinbase commitment for a block (modifies the hash, don't call for mined blocks). */
std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams);

/** Calculates script necessary for p2ch peg-in transactions */
CScript calculate_contract(const CScript& federationRedeemScript, const CScript& witnessProgram);

/** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */
class CVerifyDB {
public:
Expand Down
70 changes: 2 additions & 68 deletions src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3389,72 +3389,6 @@ class CSecp256k1Init {
static CSecp256k1Init instance_of_csecp256k1;
}

/* Takes federation redeeem script and adds SHA2(witnessProgram) as a tweak to each pubkey */
CScriptID calculate_contract(const CScript& federationRedeemScript, const CScript& witnessProgram) {
CScript scriptDestination(federationRedeemScript);
int version;
std::vector<unsigned char> program;
if (!witnessProgram.IsWitnessProgram(version, program)) {
assert(false);
}
txnouttype type;
std::vector<std::vector<unsigned char> > solutions;
// Sanity check fedRedeemScript
if (!Solver(federationRedeemScript, type, solutions) || (type != TX_MULTISIG && type != TX_TRUE)) {
assert(false);
}

{
CScript::iterator sdpc = scriptDestination.begin();
vector<unsigned char> vch;
opcodetype opcodeTmp;
while (scriptDestination.GetOp(sdpc, opcodeTmp, vch))
{
if (vch.size() == 33)
{

unsigned char tweak[32];
size_t pub_len = 33;
int ret;
unsigned char *pub_start = &(*(sdpc - pub_len));
CHMAC_SHA256(pub_start, pub_len).Write(witnessProgram.data(), witnessProgram.size()).Finalize(tweak);
secp256k1_pubkey watchman;
secp256k1_pubkey tweaked;
ret = secp256k1_ec_pubkey_parse(secp256k1_ctx, &watchman, pub_start, pub_len);
assert(ret == 1);
ret = secp256k1_ec_pubkey_parse(secp256k1_ctx, &tweaked, pub_start, pub_len);
assert(ret == 1);
// If someone creates a tweak that makes this fail, they broke SHA256
ret = secp256k1_ec_pubkey_tweak_add(secp256k1_ctx, &tweaked, tweak);
assert(ret == 1);
ret = secp256k1_ec_pubkey_serialize(secp256k1_ctx, pub_start, &pub_len, &tweaked, SECP256K1_EC_COMPRESSED);
assert(ret == 1);
assert(pub_len == 33);

// Sanity checks to reduce pegin risk. If the tweaked
// value flips a bit, we may lose pegin funds irretrievably.
// We take the tweak, derive its pubkey and check that
// `tweaked - watchman = tweak` to check the computation
// two different ways
secp256k1_pubkey tweaked2;
ret = secp256k1_ec_pubkey_create(secp256k1_ctx, &tweaked2, tweak);
assert(ret);
ret = secp256k1_ec_pubkey_negate(secp256k1_ctx, &watchman);
assert(ret);
secp256k1_pubkey* pubkey_combined[2];
pubkey_combined[0] = &watchman;
pubkey_combined[1] = &tweaked;
secp256k1_pubkey maybe_tweaked2;
ret = secp256k1_ec_pubkey_combine(secp256k1_ctx, &maybe_tweaked2, pubkey_combined, 2);
assert(ret);
assert(!memcmp(&maybe_tweaked2, &tweaked2, 64));
}
}
}

return CScriptID(scriptDestination);
}

UniValue getpeginaddress(const JSONRPCRequest& request)
{
if (!EnsureWalletIsAvailable(request.fHelp))
Expand Down Expand Up @@ -3492,7 +3426,7 @@ UniValue getpeginaddress(const JSONRPCRequest& request)
CScript witProg = GetScriptForWitness(destScript);

//Call contracthashtool, get deposit address on mainchain.
CParentBitcoinAddress destAddr(calculate_contract(Params().GetConsensus().fedpegScript, witProg));
CParentBitcoinAddress destAddr(CScriptID(calculate_contract(Params().GetConsensus().fedpegScript, witProg)));

UniValue fundinginfo(UniValue::VOBJ);

Expand Down Expand Up @@ -3568,7 +3502,7 @@ unsigned int GetPeginTxnOutputIndex(const Sidechain::Bitcoin::CTransaction& txn,
{
unsigned int nOut = 0;
//Call contracthashtool
CScript mainchain_script = GetScriptForDestination(calculate_contract(Params().GetConsensus().fedpegScript, witnessProgram));
CScript mainchain_script = GetScriptForDestination(CScriptID(calculate_contract(Params().GetConsensus().fedpegScript, witnessProgram)));
for (; nOut < txn.vout.size(); nOut++)
if (txn.vout[nOut].scriptPubKey == mainchain_script)
break;
Expand Down

0 comments on commit 13c3dad

Please sign in to comment.