Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/noir/lib/inclusion-check/country/src/lib.nr
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,39 @@ pub unconstrained fn unsafe_get_index<let N: u32>(
index
}

/// Check that the country list is correctly padded at the end with the empty
/// country code (three null characters). Once an empty country code is encountered,
/// all subsequent entries must also be empty. This prevents injection of country
/// codes after the first padding entry.
///
/// # Arguments
///
/// * `country_list`: The list of countries
pub fn check_country_list_padding<let N: u32>(country_list: [Alpha3CountryCode; N]) {
let empty = EMPTY_ALPHA3_COUNTRY_CODE.as_bytes();
let mut found_padding = false;
for i in 0..N {
let is_empty = country_list[i].as_bytes() == empty;
if is_empty {
found_padding = true;
}
if found_padding {
assert(is_empty, "Country list cannot contain country codes after the padding");
}
}
}

/// Check if the nationality from the MRZ is in the country list
///
/// # Arguments
///
/// * `dg1`: The MRZ
/// * `country_list`: The list of countries
pub fn check_nationality_inclusion<let N: u32>(dg1: DG1Data, country_list: [Alpha3CountryCode; N]) {
// Make sure the country list is properly padded with empty country codes at the end
// so that no additional country code can be injected after the first padding entry
check_country_list_padding(country_list);

let nationality_bytes = get_nationality_from_mrz(dg1);

// Safety: get the index of the country in the list from an unconstrained function
Expand All @@ -59,6 +85,10 @@ pub fn check_issuing_country_inclusion<let N: u32>(
dg1: DG1Data,
country_list: [Alpha3CountryCode; N],
) {
// Make sure the country list is properly padded with empty country codes at the end
// so that no additional country code can be injected after the first padding entry
check_country_list_padding(country_list);

let issuing_country_bytes = get_issuing_country_from_mrz(dg1);

// Safety: get the index of the country in the list from an unconstrained function
Expand Down
56 changes: 55 additions & 1 deletion src/noir/lib/inclusion-check/country/src/tests.nr
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use super::{check_issuing_country_inclusion, check_nationality_inclusion, unsafe_get_index};
use super::{
check_country_list_padding, check_issuing_country_inclusion, check_nationality_inclusion,
unsafe_get_index,
};
use utils::{constants::{EMPTY_ALPHA3_COUNTRY_CODE, SAMPLE_DG1}, types::Alpha3CountryCode};

fn pad_country_list<let N: u32>(country_list: [Alpha3CountryCode; N]) -> [Alpha3CountryCode; 200] {
Expand Down Expand Up @@ -47,3 +50,54 @@ fn test_check_issuing_country_inclusion_fail() {
let country_list = pad_country_list(["FRA", "NZL", "USA"]);
check_issuing_country_inclusion(SAMPLE_DG1, country_list);
}

#[test]
fn test_check_country_list_padding_padded() {
let country_list = pad_country_list(["AUS", "NZL", "USA"]);
check_country_list_padding(country_list);
}

#[test]
fn test_check_country_list_padding_full_list() {
let country_list: [Alpha3CountryCode; 3] = ["AUS", "NZL", "USA"];
check_country_list_padding(country_list);
}

#[test]
fn test_check_country_list_padding_fully_empty() {
let country_list: [Alpha3CountryCode; 3] =
[EMPTY_ALPHA3_COUNTRY_CODE, EMPTY_ALPHA3_COUNTRY_CODE, EMPTY_ALPHA3_COUNTRY_CODE];
check_country_list_padding(country_list);
}

#[test(should_fail_with = "Country list cannot contain country codes after the padding")]
fn test_check_country_list_padding_injection_after_padding() {
let country_list: [Alpha3CountryCode; 4] =
["AUS", EMPTY_ALPHA3_COUNTRY_CODE, "USA", EMPTY_ALPHA3_COUNTRY_CODE];
check_country_list_padding(country_list);
}

#[test(should_fail_with = "Country list cannot contain country codes after the padding")]
fn test_check_country_list_padding_starts_with_empty() {
let country_list: [Alpha3CountryCode; 3] =
[EMPTY_ALPHA3_COUNTRY_CODE, "AUS", EMPTY_ALPHA3_COUNTRY_CODE];
check_country_list_padding(country_list);
}

#[test(should_fail_with = "Country list cannot contain country codes after the padding")]
fn test_check_nationality_inclusion_fail_injection_after_padding() {
let mut country_list: [Alpha3CountryCode; 200] = [EMPTY_ALPHA3_COUNTRY_CODE; 200];
country_list[0] = "AUS";
// Inject a country code after the padding has started
country_list[5] = "USA";
check_nationality_inclusion(SAMPLE_DG1, country_list);
}

#[test(should_fail_with = "Country list cannot contain country codes after the padding")]
fn test_check_issuing_country_inclusion_fail_injection_after_padding() {
let mut country_list: [Alpha3CountryCode; 200] = [EMPTY_ALPHA3_COUNTRY_CODE; 200];
country_list[0] = "AUS";
// Inject a country code after the padding has started
country_list[5] = "USA";
check_issuing_country_inclusion(SAMPLE_DG1, country_list);
}
Loading