UNPKG

@holochain/client

Version:

A JavaScript client for the Holochain Conductor API

159 lines (158 loc) 5.36 kB
import { encode } from "@msgpack/msgpack"; import { HoloHashType } from "../types.js"; import blake2b from "@bitgo/blake2b"; import isEqual from "lodash-es/isEqual.js"; const HASH_TYPE_START = 0; const HASH_TYPE_BYTE_LENGTH = 3; const CORE_HASH_BYTE_LENGTH = 32; const DHT_LOCATION_BYTE_LENGTH = 4; const HASH_TYPE_PREFIX_U8 = { [HoloHashType.Agent]: [132, 32, 36], [HoloHashType.Entry]: [132, 33, 36], [HoloHashType.DhtOp]: [132, 36, 36], [HoloHashType.Warrant]: [132, 44, 36], [HoloHashType.Dna]: [132, 45, 36], [HoloHashType.Action]: [132, 41, 36], [HoloHashType.Wasm]: [132, 42, 36], [HoloHashType.External]: [132, 47, 36], }; /** * Hash type labels mapped to their 3 byte values (forming the first 3 bytes of hash). * * From https://github.com/holochain/holochain/blob/develop/crates/holo_hash/src/hash_type/primitive.rs * * @public */ export const HASH_TYPE_PREFIX = { [HoloHashType.Agent]: Uint8Array.from(HASH_TYPE_PREFIX_U8[HoloHashType.Agent]), [HoloHashType.Entry]: Uint8Array.from(HASH_TYPE_PREFIX_U8[HoloHashType.Entry]), [HoloHashType.DhtOp]: Uint8Array.from(HASH_TYPE_PREFIX_U8[HoloHashType.DhtOp]), [HoloHashType.Warrant]: Uint8Array.from(HASH_TYPE_PREFIX_U8[HoloHashType.Warrant]), [HoloHashType.Dna]: Uint8Array.from(HASH_TYPE_PREFIX_U8[HoloHashType.Dna]), [HoloHashType.Action]: Uint8Array.from(HASH_TYPE_PREFIX_U8[HoloHashType.Action]), [HoloHashType.Wasm]: Uint8Array.from(HASH_TYPE_PREFIX_U8[HoloHashType.Wasm]), [HoloHashType.External]: Uint8Array.from(HASH_TYPE_PREFIX_U8[HoloHashType.External]), }; /** * Get hash type (initial 3 bytes) from a hash. * * From https://github.com/holochain/holochain/blob/develop/crates/holo_hash/src/hash_type/primitive.rs * * @param hash - The full 39 byte hash. * @returns The initial 3 bytes of the hash. * * @public */ export function sliceHashType(hash) { return Uint8Array.from(hash.slice(0, 3)); } /** * Get core hash from a Holochain hash (32 bytes). * * From https://github.com/holochain/holochain/blob/develop/crates/holo_hash/src/hash_type/primitive.rs * * @param hash - The full 39 byte hash. * @returns The core 32 bytes of the hash. * * @public */ export function sliceCore32(hash) { const start = HASH_TYPE_START + HASH_TYPE_BYTE_LENGTH; const end = start + CORE_HASH_BYTE_LENGTH; return Uint8Array.from(hash.slice(start, end)); } /** * Get DHT location (last 4 bytes) from a hash. * * From https://github.com/holochain/holochain/blob/develop/crates/holo_hash/src/hash_type/primitive.rs * * @param hash - The full 39 byte hash. * @returns The last 4 bytes of the hash. * * @public */ export function sliceDhtLocation(hash) { const start = HASH_TYPE_START + HASH_TYPE_BYTE_LENGTH + CORE_HASH_BYTE_LENGTH; const end = start + DHT_LOCATION_BYTE_LENGTH; return Uint8Array.from(hash.slice(start, end)); } /** * Generate DHT location (last 4 bytes) from a core hash (middle 32 bytes). * * From https://github.com/holochain/holochain/blob/develop/crates/holo_hash/src/hash_type/primitive.rs * * @param hashCore - The core 32 bytes of the hash. * @returns The last 4 bytes of the hash. * * @public */ export function dhtLocationFrom32(hashCore) { const hash = new Uint8Array(16); blake2b(hash.length).update(hashCore).digest(hash); const out = hash.slice(0, 4); [4, 8, 12].forEach((i) => { out[0] ^= hash[i]; out[1] ^= hash[i + 1]; out[2] ^= hash[i + 2]; out[3] ^= hash[i + 3]; }); return out; } /** * Get hash type of a hash, by reading the first 3 bytes. * * From https://github.com/holochain/holochain/blob/develop/crates/holo_hash/src/hash_type/primitive.rs * * @param hash - The full 39 byte hash. * @returns The HashType * * @public */ export function getHashType(hash) { const hashTypeBytes = Array.from(hash.slice(0, 3)); const res = Object.entries(HASH_TYPE_PREFIX_U8).find(([, val]) => isEqual(val, hashTypeBytes)); if (res === undefined) { throw new Error("First 3 bytes of hash do not match any known HashType"); } return res[0]; } /** * Generate full hash from a core hash (middle 32 bytes) and hash type label. * * From https://github.com/holochain/holochain/blob/develop/crates/holo_hash/src/hash_type/primitive.rs * * @param hashCore - The core 32 bytes of the hash. * @param hashType - The type of the hash. * @returns The full 39 byte hash. * * @public */ export function hashFrom32AndType(hashCore, hashType) { return Uint8Array.from([ ...HASH_TYPE_PREFIX[hashType], ...hashCore, ...dhtLocationFrom32(hashCore), ]); } /** * Generate full hash from some data content and hash type label. * * From https://github.com/holochain/holochain/blob/develop/crates/holo_hash/src/hash_type/primitive.rs * * @param content - The data to hash. * @param hashType - The type of the hash. * @returns The full 39 byte hash. * * @public */ export function hashFromContentAndType( // eslint-disable-next-line @typescript-eslint/no-explicit-any content, hashType) { const hashCore = new Uint8Array(32); blake2b(hashCore.length).update(encode(content)).digest(hashCore); return Uint8Array.from([ ...HASH_TYPE_PREFIX[hashType], ...hashCore, ...dhtLocationFrom32(hashCore), ]); }