Skip to content

Conversation

@PastaPastaPasta
Copy link
Member

@PastaPastaPasta PastaPastaPasta commented Dec 31, 2025

The identity_update, identity_credit_transfer, and identity_credit_withdrawal functions only supported ECDSA_HASH160 keys, but most identities (including all DashPay-created identities) use ECDSA_SECP256K1 keys. This caused these operations to fail with "Provided private key does not match any master key".

Changes:

  • Add private_key_matches_public_key helper that handles both key types:
    • ECDSA_SECP256K1: compares full 33-byte compressed public key
    • ECDSA_HASH160: compares 20-byte hash160
  • Update identity_update master key lookup to use the helper
  • Update identity_credit_transfer key lookups to use the helper
  • Update identity_credit_withdrawal key lookups to use the helper

🤖 Generated with Claude Code

How Has This Been Tested?

  • Add 5 regression tests to verify the fix and prevent future regressions

Breaking Changes

None

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

Summary by CodeRabbit

  • Tests

    • Expanded coverage for identity key validation, adding scenarios for ECDSA-derived key matching and ensuring non-ECDSA types do not match; includes regression checks.
  • Refactor

    • Unified identity key matching logic across creation, transfer, withdrawal, and update flows to improve consistency and reliability without changing public APIs.

✏️ Tip: You can customize this high-level summary in your review settings.

The identity_update, identity_credit_transfer, and identity_credit_withdrawal
functions only supported ECDSA_HASH160 keys, but most identities (including all
DashPay-created identities) use ECDSA_SECP256K1 keys. This caused these
operations to fail with "Provided private key does not match any master key".

Changes:
- Add private_key_matches_public_key helper that handles both key types:
  - ECDSA_SECP256K1: compares full 33-byte compressed public key
  - ECDSA_HASH160: compares 20-byte hash160
- Update identity_update master key lookup to use the helper
- Update identity_credit_transfer key lookups to use the helper
- Update identity_credit_withdrawal key lookups to use the helper
- Add 5 regression tests to verify the fix and prevent future regressions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@PastaPastaPasta PastaPastaPasta added this to the v3.0.0 milestone Dec 31, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 31, 2025

📝 Walkthrough

Walkthrough

Added a private helper ecdsa_public_key_matches_identity_key to centralize ECDSA identity key validation and refactored identity creation, update, withdrawal, and credit transfer flows to use it; new unit tests exercise matching and non-matching scenarios across key types.

Changes

Cohort / File(s) Summary
ECDSA helper & identity flow refactors
packages/wasm-sdk/src/state_transitions/identity/mod.rs
Added private helper ecdsa_public_key_matches_identity_key(public_key_bytes, public_key_hash160, key) that returns true for ECDSA_SECP256K1 (33-byte public key compare) and ECDSA_HASH160 (20-byte hash160 compare); replaced inline key-type/data checks in identity creation, credit transfer, withdrawal, and update with the helper.
Tests (identity key matching)
packages/wasm-sdk/src/state_transitions/identity/mod.rs
Added unit tests for ECDSA_SECP256K1 and ECDSA_HASH160 match/mismatch, tests ensuring non-ECDSA types (BLS, EDDSA) do not match, and a regression test for master key matching.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I checked each key, hash and byte,
A helper made the matches right,
No duplicated checks to sow,
Hopping tidy through the flow,
🥕🔐

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(wasm-sdk): support ECDSA_SECP256K1 keys in identity operations' clearly and accurately summarizes the main change: adding support for ECDSA_SECP256K1 keys in identity operations to fix existing failures.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings

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 and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/wasm-sdk/src/state_transitions/identity/mod.rs (1)

1502-1670: Excellent test coverage with comprehensive regression testing.

The tests thoroughly validate the helper function for all key types, including positive/negative cases and the specific regression scenario described in the PR. The test names are clear and the assertions include helpful failure messages.

Optional: Minor simplification in test helper

Line 1510 uses 0u32.into() for the id field, but based on line 365 where id: key_id is used directly (key_id is u32), the field type is u32. You could simplify to:

-            id: 0u32.into(),
+            id: 0,

This is purely cosmetic and doesn't affect correctness.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1c9a855 and 2b0041c.

📒 Files selected for processing (1)
  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Rust code must pass cargo clippy --workspace linter checks
Rust code must be formatted using cargo fmt --all

**/*.rs: Use 4-space indent for Rust files
Follow rustfmt defaults and keep code clippy-clean for Rust modules
Use snake_case for Rust module names
Use PascalCase for Rust type names
Use SCREAMING_SNAKE_CASE for Rust constants

Files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
🧠 Learnings (9)
📓 Common learnings
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2673
File: packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_update/mod.rs:1164-1197
Timestamp: 2025-06-18T03:44:14.385Z
Learning: QuantumExplorer determined that a CodeRabbit suggestion about fixing signable_bytes calculation in identity update tests with contract-bound keys was incorrect - the code flow is working as intended without the suggested changes.
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2711
File: packages/wasm-sdk/docs.html:2359-2383
Timestamp: 2025-07-28T20:00:24.323Z
Learning: In packages/wasm-sdk/docs.html, QuantumExplorer confirmed that placeholder private keys in documentation examples are acceptable as they are not real keys, though field name accuracy for the SDK API should still be maintained.
Learnt from: thephez
Repo: dashpay/platform PR: 2718
File: packages/wasm-sdk/index.html:0-0
Timestamp: 2025-08-05T13:55:39.147Z
Learning: The get_identity_keys_with_proof_info function in the Rust WASM bindings does not support the "search" key request type and lacks the searchPurposeMap parameter. When proof mode is enabled with keyRequestType === 'search', the implementation falls back to the non-proof version (get_identity_keys) to maintain functionality.
Learnt from: CR
Repo: dashpay/platform PR: 0
File: packages/swift-sdk/SwiftExampleApp/CLAUDE.md:0-0
Timestamp: 2025-11-25T13:10:38.019Z
Learning: Applies to packages/swift-sdk/SwiftExampleApp/**/*.swift : Always validate private keys match their public keys using KeyValidation.validatePrivateKeyForPublicKey before cryptographic operations
📚 Learning: 2024-10-06T16:11:34.946Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2215
File: packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/create_owner_identity/v1/mod.rs:19-30
Timestamp: 2024-10-06T16:11:34.946Z
Learning: In the Rust file `packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/create_owner_identity/v1/mod.rs`, within the `create_owner_identity_v1` function, the `add_public_keys` method of the `Identity` struct cannot fail and does not require explicit error handling.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2024-11-20T20:43:41.185Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/tests/strategy_tests/masternodes.rs:212-220
Timestamp: 2024-11-20T20:43:41.185Z
Learning: In `packages/rs-drive-abci/tests/strategy_tests/masternodes.rs`, the pattern of generating a `PrivateKey`, converting it to bytes, and reconstructing a `BlsPrivateKey` from those bytes is intentional. Avoid suggesting to simplify this code in future reviews.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2025-08-05T13:55:39.147Z
Learnt from: thephez
Repo: dashpay/platform PR: 2718
File: packages/wasm-sdk/index.html:0-0
Timestamp: 2025-08-05T13:55:39.147Z
Learning: The get_identity_keys_with_proof_info function in the Rust WASM bindings does not support the "search" key request type and lacks the searchPurposeMap parameter. When proof mode is enabled with keyRequestType === 'search', the implementation falls back to the non-proof version (get_identity_keys) to maintain functionality.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2024-11-20T16:05:40.200Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving.rs:148-151
Timestamp: 2024-11-20T16:05:40.200Z
Learning: In `packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving.rs`, when converting public keys from `QuorumForSavingV0` to `VerificationQuorum`, it's acceptable to use `.expect()` for public key conversion, as the conversion has been verified and panics are acceptable in this context.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2024-10-21T01:03:42.458Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2227
File: packages/rs-dpp/src/core_types/validator_set/v0/mod.rs:299-299
Timestamp: 2024-10-21T01:03:42.458Z
Learning: In the `test_serialize_deserialize_validator_set_v0` test within `packages/rs-dpp/src/core_types/validator_set/v0/mod.rs`, deterministic BLS keys cannot be easily used; therefore, using `BlsPublicKey::generate()` is acceptable.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2025-11-25T13:10:38.019Z
Learnt from: CR
Repo: dashpay/platform PR: 0
File: packages/swift-sdk/SwiftExampleApp/CLAUDE.md:0-0
Timestamp: 2025-11-25T13:10:38.019Z
Learning: Applies to packages/swift-sdk/SwiftExampleApp/**/{KeychainManager,*Key,*Identity}.swift : Store private keys separately from identities using iOS Keychain for secure storage; private keys belong to public keys, not identities

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2024-10-03T11:51:06.980Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2201
File: packages/rs-platform-version/src/version/v2.rs:1186-1188
Timestamp: 2024-10-03T11:51:06.980Z
Learning: In the `IdentityTransitionVersions` structure within `packages/rs-platform-version/src/version/v2.rs`, the field `credit_withdrawal` does not need the `identity_` prefix since it is already encompassed within identity state transitions.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2024-10-30T11:19:59.163Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-sdk/tests/fetch/config.rs:233-233
Timestamp: 2024-10-30T11:19:59.163Z
Learning: In the Rust SDK's `rs-sdk/tests` integration tests (e.g., in `packages/rs-sdk/tests/fetch/config.rs`), we cannot create objects during tests because there is no support for object creation in this context. Therefore, hardcoded values for test identities must be used.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci, SDK_TEST_DATA=true
    ) / Build Drive image
  • GitHub Check: Build JS packages / Build JS
  • GitHub Check: Rust crates security audit
🔇 Additional comments (4)
packages/wasm-sdk/src/state_transitions/identity/mod.rs (4)

23-43: LGTM! Well-designed helper function with clear semantics.

The function correctly distinguishes between ECDSA_SECP256K1 (full 33-byte comparison) and ECDSA_HASH160 (20-byte hash comparison), with appropriate handling of unsupported key types. The documentation clearly explains why BLS and other key types return false.


669-708: Correct integration of the helper function for credit transfers.

Both code paths (specific key ID lookup and any matching key search) correctly use the helper with appropriate filtering on Purpose::TRANSFER. The implementation ensures ECDSA_SECP256K1 keys will now be properly matched.


856-905: Correct integration of the helper function for withdrawals.

The implementation appropriately handles both TRANSFER and OWNER keys for withdrawals, with proper prioritization of TRANSFER keys. The helper is used consistently across all matching scenarios.


1029-1041: Critical fix: Master key lookup now supports both ECDSA key types.

This resolves the core issue where identity_update failed for ECDSA_SECP256K1 master keys. The helper correctly validates master keys with Purpose::AUTHENTICATION and SecurityLevel::MASTER filters.

QuantumExplorer
QuantumExplorer previously approved these changes Jan 2, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/wasm-sdk/src/state_transitions/identity/mod.rs (1)

23-44: LGTM! Helper function correctly handles both ECDSA key types.

The implementation properly distinguishes between ECDSA_SECP256K1 (33-byte full public key) and ECDSA_HASH160 (20-byte hash) comparisons, and correctly returns false for non-ECDSA types that require different key derivation.

Optional: Add debug assertions for input validation

While the current implementation is safe (all call sites correctly derive the inputs), you could add defensive checks to catch potential future mistakes in debug builds:

 fn ecdsa_public_key_matches_identity_key(
     public_key_bytes: &[u8],   // 33-byte compressed secp256k1 public key
     public_key_hash160: &[u8], // 20-byte hash160 of the public key
     key: &IdentityPublicKey,
 ) -> bool {
+    debug_assert_eq!(public_key_bytes.len(), 33, "public_key_bytes must be 33 bytes");
+    debug_assert_eq!(public_key_hash160.len(), 20, "public_key_hash160 must be 20 bytes");
+    
     match key.key_type() {

This is purely optional since the function is private and all current usages are correct.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b0041c and 46eb061.

📒 Files selected for processing (1)
  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Rust code must pass cargo clippy --workspace linter checks
Rust code must be formatted using cargo fmt --all

**/*.rs: Use 4-space indent for Rust files
Follow rustfmt defaults and keep code clippy-clean for Rust modules
Use snake_case for Rust module names
Use PascalCase for Rust type names
Use SCREAMING_SNAKE_CASE for Rust constants

Files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
🧠 Learnings (9)
📓 Common learnings
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2673
File: packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_update/mod.rs:1164-1197
Timestamp: 2025-06-18T03:44:14.385Z
Learning: QuantumExplorer determined that a CodeRabbit suggestion about fixing signable_bytes calculation in identity update tests with contract-bound keys was incorrect - the code flow is working as intended without the suggested changes.
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2711
File: packages/wasm-sdk/docs.html:2359-2383
Timestamp: 2025-07-28T20:00:24.323Z
Learning: In packages/wasm-sdk/docs.html, QuantumExplorer confirmed that placeholder private keys in documentation examples are acceptable as they are not real keys, though field name accuracy for the SDK API should still be maintained.
Learnt from: CR
Repo: dashpay/platform PR: 0
File: packages/swift-sdk/SwiftExampleApp/CLAUDE.md:0-0
Timestamp: 2025-11-25T13:10:38.019Z
Learning: Applies to packages/swift-sdk/SwiftExampleApp/**/*.swift : Always validate private keys match their public keys using KeyValidation.validatePrivateKeyForPublicKey before cryptographic operations
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2227
File: packages/rs-dpp/src/core_types/validator_set/v0/mod.rs:299-299
Timestamp: 2024-10-21T01:03:42.458Z
Learning: In the `test_serialize_deserialize_validator_set_v0` test within `packages/rs-dpp/src/core_types/validator_set/v0/mod.rs`, deterministic BLS keys cannot be easily used; therefore, using `BlsPublicKey::generate()` is acceptable.
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/tests/strategy_tests/masternodes.rs:212-220
Timestamp: 2024-11-20T20:43:41.185Z
Learning: In `packages/rs-drive-abci/tests/strategy_tests/masternodes.rs`, the pattern of generating a `PrivateKey`, converting it to bytes, and reconstructing a `BlsPrivateKey` from those bytes is intentional. Avoid suggesting to simplify this code in future reviews.
📚 Learning: 2024-10-06T16:11:34.946Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2215
File: packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/create_owner_identity/v1/mod.rs:19-30
Timestamp: 2024-10-06T16:11:34.946Z
Learning: In the Rust file `packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/create_owner_identity/v1/mod.rs`, within the `create_owner_identity_v1` function, the `add_public_keys` method of the `Identity` struct cannot fail and does not require explicit error handling.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2024-11-20T20:43:41.185Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/tests/strategy_tests/masternodes.rs:212-220
Timestamp: 2024-11-20T20:43:41.185Z
Learning: In `packages/rs-drive-abci/tests/strategy_tests/masternodes.rs`, the pattern of generating a `PrivateKey`, converting it to bytes, and reconstructing a `BlsPrivateKey` from those bytes is intentional. Avoid suggesting to simplify this code in future reviews.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2025-08-05T13:55:39.147Z
Learnt from: thephez
Repo: dashpay/platform PR: 2718
File: packages/wasm-sdk/index.html:0-0
Timestamp: 2025-08-05T13:55:39.147Z
Learning: The get_identity_keys_with_proof_info function in the Rust WASM bindings does not support the "search" key request type and lacks the searchPurposeMap parameter. When proof mode is enabled with keyRequestType === 'search', the implementation falls back to the non-proof version (get_identity_keys) to maintain functionality.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2024-11-20T16:05:40.200Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving.rs:148-151
Timestamp: 2024-11-20T16:05:40.200Z
Learning: In `packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving.rs`, when converting public keys from `QuorumForSavingV0` to `VerificationQuorum`, it's acceptable to use `.expect()` for public key conversion, as the conversion has been verified and panics are acceptable in this context.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2024-10-21T01:03:42.458Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2227
File: packages/rs-dpp/src/core_types/validator_set/v0/mod.rs:299-299
Timestamp: 2024-10-21T01:03:42.458Z
Learning: In the `test_serialize_deserialize_validator_set_v0` test within `packages/rs-dpp/src/core_types/validator_set/v0/mod.rs`, deterministic BLS keys cannot be easily used; therefore, using `BlsPublicKey::generate()` is acceptable.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2024-10-03T11:51:06.980Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2201
File: packages/rs-platform-version/src/version/v2.rs:1186-1188
Timestamp: 2024-10-03T11:51:06.980Z
Learning: In the `IdentityTransitionVersions` structure within `packages/rs-platform-version/src/version/v2.rs`, the field `credit_withdrawal` does not need the `identity_` prefix since it is already encompassed within identity state transitions.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2025-06-18T03:44:14.385Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2673
File: packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_update/mod.rs:1164-1197
Timestamp: 2025-06-18T03:44:14.385Z
Learning: QuantumExplorer determined that a CodeRabbit suggestion about fixing signable_bytes calculation in identity update tests with contract-bound keys was incorrect - the code flow is working as intended without the suggested changes.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2024-10-30T11:19:59.163Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-sdk/tests/fetch/config.rs:233-233
Timestamp: 2024-10-30T11:19:59.163Z
Learning: In the Rust SDK's `rs-sdk/tests` integration tests (e.g., in `packages/rs-sdk/tests/fetch/config.rs`), we cannot create objects during tests because there is no support for object creation in this context. Therefore, hardcoded values for test identities must be used.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci, SDK_TEST_DATA=true
    ) / Build Drive image
  • GitHub Check: Build JS packages / Build JS
  • GitHub Check: Rust crates security audit
🔇 Additional comments (4)
packages/wasm-sdk/src/state_transitions/identity/mod.rs (4)

669-709: LGTM! Credit transfer correctly uses the helper for key matching.

The implementation properly supports both ECDSA_SECP256K1 and ECDSA_HASH160 keys for transfer operations, with clear logic for both explicit key_id selection and automatic key discovery.


855-906: LGTM! Withdrawal key matching correctly prioritizes TRANSFER keys with OWNER fallback.

The implementation properly handles both ECDSA key types and appropriately supports both TRANSFER and OWNER purpose keys for withdrawal operations, with sensible fallback logic.


1030-1042: LGTM! Master key lookup now supports both ECDSA key types.

This fix resolves the core issue where identity_update failed for DashPay-created identities that use ECDSA_SECP256K1 master keys. The implementation correctly filters for AUTHENTICATION purpose and MASTER security level while now matching both ECDSA key variants.


1503-1671: LGTM! Comprehensive test coverage for the key matching helper.

The test suite thoroughly validates:

  • ECDSA_SECP256K1 matching (positive and negative)
  • ECDSA_HASH160 matching (positive and negative)
  • Non-ECDSA types correctly return false (BLS12_381, BIP13_SCRIPT_HASH, EDDSA_25519_HASH160)
  • Regression test specifically addresses the original bug where ECDSA_SECP256K1 master keys couldn't be matched

The tests use realistic key data and clear assertion messages, providing excellent protection against future regressions.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/wasm-sdk/src/state_transitions/identity/mod.rs (1)

1513-1525: Minor: Unnecessary .into() call.

The id field in IdentityPublicKeyV0 is u32, so 0u32.into() is redundant. Consider simplifying to id: 0.

Suggested simplification
     fn create_test_key(key_type: KeyType, data: Vec<u8>) -> IdentityPublicKey {
         IdentityPublicKeyV0 {
-            id: 0u32.into(),
+            id: 0,
             key_type,
             purpose: Purpose::AUTHENTICATION,
             security_level: SecurityLevel::MASTER,
             read_only: false,
             disabled_at: None,
             data: data.into(),
             contract_bounds: None,
         }
         .into()
     }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 46eb061 and f88a7cb.

📒 Files selected for processing (1)
  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Rust code must pass cargo clippy --workspace linter checks
Rust code must be formatted using cargo fmt --all

**/*.rs: Use 4-space indent for Rust files
Follow rustfmt defaults and keep code clippy-clean for Rust modules
Use snake_case for Rust module names
Use PascalCase for Rust type names
Use SCREAMING_SNAKE_CASE for Rust constants

Files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: dashpay/platform PR: 0
File: packages/swift-sdk/SwiftExampleApp/CLAUDE.md:0-0
Timestamp: 2025-11-25T13:10:38.019Z
Learning: Applies to packages/swift-sdk/SwiftExampleApp/**/{KeychainManager,*Key,*Identity}.swift : Store private keys separately from identities using iOS Keychain for secure storage; private keys belong to public keys, not identities
Learnt from: CR
Repo: dashpay/platform PR: 0
File: packages/swift-sdk/SwiftExampleApp/CLAUDE.md:0-0
Timestamp: 2025-11-25T13:10:38.019Z
Learning: Applies to packages/swift-sdk/SwiftExampleApp/**/*.swift : Always validate private keys match their public keys using KeyValidation.validatePrivateKeyForPublicKey before cryptographic operations
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2673
File: packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_update/mod.rs:1164-1197
Timestamp: 2025-06-18T03:44:14.385Z
Learning: QuantumExplorer determined that a CodeRabbit suggestion about fixing signable_bytes calculation in identity update tests with contract-bound keys was incorrect - the code flow is working as intended without the suggested changes.
📚 Learning: 2024-10-06T16:11:34.946Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2215
File: packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/create_owner_identity/v1/mod.rs:19-30
Timestamp: 2024-10-06T16:11:34.946Z
Learning: In the Rust file `packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/create_owner_identity/v1/mod.rs`, within the `create_owner_identity_v1` function, the `add_public_keys` method of the `Identity` struct cannot fail and does not require explicit error handling.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2024-11-20T20:43:41.185Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/tests/strategy_tests/masternodes.rs:212-220
Timestamp: 2024-11-20T20:43:41.185Z
Learning: In `packages/rs-drive-abci/tests/strategy_tests/masternodes.rs`, the pattern of generating a `PrivateKey`, converting it to bytes, and reconstructing a `BlsPrivateKey` from those bytes is intentional. Avoid suggesting to simplify this code in future reviews.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2025-08-05T13:55:39.147Z
Learnt from: thephez
Repo: dashpay/platform PR: 2718
File: packages/wasm-sdk/index.html:0-0
Timestamp: 2025-08-05T13:55:39.147Z
Learning: The get_identity_keys_with_proof_info function in the Rust WASM bindings does not support the "search" key request type and lacks the searchPurposeMap parameter. When proof mode is enabled with keyRequestType === 'search', the implementation falls back to the non-proof version (get_identity_keys) to maintain functionality.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2024-11-20T16:05:40.200Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving.rs:148-151
Timestamp: 2024-11-20T16:05:40.200Z
Learning: In `packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving.rs`, when converting public keys from `QuorumForSavingV0` to `VerificationQuorum`, it's acceptable to use `.expect()` for public key conversion, as the conversion has been verified and panics are acceptable in this context.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2024-10-21T01:03:42.458Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2227
File: packages/rs-dpp/src/core_types/validator_set/v0/mod.rs:299-299
Timestamp: 2024-10-21T01:03:42.458Z
Learning: In the `test_serialize_deserialize_validator_set_v0` test within `packages/rs-dpp/src/core_types/validator_set/v0/mod.rs`, deterministic BLS keys cannot be easily used; therefore, using `BlsPublicKey::generate()` is acceptable.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2024-10-03T11:51:06.980Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2201
File: packages/rs-platform-version/src/version/v2.rs:1186-1188
Timestamp: 2024-10-03T11:51:06.980Z
Learning: In the `IdentityTransitionVersions` structure within `packages/rs-platform-version/src/version/v2.rs`, the field `credit_withdrawal` does not need the `identity_` prefix since it is already encompassed within identity state transitions.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2025-07-28T20:00:08.502Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2711
File: packages/wasm-sdk/AI_REFERENCE.md:771-783
Timestamp: 2025-07-28T20:00:08.502Z
Learning: In packages/wasm-sdk/AI_REFERENCE.md, the documentation correctly shows the actual SDK method signatures (including identityCreate and identityTopUp with their full parameter lists), which may differ from the UI inputs shown in fixed_definitions.json. The UI may collect fewer parameters from users while handling additional requirements internally.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
📚 Learning: 2024-10-30T11:19:59.163Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-sdk/tests/fetch/config.rs:233-233
Timestamp: 2024-10-30T11:19:59.163Z
Learning: In the Rust SDK's `rs-sdk/tests` integration tests (e.g., in `packages/rs-sdk/tests/fetch/config.rs`), we cannot create objects during tests because there is no support for object creation in this context. Therefore, hardcoded values for test identities must be used.

Applied to files:

  • packages/wasm-sdk/src/state_transitions/identity/mod.rs
🧬 Code graph analysis (1)
packages/wasm-sdk/src/state_transitions/identity/mod.rs (2)
packages/wasm-sdk/src/queries/identity.rs (2)
  • key_id (51-53)
  • key_type (56-58)
packages/wasm-sdk/src/queries/mod.rs (1)
  • data (268-270)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci, SDK_TEST_DATA=true
    ) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build JS packages / Build JS
  • GitHub Check: Rust crates security audit
🔇 Additional comments (5)
packages/wasm-sdk/src/state_transitions/identity/mod.rs (5)

23-44: LGTM!

The helper function is well-designed with clear documentation. The key type matching logic is correct:

  • ECDSA_SECP256K1 stores 33-byte compressed public key, so direct comparison is appropriate
  • ECDSA_HASH160 stores 20-byte hash, so hash comparison is appropriate
  • Returning false for non-ECDSA types is the correct behavior since they require different key derivation

670-709: LGTM!

The helper integration in identity_credit_transfer is correct. Both the specific key lookup (by ID) and the fallback search properly combine the Purpose::TRANSFER check with the new key matching logic.


857-906: LGTM!

The helper integration in identity_credit_withdrawal is correct. The withdrawal logic properly:

  1. Accepts both TRANSFER and OWNER purpose keys
  2. Prefers TRANSFER keys before falling back to OWNER keys
  3. Uses the helper in all three matching closures

1030-1046: LGTM!

This is the core fix. The master key lookup in identity_update now correctly supports both ECDSA_SECP256K1 and ECDSA_HASH160 key types, resolving the original bug where DashPay identities (which use ECDSA_SECP256K1) couldn't be updated.


1527-1694: LGTM!

Excellent test coverage with 5 well-structured tests:

  1. test_private_key_matches_ecdsa_secp256k1 - verifies 33-byte key matching
  2. test_private_key_matches_ecdsa_hash160 - verifies 20-byte hash matching
  3. test_private_key_does_not_match_bls_keys - ensures BLS keys are rejected
  4. test_private_key_does_not_match_other_key_types - ensures other types are rejected
  5. test_regression_secp256k1_key_not_mistaken_for_hash160 - regression test documenting the original bug

The regression test at lines 1660-1694 is particularly valuable as it documents the exact failure mode being fixed.

@QuantumExplorer QuantumExplorer merged commit ccee0b4 into v3.0-dev Jan 3, 2026
27 of 28 checks passed
@QuantumExplorer QuantumExplorer deleted the fix/wasm-sdk-identity-update-key-types branch January 3, 2026 00:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants