The cryptography that keeps Pyde secure.
pyde-crypto is the cryptography crate underlying Pyde,
a post-quantum, MEV-resistant Layer 1 blockchain. It ships the core
primitives the chain signs and hashes with: FALCON-512 signatures and
Poseidon2 hashing over the Goldilocks field, plus the Hash256 output
type shared across both.
Pyde's front-running defense is a keyless commit-reveal scheme implemented in the node — senders publish a hash commitment first and the plaintext transaction second — built on the FALCON signatures and hashing this crate provides. There is no threshold-decryption or trusted-committee key material anywhere in the crate.
The crate has no elliptic-curve dependencies anywhere in its API
surface and is no_std + alloc, so it can be embedded in WASM,
embedded hardware, and any environment that doesn't ship a libc. It
contains no first-party unsafe code.
You can use it standalone for any Rust project that needs post-quantum signatures or a ZK-friendly algebraic hash — it does not require running a Pyde node, doesn't pull in a network stack, and doesn't open any I/O.
- Install
- Quickstart
- Modules
- Security model
- Versioning + compatibility
- Performance
- Building, testing, benchmarking
- Audit status
- Contributing
- License
[dependencies]
pyde-crypto = "0.1.0-testnet.1"Or as a path dependency during development, when the crate lives alongside its consumers in a polyrepo layout:
[dependencies]
pyde-crypto = { path = "../pyde-crypto" }no_std + alloc is supported out of the box — default-features are
already off-by-design.
use pyde_crypto::falcon::{falcon_keygen, falcon_sign, falcon_verify};
use pyde_crypto::poseidon2::poseidon2_hash;
// FALCON-512 signature. keygen and sign return `Result` (the lattice
// sampler can fail on bad entropy), so unwrap or propagate.
let (pk, sk) = falcon_keygen().expect("keygen");
let msg = b"hello pyde";
let sig = falcon_sign(&sk, msg).expect("sign");
assert!(falcon_verify(&pk, msg, &sig));
// Poseidon2 hash (ZK-circuit-friendly, Goldilocks field, 256-bit output)
let digest = poseidon2_hash(msg);That's the working surface for nearly every consumer.
Type: FALCON-512 (FN-DSA-512, the FIPS 206 draft), an NTRU-lattice post-quantum signature scheme. ~666-byte signatures (average), 897-byte public keys, 1281-byte secret keys.
Use for: every user transaction, every consensus vertex, every state-root attestation, every beacon signature, the commit-reveal front-running defense, and every peer-handshake binding.
use pyde_crypto::falcon::{
FalconPublicKey, FalconSecretKey, FalconSignature,
falcon_keygen, falcon_sign, falcon_verify, falcon_verify_all,
};
let (pk, sk) = falcon_keygen().expect("keygen");
let sig = falcon_sign(&sk, b"msg").expect("sign");
assert!(falcon_verify(&pk, b"msg", &sig));
// Verify a list of signatures. This is a short-circuiting `forall`
// over `falcon_verify` — NOT an algebraic batch scheme that amortizes
// work across signatures. Algebraic batching is post-mainnet hardening.
let items: Vec<(&FalconPublicKey, &[u8], &FalconSignature)> =
vec![(&pk, b"msg" as &[u8], &sig)];
assert!(falcon_verify_all(&items));Determinism: signing is deterministic. The Gaussian sampler is
seeded from the message plus a domain-separation tag
(b"pyde-falcon-v1"), so the same (sk, msg) always produces the same
sig.
Secret-key zeroization: FalconSecretKey derives Zeroize + ZeroizeOnDrop. Cloning preserves zeroization (each clone independently
zeros on its own drop).
Type: Poseidon2 sponge over the Goldilocks field
(p = 2^64 − 2^32 + 1). 8-element state, 4-element rate, 8 external +
22 internal rounds, x^7 S-box, 256-bit output.
Use for: state-root commitment, address derivation, contract
storage-key derivation, transaction hashing, and the poseidon2 WASM
host function. Roughly 1000× cheaper inside an algebraic constraint
system than Keccak — so the right choice anywhere a hash might be
exposed to a future ZK proof.
use pyde_crypto::poseidon2::{poseidon2_hash, poseidon2_pair, poseidon2_many};
let h = poseidon2_hash(b"variable-length input");
let h2 = poseidon2_pair(h, h); // Merkle-node-style
let h3 = poseidon2_many(&[h, h2]); // sponge over a slice of hashesDomain-separation by length-prefixing is built into the encoding — variable-length inputs cannot collide with fixed-length inputs.
Type: Hash256, a 32-byte hash-output newtype. This is the shared
return type for poseidon2_* and the canonical 256-bit digest type
used across Pyde's state and consensus code. It carries no hashing
algorithm of its own — high-volume native Blake3 hashing lives in the
node, which stores its results in this type.
use pyde_crypto::hash::Hash256;
let h = Hash256::from_slice(&[0u8; 32]).expect("exactly 32 bytes");
assert_eq!(h.to_bytes().len(), 32);
println!("{h}"); // 0x0000…0000from_slice returns None for any length other than 32 — it never
silently pads or truncates, so a malformed digest surfaces at the call
site instead of comparing equal to a real hash by accident.
Key handling. FalconSecretKey derives Zeroize and
ZeroizeOnDrop from the zeroize crate, so dropping a key overwrites
the bytes in place rather than leaving them in deallocated heap pages
where a later allocation, swap-to-disk page, or core dump could read
them.
unsafe surface. This crate contains no first-party unsafe
code. The only FFI lives inside the upstream falcon-rs and Plonky3
(p3-*) dependencies, behind their own safe APIs.
Domain separation. Every cross-cryptographic-context hash input is
domain-separated by a string prefix (e.g., b"pyde-falcon-v1"), and
poseidon2 length-prefixes variable-length inputs. Cross-context
confusion attacks are blocked by construction.
- Pre-1.0. API may change between minor releases.
falcon-rsand the Plonky3 (p3-*) crates are pre-1.0 upstreams; behaviour-changing patch bumps are guarded by the Known-Answer Tests insrc/kat.rs, which pin(input, output)vectors for every primitive so a silent drift failscargo testbefore shipping.- MSRV: recent stable Rust (no specific minimum pinned).
Order-of-magnitude figures on commodity x86_64 (Apple Silicon similar).
These are illustrative; run cargo bench for numbers on your hardware.
| Primitive | Operation | ~Time |
|---|---|---|
| FALCON-512 | Verify | ~80 μs |
| FALCON-512 | Sign | ~300 μs (key prep amortized over many signs) |
| Poseidon2 | Hash (32 bytes) | ~5 μs |
cargo build
cargo build --release # recommended for crypto
cargo test # unit tests + Known-Answer Tests
cargo bench # poseidon2_bench, falcon_benchReproducible — the crate pins Cargo.lock for deterministic builds
across machines, important for audit workflows.
Pre-mainnet status: planned but not started. Pyde's launch plan commits to multiple external audits, of which this crate is one — specifically the post-quantum-cryptography pass.
Known constraints to surface to auditors:
falcon-rsand the Plonky3 crates are pre-1.0 upstreams.falcon_verify_allis a sequentialforall, not an algebraic batch verifier (algebraic batching is post-mainnet hardening).
This crate is part of the Pyde project. Substantive, protocol-affecting changes are proposed through Pyde's improvement-proposal process; non-substantive changes (clippy fixes, test additions, doc improvements) are welcome via PR.
Apache-2.0. See LICENSE.
