Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

README.md

4.34 Kb · 87 lines

gno.land/p/moul/x/wesh/v0

The publishable half of the Wesh protocol (weshnet, the network behind Berty) as a pure gno library: Contact, WebLink, ParseWebLink, RendezvousPoint, SeedCommitment, BindStatement, DeviceStatement, VerifyBind, VerifyDevice, HMACSHA256.

1import "gno.land/p/moul/x/wesh/v0"
2
3c := wesh.Contact{AccountPK: pk, Seed: seed, DisplayName: "Alice"}
4link, _ := c.WebLink()   // https://berty.tech/id#contact/<base58>/name=Alice
5pt, _ := c.RendezvousPointAt(now, wesh.DefaultRotationInterval)

Why a chain at all

Wesh is off-grid, peer-to-peer and end-to-end encrypted. A public chain is the opposite in nearly every dimension, so this is deliberately not "weshnet on chain". It carries only the parts that need an authenticated, ordered, publicly auditable record, the one thing a peer-to-peer network cannot give itself, and which Wesh is missing in three specific places:

  • Identities do not resolve. A Berty ID travels out of band as a QR code or a https://berty.tech/id# link, and there is no lookup.
  • Seed resets are silent. ContactRequestResetReference gives the account a new rendezvous seed, which kills every link ever shared, with no channel to announce it.
  • Devices can never be revoked. The protocol documentation says so outright: the account metadata log is append-only and no authority can void an entry.

What is in here

piece what it is
Contact weshnet's ShareableContact: account key + public rendezvous seed + display name, with weshnet's own CheckFormat length rules
Blob, WebLink, ParseWebLink the Berty link codec, hand-rolled protobuf + base58
RendezvousPoint, RoundPeriod, NextPeriod weshnet's rotating DHT topic derivation
SeedCommitment, OpenCommitment publish H(seed ‖ salt) instead of the seed
BindStatement, DeviceStatement, VerifyBind, VerifyDevice the canonical texts an account signs, and their ed25519 verification
HMACSHA256 RFC 2104, because gno has sha256.Sum256 but no crypto/hmac

The link codec is conformance-tested, not guessed: TestBlobEncodingMatches BertyGoldenVector reproduces the exact base58 payload from berty's own links_test.go, byte for byte. The rendezvous derivation is pinned against vectors computed with weshnet's GenerateRendezvousPointForPeriod, and the HMAC against RFC 4231, including case 6, the longer-than-block-size key.

What is deliberately absent

There is no type here that can hold a secret. Group secrets, device chain keys, message keys and ciphertexts never touch a chain: publishing a group secret hands the group to everyone, and publishing ciphertext is permanent, expensive, and leaks the social graph through access patterns.

The privacy trade-off

Publishing a rendezvous seed is equivalent to printing your Berty QR code on a billboard: anyone can then derive today's rendezvous point and watch the DHT for it. That is the right trade only for an identity that wants to be found. SeedCommitment is the alternative: the chain attests the binding, the seed travels out of band, and the rendezvous point stays private.

Cost

WebLink is base58 over a ~70-byte payload, which is big-integer work: TestWebLink reports ~19M gas for one encode, TestWebLinkRoundTrip ~61M per encode-plus-decode. That is fine in a Render (a query) and worth avoiding per-row in a list. Signature verification is a native op and costs far less.

Live realm: r/moul/x/wesh · render it at /r/moul/x/wesh/v0.


Part of moul/gno-contracts — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage.

Dependency graph:

gno.land/p/moul/x/wesh/v0 dependency graph

🧪 Highly experimental — potentially vibe-coded. Not audited; may break, change, or be removed at any time. Do not use with anything of value. Full disclaimer: DISCLAIMER.