Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Build KeepKey Vault

on:
push:
branches: [master, 'release/*']
branches: [master, develop, 'release/*']
# NOTE: deliberately NOT triggering on tag push. action-gh-release creates
# the v* tag when it creates the draft release, which used to trigger a
# SECOND CI run on the tag ref. That rerun rebuilt the unsigned macOS x64
Expand All @@ -11,7 +11,7 @@ on:
# placed. v1.2.16 release hit this and had to be manually repaired.
# If you ever need to re-run CI on a tag, use workflow_dispatch.
pull_request:
branches: [master, 'release/*']
branches: [master, develop, 'release/*']
workflow_dispatch:

concurrency:
Expand Down Expand Up @@ -66,7 +66,7 @@ jobs:
uses: actions/cache@v4
with:
path: modules/proto-tx-builder/node_modules
key: proto-tx-builder-${{ runner.os }}-${{ hashFiles('modules/proto-tx-builder/package.json') }}
key: proto-tx-builder-${{ runner.os }}-${{ hashFiles('modules/proto-tx-builder/package.json', 'modules/proto-tx-builder/yarn.lock') }}

- name: Cache hdwallet
uses: actions/cache@v4
Expand Down Expand Up @@ -100,8 +100,8 @@ jobs:
yarn tsc --build

cd ../proto-tx-builder
bun install
git submodule update --init osmosis-frontend
yarn install --frozen-lockfile
npx tsc -p .
test -f dist/index.js

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ $(DEVICE_PROTOCOL_BUILD_STAMP): $(DEVICE_PROTOCOL_INPUTS) $(SUBMODULES_STAMP) |
# --- Module Builds (hdwallet + proto-tx-builder from source) ---

$(PROTO_INSTALL_STAMP): modules/proto-tx-builder/package.json modules/proto-tx-builder/yarn.lock $(SUBMODULES_STAMP) | $(STAMP_DIR)
cd modules/proto-tx-builder && bun install
@# Init the nested osmosis-frontend submodule (provides Cosmos/Osmosis proto codegen)
cd modules/proto-tx-builder && git submodule update --init osmosis-frontend
cd modules/proto-tx-builder && yarn install --frozen-lockfile
@touch $@

