Skip to content

Commit 70e6128

Browse files
committed
Add discrete_log_example as a normal folder
1 parent e8a91b4 commit 70e6128

File tree

5 files changed

+144
-0
lines changed

5 files changed

+144
-0
lines changed

discrete_log_example/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
circuits/target/

discrete_log_example/README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Noir Elliptic Curve Discrete Log Proof Circuit
2+
3+
This repository contains a Noir circuit for proving knowledge of the discrete logarithm on the secp256k1 elliptic curve. The circuit demonstrates, in zero-knowledge, that the prover knows a secret scalar \( k \) such that \( Q = k \cdot G \), where \( G \) is a public point and \( Q \) is the resulting public point.
4+
5+
## Features
6+
7+
- **Proves knowledge of discrete log:**
8+
Given a base point \( G = (x, y) \), a secret scalar \( k \) (kept private), and a result point \( Q = (x', y') \), the circuit proves that \( Q = k \cdot G \) without revealing \( k \).
9+
10+
- **Curve Membership Checks:**
11+
Both \( G \) and \( Q \) are asserted to be on the secp256k1 curve.
12+
13+
- **Flexible Test Suite:**
14+
Includes tests for:
15+
- Correct proofs (valid \( k \), \( G \), \( Q \))
16+
- Invalid results
17+
- Non-curve points
18+
- Edge cases (e.g., zero scalar, point at infinity)
19+
20+
## Structure
21+
22+
- `src/main.nr`
23+
Main Noir circuit, containing the core logic and tests.
24+
- `src/`
25+
May contain additional helper or test files.
26+
- `README.md`
27+
This file.
28+
29+
## Usage
30+
31+
### Requirements
32+
33+
- [Noir](https://noir-lang.org/) (v0.18+ recommended)
34+
- [nargo](https://noir-lang.org/docs/getting_started/quick_start#installation) (Noir package manager)
35+
- Rust (for installing Noir)
36+
37+
### Running Tests
38+
39+
To run all tests:
40+
41+
```bash
42+
nargo test
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "discrete_log_example"
3+
type = "bin"
4+
authors = [""]
5+
compiler_version = ">=1.0.0"
6+
7+
[dependencies]
8+
noir_bigcurve = { git = "https://github.com/noir-lang/noir_bigcurve", tag = "v0.9.0" }
9+
bignum = { tag = "v0.7.3", git = "https://github.com/noir-lang/noir-bignum" }
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[g_x]
2+
limbs = ["809934545436666192144300149831112600", "532189659306663695932703699144214274", "31166"]
3+
4+
[g_y]
5+
limbs = ["123079417438355278731207347528586424", "1134337383257087261818981465599813885", "18490"]
6+
7+
[k]
8+
limbs = ["2", "0", "0"]
9+
10+
[q_x]
11+
limbs = ["620769414058672675662360539292540645", "662428720985405666719129047941306460", "50692"]
12+
13+
[q_y]
14+
limbs = ["1278327165322711450801813382677652778", "545163776316525295403132726738087671", "6881"]
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use noir_bigcurve::curves::secp256k1::Secp256k1;
2+
use noir_bigcurve::curves::secp256k1::Secp256k1Scalar;
3+
use noir_bigcurve::scalar_field::ScalarFieldTrait;
4+
use noir_bigcurve::BigCurveTrait;
5+
use bignum::{Secp256k1_Fq, Secp256k1_Fr, BigNum};
6+
7+
// No 'pub' on these
8+
fn prove_discrete_log(
9+
g_x: Secp256k1_Fq,
10+
g_y: Secp256k1_Fq,
11+
k: Secp256k1_Fr,
12+
q_x: Secp256k1_Fq,
13+
q_y: Secp256k1_Fq,
14+
) {
15+
let G = Secp256k1 { x: g_x, y: g_y, is_infinity: false };
16+
assert(!G.is_infinity);
17+
G.validate_on_curve();
18+
19+
let Q = Secp256k1 { x: q_x, y: q_y, is_infinity: false };
20+
Q.validate_on_curve();
21+
22+
let k_scalar: Secp256k1Scalar = Secp256k1Scalar::from_bignum(k);
23+
let computed_Q = G.mul(k_scalar);
24+
25+
assert(computed_Q.x == q_x);
26+
assert(computed_Q.y == q_y);
27+
}
28+
29+
// Only 'pub' in main for public inputs
30+
pub fn main(
31+
g_x: pub Secp256k1_Fq,
32+
g_y: pub Secp256k1_Fq,
33+
k: Secp256k1_Fr,
34+
q_x: pub Secp256k1_Fq,
35+
q_y: pub Secp256k1_Fq,
36+
) {
37+
prove_discrete_log(g_x, g_y, k, q_x, q_y);
38+
}
39+
// Example test: Prove knowledge of k such that Q = kG
40+
#[test]
41+
fn test_prove_discrete_log() {
42+
let g_x = Secp256k1_Fq::from_limbs([809934545436666192144300149831112600, 532189659306663695932703699144214274, 31166]);
43+
let g_y = Secp256k1_Fq::from_limbs([123079417438355278731207347528586424, 1134337383257087261818981465599813885, 18490]);
44+
45+
// Secret scalar k (witness)
46+
let k = Secp256k1_Fr::from_limbs([2,0,0]);
47+
48+
// Public Q = k * G
49+
let q_x = Secp256k1_Fq::from_limbs([620769414058672675662360539292540645, 662428720985405666719129047941306460, 50692]);
50+
let q_y = Secp256k1_Fq::from_limbs([1278327165322711450801813382677652778, 545163776316525295403132726738087671, 6881]);
51+
52+
prove_discrete_log(g_x, g_y, k, q_x, q_y);
53+
}
54+
55+
#[test(should_fail)]
56+
fn test_prove_discrete_log_wrong_Q() {
57+
let g_x = Secp256k1_Fq::from_limbs([809934545436666192144300149831112600, 532189659306663695932703699144214274, 31166]);
58+
let g_y = Secp256k1_Fq::from_limbs([123079417438355278731207347528586424, 1134337383257087261818981465599813885, 18490]);
59+
60+
let k = Secp256k1_Fr::from_limbs([2,0,0]);
61+
62+
// Wrong Q
63+
let q_x = Secp256k1_Fq::from_limbs([258484535409603203050605737993582329, 716568843669635254349561846039718325, 63792]);
64+
let q_y = Secp256k1_Fq::from_limbs([3439865459799723184042666981123698, 638964607539318458049780617139410533, 14479]);
65+
66+
prove_discrete_log(g_x, g_y, k, q_x, q_y);
67+
}
68+
#[test(should_fail)]
69+
fn test_prove_discrete_log_wrong_point() {
70+
// Deliberately choose a point NOT on secp256k1
71+
let bad_x = Secp256k1_Fq::from_limbs([258484535409603203050605737993582330, 716568843669635254349561846039718325, 63792]);
72+
let bad_y = Secp256k1_Fq::from_limbs([3439865459799723184042666981123699, 638964607539318458049780617139410533, 14479]);
73+
let k = Secp256k1_Fr::from_limbs([2,0,0]);
74+
let q_x = Secp256k1_Fq::from_limbs([516969070819206406101211480282132933, 103909691554354635795316631799092074, 62049]);
75+
let q_y = Secp256k1_Fq::from_limbs([6879730919599446368085333962247398, 1277929215078636916099561234278821066, 28958]);
76+
77+
prove_discrete_log(bad_x, bad_y, k, q_x, q_y);
78+
}

0 commit comments

Comments
 (0)