@vbyte/btc-dev
Version:
Batteries-included toolset for plebian bitcoin development
80 lines (79 loc) • 2.99 kB
JavaScript
import { Buff } from '@vbyte/buff';
import { Assert, B58chk, Bech32, Bech32m } from '@vbyte/micro-lib';
const ENCODING_REGEX = {
base58: /^[13mn2][a-km-zA-HJ-NP-Z1-9]{25,34}$/,
bech32: /^(bc|tb|bcrt)1q[ac-hj-np-z02-9]{6,87}$/,
bech32m: /^(bc|tb|bcrt)1p[ac-hj-np-z02-9]{6,87}$/
};
const VERSION = {
bech32: 0,
bech32m: 1
};
export function decode_address(address) {
const format = get_address_format(address);
if (format === null)
throw new Error('unrecognized address format: ' + format);
if (format === 'base58')
return base58_decode(address);
if (format === 'bech32')
return bech32_decode(address);
if (format === 'bech32m')
return bech32m_decode(address);
throw new Error('unable to find a matching address configuration');
}
export function encode_address(config) {
if (config.format === 'base58')
return base58_encode(config);
if (config.format === 'bech32')
return bech32_encode(config);
if (config.format === 'bech32m')
return bech32m_encode(config);
throw new Error('unrecognized encoding format: ' + config.format);
}
function get_address_format(address) {
for (const [format, regex] of Object.entries(ENCODING_REGEX)) {
if (regex.test(address))
return format;
}
return null;
}
function base58_encode(config) {
Assert.ok(config.format === 'base58', 'encoding mismatch');
Assert.exists(config.version, 'must specify a version');
const bytes = Buff.join([config.version, config.data]);
return B58chk.encode(bytes);
}
function base58_decode(encoded) {
const bytes = B58chk.decode(encoded);
const data = bytes.slice(1);
const version = bytes[0];
return { data, format: 'base58', version };
}
function bech32_encode(config) {
Assert.ok(config.format === 'bech32', 'encoding mismatch');
Assert.exists(config.prefix, 'prefix is required');
const bytes = Buff.bytes(config.data);
const words = Bech32.to_words(bytes);
return Bech32.encode(config.prefix, [VERSION.bech32, ...words]);
}
function bech32_decode(encoded) {
const { prefix, words } = Bech32.decode(encoded);
const [version, ...rest] = words;
Assert.ok(version === VERSION.bech32, 'bech32 version mismatch');
const data = Bech32.to_bytes(rest);
return { data, format: 'bech32', prefix, version };
}
function bech32m_encode(config) {
Assert.ok(config.format === 'bech32m', 'encoding mismatch');
Assert.exists(config.prefix, 'prefix is required');
const bytes = Buff.bytes(config.data);
const words = Bech32m.to_words(bytes);
return Bech32m.encode(config.prefix, [VERSION.bech32m, ...words]);
}
function bech32m_decode(encoded) {
const { prefix, words } = Bech32m.decode(encoded);
const [version, ...rest] = words;
Assert.ok(version === VERSION.bech32m, 'bech32m version mismatch');
const data = Bech32m.to_bytes(rest);
return { data, format: 'bech32m', prefix, version };
}