@@ -22,6 +22,55 @@ const (
2222// the output of a SHA256 hash.
2323type Hash256 [sha256 .Size ]byte
2424
25+ // SingleKeyECDH is an abstraction interface that hides the implementation of an
26+ // ECDH operation against a specific private key. We use this abstraction for
27+ // the long term keys which we eventually want to be able to keep in a hardware
28+ // wallet or HSM.
29+ type SingleKeyECDH interface {
30+ // PubKey returns the public key of the private key that is abstracted
31+ // away by the interface.
32+ PubKey () * btcec.PublicKey
33+
34+ // ECDH performs a scalar multiplication (ECDH-like operation) between
35+ // the abstracted private key and a remote public key. The output
36+ // returned will be the sha256 of the resulting shared point serialized
37+ // in compressed format.
38+ ECDH (pubKey * btcec.PublicKey ) ([32 ]byte , error )
39+ }
40+
41+ // PrivKeyECDH is an implementation of the SingleKeyECDH in which we do have the
42+ // full private key. This can be used to wrap a temporary key to conform to the
43+ // SingleKeyECDH interface.
44+ type PrivKeyECDH struct {
45+ // PrivKey is the private key that is used for the ECDH operation.
46+ PrivKey * btcec.PrivateKey
47+ }
48+
49+ // PubKey returns the public key of the private key that is abstracted away by
50+ // the interface.
51+ //
52+ // NOTE: This is part of the SingleKeyECDH interface.
53+ func (p * PrivKeyECDH ) PubKey () * btcec.PublicKey {
54+ return p .PrivKey .PubKey ()
55+ }
56+
57+ // ECDH performs a scalar multiplication (ECDH-like operation) between the
58+ // abstracted private key and a remote public key. The output returned will be
59+ // the sha256 of the resulting shared point serialized in compressed format. If
60+ // k is our private key, and P is the public key, we perform the following
61+ // operation:
62+ //
63+ // sx := k*P
64+ // s := sha256(sx.SerializeCompressed())
65+ //
66+ // NOTE: This is part of the SingleKeyECDH interface.
67+ func (p * PrivKeyECDH ) ECDH (pub * btcec.PublicKey ) ([32 ]byte , error ) {
68+ s := & btcec.PublicKey {}
69+ s .X , s .Y = btcec .S256 ().ScalarMult (pub .X , pub .Y , p .PrivKey .D .Bytes ())
70+
71+ return sha256 .Sum256 (s .SerializeCompressed ()), nil
72+ }
73+
2574// DecryptedError contains the decrypted error message and its sender.
2675type DecryptedError struct {
2776 // Sender is the node that sent the error. Note that a node may occur in
@@ -149,21 +198,7 @@ func (r *Router) generateSharedSecret(dhKey *btcec.PublicKey) (Hash256, error) {
149198 }
150199
151200 // Compute our shared secret.
152- sharedSecret = generateSharedSecret (dhKey , r .onionKey )
153- return sharedSecret , nil
154- }
155-
156- // generateSharedSecret generates the shared secret for a particular hop. The
157- // shared secret is generated by taking the group element contained in the
158- // mix-header, and performing an ECDH operation with the node's long term onion
159- // key. We then take the _entire_ point generated by the ECDH operation,
160- // serialize that using a compressed format, then feed the raw bytes through a
161- // single SHA256 invocation. The resulting value is the shared secret.
162- func generateSharedSecret (pub * btcec.PublicKey , priv * btcec.PrivateKey ) Hash256 {
163- s := & btcec.PublicKey {}
164- s .X , s .Y = btcec .S256 ().ScalarMult (pub .X , pub .Y , priv .D .Bytes ())
165-
166- return sha256 .Sum256 (s .SerializeCompressed ())
201+ return r .onionKey .ECDH (dhKey )
167202}
168203
169204// onionEncrypt obfuscates the data with compliance with BOLT#4. As we use a
@@ -200,10 +235,14 @@ func (o *OnionErrorDecrypter) DecryptError(encryptedData []byte) (
200235 len (encryptedData ))
201236 }
202237
203- sharedSecrets := generateSharedSecrets (
238+ sharedSecrets , err := generateSharedSecrets (
204239 o .circuit .PaymentPath ,
205240 o .circuit .SessionKey ,
206241 )
242+ if err != nil {
243+ return nil , fmt .Errorf ("error generating shared secret: %v" ,
244+ err )
245+ }
207246
208247 var (
209248 sender int
0 commit comments