atproto-record

Crates.ioatproto-record
lib.rsatproto-record
version0.11.2
created_at2025-05-30 16:58:48.516915+00
updated_at2025-08-20 18:53:46.693387+00
descriptionAT Protocol record signature operations - cryptographic signing and verification for AT Protocol records
homepagehttps://tangled.sh/@smokesignal.events/atproto-identity-rs
repositoryhttps://tangled.sh/@smokesignal.events/atproto-identity-rs
max_upload_size
id1695391
size259,656
Nick Gerakines (ngerakines)

documentation

https://docs.rs/atproto-record

README

atproto-record

Cryptographic signature operations and utilities for AT Protocol records.

Overview

A comprehensive Rust library for working with AT Protocol records, providing cryptographic signature creation and verification, AT-URI parsing, and datetime utilities. Built on IPLD DAG-CBOR serialization with support for P-256, P-384, and K-256 elliptic curve cryptography.

Features

  • Record signing: Create cryptographic signatures on AT Protocol records following community.lexicon.attestation.signature specification
  • Signature verification: Verify record signatures against public keys with issuer validation
  • AT-URI parsing: Parse and validate AT Protocol URIs (at://authority/collection/record_key) with robust error handling
  • IPLD serialization: DAG-CBOR serialization ensuring deterministic and verifiable record encoding
  • Multi-curve support: Full support for P-256, P-384, and K-256 elliptic curve signatures
  • DateTime utilities: RFC 3339 datetime serialization with millisecond precision for consistent timestamp handling
  • Structured errors: Type-safe error handling following project conventions with detailed error messages

CLI Tools

The following command-line tools are available when built with the clap feature:

  • atproto-record-sign: Sign AT Protocol records with private keys, supporting flexible argument ordering
  • atproto-record-verify: Verify AT Protocol record signatures by validating cryptographic signatures against issuer DIDs and public keys

Library Usage

Creating Signatures

use atproto_record::signature;
use atproto_identity::key::identify_key;
use serde_json::json;

// Parse the signing key from a did:key
let key_data = identify_key("did:key:zQ3sh...")?;

// The record to sign
let record = json!({"$type": "app.bsky.feed.post", "text": "Hello world!"});

// Signature metadata (issuer is required, other fields are optional)
let signature_object = json!({
    "issuer": "did:plc:issuer"
    // Optional: "issuedAt", "purpose", "expiry", etc.
});

// Create the signed record with embedded signatures array
let signed_record = signature::create(
    &key_data,
    &record,
    "did:plc:repository",
    "app.bsky.feed.post",
    signature_object
).await?;

Verifying Signatures

use atproto_record::signature;
use atproto_identity::key::identify_key;

// Parse the public key for verification
let issuer_key = identify_key("did:key:zQ3sh...")?;

// Verify the signature (throws error if invalid)
signature::verify(
    "did:plc:issuer",      // Expected issuer DID
    &issuer_key,           // Public key for verification
    signed_record,         // The signed record
    "did:plc:repository",  // Repository context
    "app.bsky.feed.post"   // Collection context
).await?;

AT-URI Parsing

use atproto_record::aturi::ATURI;
use std::str::FromStr;

// Parse an AT-URI into its components
let aturi = ATURI::from_str("at://did:plc:abc123/app.bsky.feed.post/3k2k4j5h6g")?;

// Access the parsed components
println!("Authority: {}", aturi.authority);   // "did:plc:abc123"
println!("Collection: {}", aturi.collection);  // "app.bsky.feed.post"
println!("Record Key: {}", aturi.record_key);  // "3k2k4j5h6g"

// The Display trait formats back to a valid AT-URI
println!("Full URI: {}", aturi);  // "at://did:plc:abc123/app.bsky.feed.post/3k2k4j5h6g"

DateTime Utilities

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

// Use the datetime module for consistent RFC 3339 formatting
#[derive(Serialize, Deserialize)]
struct Record {
    #[serde(with = "atproto_record::datetime::format")]
    created_at: DateTime<Utc>,
    
    #[serde(with = "atproto_record::datetime::optional_format")]
    updated_at: Option<DateTime<Utc>>,
}

Command Line Usage

All CLI tools require the clap feature:

# Build with CLI support
cargo build --features clap --bins

# Sign a record
cargo run --features clap --bin atproto-record-sign -- \
  did:key:zQ3sh...                    # Signing key (did:key format)
  did:plc:issuer                      # Issuer DID
  record.json                          # Record file (or use -- for stdin)
  repository=did:plc:repo              # Repository context
  collection=app.bsky.feed.post        # Collection type

# Sign with custom fields (e.g., issuedAt, purpose, expiry)
cargo run --features clap --bin atproto-record-sign -- \
  did:key:zQ3sh... did:plc:issuer record.json \
  repository=did:plc:repo collection=app.bsky.feed.post \
  issuedAt="2024-01-01T00:00:00.000Z" purpose="attestation"

# Verify a signature
cargo run --features clap --bin atproto-record-verify -- \
  did:plc:issuer                      # Expected issuer DID
  did:key:zQ3sh...                    # Verification key
  signed.json                          # Signed record file
  repository=did:plc:repo              # Repository context (must match signing)
  collection=app.bsky.feed.post        # Collection type (must match signing)

# Read from stdin
echo '{"text":"Hello"}' | cargo run --features clap --bin atproto-record-sign -- \
  did:key:zQ3sh... did:plc:issuer -- \
  repository=did:plc:repo collection=app.bsky.feed.post

License

MIT License

Commit count: 0

cargo fmt