c32check
Version:
Crockford base-32 checksum encoding
76 lines (75 loc) • 3.13 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.c32checkDecode = exports.c32checkEncode = void 0;
const sha256_1 = require("@noble/hashes/sha256");
const utils_1 = require("@noble/hashes/utils");
const encoding_1 = require("./encoding");
/**
* Get the c32check checksum of a hex-encoded string
* @param {string} dataHex - the hex string
* @returns {string} the c32 checksum, as a bin-encoded string
*/
function c32checksum(dataHex) {
const dataHash = (0, sha256_1.sha256)((0, sha256_1.sha256)((0, utils_1.hexToBytes)(dataHex)));
const checksum = (0, utils_1.bytesToHex)(dataHash.slice(0, 4));
return checksum;
}
/**
* Encode a hex string as a c32check string. This is a lot like how
* base58check works in Bitcoin-land, but this algorithm uses the
* z-base-32 alphabet instead of the base58 alphabet. The algorithm
* is as follows:
* * calculate the c32checksum of version + data
* * c32encode version + data + c32checksum
* @param {number} version - the version string (between 0 and 31)
* @param {string} data - the data to encode
* @returns {string} the c32check representation
*/
function c32checkEncode(version, data) {
if (version < 0 || version >= 32) {
throw new Error('Invalid version (must be between 0 and 31)');
}
if (!data.match(/^[0-9a-fA-F]*$/)) {
throw new Error('Invalid data (not a hex string)');
}
data = data.toLowerCase();
if (data.length % 2 !== 0) {
data = `0${data}`;
}
let versionHex = version.toString(16);
if (versionHex.length === 1) {
versionHex = `0${versionHex}`;
}
const checksumHex = c32checksum(`${versionHex}${data}`);
const c32str = (0, encoding_1.c32encode)(`${data}${checksumHex}`);
return `${encoding_1.c32[version]}${c32str}`;
}
exports.c32checkEncode = c32checkEncode;
/*
* Decode a c32check string back into its version and data payload. This is
* a lot like how base58check works in Bitcoin-land, but this algorithm uses
* the z-base-32 alphabet instead of the base58 alphabet. The algorithm
* is as follows:
* * extract the version, data, and checksum
* * verify the checksum matches c32checksum(version + data)
* * return data
* @param {string} c32data - the c32check-encoded string
* @returns {array} [version (number), data (string)]. The returned data
* will be a hex string. Throws an exception if the checksum does not match.
*/
function c32checkDecode(c32data) {
c32data = (0, encoding_1.c32normalize)(c32data);
const dataHex = (0, encoding_1.c32decode)(c32data.slice(1));
const versionChar = c32data[0];
const version = encoding_1.c32.indexOf(versionChar);
const checksum = dataHex.slice(-8);
let versionHex = version.toString(16);
if (versionHex.length === 1) {
versionHex = `0${versionHex}`;
}
if (c32checksum(`${versionHex}${dataHex.substring(0, dataHex.length - 8)}`) !== checksum) {
throw new Error('Invalid c32check string: checksum mismatch');
}
return [version, dataHex.substring(0, dataHex.length - 8)];
}
exports.c32checkDecode = c32checkDecode;