Skip to content

fix(platform-wallet)!: check identity creation keys and funding in the Rust core - #5645

Open
Claudius-Maginificent wants to merge 12 commits into
v5.1-devfrom
fix/platform-wallet-dip11-identity-key-layout
Open

Claudius-Maginificent wants to merge 12 commits into
v5.1-devfrom
fix/platform-wallet-dip11-identity-key-layout

Conversation

@Claudius-Maginificent

@Claudius-Maginificent Claudius-Maginificent commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

TL;DR

The wallet's Rust core now decides which keys a new identity gets and how much it must be funded with. Before anything is signed or broadcast, it checks that the key set can create a working identity and that the asset lock can pay for it. New identities get the same keys they get today. Existing identities and interrupted registrations keep working.

This PR can land on its own. The current Swift and Kotlin apps already send key sets that pass the new check. The stacked PR #5647 then moves the layout and minimum-funding rules out of the apps and into Rust.

User story

As a wallet user, I want the wallet to refuse an identity it can't create before it locks my DASH, so that I'm not left with a stuck registration or an identity that can't sign the actions I need.

Scenario

Base flow

  1. The user creates an identity from the wallet, funded from the wallet balance or from an existing asset lock.
  2. The app supplies the keys and the funding amount; the wallet registers the identity.

Actual behavior

  • The Rust core only checks that key 0 is the MASTER authentication key. A key set with no CRITICAL key (needed for tokens) or no HIGH key (needed for documents) is registered anyway.
  • Nothing checks that the funding covers the key set before the lock is built. Resuming a tracked lock that is too small for its keys waits for finality and is only then rejected by Platform.
  • A disabled key in the set is silently registered as enabled.

Expected behavior

  • The Rust core owns the creation key layout and the minimum funding. The minimum comes from the versioned fee schedule.
  • A registration is refused before any asset lock is built, waited on or signed when:
    • the key set lacks an AUTHENTICATION key at MASTER, CRITICAL or HIGH;
    • key 0 is not MASTER;
    • any key is disabled;
    • Platform's structure rules for a new identity would refuse the keys (too many keys, a second MASTER key, the same key data twice, a purpose at a level it may not have, a hash key whose data is not a hash);
    • the funding is below the minimum for the keys.
  • Existing identities load, sync, sign and recover exactly as before, including the HASH160 identities created by Dash Evo Tool.

Detailed discussion

Layout (rs-platform-wallet wallet/identity/network/creation_keys.rs; every key is ECDSA_SECP256K1 with key id = DIP-9 key index). These are the keys the v5.1-dev hosts register today, unchanged:

id NewIdentity NewIdentityWithDashPayKeys
0 AUTH MASTER AUTH MASTER
1 AUTH CRITICAL AUTH CRITICAL
2 AUTH HIGH AUTH HIGH
3 TRANSFER CRITICAL TRANSFER CRITICAL
4 – ENC MEDIUM (DashPay contactRequest)
5 – DEC MEDIUM (DashPay contactRequest)

No AUTHENTICATION/MEDIUM key. DIP-11 asks for an authentication key at every level, MEDIUM included. We leave MEDIUM out:

  • max_public_keys_in_creation is 6 in every protocol version, and the DashPay layout already uses all six slots. A MEDIUM key would have made 7, which consensus refuses.
  • No system contract accepts a MEDIUM signature; they all require HIGH. The key would have no use.
  • Consensus is not changed.

The constant REQUIRED_AUTHENTICATION_LEVELS carries a comment explaining this.

Pre-flight. IdentityWallet::identity_creation_keys builds the validated key set, and every identity-creating entry point takes it instead of a raw key map. It requires:

  • an AUTHENTICATION key at each of MASTER, CRITICAL and HIGH;
  • key 0 to be MASTER;
  • each key stored under its own id;
  • no disabled key. A key in creation carries no disabled state, so a disabled key would be registered as enabled.

It then runs dpp's validate_identity_public_keys_structure at the wallet SDK's current protocol version, so no consensus rule is copied here and a caller cannot choose another version. An unpinned SDK's version can lag the network until its first proved response. The difference only matters to a host sending a wrong-size hash key or a key-limit violation, which the Swift, Kotlin and Dash Evo Tool key sets do not contain. Key types stay free, so caller-built HASH160 sets pass, provided their data is a 20-byte hash where that version requires it. Secp256k1 key data is left to proof of possession.

Errors are typed (IdentityCreationKeysError). A refusal maps to ErrorInvalidParameter over FFI, and StructureRefused names the consensus reasons. ValidationUnavailable means the validation could not run, which is not the caller's fault, and maps to ErrorUnknown.

Funding floor (register_identity_with_funding). The minimum is calculate_min_required_fee for the actual keys:

  • Wallet-balance funding below the minimum is refused before the lock is built.
  • Drain funding has its floor raised to the minimum.
  • Tracked lock (FromExistingAssetLock, both resume and invitation-voucher reclaim): refused when the persisted amount is below the minimum, before the finality wait or any signing.
  • Untracked lock: no floor check. The funding resolver handles it exactly as on v5.1-dev, where it already refuses an untracked lock. claim_invitation does not go through this path.

Host-facing minimums. identity_creation_min_funding_duffs and identity_creation_from_addresses_min_fees return the minimum for each layout, so the stacked PR can drop the hosts' fee constants.

Consensus check of the layouts. A test runs every layout through dpp's validate_identity_public_keys_structure, which drive-abci applies to asset-lock, address-funded and shielded identity creates. The same test runs the address-funded IdentityCreateFromAddressesTransition::validate_structure. Both run at PlatformVersion::latest(). A control case proves one key over the limit fails with MaxIdentityPublicKeyLimitReached.

FFI in this PR. A minimal shim only: platform-wallet-ffi runs the pre-flight before either signer is touched, and after the wallet handle lookup, because the version comes from the wallet's SDK. An unknown handle therefore returns NotFound ahead of a key-set fault; on the shielded path an unknown wallet or a manager without shielded configured returns ErrorWalletOperation first. The host-facing layout and minimum queries are in #5647.

Placement follows layer-ownership: the decision lives in rs-platform-wallet, and the bindings only marshal.

Breaking Changes

  • register_identity_with_funding, register_from_addresses, claim_invitation and shielded_identity_create_from_pool take IdentityCreationKeys instead of a raw key map. Dash Evo Tool stops compiling on its next platform bump. It must build its key set with wallet.identity().identity_creation_keys(keys). Its current HASH160 key set passes unchanged.
  • IdentityCreationKeysError gains StructureRefused and ValidationUnavailable, and no longer derives Clone, PartialEq or Eq.
  • wallet::shielded::operations::identity_create_from_shielded_pool is pub(crate); use IdentityWallet, which takes the validated key set.
  • New PlatformWalletError::IdentityCreationKeys variant.
  • Behavior changes:
    • A key set without MASTER, CRITICAL and HIGH authentication keys, with a disabled key, or failing dpp's structure rules is refused (ErrorInvalidParameter).
    • An asset lock below the minimum for its keys is refused before signing (ErrorAssetLockInsufficientFunds).
    • Platform would reject both anyway; the current Swift and Kotlin apps already meet both rules.

Testing

New Rust tests cover:

  • the layout table;
  • the pre-flight: every missing level, stronger keys and transfer keys not counting, disabled keys, key-0 and structure errors;
  • the structure rules: over the limit, duplicate data, two MASTER keys, an invalid purpose or level, an invalid hash size, validation at the wallet's protocol version, and the consensus reason in the refusal;
  • that both layouts and Dash Evo Tool's real default key set (20-byte HASH160 keys plus the DashPay pair) still pass;
  • the funding floor for wallet, drain, resume and reclaim funding, including the untracked pass-through;
  • end-to-end refusals through register_identity_with_funding for fresh and resumed funding, before any signer is reached;
  • the dpp creation-structure check of every layout (should_pass_dpp_creation_structure_validation_for_every_layout);
  • FFI pre-flight wiring: each entry point refuses such a key set on a live wallet handle with dangling signers, so reaching a signer would crash the test.

Verification:

  • cargo clippy -p platform-wallet -p platform-wallet-ffi -p rs-unified-sdk-jni --all-targets --features platform-wallet-ffi/shielded -- -D warnings is clean.
  • cargo nextest run -p platform-wallet -p platform-wallet-ffi --features platform-wallet-ffi/shielded: 2297 passed, 8 skipped.
  • A mutation check confirms the dpp-structure test fails when a 7th key is added to the DashPay layout.

Swift and Kotlin were not built locally (no Xcode or JDK on the build host). This PR does not touch them.

Checklist

  • I have performed a self-review of my own code
  • My Rust, FFI, WASM, Swift or Kotlin changes follow the coding conventions
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have described breaking changes in the corresponding section if my code contains any

🤖 Generated with Claude Code

https://claude.ai/code/session_01WunYYjpfLux1ByK7fGF7SG

🤖 Co-authored by Claudius the Magnificent AI Agent

PR Hygiene · 5f17b3b

  • Bots — thepastaclaw requested changes — dismiss the review or push a fix
  • Self-review — not asked of a bot author
  • Build green
  • Approvals
    • rs-platform-wallet-ffi (packages/rs-platform-wallet-ffi/src/error.rs, packages/rs-platform-wallet-ffi/src/identity_registration_funded_with_signer.rs, packages/rs-platform-wallet-ffi/src/identity_registration_with_signer.rs and 3 more) — HashEngineering or ZocoLini or llbartekll or romchornyi
    • rs-platform-wallet (packages/rs-platform-wallet/src/error.rs, packages/rs-platform-wallet/src/lib.rs, packages/rs-platform-wallet/src/test_support.rs and 10 more) — HashEngineering or ZocoLini or llbartekll or romchornyi

When every merge requirement is met, the PR Hygiene check passes. Reviewer limits do not block merging; other required GitHub checks and protections still apply.

Summary by CodeRabbit

  • New Features
    • Identity creation supports base and DashPay key layouts, with validation for required authentication keys at MASTER, CRITICAL, and HIGH security levels.
    • Registration funding requirements are calculated for the selected key layout. Wallet-funded and tracked-lock registrations below the minimum are rejected, while drain-account funding is raised to meet the minimum.
  • Bug Fixes
    • Invalid identity-creation keys now return a clear error, and key validation occurs before signing for registration, invitation claims, and shielded identity creation.

lklimek and others added 3 commits October 28, 2026 14:12
…evel

DIP-11 requires a new identity to hold at least one authentication key at
each security level. The wallet registered AUTH keys at MASTER, CRITICAL and
HIGH only, and every host (FFI, Swift, Kotlin) kept its own copy of the slot
table.

rs-platform-wallet now owns the single creation layout
(`IdentityCreationKeyLayout`): AUTH MASTER/CRITICAL/HIGH and TRANSFER
CRITICAL at ids 0-3, the optional DashPay ENC/DEC pair at 4-5, and a new
AUTH/MEDIUM ECDSA_SECP256K1 key at the next free id (4, or 6 with DashPay).
Existing ids and derivation slots do not move. The FFI, the JNI bridge,
Swift and Kotlin read the layout from Rust and only marshal it.

Every identity-creating entry point (asset-lock registration, from
addresses, invitation claim, shielded pool) takes `IdentityCreationKeys`
instead of a raw key map. This pre-flight refuses, with a typed
`IdentityCreationKeysError`, a set that lacks an enabled AUTH key AT
MASTER, CRITICAL, HIGH and MEDIUM. It checks levels and structure, never
key types, so an ECDSA_HASH160 set plus a MEDIUM key passes.

Backward compatibility: the rule applies to new creations only. Discovery,
sync, signing and recovery of existing identities are untouched. The one
exemption is resuming a tracked registration asset lock
(`FromExistingAssetLock { consume_invitation_voucher: false }`) whose
persisted amount cannot pay for the DIP-11 key set at the current platform
version's fee schedule (computed with the versioned
`calculate_min_required_fee`). Such a lock was funded for the four
pre-DIP-11 keys, so it resumes with exactly those, at no extra fee, and the
exemption is logged at info with the outpoint. Rust decides it
(`IdentityWallet::resume_key_layout`, `creation_keys_for_funding`, and the
new `platform_wallet_resume_identity_key_layout` FFI); hosts never compare
amounts. A lock built first and funded for the full set, fresh funding and
invitation reclaims always get the DIP-11 check.

Known gap: an interrupted registration started after this change whose lock
was funded below the 5-key minimum is grandfathered too, since the tracked
lock records no provenance. Follow-up (option A): persist the creation
layout on the tracked lock in every persister (SQLite, SwiftData, Room).

Breaking for callers: `register_identity_with_funding`,
`register_from_addresses`, `claim_invitation` and
`shielded_identity_create_from_pool` take `IdentityCreationKeys`; the
derive/preview FFIs take an `IdentityCreationKeyLayoutFFI` instead of a key
count. Dash Evo Tool stops compiling: it calls
`register_identity_with_funding` with its own key map (no MEDIUM key) and
must add an AUTH/MEDIUM key or adopt `IdentityCreationKeyLayout`, then build
the keys with `IdentityWallet::creation_keys_for_funding`.

Swift and Kotlin changes are unbuilt (no Xcode or JDK on the build host).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he exact legacy resume keys

`register_identity_with_funding` now refuses a `FromWalletBalance` amount
below the versioned minimum for its keys (`AssetLockInsufficientFunds`)
before any lock is built or broadcast, and raises a drain's floor to it,
mirroring the address-funding floor. A fresh registration built by this
crate can therefore never turn into an underfunded lock that later
resumes under the pre-DIP-11 exemption. The remaining gap is a lock built
outside this path and funded below the DIP-11 minimum; the follow-up
(persist the creation layout on the tracked lock) is unchanged.

The exempt resume accepts exactly the four pre-DIP-11 keys (ids 0-3: AUTH
MASTER, CRITICAL, HIGH, TRANSFER CRITICAL; any key type) and refuses any
other set with `IdentityCreationKeysError::NotLegacyResumeLayout`, so a
host that derives the wrong layout gets a typed error instead of signing a
set the lock cannot fund.

Rust also owns the creation minimums hosts used to copy:
`IdentityWallet::identity_creation_min_funding_duffs` and
`identity_creation_from_addresses_min_fees`, exposed through
`platform_wallet_identity_creation_min_funding_duffs`,
`platform_wallet_identity_creation_from_addresses_min_fees` (+ `_free`) and
the matching JNI exports. The FFI registration and resume paths run the
creation check before touching either signer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… apps

Swift and Kotlin drop their copies of the identity-create fee schedule
(per-key cost, base cost, asset-lock base, address input cost, the dead
228k constant) and the minimum arithmetic built on them. The minimum
funding and the address-funded fee per input count come from the new Rust
queries; a failed query is shown and blocks submit instead of falling
back to zero. Kotlin's input packing is capped at the protocol's maximum
input count Rust reports.

Swift parses a resume's outpoint before deriving or persisting any key
and fails the submission on a malformed one, with no fresh-layout
fallback. The new Swift and Kotlin resume-layout docs no longer split the
existing resume docs, and the resume KDoc states that the layout comes
from `resumeKeyLayout`.

Swift and Kotlin are unbuilt (no Xcode or JDK on the build host).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 8 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
Commits

Reviewing files that changed from the base of the PR and between b1ce749 and 5f17b3b.

Files selected for processing: 19
  • packages/rs-platform-wallet-ffi/src/error.rs
  • packages/rs-platform-wallet-ffi/src/identity_registration_funded_with_signer.rs
  • packages/rs-platform-wallet-ffi/src/identity_registration_with_signer.rs
  • packages/rs-platform-wallet-ffi/src/invitation.rs
  • packages/rs-platform-wallet-ffi/src/shielded_send.rs
  • packages/rs-platform-wallet-ffi/src/test_fixtures.rs
  • packages/rs-platform-wallet/src/error.rs
  • packages/rs-platform-wallet/src/lib.rs
  • packages/rs-platform-wallet/src/test_support.rs
  • packages/rs-platform-wallet/src/util.rs
  • packages/rs-platform-wallet/src/wallet/asset_lock/sync/tracking.rs
  • packages/rs-platform-wallet/src/wallet/identity/network/creation_keys.rs
  • packages/rs-platform-wallet/src/wallet/identity/network/invitation.rs
  • packages/rs-platform-wallet/src/wallet/identity/network/mod.rs
  • packages/rs-platform-wallet/src/wallet/identity/network/register_from_addresses.rs
  • packages/rs-platform-wallet/src/wallet/identity/network/registration.rs
  • packages/rs-platform-wallet/src/wallet/platform_addresses/fund_from_asset_lock.rs
  • packages/rs-platform-wallet/src/wallet/platform_wallet.rs
  • packages/rs-platform-wallet/src/wallet/shielded/operations.rs

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 6fdb39b and b1ce749.

Files selected for processing: 15
  • packages/rs-platform-wallet-ffi/src/error.rs
  • packages/rs-platform-wallet-ffi/src/identity_registration_funded_with_signer.rs
  • packages/rs-platform-wallet-ffi/src/identity_registration_with_signer.rs
  • packages/rs-platform-wallet-ffi/src/invitation.rs
  • packages/rs-platform-wallet-ffi/src/shielded_send.rs
  • packages/rs-platform-wallet-ffi/src/test_fixtures.rs
  • packages/rs-platform-wallet/src/error.rs
  • packages/rs-platform-wallet/src/lib.rs
  • packages/rs-platform-wallet/src/wallet/identity/network/creation_keys.rs
  • packages/rs-platform-wallet/src/wallet/identity/network/invitation.rs
  • packages/rs-platform-wallet/src/wallet/identity/network/mod.rs
  • packages/rs-platform-wallet/src/wallet/identity/network/register_from_addresses.rs
  • packages/rs-platform-wallet/src/wallet/identity/network/registration.rs
  • packages/rs-platform-wallet/src/wallet/platform_addresses/fund_from_asset_lock.rs
  • packages/rs-platform-wallet/src/wallet/shielded/operations.rs
Files skipped from review as they are similar to previous changes: 1
  • packages/rs-platform-wallet/src/wallet/identity/network/register_from_addresses.rs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

The wallet adds validated identity-creation key layouts and applies layout-based funding checks to registration. Wallet and FFI APIs pass validated keys through registration, invitation claims, and shielded identity creation.

Changes: Identity creation

Layer / File(s) Summary
Key layouts and validation
packages/rs-platform-wallet/src/wallet/identity/network/creation_keys.rs, packages/rs-platform-wallet/src/error.rs, packages/rs-platform-wallet/src/wallet/identity/network/mod.rs, packages/rs-platform-wallet/src/lib.rs
Adds base and DashPay key layouts and IdentityCreationKeys validation. Construction checks required authentication keys at MASTER, CRITICAL, and HIGH, along with key IDs and enabled status.
Layout fees and funding floors
packages/rs-platform-wallet/src/wallet/identity/network/creation_keys.rs, packages/rs-platform-wallet/src/wallet/asset_lock/sync/tracking.rs, packages/rs-platform-wallet/src/util.rs, packages/rs-platform-wallet/src/wallet/platform_addresses/fund_from_asset_lock.rs, packages/rs-platform-wallet/src/test_support.rs
Adds layout-based fee queries and funding checks. Wallet-balance and tracked-lock funding below the required amount is rejected. Drain-account funding receives a minimum that is at least the layout requirement.
Wallet identity-creation APIs
packages/rs-platform-wallet/src/wallet/identity/network/registration.rs, packages/rs-platform-wallet/src/wallet/identity/network/register_from_addresses.rs, packages/rs-platform-wallet/src/wallet/identity/network/invitation.rs, packages/rs-platform-wallet/src/wallet/platform_wallet.rs, packages/rs-platform-wallet/src/wallet/shielded/operations.rs
Registration and invitation claims accept validated key sets. Address-funded registration builds its placeholder identity from the keys, and shielded identity creation converts the keys for the shield operation. The shielded operation is crate-visible.
FFI key validation and error mapping
packages/rs-platform-wallet-ffi/src/error.rs, packages/rs-platform-wallet-ffi/src/identity_registration_funded_with_signer.rs, packages/rs-platform-wallet-ffi/src/identity_registration_with_signer.rs, packages/rs-platform-wallet-ffi/src/invitation.rs, packages/rs-platform-wallet-ffi/src/shielded_send.rs, packages/rs-platform-wallet-ffi/src/test_fixtures.rs
FFI paths convert decoded keys to validated key sets and return construction errors. Validation-unavailable errors map to ErrorUnknown; other key errors map to ErrorInvalidParameter. Tests cover invalid keys, unknown wallets, and rejection before signer use.

