// atproto block CIDs — CIDv1, dag-cbor codec (0x71), sha2-256 multihash (0x12).
// Every block in a repo (commit, MST node, record) is content-addressed this way,
// so computeCid(dag-cbor(block)) IS the block's identity. This is the anchor for
// byte-exact fidelity: if our re-encoded bytes hash to the same CID the reference
// produced, our encoding is byte-identical.
import { CID } from 'multiformats/cid'
import * as Digest from 'multiformats/hashes/digest'
import { sha256 as nobleSha256 } from '@noble/hashes/sha2'
import * as dagCbor from '@ipld/dag-cbor'
import * as raw from 'multiformats/codecs/raw'
// raw block bytes -> CID. Uses noble's pure-JS sha256 (same as the sync path) rather
// than multiformats' `crypto.subtle` path — identical CID, and no WebCrypto dependency
// (so it loads + runs under Bare, which has no crypto.subtle).
export async function cidForBytes (bytes) {
return cidForBytesSync(bytes)
}
// Synchronous variant — needed by the recursive MST build. Same result as
// cidForBytes (CIDv1 / dag-cbor 0x71 / sha2-256 0x12), just without the async
// WebCrypto digest.
export function cidForBytesSync (bytes) {
const digest = Digest.create(0x12, nobleSha256(bytes)) // 0x12 = sha2-256 multihash code
return CID.createV1(dagCbor.code, digest)
}
// BLOB CID — CIDv1, RAW codec (0x55), sha2-256. atproto blobs (images/avatars) are
// content-addressed with the raw codec (opaque bytes), NOT dag-cbor. This is the CID that
// goes in a blob ref ({$type:'blob', ref:{$link:<this>}, mimeType, size}) and the key
// com.atproto.sync.getBlob serves by.
export function cidForBlobSync (bytes) {
const digest = Digest.create(0x12, nobleSha256(bytes))
return CID.createV1(raw.code, digest)
}
// a JS value -> its canonical dag-cbor bytes + CID
export async function cidForValue (value) {
const bytes = dagCbor.encode(value)
return { bytes, cid: await cidForBytes(bytes) }
}