kind 35128 · 2026-10-11 16:07 UTC
AnonymousVotingNostr - Anonymous Polls on Nostr
AnonymousVotingNostr — Anonymous Polls on Nostr A decentralized polling client that runs entirely in your browser. You sign in with a Nostr private key, create a poll with a ring of public keys, and ring members vote without anyone being able to tell which member cast which vote. Nothing is stored on a server. Everything is a signed Nostr event published to relays you choose. What it is AnonymousVotingNostr is a single-file web app. There is no backend, no database, no account, no tracking. Open the page, paste an nsec, and you are a Nostr client. Polls are published as kind 30078 events tagged avn-poll. Votes are published as kind 20078 events tagged avn-vote. Both are read back by anyone connected to the same relays. How anonymity works Each poll defines a ring: a list of public keys, one of which is yours. When you vote, your browser produces an LSAG ring signature — an adaptation of the Liu–Wei–Wong construction to secp256k1 and BIP-340 Schnorr. The signature proves that some member of the ring signed the vote, without revealing which one. Verifiers learn exactly two things: that a ring member voted, and what they voted for. Nothing else. Double-voting is prevented by a key image. Every signature publishes I = x·Hp(P), a value that depends only on your secret key and your own public key. The same key produces the same I for the same poll every time. Honest clients count only the first valid vote per key image. Anyone can see that two votes share a key image; nobody can tell whose it is. The outer Nostr event is signed by a freshly generated throwaway keypair for each vote, so the event's pubkey never points back at you. Only the ring signature inside the event content connects the vote to the ring — and it does not say which member. Cross-poll unlinkability The poll ID is included in the message that gets signed. Two votes by the same person in two different polls therefore produce two completely independent key images. Your voting history cannot be stitched together across polls by anyone except you. What this does not protect against Relays see your IP address. Use Tor or a VPN if network-level metadata matters to you. Relays also see arrival time, even though the event's created_at is randomized within a one-hour window. Small rings are weak — a ring of two or three people narrows the signer almost immediately, so use rings of at least eight for meaningful anonymity. If every other member of a ring colludes with a relay operator, the signer set collapses to you. There is no forward secrecy: if your nsec ever leaks, an attacker can recompute the key image for every past poll and identify which votes were yours. The signature proves control of a key in the declared ring, not entitlement to vote — curate rings carefully. This is a reference implementation and has not been audited. Do not use it for elections that matter without an independent cryptographic review. Relay selection The app keeps up to four relay WebSocket connections open at once, no matter how many relays you configure. Additional relays sit in a queue. The pool scores each relay continuously — connection success rate, publish success rate, event throughput, latency, and any recent errors — and picks the best-scoring wanted relays to keep connected. User-added relays outrank the built-in defaults. If a connected relay starts failing, a higher-scoring queued relay swaps in automatically. If a relay fails hard (eight consecutive reconnect attempts), it goes on a five-minute cooldown so the pool stops hammering it. Your configured relay list is saved in localStorage and restored on reload. It is never overwritten by opening a poll or switching views. Only secure wss:// relays are accepted, with the sole exception of ws:// on localhost for local testing. First sign-in walkthrough The first time you sign in with a given public key, an animated guided tour runs through the interface: your identity, the relay bar, how to add relays, the poll feed, how to create a poll, and where the diagnostics live. The tour can be skipped at any point, dismissed with Escape, and navigated with the arrow keys. Once completed for a pubkey, it will not appear again for that pubkey unless you explicitly restart it from the footer link. Dev diagnostics A panel at the bottom of the page runs cryptographic self-tests at every page load. Three honest sign-and-verify rounds, four tampered-signature checks (mutated s, mutated c0, mutated I, wrong message), a cross-poll linkability check, a same-poll linkability check, and a ring-size guard. Alongside those, a relay-URL validator is exercised against eight cases. Any failure surfaces in the panel and in the error log. The error log is also reachable at the URL fragment #__errors for a JSON dump to the console. Signing in Paste an nsec1… bech32 string or a 64-character hex private key. The key lives in memory only. It is never written to localStorage. Refresh the page and you are signed out. If you are uncomfortable pasting your main nsec into a web page, generate a fresh keypair for this app and treat it as a dedicated voting identity. Creating a poll Sign in. Click Create poll. Fill in a question, two to eight choices, and a ring of at least two pubkeys (npub1… or hex, one per line). Your own pubkey must be in the ring or the form will refuse to submit. Optionally set an end time. Publish. The poll is signed with your real key so it can be attributed to you as the creator, then broadcast to every open relay. Voting Open a poll. If you are not in the ring, you will see a notice. If you are, pick a choice and click Sign & publish vote. The app signs a ring signature locally, verifies it locally, refuses to publish if self-verification fails, generates a throwaway keypair for the outer event, signs the event, and broadcasts. The vote's key image is recorded locally so you cannot accidentally vote twice. Reading results Results show only votes whose ring signatures verify against the poll's declared ring. Votes are deduplicated by key image, keeping the earliest by signedAt. A checkbox lets you include unverified votes for transparency or debugging — the tally then counts the first vote per key image regardless of signature validity. Below the tally, every received vote is listed with a valid/invalid badge, the timestamp, the chosen option, and the first bytes of its key image. Security caveats summary Your nsec lives in memory only. Relays see your IP. Small rings are weak. No forward secrecy. Not audited. Use wss:// or better, and prefer your own relays. If you need network-level metadata hiding, wrap vote events in NIP-59 gift wrap before publishing. License and status Reference implementation, provided as-is. Not audited. Do not use for elections that matter without independent cryptographic review.
Missing files
These files were checked. They were not on the hosts listed here.
| path | sha256 | missing on |
|---|---|---|
| /__MACOSX/._index.html | 19d1b7c6d08ba1606f9e489a7323227803bd4e4b06407afac3d232ebfc845284 |
https://nsite.run · missing
|
Manifest
- event id
- 989b869a660876a20958f0d9970b1f087974641e780516de5e92ac75983a6e37
- aggregate x
- None
- d tag
- vote
Paths
| path | sha256 | hosts | |
|---|---|---|---|
| /index.html | 56c5ff6f800bf6350ea22ec33ea58111fb9b2b0b91cfb6f7ceb19bcf49b34d24 |
https://nsite.run · degraded
https://blssm.us · degraded
https://blossom.yakihonne.com · degraded
https://zencrown.relay2aeon.quest/ · degraded
|
preview |
| /__MACOSX/._index.html | 19d1b7c6d08ba1606f9e489a7323227803bd4e4b06407afac3d232ebfc845284 |
https://nsite.run · missing
https://blssm.us · degraded
https://blossom.yakihonne.com · degraded
https://zencrown.relay2aeon.quest/ · degraded
|
preview |
| /404.html | 56c5ff6f800bf6350ea22ec33ea58111fb9b2b0b91cfb6f7ceb19bcf49b34d24 |
https://nsite.run · degraded
https://blssm.us · degraded
https://blossom.yakihonne.com · degraded
https://zencrown.relay2aeon.quest/ · degraded
|
preview |