kernel-swarm/src/addr.ts

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 = [];
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 = [];
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;
}