Skip to content

Commit

Permalink
feat: make precomputed sha work
Browse files Browse the repository at this point in the history
  • Loading branch information
Bisht13 committed Sep 3, 2024
1 parent 39e028e commit 37ce05f
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 28 deletions.
Binary file modified bin/binary-arm64.node
Binary file not shown.
54 changes: 47 additions & 7 deletions src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ struct CircuitInput {
pub body_hash_idx: Option<usize>, // The index in header where the body hash is stored
}

#[derive(Debug, Clone)]
pub struct CircuitInputParams {
body: Vec<u8>, // The email body in bytes
header: Vec<u8>, // The email header in bytes
Expand Down Expand Up @@ -240,14 +241,14 @@ pub async fn generate_email_circuit_input(
let circuit_input_params = CircuitInputParams::new(circuit_params, circuit_options);

// Generate the circuit inputs from the parameters
let email_circuit_inputs = generate_circuit_inputs(circuit_input_params)?;
let email_circuit_inputs = generate_circuit_inputs(circuit_input_params.clone())?;

// Extract indices for various email components
let from_addr_idx = parsed_email.get_from_addr_idxes()?.0;
let domain_idx = parsed_email.get_email_domain_idxes()?.0;
let subject_idx = parsed_email.get_subject_all_idxes()?.0;
// Handle optional indices with default fallbacks
let code_idx = match parsed_email.get_invitation_code_idxes(
let mut code_idx = match parsed_email.get_invitation_code_idxes(
params
.as_ref()
.map_or(false, |p| p.ignore_body_hash_check.unwrap_or(false)),
Expand All @@ -259,13 +260,14 @@ pub async fn generate_email_circuit_input(
Ok(indexes) => indexes.0,
Err(_) => 0,
};
let command_idx = match parsed_email.get_command_idxes() {
Ok(indexes) => indexes.0,
Err(_) => 0,
};
let mut command_idx =
match parsed_email.get_command_idxes(circuit_input_params.ignore_body_hash_check) {
Ok(indexes) => indexes.0,
Err(_) => 0,
};

// Clean the body if necessary
let padded_cleaned_body = if parsed_email.need_soft_line_breaks() {
let padded_cleaned_body = if parsed_email.need_soft_line_breaks()? {
email_circuit_inputs
.body_padded
.clone()
Expand All @@ -274,6 +276,44 @@ pub async fn generate_email_circuit_input(
None
};

if email_circuit_inputs.precomputed_sha.is_some() {
let code = parsed_email.get_invitation_code(circuit_input_params.ignore_body_hash_check)?;
let command = parsed_email.get_command(circuit_input_params.ignore_body_hash_check)?;

// Find indices for the code and command in the body
if parsed_email.need_soft_line_breaks()? {
// If soft line breaks are needed, search in the cleaned body
code_idx = padded_cleaned_body
.as_ref()
.and_then(|body| body.windows(code.len()).position(|w| w == code.as_bytes()))
.unwrap_or(0); // Default to 0 if not found
command_idx = padded_cleaned_body
.as_ref()
.and_then(|body| {
// Search for the command in the cleaned body
body.windows(command.len())
.position(|w| w == command.as_bytes())
})
.unwrap_or(0); // Default to 0 if not found
} else {
// If no soft line breaks, search in the padded body
code_idx = email_circuit_inputs
.body_padded
.as_ref()
.and_then(|body| body.windows(code.len()).position(|w| w == code.as_bytes()))
.unwrap_or(0); // Default to 0 if not found
command_idx = email_circuit_inputs
.body_padded
.as_ref()
.and_then(|body| {
// Search for the command in the padded body
body.windows(command.len())
.position(|w| w == command.as_bytes())
})
.unwrap_or(0); // Default to 0 if not found
}
}

// Construct the email circuit input from the generated data
let email_auth_input = EmailCircuitInput {
padded_header: email_circuit_inputs.header_padded,
Expand Down
80 changes: 59 additions & 21 deletions src/parse_email.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,19 @@ impl ParsedEmail {
/// Extracts the invitation code from the canonicalized email body.
pub fn get_invitation_code(&self, ignore_body_hash_check: bool) -> Result<String> {
let regex_config = serde_json::from_str(include_str!("../regexes/invitation_code.json"))?;
let idxes = if ignore_body_hash_check {
extract_substr_idxes(&self.canonicalized_header, &regex_config)?[0]
} else if self.need_soft_line_breaks() {
extract_substr_idxes(&self.cleaned_body, &regex_config)?[0]
if ignore_body_hash_check {
let idxes = extract_substr_idxes(&self.canonicalized_header, &regex_config)?[0];
let str = self.canonicalized_header[idxes.0..idxes.1].to_string();
Ok(str)
} else if self.need_soft_line_breaks()? {
let idxes = extract_substr_idxes(&self.cleaned_body, &regex_config)?[0];
let str = self.cleaned_body[idxes.0..idxes.1].to_string();
Ok(str)
} else {
extract_substr_idxes(&self.canonicalized_body, &regex_config)?[0]
};
let str = self.canonicalized_body[idxes.0..idxes.1].to_string();
Ok(str)
let idxes = extract_substr_idxes(&self.canonicalized_body, &regex_config)?[0];
let str = self.canonicalized_body[idxes.0..idxes.1].to_string();
Ok(str)
}
}

/// Retrieves the index range of the invitation code within the canonicalized email body.
Expand All @@ -170,7 +174,7 @@ impl ParsedEmail {
if ignore_body_hash_check {
let idxes = extract_substr_idxes(&self.canonicalized_header, &regex_config)?[0];
Ok(idxes)
} else if self.need_soft_line_breaks() {
} else if self.need_soft_line_breaks()? {
let idxes = extract_substr_idxes(&self.cleaned_body, &regex_config)?[0];
Ok(idxes)
} else {
Expand Down Expand Up @@ -203,16 +207,37 @@ impl ParsedEmail {
Ok(str)
}

pub fn get_command(&self) -> Result<String> {
/// Extracts the command from the canonicalized email header or body.
pub fn get_command(&self, ignore_body_hash_check: bool) -> Result<String> {
let regex_config = serde_json::from_str(include_str!("../regexes/command.json"))?;
let idxes = extract_substr_idxes(&self.canonicalized_body, &regex_config)?[0];
let str = self.canonicalized_body[idxes.0..idxes.1].to_string();
Ok(str)
if ignore_body_hash_check {
let idxes = extract_substr_idxes(&self.canonicalized_header, &regex_config)?[0];
let str = self.canonicalized_header[idxes.0..idxes.1].to_string();
Ok(str)
} else {
let idxes = extract_substr_idxes(&self.canonicalized_body, &regex_config)?[0];
let str = self.canonicalized_body[idxes.0..idxes.1].to_string();
if str.contains("=\r\n") {
let cleaned_str = remove_quoted_printable_soft_breaks(str.as_bytes().to_vec());
// Remove any null bytes at the end of the cleaned string
let cleaned_str_no_nulls = cleaned_str
.into_iter()
.filter(|&byte| byte != 0)
.collect::<Vec<u8>>();
Ok(String::from_utf8(cleaned_str_no_nulls)?)
} else {
Ok(str)
}
}
}

pub fn get_command_idxes(&self) -> Result<(usize, usize)> {
/// Retrieves the index range of the command within the canonicalized email header or body.
pub fn get_command_idxes(&self, ignore_body_hash_check: bool) -> Result<(usize, usize)> {
let regex_config = serde_json::from_str(include_str!("../regexes/command.json"))?;
if self.need_soft_line_breaks() {
if ignore_body_hash_check {
let idxes = extract_substr_idxes(&self.canonicalized_header, &regex_config)?[0];
Ok(idxes)
} else if self.need_soft_line_breaks()? {
let idxes = extract_substr_idxes(&self.cleaned_body, &regex_config)?[0];
Ok(idxes)
} else {
Expand All @@ -221,19 +246,32 @@ impl ParsedEmail {
}
}

pub fn need_soft_line_breaks(&self) -> bool {
if let Ok(command) = self.get_command() {
command.contains("=\r\n")
} else {
false
}
/// Determines if the email body contains quoted-printable soft line breaks.
pub fn need_soft_line_breaks(&self) -> Result<bool> {
let regex_config = serde_json::from_str(include_str!("../regexes/command.json"))?;
let idxes = extract_substr_idxes(&self.canonicalized_body, &regex_config)?[0];
let str = self.canonicalized_body[idxes.0..idxes.1].to_string();
Ok(str.contains("=\r\n"))
}

/// Returns the cleaned email body with quoted-printable soft line breaks removed.
pub fn get_body_with_soft_line_breaks(&self) -> Result<String> {
Ok(self.cleaned_body.clone())
}
}

/// Removes quoted-printable soft line breaks from an email body.
///
/// Quoted-printable encoding uses `=` followed by `\r\n` to indicate a soft line break.
/// This function removes such sequences from the input `Vec<u8>`.
///
/// # Arguments
///
/// * `body` - A `Vec<u8>` representing the email body to be cleaned.
///
/// # Returns
///
/// A `Vec<u8>` with all quoted-printable soft line breaks removed.
pub(crate) fn remove_quoted_printable_soft_breaks(body: Vec<u8>) -> Vec<u8> {
let mut result = Vec::with_capacity(body.len());
let mut iter = body.iter().enumerate();
Expand Down

0 comments on commit 37ce05f

Please sign in to comment.