Commit e4a8734
authored
feat(tbtc/signer): Phase 7.1 hardened interactive signing session (#4051)
## What
Phase 7.1 of the frozen spec
([#4049](#4049),
`docs/phase-7-interactive-session-spec-freeze.md` §§4–5): the engine
session layer for the interactive two-round signing path, with
**engine-held nonce custody** as the defining property.
## The custody contract (spec §4)
- Round-1 nonces: OS randomness, in-memory only, bound to `(session_id,
attempt_id)`, zeroized on consumption/abort/expiry/replacement,
**never** in any request, response, or persisted state.
- **Consumption-before-release**: the durable per-attempt marker
persists BEFORE the share leaves the engine. Persist failure → marker
rolled back, nonces stay live, no share escaped (pinned by a
persist-fault-injection test). Marker-without-share → attempt dead, fail
closed.
- Restart can never yield a second share under one nonce pair; the
cloned-state nonce-reuse class is structurally eliminated. Pinned by a
restart test: the marker survives reload and rejects the consumed
attempt at every entry point while a fresh attempt proceeds.
## The API (spec §5, strict-mode only)
| Call | Contract highlights |
|---|---|
| `InteractiveSessionOpen` | Key package once per session (validated
against member); idempotent by fingerprint; conflicting reopen fails
closed; **newer attempt implicitly aborts the prior live one**; consumed
attempts rejected |
| `InteractiveRound1` | Fresh nonces + commitments; idempotent until
consumed |
| `InteractiveRound2` | **All verification precedes consumption**:
message binding, subset ⊆ included set, exactly-`t` size, own
membership, and check (f) — own-commitment byte-identity, defeating
coordinator framing of honest members |
| `InteractiveSessionAbort` | Idempotent; destroys nonces without a
marker (never-consumed attempts may reopen with fresh nonces) |
Live-state bounds per the spec: fail-closed capacity cap
(`TBTC_SIGNER_MAX_LIVE_INTERACTIVE_SESSIONS`, default 64) + lazy TTL
sweep with abort semantics
(`TBTC_SIGNER_INTERACTIVE_SESSION_TTL_SECONDS`, default 3600); both
knobs ride the init-config surface. New structured error
`consumed_nonce_replay`. Telemetry: call/success counters ×4, latency
for the two cryptographic rounds.
The four `frost_tbtc_interactive_*` FFI exports ship additively per the
established pattern (Go adoption is Phase 7.3; nothing breaks until the
host calls them).
## Verification
- **10 engine tests**: e2e round trip with one member through the
session API and one through the stateless primitive, aggregating to a
**verified BIP-340 signature** (custody changed, cryptography didn't);
framing-attack rejection then honest-package acceptance
(verify-before-consume); package-shape rejections (outside-set, message
mismatch, oversized, self-missing); round-1 idempotency → consumed
replay; restart-marker durability; persist-fault rollback; open
lifecycle (idempotent/conflict/replacement); abort; TTL expiry; capacity
fail-closed.
- **1 FFI dispatch smoke test** across all four exports.
- Full suite **255 passed / 1 ignored** (baseline 244+1 plus the 11
new), `clippy -D warnings` clean on all targets incl. the bench shape,
**Phase 5 chaos suite green**, persisted-state schema additive (existing
state files load unchanged).
## Scope boundary
`InteractiveAggregate` + package-envelope evidence + cross-language
vectors are Phase 7.2 by the frozen phasing; Go orchestration is 7.3.
Out of scope per the freeze: DKG secret-package custody (named
follow-up).
🤖 Generated with [Claude Code](https://claude.com/claude-code)13 files changed
Lines changed: 2900 additions & 14 deletions
File tree
- pkg/tbtc/signer
- docs
- include
- src
- engine
Lines changed: 11 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
145 | 145 | | |
146 | 146 | | |
147 | 147 | | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
148 | 159 | | |
149 | 160 | | |
150 | 161 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
57 | 57 | | |
58 | 58 | | |
59 | 59 | | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
60 | 76 | | |
61 | 77 | | |
62 | 78 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
146 | 146 | | |
147 | 147 | | |
148 | 148 | | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
149 | 230 | | |
150 | 231 | | |
151 | 232 | | |
| |||
521 | 602 | | |
522 | 603 | | |
523 | 604 | | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
524 | 629 | | |
525 | 630 | | |
526 | 631 | | |
| |||
565 | 670 | | |
566 | 671 | | |
567 | 672 | | |
| 673 | + | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
568 | 677 | | |
569 | 678 | | |
570 | 679 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
54 | 68 | | |
55 | 69 | | |
56 | 70 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
267 | 267 | | |
268 | 268 | | |
269 | 269 | | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
270 | 280 | | |
271 | 281 | | |
272 | 282 | | |
| |||
0 commit comments