A client-side anonymous voting platform using Nostr-compatible ring signatures.
Ringable allows users to create proposals and vote anonymously as part of a predefined group (a "ring" of public keys). It leverages the cryptographic power of bLSAG ring signatures to ensure that while votes are verified as coming from a valid member of the ring, the specific voter's identity remains hidden.
The cryptographic functions are powered by the Nostringer Rust library, compiled to WebAssembly (WASM) for use in the browser.
Built with a fun, retro pixel-art aesthetic, Ringable demonstrates modern cryptography in an engaging, user-friendly way.
- True Anonymity: Votes are cryptographically signed by a ring member without revealing which member signed.
- Linkability (Duplicate Prevention): Uses bLSAG signatures, which generate a unique "key image" per voter per proposal, preventing the same person from voting multiple times anonymously.
- Client-Side Only: No backend server required! All data (keys, rings, proposals, votes) is stored locally in the browser's
localStorage
, managed via Zustand. - Retro Pixel-Art UI: A unique, game-inspired interface built with React and Tailwind CSS.
- Nostr Compatible Keys: Uses secp256k1 keys, compatible with the Nostr ecosystem.
- Monorepo Structure: Organized using Turborepo for better code sharing and maintainability.
- Monorepo: Turborepo
- Framework: Next.js 14 (App Router)
- Language: TypeScript
- Styling: Tailwind CSS
- State Management: Zustand (with
persist
middleware forlocalStorage
) - UI Components: React (within shared
packages/ui
) - Cryptography: Nostringer (Rust library supporting WASM)
- Package Manager: pnpm
- Linting/Formatting: ESLint, Prettier
This project uses a Turborepo monorepo structure:
.
├── apps
│ ├── web/ # Main Next.js web application (Ringable UI)
│ └── docs/ # (Optional) Placeholder for documentation site
├── packages
│ ├── crypto/ # Wrapper for cryptography functions (Nostringer WASM - currently mocked)
│ ├── eslint-config/ # Shared ESLint configuration
│ ├── tailwind-config/ # Shared Tailwind CSS configuration
│ ├── tsconfig/ # Shared TypeScript configuration
│ └── ui/ # Shared React UI components (Button, Card, Input, etc.)
└── package.json # Root configuration
- Node.js (Version specified in root
package.json
engines field, e.g., >=18) - pnpm (Version specified in root
package.json
packageManager field, e.g., 8.x) - (Future Step) Rust toolchain and
wasm-pack
for compiling thenostringer
library if replacing mocks.
- Clone the repository:
git clone https://github.com/AbdelStark/ringable.git cd ringable
- Install dependencies from the root directory:
pnpm install
- Start the development server (this will run the Next.js app and watch for changes in shared packages):
pnpm run dev
- Open your browser to
http://localhost:3000
to see the Ringable web application.
This project is licensed under the MIT License - see the LICENSE file for details.
Built with love by AbdelStark 🧡
Feel free to follow me on Nostr if you'd like, using my public key:
npub1hr6v96g0phtxwys4x0tm3khawuuykz6s28uzwtj5j0zc7lunu99snw2e29
Or just scan this QR code to find me: