veil-sdk
Rust client for the Mugen Veil verifiable inference network.
Submit ML inference jobs to the Mugen gateway, receive SP1 ZK proofs, and verify them on HashKey Chain — from idiomatic async Rust.
Requirements
- Rust 1.75+
- Tokio async runtime
- A running Mugen gateway
Installation
[]
= { = "sdk/Rust" }
= { = "1", = ["full"] }
Quick Start
use VeilClient;
async
API
VeilClient::builder() → VeilClientBuilder
Construct a client using the builder pattern.
use VeilClient;
use Duration;
let client = builder
.base_url
.timeout
.poll_interval
.build?;
Builder options:
| Method | Type | Default | Description |
|---|---|---|---|
base_url |
&str |
"http://localhost:8080" |
Gateway base URL. Trailing slashes are stripped. |
timeout |
Duration |
600s |
Max wall-clock time for verify_inference to reach a terminal state. SP1 proving + batch aggregation takes 2–5 min. |
poll_interval |
Duration |
3s |
How often to poll GET /v1/jobs/{id} while waiting. |
VeilClient is cheap to clone — the underlying reqwest::Client uses an Arc internally and shares the connection pool across clones.
verify_inference → VerifyResult
The primary high-level method. Submits an inference job and blocks until it reaches a terminal state (settled or failed), polling at the configured interval.
let result = client
.verify_inference
.await?;
Returns VerifyResult:
The attestation_hash is the cryptographic fingerprint binding the model, input, and output together permanently. It is queryable on-chain via InferenceVerifier.isVerified(outputHash).
Errors:
| Error | Condition |
|---|---|
VeilError::Timeout |
Polling exceeded configured timeout |
VeilError::JobFailed |
Gateway reported the job as failed |
VeilError::Api |
Gateway returned a non-2xx HTTP response |
VeilError::Http |
Network-level failure |
submit_job → String
Submit a job without waiting. Returns the job_id immediately.
let job_id = client
.submit_job
.await?;
get_job → Job
Poll the current status of a job.
let job = client.get_job.await?;
// job.status: JobStatus
// job.attestation_hash: Option<String> — available once status is Proving
// job.tx_hash: Option<String> — available once status is Settled
// job.reason: Option<String> — populated on failure
get_proof → Proof
Fetch attestation info for a completed job. Returns HTTP 202 (surfaced as VeilError::Api { status: 202, .. }) if the job is not yet complete.
let proof = client.get_proof.await?;
// proof.attestation_hash: String
// proof.status: String
register_model → RegisterModelResponse
Register a model with the gateway — pins artifact to IPFS and records on-chain.
use RegisterModelRequest;
let resp = client.register_model.await?;
println!;
println!;
health_check → Health
let health = client.health_check.await?;
if health.is_healthy
Job Status Lifecycle
queued → running → proving → done → settled
↘ failed
JobStatus |
Meaning |
|---|---|
Queued |
Job accepted, waiting for SP1 prover slot |
Running |
SP1 prover executing inference inside the zkVM |
Proving |
Phase 1 complete — compressed STARK proof ready, attestation_hash available |
Done |
Proof queued in batch collector awaiting aggregation |
Settled |
Aggregated Groth16 proof verified on HashKey testnet, tx_hash available |
Failed |
Proving or settlement failed |
JobStatus::is_terminal() returns true for Settled, Done, and Failed.
The attestation_hash is available as soon as status reaches Proving (~60s). You do not need to wait for full settlement to use it.
Error Handling
All SDK errors implement std::error::Error and are defined in veil_sdk::error::VeilError.
use ;
match client.verify_inference.await
Error variants:
| Variant | Fields | Condition |
|---|---|---|
InvalidUrl |
String |
Base URL could not be parsed |
Http |
reqwest::Error |
Network-level failure |
Api |
status: u16, message: String |
Gateway returned non-2xx |
Timeout |
job_id, elapsed_ms, last_status |
Polling exceeded timeout |
JobFailed |
job_id, reason: Option<String> |
Gateway reported job failed |
Advanced Usage
Submit and poll manually
use VeilClient;
use Duration;
async
Concurrent jobs
VeilClient is Clone — share a single client across multiple tasks:
use VeilClient;
use Arc;
let client = new;
let mut handles = Vecnew;
for i in 0..5
for handle in handles
Tracing / logging
veil-sdk emits structured logs via the tracing crate. Enable them with tracing_subscriber:
fmt
.with_env_filter
.init;
Run the e2e test
GATEWAY_URL=http://localhost:8080
Or as an ignored integration test:
GATEWAY_URL=http://localhost:8080
Project Structure
sdk/Rust/
├── src/
│ ├── lib.rs — crate root, public re-exports, module-level docs
│ ├── client.rs — VeilClient + VeilClientBuilder
│ ├── types.rs — Job, JobStatus, VerifyResult, Health, Proof, RegisterModelRequest
│ ├── error.rs — VeilError enum, Result alias
│ └── e2e_verify.rs — live end-to-end binary against a running gateway
├── Cargo.toml
└── README.md
On-chain Verification
After settlement, verify directly on HashKey testnet:
# Check if output hash is verified on-chain
The attestation_hash returned by the SDK is keccak256(model_id || input_hash || output_hash). The output_hash component (pv[64..96]) is the on-chain lookup key stored in InferenceVerifier.isVerified.
See Also
- Mugen Gateway README — full architecture, contract addresses, deployment guide
- TypeScript SDK —
@mugen-ai/sdknpm package - Polymarket Veil Agent — example consumer built on this SDK
License
MIT