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