open-standards/jouleclaw/jouleclaw-rs/crates/jouleclaw-jcr1
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Transaction Science 84768074ca
Some checks failed
energy meters on real hardware / RAPL and NVML on jetson-hub (push) Has been cancelled
energy meters on real hardware / sink decode table · RAPL on jetson-hub (NVML surveyed) (push) Has been cancelled
energy meters on real hardware / sink decode table · per-task energy and the GPU rail on macOS (push) Has been cancelled
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Has been cancelled
jouleclaw public surface must stay documented / Public-surface audit (jouleclaw-rs) (push) Has been cancelled
joule-code conformance gate / joule-moq-relay, its own energy on a counter (macos) (push) Successful in 2m15s
wai-app and Create / wai-app · does this change touch it (push) Successful in 1m45s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Has been cancelled
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Has been cancelled
joule-code conformance gate / Build + round-trip C1-C4 vectors (push) Successful in 5m43s
joule-code conformance gate / joule-moq-ingest, every target (push) Has been cancelled
joule-code conformance gate / joule-moq-relay, every target (push) Has been cancelled
Every text that states the IOReport liveness rule states it as the meters apply it
The meters count an IOReport interval only within three of the probe's ticks, and
the texts that state the rule said nothing of it, so an implementation following
any of them would call a lump-refreshed rail live once load stretched its intervals.
Each now says what an interval is (from one sample in hand to the next), that only
one no longer than three of the probe's ticks (75 ms at its 25 ms tick) counts, that
a longer one counts as nothing (not among the intervals, not as an advance, not
towards the 300 ms), and that the 300 ms is the summed length of the intervals that
count.

The normative clauses in arl/ARL-S.md, jcp/SPEC.md, joule-code/spec/receipt.md,
joule-ui/SPEC.md, jouleclaw/SPEC.md, JCR-1-spec.md, map/spec/receipt.md,
mesh/SPEC.md (a block quote), proof/SPEC.md and sense/SPEC.md; proof-schema's
quotation of proof/SPEC.md's; jouleclaw-energy's conformance README; and the proof
and sandbox READMEs, which say the cap is IOReport's alone. Map's and Joule Code's
unreleased changelog entries, which record the rule as it was added, are amended,
since neither release has gone out. No wire or conformance-vector change.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-07 08:20:02 -05:00
..
conformance jouleclaw-energy: a live IOReport reading is a hardware reading, and only a live one 2026-09-30 20:17:13 -04:00
docs Every text that states the IOReport liveness rule states it as the meters apply it 2026-11-07 08:20:02 -05:00
examples jouleclaw-energy: RAPL is the sum of every package zone, each of which must be live and each wrapped at its own range 2026-09-30 22:20:49 -04:00
src jouleclaw: wave-54 — event-sourced agent substrate (ActiveGraph ingest) 2026-06-05 13:01:12 -04:00
Cargo.toml Cargo: no minimum-supported-version floor, because the policy is latest stable 2026-11-03 17:42:20 -05:00
README.md jouleclaw-energy: a live IOReport reading is a hardware reading, and only a live one 2026-09-30 20:17:13 -04:00
run.sh jouleclaw-jcr1: JCR-1 reference + 10 vectors + Rust producer + Python/Go verifiers 2026-06-01 03:32:44 -04:00

jouleclaw-jcr1 — JCR-1 reference

The Rust-side reference for the JouleClaw Receipt Specification (JCR-1) — a canonical, signed, per-resolution thermodynamic receipt that any third party can verify with the spec, the public key, and standard CBOR + COSE tooling. No JouleClaw dependency required to check a receipt; this crate is needed only to mint one.

The wedge: a system that claims joule efficiency is worth nothing if a third party can't audit the numbers. JCR-1 makes the receipt the audit primitive.

What this ships

crates/jouleclaw-jcr1/
├── README.md
├── run.sh                       ← Rust mints, Python + Go each verify
├── docs/
│   ├── JCR-1-spec.md            ← the receipt standard (CC-BY-4.0)
│   └── JCR-1-v1.1-intent.md     ← additive v1.1 proposal: intent in signed core
├── conformance/
│   ├── README.md                ← suite guide + negative-test results
│   ├── vectors.json             ← 10 signed conformance vectors
│   ├── test-keys.json           ← published test keys (TEST ONLY)
│   ├── verify.py                ← Python reference verifier (cbor2 + cryptography)
│   └── verify.go                ← independent Go verifier (stdlib only)
├── examples/
│   └── jcr1_mint.rs             ← Rust producer: read energy → sign → emit
└── src/lib.rs                   ← det-CBOR encoder, COSE_Sign1, HMAC, projection

Three implementations, one standard

  • Rust (this crate's lib.rs + examples/jcr1_mint.rs) — mints receipts from a live energy reading, projects a [Receipt] to the JCR-1 wire form, canonicalises with RFC 8949 §4.2.1 (length-first then bytewise key order), seals in COSE_Sign1 (RFC 9052, EdDSA / Ed25519). 25 lib tests including byte-equal re-encode of all 10 conformance vectors.
  • Python (conformance/verify.py) — reference verifier using cbor2 and cryptography.
  • Go (conformance/verify.go) — independent verifier using only the Go standard library, with a from-scratch canonical CBOR encoder. Agreement byte-for-byte with the Python output is what makes the spec — not the reference code — the source of truth.

Quickstart

./crates/jouleclaw-jcr1/run.sh

You'll see, in order:

  1. The Rust producer mints a fresh receipt from a measured energy reading (HwShunt on Linux/x86 with RAPL; honest Estimator + 1 mJ floor everywhere else).
  2. The Python reference verifier accepts the 10 canonical vectors.
  3. The independent Go verifier accepts the same 10 vectors.
  4. Both Python and Go accept the freshly Rust-minted receipt.

Public Rust API

use jouleclaw_jcr1::{
    canonical_cbor,              // any JSON Value → det-CBOR bytes
    canonical_signed_core,       // &Receipt → signed-core bytes
    to_jcr1_wire,                // &Receipt → JCR-1 wire JSON Value
    signed_core_bytes,           // wire Value → signed-core bytes
    cose_sign1_envelope,         // build COSE_Sign1 over a core
    verify_cose_sign1,           // verify + extract payload
    hmac_tool_payload,           // §5 NUL-delimited bytes
    hmac_tool_hex,               // HMAC-SHA-256 lowercase hex
    check_honesty,               // §6 step 5 consistency rules
    VECTORS_JSON, TEST_KEYS_JSON, // embedded conformance suite
};

Honest scope (v0.1)

  • JCR-1 v1 wire form only. The wave-8 Receipt.model_id and Receipt.intent fields ride along on the Rust Receipt type but are NOT in the signed core — see docs/JCR-1-v1.1-intent.md for the proposed additive bump.
  • Ed25519 (alg = -8) only. ES256 (alg = -7) is permitted by the spec but not implemented here; the envelope verifier rejects other algorithms.
  • Key transparency / rotation is out of scope. KERI AID rotation is recommended by JCR-1 §4 but kid → public key resolution is the consumer's job.
  • The 10 vectors are TOY joule values exercising each spec path. They become measurements only when minted off real RAPL / NVML / IOReport counters that were live for the domain they claim (JCR-1 §2.3, Liveness) and cross-validated against Zeus. Vector 6's ModelBased span is a toy grade on a toy figure, not an IOReport reading.

License

Code: Apache-2.0 (workspace default). Specification text + conformance vectors: CC-BY-4.0.