# DEV Article

DEV rewards real articles with cover images, accurate tags, alt text on body images, and a canonical URL when the post lives elsewhere first. The audience skews "developer who wants the story behind the artifact" — long-form is welcome, but every paragraph should pull weight.

This is the article HN, r/rust, and Twitter all link to. Treat it as the proof depot. If a skeptic clicks through from any platform and reads only this article, they should leave able to (a) explain to a colleague what `rscrypto` is, (b) decide whether to try it, and (c) know exactly where to look if they want to argue with the numbers.

The opening matters most. The current draft's first paragraph (the "two kinds of complexity" framing) is the strongest part of the existing copy. Keep it. Sharpen the middle. Replace the bullet-list "performance work" section with running prose, and put the cover image somewhere it actually exists.

---

## Front Matter

```yaml
---
title: "Building a pure-Rust crypto stack across six architecture families"
published: false
description: "Why I built rscrypto: zero default dependencies, no C libs in the primitive stack, hardware acceleration across x86_64 / ARM64 / RISC-V / IBM Z / IBM POWER / Apple Silicon, portable Rust as the byte-for-byte authority, and the public benchmark data behind the claim."
tags: rust, opensource, cryptography, performance
canonical_url: https://github.com/loadingalias/rscrypto/releases/tag/v0.3.0
cover_image: https://raw.githubusercontent.com/loadingalias/rscrypto/main/assets/distribution/platform-matrix.png
series: rscrypto launch
---
```

`canonical_url` points at the GitHub Release because Discussions are not currently enabled on the repo. If Discussions are enabled later, switch this to an Announcements discussion so the article has a long-lived comment surface.

`cover_image` references `assets/distribution/platform-matrix.png`. See [`visuals.md`](visuals.md) for the production spec and the alt text.

`tags` are capped at four on DEV. `rust`, `opensource`, `cryptography`, `performance` are the four with the largest active follower bases that match this content.

---

## Article

````markdown
Most Rust crypto stacks make you choose between two kinds of complexity.

You can compose a pile of focused crates, each with its own feature flags, release cadence, audit surface, and performance model. Or you can bind to a native library and inherit C tooling, platform packaging, and a supply-chain story that may not fit your deployment.

The practical result is that crypto becomes the place otherwise portable Rust software stops being portable.

Your server build works. Your WASM build needs a different answer. Your `no_std` target needs a different feature set. Your RISC-V target is "supported" until a backend or native library says otherwise. Your dependency tree is a stack of independent release cadences and platform assumptions, and your security review is a stack of independent threat models.

I wanted a third option: a single pure-Rust crate that can be tiny when you only need one primitive and broad when you need the whole toolbox, with hardware acceleration on the CPUs my services actually run on.

That is why I built `rscrypto`.

