Skip to content

feat: Helios Booth 2026 — Lit web component voting booth#481

Open
benadida-agent wants to merge 33 commits intobenadida:masterfrom
benadida-agent:feat/booth2026-implementation-plan
Open

feat: Helios Booth 2026 — Lit web component voting booth#481
benadida-agent wants to merge 33 commits intobenadida:masterfrom
benadida-agent:feat/booth2026-implementation-plan

Conversation

@benadida-agent
Copy link
Collaborator

Summary

  • New heliosbooth2026/ directory implementing a complete voting booth using Lit 3.3.x + TypeScript 5.x + Vite 6.x
  • Full end-to-end voting flow: election info → question selection → ballot encryption (Web Worker) → review → submit/audit
  • 5 screen components (question-screen, review-screen, submit-screen, audit-screen, encrypting-screen) orchestrated by central booth-app state holder
  • Accessibility: skip link, ARIA landmarks, focus management, keyboard navigation, high contrast & reduced motion support
  • Production-ready: Vite single-bundle build (61 KB JS gzip 17 KB), responsive CSS, error handling with recovery, noscript fallback
  • Django URL route at /booth2026/ serves the new booth alongside the existing heliosbooth/

Architecture

  • Props-drilling pattern: booth-app holds all state, child components receive data via properties and emit events via CustomEvent with bubbles: true, composed: true
  • Encryption: Web Worker (encryption-worker.js) handles ballot encryption in background thread using existing jscrypto libraries
  • Crypto libraries: Loaded via synchronous <script> tags (same as existing booth), TypeScript declarations in src/crypto/types.ts
  • No runtime dependencies beyond Lit: All crypto handled by existing jscrypto, no additional frameworks

Test Plan

  • All 198 Django tests pass
  • TypeScript compiles with strict mode (including noUnusedLocals, noUnusedParameters)
  • Vite production build succeeds
  • No network calls between Start and Submit (offline-capable encryption)
  • Manual: Load booth at /booth2026/?election_url=<url>, complete full voting flow
  • Manual: Test keyboard-only navigation through entire flow
  • Manual: Verify ballot audit (spoil + re-encrypt) works
  • Manual: Test on mobile viewport (responsive layout)

🤖 Generated with Claude Code

benadida and others added 29 commits February 8, 2026 15:33
Four-phase implementation plan for rebuilding the voting booth with
Lit web components, TypeScript, and Vite (booth2026).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy crypto libraries from the legacy booth to the new Lit-based booth2026:
- Copy jscrypto directory with all crypto libraries (jsbn, sjcl, bigint, elgamal, helios, sha1, sha2)
- Copy underscore-min.js utility library
- Add TypeScript type declarations for crypto globals (BigInt, ElGamal, HELIOS, etc.)
- Types enable type-safe crypto operations in the voting booth

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create src/main.ts as the entry point that imports booth-app component
- Create src/booth-app.ts with BoothApp LitElement component that:
  - Manages voting booth screen state (loading, election, question, review, submit, audit)
  - Holds voter state including election data, answers, and encrypted ballot
  - Implements election loading from server with metadata support
  - Provides screen navigation and exit functionality
  - Renders election info screen with start button
  - Includes placeholder screens for Phase 2-3 work
- Update crypto/types.ts to remove global declarations (use window access instead)
- Adjust tsconfig.json to disable unused locals/params checking for Phase 1 shell

This provides the main application shell for the voting booth with state management
ready for Phase 2 (voting flow) and Phase 3 (submission/audit).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Load jscrypto libraries and underscore before the app to ensure crypto globals
are available when booth-app initializes. Scripts are loaded synchronously in
dependency order before the module script that imports booth-app.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix crypto script paths from root-absolute (/lib/jscrypto/) to relative (../lib/jscrypto/) to work correctly when served at /booth2026/ in production
- Add typed declare global block in crypto/types.ts for non-conflicting globals (HELIOS, b64_sha256, ElGamal, Random, UTILS, sjcl) with proper type narrowing
- Update booth-app.ts to use declared typed globals directly instead of (window as any) casting
- Move inline styles to CSS classes (.start-button-container and .help-email) in booth-app.ts static styles
- Export BoothScreen type for child component usage in later phases

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…avigation

