UHRP — Universal Hash Resolution Protocol
UHRP (BRC-26) enables content-addressed file storage on BSV. Files are identified and retrieved by their SHA-256 hash, not by path. A UHRP server stores files and publishes availability advertisements on the overlay network (
tm_uhrptopic). Clients discover storage locations and verify file integrity by hash.
At a glance
| Field | Value |
|---|---|
| Format | OpenAPI 3.1 |
| Version | 1.0.0 |
| Status | stable |
| Implementations | @bsv/overlay-topics (tm_uhrp topic manager) |
What problem this solves
Permanent, hash-addressed file storage. Traditional URLs break when servers move. UHRP uses SHA-256 hash as permanent file ID: uhrp://abc123... always refers to the same content. Any server can host the file; clients verify integrity by hashing the retrieved data.
Decentralized availability. Files are mirrored across multiple UHRP servers. Clients query the overlay network (ls_uhrp lookup service) to find all hosts with a given hash, then download from any available server. No single point of failure.
Peer discovery via overlay. UHRP servers publish availability advertisements to the overlay's tm_uhrp topic. These advertisements record file hash, size, expiry, and download URLs. The ls_uhrp lookup service indexes these advertisements, enabling instant discovery.
Protocol overview
Three-phase flow (upload → advertise → retrieve):
Phase 1 — Upload File
-
Client → UHRP Server
POST /upload- File binary data (raw bytes)
- Server computes SHA-256 hash
- Returns: UHRP URL (
uhrp://hash...) and metadata
-
UHRP Server stores file and generates advertisement
Phase 2 — Publish to Overlay
- UHRP Server → Overlay (via
POST /submit)- PushDrop transaction tagged with
tm_uhrptopic - Advertisement contains: hash, file size, download URL, expiry timestamp
- Overlay records admission;
ls_uhrplookup service indexes it
- PushDrop transaction tagged with
Phase 3 — Retrieve File
-
Client → Overlay
POST /lookup- Query:
{ service: "ls_uhrp", query: { hash: "abc123..." } } - Lookup service returns: array of servers hosting the file
- Query:
-
Client → UHRP Server
GET /{hash}- Downloads file from any available server
- Verifies SHA-256 matches requested hash
- Rejects file if hash doesn't match
Key types / endpoints
| Method | Path | Purpose | Request | Response |
|---|---|---|---|---|
| POST | /upload | Upload file | Binary file data | { hash, uhrpUrl, size, expiryTimestamp } |
| GET | /{hash} | Download file | (none) | Binary file data + Content-Hash header |
| HEAD | /{hash} | Check availability | (none) | 200 OK + Content-Hash header |
| GET | /info/{hash} | Get metadata | (none) | { hash, size, expiryTimestamp, hosts: [...] } |
Overlay integration:
tm_uhrptopic manager — Validates UHRP advertisementsls_uhrplookup service — Queries for files by hash; returns host list
Example: Upload and retrieve file
import { StorageUploader, StorageDownloader, WalletClient } from '@bsv/sdk'
// 1. Upload file to UHRP server
const wallet = new WalletClient('auto', 'example.com')
const uploader = new StorageUploader({
storageURL: 'https://uhrp-storage.example.com',
wallet
})
const file = new TextEncoder().encode('Hello, UHRP!')
const result = await uploader.publishFile({
file: { data: file, type: 'text/plain' },
retentionPeriod: 7
})
console.log('File stored at:', result.uhrpURL) // uhrp://abc123...
// 2. Publish advertisement to overlay (server does this automatically)
// UHRP server issues a PushDrop transaction to tm_uhrp topic
// 3. Retrieve file later (from any server)
const downloader = new StorageDownloader()
const retrieved = await downloader.download(result.uhrpURL)
// 4. StorageDownloader verifies the content hash before returning data
console.log(new TextDecoder().decode(retrieved.data))Example: Query overlay for file locations
import { LookupResolver } from '@bsv/sdk'
const lookupResolver = new LookupResolver({
hostOverrides: {
ls_uhrp: ['https://overlay.example.com']
}
})
// 1. Find all servers hosting a file
const locations = await lookupResolver.query({
service: 'ls_uhrp',
query: { uhrpUrl: 'uhrp://abc123...' }
})
if (locations.type !== 'output-list') {
throw new Error('UHRP lookup must return an output list')
}
// StorageDownloader resolves the same output list and decodes the
// hosted file URLs from the UHRP advertisement outputs.
console.log('Advertisement outputs:', locations.outputs)Conformance vectors
UHRP conformance is tested in conformance/vectors/storage/uhrp/:
- File upload and hash computation
- SHA-256 hash verification on download
- Advertisement publication and overlay indexing
- Lookup service correctness (returns all hosts for a hash)
- Expiry timestamp handling
Implementations in ts-stack
| Package | Notes |
|---|---|
| @bsv/overlay-topics | UHRPTopicManager (validates advertisements), createUHRPLookupService (indexes hashes) |
| @bsv/sdk | StorageUploader, StorageDownloader, and LookupResolver client classes |
Related specs
- Overlay HTTP — Overlay network where UHRP advertisements are published
- BRC-26 — Full UHRP specification