Repository navigation
feat: discord #34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
feat: discord #34
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
24 changes: 24 additions & 0 deletions
24
script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointDiscord.s.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.30; | ||
|
|
||
| import { DeployLinkHandleEntrypointScript } from "./_DeployLinkHandleEntrypoint.s.sol"; | ||
| import { HonkVerifier } from "../../test/fixtures/linkHandleCommand/discord/target/HonkVerifier.sol"; | ||
|
|
||
| contract DeployLinkHandleEntrypointDiscordScript is DeployLinkHandleEntrypointScript { | ||
| function _deployHonkVerifier() internal override returns (address) { | ||
| return address(new HonkVerifier()); | ||
| } | ||
|
|
||
| function _getDkimRegistryAddress() internal pure override returns (address) { | ||
| // sepolia always valid dkim registry | ||
| return 0xc4f628496b8c474096650C8f9023954643cC614F; | ||
| } | ||
|
|
||
| function _getPlatformName() internal pure override returns (string memory) { | ||
| return "Discord"; | ||
| } | ||
|
|
||
| function _getRecordName() internal pure override returns (string memory) { | ||
| return "com.discord"; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| [package] | ||
| name = "zkemail/discord_2@1" | ||
| type = "bin" | ||
| authors = [] | ||
| compiler_version = ">=1.0.0" | ||
|
|
||
| [dependencies] | ||
| zkemail = { tag = "v.1.0.1-beta.5", git = "https://github.com/zkemail/zkemail.nr", directory = "lib" } | ||
| zkregex = { tag = "2.2.0", git = "https://github.com/zkemail/zk-regex", directory = "noir" } | ||
| poseidon = { tag = "v0.1.0", git = "https://github.com/noir-lang/poseidon" } | ||
60 changes: 60 additions & 0 deletions
60
test/fixtures/linkHandleCommand/discord/files/blueprint.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| { | ||
| "name": "discord_2", | ||
| "values": [ | ||
| { | ||
| "parts": [ | ||
| { | ||
| "isPublic": false, | ||
| "regexDef": ">Hey " | ||
| }, | ||
| { | ||
| "isPublic": true, | ||
| "regexDef": "[A-Za-z0-9_]+", | ||
| "maxLength": 64 | ||
| }, | ||
| { | ||
| "isPublic": false, | ||
| "regexDef": "," | ||
| } | ||
| ], | ||
| "name": "handle", | ||
| "maxLength": 64, | ||
| "location": "body", | ||
| "maxMatchLength": 64 | ||
| }, | ||
| { | ||
| "parts": [ | ||
| { | ||
| "isPublic": false, | ||
| "regexDef": "(?:\\r\\n|^)from:[^\\r\\n]*@" | ||
| }, | ||
| { | ||
| "isPublic": true, | ||
| "regexDef": "[A-Za-z0-9][A-Za-z0-9\\.-]+", | ||
| "maxLength": 64 | ||
| }, | ||
| { | ||
| "isPublic": false, | ||
| "regexDef": "[>\\r\\n]" | ||
| } | ||
|
benceharomi marked this conversation as resolved.
|
||
| ], | ||
| "name": "sender_domain", | ||
| "maxLength": 64, | ||
| "location": "header", | ||
| "maxMatchLength": 64 | ||
| } | ||
| ], | ||
| "version": 1, | ||
| "senderDomain": "discord.com", | ||
| "externalInputs": [ | ||
| { | ||
| "name": "command", | ||
| "maxLength": 605 | ||
| } | ||
| ], | ||
| "emailBodyMaxLength": 16384, | ||
| "ignoreBodyHashCheck": false, | ||
| "emailHeaderMaxLength": 960, | ||
| "clientZkFramework": "Noir", | ||
| "serverZkFramework": "SP1" | ||
| } | ||
118 changes: 118 additions & 0 deletions
118
test/fixtures/linkHandleCommand/discord/src/handle_regex.nr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| use zkregex::utils::{ | ||
| select_subarray, | ||
| captures::capture_substring, | ||
| sparse_array::SparseArray, | ||
| transitions::check_transition_with_captures | ||
| }; | ||
|
benceharomi marked this conversation as resolved.
|
||
|
|
||
| global TRANSITION_TABLE: SparseArray<133, Field> = SparseArray { | ||
| keys: [0x00000000, 0x00024240, 0x00024241, 0x00034e4d, 0x00046d6c, 0x00058382, 0x00062c2b, 0x00073e3d, 0x00073e3e, 0x00073f3e, 0x00073f3f, 0x0007403f, 0x00074040, 0x00074140, 0x00074141, 0x00074241, 0x00074242, 0x00074342, 0x00074343, 0x00074443, 0x00074444, 0x00074544, 0x00074545, 0x00074645, 0x00074646, 0x00074746, 0x00074747, 0x00074f4e, 0x00074f4f, 0x0007504f, 0x00075050, 0x00075150, 0x00075151, 0x00075251, 0x00075252, 0x00075352, 0x00075353, 0x00075453, 0x00075454, 0x00075554, 0x00075555, 0x00075655, 0x00075656, 0x00075756, 0x00075757, 0x00075857, 0x00075858, 0x00075958, 0x00075959, 0x00075a59, 0x00075a5a, 0x00075b5a, 0x00075b5b, 0x00075c5b, 0x00075c5c, 0x00075d5c, 0x00075d5d, 0x00075e5d, 0x00075e5e, 0x00075f5e, 0x00075f5f, 0x0007605f, 0x00076060, 0x00076160, 0x00076161, 0x00076261, 0x00076262, 0x00076362, 0x00076363, 0x00076463, 0x00076464, 0x00076564, 0x00076565, 0x00076665, 0x00076666, 0x00076766, 0x00076767, 0x00076867, 0x00076868, 0x00076d6c, 0x00076d6d, 0x00076f6e, 0x00076f6f, 0x0007706f, 0x00077070, 0x00077170, 0x00077171, 0x00077271, 0x00077272, 0x00077372, 0x00077373, 0x00077473, 0x00077474, 0x00077574, 0x00077575, 0x00077675, 0x00077676, 0x00077776, 0x00077777, 0x00077877, 0x00077878, 0x00077978, 0x00077979, 0x00077a79, 0x00077a7a, 0x00077b7a, 0x00077b7b, 0x00077c7b, 0x00077c7c, 0x00077d7c, 0x00077d7d, 0x00077e7d, 0x00077e7e, 0x00077f7e, 0x00077f7f, 0x0007807f, 0x00078080, 0x00078180, 0x00078181, 0x00078281, 0x00078282, 0x00078382, 0x00078383, 0x00078483, 0x00078484, 0x00078584, 0x00078585, 0x00078685, 0x00078686, 0x00078786, 0x00078787, 0x00078887, 0x00078888, 0x00083c3b, 0x0009100f], | ||
| values: [0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000001, 0x00000000], | ||
| maximum: 0x0009100f | ||
| }; | ||
|
|
||
| pub global CAPTURE_1_MAX_LENGTH: u32 = 64; | ||
| pub global NUM_CAPTURE_GROUPS: u32 = 1; | ||
|
|
||
| /** | ||
| * Constrains a start state to be valid | ||
| * @dev start states are hardcoded in this function - "(start_state - {state})" for each start | ||
| * example: `(start_state - 0) * (start_state - 1) * (start_state - 2)` means 0, 1, or 2 | ||
| * are valid first states | ||
| * | ||
| * @param start_state - The start state of the NFA | ||
| */ | ||
| fn check_start_state(start_state: Field) { | ||
| let valid_start_state = (start_state - 0) * (start_state - 1); | ||
| assert(valid_start_state == 0, "Invalid start state"); | ||
| } | ||
|
|
||
| /** | ||
| * Constrains the recognition of accept_state being reached. If an aceppt state is reached, | ||
| * ensures asserted traversal path is valid | ||
| * @dev accept states are hardcoded in this function - "(next_state - {state})" for each accept | ||
| * example: `(next_state - 19) * (next_state - 20) * (next_state - 21)` means 19, 20, or 21 | ||
| * are valid accept states | ||
| * | ||
| * @param next_state - The asserted next state of the NFA | ||
| * @param haystack_index - The index being operated on in the haystack | ||
| * @param asserted_match_length - The asserted traversal path length | ||
| * @return - 0 if accept_state is reached, nonzero otherwise | ||
| */ | ||
| fn check_accept_state( | ||
| next_state: Field, | ||
| haystack_index: Field, | ||
| asserted_match_length: Field | ||
| ) -> Field { | ||
| // check if the next state is an accept state | ||
| let accept_state_reached = (next_state - 8); | ||
| let accept_state_reached_bool = (accept_state_reached == 0) as Field; | ||
|
|
||
| // check if the haystack index is the asserted match length | ||
| // should equal 1 since haystack_index should be 1 less than asserted_match)length | ||
| let asserted_path_traversed = (asserted_match_length - haystack_index == 1) as Field; | ||
|
|
||
| (1 - (accept_state_reached_bool * asserted_path_traversed)) | ||
| } | ||
|
|
||
| /** | ||
| * HandleRegex matching function | ||
| * Regex: >Hey ([A-Za-z0-9_]+), | ||
| * @param in_haystack - The input haystack to search from | ||
| * @param match_start - The start index in the haystack for the subarray to match from | ||
| * @param match_length - The length of the subarray to extract from haystack | ||
| * @param current_states - The current states of the NFA at each index in the match subarray | ||
| * @param next_states - The next states of the NFA at each index in the match subarray | ||
| * @param capture_group_<group>_ids - The ids of the capture groups in the match subarray | ||
| * @param capture_group_<group>_starts - The start positions of the capture groups in the match subarray | ||
| * @param capture_group_start_indices - The start indices of the capture groups in the match subarray | ||
| * @return - tuple of substring captures as dictated by the regular expression | ||
| */ | ||
| pub fn regex_match<let MAX_HAYSTACK_LEN: u32, let MAX_MATCH_LEN: u32>( | ||
| in_haystack: [u8; MAX_HAYSTACK_LEN], | ||
| match_start: u32, | ||
| match_length: u32, | ||
| current_states: [Field; MAX_MATCH_LEN], | ||
| next_states: [Field; MAX_MATCH_LEN], | ||
| capture_group_1_id: [Field; MAX_MATCH_LEN], | ||
| capture_group_1_start: [Field; MAX_MATCH_LEN], | ||
| capture_group_start_indices: [Field; NUM_CAPTURE_GROUPS], | ||
| ) -> (BoundedVec<u8, CAPTURE_1_MAX_LENGTH>) { | ||
| // resize haystack | ||
| let haystack: [u8; MAX_MATCH_LEN] = select_subarray::<MAX_HAYSTACK_LEN, MAX_MATCH_LEN>(in_haystack, match_start, match_length); | ||
|
|
||
| check_start_state(current_states[0]); | ||
| for i in 0..MAX_MATCH_LEN-1 { | ||
| // match length - 1 since current states should be 1 less than next states | ||
| let in_range = (i < match_length - 1) as Field; | ||
| let matching_states = current_states[i + 1] - next_states[i]; | ||
| assert(in_range * matching_states == 0, "Invalid Transition Input"); | ||
| } | ||
| let mut reached_end_state = 1; | ||
| for i in 0..MAX_MATCH_LEN { | ||
| let active_capture_groups_at_index = [capture_group_1_id[i]]; | ||
| let active_capture_groups_starts_at_index = [capture_group_1_start[i]]; | ||
| check_transition_with_captures( | ||
| TRANSITION_TABLE, | ||
| haystack[i] as Field, | ||
| current_states[i], | ||
| next_states[i], | ||
| active_capture_groups_at_index, | ||
| active_capture_groups_starts_at_index, | ||
| reached_end_state | ||
| ); | ||
| reached_end_state = reached_end_state * check_accept_state(next_states[i], i as Field, match_length as Field); | ||
| } | ||
| assert(reached_end_state == 0, "Did not reach a valid end state"); | ||
|
|
||
| // Capture Group 1 | ||
| let capture_1 = capture_substring::<MAX_MATCH_LEN, CAPTURE_1_MAX_LENGTH, 1>( | ||
| haystack, | ||
| capture_group_1_id, | ||
| capture_group_1_start, | ||
| capture_group_start_indices[0] | ||
| ); | ||
|
|
||
| (capture_1) | ||
| } | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
|
|
||
| mod handle_regex; | ||
| mod sender_domain_regex; | ||
| use poseidon::poseidon; | ||
| use std::{collections::bounded_vec::BoundedVec, hash::pedersen_hash}; | ||
| use zkemail::{ | ||
| dkim::RSAPubkey, hash::poseidon_large, headers::body_hash::get_body_hash, KEY_LIMBS_2048, | ||
| partial_hash::partial_sha256_var_end, remove_soft_line_breaks::remove_soft_line_breaks, | ||
| Sequence, utils::pack_bytes, | ||
| }; | ||
| fn main( | ||
| header: BoundedVec<u8, 960>, | ||
| pubkey: RSAPubkey<KEY_LIMBS_2048>, | ||
| signature: [Field; KEY_LIMBS_2048], | ||
| prover_address: [Field; 1], | ||
| dkim_header_sequence: Sequence, | ||
| body: BoundedVec<u8, 16384>, | ||
| body_hash_index: u32, | ||
| partial_body_hash: [u32; 8], | ||
| partial_body_real_length: u64, | ||
| decoded_body: BoundedVec<u8, 16384>, | ||
| command: [Field; 20], | ||
| handle_match_start: u32, | ||
| handle_match_length: u32, | ||
| handle_current_states: [Field; 64], | ||
| handle_next_states: [Field; 64], | ||
| handle_capture_group_1_id: [Field; 64], | ||
| handle_capture_group_1_start: [Field; 64], | ||
| handle_capture_group_start_indices: [Field; 1], | ||
| sender_domain_match_start: u32, | ||
| sender_domain_match_length: u32, | ||
| sender_domain_current_states: [Field; 64], | ||
| sender_domain_next_states: [Field; 64], | ||
| sender_domain_capture_group_1_id: [Field; 64], | ||
| sender_domain_capture_group_1_start: [Field; 64], | ||
| sender_domain_capture_group_start_indices: [Field; 1], | ||
| ) -> pub (Field, Field, Field, Field, [Field; 1] , [Field; 20], BoundedVec<u8, 64>, BoundedVec<u8, 64>) { | ||
|
benceharomi marked this conversation as resolved.
|
||
| // check the body and header lengths are within bounds | ||
| assert(header.len() <= 960); | ||
| assert(body.len() <= 16384); | ||
| // DKIM Verification | ||
| let header_hash: [u8; 32] = pubkey.verify_dkim_signature(header, signature); | ||
| let header_hash: [Field; 2] = pack_bytes::<32, 16>(header_hash); | ||
| // Body Hash Verification | ||
| let signed_body_hash = get_body_hash(header, dkim_header_sequence, body_hash_index); | ||
| let computed_body_hash: [u8; 32] = partial_sha256_var_end( | ||
| partial_body_hash, | ||
| body.storage(), | ||
| body.len() as u64, | ||
| partial_body_real_length, | ||
| ); | ||
| assert( | ||
| signed_body_hash == computed_body_hash, | ||
| "SHA256 hash computed over body does not match body hash found in DKIM-signed header", | ||
| ); | ||
| assert( | ||
| remove_soft_line_breaks(body.storage(), decoded_body.storage()), | ||
| "Decoded body does not properly remove soft line breaks", | ||
| ); | ||
| let pubkey_hash = pubkey.hash(); | ||
| let email_nullifier = poseidon::bn254::hash_1([poseidon_large(signature)]); | ||
| let handle_capture_1 = handle_regex::regex_match::<16384, 64>( | ||
| decoded_body.storage(), | ||
| handle_match_start, | ||
| handle_match_length, | ||
| handle_current_states, | ||
| handle_next_states, | ||
| handle_capture_group_1_id, | ||
| handle_capture_group_1_start, | ||
| handle_capture_group_start_indices, | ||
| ); | ||
| let sender_domain_capture_1 = sender_domain_regex::regex_match::<960, 64>( | ||
| header.storage(), | ||
| sender_domain_match_start, | ||
| sender_domain_match_length, | ||
| sender_domain_current_states, | ||
| sender_domain_next_states, | ||
| sender_domain_capture_group_1_id, | ||
| sender_domain_capture_group_1_start, | ||
| sender_domain_capture_group_start_indices, | ||
| ); | ||
| (pubkey_hash, email_nullifier, header_hash[0], header_hash[1], prover_address, command, handle_capture_1, sender_domain_capture_1) | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.