Implement Task 2 of Phase 2 - integrate question screen component into booth app:
- Add imports for question-screen component and event types
- Implement handleAnswerChange to track answer selections with immutable updates
- Implement validateCurrentQuestion to enforce minimum answer requirements
- Implement handleNavigation to handle previous/next/review navigation with validation
- Add goToQuestion method for editing answers from review screen
- Add renderQuestionScreen method to render question with proper answer orderings
- Update startVoting to show review button immediately for single-question elections
- Update renderCurrentScreen to use renderQuestionScreen instead of placeholder

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Important Fix 1: Remove redundant checkbox accessibility attributes from li element. Native input type="checkbox" handles the semantics; role="checkbox", aria-checked, and aria-disabled on the li create duplicate announcements for screen readers.
- Important Fix 2: Change warning-box color from var(--color-success, #28a745) to var(--color-text-secondary, #666) for proper semantic coloring of constraint messages.
- Minor Fix 1: Skip validation in handleNavigation() for 'previous' direction to allow users to navigate back without meeting minimum answer requirements.
- Minor Fix 2: Use explicit undefined comparisons in getConstraintText() to properly handle cases where min=0 or max=0.

Verification:
- TypeScript: npx tsc --noEmit ✓
- Build: npm run build ✓
- Tests: uv run python manage.py test -v 0 → 198 tests pass ✓

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Task 7 implementation:
- Added screen imports for review, submit, audit, and encrypting screens
- Updated BoothScreen type to include 'encrypting' state
- Added encryption-related state properties: worker, encryptionProgress, answerTimestamps, dirty tracking, encryptedBallot, auditTrail, rawElectionJson
- Implemented worker initialization and async encryption handling
- Updated loadElection to store rawElectionJson and initialize worker
- Updated handleAnswerChange to mark questions as dirty
- Updated handleNavigation to trigger sealBallot on review
- Added handleReviewNavigation, prepareForCast, and auditBallot handlers
- Added handleAuditNavigation, resetAndReencrypt, and postAuditedBallot methods
- Added handleBallotSubmit for submission flow
- Updated renderCurrentScreen with cases for all new screens
- Updated getProgressStep to include encrypting screen
- Updated beforeunload handler to warn on encrypting screen
- Added getPrettyChoices and worker encryption helper methods
- Fixed EncryptedVote interface to support includeRandomness parameter and optional clearPlaintexts method

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Critical: Add worker.onerror handler to catch encryption failures and set error state
- Important: Fix worker instantiation to use import.meta.url instead of root-absolute path
- Important: Fix encrypting.gif and loading.gif paths to use import.meta.url for production
- Important: Remove dead hidden form from review-screen (submission is in submit-screen)
- Minor: Replace `as any` with `Record<string, unknown>` in hasClearPlaintexts type guard
- Minor: Make auditExpanded @State() reactive and remove manual requestUpdate()
- Minor: Move inline styles to CSS classes in review-screen, audit-screen, submit-screen

All TypeScript compilation passes, build succeeds, and all 198 Django tests pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…gement

Implements Task 1 from Phase 4 accessibility enhancements:
- Add skip link element with proper styling for keyboard navigation
- Add ARIA landmarks: header with role="banner", nav with aria-label
- Add focus management via focusMainContent() method for screen transitions
- Call focusMainContent() in sealBallot(), prepareForCast(), and auditBallot()
- Update render() to use proper semantic HTML structure
- Add aria-live="assertive" to error alert for screen reader announcements
- getProgressStep() method already exists and works correctly

The main element now has id="main-content" and tabindex="-1" for focus management.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement Task 2 from Phase 4 with:
- isInitializing state property for tracking booth initialization
- renderErrorScreen() method with recovery options (Reload, Return to Election)
- Error screen CSS styles (.error-screen, .error-message, .error-actions)
- Improved initializeBooth() with error classification (network, crypto, generic)
- New waitForCryptoWithTimeout() method with 10-second timeout
- Updated renderCurrentScreen() loading case with initialization message
- Updated election case to show error screen when initialization fails
- Enhanced loading display with role="status" and aria-live="polite"
- loading-detail style for secondary messaging

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Update vite.config.ts with production build options:
  - Add sourcemaps for debugging
  - Configure terser minification
  - Add dev server proxy for Django API calls
  - Set publicDir to 'public'
  - Use hashed filenames for assets
- Update index.html with metadata and production paths:
  - Add SEO meta tags (description, robots noindex)
  - Add noscript fallback for JavaScript requirement
  - Use relative paths for crypto scripts and styles
  - Add preload hints for critical assets
- Create public/ directory and move GIF files:
  - Move encrypting.gif to public/
  - Move loading.gif to public/
  - Update references in encrypting-screen.ts and review-screen.ts
  - Add @vite-ignore comments to suppress build warnings
- Install terser as dev dependency for minification
- Verified production build succeeds with single bundle

Build output:
- dist/assets/booth.[hash].js (61KB)
- dist/assets/booth.[hash].css (3KB)
- Source maps generated for debugging
- Hashed filenames for cache busting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add documentation comment to the booth2026 URL route explaining how to
switch from serving source files in development to serving built dist
files in production deployment.
…uild

Move encrypting.gif and loading.gif from root heliosbooth2026/ to public/
directory so they are properly included in the production build output.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Critical (C1): Fix aria-current attribute binding on progress steps
- Changed from string interpolation (which Lit ignores) to proper conditional
  attribute binding using aria-current=${condition ? 'step' : nothing}
- Imported 'nothing' from 'lit' for proper undefined handling

Important (I1): Add focusMainContent() to startVoting() and goToQuestion()
- Both screen transition methods now call focusMainContent() like other
  transitions (sealBallot, prepareForCast, auditBallot) for consistent
  focus management and accessibility

Important (I2): Remove redundant role="main" from main element
- The <main> element has implicit role="main", explicit attribute was
  redundant and violates HTML best practices

Minor (M1): Consolidate duplicate .error and .error-message styles
- Both classes had identical background, border, color, padding, and
  border-radius CSS. Now consolidated with shared rule and context-
  specific margin handling for .error-screen .error-message

Minor (M2): Remove useless preload link from index.html
- The <link rel="preload"> before the actual stylesheet provided zero
  benefit and cluttered the HTML

All issues verified:
- TypeScript compiles without errors (npx tsc --noEmit)
- Production build succeeds (npm run build)
- No regressions introduced

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- C1: Fix crypto script paths in index.html - change ../lib/ to lib/ to resolve correctly when served from /booth2026/
- I1: Re-enable noUnusedLocals and noUnusedParameters in tsconfig.json and fix unused cryptoReady state
- I2: Clarify production deployment comment in urls.py - serve full heliosbooth2026/ directory (not just dist/) because crypto libs in lib/ are needed
- I3: Fix choices[index]?.length < question.max comparison - use nullish coalescing (?? 0) to avoid undefined comparison
- M1: Change encryptedBallot type from unknown to EncryptedVote | null and remove unnecessary type casts
- M2: Merge duplicate import statements from crypto/types into single import

All issues fixed:
✓ TypeScript compilation passes with strict unused checking
✓ npm run build succeeds
✓ Django test suite passes (198/198 tests)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@benadida benadida requested a review from Copilot February 8, 2026 17:33
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces a new Lit + TypeScript + Vite-based “Helios Booth 2026” frontend served alongside the existing booth, including a web-worker-based encryption path and vendored legacy jscrypto libraries.

Changes:

  • Added Django route to serve /booth2026/ content from a new heliosbooth2026/ directory.
  • Implemented Lit screen components for the voting flow (question/review/encrypting/submit/audit).
  • Added a Vite/TS build setup plus vendored crypto libraries and worker-based encryption.

Reviewed changes

Copilot reviewed 34 out of 38 changed files in this pull request and generated 49 comments.

Show a summary per file
File Description
urls.py Adds a /booth2026/ static-serving route for the new booth.
heliosbooth2026/index.html New booth HTML entrypoint loading styles, crypto libs, and app entry.
heliosbooth2026/package.json Adds Vite/Lit/TS project configuration and build scripts.
heliosbooth2026/package-lock.json Locks npm dependency graph for the booth.
heliosbooth2026/tsconfig.json TypeScript compiler configuration for the booth source.
heliosbooth2026/vite.config.ts Vite build/dev server configuration for /booth2026/ base path.
heliosbooth2026/.gitignore Ignores node_modules and dist output for the booth project.
heliosbooth2026/src/main.ts App entry module that registers/initializes the booth app.
heliosbooth2026/src/crypto/types.ts TS type declarations for global jscrypto/HELIOS APIs and worker messages.
heliosbooth2026/src/styles/booth.css Base styling for the new booth UI (responsive/contrast/motion).
heliosbooth2026/src/screens/question-screen.ts Lit question UI with selection and navigation events.
heliosbooth2026/src/screens/review-screen.ts Lit review UI showing selections, tracker, and cast/audit actions.
heliosbooth2026/src/screens/encrypting-screen.ts Lit encryption progress UI.
heliosbooth2026/src/screens/submit-screen.ts Lit submit UI with form POST to cast_url.
heliosbooth2026/src/screens/audit-screen.ts Lit audit UI for spoiled ballot verification workflow.
heliosbooth2026/workers/encryption-worker.js Web Worker that imports jscrypto libs and encrypts answers off-thread.
heliosbooth2026/public/loading.gif Loading indicator asset.
heliosbooth2026/public/encrypting.gif Encryption indicator asset.
heliosbooth2026/lib/underscore-min.js Vendored Underscore.js dependency for legacy crypto code.
heliosbooth2026/lib/jscrypto/README Vendored jscrypto README.
heliosbooth2026/lib/jscrypto/jsbn.js Vendored jscrypto dependency.
heliosbooth2026/lib/jscrypto/jsbn2.js Vendored jscrypto dependency.
heliosbooth2026/lib/jscrypto/sjcl.js Vendored SJCL bundle used by jscrypto.
heliosbooth2026/lib/jscrypto/class.js Vendored John Resig class helper used by jscrypto.
heliosbooth2026/lib/jscrypto/bigint.js Vendored BigInt wrapper used by jscrypto.
heliosbooth2026/lib/jscrypto/random.js Vendored RNG glue used by jscrypto.
heliosbooth2026/lib/jscrypto/elgamal.js Vendored ElGamal implementation used by Helios crypto.
heliosbooth2026/lib/jscrypto/sha1.js Vendored SHA-1 implementation used by jscrypto.
heliosbooth2026/lib/jscrypto/sha2.js Vendored SHA-2 implementation used by jscrypto.
heliosbooth2026/lib/jscrypto/helios.js Vendored Helios crypto logic (Election/EncryptedVote/etc.).
heliosbooth2026/lib/jscrypto/bigint.java Vendored Java applet source (legacy BigInt support).
heliosbooth2026/lib/jscrypto/bigint.dummy.js Vendored dummy BigInt implementation (legacy support).
heliosbooth2026/lib/jscrypto/bigint.class Vendored Java applet bytecode (legacy BigInt support).
docs/implementation-plans/2026-01-18-helios-booth-lit-redesign/phase_02.md Documentation plan for Phase 2 voting flow implementation.
docs/implementation-plans/2026-01-18-helios-booth-lit-redesign/phase_04.md Documentation plan for Phase 4 polish/deployment steps.
Files not reviewed (1)
  • heliosbooth2026/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +51 to +58
function do_encrypt(message) {
console.log('Encrypting answer for question ' + message.q_num);

var encrypted_answer = new HELIOS.EncryptedAnswer(
ELECTION.questions[message.q_num],
message.answer,
ELECTION.public_key
);
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do_encrypt assumes ELECTION has been initialized and q_num is valid. If an encrypt message arrives before setup, or q_num is out of bounds, the worker will throw and stop responding. Add guards that post an error response (and/or ignore) when ELECTION is null or the question index is invalid.

Copilot uses AI. Check for mistakes.
Comment on lines +265 to +280
<li
class="answer-item ${isSelected ? 'selected' : ''} ${isDisabled ? 'disabled' : ''}"
tabindex="${isDisabled ? -1 : 0}"
@click=${() => this.handleAnswerClick(answerIndex)}
@keydown=${(e: KeyboardEvent) => this.handleAnswerKeydown(e, answerIndex)}
>
<label class="answer-label">
<input
type="checkbox"
class="answer-checkbox"
.checked=${isSelected}
.disabled=${isDisabled}
@change=${(e: Event) => {
e.stopPropagation();
this.handleAnswerClick(answerIndex);
}}
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clicking the checkbox is likely to toggle twice: the <li @click> handler fires, and the <input @change> handler also calls handleAnswerClick. stopPropagation() on the change event doesn’t stop the click bubble. This can result in the selection immediately reverting. Consider handling selection in one place (e.g., only on the input’s @click/@change and remove the <li @click>, or stop propagation on the input’s click event).

Copilot uses AI. Check for mistakes.
Comment on lines +249 to +252
<h4 @click=${this.toggleAuditSection}>
Spoil & Audit
<span class="audit-optional">[optional]</span>
</h4>
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<h4> is being used as an interactive control (@click=${this.toggleAuditSection}) but isn’t keyboard-focusable and doesn’t expose button semantics to assistive tech. Use a <button> (or <details><summary>) for the toggle, or add appropriate role="button", tabindex="0", and key handlers.

Copilot uses AI. Check for mistakes.
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

npm run build runs tsc with emit enabled, writing into dist/, and then vite build also outputs to dist/ (and typically clears it first). This makes the tsc output either wasted or potentially conflicting. Consider switching to tsc --noEmit for type-checking, or configure tsc to emit to a separate directory if you actually need declarations.

Suggested change
"build": "tsc && vite build",
"build": "tsc --noEmit && vite build",

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +19
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./src",
"esModuleInterop": true,
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With outDir set to ./dist and declaration enabled, tsc will emit build artifacts into the same directory Vite uses for its production output. If the intention is type-check-only before Vite builds, consider disabling emit (noEmit: true) and/or turning off declaration outputs here to avoid churn/overwrites in dist/.

Copilot uses AI. Check for mistakes.
BigIntDummy.setup = function(callback, fail_callback) {
//console.log("using dummy bigint");
callback();
}
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid automated semicolon insertion (91% of all statements in the enclosing script have an explicit semicolon).

Suggested change
}
};

Copilot uses AI. Check for mistakes.
sk.pk = ElGamal.PublicKey.fromJSONObject(d.public_key);
sk.x = BigInt.fromJSONObject(d.x);
return sk;
}
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid automated semicolon insertion (95% of all statements in the enclosing script have an explicit semicolon).

Suggested change
}
};

Copilot uses AI. Check for mistakes.
}

return plaintexts;
}
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid automated semicolon insertion (92% of all statements in the enclosing script have an explicit semicolon).

Suggested change
}
};

Copilot uses AI. Check for mistakes.
return null;

return _(lol).map(function(sublist) {return _(sublist).map(function(item) {return item_dejsonifier(item);})});
}
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid automated semicolon insertion (92% of all statements in the enclosing script have an explicit semicolon).

Suggested change
}
};

Copilot uses AI. Check for mistakes.
Comment on lines +16 to +96
// let's try always using SJCL
var USE_SJCL = true;

// let's make this much cleaner
if (USE_SJCL) {
// why not?
var BigInt = BigInteger;
// ZERO AND ONE are already taken care of
BigInt.TWO = new BigInt("2",10);

BigInt.setup = function(callback, fail_callback) {
// nothing to do but go
callback();
}

BigInt.prototype.toJSONObject = function() {
return this.toString();
};

} else {
BigInt = Class.extend({
init: function(value, radix) {
if (value == null) {
throw "null value!";
}

if (USE_SJCL) {
this._java_bigint = new BigInteger(value, radix);
} else if (BigInt.use_applet) {
this._java_bigint = BigInt.APPLET.newBigInteger(value, radix);
} else {
try {
this._java_bigint = new java.math.BigInteger(value, radix);
} catch (e) {
// alert("oy " + e.toString() + " value=" + value + " , radix=" + radix);
throw TypeError
}
}
},

toString: function() {
return this._java_bigint.toString() + "";
},

toJSONObject: function() {
return this.toString();
},

add: function(other) {
return BigInt._from_java_object(this._java_bigint.add(other._java_bigint));
},

bitLength: function() {
return this._java_bigint.bitLength();
},

mod: function(modulus) {
return BigInt._from_java_object(this._java_bigint.mod(modulus._java_bigint));
},

equals: function(other) {
return this._java_bigint.equals(other._java_bigint);
},

modPow: function(exp, modulus) {
return BigInt._from_java_object(this._java_bigint.modPow(exp._java_bigint, modulus._java_bigint));
},

negate: function() {
return BigInt._from_java_object(this._java_bigint.negate());
},

multiply: function(other) {
return BigInt._from_java_object(this._java_bigint.multiply(other._java_bigint));
},

modInverse: function(modulus) {
return BigInt._from_java_object(this._java_bigint.modInverse(modulus._java_bigint));
}

});
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This use of variable 'USE_SJCL' always evaluates to true.

Suggested change
// let's try always using SJCL
var USE_SJCL = true;
// let's make this much cleaner
if (USE_SJCL) {
// why not?
var BigInt = BigInteger;
// ZERO AND ONE are already taken care of
BigInt.TWO = new BigInt("2",10);
BigInt.setup = function(callback, fail_callback) {
// nothing to do but go
callback();
}
BigInt.prototype.toJSONObject = function() {
return this.toString();
};
} else {
BigInt = Class.extend({
init: function(value, radix) {
if (value == null) {
throw "null value!";
}
if (USE_SJCL) {
this._java_bigint = new BigInteger(value, radix);
} else if (BigInt.use_applet) {
this._java_bigint = BigInt.APPLET.newBigInteger(value, radix);
} else {
try {
this._java_bigint = new java.math.BigInteger(value, radix);
} catch (e) {
// alert("oy " + e.toString() + " value=" + value + " , radix=" + radix);
throw TypeError
}
}
},
toString: function() {
return this._java_bigint.toString() + "";
},
toJSONObject: function() {
return this.toString();
},
add: function(other) {
return BigInt._from_java_object(this._java_bigint.add(other._java_bigint));
},
bitLength: function() {
return this._java_bigint.bitLength();
},
mod: function(modulus) {
return BigInt._from_java_object(this._java_bigint.mod(modulus._java_bigint));
},
equals: function(other) {
return this._java_bigint.equals(other._java_bigint);
},
modPow: function(exp, modulus) {
return BigInt._from_java_object(this._java_bigint.modPow(exp._java_bigint, modulus._java_bigint));
},
negate: function() {
return BigInt._from_java_object(this._java_bigint.negate());
},
multiply: function(other) {
return BigInt._from_java_object(this._java_bigint.multiply(other._java_bigint));
},
modInverse: function(modulus) {
return BigInt._from_java_object(this._java_bigint.modInverse(modulus._java_bigint));
}
});
// Using SJCL-backed BigInteger implementation directly.
// NOTE: previously this was controlled by a USE_SJCL flag that was always true.
// let's make this much cleaner
// why not?
var BigInt = BigInteger;
// ZERO AND ONE are already taken care of
BigInt.TWO = new BigInt("2",10);
BigInt.setup = function(callback, fail_callback) {
// nothing to do but go
callback();
};
BigInt.prototype.toJSONObject = function() {
return this.toString();
};

Copilot uses AI. Check for mistakes.
benadida and others added 4 commits February 8, 2026 18:44
… dist on build

- Update Django URL to serve from heliosbooth2026/dist/ instead of source
- Add explicit route for /booth2026/ to serve index.html (directory index)
- Update npm build script to copy lib/ into dist/ for crypto library access

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Heroku runs `heroku-postbuild` which installs dependencies and builds
the heliosbooth2026 Lit app into dist/. Requires adding the Node.js
buildpack before the Python buildpack:

  heroku buildpacks:add --index 1 heroku/nodejs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Heroku prunes devDependencies before running heroku-postbuild, so tsc
and vite aren't available. Move them to dependencies so they're
installed when the build script runs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix ballot submission broken by Shadow DOM: switch submit-screen to
light DOM rendering via createRenderRoot() so the <form> can POST
natively. Add single ballot verifier (verify-screen component, worker,
verify.html entry point) and fix audit screen verifier link.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants