Feature/sm3 impl - #89
Conversation
|
Thanks David! So I think this PR will need to sit until I or someone else has time to review it deeply. Or maybe we could merge it into an Thoughts? |
|
wycheproof has test vectors for sm4, but not sm3, so I'm also not sure where to get a good set of vectors. |
|
English version of the spec is here: http://www.gmbz.org.cn/upload/2024-11-18/1731899426565012428.pdf Sadly all the examples are octet aligned. There's also this: https://datatracker.ietf.org/doc/draft-sca-cfrg-sm3/01/ For some unknown reason all the GM related standards submitted to the IETF ran out of puff. Attempts to contact the authors resulted in failure. I think one of the examples in the draft might have a typo in it as well, but BC's original implementation was based on the IETF draft. If it's any further help, the SM3 implementation is based on BC's. The Rust implementation has also been tested against OpenSSL's, although note neither of these implementations support partial bytes. Both BC's and OpenSSL's implementations of SM3 have had extensive use at this point. I think we'll need to talk to the OpenSSL team concerning test vectors for non-byte aligned data. The implementation seems to be coherent with the spec, section 5.2 of the document shows the padding mechanism that's used. |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New crate crypto/sm3 following the sha2 conventions:
- SM3 implements Hash, Algorithm, HashAlgParams, AlgorithmOID
(1.2.156.10197.1.401) and Suspendable, with a single spec-commented
finalize() shared by do_final_out and do_final_partial_bits_out.
Bit-oriented messages return HashError::InvalidInput rather than panic.
- Round constants T_j <<< (j mod 32) are computed at compile time; the
chaining value and input buffer live in Secret<>. Compression is a free
function over the chaining value (no unsafe, no data-dependent branches).
- Crate docs with Usage Examples, Memory Usage (112 B object, 108 B
suspended state, 272 B message schedule) and Security Considerations.
- Tests: core-test-framework Hash suite, GB/T 32905-2016 Appendix A vectors,
bc-java SM3DigestTest vectors, openssl-generated DUMMY_SEED and padding
boundary (55/56/63/64/65/119/128 byte) vectors incl. byte-at-a-time
streaming, constants/OID/strength checks, and Suspendable round-trip with
corrupt-state rejection.
- criterion bench (16KiB throughput), matching sha2_benches.
- Registered in HashFactory ("SM3"), the bouncycastle umbrella crate
(bouncycastle::sm3), and the bc-rust CLI (`bc-rust sm3 [-x]`, streaming
stdin -> stdout). Factory test added.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- bouncycastle-hmac: `HMAC_SM3 = HMAC<SM3, 64>` type alias with Algorithm
("HMAC-SM3", 128-bit), AlgorithmOID (1.2.156.10197.1.401.2), keygen(),
and SUSPENDED_HMAC_SM3_STATE_LEN. Tests: known answers generated with
`openssl dgst -sm3 -mac HMAC` over the RFC 4231 case 1/2/6 keys and
messages (incl. an over-block-size key) plus a zero-length key, and the
existing alias / algorithm-name / keygen / suspend-resume suites extended
to cover it. Criterion bench added alongside the SHA-256/512 ones.
- MACFactory: HMAC_SM3 variant, constructible as "HMAC-SM3"; factory test.
- CLI: `bc-rust hmac-sm3 [--key HEX | -k FILE] [-v MAC] [-x]`, same
streaming behaviour as hmac-sha256/512.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All SM3 DUMMY_SEED / padding-boundary digests and all HMAC-SM3 known answers were recomputed with bc-java (SM3Digest, HMac(new SM3Digest())) and match the openssl-generated values used in the tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…905-2016 s. 5.2 Replaces the InvalidInput error path with a real implementation, so every HashFactory variant now supports non-byte-aligned input. - finalize(partial_byte, num_partial_bits, output): the num_partial_bits least significant bits of partial_byte are placed MSB-first in the final message byte, immediately followed by the "1" pad bit, and the 64-bit length field is (byte_count << 3) | num_partial_bits. do_final_out is the zero-bit case. - do_final_partial_bits_out validates num_partial_bits <= 7 (InvalidLength) and delegates; nothing panics. - Crate docs: partial-bits usage example replaces the "not supported" note. Tests: core-test-framework partial-input tests enabled; `partial_bits` checks 0-bit equivalence, range validation, low-bit-only influence and second-block spill; `partial_bits_known_answers` holds 6 bit-length digests from an independent pure-Python GB/T 32905-2016 reference (validated against openssl dgst -sm3 on byte-aligned inputs; neither openssl nor bc-java expose a bit-length SM3 API). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
8d20170 to
409b918
Compare
409b918 to
3ecdaac
Compare
|
FWIW: I've implemented it long time ago also, in Go, should you wish to test against some other implementation. The code has some test vectors too: |
Chinese SM3 Digest, including HMAC. Implementation supports partial bytes, may need to ask around at OpenSSL about getting some test vectors though.