jacs-core
Portable JACS protocol layer — no I/O.
jacs-core is the compile-anywhere protocol crate for JACS.
It holds the cryptographic primitives, canonical JSON serializer, embedded
schemas, encrypted-key envelope codec, and agreement payload helpers that
both the native jacs crate and the
browser-side 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_messageround-trip through nativejacs::Agent::verify_stringand back. - The home of
Ed25519DalekSigner,Pq2025Signer, theDetachedSignertrait,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
tracingsubscriber wiring, no metrics export. - Not a CLI or MCP server. Those live in
jacs-cliandjacs-mcp, both built onjacs.
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
use ;
use json;
let mut agent = ephemeral?;
let signed = agent.sign_message?;
let outcome = agent.verify?;
assert!;
For multi-party agreements:
use ;
use json;
let mut alice = ephemeral?;
let mut bob = ephemeral?;
let alice_id = alice.export_agent.as_str.unwrap.to_string;
let bob_id = bob.export_agent.as_str.unwrap.to_string;
let mut doc = create?;
sign?;
sign?;
let signers: = vec!;
let outcome = verify?;
assert!;
Encrypted private-key envelopes
jacs-core::envelope reads two on-disk formats — the same two the native
jacs CLI has shipped:
- V2 JSON envelope (current writer) — AES-256-GCM cipher, Argon2id
key derivation. Default for all newly-encrypted keys. Always starts
with
{. - 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-unknownpasses.bash scripts/forbidden-deps.sh jacs-core wasm32-unknown-unknownis the CI gate: it fails the build ifring,tokio,reqwest,hickory-resolver,object_store,rusqlite,duckdb,surrealdb,keyring,rpassword,dirs,jacs-media,mail-parser,html5ever, oropentelemetry-otlpever appear injacs-core's dependency graph.
Where to go next
jacs— native facade. Filesystem, DNS, HTTP, MCP, CLI, storage.jacs-wasm— browser bindings that wrapjacs-corewith a TypeScript API.- PRD — full design + scope of the native/wasm split (HAI internal).
License
Apache-2.0. See LICENSE-APACHE.