de-dupe calculate_contract code

This commit is contained in:
Gregory Sanders 2017-10-04 09:54:57 -04:00
parent 6534bd3b86
commit 13c3dad52f
3 changed files with 73 additions and 105 deletions

View file

@ -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:
@ -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;

View file

@ -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:

View file

@ -3389,72 +3389,6 @@ public:
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))
@ -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);
@ -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;