exchange.go raw

   1  package exchange
   2  
   3  import (
   4  	"next.orly.dev/pkg/p256k1"
   5  )
   6  
   7  // =============================================================================
   8  // Type Aliases
   9  // =============================================================================
  10  
  11  // PublicKey represents a secp256k1 public key.
  12  type PublicKey = p256k1.PublicKey
  13  
  14  // HashFunc is a function type for hashing ECDH shared secrets.
  15  // It receives output buffer, x-coordinate (32 bytes), and y-coordinate (32 bytes).
  16  type HashFunc = p256k1.ECDHHashFunction
  17  
  18  // =============================================================================
  19  // ECDH Shared Secret Computation (Domain Service)
  20  // =============================================================================
  21  
  22  // SharedSecret computes an ECDH shared secret between a private key and
  23  // a public key.
  24  //
  25  // The result is SHA256(version || x) where version depends on Y coordinate parity.
  26  // This follows the standard secp256k1 ECDH convention.
  27  //
  28  // Parameters:
  29  //   - pubkey: The other party's public key
  30  //   - privateKey: Your 32-byte private key
  31  //
  32  // Returns a 32-byte shared secret suitable for use as a symmetric key.
  33  func SharedSecret(pubkey *PublicKey, privateKey []byte) ([]byte, error) {
  34  	output := make([]byte, 32)
  35  	if err := p256k1.ECDH(output, pubkey, privateKey, nil); err != nil {
  36  		return nil, err
  37  	}
  38  	return output, nil
  39  }
  40  
  41  // SharedSecretWithHash computes an ECDH shared secret using a custom hash function.
  42  //
  43  // The hash function receives the x and y coordinates and should produce
  44  // the final shared secret.
  45  func SharedSecretWithHash(pubkey *PublicKey, privateKey []byte, hashFn HashFunc) ([]byte, error) {
  46  	output := make([]byte, 32)
  47  	if err := p256k1.ECDH(output, pubkey, privateKey, hashFn); err != nil {
  48  		return nil, err
  49  	}
  50  	return output, nil
  51  }
  52  
  53  // SharedSecretRaw computes an ECDH shared secret and writes it to the provided buffer.
  54  // This avoids allocation by writing directly to the caller's buffer.
  55  func SharedSecretRaw(output []byte, pubkey *PublicKey, privateKey []byte) error {
  56  	return p256k1.ECDH(output, pubkey, privateKey, nil)
  57  }
  58  
  59  // =============================================================================
  60  // X-Only ECDH (BIP-340 Compatible)
  61  // =============================================================================
  62  
  63  // XOnlySharedSecret computes an X-only ECDH shared secret.
  64  //
  65  // Returns only the X coordinate of the shared point (32 bytes).
  66  // This is useful for BIP-340 compatible protocols.
  67  func XOnlySharedSecret(pubkey *PublicKey, privateKey []byte) ([]byte, error) {
  68  	output := make([]byte, 32)
  69  	if err := p256k1.ECDHXOnly(output, pubkey, privateKey); err != nil {
  70  		return nil, err
  71  	}
  72  	return output, nil
  73  }
  74  
  75  // XOnlySharedSecretRaw computes an X-only shared secret and writes it to the provided buffer.
  76  func XOnlySharedSecretRaw(output []byte, pubkey *PublicKey, privateKey []byte) error {
  77  	return p256k1.ECDHXOnly(output, pubkey, privateKey)
  78  }
  79  
  80  // =============================================================================
  81  // Key Derivation (Domain Service)
  82  // =============================================================================
  83  
  84  // DeriveKey derives a key from input keying material using HKDF (RFC 5869).
  85  //
  86  // Parameters:
  87  //   - output: Buffer to write the derived key (any length)
  88  //   - ikm: Input keying material (e.g., ECDH shared secret)
  89  //   - salt: Optional salt value (can be nil for no salt)
  90  //   - info: Optional context/application-specific info (can be nil)
  91  //
  92  // This is useful for deriving multiple keys from a single shared secret,
  93  // for example separate encryption and MAC keys.
  94  func DeriveKey(output, ikm, salt, info []byte) error {
  95  	return p256k1.HKDF(output, ikm, salt, info)
  96  }
  97  
  98  // SharedSecretWithDerivation combines ECDH and HKDF into a single operation.
  99  //
 100  // Computes the ECDH shared secret and then derives a key using HKDF.
 101  // This is a convenience function for the common pattern of:
 102  //  1. Compute ECDH shared secret
 103  //  2. Derive key using HKDF
 104  func SharedSecretWithDerivation(pubkey *PublicKey, privateKey, salt, info []byte, keyLen int) ([]byte, error) {
 105  	output := make([]byte, keyLen)
 106  	if err := p256k1.ECDHWithHKDF(output, pubkey, privateKey, salt, info); err != nil {
 107  		return nil, err
 108  	}
 109  	return output, nil
 110  }
 111  
 112  // SharedSecretWithDerivationRaw is like SharedSecretWithDerivation but writes to a provided buffer.
 113  func SharedSecretWithDerivationRaw(output []byte, pubkey *PublicKey, privateKey, salt, info []byte) error {
 114  	return p256k1.ECDHWithHKDF(output, pubkey, privateKey, salt, info)
 115  }
 116