From 1f90f2acf794a235e38fc099c4affa90b891b14c Mon Sep 17 00:00:00 2001 From: Gabe Rodriguez Date: Wed, 9 Oct 2024 22:02:09 +0200 Subject: [PATCH 1/4] Wasm helpers for noble addrs --- packages/wasm/crate/Cargo.lock | 42 +++++++++++++------------- packages/wasm/crate/Cargo.toml | 31 ++++++++++--------- packages/wasm/crate/src/keys.rs | 39 +++++++++++++++++++++++- packages/wasm/crate/tests/test_keys.rs | 40 ++++++++++++++++++++++-- packages/wasm/src/keys.ts | 15 +++++++++ 5 files changed, 128 insertions(+), 39 deletions(-) diff --git a/packages/wasm/crate/Cargo.lock b/packages/wasm/crate/Cargo.lock index 2076d2b253..b814453641 100644 --- a/packages/wasm/crate/Cargo.lock +++ b/packages/wasm/crate/Cargo.lock @@ -805,7 +805,7 @@ dependencies = [ [[package]] name = "decaf377-fmd" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "ark-ff", "ark-serialize", @@ -819,7 +819,7 @@ dependencies = [ [[package]] name = "decaf377-ka" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "ark-ff", "decaf377", @@ -2104,7 +2104,7 @@ dependencies = [ [[package]] name = "penumbra-asset" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2142,7 +2142,7 @@ dependencies = [ [[package]] name = "penumbra-auction" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2187,7 +2187,7 @@ dependencies = [ [[package]] name = "penumbra-community-pool" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2217,7 +2217,7 @@ dependencies = [ [[package]] name = "penumbra-compact-block" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2248,7 +2248,7 @@ dependencies = [ [[package]] name = "penumbra-dex" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2301,7 +2301,7 @@ dependencies = [ [[package]] name = "penumbra-distributions" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "async-trait", @@ -2317,7 +2317,7 @@ dependencies = [ [[package]] name = "penumbra-fee" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2341,7 +2341,7 @@ dependencies = [ [[package]] name = "penumbra-governance" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2390,7 +2390,7 @@ dependencies = [ [[package]] name = "penumbra-ibc" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2425,7 +2425,7 @@ dependencies = [ [[package]] name = "penumbra-keys" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "aes", "anyhow", @@ -2469,7 +2469,7 @@ dependencies = [ [[package]] name = "penumbra-num" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2505,7 +2505,7 @@ dependencies = [ [[package]] name = "penumbra-proof-params" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ec", @@ -2530,7 +2530,7 @@ dependencies = [ [[package]] name = "penumbra-proto" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "async-trait", @@ -2557,7 +2557,7 @@ dependencies = [ [[package]] name = "penumbra-sct" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2590,7 +2590,7 @@ dependencies = [ [[package]] name = "penumbra-shielded-pool" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2641,7 +2641,7 @@ dependencies = [ [[package]] name = "penumbra-stake" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2682,7 +2682,7 @@ dependencies = [ [[package]] name = "penumbra-tct" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "ark-ed-on-bls12-377", "ark-ff", @@ -2710,7 +2710,7 @@ dependencies = [ [[package]] name = "penumbra-transaction" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2761,7 +2761,7 @@ dependencies = [ [[package]] name = "penumbra-txhash" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "blake2b_simd 1.0.2", diff --git a/packages/wasm/crate/Cargo.toml b/packages/wasm/crate/Cargo.toml index b8782283ca..aeca1c44b0 100644 --- a/packages/wasm/crate/Cargo.toml +++ b/packages/wasm/crate/Cargo.toml @@ -14,21 +14,22 @@ default = ["console_error_panic_hook"] mock-database = [] [dependencies] -penumbra-auction = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-auction", default-features = false } -penumbra-asset = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-asset" } -penumbra-compact-block = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-compact-block", default-features = false } -penumbra-dex = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-dex", default-features = false } -penumbra-fee = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-fee", default-features = false } -penumbra-governance = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-governance", default-features = false } -penumbra-keys = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-keys" } -penumbra-num = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-num" } -penumbra-proof-params = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-proof-params", default-features = false } -penumbra-proto = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-proto", default-features = false } -penumbra-sct = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-sct", default-features = false } -penumbra-shielded-pool = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-shielded-pool", default-features = false } -penumbra-stake = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-stake", default-features = false } -penumbra-tct = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-tct" } -penumbra-transaction = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-transaction", default-features = false } +# Update to tag dependency once https://github.com/penumbra-zone/penumbra/pull/4878 is in a release +penumbra-auction = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-auction", default-features = false } +penumbra-asset = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-asset" } +penumbra-compact-block = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-compact-block", default-features = false } +penumbra-dex = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-dex", default-features = false } +penumbra-fee = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-fee", default-features = false } +penumbra-governance = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-governance", default-features = false } +penumbra-keys = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-keys" } +penumbra-num = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-num" } +penumbra-proof-params = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-proof-params", default-features = false } +penumbra-proto = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-proto", default-features = false } +penumbra-sct = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-sct", default-features = false } +penumbra-shielded-pool = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-shielded-pool", default-features = false } +penumbra-stake = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-stake", default-features = false } +penumbra-tct = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-tct" } +penumbra-transaction = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-transaction", default-features = false } anyhow = "1.0.89" ark-ff = { version = "0.4.2", features = ["std"] } diff --git a/packages/wasm/crate/src/keys.rs b/packages/wasm/crate/src/keys.rs index 209d26a350..a7cf031594 100644 --- a/packages/wasm/crate/src/keys.rs +++ b/packages/wasm/crate/src/keys.rs @@ -1,7 +1,7 @@ use std::str::FromStr; use anyhow; -use penumbra_keys::keys::{Bip44Path, SeedPhrase, SpendKey}; +use penumbra_keys::keys::{AddressIndex, Bip44Path, SeedPhrase, SpendKey}; use penumbra_keys::{Address, FullViewingKey}; use penumbra_proof_params::{ CONVERT_PROOF_PROVING_KEY, DELEGATOR_VOTE_PROOF_PROVING_KEY, OUTPUT_PROOF_PROVING_KEY, @@ -136,3 +136,40 @@ pub fn is_controlled_address(full_viewing_key: &[u8], address: &[u8]) -> WasmRes pub fn is_controlled_inner(fvk: &FullViewingKey, address: &Address) -> bool { fvk.address_index(address).is_some() } + +/// Generates an address that can be used as a forwarding address for Noble +/// Returns: Uint8Array representing encoded Address +#[wasm_bindgen] +pub fn get_forwarding_address_for_sequence( + sequence: u16, + full_viewing_key: &[u8], + account: Option, +) -> WasmResult> { + let fvk: FullViewingKey = FullViewingKey::decode(full_viewing_key)?; + let addr = forwarding_addr_inner(sequence, account, &fvk); + Ok(addr.encode_to_vec()) +} + +/// Noble Randomizer: [0xff; 10] followed by LE16(sequence) +pub fn forwarding_addr_inner(sequence: u16, account: Option, fvk: &FullViewingKey) -> Address { + let mut randomizer: [u8; 12] = [0xff; 12]; // Initialize all 12 bytes to 0xff + let seq_bytes = sequence.to_le_bytes(); + randomizer[10..].copy_from_slice(&seq_bytes); // Replace the last 2 bytes with seq_bytes + + let index = AddressIndex { + account: account.unwrap_or_default(), + randomizer, + }; + + let (address, _dtk) = fvk.incoming().payment_address(index); + + address +} + +/// Generates Bech32m noble address +#[wasm_bindgen] +pub fn generate_noble_addr(address: &[u8], channel: &str) -> WasmResult { + let address: Address = Address::decode(address)?; + let forwarding_addr = address.noble_forwarding_address(channel); + Ok(forwarding_addr.to_string()) +} diff --git a/packages/wasm/crate/tests/test_keys.rs b/packages/wasm/crate/tests/test_keys.rs index 13b8d62d25..1dcf31bb2b 100644 --- a/packages/wasm/crate/tests/test_keys.rs +++ b/packages/wasm/crate/tests/test_keys.rs @@ -6,8 +6,8 @@ use penumbra_keys::keys::{ use penumbra_keys::{Address, FullViewingKey}; use penumbra_proto::{DomainType, Message}; use penumbra_wasm::keys::{ - generate_spend_key, get_address_by_index, get_full_viewing_key, get_wallet_id, - is_controlled_address, + forwarding_addr_inner, generate_spend_key, get_address_by_index, get_full_viewing_key, + get_wallet_id, is_controlled_address, }; use rand_core::OsRng; use std::str::FromStr; @@ -87,3 +87,39 @@ fn returns_false_on_unknown_addr() { .0; assert!(!is_controlled_address(&fvk.encode_to_vec(), &other_address.encode_to_vec()).unwrap()); } + +#[test] +fn test_forwarding_addr_sequence_variation() { + let spend_key = generate_spend_key(TEST_SEED_PHRASE).unwrap(); + let fvk_bytes = get_full_viewing_key(spend_key.as_slice()).unwrap(); + let fvk = FullViewingKey::decode(fvk_bytes.as_slice()).unwrap(); + + // Use two different sequences + let sequence1 = 1234; + let sequence2 = 5678; + let account = Some(1); + + let address1 = forwarding_addr_inner(sequence1, account, &fvk); + let address2 = forwarding_addr_inner(sequence2, account, &fvk); + + // Check that the addresses are different + assert_ne!(address1, address2); +} + +#[test] +fn test_forwarding_addr_account_variation() { + let spend_key = generate_spend_key(TEST_SEED_PHRASE).unwrap(); + let fvk_bytes = get_full_viewing_key(spend_key.as_slice()).unwrap(); + let fvk = FullViewingKey::decode(fvk_bytes.as_slice()).unwrap(); + + let sequence = 1234; + + let account1 = Some(1); + let account2 = Some(2); + + let address1 = forwarding_addr_inner(sequence, account1, &fvk); + let address2 = forwarding_addr_inner(sequence, account2, &fvk); + + // Check that the addresses are different + assert_ne!(address1, address2); +} diff --git a/packages/wasm/src/keys.ts b/packages/wasm/src/keys.ts index 45e9b372c7..0afd60bed0 100644 --- a/packages/wasm/src/keys.ts +++ b/packages/wasm/src/keys.ts @@ -1,7 +1,9 @@ import { + generate_noble_addr, generate_spend_key, get_address_by_index, get_ephemeral_address, + get_forwarding_address_for_sequence, get_full_viewing_key, get_wallet_id, } from '../wasm/index.js'; @@ -30,3 +32,16 @@ export const getEphemeralByIndex = (fullViewingKey: FullViewingKey, index: numbe export const getWalletId = (fullViewingKey: FullViewingKey) => WalletId.fromBinary(get_wallet_id(fullViewingKey.toBinary())); + +export const getForwardingAddressForSequence = ( + sequence: number, + fvk: FullViewingKey, + account?: number, +): Address => { + const res = get_forwarding_address_for_sequence(sequence, fvk.toBinary(), account); + return Address.fromBinary(res); +}; + +export const generateNobleAddr = (address: Address, channel: string): string => { + return generate_noble_addr(address.toBinary(), channel); +}; From 593fae5c36df2f0b0003fc16a3d4b8db201b55e3 Mon Sep 17 00:00:00 2001 From: Gabe Rodriguez Date: Fri, 11 Oct 2024 15:53:51 +0200 Subject: [PATCH 2/4] adjust func --- packages/wasm/crate/src/keys.rs | 36 ++++++++++++++++++++------------- packages/wasm/src/keys.ts | 30 ++++++++++++++++++--------- 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/packages/wasm/crate/src/keys.rs b/packages/wasm/crate/src/keys.rs index a7cf031594..1838ff75ca 100644 --- a/packages/wasm/crate/src/keys.rs +++ b/packages/wasm/crate/src/keys.rs @@ -1,5 +1,3 @@ -use std::str::FromStr; - use anyhow; use penumbra_keys::keys::{AddressIndex, Bip44Path, SeedPhrase, SpendKey}; use penumbra_keys::{Address, FullViewingKey}; @@ -10,6 +8,7 @@ use penumbra_proof_params::{ use penumbra_proto::core::keys::v1 as pb; use penumbra_proto::DomainType; use rand_core::OsRng; +use std::str::FromStr; use wasm_bindgen::prelude::*; use crate::error::WasmResult; @@ -137,17 +136,34 @@ pub fn is_controlled_inner(fvk: &FullViewingKey, address: &Address) -> bool { fvk.address_index(address).is_some() } +#[wasm_bindgen(getter_with_clone)] +pub struct ForwardingAddrResponse { + /// A noble address that will be used for registration on the noble network + pub noble_addr_bech32: String, + /// Byte representation of the noble forwarding address. Used for broadcasting cosmos message. + pub noble_addr_bytes: Vec, + /// The penumbra address that a deposit to the noble address with forward to + /// Vec encoded `pb::Address` + pub penumbra_addr_bytes: Vec, +} + /// Generates an address that can be used as a forwarding address for Noble /// Returns: Uint8Array representing encoded Address #[wasm_bindgen] -pub fn get_forwarding_address_for_sequence( +pub fn get_noble_forwarding_addr( sequence: u16, full_viewing_key: &[u8], + channel: &str, account: Option, -) -> WasmResult> { +) -> WasmResult { let fvk: FullViewingKey = FullViewingKey::decode(full_viewing_key)?; - let addr = forwarding_addr_inner(sequence, account, &fvk); - Ok(addr.encode_to_vec()) + let penumbra_addr = forwarding_addr_inner(sequence, account, &fvk); + let noble_addr = penumbra_addr.noble_forwarding_address(channel); + Ok(ForwardingAddrResponse { + noble_addr_bech32: noble_addr.to_string(), + noble_addr_bytes: noble_addr.bytes(), + penumbra_addr_bytes: penumbra_addr.encode_to_vec(), + }) } /// Noble Randomizer: [0xff; 10] followed by LE16(sequence) @@ -165,11 +181,3 @@ pub fn forwarding_addr_inner(sequence: u16, account: Option, fvk: &FullView address } - -/// Generates Bech32m noble address -#[wasm_bindgen] -pub fn generate_noble_addr(address: &[u8], channel: &str) -> WasmResult { - let address: Address = Address::decode(address)?; - let forwarding_addr = address.noble_forwarding_address(channel); - Ok(forwarding_addr.to_string()) -} diff --git a/packages/wasm/src/keys.ts b/packages/wasm/src/keys.ts index 0afd60bed0..24340e210f 100644 --- a/packages/wasm/src/keys.ts +++ b/packages/wasm/src/keys.ts @@ -1,10 +1,9 @@ import { - generate_noble_addr, generate_spend_key, get_address_by_index, get_ephemeral_address, - get_forwarding_address_for_sequence, get_full_viewing_key, + get_noble_forwarding_addr, get_wallet_id, } from '../wasm/index.js'; import { @@ -33,15 +32,26 @@ export const getEphemeralByIndex = (fullViewingKey: FullViewingKey, index: numbe export const getWalletId = (fullViewingKey: FullViewingKey) => WalletId.fromBinary(get_wallet_id(fullViewingKey.toBinary())); -export const getForwardingAddressForSequence = ( +export interface NobleAddrResponse { + // A noble address that will be used for registration on the noble network + nobleAddrBech32: string; + // Byte representation of the noble forwarding address. Used for broadcasting cosmos message. + nobleAddrBytes: Uint8Array; + // The penumbra address that a deposit to the noble address with forward to + penumbraAddr: Address; +} + +// Generates an address that can be used as a forwarding address for Noble +export const getNobleForwardingAddr = ( sequence: number, fvk: FullViewingKey, + channel: string, account?: number, -): Address => { - const res = get_forwarding_address_for_sequence(sequence, fvk.toBinary(), account); - return Address.fromBinary(res); -}; - -export const generateNobleAddr = (address: Address, channel: string): string => { - return generate_noble_addr(address.toBinary(), channel); +): NobleAddrResponse => { + const res = get_noble_forwarding_addr(sequence, fvk.toBinary(), channel, account); + return { + nobleAddrBech32: res.noble_addr_bech32, + nobleAddrBytes: res.noble_addr_bytes, + penumbraAddr: Address.fromBinary(res.penumbra_addr_bytes), + }; }; From 97755fbc88598bb520c4dee897151294c8e32dbf Mon Sep 17 00:00:00 2001 From: Gabe Rodriguez Date: Tue, 15 Oct 2024 14:48:16 +0200 Subject: [PATCH 3/4] changeset --- .changeset/funny-knives-refuse.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/funny-knives-refuse.md diff --git a/.changeset/funny-knives-refuse.md b/.changeset/funny-knives-refuse.md new file mode 100644 index 0000000000..7acb371c34 --- /dev/null +++ b/.changeset/funny-knives-refuse.md @@ -0,0 +1,5 @@ +--- +'@penumbra-zone/wasm': minor +--- + +Added noble forwarding address wasm helpers From 0816493f76296f02f19958270800608fb46e590b Mon Sep 17 00:00:00 2001 From: Gabe Rodriguez Date: Wed, 16 Oct 2024 16:19:31 +0200 Subject: [PATCH 4/4] Additional test cases --- packages/wasm/crate/tests/test_keys.rs | 58 ++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/packages/wasm/crate/tests/test_keys.rs b/packages/wasm/crate/tests/test_keys.rs index 1dcf31bb2b..1abb478ef5 100644 --- a/packages/wasm/crate/tests/test_keys.rs +++ b/packages/wasm/crate/tests/test_keys.rs @@ -123,3 +123,61 @@ fn test_forwarding_addr_account_variation() { // Check that the addresses are different assert_ne!(address1, address2); } + +#[test] +fn test_forwarding_addr_sequence_boundaries() { + let spend_key = generate_spend_key(TEST_SEED_PHRASE).unwrap(); + let fvk_bytes = get_full_viewing_key(spend_key.as_slice()).unwrap(); + let fvk = FullViewingKey::decode(fvk_bytes.as_slice()).unwrap(); + + let account = Some(1); + + let sequence_min = 0; + let sequence_max = u16::MAX; + + let address_min = forwarding_addr_inner(sequence_min, account, &fvk); + let address_max = forwarding_addr_inner(sequence_max, account, &fvk); + + // Check that the addresses are different + assert_ne!(address_min, address_max); +} + +#[test] +fn test_forwarding_addr_same_sequence_and_account() { + let spend_key = generate_spend_key(TEST_SEED_PHRASE).unwrap(); + let fvk_bytes = get_full_viewing_key(spend_key.as_slice()).unwrap(); + let fvk = FullViewingKey::decode(fvk_bytes.as_slice()).unwrap(); + + let sequence = 1234; + let account = Some(1); + + let address1 = forwarding_addr_inner(sequence, account, &fvk); + let address2 = forwarding_addr_inner(sequence, account, &fvk); + + // Check that the addresses are the same + assert_eq!(address1, address2); +} + +#[test] +fn test_forwarding_addr_different_fvks() { + // Generate first Full Viewing Key + let spend_key1 = generate_spend_key(TEST_SEED_PHRASE).unwrap(); + let fvk_bytes1 = get_full_viewing_key(spend_key1.as_slice()).unwrap(); + let fvk1 = FullViewingKey::decode(fvk_bytes1.as_slice()).unwrap(); + + // Generate second Full Viewing Key with different seed phrase + const TEST_SEED_PHRASE_2: &str = + "flag public tonight parrot gospel treat tiny section useless smoke swim armor"; + let spend_key2 = generate_spend_key(TEST_SEED_PHRASE_2).unwrap(); + let fvk_bytes2 = get_full_viewing_key(spend_key2.as_slice()).unwrap(); + let fvk2 = FullViewingKey::decode(fvk_bytes2.as_slice()).unwrap(); + + let sequence = 1234; + let account = Some(1); + + let address1 = forwarding_addr_inner(sequence, account, &fvk1); + let address2 = forwarding_addr_inner(sequence, account, &fvk2); + + // Check that the addresses are different + assert_ne!(address1, address2); +}