dcrd/txscript/consensus.go
Dave Collins 55fb28cbbd
txscript: Prepare v4.0.0.
This updates the txscript module dependencies, the copyright year in the
files modified since the previous release, and serves as a base for
txscript/v4.0.0.

The updated direct dependencies in this commit are as follows:

- github.com/decred/dcrd/chaincfg/chainhash@v1.0.3
- github.com/decred/dcrd/chaincfg/v3@v3.1.0
- github.com/decred/dcrd/dcrec/edwards/v2@v2.0.2
- github.com/decred/dcrd/dcrec/secp256k1/v4@v4.0.1
- github.com/decred/dcrd/wire@v1.5.0
- github.com/decred/slog@v1.2.0

The full list of updated direct dependencies since the previous
txscript/v3.0.0 release are as follows:

- github.com/dchest/siphash@v1.2.2
- github.com/decred/base58@v1.0.3
- github.com/decred/dcrd/chaincfg/chainhash@v1.0.3
- github.com/decred/dcrd/chaincfg/v3@v3.1.0
- github.com/decred/dcrd/crypto/blake256@v1.0.0
- github.com/decred/dcrd/dcrec/edwards/v2@v2.0.2
- github.com/decred/dcrd/dcrec/secp256k1/v4@v4.0.1
- github.com/decred/dcrd/wire@v1.5.0
- github.com/decred/slog@v1.2.0

The following direct dependencies are no longer required as compared to
the previous txscript/v3.0.0 release:

- github.com/decred/dcrd/dcrutil/v3

Finally, all modules in the repository that depend on txscript are
tidied to ensure they are updated to use the latest versions hoisted
forward as a result.
2021-11-18 23:14:01 -06:00

289 lines
10 KiB
Go

// Copyright (c) 2015-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package txscript
import (
"fmt"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
)
const (
// LockTimeThreshold is the number below which a lock time is
// interpreted to be a block number. Since an average of one block
// is generated per 10 minutes, this allows blocks for about 9,512
// years.
LockTimeThreshold = 5e8 // Tue Nov 5 00:53:20 1985 UTC
)
// CheckSignatureEncoding returns whether or not the passed signature adheres to
// the strict encoding requirements.
func CheckSignatureEncoding(sig []byte) error {
// The format of a DER encoded signature is as follows:
//
// 0x30 <total length> 0x02 <length of R> <R> 0x02 <length of S> <S>
// - 0x30 is the ASN.1 identifier for a sequence
// - Total length is 1 byte and specifies length of all remaining data
// - 0x02 is the ASN.1 identifier that specifies an integer follows
// - Length of R is 1 byte and specifies how many bytes R occupies
// - R is the arbitrary length big-endian encoded number which
// represents the R value of the signature. DER encoding dictates
// that the value must be encoded using the minimum possible number
// of bytes. This implies the first byte can only be null if the
// highest bit of the next byte is set in order to prevent it from
// being interpreted as a negative number.
// - 0x02 is once again the ASN.1 integer identifier
// - Length of S is 1 byte and specifies how many bytes S occupies
// - S is the arbitrary length big-endian encoded number which
// represents the S value of the signature. The encoding rules are
// identical as those for R.
const (
asn1SequenceID = 0x30
asn1IntegerID = 0x02
// minSigLen is the minimum length of a DER encoded signature and is
// when both R and S are 1 byte each.
//
// 0x30 + <1-byte> + 0x02 + 0x01 + <byte> + 0x2 + 0x01 + <byte>
minSigLen = 8
// maxSigLen is the maximum length of a DER encoded signature and is
// when both R and S are 33 bytes each. It is 33 bytes because a
// 256-bit integer requires 32 bytes and an additional leading null byte
// might required if the high bit is set in the value.
//
// 0x30 + <1-byte> + 0x02 + 0x21 + <33 bytes> + 0x2 + 0x21 + <33 bytes>
maxSigLen = 72
// sequenceOffset is the byte offset within the signature of the
// expected ASN.1 sequence identifier.
sequenceOffset = 0
// dataLenOffset is the byte offset within the signature of the expected
// total length of all remaining data in the signature.
dataLenOffset = 1
// rTypeOffset is the byte offset within the signature of the ASN.1
// identifier for R and is expected to indicate an ASN.1 integer.
rTypeOffset = 2
// rLenOffset is the byte offset within the signature of the length of
// R.
rLenOffset = 3
// rOffset is the byte offset within the signature of R.
rOffset = 4
)
// The signature must adhere to the minimum and maximum allowed length.
sigLen := len(sig)
if sigLen < minSigLen {
str := fmt.Sprintf("malformed signature: too short: %d < %d", sigLen,
minSigLen)
return scriptError(ErrSigTooShort, str)
}
if sigLen > maxSigLen {
str := fmt.Sprintf("malformed signature: too long: %d > %d", sigLen,
maxSigLen)
return scriptError(ErrSigTooLong, str)
}
// The signature must start with the ASN.1 sequence identifier.
if sig[sequenceOffset] != asn1SequenceID {
str := fmt.Sprintf("malformed signature: format has wrong type: %#x",
sig[sequenceOffset])
return scriptError(ErrSigInvalidSeqID, str)
}
// The signature must indicate the correct amount of data for all elements
// related to R and S.
if int(sig[dataLenOffset]) != sigLen-2 {
str := fmt.Sprintf("malformed signature: bad length: %d != %d",
sig[dataLenOffset], sigLen-2)
return scriptError(ErrSigInvalidDataLen, str)
}
// Calculate the offsets of the elements related to S and ensure S is inside
// the signature.
//
// rLen specifies the length of the big-endian encoded number which
// represents the R value of the signature.
//
// sTypeOffset is the offset of the ASN.1 identifier for S and, like its R
// counterpart, is expected to indicate an ASN.1 integer.
//
// sLenOffset and sOffset are the byte offsets within the signature of the
// length of S and S itself, respectively.
rLen := int(sig[rLenOffset])
sTypeOffset := rOffset + rLen
sLenOffset := sTypeOffset + 1
if sTypeOffset >= sigLen {
str := "malformed signature: S type indicator missing"
return scriptError(ErrSigMissingSTypeID, str)
}
if sLenOffset >= sigLen {
str := "malformed signature: S length missing"
return scriptError(ErrSigMissingSLen, str)
}
// The lengths of R and S must match the overall length of the signature.
//
// sLen specifies the length of the big-endian encoded number which
// represents the S value of the signature.
sOffset := sLenOffset + 1
sLen := int(sig[sLenOffset])
if sOffset+sLen != sigLen {
str := "malformed signature: invalid S length"
return scriptError(ErrSigInvalidSLen, str)
}
// R elements must be ASN.1 integers.
if sig[rTypeOffset] != asn1IntegerID {
str := fmt.Sprintf("malformed signature: R integer marker: %#x != %#x",
sig[rTypeOffset], asn1IntegerID)
return scriptError(ErrSigInvalidRIntID, str)
}
// Zero-length integers are not allowed for R.
if rLen == 0 {
str := "malformed signature: R length is zero"
return scriptError(ErrSigZeroRLen, str)
}
// R must not be negative.
if sig[rOffset]&0x80 != 0 {
str := "malformed signature: R is negative"
return scriptError(ErrSigNegativeR, str)
}
// Null bytes at the start of R are not allowed, unless R would otherwise be
// interpreted as a negative number.
if rLen > 1 && sig[rOffset] == 0x00 && sig[rOffset+1]&0x80 == 0 {
str := "malformed signature: R value has too much padding"
return scriptError(ErrSigTooMuchRPadding, str)
}
// S elements must be ASN.1 integers.
if sig[sTypeOffset] != asn1IntegerID {
str := fmt.Sprintf("malformed signature: S integer marker: %#x != %#x",
sig[sTypeOffset], asn1IntegerID)
return scriptError(ErrSigInvalidSIntID, str)
}
// Zero-length integers are not allowed for S.
if sLen == 0 {
str := "malformed signature: S length is zero"
return scriptError(ErrSigZeroSLen, str)
}
// S must not be negative.
if sig[sOffset]&0x80 != 0 {
str := "malformed signature: S is negative"
return scriptError(ErrSigNegativeS, str)
}
// Null bytes at the start of S are not allowed, unless S would otherwise be
// interpreted as a negative number.
if sLen > 1 && sig[sOffset] == 0x00 && sig[sOffset+1]&0x80 == 0 {
str := "malformed signature: S value has too much padding"
return scriptError(ErrSigTooMuchSPadding, str)
}
// Strip leading zeroes from S.
sBytes := sig[sOffset : sOffset+sLen]
for len(sBytes) > 0 && sBytes[0] == 0x00 {
sBytes = sBytes[1:]
}
// Verify the S value is <= half the order of the curve. This check is done
// because when it is higher, the complement modulo the order can be used
// instead which is a shorter encoding by 1 byte.
//
// Also notice the check for the maximum number of bytes is required because
// SetByteSlice truncates as noted in its comment so it could otherwise fail
// to detect the overflow.
var s secp256k1.ModNScalar
if len(sBytes) > 32 {
str := "non-canonical signature: S is larger than 256 bits"
return scriptError(ErrSigHighS, str)
}
if overflow := s.SetByteSlice(sBytes); overflow {
str := "non-canonical signature: S >= group order"
return scriptError(ErrSigHighS, str)
}
if s.IsOverHalfOrder() {
str := "non-canonical signature: S > group half order"
return scriptError(ErrSigHighS, str)
}
return nil
}
// IsStrictSignatureEncoding returns false if the passed signature does not
// adhere to the strict encoding requirements.
func IsStrictSignatureEncoding(signature []byte) bool {
return CheckSignatureEncoding(signature) == nil
}
// CheckPubKeyEncoding returns an error if the passed public key does not
// adhere to the strict encoding requirements.
func CheckPubKeyEncoding(pubKey []byte) error {
if !isStrictPubKeyEncoding(pubKey) {
return scriptError(ErrPubKeyType, "unsupported public key type")
}
return nil
}
// CheckHashTypeEncoding returns whether or not the passed hashtype adheres to
// the strict encoding requirements.
func CheckHashTypeEncoding(hashType SigHashType) error {
sigHashType := hashType & ^SigHashAnyOneCanPay
if sigHashType < SigHashAll || sigHashType > SigHashSingle {
str := fmt.Sprintf("invalid hash type 0x%x", hashType)
return scriptError(ErrInvalidSigHashType, str)
}
return nil
}
// IsStrictCompressedPubKeyEncoding returns whether or not the passed public
// key adheres to the strict compressed encoding requirements.
func IsStrictCompressedPubKeyEncoding(pubKey []byte) bool {
if len(pubKey) == 33 && (pubKey[0] == 0x02 || pubKey[0] == 0x03) {
// Compressed
return true
}
return false
}
// IsStrictNullData returns whether or not the passed data is an OP_RETURN
// followed by specified length data push. It explicitly verifies that the
// opcode is identical to the required length. This function will always return
// false for required lengths > 75 bytes.
func IsStrictNullData(scriptVersion uint16, script []byte, requiredLen uint32) bool {
// The only currently supported script version is 0.
if scriptVersion != 0 {
return false
}
// The script can't possibly be a null data script if it doesn't start
// with OP_RETURN. Fail fast to avoid more work below.
if len(script) < 1 || script[0] != OP_RETURN {
return false
}
// Allow bare OP_RETURN when the required length is 0.
if len(script) == 1 && requiredLen == 0 {
return true
}
// OP_RETURN followed by data push of the required size.
tokenizer := MakeScriptTokenizer(scriptVersion, script[1:])
return tokenizer.Next() && tokenizer.Done() &&
isCanonicalPush(tokenizer.Opcode(), tokenizer.Data()) &&
((IsSmallInt(tokenizer.Opcode()) && requiredLen == 1) ||
(tokenizer.Opcode() <= OP_DATA_75 &&
uint32(len(tokenizer.Data())) == requiredLen))
}