Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
43bc846
Added ci.yml to run unit tests, but also check format, run clippy, an…
officialfrancismendoza Jul 15, 2026
27e2574
Added badges for new workflows and existing style workflow (#45)
officialfrancismendoza Jul 16, 2026
2a17ce2
Add initial rust-build.yml (#45)
officialfrancismendoza Jul 16, 2026
6116291
Add initial rust-docs.yml (#45)
officialfrancismendoza Jul 16, 2026
0bd460f
Add initial rust-test.yml (#45)
officialfrancismendoza Jul 16, 2026
1c888b9
Added workflow dispatch (#45)
officialfrancismendoza Jul 16, 2026
6d60f6d
Update all crates inherit version from version.workspace
tad-fr Jul 24, 2026
296a874
Deduplicate internal dependencies version in core cargo.toml
tad-fr Jul 24, 2026
366363c
tweaks to centralized versioning
ounsworth Jul 28, 2026
43e2536
rustfmt
ounsworth Jul 28, 2026
b9aa184
Merge PR #62
ounsworth Jul 28, 2026
e4bf0b8
Merge branch 'feature/officialfrancismendoza/45-github-action-unit-te…
ounsworth Jul 29, 2026
eadea3a
Merge PR #59: run unit tests on github PR
ounsworth Jul 29, 2026
519e4a4
Extend the ct.rs Condition to unsigned datatypes. PR #63
ounsworth Aug 21, 2026
3954671
Added the `#[non_exhaustive]` attribute to enums that are likely to g…
ounsworth Aug 21, 2026
57998ee
Polynomial was left pub as a consequence of the old way of handling s…
ounsworth Aug 21, 2026
aecdf5e
Merged PR: Added the #[non_exhaustive] attribute - #81
ounsworth Aug 23, 2026
c026339
Updated CLAUDE.md to cover spec-aware development for RFCs and NIST d…
ounsworth Aug 25, 2026
e537e23
core: split BlockCipher into block-aligned BlockCipherEncryptor/Decry…
dghgit Aug 30, 2026
e6ad944
rustfmt: wrap long trait signatures and imports
dghgit Aug 30, 2026
1a44d5b
core: add one-shot encrypt_blocks/decrypt_blocks to the block cipher …
dghgit Aug 30, 2026
b770f56
Add 0.1.3 release notes for the block cipher trait changes (PR #96)
dghgit Aug 31, 2026
75789c9
Added all src files for aes-lowmemory (#98)
officialfrancismendoza Aug 31, 2026
44ef51a
Added tests for aes-lowmemory (#98)
officialfrancismendoza Aug 31, 2026
64ce2df
Added benchmarking for aes-lowmemory (#98)
officialfrancismendoza Aug 31, 2026
2a6a46d
Added Cargo.toml and summary.md (#98)
officialfrancismendoza Aug 31, 2026
961e13f
Added updated release notes, .toml, mem_usage_benches, and other misc…
officialfrancismendoza Aug 31, 2026
f119c2a
Updated .gitignore
officialfrancismendoza Aug 31, 2026
ff9fa67
Initial add for AES-lightengine CBC mode (#100)
officialfrancismendoza Sep 1, 2026
ccda83a
Added CLI commands for 3 separate CBC modes (#100)
officialfrancismendoza Sep 1, 2026
70706e7
Linked different CLI commands to CBC test ectors, corrected wrong bra…
officialfrancismendoza Sep 1, 2026
11add61
Initial additions to CFB mode according to modes plan (#103)
officialfrancismendoza Sep 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/workflows/rust-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Rust Build

on:
pull_request:
workflow_dispatch:

permissions:
contents: read

env:
CARGO_TERM_COLOR: always

jobs:
build:
name: Build
runs-on: ubuntu-latest

steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable

- name: Build workspace
run: cargo build --workspace --all-targets --all-features
26 changes: 26 additions & 0 deletions .github/workflows/rust-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Rust Docs

on:
pull_request:
workflow_dispatch:

permissions:
contents: read

env:
CARGO_TERM_COLOR: always

jobs:
docs:
name: Documentation
runs-on: ubuntu-latest

steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable

- name: Build documentation
run: cargo doc --all
26 changes: 26 additions & 0 deletions .github/workflows/rust-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Rust Tests

on:
pull_request:
workflow_dispatch:

permissions:
contents: read

env:
CARGO_TERM_COLOR: always

jobs:
test:
name: Tests
runs-on: ubuntu-latest

steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable

- name: Run tests
run: cargo test --all
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,13 @@ mutants.out*/

.idea/
.vscode/

# Claude Code: ignore personal/local state, but share team tooling
# (skills, slash commands, subagents, and project settings.json).
.claude/*
!.claude/settings.json
!.claude/skills/
!.claude/commands/
!.claude/agents/
.claude/settings.local.json
.claude 2/
29 changes: 28 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,16 +79,43 @@ These are non-obvious house rules — follow them when writing or modifying code
- **One-shot static APIs are the default.** Every primitive should expose a take-data-return-result static method in addition to any streaming API.
- **Sensitive types impl `core::Secret` (and its supertraits).** Anything that holds key material needs this — don't reach for raw byte arrays for secrets.
- **`unwrap()` requires justification.** Either a preceding check that proves success, or an inline comment explaining why it's infallible.
- **Spec correspondence in comments.** Code that mirrors a FIPS/NIST/RFC spec should be commented line-by-line against the spec. Any deliberate deviation must be called out and justified. The "would 6-months-from-now me need >10 minutes to re-understand this?" check is the bar.
- **Spec correspondence in comments.** Code that mirrors a FIPS/NIST/RFC spec should be commented line-by-line against the spec, citing section/algorithm/step numbers. Any deliberate deviation must be called out and justified. The "would 6-months-from-now me need >10 minutes to re-understand this?" check is the bar. Never write or check these comments from memory — see "Working from specifications" below.
- **Every primitive crate must ship: tests (`src/tests` or `tests/`), criterion benches in `benches/`, and a CLI subcommand.** Stack-memory characteristics matter — algorithms with non-trivial stack usage get a `mem_usage_benches/` harness.
- **CLI commands stream.** The `cli/` binary's design is stdin→stdout with ~1 KB buffers so commands compose in shell pipelines; preserve that when adding subcommands.
- **Crate docs must include sections:** "Usage Examples", "Memory Usage" (stack-usage table), and usually "Security Considerations".

## Working from specifications

**Never cite, paraphrase, or implement a specification from recall.** Model recall of RFC text, FIPS algorithm steps, NIST parameter tables, and section numbering is unreliable — plausible-looking but wrong step numbers and subtly wrong constants are the failure mode. Before writing or reviewing any code, comment, or doc that references a spec, download a fresh copy and read the relevant part of it.

Where to get them:

```
# RFCs — plain text is easiest to grep and quote
curl -sL https://www.rfc-editor.org/rfc/rfc8446.txt -o "$SCRATCH/rfc8446.txt"

# NIST FIPS (e.g. FIPS 203 ML-KEM, FIPS 204 ML-DSA, FIPS 202 SHA-3, FIPS 180-4 SHA-2)
curl -sL https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf -o "$SCRATCH/FIPS-203.pdf"

# NIST SP 800-series (note the revision suffix, e.g. r2)
curl -sL https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Cr2.pdf -o "$SCRATCH/SP-800-56Cr2.pdf"
```

Download into the session scratchpad directory, not into the repo — spec PDFs must never be committed. Read PDFs with the `Read` tool's `pages` parameter (max 20 pages per call); if a download fails or the URL 404s, say so and ask rather than falling back on recall.

Rules when working from the downloaded copy:

- **Quote exactly, and locate precisely.** Comments and commit messages should name the document with its revision (e.g. "FIPS 203, Algorithm 13 (ML-KEM.Encaps_internal), step 2", "RFC 5869 §2.2"), and quote the spec verbatim where a quote is clearer than a paraphrase. Verify every section/algorithm/step number against the file you just downloaded — including numbers already present in the code, which may predate a spec revision.
- **The specification is the source of truth for correct behaviour** — not the C/Java/Go implementation you have seen, not the BC Java or BC C# port, and not another crate. When an existing implementation appears to disagree with the spec, re-read the spec, and if the disagreement is real, follow the spec and note the discrepancy in the PR description rather than silently copying the other implementation.
- **Optimizations are allowed, provided externally-visible behaviour is identical.** Restructuring loops, fusing steps, precomputing tables, constant-time rewrites, and in-place buffer reuse are all fine — the spec constrains observable outputs (and, for this library, timing behaviour on secret data), not the shape of the code. Any such deviation from the spec's literal steps gets a comment saying which spec steps it implements and why it is equivalent.
- **Test vectors come from the spec or its official companion files** (NIST CAVP / ACVP vectors, RFC test-vector appendices), downloaded the same way. Never hand-write an "expected" value from recall.

## Notes on testing

- `cargo mutants` is expected to be run on each crate; surviving mutants must be investigated but not all need to die (e.g. XOR/OR equivalences in crypto code are acceptable). Config lives in `.cargo/mutants.toml` (output dir `custom_mutants_output/`).
- Behaviour-critical private functions can use in-file `#[cfg(test)] mod tests` blocks when they can't be exercised from outside the crate.
- For traits in `core`, the canonical tests live in `core-test-framework` and are invoked from each implementor's integration tests — don't duplicate them per-implementation.
- The per-width `impl Condition<W>` blocks in `crypto/utils/src/ct.rs` (and their test modules) are deliberately duplicated rather than macro-generated: `cargo mutants` cannot see into `macro_rules!` bodies, so a macro would hide the mask identities from mutation testing. Do not fold them back into a macro. Any change to one width in a group (i64/i32, u64/u32) must be applied to every width in that group.

## CI

Expand Down
41 changes: 23 additions & 18 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,29 @@ members = ["cli", "crypto/*", "mem_usage_benches"]

[workspace.package]
edition = "2024"
version = "0.1.3"

[workspace.dependencies]

# *** Internal Dependencies ***
bouncycastle = { path = "./", version = "0.1.2" }
bouncycastle-base64 = { path = "./crypto/base64", version = "0.1.2" }
bouncycastle-core = { path = "crypto/core", version = "0.1.2" }
bouncycastle-core-test-framework = { path = "./crypto/core-test-framework", version = "0.1.2" }
bouncycastle-factory = { path = "./crypto/factory", version = "0.1.2" }
bouncycastle-hex = { path = "./crypto/hex", version = "0.1.2" }
bouncycastle-hkdf = { path = "./crypto/hkdf", version = "0.1.2" }
bouncycastle-hmac = { path = "./crypto/hmac", version = "0.1.2" }
bouncycastle-mlkem = { path = "./crypto/mlkem", version = "0.1.2" }
bouncycastle-mlkem-lowmemory = { path = "./crypto/mlkem-lowmemory", version = "0.1.2" }
bouncycastle-mldsa = { path = "./crypto/mldsa", version = "0.1.2" }
bouncycastle-mldsa-lowmemory = { path = "./crypto/mldsa-lowmemory", version = "0.1.2" }
bouncycastle-rng = { path = "./crypto/rng", version = "0.1.2" }
bouncycastle-sha2 = { path = "./crypto/sha2", version = "0.1.2" }
bouncycastle-sha3 = { path = "./crypto/sha3", version = "0.1.2" }
bouncycastle-utils = { path = "./crypto/utils", version = "0.1.2" }
bouncycastle = { path = "./" }
bouncycastle-aes-lowmemory = { path = "./crypto/aes-lowmemory" }
bouncycastle-base64 = { path = "./crypto/base64" }
bouncycastle-modes = { path = "./crypto/modes" }
bouncycastle-core = { path = "crypto/core" }
bouncycastle-core-test-framework = { path = "./crypto/core-test-framework" }
bouncycastle-factory = { path = "./crypto/factory" }
bouncycastle-hex = { path = "./crypto/hex" }
bouncycastle-hkdf = { path = "./crypto/hkdf" }
bouncycastle-hmac = { path = "./crypto/hmac" }
bouncycastle-mlkem = { path = "./crypto/mlkem" }
bouncycastle-mlkem-lowmemory = { path = "./crypto/mlkem-lowmemory" }
bouncycastle-mldsa = { path = "./crypto/mldsa" }
bouncycastle-mldsa-lowmemory = { path = "./crypto/mldsa-lowmemory" }
bouncycastle-rng = { path = "./crypto/rng" }
bouncycastle-sha2 = { path = "./crypto/sha2" }
bouncycastle-sha3 = { path = "./crypto/sha3" }
bouncycastle-utils = { path = "./crypto/utils" }


# *** External Dependencies ***
Expand All @@ -36,10 +39,11 @@ strip = "debuginfo"
# libbouncycastle
[package]
name = "bouncycastle"
version = "0.1.2"
version.workspace = true
edition.workspace = true

[dependencies]
bouncycastle-aes-lowmemory.workspace = true
bouncycastle-base64.workspace = true
bouncycastle-core.workspace = true
bouncycastle-factory.workspace = true
Expand All @@ -50,6 +54,7 @@ bouncycastle-mldsa.workspace = true
bouncycastle-mldsa-lowmemory.workspace = true
bouncycastle-mlkem.workspace = true
bouncycastle-mlkem-lowmemory.workspace = true
bouncycastle-modes.workspace = true
bouncycastle-rng.workspace = true
bouncycastle-sha2.workspace = true
bouncycastle-sha3.workspace = true
bouncycastle-sha3.workspace = true
35 changes: 24 additions & 11 deletions QUALITY_AND_STYLE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
This document lists general quality and style guidelines used across the library.
Hint: ask an AI to help review your PR against this style guide.
This document lists general quality and style guidelines used across the library. Hint: ask an AI to help review your PR
against this style guide.

# Architecture

Expand Down Expand Up @@ -77,20 +77,20 @@ All normal rust naming convensions from clippy apply. In addition, some library-
Where possible, primitives should expose "one-shot APIs" that simply take data and return a result as a static member
function that does not require object instantiation.

Other version of Bouncy Castle have a design pattern where stateful objects follow a pattern of new() -> init() ->
do_update() -> do_final(), and then optionally reset() that sets the object back to an unitialized state. Instead,
bc-rust does not have init() functions (moving this logic into new() or from() as appropriate), and consequently it also
does not have reset(). Also, we take advantage of the rust borrow checker's syntax so that all do_final() functions are
actually final, in other words they must take ownership of self `do_final(self, ...)` so that no subsequent calls can be
made to this object (as opposed to the usual pattern of taking a ref to self as in `do_update(&self, ...)`). These
tricks go a long way to reducing fallibility since now in general there is no (or very very little) object state to
track and return errors about.
Other version of Bouncy Castle have a design pattern where stateful objects follow a pattern of new () -> init () ->
do_update () -> do_final (), and then optionally reset () that sets the object back to an unitialized state. Instead,
bc-rust does not have init () functions (moving this logic into new () or from () as appropriate), and consequently it
also does not have reset (). Also, we take advantage of the rust borrow checker's syntax so that all do_final ()
functions are actually final, in other words they must take ownership of self `do_final(self, ...)` so that no
subsequent calls can be made to this object (as opposed to the usual pattern of taking a ref to self as in
`do_update(&self, ...)`). These tricks go a long way to reducing fallibility since now in general there is no (or very
very little) object state to track and return errors about.

Any struct that holds sensitive data must impl the `core::Secret` trait and all associated super-traits.

## Fallibility

As much as humanly possible, Result and unwrap() should be used for "Bad input data" type things and not "Programmer
As much as humanly possible, Result and unwrap () should be used for "Bad input data" type things and not "Programmer
didn't read the docs" type things.

`.unwrap()` causes system crashes. The use of `.unwrap()` should always be preceeded by testing that we're in a state
Expand All @@ -115,6 +115,19 @@ tracks it.
Use `./dev_scripts/quality_stats.sh` to see the fallibility metrics for the crate you're working on and try to get those
numbers down.

## Macros

Fundamentally, macros are an optimization that allows future maintainers to easily add existing boilerplate code to a
new type. That said, macros are typically more complex, harder to code review, and harder to debug than the unrolled
boilerplate code that they are replacing.

Any PR that uses macros will need to justify that the macros are clearly reducing future maintainer complexity compared
to the equivalent unrolled code. Simply reducing the number of lines of code is not a sufficient justification.

Note that rust macros tend not to play well with a lot of dev tooling for compiler errors, debuggers, profilers, and
`cargo mutants`, which is a good reason to avoid macros in core algorithm or data processing code. Macros can be used
more freely within test code.

# Docs

## Usage Examples
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# The Bouncy Castle Crypto Package For Rust

[![Rust Style](https://github.com/bcgit/bc-rust/actions/workflows/rust-style.yml/badge.svg)](https://github.com/bcgit/bc-rust/actions/workflows/rust-style.yml)
[![Rust Build](https://github.com/bcgit/bc-rust/actions/workflows/rust-build.yml/badge.svg)](https://github.com/bcgit/bc-rust/actions/workflows/rust-build.yml)
[![Rust Tests](https://github.com/bcgit/bc-rust/actions/workflows/rust-test.yml/badge.svg)](https://github.com/bcgit/bc-rust/actions/workflows/rust-test.yml)
[![Rust Docs](https://github.com/bcgit/bc-rust/actions/workflows/rust-docs.yml/badge.svg)](https://github.com/bcgit/bc-rust/actions/workflows/rust-docs.yml)

> [!WARNING]
> This package is currently in ALPHA, meaning that it is not complete or production-ready and will be evolving rapidly over the coming months.
> We are releasing only a small set of cryptographic algorithms in order to get feedback from the community on the API and build structure.
Expand Down
60 changes: 0 additions & 60 deletions alpha_0.1.2_release_notes.md

This file was deleted.

Loading
Loading