Expand description
YubiKey EVM Signer Core Library
This crate provides the core functionality for signing Ethereum transactions using a YubiKey’s PIV applet with secp256r1 (P-256) ECDSA.
§Overview
With EIP-7951, Ethereum now supports native verification of secp256r1 signatures, enabling hardware security modules like YubiKey to be used directly for transaction signing without curve conversion.
This library provides:
- Transaction Types: EIP-155 legacy and EIP-1559 transaction support
- EIP-712: Typed structured data hashing for human-readable signing
- YubiKey Integration: PIV applet communication for key management and signing
- Address Derivation: Ethereum address computation from P-256 public keys
§Architecture
┌─────────────────────────────────────────────────────────────┐
│ Application Layer │
├─────────────────────────────────────────────────────────────┤
│ Transaction │ EIP-712 │ Address │ Signature │
│ Building │ Hashing │ Derivation │ Types │
├─────────────────────────────────────────────────────────────┤
│ YubiKey PIV Layer │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────────────┐ │
│ │ Slot │ │ APDU │ │ PIV │ │ Transport │ │
│ │ Mgmt │ │ Encode │ │ Session │ │ Abstraction │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Transport Layer (CCID / WebUSB) │
└─────────────────────────────────────────────────────────────┘§Quick Start
§Creating a Transaction
use yubikey_evm_signer_core::{Transaction, Eip1559Transaction, Address};
use alloy_primitives::U256;
// Create an EIP-1559 transaction
let tx = Transaction::Eip1559(Eip1559Transaction {
chain_id: 1,
nonce: 0,
max_priority_fee_per_gas: U256::from(1_000_000_000u64),
max_fee_per_gas: U256::from(100_000_000_000u64),
gas_limit: 21000,
to: Some(Address::zero()),
value: U256::from(1_000_000_000_000_000_000u128),
data: vec![],
access_list: vec![],
});
// Get the hash to sign
let hash = tx.signing_hash();§Signing with EIP-712 Typed Data
use yubikey_evm_signer_core::{TypedData, Eip712Domain};
use serde_json::json;
let domain = Eip712Domain {
name: Some("My DApp".to_string()),
version: Some("1".to_string()),
chain_id: Some(1),
verifying_contract: None,
salt: None,
};
let types = json!({
"Transfer": [
{"name": "to", "type": "address"},
{"name": "amount", "type": "uint256"}
]
});
let message = json!({
"to": "0x0000000000000000000000000000000000000001",
"amount": "1000000000000000000"
});
let typed_data = TypedData::new(domain, types, "Transfer".to_string(), message);
let hash = typed_data.signing_hash().unwrap();§Address Derivation
use yubikey_evm_signer_core::Address;
// Derive address from a 64-byte public key (x || y)
let pubkey_bytes = [0u8; 64];
let address = Address::from_public_key_bytes(&pubkey_bytes).unwrap();
println!("Address: {address}");§YubiKey Integration
The library provides a transport-agnostic interface for YubiKey communication.
Implement the yubikey::Transport trait for your platform:
- Native: Use CCID/PC/SC for desktop applications
- Browser: Use WebUSB for web applications (see
yubikey-evm-signer-wasm)
ⓘ
use yubikey_evm_signer_core::yubikey::{PivSession, Slot, Transport};
// Create a transport (implementation depends on platform)
let transport: Box<dyn Transport> = create_transport()?;
// Create a PIV session
let mut session = PivSession::new(transport);
session.select()?;
session.verify_pin("123456")?;
// Generate a key
let public_key = session.generate_key(Slot::Authentication)?;
// Sign data
let signature = session.sign(Slot::Authentication, &hash)?;§Feature Flags
This crate currently has no optional features. All functionality is included by default.
§Security Considerations
- Private keys never leave the YubiKey hardware
- PIN verification is required before signing (except slot 9e)
- Touch confirmation can be enforced for additional security
- Signatures are normalized to low-S form to prevent malleability
Re-exports§
pub use address::Address;pub use eip712::Eip712Domain;pub use eip712::TypedData;pub use error::Error;pub use error::Result;pub use signature::Signature;pub use transaction::AccessListEntry;pub use transaction::Eip1559Transaction;pub use transaction::LegacyTransaction;pub use transaction::Transaction;
Modules§
- address
- Ethereum address derivation from secp256r1 public keys.
- crypto
- Cryptographic utilities for secp256r1 (P-256) ECDSA.
- eip712
- EIP-712 typed structured data hashing.
- error
- Error types for the YubiKey EVM signer library.
- signature
- Ethereum signature types for secp256r1 (P-256) ECDSA.
- transaction
- Ethereum transaction types and signing payload generation.
- yubikey
- YubiKey PIV communication module.
Type Aliases§
- B256
- 32-byte fixed byte-array type.
- U256
- 256-bit unsigned integer type, consisting of 4, 64-bit limbs.