Skip to content

Commit 40ae512

Browse files
chore: public release packaging
Publication packaging: anvil release pipeline, dependabot, SECURITY/CHANGELOG, badges, examples, agent docs. No library code changes.
1 parent 31850cc commit 40ae512

19 files changed

Lines changed: 654 additions & 7 deletions

.github/FUNDING.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
github: TheCryptoDonkey

.github/dependabot.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
version: 2
2+
3+
# Canonical dependabot config for npm/TypeScript repos in forgesworn.
4+
# Synced from forgesworn/.github/templates/dependabot/dependabot.npm.yml.
5+
# Edit the template, not individual repos -- run the propagator to sync.
6+
#
7+
# Tiering:
8+
# patch + minor -> grouped, auto-merged on green CI
9+
# major -> individual PR, manual review
10+
# TS / Node / framework majors -> ignored here, upgraded deliberately
11+
12+
updates:
13+
- package-ecosystem: npm
14+
directory: "/"
15+
schedule:
16+
interval: weekly
17+
day: monday
18+
open-pull-requests-limit: 10
19+
commit-message:
20+
prefix: chore
21+
include: scope
22+
groups:
23+
production-minor:
24+
dependency-type: production
25+
update-types: ["patch", "minor"]
26+
dev-minor:
27+
dependency-type: development
28+
update-types: ["patch", "minor"]
29+
ignore:
30+
- dependency-name: "typescript"
31+
update-types: ["version-update:semver-major"]
32+
- dependency-name: "@types/node"
33+
update-types: ["version-update:semver-major"]
34+
- dependency-name: "node"
35+
update-types: ["version-update:semver-major"]
36+
37+
- package-ecosystem: github-actions
38+
directory: "/"
39+
schedule:
40+
interval: monthly
41+
open-pull-requests-limit: 5
42+
commit-message:
43+
prefix: chore
44+
include: scope
45+
groups:
46+
actions-minor:
47+
update-types: ["patch", "minor"]

.github/workflows/auto-release.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
name: auto-release
2+
3+
on:
4+
push:
5+
branches: [main]
6+
7+
permissions:
8+
contents: write
9+
actions: write
10+
11+
jobs:
12+
auto-release:
13+
uses: forgesworn/anvil/.github/workflows/auto-release.yml@v0

.github/workflows/ci.yml

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,25 @@
11
name: CI
2-
on: [push, pull_request]
2+
3+
on:
4+
push:
5+
branches: [main, dev, 'feat/**', 'fix/**', 'chore/**']
6+
pull_request:
7+
branches: [main, dev]
8+
9+
permissions:
10+
contents: read
11+
312
jobs:
413
test:
514
runs-on: ubuntu-latest
615
steps:
7-
- uses: actions/checkout@v4
8-
- uses: actions/setup-node@v4
16+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
17+
18+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
919
with:
10-
node-version: '22'
20+
node-version: 24
21+
cache: npm
22+
1123
- run: npm ci
12-
- run: npx tsc --noEmit
13-
- run: npm test
24+
- run: npm run typecheck
25+
- run: npm run coverage
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Dependabot auto-merge
2+
3+
# Auto-merges dependabot PRs for patch/minor bumps once required checks pass.
4+
# Majors are never auto-merged -- they open a normal PR for deliberate review.
5+
# Security advisories always open their own PR and follow the same gate.
6+
#
7+
# Synced from forgesworn/.github/templates/dependabot/dependabot-auto-merge.yml.
8+
9+
on: pull_request
10+
11+
permissions:
12+
contents: write
13+
pull-requests: write
14+
15+
jobs:
16+
auto-merge:
17+
if: github.event.pull_request.user.login == 'dependabot[bot]'
18+
runs-on: ubuntu-latest
19+
steps:
20+
- name: Fetch dependabot metadata
21+
id: meta
22+
uses: dependabot/fetch-metadata@d7267f607e9d3fb96fc2fbe83e0af444713e90b7 # v2.3.0
23+
24+
- name: Enable auto-merge for patch/minor
25+
if: steps.meta.outputs.update-type == 'version-update:semver-patch' || steps.meta.outputs.update-type == 'version-update:semver-minor'
26+
env:
27+
PR_URL: ${{ github.event.pull_request.html_url }}
28+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
29+
run: gh pr merge --auto --squash --delete-branch "$PR_URL"

.github/workflows/release.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: release
2+
3+
on:
4+
release:
5+
types: [published]
6+
workflow_dispatch:
7+
inputs:
8+
tag:
9+
description: Release tag to publish
10+
type: string
11+
required: true
12+
13+
permissions:
14+
contents: write
15+
id-token: write
16+
17+
jobs:
18+
release:
19+
uses: forgesworn/anvil/.github/workflows/release.yml@v0
20+
with:
21+
tag: ${{ inputs.tag || '' }}

