73 lines
1.8 KiB
TypeScript
73 lines
1.8 KiB
TypeScript
/*
|
|
The following is based on https://github.com/yggdrasil-network/yggdrasil-go/blob/develop/src/address/address.go, which is licensed LGPL3. Full credit to them for the idea and original algorithm
|
|
*/
|
|
|
|
export function pubKeyToIpv6(publicKey: Uint8Array) {
|
|
const keySize = 32;
|
|
if (publicKey.length !== keySize) {
|
|
return null;
|
|
}
|
|
|
|
const buf = new Uint8Array(keySize);
|
|
for (let i = 0; i < keySize; i++) {
|
|
buf[i] = buf[i] = publicKey[i] ^ 0xff;
|
|
}
|
|
|
|
const prefix = [0x02];
|
|
const ones = getLeadingOnes(buf);
|
|
const nodeId = getTruncatedNodeID(buf);
|
|
|
|
const addr = new Uint8Array(prefix.length + 1 + nodeId.length);
|
|
addr.set(prefix, 0);
|
|
addr[prefix.length] = ones;
|
|
addr.set(nodeId, prefix.length + 1);
|
|
|
|
const result: string[] = [];
|
|
for (let i = 0; i < 8; i++) {
|
|
const num1 = addr[i * 2].toString(16).padStart(2, "0");
|
|
const num2 = addr[i * 2 + 1].toString(16).padStart(2, "0");
|
|
result.push(`${num1}${num2}`);
|
|
}
|
|
return result.join(":");
|
|
}
|
|
|
|
function getLeadingOnes(buf: Uint8Array) {
|
|
let done = false;
|
|
let ones = 0;
|
|
for (let i = 0; i < buf.length * 8; i++) {
|
|
const bit = (buf[i >>> 3] & (0x80 >> (i & 7))) >> (7 - (i & 7));
|
|
if (!done && bit !== 0) {
|
|
ones++;
|
|
} else if (!done && bit === 0) {
|
|
done = true;
|
|
}
|
|
}
|
|
return ones;
|
|
}
|
|
|
|
function getTruncatedNodeID(buf: Uint8Array) {
|
|
const result: number[] = [];
|
|
let done = false;
|
|
let bits = 0;
|
|
let nBits = 0;
|
|
for (let i = 0; i < buf.length * 8; i++) {
|
|
const bit = (buf[i >>> 3] & (0x80 >> (i & 7))) >> (7 - (i & 7));
|
|
if (!done && bit !== 0) {
|
|
continue;
|
|
}
|
|
|
|
if (!done && bit === 0) {
|
|
done = true;
|
|
continue;
|
|
}
|
|
|
|
bits = (bits << 1) | bit;
|
|
nBits++;
|
|
if (nBits === 8) {
|
|
nBits = 0;
|
|
result.push(bits);
|
|
}
|
|
}
|
|
return result;
|
|
}
|