···11# Crypto Crate
2233-Last verified: 2026-03-13
33+Last verified: 2026-03-14
4455## Purpose
66Provides cryptographic primitives for the ezpds workspace: P-256 key generation,
77did:key derivation, AES-256-GCM encryption/decryption of private key material,
88-and Shamir Secret Sharing for DID rotation key recovery.
88+Shamir Secret Sharing for DID rotation key recovery, and did:plc genesis
99+operation building and verification.
910This is a pure functional core -- no I/O, no database, no config.
10111112## Contracts
···6465- Deterministic: same inputs → same DID (RFC 6979 ECDSA + SHA-256 + base32)
6566- Errors: `CryptoError::PlcOperation` if `signing_private_key` is an invalid P-256 scalar
66676868+**`verify_genesis_op`** (new, MM-90)
6969+```rust
7070+pub fn verify_genesis_op(
7171+ signed_op_json: &str, // JSON-encoded signed genesis op from client
7272+ rotation_key: &DidKeyUri, // P-256 did:key URI to verify signature against
7373+) -> Result<VerifiedGenesisOp, CryptoError>
7474+```
7575+- Parses signed op JSON (rejects unknown fields via `serde(deny_unknown_fields)`)
7676+- Reconstructs unsigned op with DAG-CBOR canonical field ordering, verifies ECDSA-SHA256 signature
7777+- Derives DID from SHA-256 of signed CBOR (same algorithm as `build_did_plc_genesis_op`)
7878+- Returns extracted op fields for semantic validation by the caller
7979+- Errors: `CryptoError::PlcOperation` for any parse, format, or signature failure
8080+6781### Public types
68826983**`P256Keypair`**
···7589- `did`: `"did:plc:xxxx..."` (28 chars total)
7690- `signed_op_json`: contains `type`, `rotationKeys`, `verificationMethods`, `alsoKnownAs`, `services`, `prev` (null), `sig`
77919292+**`VerifiedGenesisOp`** (new, MM-90)
9393+- `did`: derived DID string
9494+- `rotation_keys`: full `rotationKeys` array from the op
9595+- `also_known_as`: full `alsoKnownAs` array from the op
9696+- `verification_methods`: full `verificationMethods` map from the op
9797+- `atproto_pds_endpoint`: endpoint from `services["atproto_pds"]`, if present
9898+7899**`ShamirShare`**
79100- `index`: u8 in [1, 3] (not secret)
80101- `data`: `Zeroizing<[u8; 32]>` (zeroized on drop)
···9011191112## Dependencies
92113- **Uses**: p256 (ECDSA/key generation), aes-gcm (AES-256-GCM), multibase (base58btc encoding), rand_core (OS RNG), base64 (storage encoding), zeroize (secret cleanup), ciborium (CBOR serialization for did:plc), data-encoding (base32-lowercase), sha2 (SHA-256), serde/serde_json (struct serialization)
9393-- **Used by**: `crates/relay/` (key generation, did:plc genesis endpoint)
114114+- **Used by**: `crates/relay/` (key generation, did:plc genesis building and verification in POST /v1/dids)
9411595116## Invariants
96117- Private key bytes are always wrapped in `Zeroizing` -- callers must not copy them into non-zeroizing storage
···104125## Key Files
105126- `src/lib.rs` - Re-exports public API
106127- `src/keys.rs` - P-256 key generation, AES-256-GCM encrypt/decrypt
107107-- `src/plc.rs` - did:plc genesis operation builder (MM-89)
128128+- `src/plc.rs` - did:plc genesis operation builder (MM-89) and verifier (MM-90)
108129- `src/shamir.rs` - Shamir Secret Sharing (split/combine, GF(2^8) arithmetic)
109130- `src/error.rs` - CryptoError enum