Thanks to visit codestin.com
Credit goes to github.com

Skip to content
/ Grace Public

A Rust toolkit for privacy-preserving relationship systems using anonymous credentials.

License

Notifications You must be signed in to change notification settings

FeurJak/Grace

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GRACE

Gated Relationships via Anonymous Credential Exchange

Warning: This is experimental cryptographic software. Do not use in production.

A Rust toolkit for building privacy-preserving relationship systems using anonymous credentials. Grace enables entities to form cryptographically-verified associations while maintaining privacy through credential-gated encryption.

Overview

Grace provides a complete system for:

  • Anonymous Credentials: Issue and verify credentials without revealing identity
  • Gated Encryption: Encrypt messages that only authorized credential holders can decrypt
  • Association Graphs: Build verifiable relationship networks between entities
  • Lazy Revocation: Efficiently revoke entities with automatic credential refresh

Architecture

┌─────────────────────────────────────────────────────────────────────────────┐
│                              grace (facade)                                 │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐ │
│  │   Domain    │  │   Entity    │  │    KMS      │  │       Store         │ │
│  │   Handle    │  │   Builder   │  │  (Keys)     │  │   (Persistence)     │ │
│  └─────────────┘  └─────────────┘  └─────────────┘  └─────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
                                      │
          ┌───────────────────────────┼───────────────────────────┐
          ▼                           ▼                           ▼
┌─────────────────────┐   ┌─────────────────────┐   ┌─────────────────────┐
│   grace-primitives  │   │    grace-crypto     │   │    grace-common     │
│                     │   │                     │   │                     │
│  - Domain           │   │  - SAGA (BBS MAC)   │   │  - Point, Scalar    │
│  - Entity           │   │  - MKVAC            │   │  - Hash functions   │
│  - Policy           │   │  - Gated-KEM        │   │  - Serialization    │
│  - Header           │   │                     │   │                     │
└─────────────────────┘   └─────────────────────┘   └─────────────────────┘

Crates

Crate Description
grace High-level API with DomainHandle, EntityBuilder, storage, and KMS
grace-primitives Core domain types: Entity, Policy, Header, Domain
grace-crypto Cryptographic primitives: SAGA, MKVAC, Gated-KEM
grace-common Shared utilities: Point, Scalar, hash functions

Quick Start

Installation

Add Grace to your Cargo.toml:

[dependencies]
grace = { path = "path/to/grace" }

With optional features:

[dependencies]
grace = { path = "path/to/grace", features = ["file-kms", "redb-store"] }

Basic Usage

