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.
This commit is contained in:
David Hill 2015-03-11 11:33:42 -04:00
parent 9523345814
commit 369b352452
3 changed files with 36 additions and 2 deletions

View file

@ -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",

View file

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

View file

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