diff --git a/txscript/script.go b/txscript/script.go index c642069c..00df5216 100644 --- a/txscript/script.go +++ b/txscript/script.go @@ -66,11 +66,7 @@ func isScriptHash(pops []parsedOpcode) bool { // IsPayToPubKey returns true if the script is in the standard pay-to-pubkey // (P2PK) format, false otherwise. func IsPayToPubKey(script []byte) bool { - pops, err := parseScript(script) - if err != nil { - return false - } - return isPubkey(pops) + return isPubKeyScript(script) } // IsPayToScriptHash returns true if the script is in the standard diff --git a/txscript/standard.go b/txscript/standard.go index 94b3cce5..0a835dbb 100644 --- a/txscript/standard.go +++ b/txscript/standard.go @@ -85,6 +85,64 @@ func (t ScriptClass) String() string { return scriptClassToName[t] } +// extractCompressedPubKey extracts a compressed public key from the passed +// script if it is a standard pay-to-compressed-secp256k1-pubkey script. It +// will return nil otherwise. +func extractCompressedPubKey(script []byte) []byte { + // A pay-to-compressed-pubkey script is of the form: + // OP_DATA_33 <33-byte compressed pubkey> OP_CHECKSIG + + // All compressed secp256k1 public keys must start with 0x02 or 0x03. + if len(script) == 35 && + script[34] == OP_CHECKSIG && + script[0] == OP_DATA_33 && + (script[1] == 0x02 || script[1] == 0x03) { + + return script[1:34] + } + + return nil +} + +// extractUncompressedPubKey extracts an uncompressed public key from the +// passed script if it is a standard pay-to-uncompressed-secp256k1-pubkey +// script. It will return nil otherwise. +func extractUncompressedPubKey(script []byte) []byte { + // A pay-to-uncompressed-pubkey script is of the form: + // OP_DATA_65 <65-byte uncompressed pubkey> OP_CHECKSIG + // + // All non-hybrid uncompressed secp256k1 public keys must start with 0x04. + // Hybrid uncompressed secp256k1 public keys start with 0x06 or 0x07: + // - 0x06 => hybrid format for even Y coords + // - 0x07 => hybrid format for odd Y coords + if len(script) == 67 && + script[66] == OP_CHECKSIG && + script[0] == OP_DATA_65 && + (script[1] == 0x04 || script[1] == 0x06 || script[1] == 0x07) { + + return script[1:66] + } + return nil +} + +// extractPubKey extracts either compressed or uncompressed public key from the +// passed script if it is a either a standard pay-to-compressed-secp256k1-pubkey +// or pay-to-uncompressed-secp256k1-pubkey script, respectively. It will return +// nil otherwise. +func extractPubKey(script []byte) []byte { + if pubKey := extractCompressedPubKey(script); pubKey != nil { + return pubKey + } + return extractUncompressedPubKey(script) +} + +// isPubKeyScript returns whether or not the passed script is either a standard +// pay-to-compressed-secp256k1-pubkey or pay-to-uncompressed-secp256k1-pubkey +// script. +func isPubKeyScript(script []byte) bool { + return extractPubKey(script) != nil +} + // isPubkey returns true if the script passed is a pay-to-pubkey transaction, // false otherwise. func isPubkey(pops []parsedOpcode) bool {