ecdh.go raw

   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