Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci: run mocha tests #14

Closed
wants to merge 28 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
0d3b065
ECDH Basics, tsconfig.json - No tests yet
Jul 26, 2024
a6ec58f
feat(ecdh): eCDH Encryption without internal tests
Jul 26, 2024
5bab3bb
feat(ecdh): ds
Jul 29, 2024
3502e23
feat(circuit): ds
Jul 29, 2024
3b4cba8
feat(circuit): ds
Jul 29, 2024
399ced1
feat(circuit): new Improved Circuit
Jul 29, 2024
d1be79c
refactor: noir Tests in JS
Jul 29, 2024
0d957d9
feat(ecdh): yO
Jul 30, 2024
120fd63
feat(ecdh): ds
Jul 30, 2024
ed1c46e
feat(ecdh): eCDH Test
Jul 30, 2024
f8f046f
Basic Unit Test Added
Aug 5, 2024
4d880f1
Formatted yarn fmt
Aug 5, 2024
25068d4
feat(ecdh): hI
Aug 5, 2024
820bb61
feat(ecdh): k
Aug 6, 2024
3c26856
refactor: l
Aug 11, 2024
9960f44
refactor(ecdh): Added two more tests, ECC BabyJubJub
Aug 12, 2024
83878f7
refactor(ecdh): NoirJS
Aug 13, 2024
696fb69
refactor(ecdh): README UPDATED
Aug 17, 2024
6375464
refactor(ecdh): refactor: mocha test files, test file
Aug 23, 2024
1385f9e
refactor(ecdh): refactor: package.json, .toml files
Aug 26, 2024
40dab0e
refactor(ecdh): refactor - .toml, lib.nr and main.nr in ECDH
Aug 26, 2024
fa95ff4
refactor(ecdh): refactor: package.json
Aug 26, 2024
b4c0027
refactor(ecdh): refactor: globals, lib, ecdh.test.ts
Aug 26, 2024
2a6bd28
refactor(ecdh): refactor: ecdh.test.ts
Aug 26, 2024
5d69406
refactor(ecdh): refactor: yarn fmt
Aug 26, 2024
973e3b7
refactor(ecdh): refactor: .gitignore added target
Aug 26, 2024
0ef2486
refactor(ecdh): refactor: removed wait times in test.ts
Aug 26, 2024
0cd0844
ci: run mocha tests
sripwoud Aug 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .dprint.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
"yarn.lock",
".yarn",
"packages/merkle-trees/src/globals.nr",
"packages/ecdh/src/globals.nr",
"target/",
],
"plugins": [
"https://plugins.dprint.dev/json-0.19.3.wasm",
Expand Down
68 changes: 61 additions & 7 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,60 @@ concurrency:
cancel-in-progress: true

jobs:
deps:
runs-on: ubuntu-latest
outputs:
cache-key: ${{ steps.cache-env.outputs.cache-key }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Output cache key
id: cache-env
run: echo "cache-key=${{ runner.os }}-node_modules-${{ hashFiles('yarn.lock') }}" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
id: cache
with:
path: node_modules
key: ${{ steps.cache-env.outputs.cache-key }}
restore-keys: ${{ runner.os }}-node_modules-

- if: steps.cache.outputs.cache-hit != 'true'
run: yarn

changed-files:
runs-on: ubuntu-latest
outputs:
any_nr_changed: ${{ steps.changed-files.outputs.any_changed }}
nr_any__changed: ${{ steps.changed-files.outputs.nr_any_changed }}
ts_any_changed: ${{ steps.changed-files.outputs.ts_any_changed }}
steps:
- uses: actions/checkout@v4
- uses: tj-actions/changed-files@v44
id: changed-files
with:
files: |
packages/**/*.{nr,toml}
Nargo.toml
files_yaml: |
nr:
- **/*.{nr,toml}
ts:
- tsconfig.json
- **/*.ts

style:
needs: deps
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: yarn
- run: yarn
- uses: actions/cache/restore@v4
with:
path: node_modules
key: ${{ needs.deps.outputs.cache-key }}
- run: yarn check

test:
test.nargo:
needs: changed-files
if: needs.changed-files.outputs.any_nr_changed == 'true'
runs-on: ubuntu-latest
Expand All @@ -44,3 +73,28 @@ jobs:
with:
toolchain: 0.30.0
- run: nargo test

test.mocha:
needs: deps
if: needs.changed-files.outputs.ts_any_changed == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- uses: actions/cache/restore@v4
with:
path: node_modules
key: ${{ needs.deps.outputs.cache-key }}
- run: yarn run mocha

tests:
needs: [test.mocha, test.nargo]
# workaround for https://github.com/orgs/community/discussions/13690
# https://stackoverflow.com/a/77066140/9771158
if: ${{ !(failure() || cancelled()) }}
runs-on: ubuntu-latest
steps:
- name: Tests OK (passed or skipped)
run: true
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*

# Nargo Compile
target/

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

Expand Down
1 change: 1 addition & 0 deletions .husky/commit-msg
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
. "$(dirname -- "$0")/_/husky.sh"

npx --no-install commitlint --edit $1

8 changes: 8 additions & 0 deletions .mocharc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"require": "ts-node/register",
"spec": "packages/ecdh/tests/**/*.test.ts",
"timeout": 25000,
"recursive": true,
"parallel": false,
"exit": true
}
2 changes: 1 addition & 1 deletion Nargo.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[workspace]
members = ["packages/merkle-trees"]
members = ["packages/ecdh", "packages/merkle-trees"]
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
## 📦 Packages

- [merkle-trees](https://github.com/privacy-scaling-explorations/zk-kit.noir/tree/main/packages/merkle-trees)
- [ecdh](https://github.com/privacy-scaling-explorations/zk-kit.noir/tree/main/packages/ecdh)

## 👥 Ways to contribute

Expand Down
23 changes: 17 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"check": "dprint check",
"fmt": "dprint fmt",
"postinstall": "husky && git config --local core.editor cat",
"test": "nargo test",
"build": "nargo compile",
"test": "npm run build && mocha && nargo test --workspace",
"version:release": "changelogithub"
},
"keywords": [
Expand All @@ -25,12 +26,22 @@
],
"packageManager": "[email protected]",
"devDependencies": {
"@commitlint/cli": "^18.6.1",
"@commitlint/config-conventional": "^18.6.2",
"@commitlint/cli": "^19.3.0",
"@commitlint/config-conventional": "^19.2.2",
"@types/chai": "^4",
"@types/mocha": "^10",
"changelogithub": "patch:changelogithub@npm%3A0.13.3#~/.yarn/patches/changelogithub-npm-0.13.3-1783949906.patch",
"czg": "^1.9.1",
"dprint": "^0.46.3",
"husky": "^9.0.11",
"lint-staged": "^15.2.2"
}
"husky": "4",
"lint-staged": "^15.2.2",
"ts-node": "^10.9.2",
"typescript": "^5.5.4",
"@noir-lang/backend_barretenberg": "^0.30.0",
"@noir-lang/noir_js": "^0.30.0",
"@noir-lang/noir_wasm": "^0.32.0",
"chai": "^4.5.0",
"mocha": "^10.7.0"
},
"dependencies": {}
}
5 changes: 5 additions & 0 deletions packages/ecdh/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
name = "ecdh"
type = "bin"
authors = ["YashBit"]
compiler_version = ">=0.30.0"
35 changes: 35 additions & 0 deletions packages/ecdh/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# ECDH Library using Baby JubJub Curve

