txscript: Implement ScriptVerifyNullFail

ScriptVerifyNullFail defines that signatures must be empty if a
CHECKSIG or CHECKMULTISIG operation fails.

This commit also enables ScriptVerifyNullFail at the mempool policy
level.
This commit is contained in:
David Hill 2016-11-17 22:08:06 -05:00
parent 153dca5c1e
commit 0efea24aa6
7 changed files with 53 additions and 1 deletions

View File

@ -1492,6 +1492,20 @@
"OK",
"BIP66 example 4, with DERSIG, non-null DER-compliant signature"
],
[
"0",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
"DERSIG,NULLFAIL",
"OK",
"BIP66 example 4, with DERSIG and NULLFAIL"
],
[
"0x09 0x300602010102010101",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
"DERSIG,NULLFAIL",
"NULLFAIL",
"BIP66 example 4, with DERSIG and NULLFAIL, non-null DER-compliant signature"
],
[
"1",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
@ -1844,5 +1858,15 @@
["4294967296", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME",
"CSV fails if stack top bit 1 << 31 is not set, and tx version < 2"],
["NULLFAIL should cover all signatures and signatures only"],
["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG", "OK", "BIP66 and NULLFAIL-compliant"],
["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL", "OK", "BIP66 and NULLFAIL-compliant"],
["1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL", "OK", "BIP66 and NULLFAIL-compliant, not NULLDUMMY-compliant"],
["1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL,NULLDUMMY", "SIG_NULLDUMMY", "BIP66 and NULLFAIL-compliant, not NULLDUMMY-compliant"],
["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0x09 0x300602010102010101", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG", "OK", "BIP66-compliant but not NULLFAIL-compliant"],
["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0x09 0x300602010102010101", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL", "NULLFAIL", "BIP66-compliant but not NULLFAIL-compliant"],
["0 0x09 0x300602010102010101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG", "OK", "BIP66-compliant but not NULLFAIL-compliant"],
["0 0x09 0x300602010102010101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL", "NULLFAIL", "BIP66-compliant but not NULLFAIL-compliant"],
["The End"]
]

View File

@ -62,6 +62,10 @@ const (
// push operator. This is both rules 3 and 4 of BIP0062.
ScriptVerifyMinimalData
// ScriptVerifyNullFail defines that signatures must be empty if
// a CHECKSIG or CHECKMULTISIG operation fails.
ScriptVerifyNullFail
// ScriptVerifySigPushOnly defines that signature scripts must contain
// only pushed data. This is rule 2 of BIP0062.
ScriptVerifySigPushOnly

View File

@ -204,6 +204,11 @@ const (
// single element.
ErrCleanStack
// ErrNullFail is returned when the ScriptVerifyNullFail flag is
// set and signatures are not empty on failed checksig or checkmultisig
// operations.
ErrNullFail
// -------------------------------
// Failures related to soft forks.
// -------------------------------
@ -266,6 +271,7 @@ var errorCodeStrings = map[ErrorCode]string{
ErrSigNullDummy: "ErrSigNullDummy",
ErrPubKeyType: "ErrPubKeyType",
ErrCleanStack: "ErrCleanStack",
ErrNullFail: "ErrNullFail",
ErrDiscourageUpgradableNOPs: "ErrDiscourageUpgradableNOPs",
ErrNegativeLockTime: "ErrNegativeLockTime",
ErrUnsatisfiedLockTime: "ErrUnsatisfiedLockTime",

View File

@ -53,6 +53,7 @@ func TestErrorCodeStringer(t *testing.T) {
{ErrSigNullDummy, "ErrSigNullDummy"},
{ErrPubKeyType, "ErrPubKeyType"},
{ErrCleanStack, "ErrCleanStack"},
{ErrNullFail, "ErrNullFail"},
{ErrDiscourageUpgradableNOPs, "ErrDiscourageUpgradableNOPs"},
{ErrNegativeLockTime, "ErrNegativeLockTime"},
{ErrUnsatisfiedLockTime, "ErrUnsatisfiedLockTime"},

View File

@ -2084,6 +2084,11 @@ func opcodeCheckSig(op *parsedOpcode, vm *Engine) error {
valid = signature.Verify(hash, pubKey)
}
if !valid && vm.hasFlag(ScriptVerifyNullFail) && len(sigBytes) > 0 {
str := "signature not empty on failed checksig"
return scriptError(ErrNullFail, str)
}
vm.dstack.PushBool(valid)
return nil
}
@ -2318,6 +2323,15 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error {
}
}
if !success && vm.hasFlag(ScriptVerifyNullFail) {
for _, sig := range signatures {
if len(sig.signature) > 0 {
str := "not all signatures empty on failed checkmultisig"
return scriptError(ErrNullFail, str)
}
}
}
vm.dstack.PushBool(success)
return nil
}

View File

@ -160,6 +160,8 @@ func parseScriptFlags(flagStr string) (ScriptFlags, error) {
// Nothing.
case "NULLDUMMY":
flags |= ScriptStrictMultiSig
case "NULLFAIL":
flags |= ScriptVerifyNullFail
case "P2SH":
flags |= ScriptBip16
case "SIGPUSHONLY":
@ -191,7 +193,7 @@ func parseExpectedResult(expected string) ([]ErrorCode, error) {
case "EQUALVERIFY":
return []ErrorCode{ErrEqualVerify}, nil
case "NULLFAIL":
return []ErrorCode{ErrSigNullDummy}, nil
return []ErrorCode{ErrNullFail}, nil
case "SIG_HIGH_S":
return []ErrorCode{ErrSigHighS}, nil
case "SIG_HASHTYPE":

View File

@ -33,6 +33,7 @@ const (
ScriptStrictMultiSig |
ScriptDiscourageUpgradableNops |
ScriptVerifyCleanStack |
ScriptVerifyNullFail |
ScriptVerifyCheckLockTimeVerify |
ScriptVerifyCheckSequenceVerify |
ScriptVerifyLowS