jacs-core 0.11.3

JACS portable protocol layer (no I/O, no native deps)
Documentation
# jacs-core

**Portable JACS protocol layer — no I/O.**

`jacs-core` is the compile-anywhere protocol crate for [JACS](https://github.com/HumanAssisted/JACS).
It holds the cryptographic primitives, canonical JSON serializer, embedded
schemas, encrypted-key envelope codec, and agreement payload helpers that
both the native [`jacs`](https://crates.io/crates/jacs) crate and the
browser-side [`jacs-wasm`](https://www.npmjs.com/package/@jacs/wasm) wrapper
share.

## What it is

- A pure-Rust library that compiles for both native targets and
  `wasm32-unknown-unknown`.
- The single source of truth for canonical JACS bytes — signatures and
  agreements produced by `jacs_core::CoreAgent::sign_message` round-trip
  through native `jacs::Agent::verify_string` and back.
- The home of `Ed25519DalekSigner`, `Pq2025Signer`, the `DetachedSigner`
  trait, `CoreAgent`, the AES-256-GCM + Argon2id encrypted-key envelope,
  the embedded JSON schema set (Draft 7), and the multi-party agreement
  payload logic.

## What it is not

- **Not a filesystem layer.** No `std::fs`, no path resolution, no
  config loading.
- **Not a network layer.** No DNS, no HTTP, no remote registry.
- **Not an observability layer.** No env-var-driven logging,
  no `tracing` subscriber wiring, no metrics export.
- **Not a CLI or MCP server.** Those live in
  [`jacs-cli`]https://crates.io/crates/jacs-cli and
  [`jacs-mcp`]https://crates.io/crates/jacs-mcp, both built on `jacs`.

If you want the full native JACS experience (storage backends, A2A,
attestation, MCP, observability), use `jacs`. If you want to sign or
verify a JACS document in the browser, use `@jacs/wasm`.

## Quick start

```rust,ignore
use jacs_core::{CoreAgent, SigningAlgorithm};
use serde_json::json;

let mut agent = CoreAgent::ephemeral(SigningAlgorithm::Ed25519)?;
let signed = agent.sign_message(&json!({ "hello": "world" }))?;
let outcome = agent.verify(&signed)?;
assert!(outcome.valid);
```

For multi-party agreements:

```rust,ignore
use jacs_core::{CoreAgent, SigningAlgorithm, agreements};
use serde_json::json;

let mut alice = CoreAgent::ephemeral(SigningAlgorithm::Ed25519)?;
let mut bob = CoreAgent::ephemeral(SigningAlgorithm::Pq2025)?;
let alice_id = alice.export_agent()["jacsId"].as_str().unwrap().to_string();
let bob_id = bob.export_agent()["jacsId"].as_str().unwrap().to_string();

let mut doc = agreements::create(
    &json!({ "topic": "merge proposal" }),
    &[alice_id.clone(), bob_id.clone()],
    Some("Approve?"),
    None,
)?;
agreements::sign(&mut alice, &mut doc, "alice")?;
agreements::sign(&mut bob, &mut doc, "bob")?;

let signers: Vec<(&str, &[u8], SigningAlgorithm)> = vec![
    (alice_id.as_str(), alice.public_key(), SigningAlgorithm::Ed25519),
    (bob_id.as_str(),   bob.public_key(),   SigningAlgorithm::Pq2025),
];
let outcome = agreements::verify(&doc, &signers)?;
assert!(outcome.all_valid);
```

## Encrypted private-key envelopes

`jacs-core::envelope` reads two on-disk formats — the same two the native
`jacs` CLI has shipped:

1. **V2 JSON envelope (current writer)** — AES-256-GCM cipher, Argon2id
   key derivation. Default for all newly-encrypted keys. Always starts
   with `{`.
2. **Legacy raw-binary PBKDF2 envelope**`salt(16) || nonce(12) ||
   ciphertext`, PBKDF2-HMAC-SHA256 @ 600k iterations with a 100k legacy
   fallback. Read-only — no new writes.

### Reserved magic prefixes

Inputs whose first 4 bytes match the ASCII pattern `^J[A-Z]{2}[0-9]$`
(for example `JAA1`, `JAC2`, `JAS9`) are reserved for future envelope
formats — memory-hard KDF variants, post-quantum AEAD wrappers, and the
like. `decrypt_private_key` rejects them up front with
`CoreError::UnsupportedAlgorithm("<prefix>")` so they aren't misclassified
as malformed legacy PBKDF2 noise.

## Compile-target guarantees

- `cargo check -p jacs-core --target wasm32-unknown-unknown` passes.
- `bash scripts/forbidden-deps.sh jacs-core wasm32-unknown-unknown` is
  the CI gate: it fails the build if `ring`, `tokio`, `reqwest`,
  `hickory-resolver`, `object_store`, `rusqlite`, `duckdb`, `surrealdb`,
  `keyring`, `rpassword`, `dirs`, `jacs-media`, `mail-parser`,
  `html5ever`, or `opentelemetry-otlp` ever appear in `jacs-core`'s
  dependency graph.

## Where to go next

- [`jacs`]../jacs/README.md — native facade. Filesystem, DNS, HTTP, MCP, CLI, storage.
- [`jacs-wasm`]../jacs-wasm/README.md — browser bindings that wrap `jacs-core` with a TypeScript API.
- [PRD]../docs/jacs/JACS_WASM_PRD.md — full design + scope of the native/wasm split (HAI internal).

## License

Apache-2.0. See [`LICENSE-APACHE`](../LICENSE-APACHE).