atproto-record 0.5.0

AT Protocol record signature operations - cryptographic signing and verification for AT Protocol records
Documentation
# atproto-record

A Rust library for AT Protocol record signature operations, providing cryptographic signing and verification capabilities for AT Protocol records.

## Overview

This crate provides functionality for:

- **Record Signing**: Create cryptographic signatures for AT Protocol records
- **Signature Verification**: Verify existing signatures against records and public keys
- **Error Handling**: Structured error types for signature operations
- **Multi-curve Support**: Support for P-256 and K-256 elliptic curves via `atproto-identity`

## Features

- Create signatures for AT Protocol records with proper `$sig` object handling
- Required signature object validation (must include `issuer` and `issued_at` fields)
- Verify record signatures against issuer public keys
- IPLD DAG-CBOR serialization for consistent signature generation
- Multibase encoding for signature representation
- Integration with `atproto-identity` for cryptographic key operations
- Repository and collection context support in signature objects
- Comprehensive error handling with structured error types including creation and verification errors

## Usage

### Creating Signatures

```rust
use atproto_record::signature;
use atproto_identity::key::{identify_key, KeyType};
use serde_json::json;
use atproto_record::errors::VerificationError;

# async fn example() -> Result<(), VerificationError> {
// Prepare key data
let key_data = identify_key("did:key:example...").map_err(|e| {
    VerificationError::KeyOperationFailed(e)
})?;

// Create a record to sign
let record = json!({
    "$type": "app.bsky.feed.post",
    "text": "Hello AT Protocol!",
    "createdAt": "2024-01-01T00:00:00Z"
});

// Create signature object with required fields
let signature_object = json!({
    "issuer": "did:plc:signer123",
    "issued_at": "2024-01-01T00:00:00Z"
});

// Create signature
let signed_record = signature::create(
    &key_data,
    &record,
    "did:plc:user123",
    "app.bsky.feed.post",
    signature_object
).await?;
# Ok(())
# }
```

### Verifying Signatures

```rust
use atproto_record::signature;
use atproto_identity::key::identify_key;
use atproto_record::errors::VerificationError;

# async fn example() -> Result<(), VerificationError> {
// Get the issuer's public key
let issuer_key = identify_key("did:key:issuer...").map_err(|e| {
    VerificationError::KeyOperationFailed(e)
})?;

// Verify the signature
signature::verify(
    "did:plc:issuer123",
    &issuer_key,
    signed_record,
    "did:plc:user123",
    "app.bsky.feed.post"
).await?;
# Ok(())
# }
```

## Command Line Tools

The crate includes two command-line tools for AT Protocol record signature operations:

### `atproto-record-sign`

Creates cryptographic signatures for AT Protocol records with proper `$sig` object handling and embedded signature metadata. This tool reads JSON records, applies cryptographic signatures using DID keys, and outputs signed records ready for AT Protocol repository storage.

**Features:**
- **Flexible Input**: Reads records from files or stdin
- **DID Key Support**: Works with both P-256 and K-256 cryptographic keys
- **Signature Object Creation**: Automatically creates required signature metadata with issuer and timestamp
- **Repository Context**: Includes repository and collection context in signatures
- **IPLD Serialization**: Uses DAG-CBOR serialization for consistent signature generation
- **Multibase Encoding**: Outputs signatures in multibase format for AT Protocol compatibility

```bash
# Sign a record from a file with all required parameters
cargo run --bin atproto-record-sign did:key:zQ3sh... did:plc:issuer123 record.json repository=did:plc:user123 collection=app.bsky.feed.post

# Sign a record from stdin
echo '{"$type":"app.bsky.feed.post","text":"Hello AT Protocol!"}' | \
  cargo run --bin atproto-record-sign did:key:zQ3sh... did:plc:issuer123 -- \
  repository=did:plc:user123 collection=app.bsky.feed.post

# Example output: JSON record with embedded signatures array
```

