# Affinidi Data Integrity Library
[](https://crates.io/crates/affinidi-data-integrity)
[](https://docs.rs/affinidi-data-integrity)
[](https://github.com/affinidi/affinidi-tdk-rs/tree/main/crates/affinidi-tdk/common/affinidi-data-integrity)
**IMPORTANT:**
> affinidi-data-integrity crate is provided "as is" without any warranties or
> guarantees, and by using this framework, users agree to assume all risks
> associated with its deployment and use including implementing security, and
> privacy measures in their applications. Affinidi assumes no liability for any
> issues arising from the use or modification of the project.
## Overview
An implementation of the [W3C Data Integrity](https://www.w3.org/TR/vc-data-integrity/)
specification that is integrated with the Affinidi Trust Development Kit (TDK) framework.
## Supported Cryptosuites
This crate supports the following [W3C vc-di-eddsa](https://www.w3.org/TR/vc-di-eddsa/)
cryptosuites, both using Ed25519 for signing and verification:
| `eddsa-jcs-2022` | JSON Canonicalization Scheme (JCS) | General JSON documents |
| `eddsa-rdfc-2022` | RDF Dataset Canonicalization (RDFC-1.0) | JSON-LD / Verifiable Credentials |
**JCS** canonicalizes raw JSON using [RFC 8785](https://www.rfc-editor.org/rfc/rfc8785)
and works with any serializable data structure.
**RDFC** expands JSON-LD documents into RDF, canonicalizes via
[RDFC-1.0](https://www.w3.org/TR/rdf-canon/), and produces order-independent
canonical N-Quads. Documents **must** contain an `@context` field. Use this for
W3C Verifiable Credentials.
## Usage
### Creating a Proof (JCS)
Use `sign_jcs_data()` for general JSON documents:
```rust
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!"
});
// Load your Ed25519 signing key
let secret = Secret::from_multibase(
"z3u2en7t5LR2WtQH5PfFqMqwVHBeXouLzo6haApm8XHqvjxq",
Some("did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2#z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2"),
).expect("Invalid key");
let proof = DataIntegrityProof::sign_jcs_data(
&document,
None, // optional @context for the proof
&secret,
None, // auto-generates created timestamp
).expect("Signing failed");
println!("Proof value: {}", proof.proof_value.as_ref().unwrap());
```
### Creating a Proof (RDFC)
Use `sign_rdfc_data()` for JSON-LD documents such as Verifiable Credentials.
The document **must** contain an `@context` field:
```rust
use affinidi_data_integrity::DataIntegrityProof;
use affinidi_secrets_resolver::secrets::Secret;
use serde_json::json;
let credential = json!({
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"id": "urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33",
"type": ["VerifiableCredential", "AlumniCredential"],
"issuer": "https://vc.example/issuers/5678",
"validFrom": "2023-01-01T00:00:00Z",
"credentialSubject": {
"id": "did:example:abcdefgh",
"alumniOf": "The School of Examples"
}
});
let secret = Secret::from_multibase(
"z3u2en7t5LR2WtQH5PfFqMqwVHBeXouLzo6haApm8XHqvjxq",
Some("did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2#z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2"),
).expect("Invalid key");
let proof = DataIntegrityProof::sign_rdfc_data(
&credential,
None, // uses document's @context by default
&secret,
None, // auto-generates created timestamp
).expect("Signing failed");
println!("Proof value: {}", proof.proof_value.as_ref().unwrap());
```
### Verifying a Proof
Verification auto-dispatches based on the `cryptosuite` field in the proof,
so the same function works for both JCS and RDFC proofs:
```rust
use affinidi_data_integrity::verification_proof::verify_data_with_public_key;
use affinidi_secrets_resolver::secrets::Secret;
// `document` is the original data (without the proof attached)
// `proof` is the DataIntegrityProof from signing
// `context` must match the @context used during signing (if any)
let public_key_bytes = Secret::decode_multikey(
"z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2"
).expect("Invalid multikey");
let result = verify_data_with_public_key(
&document,
context, // Option<Vec<String>>
&proof,
public_key_bytes.as_slice(),
).expect("Verification failed");
assert!(result.verified);
```
## Choosing a Cryptosuite
**Prefer `eddsa-jcs-2022` (JCS) unless you specifically need RDFC.** JCS is
significantly faster because it canonicalizes JSON directly, while RDFC must
expand JSON-LD into RDF and run the full RDFC-1.0 canonicalization algorithm.
Both produce equally valid W3C Data Integrity proofs with the same Ed25519
security.
Use `eddsa-rdfc-2022` (RDFC) when:
- Interoperating with systems that require RDFC proofs
- Working with JSON-LD documents where semantic equivalence across different
JSON serializations matters (e.g. key ordering, `@context` aliasing)
- A specification or verifier explicitly mandates RDFC
## Performance
Benchmarks run on the W3C vc-di-eddsa B.1 Alumni Credential (Apple M4 Pro,
Rust 1.90, `--release`):
| **Sign** | ~46 µs | ~199 µs | ~4.3x slower |
| **Verify** | ~61 µs | ~212 µs | ~3.5x slower |
The Ed25519 cryptographic operations are identical for both suites. The
performance difference is entirely in the transformation step — JCS runs a
single-pass JSON canonicalization, while RDFC performs JSON-LD expansion, RDF
conversion, and RDFC-1.0 dataset canonicalization.
To reproduce these benchmarks:
```sh
cargo bench -p affinidi-data-integrity --bench proof_benchmarks
```
HTML reports are generated in `target/criterion/` for detailed analysis.
## Support & Feedback
If you face any issues or have suggestions, please don't hesitate to contact us
using [this link](https://www.affinidi.com/get-in-touch).
### Reporting Technical Issues
If you have a technical issue with the Affinidi Data Integrity Library GitHub
repo, you can also create an issue directly in GitHub.
If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/affinidi/affinidi-tdk-rs/issues/new).
Be sure to include a **title and clear description**, as much relevant information
as possible, and a **code sample** or an **executable test case** demonstrating
the expected behavior that is not occurring.