1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
//! Unified signing traits and types for multi-chain transaction signers.
//!
//! This crate defines the capability traits that every chain-specific signer
//! crate implements — [`Sign`] for the mandatory signing surface,
//! [`SignMessage`] / [`EncodeSignedTransaction`] / [`ExtractSignableBytes`]
//! for opt-in capabilities — plus the discriminated [`SignOutput`] enum that
//! covers every wire format the workspace produces.
//!
//! # Design principles
//!
//! - **Single source of truth** — [`SignError`] is defined once here; chain
//! crates re-export it directly and only introduce a wrapper enum when they
//! carry additional failure modes.
//! - **Capability traits** — [`Sign`] is the mandatory primitive-level
//! minimum ([`sign_hash`](Sign::sign_hash) over 32 bytes); optional
//! capabilities live in separate traits so types never carry "not
//! implemented" lies. Chains without a canonical message-signing standard
//! (e.g. XRPL, Cosmos) simply do not implement [`SignMessage`]. Chain-
//! specific `sign_transaction` is an inherent method on each chain's
//! `Signer`, not part of a trait — transaction bytes semantics differ
//! irreconcilably across chains, so a trait method would be a false
//! abstraction.
//! - **Type-safe digests** — `sign_hash` accepts `&[u8; 32]`; ragged byte
//! slices are rejected at compile time.
//! - **Discriminated output** — [`SignOutput`] variants mirror real wire
//! formats; callers pattern-match instead of juggling `Option` metadata.
//! - **Fallible randomness** — every primitive exposes a `try_random`
//! constructor that surfaces [`getrandom`] failures; the panicking
//! `random()` helper is kept only as an ergonomic wrapper.
//! - **Thread-safe** — every signer is `Send + Sync` and ready to share
//! across async tasks.
//! - **No address derivation** — that responsibility lives in `kobe`.
//!
//! # Verification
//!
//! Verification lives on each chain's inherent `Signer` (e.g.
//! [`signer_btc::Signer::verify_hash`](https://docs.rs/signer-btc)).
//! Because every chain derives its signable digest through a different
//! transform (EIP-191, Bitcoin message prefix, Sui intent, …), a single
//! generic `Verify` trait would have to replay chain logic, so the workspace
//! keeps verification inherent to avoid false abstraction.
extern crate alloc;
use String;
use Vec;
pub use Ed25519Signer;
pub use SignError;
pub use SchnorrSigner;
pub use Secp256k1Signer;
/// Signature output across every scheme the workspace supports.
///
/// Each variant mirrors a concrete wire format; callers pattern-match on the
/// variant rather than inspect optional metadata.
/// Primitive-level signing surface implemented by every chain-specific `Signer`.
///
/// # Contract (primitive-level, **not** protocol-level)
///
/// [`sign_hash`](Self::sign_hash) runs the underlying cryptographic primitive
/// over 32 bytes. The semantics of those 32 bytes differ by curve:
///
/// - **secp256k1 ECDSA / BIP-340 Schnorr**: the 32 bytes are treated as a
/// pre-computed digest (RFC 6979 / BIP-340 prehash semantics).
/// - **Ed25519**: the 32 bytes are signed as the **entire message** (`EdDSA` /
/// RFC 8032 does not accept pre-hashed input). Do not equate this with
/// signing a pre-computed digest on on-chain verifiers.
///
/// # On-chain applicability
///
/// [`sign_hash`](Self::sign_hash) output is directly on-chain verifiable
/// when the 32 bytes is the chain's native sighash — true for EVM, BTC,
/// Cosmos, Tron, Filecoin, Spark, XRPL, and Nostr event ids.
///
/// For **Sui** and **Aptos**, [`sign_hash`](Self::sign_hash) output is
/// **not on-chain verifiable** without intent / domain framing around the
/// 32 bytes. Use each
/// chain's inherent `Signer::sign_transaction` (not part of this trait) for
/// on-chain-correct output.
///
/// # Chain-specific transaction signing
///
/// `sign_transaction` is deliberately **not** part of this trait: every chain
/// interprets its `tx_bytes` argument under a different canonical format
/// (RLP, sighash preimage, `SignDoc`, BCS, …) and hashes with a different
/// algorithm, so the trait abstraction would provide no real constraint.
/// Each chain crate exposes `sign_transaction` as a documented inherent
/// method on its own `Signer` type.
///
/// Off-chain message signing lives on the opt-in [`SignMessage`] trait for
/// the same reason it is not universal: XRPL and Cosmos have no canonical
/// single-argument scheme.
///
/// # Thread safety
///
/// Implementors must be `Send + Sync` so signers can cross async task
/// boundaries and multi-threaded executors.
///
/// # Error contract
///
/// `Error` must be a real [`core::error::Error`] and losslessly liftable
/// from [`SignError`], so downstream code can attribute core failures
/// without string-matching while still participating in the standard
/// `?` / `Box<dyn Error>` ecosystem.
///
/// # Example
///
/// ```
/// use signer_primitives::{Sign, SignOutput};
///
/// fn sign_hash_generic<S: Sign>(signer: &S, hash: &[u8; 32]) -> Result<SignOutput, S::Error> {
/// signer.sign_hash(hash)
/// }
/// ```
/// Opt-in capability: sign an off-chain message with the chain's own
/// message-signing convention.
///
/// Implemented only by chains with a well-defined standard for signing
/// arbitrary messages. Chains without one (XRPL, Cosmos, Filecoin, TON,
/// Aptos) deliberately do **not** implement this trait, making the
/// capability visible in the type system rather than hidden behind a
/// runtime `Err`. Those chains expose only the inherent signing entry
/// points (`sign_transaction` and, for Ed25519 chains, `sign_raw`).
///
/// | Chain | Transform | `v` on `Ecdsa` |
/// |------------------|--------------------------------------------------------------------|-------------------|
/// | EVM | Keccak-256 of `\x19Ethereum Signed Message:\n{len}` + message | `27` or `28` |
/// | Bitcoin / Spark | double-SHA256 of `\x18Bitcoin Signed Message:\n` + CompactSize+msg | `31` or `32` |
/// | Tron | Keccak-256 of `\x19TRON Signed Message:\n{len}` + message | `27` or `28` |
/// | Solana | Raw Ed25519 over the message (matches `nacl.sign.detached`) | — (Ed25519) |
/// | Sui | BLAKE2b-256 of `PersonalMessage` intent + BCS-encoded message | — (Ed25519) |
/// | Nostr | Raw BIP-340 Schnorr over the message (no prefix) | — (Schnorr) |
///
/// # Example
///
/// ```
/// use signer_primitives::{SignMessage, SignOutput};
///
/// fn personal_sign<S: SignMessage>(signer: &S, msg: &[u8]) -> Result<SignOutput, S::Error> {
/// signer.sign_message(msg)
/// }
/// ```
/// Optional capability: extract the signable portion from a fully serialized
/// transaction.
///
/// Implemented by chains whose wire format interleaves signed payload and
/// unsigned metadata (e.g. Solana's compact-u16 header plus signature-slot
/// placeholders). The majority of chains sign the entire input verbatim and
/// therefore do not implement this trait.
///
/// ```
/// use signer_primitives::{ExtractSignableBytes, Sign};
///
/// fn strip<'a, S: Sign + ExtractSignableBytes>(
/// signer: &S,
/// tx: &'a [u8],
/// ) -> Result<&'a [u8], S::Error> {
/// signer.extract_signable_bytes(tx)
/// }
/// ```
/// Optional capability: assemble the final signed-transaction wire bytes from
/// the unsigned input plus a [`SignOutput`].
///
/// Implemented by chains whose wire format can be reconstructed from
/// `(unsigned_tx, signature)` without recomputing hashes (currently EVM's
/// typed transaction RLP and Solana's signature-slot splicing). Other chains
/// expect callers to splice the signature into their own domain-specific
/// envelope and therefore do not implement this trait.
///
/// ```
/// use signer_primitives::{EncodeSignedTransaction, Sign, SignOutput};
///
/// fn wrap<S: Sign + EncodeSignedTransaction>(
/// signer: &S,
/// unsigned: &[u8],
/// signature: &SignOutput,
/// ) -> Result<Vec<u8>, S::Error> {
/// signer.encode_signed_transaction(unsigned, signature)
/// }
/// ```