Forum software didnot allow me to upload script file, you can find the code below.
const GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];
const CHARSET = ‘qpzry9x8gf2tvdw0s3jn54khce6mua7l’;
const CHARKEY_KEY = [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1];
/**
-
Converts string to int array like php unpack function
-
@param {*} inp
*/
function unpack(inp){
ret =
for(let i=0;i<inp.length;i++){
ret.push(inp.charCodeAt(i));
}
return ret;
}
function pack(inp_arr){
ret = "";
for (let i=0;i<inp_arr.length;i++){
ret += String.fromCharCode(inp_arr[i]);
}
return ret;
}
function ord(c){
return c.charCodeAt(0);
}
function polyMod(values,numvalues){
let chk = 1;
for(let i =0; i<numvalues;i++){
let top = chk >> 25;
chk = (chk & 0x1ffffff) << 5 ^ values[i];
for (let j=0;j<5; j++){
let value = ((top >> j)& 1) ? GENERATOR[j] : 0
chk ^= value;
}
}
return chk;
}
/**
-
Expands the human readable part into a character array for checksumming.
-
@param string hrp
-
@param int hrpLen
-
@return int
*/
function hrpExpand(hrp,hrpLen){
let expand1 = ;
let expand2 = ;
for (let i=0;i< hrpLen;i++){
let o = ord(hrp[i]);
expand1.push(o >>5);
expand2.push(o & 31);
}
return expand1.concat([0]).concat(expand2);
}
/**
-
Converts words of $fromBits bits to $toBits bits in size.
-
@param int data - character array of data to convert
-
@param int inLen - number of elements in array
-
@param int fromBits - word (bit count) size of provided data
-
@param int toBits - requested word size (bit count)
-
@param bool pad - whether to pad (only when encoding)
-
@return int
-
@throws Exception
*/
function convertBits(data,inLen,fromBits,toBits,pad=true){
let acc =0;
let bits = 0;
let ret =
let maxv = (1 << toBits) -1;
let maxacc = ( 1 << (fromBits + toBits -1)) -1;
for (let i = 0; i< inLen; i++){
let value = data[i];
if (value < 0 || value >> fromBits){
throw new Error(‘Invalid value for convert bits’);
}
acc = ((acc << fromBits) | value ) & maxacc;
bits += fromBits;
while (bits >= toBits){
bits -= toBits;
ret.push( ((acc>>bits)& maxv) );
}
}
if (pad)
{
if (bits){
ret.push( (acc<< toBits - bits) &maxv );
}
} else if (bits >= fromBits || (((acc << (toBits - bits))) & maxv))
{
throw new Error(‘Invalid Data’);
}
return ret;
}
/**
-
Verifies the checksum given hrp and convertedDataChars.
-
@param string hrp
-
@param int convertedDataChars
-
@return bool
*/
function verifyChecksum(hrp, convertedDataChars)
{
expandHrp = hrpExpand(hrp, hrp.length );
let r = expandHrp.concat(convertedDataChars);
let poly = polyMod(r, r.length);
return poly === 1;
}
/**
-
@throws Exception
-
@param string sBech - the bech32 encoded string
-
@return array - returns [hrp, dataChars]
*/
function decodeRaw(sBech){
length = sBech.length;
if(length<8) {
throw new Error(“Bech32 string is too short”);
}
chars = unpack(sBech);
let haveUpper=false;
let haveLower=false;
let positionOne = -1;
for(let i=0;i<length;i++){
let x = chars[i];
console.log("x: ",x);
if (x< 33 || x > 126)
{
throw new Exception("Out of range character in bech32 string");
}
if (x >= 0x61 && x <= 0x7a)
{
haveLower = true;
}
if (x >= 0x41 && x <= 0x5a)
{
haveUpper = true;
x = chars[i] = x + 0x20;
}
// find location of last '1' character
if (x === 0x31)
{
positionOne = i;
}
}
if (haveUpper && haveLower)
{
throw new Error(‘Data contains mixture of higher/lower case characters’);
}
if (positionOne === - 1)
{
throw new Error(“Missing separator character”);
}
if (positionOne < 1)
{
throw new Error(“Empty HRP”);
}
if ((positionOne + 7) > length)
{
throw new Error(‘Too short checksum’);
}
let hrp = pack(chars.slice(0,positionOne));
let data =
for (let i=positionOne + 1;i<length;i++){
data.push( (chars[i] & 0x80 ) ? -1 : CHARKEY_KEY[chars[i]]);
}
console.log("hrp: ",hrp.length, hrp);
console.log("data: ",data.length,data);
if (!verifyChecksum(hrp, data))
{
throw new Error(‘Invalid bech32 checksum’);
}
return [hrp, data.slice(0,-6) ];
}
/**
-
Validates a bech32 string and returns [hrp, dataChars] if
-
the conversion was successful. An exception is thrown on invalid
-
data.
-
@param string sBech - the bech32 encoded string
-
@return array - returns [hrp, dataChars]
-
@throws Exception
*/
function decode(sBech)
{
if (sBech.length > 90)
{
throw new Error(‘Bech32 string cannot exceed 90 characters in length’);
}
return decodeRaw($sBech);
}
// BASE32
const ALPHABET = ‘ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=’;
/**
- Maps the Base32 character to its corresponding bit value.
*/
const MAPPING = {
‘=’ : 0b00000,
‘A’ : 0b00000,
‘B’ : 0b00001,
‘C’ : 0b00010,
‘D’ : 0b00011,
‘E’ : 0b00100,
‘F’ : 0b00101,
‘G’ : 0b00110,
‘H’ : 0b00111,
‘I’ : 0b01000,
‘J’ : 0b01001,
‘K’ : 0b01010,
‘L’ : 0b01011,
‘M’ : 0b01100,
‘N’ : 0b01101,
‘O’ : 0b01110,
‘P’ : 0b01111,
‘Q’ : 0b10000,
‘R’ : 0b10001,
‘S’ : 0b10010,
‘T’ : 0b10011,
‘U’ : 0b10100,
‘V’ : 0b10101,
‘W’ : 0b10110,
‘X’ : 0b10111,
‘Y’ : 0b11000,
‘Z’ : 0b11001,
‘2’ : 0b11010,
‘3’ : 0b11011,
‘4’ : 0b11100,
‘5’ : 0b11101,
‘6’ : 0b11110,
‘7’ : 0b11111,
};
function Base32_encode(inp_str){
// Empty string results in empty string
if ('' === inp_str ) {
return '';
}
let encoded='';
// set the initial values
let n = 0;
let bitLen = 0;
let val = 0;
let len = inp_str.length;
// pad the end of the string - this ensures that there are enough zeros
inp_str = inp_str.concat(String.fromCharCode(0).repeat(4));
// Explode string into integers
let chars = unpack(inp_str);
while (n < len || 0 != bitLen){
//If the bit length has fallen below 5, shift left 8 and add the next character.
if (bitLen < 5) {
val = val << 8;
bitLen += 8;
n++;
val += chars[n];
}
let shift = bitLen - 5;
encoded += (n - ( bitLen > 8) > len && 0 == val) ? '=' : ALPHABET[val >> shift];
val = val & ((1 << shift) - 1);
bitLen -= 5;
}
return encoded;
}
/**
- Decodes base32.
- @param string base32String Base32 encoded string
- @return string Clear text string
*/
function Base32_decode(base32String){
base32String = base32String.toUpperCase();
base32String = base32String.replace(/[^A-Z2-7]/,'');
// Empty string results in empty string
if ('' === base32String || null === base32String) {
return '';
}
let decoded = '';
//Set the initial values
let len = base32String.length;
let n = 0;
let bitLen = 5;
let val = MAPPING[base32String[0]];
while (n < len){
//If the bit length has fallen below 8, shift left 5 and add the next pentet.
if (bitLen < 8) {
val = val << 5;
bitLen += 5;
n++;
let pentet = '=';
if (base32String[n]!==null){
pentet = base32String[n];
}
//If the new pentet is padding, make this the last iteration.
if ('=' === pentet) {
n = len;
}
val += MAPPING[pentet];
continue;
}
let shift = bitLen - 8;
decoded += String.fromCharCode($val >> $shift);
val = val & ((1 << $shift) - 1);
bitLen -= 8;
}
return decoded;
}
// BASE32 END
let wallet=“grin1zxwrf5yaxlyps4mpx3n7j9kp4su3gzgpdhfk2sgv56q0prcdlzls9e6e0y”;
let correct_address = “cgodjue5g7ebqv3bgrt6sfwbvq4ricibnxjwkqimu2apbdyn7c752iyd”;
let data = decodeRaw(wallet)[1];
let hrp_data = decodeRaw(wallet)[0];
console.log(“hrp_data”);
console.log(hrp_data);
let decoded = convertBits(data,data.length,5,8,false);
console.log(data);
console.log("\ndecoded (length: "+ decoded.length);
console.log(decoded);
console.log(“CORRECT THIS FAR ----------------------------------------\n\n”);
// Correct array [17,156,52,208]
let pkb = pack( decoded);
console.log("pkb(pack) : "+pkb.length.toString());
console.log(pkb);
const {createHash} = require(‘crypto’);
let checkSumArray = “.onion checksum” + pkb + “\x03”;
// Not sure which encoding to use, so I try each one of them
let encodings = [‘utf8’,‘binary’,‘hex’,‘ascii’,‘latin1’]
console.log('checksum: ');
for (let i =0;i<encodings.length;i++){
let hash = createHash(‘sha256’);
let checksumBuffer = Buffer.from(checkSumArray,encodings[i]);
hash.update( checksumBuffer);
let checksum = hash.digest('base32');
console.log(checksum);
}
let wallet_address = Base32_encode(pkb);
console.log(“\n\nDerived address:”);
console.log(wallet_address);
console.log(“correct address:”);
console.log(correct_address);
console.log(“\n\n----- END -------”);