1 package secp256k1
2 3 import "math/big"
4 5 // ECDH returns the x coordinate of the point sk*Q, where Q is the point with
6 // the given x-only public key and even Y. Nostr keys are x-only, and negating
7 // Q negates the product, which leaves the x coordinate unchanged, so the even-Y
8 // lift is the correct representative for a key-exchange input.
9 //
10 // The result is the raw 32-byte shared secret used by NIP-44. It returns false
11 // when the secret key is out of range or the public key is not on the curve.
12 func ECDH(sk [32]byte, pub [32]byte) ([32]byte, bool) {
13 var out [32]byte
14 d := new(big.Int).SetBytes(sk[:])
15 if d.Sign() == 0 || d.Cmp(N) >= 0 {
16 return out, false
17 }
18 q := liftX(new(big.Int).SetBytes(pub[:]))
19 if q == nil {
20 return out, false
21 }
22 p := scalarMult(d, fromAffine(*q))
23 if p.isInfinity() {
24 return out, false
25 }
26 toAffine(p).x.FillBytes(out[:])
27 return out, true
28 }
29 30 // ValidatePubKey reports whether pub is the x coordinate of a point on the
31 // curve. It is the check NIP-44 requires before deriving a conversation key.
32 func ValidatePubKey(pub [32]byte) bool {
33 return liftX(new(big.Int).SetBytes(pub[:])) != nil
34 }
35