75 lines
1.6 KiB
TypeScript
75 lines
1.6 KiB
TypeScript
import { base58btc } from "multiformats/bases/base58";
|
|
import * as edUtils from "@noble/curves/abstract/utils";
|
|
|
|
export const MAGIC_BYTES = new Uint8Array([0x26, 0x1f]);
|
|
|
|
export interface CID {
|
|
hash: Uint8Array;
|
|
size: bigint;
|
|
}
|
|
|
|
export function encodeCid(hash: Uint8Array, size: bigint);
|
|
export function encodeCid(hash: string, size: bigint);
|
|
export function encodeCid(hash: any, size: bigint) {
|
|
if (typeof hash === "string") {
|
|
hash = edUtils.hexToBytes(hash);
|
|
}
|
|
|
|
if (!(hash instanceof Uint8Array)) {
|
|
throw new Error();
|
|
}
|
|
|
|
if (!size) {
|
|
throw new Error("size required");
|
|
}
|
|
|
|
size = BigInt(size);
|
|
|
|
const sizeBytes = new Uint8Array(8);
|
|
const sizeView = new DataView(sizeBytes.buffer);
|
|
sizeView.setBigInt64(0, size, true);
|
|
|
|
const prefixedHash = Uint8Array.from([...MAGIC_BYTES, ...hash, ...sizeBytes]);
|
|
return base58btc.encode(prefixedHash).toString();
|
|
}
|
|
|
|
export function decodeCid(cid: string): CID {
|
|
let bytes = base58btc.decode(cid);
|
|
|
|
if (!arrayBufferEqual(bytes.slice(0, 2).buffer, bytes.buffer)) {
|
|
throw new Error("Invalid cid");
|
|
}
|
|
|
|
bytes = bytes.slice(2);
|
|
let cidHash = bytes.slice(0, 32);
|
|
let size = bytes.slice(32);
|
|
const sizeView = new DataView(size.buffer);
|
|
|
|
return {
|
|
hash: cidHash,
|
|
size: sizeView.getBigInt64(0, true),
|
|
};
|
|
}
|
|
|
|
function arrayBufferEqual(buf1, buf2) {
|
|
if (buf1 === buf2) {
|
|
return true;
|
|
}
|
|
|
|
if (buf1.byteLength !== buf2.byteLength) {
|
|
return false;
|
|
}
|
|
|
|
var view1 = new DataView(buf1);
|
|
var view2 = new DataView(buf2);
|
|
|
|
var i = buf1.byteLength;
|
|
while (i--) {
|
|
if (view1.getUint8(i) !== view2.getUint8(i)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|