affinidi-data-integrity 0.5.0

W3C Data Integrity Implementation
Documentation

affinidi-data-integrity

Crates.io Documentation Rust License

An implementation of the W3C Data Integrity specification, integrated with the Affinidi Trust Development Kit. Create and verify cryptographic proofs over JSON and JSON-LD documents using Ed25519.

Supported Cryptosuites

Cryptosuite Canonicalization Use Case
eddsa-jcs-2022 JSON Canonicalization Scheme (JCS) General JSON documents
eddsa-rdfc-2022 RDF Dataset Canonicalization (RDFC-1.0) JSON-LD / Verifiable Credentials

Prefer JCS unless you specifically need RDFC. JCS is ~4x faster as it canonicalizes JSON directly, while RDFC must expand JSON-LD into RDF.

Installation

[dependencies]
affinidi-data-integrity = "0.5"

Usage

Sign a JSON Document (JCS)

Signing methods are async and accept any implementation of the Signer trait. The Secret type implements Signer directly, so existing code only needs to add .await:

use affinidi_data_integrity::DataIntegrityProof;
use affinidi_secrets_resolver::secrets::Secret;
use serde_json::json;

let document = json!({
    "id": "urn:uuid:example-123",
    "type": "ExampleDocument",
    "data": "Hello, world!"
});

let secret = Secret::from_multibase(
    "z3u2en7t5LR2WtQH5PfFqMqwVHBeXouLzo6haApm8XHqvjxq",
    Some("did:key:z6Mkr...#z6Mkr..."),
).expect("Invalid key");

let proof = DataIntegrityProof::sign_jcs_data(
    &document, None, &secret, None,
).await.expect("Signing failed");

Sign a Verifiable Credential (RDFC)

let credential = json!({
    "@context": [
        "https://www.w3.org/ns/credentials/v2",
        "https://www.w3.org/ns/credentials/examples/v2"
    ],
    "type": ["VerifiableCredential", "AlumniCredential"],
    "issuer": "https://vc.example/issuers/5678",
    "credentialSubject": {
        "id": "did:example:abcdefgh",
        "alumniOf": "The School of Examples"
    }
});

let proof = DataIntegrityProof::sign_rdfc_data(
    &credential, None, &secret, None,
).await.expect("Signing failed");

Custom Signer (KMS/HSM)

Implement the Signer trait to use external signing backends:

use affinidi_data_integrity::signer::Signer;
use affinidi_secrets_resolver::secrets::KeyType;
use async_trait::async_trait;

struct MyKmsSigner { /* ... */ }

#[async_trait]
impl Signer for MyKmsSigner {
    fn key_type(&self) -> KeyType { KeyType::Ed25519 }
    fn verification_method(&self) -> &str { "did:key:z6Mk...#z6Mk..." }

    async fn sign(&self, data: &[u8]) -> Result<Vec<u8>, DataIntegrityError> {
        // Call your KMS/HSM service here
        todo!()
    }
}

let proof = DataIntegrityProof::sign_jcs_data(
    &document, None, &my_kms_signer, None,
).await.expect("Signing failed");

Verify a Proof

Verification auto-dispatches based on the cryptosuite field:

use affinidi_data_integrity::verification_proof::verify_data_with_public_key;

let public_key_bytes = Secret::decode_multikey("z6Mkr...").expect("Invalid multikey");

let result = verify_data_with_public_key(
    &document, context, &proof, public_key_bytes.as_slice(),
).expect("Verification failed");

assert!(result.verified);

Performance

Benchmarks on the W3C vc-di-eddsa B.1 Alumni Credential (Apple M4 Pro, --release):

Operation JCS RDFC Ratio
Sign ~46 us ~199 us ~4.3x slower
Verify ~61 us ~212 us ~3.5x slower

Run benchmarks:

cargo bench -p affinidi-data-integrity --bench proof_benchmarks

Related Crates

License

Apache-2.0