This repository introduces a set of functions and utilities for elliptic curve cryptography using the Baby JubJub curve. The library provides essential operations for the Elliptic Curve Diffie-Hellman (ECDH) protocol, along with utility functions for key generation, field element conversion, and shared key computation.

## Features

- **Byte Array to Field Element Conversion:** Utility functions to convert byte arrays into field elements for use in elliptic curve operations.
- **Public Key Generation:** Generate public keys from private keys using the Baby JubJub curve, with both standard and optimized methods.
- **Shared Key Computation:** Compute shared keys for secure communication using the ECDH protocol.
- **Main Function:** A main function to generate ECDH shared keys, demonstrating the usage of the library.
- **Testing:** Comprehensive tests to verify the correctness of key derivation and field conversion functions.

## Compiling the Circuit

To compile the circuit, navigate one directory above the source code and run the following command:

```bash
nargo compile
```

## Running Tests

To run the tests for this library, use the following command:

```bash
yarn test
```

## Running Tests with Mocha

To run the tests using Mocha with TypeScript, use the following command:

```bash
npx mocha -r ts-node/register tests/ecdh.tests.ts
```
5 changes: 5 additions & 0 deletions packages/ecdh/src/globals.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Globals Edward Curves supported Baby JubJub
use dep::std::ec::consts::te::{baby_jubjub};

global BJJ = baby_jubjub();
global G = BJJ.base8;
58 changes: 58 additions & 0 deletions packages/ecdh/src/lib.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
mod globals;
use dep::std::ec::tecurve::affine::{Curve, Point};

// @@@@@@ Core ECDH Implementation

/// Converts a byte array to a field element.
/// # Arguments
/// * `bytes` - A fixed-size array of 32 bytes.
/// * `big_endian` - A boolean indicating if the byte array is in big-endian format.
/// # Returns
/// A `Field` element representing the converted byte array.
pub fn field_from_bytes(bytes: [u8; 32], big_endian: bool) -> Field {
let mut as_field: Field = 0;
let mut offset: Field = 1;

for i in 0..32 {
let index = if big_endian { 31 - i } else { i };
as_field += (bytes[index] as Field) * offset;
offset *= 256;
}

as_field
}

