Skip to content

Add elgamal#617

Open
andrew-fleming wants to merge 14 commits into
OpenZeppelin:mainfrom
andrew-fleming:add-elgamal
Open

Add elgamal#617
andrew-fleming wants to merge 14 commits into
OpenZeppelin:mainfrom
andrew-fleming:add-elgamal

Conversation

@andrew-fleming

@andrew-fleming andrew-fleming commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Fixes #606

Summary by CodeRabbit

  • New Features

    • Added ElGamal cryptographic module supporting key derivation, encryption/decryption, and homomorphic operations including addition, subtraction, scalar multiplication, and rerandomization.
  • Tests

    • Added comprehensive test suite validating ElGamal functionality and behavior.

@andrew-fleming andrew-fleming requested review from a team as code owners June 21, 2026 22:30
@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 24d7e05a-0593-4650-b25b-5433ecbb8543

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Adds a new ElGamal Compact module implementing stateless ElGamal encryption over the Jubjub curve, including key derivation, encryption primitives, ciphertext homomorphic algebra, rerandomization, and verification circuits. A MockElGamal test contract, ElGamalSimulator TypeScript class, and a Vitest suite cover all operations. Build pipeline wiring registers the new compact:crypto task.

Changes

ElGamal Module

Layer / File(s) Summary
Build pipeline and changelog wiring
turbo.json, package.json, contracts/package.json, CHANGELOG.md
Registers a compact:crypto turbo task with inputs/outputs/env, wires it into the top-level compact task, adds matching compact:crypto npm scripts in root and contracts package.json, and records the change in the changelog.
ElGamal module: Ciphertext type and key/scalar derivation circuits
contracts/src/crypto/ElGamal.compact
Defines the module header and imports, the exported Ciphertext struct (c1, c2 as JubjubPoints), secretToScalar, derivePk, expandRandomness, JUBJUB_SUBGROUP_ORDER_MINUS_ONE, and the ecNeg point-negation helper.
ElGamal module: encryption, ciphertext algebra, and verification circuits
contracts/src/crypto/ElGamal.compact
Implements encryptZero, encryptPoint (with identity-key assertion), lifted encrypt; ciphertext algebra negate, add, sub, scalarMul, addEncrypted, subEncrypted; rerandomization via homomorphic zero-encryption addition; and verification circuits assertKeyPair, assertDecryptsToPoint, assertDecryptsTo.
Test mock contract, witnesses, and simulator
contracts/src/crypto/test/mocks/MockElGamal.compact, contracts/src/crypto/test/witnesses/ElGamalWitnesses.ts, contracts/src/crypto/test/simulators/ElGamalSimulator.ts
MockElGamal.compact re-exports the Ciphertext type and exposes all internal circuits as export pure circuit wrappers. ElGamalWitnesses.ts provides an empty private state and witness factory. ElGamalSimulator.ts wires MockElGamal through createSimulator and surfaces the full ElGamal API as typed TypeScript methods.
ElGamal Vitest test suite
contracts/src/crypto/test/ElGamal.test.ts
Covers secretToScalar, derivePk, expandRandomness, encrypt/decrypt round-trips and rejection cases, point encryption, encryptZero, additive/subtractive homomorphism, scalar multiplication, rerandomization, key-pair assertions, a composed balance scenario, and simulator public-state wiring.

Sequence Diagram(s)

sequenceDiagram
  participant Test as ElGamal.test.ts
  participant Sim as ElGamalSimulator
  participant Mock as MockElGamal.compact
  participant Core as ElGamal.compact

  Test->>Sim: encrypt(pk, value, r)
  Sim->>Mock: circuits.pure.encrypt(pk, value, r)
  Mock->>Core: ElGamal_encrypt(pk, value, r)
  Core-->>Mock: Ciphertext
  Mock-->>Sim: Ciphertext
  Sim-->>Test: Ciphertext

  Test->>Sim: assertDecryptsTo(ct, pk, ek, claimedValue)
  Sim->>Mock: circuits.pure.assertDecryptsTo(ct, pk, ek, claimedValue)
  Mock->>Core: ElGamal_assertDecryptsTo(...)
  Core->>Core: ek_scalar = secretToScalar(ek)
  Core->>Core: m = c2 - ek_scalar*c1
  Core->>Core: assert m == g^claimedValue
  Core-->>Mock: pass/throw
  Mock-->>Sim: pass/throw
  Sim-->>Test: pass/throw
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested labels

enhancement

