types.go raw
1 // Package types provides fixed-size cryptographic types for Nostr.
2 //
3 // These types use fixed-size arrays instead of slices, which provides:
4 // - Stack allocation (no heap escape for copies)
5 // - Implicit copy-on-assignment (safe concurrent use)
6 // - Type safety (compiler enforces correct sizes)
7 //
8 // Migration: Existing code using []byte continues to work via Bytes() methods.
9 // New code should prefer the fixed types for better performance and safety.
10 package types
11
12 import (
13 "encoding/hex"
14 )
15
16 // Size constants for Nostr cryptographic values
17 const (
18 EventIDSize = 32 // SHA256 hash
19 PubkeySize = 32 // secp256k1 x-coordinate (32 bytes)
20 SignatureSize = 64 // Schnorr signature
21 SecretKeySize = 32 // secp256k1 secret key
22 )
23
24 // EventID is a 32-byte SHA256 hash of an event's canonical serialization.
25 // Stack-allocated, copied on assignment.
26 type EventID [EventIDSize]byte
27
28 // Pubkey is a 32-byte secp256k1 public key (x-coordinate only, y is derived).
29 // Stack-allocated, copied on assignment.
30 type Pubkey [PubkeySize]byte
31
32 // Signature is a 64-byte Schnorr signature.
33 // Stack-allocated, copied on assignment.
34 type Signature [SignatureSize]byte
35
36 // SecretKey is a 32-byte secp256k1 secret key.
37 // Stack-allocated, copied on assignment.
38 type SecretKey [SecretKeySize]byte
39
40 // --- EventID methods ---
41
42 // Bytes returns a slice view of the EventID.
43 // WARNING: The returned slice shares memory with the EventID.
44 // Use Copy() if you need an independent slice.
45 // Pointer receiver ensures the slice references the original, not a copy.
46 func (id *EventID) Bytes() []byte { return id[:] }
47
48 // Copy returns an independent heap-allocated copy as a slice.
49 // Use when you need to pass to APIs that may retain or mutate the slice.
50 func (id EventID) Copy() []byte {
51 b := make([]byte, EventIDSize)
52 copy(b, id[:])
53 return b
54 }
55
56 // Hex returns the lowercase hex encoding of the EventID.
57 func (id EventID) Hex() string { return hex.EncodeToString(id[:]) }
58
59 // IsZero returns true if the EventID is all zeros (uninitialized).
60 func (id EventID) IsZero() bool { return id == EventID{} }
61
62 // EventIDFromBytes creates an EventID from a byte slice.
63 // If src is shorter than 32 bytes, remaining bytes are zero.
64 // If src is longer, extra bytes are ignored.
65 func EventIDFromBytes(src []byte) (id EventID) {
66 copy(id[:], src)
67 return
68 }
69
70 // EventIDFromHex creates an EventID from a hex string.
71 // Returns zero EventID and error if hex is invalid.
72 func EventIDFromHex(s string) (id EventID, err error) {
73 var b []byte
74 b, err = hex.DecodeString(s)
75 if err != nil {
76 return
77 }
78 copy(id[:], b)
79 return
80 }
81
82 // --- Pubkey methods ---
83
84 // Bytes returns a slice view of the Pubkey.
85 // WARNING: The returned slice shares memory with the Pubkey.
86 // Pointer receiver ensures the slice references the original, not a copy.
87 func (pk *Pubkey) Bytes() []byte { return pk[:] }
88
89 // Copy returns an independent heap-allocated copy as a slice.
90 func (pk Pubkey) Copy() []byte {
91 b := make([]byte, PubkeySize)
92 copy(b, pk[:])
93 return b
94 }
95
96 // Hex returns the lowercase hex encoding of the Pubkey.
97 func (pk Pubkey) Hex() string { return hex.EncodeToString(pk[:]) }
98
99 // IsZero returns true if the Pubkey is all zeros (uninitialized).
100 func (pk Pubkey) IsZero() bool { return pk == Pubkey{} }
101
102 // PubkeyFromBytes creates a Pubkey from a byte slice.
103 func PubkeyFromBytes(src []byte) (pk Pubkey) {
104 copy(pk[:], src)
105 return
106 }
107
108 // PubkeyFromHex creates a Pubkey from a hex string.
109 func PubkeyFromHex(s string) (pk Pubkey, err error) {
110 var b []byte
111 b, err = hex.DecodeString(s)
112 if err != nil {
113 return
114 }
115 copy(pk[:], b)
116 return
117 }
118
119 // --- Signature methods ---
120
121 // Bytes returns a slice view of the Signature.
122 // WARNING: The returned slice shares memory with the Signature.
123 // Pointer receiver ensures the slice references the original, not a copy.
124 func (sig *Signature) Bytes() []byte { return sig[:] }
125
126 // Copy returns an independent heap-allocated copy as a slice.
127 func (sig Signature) Copy() []byte {
128 b := make([]byte, SignatureSize)
129 copy(b, sig[:])
130 return b
131 }
132
133 // Hex returns the lowercase hex encoding of the Signature.
134 func (sig Signature) Hex() string { return hex.EncodeToString(sig[:]) }
135
136 // IsZero returns true if the Signature is all zeros (uninitialized).
137 func (sig Signature) IsZero() bool { return sig == Signature{} }
138
139 // SignatureFromBytes creates a Signature from a byte slice.
140 func SignatureFromBytes(src []byte) (sig Signature) {
141 copy(sig[:], src)
142 return
143 }
144
145 // SignatureFromHex creates a Signature from a hex string.
146 func SignatureFromHex(s string) (sig Signature, err error) {
147 var b []byte
148 b, err = hex.DecodeString(s)
149 if err != nil {
150 return
151 }
152 copy(sig[:], b)
153 return
154 }
155
156 // --- SecretKey methods ---
157
158 // Bytes returns a slice view of the SecretKey.
159 // WARNING: The returned slice shares memory with the SecretKey.
160 // Pointer receiver ensures the slice references the original, not a copy.
161 func (sk *SecretKey) Bytes() []byte { return sk[:] }
162
163 // Copy returns an independent heap-allocated copy as a slice.
164 func (sk SecretKey) Copy() []byte {
165 b := make([]byte, SecretKeySize)
166 copy(b, sk[:])
167 return b
168 }
169
170 // Hex returns the lowercase hex encoding of the SecretKey.
171 // WARNING: Be careful with secret key hex representations.
172 func (sk SecretKey) Hex() string { return hex.EncodeToString(sk[:]) }
173
174 // IsZero returns true if the SecretKey is all zeros (uninitialized).
175 func (sk SecretKey) IsZero() bool { return sk == SecretKey{} }
176
177 // SecretKeyFromBytes creates a SecretKey from a byte slice.
178 func SecretKeyFromBytes(src []byte) (sk SecretKey) {
179 copy(sk[:], src)
180 return
181 }
182
183 // SecretKeyFromHex creates a SecretKey from a hex string.
184 func SecretKeyFromHex(s string) (sk SecretKey, err error) {
185 var b []byte
186 b, err = hex.DecodeString(s)
187 if err != nil {
188 return
189 }
190 copy(sk[:], b)
191 return
192 }
193
194 // Zero clears the secret key memory.
195 // Call this when done with a secret key to reduce exposure window.
196 func (sk *SecretKey) Zero() {
197 for i := range sk {
198 sk[i] = 0
199 }
200 }
201