![Build-shape diagram: rscrypto can be enabled as one leaf primitive, one primitive family, or the full primitive stack. The bottom row calls out zero default dependencies, no C or FFI or OpenSSL, no_std-first design, and native WASM support.](https://raw.githubusercontent.com/loadingalias/rscrypto/main/assets/distribution/dependency-collapse.png)

## What `rscrypto` is

`rscrypto` is a feature-selectable Rust cryptography stack. One crate, one feature matrix, one dispatch model, one error vocabulary. The scope:

- **Cryptographic hashes** — SHA-2 (224/256/384/512/512-256), SHA-3 (224/256/384/512), SHAKE128/256, cSHAKE256, BLAKE2b/2s, BLAKE3 (hash, keyed, derive-key, XOF), Ascon-Hash256, Ascon-Xof, Ascon-CXof.
- **Fast (non-cryptographic) hashes** — XXH3-64, XXH3-128, RapidHash 64/128 with `BuildHasher`.
- **Checksums** — CRC-16 (CCITT, IBM), CRC-24 (OpenPGP), CRC-32 (ISO-HDLC), CRC-32C (Castagnoli), CRC-64/XZ, CRC-64/NVMe.
- **MACs and KDFs** — HMAC-SHA-{256, 384, 512}, KMAC256, HKDF-SHA-{256, 384}, PBKDF2-HMAC-SHA-{256, 512}.
- **Password hashing** — Argon2 (id/d/i), scrypt, PHC-string encode + bounded-policy verify.
- **Signatures and key exchange** — RSA, Ed25519, X25519.
- **AEADs** — AES-256-GCM, AES-256-GCM-SIV, ChaCha20-Poly1305, XChaCha20-Poly1305, AEGIS-256, Ascon-AEAD128.

Use one primitive:

```toml
[dependencies]
rscrypto = { version = "0.3.0", default-features = false, features = ["sha2"] }
```

Or the full stack:

```toml
[dependencies]
rscrypto = { version = "0.3.0", default-features = false, features = ["full"] }
```

The `full` feature does not pull OpenSSL, C FFI, RustCrypto, dalek, blake3, or any of the `crc-*` crates. Optional integration features for `getrandom` (entropy), `serde` (encode wrappers for non-secret types), and `rayon` (parallel BLAKE3, parallel Argon2) stay out of the dependency graph until you ask for them.

The trade is concrete:

| Before | With `rscrypto` |
|---|---|
| Many single-purpose crypto crates | One feature-selected crate |
| Native-library risk in some stacks | No C libraries in the primitive stack |
| Per-crate target assumptions | One platform matrix |
| Per-primitive dispatch behavior | One dispatch model |
| x86 and ARM first, everything else later | RISC-V, IBM Z, POWER10, WASM, `no_std` are scope, not afterthoughts |

If you want literal drop-in compatibility with the RustCrypto per-primitive crates, this isn't that — `rscrypto` uses typed handles where the input shape allows it (`HmacSha256` is a concrete type, not `Hmac<Sha256>`), and infallible signatures where they're correct. Migration starters live in [the migration guide](https://github.com/loadingalias/rscrypto/blob/main/docs/migration/README.md), and most one-line replacements work.

## The platform work

The unusual part is the platform matrix.

The Linux CI benchmark suite covers nine runners: Intel Sapphire Rapids, Intel Ice Lake, AMD Zen4, AMD Zen5, AWS Graviton3, AWS Graviton4, IBM Z (s390x), IBM POWER10 (ppc64le), and RISE RISC-V. The public benchmark set now also includes a local Apple Silicon MBP M1 macOS/aarch64 full run. **IBM** opened POWER10 and IBM Z runner access for this project; **RISE** opened RISC-V runner access. Without those partnerships, the s390x, ppc64le, and riscv64 backends would not exist for a single-maintainer crate.

Three-tier dispatch keeps the kernels honest:

1. **Compile-time** — `#[cfg(target_feature = "...")]` selects backends per build target.
2. **Runtime detection** — `is_x86_feature_detected!` and platform equivalents are queried once and cached in `platform::caps()`.
3. **Portable Rust fallback** — always present, always the byte-for-byte authority.

The portable path isn't a slow safety net; it's the reference. Every SIMD or ASM kernel is differential-tested against it on every CI run. Mismatch fails the build. That gives you two properties at once: the accelerated path is provably equivalent to the auditable one, and the portable path on `no_std` / WASM / RISC-V (where SIMD dispatch is gated) computes the same byte-for-byte answer your server does.

![Dispatch-flow diagram: an API call goes through the portable Rust implementation, which is the byte-for-byte authority. A fast path is selected through CPU capabilities only when available, and CI requires accelerated output to equal portable output.](https://raw.githubusercontent.com/loadingalias/rscrypto/main/assets/distribution/dispatch-flow.png)

## How fast it is

On the Linux CI benchmark suite, `rscrypto` wins **3,545 of 5,832 fastest-external comparisons** and wins-or-ties **5,210 of 5,832** against the strongest matched Rust baseline per case, with a **1.61× geometric-mean speedup**. On the Apple Silicon MBP M1 full run, it wins **235 of 463 fastest-external comparisons**, wins-or-ties **450 of 463**, and posts a **1.25× geometric-mean speedup**. The strongest categories:

- **Checksums** — 5.03× geomean across Linux CI fastest-external comparisons.
- **SHA-3 / SHAKE** — 2.15× / 1.86× geomean vs RustCrypto `sha3`.
- **BLAKE3** — 2.31× geomean vs the `blake3` crate for one-shot/keyed/derive-key inputs ≥64 KiB.
- **AEAD** — 1.57× geomean across RustCrypto AEADs, `aegis`, `ring`, and `aws-lc-rs`; GCM-SIV, XChaCha20-Poly1305, AEGIS-256, and IBM Z are the strongest areas.
- **RSA** — import plus verification is 1.32× geomean with 75 wins out of 99 RSA comparisons, but verification-only is 0.98×.
- **Apple Silicon MBP M1** — checksums 2.76×, AEAD 1.47×, RSA import plus verification 1.45×, RSA verification-only 1.19×, and BLAKE3 ≥64 KiB 1.80× fastest-external geomean.

It is not universally faster. PBKDF2-SHA256 at `iters=1` is 0.81×, X25519 DH is 0.92×, RSA-4096 verification is 0.94×, and small-message AEAD rows still lose on Linux CI. The Apple Silicon full run adds its own pressure points: BLAKE3 keyed and derive-key 64 KiB rows are 0.82× and 0.89×, HMAC-SHA256 bulk rows against `aws-lc-rs` are 0.87×..0.93×, empty-message ChaCha20-Poly1305 rows are 0.87×..0.93×, and SHA3-256 streaming rows are 0.93×..0.95×. Hiding the ties and losses would make the data useless, so they're in the overview alongside every speedup. Speedup is `external_crate_time / rscrypto_time` from raw Criterion median times; wins are `>1.05×`, ties `0.95×–1.05×`, losses `<0.95×`. The Linux and Apple Silicon totals are deliberately not merged because they were collected on different commits and benchmark scopes.

![Linux CI geomean speedup chart: bars for checksums (5.03x), BLAKE3 large inputs (2.31x), SHA-3 (2.15x), SHAKE (1.86x), AEAD (1.57x), and RSA import plus verify (1.32x). Subtitle: "Above 1.00x means rscrypto is faster."](https://raw.githubusercontent.com/loadingalias/rscrypto/main/assets/distribution/linux-geomean-chart.png)

The full per-platform numbers, including every tie and loss, are at [`benchmark_results/OVERVIEW.md`](https://github.com/loadingalias/rscrypto/blob/main/benchmark_results/OVERVIEW.md). The CI workflow that produces them is in `.github/workflows/bench.yaml`; raw Criterion outputs are checked into `benchmark_results/<date>/<os>/<arch>/results.txt`. If you want to reproduce on hardware I haven't tested, the same `just bench` invocation produces the same shape of numbers; happy to walk through the runner setup if it's useful.

## How I keep myself honest

Performance isn't enough. This is crypto. The trust model:

- **Portable Rust is the byte-for-byte authority.** Every SIMD or ASM kernel is differential-tested against it on every CI run. Mismatch fails the build.
- **Constant-time verification.** All MAC, AEAD, and signature comparisons run through `ct::constant_time_eq` with a `black_box` barrier — no early exit, no branch on secret bytes.
- **Opaque verification errors.** `VerificationError` is zero-size and leaks no failure detail. AEAD `decrypt` paths wipe the output buffer before returning the error, so plaintext never escapes from a failed open.
- **Zeroize on drop.** Every secret-key, shared-secret, and intermediate-secret type performs volatile writes plus a compiler fence on drop.
- **Overflow-safe arithmetic.** Counters, lengths, indices, and offsets use `strict_add` / `strict_sub` / `strict_mul` / shift variants. Release builds keep `overflow-checks = true`.
- **Miri-clean** on the portable backends — the same paths the SIMD kernels are compared to.
- **Continuous fuzzing.** libFuzzer harnesses cover parsers (PHC strings, encoded params), streaming APIs, and differential oracles across every primitive family. The weekly CI lane replays the corpus.
- **`portable-only` feature flag** forces every dispatcher to the constant-time portable backend and bypasses runtime SIMD invocation — for FIPS / DO-178C / ISO 26262 / IEC 62443 deployment modes where the audited code path needs to be the only running code path.

`rscrypto` provides FIPS-aligned primitives (AES-256-GCM, SHA-2, SHA-3 / SHAKE, HMAC, KMAC, HKDF, PBKDF2) but is **not** a FIPS 140-3 validated module. It is **not** a TLS stack. It is **not** an OS key store. The 0.3 line is pre-1.0, so breaking changes are still possible if review surfaces a better shape.

A third-party audit is on the roadmap before 1.0. Until then, every claim in the docs has source code or test code I'd rather you read than take on faith.

## Why this should exist

The Rust ecosystem already has good crypto crates. The question isn't whether the established crates are correct — they are, and I use them as differential oracles in CI. The question is whether large dependency graphs are the only acceptable shape.

I don't think they are.

A single crate gives users one audit surface, one dispatch model, one feature matrix, one security/error vocabulary, fewer transitive dependencies, and fewer platform surprises. That's the bet behind `rscrypto`.

RISC-V should not be a science project. WASM should not be a second-class target. `no_std` should not mean giving up the same primitives your server runs.

## What I want from the 0.3 line

I want hard public review before the crate becomes infrastructure.

The most useful feedback right now:

- API shape mistakes that will block adoption.
- `unsafe` and SIMD soundness — every SIMD or ASM kernel sits behind a `// SAFETY:` block.
- Benchmark methodology criticism — the workflow, the raw outputs, and the recompute script are all in the repo.
- Missing migration paths from RustCrypto, `blake3`, `crc-fast`, `crc32fast`.
- Anything in the docs the code doesn't back up.

For sensitive findings, GitHub's Private Vulnerability Reporting is enabled — acknowledgment within 48 hours.

- Repo: https://github.com/loadingalias/rscrypto
- Crates.io: https://crates.io/crates/rscrypto
- Benchmarks: https://github.com/loadingalias/rscrypto/blob/main/benchmark_results/OVERVIEW.md
- Migration guides: https://github.com/loadingalias/rscrypto/blob/main/docs/migration/README.md
- GitHub Release (canonical for this article): https://github.com/loadingalias/rscrypto/releases/tag/v0.3.0
````

---

## Cover Image

The article references `https://raw.githubusercontent.com/loadingalias/rscrypto/main/assets/distribution/platform-matrix.png`. That file must exist before publishing — see [`visuals.md`](visuals.md) for the production spec.

If the asset isn't ready by publish time, fall back to a simpler card you can produce in 30 minutes from the benchmark data: a 1200×630 PNG with the project name, the headline numbers ("3,545 Linux wins; 235 Apple Silicon wins"), and the architecture strip across the bottom. DEV requires a cover image; an absent or 404 image kills the post in social previews.

Body image alt text — write your own, never let an image post without alt. Sample alts are in the article inline (look for the `![...]` markdown).

---

## Tags Strategy

DEV caps you at four tags. The four chosen — `rust`, `opensource`, `cryptography`, `performance` — were picked for follower count and topical fit, not for SEO games.

Tag rules I'm following:

- `rust` is non-negotiable; without it, the post doesn't reach the Rust DEV community.
- `cryptography` brings in the security audience.
- `opensource` is the broadest tag that signals "this is real software," not a tutorial.
- `performance` ties to the benchmark angle.

Avoid: `rustlang` (subset of `rust`), `programming` (too broad), `webdev` (wrong audience), `ai` / `llm` / `agents` (will draw the wrong readers and skew the comments).

---

## Series

Set `series: rscrypto launch` in the front matter so DEV groups the launch with future articles in the same series. Likely follow-ups (write at most one per month, do not stack them on launch day):

1. **"From `sha2` to `rscrypto` in one diff"** — concrete migration, side-by-side `Cargo.toml` and `use` statements.
2. **"Differential testing as the trust model for SIMD crypto"** — long-form on the portable-as-authority approach, with code from `tests/differential/`.
3. **"What `portable-only` actually does, and why a feature flag was the right answer"** — long-form on regulated-deployment posture, naming FIPS / DO-178C / ISO 26262 / IEC 62443 specifically.
4. **"The CRC family in Rust: from polynomial choice to RISC-V Zbc"** — niche but the kind of post that ages well.

---

## Posting Mechanics

- **Day**: Tuesday or Wednesday morning US Eastern. DEV's daily list refreshes; midweek posts get the longest visibility window.
- **Schedule it via DEV's scheduler** rather than publishing live, so you can fix the cover image and tags one last time without showing a 404.
- **Tag-follow notifications**: people who follow `#rust` get notified when the post appears. Don't waste that by publishing with a missing image or a typo in the title.
- **Reply to every comment within 24 hours**. DEV's algorithm rewards author engagement and the comment thread is part of the artifact.
- **Cross-post the link** to your other channels with a brief lead-in, not a copy of the article. The HN / r/rust / X copy is calibrated for those platforms; don't paste DEV copy into them.

---

## What Not To Do

- Do not publish without a working cover image. DEV truncates the image preview if it 404s, and the social-share card will be blank.
- Do not write the post as a release note. Release notes belong in the GitHub release page; this article is the explanation.
- Do not bury the limitations. The "what this is not" content belongs in the body, not below the fold.
- Do not use stock crypto imagery (padlocks, hooded figures, glowing matrix code). DEV's editorial culture treats it as low-effort.
- Do not paywall, lock content behind a subscription, or include affiliate links. DEV will let you, but the audience reacts the same way HN does.
