# filosottile/cpace architecture

> Architecture diagram of the GitHub repository filosottile/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/filosottile/cpace
- Repository: https://github.com/filosottile/cpace

## Overview

1. **Repository shape**
   - This is a very small Go library, not an application.
   - The codebase is centered on a single package, `filippo.io/cpace`, with one implementation file and one test file.
   - There is no server, CLI, database, or external service boundary.

2. **Primary responsibility**
   - The package implements the **CPace password-authenticated key exchange (PAKE)**.
   - It produces a shared session key between two peers who know the same password, while binding the exchange to identities and optional associated data.

3. **Cryptographic core**
   - The implementation is instantiated over **ristretto255**, a prime-order group.
   - That choice simplifies the protocol implementation because it avoids cofactor handling, twist checks, and many low-level curve edge cases.
   - The package also uses **HKDF** and **HMAC** to separate password material, salt, and context cleanly.

4. **Key inputs**
   - The core inputs are:
     - the shared password,
     - initiator identity `idA`,
     - responder identity `idB`,
     - optional associated data `ad`.
   - These are combined into a context string (`ci`) used throughout the exchange.

5. **Context binding boundary**
   - The repository deliberately treats context construction as security-critical.
   - Instead of naive concatenation, it uses structured serialization with length prefixes to avoid ambiguity between different identity pairs.
   - This is one of the important architectural boundaries in the package: it separates application-provided identity/context data from protocol cryptographic state.

6. **Initiator-side flow**
   - The initiator creates a random **salt**.
   - It generates a random scalar `a`.
   - It derives a group element from the password and context, maps it into the group, and computes the first public message `A`.
   - The initiator sends `(salt, A)` to the responder.

7. **Responder-side flow**
   - The responder receives `salt` and `A`.
   - It recomputes the same context `ci`, generates its own random scalar `b`, and computes its public message `B`.
   - It also derives the responder-side shared key material `K_b` from the transcript and the group result.

8. **Key agreement boundary**
   - After the responder sends `B`, the initiator computes its own key material `K_a`.
   - The intended architecture is symmetric at the cryptographic result level: both sides derive the same shared key from the transcript and password.
   - The protocol transcript is part of the key derivation, so the key is bound to the exact exchanged values.

9. **Transcript and session binding**
   - The derived key depends on `salt`, `A`, `B`, and the context.
   - The README explicitly notes that the salt is generated by the initiator and sent to the peer, rather than being caller-supplied.
   - That makes the salt part of the protocol message flow rather than an application-managed parameter.

10. **Security model boundaries**
   - The package is intentionally low-level and does **not** include a higher-level verifier/HMAC confirmation round.
   - The README suggests that a stronger API could wrap this package to prove both peers actually derived the same secret before exposing application data.
   - That means the library currently stops at key agreement, not full authenticated channel establishment.

11. **Known API caveats**
   - The README calls out two possible misuse cases:
     - identities may be empty,
     - the initiator state may be reused with multiple responder messages.
   - These are important diagram annotations because they indicate where the current API leaves security policy to the caller.

12. **Testing and validation**
   - `cpace_test.go` provides package-level tests for the implementation.
   - There are no integration tests with external infrastructure because the repo is fully self-contained cryptographic code.

13. **What to draw in an architecture diagram**
   - Draw a single library boundary around `cpace.go`.
   - Inside it, show:
     - context construction (`idA`, `idB`, `ad` → `ci`),
     - initiator state,
     - responder state,
     - shared cryptographic primitives (ristretto255, HKDF, HMAC, randomness).
   - Outside the boundary, show two peers exchanging `(salt, A)` and `B`, both deriving the same session key from the password and transcript.

Main entry points: [`cpace.go`](https://github.com/filosottile/cpace/blob/main/cpace.go) (cpace.go), [`cpace_test.go`](https://github.com/filosottile/cpace/blob/main/cpace_test.go) (cpace_test.go)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_library["cpace package"]
  node_cpace_pkg["cpace.go<br/>[cpace.go]"]
  node_ctx["Context<br/>binding"]
  node_salt["Salt<br/>protocol input"]
  node_init_state["Initiator state<br/>protocol role"]
  node_resp_state["Responder state<br/>protocol role"]
  node_transcript["Transcript<br/>binding"]
  node_kdf{{"HKDF<br/>primitive"}}
  node_mac{{"HMAC<br/>primitive"}}
  node_group{{"ristretto255<br/>primitive"}}
  node_rand{{"Randomness<br/>primitive"}}
end

node_peer_init(("Initiator<br/>peer"))
node_peer_resp(("Responder<br/>peer"))
node_tests["cpace_test.go<br/>[cpace_test.go]"]

node_peer_init -->|"calls"| node_cpace_pkg
node_peer_resp -->|"calls"| node_cpace_pkg
node_ctx -->|"binds"| node_init_state
node_ctx -->|"binds"| node_resp_state
node_rand -->|"creates"| node_salt
node_rand -->|"samples a"| node_init_state
node_rand -->|"samples b"| node_resp_state
node_kdf -->|"derives"| node_init_state
node_kdf -->|"derives"| node_resp_state
node_group -->|"computes A"| node_init_state
node_group -->|"computes B"| node_resp_state
node_init_state -->|"uses"| node_transcript
node_resp_state -->|"uses"| node_transcript
node_transcript -->|"authenticates"| node_mac
node_transcript -->|"stretches"| node_kdf
node_cpace_pkg -->|"validated by"| node_tests
node_peer_init -->|"sends (salt, A)"| node_peer_resp
node_peer_resp -->|"returns B"| node_peer_init

click node_cpace_pkg "https://github.com/filosottile/cpace/blob/main/cpace.go"
click node_tests "https://github.com/filosottile/cpace/blob/main/cpace_test.go"

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_cpace_pkg,node_ctx,node_salt,node_init_state,node_resp_state,node_transcript,node_kdf,node_mac,node_group,node_rand toneBlue
class node_peer_init,node_peer_resp,node_tests toneNeutral
```

## Components

### cpace package

Single Go library boundary implementing the CPace PAKE.

- [cpace.go](https://github.com/filosottile/cpace/blob/main/cpace.go): package · Main implementation of the CPace protocol. · `cpace.go`
- **Context**: binding · Structured serialization of idA, idB, and associated data into ci.
- **Salt**: protocol input · Initiator-generated salt carried in the first message.
- **Initiator state**: protocol role · Derives A from password, context, random scalar, and salt.
- **Responder state**: protocol role · Derives B and shared key material from transcript and password.
- **Transcript**: binding · Binds salt, A, B, and context into the final key derivation.
- **HKDF**: primitive · Separates password material, salt, and context into protocol inputs.
- **HMAC**: primitive · Used for keyed transcript and secret derivation.
- **ristretto255**: primitive · Prime-order group used for CPace scalar and point operations.
- **Randomness**: primitive · Sources the salt and ephemeral scalars a and b.

### Other components

- **Initiator**: peer · Peer that starts the exchange and sends the first message.
- **Responder**: peer · Peer that receives the first message and returns the response.
- [cpace_test.go](https://github.com/filosottile/cpace/blob/main/cpace_test.go): test · Package-level tests for the protocol implementation. · `cpace_test.go`

## Connections

- Initiator → cpace.go: calls · Initiator uses the package API to start the exchange.
- Responder → cpace.go: calls · Responder uses the package API to complete the exchange.
- Context → Initiator state: binds · Context is incorporated before initiator message generation.
- Context → Responder state: binds · Context is recomputed on the responder side.
- Randomness → Salt: creates · Initiator generates the protocol salt.
- Randomness → Initiator state: samples a · Initiator draws ephemeral scalar a.
- Randomness → Responder state: samples b · Responder draws ephemeral scalar b.
- HKDF → Initiator state: derives · Password and context are turned into protocol input material.
- HKDF → Responder state: derives · Responder derives matching input material from the shared password and salt.
- ristretto255 → Initiator state: computes A · Initiator maps password-derived material into a group element and forms A.
- ristretto255 → Responder state: computes B · Responder computes its public message B.
- Initiator state → Transcript: uses · Initiator later folds the transcript into key material Ka.
- Responder state → Transcript: uses · Responder folds the transcript into key material Kb.
- Transcript → HMAC: authenticates · Transcript binding uses keyed MAC construction.
- Transcript → HKDF: stretches · Key derivation separates the final shared key from protocol inputs.
- cpace.go → cpace_test.go: validated by · Tests exercise the package-level implementation.
- Initiator → Responder: sends (salt, A) · Initiator sends the first protocol message.
- Responder → Initiator: returns B · Responder sends the second protocol message.
