···11# atproto-record
2233-Cryptographic signature operations for AT Protocol records.
33+Cryptographic signature operations and utilities for AT Protocol records.
4455## Overview
6677-Sign and verify AT Protocol records using IPLD DAG-CBOR serialization with support for P-256, P-384, and K-256 cryptographic signatures. Includes AT-URI parsing for record identification.
77+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.
8899## Features
10101111-- **Record signing**: Create cryptographic signatures on AT Protocol records with proper $sig object handling
1212-- **Signature verification**: Verify record signatures against public keys and issuer DIDs
1313-- **AT-URI parsing**: Parse and validate AT Protocol URIs (at://authority/collection/record_key)
1414-- **IPLD serialization**: DAG-CBOR serialization for signature consistency and integrity
1515-- **Multi-curve support**: Support for P-256, P-384, and K-256 elliptic curve signatures
1616-- **Structured errors**: Comprehensive error handling with detailed error types
1111+- **Record signing**: Create cryptographic signatures on AT Protocol records following community.lexicon.attestation.signature specification
1212+- **Signature verification**: Verify record signatures against public keys with issuer validation
1313+- **AT-URI parsing**: Parse and validate AT Protocol URIs (at://authority/collection/record_key) with robust error handling
1414+- **IPLD serialization**: DAG-CBOR serialization ensuring deterministic and verifiable record encoding
1515+- **Multi-curve support**: Full support for P-256, P-384, and K-256 elliptic curve signatures
1616+- **DateTime utilities**: RFC 3339 datetime serialization with millisecond precision for consistent timestamp handling
1717+- **Structured errors**: Type-safe error handling following project conventions with detailed error messages
17181819## CLI Tools
19202021The following command-line tools are available when built with the `clap` feature:
21222222-- **`atproto-record-sign`**: Sign AT Protocol records with private keys and create signature objects
2323-- **`atproto-record-verify`**: Verify AT Protocol record signatures against public keys and issuers
2323+- **`atproto-record-sign`**: Sign AT Protocol records with private keys, supporting flexible argument ordering
2424+- **`atproto-record-verify`**: Verify AT Protocol record signatures by validating cryptographic signatures against issuer DIDs and public keys
24252526## Library Usage
2627···3132use atproto_identity::key::identify_key;
3233use serde_json::json;
33343535+// Parse the signing key from a did:key
3436let key_data = identify_key("did:key:zQ3sh...")?;
3535-let record = json!({"$type": "app.bsky.feed.post", "text": "Hello!"});
3636-let signature_object = json!({"issuer": "did:plc:issuer", "issuedAt": "2024-01-01T00:00:00Z"});
3737+3838+// The record to sign
3939+let record = json!({"$type": "app.bsky.feed.post", "text": "Hello world!"});
4040+4141+// Signature metadata (issuer is required, other fields are optional)
4242+let signature_object = json!({
4343+ "issuer": "did:plc:issuer"
4444+ // Optional: "issuedAt", "purpose", "expiry", etc.
4545+});
37464747+// Create the signed record with embedded signatures array
3848let signed_record = signature::create(
3949 &key_data,
4050 &record,
4141- "did:plc:repo",
5151+ "did:plc:repository",
4252 "app.bsky.feed.post",
4353 signature_object
4454).await?;
···4757### Verifying Signatures
48584959```rust
6060+use atproto_record::signature;
6161+use atproto_identity::key::identify_key;
6262+6363+// Parse the public key for verification
5064let issuer_key = identify_key("did:key:zQ3sh...")?;
51656666+// Verify the signature (throws error if invalid)
5267signature::verify(
5353- "did:plc:issuer",
5454- &issuer_key,
5555- signed_record,
5656- "did:plc:repo",
5757- "app.bsky.feed.post"
6868+ "did:plc:issuer", // Expected issuer DID
6969+ &issuer_key, // Public key for verification
7070+ signed_record, // The signed record
7171+ "did:plc:repository", // Repository context
7272+ "app.bsky.feed.post" // Collection context
5873).await?;
5974```
6075···6479use atproto_record::aturi::ATURI;
6580use std::str::FromStr;
66818282+// Parse an AT-URI into its components
6783let aturi = ATURI::from_str("at://did:plc:abc123/app.bsky.feed.post/3k2k4j5h6g")?;
6868-println!("Authority: {}", aturi.authority);
6969-println!("Collection: {}", aturi.collection);
7070-println!("Record Key: {}", aturi.record_key);
8484+8585+// Access the parsed components
8686+println!("Authority: {}", aturi.authority); // "did:plc:abc123"
8787+println!("Collection: {}", aturi.collection); // "app.bsky.feed.post"
8888+println!("Record Key: {}", aturi.record_key); // "3k2k4j5h6g"
8989+9090+// The Display trait formats back to a valid AT-URI
9191+println!("Full URI: {}", aturi); // "at://did:plc:abc123/app.bsky.feed.post/3k2k4j5h6g"
9292+```
9393+9494+### DateTime Utilities
9595+9696+```rust
9797+use chrono::{DateTime, Utc};
9898+use serde::{Deserialize, Serialize};
9999+100100+// Use the datetime module for consistent RFC 3339 formatting
101101+#[derive(Serialize, Deserialize)]
102102+struct Record {
103103+ #[serde(with = "atproto_record::datetime::format")]
104104+ created_at: DateTime<Utc>,
105105+106106+ #[serde(with = "atproto_record::datetime::optional_format")]
107107+ updated_at: Option<DateTime<Utc>>,
108108+}
71109```
7211073111## Command Line Usage
···79117cargo build --features clap --bins
8011881119# Sign a record
8282-cargo run --features clap --bin atproto-record-sign -- did:key:zQ3sh... did:plc:issuer record.json \
8383- repository=did:plc:repo collection=app.bsky.feed.post
120120+cargo run --features clap --bin atproto-record-sign -- \
121121+ did:key:zQ3sh... # Signing key (did:key format)
122122+ did:plc:issuer # Issuer DID
123123+ record.json # Record file (or use -- for stdin)
124124+ repository=did:plc:repo # Repository context
125125+ collection=app.bsky.feed.post # Collection type
126126+127127+# Sign with custom fields (e.g., issuedAt, purpose, expiry)
128128+cargo run --features clap --bin atproto-record-sign -- \
129129+ did:key:zQ3sh... did:plc:issuer record.json \
130130+ repository=did:plc:repo collection=app.bsky.feed.post \
131131+ issuedAt="2024-01-01T00:00:00.000Z" purpose="attestation"
8413285133# Verify a signature
8686-cargo run --features clap --bin atproto-record-verify -- did:plc:issuer did:key:zQ3sh... signed.json \
134134+cargo run --features clap --bin atproto-record-verify -- \
135135+ did:plc:issuer # Expected issuer DID
136136+ did:key:zQ3sh... # Verification key
137137+ signed.json # Signed record file
138138+ repository=did:plc:repo # Repository context (must match signing)
139139+ collection=app.bsky.feed.post # Collection type (must match signing)
140140+141141+# Read from stdin
142142+echo '{"text":"Hello"}' | cargo run --features clap --bin atproto-record-sign -- \
143143+ did:key:zQ3sh... did:plc:issuer -- \
87144 repository=did:plc:repo collection=app.bsky.feed.post
88145```
89146
+37-7
crates/atproto-record/src/aturi.rs
···11-//! AT-URI parsing and validation.
11+//! AT-URI parsing and validation for AT Protocol record identification.
22+//!
33+//! This module provides functionality to parse and validate AT Protocol URIs (AT-URIs),
44+//! which are used to uniquely identify records within the AT Protocol ecosystem.
55+//!
66+//! ## AT-URI Format
27//!
33-//! Parse AT Protocol URIs (at://authority/collection/record_key) for
44-//! identifying records within AT Protocol repositories.
55-//! - `collection` is an NSID identifying the record type
66-//! - `record_key` is the unique identifier for the specific record
88+//! AT-URIs follow the format: `at://authority/collection/record_key`
99+//!
1010+//! - **authority**: A DID (Decentralized Identifier) - either did:plc or did:web
1111+//! - **collection**: An NSID (Namespaced Identifier) specifying the record type
1212+//! - **record_key**: A unique identifier for the specific record within the collection
1313+//!
1414+//! ## Example
1515+//!
1616+//! ```ignore
1717+//! use atproto_record::aturi::ATURI;
1818+//! use std::str::FromStr;
1919+//!
2020+//! let uri = "at://did:plc:abc123/app.bsky.feed.post/3k2k4j5h6g";
2121+//! let aturi = ATURI::from_str(uri)?;
2222+//!
2323+//! assert_eq!(aturi.authority, "did:plc:abc123");
2424+//! assert_eq!(aturi.collection, "app.bsky.feed.post");
2525+//! assert_eq!(aturi.record_key, "3k2k4j5h6g");
2626+//! ```
2727+//!
2828+//! ## Validation Rules
2929+//!
3030+//! - Must start with the `at://` scheme
3131+//! - Authority must be a valid DID (handles are not supported)
3232+//! - Collection and record_key must be non-empty
3333+//! - Trailing slashes are not permitted
734835use std::fmt;
936use std::str::FromStr;
···14411542/// Represents a parsed AT Protocol URI (AT-URI).
1643///
1717-/// AT-URIs are used to identify specific records within AT Protocol repositories.
1818-/// They consist of three components: authority (DID), collection (NSID), and record key.
4444+/// AT-URIs uniquely identify records within AT Protocol repositories by combining
4545+/// three essential components: authority (DID), collection (NSID), and record key.
4646+///
4747+/// This struct provides validated access to these components after successful parsing
4848+/// and implements `Display` for reconstructing the original URI format.
1949#[cfg_attr(debug_assertions, derive(Debug))]
2050#[derive(Clone)]
2151pub struct ATURI {
···11-//! CLI tool for verifying AT Protocol record signatures.
11+//! Command-line tool for verifying cryptographic signatures on AT Protocol records.
22+//!
33+//! This tool validates signatures on AT Protocol records by reconstructing the
44+//! signed content and verifying ECDSA signatures against public keys. It ensures
55+//! that records have valid signatures from specified issuers.
2637use anyhow::Result;
48use atproto_identity::{
+35-15
crates/atproto-record/src/datetime.rs
···11//! DateTime serialization utilities for AT Protocol records.
22//!
33-//! This module provides Serde serialization and deserialization functions for DateTime<Utc>
44-//! values with RFC 3339 formatting, including support for optional datetime fields.
55-//! Used for consistent datetime handling across AT Protocol record structures.
33+//! This module provides specialized Serde serialization and deserialization functions
44+//! for `DateTime<Utc>` values, ensuring consistent RFC 3339 formatting with millisecond
55+//! precision across all AT Protocol record structures.
66+//!
77+//! ## Usage
88+//!
99+//! These modules are designed to be used with Serde's `#[serde(with = "...")]` attribute:
1010+//!
1111+//! ```ignore
1212+//! use chrono::{DateTime, Utc};
1313+//! use serde::{Deserialize, Serialize};
1414+//!
1515+//! #[derive(Serialize, Deserialize)]
1616+//! struct Signature {
1717+//! #[serde(with = "atproto_record::datetime::format")]
1818+//! issued_at: DateTime<Utc>,
1919+//!
2020+//! #[serde(with = "atproto_record::datetime::optional_format")]
2121+//! expires_at: Option<DateTime<Utc>>,
2222+//! }
2323+//! ```
624//!
725//! ## Modules
826//!
99-//! - [`format`] - Required datetime field serialization in RFC 3339 format with milliseconds
1010-//! - [`optional_format`] - Optional datetime field serialization handling None values
2727+//! - [`format`] - Required datetime field serialization with RFC 3339 millisecond precision
2828+//! - [`optional_format`] - Optional datetime field serialization with proper None handling
11291212-/// Required datetime field serialization in RFC 3339 format with milliseconds.
3030+/// Required datetime field serialization with RFC 3339 formatting.
1331///
1414-/// Provides serde serialization functions for DateTime<Utc> values
1515-/// using RFC 3339 formatting with millisecond precision.
3232+/// This module provides serde serialization/deserialization for `DateTime<Utc>` values,
3333+/// ensuring consistent RFC 3339 format with millisecond precision (e.g., "2024-01-01T12:00:00.000Z").
3434+/// Use with `#[serde(with = "atproto_record::datetime::format")]` on required datetime fields.
1635pub mod format {
1736 use chrono::{DateTime, SecondsFormat, Utc};
1837 use serde::{self, Deserialize, Deserializer, Serializer};
19382020- /// Serializes a DateTime<Utc> to RFC 3339 format with milliseconds.
3939+ /// Serializes a `DateTime<Utc>` to RFC 3339 string with millisecond precision.
2140 pub fn serialize<S>(date: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
2241 where
2342 S: Serializer,
···2645 serializer.serialize_str(&s)
2746 }
28472929- /// Deserializes an RFC 3339 string to DateTime<Utc>.
4848+ /// Deserializes an RFC 3339 formatted string to `DateTime<Utc>`.
3049 pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTime<Utc>, D::Error>
3150 where
3251 D: Deserializer<'de>,
···3857 }
3958}
40594141-/// Optional datetime field serialization handling None values.
6060+/// Optional datetime field serialization with None value support.
4261///
4343-/// Provides serde serialization functions for Option<DateTime<Utc>> values
4444-/// using RFC 3339 formatting with proper None handling.
6262+/// This module provides serde serialization/deserialization for `Option<DateTime<Utc>>` values,
6363+/// handling both Some values (formatted as RFC 3339 with milliseconds) and None values gracefully.
6464+/// Use with `#[serde(with = "atproto_record::datetime::optional_format")]` on optional datetime fields.
4565pub mod optional_format {
4666 use chrono::{DateTime, SecondsFormat, Utc};
4767 use serde::{self, Deserialize, Deserializer, Serializer};
48684949- /// Serializes an Option<DateTime<Utc>> to RFC 3339 format with milliseconds.
6969+ /// Serializes an `Option<DateTime<Utc>>` to RFC 3339 string or null.
5070 pub fn serialize<S>(date: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
5171 where
5272 S: Serializer,
···5878 serializer.serialize_str(&s)
5979 }
60806161- /// Deserializes an optional RFC 3339 string to Option<DateTime<Utc>>.
8181+ /// Deserializes an optional RFC 3339 string to `Option<DateTime<Utc>>`.
6282 pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<DateTime<Utc>>, D::Error>
6383 where
6484 D: Deserializer<'de>,
+40-18
crates/atproto-record/src/errors.rs
···11//! Structured error types for AT Protocol record operations.
22//!
33-//! Comprehensive error handling for AT Protocol record signature verification and AT-URI parsing
44-//! operations using structured error types with the `thiserror` library. All errors follow the
55-//! project convention of prefixed error codes with descriptive messages.
33+//! This module provides comprehensive error handling for all AT Protocol record operations
44+//! using type-safe error enums powered by the `thiserror` library. All errors follow the
55+//! project's standardized naming convention for consistent error reporting and debugging.
66//!
77//! ## Error Categories
88//!
99-//! - **`VerificationError`** (verification-1 to verification-11): Record signature verification and creation errors
1010-//! - **`AturiError`** (aturi-1 to aturi-9): AT-URI parsing and validation errors
1111-//! - **`CliError`** (cli-1 to cli-8): Command-line interface specific errors including file I/O, DID validation, and argument parsing
99+//! ### `VerificationError` (Domain: verification)
1010+//! Errors related to cryptographic signature creation and verification operations.
1111+//! Error codes: verification-1 through verification-11
1212+//!
1313+//! ### `AturiError` (Domain: aturi)
1414+//! Errors occurring during AT-URI parsing and validation.
1515+//! Error codes: aturi-1 through aturi-9
1616+//!
1717+//! ### `CliError` (Domain: cli)
1818+//! Command-line interface specific errors for file I/O, argument parsing, and DID validation.
1919+//! Error codes: cli-1 through cli-8
1220//!
1321//! ## Error Format
1422//!
1515-//! All errors use the standardized format: `error-atproto-record-{domain}-{number} {message}: {details}`
2323+//! All errors follow the standardized format:
2424+//! ```text
2525+//! error-atproto-record-{domain}-{number} {message}: {details}
2626+//! ```
2727+//!
2828+//! ## Example Usage
2929+//!
3030+//! ```ignore
3131+//! use atproto_record::errors::VerificationError;
3232+//!
3333+//! fn verify_signature() -> Result<(), VerificationError> {
3434+//! // Verification logic
3535+//! Err(VerificationError::NoSignaturesField)
3636+//! }
3737+//! ```
16381739use thiserror::Error;
18401919-/// Represents errors that can occur during record signature verification operations.
4141+/// Errors that can occur during record signature creation and verification.
2042///
2121-/// These errors relate to various stages of the signature verification process
2222-/// for AT Protocol records, from parsing to cryptographic validation.
4343+/// This enum covers all failure modes in the signature lifecycle, from creating
4444+/// signatures with missing metadata fields to verifying signatures with invalid
4545+/// cryptographic proofs or serialization failures.
2346#[derive(Debug, Error)]
2447pub enum VerificationError {
2548 /// Error when no signatures field is found in the record.
···86109 /// Error when signature object is missing required fields.
87110 ///
88111 /// This error occurs when the signature object is missing fields that are
8989- /// necessary during signature creation, such as 'issuer' or
9090- /// 'issuedAt'.
112112+ /// necessary during signature creation, such as 'issuer'.
91113 #[error("error-atproto-record-verification-8 Signature object missing field: {field}")]
92114 SignatureObjectMissingField {
93115 /// The name of the missing field
···126148 },
127149}
128150129129-/// Represents errors that can occur during AT-URI parsing operations.
151151+/// Errors that can occur during AT-URI parsing and validation.
130152///
131131-/// These errors relate to various stages of parsing AT-URIs into their
132132-/// component parts (authority, collection, record key).
153153+/// This enum covers all validation failures when parsing AT-URIs, including
154154+/// format violations, missing components, and invalid authority types.
133155#[derive(Debug, Error)]
134156pub enum AturiError {
135157 /// Error when AT-URI does not start with the required "at://" prefix.
···200222 EmptyRecordKey,
201223}
202224203203-/// Error types that can occur in CLI tools.
225225+/// Errors specific to command-line interface operations.
204226///
205205-/// These errors represent failures specific to command-line interface operations
206206-/// such as file I/O, JSON parsing, DID validation, and missing required arguments.
227227+/// This enum covers failures in CLI argument parsing, file I/O operations,
228228+/// JSON processing, and DID validation that occur in the binary tools.
207229#[derive(Debug, Error)]
208230pub enum CliError {
209231 /// Occurs when DID method is not supported
+52-11
crates/atproto-record/src/lib.rs
···11-//! Cryptographic signature operations for AT Protocol records.
11+//! Cryptographic signature operations and utilities for AT Protocol records.
22//!
33-//! Sign and verify AT Protocol records using IPLD DAG-CBOR serialization
44-//! with support for P-256, P-384, and K-256 cryptographic signatures.
33+//! This library provides comprehensive functionality for working with AT Protocol records,
44+//! including cryptographic signature creation and verification, AT-URI parsing, and
55+//! datetime serialization utilities. Built on IPLD DAG-CBOR for deterministic encoding
66+//! with support for P-256, P-384, and K-256 elliptic curve cryptography.
77+//!
88+//! ## Main Features
99+//!
1010+//! - **Signature Operations**: Create and verify cryptographic signatures following the
1111+//! community.lexicon.attestation.signature specification
1212+//! - **AT-URI Support**: Parse and validate AT Protocol URIs for record identification
1313+//! - **DateTime Utilities**: RFC 3339 datetime serialization with millisecond precision
1414+//! - **Type-Safe Errors**: Structured error types following project conventions
1515+//!
1616+//! ## Example Usage
1717+//!
1818+//! ```ignore
1919+//! use atproto_record::signature;
2020+//! use atproto_identity::key::identify_key;
2121+//! use serde_json::json;
2222+//!
2323+//! // Sign a record
2424+//! let key_data = identify_key("did:key:...")?;
2525+//! let record = json!({"$type": "app.bsky.feed.post", "text": "Hello!"});
2626+//! let sig_obj = json!({"issuer": "did:plc:..."});
2727+//!
2828+//! let signed = signature::create(&key_data, &record, "did:plc:repo",
2929+//! "app.bsky.feed.post", sig_obj).await?;
3030+//!
3131+//! // Verify a signature
3232+//! signature::verify("did:plc:issuer", &key_data, signed,
3333+//! "did:plc:repo", "app.bsky.feed.post").await?;
3434+//! ```
535636#![forbid(unsafe_code)]
737#![warn(missing_docs)]
83899-/// Structured error types for signature verification operations.
3939+/// Structured error types for record operations.
1040///
1111-/// This module defines comprehensive error types that can occur during
1212-/// AT Protocol record signature verification, following the project's
1313-/// error naming conventions.
4141+/// Comprehensive error handling for signature verification, AT-URI parsing,
4242+/// and CLI operations. All errors follow the project's standardized format:
4343+/// `error-atproto-record-{domain}-{number} {message}: {details}`
1444pub mod errors;
15451616-/// Core signature creation and verification functions.
4646+/// Core signature creation and verification.
1747///
1818-/// This module provides the primary functionality for creating and verifying
1919-/// cryptographic signatures on AT Protocol records, with proper handling of
2020-/// signature objects and IPLD serialization.
4848+/// Provides functions for creating and verifying cryptographic signatures on
4949+/// AT Protocol records using IPLD DAG-CBOR serialization. Supports the
5050+/// community.lexicon.attestation.signature specification with proper $sig
5151+/// object handling and multiple signature support.
2152pub mod signature;
22535454+/// AT-URI parsing and validation.
5555+///
5656+/// Parse and validate AT Protocol URIs (at://authority/collection/record_key)
5757+/// for identifying records within repositories. Supports both did:plc and
5858+/// did:web authority types with comprehensive validation.
2359pub mod aturi;
24606161+/// DateTime serialization utilities.
6262+///
6363+/// RFC 3339 datetime serialization modules for consistent timestamp handling
6464+/// across AT Protocol records. Includes support for both required and optional
6565+/// datetime fields with millisecond precision.
2566pub mod datetime;
+89-40
crates/atproto-record/src/signature.rs
···11-//! AT Protocol record signature operations.
11+//! AT Protocol record signature creation and verification.
22+//!
33+//! This module provides comprehensive functionality for creating and verifying
44+//! cryptographic signatures on AT Protocol records following the
55+//! community.lexicon.attestation.signature specification.
66+//!
77+//! ## Signature Process
88+//!
99+//! 1. **Signing**: Records are augmented with a `$sig` object containing issuer,
1010+//! timestamp, and context information, then serialized using IPLD DAG-CBOR
1111+//! for deterministic encoding before signing with ECDSA.
1212+//!
1313+//! 2. **Storage**: Signatures are stored in a `signatures` array within the record,
1414+//! allowing multiple signatures from different issuers.
1515+//!
1616+//! 3. **Verification**: The original signed content is reconstructed by replacing
1717+//! the signatures array with the appropriate `$sig` object, then verified
1818+//! using the issuer's public key.
1919+//!
2020+//! ## Supported Curves
2121+//!
2222+//! - P-256 (NIST P-256 / secp256r1)
2323+//! - P-384 (NIST P-384 / secp384r1)
2424+//! - K-256 (secp256k1)
2525+//!
2626+//! ## Example
2727+//!
2828+//! ```ignore
2929+//! use atproto_record::signature::{create, verify};
3030+//! use atproto_identity::key::identify_key;
3131+//! use serde_json::json;
3232+//!
3333+//! // Create a signature
3434+//! let key = identify_key("did:key:...")?;
3535+//! let record = json!({"text": "Hello!"});
3636+//! let sig_obj = json!({
3737+//! "issuer": "did:plc:issuer"
3838+//! // Optional: any additional fields like "issuedAt", "purpose", etc.
3939+//! });
240//!
33-//! Sign and verify AT Protocol records using elliptic curve signatures
44-//! with IPLD DAG-CBOR serialization and proper $sig object handling.
4141+//! let signed = create(&key, &record, "did:plc:repo",
4242+//! "app.bsky.feed.post", sig_obj).await?;
4343+//!
4444+//! // Verify the signature
4545+//! verify("did:plc:issuer", &key, signed,
4646+//! "did:plc:repo", "app.bsky.feed.post").await?;
4747+//! ```
548649use atproto_identity::key::{KeyData, sign, validate};
750use serde_json::json;
···9521053use crate::errors::VerificationError;
11541212-/// Signs an AT Protocol record.
5555+/// Creates a cryptographic signature for an AT Protocol record.
1356///
1414-/// This function generates a signature for the provided record using the specified
1515-/// key data and context information. The signature is embedded into the record
1616-/// following AT Protocol signature conventions.
5757+/// This function generates a signature following the community.lexicon.attestation.signature
5858+/// specification. The record is augmented with a `$sig` object containing context information,
5959+/// serialized using IPLD DAG-CBOR, signed with the provided key, and the signature is added
6060+/// to a `signatures` array in the returned record.
1761///
1862/// # Parameters
1963///
2020-/// * `key_data` - The cryptographic key information wrapped in KeyData
2121-/// * `record` - The JSON record to be signed
2222-/// * `repository` - The repository DID context for the signature
2323-/// * `collection` - The collection name context for the signature
2424-/// * `signature_object` - Optional additional fields for the signature object
6464+/// * `key_data` - The signing key (private key) wrapped in KeyData
6565+/// * `record` - The JSON record to be signed (will not be modified)
6666+/// * `repository` - The repository DID where this record will be stored
6767+/// * `collection` - The collection type (NSID) for this record
6868+/// * `signature_object` - Metadata for the signature, must include:
6969+/// - `issuer`: The DID of the entity creating the signature (required)
7070+/// - Additional custom fields are preserved in the signature (optional)
2571///
2672/// # Returns
2773///
2828-/// Returns the original record with a `signatures` field containing the new signature.
7474+/// Returns a new record containing:
7575+/// - All original record fields
7676+/// - A `signatures` array with the new signature appended
7777+/// - No `$sig` field (only used during signing)
2978///
3079/// # Errors
3180///
3232-/// Returns an error if:
3333-/// - IPLD serialization fails
3434-/// - Cryptographic signing fails
3535-/// - JSON manipulation fails
8181+/// Returns [`VerificationError`] if:
8282+/// - Required field `issuer` is missing from signature_object
8383+/// - IPLD DAG-CBOR serialization fails
8484+/// - Cryptographic signing operation fails
8585+/// - JSON structure manipulation fails
3686pub async fn create(
3787 key_data: &KeyData,
3888 record: &serde_json::Value,
···4494 if !record_map.contains_key("issuer") {
4595 return Err(VerificationError::SignatureObjectMissingField {
4696 field: "issuer".to_string(),
4747- });
4848- }
4949- if !record_map.contains_key("issuedAt") {
5050- return Err(VerificationError::SignatureObjectMissingField {
5151- field: "issuedAt".to_string(),
5297 });
5398 }
5499 } else {
···71116 record_map.insert("$sig".to_string(), sig);
72117 }
731187474- {
7575- let thing = serde_json::to_string_pretty(&signing_record).expect("yeah");
7676- println!("{}", &thing);
7777- }
7811979120 // Create a signature.
80121 let serialized_signing_record = serde_ipld_dagcbor::to_vec(&signing_record)?;
···114155115156/// Verifies a cryptographic signature on an AT Protocol record.
116157///
117117-/// This function validates that the provided record contains a valid signature
118118-/// from the specified issuer using the provided public key. It reconstructs
119119-/// the signed content and verifies the cryptographic signature.
158158+/// This function validates signatures by reconstructing the original signed content
159159+/// (record with `$sig` object) and verifying the ECDSA signature against it.
160160+/// It searches through all signatures in the record to find one matching the
161161+/// specified issuer, then verifies it with the provided public key.
120162///
121163/// # Parameters
122164///
123123-/// * `issuer` - The DID of the expected signature issuer
124124-/// * `key_data` - The public key information for verification
125125-/// * `record` - The signed JSON record to verify
126126-/// * `repository` - The repository DID context for verification
127127-/// * `collection` - The collection name context for verification
165165+/// * `issuer` - The DID of the expected signature issuer to verify
166166+/// * `key_data` - The public key for signature verification
167167+/// * `record` - The signed record containing a `signatures` or `sigs` array
168168+/// * `repository` - The repository DID used during signing (must match)
169169+/// * `collection` - The collection type used during signing (must match)
128170///
129171/// # Returns
130172///
131131-/// Returns `Ok(())` if a valid signature from the issuer is found and verified.
173173+/// Returns `Ok(())` if a valid signature from the specified issuer is found
174174+/// and successfully verified against the reconstructed signed content.
132175///
133176/// # Errors
134177///
135135-/// Returns a [`VerificationError`] if:
136136-/// - No signatures field is found in the record
178178+/// Returns [`VerificationError`] if:
179179+/// - No `signatures` or `sigs` field exists in the record
137180/// - No signature from the specified issuer is found
138138-/// - Signature decoding or parsing fails
139139-/// - Cryptographic verification fails
140140-/// - Record serialization fails
181181+/// - The issuer's signature is malformed or missing required fields
182182+/// - Base64 decoding of the signature fails
183183+/// - IPLD DAG-CBOR serialization of reconstructed content fails
184184+/// - Cryptographic verification fails (invalid signature)
185185+///
186186+/// # Note
187187+///
188188+/// This function supports both `signatures` and `sigs` field names for
189189+/// backward compatibility with different AT Protocol implementations.
141190pub async fn verify(
142191 issuer: &str,
143192 key_data: &KeyData,