{"id":31778717,"url":"https://github.com/psychlone77/election-system-core","last_synced_at":"2026-07-01T02:31:41.639Z","repository":{"id":317966782,"uuid":"1069539958","full_name":"psychlone77/election-system-core","owner":"psychlone77","description":"A secure, privacy-preserving electronic voting system built with TypeScript and NestJS, implementing blind signatures, threshold cryptography, and end-to-end ballot encryption.","archived":false,"fork":false,"pushed_at":"2025-12-14T17:49:44.000Z","size":335,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-17T03:21:45.155Z","etag":null,"topics":["blind-signatures","cryptography","e-voting-system","nestjs","postgresql","threshold-cryptography"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/psychlone77.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-04T06:02:20.000Z","updated_at":"2025-12-14T17:49:47.000Z","dependencies_parsed_at":"2025-10-04T08:16:07.490Z","dependency_job_id":"d6274bfc-4687-4efb-83e4-434b5e4c53fc","html_url":"https://github.com/psychlone77/election-system-core","commit_stats":null,"previous_names":["psychlone77/election-system-core"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/psychlone77/election-system-core","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psychlone77%2Felection-system-core","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psychlone77%2Felection-system-core/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psychlone77%2Felection-system-core/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psychlone77%2Felection-system-core/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/psychlone77","download_url":"https://codeload.github.com/psychlone77/election-system-core/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psychlone77%2Felection-system-core/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34990845,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-01T02:00:05.325Z","response_time":130,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blind-signatures","cryptography","e-voting-system","nestjs","postgresql","threshold-cryptography"],"created_at":"2025-10-10T06:56:25.170Z","updated_at":"2026-07-01T02:31:41.634Z","avatar_url":"https://github.com/psychlone77.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Election System Core\n\nA secure, privacy-preserving electronic voting system built with TypeScript and NestJS, implementing blind signatures, threshold cryptography, and end-to-end ballot encryption.\n\n## Overview\n\nThis workspace contains three core servers and shared cryptographic libraries that work together to provide a secure voting infrastructure.  The system ensures voter anonymity through blind signature tokens while maintaining vote integrity and auditability. \n\n*For repositories for the admin panel and mobile app see the below links.*\n- https://github.com/psychlone77/election-system-admin-panel\n- https://github.com/psychlone77/election-system-mobile-app\n\n## Key Features\n\n- **Voter Anonymity**: Blind RSA signatures prevent linking voter identity to their ballot\n- **Vote Privacy**: End-to-end encryption using RSA-OAEP with threshold decryption\n- **Double-Vote Prevention**: Spent token tracking ensures one vote per eligible voter\n- **Threshold Security**: Private key shares distributed across multiple parties (t-of-n threshold scheme)\n- **Digital Signatures**: Ed25519 signatures for voter authentication\n\n## Technology Stack\n\n- **Framework**: NestJS with TypeScript\n- **Database**: PostgreSQL with TypeORM\n- **Cryptographic Libraries**:\n  - `@cloudflare/blindrsa-ts` - Blind RSA signatures (RSA-BSSA with SHA-384/PSS)\n  - `tweetnacl` - Ed25519 digital signatures\n  - `secrets.js-grempe` - Shamir's Secret Sharing for threshold cryptography\n  - Node.js `crypto` module - AES-256-GCM encryption and RSA-OAEP\n\n## Cryptographic Architecture\n\n### 1. **Blind RSA Signatures** (`libs/crypto/src/blind-rsa.ts`)\n- **Algorithm**: RSA-BSSA (Blind Signature Scheme with Appendix)\n- **Variant**: SHA384. PSS. Randomized\n- **Key Size**: 4096-bit RSA keys\n- **Purpose**: Issues unlinkable voting tokens to eligible voters\n\n**How it works**:\n1. Voter blinds a random token using the Eligibility Server's public key\n2. Server signs the blinded token without seeing the original\n3. Voter unblinds the signature to get a valid token\n4. Token can be verified by Ballot Box Server without revealing voter identity\n\n### 2. **Ed25519 Digital Signatures** (`libs/crypto/src/ed25519.ts`)\n- **Library**: TweetNaCl\n- **Purpose**:  Voter device authentication during eligibility requests\n- **Features**:  Fast, compact signatures with strong security guarantees\n\n### 3. **Threshold Cryptography** (`libs/crypto/src/threshold.ts`)\n- **Algorithm**: Shamir's Secret Sharing with RSA-OAEP\n- **Configuration**: 5 shares, threshold of 3 (configurable)\n- **Key Size**: 2048-bit RSA with SHA-256\n- **Purpose**:  Distribute tallying server's private key across multiple parties\n- **Benefit**: No single party can decrypt ballots alone\n\n### 4. **AES-GCM Encryption** (`libs/crypto/src/aes. ts`)\n- **Algorithm**: AES-256-GCM\n- **Key Size**: 256-bit\n- **IV Size**: 96-bit (recommended for GCM)\n- **Purpose**: Authenticated encryption for auxiliary data\n\n### 5. **Key Management** (`libs/crypto/src/key-store.ts`)\n- **RSA-PSS Keys**: 4096-bit for blind signatures\n- **RSA-OAEP Keys**:  2048-bit for ballot encryption\n- **Format**: PEM-encoded keys (PKCS#8 for private, SPKI for public)\n- **Storage**: File-based with secure permissions (0o600)\n\n## Architecture Diagram\n\n```mermaid\nflowchart TB\n subgraph VoterManagement[\"Voter Management \u0026 Support\"]\n        VR[\"Voter Registry Database\"]\n        Hotline[\"Election Hotline System\"]\n  end\n subgraph ElectionSystem[\"Core Election System\"]\n        Gateway([\"Secure Voting Gateway\"])\n        ES[\"Eligibility Server\"]\n        BBS[\"Ballot Box Server\"]\n        D[\"Encrypted Ballot Storage\"]\n        ST[\"Spent Token Database\"]\n        E[\"Tallying Server Cluster\"]\n  end\n subgraph Keys[\"Threshold Tallying Keys\"]\n        PK[\"Combined Public Key\"]\n        PrivKeys[\"Private Key Shares (t of n)\"]\n  end\n subgraph Public[\"Public Side\"]\n        F[\"Results Publishing Portal\"]\n  end\n    ElectionSystem --\u003e SystemLogs[\"System Logs\"]\n    Gateway \u003c--\u003e ES \u0026 BBS\n    ES \u003c--\u003e VR\n    Hotline -- Updates Lost/Stolen Device Status --\u003e VR\n    App[\"Voter Mobile App\"] \u003c--\u003e Gateway\n    BBS -- Verifies Token \u0026 Checks for Reuse --\u003e ST\n    BBS -- Stores Verified Ballot --\u003e D\n    D -- Reads All Ballots --\u003e E\n    PrivKeys -- Provides Shares for Decryption --\u003e E\n    E -- Publishes Final Tally --\u003e F\n    PK -- Use Public Key for encryption --\u003e App\n    VR@{ shape: cyl}\n    D@{ shape: cyl}\n    ST@{ shape: cyl}\n    PK@{ shape: card}\n    PrivKeys@{ shape: card}\n    SystemLogs@{ shape: cyl}\n```\n\n## Security Flow\n\n### Voting Process (Sequence Diagram)\n\n```mermaid\nsequenceDiagram\n  participant VD as Voter Device\n  participant ES as Eligibilty Server\n  participant EDB as Election Database\n  participant BBS as Ballot Box Server\n  participant BDB as Ballot Token Database\n  participant PBB as Ballot Storage\n  participant TA as Tallying Server\n\n  autonumber\n  VD -\u003e\u003e VD: 1. Generate token \u0026 blind_token\n  Note right of VD:  Voter holds VoterPrivateKey (Ed25519)\n  VD -\u003e\u003e ES: 2. Request token({NIC, blind_token}, signature)\n  Note over VD, ES: Signed with Ed25519 VoterPrivateKey\n  ES -\u003e\u003e EDB: 3. Fetch VoterPublicKey for NIC\n  ES --\u003e\u003e ES: 4. Verify request signature\n  alt Voter is eligible\n    ES -\u003e\u003e EDB: 5. Check if token already issued for NIC\n    Note right of EDB: is_token_issued == false\n    ES -\u003e\u003e EDB: 6. Mark voter as 'token-issued'\n    ES --\u003e\u003e ES: 7. Sign blinded_token\n    Note left of ES: Blind RSA signature with ESPrivateKey (4096-bit)\n    ES --\u003e\u003e VD: 8. Return blind_signature\n  else Voter not eligible or already claimed\n    ES --\u003e\u003e VD: 9. Return error\n  end\n  VD -\u003e\u003e VD: 10. Unblind signature to get (token, valid_signature)\n  VD -\u003e\u003e VD: 11. Encrypt ballot\n  Note right of VD: RSA-OAEP encryption with TAPublicKey (threshold scheme)\n  VD -\u003e\u003e BBS: 12. Submit {EncryptedBallot, (token, valid_signature)}\n  BBS --\u003e\u003e BBS: 13. Verify token signature\n  Note left of BBS: Verify with ESPublicKey (RSA-PSS 4096-bit)\n  BBS -\u003e\u003e BDB: 14. Check if token has been spent\n  alt Token is not spent\n    BBS -\u003e\u003e BDB: 15. Add token to 'spent tokens' list\n    BBS -\u003e\u003e PBB: 16. Store EncryptedBallot on PBB\n    BBS --\u003e\u003e VD: 17. Return Receipt with BallotID\n  else Token already spent\n    BBS --\u003e\u003e VD: 18. Return error (double vote attempt)\n  end\n  Note over PBB, TA: After voting period ends... \n  TA -\u003e\u003e PBB: 19. Read all EncryptedBallots\n  loop for each ballot\n    TA --\u003e\u003e TA: 20. Generate partial decryptions\n    Note right of TA: Each uses their private key share (Shamir's Secret Sharing)\n  end\n  TA --\u003e\u003e TA: 21. Combine 't' of 'n' shares to decrypt votes\n  TA -\u003e\u003e PBB: 22. Publish final tally with signature to Election Database\n```\n\n## Project Structure\n\n```\nelection-system-core/\n├── apps/\n│   ├── eligibility-server/     # Issues blind-signed tokens to eligible voters\n│   ├── ballot-box-server/      # Accepts and stores encrypted ballots\n│   └── tallying-server/        # Decrypts ballots using threshold keys\n├── libs/\n│   ├── crypto/                 # Cryptographic library\n│   │   ├── blind-rsa.ts       # Blind RSA signature operations\n│   │   ├── ed25519.ts         # Digital signature operations\n│   │   ├── aes.ts             # AES-GCM encryption\n│   │   ├── threshold.ts       # Shamir's Secret Sharing\n│   │   └── key-store. ts       # Key generation and management\n│   ├── database/              # TypeORM entities and repositories\n│   └── shared/                # Common utilities and config\n└── package.json\n```\n\n## Getting Started\n\n### Prerequisites\n\n- Node.js 18+ \n- PostgreSQL 14+\n- npm or yarn\n\n### Installation\n\n```bash\nnpm install\n```\n\n### Running the Servers\n\nStart individual servers from the repository root:\n\n```bash\n# Eligibility Server (Port 3001)\nnpm run start:eligibility\n\n# Ballot Box Server (Port 3002)\nnpm run start:ballot\n\n# Tallying Server (Port 3003)\nnpm run start:tally\n\n# Or start all concurrently\nnpm run start:all\n```\n\n### Key Generation\n\nKeys are automatically generated on first startup:\n\n- **Eligibility Server**:  Generates 4096-bit RSA-PSS keypair for blind signatures\n- **Tallying Server**: Generates 2048-bit RSA-OAEP keypair and splits into 5 shares (threshold:  3)\n\nKeys are stored in `apps/{server-name}/secrets/` directory with secure file permissions. \n\n## Security Considerations\n\n### Implemented Security Measures\n\n**Unlinkability**: Blind signatures prevent linking voter to ballot  \n**Vote Secrecy**: End-to-end encryption with threshold decryption  \n**Double-voting Prevention**: Spent token tracking  \n**Key Distribution**: Threshold cryptography (no single point of failure)  \n**Authenticated Encryption**: AES-GCM provides confidentiality and integrity  \n**Digital Signatures**: Ed25519 for fast, secure authentication\n\n### Important Notes\n\nThis system is a minimal scaffold for local development and demonstration purposes  \n\n## Development\n\n```bash\n# Format code\nnpm run format\n\n# Lint code\nnpm run lint\n\n# Run tests\nnpm test\n\n# Build all projects\nnpm run build\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpsychlone77%2Felection-system-core","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpsychlone77%2Felection-system-core","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpsychlone77%2Felection-system-core/lists"}