| Crates.io | pq_address |
| lib.rs | pq_address |
| version | 0.2.0 |
| created_at | 2025-05-07 08:02:43.630795+00 |
| updated_at | 2025-05-15 12:31:20.281282+00 |
| description | A Rust library for encoding and decoding post‑quantum public keys into human‑friendly Bech32m addresses. |
| homepage | |
| repository | https://github.com/p-11/pq-address-rs/ |
| max_upload_size | |
| id | 1663599 |
| size | 31,235 |
A Rust library for encoding and decoding post‑quantum public keys into human‑friendly Bech32m addresses.
Sharing a post‑quantum public key needs:
pq_address provides all four. It lets you generate and parse addresses for any public‑key type (ML‑DSA, SLH‑DSA, etc.), while guaranteeing future‑proof safety.
Bech32m (BIP‑350)
Disjoint byte ranges
0x00–0x3F (up to 64 versions).0x40–0xFF (up to 192 public key types).By carving out non-overlapping slots for versions (0x00–0x3F) and public key types (0x40–0xFF), parsing becomes trivial—and any stray or swapped byte instantly flags itself as an “unknown code,” preventing silent failures.
HRP flag
"yp" for production/mainnet, "rh" for development/testnet.Extendable
PubKeyType variants without breaking old addresses.Address example: yp1qpqg39uw700gcctpahe650p9zlzpnjt60cpz09m4kx7ncz8922635hs5cdx7q
HRP (yp / rh)
yp = Mainnetrh = TestnetSeparator
1.Data
Checksum
PQ address length is 64 characters.
Note: A Bech32 string is at most 90 characters long [BIP-173]
The default hash function for pq_address is SHA-256.
256 bit hash functions are currently considered secure against Grover's attack.
Even if the preimage is recovered, it only reveals a PQ secure public key and thus Shor's is not applicable.
Add to your Cargo.toml:
cargo add pq_address
Import pq_address
use pq_address::{
AddressDecodeError, AddressParams, Network, PubKeyType, Version, decode_address,
encode_address,
};
Encoding
let params = AddressParams {
network: Network::Mainnet,
version: Version::V1,
pubkey_type: PubKeyType::MlDsa44,
pubkey_bytes: <PUB_KEY_BYTES>,
};
match encode_address(¶ms) {
Ok(pq_addr) => println!("Encoded PQ Address: {}", pq_addr),
Err(e) => eprintln!("Encoding error: {}", e),
}
Decoding
match decode_address(&pq_addr) {
Ok(decoded) => {
println!("Decoded Network: {:?}", decoded.network);
println!("Decoded Version: {:?}", decoded.version);
println!("Decoded PubKey Type: {:?}", decoded.pubkey_type);
println!("Decoded PubKey Hash (hex): {}", decoded.pubkey_hash_hex());
println!("Re-encoded Address: {}", decoded.to_string());
}
Err(e) => eprintln!("Decoding error: {}", e),
};
Encoding errors:
enum AddressEncodeError {
/// Invalid Bech32 structure or checksum
#[error("Bech32 error: {0}")]
Bech32(#[from] bech32::EncodeError),
/// A PQ address is 64 characters long
#[error("A PQ address is 64 characters long: got {0}")]
InvalidEncodingLength(usize),
/// Invalid public key length
#[error("Invalid public key length: expected {0}, got {1}")]
InvalidPubKeyLength(usize, usize),
}
Decoding errors:
enum AddressDecodeError {
/// Invalid Bech32 structure or checksum
#[error("Bech32 error: {0}")]
Bech32(#[from] bech32::DecodeError),
/// HRP wasn’t `yp` or `rh`
#[error("unknown HRP: {0}")]
UnknownHrp(String),
/// Payload too short
#[error("payload too short (need at least version+public key type)")]
TooShort,
/// First byte isn’t a known version code
#[error("unknown version code: 0x{0:02X}")]
UnknownVersion(u8),
/// Second byte isn’t a known public key type
#[error("unknown public key type code: 0x{0:02X}")]
UnknownPubKeyType(u8),
/// Digest length didn’t match the algorithm’s expectation
#[error("invalid digest length: got {got}, expected {expected}")]
InvalidHashLength { got: usize, expected: usize },
}
See CONTRIBUTING.md for details on how to contribute to this project.
This project is licensed under the MIT License - see the LICENSE file for details.