Skip to content

Commit

Permalink
fix: move to new BoundedVec Implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Envoy-VC committed Nov 3, 2024
1 parent 24f1a6e commit caec2f7
Show file tree
Hide file tree
Showing 27 changed files with 515 additions and 196 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/nightly-canary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ jobs:
test:
name: Test on Nargo ${{matrix.toolchain}}
runs-on: ubuntu-latest
defaults:
run:
working-directory: lib
steps:
- name: Checkout sources
uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pull-request-title.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ jobs:
types: |
fix
feat
chore
chore
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ jobs:
with:
token: ${{ secrets.GITHUB_TOKEN }}
command: manifest
release-type: simple
release-type: simple
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
target
target
.vscode
node_modules
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "1.0.0"
"lib": "1.0.0"
}
9 changes: 0 additions & 9 deletions Nargo.toml

This file was deleted.

37 changes: 12 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,31 @@ Noir JWT is a library for verifying JSON Web Tokens (JWTs) in Noir. The library

Available Functions:

- `verify_jwt` - Verifies a fixed array JWT with a secret key and returns the boolean value.
- `verify_jwt_var` - Verifies a vector JWT with a vector secret key and returns the boolean value.
- `verify_jwt` - Verifies a JWT with a secret key and returns the boolean value.

## Installation

In your Nargo.toml file, add the version of this library you would like to install under dependency:

```toml
[dependencies]
noir_jwt = { tag = "v1.0.0", git = "https://github.com/Envoy-VC/noir_jwt" }
noir_jwt = { tag = "v1.0.1", git = "https://github.com/Envoy-VC/noir_jwt", directory = "lib" }
```

## Usage

For Fixed Size Arrays:

```noir
fn main() {
let jwt: [u8; 315] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE3MjkyOTkxODYsImV4cCI6MTc2MDgzNTI1NywiYXVkIjoid3d3LmV4YW1wbGUuY29tIiwic3ViIjoianJvY2tldEBleGFtcGxlLmNvbSIsImZpcnN0X25hbWUiOiJKb2huIiwibGFzdF9uYW1lIjoiRG9lIiwiZW1haWwiOiJqb2huQGRvZS5jb20ifQ.Km5zQjxqq7tkHLNdGy-Rq3f05j3IqBUUNxeyvRPXXMI".as_bytes();
let secret_key: [u8; 10] = "secret_key".as_bytes();
let header = BoundedVec::from_array("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9".as_bytes());
let payload = BoundedVec::from_array(
"eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE3MjkyOTkxODYsImV4cCI6MTc2MDgzNTI1NywiYXVkIjoid3d3LmV4YW1wbGUuY29tIiwic3ViIjoianJvY2tldEBleGFtcGxlLmNvbSIsImZpcnN0X25hbWUiOiJKb2huIiwibGFzdF9uYW1lIjoiRG9lIiwiZW1haWwiOiJqb2huQGRvZS5jb20ifQ"
.as_bytes(),
);
let signature =
BoundedVec::from_array("Km5zQjxqq7tkHLNdGy-Rq3f05j3IqBUUNxeyvRPXXMI".as_bytes());
let jwt = JWT::new(header, payload, signature);
let secret_key = BoundedVec::from_array("secret_key".as_bytes());
let res: bool = verify_jwt(jwt, secret_key);
assert(res);
}
```

For Vectors:

```noir
fn main() {
let jwt: Vec<u8> = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE3MjkyOTkxODYsImV4cCI6MTc2MDgzNTI1NywiYXVkIjoid3d3LmV4YW1wbGUuY29tIiwic3ViIjoianJvY2tldEBleGFtcGxlLmNvbSIsImZpcnN0X25hbWUiOiJKb2huIiwibGFzdF9uYW1lIjoiRG9lIiwiZW1haWwiOiJqb2huQGRvZS5jb20ifQ.Km5zQjxqq7tkHLNdGy-Rq3f05j3IqBUUNxeyvRPXXMI".as_bytes_vec();
let secret_key: Vec<u8> = "secret_key".as_bytes_vec();
let res: bool = verify_jwt_var(jwt, secret_key);
assert(res);
}
```
3 changes: 3 additions & 0 deletions examples/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[workspace]
members = ["jwt_verify", "jwt_string_verify"]
default-member = "jwt_verify"
8 changes: 8 additions & 0 deletions examples/jwt_string_verify/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "jwt_string_verify"
type = "bin"
authors = ["Vedant Chainani <[email protected]>"]
compiler_version = ">=0.36.0"

[dependencies]
noir_jwt = { path = "../../lib" }
13 changes: 13 additions & 0 deletions examples/jwt_string_verify/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use noir_jwt::{types::{JWT, SecretKey}, verify_jwt};

fn main(
jwt_string: BoundedVec<u8, 1133>,
secret_key: SecretKey,
header_length: u32,
payload_length: u32,
signature_length: u32,
) -> pub bool {
let jwt: JWT = JWT::from_vec(jwt_string, header_length, payload_length, signature_length);
let result: bool = verify_jwt(jwt, secret_key);
result
}
8 changes: 8 additions & 0 deletions examples/jwt_verify/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "jwt_verify"
type = "bin"
authors = ["Vedant Chainani <[email protected]>"]
compiler_version = ">=0.36.0"

[dependencies]
noir_jwt = { path = "../../lib" }
6 changes: 6 additions & 0 deletions examples/jwt_verify/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use noir_jwt::{types::{JWT, SecretKey}, verify_jwt};

