Skip to content

[#1924] Add Android voting delegation prep and signing#1942

Merged
nullcopy merged 22 commits into
mainfrom
greg/voting-delegation-prep
May 12, 2026
Merged

[#1924] Add Android voting delegation prep and signing#1942
nullcopy merged 22 commits into
mainfrom
greg/voting-delegation-prep

Conversation

@greg0x

@greg0x greg0x commented May 10, 2026

Copy link
Copy Markdown
Collaborator

Part of zodl-inc/zodl-android#2193.
Slice of #1924 (umbrella draft PR being split into reviewable pieces).
Depends on #1938 (second slice — voting DB handle and round lifecycle).
Resolves MOB-1109

Why

Third slice of the Android shielded-voting integration. #1938 added the voting DB handle and round lifecycle; this PR adds the prep and signing surface needed before delegation proof generation: bundle setup with per-bundle weights, hotkey derivation, governance PCZT construction, sighash extraction, and spend-auth signature extraction. Proving-cache warmup is included so callers can amortize key loading before the first proof.

Vertical SDK slice — each new JNI symbol has a matching Rust handler, Kotlin external fun, FFI model, and typesafe wrapper. No app-side wiring yet — that follows once the proof-generation slice lands.

What's in

Rust / JNI (backend-lib/src/main/rust/voting/):

  • notes.rscomputeBundleSetup, setupBundles, generateHotkey
  • rounds.rsgetBundleCount (added to existing module)
  • delegation.rsbuildGovernancePcztJson, extractPcztSighash, extractSpendAuthSig
  • util.rswarmProvingCaches
  • helpers.rs — width-checked casts (u32_to_jint, u64_to_jlong, usize_to_jint), network_from_id, orchard_fvk_bytes, hotkey_orchard_raw_address_from_wallet_seed, coin_type_for, NU6_BRANCH_ID, FFI builders for FfiVotingHotkey and FfiBundleSetupResult, round-phase guards (update_round_phase_forward, require_round_phase_for_delegation_construction), bundle helpers (bundle_setup_from_notes, bundled_notes_for_index)
  • json.rsJsonNoteInfo, JsonGovernancePczt (trimmed envelope), hex enc/dec, json_from_jstring

Bundle note identity persistence and validation are owned by zcash_voting 0.5.8 (VotingDb::setup_bundles + build_governance_pczt) — the Android side does not maintain a sidecar table.

Kotlin (sdk-lib/.../internal/):

  • jni/VotingRustBackend.ktexternal fun declarations for the new surface
  • TypesafeVotingBackend.kt + impl — suspend wrappers, native { … } helper that loads the library and dispatches on Dispatchers.IO, JSON → GovernancePcztResult parsing using the SDK's existing String.fromHex extension
  • model/voting/FfiVotingModels.ktFfiBundleSetupResult, FfiVotingHotkey (publicKey + address only — secret key stays in Rust), HotkeyPublicKey (size-validated constructor)
  • jni/JniConstants.ktJNI_HOTKEY_PUBLIC_KEY_BYTES_SIZE
  • ext/BlockExt.ktString.fromHex() made strict (rejects odd length and non-hex characters) now that it's on the JNI parse path

Not included

  • PIR precompute
  • delegation proof generation
  • delegation submission (Keystone or otherwise)
  • vote tree sync / VAN witnesses / vote commitment
  • recovery and share-tracking state
  • public Synchronizer voting API

Review focus

Primary review track: core-dev. Please look at:

  • Governance PCZT JSON envelope — only pczt_bytes / rk / action_index / pczt_sighash cross JNI. The rest of the delegation-data fields (alpha, rseed_*, padded_note_secrets, gov_nullifiers, …) are persisted by zcash_voting's store_delegation_data and read back in the proof-generation slice.
  • Byte-boundary validationjava_bytes, java_bytes_at_least, java_bytes32, fixed-width require_len / require_min_len, and width-checked u32/u64jint/jlong casts.
  • Hotkey derivation and surfacehotkey_orchard_raw_address_from_wallet_seed derives the Orchard raw address from the wallet seed at the supplied account_index, using Scope::External at index 0. The 32-byte hotkey secret key is intentionally not surfaced across JNI — it stays inside VotingDb and is used internally during PCZT construction / proof generation.
  • Round-phase guards
    • update_round_phase_forward uses an atomic conditional UPDATE (WHERE phase < ?1), so two concurrent callers cannot both advance from the same starting phase; idempotent re-advances return Ok, regressions return Err.
    • buildGovernancePczt is gated by require_round_phase_for_delegation_construction: requires HotkeyGenerated, rejects if the round has already advanced past DelegationConstructed.
  • setupBundles parity / retry contract — the chunker output is recomputed in Rust and compared against VotingDb::setup_bundles' return values to catch divergence; on mismatch the JNI returns Err. The DB write has already happened at that point, so callers must clearRound and retry; this is a hard-stop bug indicator, not a recoverable error.
  • extractSpendAuthSig failure mode — returns a descriptive Err if the action at action_index has no spend_auth_sig (e.g. PCZT not yet signed) or action_index is out of bounds; never silently returns zeroed bytes.
  • native { } helper in TypesafeVotingBackendImpl.kt — calls RustBackend.loadLibrary() before every dispatched block; idempotent and matches the pattern in RustDerivationTool / RustEip681Tool / TorClient.
  • Kotlin surface is intentionally internal and minimal.

Swift counterpart:

Validation

  • cargo check --manifest-path backend-lib/Cargo.toml --locked (pinned to zcash_voting 0.5.8)
  • cargo fmt --manifest-path backend-lib/Cargo.toml --check
  • ./gradlew :backend-lib:compileReleaseKotlin :sdk-lib:compileReleaseKotlin
  • ./gradlew ktlint detektAll
  • ./gradlew checkProperties
  • git diff --check

Author

  • Self-review your own code in GitHub web interface
  • Add automated tests as appropriate
  • Update the manual tests as appropriate
  • Check the code coverage report for the automated tests
  • Update documentation as appropriate
  • Run the demo app and try the changes
  • Pull in the latest changes from the main branch and squash your commits before assigning a reviewer

Reviewer

  • Check the code with the Code Review Guidelines checklist
  • Perform an ad hoc review
  • Review the automated tests
  • Review the manual tests
  • Review the documentation as appropriate
  • Run the demo app and try the changes

Comment thread backend-lib/src/main/rust/voting/helpers.rs Outdated
Comment thread backend-lib/src/main/rust/voting/helpers.rs
Comment thread backend-lib/Cargo.toml Outdated
Comment thread backend-lib/src/main/rust/voting/delegation.rs
Comment thread backend-lib/src/main/rust/voting/notes.rs Outdated
Comment thread backend-lib/src/main/rust/voting/notes.rs
Comment thread backend-lib/src/main/rust/voting/helpers.rs
Comment thread backend-lib/src/main/rust/voting/helpers.rs Outdated
Comment thread sdk-lib/src/main/java/cash/z/ecc/android/sdk/ext/BlockExt.kt
Comment thread backend-lib/src/main/rust/voting/delegation.rs
Comment thread backend-lib/src/main/rust/voting/helpers.rs Outdated
Comment thread backend-lib/src/main/rust/voting/helpers.rs
greg0x added a commit to valargroup/zcash-android-wallet-sdk that referenced this pull request May 11, 2026
greg0x added a commit to valargroup/zcash-android-wallet-sdk that referenced this pull request May 11, 2026
greg0x added a commit to valargroup/zcash-android-wallet-sdk that referenced this pull request May 11, 2026
@greg0x greg0x force-pushed the greg/voting-delegation-prep branch from 563de2a to 313157f Compare May 11, 2026 18:42
greg0x added a commit that referenced this pull request May 11, 2026
greg0x added a commit that referenced this pull request May 11, 2026
greg0x added a commit that referenced this pull request May 11, 2026
greg0x added a commit that referenced this pull request May 11, 2026
greg0x added a commit that referenced this pull request May 11, 2026
greg0x added a commit that referenced this pull request May 11, 2026
greg0x added a commit that referenced this pull request May 11, 2026
@greg0x greg0x force-pushed the greg/voting-delegation-prep branch from d808d3f to 442130a Compare May 11, 2026 23:52
Base automatically changed from greg/voting-jni-db-rounds to main May 12, 2026 00:23
@greg0x greg0x force-pushed the greg/voting-delegation-prep branch from 442130a to 589900b Compare May 12, 2026 08:49
Comment thread backend-lib/src/main/rust/voting/helpers.rs
Comment thread backend-lib/src/main/rust/voting/helpers.rs Outdated
Comment thread backend-lib/src/main/rust/voting/helpers.rs
Comment thread backend-lib/src/main/rust/voting/util.rs
@noop-sk noop-sk requested a review from nullcopy May 12, 2026 10:46

@nullcopy nullcopy 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.

utACK 981ca36

@nullcopy nullcopy merged commit ed1b318 into main May 12, 2026
15 checks passed
@nullcopy nullcopy deleted the greg/voting-delegation-prep branch May 12, 2026 15:04
@linear

linear Bot commented Jun 1, 2026

Copy link
Copy Markdown

MOB-1109

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.

5 participants