diff --git a/keychain/ecdh.go b/keychain/ecdh.go new file mode 100644 index 00000000..3d20c2d2 --- /dev/null +++ b/keychain/ecdh.go @@ -0,0 +1,82 @@ +package keychain + +import ( + "crypto/sha256" + + "github.com/btcsuite/btcd/btcec" +) + +// NewPubKeyECDH wraps the given key of the key ring so it adheres to the +// SingleKeyECDH interface. +func NewPubKeyECDH(keyDesc KeyDescriptor, ecdh ECDHRing) *PubKeyECDH { + return &PubKeyECDH{ + keyDesc: keyDesc, + ecdh: ecdh, + } +} + +// PubKeyECDH is an implementation of the SingleKeyECDH interface. It wraps an +// ECDH key ring so it can perform ECDH shared key generation against a single +// abstracted away private key. +type PubKeyECDH struct { + keyDesc KeyDescriptor + ecdh ECDHRing +} + +// PubKey returns the public key of the private key that is abstracted away by +// the interface. +// +// NOTE: This is part of the SingleKeyECDH interface. +func (p *PubKeyECDH) PubKey() *btcec.PublicKey { + return p.keyDesc.PubKey +} + +// ECDH performs a scalar multiplication (ECDH-like operation) between the +// abstracted private key and a remote public key. The output returned will be +// the sha256 of the resulting shared point serialized in compressed format. If +// k is our private key, and P is the public key, we perform the following +// operation: +// +// sx := k*P +// s := sha256(sx.SerializeCompressed()) +// +// NOTE: This is part of the SingleKeyECDH interface. +func (p *PubKeyECDH) ECDH(pubKey *btcec.PublicKey) ([32]byte, error) { + return p.ecdh.ECDH(p.keyDesc, pubKey) +} + +// PrivKeyECDH is an implementation of the SingleKeyECDH in which we do have the +// full private key. This can be used to wrap a temporary key to conform to the +// SingleKeyECDH interface. +type PrivKeyECDH struct { + // PrivKey is the private key that is used for the ECDH operation. + PrivKey *btcec.PrivateKey +} + +// PubKey returns the public key of the private key that is abstracted away by +// the interface. +// +// NOTE: This is part of the SingleKeyECDH interface. +func (p *PrivKeyECDH) PubKey() *btcec.PublicKey { + return p.PrivKey.PubKey() +} + +// ECDH performs a scalar multiplication (ECDH-like operation) between the +// abstracted private key and a remote public key. The output returned will be +// the sha256 of the resulting shared point serialized in compressed format. If +// k is our private key, and P is the public key, we perform the following +// operation: +// +// sx := k*P +// s := sha256(sx.SerializeCompressed()) +// +// NOTE: This is part of the SingleKeyECDH interface. +func (p *PrivKeyECDH) ECDH(pub *btcec.PublicKey) ([32]byte, error) { + s := &btcec.PublicKey{} + s.X, s.Y = btcec.S256().ScalarMult(pub.X, pub.Y, p.PrivKey.D.Bytes()) + + return sha256.Sum256(s.SerializeCompressed()), nil +} + +var _ SingleKeyECDH = (*PubKeyECDH)(nil) +var _ SingleKeyECDH = (*PrivKeyECDH)(nil) diff --git a/keychain/signer.go b/keychain/signer.go new file mode 100644 index 00000000..cdd512eb --- /dev/null +++ b/keychain/signer.go @@ -0,0 +1,56 @@ +package keychain + +import "github.com/btcsuite/btcd/btcec" + +func NewPubKeyDigestSigner(keyDesc KeyDescriptor, + signer DigestSignerRing) *PubKeyDigestSigner { + + return &PubKeyDigestSigner{ + keyDesc: keyDesc, + digestSigner: signer, + } +} + +type PubKeyDigestSigner struct { + keyDesc KeyDescriptor + digestSigner DigestSignerRing +} + +func (p *PubKeyDigestSigner) PubKey() *btcec.PublicKey { + return p.keyDesc.PubKey +} + +func (p *PubKeyDigestSigner) SignDigest(digest [32]byte) (*btcec.Signature, + error) { + + return p.digestSigner.SignDigest(p.keyDesc, digest) +} + +func (p *PubKeyDigestSigner) SignDigestCompact(digest [32]byte) ([]byte, + error) { + + return p.digestSigner.SignDigestCompact(p.keyDesc, digest) +} + +type PrivKeyDigestSigner struct { + PrivKey *btcec.PrivateKey +} + +func (p *PrivKeyDigestSigner) PubKey() *btcec.PublicKey { + return p.PrivKey.PubKey() +} + +func (p *PrivKeyDigestSigner) SignDigest(digest [32]byte) (*btcec.Signature, + error) { + + return p.PrivKey.Sign(digest[:]) +} + +func (p *PrivKeyDigestSigner) SignDigestCompact(digest [32]byte) ([]byte, + error) { + + return btcec.SignCompact(btcec.S256(), p.PrivKey, digest[:], true) +} + +var _ SingleKeyDigestSigner = (*PubKeyDigestSigner)(nil) +var _ SingleKeyDigestSigner = (*PrivKeyDigestSigner)(nil)