moss-piglet/metamorphic-crypto

GitHub: moss-piglet/metamorphic-crypto

一个用 Rust 编写的零知识端到端加密库,提供后量子混合 KEM、混合 PQ 签名及对称加密原语,支持 WASM 和多平台绑定。

Stars: 1 | Forks: 0

# metamorphic-crypto 具备后量子混合 KEM、混合 PQ 签名以及可选 **CNSA 2.0** 套件轴(强度匹配的混合方案 + 纯 ML-KEM-1024 / ML-DSA-87 / AES-256-GCM)的零知识端到端加密库。 专为 [Metamorphic](https://metamorphic.app) 和 [Mosslet](https://mosslet.com) 构建 —— 这是由 [Moss Piglet Corporation](https://mosspiglet.dev) 开发的隐私优先应用,所有用户数据均在客户端进行加密,服务器仅存储不透明的密文。 ## 本库提供什么 - **Secretbox** (XSalsa20-Poly1305) — 对称认证加密 - **Sealed box** (X25519) — 匿名公钥加密(兼容 libsodium) - **混合 PQ KEM** (ML-KEM-512 + X25519) — NIST Cat-1 后量子密钥封装(可选) - **混合 PQ KEM** (ML-KEM-768 + X25519) — NIST Cat-3 后量子密钥封装(默认) - **混合 PQ KEM** (ML-KEM-1024 + X25519) — NIST Cat-5 后量子密钥封装(可选) - **Argon2id KDF** — 基于密码的密钥派生(libsodium INTERACTIVE 参数) - **混合 PQ 签名** (ML-DSA + Ed25519) — NIST Cat-2/3/5 复合数字签名(严格 AND) - **CNSA 2.0 套件轴**(可选)— 强度匹配的混合方案(X448 / P-521 / Ed448 / ECDSA-P-521)和纯后量子方案(ML-KEM-1024、ML-DSA-87、AES-256-GCM) - **Hashing** (SHA3-512/256, SHA-256/512) — 公开的单次摘要函数(例如用于密钥指纹 / 安全码) - **WASM 绑定** — 通过 `wasm-pack` 实现浏览器就绪 - **恢复密钥** — 用于密钥备份的人类可读 base32 编码 ## 安全等级 | 等级 | ML-KEM | NIST 类别 | 等效强度 | 版本标签 | 默认 | |-------|--------|---------------|------------|-------------|---------| | Cat-1 | 512 | 1 | ~AES-128 | `0x01` | No | | Cat-3 | 768 | 3 | ~AES-192 | `0x02` | Yes | | Cat-5 | 1024 | 5 | ~AES-256 | `0x03` | No | NIST (FIPS 203) 仅在类别 1/3/5 标准化了 ML-KEM —— 不存在类别 2/4 的参数集,因此未提供此类选项。所有级别均使用相同的组合构造。经典部分在每个层级均为 **X25519(经典约 Cat-1)** —— 它不会随 ML-KEM 参数集增加而扩展;在 Cat-3/Cat-5 级别中,后量子部分占主导地位,而 X25519 是经典下限(标准混合 KEM 做法:攻破需要同时击败*两*半部分)。`hybrid_open` 会根据版本标签字节自动检测级别 —— 新旧密文可无缝共存。 ## 安全属性 - `#![forbid(unsafe_code)]` — crate 中不存在任何 unsafe 代码 - 所有密钥材料在使用后均会被清零 - 通过 RustCrypto 进行恒定时间 MAC 比较 - 通过 `getrandom` 使用操作系统 CSPRNG(无用户态 PRNG) - 混合构造:必须同时攻破 ML-KEM 和 X25519 才能威胁到被封装的密钥 ## 混合 KEM 构造 混合组合器匹配 [`@noble/post-quantum`](https://github.com/paulmillr/noble-post-quantum) 的 `ml_kem768_x25519` 所使用的格式: ``` Seed expansion: SHAKE256(seed_32) → 96 bytes [ML-KEM seed (64) || X25519 sk (32)] Combiner: SHA3-256(ss_mlkem || ss_x25519 || ct_x25519 || pk_x25519 || label) ``` ### Cat-1 (ML-KEM-512,可选) ``` Public key: ML-KEM-512 ek (800 B) || X25519 pk (32 B) = 832 bytes Ciphertext: 0x01 || ML-KEM-512 ct (768 B) || X25519 eph pk (32 B) || nonce (24 B) || secretbox ct ``` ### Cat-3 (ML-KEM-768,默认) ``` Public key: ML-KEM-768 ek (1184 B) || X25519 pk (32 B) = 1216 bytes Ciphertext: 0x02 || ML-KEM-768 ct (1088 B) || X25519 eph pk (32 B) || nonce (24 B) || secretbox ct ``` ### Cat-5 (ML-KEM-1024,可选) ``` Public key: ML-KEM-1024 ek (1568 B) || X25519 pk (32 B) = 1600 bytes Ciphertext: 0x03 || ML-KEM-1024 ct (1568 B) || X25519 eph pk (32 B) || nonce (24 B) || secretbox ct ``` ## 目标平台 | 目标 | 构建 | 用例 | |--------|-------|----------| | Native | `cargo build` | 测试、CLI 工具、Elixir NIF(`metamorphic_crypto` Hex 包) | | WASM | `wasm-pack build --target web` | 浏览器(Phoenix LiveView、任何 SPA) | | iOS | UniFFI(计划中) | 原生 Swift 应用 | | Android | UniFFI(计划中) | 原生 Kotlin 应用 | ## 用法 ``` use metamorphic_crypto::{generate_key, encrypt_secretbox_string, decrypt_secretbox_to_string}; use metamorphic_crypto::{generate_hybrid_keypair, hybrid_seal, hybrid_open}; use metamorphic_crypto::{generate_hybrid_keypair_512, hybrid_seal_512}; use metamorphic_crypto::{generate_hybrid_keypair_1024, hybrid_seal_1024}; // Symmetric encryption let key = generate_key(); let ciphertext = encrypt_secretbox_string("sensitive data", &key).unwrap(); let plaintext = decrypt_secretbox_to_string(&ciphertext, &key).unwrap(); assert_eq!(plaintext, "sensitive data"); // Hybrid PQ seal (Cat-3, default) let kp = generate_hybrid_keypair(); let sealed = hybrid_seal(b"context_key_bytes", &kp.public_key).unwrap(); let opened = hybrid_open(&sealed, &kp.secret_key).unwrap(); // Hybrid PQ seal (Cat-5) let kp5 = generate_hybrid_keypair_1024(); let sealed5 = hybrid_seal_1024(b"context_key_bytes", &kp5.public_key).unwrap(); let opened5 = hybrid_open(&sealed5, &kp5.secret_key).unwrap(); // auto-detects level // Hybrid PQ seal (Cat-1) let kp1 = generate_hybrid_keypair_512(); let sealed1 = hybrid_seal_512(b"context_key_bytes", &kp1.public_key).unwrap(); let opened1 = hybrid_open(&sealed1, &kp1.secret_key).unwrap(); // auto-detects level ``` ## Hashing 基于已有的、经过审计的 `sha3` 和 `sha2` 依赖项的公开单次摘要函数。这些函数仅用于**公开**数据 —— 密钥指纹 / 安全码以及密钥透明度日志条目 —— 其输入(例如公钥)和输出摘要本身就是预期公开的。 `sha3_512` 是推荐的默认值(NIST Cat-5,约 256 位抗碰撞性,与本 crate 基于 Keccak 的组合器保持一致)。提供 `sha3_256`、`sha256` 和 `sha512` 以便集成者匹配现有格式。 ``` use metamorphic_crypto::{sha3_512, sha3_256, sha256, sha512}; // Take raw bytes, return fixed-size byte arrays. let digest: [u8; 64] = sha3_512(b"public key bytes"); // recommended default let d256: [u8; 32] = sha3_256(b"..."); let s256: [u8; 32] = sha256(b"..."); // SHA-2 interop let s512: [u8; 64] = sha512(b"..."); // SHA-2 interop // Encode the digest yourself when needed: use metamorphic_crypto::b64; let fingerprint_b64 = b64::encode(&digest); ``` ### 域分离(推荐用于指纹 / 透明度日志) 对于密钥指纹、安全码和密钥透明度日志条目,推荐使用 `sha3_512_with_context`,它将摘要绑定到带有版本号的上下文标签,这样在不同目的下进行哈希的相同字节绝不会发生碰撞或在不同上下文之间被曲解。它具有与 `sha3_512` 完全相同的强度 —— 它*就是* SHA3-512,对消息进行明确无误的框架封装 —— 并使意图变得明确: ``` use metamorphic_crypto::sha3_512_with_context; let fp = sha3_512_with_context("mosslet/key-fingerprint/v1", pubkey_bytes); let log = sha3_512_with_context("mosslet/log-entry/v1", entry_bytes); // fp and log are unrelated even if the byte inputs coincide. ``` 稳定的传输格式(需精确复现以实现跨语言一致性): ``` SHA3-512( u64_be(len(context_utf8)) || context_utf8 || data ) ``` 8 字节的大端序长度前缀使得 `(context, data)` 边界明确无误(无边界混淆碰撞)。请使用带版本号的命名空间标签。 编码:原生函数接收 `&[u8]` 并返回原始字节数组 —— 在调用处编码为 base64 或 hex。WASM 绑定接收/返回 base64 以匹配其余的 WASM API(见下文)。 **不要用这些来哈希机密。** 裸哈希无法对其输入提供任何保证,并且(与 crate 的其余部分一致)哈希路径不添加任何 zeroize/恒定时间操作 —— 清除已经公开的临时副本只会增加开销而没有保护作用。如果您需要处理机密材料(密码、私钥),请改用正确的构造 —— 本 crate 中用于基于密码派生的 Argon2id `derive_session_key`,或专用的 KDF/MAC。处理机密的加密 API 已在 drop 时执行了清零操作。 ## 混合 PQ 签名 复合数字签名:每条消息均由 ML-DSA (FIPS 204) **和** Ed25519 (RFC 8032) **共同**签名,且验证要求**两者**都有效(严格 AND)。攻击者必须同时攻破格方案和椭圆曲线方案才能伪造签名,并且无法剥离其中一种算法来降级另一种。这是上述混合 KEM 在签名方面的对应实现。 ``` use metamorphic_crypto::{generate_signing_keypair, sign, verify, SIGN_CONTEXT_V1}; let kp = generate_signing_keypair(); // Cat-3 (ML-DSA-65 + Ed25519), default let sig = sign(b"transparency log entry", SIGN_CONTEXT_V1, &kp.secret_key).unwrap(); assert!(verify(b"transparency log entry", SIGN_CONTEXT_V1, &sig, &kp.public_key).unwrap()); // Re-derive the public key from a backed-up secret key: use metamorphic_crypto::derive_public_key; assert_eq!(derive_public_key(&kp.secret_key).unwrap(), kp.public_key); ``` Cat-2 (`generate_signing_keypair_44`) 和 Cat-5 (`generate_signing_keypair_87`) 也可用;`verify` 会从签名版本标签中自动检测级别。`secret_key` 字段在 drop 时会被清零。 ### 签名级别与模式 | 级别 | ML-DSA | NIST 类别 | 等效强度 | 版本标签 | 默认 | |-------|-----------|---------------|------------|-------------|---------| | Cat-2 | ML-DSA-44 | 2 | ~AES-128 | `0x01` | No | | Cat-3 | ML-DSA-65 | 3 | ~AES-192 | `0x02` | Yes | | Cat-5 | ML-DSA-87 | 5 | ~AES-256 | `0x03` | No | ML-DSA 使用 **hedged(随机化)** 变体进行签名 —— 这是 FIPS 204 的默认模式,也是最保守的模式(具有抗 RNG 故障弹性,强化了抵御确定性格签名可能招致的故障 / 侧信道攻击的能力)。Ed25519 根据 RFC 8032 是确定性的。因此,签名**字节是不可复现的**,但**传输格式是确定且固定的**。 ### 域分离和传输格式 两种算法均签署相同的域分离消息,其封装格式与 `sha3_512_with_context` 完全相同(带长度前缀的上下文): ``` signed_msg = I2OSP(len(context_utf8), 8) || context_utf8 || message ``` ML-DSA 使用空的原生上下文对 `signed_msg` 进行签名,因此两种算法以及所有语言绑定的封装格式都是完全相同的。字节布局(Ed25519 在前,固定大小,因此 ML-DSA 尾部不需要长度前缀): ``` signature = tag || ed25519_sig (64 B) || ml_dsa_sig (2420 / 3309 / 4627 B) public_key = tag || ed25519_pk (32 B) || ml_dsa_pk (1312 / 1952 / 2592 B) secret_key = tag || ed25519_seed(32 B) || ml_dsa_seed(32 B) = 65 B ``` ### 依赖审计状态 | 依赖项 | 版本 | 已审计 | 备注 | |-----------------|---------|---------------------|-------| | `ed25519-dalek` | 2.x | 是(成熟) | 广泛部署的 RFC 8032 实现。 | | `ml-dsa` | 0.1.x | **否** (RustCrypto) | FIPS 204 (最终版)。新 crate,尚未经过独立审计。已固定版本;为 FIPS 模式路线图进行跟踪。 | ML-DSA 在独立且强大的 Ed25519 基础上提供了深度防御:即使在年轻的 `ml-dsa` 实现中发现了缺陷,复合签名仍然至少具有与 Ed25519 相同的强度。我们如实陈述这一点,以便在后量子实现逐步走向审计 / FIPS 验证期间,集成者可以自行做出选择。 ## CNSA 2.0 套件轴(可选) 默认情况下,以上所有内容均为 **`Suite::Hybrid`** —— 经典+PQ 的严格 AND 构造(ML-KEM + X25519;ML-DSA + Ed25519)。如果您没有特定的强制要求,这是推荐的选择,您可以忽略本节。 对于必须遵循 NSA **Commercial National Security Algorithm Suite 2.0** (CNSA 2.0 / NIST IR 8547) 的部署,`Suite` 轴允许您通过*单个额外参数*来提升安全姿态。它与您已经熟悉的 `SecurityLevel` (Cat-1/3/5) 是**正交(独立)**的,因此您实际上有两个独立的调节旋钮: ``` posture (Suite) × parameter set (SecurityLevel) ┌──────────────────────────────┐ ┌───────────────────────┐ │ Hybrid (default) │ │ Cat-1 / Cat-3 / Cat-5 │ │ HybridMatched (opt-in) │ └───────────────────────┘ │ PureCnsa2 (opt-in) │ └──────────────────────────────┘ ``` | 套件 | 它是什么 | 经典搭档 | 状态 | |-------|------------|-------------------|--------| | `Hybrid` | 现有的严格 AND 经典+PQ。**逐字节不变。** | X25519 / Ed25519(每个层级) | **默认,推荐** | | `HybridMatched` | 经典搭档与 PQ 类别相匹配,确保其永远不会成为薄弱环节 | KEM: Cat-3→X448, Cat-5→P-521 ECDH · Sign: Cat-3→Ed448, Cat-5→ECDSA-P-521 | 可选 | | `PureCnsa2` | 纯后量子,无经典部分(CNSA-2.0 盒) | 无 | 可选,**仅限 Cat-5** | 在最低层级(KEM Cat-1 / sign Cat-2),`HybridMatched` 与 `Hybrid` 完全相同 —— 不会产生新的格式,因此不会破坏任何内容。 ### 新传输格式(仅限新套件) `Hybrid` 套件(以及处于最低层级的 `HybridMatched`)保持其现有的 `0x01/0x02/0x03` 密文标签和字节布局不变。匹配 / 纯套件使用新标签和符合 CNSA 标准的封装信封: | 套件 + 级别 | KEM | 标签 | |---------------|-----|-----| | `PureCnsa2` Cat-5 | ML-KEM-1024 + AES-256-GCM | `0x10` | | `HybridMatched` Cat-3 | ML-KEM-768 + X448 + AES-256-GCM | `0x13` | | `HybridMatched` Cat-5 | ML-KEM-1024 + P-521 ECDH + AES-256-GCM | `0x14` | ``` ikm = ss_mlkem (PureCnsa2) | ss_mlkem || ss_ecc (HybridMatched) key = HKDF-SHA512(ikm, info = suite_tag || context_label) -> 32-byte AES-256 key out = AES-256-GCM(key, 96-bit random nonce, AAD = suite_tag || context_label) wire = tag(1) || kem_ct || [ecc_eph_pk] || nonce(12) || ct || gcm_tag(16) ``` 每次封装都会生成新的 KEM 密钥,因此派生的 AES-256 密钥是一次性的,随机的 96 位 nonce 绝不会重复 ——在不偏离 CNSA 批准集合(不使用 AES-GCM-SIV)的情况下,提供了 SIV 级别的误用抵抗力。请注意刻意的哈希拆分:此处使用 **HKDF-SHA512** 进行*密钥派生*;**SHA3-512** 依然是*叶子节点/转录*哈希(`sha3_512_with_context`)的首选。 ### 上下文标签 新套件将带版本号的上下文标签绑定到 HKDF `info` 和 GCM AAD(对于签名,则是 I2OSP 封装的消息)中。语法规则:`"//v"`。**namespace** 是每个租户唯一的调节旋钮;协议结构保持固定。库默认值为 `SEAL_CONTEXT_V1` (`"metamorphic/seal/v1"`) 和 `SIGN_CONTEXT_V1` (`"metamorphic/sign/v1"`);传入您自己的值(例如 `"mosslet/seal/v1"`)来为您的部署设置命名空间。 ### 用法 (Rust) ``` use metamorphic_crypto::{ Suite, SecurityLevel, SignatureLevel, SEAL_CONTEXT_V1, SIGN_CONTEXT_V1, generate_hybrid_keypair_suite, hybrid_seal_suite, hybrid_open_with_context, generate_signing_keypair_suite, sign, verify, }; // --- KEM / seal: the pure CNSA-2.0 box (ML-KEM-1024 + AES-256-GCM) --- let kp = generate_hybrid_keypair_suite(Suite::PureCnsa2, SecurityLevel::Cat5).unwrap(); let sealed = hybrid_seal_suite(b"context_key_bytes", &kp.public_key, Suite::PureCnsa2, SecurityLevel::Cat5).unwrap(); // `hybrid_open` auto-detects the tag using the DEFAULT context label; if you // sealed with a custom label, open with it explicitly: let opened = hybrid_open_with_context(&sealed, &kp.secret_key, SEAL_CONTEXT_V1).unwrap(); // --- Signatures: ML-DSA-87 only (Cat-5 pure) --- let sk = generate_signing_keypair_suite(Suite::PureCnsa2, SignatureLevel::Cat5).unwrap(); let sig = sign(b"checkpoint", SIGN_CONTEXT_V1, &sk.secret_key).unwrap(); assert!(verify(b"checkpoint", SIGN_CONTEXT_V1, &sig, &sk.public_key).unwrap()); // `sign` / `verify` / `derive_public_key` auto-detect the suite from the version // tag — no suite argument is needed once the key exists. ``` `seal_for_user_with_suite` 是面向用户的封装方法,当不存在 PQ 密钥时,它会回退到传统的 X25519,这与 `seal_for_user_with_level` 类似。 ### 如实声明 声明:**“CNSA 2.0 算法套件,NCC 审计组件,纯 Rust,内存安全(`forbid-unsafe`)。”** **而非** “FIPS 140-3 认证”。`PureCnsa2` 更加符合标准,但完全依赖于(在我们的层面尚未经过独立审计的)格算法实现,这正是为什么严格 AND 的 `Hybrid` 默认设置仍被推荐的原因:它会保留经典的后备支撑,直到 PQ 实现通过审计 / 验证。 ## WASM(浏览器) ``` wasm-pack build --target web --release ``` ``` import init, { deriveSessionKey, encryptSecretboxString } from './pkg/metamorphic_crypto.js'; await init('/path/to/metamorphic_crypto_bg.wasm'); const key = deriveSessionKey(password, saltBase64); const ciphertext = encryptSecretboxString("hello", key); ``` ### Hashing (WASM) 摘要导出函数接收 base64 编码的输入,并返回 base64 格式的摘要。如果需要 hex 指纹,请在 JS 端解码或重新编码为 hex。 ``` import init, { sha3_512, sha3_512WithContext } from './pkg/metamorphic_crypto.js'; await init(); const dataB64 = btoa("public key bytes"); const digestB64 = sha3_512(dataB64); // also: sha3_256, sha256, sha512 // Domain-separated (recommended for fingerprints / transparency logs): const fp = sha3_512WithContext("mosslet/key-fingerprint/v1", dataB64); ``` ### Signatures (WASM) 密钥和签名均为 base64 格式;消息为 base64 格式,`context` 为 UTF-8 字符串。仅当两个组件签名均有效时,`verify` 才会返回 `true`。 ``` import init, { generateSigningKeyPair, sign, verify } from './pkg/metamorphic_crypto.js'; await init(); const kp = generateSigningKeyPair("cat3"); // { publicKey, secretKey } const msg = btoa("transparency log entry"); const sig = sign(msg, "metamorphic/sign/v1", kp.secretKey); const ok = verify(msg, "metamorphic/sign/v1", sig, kp.publicKey); // true ``` ### CNSA 2.0 套件 (WASM) `Suite` 轴作为字符串参数(`"hybrid"`(默认)、`"hybridMatched"` 或 `"pureCnsa2"`)公开,并附带常用的 `"cat1"`/`"cat3"`/`"cat5"` 级别。解密 / 验证会根据版本标签自动检测套件。 ``` import init, { generateHybridKeyPairSuite, hybridSealSuite, hybridOpenWithContext, generateSigningKeyPairSuite, sign, verify, } from './pkg/metamorphic_crypto.js'; await init(); // Pure CNSA-2.0 KEM box (ML-KEM-1024 + AES-256-GCM) const kp = generateHybridKeyPairSuite("pureCnsa2", "cat5"); // { publicKey, secretKey } const sealed = hybridSealSuite(btoa("key material"), kp.publicKey, "pureCnsa2", "cat5"); // Open with the context label used at seal time (default "metamorphic/seal/v1"): const opened = hybridOpenWithContext(sealed, kp.secretKey, "metamorphic/seal/v1"); // base64 // Pure ML-DSA-87 signatures const sk = generateSigningKeyPairSuite("pureCnsa2", "cat5"); const sig = sign(btoa("checkpoint"), "metamorphic/sign/v1", sk.secretKey); const ok = verify(btoa("checkpoint"), "metamorphic/sign/v1", sig, sk.publicKey); // true ``` 对于自定义的每个租户命名空间,请使用 `hybridSealSuiteWithContext(..., "mosslet/seal/v1")` 并使用相同的标签进行打开。`sealForUserWithSuite` 映射了 `sealForUser`,并在末尾追加了套件/级别参数。 ## 测试 ``` cargo test # unit + integration + cross-level compatibility cargo clippy # zero warnings cargo fmt --check # formatted ``` ## 许可证 根据您的选择,采用 [MIT](LICENSE-MIT) 或 [Apache-2.0](LICENSE-APACHE) 双重许可。
标签:AI工具, Rust, WASM, 可视化界面, 后量子加密, 密码学, 手动系统调用, 端到端加密, 网络流量审计, 通知系统, 零知识证明