hashtree-resolver
Resolve mutable Nostr names (npub1…/tree-name) to immutable Hashtree Cids.
This discovers roots; your application's store/transport must fetch their blocks.
Install and resolve a root
The default crate provides the RootResolver trait. Enable nostr for the
Nostr implementation:
Save this as src/main.rs. Run cargo run -- 'npub1…/tree-name', substituting
an actual author and tree name. Select relays that carry the author's events.
This example is compiled as a doctest; it does not run against public relays.
use ;
async
resolve_wait() waits indefinitely; an application can cancel the future or
apply its own deadline, then call stop() when finished with the resolver.
resolve() instead returns Result<Option<Cid>, ResolverError> after a bounded
lookup. None means no usable root was found in that lookup, not proof that the
tree does not exist.
For live apps, use subscribe(key).await? and keep receiving with rx.recv().await.
Its initial None means no root is cached yet: keep the subscription open.
Updates may also be None when an event has no usable key. Drop the receiver when
the app no longer needs updates, and call stop() on application shutdown.
Pass the full tree name as the resolver key; tree names may themselves contain
slashes. Resolve paths inside the selected tree with HashTree::resolve_path().
For URL parsing, see URL encoding.
Publishing and visibility
Reading public roots needs no secret key. Set NostrResolverConfig::secret_key
to the owner's persisted Keys to publish or read that owner's private roots.
Upload/replicate the tree's blocks before announcing its root.
publish(key, &cid)exposes the CID's read key in a public event.publish_shared(key, &cid, &share_secret)masks the key for link holders; readers useresolve_shared(key, &share_secret).publish_private(key, &cid)encrypts the key to the owner.
The CID and sharing secret are read capabilities. Preserve them and only share with intended readers. A successful root announcement does not upload blocks.
Event Format
Trees are published as kind 30064 (parameterized replaceable with label). Readers also accept legacy kind 30078 roots for compatibility:
npub1abc.../treename/path/to/file.ext
│ │ │
│ │ └── Path within merkle tree (client-side traversal)
│ └── d-tag value (tree identifier)
└── Author pubkey (bech32 → hex for event)
Tags:
| Tag | Purpose |
|---|---|
d |
Tree name (replaceable event key) |
l |
"hashtree" label for discovery |
hash |
Merkle root SHA256 (64 hex chars) |
key |
Decryption key (public trees) |
encryptedKey |
XOR'd key (link-visible trees) |
selfEncryptedKey |
NIP-44 encrypted (private/link-visible) |
Visibility:
- Public: plaintext
keytag - Link-visible:
encryptedKey+ link key in share URL - Private: only
selfEncryptedKey(owner access)
API and verification
From rust/, run:
This guide is also the nostr module's generated documentation. The published
API follows the selected crate release.