AGENTS.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# AGENTS.md — private-equality
2+
3+
Instructions in this file apply to the entire repository.
4+
5+
## Project Summary
6+
7+
`@forgesworn/private-equality` decides "do two parties hold the same secret —
8+
yes/no?" via the Socialist Millionaires' Protocol (OTR variant) over
9+
Ristretto255, revealing nothing else on mismatch. Pure four-message state
10+
machine; the consumer supplies the authenticated channel and ferries opaque
11+
bytes.
12+
13+
## Commands
14+
15+
- Build: `npm run build`
16+
- Test: `npm test`
17+
- Coverage gate: `npm run coverage`
18+
- Typecheck: `npm run typecheck`
19+
20+
## Rules
21+
22+
- British English in all prose. ESM-only; imports use `.js` extensions.
23+
- Commits: `type: description`. No `Co-Authored-By` lines.
24+
- Do not modify domain separators, tag bytes, the `sessionBinding` folding,
25+
identity-point rejection, or the zero-scalar guard without crypto review —
26+
see the "Crypto Safety" section of `CLAUDE.md`.
27+
- Bump `PRIVATE_EQUALITY_VERSION` (`src/types.ts`) together with
28+
`package.json` and add a `CHANGELOG.md` entry for any release.
29+
- Anvil auto-releases on push to main — work on branches.

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Changelog
2+
3+
## 0.1.0
4+
5+
Initial public release.
6+
7+
- Socialist Millionaires' Protocol (the OTR SMP variant) over Ristretto255 as a
8+
pure four-message state machine — `initiate`/`respond``session.next(incoming)`
9+
→ a single boolean, identical on both sides.
10+
- Mandatory `sessionBinding` (the consumer's authenticated-channel transcript
11+
hash) folded into every Fiat–Shamir challenge — relaying messages across two
12+
separate channels aborts with `SmpError`.
13+
- Wire hardening: identity points are rejected on decode; the ~2^-252
14+
zero-secret-scalar edge case is guarded.
15+
- 32 tests; 100% line coverage on `group`, `zkp`, and `smp`.

