keys.go raw
1 package keys
2
3 import (
4 "errors"
5
6 "next.orly.dev/pkg/p256k1"
7 )
8
9 // =============================================================================
10 // Type Aliases (Value Objects)
11 // =============================================================================
12
13 // PublicKey represents a secp256k1 public key.
14 type PublicKey = p256k1.PublicKey
15
16 // XOnlyPubkey represents a 32-byte x-only public key (BIP-340).
17 type XOnlyPubkey = p256k1.XOnlyPubkey
18
19 // KeyPair represents a secret/public key pair (Aggregate Root).
20 type KeyPair = p256k1.KeyPair
21
22 // Serialization format flags.
23 const (
24 Compressed = p256k1.ECCompressed // 33-byte compressed format
25 Uncompressed = p256k1.ECUncompressed // 65-byte uncompressed format
26 )
27
28 // =============================================================================
29 // Key Pair Management (Aggregate Root Operations)
30 // =============================================================================
31
32 // Generate creates a new random key pair.
33 //
34 // The private key is generated using a cryptographically secure random source.
35 // Returns an error if key generation fails.
36 func Generate() (*KeyPair, error) {
37 return p256k1.KeyPairGenerate()
38 }
39
40 // Create creates a key pair from an existing 32-byte private key.
41 //
42 // Returns an error if:
43 // - privateKey is not exactly 32 bytes
44 // - privateKey is zero
45 // - privateKey is >= curve order
46 func Create(privateKey []byte) (*KeyPair, error) {
47 return p256k1.KeyPairCreate(privateKey)
48 }
49
50 // =============================================================================
51 // Public Key Operations (Value Object Services)
52 // =============================================================================
53
54 // CreatePublic derives a public key from a 32-byte private key.
55 func CreatePublic(privateKey []byte) (*PublicKey, error) {
56 var pubkey PublicKey
57 if err := p256k1.ECPubkeyCreate(&pubkey, privateKey); err != nil {
58 return nil, err
59 }
60 return &pubkey, nil
61 }
62
63 // ParsePublic parses a public key from serialized form.
64 //
65 // Accepts:
66 // - 33 bytes: compressed format (0x02 or 0x03 prefix)
67 // - 65 bytes: uncompressed format (0x04 prefix)
68 func ParsePublic(input []byte) (*PublicKey, error) {
69 var pubkey PublicKey
70 if err := p256k1.ECPubkeyParse(&pubkey, input); err != nil {
71 return nil, err
72 }
73 return &pubkey, nil
74 }
75
76 // SerializePublic serializes a public key to the specified format.
77 //
78 // Returns the serialized bytes and the number of bytes written.
79 // Use Compressed for 33 bytes, Uncompressed for 65 bytes.
80 func SerializePublic(pubkey *PublicKey, format uint) []byte {
81 var output []byte
82 if format == Compressed {
83 output = make([]byte, 33)
84 } else {
85 output = make([]byte, 65)
86 }
87 n := p256k1.ECPubkeySerialize(output, pubkey, format)
88 return output[:n]
89 }
90
91 // ComparePublic compares two public keys lexicographically.
92 // Returns <0 if a < b, >0 if a > b, 0 if equal.
93 func ComparePublic(a, b *PublicKey) int {
94 return p256k1.ECPubkeyCmp(a, b)
95 }
96
97 // =============================================================================
98 // X-Only Public Key Operations
99 // =============================================================================
100
101 // ParseXOnly parses a 32-byte x-only public key.
102 func ParseXOnly(input []byte) (*XOnlyPubkey, error) {
103 return p256k1.XOnlyPubkeyParse(input)
104 }
105
106 // XOnlyFromPublic converts a full public key to x-only format.
107 // Returns the x-only key and parity (1 if Y was odd, 0 if even).
108 func XOnlyFromPublic(pubkey *PublicKey) (*XOnlyPubkey, int, error) {
109 return p256k1.XOnlyPubkeyFromPubkey(pubkey)
110 }
111
112 // SerializeXOnly serializes an x-only public key to 32 bytes.
113 func SerializeXOnly(pubkey *XOnlyPubkey) [32]byte {
114 return pubkey.Serialize()
115 }
116
117 // CompareXOnly compares two x-only public keys lexicographically.
118 // Returns <0 if a < b, >0 if a > b, 0 if equal.
119 func CompareXOnly(a, b *XOnlyPubkey) int {
120 return p256k1.XOnlyPubkeyCmp(a, b)
121 }
122
123 // =============================================================================
124 // Private Key Validation
125 // =============================================================================
126
127 // ValidatePrivate checks if a 32-byte slice is a valid private key.
128 //
129 // Returns true if the key is valid:
130 // - Exactly 32 bytes
131 // - Non-zero
132 // - Less than the curve order
133 func ValidatePrivate(privateKey []byte) bool {
134 return p256k1.ECSeckeyVerify(privateKey)
135 }
136
137 // =============================================================================
138 // Key Tweaking (Advanced Operations)
139 // =============================================================================
140
141 // TweakAddPrivate adds a 32-byte tweak to a private key.
142 // Computes: result = (privateKey + tweak) mod n
143 func TweakAddPrivate(privateKey, tweak []byte) ([]byte, error) {
144 result := make([]byte, 32)
145 copy(result, privateKey)
146 if err := p256k1.ECSeckeyTweakAdd(result, tweak); err != nil {
147 return nil, err
148 }
149 return result, nil
150 }
151
152 // TweakMulPrivate multiplies a private key by a 32-byte tweak.
153 // Computes: result = (privateKey * tweak) mod n
154 func TweakMulPrivate(privateKey, tweak []byte) ([]byte, error) {
155 result := make([]byte, 32)
156 copy(result, privateKey)
157 if err := p256k1.ECSeckeyTweakMul(result, tweak); err != nil {
158 return nil, err
159 }
160 return result, nil
161 }
162
163 // TweakAddPublic adds a 32-byte tweak to a public key.
164 // Computes: result = pubkey + tweak*G
165 func TweakAddPublic(pubkey *PublicKey, tweak []byte) (*PublicKey, error) {
166 result := *pubkey
167 if err := p256k1.ECPubkeyTweakAdd(&result, tweak); err != nil {
168 return nil, err
169 }
170 return &result, nil
171 }
172
173 // TweakMulPublic multiplies a public key by a 32-byte tweak.
174 // Computes: result = tweak * pubkey
175 func TweakMulPublic(pubkey *PublicKey, tweak []byte) (*PublicKey, error) {
176 result := *pubkey
177 if err := p256k1.ECPubkeyTweakMul(&result, tweak); err != nil {
178 return nil, err
179 }
180 return &result, nil
181 }
182
183 // =============================================================================
184 // Private Key Operations
185 // =============================================================================
186
187 // NegatePrivate negates a private key.
188 // Computes: result = -privateKey mod n
189 func NegatePrivate(privateKey []byte) ([]byte, error) {
190 result := make([]byte, 32)
191 copy(result, privateKey)
192 if !p256k1.ECSeckeyNegate(result) {
193 return nil, errors.New("invalid private key")
194 }
195 return result, nil
196 }
197