Skip to content

Latest commit

 

History

History
113 lines (84 loc) · 4.03 KB

README.md

File metadata and controls

113 lines (84 loc) · 4.03 KB

Noir JWT Verifier

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

  • Supports arbitrary sized inputs.
  • Supports partial hashing on the input.
  • Uses string_search lib to extract and verify claims efficiently.

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 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.assert_claim::<300, 5, MAX_NONCE_LENGTH>("nonce".as_bytes(), nonce);
}

With partial hash

use 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.assert_claim::<300, 5, MAX_NONCE_LENGTH>("nonce".as_bytes(), nonce);
}
  • b64_offset is the index in data from which the circuit will try to decode the base64
    • You can set this to the index of payload data (index after first . in the JWT string)
    • When using partial SHA, this should be 1, 2, or 3 to make the data after partial hash a multiple of 4
  • 300 in the above example is the PAYLOAD_RANGE, which is the index in the base64 encoded payload (from the b64_offset) up to which we will look for the key:value pair.
    • This essentially means that everything from b64_offset to PAYLOAD_RANGE should be a valid base64 character of the payload, and the key:value pair should be present in this range.
    • PAYLOAD_RANGE should be a multiple of 4 to be a valid base64 chunk.
  • If you are want to verify multiple claims, it is better to use the same PAYLOAD_RANGE (maximum needed) for all assert_claim calls as the compiler will optimize them.

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 assert_claim 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

  • Add support for arbitrary input sizes without RANGE extraction
  • Add a JS SDK
  • Add tests