**Arguments:**
- `<signing_key>` - DID key string for signing (did:key:...)
- `<issuer_did>` - DID of the signing entity
- `<record_file>` - JSON file containing the record (optional, uses stdin if omitted)
- `repository=<did>` - Repository DID where record will be stored
- `collection=<nsid>` - Collection NSID (e.g., app.bsky.feed.post)

### `atproto-record-verify`

Verifies cryptographic signatures of AT Protocol records using embedded signature metadata. This tool validates that signed records contain authentic signatures from specified issuers, ensuring record integrity and authenticity.

**Features:**
- **Signature Validation**: Verifies embedded signatures against public keys
- **Issuer Authentication**: Confirms signatures are from specified DID issuers
- **Context Verification**: Validates repository and collection context in signatures
- **Multi-Signature Support**: Handles records with multiple signatures
- **IPLD Deserialization**: Uses DAG-CBOR for signature verification consistency
- **Detailed Error Reporting**: Provides specific feedback on verification failures

```bash
# Verify a signed record from a file
cargo run --bin atproto-record-verify did:plc:issuer123 did:key:zQ3sh... signed_record.json \
  repository=did:plc:user123 collection=app.bsky.feed.post

# Verify a signed record from stdin
echo '{"signatures":[{"issuer":"did:plc:issuer123","signature":"u..."}],"$type":"app.bsky.feed.post","text":"Hello"}' | \
  cargo run --bin atproto-record-verify did:plc:issuer123 did:key:zQ3sh... -- \
  repository=did:plc:user123 collection=app.bsky.feed.post

# Successful verification returns exit code 0
# Failed verification returns exit code 1 with error details
```

**Arguments:**
- `<issuer_did>` - DID of the expected signature issuer
- `<public_key>` - DID key string for verification (did:key:...)
- `<record_file>` - JSON file containing the signed record (optional, uses stdin if omitted)
- `repository=<did>` - Repository DID context for verification
- `collection=<nsid>` - Collection NSID context for verification

**Exit Codes:**
- `0` - Signature verification successful
- `1` - Signature verification failed or invalid arguments
- `2` - File I/O or parsing errors

## Modules

- [`signature`] - Core signature creation and verification functions
- [`errors`] - Structured error types for signature operations

## Error Handling

The crate uses structured error types defined in the `errors` module:

```rust
use atproto_record::errors::VerificationError;
use serde_json::json;

// Example error handling for signature creation
let signature_object = json!({ "missing": "required_fields" });

match signature::create(&key_data, &record, "repo", "collection", signature_object).await {
    Ok(signed_record) => println!("Signature created successfully!"),
    Err(VerificationError::SignatureObjectMissingField { field }) => {
        println!("Missing required field in signature object: {}", field);
    }
    Err(VerificationError::InvalidSignatureObjectType) => {
        println!("Signature object must be a JSON object");
    }
    Err(VerificationError::KeyOperationFailed(e)) => {
        println!("Cryptographic operation failed: {}", e);
    }
    Err(e) => println!("Other error: {}", e),
}

// Example error handling for signature verification
match signature::verify("did:plc:issuer", &key_data, record, "repo", "collection").await {
    Ok(()) => println!("Signature valid!"),
    Err(VerificationError::NoValidSignatureForIssuer { issuer }) => {
        println!("No valid signature found for issuer: {}", issuer);
    }
    Err(VerificationError::NoSignaturesField) => {
        println!("Record contains no signatures field");
    }
    Err(e) => println!("Verification failed: {}", e),
}
```

## Dependencies

This crate builds on:

- [`atproto-identity`]../atproto-identity - Cryptographic key operations and DID resolution
- `serde_ipld_dagcbor` - IPLD DAG-CBOR serialization for signature content
- `multibase` - Base encoding for signature representation
- `serde_json` - JSON handling for AT Protocol records
- `anyhow` - Error handling utilities
- `thiserror` - Structured error type derivation

## License

Licensed under the MIT License.