Skip to content

fix(core): allocate NUT-20 mint-quote derivation indexes atomically #404

Description

@igbopharaoh

Context

Follow-up to #365 and #400.

Source TODO:
https://github.com/cashubtc/coco/pull/400/changes#diff-0103091746c9015f4fece02e671808fd1f9b50c0981611512e59e7f2289d9949R44

KeyRingService.generateKeyPairForPurpose() currently reads the last persisted
derivation index, increments it in memory, derives the key, and then persists
the result.

Problem

Concurrent calls can read the same last derivation index before either call
persists its key. Both calls may consequently derive and return the same
NUT-20 key.

NUT-20 mint-quote ownership requires a fresh key for every quote. Reusing a key
also weakens quote isolation and makes concurrent locked-quote creation
dependent on process-local timing.

This invariant belongs in the upstream key-allocation service and repository
contract rather than in MintBolt11Handler.

Scope

  • Add an atomic way to reserve the next derivation index for a key purpose.
  • Use that allocation path when generating NUT-20 mint-quote keys.
  • Preserve separate derivation sequences for each KeypairPurpose.
  • Ensure an allocated index cannot later be assigned to another key.
  • Update the relevant repository implementations and contract tests.
  • Document whether gaps left by interrupted or failed generation are expected.

Acceptance criteria

  • Concurrent NUT-20 key-generation calls always receive distinct derivation indexes.
  • Concurrent calls always return distinct public keys.
  • Allocation is atomic at the persistence boundary and does not rely only on a process-local lock.
  • Derivation indexes remain isolated by key purpose.
  • A reserved index is never reassigned after a failure; intentional gaps are permitted.
  • Existing deterministic derivation and key-recovery behavior remains compatible.
  • Tests exercise concurrent allocation and failure behavior for every applicable repository.

Out of scope

  • Refactoring MintBolt11Handler to coordinate key allocation itself.
  • Changing the NUT-20 signing or quote-redemption flow.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    In Progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions