Skip to content

[WAL-447] feat: Ed25519 + secp256k1 support on iOS/Android#1768

Draft
szijpeter wants to merge 17 commits into
spike/wal-1033-signum-cryptofrom
feature/wal-1033-ed25519-secp256k1-mobile
Draft

[WAL-447] feat: Ed25519 + secp256k1 support on iOS/Android#1768
szijpeter wants to merge 17 commits into
spike/wal-1033-signum-cryptofrom
feature/wal-1033-ed25519-secp256k1-mobile

Conversation

@szijpeter

@szijpeter szijpeter commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Add Ed25519 and secp256k1 support on iOS and Android, addressing the algorithm gap left by Signum (which only supports NIST curves + RSA). Uses cryptography-kotlin 0.6.0 as a supplementary crypto backend for the unsupported algorithms.

Why

Walt-id supports 8 key types. Signum handles 6 (P-256, P-384, P-521, RSA/2048/3072/4096). The 2 it cannot:

Key Type Used for Signum This PR
Ed25519 did:key, did:jwk, DID/VC interop ✅ via cryptography-kotlin
secp256k1 Bitcoin/Ethereum DIDs, blockchain VCs ✅ via cryptography-kotlin

These algorithms cannot be hardware-backed on either platform (neither Android KeyStore nor iOS Secure Enclave support them). They are software-backed keys by necessity.

Architecture

sealed class IosKey / AndroidKey
├── Hardware (Signum/Supreme)         ← P-256, RSA — platform keystore backed
│   └── create() / load() / delete()
└── Software (cryptography-kotlin)    ← Ed25519, secp256k1 — software backed
    └── create() / load(jwkBytes) / exportKeyMaterial()

No top-level companion / factory — callers go directly to the subclass they need. The type system enforces the distinction.

Persistence: PlatformKeyStore (renamed from HardwareKeyStore) stores software key material (JWK) in a SQLite column alongside hardware key metadata. Hardware keys persist in the platform keystore; software keys persist in the database.

Platform crypto providers

Platform Ed25519 secp256k1 Provider
iOS CryptoKit (via cryptography-provider-optimal) OpenSSL3 (via cryptography-provider-openssl3-prebuilt) ~5MB
Android BouncyCastle (via cryptography-provider-jdk) BouncyCastle (via cryptography-provider-jdk) Uses existing BC dep

Dependency sizes

Library Size Role
cryptography-core ~200KB Common API
cryptography-provider-optimal (iOS) ~1MB CryptoKit + Apple provider (Ed25519)
cryptography-provider-openssl3-prebuilt (iOS) ~1.4MB Prebuilt OpenSSL (secp256k1)
cryptography-provider-jdk (Android) ~200KB JCA wrapper (uses existing BouncyCastle)

What changed

Crypto module (waltid-crypto):

  • IosKey.kt / AndroidKey.kt → sealed hierarchy with Hardware + Software subclasses
  • JWKKey.ios.kt → Ed25519/secp256k1 support via SoftwareKeyOps helper
  • Added iOS tests (IosKeyTest.kt, JWKKeyIosTest.kt)
  • Rewrote AndroidKeyTest.kt with parameterized hardware + software tests

Wallet persistence (waltid-openid4vc-wallet-persistence):

  • HardwareKeyStorePlatformKeyStore (handles both hardware + software keys)
  • PlatformKeyProvider interface extended with loadSoftwareKey(), exportSoftwareKeyMaterial(), isHardwareBacked()
  • SQLite schema: added key_material TEXT column for software key JWK storage
  • IosPlatformKeyProvider / AndroidPlatformKeyProvider updated to dispatch by key type

JWS construction for EdDSA/ES256K

Signum's indispensable-josef has no JwsAlgorithm.EdDSA or JwsAlgorithm.ES256K — its JOSE types are a closed set (EC + RSA only). For software keys, JWS is constructed manually using existing utilities:

  • KeyUtils.rawSignaturePayloadForJws() — builds header + payload base64url
  • KeyUtils.signJwsWithRawSignature() — concatenates into compact serialization
  • JwsUtils.decodeJwsStrings() — parses JWS for verification

No new utility files were needed — everything reuses existing code.

Future work

  • iOS Ed25519 could use Keychain directly (Apple supports kSecAttrKeyTypeEdDSA since iOS 13) for OS-level persistence instead of SQLite
  • iOS hardware key tests need an Xcode test app (Keychain requires app bundle context)
  • If Signum adds EdDSA support (a-sit-plus/signum#162), cryptography-kotlin can be dropped

Test plan

  • iOS simulator: 17 tests pass (5 IosKey.Software + 6 JWKKey + 1 Conversion + 5 secp256k1)
  • Android emulator: 11 tests pass (5 Hardware P-256/RSA + 5 Software Ed25519/secp256k1 + 1 Conversion)
  • EUDI e2e: credential receive + present against public EUDI backends passes
  • No regressions on existing P-256/RSA operations
  • iOS hardware tests (require app bundle — TODO, tests written but need Xcode test app)

Related to WAL-447

@linear

linear Bot commented Jun 5, 2026

Copy link
Copy Markdown

WAL-447

WAL-1033

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 746e9e94-9ac6-4cb2-aa35-5221f42641dc

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@szijpeter szijpeter self-assigned this Jun 5, 2026
@szijpeter szijpeter force-pushed the feature/wal-1033-ed25519-secp256k1-mobile branch from e5b2384 to 92bd45f Compare June 5, 2026 14:28
@szijpeter szijpeter force-pushed the spike/wal-1033-signum-crypto branch from f88c5bc to d2f2aa4 Compare June 8, 2026 07:08
@szijpeter szijpeter force-pushed the feature/wal-1033-ed25519-secp256k1-mobile branch from 92bd45f to 056528c Compare June 8, 2026 07:09
@szijpeter szijpeter force-pushed the spike/wal-1033-signum-crypto branch from d2f2aa4 to e783af1 Compare June 8, 2026 07:37
@szijpeter szijpeter force-pushed the feature/wal-1033-ed25519-secp256k1-mobile branch from 056528c to 69af854 Compare June 8, 2026 07:37
@szijpeter szijpeter force-pushed the spike/wal-1033-signum-crypto branch from e783af1 to 3b66f9a Compare June 8, 2026 08:57
@szijpeter szijpeter force-pushed the feature/wal-1033-ed25519-secp256k1-mobile branch from 69af854 to 02e4409 Compare June 8, 2026 08:57
@szijpeter szijpeter force-pushed the spike/wal-1033-signum-crypto branch from 3b66f9a to 51e5e46 Compare June 8, 2026 09:37
@szijpeter szijpeter force-pushed the feature/wal-1033-ed25519-secp256k1-mobile branch from 02e4409 to 281f0bc Compare June 8, 2026 09:38
@szijpeter szijpeter force-pushed the spike/wal-1033-signum-crypto branch from 51e5e46 to 44b530d Compare June 8, 2026 09:48
@szijpeter szijpeter force-pushed the feature/wal-1033-ed25519-secp256k1-mobile branch from 281f0bc to df9f457 Compare June 8, 2026 09:48
@szijpeter szijpeter force-pushed the spike/wal-1033-signum-crypto branch from 44b530d to 8c6b5fd Compare June 8, 2026 09:52
@szijpeter szijpeter force-pushed the feature/wal-1033-ed25519-secp256k1-mobile branch from df9f457 to b7ac35b Compare June 8, 2026 09:53
@szijpeter szijpeter force-pushed the spike/wal-1033-signum-crypto branch from 8c6b5fd to 7962659 Compare June 8, 2026 09:56
@szijpeter szijpeter force-pushed the feature/wal-1033-ed25519-secp256k1-mobile branch from b7ac35b to 9db5ca8 Compare June 8, 2026 09:57
@szijpeter szijpeter force-pushed the spike/wal-1033-signum-crypto branch from 7962659 to 92556fd Compare June 8, 2026 10:01
@szijpeter szijpeter force-pushed the feature/wal-1033-ed25519-secp256k1-mobile branch 2 times, most recently from 143be5c to c5773eb Compare June 8, 2026 10:01
@szijpeter szijpeter force-pushed the spike/wal-1033-signum-crypto branch from 92556fd to 2bfda9f Compare June 8, 2026 10:05
@szijpeter szijpeter force-pushed the feature/wal-1033-ed25519-secp256k1-mobile branch from c5773eb to 6eb4763 Compare June 8, 2026 10:05
@szijpeter szijpeter force-pushed the spike/wal-1033-signum-crypto branch from 2bfda9f to 7da54e8 Compare June 8, 2026 10:30
@szijpeter szijpeter force-pushed the feature/wal-1033-ed25519-secp256k1-mobile branch 2 times, most recently from c951d06 to e2c5347 Compare June 8, 2026 11:44
@szijpeter szijpeter changed the title feat: Ed25519 + secp256k1 support on iOS/Android [WAL-477] feat: Ed25519 + secp256k1 support on iOS/Android Jun 8, 2026
@szijpeter szijpeter force-pushed the spike/wal-1033-signum-crypto branch from 26ec99d to c4d0b40 Compare June 9, 2026 11:56
@szijpeter szijpeter force-pushed the feature/wal-1033-ed25519-secp256k1-mobile branch from e2c5347 to c82fbd8 Compare June 9, 2026 11:56
@szijpeter szijpeter changed the title [WAL-477] feat: Ed25519 + secp256k1 support on iOS/Android [WAL-447] feat: Ed25519 + secp256k1 support on iOS/Android Jun 9, 2026
@szijpeter szijpeter force-pushed the spike/wal-1033-signum-crypto branch from c4d0b40 to cd1c73e Compare June 10, 2026 11:45
@szijpeter szijpeter force-pushed the feature/wal-1033-ed25519-secp256k1-mobile branch 2 times, most recently from 3dc5c3f to 3756273 Compare June 10, 2026 12:17
@szijpeter szijpeter closed this Jun 10, 2026
@szijpeter szijpeter reopened this Jun 10, 2026

@waltkb waltkb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks pretty fine in this state already

@szijpeter szijpeter force-pushed the spike/wal-1033-signum-crypto branch from cd1c73e to 2c1a8c8 Compare June 16, 2026 13:34
szijpeter added 13 commits June 16, 2026 15:47
…hy-kotlin

Signum only supports NIST curves (P-256/P-384/P-521) and RSA. This adds
Ed25519 and secp256k1 as software-backed keys using cryptography-kotlin 0.6.0:
- iOS: CryptoKit provider (Ed25519) + OpenSSL3 prebuilt (secp256k1)
- Android: JDK provider backed by BouncyCastle

Architecture changes:
- IosKey/AndroidKey refactored into sealed class with Hardware/Software subclasses
- HardwareKeyStore renamed to PlatformKeyStore, supports software key persistence
- PlatformKeyProvider extended with loadSoftwareKey/exportSoftwareKeyMaterial
- SQLite schema gains key_material column for software key JWK storage
- JWKKey.ios.kt gains Ed25519/secp256k1 support via SoftwareKeyOps helper

Bug fix: RSA sign/verify was using PKCS1 padding but Signum defaults to PSS.
@szijpeter szijpeter force-pushed the feature/wal-1033-ed25519-secp256k1-mobile branch from 3756273 to 23eb415 Compare June 16, 2026 13:48
…5519-secp256k1-mobile

# Conflicts:
#	waltid-libraries/crypto/waltid-crypto/src/androidMain/kotlin/id/walt/crypto/AndroidKey.kt
#	waltid-libraries/crypto/waltid-crypto/src/iosMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.ios.kt
@sonarqubecloud

Copy link
Copy Markdown

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.

2 participants