Skip to content

Bound the foreign-key shielded note scan (unbounded genesis-to-tip scan on hostile unfunded invitation keys) #4306

Description

@bfoss765

Problem

scan_notes_for_foreign_key (packages/rs-platform-wallet/src/wallet/shielded/sync.rs:826 at PR #4204 head 10514c366) — the L2-invitation claim path's transient scan — streams the on-chain shielded note set from position 0 with no cap (sync_shielded_notes_stream(sdk, &prepared, 0, None)). The only early exit is value coverage (total >= stop_at_value), which a syntactically valid but unfunded invitation key never triggers: one hostile invite forces a genesis-to-tip proof-verify + trial-decrypt scan of the complete shielded history.

The caller's birth-height hint cannot bound this today and is advisory-only (logged at operations.rs:1637): shielded notes are indexed by tree position and the tree exposes no height→position oracle — a chunk's block_height is the proof-tip height, not a per-note inclusion height — so the hint cannot seed the scan start.

Raised as a review suggestion on #4204: #4204 (comment)

Chosen direction

Authenticated funding position carried in the invite payload — a wire-format change to the invitation, which should ride the #4301 two-note invite format change (the natural vehicle for revising the invite payload).

A local scan budget was considered and rejected as the primary fix: a mis-sized bound turns a deep-funded legitimate invite unclaimable, and a caller-supplied birth height is attacker-controlled, so neither bounds hostile input soundly. (A resumable per-attempt scan budget with a typed "budget exhausted, resume to continue" outcome remains a possible interim guard if one is wanted before the wire-format change lands.)

Interim exposure

Bounded operationally rather than in-protocol for now:

  • The claim scan is invitee-initiated — an attacker with a hostile invite burns the accepting device's bandwidth/CPU, not the network's.
  • The Kotlin host surfaces the claim as a cancellable long-running operation, so a runaway scan is user-abortable.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions