Skip to content

Commit

Permalink
Wasm helpers for noble addrs
Browse files Browse the repository at this point in the history
  • Loading branch information
grod220 committed Oct 16, 2024
1 parent 97c3366 commit 1f90f2a
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 39 deletions.
42 changes: 21 additions & 21 deletions packages/wasm/crate/Cargo.lock

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

31 changes: 16 additions & 15 deletions packages/wasm/crate/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand Down
39 changes: 38 additions & 1 deletion packages/wasm/crate/src/keys.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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<u32>,
) -> WasmResult<Vec<u8>> {
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<u32>, 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<String> {
let address: Address = Address::decode(address)?;
let forwarding_addr = address.noble_forwarding_address(channel);
Ok(forwarding_addr.to_string())
}
40 changes: 38 additions & 2 deletions packages/wasm/crate/tests/test_keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
15 changes: 15 additions & 0 deletions packages/wasm/src/keys.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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);
};

0 comments on commit 1f90f2a

Please sign in to comment.