fn main(jwt: JWT, secret_key: SecretKey) -> pub bool {
let result = verify_jwt(jwt, secret_key);
result
}
Binary file added js/bun.lockb
Binary file not shown.
34 changes: 34 additions & 0 deletions js/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "js",
"version": "1.0.0",
"scripts": {
"test": "jest"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"jest": {
"roots": [
"<rootDir>"
],
"testPathIgnorePatterns": [
"/dist/",
"/node_modules/"
],
"testTimeout": 10000000000
},
"dependencies": {
"@noir-lang/backend_barretenberg": "^0.36.0",
"@noir-lang/noir_js": "^0.36.0",
"@noir-lang/noirc_abi": "^0.36.0",
"@types/jest": "^29.5.13",
"@types/mocha": "^10.0.9",
"@types/node": "^22.7.7",
"jest": "^29.7.0",
"jose": "^5.9.6",
"mocha": "^10.7.3",
"ts-jest": "^29.2.5",
"typescript": "^5.6.3"
}
}
135 changes: 135 additions & 0 deletions js/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import {
BarretenbergBackend,
CompiledCircuit,
ProofData,
UltraHonkBackend,
} from '@noir-lang/backend_barretenberg';
import { Noir } from '@noir-lang/noir_js';
import { InputValue, InputMap } from '@noir-lang/noirc_abi';

type ProvingBackend = 'honk' | 'plonk' | 'all';

export class Prover {
private plonk?: BarretenbergBackend;

private honk?: UltraHonkBackend;

private noir: Noir;

constructor(
/* The ACIR of the Noir circuit to prove */
circuit: CompiledCircuit,
/* Define the prover backend to use */
private provingBackend: ProvingBackend = 'plonk'
) {
// initialize the backends
if (provingBackend === 'plonk' || provingBackend === 'all') {
this.plonk = new BarretenbergBackend(circuit);
}
if (provingBackend === 'honk' || provingBackend === 'all') {
this.honk = new UltraHonkBackend(circuit);
}
// initialize the Noir instance
this.noir = new Noir(circuit);
}

/**
* Compute the witness for a given input to the circuit without generating a proof
*
* @param input - the input that should produce a satisfying witness for the circuit
* @returns - the witness for the input and the output of the circuit if satisfiable
*/
async simulateWitness(
input: InputMap
): Promise<{ witness: Uint8Array; returnValue: InputValue }> {
return this.noir.execute(input);
}

/**
* Generate a proof of a satisfying input to the circuit using a provided witness
*
* @param input - a satisfying witness for the circuit
* @param provingBackend - optionally provided if the class was initialized with both proving schemes
* @returns proof of valid execution of the circuit
*/
async prove(
witness: Uint8Array,
provingBackend?: ProvingBackend
): Promise<ProofData> {
// determine proving backend to use
let backend: BarretenbergBackend | UltraHonkBackend;
if (
(provingBackend && this.plonk) ||
(this.provingBackend === 'plonk' && this.plonk)
) {
backend = this.plonk;
} else if (
(provingBackend === 'honk' && this.honk) ||
(this.provingBackend === 'honk' && this.honk)
) {
backend = this.honk;
} else {
throw new Error(`Proving scheme ${this.provingBackend} not initialized`);
}

// generate the proof
return backend.generateProof(witness);
}

/**
* Simulate the witness for a given input and generate a proof
*
* @param input - the input that should produce a satisfying witness for the circuit
* @param provingBackend - optionally provided if the class was initialized with both proving schemes
* @returns proof of valid execution of the circuit
*/
async fullProve(
input: InputMap,
provingBackend?: ProvingBackend
): Promise<ProofData> {
const { witness } = await this.simulateWitness(input);
return this.prove(witness, provingBackend);
}

/**
* Verify a proof of a satisfying input to the circuit for a given proving scheme
*
* @param proof - the proof to verify
* @param provingBackend - optionally provided if the class was initialized with both proving schemes
* @returns true if the proof is valid, false otherwise
*/
async verify(
proof: ProofData,
provingBackend?: ProvingBackend
): Promise<boolean> {
// determine proving backend to use
let backend: BarretenbergBackend | UltraHonkBackend;
if (
(provingBackend && this.plonk) ||
(this.provingBackend === 'plonk' && this.plonk)
) {
backend = this.plonk;
} else if (
(provingBackend === 'honk' && this.honk) ||
(this.provingBackend === 'honk' && this.honk)
) {
backend = this.honk;
} else {
throw new Error(`Proving scheme ${this.provingBackend} not initialized`);
}
// verify the proof
return backend.verifyProof(proof);
}

/**
* End the prover wasm instance(s) and clean up resources
*/
async destroy() {
if (this.plonk) {
await this.plonk.destroy();
}
if (this.honk) {
await this.honk.destroy();
}
}
}
43 changes: 43 additions & 0 deletions js/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
export interface JWT {
header: BoundedVec;
payload: BoundedVec;
signature: BoundedVec;
}

export type BoundedVec = {
storage: number[];
len: number;
};

const pad = (arr: number[], length: number, value?: number): number[] => {
const res = arr.slice();
while (res.length < length) {
res.push(value || 0);
}
return res;
};

export const toBoundedVec = (data: string, maxLength: number): BoundedVec => {
const storage = pad(
data.split('').map((c) => c.charCodeAt(0)),
maxLength
);
return { storage, len: data.length };
};

export const toJWT = (data: string) => {
isValidJWT(data);
const [h, p, s] = data.split('.');
const header = toBoundedVec(h, 64);
const payload = toBoundedVec(p, 256);
const signature = toBoundedVec(s, 43);

return { header, payload, signature };
};

const isValidJWT = (data: string) => {
const [header, payload, signature] = data.split('.');
if (!header || !payload || !signature) {
throw new Error('Invalid JWT');
}
};
Loading

0 comments on commit caec2f7

Please sign in to comment.