https://github.com/zkpersona/noir-jwt
A JWT Verification and Claims Attestation Library for Noir.
https://github.com/zkpersona/noir-jwt
hmac-sha256 jwt jwt-verifier library noir-lang rsa-sha256 zero-knowledge
Last synced: 9 months ago
JSON representation
A JWT Verification and Claims Attestation Library for Noir.
- Host: GitHub
- URL: https://github.com/zkpersona/noir-jwt
- Owner: zkpersona
- License: mit
- Created: 2024-10-19T00:48:21.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-04-11T08:10:01.000Z (about 1 year ago)
- Last Synced: 2025-04-11T09:52:18.759Z (about 1 year ago)
- Topics: hmac-sha256, jwt, jwt-verifier, library, noir-lang, rsa-sha256, zero-knowledge
- Language: Noir
- Homepage:
- Size: 140 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Noir JWT
A JWT Verification and Claims Attestation Library for Noir. This library provides a set of types and functions for verifying different JWT schemes. The current implementation supports the following JWT schemes:
- HMAC-SHA256 (HS256)
- RSA-SHA256 (RS256 with 2048-bit keys)
JWT structure is defined in JWT struct, which is generic over the signature type, header length, payload length, and signature length. Signature type is either `BoundedVec` for HMAC or `BoundedVec` for RSA.
```noir
pub type Header = BoundedVec;
pub type Payload = BoundedVec;
pub type Signature = BoundedVec;
pub struct JWT {
pub header: Header,
pub payload: Payload,
pub signature: Signature,
}
```
## Installation
In your _Nargo.toml_ file, add the version of this library you would like to install under dependency:
```toml
[dependencies]
noir_jwt = { tag = "v0.1.0", git = "https://github.com/zkpersona/noir-jwt", directory = "lib" }
```
## Usage
### HMAC-SHA256 (HS256) Verification
```noir
use noir_jwt::JWT_H256 as JWT;
use noir_jwt::types::SecretKey;
pub global MAX_HEADER_LENGTH: u32 = 64;
pub global MAX_PAYLOAD_LENGTH: u32 = 256;
pub global MAX_SIGNATURE_LENGTH: u32 = 43;
pub global MAX_SECRET_KEY_LENGTH: u32 = 64;
fn main(
jwt: JWT,
secret_key: SecretKey,
) -> pub bool {
jwt.verify(secret_key)
}
```
### RSA-SHA256 (RS256) Verification
```noir
use noir_jwt::{constants::KEY_LIMBS_2048, JWT_RS256 as JWT, RSAPubkey};
pub global MAX_HEADER_LENGTH: u32 = 32;
pub global MAX_PAYLOAD_LENGTH: u32 = 128;
fn main(
jwt: JWT,
pub_key: RSAPubkey,
) -> pub bool {
jwt.verify(pub_key, 65537)
}
```
### Claim Attestation
```noir
use base64::BASE64_URL_DECODER::decode_var;
use json_parser::JSON1kb;
use noir_jwt::JWT_H256 as JWT;
use noir_jwt::types::{Payload, SecretKey};
pub global MAX_HEADER_LENGTH: u32 = 64;
pub global MAX_PAYLOAD_LENGTH: u32 = 256;
pub global MAX_SIGNATURE_LENGTH: u32 = 43;
pub global MAX_SECRET_KEY_LENGTH: u32 = 64;
unconstrained fn parse_json(payload: Payload) -> JSON1kb {
let mut decoded: BoundedVec = decode_var(payload);
for _i in decoded.len()..decoded.max_len() {
decoded.push(32); // Whitespace character
}
let json: JSON1kb = JSON1kb::parse_json(decoded.storage());
json
}
fn main(
jwt: JWT,
secret_key: SecretKey,
expected_email: BoundedVec,
) -> pub bool {
let verified = jwt.verify(secret_key);
assert(verified);
/// Safety: Payload is already verified
let json: JSON1kb = unsafe { parse_json(jwt.payload) };
let email: BoundedVec = json.get_string_unchecked("sub".as_bytes());
println(expected_email);
println(email);
email == expected_email
}
```
### Library Usage
This library provides a set of helpers functions to generate circuit inputs. To install the library, run the following command:
```bash
npm install @zkpersona/noir-jwt
# or
yarn add @zkpersona/noir-jwt
# or
pnpm add @zkpersona/noir-jwt
# or
bun add @zkpersona/noir-jwt
```
Here is an example of how to use the library to generate inputs for H256 proof:
```typescript
import type { InputMap } from '@noir-lang/noir_js';
import { BoundedVec, U8 } from '@zkpersona/noir-helpers';
import { JWT } from '@zkpersona/noir-jwt';
const jwt = new JWT(
'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNzQ0MzUxOTAzLCJleHAiOjE3NDQzNTkxMDN9.lKtDhCu1-ejUIEwrXPFWaaEvaXc5qZg1jUfxFxciQJ4'
);
const jwtInputs = jwt.toCircuitInputs({
maxHeaderLength: 64,
maxPayloadLength: 256,
maxSignatureLength: 43,
});
const secretKey = Uint8Array.from('secret_key');
const secretKeyArray = Array.from(secretKey).map((e) => new U8(e));
const secretKeyVec = new BoundedVec(64, () => new U8(0));
secretKeyVec.extendFromArray(secretKeyArray);
const inputs: InputMap = {
...jwtInputs,
secret_key: secretKeyVec.toJSON(),
};
```
And here is an example of how to use the library to generate inputs for RS256 proof:
```typescript
import type { InputMap } from '@noir-lang/noir_js';
import { JWT, RSAPubKey } from '@zkpersona/noir-jwt';
const pubKeyPem = `-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEArlZIVMkJ+pyjixkrQiZXYd3MwbIHUzsFwSCB/rjds1FpfgXAsArG
8EtyrKfDwZxdccLUGIlmdKO6uurL/wbcJcYxiMcJON5vPXztUAMeCNc6gvmlcsRa
5V1cdpFcjOsGwJKp/n+iIV5VOODfRdiIcE/YKb7fhCsu8xv03SNgUSi/7cwA+0nZ
6rzmQuWYYQ0VNMN0YJvFZe3iacjgKtQOlM79E6lD+s3noxp0N8kW+Aefv6lVxUD3
EbXTyxPSYR8XOrud88rsQqBrKfwz8L+IEk/dx4VVC9jXQAxvJ/NMRrOs3oitq91L
3R5k630h2aroD2sJi35ooWovymjAlLv+LwIDAQAB
-----END RSA PUBLIC KEY-----`;
const jwt = new JWT(
'eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNzQ0MzUyMTMyLCJleHAiOjE3NDQzNTkzMzJ9.e4wBkSuW7Xpx6oChK7dm9nZG4P6pqsibj54nqQ4Zrt5wAz0Ibeh5MRyv8YMV9TzUE5ta8n9P-EJuqwtPohL2uMuoPwnIxKWXt4qAOtxMkWFLEckHSYoHCXqvph-UyPLbGL2zTSJJP-SgTr7E9Y1bU5qM46oieDiQL0ao4CEk5pXjjH5ueAvyA5jfcNAr2kVYsZh8oFFs00VZcUPUXVyZsfjG7EvZ1O6jQ_nCgYqzpQL-kW9ZI_prSNtvDX4wK1JFMVqXHma7XNbvmZNKSvvWhKw-V-lfL3RgjcrVyZnTV-apaZTr6ihOEXlenyU-zOhRfwzAic9HdFG8DUR6_xVqHA',
'RS256'
);
const pubKey = RSAPubKey.fromPem(pubKeyPem);
const jwtInputs = jwt.toCircuitInputs({
maxHeaderLength: 32,
maxPayloadLength: 128,
maxSignatureLength: 18,
});
const inputs: InputMap = {
...jwtInputs,
...pubKey.toCircuitInputs(),
};
```
## License
This project is licensed under the MIT License.
See the [LICENSE](LICENSE) file for details.
## Contributing
Contributions are welcome! Please open an issue or submit a pull request.