Home

Awesome

Noir JWT Verifier

Noir library to verify JWT tokens, and prove claims. Currently only supports RS256 with 2048 bit keys.

You can learn more about JWT here.

Installation

In your Nargo.toml file, add jwt as a dependency with the version you want to install:

[dependencies]
jwt = { tag = "v0.1.0", git = "https://github.com/saleel/noir-jwt" }

Usage

Assusming you installed the latest version, you can use it in your Noir program like this:

use dep::jwt::JWT;

global MAX_DATA_LENGTH: u32 = 900;
global MAX_NONCE_LENGTH: u32 = 32;

fn main(
    data: BoundedVec<u8, MAX_DATA_LENGTH>,
    b64_offset: u32,
    pubkey_modulus_limbs: pub [Field; 18],
    redc_params_limbs: [Field; 18],
    signature_limbs: [Field; 18],
    domain: pub BoundedVec<u8, MAX_DOMAIN_LENGTH>,
    nonce: pub BoundedVec<u8, MAX_NONCE_LENGTH>,
) {
    let jwt = JWT::init(
        data,
        b64_offset: u32,
        pubkey_modulus_limbs,
        redc_params_limbs,
        signature_limbs,
    );

    jwt.verify();

    // Validate key value pair in payload JSON
    jwt.validate_key_value::<300, 5, MAX_NONCE_LENGTH>("nonce".as_bytes(), nonce);
}

With partial hash

use dep::jwt::JWT;

global MAX_PARTIAL_DATA_LENGTH: u32 = 640; // Data after partial SHA
global MAX_NONCE_LENGTH: u32 = 32;

fn main(
    partial_data: BoundedVec<u8, MAX_PARTIAL_DATA_LENGTH>,
    partial_hash: [u32; 8],
    full_data_length: u32,
    b64_offset: u32,
    pubkey_modulus_limbs: pub [Field; 18],
    redc_params_limbs: [Field; 18],
    signature_limbs: [Field; 18],
    nonce: pub BoundedVec<u8, MAX_NONCE_LENGTH>,
) {
    let jwt = JWT::init_with_partial_hash(
        partial_data,
        partial_hash,
        full_data_length,
        b64_offset,
        pubkey_modulus_limbs,
        redc_params_limbs,
        signature_limbs,
    );

    jwt.verify();

    // Validate key value pair in payload JSON
    jwt.validate_key_value::<300, 5, MAX_NONCE_LENGTH>("nonce".as_bytes(), nonce);
}

Input generation from JS

A JS SDK will be released soon to generate the inputs for Noir. In the meantime, refer to this example. This is for the partial SHA case, but you can use a trimmed version of the same function for the full SHA case - though you would set b64_offset as start of the payload, something like (idToken.indexOf(idToken.split(".")[1]) + 1).

Limitation

Base64 does not support variable length in put now. Due to this you need to specify a PAYLOAD_RANGE when calling validate_key_value which should always contain valid base64 characters of the payload (no padding characters). This makes it difficult to verify key/value if they are the last key in the payload - as you might not know the exact length of the payload in advance. This will be fixed in a future release.

TODO