{"id":13631044,"url":"https://github.com/Electron-Labs/ed25519-circom","last_synced_at":"2025-04-17T17:32:22.133Z","repository":{"id":36966729,"uuid":"443689572","full_name":"Electron-Labs/ed25519-circom","owner":"Electron-Labs","description":"ED25519 implementation in Circom","archived":false,"fork":false,"pushed_at":"2023-06-30T08:32:38.000Z","size":106,"stargazers_count":111,"open_issues_count":9,"forks_count":15,"subscribers_count":8,"default_branch":"main","last_synced_at":"2024-11-08T22:36:59.541Z","etag":null,"topics":["circom","ed25519","groth16","zksnark","zksnarks"],"latest_commit_sha":null,"homepage":"https://docs.electronlabs.org/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Electron-Labs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-01-02T05:31:51.000Z","updated_at":"2024-10-21T12:36:45.000Z","dependencies_parsed_at":"2024-01-14T06:53:07.754Z","dependency_job_id":"72a98763-1f13-4ca9-b697-6c9e350688f1","html_url":"https://github.com/Electron-Labs/ed25519-circom","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Electron-Labs%2Fed25519-circom","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Electron-Labs%2Fed25519-circom/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Electron-Labs%2Fed25519-circom/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Electron-Labs%2Fed25519-circom/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Electron-Labs","download_url":"https://codeload.github.com/Electron-Labs/ed25519-circom/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249360065,"owners_count":21257165,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["circom","ed25519","groth16","zksnark","zksnarks"],"created_at":"2024-08-01T22:02:08.407Z","updated_at":"2025-04-17T17:32:21.407Z","avatar_url":"https://github.com/Electron-Labs.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# Circom Ed25519\n\n[![Twitter URL](https://img.shields.io/twitter/url/https/twitter.com/labs_electron.svg?style=social\u0026label=Follow%20%40labs_electron)](https://twitter.com/labs_electron)\n![Build Status](https://github.com/Electron-Labs/ed25519-circom/actions/workflows/actions.yml/badge.svg)\n[![License](https://img.shields.io/badge/license-UNLICENSED-red)](LICENSE)\n\u003c!--- \n[![CI status](https://github.com/Electron-Labs/circom-ed25519/actions/workflows/actions.yml/badge.svg?branch=master\")](CI) \n--\u003e\n\nCurve operations and signature verification for Ed25519 digital signature scheme in circom \n\n**WARNING:** This is a research project. It has not been audited and may contain bugs and security flaws. This implementation is NOT ready for production use.\n\nhttps://docs.electronlabs.org/circom-ed25519/overview\n\nThe circuits follow the reference implementation from [IETF RFC8032](https://datatracker.ietf.org/doc/html/rfc8032#section-6)\n\n\n## Installing dependencies\n- `npm install -g snarkjs`\n- `npm install`\n- Clone and install circom - [circom docs](https://docs.circom.io/getting-started/installation/)\n- If you want to build the `verify` circuit, you'll need to download a Powers of Tau file with `2^22` constraints and copy it into the `circuits` subdirectory of the project, with the name `pot22_final.ptau`. You can download Powers of Tau files from the Hermez trusted setup from [this repository](https://github.com/iden3/snarkjs#7-prepare-phase-2)\n\n## Testing the build\n- You can run the entire testing suite (sans scalar multiplication and signature verification) using `npm run test`\n- You can test specific long running tests using `npm run test-scalarmul` or `npm run test-verify`\n\n## Benchmarks\n\nAll benchmarks were run on a 16-core 3.0GHz, 32G RAM machine (AWS c5a.4xlarge instance).\n\n||verify.circom|\n|---|---|\n|Constraints                          |2564061 |\n|Circuit compilation                  |72s     |\n|Witness generation                   |6s      |\n|Trusted setup phase 2 key generation |841s    |\n|Trusted setup phase 2 contribution   |1040s   |\n|Proving key size                     |1.6G    |\n|Proving time (rapidsnark)            |6s      |\n|Proof verification time              |1s      |\n\n## Inputs\n`msg` is the data for the signature\n\n`R8` is the first 256 bits of the signature (LSB to MSB)\n\n`S` is the first 255 bits of the last 256 bits of the signature (LSB to MSB)\n\n`A` is the public key in binary (LSB to MSB)\n\n`PointA` is the point representing the public key on the elliptic curve (encoded in base 2^85 for brevity)\n\n`PointR` is the point representing the R8 value on the elliptic curve (encoded in base 2^85) \n\nThe [algorithm](https://datatracker.ietf.org/doc/html/rfc8032#section-6) we follow only takes in `A` and `R8` in binary form, and is decompressed to get `PointA` and `PointR` respectively. However, decompression is an expensive algorithm to perform in a circuit. On the other hand, compression is cheap and easy to implement. So, we use a nifty little trick to push the onus of providing both on the `prover` and perform equality checks after compressing the points within the circuit. [Ref](https://github.com/Electron-Labs/ed25519-circom/blob/532f638b4d6ae4684a1f0907df6c92676f0ae8df/circuits/verify.circom#L57)\n\nYou can find all helper functions to change encodings from well-known formats to circuit friendly formats [here](https://github.com/Electron-Labs/ed25519-circom/blob/master/test/utils.js)\n\n## Important Circuits\n\n### Modulus upto 2*(2^255-19) -\u003e Mod2p\n```python\n  # for input in\n  def mod2p(in):\n    diff = (2**255-19) - in\n    return in if diff \u003c 0 else diff\n```\n##### Available versions\n```js\n  // ModulusAgainst2P\n  // Elements are represented in binary\n  (in: [256]) =\u003e (out: [255])\n\n  // ModulusAgainst2Q\n  // Elements are represented in binary\n  (in: [254]) =\u003e (out: [253])\n\n  // ModulusAgainst2PChunked51\n  // Elements are represented in base 2^85\n  (in: [4]) =\u003e (out: [3])\n```\n\n### Modulus with 2^255-19 -\u003e Modulus25519\n```python\n  # for input `in` of unknown size, we explot that prime p\n  # is close to a power of 2\n  # input in broken down into an expression in = b + (p + 19)*c\n  # where b is the least significant 255 bits of input and,\n  # c is the rest of the bits. Then,\n  # in mod p = (b + (p + 19)*c) mod p\n  #          = (b mod p + 19*c mod p) mod p\n  def mod25519(in):\n    p = 2**255-19\n    if in \u003c p:\n      return in\n    b = in \u0026 ((1 \u003c\u003c 255) - 1)\n    c = in \u003e\u003e 255\n    bmodp = mod2p(b)\n    c19modp = mod25519(19*c)\n    return mod2p(bmodp + c19modp)\n```\n##### Available versions\n```js\n  // ModulusWith25519\n  // Elements are represented in binary\n  (a: [n]) =\u003e (out: [255])\n\n  // ModulusWith252c\n  // Elements are represented in binary\n  (a: [n]) =\u003e (out: [253])\n\n  // ModulusWith25519Chunked51\n  // Elements are represented in base 2^85\n  (a: [n]) =\u003e (out: [3])\n```\n\n### Point Addition -\u003e PointAdd\n```python\n  # Add two points on Curve25519\n  def point_add(P, Q):\n    p = 2**255-19\n    A, B = (P[1]-P[0]) * (Q[1]-Q[0]) % p, (P[1]+P[0]) * (Q[1]+Q[0]) % p\n    C, D = 2 * P[3] * Q[3] * d % p, 2 * P[2] * Q[2] % p\n    E, F, G, H = B-A, D-C, D+C, B+A\n    return (E*F, G*H, F*G, E*H)\n```\n##### Available versions\n```js\n  // PointAdd\n  // Elements are represented in base 2^85\n  (P: [4][3], Q: [4][3]) =\u003e (R: [4][3]) \n```\n\n### Scalar Multiplication -\u003e ScalarMul\n```python\n  # Multiply a point by scalar on Curve25519\n  def point_mul(s, P):\n    p = 2**255-19\n    Q = (0, 1, 1, 0)  # Neutral element\n    while s \u003e 0:\n      if s \u0026 1:\n        Q = point_add(Q, P)\n      P = point_add(P, P)\n      s \u003e\u003e= 1\n    return Q\n```\n##### Available versions\n```js\n  // ScalarMul\n  // scalar value is represented in binary\n  // Point elements are represented in base 2^85\n  (s: [255], P: [4][3]) =\u003e (sP: [4][3]) \n```\n\n### Ed25519 Signature verification -\u003e Verify\n```python\n  def verify(msg, public, Rs, s, A, R):\n    # Check that the compressed representation of a point \n    # equates to the paramaters extracted from signature\n    assert(Rs == point_compress(R))\n    assert(public == point_compress(A))\n    h = sha512_modq(Rs + public + msg)\n    sB = point_mul(s, G)\n    hA = point_mul(h, A)\n    return point_equal(sB, point_add(R, hA))\n```\n##### Available versions\n```js\n  // out signal value is 0 or 1 depending on whether the signature validation failed or passed\n  (msg: [n], A: [256], R8: [256], S: [255], PointA: [4][3], PointR: [4][3]) =\u003e (out);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FElectron-Labs%2Fed25519-circom","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FElectron-Labs%2Fed25519-circom","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FElectron-Labs%2Fed25519-circom/lists"}