use std::sync::Arc;
use grace::{
    DomainBuilder, EntityBuilder, InsecureMemoryKms, Kms, MemoryStore,
    AssociationPolicy, EntityMetadata, ScalarExt, Scalar,
};
use rand::SeedableRng;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut rng = rand::rngs::StdRng::from_entropy();

    // 1. Create a domain with in-memory storage
    let store = Arc::new(MemoryStore::new());
    let kms = InsecureMemoryKms::new(&mut rng);
    let (master_key, _) = kms.generate_master_key()?;

    let domain = DomainBuilder::new()
        .with_store(store)
        .with_master_key(master_key)
        .with_num_attrs(2)
        .with_capacity(100)`
        .create(&mut rng)?;

    // 2. Register entities
    let alice_attrs = vec![Scalar::rand(&mut rng), Scalar::rand(&mut rng)];
    let mut alice = EntityBuilder::new()
        .with_domain(domain.clone())
        .with_attributes(&alice_attrs)
        .register(&mut rng)?;

    let bob_attrs = vec![Scalar::rand(&mut rng), Scalar::rand(&mut rng)];
    let mut bob = EntityBuilder::new()
        .with_domain(domain.clone())
        .with_attributes(&bob_attrs)
        .register(&mut rng)?;

    // 3. Alice creates a header for Bob
    let header = domain.create_header(
        &mut rng,
        alice.credential(),
        AssociationPolicy::entity(bob.id()),
        &EntityMetadata::with_name("Alice"),
    )?;

    // 4. Bob decrypts and attests to Alice
    let (sender, metadata, _, signature) = domain.decrypt_header(bob.credential(), &header)?;
    println!("Bob received message from: {} ({:?})", sender, metadata.name);

    let attestation = bob.create_attestation(alice.id(), signature);
    domain.process_attestation(&attestation)?;

    // 5. Association is now established
    assert!(domain.has_association(bob.id(), alice.id())?);

    Ok(())
}

Running the Examples

Grace includes comprehensive examples:

use grace::{run_complete_flow, run_basic_example};

// Full demonstration of all features
run_complete_flow().expect("complete flow failed");

// Minimal example with ephemeral storage
run_basic_example().expect("basic example failed");

Core Concepts

Domain

The Domain is the central authority that:

  • Maintains the entity-relationship graph
  • Issues and refreshes entity credentials
  • Processes attestations and manages associations
  • Handles entity revocation
// Create with DomainBuilder
let domain = DomainBuilder::new()
    .with_store(store)
    .with_master_key(master_key)
    .with_id("my-domain")
    .with_num_attrs(2)      // Attributes per credential
    .with_capacity(1000)    // Expected entity count
    .create(&mut rng)?;

// Or create ephemeral (no persistence)
let ephemeral_domain = DomainBuilder::new()
    .ephemeral()
    .create(&mut rng)?;

Entity

Entities are participants in the system with:

  • A unique identifier
  • A credential (signing key + gated credential)
  • Optional persistent storage
// Register through DomainHandle (recommended)
let entity = EntityBuilder::new()
    .with_domain(domain.clone())
    .with_attributes(&attrs)
    .register(&mut rng)?;

// Load existing entity
let loaded = EntityBuilder::new()
    .with_domain(domain.clone())
    .load(entity_id)?;

// Ephemeral entity (no persistence)
let temp_entity = EntityBuilder::new()
    .with_domain(domain.clone())
    .ephemeral()
    .with_attributes(&attrs)
    .register(&mut rng)?;

Headers and Policies

Headers are encrypted messages that only authorized entities can decrypt:

// Single target
let policy = AssociationPolicy::entity(bob.id());

// Multiple targets (OR - any can decrypt)
let policy = AssociationPolicy::any_of(&[bob.id(), charlie.id()]);

// Broadcast (everyone can decrypt)
let policy = AssociationPolicy::broadcast();

// Complex policies with AND
let policy = AssociationPolicy::entity(bob.id())
    & AssociationPolicy::entity(charlie.id());  // Both required

// Create header with policy
let header = domain.create_header(
    &mut rng,
    sender.credential(),
    policy,
    &EntityMetadata::with_name("Sender").with_attribute("key", "value"),
)?;

Attestation Flow

The association flow establishes relationships between entities:

sequenceDiagram
    participant Alice
    participant Domain
    participant Bob

    Alice->>Domain: create_header(policy: Bob)
    Domain-->>Alice: EntityHeader
    Alice->>Bob: Send header
    Bob->>Domain: decrypt_header(header)
    Domain-->>Bob: (sender_id, metadata, secret, signature)
    Bob->>Bob: create_attestation(alice_id, signature)
    Bob->>Domain: process_attestation(attestation)
    Note over Domain: Association (Bob → Alice) recorded
    Alice->>Domain: refresh_credential()
    Note over Alice: Now has Bob's decryption key
Loading

Credential Refresh

After attestations, entities refresh credentials to gain new rights:

// Alice can now decrypt messages from Bob
let new_cred = domain.refresh_credential(&mut rng, alice.credential(), &alice_attrs)?;

// Check rights
assert!(new_cred.gated_credential.has_right(bob.id().0));

Revocation

Revoke entities with automatic association cleanup:

let result = domain.revoke_entity(bob.id(), Some("Reason".to_string()))?;

println!("Revoked at epoch: {}", result.new_epoch);
println!("Associations removed: {}", result.associations_removed);
println!("Affected entities: {:?}", result.affected_entities);

// Affected entities should refresh their credentials
// to remove the revoked entity's rights

Storage

Grace supports multiple storage backends:

MemoryStore (Default)

In-memory storage for testing and ephemeral use:

let store = Arc::new(MemoryStore::new());

RedbStore (Feature: redb-store)

Persistent embedded database:

use grace::RedbStore;

let store = Arc::new(RedbStore::open("data/grace.redb")?);

MerkleStore (Feature: merkle-store)

Append-only store with Merkle proofs for auditability:

use grace::MerkleStore;

let store = MerkleStore::new();
store.append(b"data")?;
let proof = store.prove(0)?;
assert!(proof.verify(&store.root(), b"data"));

Key Management

InsecureMemoryKms (Testing Only)

In-memory KMS for development:

let kms = InsecureMemoryKms::new(&mut rng);
let (master_key, wrapped) = kms.generate_master_key()?;

FileKms (Feature: file-kms)

Password-protected file-based KMS using Argon2:

use grace::FileKms;

// Create new KMS
let kms = FileKms::create("keys/master.key", "strong-password")?;
let (master_key, _) = kms.generate_master_key()?;

// Load existing
let kms = FileKms::open("keys/master.key", "strong-password")?;
let master_key = kms.unwrap_key(&wrapped_key)?;

Features

Feature Description
file-kms Password-based file KMS with Argon2
redb-store Persistent storage with redb
merkle-store Append-only Merkle tree storage
async Async trait support

Cryptographic Primitives

SAGA (BBS-style MAC)

Hierarchical credential issuance with delegation:

use grace::saga::{RootIssuer, HierarchicalParams};

let params = HierarchicalParams::new(num_attrs, max_delegation_levels);
let root = RootIssuer::new(&mut rng, params);
let sub_issuer = root.delegate(&mut rng, level)?;

MKVAC (Multi-Key Verifiable Anonymous Credentials)

Anonymous credential presentation:

use grace::mkvac;

let (issuer_sk, issuer_pk) = mkvac::issuer_keygen(&mut rng, &pp);
let cred = mkvac::issue_cred(&mut rng, &pp, &issuer_sk, &attrs)?;
let (presentation, proof) = mkvac::show(&mut rng, &pp, &cred, &context)?;

Gated-KEM (Key Encapsulation Mechanism)

Credential-gated encryption:

use grace::gated_kem;

let (master, public) = gated_kem::setup(&mut rng, &rights, num_attrs)?;
let cred = gated_kem::issue_credential(&mut rng, &master, &user_rights, &attrs)?;
let (secret, ciphertext) = gated_kem::encaps(&mut rng, &public, target_right)?;
let (decrypted, proof) = gated_kem::decaps(&cred, &ciphertext)?;

Security Considerations

  • Experimental: This software has not been audited. Do not use in production.
  • Key Management: Use FileKms with strong passwords in non-test environments.
  • Revocation: Is lazy - affected entities must refresh credentials to remove revoked rights.
  • Serialization: Domain reconstruction from seed is deterministic - protect the seed.

Project Structure

Grace/
├── grace/                  # Main facade crate
│   └── src/
│       ├── domain/         # DomainHandle, DomainBuilder
│       ├── entity/         # Entity, EntityBuilder
│       ├── example/        # Usage examples
│       ├── kms/            # Key management (Memory, File)
│       ├── store/          # Storage (Memory, Redb, Merkle)
│       ├── sealed.rs       # Encryption utilities
│       └── lib.rs
├── grace-primitives/       # Core domain types
│   └── src/
│       ├── domain.rs       # Domain logic
│       ├── entity.rs       # EntityCredential, EntitySecret
│       ├── header.rs       # EntityHeader, SealedPayload
│       └── types.rs        # Policy, EntityId, etc.
├── grace-crypto/           # Cryptographic schemes
│   └── src/
│       ├── saga/           # BBS-style MAC
│       ├── mkvac/          # Anonymous credentials
│       └── gated_kem/      # Credential-gated KEM
└── grace-common/           # Shared primitives
    └── src/
        └── lib.rs          # Point, Scalar, hash

Testing

Run all tests:

cargo test --workspace --all-features

Run specific test:

cargo test --workspace --all-features test_complete_flow_example

License

MIT OR Apache-2.0

About

A Rust toolkit for privacy-preserving relationship systems using anonymous credentials.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages