lnwire: add new Sig type to handle conversion to/from btcec.Signature
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.
This commit is contained in:
parent
1afadf4822
commit
0d7b8be11b
@ -6,12 +6,16 @@ import (
|
|||||||
"github.com/roasbeef/btcd/btcec"
|
"github.com/roasbeef/btcd/btcec"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SerializeSigToWire serializes a *Signature to [64]byte in the format
|
// Sig is a fixed-sized ECDSA signature. Unlike Bitcoin, we use fixed sized
|
||||||
// specified by the Lightning RFC.
|
// signatures on the wire, instead of DER encoded signatures. This type
|
||||||
func SerializeSigToWire(b *[64]byte, e *btcec.Signature) error {
|
// 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.
|
// NewSigFromRawSignature returns a Sig from a Bitcoin raw signature encoded in
|
||||||
sig := e.Serialize()
|
// 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
|
// Extract lengths of R and S. The DER representation is laid out as
|
||||||
// 0x30 <length> 0x02 <length r> r 0x02 <length s> s
|
// 0x30 <length> 0x02 <length r> r 0x02 <length s> s
|
||||||
@ -23,14 +27,14 @@ func SerializeSigToWire(b *[64]byte, e *btcec.Signature) error {
|
|||||||
sLen := sig[5+rLen]
|
sLen := sig[5+rLen]
|
||||||
|
|
||||||
// Check to make sure R and S can both fit into their intended buffers.
|
// 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
|
// We check S first because these code blocks decrement sLen and rLen
|
||||||
// rLen in the case of a 33-byte 0-padded integer returned from
|
// in the case of a 33-byte 0-padded integer returned from Serialize()
|
||||||
// Serialize() and rLen is used in calculating array indices for
|
// and rLen is used in calculating array indices for S. We can track
|
||||||
// S. We can track this with additional variables, but it's more
|
// this with additional variables, but it's more efficient to just
|
||||||
// efficient to just check S first.
|
// check S first.
|
||||||
if sLen > 32 {
|
if sLen > 32 {
|
||||||
if (sLen > 33) || (sig[6+rLen] != 0x00) {
|
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")
|
"without padding")
|
||||||
}
|
}
|
||||||
sLen--
|
sLen--
|
||||||
@ -42,7 +46,7 @@ func SerializeSigToWire(b *[64]byte, e *btcec.Signature) error {
|
|||||||
// Do the same for R as we did for S
|
// Do the same for R as we did for S
|
||||||
if rLen > 32 {
|
if rLen > 32 {
|
||||||
if (rLen > 33) || (sig[4] != 0x00) {
|
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")
|
"without padding")
|
||||||
}
|
}
|
||||||
rLen--
|
rLen--
|
||||||
@ -50,13 +54,33 @@ func SerializeSigToWire(b *[64]byte, e *btcec.Signature) error {
|
|||||||
} else {
|
} else {
|
||||||
copy(b[32-rLen:], sig[4:4+rLen])
|
copy(b[32-rLen:], sig[4:4+rLen])
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeserializeSigFromWire deserializes a *Signature from [64]byte in the format
|
// NewSigFromSignature creates a new signature as used on the wire, from an
|
||||||
// specified by the Lightning RFC.
|
// existing btcec.Signature.
|
||||||
func DeserializeSigFromWire(e **btcec.Signature, b [64]byte) error {
|
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
|
// Extract canonically-padded bigint representations from buffer
|
||||||
r := extractCanonicalPadding(b[0:32])
|
r := extractCanonicalPadding(b[0:32])
|
||||||
s := extractCanonicalPadding(b[32:64])
|
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[4:], r) // Copy R
|
||||||
copy(sigBytes[rLen+6:], s) // Copy S
|
copy(sigBytes[rLen+6:], s) // Copy S
|
||||||
|
|
||||||
// Parse the signature with strict checks.
|
return sigBytes
|
||||||
sig, err := btcec.ParseDERSignature(sigBytes, btcec.S256())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*e = sig
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractCanonicalPadding is a utility function to extract the canonical
|
// extractCanonicalPadding is a utility function to extract the canonical
|
||||||
|
Loading…
Reference in New Issue
Block a user