gsigner
Universal cryptographic signer library supporting multiple signature schemes.
Overview
gsigner provides a unified interface for cryptographic signing operations supporting both:
- secp256k1 (ECDSA) - Ethereum-compatible signatures
- ed25519 (EdDSA) - Substrate-compatible signatures
- sr25519 (Schnorrkel) - Substrate/Polkadot-compatible signatures
This crate combines and extends the functionality from both ethexe-signer and gring crates.
Key improvements in this refactor
- Unified
CryptoSchemetrait – a single trait combines key generation, signing, verification, address derivation, and serialization. This replaces the previous split acrossSignatureScheme,KeyringScheme, andKeyCodec, reducing code duplication significantly. - sp_core-backed key material across every scheme – secp256k1, ed25519, and sr25519 now all wrap the upstream
sp_corepairs/public/signature types, so SURIs, SS58 addresses, and SCALE codecs behave exactly like Substrate tooling. - Production-parity Ethereum signing – recoverable signatures are still generated with canonical low-S normalisation and exposed as
sp_core::ecdsa::Signature, preserving compatibility with existing JSON keystores and RPC consumers. - CLI parity for every scheme – the keyring workflow that previously existed only for sr25519 is now available for secp256k1 and ed25519, including the short aliases
secp,ed, andsr. TheKeyringCommandHandlertrait provides default implementations for common operations, with scheme-specific overrides where needed. - Unified storage abstraction – every keyring command (CLI and API) understands the same storage location flags. Choose a filesystem directory with
--path, keep keys ephemeral with--memory, and optionally encrypt any scheme by passing--key-password. - Consistent address handling – SS58 encoding relies on the upstream codec (default Vara prefix 137) while Ethereum addresses remain the standard Keccak-256 derivation.
Features
secp256k1- Enable Ethereum/secp256k1 ECDSA support (enabled by default)ed25519- Enable Substrate-compatible ed25519 support (enabled by default)sr25519- Enable Substrate/sr25519 Schnorrkel support (enabled by default)cli- Enable command-line interface toolspeer-id- Enable libp2p PeerId derivation helpers (secp256k1, ed25519)
Usage
Basic Example
use secp256k1;
// Create an in-memory signer
let signer = memory;
// Generate a new key
let public_key = signer.generate_key_with_password?;
// Sign some data
let message = b"hello world";
let signature = signer.sign_with_password?;
// Verify signature
signer.verify?;
Using Different Schemes
use ;
// Ethereum signer
let eth_signer = memory;
let eth_key = eth_signer.generate_key_with_password?;
// Ed25519 signer
let ed_signer = memory;
let ed_key = ed_signer.generate_key_with_password?;
// Sr25519 signer
let sub_signer = memory;
let sub_key = sub_signer.generate_key_with_password?;
Storage Options
use secp256k1;
use PathBuf;
// In-memory storage (ephemeral)
let memory_signer = memory;
// Filesystem storage (persistent)
let fs_signer = fs?;
// Encrypted filesystem storage
let encrypted = fs?;
let public_key = encrypted.generate_key_with_password?;
// Temporary filesystem storage
let tmp_signer = fs_temporary?;
// Pass a password per key operation if you plan to export/import encrypted keystores later
let memory_with_password = memory;
let imported = memory_with_password.import_key_with_password?;
CLI Highlights
- All stateful commands now live under
<scheme> keyring ...and accept the unified storage flags (disk path, in-memory mode); commands that read or write encrypted key material also accept--key-password. - Stateless helpers such as
verify,recover,address, andpeer-idremain at the scheme root. - The CLI automatically resolves default storage locations per scheme (
$XDG_DATA_HOME/gsigner/<scheme>), so most commands work without explicitly passing--path. recoveris only available for secp256k1; ed25519 and sr25519 will report that recovery is unsupported.- Responses can be rendered as human-readable text, pretty JSON, or compact JSON using
--format human|plain|json(default:human). peer-idis available when built with--features peer-idand currently supports secp256k1 and ed25519 keys.
See CLI.md for a full command reference with examples.
Advanced Features
Secp256k1 (Ethereum) Extensions
use ;
use Address;
let signer = memory;
let key = signer.generate_key_with_password?;
// Create signed data wrapper
let signed_data = signer.signed_data_with_password?;
assert_eq!;
assert_eq!;
// Create contract-specific signature (EIP-191)
let contract_addr = Address;
let contract_sig = signer.sign_for_contract_with_password?;
Sr25519 (Substrate) Extensions
use ;
// Sign with custom context
let signer = memory;
let key = signer.generate_key_with_password?;
let sig = signer.sign_with_context_with_password?;
// Verify with context
signer.verify_with_context?;
// Generate vanity key
let vanity_key = signer.generate_vanity_key_with_password?; // SS58 address starting with "5Ge"
Ed25519 (Substrate) Basics
use ;
let signer = memory;
let key = signer.generate_key_with_password?;
// Sign and verify
let message = b"hello";
let signature = signer.sign_with_password?;
signer.verify?;
// Import from SURI
let alice = from_suri?;
let imported = signer.import_key_with_password?;
let address = signer.address;
println!;
SURI Support (Ed25519 & Sr25519)
The library supports Substrate URI (SURI) format for key derivation across both ed25519 and sr25519 keys, compatible with Polkadot/Substrate tooling:
use ;
use PrivateKey as EdPrivateKey;
use PrivateKey as SrPrivateKey;
// Well-known development accounts
let alice = from_suri?;
let ed_alice = from_suri?;
// Derivation paths
let alice_stash = from_suri?;
let custom_path = from_suri?;
// From hex seed
let from_hex = from_suri?;
// From mnemonic phrase (12 or 24 words)
let from_mnemonic = from_phrase?;
// With password for derivation
let with_password = from_suri?;
// From raw seed bytes
let seed = ;
let from_seed = from_seed?;
// Import into signers
let sr_signer = memory;
let sr_public = sr_signer.import_key_with_password?;
let ed_signer = memory;
let ed_public = ed_signer.import_key_with_password?;
Supported SURI formats:
- Named accounts:
//Alice,//Bob,//Charlie,//Dave,//Eve,//Ferdie - Derivation paths:
//Alice//stash,//Alice//0//1 - Hex seeds:
0x<64 hex chars> - Mnemonic phrases: 12 or 24 word phrases
- Password protection: Any SURI with optional password parameter
Keyring Management
The keyring feature now covers every supported scheme. Each module exposes a
scheme-specific alias around the generic [gsigner::keyring::Keyring] type
alongside helpers for its native key formats.
sr25519 (Substrate)
use Keyring;
use PathBuf;
let mut keyring = load?;
// Create a new key with optional encryption
let = keyring.create?;
let public_key = private_key.public_key;
// Import from SURI or raw seed
let = keyring.import_suri?;
let _ = keyring.add_hex?; // 32-byte hex seed
// Set primary key
keyring.set_primary?;
ed25519 (Substrate)
use Keyring;
use PathBuf;
let mut keyring = load?;
// Generate a new keypair
let = keyring.create?;
// Import from SURI or raw seed
let = keyring.import_suri?;
let _ = keyring.add_hex?; // 32-byte hex seed
// Access derived data
let public_key = keystore.public_key?;
let address = keystore.address?.as_ss58.to_string;
secp256k1 (Ethereum)
use Keyring;
use PathBuf;
let mut keyring = load?;
// Generate a fresh account
let = keyring.create?;
// Import an existing private key (0x-prefixed hex)
let imported = keyring.add_hex?;
// Import from a SURI or mnemonic
let = keyring.import_suri?;
// Inspect stored metadata
let address = imported.address?.to_hex;
Architecture
Unified CryptoScheme Trait
The library uses a single unified CryptoScheme trait that combines all cryptographic operations:
This unified trait replaces the previous separate SignatureScheme, KeyringScheme, and KeyCodec traits, reducing complexity and code duplication.
Unified CLI Command Handling
The CLI uses a KeyringCommandHandler trait that provides default implementations for common operations:
This design allows ed25519 and sr25519 to share the default handle_show and handle_clear implementations, while secp256k1 can override them for Ethereum-specific behavior (e.g., accepting addresses in addition to public keys).
Storage Abstraction
Every signer is backed by the JSON keyring defined in gsigner::keyring.
Signer::fs(path) stores keys in a namespaced directory inside the provided path, while
Signer::memory() keeps everything in-memory without touching disk. The keyring exposes the full
keystore metadata (name, creation time, associated address) and reuses the same format for both the
CLI and the library APIs. Keys can be listed, imported, or removed directly through the Signer
methods:
let signer = fs;
let public = signer.generate_key_with_password?;
let private = signer.get_private_key_with_password?;
signer.clear_keys?;
Compatibility
Ethereum (secp256k1)
- Compatible with standard Ethereum tooling
- Supports EIP-191 signatures
- Keccak256 hashing
- 20-byte addresses (0x...)
Substrate (ed25519 & sr25519)
- Unified JSON keystore format across all schemes
- SS58 address encoding (VARA network)
- Scrypt + XSalsa20-Poly1305 encryption
License
GPL-3.0-or-later WITH Classpath-exception-2.0