Skip to content

Commit

Permalink
Merge pull request #22 from zkemail/TomAFrench-tf/add-ci
Browse files Browse the repository at this point in the history
chore(ci): add a CI setup real
  • Loading branch information
jp4g authored Nov 25, 2024
2 parents 24db6af + 21de652 commit b8c9191
Show file tree
Hide file tree
Showing 12 changed files with 511 additions and 351 deletions.
66 changes: 66 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Noir tests

on:
push:
branches:
- main
pull_request:

jobs:
test:
name: Test on Nargo ${{matrix.toolchain}}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
toolchain: [0.36.0]
steps:
- name: Checkout sources
uses: actions/checkout@v4

- name: Install Nargo
uses: noir-lang/[email protected]
with:
toolchain: ${{ matrix.toolchain }}

- name: Run Noir tests
working-directory: ./lib
run: nargo test

format:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4

- name: Install Nargo
uses: noir-lang/[email protected]
with:
toolchain: 0.36.0

- name: Run formatter
working-directory: ./lib
run: nargo fmt --check

# This is a job which depends on all test jobs and reports the overall status.
# This allows us to add/remove test jobs without having to update the required workflows.
tests-end:
name: Noir End
runs-on: ubuntu-latest
# We want this job to always run (even if the dependant jobs fail) as we want this job to fail rather than skipping.
if: ${{ always() }}
needs:
- test
- format

steps:
- name: Report overall success
run: |
if [[ $FAIL == true ]]; then
exit 1
else
exit 0
fi
env:
# We treat any cancelled, skipped or failing jobs as a failure for the workflow as a whole.
FAIL: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') }}
26 changes: 15 additions & 11 deletions lib/src/dkim.nr
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
use dep::std::{collections::bounded_vec::BoundedVec, hash::{sha256_var, pedersen_hash}, panic::panic};
use dep::bignum::{params::BigNumParams, RuntimeBigNum};
use dep::rsa::{rsa::verify_sha256_pkcs1v15, types::{RBN1024, RBN2048}};
use std::hash::{sha256_var, pedersen_hash};
use bignum::{params::BigNumParams, RuntimeBigNum};
use rsa::{rsa::verify_sha256_pkcs1v15, types::{RBN1024, RBN2048}};
use crate::{KEY_LIMBS_1024, KEY_LIMBS_2048, RSA_EXPONENT};


pub struct RSAPubkey<let KEY_LIMBS: u32> {
modulus: [Field; KEY_LIMBS],
redc: [Field; KEY_LIMBS],
}

impl<let KEY_LIMBS: u32> RSAPubkey<KEY_LIMBS> {
fn hash(self) -> Field {

pub fn new(modulus: [Field; KEY_LIMBS], redc: [Field; KEY_LIMBS]) -> Self {
Self { modulus, redc }
}

pub fn hash(self) -> Field {
pedersen_hash(self.modulus)
}
}

impl RSAPubkey<KEY_LIMBS_1024> {
fn verify_dkim_signature<let MAX_HEADER_LENGTH: u32>(
pub fn verify_dkim_signature<let MAX_HEADER_LENGTH: u32>(
self,
header: BoundedVec<u8, MAX_HEADER_LENGTH>,
signature: [Field; KEY_LIMBS_1024]
signature: [Field; KEY_LIMBS_1024],
) {
// hash the header
let header_hash = sha256_var(header.storage, header.len() as u64);
let header_hash = sha256_var(header.storage(), header.len() as u64);

let params: BigNumParams<KEY_LIMBS_1024, 1024> =
BigNumParams::new(false, self.modulus, self.redc);
Expand All @@ -35,13 +39,13 @@ impl RSAPubkey<KEY_LIMBS_1024> {
}

impl RSAPubkey<KEY_LIMBS_2048> {
fn verify_dkim_signature<let MAX_HEADER_LENGTH: u32>(
pub fn verify_dkim_signature<let MAX_HEADER_LENGTH: u32>(
self,
header: BoundedVec<u8, MAX_HEADER_LENGTH>,
signature: [Field; KEY_LIMBS_2048],
) {
// hash the header
let header_hash = sha256_var(header.storage, header.len() as u64);
let header_hash = sha256_var(header.storage(), header.len() as u64);

let params: BigNumParams<KEY_LIMBS_2048, 2048> =
BigNumParams::new(false, self.modulus, self.redc);
Expand All @@ -51,4 +55,4 @@ impl RSAPubkey<KEY_LIMBS_2048> {
// verify the DKIM signature over the header
assert(verify_sha256_pkcs1v15(header_hash, signature, RSA_EXPONENT));
}
}
}
32 changes: 18 additions & 14 deletions lib/src/headers/body_hash.nr
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use dep::base64::{BASE64_DECODER};
use dep::std::collections::bounded_vec::BoundedVec;
use crate::{Sequence, BODY_HASH_BASE64_LENGTH, MAX_DKIM_HEADER_FIELD_LENGTH, headers::constrain_header_field};
use base64::BASE64_DECODER;
use crate::{
Sequence, BODY_HASH_BASE64_LENGTH, MAX_DKIM_HEADER_FIELD_LENGTH,
headers::constrain_header_field,
};

/**
* Constrained access to the body hash in the header
Expand All @@ -13,24 +15,26 @@ use crate::{Sequence, BODY_HASH_BASE64_LENGTH, MAX_DKIM_HEADER_FIELD_LENGTH, hea
pub fn get_body_hash<let MAX_HEADER_LENGTH: u32>(
header: BoundedVec<u8, MAX_HEADER_LENGTH>,
dkim_header_field_sequence: Sequence,
body_hash_index: u32
body_hash_index: u32,
) -> [u8; 32] {
// constrain the access of dkim signature field
let header_field_name: [u8; 14] = comptime {
"dkim-signature".as_bytes()
};
constrain_header_field::<MAX_HEADER_LENGTH, MAX_DKIM_HEADER_FIELD_LENGTH, 14>(header, dkim_header_field_sequence, header_field_name);
let header_field_name: [u8; 14] = comptime { "dkim-signature".as_bytes() };
constrain_header_field::<MAX_HEADER_LENGTH, MAX_DKIM_HEADER_FIELD_LENGTH, 14>(
header,
dkim_header_field_sequence,
header_field_name,
);
// constrain access to the body hash
assert(
body_hash_index > dkim_header_field_sequence.index
& body_hash_index < dkim_header_field_sequence.end_index(), "Body hash index accessed outside of DKIM header field"
& body_hash_index < dkim_header_field_sequence.end_index(),
"Body hash index accessed outside of DKIM header field",
);
let bh_prefix: [u8; 3] = comptime {
"bh=".as_bytes()
};
let bh_prefix: [u8; 3] = comptime { "bh=".as_bytes() };
for i in 0..3 {
assert(
header.get_unchecked(body_hash_index - 3 + i) == bh_prefix[i], "No 'bh=' prefix found at asserted bh index"
header.get_unchecked(body_hash_index - 3 + i) == bh_prefix[i],
"No 'bh=' prefix found at asserted bh index",
);
}
// get the body hash
Expand All @@ -46,7 +50,7 @@ pub fn get_body_hash<let MAX_HEADER_LENGTH: u32>(
*/
pub fn get_body_hash_unsafe<let MAX_HEADER_LENGTH: u32>(
header: BoundedVec<u8, MAX_HEADER_LENGTH>,
body_hash_index: u32
body_hash_index: u32,
) -> [u8; 32] {
// get the body hash
let mut body_hash_encoded: [u8; BODY_HASH_BASE64_LENGTH] = [0; BODY_HASH_BASE64_LENGTH];
Expand Down
35 changes: 22 additions & 13 deletions lib/src/headers/email_address.nr
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
use dep::std::collections::bounded_vec::BoundedVec;
use crate::{
Sequence, MAX_EMAIL_ADDRESS_LENGTH, EMAIL_ADDRESS_CHAR_TABLE,
headers::constrain_header_field_detect_last_angle_bracket
headers::constrain_header_field_detect_last_angle_bracket,
};

pub fn get_email_address<let MAX_HEADER_LENGTH: u32, let HEADER_FIELD_NAME_LENGTH: u32>(
header: BoundedVec<u8, MAX_HEADER_LENGTH>,
header_field_sequence: Sequence,
email_address_sequence: Sequence,
header_field_name: [u8; HEADER_FIELD_NAME_LENGTH]
header_field_name: [u8; HEADER_FIELD_NAME_LENGTH],
) -> BoundedVec<u8, MAX_EMAIL_ADDRESS_LENGTH> {
// check field is uninterrupted and matches the expected field name
let last_angle_bracket = constrain_header_field_detect_last_angle_bracket::<MAX_HEADER_LENGTH, MAX_EMAIL_ADDRESS_LENGTH + HEADER_FIELD_NAME_LENGTH + 1, HEADER_FIELD_NAME_LENGTH>(header, header_field_sequence, header_field_name);
let last_angle_bracket = constrain_header_field_detect_last_angle_bracket::<MAX_HEADER_LENGTH, MAX_EMAIL_ADDRESS_LENGTH + HEADER_FIELD_NAME_LENGTH + 1, HEADER_FIELD_NAME_LENGTH>(
header,
header_field_sequence,
header_field_name,
);
// if angle bracket found, assert index is +1
if last_angle_bracket != 0 {
assert(
email_address_sequence.index == last_angle_bracket + 1, "Email address must start immediately after '<' if bracket is present"
email_address_sequence.index == last_angle_bracket + 1,
"Email address must start immediately after '<' if bracket is present",
);
}
// check email sequence is within header field
assert(
email_address_sequence.index >= header_field_sequence.index
& email_address_sequence.end_index() <= header_field_sequence.end_index(), "Email address sequence out of bounds"
& email_address_sequence.end_index() <= header_field_sequence.end_index(),
"Email address sequence out of bounds",
);

// constrained get email address
Expand All @@ -30,18 +35,22 @@ pub fn get_email_address<let MAX_HEADER_LENGTH: u32, let HEADER_FIELD_NAME_LENGT

pub fn parse_email_address<let MAX_HEADER_LENGTH: u32>(
header: BoundedVec<u8, MAX_HEADER_LENGTH>,
email_address_sequence: Sequence
email_address_sequence: Sequence,
) -> BoundedVec<u8, MAX_EMAIL_ADDRESS_LENGTH> {
// check the sequence is proceeded by an acceptable character
if email_address_sequence.index != 0 {
assert(
EMAIL_ADDRESS_CHAR_TABLE[header.get_unchecked(email_address_sequence.index - 1)] == 2, "Email address must start with an acceptable character"
EMAIL_ADDRESS_CHAR_TABLE[header.get_unchecked(email_address_sequence.index - 1)] == 2,
"Email address must start with an acceptable character",
);
}
if email_address_sequence.end_index() < header.len() {
assert(
EMAIL_ADDRESS_CHAR_TABLE[header.get_unchecked(email_address_sequence.index + email_address_sequence.length)]
== 3, "Email address must end with an acceptable character"
EMAIL_ADDRESS_CHAR_TABLE[header.get_unchecked(
email_address_sequence.index + email_address_sequence.length,
)]
== 3,
"Email address must end with an acceptable character",
);
}
// check the email address and assign
Expand All @@ -50,15 +59,15 @@ pub fn parse_email_address<let MAX_HEADER_LENGTH: u32>(
let index = email_address_sequence.index + i;
if index < email_address_sequence.end_index() {
let letter = header.get_unchecked(index);
email_address.storage[i] = letter;
email_address.set_unchecked(i, letter);
assert(
EMAIL_ADDRESS_CHAR_TABLE[letter] == 1, "Email address must only contain acceptable characters"
EMAIL_ADDRESS_CHAR_TABLE[letter] == 1,
"Email address must only contain acceptable characters",
);
}
}
email_address.len = email_address_sequence.length;
// todo: should probably introduce a check for @

email_address
}

Loading

0 comments on commit b8c9191

Please sign in to comment.