# Julia-DID Chialisp Code Reference

This document is a reference for the shipped Chialisp source. For the protocol-level design, see **[did:julia Technical Specification (Doc #15)](https://not.bot/technology/did-julia-specification/)**.

**Repository:** [julia-social/julia_did_chialisp](https://github.com/julia-social/julia_did_chialisp)

The Chialisp tree contains 27 production/build puzzle files (`.clsp`), 10 shared library files (`.clib`), two precompiled Chia singleton hex files, and a Makefile.

All source paths below are relative to the repository root.

---

## 1. Codebase Organization

### 1.1 Build Order

The repository includes a Makefile that builds the puzzles in the correct order. This matters because many puzzles embed compiled hashes of other puzzles with `embed-file`; a parent puzzle cannot be compiled until the child puzzle hashes it embeds already exist.

That is the only build rule this reference relies on: use the Makefile rather than compiling files by hand in arbitrary order.

### 1.2 How DID Spends Route

The main DID singleton puzzle, `julia_did.clsp`, is the first puzzle run for a DID spend. After checking the DID state hash and lineage, it routes to one of seven top-level entrypoints:

| Entrypoint | Route type | What it does |
|------------|------------|--------------|
| `singlesig.clsp` | Normal authentication | Authenticates one key, then calls an allowed operation |
| `multisig.clsp` | Normal authentication | Authenticates a multi-class signer set, then calls an allowed operation |
| `custody_minion.clsp` | Normal authentication by custodian DID | Requires a custodian DID command, then calls an allowed operation |
| `recovery_initiate.clsp` | Direct recovery entrypoint | Starts a pending assisted recovery |
| `recovery_cancel.clsp` | Direct recovery entrypoint | Cancels a pending assisted recovery |
| `recovery_complete.clsp` | Direct recovery entrypoint | Completes an assisted recovery |
| `recovery_prerotation.clsp` | Direct recovery entrypoint | Switches to pre-rotated keys |

Normal authentication entrypoints can call two kinds of child operations:

- combineable operations, which can continue to another child puzzle
- standalone operations, which perform one action and stop

### 1.3 Combineable Operations

The combineable operations have a required invocation order:

```text
sign_message
  -> coin_control
    -> invalidate
      -> DIDdoc_announce
        -> pass_thru
          -> present_delegated
            -> present_claims
```

Any combineable operation can be skipped. For example, authenticated callers can call `present_claims` directly; `sign_message` can call `present_claims` directly; `DIDdoc_announce` can call `present_delegated` directly. The chain above shows the order when all combineable operations are used together.

Each wrapper prepends its own conditions before passing through child conditions:

| Puzzle | Adds |
|--------|------|
| `sign_message.clsp` | signed-message, timestamp, and nonce announcements |
| `coin_control.clsp` | `JDIDP` command messages to other coins |
| `invalidate.clsp` | impossible spend condition and optional time bounds |
| `DIDdoc_announce.clsp` | DID document pointer announcement |
| `pass_thru.clsp` | guarded arbitrary caller-supplied conditions |
| `present_delegated.clsp` | delegated-claim assertions and presentation announcement |
| `present_claims.clsp` | direct credential presentation announcements and claim validation conditions |

### 1.4 Standalone DID Operations

These operations are called individually by an authentication entrypoint and do not continue into the wrapper chain.

| Puzzle | Allowed caller | Purpose |
|--------|----------------|---------|
| `custodian.clsp` | `singlesig`, `multisig` | Sends a command from a custodian DID to a minion DID |
| `DIDdoc_set.clsp` | `singlesig`, `multisig`, `custody_minion` | Updates the DID Document pointer |
| `issuer_key_control.clsp` | `singlesig`, `multisig`, `custody_minion` | Sends revocation-update or melt commands to issuer key singletons |
| `launch_issuer_key.clsp` | `singlesig`, `multisig`, `custody_minion` | Launches issuer key singletons |
| `rekey.clsp` | `singlesig`, `multisig` | Replaces the DID authentication configuration |
| `recovery_authorize.clsp` | `singlesig`, `multisig` | Sends a recovery initiation or cancellation authorization message from a recovery-agent DID |

### 1.5 Recovery Paths

Recovery has two distinct call patterns. Four recovery puzzles are direct entrypoints selected by `julia_did.clsp`, bypassing normal authentication. `recovery_authorize.clsp` is different: it is a standalone operation called by the recovery-agent DID through `singlesig` or `multisig`.

| Recovery puzzle | Called by | Requires | Effect |
|-----------------|-----------|----------|--------|
| `recovery_initiate.clsp` | `julia_did` directly | Recovery-agent quorum messages and no active recovery | Starts pending recovery and records replacement state |
| `recovery_cancel.clsp` | `julia_did` directly | Recovery-agent quorum messages and active recovery | Clears pending recovery |
| `recovery_complete.clsp` | `julia_did` directly | Active recovery and elapsed relative height | Applies replacement state; anyone can complete once mature |
| `recovery_prerotation.clsp` | `julia_did` directly | Signatures from pre-rotated keys | Switches to pre-rotated keys and commits the next prerotation |
| `recovery_authorize.clsp` | `singlesig` or `multisig` | Current control of a recovery-agent DID | Sends an initiation or cancellation authorization message to another DID |

### 1.6 Issuer Key and Companion Coin Interactions

Issuer key singletons are separate from the DID singleton:

- `launch_issuer_key.clsp` is a DID operation that creates issuer key singleton launchers.
- `issuer_key.clsp` is the issuer key singleton puzzle.
- `issuer_key_functions.clsp` implements issuer key management modes for revocation updates and melt.
- `issuer_key_control.clsp` is the DID-side operation that sends commands to issuer key singletons.

Companion coin puzzles are not DID sub-puzzles:

- `p2_JDID.clsp` is used as an inner puzzle for coins controlled by a DID. It spends only when it receives a `JDIDP` command from the owning DID.
- `p2_claim.clsp` is used as an inner puzzle for coins controlled by a qualifying credential presentation and a DID command.
- `faucet_coin.clsp` is an independent faucet puzzle and is not part of the DID call graph.

### 1.7 Common Return Convention

Most sub-puzzles are called with:

```clojure
(curried-args solution)
```

They return:

```clojure
(updated-curried-args conditions)
```

The top-level `julia_did.clsp` consumes that return value, creates the next singleton generation with the updated curried-args hash, and emits the returned conditions. Leaf operations that do not change DID state return the original `curried-args`.

### 1.8 DID Curried Arguments

The DID singleton state is passed through the codebase as `curried-args`:

| Position | Field | Purpose |
|---:|------|---------|
| 1 | `julia-DID-puzzlehash` | Hash of the raw `julia_did.clsp` puzzle |
| 2 | `my-launcher-id` | Permanent DID identifier |
| 3 | `recovery-timeout-block` / `recovery-delay` | `0` when no recovery is pending; nonzero during recovery |
| 4 | `multisig-info` | Authentication tree and class quorum configuration |
| 5 | `valid-custodian-DIDs` | DID launcher IDs authorized as custodians |
| 6 | `recovery-info` | Recovery agent and prerotation configuration |
| 7 | `DID-doc` | DataLayer singleton launcher ID for the DID Document |
| 8 | pending recovery parameters | The proposed `(multisig-info, custodian-DIDs, recovery-info)` triple while a recovery is armed; the empty atom otherwise |

Every state-writing puzzle emits all eight slots. Slot 8 carries the pending triple only between `recovery_initiate` and the `recovery_complete` / `recovery_cancel` / `recovery_prerotation` that clears it, and is the empty atom (`0`, equivalently `()`) the rest of the time — it is never absent. A seven-element list and an eight-element list ending in the empty atom are distinct CLVM trees with distinct hashes, so a driver reconstructing curried args to derive a puzzle hash must emit the eighth slot on every path. Only `recovery_complete` reads it, and only after confirming a recovery is armed.

`julia_did.clsp` and `issuer_key.clsp` are curried with `CURRIED-ARGS-HASH`, not the full state. The full state is revealed in the solution and checked with `sha256tree`.

### 1.9 Chialisp Conventions

- Most files include `*standard-cl-26*`.
- Uppercase names in a `mod` signature are curried parameters; lowercase names are solution parameters.
- `embed-file` imports compiled puzzle hashes, not source.
- Bare `(x <code>)` expressions raise integer errors.
- `AGG_SIG_PUZZLE` and `ASSERT_MY_PUZZLEHASH` are used in normal singleton spends for fast-forward-compatible authorization.
- `ASSERT_MY_PARENT_ID` appears in eve spends, where the launcher relationship is being established.

---

## 2. Puzzle Reference

### 2.1 Top-Level and Companion Puzzles

#### `julia_did.clsp`

Main DID singleton puzzle.

**Mod signature:** `(CURRIED-ARGS-HASH curried-args parent-info solution)`

**State input:** Verifies `CURRIED-ARGS-HASH == sha256tree(curried-args)`.

**Regular spend behavior:**

- Destructures the DID curried args.
- Confirms `launcher-coin-id == my-launcher-id`.
- Computes valid entrypoint hashes for `singlesig`, `multisig`, `custody_minion`, `recovery_initiate`, `recovery_cancel`, `recovery_complete`, and `recovery_prerotation`.
- Runs the selected entrypoint through `puzzle-selector`.
- Emits `ASSERT_MY_PUZZLEHASH`.
- Creates the next DID singleton child with `julia-DID-curried-puzzlehash(julia-DID-puzzlehash, sha256tree(new-curried-args))`.
- Emits `REMARK new-curried-args`.
- Appends child conditions returned by the entrypoint.

**Eve spend behavior:**

- Asserts the singleton launcher as parent with `ASSERT_MY_PARENT_ID`.
- Creates the first DID singleton child.
- Emits `REMARK curried-args`.
- Sends `JDIDL` to the prelauncher coin.

**Errors:** `15` failed lineage proof; `16` invalid curried args hash.

#### `prelauncher.clsp`

Prelauncher for Julia DID coins and root of the fast-forward lineage proof.

**Mod signature:** `(PUBKEY julia-did-puzzlehash my-coin-id did-coin-curried-args-hash)`

**Conditions emitted:**

- `ASSERT_MY_COIN_ID my-coin-id`
- `CREATE_COIN singleton_launcher 1`
- `RECEIVE_MESSAGE 0x3F "JDIDL" did-coin-id`

The puzzle is curried with `PUBKEY`; the remaining values are solution parameters.

#### `p2_JDID.clsp`

Inner puzzle for coins owned by a Julia DID.

**Mod signature:** `(JDID_LAUNCHER_ID JDID-curried-args-hash conditions)`

**Behavior:**

- Computes the owning DID coin puzzle hash from `julia_did.clsp.hash.bin`, the DID launcher ID, and the DID curried-args hash.
- Requires `RECEIVE_MESSAGE 0x17 (concat "JDIDP" (sha256tree conditions)) <owning-DID-puzzlehash>`.
- Emits the supplied `conditions`.

This puzzle does not validate the business meaning of the emitted conditions; it trusts the owning DID's authenticated `coin_control` path.

#### `p2_claim.clsp`

Inner puzzle for coins controlled by possession of a valid credential claim.

**Mod signature:** `(JDID_LAUNCHER_ID my-coin-id spender-launcher-id spender-curried-args-hash conditions)`

**Behavior:**

- Asserts its own coin ID.
- Computes the spender DID puzzle hash.
- Requires an asserted puzzle announcement from the spender DID proving a `JDIDV` claim for the hardcoded payment property `sha256("cleartext://./.julia-payment")`, this coin ID as the claim value, and the payee DID launcher ID as the issuer. Built through the shared payload builder (see [Announcement payload encoding](#announcement-payload-encoding)); because the claim value is this coin's own ID, the presentation that releases this coin cannot release any other.
- Requires `RECEIVE_MESSAGE 0x17 (concat "JDIDP" (sha256tree conditions)) <spender-DID-puzzlehash>`.
- Emits the supplied `conditions`.

#### `faucet_coin.clsp`

Simple faucet coin puzzle used by the Julia Social faucet.

**Mod signature:** `(PUBKEY SERIAL conditions)`

`SERIAL` allows multiple otherwise-identical faucet coins to be created. The puzzle emits the supplied `conditions` only when authorized by:

```clojure
(AGG_SIG_ME PUBKEY (sha256tree conditions))
```

Unlike the DID puzzles, this puzzle uses `AGG_SIG_ME`, binding authorization to the specific coin spend.

---

### 2.2 Authentication Entry Points

#### `singlesig.clsp`

Single-key authentication entrypoint.

**Mod signature:** `(curried-args solution)`

**Solution shape:** `fee-coin`, one pubkey Merkle path, sides, and child puzzle input.

**Validation:**

- DID must require exactly one class.
- Exactly one pubkey path must be supplied.
- The path must validate against `multisig-info`.
- The selected class must require exactly one member.
- Recovery must not be active.

**Conditions added:**

- `AGG_SIG_PUZZLE <pubkey> (sha256tree solution)`
- Optional `ASSERT_CONCURRENT_SPEND fee-coin`

**Allowed children:** `sign_message`, `coin_control`, `custodian`, `DIDdoc_announce`, `DIDdoc_set`, `invalidate`, `issuer_key_control`, `launch_issuer_key`, `pass_thru`, `present_claims`, `present_delegated`, `rekey`, `recovery_authorize`.

**Errors:** `30`, `31`, `32`, `33`, `34`, plus `110` from `puzzle-selector`.

#### `multisig.clsp`

Multi-signer, multi-class authentication entrypoint.

**Mod signature:** `(curried-args solution)`

**Solution shape:** `fee-coin`, participant Merkle paths, path sides, and child puzzle input.

**Validation:**

- Uses `multiclass` to validate participants against `multisig-info`.
- Recovery must not be active.
- Child puzzle hash must be in the allowlist.

**Conditions added:**

- One `AGG_SIG_PUZZLE <pubkey> (sha256tree solution)` per validated participant.
- Optional `ASSERT_CONCURRENT_SPEND fee-coin`.

**Allowed children:** Same as `singlesig.clsp`.

**Errors:** `17`, plus `103`-`106` from `multiclass` and `110` from `puzzle-selector`.

#### `custody_minion.clsp`

Authentication entrypoint for DIDs controlled by an external custodian DID.

**Mod signature:** `(curried-args solution)`

**Solution shape:** custodian DID launcher ID, custodian curried-args hash, and child puzzle input.

**Validation:**

- The custodian DID must appear in `valid-custodian-DIDs`.
- Recovery must not be active.
- Requires `RECEIVE_MESSAGE 0x12 (concat "JDIDC" child-solution-hash) <custodian-DID-puzzlehash>`. Mode `0x12` commits only the two puzzle hashes, so the command is scoped to the two DIDs' states rather than to a coin; replay binding comes from the optional fee coin the commanding custodian's entry point asserts.
- Asserts this minion DID's current puzzle hash.

**Allowed children:** `sign_message`, `coin_control`, `DIDdoc_announce`, `DIDdoc_set`, `invalidate`, `issuer_key_control`, `launch_issuer_key`, `pass_thru`, `present_claims`, `present_delegated`.

**Errors:** `5`, `6`, plus `110` from `puzzle-selector`.

---

### 2.3 DID Operation Puzzles

#### `sign_message.clsp`

Adds DID-signed message announcements, timestamps, and nonces, then optionally delegates.

**Mod signature:** `(curried-args solution)`

**Solution shape:** messages list, datetime, nonce, optional child puzzle input.

**Conditions added:**

- One `CREATE_PUZZLE_ANNOUNCEMENT (concat "JDIDM" message)` per message.
- Optional `CREATE_PUZZLE_ANNOUNCEMENT (concat "JDIDT" datetime)`.
- Optional `CREATE_PUZZLE_ANNOUNCEMENT (concat "JDIDN" nonce)`.

**Allowed children:** `coin_control`, `DIDdoc_announce`, `invalidate`, `pass_thru`, `present_claims`, `present_delegated`.

**Errors:** `110` for invalid child.

#### `coin_control.clsp`

Sends DID-authorized command messages to other coins.

**Mod signature:** `(curried-args solution)`

**Solution shape:** count, `count` pairs of message and coin ID, then optional child puzzle input.

For each pair, emits:

```clojure
(SEND_MESSAGE 0x17 (concat "JDIDP" message) coin-id)
```

The code does not check whether the receiving coin uses `p2_JDID` or `p2_claim`; it only emits the command message.

**Allowed children:** `DIDdoc_announce`, `invalidate`, `pass_thru`, `present_claims`, `present_delegated`.

**Errors:** `110` for invalid child.

#### `invalidate.clsp`

Adds conditions that make a spend bundle unusable on-chain while preserving verifiability.

**Mod signature:** `(curried-args solution)`

**Solution shape:** `invalidate-flag`, `valid-from-seconds`, `valid-to-seconds`, optional child puzzle input.

**Conditions added:**

- If `invalidate-flag` is truthy: `ASSERT_CONCURRENT_SPEND` on the all-zero coin ID.
- If `valid-from-seconds` is set: `ASSERT_SECONDS_ABSOLUTE`.
- If `valid-to-seconds` is set: `ASSERT_BEFORE_SECONDS_ABSOLUTE`.

**Allowed children:** `DIDdoc_announce`, `pass_thru`, `present_claims`, `present_delegated`.

**Errors:** `110` for invalid child.

#### `DIDdoc_announce.clsp`

Announces the DataLayer singleton ID associated with the DID Document.

**Mod signature:** `(curried-args solution)`

**Condition added:**

```clojure
(CREATE_PUZZLE_ANNOUNCEMENT (concat "JDIDD" DID-doc))
```

**Allowed children:** `pass_thru`, `present_claims`, `present_delegated`.

**Errors:** `110` for invalid child.

#### `DIDdoc_set.clsp`

Updates the DID Document pointer.

**Mod signature:** `(curried-args solution)`

**Solution shape:** `new-DID-doc`.

**State change:** Replaces the `DID-doc` field in `curried-args`.

**Conditions added:** none.

#### `pass_thru.clsp`

Allows arbitrary caller-supplied conditions after guarding the `JDID` namespace.

**Mod signature:** `(curried-args solution)`

**Solution shape:** count, `count` conditions, optional child puzzle input.

**Validation:**

- Rejects structured coin/puzzle announcements.
- Rejects coin/puzzle announcements whose byte content starts with `JDID`.
- Rejects structured `SEND_MESSAGE` payloads.
- Rejects `SEND_MESSAGE` payloads whose byte content starts with `JDID`.

**Allowed children:** `present_claims`, `present_delegated`.

**Errors:** `18`, `19`, `20`, `21`, `36`.

#### `custodian.clsp`

Allows a custodian DID to command a custodied DID that uses `custody_minion.clsp`.

**Mod signature:** `(curried-args solution)`

**Solution shape:** minion DID launcher ID, minion curried-args hash, child solution hash.

**Conditions added:**

- `SEND_MESSAGE 0x12 (concat "JDIDC" child-solution-hash) <minion-DID-puzzlehash>`
- `ASSERT_MY_PUZZLEHASH <this-DID-puzzlehash>`

**State change:** none.

#### `rekey.clsp`

Routine key update using current authentication.

**Mod signature:** `(curried-args solution)`

**Solution shape:** `new-multisig-info`.

**State change:** Replaces the `multisig-info` field.

**Conditions added:** none.

---

### 2.4 Recovery Puzzles

#### `recovery_initiate.clsp`

Starts a time-locked recovery by committing pending replacement state.

**Mod signature:** `(curried-args solution)`

**Solution shape:** participant Merkle paths, participant curried-arg hashes, new multisig info, new custodian DID list, new recovery info.

**Validation:**

- Recovery must not already be active.
- Participants must satisfy `recovery-info` via `multiclass`.
- Participant and curried-arg-hash lists must balance.

**State change:**

- Sets `recovery-timeout-block` to the configured recovery delay.
- Appends pending replacement values: new multisig info, new custodian DIDs, and new recovery info.

**Conditions added:** One `RECEIVE_MESSAGE 22 (concat "JDIDR" new-params-hash) <participant-DID-puzzlehash>` per required recovery participant.

**Errors:** `27`, `28`, `29`, plus `multiclass` and Merkle-path errors.

#### `recovery_authorize.clsp`

Run by a recovery participant DID to authorize initiation or cancellation on another DID.

**Mod signature:** `(curried-args solution)`

**Solution shape:** target DID launcher ID, target curried-args hash, `initiate-or-cancel`, `new-params-hash`, `expiration-block`.

**State change:** Appends a trailing `0` marker to its own curried args.

**Conditions added:**

- `SEND_MESSAGE 22 (concat "JDID" initiate-or-cancel new-params-hash) <target-DID-puzzlehash>`
- `ASSERT_BEFORE_HEIGHT_ABSOLUTE expiration-block`

`initiate-or-cancel` must be `"R"` or `"X"`.

**Errors:** `22`.

#### `recovery_cancel.clsp`

Cancels an active recovery.

**Mod signature:** `(curried-args solution)`

**Solution shape:** participant Merkle paths and participant curried-arg hashes.

**Validation:**

- Recovery must be active.
- Participants must satisfy `recovery-info`.
- Participant and curried-arg-hash lists must balance.

**State change:** Resets `recovery-timeout-block` to `0` and removes pending recovery state.

**Conditions added:** One `RECEIVE_MESSAGE 22 "JDIDX" <participant-DID-puzzlehash>` per required recovery participant.

**Errors:** `23`, `24`, `25`, plus `multiclass` and Merkle-path errors.

#### `recovery_complete.clsp`

Completes an active recovery after the delay.

**Mod signature:** `(curried-args solution)`

**Validation:** Recovery must be active.

**State change:** Applies pending `new-multisig-info`, `new-custodian-DIDs`, and `new-recovery-info`; resets recovery delay to `0`.

**Conditions added:** `ASSERT_HEIGHT_RELATIVE recovery-delay`.

Anyone can spend this puzzle once the relative height condition can be satisfied.

**Errors:** `26`.

#### `recovery_prerotation.clsp`

Switches immediately to a pre-committed key configuration and commits the next prerotation.

**Mod signature:** `(curried-args solution)`

**Solution shape:** fee coin, participant Merkle paths, path sides, new prerotation multisig info.

**Validation:** Participants must satisfy the prerotation multisig info stored inside `recovery-info`.

**State change:**

- Replaces `multisig-info` with the previous prerotation multisig info.
- Stores the supplied next prerotation info inside `recovery-info`.
- Cancels any active recovery by setting recovery delay to `0`.

**Conditions added:**

- One `AGG_SIG_PUZZLE <pubkey> (sha256tree solution)` per prerotation signer.
- Optional `ASSERT_CONCURRENT_SPEND fee-coin`.

---

### 2.5 Issuer Key Puzzles

#### `launch_issuer_key.clsp`

Creates issuer key singleton launchers from the owning DID.

**Mod signature:** `(curried-args solution)`

**Solution shape:** DID parent, DID launcher ID, raw issuer-key puzzle hash, followed by one or more issuer key definitions: public key, `valid-from`, `valid-to`, maximum credential expiration, allowed property root, mode-1 payment puzzle hash, mode-1 payment mojos.

**Conditions added per key:**

- `CREATE_COIN singleton_launcher amount`
- `RECEIVE_MESSAGE 0x3F "JDIDI" <issuer-key-coin-id>`

**Additional condition:** `ASSERT_MY_COIN_ID my-coin-id`.

**Implementation note:** Launcher coin amounts increase across multiple launches while issuer key singleton children use amount `1`.

**Error:** `41` if `mode-1-payment-mojos > 1`, blocking free anyone-can-spend payment coins.

#### `issuer_key.clsp`

Issuer key singleton puzzle.

**Mod signature:** `(CURRIED-ARGS-HASH curried-args parent-info spend-mode spend-mode-args)`

**Issuer key curried args:**

1. `issuer-did-launcher-id`
2. `issuer-key-puzzlehash`
3. `julia-did-puzzlehash`
4. `my-launcher-id`
5. `public-key`
6. `revocation-bitfield-root`
7. `valid-from`
8. `valid-to`
9. `max-expiration`
10. `cred-property-hash-root`
11. `mode-1-payment-puzzlehash`
12. `mode-1-payment-mojos`

**Eve spend behavior:**

- `ASSERT_MY_PARENT_ID launcher-coin-id`
- Creates the first issuer key singleton child.
- Emits `REMARK curried-args`.
- Sends `JDIDI` to the issuer DID coin.

**Regular spend behavior:**

- Checks `CURRIED-ARGS-HASH`.
- Verifies launcher lineage.
- Emits `ASSERT_MY_PUZZLEHASH`.
- Mode `1`: recreates the singleton unchanged, emits `REMARK curried-args`, emits `CREATE_PUZZLE_ANNOUNCEMENT "JDIDA"`, and optionally creates the configured payment coin.
- Other modes: require `issuer_key_functions.clsp` as the spend-mode puzzle and delegate to it.

**Errors:** `9`, `10`, `11`, `42`.

#### `issuer_key_functions.clsp`

Management functions for an issuer key singleton.

**Mod signature:** `(curried-args spend-mode spend-mode-args)`

**Mode 2: update revocation by key**

- Verifies current bitfield proof.
- Replaces one bitfield leaf and computes the new root.
- Requires `AGG_SIG_PUZZLE public-key (sha256tree spend-mode-args)`.
- Creates the next issuer key singleton child and emits `REMARK new-curried-args`.
- Optionally asserts a concurrent fee coin.

**Mode 3: update revocation by DID**

- Verifies current bitfield proof.
- Replaces one bitfield leaf and computes the new root.
- Requires `RECEIVE_MESSAGE 0x16 (concat "JDIDK" (sha256tree (list index new-leaf))) <issuer-DID-puzzlehash>`.
- Creates the next issuer key singleton child and emits `REMARK new-curried-args`.

**Mode 5: melt**

- Requires `RECEIVE_MESSAGE 0x16 "JDIDZ" <issuer-DID-puzzlehash>`.
- Emits the Chia singleton melt `CREATE_COIN 0 -113`.

**Errors:** `12`, `13`, `14`.

#### `issuer_key_control.clsp`

DID-side issuer key management operation.

**Mod signature:** `(curried-args solution)`

**Solution shape:** mode, then the target issuer key's launcher ID, curried-args hash and parent coin ID, then any mode-specific values.

**Mode 3:** Emits `SEND_MESSAGE 0x16 (concat "JDIDK" (sha256tree (list index new-leaf))) <issuer-key-parent-coin> <issuer-key-puzzlehash>`.

**Mode 5:** Emits `SEND_MESSAGE 0x16 "JDIDZ" <issuer-key-parent-coin> <issuer-key-puzzlehash>`.

Both modes use `0x16`: the sender's puzzle hash plus the receiver's parent and puzzle hash. Naming the target key's parent confines an authorization to one key coin, so one that is signed but not submitted cannot be submitted later against a generation whose state happens to match.

**State change:** none.

**Error:** `35` for invalid mode.

---

### 2.6 Credential Presentation Puzzles

#### `present_claims.clsp`

Validates and presents credential claims.

**Mod signature:** `(curried-args solution)`

**Solution shape:** nonce plus claims-with-proofs.

**Behavior:**

- Emits `CREATE_PUZZLE_ANNOUNCEMENT (concat "JDIDN" nonce)`.
- Calls `validate-claims` with this DID launcher ID, the raw `julia_did` puzzle hash, the raw `issuer_key` puzzle hash, and the supplied claims-with-proofs.
- Returns unchanged `curried-args`.

See `include/validate_claims.clib` for per-claim validation details.

#### `present_delegated.clsp`

Presents claims delegated through one or more DID holders.

**Mod signature:** `(curried-args solution)`

**Solution shape:** count, delegation paths, optional `present_claims` child input.

**Behavior:**

- Asserts the original claim's holder/delegation announcement.
- Walks each delegation path.
- Requires the terminal delegatee to be this DID.
- Emits the JDIDV verification signal (see [Announcement payload encoding](#announcement-payload-encoding)) for delegated presentation as subject.
- Optionally runs `present_claims.clsp` as a child to present original claims in the same spend.

**Errors:** `37`, `38`, `39`.

---

## 3. Library Reference

### `include/sha256tree.clib`

Recursive CLVM tree hash implementation:

- Atom: `sha256(1, atom)`
- Pair: `sha256(2, sha256tree(left), sha256tree(right))`

### `include/condition_codes.clib`

Defines Chia condition constants used throughout the codebase, including signature, coin creation, announcements, messaging, self-inspection, relative/absolute time assertions, and `REMARK`.

### `include/curry_and_treehash.clib`

Computes the puzzle hash of a curried function without performing the curry. Used by `did_puzzles.clib` to reconstruct expected DID and issuer key puzzle hashes inside other puzzles.

### `include/did_puzzles.clib`

Puzzle hash helpers:

- `prelauncher-coin-puzzlehash`
- `issuer-key-curried-puzzlehash`
- `issuer-key-coin-puzzlehash`
- `julia-DID-curried-puzzlehash`
- `julia-DID-coin-puzzlehash`

Embeds the standard singleton top layer and singleton launcher hashes.

### `include/puzzle_selector.clib`

Generic allowlist router. It compares a supplied puzzle hash against valid hashes and executes the puzzle if matched. Raises `110` when no match is found.

### `include/parse_merkle_path.clib`

Validates a Merkle path and extracts `(class . leaf)`. Raises `107` for class depth beyond leaf depth, `108` for invalid class depth, and `109` for root mismatch.

### `include/multiclass.clib`

Validates multi-class quorum requirements. It parses participant Merkle paths, verifies class membership, enforces unique participant leaves, and checks that enough classes are satisfied.

Errors: `103`, `104`, `105`, `106`.

### `include/bitfield.clib`

Revocation bitfield utilities:

- `verify-tree`
- `check-bit`
- `set-leaf`

Errors: `100` offset too large, `101` negative offset, `102` invalid tree proof.

### `include/validate_claims.clib`

Credential claim validation logic. For each claim, validates subject/holder mode, issuer DID consistency, public-key consistency, expiration bounds, issuer-key validity period, revocation status, property authorization, and antecedent requirements.

Per valid claim it emits claim/holder announcements, asserts issuer-key liveness via `JDIDA`, adds time-window assertions, and requires `AGG_SIG_UNSAFE` from the issuer key over the claim tree hash.

Error: `112` claim validation failed.

### `include/jdid_announcements.clib`

<a id="announcement-payload-encoding"></a>
The payload builders for the two credential announcement channels. A payload is the five-byte channel prefix followed by a single `sha256tree` over the field list:

| Channel | Payload |
|---|---|
| `JDIDV` — this presenter has this attribute | `concat("JDIDV", sha256tree(list(claim-property-hash, claim-value-hash, issuer-did-launcher-id)))` |
| `JDIDH` — holder / antecedent / delegation link | `concat("JDIDH", sha256tree(list(subject-did-launcher-id, claim-property-hash, claim-value-hash, issuer-did-launcher-id, delegateable)))` |

The tree hash is what makes a field's position structural. No field in either tuple is length-constrained anywhere in the corpus — launcher IDs, property and value hashes and the delegateable flag arrive either from an issuer-signed claim or from the presenter's own solution — so a bare concatenation of the same fields would carry no boundaries between them, and a presenter could re-split identical bytes across the fields to satisfy an assertion built for a different tuple. Two field tuples that differ in any field build different payloads regardless of how their bytes would concatenate. Note in particular that `0` is the zero-length atom, so a false `delegateable` flag contributes no bytes to a concatenation.

Every producer of one of these announcements and every consumer that asserts one builds its payload here, so the two cannot disagree about field order or encoding. The test suite carries an independent copy derived from this specification (`tests/common/announcements.clib`), so a divergence between the library and the spec fails a test rather than cancelling out on both sides.

---

## 4. Error Codes

| Code | Source | Meaning |
|------|--------|---------|
| 5 | `custody_minion.clsp` | Custodian DID is not authorized |
| 6 | `custody_minion.clsp` | Recovery is active |
| 9 | `issuer_key.clsp` | Invalid issuer key functions puzzle |
| 10 | `issuer_key.clsp` | Invalid issuer key lineage |
| 11 | `issuer_key.clsp` | Invalid issuer key curried args hash |
| 12 | `issuer_key_functions.clsp` | Invalid bitfield proof in mode 2 |
| 13 | `issuer_key_functions.clsp` | Invalid bitfield proof in mode 3 |
| 14 | `issuer_key_functions.clsp` | Invalid issuer key spend mode |
| 15 | `julia_did.clsp` | Invalid DID lineage |
| 16 | `julia_did.clsp` | Invalid DID curried args hash |
| 17 | `multisig.clsp` | Recovery is active |
| 18 | `pass_thru.clsp` | Structured announcement rejected |
| 19 | `pass_thru.clsp` | `JDID`-prefixed announcement rejected |
| 20 | `pass_thru.clsp` | Structured message rejected |
| 21 | `pass_thru.clsp` | `JDID`-prefixed message rejected |
| 22 | `recovery_authorize.clsp` | Invalid recovery authorize flag |
| 23 | `recovery_cancel.clsp` | Participant/hash list mismatch |
| 24 | `recovery_cancel.clsp` | Participant/hash list mismatch |
| 25 | `recovery_cancel.clsp` | Recovery is not active |
| 26 | `recovery_complete.clsp` | Recovery is not active |
| 27 | `recovery_initiate.clsp` | Participant/hash list mismatch |
| 28 | `recovery_initiate.clsp` | Participant/hash list mismatch |
| 29 | `recovery_initiate.clsp` | Recovery is already active |
| 30 | `singlesig.clsp` | Selected class requires more than one member |
| 31 | `singlesig.clsp` | Selected key class is not valid |
| 32 | `singlesig.clsp` | DID requires more than one class |
| 33 | `singlesig.clsp` | More than one pubkey path supplied |
| 34 | `singlesig.clsp` | Recovery is active |
| 35 | `issuer_key_control.clsp` | Invalid issuer key control mode |
| 36 | `pass_thru.clsp` | Invalid child puzzle |
| 37 | `present_delegated.clsp` | Invalid child puzzle |
| 38 | `present_delegated.clsp` | Terminal delegatee is not this DID |
| 39 | `present_delegated.clsp` | Claim not found in delegation list |
| 41 | `launch_issuer_key.clsp` | Free anyone-can-spend payment coin rejected |
| 42 | `issuer_key.clsp` | Odd singleton child amount rejected |
| 100 | `bitfield.clib` | Bit offset exceeds `0x01FF` |
| 101 | `bitfield.clib` | Negative bit offset |
| 102 | `bitfield.clib` | Invalid bitfield tree proof |
| 103 | `multiclass.clib` | Participant class is not valid |
| 104 | `multiclass.clib` | Class quorum requirements not met |
| 105 | `multiclass.clib` | Duplicate participant leaf |
| 106 | `multiclass.clib` | Unreachable. `unique-leaves` returns 1 or aborts with `105`, never a false value, so this raise has no reaching path; `105` is the enforcement of leaf uniqueness |
| 107 | `parse_merkle_path.clib` | Class depth exceeds leaf depth |
| 108 | `parse_merkle_path.clib` | Invalid class depth |
| 109 | `parse_merkle_path.clib` | Merkle root mismatch |
| 110 | Routing helpers | Puzzle hash not in allowed set |
| 112 | `validate_claims.clib` | Claim validation failed |

---

## 5. File Inventory

### 5.1 Production/Build Puzzles

| File | Lines | Category | Summary |
|------|------:|----------|---------|
| `DIDdoc_announce.clsp` | 44 | DID Document | Announces DID Document DataLayer singleton ID |
| `DIDdoc_set.clsp` | 50 | DID Document | Updates DID Document pointer |
| `coin_control.clsp` | 60 | Operations | Sends `JDIDP` commands to controlled coins |
| `custodian.clsp` | 60 | Custody | Sends `JDIDC` commands to minion DIDs |
| `custody_minion.clsp` | 110 | Authentication | Authenticates by custodian DID command |
| `faucet_coin.clsp` | 19 | Faucet | Faucet spend puzzle authorized by `AGG_SIG_ME` |
| `invalidate.clsp` | 76 | Operations | Adds unsatisfiable or time-window conditions |
| `issuer_key.clsp` | 93 | Issuer key | Issuer key singleton |
| `issuer_key_control.clsp` | 80 | Issuer key | DID-side issuer key commands |
| `issuer_key_functions.clsp` | 178 | Issuer key | Issuer key management modes |
| `julia_did.clsp` | 95 | Top-level | Main DID singleton |
| `launch_issuer_key.clsp` | 75 | Issuer key | Launches issuer key singletons |
| `multisig.clsp` | 96 | Authentication | Multi-class multisig authentication |
| `p2_JDID.clsp` | 23 | Companion | Inner puzzle for DID-owned coins |
| `p2_claim.clsp` | 34 | Companion | Inner puzzle for credential-controlled coins |
| `pass_thru.clsp` | 90 | Operations | Guarded arbitrary condition passthrough |
| `prelauncher.clsp` | 30 | Top-level | DID prelauncher |
| `present_claims.clsp` | 30 | Credentials | Direct claim presentation |
| `present_delegated.clsp` | 158 | Credentials | Delegated claim presentation |
| `recovery_authorize.clsp` | 54 | Recovery | Recovery participant authorization token |
| `recovery_cancel.clsp` | 108 | Recovery | Cancels pending recovery |
| `recovery_complete.clsp` | 67 | Recovery | Completes pending recovery |
| `recovery_initiate.clsp` | 127 | Recovery | Starts pending recovery |
| `recovery_prerotation.clsp` | 75 | Recovery | Switches to pre-rotated keys |
| `rekey.clsp` | 43 | Operations | Routine key rotation |
| `sign_message.clsp` | 82 | Operations | DID message/timestamp/nonce announcements |
| `singlesig.clsp` | 117 | Authentication | Single-signer authentication |

### 5.2 Libraries

| File | Lines | Summary |
|------|------:|---------|
| `include/bitfield.clib` | 92 | Revocation bitfield Merkle utilities |
| `include/condition_codes.clib` | 77 | Chia condition constants |
| `include/curry_and_treehash.clib` | 68 | Curried puzzle hash computation |
| `include/did_puzzles.clib` | 46 | DID and issuer key puzzle hash helpers |
| `include/jdid_announcements.clib` | 33 | JDIDV / JDIDH announcement payload builders |
| `include/multiclass.clib` | 141 | Multi-class quorum validation |
| `include/parse_merkle_path.clib` | 66 | Merkle path parsing and class extraction |
| `include/puzzle_selector.clib` | 28 | Hash allowlist router |
| `include/sha256tree.clib` | 10 | CLVM tree hash |
| `include/validate_claims.clib` | 188 | Claim validation |

### 5.3 Other Build Files

| File | Summary |
|------|---------|
| `singleton_launcher.clsp.hex` | Precompiled Chia singleton launcher |
| `singleton_top_layer_v1_1.clsp.hex` | Precompiled Chia singleton top layer |
| `Makefile` | Build and test orchestration |
