@penumbra-zone/bech32m
Advanced tools
Comparing version 3.0.1 to 3.1.0
# @penumbra-zone/bech32 | ||
## 3.1.0 | ||
### Minor Changes | ||
- v8.0.0 versioning and manifest | ||
## 3.0.1 | ||
@@ -4,0 +10,0 @@ |
@@ -5,2 +5,3 @@ export declare const ByteLength: { | ||
readonly penumbra: 80; | ||
readonly penumbracompat1: 80; | ||
readonly penumbrafullviewingkey: 64; | ||
@@ -7,0 +8,0 @@ readonly penumbragovern: 32; |
@@ -5,2 +5,3 @@ export const ByteLength = { | ||
penumbra: 80, | ||
penumbracompat1: 80, | ||
penumbrafullviewingkey: 64, | ||
@@ -7,0 +8,0 @@ penumbragovern: 32, |
@@ -10,11 +10,27 @@ import { Prefix } from './prefix'; | ||
*/ | ||
export declare const fromBech32m: <P extends "passet" | "pauctid" | "penumbra" | "penumbrafullviewingkey" | "penumbragovern" | "penumbraspendkey" | "penumbravalid" | "penumbrawalletid" | "plpid">(b32mStr: `${P}1${string}`, prefix?: Prefix) => Uint8Array; | ||
export declare const fromBech32m: <P extends "passet" | "pauctid" | "penumbra" | "penumbracompat1" | "penumbrafullviewingkey" | "penumbragovern" | "penumbraspendkey" | "penumbravalid" | "penumbrawalletid" | "plpid">(b32mStr: `${P}1${string}`, prefix?: Prefix) => Uint8Array; | ||
/** | ||
* Similar to above, but used to convert from Bech32 for compatibility reasons. | ||
* | ||
* @param b32mStr input string | ||
* @param prefix verified or detected input prefix | ||
* @returns byte array of spec length | ||
*/ | ||
export declare const fromBech32: <P extends "passet" | "pauctid" | "penumbra" | "penumbracompat1" | "penumbrafullviewingkey" | "penumbragovern" | "penumbraspendkey" | "penumbravalid" | "penumbrawalletid" | "plpid">(b32mStr: `${P}1${string}`, prefix?: Prefix) => Uint8Array; | ||
/** | ||
* Internal use. Converts a byte array to a valid bech32m string of spec format, | ||
* throwing on invalid input. | ||
* | ||
* @param data input bytes | ||
* @param bData input bytes | ||
* @param prefix known prefix in spec | ||
* @returns bech32m string of spec format | ||
*/ | ||
export declare const toBech32m: <P extends "passet" | "pauctid" | "penumbra" | "penumbrafullviewingkey" | "penumbragovern" | "penumbraspendkey" | "penumbravalid" | "penumbrawalletid" | "plpid">(data: Uint8Array, prefix: P) => `${P}1${string}`; | ||
export declare const toBech32m: <P extends "passet" | "pauctid" | "penumbra" | "penumbracompat1" | "penumbrafullviewingkey" | "penumbragovern" | "penumbraspendkey" | "penumbravalid" | "penumbrawalletid" | "plpid">(bData: Uint8Array, prefix: P) => `${P}1${string}`; | ||
/** | ||
* Similar to above, but used to convert to Bech32 for compatibility reasons. | ||
* | ||
* @param bData input bytes | ||
* @param prefix known prefix in spec | ||
* @returns bech32 string of spec format | ||
*/ | ||
export declare const toBech32: <P extends "passet" | "pauctid" | "penumbra" | "penumbracompat1" | "penumbrafullviewingkey" | "penumbragovern" | "penumbraspendkey" | "penumbravalid" | "penumbrawalletid" | "plpid">(bData: Uint8Array, prefix: P) => `${P}1${string}`; |
@@ -1,2 +0,2 @@ | ||
import { bech32m } from 'bech32'; | ||
import { bech32, bech32m } from 'bech32'; | ||
import { StringLength } from './strings'; | ||
@@ -13,6 +13,25 @@ import { ByteLength } from './bytes'; | ||
export const fromBech32m = (b32mStr, prefix = b32mStr.slice(0, b32mStr.lastIndexOf('1'))) => { | ||
return fromBechWithLib(b32mStr, prefix, bech32m); | ||
}; | ||
/** | ||
* Similar to above, but used to convert from Bech32 for compatibility reasons. | ||
* | ||
* @param b32mStr input string | ||
* @param prefix verified or detected input prefix | ||
* @returns byte array of spec length | ||
*/ | ||
export const fromBech32 = (b32mStr, prefix = b32mStr.slice(0, b32mStr.lastIndexOf('1'))) => { | ||
return fromBechWithLib(b32mStr, prefix, bech32); | ||
}; | ||
const fromBechWithLib = (b32mStr, prefix, bechLib) => { | ||
const p = b32mStr.slice(0, b32mStr.lastIndexOf('1')); | ||
if (p !== prefix) | ||
throw new TypeError('Unexpected prefix'); | ||
return from(b32mStr, p, StringLength[p], ByteLength[p]); | ||
throw new TypeError(`Unexpected prefix: expected ${prefix}, got ${p}`); | ||
return from({ | ||
bechLib: bechLib, | ||
b32mStr, | ||
expectPrefix: p, | ||
expectLength: StringLength[p], | ||
expectBytes: ByteLength[p], | ||
}); | ||
}; | ||
@@ -23,24 +42,41 @@ /** | ||
* | ||
* @param data input bytes | ||
* @param bData input bytes | ||
* @param prefix known prefix in spec | ||
* @returns bech32m string of spec format | ||
*/ | ||
export const toBech32m = (data, prefix) => to(data, prefix, StringLength[prefix], ByteLength[prefix]); | ||
export const toBech32m = (bData, prefix) => to({ | ||
bechLib: bech32m, | ||
bData, | ||
prefix, | ||
expectLength: StringLength[prefix], | ||
expectBytes: ByteLength[prefix], | ||
}); | ||
/** | ||
* Similar to above, but used to convert to Bech32 for compatibility reasons. | ||
* | ||
* @param bData input bytes | ||
* @param prefix known prefix in spec | ||
* @returns bech32 string of spec format | ||
*/ | ||
export const toBech32 = (bData, prefix) => to({ | ||
bechLib: bech32, | ||
bData, | ||
prefix, | ||
expectLength: StringLength[prefix], | ||
expectBytes: ByteLength[prefix], | ||
}); | ||
/** | ||
* Internal use. Converts a bech32m string to a byte array. Verifies the prefix, | ||
* input string length, and output byte length. | ||
* | ||
* @param bStr input string | ||
* @param expectPrefix verify input prefix | ||
* @param expectLength verify input length | ||
* @param expectBytes expected output length | ||
* @returns byte array of length `expectBytes` | ||
*/ | ||
const from = (bStr, expectPrefix, expectLength, expectBytes) => { | ||
if (bStr.length !== expectLength) | ||
throw new TypeError('Invalid string length'); | ||
const { prefix, words } = bech32m.decode(bStr, expectLength); | ||
const from = ({ bechLib, b32mStr, expectPrefix, expectLength, expectBytes, }) => { | ||
if (b32mStr.length !== expectLength) { | ||
throw new TypeError(`Invalid string length: expected ${expectLength}, got ${b32mStr.length}`); | ||
} | ||
const { prefix, words } = bechLib.decode(b32mStr, expectLength); | ||
if (prefix !== expectPrefix) | ||
throw new TypeError('Wrong prefix'); | ||
const bytes = new Uint8Array(bech32m.fromWords(words)); | ||
const bytes = new Uint8Array(bechLib.fromWords(words)); | ||
if (bytes.length !== expectBytes) | ||
@@ -54,12 +90,9 @@ throw new TypeError('Unexpected data length'); | ||
* | ||
* @param bData input bytes | ||
* @param prefix string to use as prefix | ||
* @param expectLength expected output length, including prefix | ||
* @param expectBytes verify input byte length | ||
* @returns bech32m with prefix and length `expectLength` | ||
*/ | ||
const to = (bData, prefix, expectLength, expectBytes) => { | ||
if (bData.length !== expectBytes) | ||
throw new TypeError('Invalid data length'); | ||
const bStr = bech32m.encode(prefix, bech32m.toWords(bData), expectLength); | ||
const to = ({ bechLib, bData, prefix, expectLength, expectBytes, }) => { | ||
if (bData.length !== expectBytes) { | ||
throw new TypeError(`Invalid data length: expected ${expectBytes}, got ${bData.length}`); | ||
} | ||
const bStr = bechLib.encode(prefix, bechLib.toWords(bData), expectLength); | ||
if (bStr.length !== expectLength) | ||
@@ -66,0 +99,0 @@ throw new TypeError('Unexpected string length'); |
@@ -20,2 +20,8 @@ declare const _default: { | ||
}; | ||
readonly penumbracompat1: { | ||
readonly prefix: "penumbracompat1"; | ||
readonly stringLength: 150; | ||
readonly byteLength: 80; | ||
readonly innerName: "inner"; | ||
}; | ||
readonly penumbrafullviewingkey: { | ||
@@ -22,0 +28,0 @@ readonly prefix: "penumbrafullviewingkey"; |
@@ -24,2 +24,8 @@ import { Inner } from './inner'; | ||
}, | ||
penumbracompat1: { | ||
prefix: Prefixes.penumbracompat1, | ||
stringLength: StringLength.penumbracompat1, | ||
byteLength: ByteLength.penumbracompat1, | ||
innerName: Inner.penumbracompat1, | ||
}, | ||
penumbrafullviewingkey: { | ||
@@ -26,0 +32,0 @@ prefix: Prefixes.penumbrafullviewingkey, |
@@ -5,2 +5,3 @@ export declare const Inner: { | ||
readonly penumbra: "inner"; | ||
readonly penumbracompat1: "inner"; | ||
readonly penumbrafullviewingkey: "inner"; | ||
@@ -7,0 +8,0 @@ readonly penumbragovern: "gk"; |
@@ -5,2 +5,3 @@ export const Inner = { | ||
penumbra: 'inner', | ||
penumbracompat1: 'inner', | ||
penumbrafullviewingkey: 'inner', | ||
@@ -7,0 +8,0 @@ penumbragovern: 'gk', |
@@ -5,2 +5,3 @@ export declare const Prefixes: { | ||
readonly penumbra: "penumbra"; | ||
readonly penumbracompat1: "penumbracompat1"; | ||
readonly penumbrafullviewingkey: "penumbrafullviewingkey"; | ||
@@ -7,0 +8,0 @@ readonly penumbragovern: "penumbragovern"; |
@@ -5,2 +5,3 @@ export const Prefixes = { | ||
penumbra: 'penumbra', | ||
penumbracompat1: 'penumbracompat1', | ||
penumbrafullviewingkey: 'penumbrafullviewingkey', | ||
@@ -7,0 +8,0 @@ penumbragovern: 'penumbragovern', |
@@ -5,2 +5,3 @@ export declare const StringLength: { | ||
readonly penumbra: 143; | ||
readonly penumbracompat1: 150; | ||
readonly penumbrafullviewingkey: 132; | ||
@@ -7,0 +8,0 @@ readonly penumbragovern: 73; |
@@ -5,2 +5,3 @@ export const StringLength = { | ||
penumbra: 143, | ||
penumbracompat1: 150, | ||
penumbrafullviewingkey: 132, | ||
@@ -7,0 +8,0 @@ penumbragovern: 73, |
import { describe } from 'vitest'; | ||
import { addressFromBech32m, bech32mAddress } from '../penumbra'; | ||
import { generateTests } from './util/generate-tests'; | ||
import { Prefixes } from '../format/prefix'; | ||
import { Inner } from '../format/inner'; | ||
describe('address conversion', () => { | ||
@@ -12,3 +14,3 @@ const okInner = new Uint8Array([ | ||
const okBech32 = 'penumbra147mfall0zr6am5r45qkwht7xqqrdsp50czde7empv7yq2nk3z8yyfh9k9520ddgswkmzar22vhz9dwtuem7uxw0qytfpv7lk3q9dp8ccaw2fn5c838rfackazmgf3ahh09cxmz'; | ||
generateTests('penumbra', 'inner', okInner, okBech32, bech32mAddress, addressFromBech32m); | ||
generateTests(Prefixes.penumbra, Inner.penumbra, okInner, okBech32, bech32mAddress, addressFromBech32m); | ||
}); |
import { describe } from 'vitest'; | ||
import { bech32mFullViewingKey, fullViewingKeyFromBech32m } from '../penumbrafullviewingkey'; | ||
import { generateTests } from './util/generate-tests'; | ||
import { Prefixes } from '../format/prefix'; | ||
import { Inner } from '../format/inner'; | ||
describe('fvk conversion', () => { | ||
@@ -11,3 +13,3 @@ const okInner = new Uint8Array([ | ||
const okBech32 = 'penumbrafullviewingkey1vzfytwlvq067g2kz095vn7sgcft47hga40atrg5zu2crskm6tyyjysm28qg5nth2fqmdf5n0q530jreumjlsrcxjwtfv6zdmfpe5kqsa5lg09'; | ||
generateTests('penumbrafullviewingkey', 'inner', okInner, okBech32, bech32mFullViewingKey, fullViewingKeyFromBech32m); | ||
generateTests(Prefixes.penumbrafullviewingkey, Inner.penumbrafullviewingkey, okInner, okBech32, bech32mFullViewingKey, fullViewingKeyFromBech32m); | ||
}); |
import { describe, expect, test } from 'vitest'; | ||
import { generateInvalid } from './corrupt'; | ||
export const generateTests = (prefix, innerName, okBytes, okString, | ||
// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style | ||
testToBech32, testFromBech32) => { | ||
export const generateTests = (prefix, innerName, okBytes, okString, testToBech32, testFromBech32) => { | ||
describe(`tests for ${prefix}`, () => { | ||
@@ -7,0 +5,0 @@ test('Converts to bech32m', () => expect(testToBech32({ [innerName]: okBytes })).toBe(okString)); |
{ | ||
"name": "@penumbra-zone/bech32m", | ||
"version": "3.0.1", | ||
"version": "3.1.0", | ||
"license": "(MIT OR Apache-2.0)", | ||
@@ -5,0 +5,0 @@ "description": "Tools for manipulating Penumbra bech32m strings", |
@@ -98,1 +98,17 @@ # `@penumbra-zone/bech32m` | ||
``` | ||
## penumbracompat1 is bech32, not bech32m | ||
For IBC compatibility, we provide a `penumbracompat1` address format that is | ||
bech32 instead of bech32m. You can use `penumbracompat1` when interacting with | ||
any chain that does not support a bech32m destination. | ||
```ts | ||
import { bech32Address } from '@penumbra-zone/bech32m/penumbra'; | ||
import { bech32CompatAddress } from '@penumbra-zone/bech32m/penumbracompat1'; | ||
const bech32Chains = ['noble', 'nobletestnet']; | ||
const getCompatibleAddress = (chainName: string, address: { inner: Uint8Array }): string => { | ||
return bech32Chains.includes(chainName) ? bech32CompatAddress(address) : bech32mAddress(address); | ||
}; | ||
``` |
44167
62
915
114