🐇 A curve called Jubjub, a secret compressed,
Two points in the struct, c1 and c2 dressed,
Encrypt with a scalar, then add, sub, or negate,
Rerandomize freely—the plaintext stays great,
The rabbit hops home with cryptography blessed! 🔐

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Add elgamal' is generic and lacks specificity. While it clearly relates to the main change (ElGamal module implementation), it provides minimal context about what the module contains or its purpose. Enhance the title with more specificity about ElGamal functionality, e.g., 'Add ElGamal cryptographic module with encryption and homomorphic operations' or 'Add ElGamal primitives for stateless encryption'.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR implements core ElGamal cryptographic functionality including key derivation, encryption primitives, homomorphic operations, decryption assertions, and verification circuits, aligning with the issue #606 objective to add ElGamal module with primitives.
Out of Scope Changes check ✅ Passed All changes are scoped to ElGamal implementation: core module, test suite, mock contract, simulator, witnesses, and supporting build configuration (package.json, turbo.json, CHANGELOG.md). No unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
contracts/src/crypto/test/ElGamal.test.ts (1)

33-33: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Use const for immutable binding.

The contract variable is assigned once and never reassigned. Declare it with const instead of let to clearly signal immutability.

♻️ Proposed fix
-let contract: ElGamalSimulator;
+const contract = new ElGamalSimulator();

Then remove the assignment on line 36, which would now be redundant.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@contracts/src/crypto/test/ElGamal.test.ts` at line 33, The contract variable
is declared with let but is assigned only once and never reassigned, so it
should be declared as const instead. Change the let keyword to const for the
contract variable of type ElGamalSimulator, and then remove the redundant
assignment statement on line 36 that would now be unnecessary since const
bindings must be initialized at declaration.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CHANGELOG.md`:
- Line 12: The changelog entry on line 12 contains an unresolved placeholder
`#???` in the ElGamal module entry that needs to be replaced with the actual
GitHub issue or pull request number to make the release note traceable and
actionable. Locate the line containing "Add ElGamal module (#???)" and replace
the `#???` placeholder with the correct issue or PR reference number.

In `@contracts/src/crypto/ElGamal.compact`:
- Around line 187-193: The encryptPoint circuit function currently accepts a
zero value for the randomness parameter r, which creates a security
vulnerability by allowing plaintext exposure when r equals 0. Add an assertion
at the beginning of the encryptPoint function to validate that r is not zero,
similar to the existing identity check for pk. This guard should reject any
attempt to encrypt with zero randomness and will automatically protect all
functions that depend on encryptPoint (such as encrypt, addEncrypted,
subEncrypted, and rerandomize) from this vulnerability.

In `@contracts/src/crypto/test/mocks/MockElGamal.compact`:
- Around line 99-119: Remove the `pure` qualifier from the circuit declarations
in MockElGamal.compact to match the upstream ElGamal.compact signatures.
Specifically, change `export pure circuit` to `export circuit` for the three
assertion circuits: assertKeyPair, assertDecryptsToPoint, and assertDecryptsTo.
Then update ElGamalSimulator.ts to access these circuits correctly by replacing
`this.circuits.pure.assertKeyPair`, `this.circuits.pure.assertDecryptsToPoint`,
and `this.circuits.pure.assertDecryptsTo` with `this.circuits.assertKeyPair`,
`this.circuits.assertDecryptsToPoint`, and `this.circuits.assertDecryptsTo`
respectively.

---

Nitpick comments:
In `@contracts/src/crypto/test/ElGamal.test.ts`:
- Line 33: The contract variable is declared with let but is assigned only once
and never reassigned, so it should be declared as const instead. Change the let
keyword to const for the contract variable of type ElGamalSimulator, and then
remove the redundant assignment statement on line 36 that would now be
unnecessary since const bindings must be initialized at declaration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dad3aa24-f757-430d-9e53-a11b8b4078d4

📥 Commits

Reviewing files that changed from the base of the PR and between cb74178 and bc57019.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • contracts/package.json
  • contracts/src/crypto/ElGamal.compact
  • contracts/src/crypto/test/ElGamal.test.ts
  • contracts/src/crypto/test/mocks/MockElGamal.compact
  • contracts/src/crypto/test/simulators/ElGamalSimulator.ts
  • contracts/src/crypto/test/witnesses/ElGamalWitnesses.ts
  • package.json
  • turbo.json

Comment thread CHANGELOG.md Outdated
Comment thread contracts/src/crypto/ElGamal.compact
Comment thread contracts/src/crypto/test/mocks/MockElGamal.compact
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.

Add ElGamal module with primitives

1 participant