# Eight Implementations, One Cipher: A Cross-Language Differential Study of SM4 (GB/T 32907-2016)

Author: Daozhendong Yang (yxpil), Yunnan Technology and Business University — hi@yxpil.com
Artifact: https://github.com/yxpil/SM4Kit

## Suggested arXiv classification

- **Primary:** `cs.CR` (Cryptography and Security)
- **Cross-list:** `cs.SE` (Software Engineering)
- **Cross-list:** `cs.PL` (Programming Languages)

The same categories are recorded in the header comment of `main.tex`.

## Abstract (verbatim from `main.tex`)

SM4 is a 128-bit block cipher standardised in GB/T 32907-2016. SM4Kit is an
open-source library that implements it eight times --- in JavaScript, Python,
Go, Java, Rust, PHP, Ruby and C --- behind one API, with no third-party
dependencies. This paper is not a proposal for a cipher and claims no
cryptographic novelty; it is a differential-testing study of those eight
implementations. We describe a harness that drives each of them through the
GB/T 32907 Annex A vectors, a deterministic corpus of 256 random keys and
blocks, and nine ECB/CBC payloads at boundary lengths, and that compares
ciphertexts, the full 32-word round-key schedule, and mode outputs against one
another and against a harness-local reference model. Four toolchains
(JavaScript, Python, Java, Rust) were available on the authoring machine and
were executed; Go, PHP, Ruby and C were read and statically checked but
*not executed*, and are reported as not executed rather than as passes.
For the four executed implementations the harness finds no divergence at all:
259 block cases, 8,288 round-key words and 18 mode outputs per language agree
exactly, and all six language pairs agree pairwise. A static extraction of the
S-box table from all eight sources finds a single 256-entry bijection,
identical everywhere. To show that this null result is not vacuous we inject
294 single-point mutants into the reference model: the standard vector alone
detects 244 of them (83.0%), missing 50 of the 256 S-box table mutations,
while a 16-case differential corpus detects 294 of 294. The harness, corpus,
drivers, raw transcripts and figure scripts are released so that a reader with
the four missing toolchains can complete the matrix.

Note: in the LaTeX source `---` is an em dash, `*not executed*` is
`\emph{not executed}`, and `8,288` is `8{,}288`. Wording is otherwise identical.

## File manifest

```
papers/sm4kit/
  main.tex                  the paper (two-column, article, 10pt)
  refs.bib                  16 bibliography entries (GB/T 32907, differential
                            testing, crypto validation, modes/padding)
  common.tex                shared preamble/macros, copied from papers/_shared/common.tex
  README.md                 this file
  figures/
    loc.pdf                 Figure 1: core vs self-test lines of code per language
    matrix.pdf              Figure 2: executed/pass/not-run matrix, 8 languages x 9 checks
    mutation.pdf            Figure 3: S-box mutant detection vs corpus size
  scripts/
    reference.py            harness-local reference model of SM4 (ninth oracle),
                            S-box transcribed from GB/T 32907 Table 6
    differential.py         the single harness: builds the corpus, runs toolchains,
                            drives per-language drivers, compares ciphertexts,
                            round keys and mode outputs, runs static checks and
                            the mutation study, writes data/*.json and data/*.csv
    make_figures.py         regenerates the three PDF figures from data/*.json
    drivers/
      driver.js             JavaScript driver (node)
      driver.go             Go driver
      SM4Driver.java        Java driver
      driver.rs             Rust driver
      driver.php            PHP driver
      driver.rb             Ruby driver
      driver.c              C driver
    (Python has no driver process: it is imported and driven in-process by
    differential.py, because the interpreter is already running.)
  data/
    differential.json       full results: status, per-language results, pairwise
                            agreement, S-box hashes, LOC, self-test outcomes
    differential.csv        the same per-case results in flat form
    mutation.json           the 294-mutant detection study
    jobs/cases.tsv          the exact block corpus driven (key, block, expected)
    jobs/payloads.tsv       the exact ECB/CBC payload corpus driven
    transcripts/*.tsv       raw driver output, one file per executed language
    logs/*-selftest.log     raw self-test output, one file per executed language
    harness-run.log         console transcript of the final harness run
```

## Build

The paper needs only a standard TeX Live / MiKTeX installation; it uses
`abbrvnat`, `natbib`, `amsmath`/`amssymb`, `graphicx`, `booktabs`, `url`,
`hyperref` and `enumitem` (all in `common.tex` plus one extra package).

```bash
cd papers/sm4kit
pdflatex main.tex
bibtex main
pdflatex main.tex
pdflatex main.tex
```

The build was **not** executed as part of preparing this package: no LaTeX
compiler was installed on the authoring machine. The source has therefore been
checked by reading, not by compiling; if a warning or error appears, it is the
first thing to fix.

## Packaging for submission

From the repository root:

```bash
bash papers/make_package.sh sm4kit
```

## Submission

Upload the generated archive at https://arxiv.org/submit (choose `cs.CR` as
primary, `cs.SE` and `cs.PL` as cross-lists). arXiv compiles the source itself;
`main.tex`, `refs.bib`, `common.tex` and `figures/*.pdf` must all be present in
the archive. The abstract is 1,698 characters, inside arXiv's 1,920-character
form limit, so it can be pasted into the submission form unchanged.

## Reproduction

Requirements: Python 3, plus whichever of `node`, `python`, `go`, `javac`/`java`,
`rustc`, `php`, `ruby`, `gcc`/`cc`/`clang` are installed. Missing toolchains are
detected and reported as `not_executed`; they are never reported as passes.

```bash
cd papers/sm4kit

# 1. Run the differential harness (writes data/differential.json,
#    data/differential.csv, data/mutation.json and the raw transcripts).
python scripts/differential.py

# 2. Regenerate the figures from those results.
python scripts/make_figures.py

# 3. Optional: repeat the differential corpus without re-running the
#    repository self-tests (they dominate the wall clock; the Python suite
#    alone takes about 48 s because of the 1,000,000-iteration vector).
python scripts/differential.py --skip-selftest
```

Useful flags for `differential.py`: `--repo PATH` (default `_repos/SM4Kit`),
`--cases N` (default 256 random keys/blocks), `--seed N` (default `0x534D34`).

Status of the shipped run: JavaScript (node 24.21.0), Python (CPython 3.13.14),
Java (JDK 27) and Rust (rustc 1.98.1) executed and passed; Go, PHP, Ruby and C
were read and statically checked only, because no Go, PHP, Ruby or C toolchain
was installed. To complete the matrix, install those four toolchains and re-run
step 1; the drivers are already in `scripts/drivers/`.

## What this paper does not claim

- **No new cipher and no cryptographic novelty.** SM4 is a published standard
  (GB/T 32907-2016). Nothing here improves, attacks or re-parameterises it. The
  contribution is the cross-language conformance methodology and the artefacts.
- **No security claim about SM4Kit as a system.** The library provides ECB and
  CBC with PKCS#7 padding and no authentication; CBC without a MAC is exposed to
  padding-oracle attacks. The paper does not evaluate the library's security
  beyond conformance.
- **No constant-time claim.** No timing, cache or side-channel measurement was
  performed; the implementations are ordinary table-driven code with a 256-entry
  S-box and are not claimed to be constant time.
- **No claim that all eight languages passed.** Only four were executed. Go,
  PHP, Ruby and C are reported as not executed; their source was read and their
  S-box tables were extracted and compared, which is not execution.
- **No claim that agreement proves correctness.** Agreement among
  implementations is evidence of conformance, not proof. A shared mistake
  inherited from the standard vector would be invisible to the pairwise
  comparison; the mutation study measures this blind spot (the standard vector
  alone misses 50 of 256 S-box mutants) rather than removing it.
- **No claim of independence between the implementations.** They share one
  author, one reference and one review process; "separate" is intended
  throughout, not "independently developed" in the N-version sense.
- **No performance or memory evaluation.** Timings quoted are wall-clock
  measurements of the harness on one Windows 11 x86-64 machine, not benchmarks.
- **No claim about TypeScript.** The repository has a `.d.ts` declaration file
  only; there is no separate TypeScript implementation, so the abstract's list of
  eight languages is JavaScript, Python, Go, Java, Rust, PHP, Ruby and C.
