multiformats
Version:
Interface for multihash, multicodec, multibase and CID
79 lines (67 loc) • 2.37 kB
text/typescript
import { coerce, equals as equalBytes, toArrayBufferBackedArray } from '../bytes.ts'
import * as varint from '../varint.ts'
import type { MultihashDigest } from './interface.ts'
/**
* Creates a multihash digest.
*/
export function create <Code extends number> (code: Code, digest: Uint8Array): Digest<Code, number> {
const size = digest.byteLength
const sizeOffset = varint.encodingLength(code)
const digestOffset = sizeOffset + varint.encodingLength(size)
const bytes = new Uint8Array(digestOffset + size)
varint.encodeTo(code, bytes, 0)
varint.encodeTo(size, bytes, sizeOffset)
bytes.set(digest, digestOffset)
return new Digest(code, size, digest, bytes)
}
/**
* Turns bytes representation of multihash digest into an instance.
*/
export function decode (multihash: Uint8Array): MultihashDigest {
const bytes = coerce(multihash)
const [code, sizeOffset] = varint.decode(bytes)
const [size, digestOffset] = varint.decode(bytes.subarray(sizeOffset))
const digest = bytes.subarray(sizeOffset + digestOffset)
if (digest.byteLength !== size) {
throw new Error('Incorrect length')
}
return new Digest(code, size, digest, bytes)
}
export function equals (a: MultihashDigest, b: unknown): b is MultihashDigest {
if (a === b) {
return true
} else {
const data = b as { code?: unknown, size?: unknown, bytes?: unknown }
return (
a.code === data.code &&
a.size === data.size &&
data.bytes instanceof Uint8Array &&
equalBytes(a.bytes, data.bytes)
)
}
}
/**
* Represents a multihash digest which carries information about the
* hashing algorithm and an actual hash digest.
*/
export class Digest<Code extends number, Size extends number> implements MultihashDigest {
readonly code: Code
readonly size: Size
readonly digest: Uint8Array<ArrayBuffer>
readonly bytes: Uint8Array<ArrayBuffer>
/**
* Creates a multihash digest.
*/
constructor (code: Code, size: Size, digest: Uint8Array, bytes: Uint8Array) {
this.code = code
this.size = size
this.digest = toArrayBufferBackedArray(digest)
this.bytes = toArrayBufferBackedArray(bytes)
}
}
/**
* Used to check that the passed multihash has the passed code
*/
export function hasCode <T extends number> (digest: MultihashDigest, code: T): digest is MultihashDigest<T> {
return digest.code === code
}