Skip to content

Commit

Permalink
add compat and t-addr bech32 encoding
Browse files Browse the repository at this point in the history
  • Loading branch information
TalDerei committed Dec 22, 2024
1 parent ec1c370 commit 486e9a8
Show file tree
Hide file tree
Showing 14 changed files with 152 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/bech32m/src/format/bytes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ export const ByteLength = {
passet: 32,
pauctid: 32,
penumbra: 80,
penumbracompat1: 80,
penumbrafullviewingkey: 64,
penumbragovern: 32,
penumbraspendkey: 32,
penumbravalid: 32,
penumbrawalletid: 32,
plpid: 32,
tpenumbra: 32,
} as const satisfies Required<Record<Prefix, number>>;
12 changes: 12 additions & 0 deletions packages/bech32m/src/format/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,16 @@ export default {
byteLength: ByteLength.plpid,
innerName: Inner.plpid,
},
penumbracompat1: {
prefix: Prefixes.penumbracompat1,
stringLength: StringLength.penumbracompat1,
byteLength: ByteLength.penumbracompat1,
innerName: Inner.penumbracompat1,
},
tpenumbra: {
prefix: Prefixes.tpenumbra,
stringLength: StringLength.tpenumbra,
byteLength: ByteLength.tpenumbra,
innerName: Inner.tpenumbra,
},
} as const satisfies PenumbraBech32mSpec;
2 changes: 2 additions & 0 deletions packages/bech32m/src/format/inner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ export const Inner = {
penumbravalid: 'ik',
penumbrawalletid: 'inner',
plpid: 'inner',
penumbracompat1: 'inner',
tpenumbra: 'inner',
} as const satisfies Required<Record<Prefix, string>>;
2 changes: 2 additions & 0 deletions packages/bech32m/src/format/prefix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export const Prefixes = {
penumbravalid: 'penumbravalid',
penumbrawalletid: 'penumbrawalletid',
plpid: 'plpid',
penumbracompat1: 'penumbracompat1',
tpenumbra: 'tpenumbra',
} as const;

export type Prefix = keyof typeof Prefixes;
2 changes: 2 additions & 0 deletions packages/bech32m/src/format/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ export const StringLength = {
penumbravalid: 72,
penumbrawalletid: 75,
plpid: 64,
penumbracompat1: 150,
tpenumbra: 68,
} as const satisfies Required<Record<Prefix, number>>;
3 changes: 3 additions & 0 deletions packages/bech32m/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ export const PENUMBRA_BECH32M_WALLETID_PREFIX = SPEC.penumbrawalletid.prefix;

export const PENUMBRA_BECH32M_POSITIONID_LENGTH = SPEC.plpid.stringLength;
export const PENUMBRA_BECH32M_POSITIONID_PREFIX = SPEC.plpid.prefix;

export const PENUMBRA_BECH32M_TRANSPARENT_LENGTH = SPEC.tpenumbra.stringLength;
export const PENUMBRA_BECH32M_TRANSPARENT_PREFIX = SPEC.tpenumbra.prefix;
24 changes: 24 additions & 0 deletions packages/bech32m/src/penumbracompat1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { fromBech32, toBech32 } from './format/convert.js';
import { Inner } from './format/inner.js';
import { Prefixes } from './format/prefix.js';

const innerName = Inner.penumbracompat1;
const prefix = Prefixes.penumbracompat1;

export const bech32CompatAddress = ({ [innerName]: bytes }: { [innerName]: Uint8Array }) =>
toBech32(bytes, prefix);

export const compatAddressFromBech32 = (penumbracompat1: string): { [innerName]: Uint8Array } => ({
[innerName]: fromBech32(penumbracompat1 as `${typeof prefix}1${string}`, prefix),
});

export const isCompatAddress = (check: string): check is `${typeof prefix}1${string}` => {
try {
compatAddressFromBech32(check);
return true;
} catch {
return false;
}
};

export { PENUMBRA_BECH32M_ADDRESS_LENGTH, PENUMBRA_BECH32M_ADDRESS_PREFIX } from './index.js';
25 changes: 25 additions & 0 deletions packages/bech32m/src/test/penumbracompat1.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { describe } from 'vitest';
import { generateTests } from './util/generate-tests.js';
import { bech32CompatAddress, compatAddressFromBech32 } from '../penumbracompat1.js';
import { Prefixes } from '../format/prefix.js';
import { Inner } from '../format/inner.js';

