Skip to content

Instantly share code, notes, and snippets.

@jaonoctus
Last active April 24, 2024 14:55
Show Gist options
  • Save jaonoctus/db0f07aba4d2277be4ecb411b44f93d3 to your computer and use it in GitHub Desktop.
Save jaonoctus/db0f07aba4d2277be4ecb411b44f93d3 to your computer and use it in GitHub Desktop.
var base58 = require('bs58')
var { sha256 } = require('@noble/hashes/sha256')
const useBs58check = function (checksumFn) {
// Encode a buffer as a base58-check encoded string
function encode (payload) {
var payloadU8 = Uint8Array.from(payload)
var checksum = checksumFn(payloadU8)
var length = payloadU8.length + 4
var both = new Uint8Array(length)
both.set(payloadU8, 0)
both.set(checksum.subarray(0, 4), payloadU8.length)
return base58.encode(both, length)
}
function decodeRaw (buffer) {
var payload = buffer.slice(0, -4)
var checksum = buffer.slice(-4)
var newChecksum = checksumFn(payload)
if (checksum[0] ^ newChecksum[0] |
checksum[1] ^ newChecksum[1] |
checksum[2] ^ newChecksum[2] |
checksum[3] ^ newChecksum[3]) return
return payload
}
// Decode a base58-check encoded string to a buffer, no result if checksum is wrong
function decodeUnsafe (string) {
var buffer = base58.decodeUnsafe(string)
if (!buffer) return
return decodeRaw(buffer)
}
function decode (string) {
var buffer = base58.decode(string)
var payload = decodeRaw(buffer, checksumFn)
if (!payload) throw new Error('Invalid checksum')
return payload
}
return {
encode: encode,
decode: decode,
decodeUnsafe: decodeUnsafe
}
}
function doubleSha256 (buffer) {
return sha256(sha256(buffer))
}
const bs58check = useBs58check(doubleSha256)
/*
This script uses version bytes as described in SLIP-132
https://github.com/satoshilabs/slips/blob/master/slip-0132.md
*/
const prefixes = new Map([
['xpub', '0488b21e'],
['ypub', '049d7cb2'],
['Ypub', '0295b43f'],
['zpub', '04b24746'],
['Zpub', '02aa7ed3'],
['tpub', '043587cf'],
['upub', '044a5262'],
['Upub', '024289ef'],
['vpub', '045f1cf6'],
['Vpub', '02575483'],
])
/*
* This function takes an extended public key (with any version bytes, it doesn't need to be an xpub)
* and converts it to an extended public key formatted with the desired version bytes
* @param xpub: an extended public key in base58 format. Example: xpub6CpihtY9HVc1jNJWCiXnRbpXm5BgVNKqZMsM4XqpDcQigJr6AHNwaForLZ3kkisDcRoaXSUms6DJNhxFtQGeZfWAQWCZQe1esNetx5Wqe4M
* @param targetFormat: a string representing the desired prefix; must exist in the "prefixes" mapping defined above. Example: Zpub
*/
function changeVersionBytes(xpub, targetFormat) {
if (!prefixes.has(targetFormat)) {
return 'Invalid target version'
}
// trim whitespace
xpub = xpub.trim()
try {
var data = bs58check.decode(xpub)
data = data.slice(4)
data = Buffer.concat([Buffer.from(prefixes.get(targetFormat), 'hex'), data])
data = bs58check.encode(data)
return data
} catch (err) {
return 'Invalid extended public key'
}
}
// example
const input = 'zpub6rD5AGSXPTDMSnpmczjENMT3NvVF7q5MySww6uxitUsBYgkZLeBywrcwUWhW5YkeY2aS7xc45APPgfA6s6wWfG2gnfABq6TDz9zqeMu2JCY'
changeVersionBytes(input, 'xpub')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment