Complete documentation of the hybrid cryptographic library — ML-DSA-87 (FIPS 204) plus P-521 and Ed448, quantum-secure, Ethereum-compatible, one Rust crate for native nodes, the Substrate runtime and the browser wallet.
3
Signature Schemes
NIST L5
PQ Security (FIPS 204)
4.873 B
Composite Signature
0
unsafe Blocks (forbidden)
01 · Overview
What is Infyn Crypto?
A hybrid cryptographic library that combines one post-quantum and two classical signature schemes into a single composite signature — Defense in Depth for the post-quantum era, implemented in Rust with #![forbid(unsafe_code)].
ML-DSA-87
Post-quantum signature scheme based on Module-LWE/SIS lattice problems, standardised as FIPS 204 (successor of CRYSTALS-Dilithium5). NIST Level 5 (≈ AES-256). Public key 2,592 B, signature 4,627 B. The secret key is stored as its 32-byte seed and re-expanded on demand. Crate: ml-dsa.
Post-Quantum
P-521 ECDSA
NIST P-521 (FIPS 186-4) with ~256-bit classical security. Uncompressed SEC1 public key 133 B, fixed-width signature r ‖ s = 132 B. No recovery ID — the composite public key travels inside the transaction. Crate: p521.
Classical
Ed448
Edwards curve Ed448 per RFC 8032 with 224-bit security. Deterministic signatures, public key 57 B, signature 114 B. Key generation and signing via ed448-rust, verification via ed448-goldilocks — validated against the RFC 8032 test vectors.
Classical
Defense in Depth:An attacker would have to break all three schemes at once — ML-DSA-87 (Module-LWE/SIS) plus P-521 and Ed448 (ECDLP on two independent curves). A cryptographically relevant quantum computer breaks the two ECC schemes via Shor; security then rests on ML-DSA-87 alone. Conversely, the ECC layer protects against a yet-unknown weakness in the lattice scheme. Verification only succeeds if all three partial signatures are valid.
02 · System Architecture
Crate Organisation
One Rust crate (blackchain-crypto-lib-rust, edition 2024, MSRV 1.85) with clear module boundaries. Consensus-critical dependencies are exact-pinned so that signature validity can never drift with a patch release.
Holds the composite key types. BlackChainPrivateKey::generate(seed) derives all three key pairs from a 64-byte seed, derive_address() computes the Keccak-256 address, sign_message() / verify_message() implement the off-chain message protocol. Secret material is wrapped in Zeroizing and cleared on drop; Debug output redacts keys.
src/sign.rs — Unified Traits
Scheme, PublicKey, PrivateKey, TypedScheme traits
SchemeTypedSchemeSignatureOpts
Defines the common traits for all signature schemes: Scheme (object-safe: generate_key, derive_key, sign, verify, public_key_size, signature_size, seed_size) and TypedScheme (typed keys). Private-key equality must be constant-time. Trait methods may panic on wrong key types — the typed API in crypto.rs and api.rs is the safe entry point.
src/dilithium/ — Post-Quantum
ML-DSA-87 (FIPS 204) via the ml-dsa crate
MlDsa87FIPS 204Seed 32 B
Wraps the RustCrypto ml-dsa crate (ML-DSA-87). The module path dilithium is kept for historical reasons — the algorithm is ML-DSA-87 per FIPS 204, not Dilithium Round 3. Keys are derived deterministically from a 32-byte seed ξ (new_key_from_seed); the private key is stored and serialised as this seed. Constants: PUBLIC_KEY_SIZE = 2592, SIGNATURE_SIZE = 4627, PRIVATE_KEY_SIZE = 32.
src/mdecc/ — Multi-Dimensional ECC
p521.rs and ed448.rs implementations
P-521Ed448Curve-ID 1 / 2
Two elliptic-curve schemes behind the common traits. p521.rs: ECDSA on NIST P-521 (RustCrypto p521), fixed-width 132-byte signatures, on-curve validation on parse. ed448.rs: RFC 8032 Ed448, keygen/sign with ed448-rust, verify with ed448-goldilocks. Each curve has a domain-separation ID (P-521 = 1, Ed448 = 2) used both in seed derivation and in the signed message.
src/hdwallet/ — HD Wallet
bip39.rs (24 words only), derivation.rs (hardened-only BIP-32)
BIP-39BIP-32Hardened-Only
bip39.rs generates 24-word mnemonics from 256 bits of OS entropy and turns them into a 64-byte root seed (Zeroizing). 12-word phrases are rejected by policy. derivation.rs implements the hardened-only BIP-32 child derivation, the path parser ("m/44'/60'/0'/0'/0'") and the per-curve curve seed derivation (SHAKE256 + HKDF-SHA3-512).
types.rs defines BlackChainTxType (EIP-1559 fee fields plus pqc_signature and pub_key, type byte 0x80). rlp.rs implements canonical encoding and decoding with alloy-rlp. signing.rs contains signature_hash(), sign_transaction() and recover_sender() including the chain-bound entanglement protocol.
src/api.rs · src/wasm.rs — Facades
High-level developer API and browser bindings (feature "browser")
create_walletsign_transactionBlackWallet (JS)
api.rs is the five-call developer surface (create_wallet, restore_wallet, sign_message, verify_message, sign_transaction, verify_transaction). wasm.rs exposes the same functionality to JavaScript via wasm-bindgen (BlackWallet, verifyMessage, recoverSender, validateMnemonic) — compiled only for wasm32 with the browser feature, so the Substrate runtime build stays free of browser dependencies.
Module Dependency Graph
Module diagram — crypto.rs and transaction/ build on the scheme modules; api.rs and wasm.rs are thin facades on top.
Data Flow: Sign Transaction
1
Key Derivation
The 64-byte account seed is split in two halves: seed[0..32] → ML-DSA-87 ξ, seed[32..64] → curve master. P-521 and Ed448 seeds are expanded from the curve master via SHAKE256 (curve ID) + HKDF-SHA3-512.
2
Transaction Hash
The unsigned transaction is RLP-encoded, prefixed with the type byte and hashed: H = Keccak-256(0x80 ‖ RLP(chain_id, nonce, fees, gas, to, value, data))
3
Entanglement (chain-bound)
Nonce and combined hash bind the signature to chain, address and key set: entg_nonce = SHAKE256("entangle" ‖ ALGO_ID ‖ VERSION ‖ chain_id₈ ‖ address)[0..16], then h_combined = SHAKE256(pk_dil ‖ pk_p521 ‖ pk_ed448 ‖ entg_nonce)[0..32]
4
Three Signatures
ML-DSA-87 signs the raw hash H. P-521 signs H ‖ h_combined ‖ 0x01, Ed448 signs H ‖ h_combined ‖ 0x02. The curve ID prevents cross-curve reuse; h_combined links the ECC signatures to all three public keys.
5
Composite Signature
Concatenation: pqc_signature = σ_dil ‖ σ_p521 ‖ σ_ed448 → exactly 4,873 bytes. The composite public key (2,782 B) is embedded as pub_key; v = chain_id·2 + 35, r = s = 0 remain as EIP-155 framing placeholders and are checked on recovery.
03 · Hierarchical Deterministic Wallet
HD Wallet System
BIP-39/32/44 compatible wallet with one 24-word mnemonic for all three schemes — hardened-only derivation, 256-bit master secrets for both the post-quantum and the ECC layer.
m / 44' / 60' / 0' / 0' / 0' ↑ ↑ ↑ ↑ ↑ BIP-44 ETH Account Change Index
Every index must be hardened (≥ 0x80000000); bare integers in a path string are hardened automatically, non-hardened indices are rejected. Hardened-only because ML-DSA-87 and Ed448 do not support public child-key derivation — and it removes the parent-key exposure attack.
Coin type 60 = Ethereum (SLIP-44) — for address compatibility. Account i of the browser wallet: m/44'/60'/0'/0'/i'
wallet_example.rs
use blackchain_crypto_lib_rust::api::{create_wallet, restore_wallet, sign_message, verify_message};
// Create wallet: fresh 24-word mnemonic + account key at m/44'/60'/0'/0'/0'let (mnemonic, key) = create_wallet("")?; // "" = no BIP-39 passphraselet address = key.public_key().derive_address(); // 0x… (20 bytes, EIP-55)// Sign and verify a message (off-chain protocol, zeroed nonce)let sig = sign_message(b"Hello, Infyn!", &key)?; // 4,873 byteslet ok = verify_message(b"Hello, Infyn!", &sig, key.public_key())?;
// Restore later from the backed-up mnemoniclet same = restore_wallet(&mnemonic, "")?;
assert_eq!(same.public_key().derive_address(), address);
Key Derivation Tree — Mnemonic to 3 Key Pairs
Visualisation: the 64-byte account seed is split into two 256-bit halves. The curve half is expanded per curve via SHAKE256 (curve ID) + HKDF-SHA3-512.
04 · Signature System
Hybrid Signature Linking
The entanglement mechanism prevents signature reuse by cryptographically binding all three schemes — Chain Binding, Address Binding, Public Key Linking, Curve Separation.
Final test phase — 512-bit pre-hash. Before genesis, the transaction hash moves from Keccak-256 to a 512-bit pre-hash (SHA3-512) over the canonical transcript, signed as HashML-DSA per FIPS 204 §5.4 with the same binding nonce for P-521 and Ed448. This lifts the transcript from collision class 2¹²⁸ to 2²⁵⁶ (category 5 end to end); the old hash path is retired by a versioned switch-off rule. Keccak-256 remains for transaction ID and address — it identifies, it does not authorize.
Step 4: Three signatures σ_dil = ML-DSA-87.Sign(sk_dil, H) σ_p521 = ECDSA-P521.Sign(sk_p521, H ‖ h_combined ‖ 0x01) σ_ed448 = Ed448.Sign(sk_ed448, H ‖ h_combined ‖ 0x02)
Step 5: Composite signature pqc_signature = σ_dil[4627] ‖ σ_p521[132] ‖ σ_ed448[114] |pqc_signature| = 4,873 bytes (fixed — any other length is rejected)
Message signing (off-chain) uses the same construction with a zeroed 16-byte nonce.
Signature Structure
Security Mechanisms
Chain & Address Binding
The entanglement nonce contains the 8-byte chain ID and the sender address. A signature made for one network is invalid on every other network, and signatures of one address cannot be reused for another — replay across chains and accounts is rejected by construction.
Public Key Linking
h_combined binds all three public keys. Sub-signatures and sub-keys cannot be spliced across key sets. Note: σ_dil signs H directly — binding to chain, address and key set is enforced by the two ECC signatures and by the verifier recomputing the address from pub_key.
Curve Separation
Each ECC signature covers its curve ID (P-521 = 1, Ed448 = 2). Cross-curve signature reuse is prevented; the same IDs domain-separate the seed derivation.
Signature Entanglement — Cryptographic Linking
The three schemes are linked via the combined hash (SHAKE256). Every signature is bound to chain ID, sender address and all public keys.
05 · Transaction System
Ethereum-compatible Transactions
EIP-1559 fee fields, EIP-2718 typed envelope (type 0x80), canonical RLP via alloy-rlp for consensus and serde-JSON for APIs — extended with the composite post-quantum signature and the embedded public key.
Transaction Lifecycle
1
Create
Fill TX fields
2
Hash
Keccak(0x80‖RLP)
3
Entangle
SHAKE256 · chain-bound
4
Sign
3× Sign ~17.8 ms
5
Encode
RLP / JSON
6
Broadcast
~7.8 KB TX
7
Recover
3× Verify ~3.5 ms
8
Finalized
On-Chain
Field
Type
Description
chain_id
u64
EIP-155 chain identifier — also part of the entanglement nonce
Composite public key (2,782 bytes) — enables sender recovery without a key registry
RLP layout: [chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data] unsigned; signed transactions append [v, r, s, pqc_signature, pub_key]. Type byte 0x80 is prepended to the envelope. Protocol constants: VERSION = 1, ALGO_ID = 1.
transaction_example.rs
use blackchain_crypto_lib_rust::transaction::types::BlackChainTxType;
use alloy_primitives::{address, Bytes, U256};
// Create and sign a transactionlet mut tx = BlackChainTxType {
chain_id: 8888, // Infyn EVM chain ID
nonce: 0,
max_priority_fee_per_gas: U256::from(2_000_000_000u64), // 2 Gwei
max_fee_per_gas: U256::from(30_000_000_000u64), // 30 Gwei
gas_limit: 21_000,
to: Some(address!("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")),
value: U256::from(1_000_000_000_000_000_000u128), // 1 INFYN (18 decimals)
data: Bytes::new(),
v: None, r: None, s: None, pqc_signature: None, pub_key: None,
};
tx.sign_transaction(&key)?; // fills v, r, s, pqc_signature, pub_key// Sender recovery (= full verification of all three signatures)let sender = tx.recover_sender()?;
assert_eq!(sender, key.public_key().derive_address());
// Canonical RLP for the wire / JSON for RPClet mut raw = vec![BlackChainTxType::TX_TYPE]; // 0x80
alloy_rlp::Encodable::encode(&tx, &mut raw);
06 · Technical Specifications
Key & Signature Sizes
All sizes are fixed and enforced by the parsers — a composite key or signature of any other length is rejected before any cryptographic operation runs.
Composite Public Key: 2,782 Bytes
ML-DSA-87
2.592 B
P-521
133 B
Ed448
57 B
Composite Signature: 4,873 Bytes
ML-DSA-87
4.627 B
P-521
132 B
Ed448
114 B
2.782
Public Key (bytes)
155
Private Key (bytes, 32 + 66 + 57)
4.873
Signature (bytes)
20
Address (bytes)
~7.8 KB
TX Size (transfer)
64
Seed (bytes, 32 + 32)
Private key: the ML-DSA-87 secret is stored as its 32-byte seed and re-expanded to the 4,896-byte FIPS 204 signing key on demand; P-521 scalar 66 B, Ed448 seed 57 B. All secret buffers are zeroized on drop.
Algorithm
Security Level
Quantum Resistant
Basis / Standard
ML-DSA-87
NIST Level 5 (≈ AES-256)
✓ Yes
Module-LWE / SIS · FIPS 204
P-521 ECDSA
~256-bit (curve)
✗ No
ECDLP (Weierstraß) · FIPS 186-4
Ed448
224-bit (curve)
✗ No
ECDLP (Edwards, Curve448) · RFC 8032
Combined
NIST L5 PQ + 224-bit classical (min. of the ECC layer)
✓ Yes
Hybrid Defense-in-Depth
Both seed halves are 256 bit, so the ECC layer is no longer capped by the seed; the classical bound is set by the curves themselves (Ed448: 224 bit).
Size Comparison: Infyn vs. Bitcoin vs. Ethereum
Infyn
Public Key2.782 B
Signature4.873 B
TX Size~7.8 KB
PQ Secure✓ NIST L5
Schemes3 hybrid
Bitcoin
Public Key33 B
Signature64 B
TX Size~250 B
PQ Secure✗ No
Schemes1 (secp256k1)
Ethereum
Public Key33 B
Signature65 B
TX Size~110 B
PQ Secure✗ No
Schemes1 (secp256k1)
Trade-off:An Infyn transfer (~7.8 KB: 4,873 B signature + 2,782 B public key + ~110 B payload) is ~70× larger than an Ethereum transaction (~110 B) and ~30× larger than a Bitcoin transaction (~250 B). This overhead is the price for post-quantum security and triple cryptographic protection; it bounds L1 throughput mainly via bandwidth (see whitepaper, section 05).
07 · Performance
Operation Times
Measured with the crate's criterion benchmark suite (benches/latency.rs) in release mode on Intel Xeon 2.8 GHz (x86-64) (single core). Numbers are medians; your hardware will differ.
Generate mnemonic
1.7 µs
Mnemonic → root seed (PBKDF2)
1.7 ms
BIP-32 path derivation (5 levels)
0.40 ms
Hybrid keygen from seed (3 schemes)
6.9 ms
Transaction hash (Keccak + RLP)
0.8 µs
Sign transaction (composite)
17.8 ms
Recover sender (verify all three)
3.5 ms
Derive address (Keccak-256)
10.8 µs
Build requirements: Rust 1.85+ (edition 2024), Linux/macOS/Windows, x86-64 or arm64; wasm32-unknown-unknown target plus wasm-pack for the browser build. No unsafe code, no C dependencies. ~7.8 KB storage per transaction.
08 · API Reference
Interface Documentation
Core functions of the main modules — api, crypto, transaction, hdwallet, dilithium, mdecc and the JavaScript bindings.
api create_wallet / restore_wallet / sign_* / verify_*
Built on the RustCrypto ecosystem. Consensus-critical crates are pinned to exact versions (=x.y.z) in lock-step with Cargo.lock; a patch-version drift would otherwise change verify behaviour and split the network.
ml-dsa =0.1.1
ML-DSA-87 per FIPS 204 (RustCrypto). Deterministic keygen from the 32-byte seed, signing and verification. Apache-2.0 / MIT.
Ed448 key generation and signing (ed448-rust) plus verification (ed448-goldilocks), cross-checked against RFC 8032 vectors.
sha3 =0.10.8 · hkdf =0.12.4 · sha2 =0.10.9
Keccak-256, SHAKE256, SHA3-512 and HKDF for hashing, nonces, address derivation and per-curve seed expansion.
alloy-primitives =1.5.7 · alloy-rlp =0.3.13
Ethereum types (Address, U256, Bytes) and canonical RLP encoding/decoding of the transaction envelope.
bip39 =2.2.2 · bip32 0.5 · zeroize =1.8.2
BIP-39 mnemonics (24 words), hardened BIP-32 derivation, and zeroization of every secret buffer on drop.
Test & Verification Suite
148 Unit & KAT Tests
Known-answer tests against RFC 8032 (Ed448), FIPS 204 (ML-DSA-87) and FIPS 186-4 (P-521), golden vectors for composite keys, addresses and transaction hashes, plus attack_vectors.rs: malleability, sub-signature and sub-key splicing, tampering, non-canonical RLP, degenerate keys — each asserted to be rejected.
Property-based (proptest)
tests/adversarial.rs: random sign→recover round-trips, bit-flip resilience, cross-chain replay protection and address determinism over thousands of generated inputs.
6 libFuzzer Targets
fuzz_tx_decode, fuzz_pubkey_parse, fuzz_composite_sig_verify, fuzz_tx_sign_recover, fuzz_mnemonic_seed, fuzz_signature_hash — each encodes explicit invariants, not just absence of crashes (see FUZZING.md).
criterion Benchmarks
benches/latency.rs measures BIP-39 setup, HD derivation, keygen, key serialisation, transaction hashing, composite signing, recovery and payload scaling — the source of section 07.
CI / Supply Chain
GitHub Actions: fmt, clippy, tests, cargo audit; Dependabot for dependency updates; #![forbid(unsafe_code)] at crate root; MSRV 1.85 pinned.
WASM Build
Target-gated wasm32-unknown-unknown package for the browser wallet extension; the same crate is linked natively into the node and the Substrate runtime host function.
Audit status:The library has not yet undergone an independent cryptographic audit (see SECURITY.md). Until the external review is complete it is designated for research, development and evaluation; the mainnet launch plan gates value transfers on that review.
testing
# Run all tests (unit, KAT, attack vectors, proptest)cargo test --release
# Lint and audit as in CIcargo clippy --all-targets -- -D warnings
cargo audit# Benchmarks (criterion)cargo bench --bench latency
# Fuzzing (nightly) and browser buildcargo +nightly fuzz run fuzz_tx_sign_recover -- -max_total_time=300
wasm-pack build --target web --release --features browser
Conclusion
Quantum-secure Cryptography for the Blockchain Era
Infyn Crypto combines the proven security of classical elliptic-curve cryptography with the future protection of the standardised lattice scheme ML-DSA-87. Three signature schemes, one composite signature, one Rust crate for node, runtime and browser — with full Ethereum address and transaction compatibility.
Infyn Development · blackchain-crypto-lib-rust 0.1.0 · September 2026