CLAUDE.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# CLAUDE.md — @forgesworn/private-equality
2+
3+
AI agent instructions for working on this codebase.
4+
5+
## Build & Test
6+
7+
```bash
8+
npm run build # tsc → dist/
9+
npm test # vitest (single run)
10+
npm run coverage # vitest with the per-file coverage gate
11+
npm run typecheck # tsc --noEmit
12+
```
13+
14+
Always run `npm test` after changes. Always run `npm run typecheck` before committing.
15+
16+
## Architecture
17+
18+
| File | Purpose |
19+
|------|---------|
20+
| `src/group.ts` | Isolates `@noble/curves` ristretto255 — the ONLY file importing it. Point/scalar codecs, `hashToScalar`, `randomScalar`. `Pt` is a structural interface (dodges TS4094 on @noble's anonymous class). |
21+
| `src/zkp.ts` | Three sigma proofs: PoK of a discrete log, representation (`P = g3^r`, `Q = g1^r · g2^y`), equality of two discrete logs. All Fiat–Shamir with domain separation + per-proof tag byte. |
22+
| `src/smp.ts` | The four-message OTR-SMP state machine + fixed-layout wire codec. `initiate`/`respond` entry points. |
23+
| `src/types.ts` | Public types: `Secret`, `SmpResult`, `SmpStep`, `SmpSession`, `SmpError`, `PRIVATE_EQUALITY_VERSION`. |
24+
| `src/index.ts` | Public API re-exports. |
25+
26+
### Data flow
27+
28+
Pure state machine — no transport. The consumer ferries opaque `Uint8Array`
29+
messages over an authenticated channel: `initiate(secret, binding)`
30+
`{ session, first }`; each side calls `session.next(incoming)` until
31+
`{ done: true, result: { match } }`. Four messages total.
32+
33+
## Crypto Safety — Do Not Change Without Expert Review
34+
35+
- **Domain separators** (`private-equality/pok-v1`, `private-equality/repr-v1`,
36+
`private-equality/eq-v1`, `private-equality/secret-v1`) are protocol
37+
constants. Changing them breaks interoperability between versions.
38+
- **Per-proof tag bytes** separate the distinct proofs within a session. Do not
39+
renumber or merge them — two proofs sharing a challenge domain enables proof
40+
transplantation.
41+
- **`sessionBinding` is folded into every Fiat–Shamir challenge.** Never make it
42+
optional and never drop it from a challenge — it is the MITM defence.
43+
- **Identity points are rejected on the wire** (decode-time). Do not relax this —
44+
it closes the degenerate `QaQb = identity` case.
45+
- **The zero secret-scalar guard** in secret derivation is intentional. Do not
46+
remove it.
47+
- **The wire codec is fixed-layout** (32-byte points and scalars, strict length
48+
checks). Do not add variable-length fields without redesigning the codec.
49+
- **`PRIVATE_EQUALITY_VERSION` in `src/types.ts` is pinned by
50+
`src/smoke.test.ts` as a literal string.** Anvil bumps `package.json` from
51+
commit prefixes; the constant does not update itself. Any releasing change
52+
(`feat:`/`fix:`) must update `src/types.ts` and `src/smoke.test.ts` to the
53+
new version in the same PR.
54+
55+
## Conventions
56+
57+
- **British English** in all prose (colour, initialise, behaviour, licence).
58+
- **ESM-only** — all imports use `.js` extensions.
59+
- **Commit messages**: `type: description` (e.g. `feat: add subpath export`, `fix: reject oversized message`).
60+
- **No `Co-Authored-By`** lines in commits.
61+
- **Anvil auto-release on main** — every push to main runs `forgesworn/anvil@v0` and can auto-publish. Work on branches; merge to main only when a logical chunk is complete.
62+
63+
## Release & Versioning
64+
65+
**Automated via [forgesworn/anvil](https://github.com/forgesworn/anvil)**
66+
`auto-release.yml` reads conventional commits on push to `main`, bumps the
67+
version, and creates a GitHub Release; `release.yml` then runs the pre-publish
68+
gates and publishes to npm via OIDC trusted publishing.
69+
70+
| Type | Version Bump |
71+
|------|--------------|
72+
| `fix:` | Patch (0.1.x) |
73+
| `feat:` | Minor (0.x.0) |
74+
| `BREAKING CHANGE:` (in commit body) | Major (x.0.0) |
75+
| `chore:`, `docs:`, `refactor:`, `ci:` | None |
76+
77+
Every release needs a matching `CHANGELOG.md` entry (anvil extracts the release
78+
body from it) and a synchronised `PRIVATE_EQUALITY_VERSION`.
79+
80+
## Testing
81+
82+
Tests live in `src/*.test.ts`. Vitest with a per-file coverage gate
83+
(`vitest.config.ts`). Coverage floor: `group`/`zkp` at 100%, `smp` at 100%
84+
lines / 87% branch. Tests cover the full protocol round-trip, mismatch
85+
non-leakage, binding mismatch aborts, malformed/replayed messages, and
86+
tampered proofs. PRs touching `zkp.ts` or `smp.ts` require crypto review.

CONTRIBUTING.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Contributing
2+
3+
## Setup
4+
5+
```bash
6+
git clone https://github.com/forgesworn/private-equality.git
7+
cd private-equality
8+
npm install
9+
npm test
10+
```
11+
12+
## Development Workflow
13+
14+
```bash
15+
npm run build # Compile TypeScript → dist/
16+
npm test # Run test suite (vitest)
17+
npm run coverage # Test suite with the per-file coverage gate
18+
npm run typecheck # Type-check without emitting (tsc --noEmit)
19+
```
20+
21+
Always run `npm run typecheck` and `npm test` before committing.
22+
23+
## Branch Strategy
24+
25+
This repository releases via [forgesworn/anvil](https://github.com/forgesworn/anvil)
26+
on `main` — pushes to `main` with a releasing commit type automatically publish
27+
a new npm version.
28+
29+
- **Always work on a branch** (never commit directly to `main`).
30+
- Merge or squash to `main` only when a logical chunk of work is complete.
31+
- This produces one clean release instead of many incremental versions.
32+
33+
## Commit Conventions
34+
35+
Commit messages follow the `type: description` format. The type determines the
36+
version bump:
37+
38+
| Type | Version bump | Example |
39+
|------|-------------|---------|
40+
| `feat:` | minor | `feat: add subpath export` |
41+
| `fix:` | patch | `fix: reject oversized message` |
42+
| `docs:` | none | `docs: clarify session binding derivation` |
43+
| `refactor:` | none | `refactor: extract challenge helper` |
44+
| `test:` | none | `test: add binding mismatch cases` |
45+
| `chore:` | none | `chore: update dev dependencies` |
46+
47+
Use `BREAKING CHANGE:` in the commit body (or `feat!:` / `fix!:`) for major
48+
version bumps. Releases also need a `CHANGELOG.md` entry and a synchronised
49+
`PRIVATE_EQUALITY_VERSION` (see `CLAUDE.md`).
50+
51+
## Crypto Review Policy
52+
53+
**PRs that touch protocol logic require careful review.** This includes:
54+
55+
- Anything in `src/zkp.ts`, `src/smp.ts`, or `src/group.ts`
56+
- Changes to domain separators, tag bytes, hashing, or scalar arithmetic
57+
- Changes to `sessionBinding` handling or wire-format validation
58+
59+
If you are unsure whether a change affects cryptographic security, flag it for
60+
review. The domain separators (`private-equality/pok-v1`, `.../repr-v1`,
61+
`.../eq-v1`, `.../secret-v1`) are protocol constants — changing them breaks
62+
interoperability between versions.
63+
64+
## Style
65+
66+
- **British English** in all prose — colour, initialise, behaviour, licence.
67+
- **ESM-only** — all imports use `.js` extensions.
68+
- Keep test coverage high. Every new function or code path should have
69+
corresponding tests.
70+
71+
## Reporting Issues
72+
73+
Open an issue on GitHub. If the issue involves a potential security
74+
vulnerability, use GitHub's private vulnerability reporting instead of a
75+
public issue — see `SECURITY.md`.

0 commit comments

Comments
 (0)