# 1password/cpace architecture

> Architecture diagram of the GitHub repository 1password/cpace, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-16). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/1password/cpace
- Repository: https://github.com/1password/cpace

## Overview

1. **What this repository is**
   - This is a single Rust library crate implementing **CPace**, a balanced PAKE, for **Ristretto255 with SHA-512**.
   - It is intentionally **`no_std` compatible**, so the architecture is focused on pure cryptographic protocol logic rather than OS, network, or application integration.

2. **Top-level shape**
   - The crate is small and modular: `src/lib.rs` is the public entry point, and the implementation is split into a few internal support modules:
     - `encoding.rs`
     - `formatting.rs`
     - `keys.rs`
     - `errors.rs`
   - There are no subcrates, services, or runtime processes; this is a **library-only** architecture.

3. **Public API boundary**
   - `lib.rs` is the main boundary between consumers and the protocol implementation.
   - It likely exposes the CPace session flow, key material types, and protocol-side operations, while keeping protocol internals hidden in the helper modules.
   - For an architecture diagram, treat this as the **API façade**.

4. **Protocol flow**
   - The core data flow is: shared password/secret + protocol context/identifiers → CPace formatting/encoding → ephemeral protocol exchange → shared session key → key confirmation.
   - The README makes clear that the library enforces an **extra key-confirmation round** beyond the bare CPace exchange, so the protocol flow is not just key derivation but also **mutual proof of key agreement**.

5. **`formatting.rs` role**
   - This module is the protocol’s **domain-separation and transcript-construction layer**.
   - In a PAKE, this is where identities, labels, and context are normalized into the byte strings that feed later cryptographic steps.
   - Architecturally, it sits between caller-provided inputs and low-level hashing/encoding.

6. **`encoding.rs` role**
   - This module handles **byte-level representation** of protocol values.
   - It is the likely place for translating group elements, scalars, and transcript fields into canonical encoded forms used by the protocol.
   - For a diagram, this is the **serialization/normalization boundary** that prevents higher layers from depending on raw internal representations.

7. **`keys.rs` role**
   - This module is the **key schedule and key confirmation** layer.
   - It likely derives the final shared key from protocol secrets and then produces/verifies confirmation material so both sides can prove they arrived at the same result.
   - This is the most security-sensitive part of the control flow after the core group operations.

8. **`errors.rs` role**
   - This module centralizes the crate’s **failure model**.
   - In a crypto library, this usually represents invalid inputs, decoding/encoding failures, protocol-state mismatches, or confirmation failures.
   - It forms the boundary for how the library reports recoverable issues to callers without exposing internals.

9. **Cryptographic constraints and assumptions**
   - The implementation is fixed to **Ristretto255 + SHA-512**, which simplifies the architecture by removing algorithm selection at runtime.
   - That hardcoding means the protocol code can rely on a specific group abstraction and avoid unsafe low-level input handling from network attackers.
   - The diagram should reflect this as a **fixed crypto backend**, not a pluggable one.

10. **External dependencies and system boundaries**
   - There is no evidence of networking, storage, UI, or async runtime integration in this repo.
   - The external surface is the Rust consumer of the library; everything else is internal protocol machinery.
   - The included Cure53 audit PDF is documentation/assurance material, not part of execution flow.

11. **How to draw it**
   - Show one outer box: **Rust application / consumer**.
   - Inside the crate, show a **public CPace API** in `lib.rs`, feeding into helper layers:
     - input formatting/domain separation
     - encoding/decoding of protocol values
     - key derivation and confirmation
     - error handling
   - Annotate the cryptographic core with **Ristretto255 + SHA-512**, and the protocol outcome as **shared session key + confirmation success**.

