github.com/decred/dcrlnd@v0.7.6/keychain/ecdh.go (about) 1 package keychain 2 3 import ( 4 "crypto/sha256" 5 "fmt" 6 7 "github.com/decred/dcrd/dcrec/secp256k1/v4" 8 ) 9 10 // NewPubKeyECDH wraps the given key of the key ring so it adheres to the 11 // SingleKeyECDH interface. 12 func NewPubKeyECDH(keyDesc KeyDescriptor, ecdh ECDHRing) *PubKeyECDH { 13 return &PubKeyECDH{ 14 keyDesc: keyDesc, 15 ecdh: ecdh, 16 } 17 } 18 19 // PubKeyECDH is an implementation of the SingleKeyECDH interface. It wraps an 20 // ECDH key ring so it can perform ECDH shared key generation against a single 21 // abstracted away private key. 22 type PubKeyECDH struct { 23 keyDesc KeyDescriptor 24 ecdh ECDHRing 25 } 26 27 // PubKey returns the public key of the private key that is abstracted away by 28 // the interface. 29 // 30 // NOTE: This is part of the SingleKeyECDH interface. 31 func (p *PubKeyECDH) PubKey() *secp256k1.PublicKey { 32 return p.keyDesc.PubKey 33 } 34 35 // ECDH performs a scalar multiplication (ECDH-like operation) between the 36 // abstracted private key and a remote public key. The output returned will be 37 // the sha256 of the resulting shared point serialized in compressed format. If 38 // k is our private key, and P is the public key, we perform the following 39 // operation: 40 // 41 // sx := k*P 42 // s := sha256(sx.SerializeCompressed()) 43 // 44 // NOTE: This is part of the SingleKeyECDH interface. 45 func (p *PubKeyECDH) ECDH(pubKey *secp256k1.PublicKey) ([32]byte, error) { 46 return p.ecdh.ECDH(p.keyDesc, pubKey) 47 } 48 49 // PrivKeyECDH is an implementation of the SingleKeyECDH in which we do have the 50 // full private key. This can be used to wrap a temporary key to conform to the 51 // SingleKeyECDH interface. 52 type PrivKeyECDH struct { 53 // PrivKey is the private key that is used for the ECDH operation. 54 PrivKey *secp256k1.PrivateKey 55 } 56 57 // PubKey returns the public key of the private key that is abstracted away by 58 // the interface. 59 // 60 // NOTE: This is part of the SingleKeyECDH interface. 61 func (p *PrivKeyECDH) PubKey() *secp256k1.PublicKey { 62 return p.PrivKey.PubKey() 63 } 64 65 // ECDH performs a scalar multiplication (ECDH-like operation) between the 66 // abstracted private key and a remote public key. The output returned will be 67 // the sha256 of the resulting shared point serialized in compressed format. If 68 // k is our private key, and P is the public key, we perform the following 69 // operation: 70 // 71 // sx := k*P 72 // s := sha256(sx.SerializeCompressed()) 73 // 74 // NOTE: This is part of the SingleKeyECDH interface. 75 func (p *PrivKeyECDH) ECDH(pub *secp256k1.PublicKey) ([32]byte, error) { 76 77 // Privkey to ModNScalar. 78 var privKeyModn secp256k1.ModNScalar 79 privKeyModn.SetByteSlice(p.PrivKey.Serialize()) 80 81 // Pubkey to JacobianPoint. 82 var pubJacobian, res secp256k1.JacobianPoint 83 pub.AsJacobian(&pubJacobian) 84 85 // Calculate shared point and ensure it's on the curve. 86 secp256k1.ScalarMultNonConst(&privKeyModn, &pubJacobian, &res) 87 res.ToAffine() 88 sharedPub := secp256k1.NewPublicKey(&res.X, &res.Y) 89 if !sharedPub.IsOnCurve() { 90 return [32]byte{}, fmt.Errorf("Derived ECDH point is not on the secp256k1 curve") 91 } 92 93 // Hash of the serialized point is the shared secret. 94 h := sha256.Sum256(sharedPub.SerializeCompressed()) 95 return h, nil 96 } 97 98 var _ SingleKeyECDH = (*PubKeyECDH)(nil) 99 var _ SingleKeyECDH = (*PrivKeyECDH)(nil)