package secp256k1 import "math/big" // ECDH returns the x coordinate of the point sk*Q, where Q is the point with // the given x-only public key and even Y. Nostr keys are x-only, and negating // Q negates the product, which leaves the x coordinate unchanged, so the even-Y // lift is the correct representative for a key-exchange input. // // The result is the raw 32-byte shared secret used by NIP-44. It returns false // when the secret key is out of range or the public key is not on the curve. func ECDH(sk [32]byte, pub [32]byte) ([32]byte, bool) { var out [32]byte d := new(big.Int).SetBytes(sk[:]) if d.Sign() == 0 || d.Cmp(N) >= 0 { return out, false } q := liftX(new(big.Int).SetBytes(pub[:])) if q == nil { return out, false } p := scalarMult(d, fromAffine(*q)) if p.isInfinity() { return out, false } toAffine(p).x.FillBytes(out[:]) return out, true } // ValidatePubKey reports whether pub is the x coordinate of a point on the // curve. It is the check NIP-44 requires before deriving a conversation key. func ValidatePubKey(pub [32]byte) bool { return liftX(new(big.Int).SetBytes(pub[:])) != nil }