describe('compat address conversion', () => {
const okInner = new Uint8Array([
175, 182, 158, 255, 239, 16, 245, 221, 208, 117, 160, 44, 235, 175, 198, 0, 6, 216, 6, 143, 192,
155, 159, 103, 97, 103, 136, 5, 78, 209, 17, 200, 68, 220, 182, 45, 20, 246, 181, 16, 117, 182,
46, 141, 74, 101, 196, 86, 185, 124, 206, 253, 195, 57, 224, 34, 210, 22, 123, 246, 136, 10,
208, 159, 24, 235, 148, 153, 211, 7, 137, 198, 158, 226, 221, 22, 208, 152, 246, 247,
]);
const okBech32 =
'penumbracompat1147mfall0zr6am5r45qkwht7xqqrdsp50czde7empv7yq2nk3z8yyfh9k9520ddgswkmzar22vhz9dwtuem7uxw0qytfpv7lk3q9dp8ccaw2fn5c838rfackazmgf3ahhwqq0da';

generateTests(
Prefixes.penumbracompat1,
Inner.penumbracompat1,
okInner,
okBech32,
bech32CompatAddress,
compatAddressFromBech32,
);
});
22 changes: 22 additions & 0 deletions packages/bech32m/src/test/tpenumbra.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { describe } from 'vitest';
import { generateTests } from './util/generate-tests.js';
import { bech32TransparentAddress, transparentAddressFromBech32 } from '../tpenumbra.js';
import { Prefixes } from '../format/prefix.js';
import { Inner } from '../format/inner.js';

describe('transparent address conversion', () => {
const okInner = new Uint8Array([
102, 236, 169, 166, 203, 152, 194, 89, 236, 246, 59, 69, 221, 32, 49, 49, 83, 29, 119, 117, 124,
201, 194, 156, 219, 251, 137, 202, 157, 235, 1, 15,
]);
const okBech32 = 'tpenumbra1vmk2nfktnrp9nm8k8dza6gp3x9f36am40nyu98xmlwyu480tqy8sr3jfzd';

generateTests(
Prefixes.tpenumbra,
Inner.tpenumbra,
okInner,
okBech32,
bech32TransparentAddress,
transparentAddressFromBech32,
);
});
27 changes: 27 additions & 0 deletions packages/bech32m/src/tpenumbra.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { fromBech32, toBech32 } from './format/convert.js';
import { Inner } from './format/inner.js';
import { Prefixes } from './format/prefix.js';

const innerName = Inner.tpenumbra;
const prefix = Prefixes.tpenumbra;

export const bech32TransparentAddress = ({ [innerName]: bytes }: { [innerName]: Uint8Array }) =>
toBech32(bytes, prefix);

export const transparentAddressFromBech32 = (penumbra1: string): { [innerName]: Uint8Array } => ({
[innerName]: fromBech32(penumbra1 as `${typeof prefix}1${string}`, prefix),
});

export const isAddress = (check: string): check is `${typeof prefix}1${string}` => {
try {
transparentAddressFromBech32(check);
return true;
} catch {
return false;
}
};

export {
PENUMBRA_BECH32M_TRANSPARENT_LENGTH,
PENUMBRA_BECH32M_TRANSPARENT_PREFIX,
} from './index.js';
8 changes: 8 additions & 0 deletions packages/types/src/address.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ import { describe, expect, test } from 'vitest';
import { parseIntoAddr } from './address.js';

describe('parseIntoAddr', () => {
test('works with compat', () => {
expect(() =>
parseIntoAddr(
'penumbracompat1147mfall0zr6am5r45qkwht7xqqrdsp50czde7empv7yq2nk3z8yyfh9k9520ddgswkmzar22vhz9dwtuem7uxw0qytfpv7lk3q9dp8ccaw2fn5c838rfackazmgf3ahhwqq0da',
),
).not.toThrow();
});

test('works with normal addresses', () => {
expect(() =>
parseIntoAddr(
Expand Down
4 changes: 4 additions & 0 deletions packages/types/src/address.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { Address } from '@penumbra-zone/protobuf/penumbra/core/keys/v1/keys_pb';
import { addressFromBech32m } from '@penumbra-zone/bech32m/penumbra';
import { compatAddressFromBech32, isCompatAddress } from '@penumbra-zone/bech32m/penumbracompat1';

export const parseIntoAddr = (addrStr: string): Address => {
if (isCompatAddress(addrStr)) {
return new Address(compatAddressFromBech32(addrStr));
}
return new Address(addressFromBech32m(addrStr));
};
13 changes: 13 additions & 0 deletions packages/wasm/crate/src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,16 @@ pub fn get_transparent_address(full_viewing_key: &[u8]) -> WasmResult<Transparen
encoding: encoding.to_string(),
})
}

/// get transmission key (public key for this payment address)
/// Arguments:
/// address: `byte representation inner Address`
/// Returns: `Uint8Array representing inner Address`
#[wasm_bindgen]
pub fn get_transmission_key_by_address(address: &[u8]) -> WasmResult<Vec<u8>> {
utils::set_panic_hook();

let address: Address = Address::decode(address)?;
let transmission_key = address.transmission_key();
Ok(transmission_key.0.to_vec())
}
6 changes: 6 additions & 0 deletions packages/wasm/src/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
get_full_viewing_key,
get_noble_forwarding_addr,
get_transparent_address,
get_transmission_key_by_address,
get_wallet_id,
} from '../wasm/index.js';
import {
Expand Down Expand Up @@ -65,3 +66,8 @@ export const getTransparentAddress = (fvk: FullViewingKey) => {
encoding: res.encoding,
};
};

export const getTransmissionKeyByAddress = (address: Address) => {
const transmission_key = get_transmission_key_by_address(address.toBinary());
return transmission_key;
};

0 comments on commit 486e9a8

Please sign in to comment.