this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: three-way trust chain verification (zig + go + rust)

add `just verify` and `just chart` — full AT Protocol trust chain
verification with timing across all three SDKs. includes O(1) block
lookup fix (HashMap vs linear scan), SVG chart generation, and
results in README.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

zzstoatzz 44f58000 1c512eed

+4457
+5
.gitignore
··· 7 7 rust-raw/target/ 8 8 rust-rsky/target/ 9 9 rust-sigs/target/ 10 + rust-verify/target/ 10 11 11 12 # go 12 13 go/atproto-bench 13 14 go-raw/atproto-bench-go-raw 14 15 go-sigs/atproto-bench-sigs 16 + go-verify/go-verify 17 + 18 + # traces 19 + *.trace/ 15 20 16 21 # python 17 22 python/.venv/
+42
README.md
··· 213 213 | go | [indigo](https://github.com/bluesky-social/indigo) | latest | [cbor-gen](https://github.com/whyrusleeping/cbor-gen) (code-generated) | [go-car/v2](https://github.com/ipld/go-car) (+ SHA-256 CID verify) | 214 214 | python | [atproto](https://github.com/MarshalX/atproto) | 0.0.65 | [libipld](https://github.com/MarshalX/atproto) (Rust via PyO3) | libipld | 215 215 216 + ## trust chain verification 217 + 218 + a third benchmark measures the full end-to-end AT Protocol trust chain: given a handle, resolve identity, fetch the repo, and cryptographically verify everything. this exercises the complete pipeline that any independent verifier needs. 219 + 220 + ### what it measures 221 + 222 + per handle, all three SDKs do the same work: 223 + 1. resolve handle → DID (HTTP well-known or DNS TXT) 224 + 2. resolve DID → DID document → extract signing key + PDS endpoint 225 + 3. fetch full repo CAR from PDS (`com.atproto.sync.getRepo`) 226 + 4. parse CAR with CID verification (SHA-256 per block) 227 + 5. ECDSA verify the commit signature against the signing key 228 + 6. walk the MST to count all records 229 + 7. rebuild MST and verify root CID matches commit (zig and go only) 230 + 231 + ### results 232 + 233 + _pfrazee.com — 192,144 records, 243,470 blocks, 70.6 MB CAR, macOS arm64 (M3 Max)_ 234 + 235 + <img src="docs/verify-compute.svg" alt="trust chain compute breakdown" width="790"> 236 + 237 + | SDK | CAR parse | sig verify | MST walk | MST rebuild | compute total | network | 238 + |-----|----------:|----------:|---------:|------------:|-------------:|--------:| 239 + | zig ([zat](https://tangled.sh/@zzstoatzz.io/zat)) | 81.6ms | 0.6ms | 45.5ms | 172.6ms | 300.4ms | 9.8s | 240 + | go ([indigo](https://github.com/bluesky-social/indigo)) | 403.8ms | 0.4ms | 5.8ms | 0.0ms | 410.0ms | 20.8s | 241 + | rust (RustCrypto) | 301.0ms | 0.2ms | 120.9ms | N/A | 422.1ms | 8.7s | 242 + 243 + compute time is dominated by CAR parsing (SHA-256 verification of 243k blocks) and MST operations. signature verification is sub-millisecond for all three — single ECDSA verify is trivial compared to the bulk data work. 244 + 245 + zig's CAR parse advantage carries over from the decode benchmarks (arena allocation + zero-copy). go's MST walk is fastest because indigo's `MST.Walk()` operates on an already-loaded in-memory tree. rust skips MST rebuild (no equivalent crate exists) but the trust chain is still fully proven by signature + walk. 246 + 247 + network time varies by run (PDS response time, TLS handshake, geographic distance). compare compute columns, not totals. 248 + 249 + ```sh 250 + just verify pfrazee.com # run all three 251 + just chart pfrazee.com # run + generate SVG charts 252 + ``` 253 + 216 254 ## usage 217 255 218 256 ```sh ··· 228 266 just bench-sigs-zig 229 267 just bench-sigs-rust 230 268 just bench-sigs-go 269 + 270 + # trust chain verification 271 + just verify pfrazee.com # run all three implementations 272 + just chart pfrazee.com # run + generate SVG charts to docs/ 231 273 ``` 232 274 233 275 ## methodology
+47
docs/verify-compute.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 790 267" font-family="'SF Mono', 'Fira Code', 'Cascadia Code', Menlo, monospace"> 2 + <rect width="790" height="267" fill="#1a1a2e" rx="8"/> 3 + <text x="395.0" y="28" text-anchor="middle" fill="#e0e0e0" font-size="15" font-weight="600">AT Protocol trust chain — compute</text> 4 + <text x="395.0" y="44" text-anchor="middle" fill="#666" font-size="11">192,144 records</text> 5 + <line x1="160.0" y1="53" x2="160.0" y2="211" stroke="#262640" stroke-width="1"/> 6 + <line x1="264.0" y1="53" x2="264.0" y2="211" stroke="#262640" stroke-width="1"/> 7 + <line x1="368.0" y1="53" x2="368.0" y2="211" stroke="#262640" stroke-width="1"/> 8 + <line x1="472.0" y1="53" x2="472.0" y2="211" stroke="#262640" stroke-width="1"/> 9 + <line x1="576.0" y1="53" x2="576.0" y2="211" stroke="#262640" stroke-width="1"/> 10 + <line x1="680.0" y1="53" x2="680.0" y2="211" stroke="#262640" stroke-width="1"/> 11 + <text x="146" y="79.0" text-anchor="end" fill="#c0c0c0" font-size="13">zig (zat)</text> 12 + <rect x="160.0" y="55" width="100.5" height="38" fill="#e8944a" rx="3"/> 13 + <text x="210.3" y="78.0" text-anchor="middle" fill="white" font-size="10" font-weight="500">CAR parse</text> 14 + <rect x="260.5" y="55" width="1.0" height="38" fill="#ed7d31" rx="3"/> 15 + <rect x="261.5" y="55" width="56.1" height="38" fill="#c55a11" rx="3"/> 16 + <text x="289.6" y="78.0" text-anchor="middle" fill="white" font-size="10" font-weight="500">MST walk</text> 17 + <rect x="317.6" y="55" width="212.6" height="38" fill="#a04000" rx="3"/> 18 + <text x="423.9" y="78.0" text-anchor="middle" fill="white" font-size="10" font-weight="500">MST rebuild</text> 19 + <text x="540.2" y="79.0" fill="#a0a0a0" font-size="12" font-weight="500">300ms</text> 20 + <text x="146" y="137.0" text-anchor="end" fill="#c0c0c0" font-size="13">go (indigo)</text> 21 + <rect x="160.0" y="113" width="497.5" height="38" fill="#e8944a" rx="3"/> 22 + <text x="408.7" y="136.0" text-anchor="middle" fill="white" font-size="10" font-weight="500">CAR parse</text> 23 + <rect x="657.5" y="113" width="1.0" height="38" fill="#ed7d31" rx="3"/> 24 + <rect x="658.5" y="113" width="7.1" height="38" fill="#c55a11" rx="3"/> 25 + <text x="675.6" y="137.0" fill="#a0a0a0" font-size="12" font-weight="500">410ms</text> 26 + <text x="146" y="195.0" text-anchor="end" fill="#c0c0c0" font-size="13">rust (RustCrypto)</text> 27 + <rect x="160.0" y="171" width="370.8" height="38" fill="#e8944a" rx="3"/> 28 + <text x="345.4" y="194.0" text-anchor="middle" fill="white" font-size="10" font-weight="500">CAR parse</text> 29 + <rect x="530.8" y="171" width="1.0" height="38" fill="#ed7d31" rx="3"/> 30 + <rect x="531.8" y="171" width="148.9" height="38" fill="#c55a11" rx="3"/> 31 + <text x="606.3" y="194.0" text-anchor="middle" fill="white" font-size="10" font-weight="500">MST walk</text> 32 + <text x="690.8" y="195.0" fill="#a0a0a0" font-size="12" font-weight="500">422ms</text> 33 + <text x="160.0" y="227" text-anchor="middle" fill="#606060" font-size="10">0</text> 34 + <text x="264.0" y="227" text-anchor="middle" fill="#606060" font-size="10">84ms</text> 35 + <text x="368.0" y="227" text-anchor="middle" fill="#606060" font-size="10">169ms</text> 36 + <text x="472.0" y="227" text-anchor="middle" fill="#606060" font-size="10">253ms</text> 37 + <text x="576.0" y="227" text-anchor="middle" fill="#606060" font-size="10">338ms</text> 38 + <text x="680.0" y="227" text-anchor="middle" fill="#606060" font-size="10">422ms</text> 39 + <rect x="160" y="241" width="10" height="10" fill="#e8944a" rx="2"/> 40 + <text x="174" y="249" fill="#808080" font-size="10">CAR parse</text> 41 + <rect x="242" y="241" width="10" height="10" fill="#ed7d31" rx="2"/> 42 + <text x="256" y="249" fill="#808080" font-size="10">sig verify</text> 43 + <rect x="330" y="241" width="10" height="10" fill="#c55a11" rx="2"/> 44 + <text x="344" y="249" fill="#808080" font-size="10">MST walk</text> 45 + <rect x="405" y="241" width="10" height="10" fill="#a04000" rx="2"/> 46 + <text x="419" y="249" fill="#808080" font-size="10">MST rebuild</text> 47 + </svg>
+59
docs/verify-total.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 790 267" font-family="'SF Mono', 'Fira Code', 'Cascadia Code', Menlo, monospace"> 2 + <rect width="790" height="267" fill="#1a1a2e" rx="8"/> 3 + <text x="395.0" y="28" text-anchor="middle" fill="#e0e0e0" font-size="15" font-weight="600">AT Protocol trust chain — total (network + compute)</text> 4 + <text x="395.0" y="44" text-anchor="middle" fill="#666" font-size="11">192,144 records</text> 5 + <line x1="160.0" y1="53" x2="160.0" y2="211" stroke="#262640" stroke-width="1"/> 6 + <line x1="264.0" y1="53" x2="264.0" y2="211" stroke="#262640" stroke-width="1"/> 7 + <line x1="368.0" y1="53" x2="368.0" y2="211" stroke="#262640" stroke-width="1"/> 8 + <line x1="472.0" y1="53" x2="472.0" y2="211" stroke="#262640" stroke-width="1"/> 9 + <line x1="576.0" y1="53" x2="576.0" y2="211" stroke="#262640" stroke-width="1"/> 10 + <line x1="680.0" y1="53" x2="680.0" y2="211" stroke="#262640" stroke-width="1"/> 11 + <text x="146" y="79.0" text-anchor="end" fill="#c0c0c0" font-size="13">zig (zat)</text> 12 + <rect x="160.0" y="55" width="18.0" height="38" fill="#6ea8d9" rx="3"/> 13 + <rect x="178.0" y="55" width="8.4" height="38" fill="#5b9bd5" rx="3"/> 14 + <rect x="186.4" y="55" width="214.2" height="38" fill="#4472c4" rx="3"/> 15 + <text x="293.5" y="78.0" text-anchor="middle" fill="white" font-size="10" font-weight="500">fetch</text> 16 + <rect x="400.6" y="55" width="2.0" height="38" fill="#e8944a" rx="3"/> 17 + <rect x="402.6" y="55" width="1.0" height="38" fill="#ed7d31" rx="3"/> 18 + <rect x="403.6" y="55" width="1.1" height="38" fill="#c55a11" rx="3"/> 19 + <rect x="404.7" y="55" width="4.2" height="38" fill="#a04000" rx="3"/> 20 + <text x="419.0" y="79.0" fill="#a0a0a0" font-size="12" font-weight="500">10.1s</text> 21 + <text x="146" y="137.0" text-anchor="end" fill="#c0c0c0" font-size="13">go (indigo)</text> 22 + <rect x="160.0" y="113" width="1.3" height="38" fill="#6ea8d9" rx="3"/> 23 + <rect x="161.3" y="113" width="3.6" height="38" fill="#5b9bd5" rx="3"/> 24 + <rect x="164.9" y="113" width="505.0" height="38" fill="#4472c4" rx="3"/> 25 + <text x="417.4" y="136.0" text-anchor="middle" fill="white" font-size="10" font-weight="500">fetch</text> 26 + <rect x="670.0" y="113" width="9.9" height="38" fill="#e8944a" rx="3"/> 27 + <rect x="679.8" y="113" width="1.0" height="38" fill="#ed7d31" rx="3"/> 28 + <rect x="680.8" y="113" width="1.0" height="38" fill="#c55a11" rx="3"/> 29 + <text x="691.8" y="137.0" fill="#a0a0a0" font-size="12" font-weight="500">21.2s</text> 30 + <text x="146" y="195.0" text-anchor="end" fill="#c0c0c0" font-size="13">rust (RustCrypto)</text> 31 + <rect x="160.0" y="171" width="16.3" height="38" fill="#6ea8d9" rx="3"/> 32 + <rect x="176.3" y="171" width="5.0" height="38" fill="#5b9bd5" rx="3"/> 33 + <rect x="181.2" y="171" width="191.0" height="38" fill="#4472c4" rx="3"/> 34 + <text x="276.7" y="194.0" text-anchor="middle" fill="white" font-size="10" font-weight="500">fetch</text> 35 + <rect x="372.2" y="171" width="7.4" height="38" fill="#e8944a" rx="3"/> 36 + <rect x="379.6" y="171" width="1.0" height="38" fill="#ed7d31" rx="3"/> 37 + <rect x="380.6" y="171" width="3.0" height="38" fill="#c55a11" rx="3"/> 38 + <text x="393.6" y="195.0" fill="#a0a0a0" font-size="12" font-weight="500">9.1s</text> 39 + <text x="160.0" y="227" text-anchor="middle" fill="#606060" font-size="10">0</text> 40 + <text x="264.0" y="227" text-anchor="middle" fill="#606060" font-size="10">4.2s</text> 41 + <text x="368.0" y="227" text-anchor="middle" fill="#606060" font-size="10">8.5s</text> 42 + <text x="472.0" y="227" text-anchor="middle" fill="#606060" font-size="10">12.7s</text> 43 + <text x="576.0" y="227" text-anchor="middle" fill="#606060" font-size="10">17.0s</text> 44 + <text x="680.0" y="227" text-anchor="middle" fill="#606060" font-size="10">21.2s</text> 45 + <rect x="160" y="241" width="10" height="10" fill="#6ea8d9" rx="2"/> 46 + <text x="174" y="249" fill="#808080" font-size="10">handle</text> 47 + <rect x="223" y="241" width="10" height="10" fill="#5b9bd5" rx="2"/> 48 + <text x="237" y="249" fill="#808080" font-size="10">DID doc</text> 49 + <rect x="293" y="241" width="10" height="10" fill="#4472c4" rx="2"/> 50 + <text x="307" y="249" fill="#808080" font-size="10">fetch</text> 51 + <rect x="350" y="241" width="10" height="10" fill="#e8944a" rx="2"/> 52 + <text x="364" y="249" fill="#808080" font-size="10">CAR parse</text> 53 + <rect x="431" y="241" width="10" height="10" fill="#ed7d31" rx="2"/> 54 + <text x="445" y="249" fill="#808080" font-size="10">sig verify</text> 55 + <rect x="519" y="241" width="10" height="10" fill="#c55a11" rx="2"/> 56 + <text x="533" y="249" fill="#808080" font-size="10">MST walk</text> 57 + <rect x="595" y="241" width="10" height="10" fill="#a04000" rx="2"/> 58 + <text x="609" y="249" fill="#808080" font-size="10">MST rebuild</text> 59 + </svg>
+72
go-verify/go.mod
··· 1 + module go-verify 2 + 3 + go 1.25.1 4 + 5 + require ( 6 + github.com/bluesky-social/indigo v0.0.0-20260220055544-bf41e2ee75ab 7 + github.com/ipfs/go-cid v0.4.1 8 + ) 9 + 10 + require ( 11 + github.com/beorn7/perks v1.0.1 // indirect 12 + github.com/cespare/xxhash/v2 v2.2.0 // indirect 13 + github.com/earthboundkid/versioninfo/v2 v2.24.1 // indirect 14 + github.com/go-logr/logr v1.4.1 // indirect 15 + github.com/go-logr/stdr v1.2.2 // indirect 16 + github.com/gogo/protobuf v1.3.2 // indirect 17 + github.com/google/uuid v1.4.0 // indirect 18 + github.com/hashicorp/golang-lru v1.0.2 // indirect 19 + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect 20 + github.com/ipfs/bbloom v0.0.4 // indirect 21 + github.com/ipfs/go-block-format v0.2.0 // indirect 22 + github.com/ipfs/go-blockservice v0.5.2 // indirect 23 + github.com/ipfs/go-datastore v0.6.0 // indirect 24 + github.com/ipfs/go-ipfs-blockstore v1.3.1 // indirect 25 + github.com/ipfs/go-ipfs-ds-help v1.1.1 // indirect 26 + github.com/ipfs/go-ipfs-exchange-interface v0.2.1 // indirect 27 + github.com/ipfs/go-ipfs-util v0.0.3 // indirect 28 + github.com/ipfs/go-ipld-cbor v0.1.0 // indirect 29 + github.com/ipfs/go-ipld-format v0.6.0 // indirect 30 + github.com/ipfs/go-ipld-legacy v0.2.1 // indirect 31 + github.com/ipfs/go-log v1.0.5 // indirect 32 + github.com/ipfs/go-log/v2 v2.5.1 // indirect 33 + github.com/ipfs/go-merkledag v0.11.0 // indirect 34 + github.com/ipfs/go-metrics-interface v0.0.1 // indirect 35 + github.com/ipfs/go-verifcid v0.0.3 // indirect 36 + github.com/ipld/go-car v0.6.1-0.20230509095817-92d28eb23ba4 // indirect 37 + github.com/ipld/go-codec-dagpb v1.6.0 // indirect 38 + github.com/ipld/go-ipld-prime v0.21.0 // indirect 39 + github.com/jbenet/goprocess v0.1.4 // indirect 40 + github.com/klauspost/cpuid/v2 v2.2.7 // indirect 41 + github.com/mattn/go-isatty v0.0.20 // indirect 42 + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect 43 + github.com/minio/sha256-simd v1.0.1 // indirect 44 + github.com/mr-tron/base58 v1.2.0 // indirect 45 + github.com/multiformats/go-base32 v0.1.0 // indirect 46 + github.com/multiformats/go-base36 v0.2.0 // indirect 47 + github.com/multiformats/go-multibase v0.2.0 // indirect 48 + github.com/multiformats/go-multihash v0.2.3 // indirect 49 + github.com/multiformats/go-varint v0.0.7 // indirect 50 + github.com/opentracing/opentracing-go v1.2.0 // indirect 51 + github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f // indirect 52 + github.com/prometheus/client_golang v1.17.0 // indirect 53 + github.com/prometheus/client_model v0.5.0 // indirect 54 + github.com/prometheus/common v0.45.0 // indirect 55 + github.com/prometheus/procfs v0.12.0 // indirect 56 + github.com/spaolacci/murmur3 v1.1.0 // indirect 57 + github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e // indirect 58 + gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect 59 + gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect 60 + go.opentelemetry.io/otel v1.21.0 // indirect 61 + go.opentelemetry.io/otel/metric v1.21.0 // indirect 62 + go.opentelemetry.io/otel/trace v1.21.0 // indirect 63 + go.uber.org/atomic v1.11.0 // indirect 64 + go.uber.org/multierr v1.11.0 // indirect 65 + go.uber.org/zap v1.26.0 // indirect 66 + golang.org/x/crypto v0.21.0 // indirect 67 + golang.org/x/sys v0.22.0 // indirect 68 + golang.org/x/time v0.3.0 // indirect 69 + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect 70 + google.golang.org/protobuf v1.33.0 // indirect 71 + lukechampine.com/blake3 v1.2.1 // indirect 72 + )
+324
go-verify/go.sum
··· 1 + github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 2 + github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 3 + github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= 4 + github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 5 + github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 6 + github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 7 + github.com/bluesky-social/indigo v0.0.0-20260220055544-bf41e2ee75ab h1:Cs35T2tAN3Q6mMH5mBaY09nmCNOn/GkZS1F7jfMxlR8= 8 + github.com/bluesky-social/indigo v0.0.0-20260220055544-bf41e2ee75ab/go.mod h1:VG/LeqLGNI3Ew7lsYixajnZGFfWPv144qbUddh+Oyag= 9 + github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= 10 + github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 11 + github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 12 + github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= 13 + github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= 14 + github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 15 + github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 16 + github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 17 + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= 18 + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= 19 + github.com/earthboundkid/versioninfo/v2 v2.24.1 h1:SJTMHaoUx3GzjjnUO1QzP3ZXK6Ee/nbWyCm58eY3oUg= 20 + github.com/earthboundkid/versioninfo/v2 v2.24.1/go.mod h1:VcWEooDEuyUJnMfbdTh0uFN4cfEIg+kHMuWB2CDCLjw= 21 + github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= 22 + github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= 23 + github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 24 + github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= 25 + github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 26 + github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= 27 + github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 28 + github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= 29 + github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 30 + github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 31 + github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 32 + github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 33 + github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= 34 + github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= 35 + github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 36 + github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= 37 + github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 38 + github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= 39 + github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 40 + github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= 41 + github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= 42 + github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= 43 + github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= 44 + github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= 45 + github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= 46 + github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= 47 + github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= 48 + github.com/ipfs/go-bitswap v0.11.0 h1:j1WVvhDX1yhG32NTC9xfxnqycqYIlhzEzLXG/cU1HyQ= 49 + github.com/ipfs/go-bitswap v0.11.0/go.mod h1:05aE8H3XOU+LXpTedeAS0OZpcO1WFsj5niYQH9a1Tmk= 50 + github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs= 51 + github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= 52 + github.com/ipfs/go-blockservice v0.5.2 h1:in9Bc+QcXwd1apOVM7Un9t8tixPKdaHQFdLSUM1Xgk8= 53 + github.com/ipfs/go-blockservice v0.5.2/go.mod h1:VpMblFEqG67A/H2sHKAemeH9vlURVavlysbdUI632yk= 54 + github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= 55 + github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= 56 + github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= 57 + github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= 58 + github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= 59 + github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= 60 + github.com/ipfs/go-ipfs-blockstore v1.3.1 h1:cEI9ci7V0sRNivqaOr0elDsamxXFxJMMMy7PTTDQNsQ= 61 + github.com/ipfs/go-ipfs-blockstore v1.3.1/go.mod h1:KgtZyc9fq+P2xJUiCAzbRdhhqJHvsw8u2Dlqy2MyRTE= 62 + github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= 63 + github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= 64 + github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= 65 + github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= 66 + github.com/ipfs/go-ipfs-ds-help v1.1.1 h1:B5UJOH52IbcfS56+Ul+sv8jnIV10lbjLF5eOO0C66Nw= 67 + github.com/ipfs/go-ipfs-ds-help v1.1.1/go.mod h1:75vrVCkSdSFidJscs8n4W+77AtTpCIAdDGAwjitJMIo= 68 + github.com/ipfs/go-ipfs-exchange-interface v0.2.1 h1:jMzo2VhLKSHbVe+mHNzYgs95n0+t0Q69GQ5WhRDZV/s= 69 + github.com/ipfs/go-ipfs-exchange-interface v0.2.1/go.mod h1:MUsYn6rKbG6CTtsDp+lKJPmVt3ZrCViNyH3rfPGsZ2E= 70 + github.com/ipfs/go-ipfs-exchange-offline v0.3.0 h1:c/Dg8GDPzixGd0MC8Jh6mjOwU57uYokgWRFidfvEkuA= 71 + github.com/ipfs/go-ipfs-exchange-offline v0.3.0/go.mod h1:MOdJ9DChbb5u37M1IcbrRB02e++Z7521fMxqCNRrz9s= 72 + github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY= 73 + github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= 74 + github.com/ipfs/go-ipfs-routing v0.3.0 h1:9W/W3N+g+y4ZDeffSgqhgo7BsBSJwPMcyssET9OWevc= 75 + github.com/ipfs/go-ipfs-routing v0.3.0/go.mod h1:dKqtTFIql7e1zYsEuWLyuOU+E0WJWW8JjbTPLParDWo= 76 + github.com/ipfs/go-ipfs-util v0.0.3 h1:2RFdGez6bu2ZlZdI+rWfIdbQb1KudQp3VGwPtdNCmE0= 77 + github.com/ipfs/go-ipfs-util v0.0.3/go.mod h1:LHzG1a0Ig4G+iZ26UUOMjHd+lfM84LZCrn17xAKWBvs= 78 + github.com/ipfs/go-ipld-cbor v0.1.0 h1:dx0nS0kILVivGhfWuB6dUpMa/LAwElHPw1yOGYopoYs= 79 + github.com/ipfs/go-ipld-cbor v0.1.0/go.mod h1:U2aYlmVrJr2wsUBU67K4KgepApSZddGRDWBYR0H4sCk= 80 + github.com/ipfs/go-ipld-format v0.6.0 h1:VEJlA2kQ3LqFSIm5Vu6eIlSxD/Ze90xtc4Meten1F5U= 81 + github.com/ipfs/go-ipld-format v0.6.0/go.mod h1:g4QVMTn3marU3qXchwjpKPKgJv+zF+OlaKMyhJ4LHPg= 82 + github.com/ipfs/go-ipld-legacy v0.2.1 h1:mDFtrBpmU7b//LzLSypVrXsD8QxkEWxu5qVxN99/+tk= 83 + github.com/ipfs/go-ipld-legacy v0.2.1/go.mod h1:782MOUghNzMO2DER0FlBR94mllfdCJCkTtDtPM51otM= 84 + github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= 85 + github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= 86 + github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= 87 + github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= 88 + github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= 89 + github.com/ipfs/go-merkledag v0.11.0 h1:DgzwK5hprESOzS4O1t/wi6JDpyVQdvm9Bs59N/jqfBY= 90 + github.com/ipfs/go-merkledag v0.11.0/go.mod h1:Q4f/1ezvBiJV0YCIXvt51W/9/kqJGH4I1LsA7+djsM4= 91 + github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= 92 + github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= 93 + github.com/ipfs/go-peertaskqueue v0.8.0 h1:JyNO144tfu9bx6Hpo119zvbEL9iQ760FHOiJYsUjqaU= 94 + github.com/ipfs/go-peertaskqueue v0.8.0/go.mod h1:cz8hEnnARq4Du5TGqiWKgMr/BOSQ5XOgMOh1K5YYKKM= 95 + github.com/ipfs/go-verifcid v0.0.3 h1:gmRKccqhWDocCRkC+a59g5QW7uJw5bpX9HWBevXa0zs= 96 + github.com/ipfs/go-verifcid v0.0.3/go.mod h1:gcCtGniVzelKrbk9ooUSX/pM3xlH73fZZJDzQJRvOUw= 97 + github.com/ipld/go-car v0.6.1-0.20230509095817-92d28eb23ba4 h1:oFo19cBmcP0Cmg3XXbrr0V/c+xU9U1huEZp8+OgBzdI= 98 + github.com/ipld/go-car v0.6.1-0.20230509095817-92d28eb23ba4/go.mod h1:6nkFF8OmR5wLKBzRKi7/YFJpyYR7+oEn1DX+mMWnlLA= 99 + github.com/ipld/go-codec-dagpb v1.6.0 h1:9nYazfyu9B1p3NAgfVdpRco3Fs2nFC72DqVsMj6rOcc= 100 + github.com/ipld/go-codec-dagpb v1.6.0/go.mod h1:ANzFhfP2uMJxRBr8CE+WQWs5UsNa0pYtmKZ+agnUw9s= 101 + github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E= 102 + github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ= 103 + github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= 104 + github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= 105 + github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= 106 + github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= 107 + github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= 108 + github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= 109 + github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 110 + github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 111 + github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 112 + github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= 113 + github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= 114 + github.com/koron/go-ssdp v0.0.3 h1:JivLMY45N76b4p/vsWGOKewBQu6uf39y8l+AQ7sDKx8= 115 + github.com/koron/go-ssdp v0.0.3/go.mod h1:b2MxI6yh02pKrsyNoQUsk4+YNikaGhe4894J+Q5lDvA= 116 + github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 117 + github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 118 + github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 119 + github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 120 + github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 121 + github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 122 + github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 123 + github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= 124 + github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= 125 + github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= 126 + github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= 127 + github.com/libp2p/go-libp2p v0.22.0 h1:2Tce0kHOp5zASFKJbNzRElvh0iZwdtG5uZheNW8chIw= 128 + github.com/libp2p/go-libp2p v0.22.0/go.mod h1:UDolmweypBSjQb2f7xutPnwZ/fxioLbMBxSjRksxxU4= 129 + github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= 130 + github.com/libp2p/go-libp2p-asn-util v0.2.0/go.mod h1:WoaWxbHKBymSN41hWSq/lGKJEca7TNm58+gGJi2WsLI= 131 + github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0= 132 + github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk= 133 + github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= 134 + github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= 135 + github.com/libp2p/go-msgio v0.2.0 h1:W6shmB+FeynDrUVl2dgFQvzfBZcXiyqY4VmpQLu9FqU= 136 + github.com/libp2p/go-msgio v0.2.0/go.mod h1:dBVM1gW3Jk9XqHkU4eKdGvVHdLa51hoGfll6jMJMSlY= 137 + github.com/libp2p/go-nat v0.1.0 h1:MfVsH6DLcpa04Xr+p8hmVRG4juse0s3J8HyNWYHffXg= 138 + github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC3uRBM= 139 + github.com/libp2p/go-netroute v0.2.0 h1:0FpsbsvuSnAhXFnCY0VLFbJOzaK0VnP0r1QT/o4nWRE= 140 + github.com/libp2p/go-netroute v0.2.0/go.mod h1:Vio7LTzZ+6hoT4CMZi5/6CpY3Snzh2vgZhWgxMNwlQI= 141 + github.com/libp2p/go-openssl v0.1.0 h1:LBkKEcUv6vtZIQLVTegAil8jbNpJErQ9AnT+bWV+Ooo= 142 + github.com/libp2p/go-openssl v0.1.0/go.mod h1:OiOxwPpL3n4xlenjx2h7AwSGaFSC/KZvf6gNdOBQMtc= 143 + github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 144 + github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 145 + github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 146 + github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0= 147 + github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= 148 + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= 149 + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= 150 + github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= 151 + github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= 152 + github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= 153 + github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= 154 + github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= 155 + github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= 156 + github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= 157 + github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= 158 + github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= 159 + github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= 160 + github.com/multiformats/go-multiaddr v0.7.0 h1:gskHcdaCyPtp9XskVwtvEeQOG465sCohbQIirSyqxrc= 161 + github.com/multiformats/go-multiaddr v0.7.0/go.mod h1:Fs50eBDWvZu+l3/9S6xAE7ZYj6yhxlvaVZjakWN7xRs= 162 + github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= 163 + github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= 164 + github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= 165 + github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= 166 + github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= 167 + github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= 168 + github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= 169 + github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= 170 + github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= 171 + github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= 172 + github.com/multiformats/go-multistream v0.3.3 h1:d5PZpjwRgVlbwfdTDjife7XszfZd8KYWfROYFlGcR8o= 173 + github.com/multiformats/go-multistream v0.3.3/go.mod h1:ODRoqamLUsETKS9BNcII4gcRsJBU5VAwRIv7O39cEXg= 174 + github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= 175 + github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= 176 + github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= 177 + github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= 178 + github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 179 + github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 180 + github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 181 + github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f h1:VXTQfuJj9vKR4TCkEuWIckKvdHFeJH/huIFJ9/cXOB0= 182 + github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= 183 + github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= 184 + github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= 185 + github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= 186 + github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= 187 + github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= 188 + github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= 189 + github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= 190 + github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= 191 + github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 192 + github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= 193 + github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= 194 + github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 195 + github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 196 + github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= 197 + github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= 198 + github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= 199 + github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= 200 + github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= 201 + github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= 202 + github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= 203 + github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 204 + github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 205 + github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 206 + github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 207 + github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 208 + github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 209 + github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 210 + github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= 211 + github.com/warpfork/go-testmark v0.12.1 h1:rMgCpJfwy1sJ50x0M0NgyphxYYPMOODIJHhsXyEHU0s= 212 + github.com/warpfork/go-testmark v0.12.1/go.mod h1:kHwy7wfvGSPh1rQJYKayD4AbtNaeyZdcGi9tNJTaa5Y= 213 + github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ= 214 + github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= 215 + github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e h1:28X54ciEwwUxyHn9yrZfl5ojgF4CBNLWX7LR0rvBkf4= 216 + github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so= 217 + github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 218 + github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 219 + github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 220 + gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRySiX3drau9C6Q5CAbNIApmLdat5jPMqChvDA= 221 + gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8= 222 + gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q= 223 + gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02/go.mod h1:JTnUj0mpYiAsuZLmKjTx/ex3AtMowcCgnE7YNyCEP0I= 224 + go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= 225 + go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= 226 + go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= 227 + go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= 228 + go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= 229 + go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= 230 + go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 231 + go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 232 + go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= 233 + go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= 234 + go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= 235 + go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= 236 + go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= 237 + go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= 238 + go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 239 + go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= 240 + go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= 241 + go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= 242 + go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= 243 + go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= 244 + go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= 245 + go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= 246 + golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 247 + golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 248 + golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 249 + golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 250 + golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= 251 + golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= 252 + golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 253 + golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 254 + golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 255 + golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 256 + golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 257 + golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= 258 + golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 259 + golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 260 + golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 261 + golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 262 + golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 263 + golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 264 + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 265 + golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= 266 + golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= 267 + golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 268 + golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 269 + golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 270 + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 271 + golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= 272 + golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 273 + golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 274 + golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 275 + golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 276 + golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 277 + golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 278 + golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 279 + golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 280 + golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 281 + golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 282 + golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= 283 + golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 284 + golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 285 + golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 286 + golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 287 + golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= 288 + golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 289 + golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 290 + golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 291 + golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 292 + golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 293 + golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 294 + golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 295 + golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 296 + golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 297 + golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 298 + golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 299 + golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= 300 + golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= 301 + golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 302 + golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 303 + golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 304 + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 305 + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= 306 + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= 307 + google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= 308 + google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 309 + gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 310 + gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 311 + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 312 + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 313 + gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 314 + gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 315 + gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 316 + gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 317 + gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 318 + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 319 + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 320 + gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 321 + gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 322 + honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 323 + lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= 324 + lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
+231
go-verify/main.go
··· 1 + // full AT Protocol trust chain verification — go (indigo) 2 + // 3 + // resolves handle → DID → DID doc → signing key + PDS, 4 + // fetches repo CAR, parses it, verifies commit signature, 5 + // walks MST, and rebuilds to verify root CID match. 6 + package main 7 + 8 + import ( 9 + "bytes" 10 + "context" 11 + "fmt" 12 + "io" 13 + "net/http" 14 + "os" 15 + "time" 16 + 17 + "github.com/bluesky-social/indigo/atproto/atcrypto" 18 + "github.com/bluesky-social/indigo/atproto/identity" 19 + "github.com/bluesky-social/indigo/atproto/repo" 20 + "github.com/bluesky-social/indigo/atproto/syntax" 21 + "github.com/ipfs/go-cid" 22 + ) 23 + 24 + func main() { 25 + if len(os.Args) < 2 { 26 + fmt.Println("usage: go-verify <handle-or-did>") 27 + os.Exit(1) 28 + } 29 + input := os.Args[1] 30 + 31 + fmt.Printf("\n=== go (indigo): full AT Protocol trust chain ===\n\n") 32 + 33 + totalStart := time.Now() 34 + ctx := context.Background() 35 + dir := identity.BaseDirectory{} 36 + 37 + // --- step 1: resolve identifier --- 38 + stepStart := time.Now() 39 + 40 + var did syntax.DID 41 + var handle syntax.Handle 42 + var isDID bool 43 + 44 + if d, err := syntax.ParseDID(input); err == nil { 45 + did = d 46 + isDID = true 47 + } else { 48 + h, err := syntax.ParseHandle(input) 49 + if err != nil { 50 + fmt.Printf("error: invalid handle or DID: %s\n", input) 51 + os.Exit(1) 52 + } 53 + handle = h 54 + resolved, err := dir.ResolveHandle(ctx, handle) 55 + if err != nil { 56 + fmt.Printf("error: handle resolution failed: %v\n", err) 57 + os.Exit(1) 58 + } 59 + did = resolved 60 + } 61 + handleMs := time.Since(stepStart) 62 + 63 + if isDID { 64 + fmt.Printf("DID %s\n", did) 65 + handleMs = 0 66 + } else { 67 + fmt.Printf("handle %s\n", handle) 68 + printPadded(fmt.Sprintf(" → %s", did), handleMs) 69 + } 70 + 71 + // --- step 2: resolve DID document --- 72 + stepStart = time.Now() 73 + 74 + doc, err := dir.ResolveDID(ctx, did) 75 + if err != nil { 76 + fmt.Printf("error: DID resolution failed: %v\n", err) 77 + os.Exit(1) 78 + } 79 + ident := identity.ParseIdentity(doc) 80 + 81 + pubkey, err := ident.PublicKey() 82 + if err != nil { 83 + fmt.Printf("error: no signing key: %v\n", err) 84 + os.Exit(1) 85 + } 86 + 87 + pdsEndpoint := ident.PDSEndpoint() 88 + if pdsEndpoint == "" { 89 + fmt.Println("error: no PDS endpoint in DID document") 90 + os.Exit(1) 91 + } 92 + 93 + didMs := time.Since(stepStart) 94 + 95 + keyType := keyTypeName(pubkey) 96 + fmt.Printf("\nDID doc %s\n", did) 97 + printPadded(fmt.Sprintf(" → signing key: %s", keyType), didMs) 98 + fmt.Printf(" → PDS: %s\n", pdsEndpoint) 99 + 100 + // --- step 3: fetch repo CAR --- 101 + stepStart = time.Now() 102 + 103 + repoURL := fmt.Sprintf("%s/xrpc/com.atproto.sync.getRepo?did=%s", pdsEndpoint, did) 104 + resp, err := http.Get(repoURL) 105 + if err != nil { 106 + fmt.Printf("error: failed to fetch repo: %v\n", err) 107 + os.Exit(1) 108 + } 109 + defer resp.Body.Close() 110 + 111 + if resp.StatusCode != 200 { 112 + fmt.Printf("error: PDS returned HTTP %d\n", resp.StatusCode) 113 + os.Exit(1) 114 + } 115 + 116 + carBytes, err := io.ReadAll(resp.Body) 117 + if err != nil { 118 + fmt.Printf("error: failed to read response: %v\n", err) 119 + os.Exit(1) 120 + } 121 + 122 + fetchMs := time.Since(stepStart) 123 + 124 + fmt.Printf("\nrepo com.atproto.sync.getRepo\n") 125 + printPadded(fmt.Sprintf(" → %s CAR", fmtSize(len(carBytes))), fetchMs) 126 + 127 + // --- step 4: parse CAR + load MST --- 128 + stepStart = time.Now() 129 + 130 + commit, loadedRepo, err := repo.LoadRepoFromCAR(ctx, bytes.NewReader(carBytes)) 131 + if err != nil { 132 + fmt.Printf("error: failed to parse CAR: %v\n", err) 133 + os.Exit(1) 134 + } 135 + 136 + carMs := time.Since(stepStart) 137 + 138 + // --- step 5: verify signature --- 139 + stepStart = time.Now() 140 + 141 + if err := commit.VerifySignature(pubkey); err != nil { 142 + fmt.Printf("error: signature verification failed: %v\n", err) 143 + os.Exit(1) 144 + } 145 + 146 + sigMs := time.Since(stepStart) 147 + 148 + // --- step 6: walk MST + count records --- 149 + stepStart = time.Now() 150 + 151 + recordCount := 0 152 + err = loadedRepo.MST.Walk(func(key []byte, val cid.Cid) error { 153 + recordCount++ 154 + return nil 155 + }) 156 + if err != nil { 157 + fmt.Printf("error: MST walk failed: %v\n", err) 158 + os.Exit(1) 159 + } 160 + 161 + walkMs := time.Since(stepStart) 162 + 163 + // --- step 7: verify MST root CID --- 164 + stepStart = time.Now() 165 + 166 + rootCID, err := loadedRepo.MST.RootCID() 167 + if err != nil { 168 + fmt.Printf("error: MST root CID computation failed: %v\n", err) 169 + os.Exit(1) 170 + } 171 + 172 + rebuildMs := time.Since(stepStart) 173 + cidMatch := rootCID != nil && rootCID.Equals(commit.Data) 174 + 175 + // --- output --- 176 + rev := commit.Rev 177 + if len(rev) > 6 { 178 + rev = rev[:6] 179 + } 180 + fmt.Printf("\nverify commit rev=%s...\n", rev) 181 + printPadded(" → CAR parse + MST load", carMs) 182 + printPadded(fmt.Sprintf(" → commit signature VERIFIED (%s)", keyType), sigMs) 183 + printPadded(fmt.Sprintf(" → MST walk: %d records", recordCount), walkMs) 184 + if cidMatch { 185 + printPadded(" → MST root CID match", rebuildMs) 186 + } else { 187 + fmt.Println(" → MST root CID MISMATCH!") 188 + } 189 + 190 + totalMs := time.Since(totalStart) 191 + networkMs := handleMs + didMs + fetchMs 192 + computeMs := carMs + sigMs + walkMs + rebuildMs 193 + fmt.Printf("\ntotal %s (network: %s, compute: %s)\n\n", 194 + fmtDuration(totalMs), fmtDuration(networkMs), fmtDuration(computeMs)) 195 + } 196 + 197 + func printPadded(desc string, d time.Duration) { 198 + ms := float64(d.Nanoseconds()) / 1e6 199 + pad := 50 - len(desc) 200 + if pad < 1 { 201 + pad = 1 202 + } 203 + fmt.Printf("%s%*s%.1fms\n", desc, pad, "", ms) 204 + } 205 + 206 + func fmtDuration(d time.Duration) string { 207 + ms := float64(d.Nanoseconds()) / 1e6 208 + if ms >= 1000 { 209 + return fmt.Sprintf("%.1fs", ms/1000) 210 + } 211 + return fmt.Sprintf("%.1fms", ms) 212 + } 213 + 214 + func keyTypeName(key atcrypto.PublicKey) string { 215 + switch key.(type) { 216 + case *atcrypto.PublicKeyK256: 217 + return "secp256k1" 218 + case *atcrypto.PublicKeyP256: 219 + return "p256" 220 + default: 221 + return "unknown" 222 + } 223 + } 224 + 225 + func fmtSize(n int) string { 226 + v := float64(n) 227 + if v >= 1024*1024 { 228 + return fmt.Sprintf("%.1f MB", v/(1024*1024)) 229 + } 230 + return fmt.Sprintf("%.1f KB", v/1024) 231 + }
+15
justfile
··· 50 50 bench-python: _ensure-fixtures 51 51 cd python && uv run bench.py 52 52 53 + # --- live trust chain demo --- 54 + 55 + # run full AT Protocol trust chain verification with timing (all three implementations) 56 + verify *ARGS: 57 + @echo "" 58 + cd zig && zig build run-verify -Doptimize=ReleaseFast -- {{ARGS}} 59 + @echo "--------------------------------------------" 60 + cd go-verify && go run . {{ARGS}} 61 + @echo "--------------------------------------------" 62 + cd rust-verify && cargo run --release -- {{ARGS}} 2>&1 63 + 64 + # generate SVG charts from verify output 65 + chart *ARGS: 66 + just verify {{ARGS}} 2>&1 | uv run scripts/verify_chart.py 67 + 53 68 # --- signature verification --- 54 69 55 70 # capture signed commits + public keys from firehose (~10s)
+2188
rust-verify/Cargo.lock
··· 1 + # This file is automatically @generated by Cargo. 2 + # It is not intended for manual editing. 3 + version = 4 4 + 5 + [[package]] 6 + name = "anyhow" 7 + version = "1.0.102" 8 + source = "registry+https://github.com/rust-lang/crates.io-index" 9 + checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" 10 + 11 + [[package]] 12 + name = "atomic-waker" 13 + version = "1.1.2" 14 + source = "registry+https://github.com/rust-lang/crates.io-index" 15 + checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 16 + 17 + [[package]] 18 + name = "base-x" 19 + version = "0.2.11" 20 + source = "registry+https://github.com/rust-lang/crates.io-index" 21 + checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" 22 + 23 + [[package]] 24 + name = "base16ct" 25 + version = "0.2.0" 26 + source = "registry+https://github.com/rust-lang/crates.io-index" 27 + checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" 28 + 29 + [[package]] 30 + name = "base256emoji" 31 + version = "1.0.2" 32 + source = "registry+https://github.com/rust-lang/crates.io-index" 33 + checksum = "b5e9430d9a245a77c92176e649af6e275f20839a48389859d1661e9a128d077c" 34 + dependencies = [ 35 + "const-str", 36 + "match-lookup", 37 + ] 38 + 39 + [[package]] 40 + name = "base64" 41 + version = "0.22.1" 42 + source = "registry+https://github.com/rust-lang/crates.io-index" 43 + checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 44 + 45 + [[package]] 46 + name = "base64ct" 47 + version = "1.8.3" 48 + source = "registry+https://github.com/rust-lang/crates.io-index" 49 + checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" 50 + 51 + [[package]] 52 + name = "bitflags" 53 + version = "2.11.0" 54 + source = "registry+https://github.com/rust-lang/crates.io-index" 55 + checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" 56 + 57 + [[package]] 58 + name = "block-buffer" 59 + version = "0.10.4" 60 + source = "registry+https://github.com/rust-lang/crates.io-index" 61 + checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 62 + dependencies = [ 63 + "generic-array", 64 + ] 65 + 66 + [[package]] 67 + name = "bumpalo" 68 + version = "3.20.2" 69 + source = "registry+https://github.com/rust-lang/crates.io-index" 70 + checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" 71 + 72 + [[package]] 73 + name = "bytes" 74 + version = "1.11.1" 75 + source = "registry+https://github.com/rust-lang/crates.io-index" 76 + checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" 77 + 78 + [[package]] 79 + name = "cbor4ii" 80 + version = "0.2.14" 81 + source = "registry+https://github.com/rust-lang/crates.io-index" 82 + checksum = "b544cf8c89359205f4f990d0e6f3828db42df85b5dac95d09157a250eb0749c4" 83 + dependencies = [ 84 + "serde", 85 + ] 86 + 87 + [[package]] 88 + name = "cc" 89 + version = "1.2.56" 90 + source = "registry+https://github.com/rust-lang/crates.io-index" 91 + checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" 92 + dependencies = [ 93 + "find-msvc-tools", 94 + "shlex", 95 + ] 96 + 97 + [[package]] 98 + name = "cfg-if" 99 + version = "1.0.4" 100 + source = "registry+https://github.com/rust-lang/crates.io-index" 101 + checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" 102 + 103 + [[package]] 104 + name = "cid" 105 + version = "0.11.1" 106 + source = "registry+https://github.com/rust-lang/crates.io-index" 107 + checksum = "3147d8272e8fa0ccd29ce51194dd98f79ddfb8191ba9e3409884e751798acf3a" 108 + dependencies = [ 109 + "core2", 110 + "multibase", 111 + "multihash", 112 + "serde", 113 + "serde_bytes", 114 + "unsigned-varint", 115 + ] 116 + 117 + [[package]] 118 + name = "const-oid" 119 + version = "0.9.6" 120 + source = "registry+https://github.com/rust-lang/crates.io-index" 121 + checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" 122 + 123 + [[package]] 124 + name = "const-str" 125 + version = "0.4.3" 126 + source = "registry+https://github.com/rust-lang/crates.io-index" 127 + checksum = "2f421161cb492475f1661ddc9815a745a1c894592070661180fdec3d4872e9c3" 128 + 129 + [[package]] 130 + name = "core-foundation" 131 + version = "0.9.4" 132 + source = "registry+https://github.com/rust-lang/crates.io-index" 133 + checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 134 + dependencies = [ 135 + "core-foundation-sys", 136 + "libc", 137 + ] 138 + 139 + [[package]] 140 + name = "core-foundation" 141 + version = "0.10.1" 142 + source = "registry+https://github.com/rust-lang/crates.io-index" 143 + checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" 144 + dependencies = [ 145 + "core-foundation-sys", 146 + "libc", 147 + ] 148 + 149 + [[package]] 150 + name = "core-foundation-sys" 151 + version = "0.8.7" 152 + source = "registry+https://github.com/rust-lang/crates.io-index" 153 + checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 154 + 155 + [[package]] 156 + name = "core2" 157 + version = "0.4.0" 158 + source = "registry+https://github.com/rust-lang/crates.io-index" 159 + checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" 160 + dependencies = [ 161 + "memchr", 162 + ] 163 + 164 + [[package]] 165 + name = "cpufeatures" 166 + version = "0.2.17" 167 + source = "registry+https://github.com/rust-lang/crates.io-index" 168 + checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" 169 + dependencies = [ 170 + "libc", 171 + ] 172 + 173 + [[package]] 174 + name = "crypto-bigint" 175 + version = "0.5.5" 176 + source = "registry+https://github.com/rust-lang/crates.io-index" 177 + checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" 178 + dependencies = [ 179 + "generic-array", 180 + "rand_core", 181 + "subtle", 182 + "zeroize", 183 + ] 184 + 185 + [[package]] 186 + name = "crypto-common" 187 + version = "0.1.6" 188 + source = "registry+https://github.com/rust-lang/crates.io-index" 189 + checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 190 + dependencies = [ 191 + "generic-array", 192 + "typenum", 193 + ] 194 + 195 + [[package]] 196 + name = "data-encoding" 197 + version = "2.10.0" 198 + source = "registry+https://github.com/rust-lang/crates.io-index" 199 + checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" 200 + 201 + [[package]] 202 + name = "data-encoding-macro" 203 + version = "0.1.19" 204 + source = "registry+https://github.com/rust-lang/crates.io-index" 205 + checksum = "8142a83c17aa9461d637e649271eae18bf2edd00e91f2e105df36c3c16355bdb" 206 + dependencies = [ 207 + "data-encoding", 208 + "data-encoding-macro-internal", 209 + ] 210 + 211 + [[package]] 212 + name = "data-encoding-macro-internal" 213 + version = "0.1.17" 214 + source = "registry+https://github.com/rust-lang/crates.io-index" 215 + checksum = "7ab67060fc6b8ef687992d439ca0fa36e7ed17e9a0b16b25b601e8757df720de" 216 + dependencies = [ 217 + "data-encoding", 218 + "syn", 219 + ] 220 + 221 + [[package]] 222 + name = "der" 223 + version = "0.7.10" 224 + source = "registry+https://github.com/rust-lang/crates.io-index" 225 + checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" 226 + dependencies = [ 227 + "const-oid", 228 + "pem-rfc7468", 229 + "zeroize", 230 + ] 231 + 232 + [[package]] 233 + name = "digest" 234 + version = "0.10.7" 235 + source = "registry+https://github.com/rust-lang/crates.io-index" 236 + checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 237 + dependencies = [ 238 + "block-buffer", 239 + "const-oid", 240 + "crypto-common", 241 + "subtle", 242 + ] 243 + 244 + [[package]] 245 + name = "displaydoc" 246 + version = "0.2.5" 247 + source = "registry+https://github.com/rust-lang/crates.io-index" 248 + checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 249 + dependencies = [ 250 + "proc-macro2", 251 + "quote", 252 + "syn", 253 + ] 254 + 255 + [[package]] 256 + name = "ecdsa" 257 + version = "0.16.9" 258 + source = "registry+https://github.com/rust-lang/crates.io-index" 259 + checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" 260 + dependencies = [ 261 + "der", 262 + "digest", 263 + "elliptic-curve", 264 + "rfc6979", 265 + "signature", 266 + "spki", 267 + ] 268 + 269 + [[package]] 270 + name = "elliptic-curve" 271 + version = "0.13.8" 272 + source = "registry+https://github.com/rust-lang/crates.io-index" 273 + checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" 274 + dependencies = [ 275 + "base16ct", 276 + "crypto-bigint", 277 + "digest", 278 + "ff", 279 + "generic-array", 280 + "group", 281 + "pem-rfc7468", 282 + "pkcs8", 283 + "rand_core", 284 + "sec1", 285 + "subtle", 286 + "zeroize", 287 + ] 288 + 289 + [[package]] 290 + name = "encoding_rs" 291 + version = "0.8.35" 292 + source = "registry+https://github.com/rust-lang/crates.io-index" 293 + checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" 294 + dependencies = [ 295 + "cfg-if", 296 + ] 297 + 298 + [[package]] 299 + name = "equivalent" 300 + version = "1.0.2" 301 + source = "registry+https://github.com/rust-lang/crates.io-index" 302 + checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 303 + 304 + [[package]] 305 + name = "errno" 306 + version = "0.3.14" 307 + source = "registry+https://github.com/rust-lang/crates.io-index" 308 + checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" 309 + dependencies = [ 310 + "libc", 311 + "windows-sys 0.61.2", 312 + ] 313 + 314 + [[package]] 315 + name = "fastrand" 316 + version = "2.3.0" 317 + source = "registry+https://github.com/rust-lang/crates.io-index" 318 + checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 319 + 320 + [[package]] 321 + name = "ff" 322 + version = "0.13.1" 323 + source = "registry+https://github.com/rust-lang/crates.io-index" 324 + checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" 325 + dependencies = [ 326 + "rand_core", 327 + "subtle", 328 + ] 329 + 330 + [[package]] 331 + name = "find-msvc-tools" 332 + version = "0.1.9" 333 + source = "registry+https://github.com/rust-lang/crates.io-index" 334 + checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" 335 + 336 + [[package]] 337 + name = "fnv" 338 + version = "1.0.7" 339 + source = "registry+https://github.com/rust-lang/crates.io-index" 340 + checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 341 + 342 + [[package]] 343 + name = "foldhash" 344 + version = "0.1.5" 345 + source = "registry+https://github.com/rust-lang/crates.io-index" 346 + checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" 347 + 348 + [[package]] 349 + name = "foreign-types" 350 + version = "0.3.2" 351 + source = "registry+https://github.com/rust-lang/crates.io-index" 352 + checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 353 + dependencies = [ 354 + "foreign-types-shared", 355 + ] 356 + 357 + [[package]] 358 + name = "foreign-types-shared" 359 + version = "0.1.1" 360 + source = "registry+https://github.com/rust-lang/crates.io-index" 361 + checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 362 + 363 + [[package]] 364 + name = "form_urlencoded" 365 + version = "1.2.2" 366 + source = "registry+https://github.com/rust-lang/crates.io-index" 367 + checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" 368 + dependencies = [ 369 + "percent-encoding", 370 + ] 371 + 372 + [[package]] 373 + name = "futures-channel" 374 + version = "0.3.32" 375 + source = "registry+https://github.com/rust-lang/crates.io-index" 376 + checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" 377 + dependencies = [ 378 + "futures-core", 379 + "futures-sink", 380 + ] 381 + 382 + [[package]] 383 + name = "futures-core" 384 + version = "0.3.32" 385 + source = "registry+https://github.com/rust-lang/crates.io-index" 386 + checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" 387 + 388 + [[package]] 389 + name = "futures-io" 390 + version = "0.3.32" 391 + source = "registry+https://github.com/rust-lang/crates.io-index" 392 + checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" 393 + 394 + [[package]] 395 + name = "futures-sink" 396 + version = "0.3.32" 397 + source = "registry+https://github.com/rust-lang/crates.io-index" 398 + checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" 399 + 400 + [[package]] 401 + name = "futures-task" 402 + version = "0.3.32" 403 + source = "registry+https://github.com/rust-lang/crates.io-index" 404 + checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" 405 + 406 + [[package]] 407 + name = "futures-util" 408 + version = "0.3.32" 409 + source = "registry+https://github.com/rust-lang/crates.io-index" 410 + checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" 411 + dependencies = [ 412 + "futures-core", 413 + "futures-io", 414 + "futures-sink", 415 + "futures-task", 416 + "memchr", 417 + "pin-project-lite", 418 + "slab", 419 + ] 420 + 421 + [[package]] 422 + name = "generic-array" 423 + version = "0.14.9" 424 + source = "registry+https://github.com/rust-lang/crates.io-index" 425 + checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" 426 + dependencies = [ 427 + "typenum", 428 + "version_check", 429 + "zeroize", 430 + ] 431 + 432 + [[package]] 433 + name = "getrandom" 434 + version = "0.2.17" 435 + source = "registry+https://github.com/rust-lang/crates.io-index" 436 + checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" 437 + dependencies = [ 438 + "cfg-if", 439 + "libc", 440 + "wasi", 441 + ] 442 + 443 + [[package]] 444 + name = "getrandom" 445 + version = "0.4.1" 446 + source = "registry+https://github.com/rust-lang/crates.io-index" 447 + checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" 448 + dependencies = [ 449 + "cfg-if", 450 + "libc", 451 + "r-efi", 452 + "wasip2", 453 + "wasip3", 454 + ] 455 + 456 + [[package]] 457 + name = "group" 458 + version = "0.13.0" 459 + source = "registry+https://github.com/rust-lang/crates.io-index" 460 + checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" 461 + dependencies = [ 462 + "ff", 463 + "rand_core", 464 + "subtle", 465 + ] 466 + 467 + [[package]] 468 + name = "h2" 469 + version = "0.4.13" 470 + source = "registry+https://github.com/rust-lang/crates.io-index" 471 + checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" 472 + dependencies = [ 473 + "atomic-waker", 474 + "bytes", 475 + "fnv", 476 + "futures-core", 477 + "futures-sink", 478 + "http", 479 + "indexmap", 480 + "slab", 481 + "tokio", 482 + "tokio-util", 483 + "tracing", 484 + ] 485 + 486 + [[package]] 487 + name = "hashbrown" 488 + version = "0.15.5" 489 + source = "registry+https://github.com/rust-lang/crates.io-index" 490 + checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" 491 + dependencies = [ 492 + "foldhash", 493 + ] 494 + 495 + [[package]] 496 + name = "hashbrown" 497 + version = "0.16.1" 498 + source = "registry+https://github.com/rust-lang/crates.io-index" 499 + checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" 500 + 501 + [[package]] 502 + name = "heck" 503 + version = "0.5.0" 504 + source = "registry+https://github.com/rust-lang/crates.io-index" 505 + checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 506 + 507 + [[package]] 508 + name = "hmac" 509 + version = "0.12.1" 510 + source = "registry+https://github.com/rust-lang/crates.io-index" 511 + checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 512 + dependencies = [ 513 + "digest", 514 + ] 515 + 516 + [[package]] 517 + name = "http" 518 + version = "1.4.0" 519 + source = "registry+https://github.com/rust-lang/crates.io-index" 520 + checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" 521 + dependencies = [ 522 + "bytes", 523 + "itoa", 524 + ] 525 + 526 + [[package]] 527 + name = "http-body" 528 + version = "1.0.1" 529 + source = "registry+https://github.com/rust-lang/crates.io-index" 530 + checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 531 + dependencies = [ 532 + "bytes", 533 + "http", 534 + ] 535 + 536 + [[package]] 537 + name = "http-body-util" 538 + version = "0.1.3" 539 + source = "registry+https://github.com/rust-lang/crates.io-index" 540 + checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" 541 + dependencies = [ 542 + "bytes", 543 + "futures-core", 544 + "http", 545 + "http-body", 546 + "pin-project-lite", 547 + ] 548 + 549 + [[package]] 550 + name = "httparse" 551 + version = "1.10.1" 552 + source = "registry+https://github.com/rust-lang/crates.io-index" 553 + checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" 554 + 555 + [[package]] 556 + name = "hyper" 557 + version = "1.8.1" 558 + source = "registry+https://github.com/rust-lang/crates.io-index" 559 + checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" 560 + dependencies = [ 561 + "atomic-waker", 562 + "bytes", 563 + "futures-channel", 564 + "futures-core", 565 + "h2", 566 + "http", 567 + "http-body", 568 + "httparse", 569 + "itoa", 570 + "pin-project-lite", 571 + "pin-utils", 572 + "smallvec", 573 + "tokio", 574 + "want", 575 + ] 576 + 577 + [[package]] 578 + name = "hyper-rustls" 579 + version = "0.27.7" 580 + source = "registry+https://github.com/rust-lang/crates.io-index" 581 + checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" 582 + dependencies = [ 583 + "http", 584 + "hyper", 585 + "hyper-util", 586 + "rustls", 587 + "rustls-pki-types", 588 + "tokio", 589 + "tokio-rustls", 590 + "tower-service", 591 + ] 592 + 593 + [[package]] 594 + name = "hyper-tls" 595 + version = "0.6.0" 596 + source = "registry+https://github.com/rust-lang/crates.io-index" 597 + checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 598 + dependencies = [ 599 + "bytes", 600 + "http-body-util", 601 + "hyper", 602 + "hyper-util", 603 + "native-tls", 604 + "tokio", 605 + "tokio-native-tls", 606 + "tower-service", 607 + ] 608 + 609 + [[package]] 610 + name = "hyper-util" 611 + version = "0.1.20" 612 + source = "registry+https://github.com/rust-lang/crates.io-index" 613 + checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" 614 + dependencies = [ 615 + "base64", 616 + "bytes", 617 + "futures-channel", 618 + "futures-util", 619 + "http", 620 + "http-body", 621 + "hyper", 622 + "ipnet", 623 + "libc", 624 + "percent-encoding", 625 + "pin-project-lite", 626 + "socket2", 627 + "system-configuration", 628 + "tokio", 629 + "tower-service", 630 + "tracing", 631 + "windows-registry", 632 + ] 633 + 634 + [[package]] 635 + name = "icu_collections" 636 + version = "2.1.1" 637 + source = "registry+https://github.com/rust-lang/crates.io-index" 638 + checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" 639 + dependencies = [ 640 + "displaydoc", 641 + "potential_utf", 642 + "yoke", 643 + "zerofrom", 644 + "zerovec", 645 + ] 646 + 647 + [[package]] 648 + name = "icu_locale_core" 649 + version = "2.1.1" 650 + source = "registry+https://github.com/rust-lang/crates.io-index" 651 + checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" 652 + dependencies = [ 653 + "displaydoc", 654 + "litemap", 655 + "tinystr", 656 + "writeable", 657 + "zerovec", 658 + ] 659 + 660 + [[package]] 661 + name = "icu_normalizer" 662 + version = "2.1.1" 663 + source = "registry+https://github.com/rust-lang/crates.io-index" 664 + checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" 665 + dependencies = [ 666 + "icu_collections", 667 + "icu_normalizer_data", 668 + "icu_properties", 669 + "icu_provider", 670 + "smallvec", 671 + "zerovec", 672 + ] 673 + 674 + [[package]] 675 + name = "icu_normalizer_data" 676 + version = "2.1.1" 677 + source = "registry+https://github.com/rust-lang/crates.io-index" 678 + checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" 679 + 680 + [[package]] 681 + name = "icu_properties" 682 + version = "2.1.2" 683 + source = "registry+https://github.com/rust-lang/crates.io-index" 684 + checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" 685 + dependencies = [ 686 + "icu_collections", 687 + "icu_locale_core", 688 + "icu_properties_data", 689 + "icu_provider", 690 + "zerotrie", 691 + "zerovec", 692 + ] 693 + 694 + [[package]] 695 + name = "icu_properties_data" 696 + version = "2.1.2" 697 + source = "registry+https://github.com/rust-lang/crates.io-index" 698 + checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" 699 + 700 + [[package]] 701 + name = "icu_provider" 702 + version = "2.1.1" 703 + source = "registry+https://github.com/rust-lang/crates.io-index" 704 + checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" 705 + dependencies = [ 706 + "displaydoc", 707 + "icu_locale_core", 708 + "writeable", 709 + "yoke", 710 + "zerofrom", 711 + "zerotrie", 712 + "zerovec", 713 + ] 714 + 715 + [[package]] 716 + name = "id-arena" 717 + version = "2.3.0" 718 + source = "registry+https://github.com/rust-lang/crates.io-index" 719 + checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" 720 + 721 + [[package]] 722 + name = "idna" 723 + version = "1.1.0" 724 + source = "registry+https://github.com/rust-lang/crates.io-index" 725 + checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" 726 + dependencies = [ 727 + "idna_adapter", 728 + "smallvec", 729 + "utf8_iter", 730 + ] 731 + 732 + [[package]] 733 + name = "idna_adapter" 734 + version = "1.2.1" 735 + source = "registry+https://github.com/rust-lang/crates.io-index" 736 + checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" 737 + dependencies = [ 738 + "icu_normalizer", 739 + "icu_properties", 740 + ] 741 + 742 + [[package]] 743 + name = "indexmap" 744 + version = "2.13.0" 745 + source = "registry+https://github.com/rust-lang/crates.io-index" 746 + checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" 747 + dependencies = [ 748 + "equivalent", 749 + "hashbrown 0.16.1", 750 + "serde", 751 + "serde_core", 752 + ] 753 + 754 + [[package]] 755 + name = "ipld-core" 756 + version = "0.4.3" 757 + source = "registry+https://github.com/rust-lang/crates.io-index" 758 + checksum = "090f624976d72f0b0bb71b86d58dc16c15e069193067cb3a3a09d655246cbbda" 759 + dependencies = [ 760 + "cid", 761 + "serde", 762 + "serde_bytes", 763 + ] 764 + 765 + [[package]] 766 + name = "ipnet" 767 + version = "2.11.0" 768 + source = "registry+https://github.com/rust-lang/crates.io-index" 769 + checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" 770 + 771 + [[package]] 772 + name = "iri-string" 773 + version = "0.7.10" 774 + source = "registry+https://github.com/rust-lang/crates.io-index" 775 + checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" 776 + dependencies = [ 777 + "memchr", 778 + "serde", 779 + ] 780 + 781 + [[package]] 782 + name = "itoa" 783 + version = "1.0.17" 784 + source = "registry+https://github.com/rust-lang/crates.io-index" 785 + checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" 786 + 787 + [[package]] 788 + name = "js-sys" 789 + version = "0.3.90" 790 + source = "registry+https://github.com/rust-lang/crates.io-index" 791 + checksum = "14dc6f6450b3f6d4ed5b16327f38fed626d375a886159ca555bd7822c0c3a5a6" 792 + dependencies = [ 793 + "once_cell", 794 + "wasm-bindgen", 795 + ] 796 + 797 + [[package]] 798 + name = "k256" 799 + version = "0.13.4" 800 + source = "registry+https://github.com/rust-lang/crates.io-index" 801 + checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" 802 + dependencies = [ 803 + "cfg-if", 804 + "ecdsa", 805 + "elliptic-curve", 806 + "once_cell", 807 + "sha2", 808 + "signature", 809 + ] 810 + 811 + [[package]] 812 + name = "leb128fmt" 813 + version = "0.1.0" 814 + source = "registry+https://github.com/rust-lang/crates.io-index" 815 + checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" 816 + 817 + [[package]] 818 + name = "libc" 819 + version = "0.2.182" 820 + source = "registry+https://github.com/rust-lang/crates.io-index" 821 + checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" 822 + 823 + [[package]] 824 + name = "linux-raw-sys" 825 + version = "0.12.1" 826 + source = "registry+https://github.com/rust-lang/crates.io-index" 827 + checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" 828 + 829 + [[package]] 830 + name = "litemap" 831 + version = "0.8.1" 832 + source = "registry+https://github.com/rust-lang/crates.io-index" 833 + checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" 834 + 835 + [[package]] 836 + name = "log" 837 + version = "0.4.29" 838 + source = "registry+https://github.com/rust-lang/crates.io-index" 839 + checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" 840 + 841 + [[package]] 842 + name = "match-lookup" 843 + version = "0.1.2" 844 + source = "registry+https://github.com/rust-lang/crates.io-index" 845 + checksum = "757aee279b8bdbb9f9e676796fd459e4207a1f986e87886700abf589f5abf771" 846 + dependencies = [ 847 + "proc-macro2", 848 + "quote", 849 + "syn", 850 + ] 851 + 852 + [[package]] 853 + name = "memchr" 854 + version = "2.8.0" 855 + source = "registry+https://github.com/rust-lang/crates.io-index" 856 + checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" 857 + 858 + [[package]] 859 + name = "mime" 860 + version = "0.3.17" 861 + source = "registry+https://github.com/rust-lang/crates.io-index" 862 + checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 863 + 864 + [[package]] 865 + name = "mio" 866 + version = "1.1.1" 867 + source = "registry+https://github.com/rust-lang/crates.io-index" 868 + checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" 869 + dependencies = [ 870 + "libc", 871 + "wasi", 872 + "windows-sys 0.61.2", 873 + ] 874 + 875 + [[package]] 876 + name = "multibase" 877 + version = "0.9.2" 878 + source = "registry+https://github.com/rust-lang/crates.io-index" 879 + checksum = "8694bb4835f452b0e3bb06dbebb1d6fc5385b6ca1caf2e55fd165c042390ec77" 880 + dependencies = [ 881 + "base-x", 882 + "base256emoji", 883 + "data-encoding", 884 + "data-encoding-macro", 885 + ] 886 + 887 + [[package]] 888 + name = "multihash" 889 + version = "0.19.3" 890 + source = "registry+https://github.com/rust-lang/crates.io-index" 891 + checksum = "6b430e7953c29dd6a09afc29ff0bb69c6e306329ee6794700aee27b76a1aea8d" 892 + dependencies = [ 893 + "core2", 894 + "serde", 895 + "unsigned-varint", 896 + ] 897 + 898 + [[package]] 899 + name = "native-tls" 900 + version = "0.2.18" 901 + source = "registry+https://github.com/rust-lang/crates.io-index" 902 + checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" 903 + dependencies = [ 904 + "libc", 905 + "log", 906 + "openssl", 907 + "openssl-probe", 908 + "openssl-sys", 909 + "schannel", 910 + "security-framework", 911 + "security-framework-sys", 912 + "tempfile", 913 + ] 914 + 915 + [[package]] 916 + name = "once_cell" 917 + version = "1.21.3" 918 + source = "registry+https://github.com/rust-lang/crates.io-index" 919 + checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 920 + 921 + [[package]] 922 + name = "openssl" 923 + version = "0.10.75" 924 + source = "registry+https://github.com/rust-lang/crates.io-index" 925 + checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" 926 + dependencies = [ 927 + "bitflags", 928 + "cfg-if", 929 + "foreign-types", 930 + "libc", 931 + "once_cell", 932 + "openssl-macros", 933 + "openssl-sys", 934 + ] 935 + 936 + [[package]] 937 + name = "openssl-macros" 938 + version = "0.1.1" 939 + source = "registry+https://github.com/rust-lang/crates.io-index" 940 + checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 941 + dependencies = [ 942 + "proc-macro2", 943 + "quote", 944 + "syn", 945 + ] 946 + 947 + [[package]] 948 + name = "openssl-probe" 949 + version = "0.2.1" 950 + source = "registry+https://github.com/rust-lang/crates.io-index" 951 + checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" 952 + 953 + [[package]] 954 + name = "openssl-sys" 955 + version = "0.9.111" 956 + source = "registry+https://github.com/rust-lang/crates.io-index" 957 + checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" 958 + dependencies = [ 959 + "cc", 960 + "libc", 961 + "pkg-config", 962 + "vcpkg", 963 + ] 964 + 965 + [[package]] 966 + name = "p256" 967 + version = "0.13.2" 968 + source = "registry+https://github.com/rust-lang/crates.io-index" 969 + checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" 970 + dependencies = [ 971 + "ecdsa", 972 + "elliptic-curve", 973 + "primeorder", 974 + "sha2", 975 + ] 976 + 977 + [[package]] 978 + name = "pem-rfc7468" 979 + version = "0.7.0" 980 + source = "registry+https://github.com/rust-lang/crates.io-index" 981 + checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" 982 + dependencies = [ 983 + "base64ct", 984 + ] 985 + 986 + [[package]] 987 + name = "percent-encoding" 988 + version = "2.3.2" 989 + source = "registry+https://github.com/rust-lang/crates.io-index" 990 + checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" 991 + 992 + [[package]] 993 + name = "pin-project-lite" 994 + version = "0.2.17" 995 + source = "registry+https://github.com/rust-lang/crates.io-index" 996 + checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" 997 + 998 + [[package]] 999 + name = "pin-utils" 1000 + version = "0.1.0" 1001 + source = "registry+https://github.com/rust-lang/crates.io-index" 1002 + checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1003 + 1004 + [[package]] 1005 + name = "pkcs8" 1006 + version = "0.10.2" 1007 + source = "registry+https://github.com/rust-lang/crates.io-index" 1008 + checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" 1009 + dependencies = [ 1010 + "der", 1011 + "spki", 1012 + ] 1013 + 1014 + [[package]] 1015 + name = "pkg-config" 1016 + version = "0.3.32" 1017 + source = "registry+https://github.com/rust-lang/crates.io-index" 1018 + checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" 1019 + 1020 + [[package]] 1021 + name = "potential_utf" 1022 + version = "0.1.4" 1023 + source = "registry+https://github.com/rust-lang/crates.io-index" 1024 + checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" 1025 + dependencies = [ 1026 + "zerovec", 1027 + ] 1028 + 1029 + [[package]] 1030 + name = "prettyplease" 1031 + version = "0.2.37" 1032 + source = "registry+https://github.com/rust-lang/crates.io-index" 1033 + checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" 1034 + dependencies = [ 1035 + "proc-macro2", 1036 + "syn", 1037 + ] 1038 + 1039 + [[package]] 1040 + name = "primeorder" 1041 + version = "0.13.6" 1042 + source = "registry+https://github.com/rust-lang/crates.io-index" 1043 + checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" 1044 + dependencies = [ 1045 + "elliptic-curve", 1046 + ] 1047 + 1048 + [[package]] 1049 + name = "proc-macro2" 1050 + version = "1.0.106" 1051 + source = "registry+https://github.com/rust-lang/crates.io-index" 1052 + checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" 1053 + dependencies = [ 1054 + "unicode-ident", 1055 + ] 1056 + 1057 + [[package]] 1058 + name = "quote" 1059 + version = "1.0.44" 1060 + source = "registry+https://github.com/rust-lang/crates.io-index" 1061 + checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" 1062 + dependencies = [ 1063 + "proc-macro2", 1064 + ] 1065 + 1066 + [[package]] 1067 + name = "r-efi" 1068 + version = "5.3.0" 1069 + source = "registry+https://github.com/rust-lang/crates.io-index" 1070 + checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" 1071 + 1072 + [[package]] 1073 + name = "rand_core" 1074 + version = "0.6.4" 1075 + source = "registry+https://github.com/rust-lang/crates.io-index" 1076 + checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1077 + dependencies = [ 1078 + "getrandom 0.2.17", 1079 + ] 1080 + 1081 + [[package]] 1082 + name = "reqwest" 1083 + version = "0.12.28" 1084 + source = "registry+https://github.com/rust-lang/crates.io-index" 1085 + checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" 1086 + dependencies = [ 1087 + "base64", 1088 + "bytes", 1089 + "encoding_rs", 1090 + "futures-channel", 1091 + "futures-core", 1092 + "futures-util", 1093 + "h2", 1094 + "http", 1095 + "http-body", 1096 + "http-body-util", 1097 + "hyper", 1098 + "hyper-rustls", 1099 + "hyper-tls", 1100 + "hyper-util", 1101 + "js-sys", 1102 + "log", 1103 + "mime", 1104 + "native-tls", 1105 + "percent-encoding", 1106 + "pin-project-lite", 1107 + "rustls-pki-types", 1108 + "serde", 1109 + "serde_json", 1110 + "serde_urlencoded", 1111 + "sync_wrapper", 1112 + "tokio", 1113 + "tokio-native-tls", 1114 + "tower", 1115 + "tower-http", 1116 + "tower-service", 1117 + "url", 1118 + "wasm-bindgen", 1119 + "wasm-bindgen-futures", 1120 + "web-sys", 1121 + ] 1122 + 1123 + [[package]] 1124 + name = "rfc6979" 1125 + version = "0.4.0" 1126 + source = "registry+https://github.com/rust-lang/crates.io-index" 1127 + checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" 1128 + dependencies = [ 1129 + "hmac", 1130 + "subtle", 1131 + ] 1132 + 1133 + [[package]] 1134 + name = "ring" 1135 + version = "0.17.14" 1136 + source = "registry+https://github.com/rust-lang/crates.io-index" 1137 + checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" 1138 + dependencies = [ 1139 + "cc", 1140 + "cfg-if", 1141 + "getrandom 0.2.17", 1142 + "libc", 1143 + "untrusted", 1144 + "windows-sys 0.52.0", 1145 + ] 1146 + 1147 + [[package]] 1148 + name = "rust-verify" 1149 + version = "0.1.0" 1150 + dependencies = [ 1151 + "ecdsa", 1152 + "ipld-core", 1153 + "k256", 1154 + "multibase", 1155 + "p256", 1156 + "reqwest", 1157 + "serde", 1158 + "serde_ipld_dagcbor", 1159 + "serde_json", 1160 + "sha2", 1161 + "unsigned-varint", 1162 + ] 1163 + 1164 + [[package]] 1165 + name = "rustix" 1166 + version = "1.1.4" 1167 + source = "registry+https://github.com/rust-lang/crates.io-index" 1168 + checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" 1169 + dependencies = [ 1170 + "bitflags", 1171 + "errno", 1172 + "libc", 1173 + "linux-raw-sys", 1174 + "windows-sys 0.61.2", 1175 + ] 1176 + 1177 + [[package]] 1178 + name = "rustls" 1179 + version = "0.23.37" 1180 + source = "registry+https://github.com/rust-lang/crates.io-index" 1181 + checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" 1182 + dependencies = [ 1183 + "once_cell", 1184 + "rustls-pki-types", 1185 + "rustls-webpki", 1186 + "subtle", 1187 + "zeroize", 1188 + ] 1189 + 1190 + [[package]] 1191 + name = "rustls-pki-types" 1192 + version = "1.14.0" 1193 + source = "registry+https://github.com/rust-lang/crates.io-index" 1194 + checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" 1195 + dependencies = [ 1196 + "zeroize", 1197 + ] 1198 + 1199 + [[package]] 1200 + name = "rustls-webpki" 1201 + version = "0.103.9" 1202 + source = "registry+https://github.com/rust-lang/crates.io-index" 1203 + checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" 1204 + dependencies = [ 1205 + "ring", 1206 + "rustls-pki-types", 1207 + "untrusted", 1208 + ] 1209 + 1210 + [[package]] 1211 + name = "rustversion" 1212 + version = "1.0.22" 1213 + source = "registry+https://github.com/rust-lang/crates.io-index" 1214 + checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" 1215 + 1216 + [[package]] 1217 + name = "ryu" 1218 + version = "1.0.23" 1219 + source = "registry+https://github.com/rust-lang/crates.io-index" 1220 + checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" 1221 + 1222 + [[package]] 1223 + name = "schannel" 1224 + version = "0.1.28" 1225 + source = "registry+https://github.com/rust-lang/crates.io-index" 1226 + checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" 1227 + dependencies = [ 1228 + "windows-sys 0.61.2", 1229 + ] 1230 + 1231 + [[package]] 1232 + name = "scopeguard" 1233 + version = "1.2.0" 1234 + source = "registry+https://github.com/rust-lang/crates.io-index" 1235 + checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1236 + 1237 + [[package]] 1238 + name = "sec1" 1239 + version = "0.7.3" 1240 + source = "registry+https://github.com/rust-lang/crates.io-index" 1241 + checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" 1242 + dependencies = [ 1243 + "base16ct", 1244 + "der", 1245 + "generic-array", 1246 + "pkcs8", 1247 + "subtle", 1248 + "zeroize", 1249 + ] 1250 + 1251 + [[package]] 1252 + name = "security-framework" 1253 + version = "3.7.0" 1254 + source = "registry+https://github.com/rust-lang/crates.io-index" 1255 + checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" 1256 + dependencies = [ 1257 + "bitflags", 1258 + "core-foundation 0.10.1", 1259 + "core-foundation-sys", 1260 + "libc", 1261 + "security-framework-sys", 1262 + ] 1263 + 1264 + [[package]] 1265 + name = "security-framework-sys" 1266 + version = "2.17.0" 1267 + source = "registry+https://github.com/rust-lang/crates.io-index" 1268 + checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" 1269 + dependencies = [ 1270 + "core-foundation-sys", 1271 + "libc", 1272 + ] 1273 + 1274 + [[package]] 1275 + name = "semver" 1276 + version = "1.0.27" 1277 + source = "registry+https://github.com/rust-lang/crates.io-index" 1278 + checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" 1279 + 1280 + [[package]] 1281 + name = "serde" 1282 + version = "1.0.228" 1283 + source = "registry+https://github.com/rust-lang/crates.io-index" 1284 + checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" 1285 + dependencies = [ 1286 + "serde_core", 1287 + "serde_derive", 1288 + ] 1289 + 1290 + [[package]] 1291 + name = "serde_bytes" 1292 + version = "0.11.19" 1293 + source = "registry+https://github.com/rust-lang/crates.io-index" 1294 + checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" 1295 + dependencies = [ 1296 + "serde", 1297 + "serde_core", 1298 + ] 1299 + 1300 + [[package]] 1301 + name = "serde_core" 1302 + version = "1.0.228" 1303 + source = "registry+https://github.com/rust-lang/crates.io-index" 1304 + checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" 1305 + dependencies = [ 1306 + "serde_derive", 1307 + ] 1308 + 1309 + [[package]] 1310 + name = "serde_derive" 1311 + version = "1.0.228" 1312 + source = "registry+https://github.com/rust-lang/crates.io-index" 1313 + checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" 1314 + dependencies = [ 1315 + "proc-macro2", 1316 + "quote", 1317 + "syn", 1318 + ] 1319 + 1320 + [[package]] 1321 + name = "serde_ipld_dagcbor" 1322 + version = "0.6.4" 1323 + source = "registry+https://github.com/rust-lang/crates.io-index" 1324 + checksum = "46182f4f08349a02b45c998ba3215d3f9de826246ba02bb9dddfe9a2a2100778" 1325 + dependencies = [ 1326 + "cbor4ii", 1327 + "ipld-core", 1328 + "scopeguard", 1329 + "serde", 1330 + ] 1331 + 1332 + [[package]] 1333 + name = "serde_json" 1334 + version = "1.0.149" 1335 + source = "registry+https://github.com/rust-lang/crates.io-index" 1336 + checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" 1337 + dependencies = [ 1338 + "itoa", 1339 + "memchr", 1340 + "serde", 1341 + "serde_core", 1342 + "zmij", 1343 + ] 1344 + 1345 + [[package]] 1346 + name = "serde_urlencoded" 1347 + version = "0.7.1" 1348 + source = "registry+https://github.com/rust-lang/crates.io-index" 1349 + checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1350 + dependencies = [ 1351 + "form_urlencoded", 1352 + "itoa", 1353 + "ryu", 1354 + "serde", 1355 + ] 1356 + 1357 + [[package]] 1358 + name = "sha2" 1359 + version = "0.10.9" 1360 + source = "registry+https://github.com/rust-lang/crates.io-index" 1361 + checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" 1362 + dependencies = [ 1363 + "cfg-if", 1364 + "cpufeatures", 1365 + "digest", 1366 + ] 1367 + 1368 + [[package]] 1369 + name = "shlex" 1370 + version = "1.3.0" 1371 + source = "registry+https://github.com/rust-lang/crates.io-index" 1372 + checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1373 + 1374 + [[package]] 1375 + name = "signature" 1376 + version = "2.2.0" 1377 + source = "registry+https://github.com/rust-lang/crates.io-index" 1378 + checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" 1379 + dependencies = [ 1380 + "digest", 1381 + "rand_core", 1382 + ] 1383 + 1384 + [[package]] 1385 + name = "slab" 1386 + version = "0.4.12" 1387 + source = "registry+https://github.com/rust-lang/crates.io-index" 1388 + checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" 1389 + 1390 + [[package]] 1391 + name = "smallvec" 1392 + version = "1.15.1" 1393 + source = "registry+https://github.com/rust-lang/crates.io-index" 1394 + checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 1395 + 1396 + [[package]] 1397 + name = "socket2" 1398 + version = "0.6.2" 1399 + source = "registry+https://github.com/rust-lang/crates.io-index" 1400 + checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" 1401 + dependencies = [ 1402 + "libc", 1403 + "windows-sys 0.60.2", 1404 + ] 1405 + 1406 + [[package]] 1407 + name = "spki" 1408 + version = "0.7.3" 1409 + source = "registry+https://github.com/rust-lang/crates.io-index" 1410 + checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" 1411 + dependencies = [ 1412 + "base64ct", 1413 + "der", 1414 + ] 1415 + 1416 + [[package]] 1417 + name = "stable_deref_trait" 1418 + version = "1.2.1" 1419 + source = "registry+https://github.com/rust-lang/crates.io-index" 1420 + checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" 1421 + 1422 + [[package]] 1423 + name = "subtle" 1424 + version = "2.6.1" 1425 + source = "registry+https://github.com/rust-lang/crates.io-index" 1426 + checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1427 + 1428 + [[package]] 1429 + name = "syn" 1430 + version = "2.0.117" 1431 + source = "registry+https://github.com/rust-lang/crates.io-index" 1432 + checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" 1433 + dependencies = [ 1434 + "proc-macro2", 1435 + "quote", 1436 + "unicode-ident", 1437 + ] 1438 + 1439 + [[package]] 1440 + name = "sync_wrapper" 1441 + version = "1.0.2" 1442 + source = "registry+https://github.com/rust-lang/crates.io-index" 1443 + checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 1444 + dependencies = [ 1445 + "futures-core", 1446 + ] 1447 + 1448 + [[package]] 1449 + name = "synstructure" 1450 + version = "0.13.2" 1451 + source = "registry+https://github.com/rust-lang/crates.io-index" 1452 + checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" 1453 + dependencies = [ 1454 + "proc-macro2", 1455 + "quote", 1456 + "syn", 1457 + ] 1458 + 1459 + [[package]] 1460 + name = "system-configuration" 1461 + version = "0.7.0" 1462 + source = "registry+https://github.com/rust-lang/crates.io-index" 1463 + checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" 1464 + dependencies = [ 1465 + "bitflags", 1466 + "core-foundation 0.9.4", 1467 + "system-configuration-sys", 1468 + ] 1469 + 1470 + [[package]] 1471 + name = "system-configuration-sys" 1472 + version = "0.6.0" 1473 + source = "registry+https://github.com/rust-lang/crates.io-index" 1474 + checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" 1475 + dependencies = [ 1476 + "core-foundation-sys", 1477 + "libc", 1478 + ] 1479 + 1480 + [[package]] 1481 + name = "tempfile" 1482 + version = "3.26.0" 1483 + source = "registry+https://github.com/rust-lang/crates.io-index" 1484 + checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" 1485 + dependencies = [ 1486 + "fastrand", 1487 + "getrandom 0.4.1", 1488 + "once_cell", 1489 + "rustix", 1490 + "windows-sys 0.61.2", 1491 + ] 1492 + 1493 + [[package]] 1494 + name = "tinystr" 1495 + version = "0.8.2" 1496 + source = "registry+https://github.com/rust-lang/crates.io-index" 1497 + checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" 1498 + dependencies = [ 1499 + "displaydoc", 1500 + "zerovec", 1501 + ] 1502 + 1503 + [[package]] 1504 + name = "tokio" 1505 + version = "1.49.0" 1506 + source = "registry+https://github.com/rust-lang/crates.io-index" 1507 + checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" 1508 + dependencies = [ 1509 + "bytes", 1510 + "libc", 1511 + "mio", 1512 + "pin-project-lite", 1513 + "socket2", 1514 + "windows-sys 0.61.2", 1515 + ] 1516 + 1517 + [[package]] 1518 + name = "tokio-native-tls" 1519 + version = "0.3.1" 1520 + source = "registry+https://github.com/rust-lang/crates.io-index" 1521 + checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 1522 + dependencies = [ 1523 + "native-tls", 1524 + "tokio", 1525 + ] 1526 + 1527 + [[package]] 1528 + name = "tokio-rustls" 1529 + version = "0.26.4" 1530 + source = "registry+https://github.com/rust-lang/crates.io-index" 1531 + checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" 1532 + dependencies = [ 1533 + "rustls", 1534 + "tokio", 1535 + ] 1536 + 1537 + [[package]] 1538 + name = "tokio-util" 1539 + version = "0.7.18" 1540 + source = "registry+https://github.com/rust-lang/crates.io-index" 1541 + checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" 1542 + dependencies = [ 1543 + "bytes", 1544 + "futures-core", 1545 + "futures-sink", 1546 + "pin-project-lite", 1547 + "tokio", 1548 + ] 1549 + 1550 + [[package]] 1551 + name = "tower" 1552 + version = "0.5.3" 1553 + source = "registry+https://github.com/rust-lang/crates.io-index" 1554 + checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" 1555 + dependencies = [ 1556 + "futures-core", 1557 + "futures-util", 1558 + "pin-project-lite", 1559 + "sync_wrapper", 1560 + "tokio", 1561 + "tower-layer", 1562 + "tower-service", 1563 + ] 1564 + 1565 + [[package]] 1566 + name = "tower-http" 1567 + version = "0.6.8" 1568 + source = "registry+https://github.com/rust-lang/crates.io-index" 1569 + checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" 1570 + dependencies = [ 1571 + "bitflags", 1572 + "bytes", 1573 + "futures-util", 1574 + "http", 1575 + "http-body", 1576 + "iri-string", 1577 + "pin-project-lite", 1578 + "tower", 1579 + "tower-layer", 1580 + "tower-service", 1581 + ] 1582 + 1583 + [[package]] 1584 + name = "tower-layer" 1585 + version = "0.3.3" 1586 + source = "registry+https://github.com/rust-lang/crates.io-index" 1587 + checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" 1588 + 1589 + [[package]] 1590 + name = "tower-service" 1591 + version = "0.3.3" 1592 + source = "registry+https://github.com/rust-lang/crates.io-index" 1593 + checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 1594 + 1595 + [[package]] 1596 + name = "tracing" 1597 + version = "0.1.44" 1598 + source = "registry+https://github.com/rust-lang/crates.io-index" 1599 + checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" 1600 + dependencies = [ 1601 + "pin-project-lite", 1602 + "tracing-core", 1603 + ] 1604 + 1605 + [[package]] 1606 + name = "tracing-core" 1607 + version = "0.1.36" 1608 + source = "registry+https://github.com/rust-lang/crates.io-index" 1609 + checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" 1610 + dependencies = [ 1611 + "once_cell", 1612 + ] 1613 + 1614 + [[package]] 1615 + name = "try-lock" 1616 + version = "0.2.5" 1617 + source = "registry+https://github.com/rust-lang/crates.io-index" 1618 + checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 1619 + 1620 + [[package]] 1621 + name = "typenum" 1622 + version = "1.19.0" 1623 + source = "registry+https://github.com/rust-lang/crates.io-index" 1624 + checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" 1625 + 1626 + [[package]] 1627 + name = "unicode-ident" 1628 + version = "1.0.24" 1629 + source = "registry+https://github.com/rust-lang/crates.io-index" 1630 + checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" 1631 + 1632 + [[package]] 1633 + name = "unicode-xid" 1634 + version = "0.2.6" 1635 + source = "registry+https://github.com/rust-lang/crates.io-index" 1636 + checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" 1637 + 1638 + [[package]] 1639 + name = "unsigned-varint" 1640 + version = "0.8.0" 1641 + source = "registry+https://github.com/rust-lang/crates.io-index" 1642 + checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" 1643 + 1644 + [[package]] 1645 + name = "untrusted" 1646 + version = "0.9.0" 1647 + source = "registry+https://github.com/rust-lang/crates.io-index" 1648 + checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1649 + 1650 + [[package]] 1651 + name = "url" 1652 + version = "2.5.8" 1653 + source = "registry+https://github.com/rust-lang/crates.io-index" 1654 + checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" 1655 + dependencies = [ 1656 + "form_urlencoded", 1657 + "idna", 1658 + "percent-encoding", 1659 + "serde", 1660 + ] 1661 + 1662 + [[package]] 1663 + name = "utf8_iter" 1664 + version = "1.0.4" 1665 + source = "registry+https://github.com/rust-lang/crates.io-index" 1666 + checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 1667 + 1668 + [[package]] 1669 + name = "vcpkg" 1670 + version = "0.2.15" 1671 + source = "registry+https://github.com/rust-lang/crates.io-index" 1672 + checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1673 + 1674 + [[package]] 1675 + name = "version_check" 1676 + version = "0.9.5" 1677 + source = "registry+https://github.com/rust-lang/crates.io-index" 1678 + checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1679 + 1680 + [[package]] 1681 + name = "want" 1682 + version = "0.3.1" 1683 + source = "registry+https://github.com/rust-lang/crates.io-index" 1684 + checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1685 + dependencies = [ 1686 + "try-lock", 1687 + ] 1688 + 1689 + [[package]] 1690 + name = "wasi" 1691 + version = "0.11.1+wasi-snapshot-preview1" 1692 + source = "registry+https://github.com/rust-lang/crates.io-index" 1693 + checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" 1694 + 1695 + [[package]] 1696 + name = "wasip2" 1697 + version = "1.0.2+wasi-0.2.9" 1698 + source = "registry+https://github.com/rust-lang/crates.io-index" 1699 + checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" 1700 + dependencies = [ 1701 + "wit-bindgen", 1702 + ] 1703 + 1704 + [[package]] 1705 + name = "wasip3" 1706 + version = "0.4.0+wasi-0.3.0-rc-2026-01-06" 1707 + source = "registry+https://github.com/rust-lang/crates.io-index" 1708 + checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" 1709 + dependencies = [ 1710 + "wit-bindgen", 1711 + ] 1712 + 1713 + [[package]] 1714 + name = "wasm-bindgen" 1715 + version = "0.2.113" 1716 + source = "registry+https://github.com/rust-lang/crates.io-index" 1717 + checksum = "60722a937f594b7fde9adb894d7c092fc1bb6612897c46368d18e7a20208eff2" 1718 + dependencies = [ 1719 + "cfg-if", 1720 + "once_cell", 1721 + "rustversion", 1722 + "wasm-bindgen-macro", 1723 + "wasm-bindgen-shared", 1724 + ] 1725 + 1726 + [[package]] 1727 + name = "wasm-bindgen-futures" 1728 + version = "0.4.63" 1729 + source = "registry+https://github.com/rust-lang/crates.io-index" 1730 + checksum = "8a89f4650b770e4521aa6573724e2aed4704372151bd0de9d16a3bbabb87441a" 1731 + dependencies = [ 1732 + "cfg-if", 1733 + "futures-util", 1734 + "js-sys", 1735 + "once_cell", 1736 + "wasm-bindgen", 1737 + "web-sys", 1738 + ] 1739 + 1740 + [[package]] 1741 + name = "wasm-bindgen-macro" 1742 + version = "0.2.113" 1743 + source = "registry+https://github.com/rust-lang/crates.io-index" 1744 + checksum = "0fac8c6395094b6b91c4af293f4c79371c163f9a6f56184d2c9a85f5a95f3950" 1745 + dependencies = [ 1746 + "quote", 1747 + "wasm-bindgen-macro-support", 1748 + ] 1749 + 1750 + [[package]] 1751 + name = "wasm-bindgen-macro-support" 1752 + version = "0.2.113" 1753 + source = "registry+https://github.com/rust-lang/crates.io-index" 1754 + checksum = "ab3fabce6159dc20728033842636887e4877688ae94382766e00b180abac9d60" 1755 + dependencies = [ 1756 + "bumpalo", 1757 + "proc-macro2", 1758 + "quote", 1759 + "syn", 1760 + "wasm-bindgen-shared", 1761 + ] 1762 + 1763 + [[package]] 1764 + name = "wasm-bindgen-shared" 1765 + version = "0.2.113" 1766 + source = "registry+https://github.com/rust-lang/crates.io-index" 1767 + checksum = "de0e091bdb824da87dc01d967388880d017a0a9bc4f3bdc0d86ee9f9336e3bb5" 1768 + dependencies = [ 1769 + "unicode-ident", 1770 + ] 1771 + 1772 + [[package]] 1773 + name = "wasm-encoder" 1774 + version = "0.244.0" 1775 + source = "registry+https://github.com/rust-lang/crates.io-index" 1776 + checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" 1777 + dependencies = [ 1778 + "leb128fmt", 1779 + "wasmparser", 1780 + ] 1781 + 1782 + [[package]] 1783 + name = "wasm-metadata" 1784 + version = "0.244.0" 1785 + source = "registry+https://github.com/rust-lang/crates.io-index" 1786 + checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" 1787 + dependencies = [ 1788 + "anyhow", 1789 + "indexmap", 1790 + "wasm-encoder", 1791 + "wasmparser", 1792 + ] 1793 + 1794 + [[package]] 1795 + name = "wasmparser" 1796 + version = "0.244.0" 1797 + source = "registry+https://github.com/rust-lang/crates.io-index" 1798 + checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" 1799 + dependencies = [ 1800 + "bitflags", 1801 + "hashbrown 0.15.5", 1802 + "indexmap", 1803 + "semver", 1804 + ] 1805 + 1806 + [[package]] 1807 + name = "web-sys" 1808 + version = "0.3.90" 1809 + source = "registry+https://github.com/rust-lang/crates.io-index" 1810 + checksum = "705eceb4ce901230f8625bd1d665128056ccbe4b7408faa625eec1ba80f59a97" 1811 + dependencies = [ 1812 + "js-sys", 1813 + "wasm-bindgen", 1814 + ] 1815 + 1816 + [[package]] 1817 + name = "windows-link" 1818 + version = "0.2.1" 1819 + source = "registry+https://github.com/rust-lang/crates.io-index" 1820 + checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 1821 + 1822 + [[package]] 1823 + name = "windows-registry" 1824 + version = "0.6.1" 1825 + source = "registry+https://github.com/rust-lang/crates.io-index" 1826 + checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" 1827 + dependencies = [ 1828 + "windows-link", 1829 + "windows-result", 1830 + "windows-strings", 1831 + ] 1832 + 1833 + [[package]] 1834 + name = "windows-result" 1835 + version = "0.4.1" 1836 + source = "registry+https://github.com/rust-lang/crates.io-index" 1837 + checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" 1838 + dependencies = [ 1839 + "windows-link", 1840 + ] 1841 + 1842 + [[package]] 1843 + name = "windows-strings" 1844 + version = "0.5.1" 1845 + source = "registry+https://github.com/rust-lang/crates.io-index" 1846 + checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" 1847 + dependencies = [ 1848 + "windows-link", 1849 + ] 1850 + 1851 + [[package]] 1852 + name = "windows-sys" 1853 + version = "0.52.0" 1854 + source = "registry+https://github.com/rust-lang/crates.io-index" 1855 + checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1856 + dependencies = [ 1857 + "windows-targets 0.52.6", 1858 + ] 1859 + 1860 + [[package]] 1861 + name = "windows-sys" 1862 + version = "0.60.2" 1863 + source = "registry+https://github.com/rust-lang/crates.io-index" 1864 + checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" 1865 + dependencies = [ 1866 + "windows-targets 0.53.5", 1867 + ] 1868 + 1869 + [[package]] 1870 + name = "windows-sys" 1871 + version = "0.61.2" 1872 + source = "registry+https://github.com/rust-lang/crates.io-index" 1873 + checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" 1874 + dependencies = [ 1875 + "windows-link", 1876 + ] 1877 + 1878 + [[package]] 1879 + name = "windows-targets" 1880 + version = "0.52.6" 1881 + source = "registry+https://github.com/rust-lang/crates.io-index" 1882 + checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1883 + dependencies = [ 1884 + "windows_aarch64_gnullvm 0.52.6", 1885 + "windows_aarch64_msvc 0.52.6", 1886 + "windows_i686_gnu 0.52.6", 1887 + "windows_i686_gnullvm 0.52.6", 1888 + "windows_i686_msvc 0.52.6", 1889 + "windows_x86_64_gnu 0.52.6", 1890 + "windows_x86_64_gnullvm 0.52.6", 1891 + "windows_x86_64_msvc 0.52.6", 1892 + ] 1893 + 1894 + [[package]] 1895 + name = "windows-targets" 1896 + version = "0.53.5" 1897 + source = "registry+https://github.com/rust-lang/crates.io-index" 1898 + checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" 1899 + dependencies = [ 1900 + "windows-link", 1901 + "windows_aarch64_gnullvm 0.53.1", 1902 + "windows_aarch64_msvc 0.53.1", 1903 + "windows_i686_gnu 0.53.1", 1904 + "windows_i686_gnullvm 0.53.1", 1905 + "windows_i686_msvc 0.53.1", 1906 + "windows_x86_64_gnu 0.53.1", 1907 + "windows_x86_64_gnullvm 0.53.1", 1908 + "windows_x86_64_msvc 0.53.1", 1909 + ] 1910 + 1911 + [[package]] 1912 + name = "windows_aarch64_gnullvm" 1913 + version = "0.52.6" 1914 + source = "registry+https://github.com/rust-lang/crates.io-index" 1915 + checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1916 + 1917 + [[package]] 1918 + name = "windows_aarch64_gnullvm" 1919 + version = "0.53.1" 1920 + source = "registry+https://github.com/rust-lang/crates.io-index" 1921 + checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" 1922 + 1923 + [[package]] 1924 + name = "windows_aarch64_msvc" 1925 + version = "0.52.6" 1926 + source = "registry+https://github.com/rust-lang/crates.io-index" 1927 + checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1928 + 1929 + [[package]] 1930 + name = "windows_aarch64_msvc" 1931 + version = "0.53.1" 1932 + source = "registry+https://github.com/rust-lang/crates.io-index" 1933 + checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" 1934 + 1935 + [[package]] 1936 + name = "windows_i686_gnu" 1937 + version = "0.52.6" 1938 + source = "registry+https://github.com/rust-lang/crates.io-index" 1939 + checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1940 + 1941 + [[package]] 1942 + name = "windows_i686_gnu" 1943 + version = "0.53.1" 1944 + source = "registry+https://github.com/rust-lang/crates.io-index" 1945 + checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" 1946 + 1947 + [[package]] 1948 + name = "windows_i686_gnullvm" 1949 + version = "0.52.6" 1950 + source = "registry+https://github.com/rust-lang/crates.io-index" 1951 + checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1952 + 1953 + [[package]] 1954 + name = "windows_i686_gnullvm" 1955 + version = "0.53.1" 1956 + source = "registry+https://github.com/rust-lang/crates.io-index" 1957 + checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" 1958 + 1959 + [[package]] 1960 + name = "windows_i686_msvc" 1961 + version = "0.52.6" 1962 + source = "registry+https://github.com/rust-lang/crates.io-index" 1963 + checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1964 + 1965 + [[package]] 1966 + name = "windows_i686_msvc" 1967 + version = "0.53.1" 1968 + source = "registry+https://github.com/rust-lang/crates.io-index" 1969 + checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" 1970 + 1971 + [[package]] 1972 + name = "windows_x86_64_gnu" 1973 + version = "0.52.6" 1974 + source = "registry+https://github.com/rust-lang/crates.io-index" 1975 + checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1976 + 1977 + [[package]] 1978 + name = "windows_x86_64_gnu" 1979 + version = "0.53.1" 1980 + source = "registry+https://github.com/rust-lang/crates.io-index" 1981 + checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" 1982 + 1983 + [[package]] 1984 + name = "windows_x86_64_gnullvm" 1985 + version = "0.52.6" 1986 + source = "registry+https://github.com/rust-lang/crates.io-index" 1987 + checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1988 + 1989 + [[package]] 1990 + name = "windows_x86_64_gnullvm" 1991 + version = "0.53.1" 1992 + source = "registry+https://github.com/rust-lang/crates.io-index" 1993 + checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" 1994 + 1995 + [[package]] 1996 + name = "windows_x86_64_msvc" 1997 + version = "0.52.6" 1998 + source = "registry+https://github.com/rust-lang/crates.io-index" 1999 + checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2000 + 2001 + [[package]] 2002 + name = "windows_x86_64_msvc" 2003 + version = "0.53.1" 2004 + source = "registry+https://github.com/rust-lang/crates.io-index" 2005 + checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" 2006 + 2007 + [[package]] 2008 + name = "wit-bindgen" 2009 + version = "0.51.0" 2010 + source = "registry+https://github.com/rust-lang/crates.io-index" 2011 + checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" 2012 + dependencies = [ 2013 + "wit-bindgen-rust-macro", 2014 + ] 2015 + 2016 + [[package]] 2017 + name = "wit-bindgen-core" 2018 + version = "0.51.0" 2019 + source = "registry+https://github.com/rust-lang/crates.io-index" 2020 + checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" 2021 + dependencies = [ 2022 + "anyhow", 2023 + "heck", 2024 + "wit-parser", 2025 + ] 2026 + 2027 + [[package]] 2028 + name = "wit-bindgen-rust" 2029 + version = "0.51.0" 2030 + source = "registry+https://github.com/rust-lang/crates.io-index" 2031 + checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" 2032 + dependencies = [ 2033 + "anyhow", 2034 + "heck", 2035 + "indexmap", 2036 + "prettyplease", 2037 + "syn", 2038 + "wasm-metadata", 2039 + "wit-bindgen-core", 2040 + "wit-component", 2041 + ] 2042 + 2043 + [[package]] 2044 + name = "wit-bindgen-rust-macro" 2045 + version = "0.51.0" 2046 + source = "registry+https://github.com/rust-lang/crates.io-index" 2047 + checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" 2048 + dependencies = [ 2049 + "anyhow", 2050 + "prettyplease", 2051 + "proc-macro2", 2052 + "quote", 2053 + "syn", 2054 + "wit-bindgen-core", 2055 + "wit-bindgen-rust", 2056 + ] 2057 + 2058 + [[package]] 2059 + name = "wit-component" 2060 + version = "0.244.0" 2061 + source = "registry+https://github.com/rust-lang/crates.io-index" 2062 + checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" 2063 + dependencies = [ 2064 + "anyhow", 2065 + "bitflags", 2066 + "indexmap", 2067 + "log", 2068 + "serde", 2069 + "serde_derive", 2070 + "serde_json", 2071 + "wasm-encoder", 2072 + "wasm-metadata", 2073 + "wasmparser", 2074 + "wit-parser", 2075 + ] 2076 + 2077 + [[package]] 2078 + name = "wit-parser" 2079 + version = "0.244.0" 2080 + source = "registry+https://github.com/rust-lang/crates.io-index" 2081 + checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" 2082 + dependencies = [ 2083 + "anyhow", 2084 + "id-arena", 2085 + "indexmap", 2086 + "log", 2087 + "semver", 2088 + "serde", 2089 + "serde_derive", 2090 + "serde_json", 2091 + "unicode-xid", 2092 + "wasmparser", 2093 + ] 2094 + 2095 + [[package]] 2096 + name = "writeable" 2097 + version = "0.6.2" 2098 + source = "registry+https://github.com/rust-lang/crates.io-index" 2099 + checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" 2100 + 2101 + [[package]] 2102 + name = "yoke" 2103 + version = "0.8.1" 2104 + source = "registry+https://github.com/rust-lang/crates.io-index" 2105 + checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" 2106 + dependencies = [ 2107 + "stable_deref_trait", 2108 + "yoke-derive", 2109 + "zerofrom", 2110 + ] 2111 + 2112 + [[package]] 2113 + name = "yoke-derive" 2114 + version = "0.8.1" 2115 + source = "registry+https://github.com/rust-lang/crates.io-index" 2116 + checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" 2117 + dependencies = [ 2118 + "proc-macro2", 2119 + "quote", 2120 + "syn", 2121 + "synstructure", 2122 + ] 2123 + 2124 + [[package]] 2125 + name = "zerofrom" 2126 + version = "0.1.6" 2127 + source = "registry+https://github.com/rust-lang/crates.io-index" 2128 + checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" 2129 + dependencies = [ 2130 + "zerofrom-derive", 2131 + ] 2132 + 2133 + [[package]] 2134 + name = "zerofrom-derive" 2135 + version = "0.1.6" 2136 + source = "registry+https://github.com/rust-lang/crates.io-index" 2137 + checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" 2138 + dependencies = [ 2139 + "proc-macro2", 2140 + "quote", 2141 + "syn", 2142 + "synstructure", 2143 + ] 2144 + 2145 + [[package]] 2146 + name = "zeroize" 2147 + version = "1.8.2" 2148 + source = "registry+https://github.com/rust-lang/crates.io-index" 2149 + checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" 2150 + 2151 + [[package]] 2152 + name = "zerotrie" 2153 + version = "0.2.3" 2154 + source = "registry+https://github.com/rust-lang/crates.io-index" 2155 + checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" 2156 + dependencies = [ 2157 + "displaydoc", 2158 + "yoke", 2159 + "zerofrom", 2160 + ] 2161 + 2162 + [[package]] 2163 + name = "zerovec" 2164 + version = "0.11.5" 2165 + source = "registry+https://github.com/rust-lang/crates.io-index" 2166 + checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" 2167 + dependencies = [ 2168 + "yoke", 2169 + "zerofrom", 2170 + "zerovec-derive", 2171 + ] 2172 + 2173 + [[package]] 2174 + name = "zerovec-derive" 2175 + version = "0.11.2" 2176 + source = "registry+https://github.com/rust-lang/crates.io-index" 2177 + checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" 2178 + dependencies = [ 2179 + "proc-macro2", 2180 + "quote", 2181 + "syn", 2182 + ] 2183 + 2184 + [[package]] 2185 + name = "zmij" 2186 + version = "1.0.21" 2187 + source = "registry+https://github.com/rust-lang/crates.io-index" 2188 + checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
+23
rust-verify/Cargo.toml
··· 1 + [package] 2 + name = "rust-verify" 3 + version = "0.1.0" 4 + edition = "2021" 5 + 6 + [dependencies] 7 + reqwest = { version = "0.12", features = ["blocking", "json"] } 8 + serde = { version = "1", features = ["derive"] } 9 + serde_json = "1" 10 + serde_ipld_dagcbor = "0.6" 11 + ipld-core = { version = "0.4", features = ["serde"] } 12 + k256 = { version = "0.13", features = ["ecdsa"] } 13 + p256 = { version = "0.13", features = ["ecdsa"] } 14 + ecdsa = "0.16" 15 + sha2 = "0.10" 16 + unsigned-varint = "0.8" 17 + multibase = "0.9" 18 + 19 + [profile.release] 20 + opt-level = 3 21 + lto = true 22 + codegen-units = 1 23 + panic = "abort"
+601
rust-verify/src/main.rs
··· 1 + //! full AT Protocol trust chain verification — rust (RustCrypto) 2 + //! 3 + //! resolves handle → DID → DID doc → signing key + PDS, 4 + //! fetches repo CAR, parses it, verifies commit signature, 5 + //! and walks MST to count records. 6 + //! 7 + //! no indigo equivalent exists in rust, so handle/DID resolution, 8 + //! CAR parsing, and MST walking are manual. 9 + 10 + use ecdsa::signature::Verifier; 11 + use ipld_core::ipld::Ipld; 12 + use sha2::{Digest, Sha256}; 13 + use std::collections::HashMap; 14 + use std::process::Command; 15 + use std::time::Instant; 16 + 17 + fn main() { 18 + let args: Vec<String> = std::env::args().collect(); 19 + if args.len() < 2 { 20 + eprintln!("usage: rust-verify <handle-or-did>"); 21 + std::process::exit(1); 22 + } 23 + let input = &args[1]; 24 + 25 + println!("\n=== rust (RustCrypto): full AT Protocol trust chain ===\n"); 26 + 27 + let total_start = Instant::now(); 28 + 29 + // --- step 1: resolve identifier --- 30 + let step_start = Instant::now(); 31 + 32 + let (did, handle, is_did) = if input.starts_with("did:") { 33 + (input.clone(), None, true) 34 + } else { 35 + // try HTTP .well-known first, fall back to DNS TXT 36 + let did = resolve_handle(input); 37 + (did, Some(input.clone()), false) 38 + }; 39 + 40 + let handle_ms = step_start.elapsed(); 41 + 42 + if is_did { 43 + println!("DID {did}"); 44 + } else { 45 + println!("handle {}", handle.as_ref().unwrap()); 46 + print_padded(&format!(" → {did}"), handle_ms); 47 + } 48 + 49 + // --- step 2: resolve DID document --- 50 + let step_start = Instant::now(); 51 + 52 + let did_doc = resolve_did_doc(&did); 53 + let (key_type, key_bytes) = extract_signing_key(&did_doc); 54 + let pds_endpoint = extract_pds_endpoint(&did_doc); 55 + 56 + let did_ms = step_start.elapsed(); 57 + 58 + println!("\nDID doc {did}"); 59 + print_padded( 60 + &format!(" → signing key: {} (compressed, {} bytes)", key_type, key_bytes.len()), 61 + did_ms, 62 + ); 63 + println!(" → PDS: {pds_endpoint}"); 64 + 65 + // --- step 3: fetch repo CAR --- 66 + let step_start = Instant::now(); 67 + 68 + let repo_url = format!("{pds_endpoint}/xrpc/com.atproto.sync.getRepo?did={did}"); 69 + let resp = match reqwest::blocking::get(&repo_url) { 70 + Ok(r) => r, 71 + Err(e) => { 72 + eprintln!("error: failed to fetch repo: {e}"); 73 + std::process::exit(1); 74 + } 75 + }; 76 + if resp.status() != 200 { 77 + eprintln!("error: PDS returned HTTP {}", resp.status()); 78 + std::process::exit(1); 79 + } 80 + let car_bytes = resp.bytes().unwrap_or_default().to_vec(); 81 + 82 + let fetch_ms = step_start.elapsed(); 83 + 84 + println!("\nrepo com.atproto.sync.getRepo"); 85 + print_padded(&format!(" → {} CAR", fmt_size(car_bytes.len())), fetch_ms); 86 + 87 + // --- step 4: parse CAR --- 88 + let step_start = Instant::now(); 89 + 90 + let (roots, block_map, block_count) = parse_car(&car_bytes); 91 + if roots.is_empty() { 92 + eprintln!("error: no roots in CAR"); 93 + std::process::exit(1); 94 + } 95 + 96 + let car_ms = step_start.elapsed(); 97 + 98 + // --- step 5: find + decode commit --- 99 + let commit_cid = &roots[0]; 100 + let commit_data = match find_block(&block_map, commit_cid) { 101 + Some(d) => d, 102 + None => { 103 + eprintln!("error: commit block not found"); 104 + std::process::exit(1); 105 + } 106 + }; 107 + 108 + let commit: Ipld = match serde_ipld_dagcbor::from_slice(commit_data) { 109 + Ok(c) => c, 110 + Err(e) => { 111 + eprintln!("error: failed to decode commit: {e}"); 112 + std::process::exit(1); 113 + } 114 + }; 115 + 116 + let commit_map = match &commit { 117 + Ipld::Map(m) => m, 118 + _ => { 119 + eprintln!("error: commit is not a map"); 120 + std::process::exit(1); 121 + } 122 + }; 123 + 124 + let rev = match commit_map.get("rev") { 125 + Some(Ipld::String(s)) => s.clone(), 126 + _ => "???".to_string(), 127 + }; 128 + 129 + let sig_bytes = match commit_map.get("sig") { 130 + Some(Ipld::Bytes(b)) => b.clone(), 131 + _ => { 132 + eprintln!("error: no signature in commit"); 133 + std::process::exit(1); 134 + } 135 + }; 136 + 137 + let data_cid_bytes = match commit_map.get("data") { 138 + Some(Ipld::Link(cid)) => cid.to_bytes(), 139 + _ => { 140 + eprintln!("error: no data CID in commit"); 141 + std::process::exit(1); 142 + } 143 + }; 144 + 145 + // --- step 6: verify signature --- 146 + let step_start = Instant::now(); 147 + 148 + // strip sig, re-encode as unsigned commit 149 + let mut unsigned_map = commit_map.clone(); 150 + unsigned_map.remove("sig"); 151 + let unsigned_bytes = serde_ipld_dagcbor::to_vec(&Ipld::Map(unsigned_map)).unwrap(); 152 + 153 + verify_signature(&key_type, &key_bytes, &unsigned_bytes, &sig_bytes); 154 + 155 + let sig_ms = step_start.elapsed(); 156 + 157 + // --- step 7: walk MST --- 158 + let step_start = Instant::now(); 159 + 160 + let record_count = walk_mst(&block_map, &data_cid_bytes); 161 + 162 + let walk_ms = step_start.elapsed(); 163 + 164 + // --- output --- 165 + let rev_short = if rev.len() > 6 { &rev[..6] } else { &rev }; 166 + println!("\nverify commit rev={rev_short}..."); 167 + print_padded( 168 + &format!(" → CAR parse ({} blocks, SHA-256 verified)", block_count), 169 + car_ms, 170 + ); 171 + print_padded( 172 + &format!(" → commit signature VERIFIED ({key_type})"), 173 + sig_ms, 174 + ); 175 + print_padded(&format!(" → MST walk: {record_count} records"), walk_ms); 176 + println!(" → MST rebuild: N/A (no MST rebuild in rust crates)"); 177 + 178 + let total_ms = total_start.elapsed(); 179 + let network_ms = if is_did { 180 + did_ms + fetch_ms 181 + } else { 182 + handle_ms + did_ms + fetch_ms 183 + }; 184 + let compute_ms = car_ms + sig_ms + walk_ms; 185 + println!( 186 + "\ntotal {} (network: {}, compute: {})\n", 187 + fmt_duration(total_ms), 188 + fmt_duration(network_ms), 189 + fmt_duration(compute_ms), 190 + ); 191 + } 192 + 193 + // --- handle resolution --- 194 + 195 + fn resolve_handle(handle: &str) -> String { 196 + // try HTTP .well-known first 197 + let url = format!("https://{handle}/.well-known/atproto-did"); 198 + if let Ok(resp) = reqwest::blocking::get(&url) { 199 + if resp.status().is_success() { 200 + let text = resp.text().unwrap_or_default().trim().to_string(); 201 + if text.starts_with("did:") { 202 + return text; 203 + } 204 + } 205 + } 206 + 207 + // fall back to DNS TXT _atproto.{handle} 208 + let output = Command::new("dig") 209 + .args(["+short", "TXT", &format!("_atproto.{handle}")]) 210 + .output() 211 + .unwrap_or_else(|e| { 212 + eprintln!("error: DNS lookup failed: {e}"); 213 + std::process::exit(1); 214 + }); 215 + let txt = String::from_utf8_lossy(&output.stdout); 216 + for line in txt.lines() { 217 + let clean = line.trim().trim_matches('"'); 218 + if let Some(did) = clean.strip_prefix("did=") { 219 + return did.to_string(); 220 + } 221 + } 222 + 223 + eprintln!("error: could not resolve handle: {handle}"); 224 + std::process::exit(1); 225 + } 226 + 227 + // --- DID resolution --- 228 + 229 + #[derive(serde::Deserialize)] 230 + #[serde(rename_all = "camelCase")] 231 + struct DidDocument { 232 + #[allow(dead_code)] 233 + id: String, 234 + #[serde(default)] 235 + verification_method: Vec<VerificationMethod>, 236 + #[serde(default)] 237 + service: Vec<Service>, 238 + } 239 + 240 + #[derive(serde::Deserialize)] 241 + #[serde(rename_all = "camelCase")] 242 + struct VerificationMethod { 243 + id: String, 244 + #[allow(dead_code)] 245 + r#type: String, 246 + public_key_multibase: Option<String>, 247 + } 248 + 249 + #[derive(serde::Deserialize)] 250 + #[serde(rename_all = "camelCase")] 251 + struct Service { 252 + id: String, 253 + #[allow(dead_code)] 254 + r#type: String, 255 + service_endpoint: String, 256 + } 257 + 258 + fn resolve_did_doc(did: &str) -> DidDocument { 259 + let url = if did.starts_with("did:plc:") { 260 + format!("https://plc.directory/{did}") 261 + } else if did.starts_with("did:web:") { 262 + let host = &did[8..]; 263 + format!("https://{host}/.well-known/did.json") 264 + } else { 265 + eprintln!("error: unsupported DID method: {did}"); 266 + std::process::exit(1); 267 + }; 268 + 269 + let resp = match reqwest::blocking::get(&url) { 270 + Ok(r) => r, 271 + Err(e) => { 272 + eprintln!("error: DID resolution failed: {e}"); 273 + std::process::exit(1); 274 + } 275 + }; 276 + 277 + match resp.json::<DidDocument>() { 278 + Ok(doc) => doc, 279 + Err(e) => { 280 + eprintln!("error: failed to parse DID document: {e}"); 281 + std::process::exit(1); 282 + } 283 + } 284 + } 285 + 286 + fn extract_signing_key(doc: &DidDocument) -> (String, Vec<u8>) { 287 + for vm in &doc.verification_method { 288 + if vm.id.ends_with("#atproto") { 289 + if let Some(ref mb) = vm.public_key_multibase { 290 + let (_, raw) = multibase::decode(mb).unwrap_or_else(|e| { 291 + eprintln!("error: multibase decode failed: {e}"); 292 + std::process::exit(1); 293 + }); 294 + // strip multicodec varint prefix to get raw compressed key 295 + let (key_type, key_bytes) = strip_multicodec(&raw); 296 + return (key_type, key_bytes); 297 + } 298 + } 299 + } 300 + eprintln!("error: no #atproto signing key in DID document"); 301 + std::process::exit(1); 302 + } 303 + 304 + fn strip_multicodec(data: &[u8]) -> (String, Vec<u8>) { 305 + if data.len() < 2 { 306 + eprintln!("error: multicodec data too short"); 307 + std::process::exit(1); 308 + } 309 + // p256: 0x80 0x24 (varint 0x1200) 310 + // secp256k1: 0xe7 0x01 (varint 0xe7) 311 + if data[0] == 0x80 && data[1] == 0x24 { 312 + ("p256".to_string(), data[2..].to_vec()) 313 + } else if data[0] == 0xe7 && data[1] == 0x01 { 314 + ("secp256k1".to_string(), data[2..].to_vec()) 315 + } else { 316 + eprintln!( 317 + "error: unknown multicodec prefix: 0x{:02x} 0x{:02x}", 318 + data[0], data[1] 319 + ); 320 + std::process::exit(1); 321 + } 322 + } 323 + 324 + fn extract_pds_endpoint(doc: &DidDocument) -> String { 325 + for svc in &doc.service { 326 + if svc.id.ends_with("#atproto_pds") { 327 + return svc.service_endpoint.clone(); 328 + } 329 + } 330 + eprintln!("error: no #atproto_pds service in DID document"); 331 + std::process::exit(1); 332 + } 333 + 334 + // --- signature verification --- 335 + 336 + fn verify_signature(key_type: &str, key_bytes: &[u8], message: &[u8], sig_bytes: &[u8]) { 337 + if sig_bytes.len() != 64 { 338 + eprintln!("error: signature must be 64 bytes, got {}", sig_bytes.len()); 339 + std::process::exit(1); 340 + } 341 + 342 + match key_type { 343 + "p256" => { 344 + let key = p256::ecdsa::VerifyingKey::from_sec1_bytes(key_bytes).unwrap_or_else(|e| { 345 + eprintln!("error: invalid P-256 key: {e}"); 346 + std::process::exit(1); 347 + }); 348 + let sig = p256::ecdsa::Signature::from_slice(sig_bytes).unwrap_or_else(|e| { 349 + eprintln!("error: invalid P-256 signature: {e}"); 350 + std::process::exit(1); 351 + }); 352 + // RustCrypto Verifier::verify hashes internally 353 + if key.verify(message, &sig).is_err() { 354 + eprintln!("error: P-256 signature verification failed"); 355 + std::process::exit(1); 356 + } 357 + } 358 + "secp256k1" => { 359 + let key = 360 + k256::ecdsa::VerifyingKey::from_sec1_bytes(key_bytes).unwrap_or_else(|e| { 361 + eprintln!("error: invalid secp256k1 key: {e}"); 362 + std::process::exit(1); 363 + }); 364 + let sig = k256::ecdsa::Signature::from_slice(sig_bytes).unwrap_or_else(|e| { 365 + eprintln!("error: invalid secp256k1 signature: {e}"); 366 + std::process::exit(1); 367 + }); 368 + if key.verify(message, &sig).is_err() { 369 + eprintln!("error: secp256k1 signature verification failed"); 370 + std::process::exit(1); 371 + } 372 + } 373 + _ => { 374 + eprintln!("error: unsupported key type: {key_type}"); 375 + std::process::exit(1); 376 + } 377 + } 378 + } 379 + 380 + // --- CAR parser --- 381 + 382 + type BlockMap = HashMap<Vec<u8>, Vec<u8>>; 383 + 384 + fn parse_car(data: &[u8]) -> (Vec<Vec<u8>>, BlockMap, usize) { 385 + let mut pos = 0; 386 + 387 + // header length 388 + let header_len = read_uvarint(data, &mut pos); 389 + let header_end = pos + header_len; 390 + if header_end > data.len() { 391 + eprintln!("error: truncated CAR header"); 392 + std::process::exit(1); 393 + } 394 + 395 + // decode header as DAG-CBOR to get roots 396 + let header: Ipld = serde_ipld_dagcbor::from_slice(&data[pos..header_end]).unwrap_or_else(|e| { 397 + eprintln!("error: failed to decode CAR header: {e}"); 398 + std::process::exit(1); 399 + }); 400 + let roots = match &header { 401 + Ipld::Map(m) => match m.get("roots") { 402 + Some(Ipld::List(roots)) => roots 403 + .iter() 404 + .filter_map(|r| match r { 405 + Ipld::Link(cid) => Some(cid.to_bytes()), 406 + _ => None, 407 + }) 408 + .collect(), 409 + _ => vec![], 410 + }, 411 + _ => vec![], 412 + }; 413 + 414 + pos = header_end; 415 + 416 + // blocks — hash map keyed by CID bytes for O(1) lookup 417 + let mut block_map = BlockMap::new(); 418 + let mut block_count = 0; 419 + while pos < data.len() { 420 + let block_len = read_uvarint(data, &mut pos); 421 + let block_end = pos + block_len; 422 + if block_end > data.len() { 423 + eprintln!("error: truncated CAR block"); 424 + std::process::exit(1); 425 + } 426 + 427 + let block_data = &data[pos..block_end]; 428 + let cid_len = cid_length(block_data); 429 + if cid_len > block_data.len() { 430 + eprintln!("error: CID extends beyond block"); 431 + std::process::exit(1); 432 + } 433 + 434 + let cid_bytes = block_data[..cid_len].to_vec(); 435 + let content = &block_data[cid_len..]; 436 + 437 + // verify SHA-256 hash 438 + if let Some(expected_digest) = extract_sha256_digest(&cid_bytes) { 439 + let mut hasher = Sha256::new(); 440 + hasher.update(content); 441 + let computed: [u8; 32] = hasher.finalize().into(); 442 + if computed != expected_digest { 443 + eprintln!("error: CID hash mismatch"); 444 + std::process::exit(1); 445 + } 446 + } 447 + 448 + block_map.insert(cid_bytes, content.to_vec()); 449 + block_count += 1; 450 + 451 + pos = block_end; 452 + } 453 + 454 + (roots, block_map, block_count) 455 + } 456 + 457 + fn read_uvarint(data: &[u8], pos: &mut usize) -> usize { 458 + let mut result: u64 = 0; 459 + let mut shift = 0u32; 460 + loop { 461 + if *pos >= data.len() { 462 + eprintln!("error: truncated uvarint"); 463 + std::process::exit(1); 464 + } 465 + let b = data[*pos]; 466 + *pos += 1; 467 + result |= ((b & 0x7f) as u64) << shift; 468 + if b & 0x80 == 0 { 469 + break; 470 + } 471 + shift += 7; 472 + } 473 + result as usize 474 + } 475 + 476 + fn cid_length(data: &[u8]) -> usize { 477 + if data.len() >= 2 && data[0] == 0x12 && data[1] == 0x20 { 478 + return 34; // CIDv0 479 + } 480 + // CIDv1: version + codec + hash_fn + digest_len + digest 481 + let mut pos = 0; 482 + let _ = read_uvarint_at(data, &mut pos); // version 483 + let _ = read_uvarint_at(data, &mut pos); // codec 484 + let _ = read_uvarint_at(data, &mut pos); // hash_fn 485 + let digest_len = read_uvarint_at(data, &mut pos); // digest_len 486 + pos + digest_len 487 + } 488 + 489 + fn read_uvarint_at(data: &[u8], pos: &mut usize) -> usize { 490 + let mut result: u64 = 0; 491 + let mut shift = 0u32; 492 + loop { 493 + if *pos >= data.len() { 494 + return 0; 495 + } 496 + let b = data[*pos]; 497 + *pos += 1; 498 + result |= ((b & 0x7f) as u64) << shift; 499 + if b & 0x80 == 0 { 500 + break; 501 + } 502 + shift += 7; 503 + } 504 + result as usize 505 + } 506 + 507 + fn extract_sha256_digest(cid_bytes: &[u8]) -> Option<[u8; 32]> { 508 + // CIDv0: 0x12 0x20 <32 bytes> 509 + if cid_bytes.len() == 34 && cid_bytes[0] == 0x12 && cid_bytes[1] == 0x20 { 510 + let mut digest = [0u8; 32]; 511 + digest.copy_from_slice(&cid_bytes[2..34]); 512 + return Some(digest); 513 + } 514 + // CIDv1: skip version + codec, then check hash_fn == 0x12, digest_len == 0x20 515 + let mut pos = 0; 516 + let _ = read_uvarint_at(cid_bytes, &mut pos); // version 517 + let _ = read_uvarint_at(cid_bytes, &mut pos); // codec 518 + let hash_fn = read_uvarint_at(cid_bytes, &mut pos); 519 + let digest_len = read_uvarint_at(cid_bytes, &mut pos); 520 + if hash_fn == 0x12 && digest_len == 32 && pos + 32 <= cid_bytes.len() { 521 + let mut digest = [0u8; 32]; 522 + digest.copy_from_slice(&cid_bytes[pos..pos + 32]); 523 + Some(digest) 524 + } else { 525 + None 526 + } 527 + } 528 + 529 + fn find_block<'a>(block_map: &'a BlockMap, cid_bytes: &[u8]) -> Option<&'a [u8]> { 530 + block_map.get(cid_bytes).map(|v| v.as_slice()) 531 + } 532 + 533 + // --- MST walker --- 534 + 535 + fn walk_mst(block_map: &BlockMap, node_cid_bytes: &[u8]) -> usize { 536 + let block_data = match find_block(block_map, node_cid_bytes) { 537 + Some(d) => d, 538 + None => return 0, 539 + }; 540 + 541 + let node: Ipld = match serde_ipld_dagcbor::from_slice(block_data) { 542 + Ok(n) => n, 543 + Err(_) => return 0, 544 + }; 545 + 546 + let node_map = match &node { 547 + Ipld::Map(m) => m, 548 + _ => return 0, 549 + }; 550 + 551 + let mut count = 0; 552 + 553 + // walk left subtree 554 + if let Some(Ipld::Link(left_cid)) = node_map.get("l") { 555 + count += walk_mst(block_map, &left_cid.to_bytes()); 556 + } 557 + 558 + // walk entries 559 + if let Some(Ipld::List(entries)) = node_map.get("e") { 560 + for entry in entries { 561 + if let Ipld::Map(entry_map) = entry { 562 + // count this record (has a value CID) 563 + if entry_map.contains_key("v") { 564 + count += 1; 565 + } 566 + // walk right subtree 567 + if let Some(Ipld::Link(tree_cid)) = entry_map.get("t") { 568 + count += walk_mst(block_map, &tree_cid.to_bytes()); 569 + } 570 + } 571 + } 572 + } 573 + 574 + count 575 + } 576 + 577 + // --- formatting --- 578 + 579 + fn print_padded(desc: &str, d: std::time::Duration) { 580 + let ms = d.as_nanos() as f64 / 1_000_000.0; 581 + let pad = if desc.len() < 50 { 50 - desc.len() } else { 1 }; 582 + println!("{desc}{:>pad$}{ms:.1}ms", ""); 583 + } 584 + 585 + fn fmt_duration(d: std::time::Duration) -> String { 586 + let ms = d.as_nanos() as f64 / 1_000_000.0; 587 + if ms >= 1000.0 { 588 + format!("{:.1}s", ms / 1000.0) 589 + } else { 590 + format!("{ms:.1}ms") 591 + } 592 + } 593 + 594 + fn fmt_size(n: usize) -> String { 595 + let v = n as f64; 596 + if v >= 1024.0 * 1024.0 { 597 + format!("{:.1} MB", v / (1024.0 * 1024.0)) 598 + } else { 599 + format!("{:.1} KB", v / 1024.0) 600 + } 601 + }
+349
scripts/verify_chart.py
··· 1 + #!/usr/bin/env python3 2 + # /// script 3 + # requires-python = ">=3.11" 4 + # dependencies = ["plotext"] 5 + # /// 6 + """generate verify timing charts from `just verify` output. 7 + 8 + produces two SVGs: 9 + verify-compute.svg — compute-only breakdown (the interesting part) 10 + verify-total.svg — full timeline including network 11 + 12 + usage: 13 + just verify pfrazee.com 2>&1 | uv run scripts/verify_chart.py 14 + just verify pfrazee.com 2>&1 | uv run scripts/verify_chart.py --dir charts/ 15 + """ 16 + 17 + import re 18 + import sys 19 + from dataclasses import dataclass, field 20 + from pathlib import Path 21 + 22 + import plotext as plt 23 + 24 + 25 + @dataclass 26 + class VerifyResult: 27 + name: str 28 + handle_ms: float = 0 29 + did_ms: float = 0 30 + fetch_ms: float = 0 31 + car_ms: float = 0 32 + sig_ms: float = 0 33 + walk_ms: float = 0 34 + rebuild_ms: float = 0 35 + total_ms: float = 0 36 + record_count: int = 0 37 + block_count: int = 0 38 + 39 + @property 40 + def network_ms(self) -> float: 41 + return self.handle_ms + self.did_ms + self.fetch_ms 42 + 43 + @property 44 + def compute_ms(self) -> float: 45 + return self.car_ms + self.sig_ms + self.walk_ms + self.rebuild_ms 46 + 47 + 48 + def parse_output(text: str) -> list[VerifyResult]: 49 + results = [] 50 + current = None 51 + 52 + for line in text.splitlines(): 53 + if "=== zat:" in line: 54 + current = VerifyResult(name="zig (zat)") 55 + elif "=== go" in line: 56 + current = VerifyResult(name="go (indigo)") 57 + elif "=== rust" in line: 58 + current = VerifyResult(name="rust (RustCrypto)") 59 + 60 + if current is None: 61 + continue 62 + 63 + # extract trailing timing value 64 + m = re.search(r"(\d+\.?\d*)\s*ms\s*$", line) 65 + if not m: 66 + m = re.search(r"(\d+\.?\d*)\s*s\s*$", line) 67 + if m: 68 + ms = float(m.group(1)) * 1000 69 + else: 70 + ms = None 71 + else: 72 + ms = float(m.group(1)) 73 + 74 + if ms is not None: 75 + if "handle" in line.lower() or ("→ did:" in line and "DID doc" not in line): 76 + if current.handle_ms == 0: 77 + current.handle_ms = ms 78 + elif "signing key" in line: 79 + current.did_ms = ms 80 + elif "CAR" in line and ("parse" in line or "load" in line): 81 + current.car_ms = ms 82 + elif ("CAR" in line and "MB" in line) or ("CAR" in line and "KB" in line): 83 + current.fetch_ms = ms 84 + elif "signature" in line.lower() or "VERIFIED" in line: 85 + current.sig_ms = ms 86 + elif "walk" in line.lower(): 87 + current.walk_ms = ms 88 + rc = re.search(r"(\d+)\s+records", line) 89 + if rc: 90 + current.record_count = int(rc.group(1)) 91 + elif "rebuild" in line.lower() or "root CID" in line: 92 + current.rebuild_ms = ms 93 + 94 + # total line 95 + tm = re.match( 96 + r"total\s+(\d+\.?\d*)(ms|s)\s+\(network:\s+(\d+\.?\d*)(ms|s),\s+compute:\s+(\d+\.?\d*)(ms|s)\)", 97 + line.strip(), 98 + ) 99 + if tm: 100 + current.total_ms = float(tm.group(1)) * (1000 if tm.group(2) == "s" else 1) 101 + results.append(current) 102 + current = None 103 + 104 + bc = re.search(r"(\d+)\s+blocks", line) 105 + if bc and current: 106 + current.block_count = int(bc.group(1)) 107 + 108 + return results 109 + 110 + 111 + def show_terminal(results: list[VerifyResult]) -> None: 112 + """plotext chart in terminal.""" 113 + names = [r.name for r in results] 114 + compute = [r.compute_ms for r in results] 115 + 116 + plt.clear_figure() 117 + plt.theme("dark") 118 + plt.title("compute breakdown (ms)") 119 + plt.bar(names, compute, color="orange", orientation="h") 120 + plt.xlabel("time (ms)") 121 + plt.plotsize(80, max(10, len(results) * 3 + 4)) 122 + plt.show() 123 + print() 124 + 125 + for r in results: 126 + print( 127 + f" {r.name:<20s}" 128 + f" car={r.car_ms:>6.1f}ms" 129 + f" sig={r.sig_ms:>5.1f}ms" 130 + f" walk={r.walk_ms:>6.1f}ms" 131 + f" rebuild={r.rebuild_ms:>6.1f}ms" 132 + f" total={r.compute_ms:>7.1f}ms" 133 + f" (network={r.network_ms:>8.0f}ms)" 134 + ) 135 + print() 136 + 137 + 138 + # --- SVG --- 139 + 140 + COLORS = { 141 + "handle": "#6ea8d9", 142 + "DID doc": "#5b9bd5", 143 + "fetch": "#4472c4", 144 + "CAR parse": "#e8944a", 145 + "sig verify": "#ed7d31", 146 + "MST walk": "#c55a11", 147 + "MST rebuild": "#a04000", 148 + } 149 + 150 + 151 + def generate_svg( 152 + results: list[VerifyResult], 153 + path: str, 154 + title: str, 155 + segments_fn, 156 + subtitle: str = "", 157 + ) -> None: 158 + bar_h = 38 159 + bar_gap = 20 160 + left_margin = 160 161 + right_margin = 110 162 + top_margin = 55 if subtitle else 45 163 + bottom_margin = 58 164 + chart_w = 520 165 + 166 + n = len(results) 167 + chart_h = n * (bar_h + bar_gap) - bar_gap 168 + w = left_margin + chart_w + right_margin 169 + h = top_margin + chart_h + bottom_margin 170 + 171 + all_segments = [segments_fn(r) for r in results] 172 + max_ms = max(sum(ms for _, ms in segs) for segs in all_segments) 173 + if max_ms == 0: 174 + max_ms = 1 175 + 176 + lines = [] 177 + lines.append( 178 + f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {w} {h}"' 179 + f" font-family=\"'SF Mono', 'Fira Code', 'Cascadia Code', Menlo, monospace\">" 180 + ) 181 + lines.append(f'<rect width="{w}" height="{h}" fill="#1a1a2e" rx="8"/>') 182 + 183 + # title 184 + lines.append( 185 + f'<text x="{w / 2}" y="28" text-anchor="middle" fill="#e0e0e0"' 186 + f' font-size="15" font-weight="600">{title}</text>' 187 + ) 188 + if subtitle: 189 + lines.append( 190 + f'<text x="{w / 2}" y="44" text-anchor="middle" fill="#666"' 191 + f' font-size="11">{subtitle}</text>' 192 + ) 193 + 194 + # gridlines 195 + tick_count = 5 196 + for i in range(tick_count + 1): 197 + x = left_margin + chart_w * i / tick_count 198 + lines.append( 199 + f'<line x1="{x:.1f}" y1="{top_margin - 2}"' 200 + f' x2="{x:.1f}" y2="{top_margin + chart_h + 2}"' 201 + f' stroke="#262640" stroke-width="1"/>' 202 + ) 203 + 204 + # bars 205 + for i, (r, segs) in enumerate(zip(results, all_segments)): 206 + y = top_margin + i * (bar_h + bar_gap) 207 + 208 + # label 209 + lines.append( 210 + f'<text x="{left_margin - 14}" y="{y + bar_h / 2 + 5}"' 211 + f' text-anchor="end" fill="#c0c0c0" font-size="13">{r.name}</text>' 212 + ) 213 + 214 + # stacked segments 215 + x = left_margin 216 + for label, ms in segs: 217 + if ms <= 0: 218 + continue 219 + seg_w = max(1, ms / max_ms * chart_w) 220 + color = COLORS.get(label, "#888") 221 + lines.append( 222 + f'<rect x="{x:.1f}" y="{y}" width="{seg_w:.1f}"' 223 + f' height="{bar_h}" fill="{color}" rx="3"/>' 224 + ) 225 + if seg_w > 55: 226 + lines.append( 227 + f'<text x="{x + seg_w / 2:.1f}" y="{y + bar_h / 2 + 4}"' 228 + f' text-anchor="middle" fill="white" font-size="10"' 229 + f' font-weight="500">{label}</text>' 230 + ) 231 + x += seg_w 232 + 233 + # total label 234 + total = sum(ms for _, ms in segs) 235 + lines.append( 236 + f'<text x="{x + 10:.1f}" y="{y + bar_h / 2 + 5}"' 237 + f' fill="#a0a0a0" font-size="12" font-weight="500">{format_ms(total)}</text>' 238 + ) 239 + 240 + # x-axis 241 + axis_y = top_margin + chart_h + 18 242 + for i in range(tick_count + 1): 243 + ms = max_ms * i / tick_count 244 + x = left_margin + chart_w * i / tick_count 245 + lines.append( 246 + f'<text x="{x:.1f}" y="{axis_y}" text-anchor="middle"' 247 + f' fill="#606060" font-size="10">{format_ms(ms)}</text>' 248 + ) 249 + 250 + # legend 251 + legend_y = top_margin + chart_h + 40 252 + used_labels = set() 253 + for segs in all_segments: 254 + for label, ms in segs: 255 + if ms > 0: 256 + used_labels.add(label) 257 + 258 + lx = left_margin 259 + for label in ["handle", "DID doc", "fetch", "CAR parse", "sig verify", "MST walk", "MST rebuild"]: 260 + if label not in used_labels: 261 + continue 262 + color = COLORS[label] 263 + lines.append( 264 + f'<rect x="{lx:.0f}" y="{legend_y - 8}" width="10" height="10"' 265 + f' fill="{color}" rx="2"/>' 266 + ) 267 + lx += 14 268 + lines.append( 269 + f'<text x="{lx:.0f}" y="{legend_y}" fill="#808080" font-size="10">{label}</text>' 270 + ) 271 + lx += len(label) * 6.2 + 12 272 + 273 + lines.append("</svg>") 274 + Path(path).write_text("\n".join(lines)) 275 + print(f" saved: {path}") 276 + 277 + 278 + def format_ms(ms: float) -> str: 279 + if ms == 0: 280 + return "0" 281 + if ms >= 1000: 282 + return f"{ms / 1000:.1f}s" 283 + if ms >= 1: 284 + return f"{ms:.0f}ms" 285 + return f"{ms:.1f}ms" 286 + 287 + 288 + def compute_segments(r: VerifyResult): 289 + return [ 290 + ("CAR parse", r.car_ms), 291 + ("sig verify", r.sig_ms), 292 + ("MST walk", r.walk_ms), 293 + ("MST rebuild", r.rebuild_ms), 294 + ] 295 + 296 + 297 + def total_segments(r: VerifyResult): 298 + return [ 299 + ("handle", r.handle_ms), 300 + ("DID doc", r.did_ms), 301 + ("fetch", r.fetch_ms), 302 + ("CAR parse", r.car_ms), 303 + ("sig verify", r.sig_ms), 304 + ("MST walk", r.walk_ms), 305 + ("MST rebuild", r.rebuild_ms), 306 + ] 307 + 308 + 309 + def main() -> None: 310 + import argparse 311 + 312 + parser = argparse.ArgumentParser(description="chart verify output") 313 + parser.add_argument("--dir", default=".", help="output directory for SVGs") 314 + args = parser.parse_args() 315 + 316 + text = sys.stdin.read() 317 + results = parse_output(text) 318 + 319 + if not results: 320 + print("error: no verify results found in input") 321 + print("usage: just verify pfrazee.com 2>&1 | uv run scripts/verify_chart.py") 322 + sys.exit(1) 323 + 324 + show_terminal(results) 325 + 326 + out = Path(args.dir) 327 + out.mkdir(parents=True, exist_ok=True) 328 + 329 + records = results[0].record_count 330 + subtitle = f"{records:,} records" if records else "" 331 + 332 + generate_svg( 333 + results, 334 + str(out / "verify-compute.svg"), 335 + "AT Protocol trust chain — compute", 336 + compute_segments, 337 + subtitle=subtitle, 338 + ) 339 + generate_svg( 340 + results, 341 + str(out / "verify-total.svg"), 342 + "AT Protocol trust chain — total (network + compute)", 343 + total_segments, 344 + subtitle=subtitle, 345 + ) 346 + 347 + 348 + if __name__ == "__main__": 349 + main()
+17
zig/build.zig
··· 70 70 const capture_sigs_step = b.step("run-capture-sigs", "capture sig verify corpus from live network"); 71 71 capture_sigs_step.dependOn(&run_capture_sigs.step); 72 72 73 + // verify — live trust chain demo with timing 74 + const verify = b.addExecutable(.{ 75 + .name = "verify", 76 + .root_module = b.createModule(.{ 77 + .root_source_file = b.path("src/verify.zig"), 78 + .target = target, 79 + .optimize = optimize, 80 + .imports = &.{.{ .name = "zat", .module = zat_mod }}, 81 + }), 82 + }); 83 + b.installArtifact(verify); 84 + 85 + const run_verify = b.addRunArtifact(verify); 86 + if (b.args) |a| run_verify.addArgs(a); 87 + const verify_step = b.step("run-verify", "run full AT Protocol trust chain verification"); 88 + verify_step.dependOn(&run_verify.step); 89 + 73 90 // k256 — optimized secp256k1 verification 74 91 const k256_mod = b.dependency("k256", .{ 75 92 .target = target,
+484
zig/src/verify.zig
··· 1 + const std = @import("std"); 2 + const zat = @import("zat"); 3 + 4 + const Allocator = std.mem.Allocator; 5 + const crypto = std.crypto; 6 + 7 + pub fn main() !void { 8 + var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init; 9 + defer _ = gpa.deinit(); 10 + const allocator = gpa.allocator(); 11 + 12 + const args = try std.process.argsAlloc(allocator); 13 + defer std.process.argsFree(allocator, args); 14 + 15 + if (args.len < 2) { 16 + std.debug.print("usage: verify <handle-or-did>\n", .{}); 17 + std.process.exit(1); 18 + } 19 + 20 + const identifier = args[1]; 21 + const p = std.debug.print; 22 + p("\n=== zat: full AT Protocol trust chain ===\n\n", .{}); 23 + 24 + var total_timer = try std.time.Timer.start(); 25 + 26 + var arena = std.heap.ArenaAllocator.init(allocator); 27 + defer arena.deinit(); 28 + const alloc = arena.allocator(); 29 + 30 + // --- step 1: resolve identifier to DID --- 31 + var step_timer = try std.time.Timer.start(); 32 + 33 + const is_did = zat.Did.parse(identifier) != null; 34 + const did_str = if (is_did) 35 + identifier 36 + else blk: { 37 + const handle = zat.Handle.parse(identifier) orelse { 38 + std.debug.print("error: invalid handle or DID: {s}\n", .{identifier}); 39 + std.process.exit(1); 40 + }; 41 + var resolver = zat.HandleResolver.init(alloc); 42 + defer resolver.deinit(); 43 + break :blk try resolver.resolve(handle); 44 + }; 45 + 46 + var handle_ms = step_timer.read(); 47 + 48 + if (is_did) { 49 + p("DID {s}\n", .{identifier}); 50 + handle_ms = 0; 51 + } else { 52 + p("handle {s}\n", .{identifier}); 53 + p(" → {s}", .{did_str}); 54 + printPadded(4 + did_str.len, handle_ms); 55 + } 56 + 57 + // --- step 2: resolve DID document --- 58 + step_timer = try std.time.Timer.start(); 59 + 60 + const did = zat.Did.parse(did_str) orelse { 61 + std.debug.print("error: invalid DID: {s}\n", .{did_str}); 62 + std.process.exit(1); 63 + }; 64 + 65 + var did_resolver = zat.DidResolver.init(alloc); 66 + defer did_resolver.deinit(); 67 + var did_doc = try did_resolver.resolve(did); 68 + defer did_doc.deinit(); 69 + 70 + const signing_vm = did_doc.signingKey() orelse { 71 + std.debug.print("error: no signing key in DID document\n", .{}); 72 + std.process.exit(1); 73 + }; 74 + 75 + const key_bytes = try zat.multibase.decode(alloc, signing_vm.public_key_multibase); 76 + const public_key = try zat.multicodec.parsePublicKey(key_bytes); 77 + 78 + const pds_endpoint = did_doc.pdsEndpoint() orelse { 79 + std.debug.print("error: no PDS endpoint in DID document\n", .{}); 80 + std.process.exit(1); 81 + }; 82 + 83 + const did_ns = step_timer.read(); 84 + const key_type_str: []const u8 = switch (public_key.key_type) { 85 + .secp256k1 => "secp256k1", 86 + .p256 => "p256", 87 + }; 88 + 89 + p("\nDID doc {s}\n", .{did_str}); 90 + { 91 + var buf: [80]u8 = undefined; 92 + const desc = std.fmt.bufPrint(&buf, " → signing key: {s} (compressed, {d} bytes)", .{ key_type_str, public_key.raw.len }) catch ""; 93 + p("{s}", .{desc}); 94 + printPadded(desc.len, did_ns); 95 + } 96 + p(" → PDS: {s}\n", .{pds_endpoint}); 97 + 98 + // --- step 3: fetch repo CAR --- 99 + step_timer = try std.time.Timer.start(); 100 + 101 + const url = try std.fmt.allocPrint(alloc, "{s}/xrpc/com.atproto.sync.getRepo?did={s}", .{ pds_endpoint, did_str }); 102 + 103 + var http_client: std.http.Client = .{ .allocator = alloc }; 104 + defer http_client.deinit(); 105 + 106 + var aw: std.Io.Writer.Allocating = .init(alloc); 107 + 108 + const result = http_client.fetch(.{ 109 + .location = .{ .url = url }, 110 + .response_writer = &aw.writer, 111 + .headers = .{ .accept_encoding = .{ .override = "identity" } }, 112 + }) catch { 113 + std.debug.print("error: failed to fetch repo from {s}\n", .{pds_endpoint}); 114 + std.process.exit(1); 115 + }; 116 + 117 + if (result.status != .ok) { 118 + std.debug.print("error: PDS returned HTTP {d}\n", .{@intFromEnum(result.status)}); 119 + std.process.exit(1); 120 + } 121 + 122 + const car_bytes = aw.toArrayList().items; 123 + const fetch_ns = step_timer.read(); 124 + 125 + p("\nrepo com.atproto.sync.getRepo\n", .{}); 126 + { 127 + var buf: [80]u8 = undefined; 128 + const desc = std.fmt.bufPrint(&buf, " → {s} CAR", .{trimFmt(&fmtSize(car_bytes.len))}) catch ""; 129 + p("{s}", .{desc}); 130 + printPadded(desc.len, fetch_ns); 131 + } 132 + 133 + // --- step 4: parse CAR (inline parser — no size limits for full repos) --- 134 + step_timer = try std.time.Timer.start(); 135 + 136 + const repo_car = parseCar(alloc, car_bytes) catch { 137 + std.debug.print("error: failed to parse CAR\n", .{}); 138 + std.process.exit(1); 139 + }; 140 + 141 + if (repo_car.roots.len == 0) { 142 + std.debug.print("error: no roots in CAR\n", .{}); 143 + std.process.exit(1); 144 + } 145 + 146 + const car_ns = step_timer.read(); 147 + 148 + // --- step 5: find + decode commit --- 149 + const commit_data = findBlock(repo_car.block_map, repo_car.roots[0].raw) orelse { 150 + std.debug.print("error: commit block not found\n", .{}); 151 + std.process.exit(1); 152 + }; 153 + 154 + const commit = zat.cbor.decodeAll(alloc, commit_data) catch { 155 + std.debug.print("error: failed to decode commit\n", .{}); 156 + std.process.exit(1); 157 + }; 158 + 159 + const commit_rev = commit.getString("rev") orelse "???"; 160 + const sig_bytes = commit.getBytes("sig") orelse { 161 + std.debug.print("error: no signature in commit\n", .{}); 162 + std.process.exit(1); 163 + }; 164 + 165 + const data_cid = switch (commit.get("data") orelse { 166 + std.debug.print("error: no data CID in commit\n", .{}); 167 + std.process.exit(1); 168 + }) { 169 + .cid => |c| c, 170 + else => { 171 + std.debug.print("error: data field is not a CID\n", .{}); 172 + std.process.exit(1); 173 + }, 174 + }; 175 + 176 + // --- step 6: verify signature --- 177 + step_timer = try std.time.Timer.start(); 178 + 179 + const unsigned_commit_bytes = try encodeUnsignedCommit(alloc, commit); 180 + try verifySig(public_key.key_type, unsigned_commit_bytes, sig_bytes, public_key.raw); 181 + 182 + const sig_ns = step_timer.read(); 183 + 184 + // --- step 7: walk MST --- 185 + step_timer = try std.time.Timer.start(); 186 + 187 + var records: std.ArrayList(MstRecord) = .{}; 188 + try walkMst(alloc, repo_car.block_map, data_cid.raw, &records); 189 + 190 + const walk_ns = step_timer.read(); 191 + 192 + // --- step 8: rebuild MST + verify root CID --- 193 + step_timer = try std.time.Timer.start(); 194 + 195 + var tree = zat.mst.Mst.init(alloc); 196 + for (records.items) |record| { 197 + try tree.put(record.key, record.value); 198 + } 199 + const rebuilt_root = try tree.rootCid(); 200 + 201 + const rebuild_ns = step_timer.read(); 202 + const cid_match = std.mem.eql(u8, rebuilt_root.raw, data_cid.raw); 203 + 204 + // --- output --- 205 + const rev_short = if (commit_rev.len > 6) commit_rev[0..6] else commit_rev; 206 + 207 + p("\nverify commit rev={s}...\n", .{rev_short}); 208 + { 209 + var buf: [80]u8 = undefined; 210 + const desc = std.fmt.bufPrint(&buf, " → CAR parse ({d} blocks, CID verified)", .{repo_car.block_count}) catch ""; 211 + p("{s}", .{desc}); 212 + printPadded(desc.len, car_ns); 213 + } 214 + { 215 + var buf: [80]u8 = undefined; 216 + const desc = std.fmt.bufPrint(&buf, " → commit signature VERIFIED ({s})", .{key_type_str}) catch ""; 217 + p("{s}", .{desc}); 218 + printPadded(desc.len, sig_ns); 219 + } 220 + { 221 + var buf: [80]u8 = undefined; 222 + const desc = std.fmt.bufPrint(&buf, " → MST walk: {d} records", .{records.items.len}) catch ""; 223 + p("{s}", .{desc}); 224 + printPadded(desc.len, walk_ns); 225 + } 226 + if (cid_match) { 227 + const desc = " → MST rebuild + root CID match"; 228 + p("{s}", .{desc}); 229 + printPadded(desc.len, rebuild_ns); 230 + } else { 231 + p(" → MST rebuild + root CID MISMATCH!\n", .{}); 232 + } 233 + 234 + const total_ns = total_timer.read(); 235 + const network_ns = handle_ms + did_ns + fetch_ns; 236 + const compute_ns = car_ns + sig_ns + walk_ns + rebuild_ns; 237 + 238 + p("\ntotal {s} (network: {s}, compute: {s})\n\n", .{ 239 + trimFmt(&fmtNs(total_ns)), 240 + trimFmt(&fmtNs(network_ns)), 241 + trimFmt(&fmtNs(compute_ns)), 242 + }); 243 + } 244 + 245 + // --- helpers --- 246 + 247 + const MstRecord = struct { 248 + key: []const u8, 249 + value: zat.cbor.Cid, 250 + }; 251 + 252 + fn encodeUnsignedCommit(allocator: Allocator, commit: zat.cbor.Value) ![]u8 { 253 + const entries = switch (commit) { 254 + .map => |m| m, 255 + else => return error.InvalidCommit, 256 + }; 257 + 258 + var unsigned_entries: std.ArrayList(zat.cbor.Value.MapEntry) = .{}; 259 + for (entries) |entry| { 260 + if (!std.mem.eql(u8, entry.key, "sig")) { 261 + try unsigned_entries.append(allocator, entry); 262 + } 263 + } 264 + 265 + const unsigned_value: zat.cbor.Value = .{ .map = unsigned_entries.items }; 266 + return zat.cbor.encodeAlloc(allocator, unsigned_value); 267 + } 268 + 269 + fn walkMst(allocator: Allocator, block_map: BlockMap, node_cid_raw: []const u8, records: *std.ArrayList(MstRecord)) !void { 270 + const block_data = findBlock(block_map, node_cid_raw) orelse return; 271 + const node = zat.cbor.decodeAll(allocator, block_data) catch return; 272 + 273 + if (node.get("l")) |left_val| { 274 + switch (left_val) { 275 + .cid => |left_cid| try walkMst(allocator, block_map, left_cid.raw, records), 276 + else => {}, 277 + } 278 + } 279 + 280 + const entries_arr = node.getArray("e") orelse return; 281 + var prev_key: []const u8 = ""; 282 + 283 + for (entries_arr) |entry_val| { 284 + const p = entry_val.getInt("p") orelse continue; 285 + const prefix_len: usize = @intCast(p); 286 + const k = entry_val.getBytes("k") orelse continue; 287 + 288 + const full_key = try std.mem.concat(allocator, u8, &.{ prev_key[0..prefix_len], k }); 289 + prev_key = full_key; 290 + 291 + if (entry_val.get("v")) |v| { 292 + switch (v) { 293 + .cid => |value_cid| try records.append(allocator, .{ .key = full_key, .value = value_cid }), 294 + else => {}, 295 + } 296 + } 297 + 298 + if (entry_val.get("t")) |t| { 299 + switch (t) { 300 + .cid => |tree_cid| try walkMst(allocator, block_map, tree_cid.raw, records), 301 + else => {}, 302 + } 303 + } 304 + } 305 + } 306 + 307 + // --- inline CAR parser (no size limits, for full-repo downloads) --- 308 + 309 + const BlockMap = std.StringHashMapUnmanaged([]const u8); 310 + 311 + const CarResult = struct { 312 + roots: []const zat.cbor.Cid, 313 + block_map: BlockMap, 314 + block_count: usize, 315 + }; 316 + 317 + fn parseCar(allocator: Allocator, data: []const u8) !CarResult { 318 + var pos: usize = 0; 319 + 320 + // header 321 + const header_len = zat.cbor.readUvarint(data, &pos) orelse return error.InvalidCar; 322 + const header_len_usize = std.math.cast(usize, header_len) orelse return error.InvalidCar; 323 + const header_end = pos + header_len_usize; 324 + if (header_end > data.len) return error.InvalidCar; 325 + 326 + const header = zat.cbor.decodeAll(allocator, data[pos..header_end]) catch return error.InvalidCar; 327 + 328 + var roots: std.ArrayList(zat.cbor.Cid) = .{}; 329 + if (header.getArray("roots")) |root_values| { 330 + for (root_values) |root_val| { 331 + switch (root_val) { 332 + .cid => |c| try roots.append(allocator, c), 333 + else => {}, 334 + } 335 + } 336 + } 337 + 338 + pos = header_end; 339 + 340 + // blocks — hash map keyed by CID bytes for O(1) lookup (like Go's TinyBlockstore) 341 + var block_map: BlockMap = .{}; 342 + var block_count: usize = 0; 343 + while (pos < data.len) { 344 + const block_len = zat.cbor.readUvarint(data, &pos) orelse return error.InvalidCar; 345 + const block_len_usize = std.math.cast(usize, block_len) orelse return error.InvalidCar; 346 + const block_end = pos + block_len_usize; 347 + if (block_end > data.len) return error.InvalidCar; 348 + 349 + const block_data = data[pos..block_end]; 350 + const cid_len = cidLength(block_data) orelse return error.InvalidCar; 351 + if (cid_len > block_data.len) return error.InvalidCar; 352 + 353 + // verify block hash (SHA-256) 354 + const cid = zat.cbor.Cid{ .raw = block_data[0..cid_len] }; 355 + const content = block_data[cid_len..]; 356 + if (cid.hashFn()) |hash_fn| { 357 + if (hash_fn == 0x12) { // sha2-256 358 + if (cid.digest()) |expected| { 359 + if (expected.len == 32) { 360 + const Sha256 = std.crypto.hash.sha2.Sha256; 361 + var computed: [Sha256.digest_length]u8 = undefined; 362 + Sha256.hash(content, &computed, .{}); 363 + if (!std.mem.eql(u8, &computed, expected)) return error.InvalidCar; 364 + } 365 + } 366 + } 367 + } 368 + 369 + try block_map.put(allocator, block_data[0..cid_len], content); 370 + block_count += 1; 371 + 372 + pos = block_end; 373 + } 374 + 375 + return .{ 376 + .roots = try roots.toOwnedSlice(allocator), 377 + .block_map = block_map, 378 + .block_count = block_count, 379 + }; 380 + } 381 + 382 + fn cidLength(data: []const u8) ?usize { 383 + if (data.len < 2) return null; 384 + // CIDv0: starts with 0x12 0x20 (sha2-256, 32 byte digest) 385 + if (data[0] == 0x12 and data[1] == 0x20) return 34; 386 + // CIDv1: version + codec + hash_fn + digest_len + digest 387 + var pos: usize = 0; 388 + _ = zat.cbor.readUvarint(data, &pos) orelse return null; 389 + _ = zat.cbor.readUvarint(data, &pos) orelse return null; 390 + _ = zat.cbor.readUvarint(data, &pos) orelse return null; 391 + const digest_len = zat.cbor.readUvarint(data, &pos) orelse return null; 392 + const digest_len_usize = std.math.cast(usize, digest_len) orelse return null; 393 + return pos + digest_len_usize; 394 + } 395 + 396 + fn findBlock(block_map: BlockMap, cid_raw: []const u8) ?[]const u8 { 397 + return block_map.get(cid_raw); 398 + } 399 + 400 + /// verify ECDSA signature with low-S rejection (matches zat's jwt.verifySecp256k1/verifyP256) 401 + fn verifySig(key_type: zat.multicodec.KeyType, message: []const u8, sig_bytes: []const u8, public_key_raw: []const u8) !void { 402 + if (sig_bytes.len != 64) return error.InvalidSignature; 403 + if (public_key_raw.len != 33) return error.InvalidPublicKey; 404 + 405 + switch (key_type) { 406 + .secp256k1 => { 407 + const Scheme = crypto.sign.ecdsa.EcdsaSecp256k1Sha256; 408 + const sig = Scheme.Signature.fromBytes(sig_bytes[0..64].*); 409 + // reject high-S (secp256k1 order/2) 410 + const half_order: [32]u8 = .{ 411 + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 412 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 413 + 0x5D, 0x57, 0x6E, 0x73, 0x57, 0xA4, 0x50, 0x1D, 414 + 0xDF, 0xE9, 0x2F, 0x46, 0x68, 0x1B, 0x20, 0xA0, 415 + }; 416 + if (bigEndianGt(sig.s, half_order)) return error.SignatureVerificationFailed; 417 + const pk = Scheme.PublicKey.fromSec1(public_key_raw) catch return error.InvalidPublicKey; 418 + sig.verify(message, pk) catch return error.SignatureVerificationFailed; 419 + }, 420 + .p256 => { 421 + const Scheme = crypto.sign.ecdsa.EcdsaP256Sha256; 422 + const sig = Scheme.Signature.fromBytes(sig_bytes[0..64].*); 423 + const half_order: [32]u8 = .{ 424 + 0x7F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 425 + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 426 + 0xDE, 0x73, 0x7D, 0x56, 0xD3, 0x8B, 0xCF, 0x42, 427 + 0x79, 0xDC, 0xE5, 0x61, 0x7E, 0x31, 0x92, 0xA8, 428 + }; 429 + if (bigEndianGt(sig.s, half_order)) return error.SignatureVerificationFailed; 430 + const pk = Scheme.PublicKey.fromSec1(public_key_raw) catch return error.InvalidPublicKey; 431 + sig.verify(message, pk) catch return error.SignatureVerificationFailed; 432 + }, 433 + } 434 + } 435 + 436 + fn bigEndianGt(a: [32]u8, b: [32]u8) bool { 437 + for (a, b) |ab, bb| { 438 + if (ab > bb) return true; 439 + if (ab < bb) return false; 440 + } 441 + return false; 442 + } 443 + 444 + // --- formatting --- 445 + 446 + fn printPadded(desc_len: usize, ns: u64) void { 447 + const ms = @as(f64, @floatFromInt(ns)) / std.time.ns_per_ms; 448 + const col: usize = 50; 449 + if (desc_len < col) { 450 + var spaces: [64]u8 = undefined; 451 + const n = col - desc_len; 452 + @memset(spaces[0..n], ' '); 453 + std.debug.print("{s}{d:.1}ms\n", .{ spaces[0..n], ms }); 454 + } else { 455 + std.debug.print(" {d:.1}ms\n", .{ms}); 456 + } 457 + } 458 + 459 + fn trimFmt(buf: []const u8) []const u8 { 460 + var end = buf.len; 461 + while (end > 0 and (buf[end - 1] == ' ' or buf[end - 1] == 0)) end -= 1; 462 + return buf[0..end]; 463 + } 464 + 465 + fn fmtNs(ns: u64) FmsBuf { 466 + var buf: FmsBuf = undefined; 467 + const ms = @as(f64, @floatFromInt(ns)) / std.time.ns_per_ms; 468 + const slice = std.fmt.bufPrint(&buf, "{d:.1}ms", .{ms}) catch "???"; 469 + @memset(buf[slice.len..], ' '); 470 + return buf; 471 + } 472 + 473 + const FmsBuf = [16]u8; 474 + 475 + fn fmtSize(n: usize) [16]u8 { 476 + var buf: [16]u8 = undefined; 477 + const val = @as(f64, @floatFromInt(n)); 478 + const slice = if (val >= 1024.0 * 1024.0) 479 + std.fmt.bufPrint(&buf, "{d:.1} MB", .{val / (1024.0 * 1024.0)}) catch "???" 480 + else 481 + std.fmt.bufPrint(&buf, "{d:.1} KB", .{val / 1024.0}) catch "???"; 482 + @memset(buf[slice.len..], ' '); 483 + return buf; 484 + }