Skip to content
Draft
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
12 changes: 12 additions & 0 deletions packages/wasm-utxo/Cargo.lock

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

5 changes: 3 additions & 2 deletions packages/wasm-utxo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ unexpected_cfgs = { level = "warn", check-cfg = [

[features]
default = []
inspect = ["dep:num-bigint", "dep:serde", "dep:serde_json", "dep:hex"]
inspect = ["dep:num-bigint", "dep:serde_json", "dep:hex"]

[dependencies]
wasm-bindgen = "0.2"
Expand All @@ -33,7 +33,8 @@ musig2 = { version = "0.3.1", default-features = false, features = ["k256"] }
getrandom = { version = "0.2", features = ["js"] }
pastey = "0.1"
num-bigint = { version = "0.4", optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }
serde = { version = "1.0", features = ["derive"] }
serde-wasm-bindgen = "0.6"
serde_json = { version = "1.0", optional = true }
hex = { version = "0.4", optional = true }

Expand Down
523 changes: 523 additions & 0 deletions packages/wasm-utxo/bips/bip-0352/bip-0352.mediawiki

Large diffs are not rendered by default.

380 changes: 380 additions & 0 deletions packages/wasm-utxo/bips/bip-0352/reference.py

Large diffs are not rendered by default.

5,729 changes: 5,729 additions & 0 deletions packages/wasm-utxo/bips/bip-0352/vectors/send_and_receive_test_vectors.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/wasm-utxo/js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export * as inscriptions from "./inscriptions.js";
export * as message from "./message.js";
export * as utxolibCompat from "./utxolibCompat.js";
export * as fixedScriptWallet from "./fixedScriptWallet/index.js";
export * as silentPayments from "./silentPayments.js";
export * as descriptorWallet from "./descriptorWallet/index.js";
export * as bip32 from "./bip32.js";
export * as ecpair from "./ecpair.js";
Expand Down
130 changes: 130 additions & 0 deletions packages/wasm-utxo/js/silentPayments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { SilentPaymentsNamespace } from "./wasm/wasm_utxo.js";

export interface SilentPaymentAddressComponents {
scanKey: Uint8Array; // 33-byte compressed
spendKey: Uint8Array; // 33-byte compressed
}

export interface DerivedOutput {
script: Uint8Array; // P2TR scriptPubKey
pubkey: Uint8Array; // 32-byte x-only
tweak: Uint8Array; // 32-byte t_k
}

export interface ScanMatch {
outputIndex: number;
tweak: Uint8Array; // 32-byte t_k
k: number;
label: number | null;
labelTweak: Uint8Array | null; // 32-byte label tweak (if label matched)
}

export interface PrivkeyInput {
key: Uint8Array; // 32-byte private key
isTaproot: boolean;
}

export interface Outpoint {
txid: Uint8Array; // 32-byte txid (LE)
vout: number;
}

export interface InputData {
privkeys: PrivkeyInput[];
outpoints: Outpoint[];
}

export interface PubkeyInput {
pubkey: Uint8Array; // 33-byte compressed pubkey
}

export interface TaprootOutputData {
pubkey: Uint8Array; // 32-byte x-only pubkey
}

export interface TxData {
inputs: PubkeyInput[];
outpoints: Outpoint[];
outputs: TaprootOutputData[];
}

/**
* Decode a silent payment address (sp1q.../tsp1q...) into its component keys.
*/
export function decodeAddress(address: string): SilentPaymentAddressComponents {
return SilentPaymentsNamespace.decode_address(address) as SilentPaymentAddressComponents;
}

/**
* Encode a silent payment address from component keys.
*
* @param scanKey 33-byte compressed scan public key
* @param spendKey 33-byte compressed spend public key
* @param network coin name ("btc", "tbtc", etc.)
*/
export function encodeAddress(scanKey: Uint8Array, spendKey: Uint8Array, network: string): string {
return SilentPaymentsNamespace.encode_address(scanKey, spendKey, network);
}

/**
* Derive output scripts for sending to silent payment recipients.
*
* @param inputData private keys and outpoints from the transaction inputs
* @param recipients array of SP address strings (sp1q.../tsp1q...)
* @returns array of derived P2TR outputs with scripts, pubkeys, and tweaks
*/
export function deriveOutputs(inputData: InputData, recipients: string[]): DerivedOutput[] {
return SilentPaymentsNamespace.derive_outputs(inputData, recipients) as DerivedOutput[];
}

/**
* Scan a transaction for silent payment outputs addressed to this receiver.
*
* @param scanKey 32-byte b_scan private key
* @param spendPubkey 33-byte B_spend public key
* @param txData transaction data (input pubkeys, outpoints, taproot outputs)
* @param labels optional array of label indices to check
* @returns array of matched outputs with tweaks
*/
export function scanTransaction(
scanKey: Uint8Array,
spendPubkey: Uint8Array,
txData: TxData,
labels?: number[] | null,
): ScanMatch[] {
return SilentPaymentsNamespace.scan_transaction(
scanKey,
spendPubkey,
txData,
labels ?? null,
) as ScanMatch[];
}

/**
* Derive the private key for spending a matched silent payment output.
*
* @param spendKey 32-byte b_spend private key
* @param tweak 32-byte t_k from scanTransaction
* @returns 32-byte derived private key p_k
*/
export function deriveSpendKey(spendKey: Uint8Array, tweak: Uint8Array): Uint8Array {
return SilentPaymentsNamespace.derive_spend_key(spendKey, tweak);
}

/**
* Create a labeled silent payment address.
*
* @param scanKey 32-byte b_scan private key
* @param spendPubkey 33-byte B_spend public key
* @param labelIndex the label index m
* @param network coin name ("btc", "tbtc", etc.)
* @returns the labeled sp1q.../tsp1q... address string
*/
export function createLabeledAddress(
scanKey: Uint8Array,
spendPubkey: Uint8Array,
labelIndex: number,
network: string,
): string {
return SilentPaymentsNamespace.create_labeled_address(scanKey, spendPubkey, labelIndex, network);
}
6 changes: 6 additions & 0 deletions packages/wasm-utxo/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,9 @@ impl From<crate::address::AddressError> for WasmUtxoError {
WasmUtxoError::StringError(err.to_string())
}
}

impl From<crate::silent_payments::SilentPaymentError> for WasmUtxoError {
fn from(err: crate::silent_payments::SilentPaymentError) -> Self {
WasmUtxoError::StringError(err.to_string())
}
}
1 change: 1 addition & 0 deletions packages/wasm-utxo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ mod networks;
pub mod p2mr;
pub mod paygo;
pub mod psbt_ops;
pub mod silent_payments;
#[cfg(test)]
mod test_utils;
pub mod zcash;
Expand Down
Loading
Loading