pub struct SimpleAgent { /* private fields */ }Expand description
A wrapper around the JACS Agent that provides a simplified, instance-based API.
This struct owns an Agent instance and provides methods for common operations
like signing and verification. Unlike the deprecated module-level functions,
SimpleAgent does not use global mutable state, making it thread-safe when
used with appropriate synchronization.
§Narrow Contract (19 methods)
These are the ONLY public methods on SimpleAgent. This list is the
single source of truth (Section 4.1.2 of ARCHITECTURE_UPGRADE.md).
Advanced operations live in super::advanced, super::batch, etc.
| # | Method | Purpose |
|---|---|---|
| 1 | create | Create agent with defaults |
| 2 | create_with_params | Create agent with full control |
| 3 | load | Load existing agent from disk |
| 4 | ephemeral | Create throwaway agent (no disk) |
| 5 | verify_self | Verify own agent document signature |
| 6 | sign_message | Sign a JSON value |
| 7 | sign_raw_bytes | Sign raw byte data |
| 8 | sign_file | Sign a file |
| 9 | verify | Verify a signed document string |
| 10 | verify_with_key | Verify with explicit public key |
| 11 | verify_by_id | Verify a stored document by ID |
| 12 | export_agent | Export agent identity JSON |
| 13 | get_public_key | Get public key as raw bytes |
| 14 | get_public_key_pem | Get public key as PEM string |
| 15 | get_agent_id | Get agent ID |
| 16 | key_id | Get key ID |
| 17 | diagnostics | Runtime diagnostic info |
| 18 | is_strict | Check strict mode |
| 19 | config_path | Get config file path |
§Thread Safety
SimpleAgent uses interior mutability via Mutex to allow safe concurrent
access to the underlying Agent. Multiple threads can share a SimpleAgent
wrapped in an Arc.
§Example
use jacs::simple::SimpleAgent;
use std::sync::Arc;
// Create and share across threads
let agent = Arc::new(SimpleAgent::create("my-agent", None, None)?);
let agent_clone = Arc::clone(&agent);
std::thread::spawn(move || {
let signed = agent_clone.sign_message(&serde_json::json!({"thread": 1})).unwrap();
});Implementations§
Source§impl SimpleAgent
impl SimpleAgent
Sourcepub fn to_yaml(&self, json_str: &str) -> Result<String, JacsError>
pub fn to_yaml(&self, json_str: &str) -> Result<String, JacsError>
Convert a JSON string to YAML.
This is a stateless convenience wrapper over convert::jacs_to_yaml.
Sourcepub fn from_yaml(&self, yaml_str: &str) -> Result<String, JacsError>
pub fn from_yaml(&self, yaml_str: &str) -> Result<String, JacsError>
Convert a YAML string to pretty-printed JSON.
This is a stateless convenience wrapper over convert::yaml_to_jacs.
Sourcepub fn verify_yaml(
&self,
yaml_str: &str,
) -> Result<VerificationResult, JacsError>
pub fn verify_yaml( &self, yaml_str: &str, ) -> Result<VerificationResult, JacsError>
Convert a YAML string to JSON and verify the document.
This is equivalent to calling from_yaml() followed by verify().
Source§impl SimpleAgent
impl SimpleAgent
Sourcepub fn key_id(&self) -> Result<String, JacsError>
pub fn key_id(&self) -> Result<String, JacsError>
Returns the JACS agent ID, used as the signing key identifier. Derived from the underlying Agent — no cached copy needed.
Sourcepub fn create(
name: &str,
purpose: Option<&str>,
key_algorithm: Option<&str>,
) -> Result<(Self, AgentInfo), JacsError>
pub fn create( name: &str, purpose: Option<&str>, key_algorithm: Option<&str>, ) -> Result<(Self, AgentInfo), JacsError>
Creates a new JACS agent with persistent identity.
This generates cryptographic keys, creates configuration files, and saves them to the current working directory.
§Arguments
name- Human-readable name for the agentpurpose- Optional description of the agent’s purposekey_algorithm- Signing algorithm: “pq2025” (default), “ed25519”, or “rsa-pss”
§Returns
A SimpleAgent instance ready for use, along with AgentInfo containing
the agent ID, name, and file paths.
§Files Created
./jacs.config.json- Configuration file./jacs.agent.json- Signed agent identity (in jacs_data/agent/)./jacs_keys/- Directory containing public and private keys
§Example
use jacs::simple::SimpleAgent;
let agent = SimpleAgent::create("my-agent", Some("Signing documents"), None)?;
println!("Agent created successfully");Sourcepub fn create_with_params(
params: CreateAgentParams,
) -> Result<(Self, AgentInfo), JacsError>
pub fn create_with_params( params: CreateAgentParams, ) -> Result<(Self, AgentInfo), JacsError>
Creates a new JACS agent with full programmatic control.
Unlike create(), this method accepts all parameters explicitly, making it
suitable for non-interactive use from bindings and automation.
§Arguments
params-CreateAgentParamswith all creation parameters
§Returns
A SimpleAgent instance and AgentInfo with the created agent’s details.
§Example
use jacs::simple::{SimpleAgent, CreateAgentParams};
let params = CreateAgentParams::builder()
.name("my-agent")
.password("MyStr0ng!Pass#2024")
.algorithm("pq2025")
.data_directory("/tmp/test_data")
.key_directory("/tmp/test_keys")
.config_path("/tmp/test.config.json")
.build();
let (agent, info) = SimpleAgent::create_with_params(params)?;Sourcepub fn load(
config_path: Option<&str>,
strict: Option<bool>,
) -> Result<Self, JacsError>
pub fn load( config_path: Option<&str>, strict: Option<bool>, ) -> Result<Self, JacsError>
Loads an existing agent from a configuration file.
§Arguments
config_path- Path to the configuration file (default: “./jacs.config.json”)
§Example
use jacs::simple::SimpleAgent;
let agent = SimpleAgent::load(None, None)?; // Load from ./jacs.config.json
// or with strict mode:
let agent = SimpleAgent::load(Some("./my-agent/jacs.config.json"), Some(true))?;Sourcepub fn loaded_info(&self) -> Result<AgentInfo, JacsError>
pub fn loaded_info(&self) -> Result<AgentInfo, JacsError>
Returns canonical metadata for the currently loaded agent.
Sourcepub fn ephemeral(
algorithm: Option<&str>,
) -> Result<(Self, AgentInfo), JacsError>
pub fn ephemeral( algorithm: Option<&str>, ) -> Result<(Self, AgentInfo), JacsError>
Creates an ephemeral in-memory agent. No config file, no directories, no environment variables, no password needed.
§Arguments
algorithm- Signing algorithm: “pq2025” (default), “ed25519”, or “rsa-pss”
§Returns
A SimpleAgent instance with in-memory keys, along with AgentInfo.
Keys are lost when the agent is dropped.
§Example
use jacs::simple::SimpleAgent;
let (agent, info) = SimpleAgent::ephemeral(None)?;
let signed = agent.sign_message(&serde_json::json!({"hello": "world"}))?;Sourcepub fn verify_self(&self) -> Result<VerificationResult, JacsError>
pub fn verify_self(&self) -> Result<VerificationResult, JacsError>
Sourcepub fn sign_message(&self, data: &Value) -> Result<SignedDocument, JacsError>
pub fn sign_message(&self, data: &Value) -> Result<SignedDocument, JacsError>
Signs arbitrary data as a JACS message.
§IMPORTANT: Signing is Sacred
Signing a document is an irreversible, permanent commitment. Once signed:
- The signature creates cryptographic proof binding you to the content
- You cannot deny having signed (non-repudiation)
- The signed document can be verified by anyone forever
- You are accountable for the content you signed
Before signing, always:
- Read and understand the complete document content
- Verify the data represents your actual intent
- Confirm you have authority to make this commitment
The data can be a JSON object, string, or any serializable value.
§Arguments
data- The data to sign (will be JSON-serialized)
§Returns
A SignedDocument containing the full signed document.
§Example
use jacs::simple::SimpleAgent;
use serde_json::json;
let agent = SimpleAgent::load(None)?;
// Review data carefully before signing!
let signed = agent.sign_message(&json!({"action": "approve", "amount": 100}))?;
println!("Document ID: {}", signed.document_id);Sourcepub fn sign_raw_bytes(&self, data: &[u8]) -> Result<Vec<u8>, JacsError>
pub fn sign_raw_bytes(&self, data: &[u8]) -> Result<Vec<u8>, JacsError>
Sign raw bytes and return the raw signature bytes.
This is a low-level signing method used by JACS email signing and other protocols that need to sign arbitrary data (not JSON documents). The data must be valid UTF-8 (JACS canonical payloads always are).
Returns the raw signature bytes (decoded from the base64 output of the underlying crypto module).
Sourcepub fn get_agent_id(&self) -> Result<String, JacsError>
pub fn get_agent_id(&self) -> Result<String, JacsError>
Get the JACS agent ID.
Returns the agent’s unique identifier from the exported agent JSON.
Sourcepub fn set_storage(&self, storage: MultiStorage) -> Result<(), JacsError>
pub fn set_storage(&self, storage: MultiStorage) -> Result<(), JacsError>
Replace the agent’s document storage backend.
After loading an agent from a filesystem config, call this with a
"memory" backend to avoid filesystem writes for subsequent
sign_message() / create_document_and_load() calls.
§Example
use jacs::storage::MultiStorage;
let agent = SimpleAgent::load(Some("./jacs.config.json"), None)?;
let mem = MultiStorage::new("memory".to_string())?;
agent.set_storage(mem)?;
// sign_message() now persists documents in-memory onlySourcepub fn sign_file(
&self,
file_path: &str,
embed: bool,
) -> Result<SignedDocument, JacsError>
pub fn sign_file( &self, file_path: &str, embed: bool, ) -> Result<SignedDocument, JacsError>
Signs a file with optional content embedding.
§IMPORTANT: Signing is Sacred
Signing a file is an irreversible, permanent commitment. Your signature:
- Cryptographically binds you to the file’s exact contents
- Cannot be revoked or denied (non-repudiation)
- Creates permanent proof that you attested to this file
- Makes you accountable for the file content forever
Before signing any file:
- Review the complete file contents
- Verify the file has not been tampered with
- Confirm you intend to attest to this specific file
- Understand your signature is permanent and verifiable
§Arguments
file_path- Path to the file to signembed- If true, embed file content; if false, store only hash reference
§Returns
A SignedDocument containing the signed file reference or embedded content.
§Example
use jacs::simple::SimpleAgent;
let agent = SimpleAgent::load(None)?;
// Review file before signing! Embed the file content
let signed = agent.sign_file("contract.pdf", true)?;
// Or just reference it by hash
let signed = agent.sign_file("large-video.mp4", false)?;Sourcepub fn verify(
&self,
signed_document: &str,
) -> Result<VerificationResult, JacsError>
pub fn verify( &self, signed_document: &str, ) -> Result<VerificationResult, JacsError>
Verifies a signed document and extracts its content.
This function auto-detects whether the document contains a message or file.
§Arguments
signed_document- The JSON string of the signed document
§Returns
A VerificationResult with the verification status and extracted content.
§Example
use jacs::simple::SimpleAgent;
let agent = SimpleAgent::load(None)?;
let result = agent.verify(&signed_json)?;
if result.valid {
println!("Content: {}", result.data);
} else {
println!("Verification failed: {:?}", result.errors);
}Sourcepub fn verify_with_key(
&self,
signed_document: &str,
public_key: Vec<u8>,
) -> Result<VerificationResult, JacsError>
pub fn verify_with_key( &self, signed_document: &str, public_key: Vec<u8>, ) -> Result<VerificationResult, JacsError>
Verifies a signed JACS document using a provided public key.
This is identical to verify() but uses the supplied
public_key bytes instead of the agent’s own key. This allows any
agent to verify documents signed by a different agent, given the
signer’s public key (e.g., from a registry or trust store).
§Arguments
signed_document- The JSON string of the signed JACS documentpublic_key- The signer’s public key bytes (PEM file content)
§Example
// agent_b verifies a document that agent_a signed
let result = agent_b.verify_with_key(&signed_doc, agent_a_pubkey)?;
if result.valid {
println!("Verified: signed by {}", result.signer_id);
}Sourcepub fn verify_by_id(
&self,
document_id: &str,
) -> Result<VerificationResult, JacsError>
pub fn verify_by_id( &self, document_id: &str, ) -> Result<VerificationResult, JacsError>
Verifies a signed document looked up by its document ID from storage.
This is a convenience method for when you have a document ID (e.g., “uuid:version”) rather than the full JSON string.
§Arguments
document_id- The document ID in “uuid:version” format
§Example
use jacs::simple::SimpleAgent;
let agent = SimpleAgent::load(None)?;
let result = agent.verify_by_id("abc123:1")?;
assert!(result.valid);Sourcepub fn export_agent(&self) -> Result<String, JacsError>
pub fn export_agent(&self) -> Result<String, JacsError>
Exports the agent’s identity JSON for P2P exchange.
Sourcepub fn get_public_key(&self) -> Result<Vec<u8>, JacsError>
pub fn get_public_key(&self) -> Result<Vec<u8>, JacsError>
Returns the agent’s public key bytes from memory.
This returns the raw public key bytes as stored in the agent’s internal
state. The format depends on the algorithm (e.g., raw 32 bytes for
Ed25519, PEM for RSA-PSS). These bytes are the same format expected by
verify_with_key() and
verify_document_signature().
Sourcepub fn get_public_key_pem(&self) -> Result<String, JacsError>
pub fn get_public_key_pem(&self) -> Result<String, JacsError>
Returns the agent’s public key in PEM format.
Sourcepub fn diagnostics(&self) -> Value
pub fn diagnostics(&self) -> Value
Returns diagnostic information including loaded agent details.
Sourcepub fn config_path(&self) -> Option<&str>
pub fn config_path(&self) -> Option<&str>
Returns the path to the configuration file, if available.
Trait Implementations§
Source§impl JacsSigner for SimpleAgent
impl JacsSigner for SimpleAgent
Source§fn sign_message(&self, data: &Value) -> Result<SignedDocument, JacsError>
fn sign_message(&self, data: &Value) -> Result<SignedDocument, JacsError>
Source§fn verify_with_key(
&self,
signed_document: &str,
public_key: Vec<u8>,
) -> Result<VerificationResult, JacsError>
fn verify_with_key( &self, signed_document: &str, public_key: Vec<u8>, ) -> Result<VerificationResult, JacsError>
Auto Trait Implementations§
impl !Freeze for SimpleAgent
impl RefUnwindSafe for SimpleAgent
impl Send for SimpleAgent
impl Sync for SimpleAgent
impl Unpin for SimpleAgent
impl UnsafeUnpin for SimpleAgent
impl UnwindSafe for SimpleAgent
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more