From 27524b7fe82a77b75f1bfd079a08a1b011bb1d0d Mon Sep 17 00:00:00 2001 From: JP Hastings-Spital Date: Mon, 22 Apr 2024 12:01:59 +0100 Subject: [PATCH] Add a memex entry for IPFS hashing --- content/memex/computing/ipfs.md | 88 +++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 content/memex/computing/ipfs.md diff --git a/content/memex/computing/ipfs.md b/content/memex/computing/ipfs.md new file mode 100644 index 00000000..9cf46f36 --- /dev/null +++ b/content/memex/computing/ipfs.md @@ -0,0 +1,88 @@ +--- +title: IPFS +summary: The InterPlanetary FileSystem, and its adjacent distributed technologies. +tags: +- computing +- communication +references: + - url: https://github.com/twdragon/ipfs-cid-local + name: IPFS CID Calculator + - url: https://go.dev/ + name: The Go Programming Language +--- + +## Generating IPFS hashes + +For some reason I often find myself wanting to generate the CID that IPFS would generate in [Go](https://go.dev/), but without having to run an entire node. I found [this repo](https://github.com/twdragon/ipfs-cid-local) from which I've extracted and tweaked the following code to generate Blake3 CIDs from arbitrary bytes. + +```go +package hash + +import ( + "bytes" + "fmt" + + "github.com/ipfs/boxo/blockservice" + blockstore "github.com/ipfs/boxo/blockstore" + chunker "github.com/ipfs/boxo/chunker" + offline "github.com/ipfs/boxo/exchange/offline" + "github.com/ipfs/boxo/ipld/merkledag" + "github.com/ipfs/boxo/ipld/unixfs/importer/balanced" + uih "github.com/ipfs/boxo/ipld/unixfs/importer/helpers" + "github.com/ipfs/go-cid" + "github.com/ipfs/go-datastore" + dsync "github.com/ipfs/go-datastore/sync" + multicodec "github.com/multiformats/go-multicodec" +) + +func CID(data []byte) (string, error) { + ds := dsync.MutexWrap(datastore.NewNullDatastore()) + bs := blockstore.NewIdStore(blockstore.NewBlockstore(ds)) + bsrv := blockservice.New(bs, offline.Exchange(bs)) + dsrv := merkledag.NewDAGService(bsrv) + + ufsImportParams := uih.DagBuilderParams{ + Maxlinks: uih.DefaultLinksPerBlock, + RawLeaves: true, + CidBuilder: cid.V1Builder{ + Codec: uint64(multicodec.Raw), + MhType: uint64(multicodec.Blake3), + MhLength: -1, + }, + Dagserv: dsrv, + NoCopy: false, + } + + r := bytes.NewReader(data) + + ufsBuilder, err := ufsImportParams.New(chunker.NewSizeSplitter(r, chunker.DefaultBlockSize)) + if err != nil { + return "", fmt.Errorf("unable to chunk the event to create a Blake3 hash: %w", err) + } + + nd, err := balanced.Layout(ufsBuilder) + if err != nil { + return "", fmt.Errorf("unable to layout the DAG while hashing the event: %w", err) + } + + return nd.Cid().String(), nil +} +``` + +This can be done _much_ more simply if you know that your data is never going to exceed 256KiB (which is the default chunker size) with the following. This works cos, without chunking, the data that'd be stored is identical to what you're providing! + +```go +import ( + "github.com/ipfs/go-cid" + "github.com/multiformats/go-multihash" +) + +func CID(data []byte) (string, error) { + hash, err := multihash.Sum(data, multihash.BLAKE3, -1) + if err != nil { + return "", err + } + + return cid.NewCidV1(cid.Raw, hash).String(), nil +} +```