Skip to content

[#1924] Add Android shielded-voting JNI foundation, round lifecycle, and delegation prep + signing#7

Closed
greg0x wants to merge 5 commits into
greg/voting-jni-db-roundsfrom
greg/voting-delegation-prep
Closed

[#1924] Add Android shielded-voting JNI foundation, round lifecycle, and delegation prep + signing#7
greg0x wants to merge 5 commits into
greg/voting-jni-db-roundsfrom
greg/voting-delegation-prep

Conversation

@greg0x

@greg0x greg0x commented May 9, 2026

Copy link
Copy Markdown

Part of zodl-inc/zodl-android#2193.
Slice of zcash#1924.

Why

Land the Android-side JNI surface needed before delegation proof generation. Pulls the Rust backend onto the released zcash_voting dependency, adds the voting DB handle and round lifecycle, and exposes the prep + signing surface: bundle setup, hotkey derivation, governance PCZT construction, sighash extraction, and spend-auth signature extraction.

Vertical slice — every new JNI symbol gets a matching Rust handler, Kotlin external fun, FFI model, and typesafe wrapper. Surface is entirely internal; no public Synchronizer API yet.

What's in

Dependenciesorchard hard-pinned to =0.13.1 with unstable-voting-circuits; zcash_voting 0.5.3 with default-features = false (no PIR / tree-sync / networking pulled in).

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

Module Exports
db.rs open / close voting DB
rounds.rs initRound, getRoundState, listRounds, getBundleCount, getVotes, clearRound, deleteSkippedBundles
notes.rs computeBundleSetup, setupBundles, generateHotkey
delegation.rs buildGovernancePcztJson, extractPcztSighash, extractSpendAuthSig
share_tracking.rs computeShareNullifier
util.rs warmProvingCaches
helpers.rs byte-boundary validators, width-checked jint/jlong casts, network/coin-type/branch-id, Orchard FVK + hotkey raw-address derivation, FFI builders
json.rs JsonNoteInfo, trimmed JsonGovernancePczt envelope, hex enc/dec, json_from_jstring

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

  • jni/VotingRustBackend.ktexternal fun declarations; nested VotingDb handle guards every native call behind a Mutex and dispatches on SdkDispatchers.DATABASE_IO.
  • TypesafeVotingBackend.kt + Implsuspend wrappers, native { … } helper that calls RustBackend.loadLibrary() before every dispatched block (idempotent; matches RustDerivationTool / RustEip681Tool / TorClient), JSON → GovernancePcztResult parsing.
  • model/voting/FfiVotingModels.ktFfiRoundState, FfiRoundSummary, FfiBundleSetupResult, FfiVotingHotkey, HotkeySecretKey, HotkeyPublicKey (all with size-validated constructors).
  • jni/JniConstants.kt — hotkey key size constants.
  • ext/BlockExt.ktString.fromHex() made strict (rejects odd length and non-hex characters) since it's now on the JNI parse path.

Not in scope

  • PIR precompute
  • Delegation proof generation
  • Delegation submission (Keystone or otherwise)
  • Vote tree sync, VAN witnesses, vote commitment
  • Recovery / share-tracking state beyond the linkage symbol
  • Public Synchronizer voting API

Review focus

  • Dependency pin rationale — orchard hard-pin and default-features = false on zcash_voting are deliberate; see comment block in backend-lib/Cargo.toml.
  • 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 u32_to_jint / u64_to_jlong / usize_to_jint cast helpers.
  • setupBundles parity check — chunker output is recomputed in Rust and compared against db.setup_bundles; on mismatch the JNI returns Err. The DB write has already happened at that point, so callers should treat the mismatch as a bug rather than a recoverable error.
  • Hotkey derivationhotkey_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.
  • VotingDb handleMutex-guarded native calls, close() nulls the handle, withHandle errors on use-after-close.

Validation

  • cargo check --manifest-path backend-lib/Cargo.toml --locked
  • cargo fmt --manifest-path backend-lib/Cargo.toml --check
  • ./gradlew :backend-lib:compileReleaseKotlin :sdk-lib:compileReleaseKotlin
  • ./gradlew ktlint detektAll
  • ./gradlew checkProperties
  • git diff --check

@greg0x greg0x force-pushed the greg/voting-delegation-prep branch from 2df5f27 to 42e5920 Compare May 9, 2026 12:58
@greg0x greg0x force-pushed the greg/voting-delegation-prep branch from 42e5920 to 4c72265 Compare May 10, 2026 23:29
@greg0x greg0x changed the title [#2193] Add Android voting delegation prep and signing [#1924] Add Android shielded-voting JNI foundation, round lifecycle, and delegation prep + signing May 10, 2026
@greg0x greg0x force-pushed the greg/voting-jni-db-rounds branch from 7171d4a to f0106ae Compare May 10, 2026 23:39
@greg0x greg0x closed this May 11, 2026
greg0x added a commit that referenced this pull request May 11, 2026
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.

1 participant