Closed zquestz closed 6 years ago
If you need, I have a one-file, dependencyless address translator here: https://github.com/cashaddress/cashaddress.github.io/blob/master/main.js#L202
Or just copy paste this:
const CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
function craftCashAddress(kind, addressHash, isMainNet) {
var payload = packCashAddressData(kind, addressHash);
if (payload.length == 0) {
return;
}
// func ExpandPrefix(prefix string) []byte {
// ret := make(data, len(prefix) + 1)
// for i := 0; i < len(prefix); i++ {
// ret[i] = byte(prefix[i]) & 0x1f;
// }
// ret[len(prefix)] = 0;
// return ret;
// }
// https://play.golang.org/p/NMR2ImCmdpZ
var expandPrefix = [];
if (isMainNet == true) {
expandPrefix = [2, 9, 20, 3, 15, 9, 14, 3, 1, 19, 8, 0];
} else {
expandPrefix = [2, 3, 8, 20, 5, 19, 20, 0];
}
var enc = expandPrefix.concat(payload);
var mod = polyMod(enc.concat([0, 0, 0, 0, 0, 0, 0, 0]));
var retChecksum = [];
var t = [];
for (var i = 0; i < 8; i++) {
// Convert the 5-bit groups in mod to checksum values.
// retChecksum[i] = (mod >> uint(5*(7-i))) & 0x1f
retChecksum[i] = simplify(and(rShift(mod, 5 * (7 - i)), [31]))[0];
}
var combined = payload.concat(retChecksum);
var ret = "";
if (isMainNet == true) {
ret = "bitcoincash:";
} else {
ret = "bchtest:";
}
for (var i = 0; i < combined.length; i++) {
ret = ret.concat(CHARSET[combined[i]]);
}
if (ret.length == 54 || ret.length == 50) {
return ret;
} else {
return ""
}
}
function packCashAddressData(addressType, addressHash) {
// Pack addr data with version byte.
var versionByte = addressType << 3;
// Those addresses are not in use!
/*var encodedSize = (addressHash.length - 20) / 4
if ((addressHash.length-20)%4 != 0) {
return []
}
if (encodedSize < 0 || encodedSize > 8) {
return []
}
versionByte |= encodedSize*/
var data = [versionByte].concat(addressHash);
return convertBits(data, 8, 5, true);
}
function convertBits(data, fromBits, tobits, pad) {
// General power-of-2 base conversion.
var acc = 0;
var bits = 0;
var ret = [];
var maxv = (1 << tobits) - 1;
var maxAcc = (1 << (fromBits + tobits - 1)) - 1;
for (var i = 0; i < data.length; i++) {
var value = data[i];
if (value < 0 || value >> fromBits !== 0) {
return [];
}
acc = ((acc << fromBits) | value) & maxAcc;
bits += fromBits;
while (bits >= tobits) {
bits -= tobits;
ret.push((acc >> bits) & maxv);
}
}
if (pad) {
if (bits > 0) {
ret.push((acc << (tobits - bits)) & maxv);
}
} else if (bits >= fromBits || ((acc << (tobits - bits)) & maxv) != 0) {
return [];
}
return ret;
}
function polyMod(v) {
var c = [0, 1];
var c0 = [0];
var temp = [];
for (var i = 0; i < v.length; i++) {
c0 = rShift(c, 35);
c = xor(add5zerosAtTheEnd(and(c, [7, -1])), [v[i]]);
if (c0.length === 0) {
c0 = [0];
}
if (c0[0] & 1) {
c = xor(c, [0x98, 0xf2bc8e61]);
}
if (c0[0] & 2) {
c = xor(c, [0x79, 0xb76d99e2]);
}
if (c0[0] & 4) {
c = xor(c, [0xf3, 0x3e5fb3c4]);
}
if (c0[0] & 8) {
c = xor(c, [0xae, 0x2eabe2a8]);
}
if (c0[0] & 16) {
c = xor(c, [0x1e, 0x4f43e470]);
}
}
return xor(c, [1]);
}
function add5zerosAtTheEnd(a) {
a = [0].concat(a);
for (var i = 1; i < a.length; i++) {
a[i - 1] |= a[i] >>> 27;
a[i] <<= 5;
}
return a;
}
function rShift(a, b) {
// 35 >= b >= 0
var t = a.slice(0);
if (t.length === 0) {
return [0];
}
if (b > 31) {
t = a.slice(0, -1);
b -= 32;
}
if (b === 0) {
return t;
}
for (var i = t.length - 1; i > 0; i--) {
t[i] >>>= b;
t[i] |= (t[i - 1] & ((2 << (b + 1)) - 1)) << (32 - b);
}
t[0] >>>= b;
if (t[0] === 0) {
return t.slice(1);
}
return t;
}
function xor(a, b) {
var t = a.length - b.length;
var c = [];
if (t > 0) {
b = Array(t)
.fill(0)
.concat(b);
} else if (t < 0) {
a = Array(-t)
.fill(0)
.concat(a);
}
for (var i = 0; i < a.length; i++) {
c.push(a[i] ^ b[i]);
}
return c;
}
function and(a, b) {
var t = a.length - b.length;
c = [];
if (t >= 0) {
for (var i = 0; i < b.length; i++) {
c.push(a[i + t] & b[i]);
}
} else {
for (var i = 0; i < a.length; i++) {
c.push(a[i] & b[i - t]);
}
}
return c;
}
function simplify(v) {
if (v.length === 0) {
return [0];
}
var i = 0;
while (v[i] === 0) {
i++;
}
var z = v.slice(i);
if (z.length === 0) {
z = [0];
}
return z;
}
alert(craftCashAddress(1, [1,8,120,1,8,120,1,8,120,1,8,120,1,8,120,1,8,120,9,100], true))
This is now up for review -> https://github.com/theantnest/bccaddress/pull/26
Done
If anyone wants to update code for the new cashaddr format that would be epic. Otherwise I will try to get to it soon. =)