2026-03-07 13:03:10 +08:00
|
|
|
# libsmx
|
|
|
|
|
|
2026-03-07 19:54:34 +08:00
|
|
|
[](https://github.com/kintaiW/libsmx/actions/workflows/ci.yml)
|
2026-03-07 19:27:41 +08:00
|
|
|
[](https://crates.io/crates/libsmx)
|
|
|
|
|
[](https://docs.rs/libsmx)
|
2026-03-07 19:54:34 +08:00
|
|
|
[](https://codecov.io/gh/kintaiW/libsmx)
|
2026-03-07 19:27:41 +08:00
|
|
|
[](LICENSE)
|
2026-03-07 20:38:34 +08:00
|
|
|
[](https://blog.rust-lang.org/2024/11/28/Rust-1.83.0.html)
|
2026-03-07 13:03:10 +08:00
|
|
|
|
2026-03-07 19:27:41 +08:00
|
|
|
Pure-Rust, `#![no_std]` implementation of Chinese commercial cryptography standards with constant-time operations throughout.
|
2026-03-07 13:03:10 +08:00
|
|
|
|
2026-03-07 19:27:41 +08:00
|
|
|
| Algorithm | Standard | Description |
|
|
|
|
|
|-----------|----------|-------------|
|
|
|
|
|
| **SM2** | GB/T 32918.1-5-2016 | Elliptic Curve Public Key Cryptography |
|
|
|
|
|
| **SM3** | GB/T 32905-2016 | Cryptographic Hash Algorithm (256-bit) |
|
|
|
|
|
| **SM4** | GB/T 32907-2016 | Block Cipher (128-bit key, ECB/CBC/CTR/GCM/CCM/XTS) |
|
|
|
|
|
| **SM9** | GB/T 38635.1-2-2020 | Identity-Based Cryptography (BN256 pairing) |
|
2026-03-08 20:02:06 +08:00
|
|
|
| **BLS** | IETF RFC 9380 | BLS Signatures & Threshold Signatures (BN256) |
|
|
|
|
|
| **FPE** | NIST SP 800-38G | Format-Preserving Encryption (FF1-like) |
|
2026-03-07 13:03:10 +08:00
|
|
|
|
2026-03-07 19:27:41 +08:00
|
|
|
## Features
|
2026-03-07 13:03:10 +08:00
|
|
|
|
2026-03-07 19:27:41 +08:00
|
|
|
- **`#![no_std]`** — works in embedded, WASM, and bare-metal environments
|
|
|
|
|
- **`#![forbid(unsafe_code)]`** — zero `unsafe` blocks
|
|
|
|
|
- **Constant-time** — all secret-dependent operations use [`subtle`](https://docs.rs/subtle) primitives
|
|
|
|
|
- **Auto-zeroize** — private keys cleared on drop via [`zeroize`](https://docs.rs/zeroize)
|
|
|
|
|
- **Side-channel resistant SM4 S-box** — boolean circuit bitslice (no table lookup)
|
|
|
|
|
- **Complete EC formulas** — SM2 point addition uses branch-free complete formulas
|
2026-03-07 13:03:10 +08:00
|
|
|
|
2026-03-07 19:27:41 +08:00
|
|
|
## Quick Start
|
|
|
|
|
|
|
|
|
|
Add to `Cargo.toml`:
|
2026-03-07 13:03:10 +08:00
|
|
|
|
|
|
|
|
```toml
|
|
|
|
|
[dependencies]
|
2026-03-08 20:02:06 +08:00
|
|
|
libsmx = "0.2"
|
2026-03-07 13:03:10 +08:00
|
|
|
```
|
|
|
|
|
|
2026-03-07 19:27:41 +08:00
|
|
|
### SM3 Hash
|
2026-03-07 13:03:10 +08:00
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
use libsmx::sm3::Sm3Hasher;
|
|
|
|
|
|
2026-03-07 19:27:41 +08:00
|
|
|
// One-shot hash
|
|
|
|
|
let digest = Sm3Hasher::digest(b"abc");
|
|
|
|
|
assert_eq!(digest.len(), 32);
|
|
|
|
|
|
|
|
|
|
// Streaming hash
|
2026-03-07 13:03:10 +08:00
|
|
|
let mut h = Sm3Hasher::new();
|
2026-03-07 19:27:41 +08:00
|
|
|
h.update(b"ab");
|
|
|
|
|
h.update(b"c");
|
|
|
|
|
assert_eq!(h.finalize(), digest);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### SM3 HMAC
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
use libsmx::sm3::hmac_sm3;
|
|
|
|
|
|
|
|
|
|
let mac = hmac_sm3(b"secret-key", b"message");
|
|
|
|
|
assert_eq!(mac.len(), 32);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### SM2 Sign / Verify
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
use libsmx::sm2::{generate_keypair, get_z, get_e, sign, verify};
|
|
|
|
|
|
|
|
|
|
let mut rng = rand::rngs::OsRng;
|
|
|
|
|
|
|
|
|
|
// Key generation
|
|
|
|
|
let (pri_key, pub_key) = generate_keypair(&mut rng);
|
|
|
|
|
|
|
|
|
|
// Sign: compute Z value and message digest per GB/T 32918.2
|
|
|
|
|
let z = get_z(b"1234567812345678", &pub_key);
|
|
|
|
|
let e = get_e(&z, b"hello SM2");
|
|
|
|
|
let sig = sign(&e, &pri_key, &mut rng);
|
|
|
|
|
|
|
|
|
|
// Verify
|
|
|
|
|
verify(&e, &pub_key, &sig).expect("signature valid");
|
2026-03-07 13:03:10 +08:00
|
|
|
```
|
|
|
|
|
|
2026-03-07 19:27:41 +08:00
|
|
|
### SM4 GCM (AEAD)
|
2026-03-07 13:03:10 +08:00
|
|
|
|
|
|
|
|
```rust
|
2026-03-07 19:27:41 +08:00
|
|
|
use libsmx::sm4::{sm4_encrypt_gcm, sm4_decrypt_gcm};
|
2026-03-07 13:03:10 +08:00
|
|
|
|
|
|
|
|
let key = [0u8; 16];
|
2026-03-07 19:27:41 +08:00
|
|
|
let nonce = [0u8; 12];
|
|
|
|
|
let aad = b"additional data";
|
|
|
|
|
let plaintext = b"secret message";
|
|
|
|
|
|
|
|
|
|
let (ciphertext, tag) = sm4_encrypt_gcm(&key, &nonce, aad, plaintext);
|
|
|
|
|
let decrypted = sm4_decrypt_gcm(&key, &nonce, aad, &ciphertext, &tag).unwrap();
|
|
|
|
|
assert_eq!(decrypted, plaintext);
|
2026-03-07 13:03:10 +08:00
|
|
|
```
|
|
|
|
|
|
2026-03-07 19:27:41 +08:00
|
|
|
### SM4 CBC
|
2026-03-07 13:03:10 +08:00
|
|
|
|
|
|
|
|
```rust
|
2026-03-07 19:27:41 +08:00
|
|
|
use libsmx::sm4::{sm4_encrypt_cbc, sm4_decrypt_cbc};
|
|
|
|
|
|
|
|
|
|
let key = [0u8; 16];
|
|
|
|
|
let iv = [0u8; 16];
|
|
|
|
|
let plaintext = [0u8; 32]; // must be 16-byte aligned
|
|
|
|
|
|
|
|
|
|
let ciphertext = sm4_encrypt_cbc(&key, &iv, &plaintext);
|
|
|
|
|
let decrypted = sm4_decrypt_cbc(&key, &iv, &ciphertext);
|
|
|
|
|
assert_eq!(decrypted, plaintext);
|
2026-03-07 13:03:10 +08:00
|
|
|
```
|
|
|
|
|
|
2026-03-07 19:27:41 +08:00
|
|
|
### SM9 Identity-Based Sign / Verify
|
2026-03-07 13:03:10 +08:00
|
|
|
|
|
|
|
|
```rust
|
2026-03-07 19:27:41 +08:00
|
|
|
use libsmx::sm9::{generate_sign_master_keypair, generate_sign_user_key};
|
|
|
|
|
use libsmx::sm9::{sm9_sign, sm9_verify};
|
|
|
|
|
|
|
|
|
|
let mut rng = rand::rngs::OsRng;
|
|
|
|
|
|
|
|
|
|
// KGC generates master keypair
|
|
|
|
|
let (master_priv, sign_pub) = generate_sign_master_keypair(&mut rng);
|
|
|
|
|
|
|
|
|
|
// KGC generates user signing key for identity
|
|
|
|
|
let user_id = b"alice@example.com";
|
|
|
|
|
let user_key = generate_sign_user_key(&master_priv, user_id).unwrap();
|
|
|
|
|
|
|
|
|
|
// User signs message
|
|
|
|
|
let msg = b"hello SM9";
|
|
|
|
|
let (h, s) = sm9_sign(msg, &user_key, &sign_pub, &mut rng).unwrap();
|
2026-03-07 13:03:10 +08:00
|
|
|
|
2026-03-07 19:27:41 +08:00
|
|
|
// Anyone can verify with user's identity + master public key
|
|
|
|
|
sm9_verify(msg, &h, &s, user_id, &sign_pub).unwrap();
|
2026-03-07 13:03:10 +08:00
|
|
|
```
|
|
|
|
|
|
2026-03-07 19:27:41 +08:00
|
|
|
## Supported SM4 Modes
|
|
|
|
|
|
|
|
|
|
| Mode | Encrypt | Decrypt |
|
|
|
|
|
|------|---------|---------|
|
|
|
|
|
| ECB | `sm4_encrypt_ecb` | `sm4_decrypt_ecb` |
|
|
|
|
|
| CBC | `sm4_encrypt_cbc` | `sm4_decrypt_cbc` |
|
|
|
|
|
| OFB | `sm4_crypt_ofb` | `sm4_crypt_ofb` |
|
|
|
|
|
| CFB | `sm4_encrypt_cfb` | `sm4_decrypt_cfb` |
|
|
|
|
|
| CTR | `sm4_crypt_ctr` | `sm4_crypt_ctr` |
|
|
|
|
|
| GCM | `sm4_encrypt_gcm` | `sm4_decrypt_gcm` |
|
|
|
|
|
| CCM | `sm4_encrypt_ccm` | `sm4_decrypt_ccm` |
|
|
|
|
|
| XTS | `sm4_encrypt_xts` | `sm4_decrypt_xts` |
|
|
|
|
|
|
|
|
|
|
## Feature Flags
|
|
|
|
|
|
|
|
|
|
| Feature | Default | Description |
|
|
|
|
|
|---------|---------|-------------|
|
|
|
|
|
| `alloc` | Yes | Enables `Vec`-returning APIs (SM2/SM9 encrypt/decrypt, SM4 modes) |
|
|
|
|
|
| `std` | No | Enables `std::error::Error` impl and re-exports `rand_core/std` |
|
|
|
|
|
|
|
|
|
|
For `no_std` without `alloc`:
|
|
|
|
|
|
|
|
|
|
```toml
|
|
|
|
|
[dependencies]
|
2026-03-08 20:02:06 +08:00
|
|
|
libsmx = { version = "0.2", default-features = false }
|
2026-03-07 19:27:41 +08:00
|
|
|
```
|
|
|
|
|
|
2026-03-07 20:23:16 +08:00
|
|
|
## Benchmarks
|
|
|
|
|
|
|
|
|
|
Measured on Linux x86_64 (single core). All operations are constant-time.
|
|
|
|
|
|
|
|
|
|
### Throughput
|
|
|
|
|
|
|
|
|
|
| Algorithm | Data Size | Time | Throughput |
|
|
|
|
|
|-----------|-----------|------|------------|
|
|
|
|
|
| SM3 hash | 64 B | 349 ns | — |
|
|
|
|
|
| SM3 hash | 1 KiB | 2.80 µs | — |
|
|
|
|
|
| SM3 hash | 64 KiB | 167 µs | **374 MiB/s** |
|
|
|
|
|
| SM4-ECB encrypt | 16 B | 1.14 µs | — |
|
|
|
|
|
| SM4-ECB encrypt | 1 KiB | 37.0 µs | — |
|
|
|
|
|
| SM4-ECB encrypt | 64 KiB | 2.32 ms | **27 MiB/s** |
|
|
|
|
|
|
|
|
|
|
### SM2 (256-bit ECC)
|
|
|
|
|
|
|
|
|
|
| Operation | Time |
|
|
|
|
|
|-----------|------|
|
|
|
|
|
| Key generation | 221 µs |
|
|
|
|
|
| Sign | 258 µs |
|
|
|
|
|
| Verify | 316 µs |
|
|
|
|
|
| Encrypt | 639 µs |
|
|
|
|
|
| Decrypt | 417 µs |
|
|
|
|
|
|
|
|
|
|
### SM9 (BN256 pairing-based)
|
|
|
|
|
|
|
|
|
|
| Operation | Time |
|
|
|
|
|
|-----------|------|
|
|
|
|
|
| Master keygen | 753 µs |
|
|
|
|
|
| User keygen | 324 µs |
|
|
|
|
|
| Sign | 3.44 ms |
|
|
|
|
|
| Verify | 5.50 ms |
|
|
|
|
|
| Encrypt | 4.68 ms |
|
|
|
|
|
| Decrypt | 1.54 ms |
|
|
|
|
|
|
|
|
|
|
Run benchmarks locally:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
cargo bench
|
|
|
|
|
```
|
|
|
|
|
|
2026-03-07 19:27:41 +08:00
|
|
|
## Security
|
|
|
|
|
|
|
|
|
|
- All secret-dependent operations are constant-time (fixed iteration counts, mask-based selection)
|
|
|
|
|
- SM4 S-box uses boolean circuit bitslice — zero memory access patterns, immune to cache-timing attacks
|
|
|
|
|
- SM2 scalar multiplication uses complete addition formulas with no data-dependent branches
|
|
|
|
|
- Private keys implement `ZeroizeOnDrop` for automatic cleanup
|
|
|
|
|
- GCM/CCM authentication tags are verified in constant time
|
|
|
|
|
|
|
|
|
|
> **Disclaimer**: This library has **not** been independently audited. See [SECURITY.md](SECURITY.md) for vulnerability reporting.
|
|
|
|
|
|
|
|
|
|
## MSRV Policy
|
2026-03-07 13:03:10 +08:00
|
|
|
|
2026-03-07 20:38:34 +08:00
|
|
|
The minimum supported Rust version is **1.83.0**. MSRV bumps are treated as minor version changes.
|
2026-03-07 13:03:10 +08:00
|
|
|
|
2026-03-07 19:27:41 +08:00
|
|
|
## License
|
2026-03-07 13:03:10 +08:00
|
|
|
|
2026-03-07 19:27:41 +08:00
|
|
|
Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for details.
|