Main entry points: [`src/lib.rs`](https://github.com/1password/cpace/blob/main/src/lib.rs) (CPace API), [`src/keys.rs`](https://github.com/1password/cpace/blob/main/src/keys.rs) (Key schedule), [`src/encoding.rs`](https://github.com/1password/cpace/blob/main/src/encoding.rs) (Encoding), [`src/errors.rs`](https://github.com/1password/cpace/blob/main/src/errors.rs) (Errors)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_external["External"]
  node_consumer["Rust consumer<br/>external"]
  node_inputs["Protocol inputs<br/>secret + context"]
end

subgraph group_crate["cpace crate"]
  node_lib["CPace API<br/>façade<br/>[lib.rs]"]
  node_formatting["Formatting<br/>domain separation<br/>[formatting.rs]"]
  node_encoding["Encoding<br/>serialization<br/>[encoding.rs]"]
  node_keys{{"Key schedule<br/>key confirmation<br/>[keys.rs]"}}
  node_errors["Errors<br/>failure model<br/>[errors.rs]"]
  node_backend[("Ristretto255 + SHA-512<br/>fixed crypto backend")]
  node_exchange(("CPace exchange<br/>balanced PAKE"))
  node_session(("Session key<br/>derived secret"))
  node_confirmation(("Confirm result<br/>mutual proof"))
end

node_consumer -->|"calls"| node_lib
node_inputs -->|"provides"| node_lib
node_lib -->|"normalizes"| node_formatting
node_lib -->|"encodes"| node_encoding
node_lib -->|"drives"| node_keys
node_lib -->|"reports"| node_errors
node_formatting -->|"feeds"| node_encoding
node_encoding -->|"prepares"| node_exchange
node_backend -->|"powers"| node_exchange
node_exchange -->|"derives"| node_session
node_session -->|"confirms"| node_keys
node_keys -->|"verifies"| node_confirmation
node_exchange -->|"fails"| node_errors
node_keys -->|"fails"| node_errors
node_confirmation -->|"returns"| node_consumer

click node_lib "https://github.com/1password/cpace/blob/main/src/lib.rs"
click node_formatting "https://github.com/1password/cpace/blob/main/src/formatting.rs"
click node_encoding "https://github.com/1password/cpace/blob/main/src/encoding.rs"
click node_keys "https://github.com/1password/cpace/blob/main/src/keys.rs"
click node_errors "https://github.com/1password/cpace/blob/main/src/errors.rs"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_consumer,node_inputs toneBlue
class node_lib,node_formatting,node_encoding,node_keys,node_errors,node_backend,node_exchange,node_session,node_confirmation toneAmber
```

## Components

### External

Rust application or library consumer

- **Rust consumer**: external · Caller using the CPace library
- **Protocol inputs**: secret + context · Password, identities, and protocol context supplied by the caller

### cpace crate

Internal protocol implementation

- [CPace API](https://github.com/1password/cpace/blob/main/src/lib.rs): façade · Public entry point and protocol boundary · `src/lib.rs`
- [Formatting](https://github.com/1password/cpace/blob/main/src/formatting.rs): domain separation · Normalizes identities, labels, and context into protocol inputs · `src/formatting.rs`
- [Encoding](https://github.com/1password/cpace/blob/main/src/encoding.rs): serialization · Canonical byte encoding and decoding of protocol values · `src/encoding.rs`
- [Key schedule](https://github.com/1password/cpace/blob/main/src/keys.rs): key confirmation · Derives the shared key and confirmation material · `src/keys.rs`
- [Errors](https://github.com/1password/cpace/blob/main/src/errors.rs): failure model · Shared recoverable error types for invalid inputs and protocol failures · `src/errors.rs`
- **Ristretto255 + SHA-512**: fixed crypto backend · Hardcoded group and hash foundation for the protocol
- **CPace exchange**: balanced PAKE · Core protocol round that mixes inputs into a shared secret
- **Session key**: derived secret · Shared key material produced by the protocol
- **Confirm result**: mutual proof · Verification that both sides derived the same session key

## Connections

- Rust consumer → CPace API: calls · Consumer invokes the public CPace API
- Protocol inputs → CPace API: provides · Caller supplies password, identities, and context
- CPace API → Formatting: normalizes · API passes protocol context into transcript construction
- CPace API → Encoding: encodes · API routes protocol values through canonical byte handling
- CPace API → Key schedule: drives · API coordinates key derivation and confirmation
- CPace API → Errors: reports · API surfaces recoverable failures through the crate error model
- Formatting → Encoding: feeds · Formatted transcript material becomes encoded protocol data
- Encoding → CPace exchange: prepares · Encoded values are consumed by the core exchange
- Ristretto255 + SHA-512 → CPace exchange: powers · Fixed Ristretto255 + SHA-512 backend underpins the PAKE computation
- CPace exchange → Session key: derives · The balanced PAKE round yields shared session key material
- Session key → Key schedule: confirms · Derived key is used for mutual confirmation
- Key schedule → Confirm result: verifies · Key confirmation success proves agreement
- CPace exchange → Errors: fails · Protocol and decoding failures are mapped to crate errors
- Key schedule → Errors: fails · Confirmation mismatches and key schedule issues become errors
- Confirm result → Rust consumer: returns · Successful completion is observed by the caller