/// Computes a public key from a private key using the Baby JubJub curve.
/// # Arguments
/// * `private_key` - The private key as a `Field` element.
/// # Returns
/// The corresponding `Point` on the Baby JubJub curve.
pub fn derive_public_key(private_key: Field) -> Point {
let base_point = Point::new(
5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203,
);
let baby_jubjub_curve = Curve::new(168700, 168696, base_point);
baby_jubjub_curve.mul(private_key, base_point)
}

/// Optimized public key derivation using Baby JubJub curve.
/// # Arguments
/// * `private_key` - The private key as a `Field` element.
/// # Returns
/// The public key as a `Point` on the Baby JubJub curve.
pub fn derive_public_key_optimized(private_key: Field) -> Point {
let X = globals::BJJ.curve.mul(private_key, globals::G);
X
}

/// Computes a shared secret key using ECDH with the Baby JubJub curve.
/// # Arguments
/// * `private_key` - The private key as a `Field` element.
/// * `public_key` - The public key as a `Point` on the Baby JubJub curve.
/// # Returns
/// The shared secret key as a `Field` element.
pub fn derive_shared_key(private_key: Field, public_key: Point) -> Field {
let shared_key = globals::BJJ.curve.mul(private_key, public_key);
shared_key.x
}
45 changes: 45 additions & 0 deletions packages/ecdh/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
mod lib;
// ECDH Circuit
fn main(private_key1: [u8; 32], private_key2: [u8; 32]) {
// Convert private keys to fields
let private_key1_as_field = lib::field_from_bytes(private_key1, true);
let private_key2_as_field = lib::field_from_bytes(private_key2, true);

// Generate public keys from private keys
let public_key1 = lib::derive_public_key_optimized(private_key1_as_field);
let public_key2 = lib::derive_public_key_optimized(private_key2_as_field);

// Generate Both ECDH Shared Keys - Scalar Multiply
let shared_key1 = lib::derive_shared_key(private_key2_as_field, public_key1);
let shared_key2 = lib::derive_shared_key(private_key1_as_field, public_key2);
assert(shared_key1 == shared_key2);
}

// ########## Tests ##########

// Description: This test verifies the correctness of the optimized public key derivation function.
// It ensures that the `derive_public_key_optimized` function produces the same result as the
// standard `derive_public_key` function for a given test input.

#[test]
fn test_derive_public_key() {
let test_field_value = 0x3fbbccb240537392421955b07a0d65eded9e7637995bf2f9cfe29e19b580e4;
let derived_public_key = lib::derive_public_key_optimized(test_field_value);
let test_derived_public_key = lib::derive_public_key(test_field_value);
assert(derived_public_key.x == test_derived_public_key.x);
assert(derived_public_key.y == test_derived_public_key.y);
}

/// Test that the `field_from_bytes` function correctly converts a 32-byte array of zeroes to a field element with a value of `0`.
///
/// This test ensures that:
/// - The input is a 32-byte array initialized with zeroes.
/// - The `field_from_bytes` function is called with the input and a boolean flag set to `true`.
/// - The output is asserted to be `0`, verifying that the conversion is correct.
#[test]
// Define the test function for `field_from_bytes`
fn field_from_bytes_correct() {
let bytes: [u8; 32] = [0; 32];
let field_result = lib::field_from_bytes(bytes, true);
assert_eq(field_result, 0);
}
45 changes: 45 additions & 0 deletions packages/ecdh/tests/ecdh.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { BarretenbergBackend } from '@noir-lang/backend_barretenberg'
import { Noir } from '@noir-lang/noir_js'
import { ProofData } from '@noir-lang/types'
import { expect } from 'chai'
import { randomBytes } from 'crypto'
import { readFileSync } from 'fs'
import { resolve } from 'path'
import 'mocha'

function generatePrivateKey(): Uint8Array {
return randomBytes(32)
}

describe('ECDH Circuit Tests', function() {
let noir: Noir
let backend: BarretenbergBackend
let correctProof: ProofData

beforeEach(async () => {
const circuitFile = readFileSync(resolve(__dirname, '../../../target/ecdh.json'), 'utf-8')
const circuit = JSON.parse(circuitFile)
backend = new BarretenbergBackend(circuit)
noir = new Noir(circuit, backend)
const pk1 = generatePrivateKey()
const pk2 = generatePrivateKey()

// Convert Uint8Array to regular arrays
const input = {
private_key1: Array.from(pk1),
private_key2: Array.from(pk2),
}

correctProof = await noir.generateProof(input)
})

it('Should generate valid proof for correct input', async function() {
expect(correctProof.proof).to.be.instanceOf(Uint8Array)
})

it('Should verify valid proof for correct input', async function() {
expect(correctProof).to.not.be.undefined // Ensure proof is generated
const verification = await noir.verifyProof(correctProof)
expect(verification).to.be.true
})
})
20 changes: 20 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"compilerOptions": {
"outDir": "./dist",
"rootDir": ".",
"module": "commonjs",
"target": "es6",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true, // Add this line
"types": ["mocha", "node"]
},
"include": [
"./src/**/*.ts",
"./tests/**/*.ts"
],
"exclude": [
"./dist"
]
}
Loading