From 369b35245299a02df71670b44f1f028c80ed7a6e Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 11 Mar 2015 11:33:42 -0400 Subject: [PATCH] txscript: Add new flag ScriptVerifyLowS The ScriptVerifyLowS flag defines that script signatures must comply with the DER format as well as have an S value less than or equal to the half order. --- txscript/data/script_invalid.json | 6 ++++++ txscript/internal_test.go | 2 ++ txscript/script.go | 30 ++++++++++++++++++++++++++++-- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/txscript/data/script_invalid.json b/txscript/data/script_invalid.json index 99d65551..92fcafc9 100644 --- a/txscript/data/script_invalid.json +++ b/txscript/data/script_invalid.json @@ -701,6 +701,12 @@ "DERSIG", "P2PK with multi-byte hashtype, with DERSIG" ], +[ + "0x48 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef001", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", + "LOW_S", + "P2PK with high S" +], [ "0x47 0x30440220745d63eb70d45652128b450aa5ca7d9b513439963f261cb1c40a60f0785e7ee402204877785b38945ca9dbec78e1c1d4dd12148cc25c868bd27480023b49ae0f310501", "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", diff --git a/txscript/internal_test.go b/txscript/internal_test.go index e307313f..14bf5caa 100644 --- a/txscript/internal_test.go +++ b/txscript/internal_test.go @@ -4579,6 +4579,8 @@ func parseScriptFlags(flagStr string) (ScriptFlags, error) { flags |= ScriptVerifyDERSignatures case "DISCOURAGE_UPGRADABLE_NOPS": flags |= ScriptDiscourageUpgradableNops + case "LOW_S": + flags |= ScriptVerifyLowS case "MINIMALDATA": flags |= ScriptVerifyMinimalData case "NONE": diff --git a/txscript/script.go b/txscript/script.go index ba270372..1338c3de 100644 --- a/txscript/script.go +++ b/txscript/script.go @@ -9,6 +9,7 @@ import ( "encoding/binary" "errors" "fmt" + "math/big" "time" "github.com/btcsuite/btcd/btcec" @@ -123,6 +124,11 @@ var ( // is over the limit. ErrStackOverflow = errors.New("Stacks overflowed") + // ErrStackInvalidLowSSignature is returned when the ScriptVerifyLowS + // flag is set and the script contains any signatures whose S values + // are higher than the half order. + ErrStackInvalidLowSSignature = errors.New("invalid low s signature") + // ErrStackInvalidPubKey is returned when the ScriptVerifyScriptEncoding // flag is set and the script contains invalid pubkeys. ErrStackInvalidPubKey = errors.New("invalid strict pubkey") @@ -164,6 +170,9 @@ var ErrUnsupportedAddress = errors.New("unsupported address type") // This timestamp corresponds to Sun Apr 1 00:00:00 UTC 2012. var Bip16Activation = time.Unix(1333238400, 0) +// curve halforder, used to tame ECDSA malleability (see BIP0062) +var halfOrder = new(big.Int).Rsh(btcec.S256().N, 1) + // SigHashType represents hash type bits at the end of a signature. type SigHashType byte @@ -232,7 +241,8 @@ type Script struct { discourageUpgradableNops bool // NOP1 to NOP10 are reserved for future soft-fork upgrades verifyStrictEncoding bool // verify strict encoding of signatures verifyCleanStack bool // verify stack is clean after script evaluation - verifyDERSignatures bool // verify signatures compily with the DER + verifyDERSignatures bool // verify signatures comply with the DER format + verifyLowS bool // verify signatures comply with the DER format and have an S value <= halforder savedFirstStack [][]byte // stack from first script for bip16 scripts } @@ -388,7 +398,7 @@ func (s *Script) checkPubKeyEncoding(pubKey []byte) error { // checkSignatureEncoding returns whether or not the passed signature adheres to // the strict encoding requirements if enabled. func (s *Script) checkSignatureEncoding(sig []byte) error { - if !s.verifyStrictEncoding && !s.verifyDERSignatures { + if !s.verifyDERSignatures && !s.verifyLowS && !s.verifyStrictEncoding { return nil } @@ -470,6 +480,14 @@ func (s *Script) checkSignatureEncoding(sig []byte) error { return fmt.Errorf("malformed signature: invalid S value") } + // Verify the S value is <= halforder. + if s.verifyLowS { + sValue := new(big.Int).SetBytes(sig[rLen+6 : rLen+6+sLen]) + if sValue.Cmp(halfOrder) > 0 { + return ErrStackInvalidLowSSignature + } + } + return nil } @@ -644,6 +662,11 @@ const ( // to compily with the DER format. ScriptVerifyDERSignatures + // ScriptVerifyLowS defines that signtures are required to comply with + // the DER format and whose S value is <= order / 2. This is rule 5 + // of BIP0062. + ScriptVerifyLowS + // ScriptVerifyMinimalData defines that signatures must use the smallest // push operator. This is both rules 3 and 4 of BIP0062. ScriptVerifyMinimalData @@ -737,6 +760,9 @@ func NewScript(scriptSig []byte, scriptPubKey []byte, txidx int, tx *wire.MsgTx, } m.verifyCleanStack = true } + if flags&ScriptVerifyLowS == ScriptVerifyLowS { + m.verifyLowS = true + } m.tx = *tx m.txidx = txidx