gsigner 2.0.0

Universal cryptographic signer supporting secp256k1 (Ethereum), ed25519, and sr25519 (Substrate)
Documentation
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
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
# gsigner CLI

Command-line interface for the gsigner universal cryptographic signing library.

## Architecture

The CLI is built on a unified `KeyringCommandHandler` trait that provides:
- **Default implementations** for `show` and `clear` commands across all schemes
- **Scheme-specific overrides** where needed (e.g., secp256k1 `show` accepts both public keys and Ethereum addresses)
- **Consistent command dispatch** via `execute_keyring_command<H>()` generic function

This means ed25519 and sr25519 share the same `show` and `clear` logic automatically, while secp256k1 can provide Ethereum-specific behavior.

## Installation

```bash
cargo build --release --features cli
```

The binary will be available at `target/release/gsigner`.

## Usage

The top-level groups accept convenient shortcuts: `gsigner secp ...`, `gsigner ed ...`, and `gsigner sr ...` map to the longer `secp256k1`, `ed25519`, and `sr25519` commands respectively.

Operations that need to read or write key storage now live under the `keyring` subcommand:

```text
gsigner <scheme> keyring <command> [--storage <path>]
```

Stateless helpers such as `verify`, `recover`, or `address` remain at the root.

### Output formatting

All commands accept `--format <human|plain|json>` (default: `human`). `plain` pretty-prints the structured response, while `json` emits a single-line JSON payload that is convenient for scripting:

```bash
gsigner secp256k1 --format json address --public-key 0x03...
```

To encrypt keys on disk, pass `--key-password <PASSWORD>` to commands that read or write encrypted key material (generate, create, import, sign, show, vanity). The same password must be supplied consistently for subsequent operations targeting the encrypted keyring.

### Storage locations

Every keyring-aware command accepts the same storage location flags:

- `--path <PATH>` (short form `-s` and alias `--storage`) stores keys on disk. When omitted the CLI falls back to the default `~/.local/share/gsigner/<scheme>` directory.
- `--memory` keeps keys entirely in memory for the lifetime of the process. This is handy for tests or scripting when nothing should touch disk.
- `--key-password <PASSWORD>` enables encryption for the keystore. Supply the same password for operations that read or write encrypted key material. If no password is provided the keyring remains plaintext.

You can mix these flags as needed, e.g. `gsigner secp keyring generate --memory --key-password test` to exercise the encryption path without creating files.

### Stateless commands

These helpers do not require stored keys:

- Verify a signature:

  ```bash
  gsigner sr25519 verify --public-key 0x... --data 48656c6c6f --signature 0x...
  ```

- Recover a secp256k1 public key from a signature:

  ```bash
  gsigner secp256k1 recover --data 48656c6c6f --signature 0x...
  ```
  _Note: recovery is only supported for secp256k1; ed25519/sr25519 will return an error._

- Derive an address; for Substrate schemes you can override the SS58 network with `--network <name|prefix>`:

  ```bash
  gsigner ed25519 address --public-key 0x... --network polkadot
  ```

- Derive a libp2p PeerId (build with `--features peer-id`; supported for secp256k1 and ed25519):

  ```bash
  gsigner secp256k1 peer-id --public-key 0x03...
  ```

### Secp256k1 (Ethereum) Commands

#### Generate a new keypair

```bash
gsigner secp256k1 keyring generate
```

With filesystem storage:

```bash
gsigner secp256k1 keyring generate --path ./keys
```

Or in-memory (ephemeral):

```bash
gsigner secp256k1 keyring generate --memory
```

#### Sign data

```bash
gsigner secp256k1 keyring sign \
  --public-key 0x03... \
  --data 48656c6c6f \
  --path ./keys
```

Sign with EIP-191 (contract-specific):

```bash
gsigner secp256k1 keyring sign \
  --public-key 0x03... \
  --data 48656c6c6f \
  --contract 0x1234567890abcdef1234567890abcdef12345678
```

#### Verify signature

```bash
gsigner secp256k1 verify \
  --public-key 0x03... \
  --data 48656c6c6f \
  --signature 0x...
```

#### Get Ethereum address

```bash
gsigner secp256k1 address --public-key 0x03...
```

#### List keys

```bash
gsigner secp256k1 keyring list --path ./keys
```

#### Clear stored keys

```bash
gsigner secp256k1 keyring clear --path ./keys
```

Removes every stored secp256k1 key from the chosen location.

#### Show key details

```bash
# By public key
gsigner secp256k1 keyring show 0x03... --path ./keys

# By Ethereum address (secp256k1 only)
gsigner secp256k1 keyring show 0x1234567890abcdef1234567890abcdef12345678 --path ./keys
```

Pass either the compressed public key or the `0x...` Ethereum address. Add `--show-secret` to include the private key in the output.

**Note:** The address lookup is a secp256k1-specific feature. Ed25519 and sr25519 only accept public keys for the `show` command.

#### Generate vanity address

```bash
gsigner secp256k1 keyring vanity \
  --name vanity \
  --prefix 0abc \
  --path ./keys \
  --show-secret
```

The prefix is matched against the lowercase Ethereum address (with or without `0x`). Use an empty prefix (`--prefix ""`) to accept the next generated key immediately.

### Ed25519 (Substrate) Commands

#### Generate a new keypair

```bash
gsigner ed25519 keyring generate
```

With filesystem storage:

```bash
gsigner ed25519 keyring generate --path ./keys
```

In-memory:

```bash
gsigner ed25519 keyring generate --memory
```
#### Import from SURI

```bash
gsigner ed25519 keyring import   --suri "//Alice"   --path ./keys
```

With password-protected SURI:

```bash
gsigner ed25519 keyring import   --suri "//Alice"   --password "mypassword"   --path ./keys
```

Import from a hex seed:

```bash
gsigner ed25519 keyring import   --seed 0x0123...   --path ./keys
```

#### Sign data

```bash
gsigner ed25519 keyring sign   --public-key 0x...   --data 48656c6c6f   --path ./keys
```

#### Verify signature

```bash
gsigner ed25519 verify   --public-key 0x...   --data 48656c6c6f   --signature 0x...
```

#### Get SS58 address

```bash
gsigner ed25519 address --public-key 0x...
```

#### List stored keys

```bash
gsigner ed25519 keyring list --path ./keys
```

#### Clear stored keys

```bash
gsigner ed25519 keyring clear --path ./keys
```

Deletes all ed25519 entries from the specified storage.

#### Show key details

```bash
gsigner ed25519 keyring show 0x... --path ./keys
```

Accepts a 32-byte hex-encoded public key. Use `--show-secret` to include the private key seed.

#### Generate vanity address

```bash
gsigner ed25519 keyring vanity \
  --name vanity \
  --prefix 5F \
  --path ./keys \
  --show-secret
```

The prefix is matched against the SS58 address. Empty prefixes (`--prefix ""`) accept the next generated key immediately.

### Sr25519 (Substrate) Commands

#### Generate a new keypair

```bash
gsigner sr25519 keyring generate
```

With filesystem storage:

```bash
gsigner sr25519 keyring generate --path ./keys
```

In-memory:

```bash
gsigner sr25519 keyring generate --memory
```
#### Import key from SURI

Import well-known development accounts:

```bash
gsigner sr25519 keyring import -u "//Alice"
gsigner sr25519 keyring import -u "//Bob"
```

Import with derivation path:

```bash
gsigner sr25519 keyring import -u "//Alice//stash"
```

Import from mnemonic phrase:

```bash
gsigner sr25519 keyring import -u "bottom drive obey lake curtain smoke basket hold race lonely fit walk"
```

Import with password:

```bash
gsigner sr25519 keyring import -u "//Alice" --password "mypassword"
```

Import from hex seed:

```bash
gsigner sr25519 keyring import --seed 0x0000000000000000000000000000000000000000000000000000000000000001
```

#### Sign data

```bash
gsigner sr25519 keyring sign \
  --public-key a1b2c3... \
  --data 48656c6c6f \
  --path ./keys
```

With custom signing context:

```bash
gsigner sr25519 keyring sign \
  --public-key a1b2c3... \
  --data 48656c6c6f \
  --context "my-app-v1"
```

#### Verify signature

```bash
gsigner sr25519 verify \
  --public-key a1b2c3... \
  --data 48656c6c6f \
  --signature d4e5f6...
```

With custom signing context:

```bash
gsigner sr25519 verify \
  --public-key a1b2c3... \
  --data 48656c6c6f \
  --signature d4e5f6... \
  --context "my-app-v1"
```

#### Get SS58 address

```bash
gsigner sr25519 address --public-key a1b2c3...
```

#### List keys

```bash
gsigner sr25519 keyring list --path ./keys
```

#### Clear stored keys

```bash
gsigner sr25519 keyring clear --path ./keys
```

Erases all sr25519 keys from the target storage.

#### Show key details

```bash
gsigner sr25519 keyring show 0x... --path ./keys
```

Accepts a 32-byte hex-encoded public key. Use `--show-secret` to print the private key seed.

#### Generate vanity address

```bash
gsigner sr25519 keyring vanity \
  --name validator \
  --prefix 5F \
  --path ./keys \
  --show-secret
```

The prefix is matched against the SS58 address. Provide a password with `--password` to encrypt the stored key.

### Keyring Management (Secp256k1)

Manage on-disk JSON keystores for Ethereum-style accounts.

#### Initialise a keyring directory

```bash
gsigner secp256k1 keyring init --path ./eth-keyring
```

#### Generate and store a new key

```bash
gsigner secp256k1 keyring create \
  --path ./eth-keyring \
  --name validator
  --key-password hunter2
```

#### Import an existing key (hex or SURI/mnemonic)

```bash
gsigner secp256k1 keyring import \
  --path ./eth-keyring \
  --name deployer \
  --private-key 0xac09...
```

```bash
gsigner secp256k1 keyring import \
  --path ./eth-keyring \
  --name alice \
  --suri "//Alice" \
  --password optional
```

#### List keyring keys

```bash
gsigner secp256k1 keyring list --path ./eth-keyring
```

### Keyring Management (Ed25519)

Manage SS58-compatible ed25519 keystores alongside sr25519.

#### Initialise a keyring directory

```bash
gsigner ed25519 keyring init --path ./ed-keyring
```

#### Generate and store a new key

```bash
gsigner ed25519 keyring create \
  --path ./ed-keyring \
  --name alice
```

#### Import a key (hex seed or SURI)

```bash
gsigner ed25519 keyring import \
  --path ./ed-keyring \
  --name charlie \
  --seed 0x0123...
```

```bash
gsigner ed25519 keyring import \
  --path ./ed-keyring \
  --name bob \
  --suri //Bob \
  --password optional
```

#### List keyring keys

```bash
gsigner ed25519 keyring list --path ./ed-keyring
```

### Keyring Management (Sr25519)

The keyring feature provides polkadot-js compatible encrypted key storage.

#### Create a new keyring

```bash
gsigner sr25519 keyring init --path ./my-keyring
```

#### Generate vanity address

Generate a key with a specific SS58 prefix (use an empty prefix to create a regular key with a custom name):

```bash
gsigner sr25519 keyring vanity \
  --path ./my-keyring \
  --name mykey \
  --prefix "5Abc"
```

**Note**: Vanity generation can take time depending on the prefix complexity.

#### List keyring keys

```bash
gsigner sr25519 keyring list --path ./my-keyring
```
## Examples

### Complete Secp256k1 Workflow

```bash
# Generate a key
gsigner secp256k1 keyring generate --path ./keys --key-password hunter2

# Output:
# ✓ Generated secp256k1 keypair
#   Public key: 0x03ff1bce2f0dfb62c173347c8fa6e1603c6e55d8f0d22091d1660bf2b70d6aa08d
#   Address: 0xbaa1d9c431593fdda5e1d860696ae67f21a607ca

# Sign some data
gsigner secp256k1 keyring sign \
  --public-key 0x03ff1bce2f0dfb62c173347c8fa6e1603c6e55d8f0d22091d1660bf2b70d6aa08d \
  --data 48656c6c6f \
  --path ./keys \
  --key-password hunter2

# Verify the signature
gsigner secp256k1 verify \
  --public-key 0x03ff1bce2f0dfb62c173347c8fa6e1603c6e55d8f0d22091d1660bf2b70d6aa08d \
  --data 48656c6c6f \
  --signature <signature-from-previous-step>
```

### Complete Sr25519 Keyring Workflow

```bash
# Create keyring
gsigner sr25519 keyring init --path ./my-keyring

# Add a named key
gsigner sr25519 keyring create \
  --path ./my-keyring \
  --name alice \
  --key-password secret

# Output:
# ✓ Added key 'alice'
#   Public key: e64d599204740c95a288a2de9814f2085b2e3a631d2e116101f29aa64a676b79
#   SS58 Address: Em4LQQZi4Zb82mVU1e26svnjmARNzHFKKChrhwDBV4A6CdML
#   Keystore: alice

# List all keys
gsigner sr25519 keyring list --path ./my-keyring

# Generate a vanity address
gsigner sr25519 keyring vanity \
  --path ./my-keyring \
  --name vanity \
  --prefix "5GrwvaEF" \
  --key-password secret
```

## Data Format

- **Hex data**: All data inputs should be hex-encoded without the `0x` prefix (e.g., `48656c6c6f` for "Hello")
- **Public keys**:
  - Secp256k1: 33 bytes compressed format with `0x` prefix
  - Ed25519/Sr25519: 32 bytes hex-encoded
- **Signatures**:
  - Secp256k1: 65 bytes (r, s, v format)
  - Ed25519/Sr25519: 64 bytes
- **Addresses**:
  - Ethereum: 20 bytes with `0x` prefix
  - Substrate: SS58 encoded string

## Security Notes

1. **Key Storage**: Keys stored in filesystem use JSON keyring files. Supply `--key-password` to encrypt any scheme; without it the keystore remains plaintext on disk.
2. **Memory Storage**: Pass `--memory` to keep keys in RAM only. Omit both `--memory` and `--path` to default to the per-scheme data directory on disk.
3. **Passwords**: When using password encryption, ensure strong passwords for production use.
4. **Vanity Generation**: Be cautious with long prefixes as generation time increases exponentially.

## Features

The CLI requires the `cli` feature to be enabled:

```bash
cargo build --features cli
```

To build with specific signature schemes:

```bash
# Only secp256k1
cargo build --features "cli,secp256k1"

# Only sr25519
cargo build --features "cli,sr25519"

# Both (default)
cargo build --features cli
```