$(PROTO_BUILD_STAMP): $(PROTO_BUILD_INPUTS) $(PROTO_INSTALL_STAMP) | $(STAMP_DIR)
Expand Down
2 changes: 1 addition & 1 deletion modules/keepkey-firmware
Submodule keepkey-firmware updated 136 files
15 changes: 8 additions & 7 deletions projects/keepkey-vault/src/bun/txbuilder/zcash-deshield.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Zcash Orchard → transparent deshielding transaction builder.
* Zcash Ironwood → transparent deshielding transaction builder.
*
* Orchestrates the flow:
* 1. Sidecar builds deshield PCZT (Orchard spends + transparent output)
Expand All @@ -26,7 +26,8 @@ interface DeshieldBuildResult {
account: number
branch_id: number
sighash: string
digests: { header: string; transparent: string; orchard: string }
pool: "orchard" | "ironwood"
digests: { header: string; transparent: string; orchard: string; ironwood: string }
header_fields?: { tx_version: number; version_group_id: number; lock_time: number; expiry_height: number }
bundle_meta: { flags: number; value_balance: number; anchor: string }
actions: Array<{
Expand All @@ -45,7 +46,7 @@ interface DeshieldBuildResult {
let deshieldInProgress = false

/**
* Full deshield flow: Orchard shielded pool → transparent ZEC.
* Full deshield flow: Ironwood shielded pool → transparent ZEC.
*
* @param wallet - hdwallet instance with zcashSignPczt method
* @param params - Deshield parameters
Expand Down Expand Up @@ -108,10 +109,10 @@ async function _deshieldZecInner(
}, 600000) // Halo2 proof can take a while

const sr = buildResult.orchard_signing_request
console.log(`[zcash-deshield] PCZT built: ${sr.n_actions} Orchard actions`)
console.log(`[zcash-deshield] PCZT built: ${sr.n_actions} ${sr.pool} actions`)
console.log(`[zcash-deshield] Display: ${buildResult.display.amount} → ${buildResult.display.action}`)

// 2. Device signs Orchard actions (same as shielded send — no transparent signing needed).
// 2. Device signs Ironwood actions (no transparent signing needed).
// The transparent output MUST be declared and streamed: the firmware recomputes the
// transparent digest from plaintext (reviewing the t-address + amount on-device) and
// derives the sighash from it. Omitting it makes the device sign against the EMPTY
Expand All @@ -132,9 +133,9 @@ async function _deshieldZecInner(
throw new Error("Device did not return signatures")
}

console.log(`[zcash-deshield] Got ${signatures.length} Orchard signatures`)
console.log(`[zcash-deshield] Got ${signatures.length} Ironwood signatures`)

// 3. Finalize via sidecar — only Orchard signatures, no transparent sigs
// 3. Finalize via sidecar — only Ironwood signatures, no transparent sigs
console.log("[zcash-deshield] Finalizing deshield transaction...")
const { raw_tx, txid } = await sendCommand("finalize_deshield", {
orchard_signatures: signatures,
Expand Down
14 changes: 7 additions & 7 deletions projects/keepkey-vault/src/bun/txbuilder/zcash-shield.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Zcash transparent → Orchard shielding transaction builder.
* Zcash transparent → Ironwood shielding transaction builder.
*
* Orchestrates the flow:
* 1. Fetch transparent UTXOs (via Pioneer)
Expand Down Expand Up @@ -78,12 +78,12 @@ interface ShieldBuildResult {
transparent_inputs: TransparentSigningInput[]
transparent_outputs?: Array<{ index: number; value: number; script_pubkey: string }>
orchard_signing_request: any
digests: { header: string; transparent: string; orchard: string }
digests: { header: string; transparent: string; orchard: string; ironwood: string }
display: { amount: string; fee: string; action: string }
}

/**
* Full shield flow: transparent ZEC → Orchard shielded pool.
* Full shield flow: transparent ZEC → Ironwood shielded pool.
*
* @param wallet - hdwallet instance with zcashSignPczt + Pioneer access
* @param pioneer - Pioneer API client for UTXO lookup
Expand Down Expand Up @@ -424,13 +424,13 @@ async function _shieldZecInner(
account,
}, 600000) // Halo2 proof can take a while

console.log(`[zcash-shield] Shield PCZT built: ${buildResult.transparent_inputs.length} transparent inputs, ${buildResult.orchard_signing_request.n_actions} Orchard actions`)
console.log(`[zcash-shield] Shield PCZT built: ${buildResult.transparent_inputs.length} transparent inputs, ${buildResult.orchard_signing_request.n_actions} Ironwood actions`)

// 5. Device signs — two-phase: Orchard first, then transparent
// 5. Device signs — two-phase: Ironwood plus transparent authorization
//
// The hybrid signing protocol (ZcashTransparentInput/ZcashTransparentSig)
// requires firmware support that may not be present. Check first and
// fall back to Orchard-only signing with a clear error for transparent.
// fail with a clear error if transparent authorization is unavailable.
console.log("[zcash-shield] Requesting device signatures...")
opts?.onProgress?.("signing")

Expand Down Expand Up @@ -485,7 +485,7 @@ async function _shieldZecInner(
const transparentSigs: string[] = (signatures as any)._transparentSignatures || []
const orchardSigs: string[] = signatures

console.log(`[zcash-shield] Got ${transparentSigs.length} transparent sigs, ${orchardSigs.length} Orchard sigs`)
console.log(`[zcash-shield] Got ${transparentSigs.length} transparent sigs, ${orchardSigs.length} Ironwood sigs`)
if (transparentSigs.length > 0) {
console.log(`[zcash-shield] Transparent sig[0]: ${transparentSigs[0]?.slice(0, 40)}...`)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Zcash Orchard shielded transaction builder.
* Zcash Orchard-family shielded transaction builder (Ironwood from NU6.3).
*
* Orchestrates the three-way flow: sidecar (crypto) + device (signing) + sidecar (finalize).
*
Expand Down Expand Up @@ -51,13 +51,15 @@ export async function displayOrchardAddressOnDevice(wallet: any, account: number

export interface SigningRequest {
n_actions: number
pool: "orchard" | "ironwood"
account: number
branch_id: number
sighash: string
digests: {
header: string
transparent: string
orchard: string
ironwood: string
}
header_fields?: {
tx_version: number
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1146,7 +1146,7 @@ export function ZcashPrivacyTab() {
<section>
<div className="page-head">
<h2>Receive ZEC</h2>
<p>Share this address. Senders pay into your Orchard pool automatically.</p>
<p>Share this unified address. New shielded funds enter the Ironwood pool.</p>
</div>

<div className="card">
Expand Down
36 changes: 18 additions & 18 deletions projects/keepkey-vault/zcash-cli/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 10 additions & 11 deletions projects/keepkey-vault/zcash-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,15 @@ env_logger = "0.11"
# BLAKE2b for ZIP-244 sighash computation
blake2b_simd = "1.0"

# Zcash crates — NU6.2 cohort (all published 2026-06-03). orchard 0.14 ships
# the FixedPostNu6_2 Orchard circuit; every prior version is yanked and builds
# pre-fork proofs that current Zebra/zcashd nodes reject ("could not validate
# orchard proof"). These versions must be upgraded together.
orchard = "0.14"
zcash_address = "0.12"
zcash_protocol = "0.9"
zcash_note_encryption = "0.4"
zcash_primitives = "0.28"
zcash_keys = "0.14"
# Zcash crates — NU6.3 cohort. These versions add the post-NU6.3 Orchard
# circuit, the Ironwood value pool, v3 (quantum-recoverable) note plaintexts,
# and transaction-v6 serialization/digests. Keep this cohort in lockstep.
orchard = "0.15.4"
zcash_address = "0.13"
zcash_protocol = "0.10.3"
zcash_note_encryption = "0.4.2"
zcash_primitives = "0.30"
zcash_keys = "0.16.1"

# Lightwalletd gRPC client
tonic = { version = "0.12", features = ["tls", "tls-roots"] }
Expand All @@ -53,7 +52,7 @@ rand = "0.8"
pasta_curves = "0.5"
ff = "0.13"
incrementalmerkletree = "0.8"
shardtree = "0.6"
shardtree = "0.7"

# ZIP-32 key derivation types
zip32 = "0.2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package cash.z.wallet.sdk.rpc;
message ChainMetadata {
uint32 saplingCommitmentTreeSize = 1;
uint32 orchardCommitmentTreeSize = 2;
uint32 ironwoodCommitmentTreeSize = 3;
}

message CompactBlock {
Expand All @@ -26,6 +27,9 @@ message CompactTx {
repeated CompactOrchardAction actions = 6;
repeated CompactTxIn vin = 7;
repeated TxOut vout = 8;
// Ironwood reuses the Orchard compact action encoding, but has a distinct
// note commitment tree and nullifier set from NU6.3 onward.
repeated CompactOrchardAction ironwoodActions = 9;
}

message CompactTxIn {
Expand Down
2 changes: 2 additions & 0 deletions projects/keepkey-vault/zcash-cli/proto/service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ message GetAddressUtxosReplyList {
enum ShieldedProtocol {
sapling = 0;
orchard = 1;
ironwood = 2;
}

message SubtreeRoot {
Expand All @@ -110,6 +111,7 @@ message TreeState {
uint32 time = 4;
string saplingTree = 5;
string orchardTree = 6;
string ironwoodTree = 7;
}

service CompactTxStreamer {
Expand Down
Loading
Loading