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
2 changes: 1 addition & 1 deletion apps/extension/public/beta-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"manifest_version": 3,
"name": "zafu wallet BETA",
"short_name": "zafu BETA",
"version": "24.1.2",
"version": "24.1.3",
"description": "Zcash + Penumbra privacy wallet. Cold signing, FROST multisig, client-side proving, ed25519 app identity, verified lightclient.",
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAumLcmfQnXRpyRqpga9emIAK2NszJC0GbCtacZXNFKRr/ZvsBCasAeu91plM7BPhuFd6E9cjsJafmesmhZ3eVQijR+rrjE77coqB5Aff5otsCFd8l0+HcWcLZrpDO2HAxlJMCceylA75DzYx4ewSc/mW1e69G6xjUxb8azaWqhCK8t6bwrYCN7YGhRYjpNzbHRtB3EA/6lf8kEVMFrTX/wlD+AJMo+Yq5ggikECK4VmRAoAxM4M+hE4M3LtKypMrj2q0+wqnMU+NdyIyMaEeEl8UbsuP6UymQf1j+NIcAkoS4HCHA9oZ68GRzDH2cpXf+TaQJnmEAnI9cjpaUiU1TFQIDAQAB",
"minimum_chrome_version": "119",
Expand Down
2 changes: 1 addition & 1 deletion apps/extension/public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"manifest_version": 3,
"name": "zafu wallet",
"short_name": "zafu",
"version": "24.1.2",
"version": "24.1.3",
"description": "Zcash + Penumbra privacy wallet. Cold signing, FROST multisig, client-side proving, ed25519 app identity, verified lightclient.",
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqh6vHXkwEKpgW8bpgfPLpIfMKX7pLH7Jmefpr/8YfvsPN79tJtvujMtxo/gy2y3Sg7QcnT+hK5iycsgdSYzj/yvnL8W1eDQ1N0jFsI/o++S6iG/CLWHkbICA2fEwhKe9rA2C9O7FWBSlfIuBD6lrXEuhnTEuykmgH67mIyAQnx88pe0Sn0ZQLmpPw58bmf07iRNfZzTZ+Oy1B98Eu5GUNbiExtxM/HM96eIxzxsP0imXi8VF9o2XDNnUmQWoWouVKEkBZ4wY3ZJ3HR2S9Psrkx4JFoNsvGTQLYVrzHAbosRiQcySn8a0vYxDTnQRenztxyN8BZC0VkTx9o5Ex5lHyQIDAQAB",
"minimum_chrome_version": "119",
Expand Down
64 changes: 64 additions & 0 deletions apps/extension/public/zafu-wasm-parallel/zafu_wasm.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,19 @@ export function build_shielding_transaction(utxos_json: string, privkey_hex: str
*/
export function build_signed_spend_transaction(seed_phrase: string, notes_json: any, recipient: string, amount: bigint, fee: bigint, anchor_hex: string, merkle_paths_json: any, account_index: number, mainnet: boolean, memo_hex?: string | null): string;

/**
* Build a PCZT for cold-wallet signing via QR.
*
* `target_height` selects the consensus branch; pass any height ≥ NU6.1
* activation for current mainnet operations. The tx version is derived from
* network upgrade rules (currently V5).
*
* Returns JSON: `{ pczt_hex, summary, action_count }`.
* The TS layer wraps `pczt_hex` in CBOR `{1: bytes}` and UR-encodes as
* `zcash-pczt` for animated QR transport.
*/
export function build_unsigned_pczt(ufvk_str: string, notes_json: any, recipient: string, amount: bigint, fee: bigint, anchor_hex: string, merkle_paths_json: any, target_height: number, mainnet: boolean, memo_hex?: string | null): any;

/**
* Build an unsigned shielding transaction (transparent → orchard) for cold-wallet signing.
*
Expand Down Expand Up @@ -260,6 +273,18 @@ export function derive_transparent_privkey(seed_phrase: string, account: number,
*/
export function encode_notes_bundle(notes_json: string, merkle_result_json: string, anchor_height: number, mainnet: boolean, attestation_hex?: string | null): Uint8Array;

/**
* Extract a broadcast-ready v5 transaction from a signed PCZT returned by zigner.
*
* Replaces the legacy `parse_signature_response` + `complete_transaction` pair.
* Instead of patching raw signature bytes into a hand-serialized tx, we let the
* pczt crate's `TransactionExtractor` reassemble the canonical v5 transaction
* from the signed PCZT (collecting all auth sigs and validating the proof).
*
* Returns hex-encoded transaction bytes ready for broadcast.
*/
export function extract_signed_tx_from_pczt(pczt_hex: string): string;

/**
* Compute the tree size from a hex-encoded frontier.
*/
Expand Down Expand Up @@ -447,6 +472,23 @@ export function transparent_pubkey_from_ufvk(ufvk_str: string, address_index: nu
*/
export function tree_root_hex(tree_state_hex: string): string;

/**
* Decode UR-encoded animated QR string frames back into CBOR bytes.
*
* Accepts a JSON array of UR strings (each `ur:<type>/...`) collected from
* successive scans of an animated QR. Returns the reconstructed payload bytes
* once the fountain decoder has enough frames (deduplicated internally), or an
* error if the parts are malformed or the fountain code can't yet reconstruct.
*
* `expected_type` is a sanity check: if non-empty, parts whose UR type doesn't
* match are rejected. Pass `""` to accept any type.
*
* Returns hex-encoded payload bytes (caller can hex_decode if it wants raw).
* We return hex (rather than `Vec<u8>` directly) to avoid a wasm-bindgen
* `Uint8Array` allocation pattern that's been flaky for us in some browsers.
*/
export function ur_decode_frames(parts_json: string, expected_type: string): string;

/**
* Encode CBOR bytes as UR-encoded animated QR string frames.
* Returns JSON array of UR strings suitable for QR display.
Expand All @@ -460,6 +502,24 @@ export function ur_encode_frames(cbor_data: Uint8Array, ur_type: string, fragmen
*/
export function validate_seed_phrase(seed_phrase: string): boolean;

/**
* Authoritatively validate a Unified Full Viewing Key string.
*
* Returns `true` iff the string decodes via the *same*
* `zcash_keys::UnifiedFullViewingKey::decode` the signing path uses. This
* is deliberately the one and only UFVK decoder: a separate hand-rolled
* bech32m/checksum validator at the import boundary would be a second
* implementation that can disagree with the authority, which is worse than
* no check. Structural pre-screening (HRP/charset/length) still happens in
* the pure `@repo/wallet` parser for cheap fail-fast and to keep that
* package wasm-free; this is the cryptographic gate the import dispatch
* calls before persisting a wallet record.
*
* Network is inferred from the HRP (`uview1` = mainnet, else testnet),
* matching every other UFVK entry point in this module.
*/
export function validate_ufvk(ufvk_str: string): boolean;

/**
* Get library version
*/
Expand Down Expand Up @@ -512,6 +572,7 @@ export interface InitOutput {
readonly build_merkle_paths: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number];
readonly build_shielding_transaction: (a: number, b: number, c: number, d: number, e: number, f: number, g: bigint, h: bigint, i: number, j: number) => [number, number, number, number];
readonly build_signed_spend_transaction: (a: number, b: number, c: any, d: number, e: number, f: bigint, g: bigint, h: number, i: number, j: any, k: number, l: number, m: number, n: number) => [number, number, number, number];
readonly build_unsigned_pczt: (a: number, b: number, c: any, d: number, e: number, f: bigint, g: bigint, h: number, i: number, j: any, k: number, l: number, m: number, n: number) => [number, number, number];
readonly build_unsigned_shielding_transaction: (a: number, b: number, c: number, d: number, e: bigint, f: bigint, g: number, h: number) => [number, number, number, number];
readonly build_unsigned_transaction: (a: number, b: number, c: any, d: number, e: number, f: bigint, g: bigint, h: number, i: number, j: any, k: number, l: number, m: number, n: number) => [number, number, number];
readonly build_witnesses_and_paths: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number];
Expand All @@ -520,15 +581,18 @@ export interface InitOutput {
readonly create_sign_request: (a: number, b: number, c: number, d: any, e: number, f: number) => [number, number, number, number];
readonly derive_transparent_privkey: (a: number, b: number, c: number, d: number) => [number, number, number, number];
readonly encode_notes_bundle: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => [number, number, number, number];
readonly extract_signed_tx_from_pczt: (a: number, b: number) => [number, number, number, number];
readonly frontier_tree_size: (a: number, b: number) => [bigint, number, number];
readonly generate_seed_phrase: () => [number, number, number, number];
readonly get_commitment_proof_request: (a: number, b: number) => [number, number, number, number];
readonly parse_signature_response: (a: number, b: number) => [number, number, number];
readonly transparent_address_from_ufvk: (a: number, b: number, c: number) => [number, number, number, number];
readonly transparent_pubkey_from_ufvk: (a: number, b: number, c: number) => [number, number, number, number];
readonly tree_root_hex: (a: number, b: number) => [number, number, number, number];
readonly ur_decode_frames: (a: number, b: number, c: number, d: number) => [number, number, number, number];
readonly ur_encode_frames: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
readonly validate_seed_phrase: (a: number, b: number) => number;
readonly validate_ufvk: (a: number, b: number) => number;
readonly version: () => [number, number];
readonly walletkeys_calculate_balance: (a: number, b: any, c: any) => [bigint, number, number];
readonly walletkeys_decrypt_transaction_memos: (a: number, b: number, c: number) => [number, number, number];
Expand Down
139 changes: 138 additions & 1 deletion apps/extension/public/zafu-wasm-parallel/zafu_wasm.js
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,44 @@ export function build_signed_spend_transaction(seed_phrase, notes_json, recipien
}
}

/**
* Build a PCZT for cold-wallet signing via QR.
*
* `target_height` selects the consensus branch; pass any height ≥ NU6.1
* activation for current mainnet operations. The tx version is derived from
* network upgrade rules (currently V5).
*
* Returns JSON: `{ pczt_hex, summary, action_count }`.
* The TS layer wraps `pczt_hex` in CBOR `{1: bytes}` and UR-encodes as
* `zcash-pczt` for animated QR transport.
* @param {string} ufvk_str
* @param {any} notes_json
* @param {string} recipient
* @param {bigint} amount
* @param {bigint} fee
* @param {string} anchor_hex
* @param {any} merkle_paths_json
* @param {number} target_height
* @param {boolean} mainnet
* @param {string | null} [memo_hex]
* @returns {any}
*/
export function build_unsigned_pczt(ufvk_str, notes_json, recipient, amount, fee, anchor_hex, merkle_paths_json, target_height, mainnet, memo_hex) {
const ptr0 = passStringToWasm0(ufvk_str, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passStringToWasm0(recipient, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
const ptr2 = passStringToWasm0(anchor_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len2 = WASM_VECTOR_LEN;
var ptr3 = isLikeNone(memo_hex) ? 0 : passStringToWasm0(memo_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len3 = WASM_VECTOR_LEN;
const ret = wasm.build_unsigned_pczt(ptr0, len0, notes_json, ptr1, len1, amount, fee, ptr2, len2, merkle_paths_json, target_height, mainnet, ptr3, len3);
if (ret[2]) {
throw takeFromExternrefTable0(ret[1]);
}
return takeFromExternrefTable0(ret[0]);
}

/**
* Build an unsigned shielding transaction (transparent → orchard) for cold-wallet signing.
*
Expand Down Expand Up @@ -790,6 +828,39 @@ export function encode_notes_bundle(notes_json, merkle_result_json, anchor_heigh
return v4;
}

/**
* Extract a broadcast-ready v5 transaction from a signed PCZT returned by zigner.
*
* Replaces the legacy `parse_signature_response` + `complete_transaction` pair.
* Instead of patching raw signature bytes into a hand-serialized tx, we let the
* pczt crate's `TransactionExtractor` reassemble the canonical v5 transaction
* from the signed PCZT (collecting all auth sigs and validating the proof).
*
* Returns hex-encoded transaction bytes ready for broadcast.
* @param {string} pczt_hex
* @returns {string}
*/
export function extract_signed_tx_from_pczt(pczt_hex) {
let deferred3_0;
let deferred3_1;
try {
const ptr0 = passStringToWasm0(pczt_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.extract_signed_tx_from_pczt(ptr0, len0);
var ptr2 = ret[0];
var len2 = ret[1];
if (ret[3]) {
ptr2 = 0; len2 = 0;
throw takeFromExternrefTable0(ret[2]);
}
deferred3_0 = ptr2;
deferred3_1 = len2;
return getStringFromWasm0(ptr2, len2);
} finally {
wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
}
}

/**
* Compute the tree size from a hex-encoded frontier.
* @param {string} tree_state_hex
Expand Down Expand Up @@ -1579,6 +1650,47 @@ export function tree_root_hex(tree_state_hex) {
}
}

/**
* Decode UR-encoded animated QR string frames back into CBOR bytes.
*
* Accepts a JSON array of UR strings (each `ur:<type>/...`) collected from
* successive scans of an animated QR. Returns the reconstructed payload bytes
* once the fountain decoder has enough frames (deduplicated internally), or an
* error if the parts are malformed or the fountain code can't yet reconstruct.
*
* `expected_type` is a sanity check: if non-empty, parts whose UR type doesn't
* match are rejected. Pass `""` to accept any type.
*
* Returns hex-encoded payload bytes (caller can hex_decode if it wants raw).
* We return hex (rather than `Vec<u8>` directly) to avoid a wasm-bindgen
* `Uint8Array` allocation pattern that's been flaky for us in some browsers.
* @param {string} parts_json
* @param {string} expected_type
* @returns {string}
*/
export function ur_decode_frames(parts_json, expected_type) {
let deferred4_0;
let deferred4_1;
try {
const ptr0 = passStringToWasm0(parts_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passStringToWasm0(expected_type, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
const ret = wasm.ur_decode_frames(ptr0, len0, ptr1, len1);
var ptr3 = ret[0];
var len3 = ret[1];
if (ret[3]) {
ptr3 = 0; len3 = 0;
throw takeFromExternrefTable0(ret[2]);
}
deferred4_0 = ptr3;
deferred4_1 = len3;
return getStringFromWasm0(ptr3, len3);
} finally {
wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
}
}

/**
* Encode CBOR bytes as UR-encoded animated QR string frames.
* Returns JSON array of UR strings suitable for QR display.
Expand Down Expand Up @@ -1624,6 +1736,31 @@ export function validate_seed_phrase(seed_phrase) {
return ret !== 0;
}

/**
* Authoritatively validate a Unified Full Viewing Key string.
*
* Returns `true` iff the string decodes via the *same*
* `zcash_keys::UnifiedFullViewingKey::decode` the signing path uses. This
* is deliberately the one and only UFVK decoder: a separate hand-rolled
* bech32m/checksum validator at the import boundary would be a second
* implementation that can disagree with the authority, which is worse than
* no check. Structural pre-screening (HRP/charset/length) still happens in
* the pure `@repo/wallet` parser for cheap fail-fast and to keep that
* package wasm-free; this is the cryptographic gate the import dispatch
* calls before persisting a wallet record.
*
* Network is inferred from the HRP (`uview1` = mainnet, else testnet),
* matching every other UFVK entry point in this module.
* @param {string} ufvk_str
* @returns {boolean}
*/
export function validate_ufvk(ufvk_str) {
const ptr0 = passStringToWasm0(ufvk_str, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.validate_ufvk(ptr0, len0);
return ret !== 0;
}

/**
* Get library version
* @returns {string}
Expand Down Expand Up @@ -2081,7 +2218,7 @@ function __wbg_get_imports(memory) {
table.set(offset + 2, true);
table.set(offset + 3, false);
},
memory: memory || new WebAssembly.Memory({initial:50,maximum:32768,shared:true}),
memory: memory || new WebAssembly.Memory({initial:51,maximum:32768,shared:true}),
};
return {
__proto__: null,
Expand Down
Binary file modified apps/extension/public/zafu-wasm-parallel/zafu_wasm_bg.wasm
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const address_from_ufvk: (a: number, b: number, c: number) => [number, nu
export const build_merkle_paths: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number];
export const build_shielding_transaction: (a: number, b: number, c: number, d: number, e: number, f: number, g: bigint, h: bigint, i: number, j: number) => [number, number, number, number];
export const build_signed_spend_transaction: (a: number, b: number, c: any, d: number, e: number, f: bigint, g: bigint, h: number, i: number, j: any, k: number, l: number, m: number, n: number) => [number, number, number, number];
export const build_unsigned_pczt: (a: number, b: number, c: any, d: number, e: number, f: bigint, g: bigint, h: number, i: number, j: any, k: number, l: number, m: number, n: number) => [number, number, number];
export const build_unsigned_shielding_transaction: (a: number, b: number, c: number, d: number, e: bigint, f: bigint, g: number, h: number) => [number, number, number, number];
export const build_unsigned_transaction: (a: number, b: number, c: any, d: number, e: number, f: bigint, g: bigint, h: number, i: number, j: any, k: number, l: number, m: number, n: number) => [number, number, number];
export const build_witnesses_and_paths: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number];
Expand All @@ -14,15 +15,18 @@ export const complete_transaction: (a: number, b: number, c: any, d: any) => [nu
export const create_sign_request: (a: number, b: number, c: number, d: any, e: number, f: number) => [number, number, number, number];
export const derive_transparent_privkey: (a: number, b: number, c: number, d: number) => [number, number, number, number];
export const encode_notes_bundle: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => [number, number, number, number];
export const extract_signed_tx_from_pczt: (a: number, b: number) => [number, number, number, number];
export const frontier_tree_size: (a: number, b: number) => [bigint, number, number];
export const generate_seed_phrase: () => [number, number, number, number];
export const get_commitment_proof_request: (a: number, b: number) => [number, number, number, number];
export const parse_signature_response: (a: number, b: number) => [number, number, number];
export const transparent_address_from_ufvk: (a: number, b: number, c: number) => [number, number, number, number];
export const transparent_pubkey_from_ufvk: (a: number, b: number, c: number) => [number, number, number, number];
export const tree_root_hex: (a: number, b: number) => [number, number, number, number];
export const ur_decode_frames: (a: number, b: number, c: number, d: number) => [number, number, number, number];
export const ur_encode_frames: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
export const validate_seed_phrase: (a: number, b: number) => number;
export const validate_ufvk: (a: number, b: number) => number;
export const version: () => [number, number];
export const walletkeys_calculate_balance: (a: number, b: any, c: any) => [bigint, number, number];
export const walletkeys_decrypt_transaction_memos: (a: number, b: number, c: number) => [number, number, number];
Expand Down
Loading
Loading