Skip to content

Conversation

@BornPsych
Copy link

@BornPsych BornPsych commented Sep 8, 2025

Note

Introduce a new regex runtime and split circuit code into circom/noir modules, update WASM/SDK integration, and add a browser proving app with stricter email validation and DKIM endpoint update.

  • Core:
    • Regex Runtime: Add new regex module (extraction, padding, patterns, WASM) using zk_regex_compiler; remove old inline regex logic and types.
    • Circuit Refactor: Split into circom and noir modules; add Noir input generation and limb/REDc utilities; consolidate helpers.
    • Email Parsing/Cryptos: Switch to new regex APIs; validate email length in PaddedEmailAddr (returns Result); update DKIM key endpoint; improve padding/sha utilities.
  • WASM:
    • Update exports to new regex functions; add Noir circuit input generators; adjust existing functions and error handling.
  • Browser Test App:
    • Add browser_test (Vite setup, worker, provers for Noir/Circom, assets) for in-browser proving.
  • Misc:
    • Bump package version; add yarn.lock.

Written by Cursor Bugbot for commit bcf50a2. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • New Features

    • Interactive browser test app with two prover UIs, sample email assets, and in-browser proving flows.
    • Runtime regex extraction and padding utilities available to JS/WASM.
    • Expanded circuit-input generation supporting regex-driven extraction and external inputs across proving flows.
  • Bug Fixes

    • Improved error messages, stricter email/input validation, and more robust runtime checks.
  • Chores

    • Version bumps, updated ignore lists, and new browser test tooling/configuration added.

✏️ Tip: You can customize this high-level summary in your review settings.

…dregex-in-sdk-and-relayerutils

Rutefig/reg 473 fix testdecomposedregex in sdk and relayerutils
@coderabbitai
Copy link

coderabbitai bot commented Oct 31, 2025

Walkthrough

Refactors circuit input generation into Circom and Noir modules, introduces an internal regex subsystem with wasm bindings, removes monolithic src/circuit.rs, adds browser_test Vite app (UI, worker, fixtures), updates dependencies/ignores, and expands the WASM API for Noir input generation.

Changes

Cohort / File(s) Summary
Repo metadata & ignores
\.gitignore, browser_test/\.gitignore, package.json, Cargo.toml
Add .claude and thoughts/ ignores; bump package and Cargo versions; add and reorganize dependencies.
Removed monolith
Deleted:
src/circuit.rs
Remove prior single-file circuit implementation and its public types/functions.
Circom circuit inputs
src/circuit/circom.rs, src/circuit/mod.rs
New Circom-focused circuit input generation, public structs/enums, serde helpers, compute_signal_length, and CircuitInputParams constructor; SHA precompute handling refactored.
Noir circuit inputs & utils
src/circuit/noir/mod.rs, src/circuit/noir/structs.rs, src/circuit/noir/utils.rs, src/circuit/utils.rs
New Noir input generators, NoirCircuitInputs types, big-int/limb helpers, header/address sequencing, selector mapping, and SHA padding trimming.
Regex subsystem (runtime & wasm)
src/regex/mod.rs, src/regex/extract.rs, src/regex/padding.rs, src/regex/patterns.rs, src/regex/types.rs, src/regex/wasm.rs
New regex extraction, padding, patterns, and types modules with NFAGraph-aware extraction; wasm-bindgen exports for JS consumption.
Parsing & cryptography updates
src/parse_email.rs, src/cryptos.rs, src/lib.rs
Update parse_email calls to new regex API signatures; make cryptos helpers return Result; change DKIM API URL; re-export local regex module from crate root.
WASM surface
src/wasm.rs
Add generateNoirCircuitInputsWithRegexesAndExternalInputs, expose Noir-related types, improve Promise/error handling; route to internal regex wasm helpers.
Browser test harness (Vite app)
browser_test/index.html, browser_test/package.json, browser_test/vite.config.js, browser_test/tsconfig.json, browser_test/src/*, browser_test/public/*.eml, browser_test/.gitignore
New Vite-based test app with UI wiring for Noir/Circom provers, sample EML fixtures, TS entry, CSS, worker, and ignore rules.
Prover client & worker
browser_test/src/main.ts, browser_test/src/noirProver.ts, browser_test/src/circomProver.ts, browser_test/src/localProverWorker.js, browser_test/src/prover-server.ts
Browser-side provers to build inputs, run provers, parse outputs; worker downloads/uncompresses/concatenates zkey chunks and invokes snarkjs groth16.
Regex padding & conversions
src/regex/padding.rs, src/circuit/noir/utils.rs, src/circuit/utils.rs
Zero-padding helpers, hex/BigInt ↔ limb conversions, Barrett reduction, header sequencing, selector mapping, and SHA padding utilities.
Tests & minor adjustments
ts_tests/circuit_input.test.ts and new unit tests across regex/circuit/cryptos modules
Update test param names; add unit tests for extraction, padding, cryptographic helpers, and edge cases.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant User
    participant Browser
    participant NoirProver as NoirProver (browser)
    participant CircomProver as CircomProver (browser)
    participant SDK as zk-email SDK / Relayer
    participant Worker as Prover Worker
    participant Snarkjs as snarkjs

    User->>Browser: Click "Prove"
    Browser->>NoirProver: setupNoirProver(container)
    Browser->>CircomProver: setupCircomProver(container)
    NoirProver->>SDK: init WASM, fetch blueprint, parse EML
    CircomProver->>SDK: init WASM, fetch blueprint, parse EML
    SDK-->>NoirProver: decomposed regexes / circuit inputs
    SDK-->>CircomProver: decomposed regexes / circuit inputs
    CircomProver->>Worker: post inputs (wasm/zkey URLs + inputs)
    Worker->>Worker: download chunks, uncompress, concatenate
    Worker->>Snarkjs: groth16.fullProve(inputs, wasm, zkey)
    Snarkjs-->>Worker: proof + public signals
    Worker-->>CircomProver: proof & signals
    NoirProver->>NoirProver: run Noir backend → proof
    NoirProver-->>Browser: proof & parsed public outputs
    CircomProver-->>Browser: proof & parsed public outputs
Loading
sequenceDiagram
    autonumber
    participant App
    participant RegexMod as src/regex
    participant Extract as extract.rs
    participant NFAG as NFAGraph (optional)

    App->>RegexMod: extract_substr_idxes(input, config, nfa?, reveal_private)
    alt NFAGraph provided
        Extract->>Extract: compose_pattern_for_nfa(nfa)
    else
        Extract->>Extract: compose_pattern_standalone(config)
    end
    Extract->>Extract: compile & match
    alt match
        Extract-->>App: return indices/substrings
    else
        Extract-->>App: return NoMatch/Error
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas to focus during review:

  • src/circuit/noir/utils.rs — big-int limb math, Barrett reduction, limb formatting.
  • src/regex/extract.rs & src/regex/patterns.rs — pattern composition, capture-group indexing, NFAGraph integration and tests.
  • src/circuit/circom.rs & src/circuit/noir/mod.rs — selector mapping between cleaned and original content, SHA precompute logic, optional-field handling and error paths.
  • src/wasm.rs & src/regex/wasm.rs — wasm-bindgen signatures, JS interop, Promise rejection semantics.
  • browser_test worker <> main thread flow — chunk download/uncompress/concatenation, localforage storage and cleanup.

Possibly related PRs

Suggested reviewers

  • rutefig

"🐰
I hopped through code to stitch and split,
Regex tamed and circuits fit.
Noir and Circom take the stage,
Browser tests set up the page.
Proofs hop forth — concise and lit!"

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'feat/new compiler' is vague and generic, using non-descriptive terms that don't adequately convey the scope and nature of the changeset. Replace with a more descriptive title such as 'feat: refactor circuit code into circom/noir modules and add regex runtime' to better summarize the primary changes.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed The PR description provides substantial context with bullet points covering core changes, WASM updates, browser test app, and misc changes. However, it lacks explicit coverage of several required template sections.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/new-compiler

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 20

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/parse_email.rs (1)

323-343: Critical: Functional bug from incomplete padding removal. The cleaned_body is padded to original_len but index_map is not.

The issue goes beyond documentation. At src/circuit/utils.rs:29, find_selector_in_clean_content indexes into position_map using indices from the cleaned content. Since cleaned_body is padded with zeros to match the original length but index_map is not, any selector match found in the padded region will attempt to access an out-of-bounds index in position_map. This affects get_adjusted_selector (called at src/circuit/mod.rs:164).

The fix requires either:

  1. Not padding cleaned_body to original length (only pad index_map with usize::MAX as documented), or
  2. Padding index_map to match cleaned_body.len() with usize::MAX entries

Recommend option 1: Remove the .resize(original_len, 0) call and adjust callers that depend on the padded length.

🧹 Nitpick comments (6)
Cargo.toml (1)

16-16: Consider using semantic versions instead of git revisions.

The zk-regex-compiler dependency is pinned to a specific git revision (35014c2bff69115bb92be2dc2c9b006fa69a6649). While this ensures reproducible builds, it makes it harder to track updates and security patches. Consider requesting the upstream maintainers to publish versioned releases, or document why this specific revision is required.

src/regex/padding.rs (2)

1-22: Consider adding test coverage for truncation behavior.

The documentation clearly warns about silent truncation, which is good. However, the test suite doesn't verify this truncation behavior. Consider adding a test case to ensure callers are aware of this critical behavior.

Add a test case like:

#[test]
fn test_pad_string_truncates_silently() {
    let input = "hello_world"; // 11 bytes
    let padded = pad_string(input, 5);
    assert_eq!(padded.len(), 5);
    assert_eq!(&padded[..], b"hello");
}

24-36: Document truncation behavior for consistency.

Similar to pad_string, this function will silently truncate if data exceeds target_len. Consider documenting this behavior for consistency.

 /// Pads a byte slice to the specified size with zero bytes
 ///
 /// # Arguments
 /// * `data` - The bytes to pad
 /// * `target_len` - The target length in bytes
 ///
 /// # Returns
 /// A vector of bytes padded to target_len with zeros
+///
+/// # Behavior
+/// - If the input data is shorter than `target_len`, it will be padded with zeros
+/// - If the input data is exactly `target_len` bytes, it will be returned as-is
+/// - If the input data exceeds `target_len`, it will be silently truncated
browser_test/src/prover-server.ts (1)

15-15: Consider parameterizing the blueprint ID.

The blueprint ID is hardcoded, making the script less flexible. Consider accepting it as a command-line argument or environment variable.

const blueprintId = process.env.BLUEPRINT_ID || "8241f8bd-9fe7-443d-a09d-0150dcc7e85e";
browser_test/src/noirProver.ts (1)

97-109: Handle required external inputs or surface them to the user.

addMaxLengthToExternalInputs([], blueprint.props.externalInputs) throws if the blueprint expects any external inputs, so proving simply fails with “You must provide the external input…”. Either gather values from the UI before calling this helper or defer wiring them until the user supplies them. At minimum, guard this path so the demo doesn’t explode on blueprints that require external data.

src/circuit/noir/utils.rs (1)

319-350: Clarify the padding detection heuristic.

The heuristic approach uses multiple fallback strategies, which is pragmatic. However, line 327's comment states "Check if everything after 0x80 is zeros or length encoding" but the code all(|&b| b != 0x80) actually checks that there's no additional 0x80 byte in the remaining data. This is a reasonable heuristic but may have edge cases where legitimate data contains 0x80 bytes.

Consider clarifying the comment:

-        // Check if everything after 0x80 is zeros or length encoding
+        // Check if there's no other 0x80 byte in the remaining data (to avoid false positives)
         let after_padding = &data[padding_start + 1..];

You may also want to add tests to verify this function handles edge cases correctly, especially when the data contains legitimate 0x80 bytes before the padding.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9b95760 and bcf50a2.

⛔ Files ignored due to path filters (4)
  • Cargo.lock is excluded by !**/*.lock
  • browser_test/bun.lock is excluded by !**/*.lock
  • browser_test/public/vite.svg is excluded by !**/*.svg
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (35)
  • .gitignore (1 hunks)
  • Cargo.toml (2 hunks)
  • browser_test/.gitignore (1 hunks)
  • browser_test/index.html (1 hunks)
  • browser_test/package.json (1 hunks)
  • browser_test/public/amazon.eml (1 hunks)
  • browser_test/public/github.eml (1 hunks)
  • browser_test/public/residency.eml (1 hunks)
  • browser_test/public/x.eml (1 hunks)
  • browser_test/src/circomProver.ts (1 hunks)
  • browser_test/src/localProverWorker.js (1 hunks)
  • browser_test/src/main.ts (1 hunks)
  • browser_test/src/noirProver.ts (1 hunks)
  • browser_test/src/prover-server.ts (1 hunks)
  • browser_test/src/style.css (1 hunks)
  • browser_test/tsconfig.json (1 hunks)
  • browser_test/vite.config.js (1 hunks)
  • package.json (1 hunks)
  • src/circuit.rs (0 hunks)
  • src/circuit/circom.rs (1 hunks)
  • src/circuit/mod.rs (1 hunks)
  • src/circuit/noir/mod.rs (1 hunks)
  • src/circuit/noir/structs.rs (1 hunks)
  • src/circuit/noir/utils.rs (1 hunks)
  • src/circuit/utils.rs (1 hunks)
  • src/cryptos.rs (9 hunks)
  • src/lib.rs (2 hunks)
  • src/parse_email.rs (5 hunks)
  • src/regex/extract.rs (1 hunks)
  • src/regex/mod.rs (1 hunks)
  • src/regex/padding.rs (1 hunks)
  • src/regex/patterns.rs (1 hunks)
  • src/regex/types.rs (1 hunks)
  • src/regex/wasm.rs (1 hunks)
  • src/wasm.rs (10 hunks)
💤 Files with no reviewable changes (1)
  • src/circuit.rs
🧰 Additional context used
🧬 Code graph analysis (14)
src/lib.rs (3)
src/regex/patterns.rs (8)
  • extract_body_hash_idxes (106-108)
  • extract_email_addr_idxes (81-83)
  • extract_email_domain_idxes (86-88)
  • extract_from_addr_idxes (91-93)
  • extract_message_id_idxes (116-118)
  • extract_subject_all_idxes (101-103)
  • extract_timestamp_idxes (111-113)
  • extract_to_addr_idxes (96-98)
src/regex/extract.rs (2)
  • extract_substr (374-386)
  • extract_substr_idxes (188-201)
src/regex/padding.rs (2)
  • pad_bytes (32-36)
  • pad_string (18-22)
browser_test/vite.config.js (1)
build.js (1)
  • path (2-2)
browser_test/src/noirProver.ts (1)
src/wasm.rs (2)
  • parseEmail (51-77)
  • generateNoirCircuitInputsWithRegexesAndExternalInputs (605-652)
browser_test/src/main.ts (2)
browser_test/src/noirProver.ts (1)
  • setupNoirProver (5-163)
browser_test/src/circomProver.ts (1)
  • setupCircomProver (22-209)
src/circuit/mod.rs (4)
src/cryptos.rs (5)
  • generate_partial_sha (494-564)
  • sha256_pad (426-462)
  • new (59-61)
  • new (260-262)
  • new (335-343)
src/parse_email.rs (1)
  • remove_quoted_printable_soft_breaks (323-344)
src/converters.rs (1)
  • to_circom_bigint_bytes (254-256)
src/circuit/utils.rs (1)
  • get_adjusted_selector (66-87)
src/parse_email.rs (2)
src/regex/patterns.rs (8)
  • extract_body_hash_idxes (106-108)
  • extract_email_addr_idxes (81-83)
  • extract_email_domain_idxes (86-88)
  • extract_from_addr_idxes (91-93)
  • extract_message_id_idxes (116-118)
  • extract_subject_all_idxes (101-103)
  • extract_timestamp_idxes (111-113)
  • extract_to_addr_idxes (96-98)
src/regex/extract.rs (1)
  • extract_substr_idxes (188-201)
src/regex/patterns.rs (1)
src/regex/extract.rs (2)
  • extract_substr (374-386)
  • extract_substr_idxes (188-201)
browser_test/src/prover-server.ts (1)
src/wasm.rs (1)
  • generateCircuitInputsWithDecomposedRegexesAndExternalInputs (168-222)
src/regex/wasm.rs (3)
src/regex/extract.rs (2)
  • extract_substr (374-386)
  • extract_substr_idxes (188-201)
src/regex/padding.rs (1)
  • pad_string (18-22)
src/regex/patterns.rs (7)
  • extract_email_addr_idxes (81-83)
  • extract_from_addr_idxes (91-93)
  • extract_to_addr_idxes (96-98)
  • extract_subject_all_idxes (101-103)
  • extract_body_hash_idxes (106-108)
  • extract_timestamp_idxes (111-113)
  • extract_message_id_idxes (116-118)
src/circuit/circom.rs (5)
src/converters.rs (4)
  • field_to_hex (76-79)
  • hex_to_u256 (302-308)
  • string_to_circom_bigint_bytes (463-483)
  • vec_u8_to_bigint (265-269)
src/parse_email.rs (3)
  • find_index_in_body (359-371)
  • remove_quoted_printable_soft_breaks (323-344)
  • new_from_raw_email (49-75)
src/circuit/noir/utils.rs (1)
  • trim_sha256_padding (319-350)
src/circuit/mod.rs (2)
  • generate_circuit_inputs (134-196)
  • new (98-113)
src/cryptos.rs (5)
  • from (273-275)
  • new (59-61)
  • new (260-262)
  • new (335-343)
  • from_email_addr (111-128)
src/circuit/noir/mod.rs (5)
src/parse_email.rs (2)
  • remove_quoted_printable_soft_breaks (323-344)
  • new_from_raw_email (49-75)
src/converters.rs (2)
  • string_to_circom_bigint_bytes (463-483)
  • vec_u8_to_bigint (265-269)
src/circuit/circom.rs (2)
  • compute_signal_length (577-579)
  • clone (122-139)
src/circuit/mod.rs (2)
  • generate_circuit_inputs (134-196)
  • new (98-113)
src/circuit/noir/utils.rs (6)
  • bn_to_limb_str_array (101-134)
  • bn_to_redc_limb_str_array (161-164)
  • get_header_sequence (195-228)
  • u8_to_u32 (304-317)
  • get_address_header_sequence (248-290)
  • trim_sha256_padding (319-350)
src/cryptos.rs (2)
src/regex/padding.rs (1)
  • pad_string (18-22)
src/converters.rs (2)
  • hex_to_field (20-67)
  • field_to_hex (76-79)
browser_test/src/circomProver.ts (1)
src/wasm.rs (2)
  • parseEmail (51-77)
  • generateCircuitInputsWithDecomposedRegexesAndExternalInputs (168-222)
src/wasm.rs (2)
src/circuit/noir/mod.rs (2)
  • generate_noir_circuit_input (26-176)
  • generate_noir_circuit_inputs_with_regexes_and_external_inputs (178-342)
src/regex/wasm.rs (3)
  • extractSubstrIdxes (15-47)
  • from_value (22-22)
  • from_value (58-58)
🪛 ast-grep (0.39.6)
browser_test/src/main.ts

[warning] 4-18: Direct modification of innerHTML or outerHTML properties detected. Modifying these properties with unsanitized user input can lead to XSS vulnerabilities. Use safe alternatives or sanitize content first.
Context: document.querySelector("#app")!.innerHTML = `

ZK Email SDK Browser Test

Prove with Noir
Prove with Circom
` Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES] - https://owasp.org/www-community/xss-filter-evasion-cheatsheet - https://cwe.mitre.org/data/definitions/79.html

(dom-content-modification)


[warning] 4-18: Direct HTML content assignment detected. Modifying innerHTML, outerHTML, or using document.write with unsanitized content can lead to XSS vulnerabilities. Use secure alternatives like textContent or sanitize HTML with libraries like DOMPurify.
Context: document.querySelector("#app")!.innerHTML = `

ZK Email SDK Browser Test

Prove with Noir
Prove with Circom
` Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES] - https://www.dhairyashah.dev/posts/why-innerhtml-is-a-bad-idea-and-how-to-avoid-it/ - https://cwe.mitre.org/data/definitions/79.html

(unsafe-html-content-assignment)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-test
🔇 Additional comments (23)
package.json (1)

13-13: LGTM! Version bump to pre-release.

The version update to 0.4.66-8 follows semantic versioning with a pre-release suffix, which is appropriate for development builds.

.gitignore (1)

11-12: LGTM! Appropriate ignore entries for development artifacts.

Adding .claude and thoughts/ to version control exclusions prevents personal notes and AI-generated artifacts from being committed.

browser_test/.gitignore (1)

1-24: LGTM! Comprehensive ignore patterns for browser test project.

The ignore patterns appropriately cover logs, build artifacts, dependencies, and IDE-specific files, following standard Node.js/Vite project conventions.

Cargo.toml (1)

19-25: LGTM! Well-chosen dependencies added.

The new dependencies are appropriate:

  • thiserror for ergonomic error handling
  • fancy-regex for advanced regex features
  • num-traits for numeric trait abstractions

All are well-maintained, widely-used crates in the Rust ecosystem.

browser_test/package.json (1)

18-32: No changes required—duplication is intentional.

The two snarkjs packages serve distinct purposes: snarkjs@^0.7.5 is used in prover-server.ts for standard Groth16 functionality, while @zk-email/snarkjs@^0.0.1 is used in localProverWorker.js for ZK-Email's specialized chunked zkey support. They are imported in different files and do not conflict; this is a valid and intentional complementary dependency structure.

browser_test/tsconfig.json (1)

1-23: LGTM!

The TypeScript configuration is well-structured with appropriate compiler options for a browser-based Vite project. Strict mode and linting rules are properly enabled.

browser_test/src/style.css (1)

1-96: LGTM!

The stylesheet provides clean, modern styling with proper light/dark theme support and responsive design. The layout and typography choices are appropriate for a browser testing UI.

browser_test/src/main.ts (1)

21-22: LGTM!

The prover initialization is straightforward and correct. The non-null assertions are safe here since the DOM elements were just created in the previous statement.

src/parse_email.rs (2)

6-10: LGTM!

The import refactoring correctly replaces the external zk_regex_apis dependency with the new internal crate::regex module, aligning with the PR's goal to internalize regex extraction functionality.


209-214: LGTM!

All call sites correctly updated to match the new signature of extract_substr_idxes, which now accepts an optional NFAGraph parameter. Passing None maintains the existing behavior while supporting the new NFAGraph-based extraction path.

Also applies to: 227-232, 266-279, 290-290

src/regex/padding.rs (1)

38-59: LGTM!

The test coverage validates the padding behavior correctly. The suggestion to add truncation tests is optional.

browser_test/vite.config.js (1)

1-80: LGTM!

The Vite configuration properly sets up Node.js polyfills required for running ZK proving operations in the browser. The extensive alias mappings and polyfill plugins are standard and necessary for this use case.

browser_test/src/prover-server.ts (2)

29-51: LGTM!

Blueprint fetching and email validation include proper error handling with clear logging.


53-121: LGTM!

Circuit input generation includes proper validation for missing regex graphs and haystack lengths. The Map-to-object conversion is handled correctly.

src/regex/mod.rs (1)

1-32: LGTM!

The module structure is clean and well-documented. The hybrid extraction approach (with/without NFAGraph) is clearly explained, and the re-exports provide a convenient public API surface.

src/circuit/noir/mod.rs (3)

208-231: LGTM - Clean external input handling.

The code properly handles missing external input values with unwrap_or("") and applies appropriate padding to match the required signal length.


270-339: LGTM - Comprehensive regex result handling.

The code properly validates that capture group data is complete (IDs, starts, and indices) and returns clear errors when required fields are missing. The rejection of Circom inputs in this Noir-specific function is appropriate.


344-361: LGTM - Clean helper functions.

The JSON conversion helpers provide a clean interface for backward compatibility and interoperability with JSON-based systems.

src/circuit/noir/utils.rs (1)

195-228: LGTM - Proper error handling for header sequence extraction.

The function correctly uses Result for error handling and provides clear error messages for edge cases like empty field names and missing fields.

src/circuit/circom.rs (4)

20-56: LGTM - Well-structured data types.

The structs are well-documented and use appropriate serde attributes for optional field handling.


58-162: LGTM - Robust serialization infrastructure.

The SerializableRegexPart abstraction with bidirectional From implementations and custom serde module enables clean JSON round-tripping. The custom Debug implementation that hides the large regex graph JSON is a nice touch for debugging.


415-454: LGTM - Proper haystack extraction logic.

The code correctly handles both header and body locations, applies appropriate cleaning based on remove_soft_line_breaks, and trims SHA256 padding before regex processing.


577-579: LGTM - Clean utility function.

The compute_signal_length function correctly computes the ceiling division by 31.

Comment on lines +1 to +1000
Delivered-To: [email protected]
Received: by 2002:a05:6520:4d11:b0:298:de86:b196 with SMTP id cy17csp1851324lkb;
Thu, 15 Aug 2024 18:01:48 -0700 (PDT)
X-Forwarded-Encrypted: i=3; AJvYcCWCx1Cb3kEOBBorrIS5l2e6GCzKJxzBxybTlA6eTJnE+qGUWcW3x0U2DbMEuuE94csCWxFvt47ftW92zpoSTnvWP+8Mc1JAPw==
X-Google-Smtp-Source: AGHT+IFy7itmDPuDlSHhbsl0mXcp4WaIqPBhoxgtMIUJ4rixUL/hmu7Y7lNb/3SE/waaKnYbynS7
X-Received: by 2002:a05:6000:a8b:b0:36b:8f94:e206 with SMTP id ffacd0b85a97d-37194315781mr855253f8f.5.1723770107871;
Thu, 15 Aug 2024 18:01:47 -0700 (PDT)
ARC-Seal: i=2; a=rsa-sha256; t=1723770107; cv=pass;
d=google.com; s=arc-20240605;
b=L4ifZud+phJJXmpjp/GJ3cSjA1D4Uhl604pR5GCQDZy4O/9FpFTTyQrlajv20a3CLA
LDohZyTwGvxXuUGOp4AnE3lb/GAeb9AQ3dfKQ5NRnBbbC5j01ow9/3hi/CQUG3K3uRxG
pCJKwe65M0PZryicz8+ZB1It0JoWHN9b9rWhTUesMV60vRLKHa76jBdrS3n5ykx6u+Hg
nDR/S+g3/qmdmopzKC4T5rKleVpLdBmBBfnpURBhyrbzR4YRAYrxHh6/Xmfxm2CXnP1G
BngzD5RfJcQJVBe2Hl7hTsPXNgDIW8Ng+G1w1sU12uUFdLUNMFL3Hmp0YXx52NGCsAxM
HjSg==
ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605;
h=feedback-id:bounces-to:mime-version:subject:message-id:to:from:date
:dkim-signature:dkim-signature;
bh=a+iNAUuMllM38rUYf1E0PCsZMSzHqdP5Rs6lXnKmcp4=;
fh=aslmXTwzSzJ1CMviWDZT1UuXOGBFyKTE9qzq5T44VcQ=;
b=Obl6fTQjJwbp1Z313OnnWM2NPRbOCUSY9p+6WdIDaWpqRQ0scS/tkVJPHyocDMPOFy
JxFpFA85L6u+XEVp249LYKd2p7z9z+uQaSW/sp0CrL5NPWk/jQcY37eLzlz9UDRVY0OR
Z8CxOzIiBJtsYGgMN594/rlliZQMEv7+EE7/bp4p0rEMweLeWmS73aT5JjmYvS6D0DrH
/shB9jMo5zS6qUNR8v8REiTJzcnN+yJ6iZ35c8Bg1rOu94hgJmnWNFLiiC47FEn5bzo9
VvuVRFPJh/F8c3pEHTWLfNfjjzzZZA4PvQJS8YJ0isrIoCzeuqJMV0dOs2U8mc+H39Y5
IGFg==;
dara=google.com
ARC-Authentication-Results: i=2; mx.google.com;
dkim=pass [email protected] header.s=yg4mwqurec7fkhzutopddd3ytuaqrvuz header.b="sk0yWvc/";
dkim=pass [email protected] header.s=ug7nbtf4gccmlpwj322ax3p6ow6yfsug header.b=lUY1ph+6;
arc=pass (i=1 dkim=pass dkdomain=amazon.com dkim=pass dkdomain=amazonses.com);
spf=pass (google.com: domain of [email protected] designates 18.9.21.22 as permitted sender) smtp.mailfrom=[email protected];
dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=amazon.com
Return-Path: <[email protected]>
Received: from exchange-forwarding-2.mit.edu (exchange-forwarding-2.mit.edu. [18.9.21.22])
by mx.google.com with ESMTPS id 5b1f17b1804b1-429ded70f98si27296005e9.143.2024.08.15.18.01.47
for <[email protected]>
(version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
Thu, 15 Aug 2024 18:01:47 -0700 (PDT)
Received-SPF: pass (google.com: domain of [email protected] designates 18.9.21.22 as permitted sender) client-ip=18.9.21.22;
Authentication-Results: mx.google.com;
dkim=pass [email protected] header.s=yg4mwqurec7fkhzutopddd3ytuaqrvuz header.b="sk0yWvc/";
dkim=pass [email protected] header.s=ug7nbtf4gccmlpwj322ax3p6ow6yfsug header.b=lUY1ph+6;
arc=pass (i=1 dkim=pass dkdomain=amazon.com dkim=pass dkdomain=amazonses.com);
spf=pass (google.com: domain of [email protected] designates 18.9.21.22 as permitted sender) smtp.mailfrom=[email protected];
dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=amazon.com
Received: from mailhub-dmz-4.mit.edu (MAILHUB-DMZ-4.MIT.EDU [18.7.62.38])
by exchange-forwarding-2.mit.edu (8.14.7/8.12.4) with ESMTP id 47G11hAQ014612
for <[email protected]>; Thu, 15 Aug 2024 21:01:45 -0400
Authentication-Results: mit.edu; dmarc=pass (p=quarantine dis=none) header.from=amazon.com
Authentication-Results: mit.edu; arc=none smtp.remote-ip=18.7.62.38
ARC-Seal: i=1; a=rsa-sha256; d=mit.edu; s=arc; t=1723770105; cv=none; b=I3uoniJRBjPCLIEB3xP3hVBkvc+i2uRrt/Qa98Z9Pew6S0B9YMYkhfyoEzqG9SAM9Me5KO0YAvZMbfMtIqtaDh99KBS+iv77kBhEsx5OqUpzb3Wl2zIM+VbewBxhPFUae85UUUYlc3FcomH+e3BYp3s0M+3tU+UeXxMu+BbkcdomHRwIHAPNE4122eo78KPjc0cWQSrX/fL+/v0Z8PY7f99hN5Rqmv15JNhgWDpyrQ7S8UZ2YwzEzN6T8pRH7VhxZDNnwP6JRhylWcaeVEOZt9/x8YaVXBxAxmzz/+mt0J19JRLghzrzbLeUJyiR2M2uqzhH2koHQFf4r5N4/zmXBA==
ARC-Message-Signature: i=1; a=rsa-sha256; d=mit.edu; s=arc; t=1723770105;
c=relaxed/relaxed; bh=a+iNAUuMllM38rUYf1E0PCsZMSzHqdP5Rs6lXnKmcp4=;
h=Date:From:Message-ID:Subject:MIME-Version:Content-Type; b=qB8UXISZyqJo1Cu2Oca57DPK/fwTk63YJ3gOT3iewE5H9ZuhwLDffJOtj+5oTIpeuPsDtEJPfxMP6K3466KjPIhHycLkjJqM1qKZM5XGjcXE2YaWVdeZvFLtPdXAbuxBc98x0GuqXpWkQUuXuDHsOMpGxeIoD0x395i4XQF6JOKCJhqf6airXGRVQ0TvLgOc1sKAsUCiy8LVFxTZIFc959rHxSCd6KN+xomr+QVCELUtwwujGEz/0d2Py7Sf6GmvpDi1Csg8B9VeLWX+vyJ08XheWzGKu7lLRZvJ9KXOTnGskQCwTXs5Melz/84G8ewhiOrHEz4sUW5fx1ksFKJmlw==
ARC-Authentication-Results: i=1; mit.edu; dkim=pass (1024-bit key; unprotected) header.d=amazon.com [email protected] header.a=rsa-sha256 header.s=yg4mwqurec7fkhzutopddd3ytuaqrvuz header.b=sk0yWvc/; dkim=pass (1024-bit key; unprotected) header.d=amazonses.com [email protected] header.a=rsa-sha256 header.s=ug7nbtf4gccmlpwj322ax3p6ow6yfsug header.b=lUY1ph+6
Authentication-Results: mit.edu;
dkim=pass (1024-bit key; unprotected) header.d=amazon.com [email protected] header.a=rsa-sha256 header.s=yg4mwqurec7fkhzutopddd3ytuaqrvuz header.b=sk0yWvc/;
dkim=pass (1024-bit key; unprotected) header.d=amazonses.com [email protected] header.a=rsa-sha256 header.s=ug7nbtf4gccmlpwj322ax3p6ow6yfsug header.b=lUY1ph+6
Received: from mailhub-dmz-4.mit.edu (mailhub-dmz-4.mit.edu [127.0.0.1])
by mailhub-dmz-4.mit.edu (8.14.7/8.9.2) with ESMTP id 47G11hGU006354
for <[email protected]>; Thu, 15 Aug 2024 21:01:43 -0400
Received: (from mdefang@localhost)
by mailhub-dmz-4.mit.edu (8.14.7/8.13.8/Submit) id 47G11di4006343
for [email protected]; Thu, 15 Aug 2024 21:01:39 -0400
Received: from BYAPR05CU005.outbound.protection.outlook.com (mail-westusazlp17010006.outbound.protection.outlook.com [40.93.1.6])
by MAILHUB-DMZ-4.MIT.EDU (envelope-sender <20240816010133af409d4398414b769006b814f360p0na-C1MH0WGB67NIL9@bounces.amazon.com>) (MIMEDefang) with ESMTP id 47G11bAg006339
for <[email protected]>; Thu, 15 Aug 2024 21:01:39 -0400
Received: from SA9PR11CA0015.namprd11.prod.outlook.com (2603:10b6:806:6e::20)
by SA0PR01MB6188.prod.exchangelabs.com (2603:10b6:806:da::21) with Microsoft
SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id
15.20.7875.18; Fri, 16 Aug 2024 01:01:34 +0000
Received: from SA2PEPF00003F61.namprd04.prod.outlook.com
(2603:10b6:806:6e:cafe::b0) by SA9PR11CA0015.outlook.office365.com
(2603:10b6:806:6e::20) with Microsoft SMTP Server (version=TLS1_2,
cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7828.33 via Frontend
Transport; Fri, 16 Aug 2024 01:01:34 +0000
Authentication-Results: spf=pass (sender IP is 54.240.13.78)
smtp.mailfrom=bounces.amazon.com; dkim=pass (signature was verified)
header.d=amazon.com;dmarc=pass action=none
header.from=amazon.com;compauth=pass reason=100
Received-SPF: Pass (protection.outlook.com: domain of bounces.amazon.com
designates 54.240.13.78 as permitted sender) receiver=protection.outlook.com;
client-ip=54.240.13.78; helo=a13-78.smtp-out.amazonses.com; pr=C
Received: from a13-78.smtp-out.amazonses.com (54.240.13.78) by
SA2PEPF00003F61.mail.protection.outlook.com (10.167.248.36) with Microsoft
SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.7849.8
via Frontend Transport; Fri, 16 Aug 2024 01:01:34 +0000
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple;
s=yg4mwqurec7fkhzutopddd3ytuaqrvuz; d=amazon.com; t=1723770094;
h=Date:From:To:Message-ID:Subject:MIME-Version:Content-Type;
bh=fHIH8oc4fnqEfBc2yA88CwZjgGRwbXrwhe87j4ItCcQ=;
b=sk0yWvc/xR48M8krmQkjZbwkeIFlDIHr96+9q2KY0UxYchD4Usu4LurSXTq0YF/8
oXyRB0j9ocgDkpl6ASsyHrQJUn/Vy1nqvmJOAFRTV9v4NJyCquwME/hanRWmyDV8AJC
SpsrDeISMzFsQMvX3/BZ09/wAO+XPKNPx3iYrwfg=
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple;
s=ug7nbtf4gccmlpwj322ax3p6ow6yfsug; d=amazonses.com; t=1723770094;
h=Date:From:To:Message-ID:Subject:MIME-Version:Content-Type:Feedback-ID;
bh=fHIH8oc4fnqEfBc2yA88CwZjgGRwbXrwhe87j4ItCcQ=;
b=lUY1ph+6Hec4F2znvRMGzsMh87R1d8Zm/OiEqyOJdcoaC7SxQgTyiCqlG09+4OH6
fH1GNOI1pZmXZ3eBxbRLf0r9wpTn+VpX7PkwvW6qZK4bDuEXGWcD7BOCL49qiDYgQ5E
WYWaB24Gp9ZuGr+aB8mX1q7X0tkjSQPh+SPwdWGA=
Date: Fri, 16 Aug 2024 01:01:34 +0000
From: "Amazon.com" <[email protected]>
To: [email protected]
Message-ID: <0100019158b441de-d0733a8e-e37c-4906-9fc0-59a546ba46cc-000000@email.amazonses.com>
Subject: Delivered: Your Amazon.com order #111-3061760-5513056
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="----=_Part_533333_1464710557.1723770094034"
X-AMAZON-MAIL-RELAY-TYPE: notification
Bounces-to: 20240816010133af409d4398414b769006b814f360p0na-C1MH0WGB67NIL9@bounces.amazon.com
X-AMAZON-METADATA: CA=C1MH0WGB67NIL9-CU=A2WSYR24L0Q7DI
X-Original-MessageID: <urn.rtn.msg.20240816010133af409d4398414b769006b814f360p0na@1723770094035.>
Feedback-ID: 917195550::1.us-east-1.ZHcGJK6s+x+i9lRHKog4RW3tECwWIf1xzTYCZyUaiec=:AmazonSES
X-SES-Outgoing: 2024.08.16-54.240.13.78
X-EOPAttributedMessage: 0
X-EOPTenantAttributedMessage: 64afd9ba-0ecf-4acf-bc36-935f6235ba8b:0
X-MS-PublicTrafficType: Email
X-MS-TrafficTypeDiagnostic: SA2PEPF00003F61:EE_|SA0PR01MB6188:EE_
X-MS-Office365-Filtering-Correlation-Id: 8b39e185-a9d4-4bc2-4904-08dcbd8ef988
X-MS-Exchange-AtpMessageProperties: SA|SL
X-MIT-ForwardedCount: 1
X-Microsoft-Antispam:
BCL:0;ARA:13230040|1032899013|12012899012|3092899012|6062899009|5062899012|5082899009|3072899012|32142699015|2092899012|69100299015|4092899012|13102899012|13012899012;
X-Microsoft-Antispam-Message-Info:
=?utf-8?B?dDA1dE50U1hkbFJkQVd3dzF0dzZoSk53clFKYU1JTmFkY2pWQ3FvZ2poQWpM?=
=?utf-8?B?NHZNR2pkWFpDQTc4dFYzUWRQTWdwSlZNRFBLdmMwZ1NoYXd6K21sQ25VTjha?=
=?utf-8?B?Y3hvdStXM0V6WDFZc1JxaGxKYXEyZnRvOFlhREN2LzZuVzVHS09CNjBQUDA3?=
=?utf-8?B?eTgrekxSUllJWm9lMVBiV1FSME1HMHhZUkdKZkNIWG92ZzdUZ09pNDYzRGVi?=
=?utf-8?B?L001VmVhbkhJWWR4L3p5NjRLNnM3Qlc1bitEWkh5dkx2VlVGNG5NRnJGa3Yz?=
=?utf-8?B?YklZVnhVaVFkM1VjR3BBZnIvU3Q3dXQ0SndNZmMyMnNNSThtN2FnUzNyNFVh?=
=?utf-8?B?SS9VZFJ2RVdrS2RjV2pNeG1iTUYvaXFJaXdaUWJSanJ4dEJqMUcyNGo5c0wz?=
=?utf-8?B?YnVLUUM4NHNsOVpkekFqSTlHbWpqQjdWWVBBeDMxL0VLdGRiekNiL3UxZlds?=
=?utf-8?B?cGZnakJmUzJQTHdHaXp0QVkrVnpVNGFXN2ZTRW4wMEtiblR6ODUvcUxoWG5H?=
=?utf-8?B?WTVoei9kbS9yVTBJOWk1RnVzL2cvL3JadEVtNUNFVktORnlJL1FMM2dWRFVv?=
=?utf-8?B?WGdydlFDRjRaMHRBZHVpTnVrMjBpZnplcHE0MGpISHErczJRYVRrMS9Lb1BQ?=
=?utf-8?B?eWFZU1ZiVzZhbDhScFNpb0czOUU3dkNVWXdTOXQ1M3BFNmw2eDNLNjU1UnRW?=
=?utf-8?B?ZDZLZDY0b1FVWkxoeVlqTSswbmwrc09tMzdjSk1FSEZ4d3R6dWRtT1NNRnc0?=
=?utf-8?B?VUp2Y01KN3pEbHJKUXYxdTRDak5zaE1QMDh1akg4NGxOUmNodTVydVErL2J4?=
=?utf-8?B?RksvdTlROFgyUjlDbzlkZXBMYjFhUC8wcDJHR0FIYVFuZmhadmEvUjhJcC9I?=
=?utf-8?B?UERhR3VxTEFBVzBaV01weDhLWjlUZVZseVN0cytlYmtTcnNQMTFDdGsyd2sr?=
=?utf-8?B?Zk9GaXFiWmE3d2lWREc0Q3NqOXRNTlE3K29DdHJuK1NsdFB2NldVbTQ5M0Ri?=
=?utf-8?B?L1ZHTWtSTlNYZmhVbVc5WUtITVlITHJ2aWo4dmY4ZG5FTGZSNUh6a0dEdTR4?=
=?utf-8?B?TDVuS2RmT1p3bElKSFc1Z3JPSVlYM0J5YXVyOUJGKzNCbERLK3dydlk0TnV1?=
=?utf-8?B?dHJlTU1HQktidEF5ajkvd29yUEtSSmt2SDMvejY5dU9XYzZzTUhKczdGTU9j?=
=?utf-8?B?QnZQSlBVT3RtcDF5NkxEeThNaGFrRG1pdlFhWUVSSXZmYnRkTEpsenJuQy91?=
=?utf-8?B?ZnRBQ21abC9NV2pscUFZQ1JGTStOUFZSOWZNdEIzcWYvTStiQ01OUE1hazVh?=
=?utf-8?B?enN6b25qbDN5OTZmVS9sUDBXQTVXWDhoNjFxS1o1S0FjYmVxQUFneFh6QkJJ?=
=?utf-8?B?K1dVUW1nTW5PbGF2MlNiNi9rRjhvbUMxWDNXZnBvQXhDZ0FWNFRjSi93RG9I?=
=?utf-8?B?SVdIc01aSVhqMEhnRmxQdlA4MmVBYWtQdXFFcGxZTnZ4Tk5hZVdsTnRoNDlk?=
=?utf-8?B?MWthWVUxZTArYUtOSUN5MVpxWjdQbmRpSHJ6VFJUYUt1VEV0WmdsWFRtNWIv?=
=?utf-8?B?T3ZXaTVtWGM2bzJlMkN5Z0pmRGoxQ2I0MjBYUGt6WkUzSkhwZHplMjVYY1Fn?=
=?utf-8?B?RG04bTBEQXJ1NmlMVi9rN3R2NDdvSTZ0RGVrNE42dGtSNVdWZXpjaUNFaGgx?=
=?utf-8?B?V2Jja3h1WXZVaktNdm1sSjBxTVVqTGdoMTlMbTVSVjVlbk9IR3NtVlFPRzhP?=
=?utf-8?B?TWhZMkluZGllNzJqRFhKNG1sMnBpLy9nTnc0WVdzbE1DNHNzbVZFTTlvRTc2?=
=?utf-8?B?Vi8vcVdSbmRUaDJNclY0a2QxM2NTNmljR01JNHF0SjBQUklkeEllYU1wNERl?=
=?utf-8?B?ekdJVlNpa09iWkZlbEJqMXR6b1dWWHE1aWpZK3JpaXlROFJtSDRFZHZjRHp3?=
=?utf-8?B?R29COXZpN2I3ajljaGlRRjkyZDIyenA4R0dIb2xBZkFLY1FJMU1kR3J3SG1U?=
=?utf-8?B?QmNMQnYzRnNqVHdQYmtlbzdES0xtRkExZE84d3FxelRYV3gyUjBySmZjdUM3?=
=?utf-8?B?QzNWVzZUKzdaL3hVb0ZvLzZ2MFFmcEM0VHNjaVZWUjE0MDlZR3dIQnc1bkIx?=
=?utf-8?B?N2VOUlZoSnF2RGYyZzgyWWZEeXJHSHlDakNIUFJhZmU1d1VXMlBUYzZTVFcw?=
=?utf-8?B?Uk5aMit5Q3ZCNzg2eFEwNTJBT3VIZlFuYlVhRnozZGoyajNhc2dVemo0SXNN?=
=?utf-8?B?RVp2RHQ1SHcvOG5ZWC93QnpQbFMycWYzUzErM0VMeGxmUnIzcnB0OThVS1VZ?=
=?utf-8?B?bk9kNk1PNS9kSFpmU2ZxUXRhWVJkTzN5ZWFqOVN1c2lDZVhaN0VjZW56cGE4?=
=?utf-8?B?eUVlNUtWTXNMVWZxVHFydzVEVDNIUjRmc3ltWVMxU3BXUFBlSnZTeEZ5SHZJ?=
=?utf-8?B?UUVHTTA4RVR3NjFYOWlGbVp1eU1FN0NDL2F6RzROanEzMEMyQzhhd3I4enh0?=
=?utf-8?Q?y43yNOONjO+?=
X-Forefront-Antispam-Report:
CIP:54.240.13.78;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:a13-78.smtp-out.amazonses.com;PTR:a13-78.smtp-out.amazonses.com;CAT:NONE;SFS:(13230040)(1032899013)(12012899012)(3092899012)(6062899009)(5062899012)(5082899009)(3072899012)(32142699015)(2092899012)(69100299015)(4092899012)(13102899012)(13012899012);DIR:INB;
X-MS-Exchange-AntiSpam-ExternalHop-MessageData-ChunkCount: 1
X-MS-Exchange-AntiSpam-ExternalHop-MessageData-0:
z1rzeYVa+P7w3Uut5PZY4XFxKFVPPMoRlChKSBEkqD70if+MiDWrj2kOzicowSH5/Ryv/yUxMBE5phZvD5onyE/TRH0DlXbWQHsVZq/ckPMOoPW60O70g7+Xp+ugQamDxA9jkDTgheWYPKDqTWmDgIAXrXe+gvQMpon+9pX4OvOUeIvap679lvHzOG7B3yR46+gn1J40mD9blXsZKSE+iDvWuc36A1bTZ8LPrpO4aWQP8UvqI8U+EebELungZppda6de5Si6ilLMSkckWRbqY/9LP9t+EUw6v9vh0GA2ExA/9TLvC/O9ARvbd4Yi2ZETUNj2awhkwVCrChWM05WWbbLXT1MqMzR1ErJxnDGIcs0jQ32ITjTNdC0zR4icAc72+gVhXdW8hdP5smLE1aD2h2zTGBo9nBHRterNuL1H1Cidl0rIjL3AA+5bgi01KTZNIatilr5DG9prwfrHNNkM2w/FT95g8nslWM2nEwu02YnP+XJEHHrxFXPPhJJHuGnqOI/dRGZ3YqEeO8VJMeC/dEqdsQMkVp8WR4TSd/rUgt46esSmEVXuMxpxaAMvcltPbFp9IFrfSz7JUCmxmgNAw6uGmPyiX1mFIA3PpRPODOpe2y/Bo/kJZul19eejoX2i
X-OriginatorOrg: mitprod.onmicrosoft.com
X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Aug 2024 01:01:34.7825
(UTC)
X-MS-Exchange-CrossTenant-Network-Message-Id: 8b39e185-a9d4-4bc2-4904-08dcbd8ef988
X-MS-Exchange-CrossTenant-Id: 64afd9ba-0ecf-4acf-bc36-935f6235ba8b
X-MS-Exchange-CrossTenant-AuthSource:
SA2PEPF00003F61.namprd04.prod.outlook.com
X-MS-Exchange-CrossTenant-AuthAs: Anonymous
X-MS-Exchange-CrossTenant-FromEntityHeader: Internet
X-MS-Exchange-Transport-CrossTenantHeadersStamped: SA0PR01MB6188
X-MS-Exchange-CrossPremises-OriginalClientIPAddress: 54.240.13.78
X-MS-Exchange-CrossPremises-TransportTrafficType: Email
X-MS-Exchange-CrossPremises-AuthSource:
SA2PEPF00003F61.namprd04.prod.outlook.com
X-MS-Exchange-CrossPremises-AuthAs: Anonymous
X-MS-Exchange-CrossPremises-Antispam-ScanContext:
DIR:Incoming;SFV:NSPM;SKIP:0;
X-MS-Exchange-CrossPremises-SCL: 1
X-MS-Exchange-CrossPremises-Processed-By-Journaling: Journal Agent
X-OrganizationHeadersPreserved: SA0PR01MB6188.prod.exchangelabs.com

------=_Part_533333_1464710557.1723770094034
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
=20
Hi Aayush,
Your package has been delivered to reception.
How was your delivery?
It was great https://www.amazon.com/progress-tracker/package?_encoding=3DUT=
F8&itemId=3D&orderId=3D111-3061760-5513056&packageIndex=3D0&shipmentId=3D30=
0612189807301&ingress=3Demail&intent=3Dfeedback_happy&ref_=3Dpdc_f_h
Not so great https://www.amazon.com/progress-tracker/package?_encoding=3DUT=
F8&itemId=3D&orderId=3D111-3061760-5513056&packageIndex=3D0&shipmentId=3D30=
0612189807301&ingress=3Demail&intent=3Dfeedback_unhappy&ref_=3Dpdc_f_s
Track package
https://www.amazon.com/gp/your-account/ship-track?ie=3DUTF8&itemId=3D&order=
Id=3D111-3061760-5513056&packageIndex=3D0&shipmentId=3DGhsHRNhnG&ref_=3Dpdc=
_pt_track
Order # 111-3061760-5513056
Return or replace items in [Your Orders](https://www.amazon.com/your-orders=
/orders?ref_=3Dpdc_yo).
=C2=A92024 Amazon.com, Inc. or its affiliates. Amazon and all related marks=
are trademarks of Amazon.com, Inc. or its affiliates, Amazon.com, Inc. 410=
Terry Avenue N., Seattle, WA 98109.
Amazon.com
------=_Part_533333_1464710557.1723770094034
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable

<!doctype html><html lang=3D"en" dir=3D"auto" xmlns=3D"http://www.w3.org/19=
99/xhtml" xmlns:v=3D"urn:schemas-microsoft-com:vml" xmlns:o=3D"urn:schemas-=
microsoft-com:office:office"><head><title></title><!--[if !mso]><!--><meta =
http-equiv=3D"X-UA-Compatible" content=3D"IE=3Dedge"><!--<![endif]--><meta =
http-equiv=3D"Content-Type" content=3D"text/html; charset=3DUTF-8"><meta na=
me=3D"viewport" content=3D"width=3Ddevice-width,initial-scale=3D1"><style t=
ype=3D"text/css">#outlook a{padding:0}body{margin:0;padding:0;-webkit-text-=
size-adjust:100%;-ms-text-size-adjust:100%}table,td{border-collapse:collaps=
e;mso-table-lspace:0pt;mso-table-rspace:0pt}img{border:0;height:auto;line-h=
eight:100%;outline:0;text-decoration:none;-ms-interpolation-mode:bicubic}p{=
display:block;margin:13px 0}</style><!--[if mso]>
<noscript>
<xml>
<o:OfficeDocumentSettings>
<o:AllowPNG/>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
</noscript>
<![endif]--><!--[if lte mso 11]>
<style type=3D"text/css">.mj-outlook-group-fix{width:100%!important}</s=
tyle>
<![endif]--><style type=3D"text/css">@media only screen and (min-width:=
600px){.mj-column-per-100{width:100%!important;max-width:100%}.mj-column-pe=
r-50{width:50%!important;max-width:50%}.mj-column-per-33{width:33%!importan=
t;max-width:33%}.mj-column-per-67{width:67%!important;max-width:67%}}</styl=
e><style media=3D"screen and (min-width:600px)">.moz-text-html .mj-column-p=
er-100 { width:100% !important; max-width: 100%; }
.moz-text-html .mj-column-per-50 { width:50% !important; max-width: 50%; }
.moz-text-html .mj-column-per-33 { width:33% !important; max-width: 33%; }
.moz-text-html .mj-column-per-67 { width:67% !important; max-width: 67%; }<=
/style><style type=3D"text/css">.rio-card-70 p+p{margin-top:1.2em}@media (p=
refers-color-scheme:dark){.rio-header-64,.rio-header-64 *{color:#fff!import=
ant}}@media (prefers-color-scheme:dark){.rio-header-65,.rio-header-65 *{col=
or:#fff!important}}@media (prefers-color-scheme:dark){.rio-text-121{color:#=
fff}}@media (prefers-color-scheme:dark){.rio-text-122{color:#fff}}@media (p=
refers-color-scheme:dark){.rio-text-123{color:#fff}}@media (prefers-color-s=
cheme:dark){.rio-text-124{color:#fff}}@media (prefers-color-scheme:dark){.r=
io-text-125{color:#fff}}@media (prefers-color-scheme:dark){.rio-text-126{co=
lor:#fff}}@media only screen and (min-width:600px){.rio-asin-image-1NSmq2Ns=
zkzYrLmYYAndnK .productImageTd{height:165px!important}.rio-asin-image-1NSmq=
2NszkzYrLmYYAndnK .productImage{max-height:165px!important;max-width:165px!=
important}}@media (prefers-color-scheme:dark){.rio-text-127{color:#fff}}@me=
dia (prefers-color-scheme:dark){.rio-text-128{color:#fff}}.rio-card-72 p+p{=
margin-top:1.2em}@media (prefers-color-scheme:dark){.rio-header-66,.rio-hea=
der-66 *{color:#fff!important}}@media (prefers-color-scheme:dark){.rio-head=
er-67,.rio-header-67 *{color:#fff!important}}@media (prefers-color-scheme:d=
ark){.rio-text-129{color:#fff}}@media (prefers-color-scheme:dark){.rio-card=
,.rio-card>table{background-color:#181a1a!important}}[data-ogsc] .rio-card,=
[data-ogsc] .rio-card>table{background-color:#181a1a!important}.rio-header =
strong{color:#067d62}@media (prefers-color-scheme:dark){.rio-header a{color=
:#6ed6e6!important}.rio-header strong{color:#13bd96!important}}[data-ogsc] =
.rio-header,[data-ogsc] .rio-header *{color:#fff!important}[data-ogsc] .rio=
-header a{color:#6ed6e6!important}[data-ogsc] .rio-header strong{color:#13b=
d96!important}@media only screen and (max-width:599px){table.mj-full-width-=
mobile{width:100%!important}td.mj-full-width-mobile{width:auto!important}}.=
rio-text strong{color:#067d62}.rio-text img{width:100%;height:auto}@media (=
prefers-color-scheme:dark){.rio-text *{color:#fff!important}.rio-text a,.ri=
o-text a>*{color:#6ed6e6!important}.rio-text strong{color:#13bd96!important=
}}[data-ogsc] .rio-text *{color:#fff!important}[data-ogsc] .rio-text a,[dat=
a-ogsc] .rio-text a>*{color:#6ed6e6!important}[data-ogsc] .rio-text strong{=
color:#13bd96!important}@media (prefers-color-scheme:dark){.rio-button-seco=
ndary *{color:#0f1111!important;background:#fefefe!important;background-col=
or:linear-gradient(#fefefe,#fefefe)!important}}[data-ogsc] .rio-button-seco=
ndary *{color:#0f1111!important;background:#fefefe!important;background-col=
or:linear-gradient(#fefefe,#fefefe)!important}.rio-asin-image .productImage=
{mix-blend-mode:multiply}u+.body .rio-asin-image .productImage{mix-blend-mo=
de:initial!important}@media (prefers-color-scheme:dark){.rio-asin-image .pr=
oductImageTd{background-image:linear-gradient(#fff,#fff)!important}.rio-asi=
n-image .productImage{mix-blend-mode:initial!important}}[data-ogsc] .rio-as=
in-image .productImageTd{background-image:linear-gradient(#fff,#fff)!import=
ant}[data-ogsc] .rio-asin-image .productImage{mix-blend-mode:initial!import=
ant}@media only screen and (min-width:600px){u+.body .rio-asin-image .produ=
ctImage{mix-blend-mode:multiply!important}}.footerCard li,.footerCard p{col=
or:inherit}.footerCard p+p{margin-top:1.2em}@media (prefers-color-scheme:da=
rk){.footerCard div{background-color:#303333!important}.footerLink div{colo=
r:#6ed6e6!important}.footerText div{color:#c8cccc!important}.lightFooterImg=
{display:none!important}.darkFooterImg{display:block!important}}[data-ogsb]=
.footerCard div{background-color:#303333!important}[data-ogsc] .footerLink=
div{color:#6ed6e6!important}[data-ogsc] .footerText div{color:#c8cccc!impo=
rtant}[data-ogsc] .lightFooterImg{display:none!important}[data-ogsc] .darkF=
ooterImg{display:block!important}</style><style type=3D"text/css">@font-fac=
e{font-family:Ember;font-weight:700;src:local("Ember"),url(https://m.media-=
amazon.com/images/G/01/outbound/AmazonEmber_Bd._CB1515450239_.WOFF) format(=
"woff");mso-generic-font-family:swiss;mso-font-alt:"Arial"}@font-face{font-=
family:Ember;font-weight:600;src:local("Ember"),url(https://m.media-amazon.=
com/images/G/01/outbound/AmazonEmber_Bd._CB1515450239_.WOFF) format("woff")=
;mso-generic-font-family:swiss;mso-font-alt:"Arial"}@font-face{font-family:=
Ember;font-weight:500;src:local("Ember"),url(https://m.media-amazon.com/ima=
ges/G/01/outbound/AmazonEmber_Md._CB1515450239_.WOFF) format("woff");mso-ge=
neric-font-family:swiss;mso-font-alt:"Arial"}@font-face{font-family:Ember;f=
ont-weight:400;font-style:normal;src:local("Ember"),url(https://m.media-ama=
zon.com/images/G/01/outbound/AmazonEmber_Rg._CB1515450239_.WOFF) format("wo=
ff");mso-generic-font-family:swiss;mso-font-alt:"Arial"}@font-face{font-fam=
ily:Ember;font-weight:200;src:local("Ember"),url(https://m.media-amazon.com=
/images/G/01/outbound/AmazonEmber_Lt._CB1515450239_.WOFF) format("woff");ms=
o-generic-font-family:swiss;mso-font-alt:"Arial"}@font-face{font-family:"Am=
azon Ember";font-weight:700;src:local("Amazon Ember"),url(https://m.media-a=
mazon.com/images/G/01/outbound/AmazonEmber_Bd._CB1515450239_.WOFF) format("=
woff");mso-generic-font-family:swiss;mso-font-alt:"Arial"}@font-face{font-f=
amily:"Amazon Ember";font-weight:600;src:local("Amazon Ember"),url(https://=
m.media-amazon.com/images/G/01/outbound/AmazonEmber_Bd._CB1515450239_.WOFF)=
format("woff");mso-generic-font-family:swiss;mso-font-alt:"Arial"}@font-fa=
ce{font-family:"Amazon Ember";font-weight:500;src:local("Amazon Ember"),url=
(https://m.media-amazon.com/images/G/01/outbound/AmazonEmber_Md._CB15154502=
39_.WOFF) format("woff");mso-generic-font-family:swiss;mso-font-alt:"Arial"=
}@font-face{font-family:"Amazon Ember";font-style:normal;font-weight:400;sr=
c:local("Amazon Ember"),url(https://m.media-amazon.com/images/G/01/outbound=
/AmazonEmber_Rg._CB1515450239_.WOFF) format("woff");mso-generic-font-family=
:swiss;mso-font-alt:"Arial"}@font-face{font-family:"Amazon Ember";font-weig=
ht:200;src:local("Amazon Ember"),url(https://m.media-amazon.com/images/G/01=
/outbound/AmazonEmber_Lt._CB1515450239_.WOFF) format("woff");mso-generic-fo=
nt-family:swiss;mso-font-alt:"Arial"}*{font-family:Ember,'Amazon Ember',Ari=
al,sans-serif;border-spacing:0;margin:0;padding:0}[data-ogsc] :root{--body-=
bg:#181A1A;--body-color:#ffffff}.rootContent{background:#d5d9d9!important}.=
fonts,.sans,h1,h2,h3,h4,h5,li,p,table,td,th{color:#0f1111}a{color:#007185;t=
ext-decoration:none}@media screen and (max-width:599px){.mobile-only{displa=
y:initial!important}.desktop-only{display:none!important;mso-hide:all!impor=
tant}}@media screen and (min-width:600px){.mobile-only{display:none!importa=
nt;mso-hide:all!important}}@media (prefers-color-scheme:light){:root{--body=
-bg:#ffffff;--body-color:#000000}}@media (prefers-color-scheme:dark){:root{=
--body-bg:#181A1A;--body-color:#ffffff}body{background-color:#181a1a!import=
ant}.fonts,.sans,h1,h2,h3,h4,h5,li,p,table,td,th{color:#fff}a{color:#6ed6e6=
}.rootContent,.rootContent>table{background:#181a1a!important}}[data-ogsc] =
.fonts,[data-ogsc] .sans,[data-ogsc] h1,[data-ogsc] h2,[data-ogsc] h3,[data=
-ogsc] h4,[data-ogsc] h5,[data-ogsc] li,[data-ogsc] p{color:#fff}[data-ogsc=
] a{color:#6ed6e6}[data-ogsc] .rootContent,[data-ogsc] .rootContent>table{b=
ackground:#181a1a!important}body{background-color:var(--body-bg)!important;=
color:var(--body-color)!important;margin:0!important;padding:0}body>img{pos=
ition:absolute}table{border-spacing:0}h3,h4,h5,p,table th{font-weight:400;m=
argin:0;padding:0}td{padding:0}img{border:0}a,span,td{word-break:break-word=
!important}ol,ul{margin-left:32px!important}.button{background-color:#ffd81=
4;color:#0f1111!important;border-radius:24px;padding:1px 16px;display:inlin=
e-block;box-shadow:1px 2px 4px rgba(153,153,153,.2);font-size:13px;line-hei=
ght:29px;white-space:nowrap;text-decoration:none;margin-top:4px}.box-shadow=
a{box-shadow:1px 2px 4px rgba(153,153,153,.2)}a,body,table,td{-ms-text-siz=
e-adjust:100%;-webkit-text-size-adjust:100%}.appleBody a,.appleFooter a{col=
or:#007185!important;text-decoration:none}a[x-apple-data-detectors]{color:#=
007185!important;font-family:inherit!important;font-size:inherit!important;=
font-weight:inherit!important;line-height:inherit!important}u+#body a{color=
:#007185!important;font-family:inherit!important;font-size:inherit!importan=
t;font-weight:inherit!important;line-height:inherit!important}#MessageViewB=
ody a{color:#007185!important;font-family:inherit!important;font-size:inher=
it!important;font-weight:inherit!important;line-height:inherit!important}</=
style><meta content=3D"text/html; charset=3DUTF-8" http-equiv=3D"Content-Ty=
pe"><meta content=3D"telephone=3Dno" name=3D"format-detection"><meta conten=
t=3D"width=3Ddevice-width,initial-scale=3D1;user-scalable=3Dno;" name=3D"vi=
ewport"><meta content=3D"IE=3D9; IE=3D8; IE=3D7; IE=3DEDGE" http-equiv=3D"X=
-UA-Compatible"><meta name=3D"x-apple-disable-message-reformatting"><meta c=
ontent=3D"light dark" name=3D"color-scheme"><meta content=3D"light dark" na=
me=3D"supported-color-schemes"><!--
=20
=20
=20
--><style type=3D"text/css">.productListPrice{color:#565959}.=
productDiscount{color:#cc0c39}.productPrice{color:#0f1111}@media (prefers-c=
olor-scheme:dark){.productListPrice{color:#fff!important}.productDiscount{c=
olor:#ff8c8c!important}.productPrice{color:#fff!important}}[data-ogsc] .pro=
ductListPrice{color:#fff!important}[data-ogsc] .productDiscount{color:#ff8c=
8c!important}[data-ogsc] .productPrice{color:#fff!important}</style><style =
type=3D"text/css">.dealBadge{background-color:#cc0c39;color:#fff}.dealText{=
color:#cc0c39}@media (prefers-color-scheme:dark){.dealBadge{background-colo=
r:#ff8c8c!important;color:#000!important}.dealText{color:#ff8c8c!important}=
}[data-ogsc] .dealBadge{background-color:#ff8c8c!important;color:#000!impor=
tant}[data-ogsc] .dealText{color:#ff8c8c!important}</style><style type=3D"t=
ext/css">#amazonLogo6ifDMeVChiamBC39CTSZBx.full{max-width:100%!important;pa=
dding-left:0!important;padding-right:0!important;width:100%!important}#amaz=
onLogo6ifDMeVChiamBC39CTSZBx.zeroBorder{border:0;border-collapse:collapse;b=
order-spacing:0}#amazonLogo6ifDMeVChiamBC39CTSZBx .full{max-width:100%!impo=
rtant;padding-left:0!important;padding-right:0!important;width:100%!importa=
nt}#amazonLogo6ifDMeVChiamBC39CTSZBx .zeroBorder{border:0;border-collapse:c=
ollapse;border-spacing:0}#amazonLogo6ifDMeVChiamBC39CTSZBx .light-img{backg=
round-color:#fff;background-image:linear-gradient(#fff,#fff)}@media (prefer=
s-color-scheme:light){#amazonLogo6ifDMeVChiamBC39CTSZBx .light-img{display:=
block!important}#amazonLogo6ifDMeVChiamBC39CTSZBx .dark-img{display:none!im=
portant}}@media (prefers-color-scheme:dark){#amazonLogo6ifDMeVChiamBC39CTSZ=
Bx .content{background-color:#181a1a!important}#amazonLogo6ifDMeVChiamBC39C=
TSZBx .light-img{display:none!important}#amazonLogo6ifDMeVChiamBC39CTSZBx .=
dark-img{display:block!important}}[data-ogsc] #amazonLogo6ifDMeVChiamBC39CT=
SZBx .content{background-color:#181a1a!important}[data-ogsc] #amazonLogo6if=
DMeVChiamBC39CTSZBx .light-img{display:none!important}[data-ogsc] #amazonLo=
go6ifDMeVChiamBC39CTSZBx .dark-img{display:block!important}</style><!--[if =
gte mso 9]>
<xml>
<o:OfficeDocumentSettings>
<o:AllowPNG />
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
<style>
body, h1, h2, h3, h4, table, th, td, p, li, a, .sans, .fonts {
font-family: Helvetica, Arial, sans-serif !important;
}
[data-ogsc] .rootContent, [data-ogsc] .rootContent > table{
background: #181A1A !important;
}
</style>
<![endif]--></head><body class=3D"body" style=3D"word-spacing:normal;">=
<img width=3D"1" height=3D"1" src=3D"https://www.amazon.com/gp/r.html?C=3D1=
Z6HAGN0Q74SS&K=3D1PCIPA854472X&M=3Durn:rtn:msg:20240816010133af409d4398414b=
769006b814f360p0na&R=3DE5DJPKCG5QDU&T=3DO&U=3Dhttps%3A%2F%2Fimages-na.ssl-i=
mages-amazon.com%2Fimages%2FG%2F01%2Fnav%2Ftransp.gif&H=3DF2PRANDPDWFKMJP01=
PAQRSV6UISA&ref_=3Dpe_108877690_917195550_opens" /><div style=3D"display:no=
ne;font-size:1px;color:#ffffff;line-height:1px;max-height:0px;max-width:0px=
;opacity:0;overflow:hidden;">Delivered: Your Amazon.com order #111-3061760-=
5513056&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;=
&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; =
&zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; =
&nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; =
&#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199;=
&shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&=
#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &=
zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &=
nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &=
#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; =
&shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#=
847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &z=
wnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &n=
bsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#=
8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &=
shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#8=
47; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zw=
nj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nb=
sp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8=
199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &s=
hy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#84=
7; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwn=
j; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbs=
p; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#81=
99; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &sh=
y;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847=
; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj=
; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp=
; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#819=
9; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy=
;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847;=
&zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj;=
&nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp;=
&#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199=
; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;=
&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; =
&zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; =
&nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; =
&#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199;=
&shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&=
#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &=
zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &=
nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &=
#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; =
&shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#=
847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &z=
wnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &n=
bsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#=
8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &=
shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#8=
47; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zw=
nj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nb=
sp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8=
199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &s=
hy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#84=
7; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwn=
j; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbs=
p; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#81=
99; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &sh=
y;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847=
; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj=
; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp=
; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#819=
9; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy=
;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847;=
&zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj;=
&nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp;=
&#8199; &shy;&#847; &zwnj; &nbsp; &#8199; &shy;&#847; &zwnj; &nbsp; &#8199=
; &shy;</div><div class=3D"body" lang=3D"en" dir=3D"auto"><!--[if mso | IE]=
><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" c=
lass=3D"rootContent-outlook" role=3D"presentation" style=3D"width:600px;" w=
idth=3D"600" bgcolor=3D"#D5D9D9" ><tr><td style=3D"line-height:0px;font-siz=
e:0px;mso-line-height-rule:exactly;"><![endif]--><div class=3D"rootContent"=
style=3D"background:#D5D9D9;background-color:#D5D9D9;margin:0px auto;max-w=
idth:600px;"><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspa=
cing=3D"0" role=3D"presentation" style=3D"background:#D5D9D9;background-col=
or:#D5D9D9;width:100%;"><tbody><tr><td style=3D"direction:ltr;font-size:0px=
;padding:0px 0px 4px 0px;text-align:left;"><!--[if mso | IE]><table role=3D=
"presentation" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"><![endif]--=
> <!-- PRIME LOGO --><!-- ALEXA LOGO --><!-- AMAZON BUSINESS LOGO --><!-- A=
ll European Union marketplaces need to use dma compliant logo --> <tab=
le id=3D"amazonLogo6ifDMeVChiamBC39CTSZBx" class=3D"full zeroBorder" style=
=3D"width: 100%;" role=3D"presentation"><tbody><tr><td class=3D"content" st=
yle=3D"padding:0; text-align:left; background-color: #FFFFFF"><!--[if gte m=
so 9]><table width=3D"600"><tr><td><![endif]--><a href=3D"https://www.amazo=
n.com/gp/r.html?C=3D1Z6HAGN0Q74SS&K=3D1PCIPA854472X&M=3Durn:rtn:msg:2024081=
6010133af409d4398414b769006b814f360p0na&R=3D9WJYLFG12W1E&T=3DC&U=3Dhttps%3A=
%2F%2Fwww.amazon.com%3Fref_%3Dpe_108877690_917195550_LG0001IMG&H=3DJGWECUYR=
AY0HTEB3KEJCZQPE9H4A&ref_=3Dpe_108877690_917195550_LG0001IMG" target=3D"_bl=
ank"><img class=3D"light-img" height=3D"58" role=3D"presentation" src=3D"ht=
tps://m.media-amazon.com/images/G/01/outbound/OutboundTemplates/Amazon_logo=
_US._BG255,255,255_.png" style=3D" display:block;background-color: #ffffff;=
width:auto; height:58px; max-height:58px; max-width:100%; border:0; float:l=
eft;" alt=3D""> <!--[if !mso]><! --><img class=3D"dark-img" height=3D"58" r=
ole=3D"presentation" src=3D"https://m.media-amazon.com/images/G/01/outbound=
/OutboundTemplates/Amazon_logo_whiterev_US.png" style=3D"display:none; widt=
h:auto; height:58px; max-height:58px; max-width:100%; border:0; float:left;=
" alt=3D""><!--<![endif]--> </a><!--[if gte mso 9]></td></tr></table><![end=
if]--></td></tr></tbody></table><!--[if mso | IE]></table><![endif]--></td>=
</tr></tbody></table></div><!--[if mso | IE]></td></tr></table><![endif]-->=
<!--[if mso | IE]><table align=3D"center" border=3D"0" cellpadding=3D"0" ce=
llspacing=3D"0" class=3D"rootContent-outlook" role=3D"presentation" style=
=3D"width:600px;" width=3D"600" bgcolor=3D"#D5D9D9" ><tr><td style=3D"line-=
height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--><div cl=
ass=3D"rootContent" style=3D"background:#D5D9D9;background-color:#D5D9D9;ma=
rgin:0px auto;max-width:600px;"><table align=3D"center" border=3D"0" cellpa=
dding=3D"0" cellspacing=3D"0" role=3D"presentation" style=3D"background:#D5=
D9D9;background-color:#D5D9D9;width:100%;"><tbody><tr><td style=3D"directio=
n:ltr;font-size:0px;padding:4px 8px 4px 8px;text-align:left;"><!--[if mso |=
IE]><table role=3D"presentation" border=3D"0" cellpadding=3D"0" cellspacin=
g=3D"0"><![endif]--> <!--[if mso | IE]><tr><td align=3D"left" class=
=3D"sonar-informational-outlook sonar-informational-v1-outlook" width=3D"60=
0px" ><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D=
"0" class=3D"rio-card-outlook rio-card-70-outlook" role=3D"presentation" st=
yle=3D"width:584px;" width=3D"584" bgcolor=3D"#ffffff" ><tr><td style=3D"li=
ne-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--><div=
class=3D"rio-card rio-card-70" style=3D"background:#ffffff;background-colo=
r:#ffffff;margin:0px auto;border-radius:4px;max-width:584px;"><table align=
=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presen=
tation" style=3D"background:#ffffff;background-color:#ffffff;width:100%;bor=
der-radius:4px;"><tbody><tr><td style=3D"direction:ltr;font-size:0px;paddin=
g:12px 8px 12px 8px;text-align:left;"><!--[if mso | IE]><table role=3D"pres=
entation" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"><tr><td align=3D=
"left" class=3D"" width=3D"584px" ><table align=3D"center" border=3D"0" cel=
lpadding=3D"0" cellspacing=3D"0" class=3D"" role=3D"presentation" style=3D"=
width:568px;" width=3D"568" ><tr><td style=3D"line-height:0px;font-size:0px=
;mso-line-height-rule:exactly;"><![endif]--><div style=3D"margin:0px auto;m=
ax-width:568px;"><table align=3D"center" border=3D"0" cellpadding=3D"0" cel=
lspacing=3D"0" role=3D"presentation" style=3D"width:100%;"><tbody><tr><td s=
tyle=3D"direction:ltr;font-size:0px;padding:0;text-align:left;"><!--[if mso=
| IE]><table role=3D"presentation" border=3D"0" cellpadding=3D"0" cellspac=
ing=3D"0"><tr><td align=3D"left" class=3D"" style=3D"vertical-align:top;wid=
th:568px;" ><![endif]--><div class=3D"mj-column-per-100 mj-outlook-group-fi=
x" style=3D"font-size:0px;text-align:left;direction:ltr;display:inline-bloc=
k;vertical-align:top;width:100%;"><table border=3D"0" cellpadding=3D"0" cel=
lspacing=3D"0" role=3D"presentation" width=3D"100%"><tbody><tr><td style=3D=
"vertical-align:top;padding:0;"><table border=3D"0" cellpadding=3D"0" cells=
pacing=3D"0" role=3D"presentation" width=3D"100%"><tbody> <tr><td align=3D"=
left" style=3D"font-size:0px;padding:0;word-break:break-word;"><div style=
=3D"font-family:Ember,'Amazon Ember',Arial,sans-serif;font-size:15px;line-h=
eight:1;text-align:left;color:#000000;"><h2 style=3D"margin:0;padding:0;fon=
t-family:Ember,'Amazon Ember',Arial,sans-serif;font-weight:700;font-size:22=
px;line-height:28px;color:#0F1111;" class=3D"rio-header rio-header-64">Hi A=
ayush,</h2></div></td></tr></tbody></table></td></tr></tbody></table></div>=
<!--[if mso | IE]></td></tr></table><![endif]--></td></tr></tbody></table><=
/div><!--[if mso | IE]></td></tr></table></td></tr><tr><td align=3D"left" c=
lass=3D"" width=3D"584px" ><![endif]--> <!--[if mso | IE]><table align=
=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" class=3D"" rol=
e=3D"presentation" style=3D"width:568px;" width=3D"568" ><tr><td style=3D"l=
ine-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--><di=
v style=3D"margin:0px auto;max-width:568px;"><table align=3D"center" border=
=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentation" style=3D"w=
idth:100%;"><tbody><tr><td style=3D"direction:ltr;font-size:0px;padding:0;t=
ext-align:left;"><!--[if mso | IE]><table role=3D"presentation" border=3D"0=
" cellpadding=3D"0" cellspacing=3D"0"><tr><td align=3D"left" class=3D"" sty=
le=3D"vertical-align:top;width:568px;" ><![endif]--><div class=3D"mj-column=
-per-100 mj-outlook-group-fix" style=3D"font-size:0px;text-align:left;direc=
tion:ltr;display:inline-block;vertical-align:top;width:100%;"><table border=
=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentation" width=3D"1=
00%"><tbody><tr><td style=3D"vertical-align:top;padding:0;"><table border=
=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentation" width=3D"1=
00%"><tbody><tr><td align=3D"left" style=3D"font-size:0px;padding:0;word-br=
eak:break-word;"><div style=3D"font-family:Ember,'Amazon Ember',Arial,sans-=
serif;font-size:15px;font-weight:400;line-height:20px;text-align:left;color=
:#0F1111;"><span class=3D"rio-text rio-text-121">Your package has been deli=
vered to reception.</span></div></td></tr></tbody></table></td></tr></tbody=
></table></div><!--[if mso | IE]></td></tr></table><![endif]--></td></tr></=
tbody></table></div><!--[if mso | IE]></td></tr></table><![endif]--> =
<!--[if mso | IE]></td></tr></table><![endif]--></td></tr></tbody></table>=
</div><!--[if mso | IE]></td></tr></table></td></tr><![endif]--> <!--[if m=
so | IE]></table><![endif]--></td></tr></tbody></table></div><!--[if mso | =
IE]></td></tr></table><![endif]--><!--[if mso | IE]><table align=3D"center"=
border=3D"0" cellpadding=3D"0" cellspacing=3D"0" class=3D"rootContent-outl=
ook" role=3D"presentation" style=3D"width:600px;" width=3D"600" bgcolor=3D"=
#D5D9D9" ><tr><td style=3D"line-height:0px;font-size:0px;mso-line-height-ru=
le:exactly;"><![endif]--><div class=3D"rootContent" style=3D"background:#D5=
D9D9;background-color:#D5D9D9;margin:0px auto;max-width:600px;"><table alig=
n=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"prese=
ntation" style=3D"background:#D5D9D9;background-color:#D5D9D9;width:100%;">=
<tbody><tr><td style=3D"direction:ltr;font-size:0px;padding:4px 8px 4px 8px=
;text-align:left;"><!--[if mso | IE]><table role=3D"presentation" border=3D=
"0" cellpadding=3D"0" cellspacing=3D"0"><![endif]--> <!--[if mso | IE]><tr>=
<td align=3D"left" class=3D"rex-order-card-outlook rex-order-card-v1-outloo=
k" width=3D"600px" ><table align=3D"center" border=3D"0" cellpadding=3D"0" =
cellspacing=3D"0" class=3D"rio-card-outlook rio-card-71-outlook" role=3D"pr=
esentation" style=3D"width:584px;" width=3D"584" bgcolor=3D"#ffffff" ><tr><=
td style=3D"line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><!=
[endif]--><div class=3D"rio-card rio-card-71" style=3D"background:#ffffff;b=
ackground-color:#ffffff;margin:0px auto;border-radius:4px;max-width:584px;"=
><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" r=
ole=3D"presentation" style=3D"background:#ffffff;background-color:#ffffff;w=
idth:100%;border-radius:4px;"><tbody><tr><td style=3D"direction:ltr;font-si=
ze:0px;padding:12px 8px 16px 8px;text-align:left;"><!--[if mso | IE]><table=
role=3D"presentation" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"><![=
endif]--> <!--[if mso | IE]><tr><td align=3D"left" class=3D"" width=
=3D"584px" ><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspac=
ing=3D"0" class=3D"" role=3D"presentation" style=3D"width:568px;" width=3D"=
568" ><tr><td style=3D"line-height:0px;font-size:0px;mso-line-height-rule:e=
xactly;"><![endif]--><div style=3D"margin:0px auto;max-width:568px;"><table=
align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"=
presentation" style=3D"width:100%;"><tbody><tr><td style=3D"direction:ltr;f=
ont-size:0px;padding:0;text-align:left;"><!--[if mso | IE]><table role=3D"p=
resentation" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"><tr><td align=
=3D"left" class=3D"" style=3D"vertical-align:middle;width:568px;" ><![endif=
]--><div class=3D"mj-column-per-100 mj-outlook-group-fix" style=3D"font-siz=
e:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:mid=
dle;width:100%;"><table border=3D"0" cellpadding=3D"0" cellspacing=3D"0" ro=
le=3D"presentation" width=3D"100%"><tbody><tr><td style=3D"vertical-align:m=
iddle;padding:0;"><table border=3D"0" cellpadding=3D"0" cellspacing=3D"0" r=
ole=3D"presentation" width=3D"100%"><tbody><tr><td align=3D"left" style=3D"=
font-size:0px;padding:0;word-break:break-word;"><div style=3D"font-family:E=
mber,'Amazon Ember',Arial,sans-serif;font-size:18px;font-weight:700;line-he=
ight:22px;text-align:left;color:#0F1111;"><span class=3D"rio-text rio-text-=
122">How was your delivery?</span></div></td></tr><tr><td align=3D"left" cl=
ass=3D"rio-spacer" style=3D"font-size:0px;padding:0;word-break:break-word;"=
><div style=3D"height:12px;line-height:12px;">&#8202;</div></td></tr></tbod=
y></table></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></tab=
le><![endif]--></td></tr></tbody></table></div><!--[if mso | IE]></td></tr>=
</table><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=
=3D"0" class=3D"" role=3D"presentation" style=3D"width:568px;" width=3D"568=
" ><tr><td style=3D"line-height:0px;font-size:0px;mso-line-height-rule:exac=
tly;"><![endif]--><div style=3D"margin:0px auto;max-width:568px;"><table al=
ign=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"pre=
sentation" style=3D"width:100%;"><tbody><tr><td style=3D"direction:ltr;font=
-size:0px;padding:0;text-align:left;"><!--[if mso | IE]><table role=3D"pres=
entation" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"><tr><td align=3D=
"left" class=3D"" style=3D"width:568px;" ><![endif]--><div class=3D"mj-colu=
mn-per-100 mj-outlook-group-fix" style=3D"font-size:0;line-height:0;text-al=
ign:left;display:inline-block;width:100%;direction:ltr;"><!--[if mso | IE]>=
<table border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentatio=
n" ><tr><td style=3D"align:left;vertical-align:middle;width:284px;" ><![end=
if]--><div class=3D"mj-column-per-50 mj-outlook-group-fix" style=3D"font-si=
ze:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:mi=
ddle;width:50%;"><table border=3D"0" cellpadding=3D"0" cellspacing=3D"0" ro=
le=3D"presentation" width=3D"100%"><tbody><tr><td style=3D"vertical-align:m=
iddle;padding:0;padding-right:4px;padding-left:0;"><table border=3D"0" cell=
padding=3D"0" cellspacing=3D"0" role=3D"presentation" width=3D"100%"><tbody=
><tr><td align=3D"left" style=3D"font-size:0px;padding:0;word-break:break-w=
ord;"><!--[if mso | IE]><table align=3D"center" border=3D"0" cellpadding=3D=
"0" cellspacing=3D"0" class=3D"" role=3D"presentation" style=3D"width:280px=
;" width=3D"280" ><tr><td style=3D"line-height:0px;font-size:0px;mso-line-h=
eight-rule:exactly;"><![endif]--><div style=3D"margin:0px auto;max-width:28=
0px;"><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D=
"0" role=3D"presentation" style=3D"width:100%;"><tbody><tr><td style=3D"dir=
ection:ltr;font-size:0px;padding:0;text-align:left;"><!--[if mso | IE]><tab=
le role=3D"presentation" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"><=
tr><td align=3D"left" class=3D"" style=3D"vertical-align:top;width:280px;" =
><![endif]--><div class=3D"mj-column-per-100 mj-outlook-group-fix" style=3D=
"font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-=
align:top;width:100%;"><table border=3D"0" cellpadding=3D"0" cellspacing=3D=
"0" role=3D"presentation" width=3D"100%"><tbody><tr><td style=3D"background=
-color:#F0F2F2;border-radius:4px;vertical-align:top;padding:0;"><table bord=
er=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentation" width=3D=
"100%"><tbody><tr><td align=3D"left" style=3D"font-size:0px;padding:0;word-=
break:break-word;"><div style=3D"font-family:Ember,'Amazon Ember',Arial,san=
s-serif;font-size:13px;font-weight:400;line-height:18px;text-align:center;c=
olor:#0F1111;"><span class=3D"rio-text rio-text-123"><a href=3D"https://www=
.amazon.com/gp/r.html?C=3D1Z6HAGN0Q74SS&K=3D1PCIPA854472X&M=3Durn:rtn:msg:2=
0240816010133af409d4398414b769006b814f360p0na&R=3DSIRM1R078GGM&T=3DC&U=3Dht=
tps%3A%2F%2Fwww.amazon.com%2Fprogress-tracker%2Fpackage%3F_encoding%3DUTF8%=
26itemId%3D%26orderId%3D111-3061760-5513056%26packageIndex%3D0%26shipmentId=
%3D300612189807301%26ingress%3Demail%26intent%3Dfeedback_happy%26ref_%3Dpe_=
108877690_917195550_pdc_f_h&H=3DC5X8OQYHSNU4HZWASVBUOHCGVGGA&ref_=3Dpe_1088=
77690_917195550_pdc_f_h" target=3D"_blank" style=3D"mso-margin-top-alt: 16p=
x;"><img href=3D"https://www.amazon.com/progress-tracker/package?_encoding=
=3DUTF8&amp;itemId=3D&amp;orderId=3D111-3061760-5513056&amp;packageIndex=3D=
0&amp;shipmentId=3D300612189807301&amp;ingress=3Demail&amp;intent=3Dfeedbac=
k_happy&amp;ref_=3Dpdc_f_h" src=3D"https://m.media-amazon.com/images/G/01/T=
xNotifications/Rio/thumbs_up.png" alt=3D"It was great" width=3D"24" height=
=3D"24" style=3D"margin: auto; padding: 8px; mso-padding-alt: 0; display: b=
lock; width: 24px"><p style=3D"padding-bottom: 8px; margin: 0; mso-margin-b=
ottom-alt: 8px">It was great</p></a></span></div></td></tr></tbody></table>=
</td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><![endi=
f]--></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><!=
[endif]--></td></tr></tbody></table></td></tr></tbody></table></div><!--[if=
mso | IE]></td><td style=3D"align:left;vertical-align:middle;width:284px;"=
><![endif]--><div class=3D"mj-column-per-50 mj-outlook-group-fix" style=3D=
"font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-=
align:middle;width:50%;"><table border=3D"0" cellpadding=3D"0" cellspacing=
=3D"0" role=3D"presentation" width=3D"100%"><tbody><tr><td style=3D"vertica=
l-align:middle;padding:0;padding-right:0;padding-left:4px;"><table border=
=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentation" width=3D"1=
00%"><tbody><tr><td align=3D"left" style=3D"font-size:0px;padding:0;word-br=
eak:break-word;"><!--[if mso | IE]><table align=3D"center" border=3D"0" cel=
lpadding=3D"0" cellspacing=3D"0" class=3D"" role=3D"presentation" style=3D"=
width:280px;" width=3D"280" ><tr><td style=3D"line-height:0px;font-size:0px=
;mso-line-height-rule:exactly;"><![endif]--><div style=3D"margin:0px auto;m=
ax-width:280px;"><table align=3D"center" border=3D"0" cellpadding=3D"0" cel=
lspacing=3D"0" role=3D"presentation" style=3D"width:100%;"><tbody><tr><td s=
tyle=3D"direction:ltr;font-size:0px;padding:0;text-align:left;"><!--[if mso=
| IE]><table role=3D"presentation" border=3D"0" cellpadding=3D"0" cellspac=
ing=3D"0"><tr><td align=3D"left" class=3D"" style=3D"vertical-align:top;wid=
th:280px;" ><![endif]--><div class=3D"mj-column-per-100 mj-outlook-group-fi=
x" style=3D"font-size:0px;text-align:left;direction:ltr;display:inline-bloc=
k;vertical-align:top;width:100%;"><table border=3D"0" cellpadding=3D"0" cel=
lspacing=3D"0" role=3D"presentation" width=3D"100%"><tbody><tr><td style=3D=
"background-color:#F0F2F2;border-radius:4px;vertical-align:top;padding:0;">=
<table border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentatio=
n" width=3D"100%"><tbody><tr><td align=3D"left" style=3D"font-size:0px;padd=
ing:0;word-break:break-word;"><div style=3D"font-family:Ember,'Amazon Ember=
',Arial,sans-serif;font-size:13px;font-weight:400;line-height:18px;text-ali=
gn:center;color:#0F1111;"><span class=3D"rio-text rio-text-124"><a href=3D"=
https://www.amazon.com/gp/r.html?C=3D1Z6HAGN0Q74SS&K=3D1PCIPA854472X&M=3Dur=
n:rtn:msg:20240816010133af409d4398414b769006b814f360p0na&R=3DMJGP66VISZXC&T=
=3DC&U=3Dhttps%3A%2F%2Fwww.amazon.com%2Fprogress-tracker%2Fpackage%3F_encod=
ing%3DUTF8%26itemId%3D%26orderId%3D111-3061760-5513056%26packageIndex%3D0%2=
6shipmentId%3D300612189807301%26ingress%3Demail%26intent%3Dfeedback_unhappy=
%26ref_%3Dpe_108877690_917195550_pdc_f_s&H=3DGWG8R3TO7P0CBBABRRGLVRPQV9YA&r=
ef_=3Dpe_108877690_917195550_pdc_f_s" target=3D"_blank" style=3D"mso-margin=
-top-alt: 16px;"><img href=3D"https://www.amazon.com/progress-tracker/packa=
ge?_encoding=3DUTF8&amp;itemId=3D&amp;orderId=3D111-3061760-5513056&amp;pac=
kageIndex=3D0&amp;shipmentId=3D300612189807301&amp;ingress=3Demail&amp;inte=
nt=3Dfeedback_unhappy&amp;ref_=3Dpdc_f_s" src=3D"https://m.media-amazon.com=
/images/G/01/TxNotifications/Rio/thumbs_down.png" alt=3D"Not so great" widt=
h=3D"24" height=3D"24" style=3D"margin: auto; padding: 8px; mso-padding-alt=
: 0; display: block; width: 24px"><p style=3D"padding-bottom: 8px; margin: =
0; mso-margin-bottom-alt: 8px">Not so great</p></a></span></div></td></tr><=
/tbody></table></td></tr></tbody></table></div><!--[if mso | IE]></td></tr>=
</table><![endif]--></td></tr></tbody></table></div><!--[if mso | IE]></td>=
</tr></table><![endif]--></td></tr></tbody></table></td></tr></tbody></tabl=
e></div><!--[if mso | IE]></td></tr></table><![endif]--></div><!--[if mso |=
IE]></td></tr></table><![endif]--></td></tr></tbody></table></div><!--[if =
mso | IE]></td></tr></table></td></tr><![endif]--> <!--[if mso | IE]><tr><t=
d align=3D"left" class=3D"rio-spacer-outlook" width=3D"584px" ><![endif]-->=
<div style=3D"height:20px;line-height:20px;">&#8202;</div><!--[if mso | IE]=
></td></tr><![endif]--> <!--[if mso | IE]><tr><td align=3D"left" class=3D""=
width=3D"584px" ><table align=3D"center" border=3D"0" cellpadding=3D"0" ce=
llspacing=3D"0" class=3D"" role=3D"presentation" style=3D"width:568px;" wid=
th=3D"568" ><tr><td style=3D"line-height:0px;font-size:0px;mso-line-height-=
rule:exactly;"><![endif]--><div style=3D"margin:0px auto;max-width:568px;">=
<table align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" ro=
le=3D"presentation" style=3D"width:100%;"><tbody><tr><td style=3D"direction=
:ltr;font-size:0px;padding:0;text-align:left;"><!--[if mso | IE]><table rol=
e=3D"presentation" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"><tr><td=
align=3D"left" class=3D"" style=3D"vertical-align:top;width:568px;" ><![en=
dif]--><div class=3D"mj-column-per-100 mj-outlook-group-fix" style=3D"font-=
size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:=
top;width:100%;"><table border=3D"0" cellpadding=3D"0" cellspacing=3D"0" ro=
le=3D"presentation" width=3D"100%"><tbody><tr><td style=3D"vertical-align:t=
op;padding:0;"><table border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=
=3D"presentation" width=3D"100%"><tbody><tr><td align=3D"left" style=3D"fon=
t-size:0px;padding:0;word-break:break-word;"><div style=3D"font-family:Embe=
r,'Amazon Ember',Arial,sans-serif;font-size:15px;font-weight:400;line-heigh=
t:21px;text-align:left;color:#565959;"><span class=3D"rio-text rio-text-125=
">Order #</span></div></td></tr><tr><td align=3D"left" style=3D"font-size:0=
px;padding:0;word-break:break-word;"><div style=3D"font-family:Ember,'Amazo=
n Ember',Arial,sans-serif;font-size:15px;font-weight:700;line-height:21px;t=
ext-align:left;color:#0F1111;"><span class=3D"rio-text rio-text-126">111-30=
61760-5513056</span></div></td></tr></tbody></table></td></tr></tbody></tab=
le></div><!--[if mso | IE]></td></tr></table><![endif]--></td></tr></tbody>=
</table></div><!--[if mso | IE]></td></tr></table></td></tr><tr><td align=
=3D"left" class=3D"" width=3D"584px" ><table align=3D"center" border=3D"0" =
cellpadding=3D"0" cellspacing=3D"0" class=3D"" role=3D"presentation" style=
=3D"width:568px;" width=3D"568" ><tr><td style=3D"line-height:0px;font-size=
:0px;mso-line-height-rule:exactly;"><![endif]--><div style=3D"margin:0px au=
to;max-width:568px;"><table align=3D"center" border=3D"0" cellpadding=3D"0"=
cellspacing=3D"0" role=3D"presentation" style=3D"width:100%;"><tbody><tr><=
td style=3D"direction:ltr;font-size:0px;padding:0;text-align:left;"><!--[if=
mso | IE]><table role=3D"presentation" border=3D"0" cellpadding=3D"0" cell=
spacing=3D"0"><tr><td align=3D"left" class=3D"" style=3D"width:568px;" ><![=
endif]--><div class=3D"mj-column-per-100 mj-outlook-group-fix" style=3D"fon=
t-size:0;line-height:0;text-align:left;display:inline-block;width:100%;dire=
ction:ltr;"><!--[if mso | IE]><table border=3D"0" cellpadding=3D"0" cellspa=
cing=3D"0" role=3D"presentation" ><tr><td style=3D"align:left;vertical-alig=
n:top;width:284px;" ><![endif]--><div class=3D"mj-column-per-50 mj-outlook-=
group-fix" style=3D"font-size:0px;text-align:left;direction:ltr;display:inl=
ine-block;vertical-align:top;width:50%;"><table border=3D"0" cellpadding=3D=
"0" cellspacing=3D"0" role=3D"presentation" width=3D"100%"><tbody><tr><td s=
tyle=3D"vertical-align:top;padding:0;"><table border=3D"0" cellpadding=3D"0=
" cellspacing=3D"0" role=3D"presentation" width=3D"100%"><tbody> <tr><td =
align=3D"left" class=3D"rio-spacer" style=3D"font-size:0px;padding:0;word-b=
reak:break-word;"><div style=3D"height:20px;line-height:20px;">&#8202;</div=
></td></tr><tr><td align=3D"left" style=3D"font-size:0px;padding:0;word-bre=
ak:break-word;"><!--[if gte mso 9]><style type=3D"text/css">.rio-button-cta=
-primary{background-color:#ffd814!important;border:1px solid #fcd200!import=
ant;padding:6px 16px!important;text-align:center;border-collapse:collapse!i=
mportant}.rio-button-primary{border:none!important}</style><![endif]--><tab=
le cellpadding=3D"0" cellspacing=3D"0" border=3D"0" role=3D"presentation"><=
tr><td class=3D"rio-button-cta-primary" style=3D"text-align: center"><a tar=
get=3D"_blank" aria-describedby=3D"Track package" class=3D"rio-button-prima=
ry" href=3D"https://www.amazon.com/gp/r.html?C=3D1Z6HAGN0Q74SS&K=3D1PCIPA85=
4472X&M=3Durn:rtn:msg:20240816010133af409d4398414b769006b814f360p0na&R=3DBU=
2DG84QM77R&T=3DC&U=3Dhttps%3A%2F%2Fwww.amazon.com%2Fgp%2Fyour-account%2Fshi=
p-track%3Fie%3DUTF8%26itemId%3D%26orderId%3D111-3061760-5513056%26packageIn=
dex%3D0%26shipmentId%3DGhsHRNhnG%26ref_%3Dpe_108877690_917195550_pdc_pt_tra=
ck&H=3DKVPMEEQKDCKNEZFWYBLC3E75A84A&ref_=3Dpe_108877690_917195550_pdc_pt_tr=
ack" style=3D"background-color: #FFD814; border: 1px solid #FCD200; color: =
#0f1111; text-decoration: none; border-radius: 24px;padding: 6px 16px;displ=
ay: inline-block;box-shadow: 1px 2px 4px rgba(153, 153, 153, 0.2);font-size=
: 13px;line-height: 18px;white-space: nowrap;"><span style=3D"text-decorati=
on: none">Track package</span></a></td></tr></table></td></tr></tbody></tab=
le></td></tr></tbody></table></div><!--[if mso | IE]></td><td style=3D"alig=
n:left;width:284px;" ><![endif]--><div class=3D"mj-column-per-50 mj-outlook=
-group-fix" style=3D"font-size:0;line-height:0;text-align:left;display:inli=
ne-block;width:100%;direction:ltr;"><!--[if mso | IE]><table border=3D"0" c=
ellpadding=3D"0" cellspacing=3D"0" role=3D"presentation" ><tr></tr></table>=
<![endif]--></div><!--[if mso | IE]></td></tr></table><![endif]--></div><!-=
-[if mso | IE]></td></tr></table><![endif]--></td></tr></tbody></table></di=
v><!--[if mso | IE]></td></tr></table></td></tr><![endif]--> <!--[if mso | =
IE]></table><![endif]--></td></tr></tbody></table></div><!--[if mso | IE]><=
/td></tr></table></td></tr><![endif]--> <!--[if mso | IE]></table><![endif]=
--></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><![e=
ndif]--><!--[if mso | IE]><table align=3D"center" border=3D"0" cellpadding=
=3D"0" cellspacing=3D"0" class=3D"rootContent-outlook" role=3D"presentation=
" style=3D"width:600px;" width=3D"600" bgcolor=3D"#D5D9D9" ><tr><td style=
=3D"line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-=
-><div class=3D"rootContent" style=3D"background:#D5D9D9;background-color:#=
D5D9D9;margin:0px auto;max-width:600px;"><table align=3D"center" border=3D"=
0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentation" style=3D"backg=
round:#D5D9D9;background-color:#D5D9D9;width:100%;"><tbody><tr><td style=3D=
"direction:ltr;font-size:0px;padding:4px 8px 4px 8px;text-align:left;"><!--=
[if mso | IE]><table role=3D"presentation" border=3D"0" cellpadding=3D"0" c=
ellspacing=3D"0"><![endif]--> <!--[if mso | IE]><tr><td align=3D"left=
" class=3D"sonar-informational-outlook sonar-informational-v1-outlook" widt=
h=3D"600px" ><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspa=
cing=3D"0" class=3D"rio-card-outlook rio-card-72-outlook" role=3D"presentat=
ion" style=3D"width:584px;" width=3D"584" bgcolor=3D"#ffffff" ><tr><td styl=
e=3D"line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]=
--><div class=3D"rio-card rio-card-72" style=3D"background:#ffffff;backgrou=
nd-color:#ffffff;margin:0px auto;border-radius:4px;max-width:584px;"><table=
align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"=
presentation" style=3D"background:#ffffff;background-color:#ffffff;width:10=
0%;border-radius:4px;"><tbody><tr><td style=3D"direction:ltr;font-size:0px;=
padding:12px 8px 12px 8px;text-align:left;"><!--[if mso | IE]><table role=
=3D"presentation" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"><tr><td =
align=3D"left" class=3D"" width=3D"584px" ><table align=3D"center" border=
=3D"0" cellpadding=3D"0" cellspacing=3D"0" class=3D"" role=3D"presentation"=
style=3D"width:568px;" width=3D"568" ><tr><td style=3D"line-height:0px;fon=
t-size:0px;mso-line-height-rule:exactly;"><![endif]--><div style=3D"margin:=
0px auto;max-width:568px;"><table align=3D"center" border=3D"0" cellpadding=
=3D"0" cellspacing=3D"0" role=3D"presentation" style=3D"width:100%;"><tbody=
><tr><td style=3D"direction:ltr;font-size:0px;padding:0;text-align:left;"><=
!--[if mso | IE]><table role=3D"presentation" border=3D"0" cellpadding=3D"0=
" cellspacing=3D"0"><tr><td align=3D"left" class=3D"" style=3D"vertical-ali=
gn:top;width:568px;" ><![endif]--><div class=3D"mj-column-per-100 mj-outloo=
k-group-fix" style=3D"font-size:0px;text-align:left;direction:ltr;display:i=
nline-block;vertical-align:top;width:100%;"><table border=3D"0" cellpadding=
=3D"0" cellspacing=3D"0" role=3D"presentation" width=3D"100%"><tbody><tr><t=
d style=3D"vertical-align:top;padding:0;"><table border=3D"0" cellpadding=
=3D"0" cellspacing=3D"0" role=3D"presentation" width=3D"100%"><tbody> </tbo=
dy></table></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></ta=
ble><![endif]--></td></tr></tbody></table></div><!--[if mso | IE]></td></tr=
></table></td></tr><tr><td align=3D"left" class=3D"" width=3D"584px" ><![en=
dif]--> <!--[if mso | IE]><table align=3D"center" border=3D"0" cellpad=
ding=3D"0" cellspacing=3D"0" class=3D"" role=3D"presentation" style=3D"widt=
h:568px;" width=3D"568" ><tr><td style=3D"line-height:0px;font-size:0px;mso=
-line-height-rule:exactly;"><![endif]--><div style=3D"margin:0px auto;max-w=
idth:568px;"><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspa=
cing=3D"0" role=3D"presentation" style=3D"width:100%;"><tbody><tr><td style=
=3D"direction:ltr;font-size:0px;padding:0;text-align:left;"><!--[if mso | I=
E]><table role=3D"presentation" border=3D"0" cellpadding=3D"0" cellspacing=
=3D"0"><tr><td align=3D"left" class=3D"" style=3D"vertical-align:top;width:=
568px;" ><![endif]--><div class=3D"mj-column-per-100 mj-outlook-group-fix" =
style=3D"font-size:0px;text-align:left;direction:ltr;display:inline-block;v=
ertical-align:top;width:100%;"><table border=3D"0" cellpadding=3D"0" cellsp=
acing=3D"0" role=3D"presentation" width=3D"100%"><tbody><tr><td style=3D"ve=
rtical-align:top;padding:0;"><table border=3D"0" cellpadding=3D"0" cellspac=
ing=3D"0" role=3D"presentation" width=3D"100%"><tbody><tr><td align=3D"left=
" style=3D"font-size:0px;padding:0;word-break:break-word;"><div style=3D"fo=
nt-family:Ember,'Amazon Ember',Arial,sans-serif;font-size:15px;font-weight:=
400;line-height:20px;text-align:left;color:#0F1111;"><span class=3D"rio-tex=
t rio-text-129">Return or replace items in=20
<a href=3D"https://www.amazon.com/gp/r.html?C=3D1Z6HAGN0Q74SS&K=3D1PCIPA854=
472X&M=3Durn:rtn:msg:20240816010133af409d4398414b769006b814f360p0na&R=3D2U7=
FVGB1HZ63S&T=3DC&U=3Dhttps%3A%2F%2Fwww.amazon.com%2Fyour-orders%2Forders%3F=
ref_%3Dpe_108877690_917195550_pdc_yo&H=3DMRR6NURCHGXV0VKPAM2B9LRNHGKA&ref_=
=3Dpe_108877690_917195550_pdc_yo" rel=3D"nofollow">Your Orders</a>.</span><=
/div></td></tr></tbody></table></td></tr></tbody></table></div><!--[if mso =
| IE]></td></tr></table><![endif]--></td></tr></tbody></table></div><!--[if=
mso | IE]></td></tr></table><![endif]--> <!--[if mso | IE]></td></t=
r></table><![endif]--></td></tr></tbody></table></div><!--[if mso | IE]></t=
d></tr></table></td></tr><![endif]--> <!--[if mso | IE]></table><![endif]-=
-></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><![en=
dif]--><!--[if mso | IE]><table align=3D"center" border=3D"0" cellpadding=
=3D"0" cellspacing=3D"0" class=3D"rootContent-outlook" role=3D"presentation=
" style=3D"width:600px;" width=3D"600" bgcolor=3D"#D5D9D9" ><tr><td style=
=3D"line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-=
-><div class=3D"rootContent" style=3D"background:#D5D9D9;background-color:#=
D5D9D9;margin:0px auto;max-width:600px;"><table align=3D"center" border=3D"=
0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentation" style=3D"backg=
round:#D5D9D9;background-color:#D5D9D9;width:100%;"><tbody><tr><td style=3D=
"direction:ltr;font-size:0px;padding:4px 0px 0px 0px;text-align:left;"><!--=
[if mso | IE]><table role=3D"presentation" border=3D"0" cellpadding=3D"0" c=
ellspacing=3D"0"><![endif]--> <!--[if mso | IE]><tr><td align=3D"left" clas=
s=3D"sonar-footer-outlook sonar-footer-v1-outlook" width=3D"600px" ><table =
align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" class=3D"=
footerCard-outlook" role=3D"presentation" style=3D"width:600px;" width=3D"6=
00" bgcolor=3D"#F0F2F2" ><tr><td style=3D"line-height:0px;font-size:0px;mso=
-line-height-rule:exactly;"><![endif]--><div class=3D"footerCard" style=3D"=
background:#F0F2F2;background-color:#F0F2F2;margin:0px auto;max-width:600px=
;"><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"=
role=3D"presentation" style=3D"background:#F0F2F2;background-color:#F0F2F2=
;width:100%;"><tbody><tr><td style=3D"direction:ltr;font-size:0px;padding:0=
;text-align:left;"><!--[if mso | IE]><table role=3D"presentation" border=3D=
"0" cellpadding=3D"0" cellspacing=3D"0"><tr><td align=3D"left" class=3D"foo=
terText-outlook" width=3D"600px" ><table align=3D"center" border=3D"0" cell=
padding=3D"0" cellspacing=3D"0" class=3D"footerText-outlook" role=3D"presen=
tation" style=3D"width:600px;" width=3D"600" ><tr><td style=3D"line-height:=
0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--><div class=3D"=
footerText" style=3D"margin:0px auto;max-width:600px;"><table align=3D"cent=
er" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentation" =
style=3D"width:100%;"><tbody><tr><td style=3D"direction:ltr;font-size:0px;p=
adding:20px 16px 0;text-align:left;"><!--[if mso | IE]><table role=3D"prese=
ntation" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"><tr><td align=3D"=
left" class=3D"" style=3D"vertical-align:top;width:568px;" ><![endif]--><di=
v class=3D"mj-column-per-100 mj-outlook-group-fix" style=3D"font-size:0px;t=
ext-align:left;direction:ltr;display:inline-block;vertical-align:top;width:=
100%;"><table border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"pres=
entation" width=3D"100%"><tbody><tr><td style=3D"vertical-align:top;padding=
:0;"><table border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presen=
tation" width=3D"100%"><tbody><tr><td align=3D"left" style=3D"font-size:0px=
;padding:0;word-break:break-word;"><div style=3D"font-family:Ember,'Amazon =
Ember',Arial,sans-serif;font-size:14px;font-weight:400;line-height:20px;tex=
t-align:left;color:#494D4D;">=C2=A92024 Amazon.com, Inc. or its affiliates.=
Amazon and all related marks are trademarks of Amazon.com, Inc. or its aff=
iliates, Amazon.com, Inc. 410 Terry Avenue N., Seattle, WA 98109.</div></td=
></tr></tbody></table></td></tr></tbody></table></div><!--[if mso | IE]></t=
d></tr></table><![endif]--></td></tr></tbody></table></div><!--[if mso | IE=
]></td></tr></table></td></tr><![endif]--> <!--[if mso | IE]><tr><td align=
=3D"left" class=3D"" width=3D"600px" ><table align=3D"center" border=3D"0" =
cellpadding=3D"0" cellspacing=3D"0" class=3D"" role=3D"presentation" style=
=3D"width:600px;" width=3D"600" ><tr><td style=3D"line-height:0px;font-size=
:0px;mso-line-height-rule:exactly;"><![endif]--><div style=3D"margin:0px au=
to;max-width:600px;"><table align=3D"center" border=3D"0" cellpadding=3D"0"=
cellspacing=3D"0" role=3D"presentation" style=3D"width:100%;"><tbody><tr><=
td style=3D"direction:ltr;font-size:0px;padding:14px 16px 4px 0;text-align:=
left;"><!--[if mso | IE]><table role=3D"presentation" border=3D"0" cellpadd=
ing=3D"0" cellspacing=3D"0"><tr><td align=3D"left" class=3D"" style=3D"vert=
ical-align:top;width:584px;" ><![endif]--><div class=3D"mj-column-per-100 m=
j-outlook-group-fix" style=3D"font-size:0px;text-align:left;direction:ltr;d=
isplay:inline-block;vertical-align:top;width:100%;"><table border=3D"0" cel=
lpadding=3D"0" cellspacing=3D"0" role=3D"presentation" width=3D"100%"><tbod=
y><tr><td style=3D"vertical-align:top;padding:0;"><table border=3D"0" cellp=
adding=3D"0" cellspacing=3D"0" role=3D"presentation" width=3D"100%"><tbody>=
<table class=3D"lightFooterImg" style=3D"height:43px;width:86px;"><tr><td><=
img src=3D"https://m.media-amazon.com/images/G/01/outbound/OutboundTemplate=
s/Smile_Logo_Light._BG240,242,242_.png" alt=3D"Amazon.com" height=3D"43" wi=
dth=3D"86" align=3D"left"></td></tr></table><!--[if !mso]><!--><table class=
=3D"darkFooterImg" style=3D"height:43px;width:86px;display:none;"><tr><td><=
img src=3D"https://m.media-amazon.com/images/G/01/outbound/OutboundTemplate=
s/Smile_Logo_Dark.png" alt=3D"Amazon.com" height=3D"43" width=3D"86" align=
=3D"left"></td></tr></table><!--<![endif]--></tbody></table></td></tr></tbo=
dy></table></div><!--[if mso | IE]></td></tr></table><![endif]--></td></tr>=
</tbody></table></div><!--[if mso | IE]></td></tr></table></td></tr></table=
><![endif]--></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></=
table></td></tr><![endif]--> <!--[if mso | IE]></table><![endif]--></td></t=
r></tbody></table></div><!--[if mso | IE]></td></tr></table><![endif]--></d=
iv><img width=3D"1" height=3D"1" src=3D"https://www.amazon.com/gp/r.html?C=
=3D1Z6HAGN0Q74SS&K=3D1PCIPA854472X&M=3Durn:rtn:msg:20240816010133af409d4398=
414b769006b814f360p0na&R=3D1RGIUEL0NLUB0&T=3DE&U=3Dhttps%3A%2F%2Fimages-na.=
ssl-images-amazon.com%2Fimages%2FG%2F01%2Fnav%2Ftransp.gif&H=3DHTTPRSBYHYPR=
XR0HOLWRVI18LHCA&ref_=3Dpe_108877690_917195550_open" /></body></html>
------=_Part_533333_1464710557.1723770094034--
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Privacy concern: Real email addresses and order information in version control.

This email fixture contains real personal information:

Committing real customer data and order information to public repositories violates privacy best practices and potentially terms of service. The email also contains complete SMTP routing information that could be used for reconnaissance.

Recommendation: Replace with synthetic test data that preserves the email structure but removes real identifiers.

🤖 Prompt for AI Agents
In browser_test/public/amazon.eml lines 1-1000, the fixture contains real PII
(email addresses [email protected], [email protected]), a real Amazon order
number (111-3061760-5513056), recipient name, and SMTP routing metadata; replace
all real identifiers with synthetic placeholders while preserving the original
email structure and formatting (e.g., replace addresses with
[email protected] and [email protected], replace order numbers with a
fake pattern like 000-0000000-0000000, redact recipient name to "Test User", and
scrub or anonymize SMTP headers/routing details) so tests still exercise
parsing/rendering but no real customer data remains in the repo.

Comment on lines +1 to +75
Delivered-To: [email protected]
Received: by 2002:a05:7108:5e85:b0:47f:4051:d657 with SMTP id ev5csp1218074gdb;
Fri, 22 Aug 2025 23:59:07 -0700 (PDT)
X-Google-Smtp-Source: AGHT+IFLl4l7A6SKSW7/X6M4sCbyCp6E/LtBnXgQitc3mXhmvPpLD9A15zKAm4Hv1x3ACxHbyy9r
X-Received: by 2002:a05:622a:209:b0:4b2:8ac4:ef6b with SMTP id d75a77b69052e-4b2aab28ce1mr69583081cf.78.1755932346900;
Fri, 22 Aug 2025 23:59:06 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1755932346; cv=none;
d=google.com; s=arc-20240605;
b=d0GamXf3hsBhtc6AO7TIZ5CPJMHh9iMnwtWtm4yJx72YNrw3dhgDUgdOU0EEfHvQRY
nOGpejLM54/1JgQtcrkQU/qPr5EwSWzspHh6R4OTZj5I2g9QVS+A6NVor9VtfdxevkDx
eN7j6A7NSYsqH8Ml1k9ZZ9FmeNf1jNeWaQ2JFkQoZMCsyzlG46IUMJRQ19/SDfR9++QG
kYIa8vqtE779vdBsWI/tV0mh4fJ3349bx9SWK/xsdoEwsR8ScJNFmjlmVHoYCXu5DUba
1LHeoKsO0GszHnJjeiBzcFXn8HLmSptPkHJYxSnN5tpd9jPCeN1vDZyTeWN4xFlRkl9e
bSYQ==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605;
h=content-transfer-encoding:mime-version:subject:message-id:to:from
:date:dkim-signature;
bh=VHgcAWi2xRXZm0DA4ihT7cYtF7t6AYCtpVyB8R4WYMY=;
fh=MrUDigLt8TyE79/Vsak8GkhPoyKFErE0pW3gJJgnYJQ=;
b=ISTi3pvc8IB6i9cnJFpLAlcdiXUS3fzaNcCMG4qCXpCvGh0sl7M9tMbfXFwvJuCzZf
KXIQHW3xkvKpYA7qPrrLYRDj89Poar6Lx9AxRnY3p4LVc6zSYmqsGujsaarceZvckFsa
7VtsM6YzT2jd9tKSJv8DmWoc0616i8yU+XUPBOlpkVD5FElN+p9WYggbrdZLDeboiPqb
25qyk5hyEo5RFCTSADJxHeiSKqUXMIHj0It1Lo5CrlhIfAC/BoQPGHGz6VlWmkfyozBj
c/vuFVqKkwL4x1L5LGOu5ouvql/XOt8Nu4dQmZxT58mwhQyhPMtpYSPt/58N3mrDAoOw
mDaw==;
dara=google.com
ARC-Authentication-Results: i=1; mx.google.com;
dkim=pass [email protected] header.s=pf2023 header.b=Juy8nwl8;
spf=pass (google.com: domain of [email protected] designates 192.30.252.211 as permitted sender) smtp.mailfrom=[email protected];
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=github.com
Return-Path: <[email protected]>
Received: from out-28.smtp.github.com (out-28.smtp.github.com. [192.30.252.211])
by mx.google.com with ESMTPS id d75a77b69052e-4b2b8e43c0dsi7393621cf.846.2025.08.22.23.59.06
for <[email protected]>
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Fri, 22 Aug 2025 23:59:06 -0700 (PDT)
Received-SPF: pass (google.com: domain of [email protected] designates 192.30.252.211 as permitted sender) client-ip=192.30.252.211;
Authentication-Results: mx.google.com;
dkim=pass [email protected] header.s=pf2023 header.b=Juy8nwl8;
spf=pass (google.com: domain of [email protected] designates 192.30.252.211 as permitted sender) smtp.mailfrom=[email protected];
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=github.com
Received: from github.com (hubbernetes-node-531b44e.ash1-iad.github.net [10.56.208.50])
by smtp.github.com (Postfix) with ESMTPA id 9B1239206DD;
Fri, 22 Aug 2025 23:59:06 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=github.com;
s=pf2023; t=1755932346;
bh=VHgcAWi2xRXZm0DA4ihT7cYtF7t6AYCtpVyB8R4WYMY=;
h=Date:From:To:Subject:From;
b=Juy8nwl8FUv8aQ1x1rEOCiikwzic8OqoCCOjBHaWe2hC46AFbFHQzQSFKc2lmi4H0
2gwbBlJQ9FU2DzNyY/l425GX+JeZMlBoJlztrmew8KoypcOHV4BqX5LhLcFAra+s5e
bDTWDfRN31+F9XhRBNpqL3jc8ybSV2rY0TWoIQEs=
Date: Fri, 22 Aug 2025 23:59:06 -0700
From: GitHub <[email protected]>
To: Yogesh Shahi <[email protected]>
Message-ID: <[email protected]>
Subject: [GitHub] A third-party OAuth application has been added to your
account
Mime-Version: 1.0
Content-Type: text/plain;
charset=UTF-8
Content-Transfer-Encoding: 7bit
X-Auto-Response-Suppress: All

Hey BornPsych!

A third-party OAuth application (ETHGlobal) with read:user and user:email scopes was recently authorized to access your account.
Visit https://github.com/settings/connections/applications/7f0a42d8039f524b6a28 for more information.

To see this and other security events for your account, visit https://github.com/settings/security-log

If you run into problems, please contact support by visiting https://github.com/contact

Thanks,
The GitHub Team

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Remove real PII from test fixture.

Line [1] stores an actual Gmail address (and related headers) inside the repo. That’s personal data, which is unnecessary for the test and creates an avoidable compliance/privacy exposure. Please redact or replace every personal identifier in this asset with synthetic placeholders before merging.

🤖 Prompt for AI Agents
In browser_test/public/github.eml around lines 1 to 75, the fixture contains
real personal data (a Gmail address and related headers). Replace all real PII
(email addresses, Message-ID values, Received/Return-Path/IPs that can identify
an individual or infrastructure) with synthetic placeholders (e.g.,
[email protected], [email protected], <[email protected]>, and generic IPs
like 192.0.2.1) and update any corresponding header fields
(DKIM/ARC/Authentication lines) to use matching placeholder values so the
fixture remains valid syntactically but contains no real personal identifiers;
keep the structure and formatting intact for tests.

Comment on lines +1 to +127
Delivered-To: [email protected]
Received: by 2002:a05:6504:1313:b0:279:6670:9162 with SMTP id s19csp1104512lto;
Thu, 5 Sep 2024 14:04:50 -0700 (PDT)
X-Forwarded-Encrypted: i=2; AJvYcCXmuTgC70UQT5Ts4OfBGnVnadr0JW74IPaiOJ5gDpOACNVP8eAJFJP4SA3ch7rvoG+htp/[email protected]
X-Google-Smtp-Source: AGHT+IH76QMWC15Dg/+ThxNbcE5CDLb7cpojHoNsy/oAHrJx5dOAKtaNl1myXNjuD8Du2en5yyVL
X-Received: by 2002:a05:6870:63a9:b0:261:19a6:41ae with SMTP id 586e51a60fabf-27b82fab31bmr675802fac.30.1725570290222;
Thu, 05 Sep 2024 14:04:50 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1725570290; cv=none;
d=google.com; s=arc-20160816;
b=LdXMuzrUNuNI+nDJ2bE4y4i/UNkay6ACfqFs51rtQOgUxDIYAuGZhqPw/monlbxkoN
NGihGo/EItYDoFyz2YenzxBQjpdSic9/g7qp6xz2O00PkGS43a1yOpd+ZVPlGaK5WZx1
LhKdW5Fk7Jx/xJtl5rKnhBgH1SaWkv2pECv5SGasqct9PROtQeg+MMv1kwGqxFBHZ8d9
4ZrRPsKrp04FiG8hbMLUEV5xd1qwsdmDSqHLvmjhX82mN/ohEM4p/laq1OGzqMnM9SuC
5vSNPUEx1wO49BEEqdQGVZ0qu8RQbAg6njk4bKUZoWSbDW1l/WU3Im+WbuCynOi8JMVw
pP6w==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
h=cc:subject:message-id:date:from:mime-version:dkim-signature;
bh=ZPnp2Ot4Oq1yml0gwfVCa+vOkRh/AoPZcUFDo94M5cA=;
fh=rt5+XsSKgJXCbjLkZz2YEwXmYMAytcEAXMTatOTpOfs=;
b=qVd1nk6MrHSij4tsjZ6Lr+Ymptz0OlsUw3AMcXtBlrNhD0U+HLQPSTScNrBaX0i3uX
or7VZjCPegexDy+ovr56hI6M0878rRWyBvW8LRJVn2IsLmImIsePhDPYjU+8YGyHnJ9T
DPz0QtdM6Tzu/WeyWeYsA+B/ab+lIfZ910dtUmOjokCSa2JxGgLaTD/x75L91FpG4KSb
T+FumRRMXfEFx5I6uwMcHQmR1LE22Krkk9D/fs7WyqmNfSBL2eruURXcjOku3zjqK3Hs
mnOqjSUXqEeJLvI+DTPcZ6xqywiq5Pq8I1sCyBi4EVprdq06eDlB7yz+L4ECLB97offc
4byg==;
dara=google.com
ARC-Authentication-Results: i=1; mx.google.com;
dkim=pass [email protected] header.s=google header.b=PbaIBUZo;
spf=pass (google.com: domain of [email protected] designates 209.85.220.41 as permitted sender) smtp.mailfrom=[email protected];
dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=succinct.xyz;
dara=pass [email protected]
Return-Path: <[email protected]>
Received: from mail-sor-f41.google.com (mail-sor-f41.google.com. [209.85.220.41])
by mx.google.com with SMTPS id 586e51a60fabf-277c34333casor4311308fac.9.2024.09.05.14.04.49
for <[email protected]>
(Google Transport Security);
Thu, 05 Sep 2024 14:04:50 -0700 (PDT)
Received-SPF: pass (google.com: domain of [email protected] designates 209.85.220.41 as permitted sender) client-ip=209.85.220.41;
Authentication-Results: mx.google.com;
dkim=pass [email protected] header.s=google header.b=PbaIBUZo;
spf=pass (google.com: domain of [email protected] designates 209.85.220.41 as permitted sender) smtp.mailfrom=[email protected];
dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=succinct.xyz;
dara=pass [email protected]
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=succinct.xyz; s=google; t=1725570289; x=1726175089; dara=google.com;
h=cc:subject:message-id:date:from:mime-version:from:to:cc:subject
:date:message-id:reply-to;
bh=ZPnp2Ot4Oq1yml0gwfVCa+vOkRh/AoPZcUFDo94M5cA=;
b=PbaIBUZod+MtWJh6mm0xQWE6KEJbub66abuVn6S+JQySDWT1c/wbaWs+Fe39s1svy3
GTiD7JdDSgJ0XOQxdeO6vTbyFLI8lFp5UknjFxhIi9TecwN/oBgCVQpjXaQ8hdIh5fA2
rZLURZB6/XnRnc1/I2DTrdegCDztjVty94pNZjKP1iRVCBQTfURoM4/r7ke1ez7P+qKG
uhKrt0XlPsEIbgeViKZpzlcjgfsbwEN0syimGnt+ccfmBx5r5lU9wG7HfW2i+EMOgOiu
+D4cX6uTOfYmBhCtH+HeErPenwgcQ0mTHxzcnAgPipVqTXA9VcQbgaCWB4hQtriMhYNU
B0ZA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1725570289; x=1726175089;
h=cc:subject:message-id:date:from:mime-version:x-gm-message-state
:from:to:cc:subject:date:message-id:reply-to;
bh=ZPnp2Ot4Oq1yml0gwfVCa+vOkRh/AoPZcUFDo94M5cA=;
b=kSvDsE08OCPix+MrHQsGps+9FNVPep2YruDdHlAU9kN7KHlWYFEunPmEqxghhqMMqW
vR2nT+a+FgXLidImEorIK+DEdoIIAEPJwHnuY7C4jsTgqktXSQvYBrNqGgl0e7oEgs3X
X4OQdV/U9zQkXRF1MTBxy+OJMX1e9MQmm2Pv1FyfqWJA2x3wFo1dtmCocvjjJU7mzgl9
2t4ijcPtdZxsW8U9CRvwN3KzFPtdbT6c6uzUVNGhBmBSFi7HfGKbW3V2+uzRZIBAfoR9
4sqmGVYf5ycQAN2e5r2QwUT6oEca47vEB5IDMRadOM3caymamT2+SLR3sq5JrKm/2/j1
C3kQ==
X-Forwarded-Encrypted: i=1; AJvYcCXxd8p4U8kra+dRtLXrArCb0RI+tf/[email protected]
X-Gm-Message-State: AOJu0YxZgyTji/ChYSYLy8R8e+cfUgPmc5ZnDATk5epwZp5EqaRpnZzP
wXv1FS+cySFJJTaopk69+6+98CWXZ2JzXBqWFpLnGwLKkW6aEp7DwMSz2oXlDBdYXt+xWXULZ96
pL4fvwj3nWBaCvEQc1dHauElTv9Bqq4rH8EwEYg==
X-Received: by 2002:a05:6870:af47:b0:278:8b:57b1 with SMTP id
586e51a60fabf-27b82fab4a7mt675702fac.35.1725570289543; Thu, 05 Sep 2024
14:04:49 -0700 (PDT)
MIME-Version: 1.0
From: Leland Lee <[email protected]>
Date: Thu, 5 Sep 2024 14:04:38 -0700
Message-ID: <CAPPv_w=[email protected]>
Subject: Welcome to the Succinct ZK Residency!
Cc: Uma Roy <[email protected]>, Eli Yang <[email protected]>
Content-Type: multipart/alternative; boundary="000000000000263095062165a40c"
Bcc: [email protected]

--000000000000263095062165a40c
Content-Type: text/plain; charset="UTF-8"
Hi All,
We're thrilled to collaborate with you at the Succinct ZK residency in
three weeks. We can't wait to build together on a daily basis and bounce
ideas off each other.
To help us support your journey, please *complete the attached form
<https://docs.google.com/forms/d/e/1FAIpQLSfszQDE3DY5Tg4k3r-v9y3z8wnJy0g_mJKaB_4TRAEx-PnlpQ/viewform>*
with details about your project and a brief bio. Every resident must
complete the form. Your project information and bio will be shared with
other residents as we encourage collaboration and building in the open.
*Logistics*
- Please join residency telegram (https://t.me/+GHNdBiwW89VhOTkx)
We'll be sharing more information soon regarding logistics and schedules
through both email and telegram!
See you soon,
Succinct Team
--000000000000263095062165a40c
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div>Hi All,</div><div><br></div><div>We&#39;re thrilled t=
o collaborate with you at the Succinct ZK residency in three weeks. We can&=
#39;t wait to build together on a daily basis and bounce ideas off each oth=
er.</div><div><br></div><div>To help us support your journey, please <b><a =
href=3D"https://docs.google.com/forms/d/e/1FAIpQLSfszQDE3DY5Tg4k3r-v9y3z8wn=
Jy0g_mJKaB_4TRAEx-PnlpQ/viewform" target=3D"_blank">complete the attached f=
orm</a></b> with details about your project and a brief bio. Every resident=
must complete the form. Your project information and bio will be shared wi=
th other residents as we encourage collaboration and building in the open.<=
br></div><div><p><b>Logistics</b><br></p></div><div><ul><li>Please join res=
idency telegram (<a href=3D"https://t.me/+GHNdBiwW89VhOTkx" target=3D"_blan=
k">https://t.me/+GHNdBiwW89VhOTkx</a>)</li></ul><div>We&#39;ll be sharing m=
ore information soon regarding logistics and schedules through both email a=
nd telegram!</div><div><br></div><div>See you soon,<br></div></div><div>Suc=
cinct=C2=A0Team</div></div>

--000000000000263095062165a40c--
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Privacy concern: Real email addresses and names in version control.

This email fixture contains real personal information including:

Committing real PII to public repositories can expose individuals to spam, phishing, and privacy violations. Consider:

  1. Using anonymized/synthetic email addresses (e.g., [email protected])
  2. Redacting or replacing real names with placeholders
  3. If these individuals have consented to public exposure, document that consent
🤖 Prompt for AI Agents
In browser_test/public/residency.eml lines 1-127 there is real PII (emails
[email protected], [email protected], [email protected], [email protected]
and full names Leland Lee, Uma Roy, Eli Yang, Aditya Bisht) and a live Telegram
invite; replace all real email addresses with synthetic placeholders (e.g.,
[email protected]), replace full names with generic placeholders (e.g.,
Resident One), and remove or redact the Telegram invite link (or replace with a
dummy link like https://example.com/telegram-invite) so no real personal contact
info remains; if the original owners have documented consent to publish, add a
brief consent note in the file header instead of leaving raw PII.

Comment on lines +1 to +405
Delivered-To: [email protected]
Received: by 2002:a05:7208:30c4:b0:a0:251d:5e41 with SMTP id e4csp175734rba;
Thu, 19 Jun 2025 04:11:00 -0700 (PDT)
X-Google-Smtp-Source: AGHT+IEqIGdeTfkTaA0FmCe08u7/OD8Ru1LUIIFHoRSiZxPbItCCdKY7agF6+p8yWEJPI2YH1evl
X-Received: by 2002:a05:6a00:10c8:b0:748:2ff7:5e22 with SMTP id d2e1a72fcca58-7489cff1950mr24545143b3a.10.1750331459999;
Thu, 19 Jun 2025 04:10:59 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1750331459; cv=none;
d=google.com; s=arc-20240605;
b=YGPxlFL/PE8FcA3Mm5VMS/Yqny5nXI+ic/pyxui4FvcTQt5Fgrb55rzAmUy1pXWdj6
3i3bwwAL6Ey4wUmaIVHdopLeYdLF9z/u7qZKE7/ZSJxMTFFV3UBQeyuzY0NzTAoIkCYD
liYFdggZb28ELmc4o/KuHTSVZZjN/+4d/MtFAspW3O8CfbpL7hksdCyHpzP/cD3s5ywq
NQ1uFvp6LJ9RWe1h8w1mjdWJQH3ppXGc6NkJ+e27/0g9FKFU3u0kW+kbV61QAWuoQPw7
g7fhIm6ffL3KqEDK8yIIi3/ap+Ra6RTfhoEG5/cRaDpJjjAlSBofQY2V9Hhpe0sKlfUl
nylg==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605;
h=feedback-id:message-id:mime-version:subject:to:from:date
:dkim-signature;
bh=nQMuQW5OYEIjDAZsqKnZrCfouvj0Gwod2TU3Wsd+et0=;
fh=fDYYgXivSc6zTOFPhUG2MdKnqwapTBkpVsOysAWOq8A=;
b=cWk0anbItsupTlJoWMOBg40BECJeiX0hTlpE2qM1g/FdYfioEX1YLwhftUmdfinJn8
L3WEHf4PI6zKs9fU3oVick6x1YZwLoDV3auVuseco/f0JDhtsJo18sLM60HfnqD/r1d9
DgSjcqEPv6YNqiFgGz89G1ZslNAg9egH4ex3ovvEybVYrMgnYZZzRCrLkzKxpd6mMYtv
XbTTc0OAADSVplnyou8tvw7tk2taM6erPZ0/6S+N3jkC4Uh90lNWNOVo/pTwDI7J4e4r
JCLHoKENpCmugckKdQm4Et9CnQnaFa3QWHD6DZKiyDB4/7jHXguJ9d+L87hrDz3PuW45
XEHQ==;
dara=google.com
ARC-Authentication-Results: i=1; mx.google.com;
dkim=pass [email protected] header.s=dkim-202308 header.b=F8Ci42hm;
spf=pass (google.com: domain of n0258ffc1a1-b6fb81bb1b404dab-thezdev1===[email protected] designates 199.59.150.95 as permitted sender) smtp.mailfrom="n0258ffc1a1-b6fb81bb1b404dab-thezdev1===[email protected]";
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=x.com
Return-Path: <n0258ffc1a1-b6fb81bb1b404dab-thezdev1===[email protected]>
Received: from spruce-goose-az.x.com (spruce-goose-az.x.com. [199.59.150.95])
by mx.google.com with ESMTPS id d2e1a72fcca58-748900de9eesi20528550b3a.117.2025.06.19.04.10.59
for <[email protected]>
(version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
Thu, 19 Jun 2025 04:10:59 -0700 (PDT)
Received-SPF: pass (google.com: domain of n0258ffc1a1-b6fb81bb1b404dab-thezdev1===[email protected] designates 199.59.150.95 as permitted sender) client-ip=199.59.150.95;
Authentication-Results: mx.google.com;
dkim=pass [email protected] header.s=dkim-202308 header.b=F8Ci42hm;
spf=pass (google.com: domain of n0258ffc1a1-b6fb81bb1b404dab-thezdev1===[email protected] designates 199.59.150.95 as permitted sender) smtp.mailfrom="n0258ffc1a1-b6fb81bb1b404dab-thezdev1===[email protected]";
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=x.com
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=x.com;
s=dkim-202308; t=1750331459;
bh=nQMuQW5OYEIjDAZsqKnZrCfouvj0Gwod2TU3Wsd+et0=;
h=Date:From:To:Subject:MIME-Version:Content-Type:Message-ID;
b=F8Ci42hmXmjWJsrA/puFKvSDEZg4bW10y7GxnTZGUTUu1eYCIV/jY9+2wNwUt/3xv
IU3mvOfxz+4doWpPankDNrd5nKqQLcqojk4j9WKp6AUpEb6k2wtbI2ts1571SORS7T
uoIcDqYYnG4xgctA6WAFq4GVPVz/9b66T10h+7hh3m94TGTsyhxbnlmG9Bynh9dzwv
EJSklFxBxvMddm8xl/SPqS1qldaXPPIJciqnL8jutY+FKr3FohdA8aGJW4XghtsK1k
4cCFQypXk7Lt2LzMemKVL3uF3q6ijiH3g0vm0lNH+QDTLIcBDB0CyESKrcZU9KY0Z2
Rr95PUd7VXpIw==
X-MSFBL: grhyOKQTvtsYESUktMBBQURsL6vKGauN1dR6VHDnwDA=|eyJnIjoiQnVsayIsImI
iOiJwZHhhLWF4ZC0yMy1zcjEtQnVsay4yMjEiLCJyIjoidGhlemRldjFAZ21haWw
uY29tIiwidSI6InRoZXpkZXYxQGdtYWlsLmNvbUBpaWQjI2I2ZmI4MWJiMWI0MDR
kYWJiMWY2ZGUzOTEzNWI4MDQ0QHVzYiMjMjRAMjk2QDE5MzU2NTYyMTcwODQ1ODg
wMzJAMEA4ZDcyMDgwYTNhNTFkM2M3MmJmZWY2MjVmYjEzODcyYjQ1NWQ4NTYwIn0
=
Date: Thu, 19 Jun 2025 11:10:59 +0000
From: X <[email protected]>
To: zdev <[email protected]>
Subject: Password reset request
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="----=_Part_2136046_1004234415.1750331459121"
X-Twitter-CID: ibis2-password_reset_pin_based_email
Message-ID: <[email protected]>
Feedback-ID: pdxa.c5bbd1c7e491b5023ff4b22a03711997:X

------=_Part_2136046_1004234415.1750331459121
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit
X
Reset your password?
If you requested a password reset for thezdev1, use the confirmation code below to complete the process. If you didn't make this request, ignore this email.
> 87i8ar3c
Getting a lot of password reset emails?
You can change your account settings to require personal information to reset your password.
account settings
> https://x.com/settings/security
------------------------
Help
> https://support.x.com/articles/14663

Not my account
> https://twitter.com/account/not_my_account/1935656217084588032/8G556-G5A82-175033?ut=1&amp;cn=cGFzc3dvcmRfcmVzZXRfcGluX2Jhc2VkX2VtYWls

Email security tips
> https://help.x.com/safety-and-security/fake-x-emails

X Corp. 1355 Market Street, Suite 900 San Francisco, CA 94103

------=_Part_2136046_1004234415.1750331459121
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www=
.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8" />
<meta name=3D"viewport" content=3D"width=3Ddevice-width, minimum-scale=3D1.=
0, maximum-scale=3D1.0, user-scalable=3D0" />
<meta name=3D"apple-mobile-web-app-capable" content=3D"yes" />
<style type=3D"text/css">
@media only screen and (max-width: 320px) {
table[class=3D"edu-module"]{
border-radius: 0px !important;
-webkit-border-radius: 0px !important;
-moz-border-radius: 0px !important;
}
td[class=3D"edu-collapse"]{
width: 0px !important;
}
td[class=3D"mobile-height"]{
height: 30px !important;
}
}
@media only screen and (max-width: 420px) {
td[class=3D"spacer"]{
font-size:4px !important;
}
span[class=3D"address"] a {
line-height:18px !important;
}
a[class=3D"cut"]{
display:none !important;
}
td[class=3D"margins"]{
width:18px !important;
}
td[class=3D"edu-margins"]{
width:18px !important;
}
td[class=3D"logo_space"]{
height:12px !important;
}
}
@media only screen and (max-width: 480px) {
table[class=3D"collapse"]{
width:100% !important;
}
table[class=3D"edu-module"]{
width:100% !important;
}
div[class=3D"collapse"]{
width:100% !important;
}
td[class=3D"logo_space"]{
height: 24px !important;
}
span[class=3D"address"]{
display:block !important;
width:240px !important;
}
td[class=3D"cut"]{
display:none !important;
}
td[class=3D"logo"] img {
width:24px !important;
}
span[class=3D"address"] a {
line-height:18px !important;
}
}
</style>
</head>
<body bgcolor=3D"#F5F8FA" style=3D"margin:0;padding:0;-webkit-text-size-adj=
ust:100%;-ms-text-size-adjust:100%;">
<table cellpadding=3D"0" cellspacing=3D"0" border=3D"0" width=3D"100%" bgco=
lor=3D"#F5F8FA" style=3D"background-color:#F5F8FA;padding:0;margin:0;line-h=
eight:1px;font-size:1px;" class=3D"body_wrapper">
<tbody>
<tr>
<td align=3D"center" style=3D"padding:0;margin:0;line-height:1px;font-size:=
1px;">
<table class=3D"collapse" id=3D"header" align=3D"center" width=3D"448" styl=
e=3D"width: 448px;padding:0;margin:0;line-height:1px;font-size:1px;" bgcolo=
r=3D"#ffffff" cellpadding=3D"0" cellspacing=3D"0" border=3D"0">
<tbody>
<tr>
<td style=3D"min-width: 448px;padding:0;margin:0;line-height:1px;font-size:=
1px;" class=3D"cut"> <img src=3D"https://ea.twimg.com/email/self_serve/medi=
a/spacer-1402696023930.png" style=3D"min-width: 448px;height:1px;margin:0;p=
adding:0;display:block;-ms-interpolation-mode:bicubic;border:none;outline:n=
one;" /> </td>
</tr>
</tbody>
</table> </td>
</tr>
<tr>
<td align=3D"center" style=3D"padding:0;margin:0;line-height:1px;font-size:=
1px;">
<!--/////////////////// header ///////////////////////////-->
<table class=3D"collapse" id=3D"header" align=3D"center" width=3D"448" styl=
e=3D"width:448px;background-color:#ffffff;padding:0;margin:0;line-height:1p=
x;font-size:1px;" bgcolor=3D"#ffffff" cellpadding=3D"0" cellspacing=3D"0" b=
order=3D"0">
<tbody>
<tr>
<td colspan=3D"4" height=3D"24" style=3D"height:24px;padding:0;margin:0;lin=
e-height:1px;font-size:1px;" class=3D"logo_space"> &nbsp; </td>
</tr>
<tr align=3D"right">
<td width=3D"24" class=3D"margin" style=3D"padding:0;margin:0;line-height:1=
px;font-size:1px;"></td>
<td align=3D"right" style=3D"padding:0;margin:0;line-height:1px;font-size:1=
px;"> <a href=3D"#" target=3D"blank" style=3D"text-decoration:none;border-s=
tyle:none;border:0;padding:0;margin:0;"> <img width=3D"32" align=3D"right" =
src=3D"https://ton.x.com/twitter_blue_for_business/verified-programs/x_logo=
.png" style=3D"width:32px;margin:0;padding:0;display:block;-ms-interpolatio=
n-mode:bicubic;border:none;outline:none;" /> </a> </td>
<td width=3D"24" class=3D"margin" style=3D"padding:0;margin:0;line-height:1=
px;font-size:1px;"></td>
</tr>
<tr>
<td colspan=3D"3" height=3D"24" style=3D"height:24px;padding:0;margin:0;lin=
e-height:1px;font-size:1px;" class=3D"logo_space"> <img width=3D"1" height=
=3D"1" style=3D"display: block;margin:0;padding:0;display:block;-ms-interpo=
lation-mode:bicubic;border:none;outline:none;" src=3D"https://twitter.com/s=
cribe/ibis?t=3D1&amp;cn=3DcGFzc3dvcmRfcmVzZXRfcGluX2Jhc2VkX2VtYWls&amp;iid=
=3Db6fb81bb1b404dabb1f6de39135b8044&amp;uid=3D1935656217084588032&amp;nid=
=3D296+20" /> </td>
</tr>
</tbody>
</table>
<!--/////////////////// end header///////////////////////////-->
<!--/////////////////// body ///////////////////////////-->
<table class=3D"collapse" id=3D"header" align=3D"center" width=3D"448" styl=
e=3D"width:448px;background-color:#ffffff;padding:0;margin:0;line-height:1p=
x;font-size:1px;" bgcolor=3D"#ffffff" cellpadding=3D"0" cellspacing=3D"0" b=
order=3D"0">
<tbody>
<tr align=3D"left;">
<td width=3D"24" class=3D"margin" style=3D"padding:0;margin:0;line-height:1=
px;font-size:1px;"></td>
<td align=3D"left;" style=3D"padding:0;margin:0;line-height:1px;font-size:1=
px;">
<table class=3D"collapse" cellpadding=3D"0" cellspacing=3D"0" border=3D"0" =
style=3D"padding:0;margin:0;line-height:1px;font-size:1px;">
<tbody>
<tr>
<td align=3D"left;" class=3D"h2" style=3D"padding:0;margin:0;line-height:1p=
x;font-size:1px;font-family:'HelveticaNeue', 'Helvetica Neue', Helvetica, A=
rial, sans-serif;font-size:24px;line-height:32px;font-weight:bold;color:#29=
2F33;text-align:left;text-decoration:none;-webkit-font-smoothing:antialiase=
d;"> Reset your password? </td>
</tr>
<tr>
<td height=3D"12" style=3D"padding:0;margin:0;line-height:1px;font-size:1px=
;"></td>
</tr>
<tr>
<td align=3D"left;" class=3D"body-text" style=3D"padding:0;margin:0;line-he=
ight:1px;font-size:1px;font-family:'HelveticaNeue', 'Helvetica Neue', Helve=
tica, Arial, sans-serif;font-size:16px;line-height:20px;font-weight:400;col=
or:#292F33;text-align:left;text-decoration:none;-webkit-font-smoothing:anti=
aliased;"> If you requested a password reset for @thezdev1, use the confirm=
ation code below to complete the process. If you didn't make this request, =
ignore this email. </td>
</tr>
<tr>
<td height=3D"24" style=3D"padding:0;margin:0;line-height:1px;font-size:1px=
;"></td>
</tr>
<!--*********** password reset pin ************-->
<tr>
<td align=3D"left;" class=3D"support" style=3D"padding:0;margin:0;line-heig=
ht:1px;font-size:1px;font-family:'HelveticaNeue', 'Helvetica Neue', Helveti=
ca, Arial, sans-serif;font-size:14px;line-height:16px;font-weight:400;color=
:#292F33;text-align:left;text-decoration:none;-webkit-font-smoothing:antial=
iased;"> <strong>87i8ar3c</strong> </td>
</tr>
<!--*********** end password reset pin ************-->
<tr>
<td height=3D"36" style=3D"height:36px;padding:0;margin:0;line-height:1px;f=
ont-size:1px;"></td>
</tr>
<tr>
<td align=3D"left;" class=3D"body-text" style=3D"padding:0;margin:0;line-he=
ight:1px;font-size:1px;font-family:'HelveticaNeue', 'Helvetica Neue', Helve=
tica, Arial, sans-serif;font-size:16px;line-height:20px;font-weight:400;col=
or:#292F33;text-align:left;text-decoration:none;-webkit-font-smoothing:anti=
aliased;"> <strong>Getting a lot of password reset emails?</strong> </td>
</tr>
<tr>
<td height=3D"12" style=3D"padding:0;margin:0;line-height:1px;font-size:1px=
;"></td>
</tr>
<tr>
<td align=3D"left;" class=3D"body-text" style=3D"padding:0;margin:0;line-he=
ight:1px;font-size:1px;font-family:'HelveticaNeue', 'Helvetica Neue', Helve=
tica, Arial, sans-serif;font-size:16px;line-height:20px;font-weight:400;col=
or:#292F33;text-align:left;text-decoration:none;-webkit-font-smoothing:anti=
aliased;"> You can change your <a href=3D"https://t.co/redirect?url=3Dhttps=
%3A%2F%2Fx.com%2Fsettings%2Fsecurity&amp;t=3D1&amp;cn=3DcGFzc3dvcmRfcmVzZXR=
fcGluX2Jhc2VkX2VtYWls&amp;sig=3D9739a501e5927c51da1d29d016567f9cfb33b210&am=
p;iid=3Db6fb81bb1b404dabb1f6de39135b8044&amp;uid=3D1935656217084588032&amp;=
nid=3D296+3" style=3D"text-decoration:none;border-style:none;border:0;paddi=
ng:0;margin:0;border:none;text-decoration:none;font-weight:400;color:#1DA1F=
2;">account settings</a> to require personal information to reset your pass=
word. </td>
</tr>
<tr>
<td height=3D"36" style=3D"padding:0;margin:0;line-height:1px;font-size:1px=
;"></td>
</tr>
</tbody>
</table> </td>
<td width=3D"24" class=3D"margin" style=3D"padding:0;margin:0;line-height:1=
px;font-size:1px;"></td>
</tr>
</tbody>
</table>
<!--/////////////////// end body///////////////////////////-->
<!--///////////////////// footer /////////////////////-->
<table class=3D"collapse" id=3D"footer" align=3D"center" width=3D"448" styl=
e=3D"width:448px; background-color:#ffffff;padding:0;margin:0;line-height:1=
px;font-size:1px;" cellpadding=3D"0" cellspacing=3D"0" border=3D"0">
<tbody>
<tr>
<td height=3D"36" style=3D"height:36px;padding:0;margin:0;line-height:1px;f=
ont-size:1px;"></td>
</tr>
<tr>
<td align=3D"center" style=3D"padding:0;margin:0;line-height:1px;font-size:=
1px;"> <span class=3D"small-copy" style=3D"font-family:'HelveticaNeue', 'He=
lvetica Neue', Helvetica, Arial, sans-serif;font-size:12px;line-height:16px=
;font-weight:400;color:#8899A6;text-align:left;text-decoration:none;-webkit=
-font-smoothing:antialiased;"> <a href=3D"https://support.x.com/articles/14=
663" class=3D"small-copy" style=3D"text-decoration:none;border-style:none;b=
order:0;padding:0;margin:0;font-family:'HelveticaNeue', 'Helvetica Neue', H=
elvetica, Arial, sans-serif;font-size:12px;line-height:16px;font-weight:400=
;color:#8899A6;text-align:left;text-decoration:none;-webkit-font-smoothing:=
antialiased;font-family:'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial=
, sans-serif;font-size:12px;line-height:16px;font-weight:600;color:#1DA1F2;=
text-align:left;text-decoration:none;-webkit-font-smoothing:antialiased;">H=
elp</a> &nbsp;|&nbsp; <a href=3D"https://twitter.com/account/not_my_account=
/1935656217084588032/8G556-G5A82-175033?ut=3D1&amp;cn=3DcGFzc3dvcmRfcmVzZXR=
fcGluX2Jhc2VkX2VtYWls" class=3D"small-copy" style=3D"text-decoration:none;b=
order-style:none;border:0;padding:0;margin:0;font-family:'HelveticaNeue', '=
Helvetica Neue', Helvetica, Arial, sans-serif;font-size:12px;line-height:16=
px;font-weight:400;color:#8899A6;text-align:left;text-decoration:none;-webk=
it-font-smoothing:antialiased;font-family:'HelveticaNeue', 'Helvetica Neue'=
, Helvetica, Arial, sans-serif;font-size:12px;line-height:16px;font-weight:=
600;color:#1DA1F2;text-align:left;text-decoration:none;-webkit-font-smoothi=
ng:antialiased;">Not my account</a> &nbsp;|&nbsp; <a href=3D"https://t.co/r=
edirect?url=3Dhttps%3A%2F%2Fhelp.x.com%2Fsafety-and-security%2Ffake-x-email=
s&amp;t=3D1&amp;cn=3DcGFzc3dvcmRfcmVzZXRfcGluX2Jhc2VkX2VtYWls&amp;sig=3D746=
eefaca4972288789c7f908c547d5895d41101&amp;iid=3Db6fb81bb1b404dabb1f6de39135=
b8044&amp;uid=3D1935656217084588032&amp;nid=3D296+6" class=3D"small-copy" s=
tyle=3D"text-decoration:none;border-style:none;border:0;padding:0;margin:0;=
font-family:'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, sans-serif=
;font-size:12px;line-height:16px;font-weight:400;color:#8899A6;text-align:l=
eft;text-decoration:none;-webkit-font-smoothing:antialiased;font-family:'He=
lveticaNeue', 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size:12px=
;line-height:16px;font-weight:600;color:#1DA1F2;text-align:left;text-decora=
tion:none;-webkit-font-smoothing:antialiased;">Email security tips</a> </sp=
an> </td>
</tr>
<tr>
<td height=3D"12" style=3D"height:12px;line-height:1px;font-size:1px;paddin=
g:0;margin:0;line-height:1px;font-size:1px;"></td>
</tr>
<tr>
<td align=3D"center" style=3D"padding:0;margin:0;line-height:1px;font-size:=
1px;"> <span class=3D"small-copy" style=3D"font-family:'HelveticaNeue', 'He=
lvetica Neue', Helvetica, Arial, sans-serif;font-size:12px;line-height:16px=
;font-weight:400;color:#8899A6;text-align:left;text-decoration:none;-webkit=
-font-smoothing:antialiased;"> This email was meant for @thezdev1 </span> <=
/td>
</tr>
<tr>
<td height=3D"6" style=3D"height:6px;line-height:1px;font-size:1px;padding:=
0;margin:0;line-height:1px;font-size:1px;"></td>
</tr>
<tr>
<td align=3D"center" style=3D"padding:0;margin:0;line-height:1px;font-size:=
1px;"> <span class=3D"address"> <a href=3D"#" style=3D"text-decoration:none=
;border-style:none;border:0;padding:0;margin:0;font-family:'HelveticaNeue',=
'Helvetica Neue', Helvetica, Arial, sans-serif;-webkit-font-smoothing:anti=
aliased;color:#8899A6;font-size:12px;padding:0px;margin:0px;font-weight:nor=
mal;line-height:12px;cursor:default;">X Corp. 1355 Market Street, Suite 900=
San Francisco, CA 94103</a> </span> </td>
</tr>
<tr>
<td height=3D"72" style=3D"height:72px;padding:0;margin:0;line-height:1px;f=
ont-size:1px;"></td>
</tr>
</tbody>
</table>
<!--///////////////////// end footer /////////////////////--> </td>
</tr>
</tbody>
</table>
</body>
</html>
------=_Part_2136046_1004234415.1750331459121--
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Privacy and security concern: Real email, password reset code, and user identifiers in version control.

This email fixture contains sensitive information:

  • Email address: [email protected]
  • Password reset code: 87i8ar3c (line 79, 279)
  • X/Twitter username: @thezdev1
  • User ID: 1935656217084588032
  • DKIM signatures and authentication headers

Even though the reset code is likely expired, committing password reset emails to public repositories is a security anti-pattern. It exposes:

  1. Valid user accounts that could be targeted
  2. The format and structure of password reset codes
  3. Email routing information that could aid social engineering

Recommendation: Use completely synthetic email addresses (e.g., [email protected]) and dummy reset codes for testing purposes.

Comment on lines +60 to +66
const params: GenerateProofInputsParams = {
maxHeaderLength: blueprint.props.emailHeaderMaxLength || 256,
maxBodyLength: blueprint.props.emailBodyMaxLength || 2560,
ignoreBodyHashCheck: blueprint.props.ignoreBodyHashCheck || false,
removeSoftLineBreaks: blueprint.props.removeSoftLinebreaks || true,
shaPrecomputeSelector: blueprint.props.shaPrecomputeSelector,
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Default removeSoftLineBreaks correctly
|| true forces the flag to true even when the blueprint explicitly sets it to false, which changes the proving behavior and breaks flows that require soft breaks preserved. Use a nullish fallback instead so an intentional false survives.

-          ignoreBodyHashCheck: blueprint.props.ignoreBodyHashCheck || false,
-          removeSoftLineBreaks: blueprint.props.removeSoftLinebreaks || true,
+          ignoreBodyHashCheck: blueprint.props.ignoreBodyHashCheck ?? false,
+          removeSoftLineBreaks: blueprint.props.removeSoftLinebreaks ?? true,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const params: GenerateProofInputsParams = {
maxHeaderLength: blueprint.props.emailHeaderMaxLength || 256,
maxBodyLength: blueprint.props.emailBodyMaxLength || 2560,
ignoreBodyHashCheck: blueprint.props.ignoreBodyHashCheck || false,
removeSoftLineBreaks: blueprint.props.removeSoftLinebreaks || true,
shaPrecomputeSelector: blueprint.props.shaPrecomputeSelector,
};
const params: GenerateProofInputsParams = {
maxHeaderLength: blueprint.props.emailHeaderMaxLength || 256,
maxBodyLength: blueprint.props.emailBodyMaxLength || 2560,
ignoreBodyHashCheck: blueprint.props.ignoreBodyHashCheck ?? false,
removeSoftLineBreaks: blueprint.props.removeSoftLinebreaks ?? true,
shaPrecomputeSelector: blueprint.props.shaPrecomputeSelector,
};
🤖 Prompt for AI Agents
In browser_test/src/circomProver.ts around lines 60 to 66, the object uses
`removeSoftLineBreaks: blueprint.props.removeSoftLinebreaks || true` which
forces the flag to true even when blueprint explicitly sets false; change the
fallback to a nullish coalescing default so an explicit false is preserved
(replace the `|| true` with `?? true`) and verify the property name spelling
matches blueprint.props (removeSoftLineBreaks vs removeSoftLinebreaks) to ensure
the value is read correctly.

Comment on lines 123 to 141
if params.sha_precompute_selector.is_some() {
noir_circuit_input.partial_body_real_length =
Some(parsed_email.canonicalized_body.len());
let partial_hash = u8_to_u32(email_circuit_inputs.precomputed_sha.unwrap().as_slice())?;
noir_circuit_input.partial_body_hash = Some(partial_hash);

// Calculate remaining body length after SHA cutoff
// TODO: This will fail if the selector is not found in the body (i.e selector is without soft line breaks).
let selector = params.sha_precompute_selector.unwrap();
let selector_bytes = selector.as_bytes();
let body_bytes = parsed_email.canonicalized_body.as_bytes();
let selector_index = body_bytes
.windows(selector_bytes.len())
.position(|window| window == selector_bytes)
.ok_or_else(|| anyhow::anyhow!("Selector not found in body"))?;
let sha_cutoff_index = (selector_index / 64) * 64;
let remaining_body_length = body_bytes.len() - sha_cutoff_index;
noir_circuit_input.body.as_mut().unwrap().len = remaining_body_length;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Replace unwrap() calls with proper error handling.

Multiple uses of unwrap() can cause runtime panics:

  • Line 126: precomputed_sha.unwrap() assumes it's always Some
  • Line 137: .ok_or_else(...)?. would be safer but still has unwrap() on line 140
  • Line 140: body.as_mut().unwrap() assumes body is always present

Additionally, the TODO comment on line 130 indicates a known failure case when the selector is not found. These should be addressed with proper error propagation.

Apply this diff to add proper error handling:

-            let partial_hash = u8_to_u32(email_circuit_inputs.precomputed_sha.unwrap().as_slice())?;
+            let partial_hash = u8_to_u32(
+                email_circuit_inputs
+                    .precomputed_sha
+                    .as_ref()
+                    .ok_or_else(|| anyhow::anyhow!("Precomputed SHA is missing"))?
+                    .as_slice()
+            )?;
             noir_circuit_input.partial_body_hash = Some(partial_hash);
 
             // Calculate remaining body length after SHA cutoff
-            // TODO: This will fail if the selector is not found in the body (i.e selector is without soft line breaks).
             let selector = params.sha_precompute_selector.unwrap();
             let selector_bytes = selector.as_bytes();
             let body_bytes = parsed_email.canonicalized_body.as_bytes();
             let selector_index = body_bytes
                 .windows(selector_bytes.len())
                 .position(|window| window == selector_bytes)
                 .ok_or_else(|| anyhow::anyhow!("Selector not found in body"))?;
             let sha_cutoff_index = (selector_index / 64) * 64;
             let remaining_body_length = body_bytes.len() - sha_cutoff_index;
-            noir_circuit_input.body.as_mut().unwrap().len = remaining_body_length;
+            noir_circuit_input.body.as_mut()
+                .ok_or_else(|| anyhow::anyhow!("Body is missing when required"))?
+                .len = remaining_body_length;
🤖 Prompt for AI Agents
In src/circuit/noir/mod.rs around lines 123-141, replace all unwrap() calls with
proper error propagation: obtain the selector with if let Some(selector) =
params.sha_precompute_selector.as_ref() (or
params.sha_precompute_selector.clone().ok_or_else(...)?) instead of unwrapping,
get the precomputed SHA via let precomputed =
email_circuit_inputs.precomputed_sha.ok_or_else(||
anyhow::anyhow!("precomputed_sha missing"))? and pass precomputed.as_slice()
into u8_to_u32(...)? to propagate errors, keep the
.position(...).ok_or_else(...) for missing selector, and replace
noir_circuit_input.body.as_mut().unwrap() with
noir_circuit_input.body.as_mut().ok_or_else(|| anyhow::anyhow!("no body
present"))? before setting len; ensure the function returns a Result and
propagate all errors with ? so no runtime panics occur.

Comment on lines +18 to +39
pub fn compute_barrett_reduction_parameter(input: &BigInt, num_bits: Option<usize>) -> BigInt {
// Determine the bit length if not provided
let bits = match num_bits {
Some(bits) => {
let actual_bits = input.bits() as usize;
if actual_bits > bits {
panic!("Given bits for bignum limbs is too small");
}
bits
}
None => input.bits() as usize,
};

// Compute overflow bits
let overflow_bits = 4;

// multiplicand = 2^(2 * k + overflow_bits)
let multiplicand = BigInt::from(1) << (2 * bits + overflow_bits);

// Compute the Barrett reduction parameter
multiplicand / input
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Replace panic! with proper error return.

Line 24 uses panic!("Given bits for bignum limbs is too small") which prevents callers from handling the error gracefully. This function should return a Result to allow proper error propagation.

Apply this diff:

-pub fn compute_barrett_reduction_parameter(input: &BigInt, num_bits: Option<usize>) -> BigInt {
+pub fn compute_barrett_reduction_parameter(input: &BigInt, num_bits: Option<usize>) -> Result<BigInt> {
     // Determine the bit length if not provided
     let bits = match num_bits {
         Some(bits) => {
             let actual_bits = input.bits() as usize;
             if actual_bits > bits {
-                panic!("Given bits for bignum limbs is too small");
+                return Err(anyhow!("Given bits for bignum limbs ({}) is too small for input ({} bits)", bits, actual_bits));
             }
             bits
         }
         None => input.bits() as usize,
     };
 
     // Compute overflow bits
     let overflow_bits = 4;
 
     // multiplicand = 2^(2 * k + overflow_bits)
     let multiplicand = BigInt::from(1) << (2 * bits + overflow_bits);
 
     // Compute the Barrett reduction parameter
-    multiplicand / input
+    Ok(multiplicand / input)
 }

Note: This change requires updating all callers of this function, including bn_to_redc_limb_str_array on line 162.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/circuit/noir/utils.rs around lines 18 to 39, the function
compute_barrett_reduction_parameter currently panics when the provided num_bits
is too small; change its signature to return Result<BigInt, ErrorType> (choose
an existing crate error type or define a small enum like ComputeBarrettError),
replace the panic! with an Err(...) returning a descriptive error, and return
Ok(multiplicand / input) on success; then update all callers (notably
bn_to_redc_limb_str_array at line 162) to handle the Result (propagate with ? or
map_err) and adjust their signatures to return Result where necessary.

Comment on lines +101 to +134
pub fn bn_to_limb_str_array(input: &BigInt, num_bits: Option<usize>) -> Vec<String> {
// Determine the bit length if not provided
let bits = match num_bits {
Some(bits) => {
let actual_bits = input.bits() as usize;
if actual_bits > bits {
panic!("Given bits for bignum limbs is too small");
}
bits
}
None => input.bits() as usize,
};

// Split into 120-bit limbs
let limbs = split_into_120bit_limbs(input.clone(), bits);

// Convert each limb to a "0x..." hexadecimal string
limbs
.into_iter()
.map(|limb| {
// Get the hex representation without the "0x" prefix
let hex_string = format!("{:x}", limb);

// Ensure even length for the hex string
let padded_hex = if hex_string.len() % 2 != 0 {
format!("0{}", hex_string)
} else {
hex_string
};

format!("0x{}", padded_hex)
})
.collect()
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Replace panic! with proper error return for consistency.

Line 107 uses panic! similar to the previous function. For consistency and proper error handling, this should also return a Result.

Apply this diff:

-pub fn bn_to_limb_str_array(input: &BigInt, num_bits: Option<usize>) -> Vec<String> {
+pub fn bn_to_limb_str_array(input: &BigInt, num_bits: Option<usize>) -> Result<Vec<String>> {
     // Determine the bit length if not provided
     let bits = match num_bits {
         Some(bits) => {
             let actual_bits = input.bits() as usize;
             if actual_bits > bits {
-                panic!("Given bits for bignum limbs is too small");
+                return Err(anyhow!("Given bits for bignum limbs ({}) is too small for input ({} bits)", bits, actual_bits));
             }
             bits
         }
         None => input.bits() as usize,
     };
 
     // Split into 120-bit limbs
     let limbs = split_into_120bit_limbs(input.clone(), bits);
 
     // Convert each limb to a "0x..." hexadecimal string
-    limbs
+    Ok(limbs
         .into_iter()
         .map(|limb| {
             // Get the hex representation without the "0x" prefix
             let hex_string = format!("{:x}", limb);
 
             // Ensure even length for the hex string
             let padded_hex = if hex_string.len() % 2 != 0 {
                 format!("0{}", hex_string)
             } else {
                 hex_string
             };
 
             format!("0x{}", padded_hex)
         })
-        .collect()
+        .collect())
 }

Note: This requires updating callers in src/circuit/noir/mod.rs (lines 68, 85) and other locations.

🤖 Prompt for AI Agents
In src/circuit/noir/utils.rs around lines 101 to 134, the function
bn_to_limb_str_array currently panics when the provided num_bits is too small;
change it to return Result<Vec<String>, E> instead of panicking so callers can
handle the error. Update the function signature to return a Result (use the
crate's standard error type or a simple String/anyhow::Error), replace the
panic! branch with an Err(...) carrying a descriptive message, keep the normal
return as Ok(limbs_vec), and propagate error handling at each call site (e.g.,
in src/circuit/noir/mod.rs lines 68 and 85 and other locations) by handling the
Result or using the ? operator as appropriate. Ensure imports and function
declarations are updated to reflect the new return type.

Comment on lines +29 to +41
if selector_start_index < position_map.len() && selector_end_index < position_map.len() {
let original_start_index = position_map[selector_start_index];
let original_end_index = position_map[selector_end_index];
if original_start_index == usize::MAX || original_end_index == usize::MAX {
return Err(anyhow!("Failed to map selector position to original body"));
}
Ok((
selector.to_string(),
original_start_index,
original_end_index,
))
} else {
Err(anyhow!("Selector index out of range in position map"))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Correct selector end mapping for matches at the buffer boundary.

When the regex match runs through the last byte of clean_content, selector_end_index equals position_map.len(). The current bounds check rejects that valid case (Line [29]), so any selector located at the end of the email body will throw “Selector index out of range” even though the match is legitimate. We also end up indexing position_map[selector_end_index], which is out of bounds in the same scenario. Please treat the exclusive end index separately: allow selector_end_index == position_map.len(), look up the last mapped byte, and add 1 to derive the exclusive original end.

-        if selector_start_index < position_map.len() && selector_end_index < position_map.len() {
-            let original_start_index = position_map[selector_start_index];
-            let original_end_index = position_map[selector_end_index];
-            if original_start_index == usize::MAX || original_end_index == usize::MAX {
-                return Err(anyhow!("Failed to map selector position to original body"));
-            }
-            Ok((
-                selector.to_string(),
-                original_start_index,
-                original_end_index,
-            ))
-        } else {
-            Err(anyhow!("Selector index out of range in position map"))
-        }
+        if selector_start_index >= position_map.len() || position_map.is_empty() {
+            return Err(anyhow!("Selector index out of range in position map"));
+        }
+
+        let original_start_index = position_map[selector_start_index];
+        if original_start_index == usize::MAX {
+            return Err(anyhow!("Failed to map selector position to original body"));
+        }
+
+        if selector_end_index == selector_start_index {
+            return Err(anyhow!("Matched selector has zero length"));
+        }
+
+        let original_end_index = if selector_end_index == position_map.len() {
+            let last_mapped = position_map[selector_end_index - 1];
+            if last_mapped == usize::MAX {
+                return Err(anyhow!("Failed to map selector position to original body"));
+            }
+            last_mapped + 1
+        } else if selector_end_index < position_map.len() {
+            let mapped = position_map[selector_end_index];
+            if mapped == usize::MAX {
+                return Err(anyhow!("Failed to map selector position to original body"));
+            }
+            mapped
+        } else {
+            return Err(anyhow!("Selector index out of range in position map"));
+        };
+
+        Ok((selector.to_string(), original_start_index, original_end_index))
🤖 Prompt for AI Agents
In src/circuit/utils.rs around lines 29 to 41, the code currently rejects a
match whose exclusive end index equals position_map.len(); update the bounds and
mapping logic so selector_start_index must be < position_map.len() but
selector_end_index may be == position_map.len(); compute original_start_index by
indexing position_map[selector_start_index] as before, and compute
original_end_index as follows: if selector_end_index == position_map.len() then
take position_map[position_map.len() - 1] and add 1 to produce the exclusive
original end, otherwise index position_map[selector_end_index]; preserve the
existing usize::MAX checks for mapped values and return the same errors when
mapping fails.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bcf50a2 and f45e528.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • Cargo.toml (3 hunks)
  • package.json (1 hunks)
🔇 Additional comments (5)
package.json (2)

13-13: Clarify the pre-release version format.

The version suffix -9 is unconventional. Pre-release versions typically follow semantic versioning conventions like 0.4.66-rc.1, 0.4.66-beta.9, or 0.4.66-alpha.1.

Is 0.4.66-9 intentional, or should this be 0.4.66-rc.1 or similar?


4-12: Verify alignment between scripts and PR scope.

The PR introduces a Vite-based browser test app, but the scripts section shows no new build or dev targets for it. Similarly, the AI summary mentions "Vite-based browser test harness," yet no Vite-related devDependencies are visible in the provided snippet.

Verify that:

  • Required devDependencies (Vite, build tools for the browser app) are declared elsewhere (e.g., workspace dependencies, root package.json in a monorepo).
  • Build/dev scripts for the browser app are intentionally omitted or defined in a separate workspace package.
Cargo.toml (3)

3-3: Version bump rationale.

The version has been bumped from 0.4.62-12 to 0.4.62-17 (a 5-patch increment in prerelease). Ensure this aligns with the scope of changes (new regex module, browser test app, circuit refactoring) and follows your project's versioning strategy.


20-20: I need to dig deeper to understand the relationship between these two dependencies.

Let me check if the external regex crate is actually imported anywhere in the codebase:

Based on my verification, I have sufficient information to generate a rewritten comment. The key findings are:

  1. fancy_regex is confirmed to be used: The script found use fancy_regex::Regex; in src/regex/extract.rs
  2. regex crate dependency: fancy-regex internally delegates to an inner NFA implementation using the regex crate, which means fancy-regex depends on regex as a transitive dependency
  3. No direct imports of external regex crate found: The search results showed only references to crate::regex:: (a local module), not use regex:: (external crate)

The review comment's concern about dual dependencies is actually valid and warrants clarification - the regex crate is not directly used in the codebase but is an indirect dependency of fancy-regex.

Dual regex dependencies are justified—regex is a transitive dependency of fancy-regex.

fancy-regex uses a hybrid approach where a backtracking virtual machine delegates to the regex crate for simple pattern matching. The regex dependency is not directly used in the codebase; rather, it's pulled in as a transitive dependency through fancy_regex. This is intentional and necessary for fancy-regex's functionality. The dual dependency can be left as-is or clarified in a comment.


53-53: No API compatibility issues found with sp1-verifier 5.0.0.

The code uses Groth16Verifier::verify() with the signature matching the v5.0.0 API, and the GROTH16_VK_BYTES constant is available. The single usage in src/wasm.rs is fully compatible. The default-features = false configuration is intentional and correct for WASM builds.

Cargo.toml Outdated
serde = { version = "1.0.159", features = ["derive"] }
zk-regex-apis = { git = "https://github.com/zkemail/zk-regex.git" }
zk-regex-compiler = { git = "https://github.com/zkemail/zk-regex.git" }
zk-regex-compiler = { git = "https://github.com/zkemail/zk-regex.git", rev = "35014c2bff69115bb92be2dc2c9b006fa69a6649" }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify zk-regex-compiler revision is valid and compatible.

The dependency is pinned to a specific commit hash. Ensure this revision exists, is reachable, and doesn't introduce security or stability issues.


🏁 Script executed:

#!/bin/bash
# Verify the zk-regex-compiler rev is valid and the git repository is accessible
git ls-remote https://github.com/zkemail/zk-regex.git 35014c2bff69115bb92be2dc2c9b006fa69a6649

Length of output: 0



---

🏁 Script executed:

```shell
#!/bin/bash
# Alternative verification: fetch repository info and check for commit
# Try with --heads and --tags to see all refs
git ls-remote --heads --tags https://github.com/zkemail/zk-regex.git | head -50

Length of output: 3471


🌐 Web query:

zkemail zk-regex commit 35014c2bff69115bb92be2dc2c9b006fa69a6649

💡 Result:

I couldn't find that exact commit hash in public zk-email/zk-regex sources. I can search GitHub (or the specific repo) for that commit and return the commit message / diff — do you want me to do that? (If yes, tell me which repo or allow me to search the zkemail org.) [1][2]

Sources:
[1] zkemail GitHub org.
[2] zk-regex documentation.


🏁 Script executed:

#!/bin/bash
# Direct attempt to fetch the specific commit
git fetch --depth=1 https://github.com/zkemail/zk-regex.git 35014c2bff69115bb92be2dc2c9b006fa69a6649 2>&1 || echo "Fetch failed or commit not found"

Length of output: 101


Fix zk-regex-compiler revision: commit does not exist in repository.

The pinned commit 35014c2bff69115bb92be2dc2c9b006fa69a6649 is not found in the zkemail/zk-regex repository. Cargo will fail to resolve this dependency during build. Use a valid commit hash or tag (e.g., tag 2.1.0 which is publicly available).

🤖 Prompt for AI Agents
In Cargo.toml around line 16, the dependency zk-regex-compiler pins a
non-existent commit hash; replace the rev value with a valid reference (either a
real commit hash from the zkemail/zk-regex repo or a published tag such as
"2.1.0") by updating the dependency to use rev = "<valid-hash>" or tag = "2.1.0"
(or use git = ... and branch = "<branch>" if preferred), then run cargo update
or cargo fetch and verify cargo build succeeds.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/parse_email.rs (1)

261-293: Align fallback logic between get_command() and get_command_idxes().

There's an inconsistency between these two methods:

  • get_command() (lines 261-282) has a fallback strategy: it first tries canonicalized_body (line 266), and if that fails, falls back to cleaned_body (line 272).
  • get_command_idxes() (lines 285-293) only searches in cleaned_body (line 290), with no fallback.

This inconsistency can lead to bugs:

  1. If the command exists in canonicalized_body but not cleaned_body, get_command() succeeds while get_command_idxes() fails.
  2. If the command exists in both bodies at different positions, the indices returned by get_command_idxes() won't match the substring returned by get_command().

Consider one of these solutions:

Option 1: Make get_command_idxes() match the fallback logic:

 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 ignore_body_hash_check {
         Ok((0, 0))
     } else {
-        let idxes = extract_substr_idxes(&self.cleaned_body, &regex_config, None, false)?[0];
-        Ok(idxes)
+        match extract_substr_idxes(&self.canonicalized_body, &regex_config, None, false) {
+            Ok(idxes) => Ok(idxes[0]),
+            Err(_) => {
+                let idxes = extract_substr_idxes(&self.cleaned_body, &regex_config, None, false)?[0];
+                Ok(idxes)
+            }
+        }
     }
 }

Option 2: Simplify both methods to only use cleaned_body (if canonicalized_body fallback is unnecessary).

♻️ Duplicate comments (4)
browser_test/src/noirProver.ts (1)

270-282: Critical: Hex decoding corrupts bytes with leading zeros.

The replace(/^0+/, "") on line 272 strips all leading zeros, corrupting bytes like 0x0a (newline) into "a" or 0x00 into "", producing odd-length hex strings that cannot decode properly. Control characters and null bytes in public outputs will be silently mangled.

Apply this diff to fix the decoding:

 function toUtf8(hex: string): string {
-  // Remove '0x' prefix and leading zeros
-  const cleanHex = hex.slice(2).replace(/^0+/, "");
+  // Remove '0x' prefix
+  let cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
+  
+  // Ensure even length by prepending '0' if needed
+  if (cleanHex.length % 2 !== 0) {
+    cleanHex = "0" + cleanHex;
+  }
 
   // Convert the hex to a Uint8Array
   const bytes = new Uint8Array(cleanHex.length / 2);
   for (let i = 0; i < cleanHex.length; i += 2) {
     bytes[i / 2] = parseInt(cleanHex.substring(i, i + 2), 16);
   }
 
   // Use TextDecoder to convert to UTF-8
   return new TextDecoder().decode(bytes);
 }
src/circuit/noir/mod.rs (3)

26-33: Security: Reconsider defaulting body hash check to skip.

Defaulting ignore_body_hash_check to true bypasses a critical email authentication mechanism, potentially allowing body tampering to go undetected. Consider defaulting to false to enforce verification by default.

Apply this diff:

-        ParsedEmail::new_from_raw_email(email, params.ignore_body_hash_check.unwrap_or(true))
+        ParsedEmail::new_from_raw_email(email, params.ignore_body_hash_check.unwrap_or(false))

158-164: Replace unwrap with error propagation.

Line 162 uses unwrap() on precomputed_sha, which will panic if it's None. Since the function returns Result, propagate the error properly.

Apply this diff:

         // Always generate partial_body_hash when body verification is enabled
         if params.ignore_body_hash_check.is_some_and(|x| !x) {
             noir_circuit_input.partial_body_real_length =
                 Some(parsed_email.canonicalized_body.len());
-            let partial_hash = u8_to_u32(email_circuit_inputs.precomputed_sha.unwrap().as_slice())?;
+            let partial_hash = u8_to_u32(
+                email_circuit_inputs
+                    .precomputed_sha
+                    .as_ref()
+                    .ok_or_else(|| anyhow::anyhow!("Precomputed SHA is missing"))?
+                    .as_slice()
+            )?;
             noir_circuit_input.partial_body_hash = Some(partial_hash);
         }

290-295: Add null checks before unwrapping body references.

Lines 292 and 294 use unwrap() without verification. If remove_soft_line_breaks is enabled but decoded_body is None, or if body processing was skipped, these will panic.

Apply this diff:

             HaystackLocation::Body => {
                 let body = if params.remove_soft_line_breaks {
-                    noir_circuit_input.decoded_body.as_ref().unwrap()
+                    noir_circuit_input.decoded_body.as_ref()
+                        .ok_or_else(|| anyhow::anyhow!("Decoded body is missing when remove_soft_line_breaks is enabled"))?
                 } else {
-                    noir_circuit_input.body.as_ref().unwrap()
+                    noir_circuit_input.body.as_ref()
+                        .ok_or_else(|| anyhow::anyhow!("Body is missing when required for regex matching"))?
                 };
🧹 Nitpick comments (2)
browser_test/src/noirProver.ts (1)

73-80: Consider using nullish coalescing for legacy field fallback.

While the current || operator works for truthy values, using nullish coalescing (??) would be more precise for handling null/undefined specifically, avoiding issues with falsy-but-valid values like empty strings.

Apply this diff:

           parts: dr.parts.map((p) => ({
             // @ts-ignore
             is_public: p.isPublic || !!p.is_public,
             // @ts-ignore
-            regex_def: p.regexDef || p.regex_def,
+            regex_def: p.regexDef ?? p.regex_def,
             // @ts-ignore
-            ...((p.isPublic || p.is_public) && { maxLength: p.maxLength || p.max_length || 64 }),
+            ...((p.isPublic ?? p.is_public) && { maxLength: p.maxLength ?? p.max_length ?? 64 }),
           })),
src/circuit/noir/mod.rs (1)

174-180: Address the TODO: handle missing selector gracefully.

The TODO comment indicates this will fail if the selector is not found in the body (e.g., when selector doesn't account for soft line breaks). Consider adding explicit error handling or validation to provide a clearer error message.

Would you like me to help implement proper error handling for the missing selector case?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 882ea5f and 02409b7.

⛔ Files ignored due to path filters (2)
  • browser_test/bun.lock is excluded by !**/*.lock
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (8)
  • browser_test/package.json (1 hunks)
  • browser_test/src/noirProver.ts (1 hunks)
  • package.json (1 hunks)
  • src/circuit/mod.rs (1 hunks)
  • src/circuit/noir/mod.rs (1 hunks)
  • src/circuit/noir/structs.rs (1 hunks)
  • src/cryptos.rs (10 hunks)
  • src/parse_email.rs (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • package.json
  • browser_test/package.json
🧰 Additional context used
🧬 Code graph analysis (6)
browser_test/src/noirProver.ts (1)
src/wasm.rs (2)
  • parseEmail (51-77)
  • generateNoirCircuitInputsWithRegexesAndExternalInputs (605-652)
src/circuit/noir/mod.rs (5)
src/parse_email.rs (2)
  • remove_quoted_printable_soft_breaks (323-345)
  • new_from_raw_email (49-75)
src/converters.rs (2)
  • string_to_circom_bigint_bytes (463-483)
  • vec_u8_to_bigint (265-269)
src/circuit/circom.rs (2)
  • compute_signal_length (577-579)
  • clone (122-139)
src/circuit/mod.rs (2)
  • generate_circuit_inputs (134-192)
  • new (98-113)
src/circuit/noir/utils.rs (6)
  • bn_to_limb_str_array (101-134)
  • bn_to_redc_limb_str_array (161-164)
  • get_header_sequence (195-228)
  • u8_to_u32 (304-317)
  • get_address_header_sequence (248-290)
  • trim_sha256_padding (319-350)
src/circuit/mod.rs (4)
src/cryptos.rs (5)
  • generate_partial_sha (494-557)
  • sha256_pad (426-462)
  • new (59-61)
  • new (260-262)
  • new (335-343)
src/parse_email.rs (1)
  • remove_quoted_printable_soft_breaks (323-345)
src/converters.rs (1)
  • to_circom_bigint_bytes (254-256)
src/circuit/utils.rs (1)
  • get_adjusted_selector (66-87)
src/cryptos.rs (3)
src/regex/padding.rs (1)
  • pad_string (18-22)
src/circuit/mod.rs (1)
  • new (98-113)
src/converters.rs (2)
  • hex_to_field (20-67)
  • field_to_hex (76-79)
src/parse_email.rs (2)
src/regex/patterns.rs (8)
  • extract_body_hash_idxes (106-108)
  • extract_email_addr_idxes (81-83)
  • extract_email_domain_idxes (86-88)
  • extract_from_addr_idxes (91-93)
  • extract_message_id_idxes (116-118)
  • extract_subject_all_idxes (101-103)
  • extract_timestamp_idxes (111-113)
  • extract_to_addr_idxes (96-98)
src/regex/extract.rs (1)
  • extract_substr_idxes (188-201)
src/circuit/noir/structs.rs (2)
src/cryptos.rs (1)
  • deserialize (183-226)
src/circuit/circom.rs (1)
  • deserialize (155-161)
🔇 Additional comments (25)
src/parse_email.rs (3)

6-10: LGTM!

The refactoring from external zk_regex_apis to the local crate::regex module is clean and aligns with the PR's goal of introducing a new internal regex runtime.


209-210: LGTM!

The API call updates correctly pass None for the new nfa_graph parameter, which aligns with the updated extract_substr_idxes signature.

Also applies to: 214-214, 227-228, 231-231


340-342: LGTM!

The refactoring to use resize() for padding is cleaner and more idiomatic than manual loop-based padding. Using usize::MAX as a sentinel value for padded positions is well-documented in the function comments and aligns with the new padding strategy.

src/cryptos.rs (8)

3-3: LGTM! Good refactoring to use centralized padding utility.

The import of pad_string from the new regex module improves code reusability and aligns with the PR's objective to consolidate padding logic.


111-127: Excellent security improvement! Validation prevents truncation collisions.

The change to return Result<Self> with explicit length validation is a critical security enhancement. By rejecting email addresses exceeding 256 bytes upfront, this prevents scenarios where different email addresses could produce identical padded representations due to silent truncation.

The error handling is clear and the documentation properly explains the security rationale.


505-505: Good improvement! Error propagation instead of panicking.

Replacing .unwrap() with ? operator for both Regex::new() and String::from_utf8() provides better error handling by propagating errors to the caller rather than panicking at runtime.

Also applies to: 515-515


800-816: LGTM! Proper error propagation throughout the function.

The function signature change to return Result<String> is consistent with the updated PaddedEmailAddr::from_email_addr signature. All error propagation using ? operator is correct, and the function now properly handles errors from:

  • Email address validation
  • Hex-to-field conversions
  • Account salt generation

Note: This is a breaking change to the public API.


833-833: Minor style improvement.

Using .or_else() for Option chaining is slightly more idiomatic than .unwrap_or_else() in this context, though both work correctly here.


601-697: Excellent test coverage for the new validation logic!

The test suite comprehensively covers:

  • Valid email address padding and verification
  • Boundary condition (exactly 256 bytes - should pass)
  • Over-limit rejection (257 bytes - should fail)
  • Collision prevention security scenarios
  • Long but valid emails under the limit
  • Integration with calculate_account_salt for both success and error paths

The tests are well-structured with clear assertions and descriptive error messages.


38-38: DKIM API endpoint is operational and returns valid data.

The new endpoint https://archive.zk.email/api/key/domain successfully returns DKIM key records in the expected JSON format with proper structure (domain, selector, firstSeenAt, lastSeenAt, value fields). The change is verified as live and compatible.


532-532: Verify circuit-level SHA padding handling with circuit implementation team.

The comment update at line 549 asserts that "the circuit handles SHA padding", allowing the remaining body to be padded to max_remaining_body_length with zeros rather than requiring it to be a multiple of 64 bytes. However, the verification script did not locate the circuit's actual SHA padding implementation (e.g., partial_sha256_var_end) or corresponding tests that validate this behavior with variable-length inputs.

Action required: Confirm with the circuit development team that the circuit implementation correctly handles variable-length remaining body inputs (i.e., not strictly multiples of 64) before this change is merged. The codebase reference alone is insufficient to verify this assumption.

src/circuit/mod.rs (3)

1-17: LGTM! Clean module organization.

The module structure and imports are well-organized, with appropriate re-exports for public APIs.


19-75: LGTM! Well-designed data structures.

The separation between public API structs (CircuitParams, CircuitOptions) and internal implementation structs (CircuitInput) provides good encapsulation. Serde annotations are correctly applied for JSON serialization.


77-114: LGTM! Secure defaults applied.

The constructor correctly applies sensible defaults, including defaulting ignore_body_hash_check to false to enforce body hash verification by default.

browser_test/src/noirProver.ts (4)

1-15: LGTM! Clean SDK initialization.

The imports and SDK configuration are well-structured, with helpful commented alternatives for different environments.


85-147: LGTM! Robust circuit execution flow.

The Noir circuit execution is well-structured with appropriate error handling and data transformations (Map to object conversion for circuit inputs).


167-178: LGTM! Clean email fetching with error handling.

The function properly handles fetch errors and returns the email content as text.


180-198: LGTM! Proper validation of required external inputs.

The function correctly ensures all required external inputs are provided and augments them with maxLength constraints.

src/circuit/noir/structs.rs (3)

4-11: LGTM! Clean custom deserializer.

The empty string to None deserializer is correctly implemented using filter, providing clean handling of empty optional strings.


13-62: LGTM! Well-designed data structures.

The struct definitions are clean and appropriate for Noir circuit inputs, with good use of Option for conditional fields and the custom deserializer for sha_precompute_selector to handle empty strings elegantly.


64-77: LGTM! Complete type definitions.

The HaystackLocation enum and RegexInput struct provide clear, type-safe interfaces for regex processing in Noir circuits.

src/circuit/noir/mod.rs (4)

1-24: LGTM! Clean module organization.

Module structure, imports, and the MODULUS_BITS constant are well-organized.


35-105: LGTM! Clean circuit input construction.

The conversion of parsed email data into circuit parameters and the initialization of NoirCircuitInputs are well-structured.


223-277: LGTM! Clean integration of external inputs.

The function properly constructs circuit parameters and processes external inputs with appropriate padding and serialization.


306-443: LGTM! Robust regex processing and test coverage.

The regex input processing correctly handles capture groups with proper error checks, and the test module provides good coverage of the circuit input generation flow.

Comment on lines +172 to +183
let result = generate_partial_sha(
body_for_sha,
body_original_len,
adjusted_selector,
params.max_body_length,
);

// Use match to handle the result and convert any error into an anyhow::Error
let (precomputed_sha, body_remaining_padded, body_remaining_length) = match result {
Ok((sha, remaining, len)) => (sha, remaining, len),
Err(e) => panic!("Failed to generate partial SHA: {:?}", e),
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Replace panic with error propagation.

The function panics on generate_partial_sha failure, but it already returns Result<CircuitInput>. Convert the error and propagate it using ? instead of panicking.

Apply this diff:

-        // Use match to handle the result and convert any error into an anyhow::Error
-        let (precomputed_sha, body_remaining_padded, body_remaining_length) = match result {
-            Ok((sha, remaining, len)) => (sha, remaining, len),
-            Err(e) => panic!("Failed to generate partial SHA: {:?}", e),
-        };
+        // Convert the error into an anyhow::Error and propagate it
+        let (precomputed_sha, body_remaining_padded, body_remaining_length) = result
+            .map_err(|e| anyhow::anyhow!("Failed to generate partial SHA: {:?}", e))?;
🤖 Prompt for AI Agents
In src/circuit/mod.rs around lines 172 to 183, the code currently panics on a
failed generate_partial_sha call; replace the match/panic with direct error
propagation. Call generate_partial_sha(...) and use the ? operator to propagate
the error (if needed, map the error into anyhow::Error with .map_err(|e|
anyhow::anyhow!(...)) before applying ?), then destructure the returned tuple
into (precomputed_sha, body_remaining_padded, body_remaining_length).

Support both legacy and new circuit input formats by:
- Adding optional fields (max_match_length, max_haystack_length, regex_graph_json) with aliases for old field names
- Implementing legacy path that generates {name}RegexIdx format for old circuits
- Using NFAGraph-based generation only when regex_graph_json is present
- Adding helper methods to detect circuit version and calculate defaults
- Fixing typo: removeSoftLinesBreaks -> removeSoftLineBreaks in tests

This ensures circuits compiled before the new compiler integration continue to work while supporting the new format.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
src/circuit/circom.rs (2)

630-637: Use u64 (not i64) for capture_group_start_indices JSON numbers

Here capture_group_start_indices elements are cast to i64 while related fields (capture_group_ids, capture_group_starts) use u64, and indices are inherently non‑negative. This inconsistency is unnecessary and can be surprising when comparing Circom vs Noir outputs.

Align this with the other fields by casting to u64:

-                                    .map(|s| serde_json::Value::Number((*s as i64).into()))
+                                    .map(|s| serde_json::Value::Number((*s as u64).into()))

283-324: Silent fallback to index 0 can hide parsing failures for code/timestamp/command

code_idx, timestamp_idx, and command_idx all map Err(_) to 0, and the body-search fallback also forces 0 when padded_cleaned_body is None. This silently suppresses errors and makes it impossible to distinguish “not found / failed to parse” from “found at position 0”, which can mis-wire circuit behavior.

Consider instead:

  • Propagating the errors (?) if these indices are required, or
  • Using Option<usize> in EmailCircuitInput and encoding the optionality explicitly at the circuit boundary, or
  • If 0 is truly a safe sentinel, document that invariant clearly and ensure the circuits never treat index 0 as a valid match location.
🧹 Nitpick comments (4)
src/lib.rs (1)

9-10: Consider whether regex needs to be a public module

You’re already re-exporting the curated regex surface at the crate root; if external consumers don’t need to reach into regex::* internals, you could make this mod regex; instead and keep the internal layout private. If consumers do rely on submodules, the current pub is fine.

src/circuit/circom.rs (3)

41-49: EmailCircuitParams.remove_soft_line_breaks is currently unused

The remove_soft_line_breaks flag is exposed on EmailCircuitParams but never read anywhere in this module, so toggling it has no effect. Either wire it into the email input generation (e.g., how the body is cleaned/padded) or drop the field to avoid a misleading public API.


569-581: Dead DecomposedRegexConfig construction in NFAGraph path

In the NFAGraph branch you build and populate decomposed_regex_config, but never actually use it; only gen_circuit_inputs with NFAGraph is called afterward. This is dead code that adds confusion and may trigger unused-variable warnings.

You can safely remove decomposed_regex_config (and the VecDeque dependency if unused elsewhere), or, if it’s intended for a future shared Circom/Noir path, add a brief comment to mark it as intentionally unused for now.


703-706: compute_signal_length is correct but lacks tests and can be simplified

The formula for compute_signal_length matches the intended “ceil(max_length / 31)”, but there’s a TODO and no tests here. Edge cases like max_length = 0 or exact multiples of 31 are easy to regress.

Consider both (a) adding a small unit test table (e.g., 0, 1, 30, 31, 32) and (b) simplifying the implementation to ((max_length + 30) / 31) for readability. I can sketch the tests if helpful.

Also applies to: 708-708

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 02409b7 and c902807.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • Cargo.toml (3 hunks)
  • package.json (1 hunks)
  • src/circuit/circom.rs (1 hunks)
  • src/lib.rs (2 hunks)
  • ts_tests/circuit_input.test.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json
🧰 Additional context used
🧬 Code graph analysis (2)
src/lib.rs (3)
src/regex/patterns.rs (8)
  • extract_body_hash_idxes (106-108)
  • extract_email_addr_idxes (81-83)
  • extract_email_domain_idxes (86-88)
  • extract_from_addr_idxes (91-93)
  • extract_message_id_idxes (116-118)
  • extract_subject_all_idxes (101-103)
  • extract_timestamp_idxes (111-113)
  • extract_to_addr_idxes (96-98)
src/regex/extract.rs (2)
  • extract_substr (374-386)
  • extract_substr_idxes (188-201)
src/regex/padding.rs (2)
  • pad_bytes (32-36)
  • pad_string (18-22)
src/circuit/circom.rs (6)
src/converters.rs (4)
  • field_to_hex (76-79)
  • hex_to_u256 (302-308)
  • string_to_circom_bigint_bytes (463-483)
  • vec_u8_to_bigint (265-269)
src/parse_email.rs (3)
  • find_index_in_body (360-372)
  • remove_quoted_printable_soft_breaks (323-345)
  • new_from_raw_email (49-75)
src/circuit/noir/utils.rs (1)
  • trim_sha256_padding (319-350)
src/circuit/mod.rs (2)
  • generate_circuit_inputs (134-192)
  • new (98-113)
src/cryptos.rs (5)
  • from (273-275)
  • new (59-61)
  • new (260-262)
  • new (335-343)
  • from_email_addr (111-128)
src/regex/extract.rs (1)
  • extract_substr_idxes (188-201)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-test
🔇 Additional comments (5)
ts_tests/circuit_input.test.ts (1)

34-34: LGTM! Typo fix applied consistently.

The property name correction from removeSoftLinesBreaks to removeSoftLineBreaks (removing the extra 's') is applied consistently across all three test cases. This aligns with the updated WASM API mentioned in the PR objectives.

Also applies to: 79-79, 153-153

src/lib.rs (2)

11-11: WASM cfg gate for wasm module looks good

The #[cfg(target_arch = "wasm32")] around the wasm module keeps the native build surface clean while exposing the WASM helpers only where relevant; no issues here.


23-30: <!-- [scratchpad_start]
[task verify_re_export_impact 2/3]
[observations]

  • Found lib.rs content showing re-export block at lines 24-30 (matches review snippet)
  • Searched for extract_ across entire codebase - found extensive usage of:
    • extract_body_hash_idxes, extract_email_addr_idxes, extract_email_domain_idxes
    • extract_from_addr_idxes, extract_message_id_idxes, extract_subject_all_idxes
    • extract_substr, extract_substr_idxes, extract_timestamp_idxes, extract_to_addr_idxes
    • pad_bytes, pad_string in multiple files
  • No results for extract_substrs (plural) - only extract_substr (singular) exists
  • All re-exported items are actively used in src/parse_email.rs, src/regex/patterns.rs, src/regex/wasm.rs, src/circuit/circom.rs
  • Functions defined in src/regex/patterns.rs (wrapper functions around extract_substr_idxes) and src/regex/extract.rs (core implementations)

[analysis]

  • The original review suggested looking for removed helpers like extract_substrs
  • No evidence of extract_substrs existing - appears never to have existed in codebase
  • All currently re-exported items are actively used and defined in the regex module
  • Singular vs plural: code uses extract_substr (singular) throughout, not plural variant

[pending]

  • Need to verify regex/mod.rs actually exports all these items
  • Need to ensure all types are properly exported (DecomposedRegexConfig, ExtractionError, etc.)
  • Check if re-export is complete or if any items are missing

[actions]

  1. Check src/regex/mod.rs to see what it actually exports
  2. Cross-reference all re-exported items with what's available in regex module
  3. Verify no breakage from the re-export set
#!/bin/bash
# Check the regex module's mod.rs to see what it exports
cat src/regex/mod.rs
#!/bin/bash
# Check if extract.rs and patterns.rs properly export their functions
grep -n "^pub fn\|^pub struct\|^pub enum" src/regex/extract.rs src/regex/patterns.rs src/regex/types.rs
#!/bin/bash
# Verify all re-exported items from lib.rs actually exist in regex module
# Check each function/type exists
rg -n "pub fn extract_body_hash_idxes|pub fn extract_email_addr_idxes|pub fn extract_email_domain_idxes|pub fn extract_from_addr_idxes|pub fn extract_message_id_idxes|pub fn extract_subject_all_idxes|pub fn extract_substr|pub fn extract_substr_idxes|pub fn extract_timestamp_idxes|pub fn extract_to_addr_idxes|pub fn pad_bytes|pub fn pad_string" src/regex/
Cargo.toml (2)

53-53: Let me search more specifically for any breaking changes documentation between versions:

Let me search for the GitHub release notes more specifically:

Based on my verification, v5.0.0 was released as a fix for a Plonky3 library issue affecting SP1 zkVM security, specifically a FRI size check vulnerability. However, I found that:

  1. No direct code usage detected: The codebase declares sp1-verifier as a dependency but contains no direct Rust code imports or usages of it.

  2. Security fix, not breaking changes: The release notes indicate this was primarily a security fix rather than breaking API changes.

  3. Incomplete verification: Without visible code usage of sp1-verifier or documented API breaking changes, I cannot definitively confirm whether the upgrade required code modifications.

Verify that the sp1-verifier 5.0.0 upgrade compiles successfully and that all tests pass. Confirm the dependency works as intended with the current codebase.


16-16: zk-regex-compiler revision is valid and reachable.

The commit hash a2ce67ff8ae667bc7846cf8920d7d866f2f02d4c has been verified as valid and accessible in the zkemail/zk-regex repository. The sp1-verifier upgrade from 4.0.0 to 5.0.0 shows no breaking changes in the public API based on the v5.0.0 release notes.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
src/circuit/circom.rs (2)

237-330: Silent 0 defaults for indices still risk hiding extraction failures

code_idx, timestamp_idx, and command_idx default to 0 on any extraction error (Lines 290–307) and are later overwritten with find_index_in_body results when precomputed_sha is present (Lines 315–329). This keeps the previous behavior but still makes it hard to distinguish “not found / error” from a genuine index at 0.

Consider one of:

  • Propagating the errors instead of mapping Err(_) => 0, or
  • Changing these fields to Option<usize> in EmailCircuitInput and using None on extraction failure, or
  • At minimum, documenting clearly that 0 is a sentinel for “missing” and never a valid match position in your circuits.

Example (propagate errors):

-    let mut code_idx = match parsed_email.get_invitation_code_idxes(
+    let mut code_idx = parsed_email
+        .get_invitation_code_idxes(
             params
                 .as_ref()
                 .map_or(false, |p| p.ignore_body_hash_check.unwrap_or(false)),
-    ) {
-        Ok(indexes) => indexes.0,
-        Err(_) => 0,
-    };
-    let timestamp_idx = match parsed_email.get_timestamp_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,
-        };
+        )?
+        .0;
+    let timestamp_idx = parsed_email.get_timestamp_idxes()?.0;
+    let mut command_idx =
+        parsed_email.get_command_idxes(circuit_input_params.ignore_body_hash_check)?.0;

This issue was already raised in a previous review and still applies.


618-656: Use u64 consistently for capture group indices instead of i64

All other Circom capture-group-related arrays here (capture_group_ids, capture_group_starts) are serialized as u64, and the Noir side uses u64 for capture_group_start_indices as well. This one cast to i64 is inconsistent and can be confusing:

.map(|s| serde_json::Value::Number((*s as i64).into()))

Switching to u64 keeps all index-like fields non-negative and aligned:

-                                    .map(|s| serde_json::Value::Number((*s as i64).into()))
+                                    .map(|s| serde_json::Value::Number((*s as u64).into()))

This was identified in an earlier review and still applies.

🧹 Nitpick comments (4)
package.json (1)

13-13: Clarify the pre-release version format.

The version "0.4.66-15" uses a non-standard pre-release suffix. Semantic versioning typically expects formats like 0.4.66-alpha.15, 0.4.66-beta.15, or 0.4.66-rc.15 to convey meaning.

Please clarify what "-15" represents (e.g., build number, draft iteration) and consider adopting a standard pre-release identifier for clarity.

src/regex/types.rs (1)

30-71: Clarify behavior when max_bytes_per_part length doesn’t match parts

LegacyDecomposedRegexConfig::to_new_config silently defaults to 256 when max_bytes_per_part is None or too short, which can surprise callers if they miscount parts.

Consider either asserting or documenting this behavior explicitly, e.g.:

 impl LegacyDecomposedRegexConfig {
     /// Convert old config to new config with optional max_bytes per part
     pub fn to_new_config(&self, max_bytes_per_part: Option<Vec<usize>>) -> DecomposedRegexConfig {
+        if let Some(ref v) = max_bytes_per_part {
+            debug_assert!(
+                v.len() >= self.parts.len(),
+                "max_bytes_per_part shorter than parts; missing entries default to 256",
+            );
+        }
         let parts = self
             .parts
             .iter()
             .enumerate()
             .map(|(i, part)| {
                 let max_bytes = max_bytes_per_part.as_ref().and_then(|v| v.get(i).copied());
                 part.to_new_part(max_bytes)
             })
             .collect();

This keeps runtime behavior but makes the implicit default less surprising.

src/circuit/circom.rs (2)

675-691: Minor readability tweak for external input value handling

The call to string_to_circom_bigint_bytes adds an extra reference:

string_to_circom_bigint_bytes(&external_input.value.as_deref().unwrap_or(""))?;

Since as_deref().unwrap_or("") already yields &str, you can simplify to:

-        let mut value =
-            string_to_circom_bigint_bytes(&external_input.value.as_deref().unwrap_or(""))?;
+        let mut value =
+            string_to_circom_bigint_bytes(external_input.value.as_deref().unwrap_or(""))?;

No functional change, just slightly clearer.


719-723: compute_signal_length logic is correct; consider adding tests

The calculation max_length / 31 + (if max_length % 31 != 0 { 1 } else { 0 }) correctly computes the number of 31-byte limbs, including the max_length == 0 case. Given the TODO, adding small table-driven tests (e.g., 0, 1, 31, 32, 62, 63) would lock this in.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c902807 and b9c0830.

📒 Files selected for processing (5)
  • package.json (1 hunks)
  • src/circuit/circom.rs (1 hunks)
  • src/circuit/mod.rs (1 hunks)
  • src/cryptos.rs (9 hunks)
  • src/regex/types.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/circuit/mod.rs
🧰 Additional context used
🧬 Code graph analysis (2)
src/circuit/circom.rs (5)
src/circuit/mod.rs (3)
  • generate_circuit_inputs_old (194-256)
  • generate_circuit_inputs (134-192)
  • new (98-113)
src/converters.rs (4)
  • field_to_hex (76-79)
  • hex_to_u256 (302-308)
  • string_to_circom_bigint_bytes (463-483)
  • vec_u8_to_bigint (265-269)
src/parse_email.rs (3)
  • find_index_in_body (360-372)
  • remove_quoted_printable_soft_breaks (323-345)
  • new_from_raw_email (49-75)
src/circuit/noir/utils.rs (1)
  • trim_sha256_padding (319-350)
src/regex/extract.rs (1)
  • extract_substr_idxes (188-201)
src/cryptos.rs (2)
src/regex/padding.rs (1)
  • pad_string (18-22)
src/converters.rs (2)
  • hex_to_field (20-67)
  • field_to_hex (76-79)
🔇 Additional comments (14)
package.json (1)

4-12: Verify npm scripts cover new browser_test app.

The PR introduces a browser_test Vite app. The current build scripts (wasm:build, wasm:postbuild, build) appear focused on Rust WASM compilation. Confirm that:

  1. The browser_test app has its own separate build/dev scripts (e.g., in a nested package.json), or
  2. New npm scripts are needed to support browser_test development/build.
src/cryptos.rs (8)

3-3: LGTM!

The new import for pad_string from the regex module is correctly used in the refactored from_email_addr method (line 123) and aligns with the PR's goal of consolidating padding utilities.


111-128: LGTM! Excellent security improvement.

The addition of length validation before padding prevents potential collision attacks where different email addresses exceeding 256 bytes could produce identical padded representations. The error handling is clear and the documentation thoroughly explains the security rationale.


559-630: LGTM! Good backward compatibility approach.

The addition of generate_partial_sha_old maintains support for the older Circom compiler that requires external padding. The 64-byte alignment check (lines 615-620) is correctly preserved for this compatibility path, while the new implementation delegates padding to the circuit.


674-770: LGTM! Excellent test coverage.

The new tests comprehensively validate the email address length validation and padding behavior:

  • Valid inputs and boundary cases (lines 674-702)
  • Error handling for overflow (lines 704-718)
  • Security properties preventing collisions (lines 720-730)
  • Integration with calculate_account_salt (lines 746-770)

The tests are well-structured and provide strong confidence in the new validation logic.


872-890: LGTM! Proper error propagation implemented.

The function signature change to return Result<String> correctly propagates errors from:

  • PaddedEmailAddr::from_email_addr (line 875)
  • hex_to_field conversions (lines 879, 881)
  • AccountSalt::new (line 886)

This provides better error visibility to callers and aligns with Rust best practices.


903-906: LGTM! Good robustness improvement.

Adding a fallback to try the lowercase "from" header improves compatibility with email systems that may use different header casing. The or_else pattern ensures no behavioral change when the standard "From" header is present.


38-38: New DKIM API endpoint verified and functional.

The endpoint change from /api/key to /api/key/domain has been confirmed. The new endpoint returns HTTP 200 with a valid JSON array format where each element contains the required "value" field with DKIM records. The existing parsing logic at lines 1038-1041 (which uses .as_array()?.iter().filter_map(|record| record.get("value"))) correctly handles this response format. Query parameters remain unchanged. No breaking changes detected.


494-557: Verify circuit handling of non-64-byte-aligned SHA padding with test evidence.

The Consensys Diligence audit of zkemail.nr (December 2024) identified that there are no tests for partial_sha256_var_end when the message size is not a multiple of block size (64 bytes). This directly validates your concern about removing the 64-byte alignment check in generate_partial_sha.

The code shifts SHA padding responsibility from Rust (generate_partial_sha_old checked alignment explicitly) to the circuit's partial_sha256_var_end, but this function is designed to hash additional parts of the message or complete the entire hash. Critical gap: no evidence in the current codebase that non-aligned inputs are tested or that recent audit findings have been addressed.

Before merging, verify:

  1. Tests exist covering remaining bodies with lengths not divisible by 64
  2. The circuit implementation has been updated to handle the documented audit gaps
  3. Hash output matches standard implementations for all edge cases
src/regex/types.rs (1)

6-28: Error type and result alias are well-structured

The ExtractionError variants and the ExtractionResult<T> alias give clear, future-proof error reporting for regex extraction; no changes needed here.

src/circuit/circom.rs (4)

61-220: Serde wrappers and legacy RegexPart handling look correct

The SerializableRegexPart, RegexPartInput, and regex_parts_serde module cleanly support both new enum-based parts and legacy configs while preserving JSON compatibility. The custom DecomposedRegex Debug/Clone implementations are also sound.


371-390: Claim circuit input generation is straightforward and correct

generate_claim_input cleanly uses PaddedEmailAddr::from_email_addr and propagates validation via ?, and the serialized shape of ClaimCircuitInput is simple and consistent.


397-451: Legacy regex circuit input generation matches old format

generate_legacy_circuit_inputs correctly reconstructs {name}RegexIdx and {name}RegexIdxN fields from extract_substr_idxes, preserving the legacy shape for old Circom circuits. No changes needed here.


581-604: NFAGraph path construction and regex_graph_json handling look correct

The NFAGraph-based path correctly guards with has_nfa_graph(), so the .unwrap() on regex_graph_json is safe, and the use of get_max_haystack_length/max_match_length cleanly wires through to gen_circuit_inputs.

Comment on lines +503 to +509
let email_circuit_inputs;
if decomposed_regexes[0].has_nfa_graph() {
email_circuit_inputs = generate_circuit_inputs(circuit_input_params.clone())?;
} else {
// TODO: remove all this temperory code for supporting old one
email_circuit_inputs = generate_circuit_inputs_old(circuit_input_params.clone())?;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Potential panic when decomposed_regexes is empty

generate_circuit_inputs_with_decomposed_regexes_and_external_inputs indexes decomposed_regexes[0] to decide between generate_circuit_inputs and generate_circuit_inputs_old. If the caller passes an empty vector (e.g., only external inputs), this will panic.

Using .first() avoids this and lets you define a safe default (e.g., new compiler by default):

-    let email_circuit_inputs;
-    if decomposed_regexes[0].has_nfa_graph() {
-        email_circuit_inputs = generate_circuit_inputs(circuit_input_params.clone())?;
-    } else {
-        // TODO: remove all this temperory code for supporting old one
-        email_circuit_inputs = generate_circuit_inputs_old(circuit_input_params.clone())?;
-    }
+    let email_circuit_inputs = if decomposed_regexes
+        .first()
+        .map(|r| r.has_nfa_graph())
+        .unwrap_or(true)
+    {
+        generate_circuit_inputs(circuit_input_params.clone())?
+    } else {
+        // TODO: remove all this temporary code for supporting old one
+        generate_circuit_inputs_old(circuit_input_params.clone())?
+    };

This keeps behavior for non-empty inputs while making the empty case safe.

🤖 Prompt for AI Agents
In src/circuit/circom.rs around lines 503 to 509, the code unsafely indexes
decomposed_regexes[0] and can panic when the vector is empty; change the logic
to use decomposed_regexes.first() (or pattern-match) and, if Some(first) call
first.has_nfa_graph() to choose between generate_circuit_inputs and
generate_circuit_inputs_old, otherwise treat the empty case as the safe default
(use generate_circuit_inputs) so the function no longer panics on empty input.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/cryptos.rs (2)

559-559: Minor: Grammatical issue in comment.

The comment reads "Just supported for older circom compiler" but should be "Only supported for older circom compiler" or "Supported only for older circom compiler" for better clarity.

Apply this diff:

-// TODO : Just supported for older circom compiler, since it's circuit doesn't had the padding inside, we padded them externally
+// TODO: Only supported for older circom compiler, since its circuit doesn't have padding inside, so we pad externally

920-929: Consider adding a clarifying comment for the .last() usage.

The use of .captures_iter(from_domain).last() cleverly handles cases where the From header might contain multiple @ symbols (e.g., in display names like "Contact @ Company <[email protected]>"). A brief comment explaining this would improve code clarity.

     // Extract domain from From header
     let from_domain = from_headers[0].as_str();
     let from_re = Regex::new(r"@([^>\s]+)").unwrap();
+    // Use .last() to get the domain from the actual email address, not from any @ in the display name
     let from_domain = from_re
         .captures_iter(from_domain)
         .last()
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b9c0830 and aeeb433.

📒 Files selected for processing (2)
  • package.json (1 hunks)
  • src/cryptos.rs (10 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/cryptos.rs (2)
src/regex/padding.rs (1)
  • pad_string (18-22)
src/converters.rs (2)
  • hex_to_field (20-67)
  • field_to_hex (76-79)
🔇 Additional comments (8)
package.json (1)

13-13: Verify the version format is appropriate for npm publishing.

The version 0.4.66-16 uses a non-standard format for npm (typically semantic versioning or standard pre-release identifiers like 0.4.66-alpha.16 or 0.4.66-rc.16 are preferred). Given that this package has public npm publish scripts, confirm that this format is intentional and won't cause issues when published to the registry.

src/cryptos.rs (7)

111-128: LGTM! Excellent security improvement.

The email length validation prevents collision attacks where different email addresses exceeding 256 bytes could produce identical padded representations. The error handling is clear and comprehensive.


494-557: LGTM! Well-structured partial SHA generation.

The function properly handles regex compilation errors, UTF-8 conversion errors, and validates the remaining body length. The padding logic is correct, and the comment at line 549 helpfully explains why 64-byte alignment checking is unnecessary (circuit handles it).


873-890: LGTM! Proper error propagation throughout.

The function correctly propagates errors from PaddedEmailAddr::from_email_addr, hex_to_field, and AccountSalt::new using the ? operator. The Result return type is appropriate for these validation steps.


903-906: LGTM! Good defensive handling of header case variations.

The fallback to lowercase "from" header improves robustness across different mail servers that may use different header capitalization.


674-744: LGTM! Comprehensive test coverage for email validation.

The tests thoroughly cover valid cases, boundary conditions (exactly 256 bytes), error cases (exceeding max length), and security concerns (collision prevention). Well-structured test suite.


746-770: LGTM! Good test coverage for account salt calculation.

The tests verify both successful salt calculation with valid inputs and proper error propagation when the email exceeds maximum length. The use of a properly formatted 32-byte hex account code is appropriate.


38-38: Add integration test for the DKIM API endpoint in CI.

The fetch_public_keys function depends on https://archive.zk.email/api/key/domain for DKIM verification, but the existing test skips in CI environments. Either add an integration test with a mock endpoint/fixture, or document the runtime requirement and expected response schema.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants