rustywallet-signer
ECDSA and Schnorr message signing and verification for Bitcoin and Ethereum using secp256k1.
Features
- Cross-platform compatibility - Works on all major platforms
- BIP340 Schnorr signatures - Modern Taproot-compatible signing
- Bitcoin message signing - BIP-137 compatible message signatures
- Ethereum personal_sign - EIP-191 compatible signatures for web3
- Recoverable signatures - Extract public keys from signatures
- Deterministic signing - RFC 6979 compliant nonce generation
- Signature verification - Verify signatures against public keys or addresses
- Security focused - Constant-time operations, no secret leakage
- Zero-copy operations - Efficient memory usage
Installation
Add this to your Cargo.toml:
[]
= "0.2"
= "0.1"
Quick Start
ECDSA Signing
use PrivateKey;
use *;
use ;
// Generate a private key
let private_key = random;
let public_key = private_key.public_key;
// Sign a message hash
let message = b"Hello, World!";
let hash: = digest.into;
let signature = sign?;
// Verify the signature
assert!;
Schnorr Signing (BIP340)
use PrivateKey;
use ;
use ;
// Generate a private key
let private_key = random;
// Sign a message hash with Schnorr
let message = b"Hello, Taproot!";
let hash: = digest.into;
let signature = private_key.sign_schnorr?;
// Get x-only public key and verify
let xonly_pubkey = private_key.x_only_public_key;
assert!;
Schnorr Signatures (BIP340)
Schnorr signatures are used in Bitcoin's Taproot upgrade and provide several advantages:
- Smaller signatures (64 bytes vs 71-72 for ECDSA)
- Linear signature aggregation (enables MuSig2)
- Provable security under standard assumptions
Using the SchnorrSigner Trait
use PrivateKey;
use ;
use ;
let key = random;
let hash: = digest.into;
// Sign using the trait
let signature = key.sign_schnorr?;
// Sign with auxiliary randomness for extra security
let aux_rand = ;
let signature_with_aux = key.sign_schnorr_with_aux?;
// Verify using the trait
let xonly = key.x_only_public_key;
assert!;
Using Convenience Functions
use PrivateKey;
use ;
use ;
let key = random;
let hash: = digest.into;
// Sign using convenience function
let signature = sign_schnorr?;
// Verify using convenience function
let xonly = key.x_only_public_key;
assert!;
Message Signing
Bitcoin Message Signing
Sign messages compatible with Bitcoin Core's signmessage RPC:
use PrivateKey;
use ;
let private_key = random;
let message = "Hello Bitcoin!";
// Sign the message
let signature = sign_bitcoin_message?;
println!;
// Verify with Bitcoin address
let address = private_key.to_bitcoin_address;
assert!;
Ethereum Personal Sign
Sign messages compatible with MetaMask and web3.js personal_sign:
use PrivateKey;
use ;
let private_key = random;
let message = b"Hello Ethereum!";
// Sign the message
let signature = sign_ethereum_message?;
println!;
// Get Ethereum address
let address = public_key_to_address;
println!;
// Verify the signature
assert!;
Signature Verification
Verify Against Public Key
use ;
use ;
let private_key = random;
let public_key = private_key.public_key;
let hash: = digest.into;
let signature = sign?;
assert!;
Verify Bitcoin Messages
use verify_bitcoin_message;
let address = "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa";
let message = "Hello Bitcoin!";
let signature = "base64_signature_here";
let is_valid = verify_bitcoin_message?;
Verify Ethereum Messages
use verify_ethereum_message;
let address = ; // 20-byte Ethereum address
let message = b"Hello Ethereum!";
let signature_hex = "0x1234..."; // 65-byte hex signature
let signature = from_hex?;
let is_valid = verify_ethereum_message?;
Recoverable Signatures
Extract public keys from signatures without prior knowledge:
use ;
use ;
let private_key = random;
let original_pubkey = private_key.public_key;
let hash: = digest.into;
// Create recoverable signature
let recoverable_sig = sign_recoverable?;
// Recover the public key
let recovered_pubkey = recover_public_key?;
assert_eq!;
Recover Ethereum Address
use ;
let private_key = random;
let message = b"Recover my address";
let signature = sign_ethereum_message?;
let recovered_address = recover_ethereum_address?;
let expected_address = public_key_to_address;
assert_eq!;
API Reference
Core Signing Functions
// Sign a 32-byte hash with ECDSA
;
// Sign with recovery information
;
// Verify a signature against a public key
;
// Recover public key from signature
;
Schnorr Module (BIP340)
// SchnorrSigner trait - implemented for PrivateKey
// SchnorrVerifier trait - implemented for XOnlyPublicKey
// Convenience functions
;
;
Bitcoin Module
// Sign a Bitcoin message (BIP-137)
;
// Verify a Bitcoin message signature
;
// Create Bitcoin message hash
;
Ethereum Module
// Sign an Ethereum personal message (EIP-191)
;
// Verify an Ethereum message signature
;
// Recover address from signature
;
// Convert public key to Ethereum address
;
// Format address with EIP-55 checksum
;
// Create Ethereum message hash
;
Types
// Standard ECDSA signature (64 bytes: r + s)
// Recoverable signature (65 bytes: r + s + recovery_id)
// Ethereum-specific signature with v, r, s components
// BIP340 Schnorr signature (64 bytes)
// X-only public key for Schnorr (32 bytes)
Error Handling
All signing operations return Result<T, SignerError>:
use ;
match sign
Security Considerations
- Deterministic signatures: Uses RFC 6979 for secure, deterministic nonce generation
- Constant-time operations: All cryptographic operations use constant-time implementations
- No secret leakage: Error messages never contain private key material
- Memory safety: Built on Rust's memory safety guarantees
- Audited dependencies: Uses the well-audited
secp256k1crate
Performance
- Zero-allocation signing and verification for pre-hashed messages
- Batch verification support for multiple signatures
- Optimized for both single operations and high-throughput scenarios
Examples
See the examples/ directory for complete working examples:
basic_signing.rs- Basic ECDSA signing and verificationbitcoin_messages.rs- Bitcoin message signing workflowethereum_messages.rs- Ethereum personal_sign implementationsignature_recovery.rs- Public key recovery examples
Contributing
Contributions are welcome! Please read our Contributing Guide for details on our code of conduct and the process for submitting pull requests.
License
This project is licensed under the MIT License - see the LICENSE file for details.