Priority: Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant FFI as FFI registration
  participant Wallet as IdentityWallet
  participant Tracking as AssetLockManager
  participant Signer as Registration signers
  FFI->>Wallet: Validated keys and funding
  Wallet->>Tracking: Read tracked lock amount
  Tracking-->>Wallet: Amount or no tracked lock
  Wallet->>Signer: Continue after funding check
Loading

Possibly related issues

  • dashpay/platform#5592: The issue concerns invitation identity-creation key IDs. This PR routes invitation keys through IdentityCreationKeys validation, including the MASTER AUTHENTICATION key at ID 0.

Possibly related PRs

  • dashpay/platform#5471: Both changes modify invitation claims. This PR passes validated IdentityCreationKeys to the claim operation.
  • dashpay/platform#5476: Both changes connect to asset-lock funding APIs. This PR adds identity-registration funding pre-flight checks.
  • dashpay/platform#5460: Both changes modify identity-registration funding paths. This PR validates creation keys and enforces funding floors.

Suggested reviewers: shumkov, quantumexplorer

Merge Risk: Minimal · previous review b1ce7

No actionable issue was established in this PR. Coordinate its landing with the companion app changes as planned.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 63.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documenta… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main changes: moving identity-creation key checks and funding checks into the Rust platform-wallet core.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 63.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 30 functions across 19 files.

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added this to the v5.1.0 milestone Oct 28, 2026
@thepastaclaw

thepastaclaw commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

⚡ Priority review — 1st in line, starts as soon as a slot frees (commit 5f17b3b)
Estimated review time once started: ~25 min (two-phase automated review; median of recent runs).

…o a stacked PR

Split #5645 so this PR carries only the Rust core in rs-platform-wallet
(canonical creation key layout, MEDIUM key, IdentityCreationKeys
pre-flight, funding floor, amount-gated resume) plus the minimal FFI
wiring the existing registration entry points need to compile against
the new wallet API.

Returned to their v5.1-dev state here and restored in the stacked
bindings PR:
- the identity_creation_key_layout FFI module (layout, minimum funding,
  address-funded minimum fees and their frees) and its golden files
- platform_wallet_resume_identity_key_layout
- the layout-based signatures of dash_sdk_derive_and_persist_identity_keys
  and platform_wallet_preview_identity_registration_key_set
- the new JNI entry points and the layout-taking previewRegistrationKeySet
- every Swift and Kotlin change

Kept: the existing registration FFIs (address-funded, wallet-funded,
resume, invitation claim, shielded create) build IdentityCreationKeys
from the decoded keys and map the typed refusal to
ErrorInvalidParameter, with the wiring tests that exercise them.

Until the bindings PR lands, Swift and Kotlin still send four keys
without a MEDIUM authentication key, so new identity creation in the
example apps is refused by the pre-flight.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Claudius-Maginificent

Copy link
Copy Markdown
Collaborator Author

Split: this PR keeps the Rust core (c616cefb34). The FFI/JNI layout queries and the Swift and Kotlin changes moved to the stacked #5647. Both must land together, because with this PR alone the example apps cannot create new identities.

🤖 Co-authored by Claudius the Magnificent AI Agent

@lklimek
lklimek marked this pull request as ready for review October 28, 2026 16:39
@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Waiting for bot review — thepastaclaw not yet. Wait for the missing reviews, or a writer can post /skip-bots to proceed without them; blocking findings still need addressing.
Full checklist in the description.

@github-actions github-actions Bot added the waiting-bots Waiting for the review bots to report on this head label Oct 28, 2026

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Final validation — Phase 1 + Phase 2

The new DashPay layout creates seven keys, but both current protocol snapshots, including the latest v15 snapshot, still enforce a maximum of six keys. Such registrations are rejected by DPP before execution, so the primary DashPay creation path cannot succeed. The wallet also has non-blocking correctness gaps around resume affordability, legacy-resume provenance, and disabled key zero handling; wallet tests covering these changes remain queued.

🔴 1 blocking | 🟡 4 suggestion(s)

Review provenance

Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: ffi-engineer); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: platform-versioning); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: critical by gpt-6.1-sol (effort low) — This is a large, intricate change to identity key handling and registration funding in rs-platform-wallet, directly affecting cryptographic keys, signatures, asset-lock construction, and funds movement.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — rust-quality (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity quota lookup failed), glm-5.3-flash (not used above high effort; tier asks max)
  • Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — ffi-engineer (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — platform-versioning (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-platform-wallet/src/wallet/identity/network/creation_keys.rs`:
- [BLOCKING] packages/rs-platform-wallet/src/wallet/identity/network/creation_keys.rs:186-195: Seven-key DashPay layout exceeds the protocol identity key limit
  `NewIdentityWithDashPayKeys` adds encryption and decryption keys at ids 4 and 5, then appends authentication/medium at id 6, producing seven keys. DPP's identity-creation structure validation rejects key sets larger than `platform_version.dpp.state_transitions.identities.max_public_keys_in_creation`; the v4 table selected by both the v14 and v15 platform snapshots still sets that limit to 6. Therefore every DashPay identity using this layout is rejected before registration. Update the appropriate versioned protocol limit and gate the layout until that limit is active, or keep the layout within the existing limit.
- [SUGGESTION] packages/rs-platform-wallet/src/wallet/identity/network/creation_keys.rs:491-503: Resume affordability is not checked against the submitted key set
  `resume_exemption` compares the tracked amount only with the five-key `NewIdentity` minimum. If a tracked lock contains enough value for five keys but less than the fee for the actual supplied set, `creation_keys_for_funding` accepts that set as a normal identity creation, while `enforce_identity_create_floor` deliberately leaves `FromExistingAssetLock` unchanged. The wallet can then sign and submit a transition that DPP deterministically rejects for insufficient asset-lock funding. For every non-legacy existing-lock resume, compare the tracked amount with the fee computed from the actual validated keys before signing.
- [SUGGESTION] packages/rs-platform-wallet/src/wallet/identity/network/creation_keys.rs:491-503: Legacy resume exemption is based on amount rather than lock provenance
  `resume_exemption` uses only the persisted amount and does not inspect the tracked lock's funding type or creation provenance. A low-value tracked non-registration lock can therefore be reported by `resume_key_layout` as an `AssetLockResume`; the later resolver rejects mismatched funding roles, but the host has already been instructed to derive the wrong four-key layout. More importantly, an externally created low-value lock tracked as an identity registration can be grandfathered into the four-key path even though it was not an interrupted pre-DIP-11 registration. The exemption should be restricted to explicitly identified legacy registration locks, with creation provenance persisted through the tracked-lock storage and persisters.
- [SUGGESTION] packages/rs-platform-wallet/src/wallet/identity/network/creation_keys.rs:615-619: Key zero validation accepts a disabled key
  `check_key_zero` verifies only the purpose and security level. A caller can supply a disabled master authentication key at id 0 and another enabled master authentication key at a different id, allowing `new_identity` to pass because the per-level scan finds the second key. When the key map is converted into `IdentityPublicKeyInCreation`, `disabled_at` is not represented and the id-0 key is registered as enabled. Require key zero to have `disabled_at().is_none()` so the pre-flight cannot silently change the caller's disabled key into an enabled identity key.
- [SUGGESTION] packages/rs-platform-wallet/src/wallet/identity/network/creation_keys.rs:200-203: Avoid allocating all layout slots to count keys
  `key_count` constructs the complete slot vector, including cloned contract bounds for the DashPay layout, only to obtain its length. This method feeds sizing and fee-related queries, so the allocation is unnecessary. Return the statically known count for each layout variant instead.

@github-actions github-actions Bot added waiting-self-review Waiting for the author to post /self-reviewed and removed waiting-bots Waiting for the review bots to report on this head labels Oct 28, 2026
…IUM key

A creation may carry at most max_public_keys_in_creation (6) keys, so the
DashPay layout with a MEDIUM authentication key (7 keys) was refused by
consensus, and no system contract accepts a MEDIUM signature anyway.

- NewIdentity is keys 0-3 and NewIdentityWithDashPayKeys adds the DashPay
  pair at 4-5, exactly what hosts register today.
- The pre-flight requires an AUTHENTICATION key at MASTER, CRITICAL and
  HIGH (key 0 MASTER) and refuses any disabled key, since a key in
  creation carries no disabled state.
- The AssetLockResume layout and the amount-gated legacy resume exemption
  are gone: a resume re-derives the NewIdentity layout, which is now the
  same four keys.
- The funding floor also covers a tracked lock being resumed or
  reclaimed: one that cannot pay for its keys is refused before the
  finality wait or any signing. An untracked lock is still left to the
  funding resolver.
- Every layout is run through the dpp creation structure validation at
  the latest platform version, so a layout over the key limit fails a
  test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WunYYjpfLux1ByK7fGF7SG
@Claudius-Maginificent Claudius-Maginificent changed the title fix!: create identities with an authentication key at every security level fix(platform-wallet)!: check identity creation keys and funding in the Rust core Oct 29, 2026
@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Waiting for bot review — thepastaclaw not yet. Wait for the missing reviews, or a writer can post /skip-bots to proceed without them; blocking findings still need addressing.
Full checklist in the description.

@github-actions github-actions Bot added waiting-bots Waiting for the review bots to report on this head and removed waiting-self-review Waiting for the author to post /self-reviewed labels Oct 29, 2026

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review — Final validation — Phase 1 + Phase 2

The Rust wallet now fixes the prior six-key layout, disabled-key, and tracked-lock affordability issues. However, IdentityCreationKeys::new_identity still accepts key maps that DPP deterministically rejects, allowing funding resolution and asset-lock construction before failure; this contradicts the PR's primary pre-lock validation guarantee. CI has no reported failed code checks, but several checks remain pending.

🔴 1 blocking | 🟡 2 suggestion(s) | 💬 2 nitpick(s)

2 finding(s) not shown inline (the lines are not part of this PR's diff)

💬 Nitpick: Stale placeholder-identity documentation after keys refactor
packages/rs-platform-wallet/src/wallet/identity/network/register_from_addresses.rs:36-40

The method summary says the caller constructs the placeholder Identity, but the signature now accepts validated IdentityCreationKeys and the wallet builds the placeholder at lines 100–105. The argument documentation was updated, so the summary is the remaining stale description of the old API contract.

    /// This method is a thin wrapper over `put_with_address_funding`
    /// plus `IdentityManager::add_identity`. The caller passes the
    /// new identity's keys (validated by
    /// [`IdentityCreationKeys::new_identity`]) and both signers; the
    /// wallet builds the placeholder `Identity` and carries no key
    /// material itself.

source: muse-spark-1.3-contributor (phase1-reviewer: general, rust-quality)

🟡 Suggestion: Document the public platform-wallet API break in the changelog
CHANGELOG.md:1-7

This PR changes the public registration APIs from raw key maps or identity arguments to IdentityCreationKeys and adds a public PlatformWalletError variant. The repository records breaking platform-wallet API migrations in the Unreleased changelog, but this change leaves CHANGELOG.md untouched. Add a migration note for downstream Rust consumers such as Dash Evo Tool; the PR description alone will not remain available as release documentation.

source: gpt-6.1-sol (phase2-reviewer: general, architecture-layering, ffi-engineer, platform-versioning, rust-quality, security-auditor)

1 carried-forward finding(s) already raised on this PR; not re-posting as new inline comments.

Review provenance

Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 3: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: ffi-engineer); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: platform-versioning); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: critical by gpt-6.1-sol (effort low) — This is a large, intricate change to identity key handling, cryptographic signing inputs, asset-lock funding and registration flows in the Rust wallet core, directly affecting funds movement and key handling.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — rust-quality (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity quota lookup failed), glm-5.3-flash (not used above high effort; tier asks max)
  • Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — ffi-engineer (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — platform-versioning (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-platform-wallet/src/wallet/identity/network/creation_keys.rs`:
- [BLOCKING] packages/rs-platform-wallet/src/wallet/identity/network/creation_keys.rs:226-255: Creation preflight accepts consensus-invalid key sets
  `IdentityCreationKeys::new_identity` checks required authentication roles, key-zero placement, map/key-id consistency, and disabled state, but it does not run the versioned DPP creation-structure validation. A caller can therefore pass seven keys with all required roles, two MASTER keys, duplicate public-key data under different IDs, an invalid purpose/security-level combination, or key data with invalid size for its key type. The wrapper returns `Ok`, and `register_identity_with_funding` then proceeds to `enforce_identity_create_floor` and funding resolution, which can build or resume an asset lock before the resulting transition is rejected by Platform. The new layout test only validates the built-in layouts directly through DPP; it does not validate arbitrary maps accepted by `new_identity`. Invoke DPP's platform-version-aware structure validation from this preflight, or expose an equivalent owner-level validation result, before any funding resolver or signer is reached. Add regression coverage for over-limit, duplicate-data, multiple-master, and invalid purpose/security-level inputs.
- [SUGGESTION] packages/rs-platform-wallet/src/wallet/identity/network/creation_keys.rs:171-173: Avoid allocating all layout slots to count keys
  (existing thread: https://github.com/dashpay/platform/pull/5645#discussion_r4405627517)
  `key_count` constructs the complete slot vector solely to return its length. For the DashPay layout this also constructs and clones the contract-bound document-type strings. The slot table should remain the source for callers that need metadata, but this count-only helper can avoid materializing it; the allocation is small and not blocking, but the method is explicitly documented as a fee-sizing helper.

In `packages/rs-platform-wallet/src/wallet/identity/network/registration.rs`:
- [NITPICK] packages/rs-platform-wallet/src/wallet/identity/network/registration.rs:187-189: Stale `keys_map` reference in placeholder comment
  The registration argument is now named `keys` and has type `IdentityCreationKeys`, but the comment still refers to a `keys_map` deep clone. This makes the comment describe an identifier and ownership model that no longer exists.

In `packages/rs-platform-wallet/src/wallet/identity/network/register_from_addresses.rs`:
- [NITPICK] packages/rs-platform-wallet/src/wallet/identity/network/register_from_addresses.rs:36-40: Stale placeholder-identity documentation after keys refactor
  The method summary says the caller constructs the placeholder `Identity`, but the signature now accepts validated `IdentityCreationKeys` and the wallet builds the placeholder at lines 100–105. The argument documentation was updated, so the summary is the remaining stale description of the old API contract.

In `CHANGELOG.md`:
- [SUGGESTION] CHANGELOG.md:1-7: Document the public platform-wallet API break in the changelog
  This PR changes the public registration APIs from raw key maps or identity arguments to `IdentityCreationKeys` and adds a public `PlatformWalletError` variant. The repository records breaking platform-wallet API migrations in the Unreleased changelog, but this change leaves `CHANGELOG.md` untouched. Add a migration note for downstream Rust consumers such as Dash Evo Tool; the PR description alone will not remain available as release documentation.

@github-actions github-actions Bot added waiting-self-review Waiting for the author to post /self-reviewed and removed waiting-bots Waiting for the review bots to report on this head labels Oct 29, 2026
lklimek and others added 2 commits October 30, 2026 09:22
…et-dip11-identity-key-layout

Conflict: packages/rs-platform-wallet/src/lib.rs re-exports, kept both the
identity creation key types and PreparedDashPayPayment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WunYYjpfLux1ByK7fGF7SG
…ation would refuse

IdentityCreationKeys::new_identity takes the platform version and runs dpp's
versioned identity-create structure validation after the wallet's own checks,
so a key set over the creation limit, with duplicate key data, a second MASTER
key, a purpose at a disallowed level, or a wrongly sized hash key is refused
before any asset lock is built, waited on or signed.

The FFI reads the version from the wallet, so an unknown wallet handle now
reports NotFound ahead of a key-set fault. identity_create_from_shielded_pool
becomes pub(crate), closing the one way around the pre-flight.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WunYYjpfLux1ByK7fGF7SG
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Waiting for bot review — thepastaclaw not yet. Wait for the missing reviews, or a writer can post /skip-bots to proceed without them; blocking findings still need addressing.
Full checklist in the description.

@github-actions github-actions Bot added the waiting-bots Waiting for the review bots to report on this head label Oct 30, 2026
@github-actions github-actions Bot removed the waiting-self-review Waiting for the author to post /self-reviewed label Oct 30, 2026

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review — Final validation — Phase 1 + Phase 2

The new DPP structure preflight and funding checks cover the main asset-lock paths, but the validated key wrapper does not retain or recheck the protocol version used for validation. A native caller can validate keys under an older protocol version and then submit them through a newer wallet, allowing funding resolution and signing before Platform rejects the transition. Address-funded and shielded creation paths also miss specific preflight checks. CI currently shows Kotlin tests and policy/PR Hygiene checks still pending or in progress, with no failed code check reported.

🔴 1 blocking | 🟡 3 suggestion(s) | 💬 1 nitpick(s)

2 finding(s) not shown inline (the lines are not part of this PR's diff)

🟡 Suggestion: Invitation claims bypass the versioned identity-creation funding floor
packages/rs-sdk/src/platform/dashpay/invitation.rs:852-879

IdentityWallet::claim_invitation now validates the key wrapper but converts it back to a raw map and delegates to Sdk::claim_invitation, which only validates key shape and does not compare the fetched voucher output with the versioned identity-creation fee for those keys. MIN_INVITATION_DUFFS is a fixed creation-time floor rather than the selected protocol fee, so an externally supplied or legacy voucher, or a voucher used after a higher fee schedule is active, can still reach proof construction and signing before Platform rejects it. After selecting the voucher output, check its amount against the same versioned fee calculation before constructing or submitting the claim.

source: gpt-6.1-sol (phase2-reviewer: general, architecture-layering, ffi-engineer, platform-versioning, rust-quality, security-auditor)

💬 Nitpick: Stale placeholder-identity documentation after keys refactor
packages/rs-platform-wallet/src/wallet/identity/network/register_from_addresses.rs:36-40

The method introduction still says that the caller constructs the placeholder Identity, but the signature now accepts IdentityCreationKeys and the method constructs the placeholder internally at lines 100–105. The argument documentation was updated, so the preceding description should be brought into agreement with the new ownership model.

    /// This method is a thin wrapper over `put_with_address_funding`
    /// plus `IdentityManager::add_identity`. The caller supplies the
    /// validated keys and both signers; the wallet builds the placeholder
    /// [`Identity`] from those keys and carries no key material.

source: muse-spark-1.3-contributor (phase1-reviewer: general); gpt-6.1-sol (phase2-reviewer: general, architecture-layering, platform-versioning)

Review provenance

Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: ffi-engineer); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: platform-versioning); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: critical by gpt-6.1-sol (effort low) — This is a large, intricate change to identity key handling, cryptographic signing inputs, asset-lock funding validation, and FFI registration paths, directly affecting funds movement and key security in files such as creation_keys.rs and identity registration functions.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — rust-quality (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity quota lookup failed), glm-5.3-flash (not used above high effort; tier asks max)
  • Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — ffi-engineer (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — platform-versioning (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-platform-wallet/src/wallet/identity/network/creation_keys.rs`:
- [BLOCKING] packages/rs-platform-wallet/src/wallet/identity/network/creation_keys.rs:249-294: Creation-key validation is not bound to the wallet's active protocol version
  `IdentityCreationKeys::new_identity` validates against the caller-supplied `PlatformVersion`, but `IdentityCreationKeys` stores only the keys. The registration methods subsequently trust the wrapper without checking it against `self.sdk.version()`. For example, the existing test demonstrates that a 19-byte `ECDSA_HASH160` key is accepted under protocol 13 and rejected by the current validation rules; a native caller can construct that wrapper with protocol 13 and pass it to a wallet using a newer protocol. The wallet can then enforce funding, resolve or resume an asset lock, and reach signing before the SDK's later structure check rejects the transition. Retain the validation version in the wrapper and verify it at every write boundary, or rerun the owner-level validation using the wallet's active version before funding or signing.

In `packages/rs-platform-wallet/src/wallet/identity/network/register_from_addresses.rs`:
- [SUGGESTION] packages/rs-platform-wallet/src/wallet/identity/network/register_from_addresses.rs:87-104: Preflight address-funded registrations against the versioned fee floor
  `register_from_addresses` accepts the validated key wrapper but immediately constructs the placeholder identity and calls `put_with_address_funding_fetching_nonces`. The new `identity_creation_from_addresses_min_fees` helper is advisory only and is not used by this write path. The SDK constructor signs the identity and address witnesses before `ensure_valid_state_transition_structure`; it does not reject an input map whose credits cannot cover the versioned fee for the actual input count and optional output. Add an owner-level preflight using the actual keys, input count, and output before either signer is reached.
- [NITPICK] packages/rs-platform-wallet/src/wallet/identity/network/register_from_addresses.rs:36-40: Stale placeholder-identity documentation after keys refactor
  The method introduction still says that the caller constructs the placeholder `Identity`, but the signature now accepts `IdentityCreationKeys` and the method constructs the placeholder internally at lines 100–105. The argument documentation was updated, so the preceding description should be brought into agreement with the new ownership model.

In `packages/rs-platform-wallet-ffi/src/shielded_send.rs`:
- [SUGGESTION] packages/rs-platform-wallet-ffi/src/shielded_send.rs:956-973: Shielded identity creation omits shielded-only key restrictions from preflight
  The shielded FFI entry point now calls the generic `IdentityCreationKeys::new_identity` validator, but shielded identity creation has additional consensus restrictions. Drive's versioned shielded-proof validation rejects contract-group-bound keys and keys carrying budgets or expiries, while the generic creation validator accepts those fields and the shared decoder permits them. The wallet reserves shielded notes before `build_identity_create_from_shielded_pool_transition` runs, so an invalid key set can consume note-reservation work and only fail later. Add a shielded-specific owner-level validation context or method and cover both contract-bound and limited keys before note reservation.

In `packages/rs-sdk/src/platform/dashpay/invitation.rs`:
- [SUGGESTION] packages/rs-sdk/src/platform/dashpay/invitation.rs:852-879: Invitation claims bypass the versioned identity-creation funding floor
  `IdentityWallet::claim_invitation` now validates the key wrapper but converts it back to a raw map and delegates to `Sdk::claim_invitation`, which only validates key shape and does not compare the fetched voucher output with the versioned identity-creation fee for those keys. `MIN_INVITATION_DUFFS` is a fixed creation-time floor rather than the selected protocol fee, so an externally supplied or legacy voucher, or a voucher used after a higher fee schedule is active, can still reach proof construction and signing before Platform rejects it. After selecting the voucher output, check its amount against the same versioned fee calculation before constructing or submitting the claim.

@github-actions github-actions Bot added waiting-self-review Waiting for the author to post /self-reviewed and removed waiting-bots Waiting for the review bots to report on this head labels Oct 30, 2026
lklimek and others added 4 commits October 30, 2026 12:14
… own version

IdentityCreationKeys::new_identity let a Rust caller pick the platform version,
so a key set could pass at one version while the wallet built an asset lock for
a Platform running another. It becomes pub(crate), and the new
IdentityWallet::identity_creation_keys reads the version from the wallet's SDK,
as the funding floor does. All FFI entry points use it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WunYYjpfLux1ByK7fGF7SG
…'s current version

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WunYYjpfLux1ByK7fGF7SG
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Waiting for bot review — thepastaclaw not yet. Wait for the missing reviews, or a writer can post /skip-bots to proceed without them; blocking findings still need addressing.
Full checklist in the description.

@github-actions github-actions Bot added waiting-bots Waiting for the review bots to report on this head and removed waiting-self-review Waiting for the author to post /self-reviewed labels Oct 30, 2026

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review — Final validation — Phase 1 + Phase 2

The PR improves identity-creation key validation and asset-lock funding checks, but two blocking preflight gaps remain. Validated key wrappers are not bound to the protocol version used at the write boundary, and the preflight accepts V1 key formats on protocol versions where those formats are inactive; both cases can proceed to funding and signing before Platform rejects the transition. Invitation and address-funded paths also bypass the new versioned funding checks, and the breaking API migration is absent from the changelog. CI has no reported code failure, but several checks remain queued or in progress.

🔴 2 blocking | 🟡 3 suggestion(s) | 💬 1 nitpick(s)

3 finding(s) not shown inline (the lines are not part of this PR's diff)

🟡 Suggestion: Invitation claims bypass the versioned identity-creation funding floor
packages/rs-sdk/src/platform/dashpay/invitation.rs:862-879

The wallet now validates the submitted keys, but Sdk::claim_invitation still only performs its legacy key-0 check and then fetches the voucher proof. It never compares the voucher's credit output with calculate_min_required_fee for the actual keys and current protocol version before constructing and signing the claim at lines 889-917. The fixed MIN_INVITATION_DUFFS policy may exceed today's minimum, but it is not tied to the versioned, key-dependent fee schedule and can leave legacy or externally created low-value vouchers proceeding to a late Platform rejection. Apply the same owner-level funding admission after the voucher output is known and before proof submission or signing.

source: muse-spark-1.3-contributor (phase1-reviewer: general, rust-quality); gpt-6.1-sol (phase2-reviewer: general, architecture-layering, rust-quality)

🟡 Suggestion: Document the public platform-wallet API break in the changelog
CHANGELOG.md:1-7

The Unreleased changelog has no migration note for the breaking platform-wallet API changes. Registration, invitation-claim, and shielded identity-creation methods now require IdentityCreationKeys; direct construction is restricted; and the public error surface changed. The PR description records these changes, but downstream Rust, FFI, and JNI consumers need the migration guidance in the durable release documentation.

source: muse-spark-1.3-contributor (phase1-reviewer: general, rust-quality); gpt-6.1-sol (phase2-reviewer: general, architecture-layering)

💬 Nitpick: Stale placeholder-identity documentation after keys refactor
packages/rs-platform-wallet/src/wallet/identity/network/register_from_addresses.rs:36-40

The method now accepts keys: IdentityCreationKeys and constructs the placeholder Identity internally at lines 100-105, but this paragraph still says that the caller constructs the placeholder identity. That describes the pre-refactor API and can mislead callers integrating the breaking change.

    /// This method is a thin wrapper over `put_with_address_funding`
    /// plus `IdentityManager::add_identity`. The caller supplies the
    /// validated keys and both signers; the placeholder identity is built
    /// here, and the wallet struct carries no key material.

source: muse-spark-1.3-contributor (phase1-reviewer: general, rust-quality); gpt-6.1-sol (phase2-reviewer: general)

2 carried-forward finding(s) already raised on this PR; not re-posting as new inline comments.

Review provenance

Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: ffi-engineer); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: platform-versioning); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: critical by gpt-6.1-sol (effort low) — This is a large, intricate change to identity creation key validation, funding and asset-lock registration across Rust wallet and FFI code, directly affecting key handling and funds movement in the listed identity registration and creation-key paths.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — rust-quality (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity quota lookup failed), glm-5.3-flash (not used above high effort; tier asks max)
  • Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — ffi-engineer (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — platform-versioning (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-platform-wallet/src/wallet/identity/network/creation_keys.rs`:
- [BLOCKING] packages/rs-platform-wallet/src/wallet/identity/network/creation_keys.rs:280-289: Preflight accepts version-14 key formats on older wallet protocol versions
  `new_identity` converts the caller's keys and invokes `validate_identity_public_keys_structure` at the wallet's current protocol version. At protocol 13 this dispatches the V0 validator, which checks counts, duplicate keys, master keys, and purpose/level combinations but does not reject a V1 key format or its limits. DPP separately makes V1 creation keys active only from protocol 14, through `StateTransition::active_version_range`. Consequently, a V1 key can pass this new preflight on a protocol-13 wallet, after which registration can resolve an asset lock and reach signing before the transition is rejected as inactive by Platform. Add an owner-level active-format validation to the preflight rather than duplicating the activation rule in the wallet.
- [BLOCKING] packages/rs-platform-wallet/src/wallet/identity/network/creation_keys.rs:238-295: Creation-key validation is not bound to the wallet's active protocol version
  (existing thread: https://github.com/dashpay/platform/pull/5645#discussion_r4422653365)
  `IdentityCreationKeys` stores only the key map, while `identity_creation_keys` validates it using the SDK version at the time the wrapper is created. The wrapper is public and can later be passed to another wallet, or retained while an auto-detected SDK ratchets to a newer protocol version. For example, the 19-byte HASH160 fixture accepted at protocol 13 is rejected by the newer structure rules. The asset-lock registration path then computes the funding floor and resolves or resumes the lock before the later transition construction uses the newer SDK version and rejects the keys. Store the validation version in `IdentityCreationKeys` and verify it at each write boundary, or rerun the owner-level validation against the current wallet version immediately before funding and signing.

In `packages/rs-sdk/src/platform/dashpay/invitation.rs`:
- [SUGGESTION] packages/rs-sdk/src/platform/dashpay/invitation.rs:862-879: Invitation claims bypass the versioned identity-creation funding floor
  The wallet now validates the submitted keys, but `Sdk::claim_invitation` still only performs its legacy key-0 check and then fetches the voucher proof. It never compares the voucher's credit output with `calculate_min_required_fee` for the actual keys and current protocol version before constructing and signing the claim at lines 889-917. The fixed `MIN_INVITATION_DUFFS` policy may exceed today's minimum, but it is not tied to the versioned, key-dependent fee schedule and can leave legacy or externally created low-value vouchers proceeding to a late Platform rejection. Apply the same owner-level funding admission after the voucher output is known and before proof submission or signing.

In `CHANGELOG.md`:
- [SUGGESTION] CHANGELOG.md:1-7: Document the public platform-wallet API break in the changelog
  The Unreleased changelog has no migration note for the breaking platform-wallet API changes. Registration, invitation-claim, and shielded identity-creation methods now require `IdentityCreationKeys`; direct construction is restricted; and the public error surface changed. The PR description records these changes, but downstream Rust, FFI, and JNI consumers need the migration guidance in the durable release documentation.

In `packages/rs-platform-wallet/src/wallet/identity/network/register_from_addresses.rs`:
- [NITPICK] packages/rs-platform-wallet/src/wallet/identity/network/register_from_addresses.rs:36-40: Stale placeholder-identity documentation after keys refactor
  The method now accepts `keys: IdentityCreationKeys` and constructs the placeholder `Identity` internally at lines 100-105, but this paragraph still says that the caller constructs the placeholder identity. That describes the pre-refactor API and can mislead callers integrating the breaking change.
- [SUGGESTION] packages/rs-platform-wallet/src/wallet/identity/network/register_from_addresses.rs:87-118: Preflight address-funded registrations against the versioned fee floor
  (existing thread: https://github.com/dashpay/platform/pull/5645#discussion_r4422653374)
  `register_from_addresses` accepts the validated key wrapper but never uses `identity_creation_from_addresses_min_fees` before constructing the placeholder and calling the SDK path that signs. The SDK passes the caller-supplied amounts directly into the transition and always deducts the fee from input 0, so an input amount below the versioned minimum for the actual input count can be rejected locally before signer invocation even though on-chain balance fetching is still needed for the full affordability check. Wire the existing versioned helper into this write path for that deterministic lower-bound check.

@github-actions github-actions Bot added waiting-self-review Waiting for the author to post /self-reviewed and removed waiting-bots Waiting for the review bots to report on this head labels Oct 30, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

waiting-self-review Waiting for the author to post /self-reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants