Skip to main content

Crate gmcrypto_core

Crate gmcrypto_core 

Source
Expand description

Constant-time-designed pure-Rust SM2 / SM3 / SM4 primitives.

no_std + alloc, no C dependency, MSRV 1.85. Every secret-touching path is written against subtle’s constant-time primitives — no ==, no if, no bool on a secret-derived value — and guarded in CI by a dudect-based detectable-leak regression harness. Failure modes are deliberately indistinguishable: fallible operations return one opaque Error or None, never a reason.

This crate has not been independently audited. Assurance is internal (KAT vectors, gmssl interop, the timing harness, a cargo-fuzz suite) and the project is solo-maintained with no support SLA. Read SECURITY.md for the threat model and disclosure process, and the README for scope, before relying on it.

§Usage

[dependencies]
gmcrypto-core = "1.11"

default = [] — the base build is the primitives below with no optional dependency. Most of what this crate can do is opt-in; see Crate features.

use gmcrypto_core::sm2::{DEFAULT_SIGNER_ID, Sm2PrivateKey, sign_with_id, verify_with_id};
use gmcrypto_core::{sm3, sm4};
use getrandom::SysRng; // any `rand_core::TryCryptoRng`; this crate ships no RNG

// SM3 (GB/T 32905): 32-byte digest.
let digest = sm3::hash(b"hello");

// SM2 (GB/T 32918): sign and verify under the GB/T default signer ID.
let key = Sm2PrivateKey::from_bytes_be(&secret_32)   // your scalar, big-endian
    .into_option().ok_or("scalar out of range")?;
let sig = sign_with_id(&key, DEFAULT_SIGNER_ID, b"hello", &mut SysRng)?;
assert!(verify_with_id(&key.public_key(), DEFAULT_SIGNER_ID, b"hello", &sig));

// SM4-CBC (GB/T 32907), PKCS#7 padded. The IV is caller-supplied and must
// be unpredictable per message; a fixed one here only because it is an example.
let key = [0x42u8; sm4::KEY_SIZE];
let iv = [0x24u8; sm4::BLOCK_SIZE];
let ciphertext = sm4::mode_cbc::encrypt(&key, &iv, b"hello world");
let recovered = sm4::mode_cbc::decrypt(&key, &iv, &ciphertext)
    .ok_or("bad padding or length — one opaque None either way")?;
assert_eq!(recovered, b"hello world");

Signing and public-key encryption take any rand_core::TryCryptoRng; an RNG failure surfaces as the same opaque Error as any other failure.

§Modules

sm2SM2 sign / verify, encrypt / decrypt (GB/T 32918). With sm2-key-exchange: sm2::key_exchange, GM/T 0003.3 key agreement
sm3SM3 hash (GB/T 32905), single-shot and streaming
sm4SM4 block cipher (GB/T 32907) with ECB / CBC / CTR. With sm4-aead: GCM, CCM, incremental GCM, length-committed streaming CCM. With sm4-xts: XTS
hmacHMAC-SM3 (RFC 2104), single-shot and streaming
kdfPBKDF2-HMAC-SM3 (RFC 8018 §5.2)
asn1Strict-canonical DER for the two SM2 wire structures: RFC 3279 signatures, GM/T 0009 ciphertexts
pem, spki, sec1, pkcs8RFC 7468 PEM, RFC 5280 SubjectPublicKeyInfo, RFC 5915 ECPrivateKey, RFC 5958 OneAsymmetricKey with PBES2 encryption
x509With x509: X.509-with-SM2 leaf parse and signature verify, linear chain verify. No trust decisions beyond structure
tlcpWith tlcp: TLCP (GB/T 38636-2020) key schedule, record protection, and — with x509[sign, enc] pair verification. Not a protocol implementation

§Crate features

default = []: no_std + alloc, no optional dependency. Every feature is additive and opt-in. Items behind a feature are badged with it on docs.rs.

Capability features — pure-core, no new dependency unless stated:

  • sm4-aead — SM4-GCM and SM4-CCM (sm4::mode_gcm, sm4::mode_ccm), plus incremental-input GCM (sm4::gcm_streaming) and length-committed streaming CCM (sm4::ccm_streaming). Pulls the workspace-internal gmcrypto-simd for GHASH (CLMUL / PMULL, with a constant-time software fallback).
  • sm4-xts — SM4-XTS sector mode (sm4::mode_xts), per GB/T 17964-2021: bit-reflected α-doubling, not IEEE 1619. Single-shot and in-place multi-sector. Confidentiality only — XTS does not authenticate.
  • sm2-key-exchange — GM/T 0003.3 key agreement (sm2::key_exchange): consume-on-transition role state machines, single-use ephemerals, key released only after the peer’s confirmation tag verifies. The standard-permitted no-confirmation completers are also provided for protocols — TLCP among them — that carry confirmation themselves.
  • x509 — X.509-with-SM2 certificate parse and signature verify (GM/T 0015 profile), strict DER, v3 only. Public inputs only, so no constant-time obligation arises. Structural trust only — see the module docs.
  • tlcp — the TLCP (GB/T 38636-2020) crypto toolkit: P_SM3 key schedule, SM4-CBC and SM4-GCM record protection with a Lucky13-hardened CBC deprotect, and with x509 the [sign, enc] double-certificate pair check. No handshake state machine, framing or I/O.

Implementation features — byte-identical output, different code path:

  • sm4-bitsliced — routes the SM4 S-box through a table-less, gate-only bitsliced inversion in GF(2^8). Constant-time by construction: no table lookups, no branches on secret bits. The default path is a linear scan with the same property; this one is faster under SIMD.
  • sm4-bitsliced-simd — packs that bitsliced S-box into AVX2 (x86_64) or NEON (aarch64) lanes for the batch paths, with runtime detection and a scalar fallback. Implies sm4-bitsliced; pulls gmcrypto-simd, where the crate’s only unsafe lives.

Ecosystem trait fits — each pulls one pre-1.0 RustCrypto crate, so a breaking release of that crate is not covered by this crate’s SemVer:

  • digest-traitsdigest::Digest for sm3::Sm3, digest::Mac for hmac::HmacSm3 (digest = "0.11").
  • cipher-traitscipher::{BlockCipherEncrypt, BlockCipherDecrypt, KeyInit} for sm4::Sm4Cipher (cipher = "0.5").
  • aead-traitsaead::{AeadCore, AeadInOut, KeyInit} for sm4::Sm4Gcm and sm4::Sm4Ccm, which yields the Vec-returning aead::Aead through that crate’s blanket impl. Thin wrappers over mode_gcm / mode_ccm; every failure becomes the one opaque aead::Error. Implies sm4-aead (aead = "0.6").
  • crypto-bigint-scalarsm2::Sm2PrivateKey::from_scalar, taking a crypto_bigint::U256 directly. The always-on from_bytes_be is the recommended constructor; this exists for callers who already hold the scalar as that type and accept crypto-bigint’s major-version contract.

§wasm32-unknown-unknown

Builds on the target, gated in CI at stable and MSRV. The crate does not pull getrandom’s wasm_js backend or wasm-bindgen into its default graph; wasm callers enable wasm_js in their own Cargo.toml and pass getrandom::SysRng — or any other rand_core::TryCryptoRng — to the SM2 operations that need randomness.

§Release notes

Every published version is in CHANGELOG.md. The project is at 1.x and additive since 1.0.0; cargo-semver-checks gates breaking changes in CI, and the three workspace crates release together at one version.

Modules§

asn1
Minimal ASN.1 DER subset.
hmac
HMAC-SM3 — RFC 2104 keyed MAC over GB/T 32905-2016 SM3.
kdf
Key derivation functions.
pem
Hand-rolled PEM (RFC 7468) codec.
pkcs8
PKCS#8 OneAsymmetricKey codec (RFC 5958) + PBES2 encryption (RFC 8018).
sec1
SEC1 ECPrivateKey codec (RFC 5915) for SM2 keys.
sm2
SM2 elliptic curve cryptography (GB/T 32918-2017).
sm3
SM3 hash function (GB/T 32905-2016).
sm4
SM4 block cipher (GB/T 32907-2016) and operating modes.
spki
X.509 SubjectPublicKeyInfo codec (RFC 5280 §4.1.2.7) for SM2 keys.
tlcptlcp
TLCP (GB/T 38636-2020) cryptographic toolkit.
x509x509
X.509-with-SM2: leaf certificate parse + SM2-with-SM3 signature verify (v1.3; GM/T 0015 profile over the RFC 5280 structure).

Enums§

Error
Workspace-wide failure type.