From 0d7b8be11b009456ef7f62b8e6a9ef0aeb3595df Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Tue, 30 Jan 2018 19:40:30 -0800 Subject: [PATCH] lnwire: add new Sig type to handle conversion to/from btcec.Signature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this commit, we add a new signature type. We’ll use this type to avoid fully decoding a signature on the wire into a btcec.Signature. This type is only really needed when we need to do signature validation, as a result, always encoding it is a waste. Several helper methods have been added to the new struct in order to ensure that we can use it in the existing codebase without substantial issues. --- lnwire/signature.go | 64 +++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/lnwire/signature.go b/lnwire/signature.go index b753ef21a..0bc2b8325 100644 --- a/lnwire/signature.go +++ b/lnwire/signature.go @@ -6,12 +6,16 @@ import ( "github.com/roasbeef/btcd/btcec" ) -// SerializeSigToWire serializes a *Signature to [64]byte in the format -// specified by the Lightning RFC. -func SerializeSigToWire(b *[64]byte, e *btcec.Signature) error { +// Sig is a fixed-sized ECDSA signature. Unlike Bitcoin, we use fixed sized +// signatures on the wire, instead of DER encoded signatures. This type +// provides several methods to convert to/from a regular Bitcoin DER encoded +// signature (raw bytes and *btcec.Signature). +type Sig [64]byte - // Serialize the signature with all the checks that entails. - sig := e.Serialize() +// NewSigFromRawSignature returns a Sig from a Bitcoin raw signature encoded in +// the cannonical DER encoding. +func NewSigFromRawSignature(sig []byte) (Sig, error) { + var b Sig // Extract lengths of R and S. The DER representation is laid out as // 0x30 0x02 r 0x02 s @@ -23,14 +27,14 @@ func SerializeSigToWire(b *[64]byte, e *btcec.Signature) error { sLen := sig[5+rLen] // Check to make sure R and S can both fit into their intended buffers. - // We check S first because these code blocks decrement sLen and - // rLen in the case of a 33-byte 0-padded integer returned from - // Serialize() and rLen is used in calculating array indices for - // S. We can track this with additional variables, but it's more - // efficient to just check S first. + // We check S first because these code blocks decrement sLen and rLen + // in the case of a 33-byte 0-padded integer returned from Serialize() + // and rLen is used in calculating array indices for S. We can track + // this with additional variables, but it's more efficient to just + // check S first. if sLen > 32 { if (sLen > 33) || (sig[6+rLen] != 0x00) { - return fmt.Errorf("S is over 32 bytes long " + + return b, fmt.Errorf("S is over 32 bytes long " + "without padding") } sLen-- @@ -42,7 +46,7 @@ func SerializeSigToWire(b *[64]byte, e *btcec.Signature) error { // Do the same for R as we did for S if rLen > 32 { if (rLen > 33) || (sig[4] != 0x00) { - return fmt.Errorf("R is over 32 bytes long " + + return b, fmt.Errorf("R is over 32 bytes long " + "without padding") } rLen-- @@ -50,13 +54,33 @@ func SerializeSigToWire(b *[64]byte, e *btcec.Signature) error { } else { copy(b[32-rLen:], sig[4:4+rLen]) } - return nil + + return b, nil } -// DeserializeSigFromWire deserializes a *Signature from [64]byte in the format -// specified by the Lightning RFC. -func DeserializeSigFromWire(e **btcec.Signature, b [64]byte) error { +// NewSigFromSignature creates a new signature as used on the wire, from an +// existing btcec.Signature. +func NewSigFromSignature(e *btcec.Signature) (Sig, error) { + // Serialize the signature with all the checks that entails. + return NewSigFromRawSignature(e.Serialize()) +} +// ToSignature converts the fixed-sized signature to a btcec.Signature objects +// which can be used for signature validation checks. +func (b *Sig) ToSignature() (*btcec.Signature, error) { + // Parse the signature with strict checks. + sigBytes := b.ToSignatureBytes() + sig, err := btcec.ParseDERSignature(sigBytes, btcec.S256()) + if err != nil { + return nil, err + } + + return sig, nil +} + +// ToSignatureBytes serializes the target fixed-sized signature into the raw +// bytes of a DER encoding. +func (b *Sig) ToSignatureBytes() []byte { // Extract canonically-padded bigint representations from buffer r := extractCanonicalPadding(b[0:32]) s := extractCanonicalPadding(b[32:64]) @@ -75,13 +99,7 @@ func DeserializeSigFromWire(e **btcec.Signature, b [64]byte) error { copy(sigBytes[4:], r) // Copy R copy(sigBytes[rLen+6:], s) // Copy S - // Parse the signature with strict checks. - sig, err := btcec.ParseDERSignature(sigBytes, btcec.S256()) - if err != nil { - return err - } - *e = sig - return nil + return sigBytes } // extractCanonicalPadding is a utility function to extract the canonical