diff --git a/Cargo.lock b/Cargo.lock index 2370d86..c019e90 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -192,7 +192,7 @@ checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -233,7 +233,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -577,7 +577,7 @@ dependencies = [ "lazy_static", "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -597,7 +597,7 @@ checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" dependencies = [ "camino", "cargo-platform", - "semver", + "semver 1.0.22", "serde", "serde_json", "thiserror", @@ -987,7 +987,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -1430,7 +1430,7 @@ dependencies = [ "reqwest", "serde", "serde_json", - "syn 2.0.57", + "syn 2.0.58", "toml", "walkdir", ] @@ -1448,7 +1448,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -1474,7 +1474,7 @@ dependencies = [ "serde", "serde_json", "strum 0.26.2", - "syn 2.0.57", + "syn 2.0.58", "tempfile", "thiserror", "tiny-keccak", @@ -1490,7 +1490,7 @@ dependencies = [ "chrono", "ethers-core", "reqwest", - "semver", + "semver 1.0.22", "serde", "serde_json", "thiserror", @@ -1599,7 +1599,7 @@ dependencies = [ "path-slash", "rayon", "regex", - "semver", + "semver 1.0.22", "serde", "serde_json", "solang-parser", @@ -1894,7 +1894,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -2447,7 +2447,7 @@ dependencies = [ "candid", "ic-agent", "once_cell", - "semver", + "semver 1.0.22", "serde", "serde_bytes", "strum 0.24.1", @@ -2806,6 +2806,16 @@ version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +[[package]] +name = "libloading" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" +dependencies = [ + "cfg-if", + "winapi", +] + [[package]] name = "libm" version = "0.2.8" @@ -2990,6 +3000,47 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" +[[package]] +name = "neon" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28e15415261d880aed48122e917a45e87bb82cf0260bb6db48bbab44b7464373" +dependencies = [ + "neon-build", + "neon-macros", + "neon-runtime", + "semver 0.9.0", + "smallvec", +] + +[[package]] +name = "neon-build" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bac98a702e71804af3dacfde41edde4a16076a7bbe889ae61e56e18c5b1c811" + +[[package]] +name = "neon-macros" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7288eac8b54af7913c60e0eb0e2a7683020dffa342ab3fd15e28f035ba897cf" +dependencies = [ + "quote", + "syn 1.0.109", + "syn-mid", +] + +[[package]] +name = "neon-runtime" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4676720fa8bb32c64c3d9f49c47a47289239ec46b4bdb66d0913cc512cb0daca" +dependencies = [ + "cfg-if", + "libloading", + "smallvec", +] + [[package]] name = "new_debug_unreachable" version = "1.0.6" @@ -3122,7 +3173,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -3134,7 +3185,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -3235,7 +3286,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -3485,7 +3536,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -3549,7 +3600,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -3587,7 +3638,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -3683,7 +3734,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" dependencies = [ "proc-macro2", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -3990,6 +4041,7 @@ dependencies = [ "halo2curves 0.4.0", "hex", "itertools 0.10.5", + "neon", "num-bigint", "num-traits", "once_cell", @@ -4172,7 +4224,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver", + "semver 1.0.22", ] [[package]] @@ -4359,6 +4411,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58bf37232d3bb9a2c4e641ca2a11d83b5062066f88df7fed36c28772046d65ba" +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + [[package]] name = "semver" version = "1.0.22" @@ -4368,6 +4429,12 @@ dependencies = [ "serde", ] +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + [[package]] name = "send_wrapper" version = "0.4.0" @@ -4427,7 +4494,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -4469,7 +4536,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -5020,7 +5087,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -5046,7 +5113,7 @@ dependencies = [ "hex", "once_cell", "reqwest", - "semver", + "semver 1.0.22", "serde", "serde_json", "sha2 0.10.8", @@ -5068,15 +5135,26 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.57" +version = "2.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "syn-mid" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea305d57546cc8cd04feb14b62ec84bf17f50e3f7b12560d7bfa9265f39d9ed" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "sync_wrapper" version = "0.1.2" @@ -5165,7 +5243,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -5272,7 +5350,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -5466,7 +5544,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -5783,7 +5861,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", "wasm-bindgen-shared", ] @@ -5817,7 +5895,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5850,7 +5928,7 @@ checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -6232,7 +6310,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] diff --git a/packages/circuits/helpers/email_auth.ts b/packages/circuits/helpers/email_auth.ts index 136ac94..aeeed0a 100644 --- a/packages/circuits/helpers/email_auth.ts +++ b/packages/circuits/helpers/email_auth.ts @@ -1,7 +1,7 @@ import fs from "fs"; import { promisify } from "util"; -import { generateCircuitInputs } from "@zk-email/helpers/dist/input-helpers"; -const emailWalletUtils = require("../../utils"); +// import { generateCircuitInputs } from "@zk-email/helpers/dist/input-helpers"; +const relayerUtils = require("../../utils"); export async function genEmailAuthInput(emailFilePath: string, accountCode: string): @@ -18,38 +18,6 @@ export async function genEmailAuthInput(emailFilePath: string, accountCode: stri code_idx: number }> { const emailRaw = await promisify(fs.readFile)(emailFilePath, "utf8"); - const parsedEmail = await emailWalletUtils.parseEmail(emailRaw); - const emailCircuitInputs = generateCircuitInputs({ - body: Buffer.from(""), - message: Buffer.from(parsedEmail.canonicalizedHeader), - bodyHash: "", - rsaSignature: BigInt(parsedEmail.signature), - rsaPublicKey: BigInt(parsedEmail.publicKey), - maxMessageLength: 1024, - maxBodyLength: 64, - ignoreBodyHashCheck: true - }); - const from_addr_idxes = emailWalletUtils.extractFromAddrIdxes(parsedEmail.canonicalizedHeader)[0]; - const fromEmailAddrPart = parsedEmail.canonicalizedHeader.slice(from_addr_idxes[0], from_addr_idxes[1]); - const subject_idx = emailWalletUtils.extractSubjectAllIdxes(parsedEmail.canonicalizedHeader)[0][0]; - const domainIdx = emailWalletUtils.extractEmailDomainIdxes(fromEmailAddrPart)[0][0]; - const timestampIdx = emailWalletUtils.extractTimestampIdxes(parsedEmail.canonicalizedHeader)[0][0]; - let codeIdx = 0; - try { - codeIdx = emailWalletUtils.extractInvitationCodeIdxes(parsedEmail.canonicalizedHeader)[0][0]; - } catch (e) { - console.log("No invitation code in header"); - } - return { - padded_header: emailCircuitInputs.in_padded, - public_key: emailCircuitInputs.pubkey, - signature: emailCircuitInputs.signature, - padded_header_len: emailCircuitInputs.in_len_padded_bytes, - account_code: accountCode, - from_addr_idx: from_addr_idxes[0], - subject_idx: subject_idx, - domain_idx: domainIdx, - timestamp_idx: timestampIdx, - code_idx: codeIdx, - }; + const jsonStr = await relayerUtils.genEmailAuthInput(emailRaw, accountCode); + return JSON.parse(jsonStr); } diff --git a/packages/circuits/helpers/recipient.ts b/packages/circuits/helpers/recipient.ts index b727ab0..5604e55 100644 --- a/packages/circuits/helpers/recipient.ts +++ b/packages/circuits/helpers/recipient.ts @@ -1,7 +1,7 @@ import fs from "fs"; import { promisify } from "util"; import { generateCircuitInputs } from "@zk-email/helpers/dist/input-helpers"; -const emailWalletUtils = require("../../utils"); +const relayerUtils = require("../../utils"); export async function genRecipientInput(emailFilePath: string): @@ -10,17 +10,17 @@ export async function genRecipientInput(emailFilePath: string): rand: string }> { const emailRaw = await promisify(fs.readFile)(emailFilePath, "utf8"); - const parsedEmail = await emailWalletUtils.parseEmail(emailRaw); - const subjectEmailIdxes = emailWalletUtils.extractSubjectAllIdxes(parsedEmail.canonicalizedHeader)[0]; + const parsedEmail = await relayerUtils.parseEmail(emailRaw); + const subjectEmailIdxes = relayerUtils.extractSubjectAllIdxes(parsedEmail.canonicalizedHeader)[0]; const subject = parsedEmail.canonicalizedHeader.slice(subjectEmailIdxes[0], subjectEmailIdxes[1]); let subjectEmailAddrIdx = 0; try { - subjectEmailAddrIdx = emailWalletUtils.extractEmailAddrIdxes(subject)[0][0]; + subjectEmailAddrIdx = relayerUtils.extractEmailAddrIdxes(subject)[0][0]; } catch (e) { console.log("No email address in subject"); subjectEmailAddrIdx = 0; } - const rand = emailWalletUtils.extractRandFromSignature(parsedEmail.signature); + const rand = relayerUtils.extractRandFromSignature(parsedEmail.signature); return { subject_email_addr_idx: subjectEmailAddrIdx, rand: rand diff --git a/packages/circuits/tests/email_auth.test.ts b/packages/circuits/tests/email_auth.test.ts index ff9850b..cea7d8f 100644 --- a/packages/circuits/tests/email_auth.test.ts +++ b/packages/circuits/tests/email_auth.test.ts @@ -6,7 +6,7 @@ const wasm_tester = circom_tester.wasm; import * as path from "path"; const p = "21888242871839275222246405745257275088548364400416034343698204186575808495617"; const field = new ff.F1Field(p); -const emailWalletUtils = require("../../utils"); +const relayerUtils = require("../../utils"); const option = { include: path.join(__dirname, "../../../node_modules") }; @@ -18,33 +18,34 @@ describe("Email Auth", () => { it("Verify a sent email whose subject has an email address", async () => { const emailFilePath = path.join(__dirname, "./emails/email_auth_test1.eml"); const emailRaw = readFileSync(emailFilePath, "utf8"); - const parsedEmail = await emailWalletUtils.parseEmail(emailRaw); + const parsedEmail = await relayerUtils.parseEmail(emailRaw); console.log(parsedEmail.canonicalizedHeader); - const accountCode = await emailWalletUtils.genAccountCode(); + const accountCode = await relayerUtils.genAccountCode(); const circuitInputs = await genEmailAuthInput(emailFilePath, accountCode); + console.log(circuitInputs); const circuit = await wasm_tester(path.join(__dirname, "../src/email_auth.circom"), option); const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); const domainName = "gmail.com"; - const paddedDomain = emailWalletUtils.padString(domainName, 255); - const domainFields = emailWalletUtils.bytes2Fields(paddedDomain); + const paddedDomain = relayerUtils.padString(domainName, 255); + const domainFields = relayerUtils.bytes2Fields(paddedDomain); for (let idx = 0; idx < domainFields.length; ++idx) { expect(BigInt(domainFields[idx])).toEqual(witness[1 + idx]); } - const expectedPubKeyHash = emailWalletUtils.publicKeyHash(parsedEmail.publicKey); + const expectedPubKeyHash = relayerUtils.publicKeyHash(parsedEmail.publicKey); expect(BigInt(expectedPubKeyHash)).toEqual(witness[1 + domainFields.length]); - const expectedEmailNullifier = emailWalletUtils.emailNullifier(parsedEmail.signature); + const expectedEmailNullifier = relayerUtils.emailNullifier(parsedEmail.signature); expect(BigInt(expectedEmailNullifier)).toEqual(witness[1 + domainFields.length + 1]); const timestamp = 1694989812n; expect(timestamp).toEqual(witness[1 + domainFields.length + 2]); const maskedSubject = "Send 0.1 ETH to "; - const paddedMaskedSubject = emailWalletUtils.padString(maskedSubject, 605); - const maskedSubjectFields = emailWalletUtils.bytes2Fields(paddedMaskedSubject); + const paddedMaskedSubject = relayerUtils.padString(maskedSubject, 605); + const maskedSubjectFields = relayerUtils.bytes2Fields(paddedMaskedSubject); for (let idx = 0; idx < maskedSubjectFields.length; ++idx) { expect(BigInt(maskedSubjectFields[idx])).toEqual(witness[1 + domainFields.length + 3 + idx]); } const fromAddr = "suegamisora@gmail.com"; - const accountSalt = emailWalletUtils.accountSalt(fromAddr, accountCode); + const accountSalt = relayerUtils.accountSalt(fromAddr, accountCode); expect(BigInt(accountSalt)).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length]); expect(0n).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length + 1]); }); @@ -52,33 +53,33 @@ describe("Email Auth", () => { it("Verify a sent email whose subject does not have an email address", async () => { const emailFilePath = path.join(__dirname, "./emails/email_auth_test2.eml"); const emailRaw = readFileSync(emailFilePath, "utf8"); - const parsedEmail = await emailWalletUtils.parseEmail(emailRaw); + const parsedEmail = await relayerUtils.parseEmail(emailRaw); console.log(parsedEmail.canonicalizedHeader); - const accountCode = await emailWalletUtils.genAccountCode(); + const accountCode = await relayerUtils.genAccountCode(); const circuitInputs = await genEmailAuthInput(emailFilePath, accountCode); const circuit = await wasm_tester(path.join(__dirname, "../src/email_auth.circom"), option); const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); const domainName = "gmail.com"; - const paddedDomain = emailWalletUtils.padString(domainName, 255); - const domainFields = emailWalletUtils.bytes2Fields(paddedDomain); + const paddedDomain = relayerUtils.padString(domainName, 255); + const domainFields = relayerUtils.bytes2Fields(paddedDomain); for (let idx = 0; idx < domainFields.length; ++idx) { expect(BigInt(domainFields[idx])).toEqual(witness[1 + idx]); } - const expectedPubKeyHash = emailWalletUtils.publicKeyHash(parsedEmail.publicKey); + const expectedPubKeyHash = relayerUtils.publicKeyHash(parsedEmail.publicKey); expect(BigInt(expectedPubKeyHash)).toEqual(witness[1 + domainFields.length]); - const expectedEmailNullifier = emailWalletUtils.emailNullifier(parsedEmail.signature); + const expectedEmailNullifier = relayerUtils.emailNullifier(parsedEmail.signature); expect(BigInt(expectedEmailNullifier)).toEqual(witness[1 + domainFields.length + 1]); const timestamp = 1696964295n; expect(timestamp).toEqual(witness[1 + domainFields.length + 2]); const maskedSubject = "Swap 1 ETH to DAI"; - const paddedMaskedSubject = emailWalletUtils.padString(maskedSubject, 605); - const maskedSubjectFields = emailWalletUtils.bytes2Fields(paddedMaskedSubject); + const paddedMaskedSubject = relayerUtils.padString(maskedSubject, 605); + const maskedSubjectFields = relayerUtils.bytes2Fields(paddedMaskedSubject); for (let idx = 0; idx < maskedSubjectFields.length; ++idx) { expect(BigInt(maskedSubjectFields[idx])).toEqual(witness[1 + domainFields.length + 3 + idx]); } const fromAddr = "suegamisora@gmail.com"; - const accountSalt = emailWalletUtils.accountSalt(fromAddr, accountCode); + const accountSalt = relayerUtils.accountSalt(fromAddr, accountCode); expect(BigInt(accountSalt)).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length]); expect(0n).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length + 1]); }); @@ -86,33 +87,33 @@ describe("Email Auth", () => { it("Verify a sent email whose from field has a dummy email address name", async () => { const emailFilePath = path.join(__dirname, "./emails/email_auth_test3.eml"); const emailRaw = readFileSync(emailFilePath, "utf8"); - const parsedEmail = await emailWalletUtils.parseEmail(emailRaw); + const parsedEmail = await relayerUtils.parseEmail(emailRaw); console.log(parsedEmail.canonicalizedHeader); - const accountCode = await emailWalletUtils.genAccountCode(); + const accountCode = await relayerUtils.genAccountCode(); const circuitInputs = await genEmailAuthInput(emailFilePath, accountCode); const circuit = await wasm_tester(path.join(__dirname, "../src/email_auth.circom"), option); const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); const domainName = "gmail.com"; - const paddedDomain = emailWalletUtils.padString(domainName, 255); - const domainFields = emailWalletUtils.bytes2Fields(paddedDomain); + const paddedDomain = relayerUtils.padString(domainName, 255); + const domainFields = relayerUtils.bytes2Fields(paddedDomain); for (let idx = 0; idx < domainFields.length; ++idx) { expect(BigInt(domainFields[idx])).toEqual(witness[1 + idx]); } - const expectedPubKeyHash = emailWalletUtils.publicKeyHash(parsedEmail.publicKey); + const expectedPubKeyHash = relayerUtils.publicKeyHash(parsedEmail.publicKey); expect(BigInt(expectedPubKeyHash)).toEqual(witness[1 + domainFields.length]); - const expectedEmailNullifier = emailWalletUtils.emailNullifier(parsedEmail.signature); + const expectedEmailNullifier = relayerUtils.emailNullifier(parsedEmail.signature); expect(BigInt(expectedEmailNullifier)).toEqual(witness[1 + domainFields.length + 1]); const timestamp = 1696965932n; expect(timestamp).toEqual(witness[1 + domainFields.length + 2]); const maskedSubject = "Send 1 ETH to "; - const paddedMaskedSubject = emailWalletUtils.padString(maskedSubject, 605); - const maskedSubjectFields = emailWalletUtils.bytes2Fields(paddedMaskedSubject); + const paddedMaskedSubject = relayerUtils.padString(maskedSubject, 605); + const maskedSubjectFields = relayerUtils.bytes2Fields(paddedMaskedSubject); for (let idx = 0; idx < maskedSubjectFields.length; ++idx) { expect(BigInt(maskedSubjectFields[idx])).toEqual(witness[1 + domainFields.length + 3 + idx]); } const fromAddr = "suegamisora@gmail.com"; - const accountSalt = emailWalletUtils.accountSalt(fromAddr, accountCode); + const accountSalt = relayerUtils.accountSalt(fromAddr, accountCode); expect(BigInt(accountSalt)).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length]); expect(0n).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length + 1]); }); @@ -120,33 +121,33 @@ describe("Email Auth", () => { it("Verify a sent email whose from field has a non-English name", async () => { const emailFilePath = path.join(__dirname, "./emails/email_auth_test4.eml"); const emailRaw = readFileSync(emailFilePath, "utf8"); - const parsedEmail = await emailWalletUtils.parseEmail(emailRaw); + const parsedEmail = await relayerUtils.parseEmail(emailRaw); console.log(parsedEmail.canonicalizedHeader); - const accountCode = await emailWalletUtils.genAccountCode(); + const accountCode = await relayerUtils.genAccountCode(); const circuitInputs = await genEmailAuthInput(emailFilePath, accountCode); const circuit = await wasm_tester(path.join(__dirname, "../src/email_auth.circom"), option); const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); const domainName = "gmail.com"; - const paddedDomain = emailWalletUtils.padString(domainName, 255); - const domainFields = emailWalletUtils.bytes2Fields(paddedDomain); + const paddedDomain = relayerUtils.padString(domainName, 255); + const domainFields = relayerUtils.bytes2Fields(paddedDomain); for (let idx = 0; idx < domainFields.length; ++idx) { expect(BigInt(domainFields[idx])).toEqual(witness[1 + idx]); } - const expectedPubKeyHash = emailWalletUtils.publicKeyHash(parsedEmail.publicKey); + const expectedPubKeyHash = relayerUtils.publicKeyHash(parsedEmail.publicKey); expect(BigInt(expectedPubKeyHash)).toEqual(witness[1 + domainFields.length]); - const expectedEmailNullifier = emailWalletUtils.emailNullifier(parsedEmail.signature); + const expectedEmailNullifier = relayerUtils.emailNullifier(parsedEmail.signature); expect(BigInt(expectedEmailNullifier)).toEqual(witness[1 + domainFields.length + 1]); const timestamp = 1696967028n; expect(timestamp).toEqual(witness[1 + domainFields.length + 2]); const maskedSubject = "Send 1 ETH to "; - const paddedMaskedSubject = emailWalletUtils.padString(maskedSubject, 605); - const maskedSubjectFields = emailWalletUtils.bytes2Fields(paddedMaskedSubject); + const paddedMaskedSubject = relayerUtils.padString(maskedSubject, 605); + const maskedSubjectFields = relayerUtils.bytes2Fields(paddedMaskedSubject); for (let idx = 0; idx < maskedSubjectFields.length; ++idx) { expect(BigInt(maskedSubjectFields[idx])).toEqual(witness[1 + domainFields.length + 3 + idx]); } const fromAddr = "suegamisora@gmail.com"; - const accountSalt = emailWalletUtils.accountSalt(fromAddr, accountCode); + const accountSalt = relayerUtils.accountSalt(fromAddr, accountCode); expect(BigInt(accountSalt)).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length]); expect(0n).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length + 1]); }); @@ -154,7 +155,7 @@ describe("Email Auth", () => { it("Verify a sent email whose subject has an email address and an invitation code", async () => { const emailFilePath = path.join(__dirname, "./emails/email_auth_test5.eml"); const emailRaw = readFileSync(emailFilePath, "utf8"); - const parsedEmail = await emailWalletUtils.parseEmail(emailRaw); + const parsedEmail = await relayerUtils.parseEmail(emailRaw); console.log(parsedEmail.canonicalizedHeader); const accountCode = "0x01eb9b204cc24c3baee11accc37d253a9c53e92b1a2cc07763475c135d575b76"; const circuitInputs = await genEmailAuthInput(emailFilePath, accountCode); @@ -162,25 +163,25 @@ describe("Email Auth", () => { const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); const domainName = "gmail.com"; - const paddedDomain = emailWalletUtils.padString(domainName, 255); - const domainFields = emailWalletUtils.bytes2Fields(paddedDomain); + const paddedDomain = relayerUtils.padString(domainName, 255); + const domainFields = relayerUtils.bytes2Fields(paddedDomain); for (let idx = 0; idx < domainFields.length; ++idx) { expect(BigInt(domainFields[idx])).toEqual(witness[1 + idx]); } - const expectedPubKeyHash = emailWalletUtils.publicKeyHash(parsedEmail.publicKey); + const expectedPubKeyHash = relayerUtils.publicKeyHash(parsedEmail.publicKey); expect(BigInt(expectedPubKeyHash)).toEqual(witness[1 + domainFields.length]); - const expectedEmailNullifier = emailWalletUtils.emailNullifier(parsedEmail.signature); + const expectedEmailNullifier = relayerUtils.emailNullifier(parsedEmail.signature); expect(BigInt(expectedEmailNullifier)).toEqual(witness[1 + domainFields.length + 1]); const timestamp = 1707866192n; expect(timestamp).toEqual(witness[1 + domainFields.length + 2]); const maskedSubject = "Send 0.12 ETH to "; - const paddedMaskedSubject = emailWalletUtils.padString(maskedSubject, 605); - const maskedSubjectFields = emailWalletUtils.bytes2Fields(paddedMaskedSubject); + const paddedMaskedSubject = relayerUtils.padString(maskedSubject, 605); + const maskedSubjectFields = relayerUtils.bytes2Fields(paddedMaskedSubject); for (let idx = 0; idx < maskedSubjectFields.length; ++idx) { expect(BigInt(maskedSubjectFields[idx])).toEqual(witness[1 + domainFields.length + 3 + idx]); } const fromAddr = "suegamisora@gmail.com"; - const accountSalt = emailWalletUtils.accountSalt(fromAddr, accountCode); + const accountSalt = relayerUtils.accountSalt(fromAddr, accountCode); expect(BigInt(accountSalt)).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length]); expect(1n).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length + 1]); }); @@ -188,32 +189,32 @@ describe("Email Auth", () => { it("Verify a sent email whose subject has an invitation code", async () => { const emailFilePath = path.join(__dirname, "./emails/email_auth_test6.eml"); const emailRaw = readFileSync(emailFilePath, "utf8"); - const parsedEmail = await emailWalletUtils.parseEmail(emailRaw); + const parsedEmail = await relayerUtils.parseEmail(emailRaw); const accountCode = "0x01eb9b204cc24c3baee11accc37d253a9c53e92b1a2cc07763475c135d575b76"; const circuitInputs = await genEmailAuthInput(emailFilePath, accountCode); const circuit = await wasm_tester(path.join(__dirname, "../src/email_auth.circom"), option); const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); const domainName = "gmail.com"; - const paddedDomain = emailWalletUtils.padString(domainName, 255); - const domainFields = emailWalletUtils.bytes2Fields(paddedDomain); + const paddedDomain = relayerUtils.padString(domainName, 255); + const domainFields = relayerUtils.bytes2Fields(paddedDomain); for (let idx = 0; idx < domainFields.length; ++idx) { expect(BigInt(domainFields[idx])).toEqual(witness[1 + idx]); } - const expectedPubKeyHash = emailWalletUtils.publicKeyHash(parsedEmail.publicKey); + const expectedPubKeyHash = relayerUtils.publicKeyHash(parsedEmail.publicKey); expect(BigInt(expectedPubKeyHash)).toEqual(witness[1 + domainFields.length]); - const expectedEmailNullifier = emailWalletUtils.emailNullifier(parsedEmail.signature); + const expectedEmailNullifier = relayerUtils.emailNullifier(parsedEmail.signature); expect(BigInt(expectedEmailNullifier)).toEqual(witness[1 + domainFields.length + 1]); const timestamp = 1711992080n; expect(timestamp).toEqual(witness[1 + domainFields.length + 2]); const maskedSubject = "Re: Accept guardian request for 0x04884491560f38342C56E26BDD0fEAbb68E2d2FC"; - const paddedMaskedSubject = emailWalletUtils.padString(maskedSubject, 605); - const maskedSubjectFields = emailWalletUtils.bytes2Fields(paddedMaskedSubject); + const paddedMaskedSubject = relayerUtils.padString(maskedSubject, 605); + const maskedSubjectFields = relayerUtils.bytes2Fields(paddedMaskedSubject); for (let idx = 0; idx < maskedSubjectFields.length; ++idx) { expect(BigInt(maskedSubjectFields[idx])).toEqual(witness[1 + domainFields.length + 3 + idx]); } const fromAddr = "suegamisora@gmail.com"; - const accountSalt = emailWalletUtils.accountSalt(fromAddr, accountCode); + const accountSalt = relayerUtils.accountSalt(fromAddr, accountCode); expect(BigInt(accountSalt)).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length]); expect(1n).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length + 1]); }); diff --git a/packages/circuits/tests/invitation_code_regex.test.ts b/packages/circuits/tests/invitation_code_regex.test.ts index de0f667..69d0387 100644 --- a/packages/circuits/tests/invitation_code_regex.test.ts +++ b/packages/circuits/tests/invitation_code_regex.test.ts @@ -1,7 +1,7 @@ const circom_tester = require("circom_tester"); const wasm_tester = circom_tester.wasm; import * as path from "path"; -const emailWalletUtils = require("../../utils"); +const relayerUtils = require("../../utils"); const option = { include: path.join(__dirname, "../../../node_modules") }; @@ -14,7 +14,7 @@ describe("Invitation Code Regex", () => { const codeStr = "Code 123abc"; // const prefixLen = "ACCOUNTKEY.0x".length; // const revealed = "123abc"; - const paddedStr = emailWalletUtils.padString(codeStr, 256); + const paddedStr = relayerUtils.padString(codeStr, 256); const circuitInputs = { msg: paddedStr, }; @@ -23,7 +23,7 @@ describe("Invitation Code Regex", () => { await circuit.checkConstraints(witness); // console.log(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = emailWalletUtils.extractInvitationCodeIdxes(codeStr)[0]; + const prefixIdxes = relayerUtils.extractInvitationCodeIdxes(codeStr)[0]; for (let idx = 0; idx < 256; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -37,7 +37,7 @@ describe("Invitation Code Regex", () => { const codeStr = "Swap 0.1 ETH to DAI code 123abc"; // const prefixLen = "sepolia+ACCOUNTKEY.0x".length; // const revealed = "123abc"; - const paddedStr = emailWalletUtils.padString(codeStr, 256); + const paddedStr = relayerUtils.padString(codeStr, 256); const circuitInputs = { msg: paddedStr, }; @@ -46,7 +46,7 @@ describe("Invitation Code Regex", () => { await circuit.checkConstraints(witness); // console.log(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = emailWalletUtils.extractInvitationCodeIdxes(codeStr)[0]; + const prefixIdxes = relayerUtils.extractInvitationCodeIdxes(codeStr)[0]; // const revealedStartIdx = emailWalletUtils.extractSubstrIdxes(codeStr, readFileSync(path.join(__dirname, "../src/regexes/invitation_code.json"), "utf8"))[0][0]; // console.log(emailWalletUtils.extractSubstrIdxes(codeStr, readFileSync(path.join(__dirname, "../src/regexes/invitation_code.json"), "utf8"))); for (let idx = 0; idx < 256; ++idx) { @@ -62,7 +62,7 @@ describe("Invitation Code Regex", () => { const codeStr = "Send 0.1 ETH to alice@gmail.com code 123abc"; // const prefixLen = "sepolia+ACCOUNTKEY.0x".length; // const revealed = "123abc"; - const paddedStr = emailWalletUtils.padString(codeStr, 256); + const paddedStr = relayerUtils.padString(codeStr, 256); const circuitInputs = { msg: paddedStr, }; @@ -71,7 +71,7 @@ describe("Invitation Code Regex", () => { await circuit.checkConstraints(witness); // console.log(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = emailWalletUtils.extractInvitationCodeIdxes(codeStr)[0]; + const prefixIdxes = relayerUtils.extractInvitationCodeIdxes(codeStr)[0]; // const revealedStartIdx = emailWalletUtils.extractSubstrIdxes(codeStr, readFileSync(path.join(__dirname, "../src/regexes/invitation_code.json"), "utf8"))[0][0]; // console.log(emailWalletUtils.extractSubstrIdxes(codeStr, readFileSync(path.join(__dirname, "../src/regexes/invitation_code.json"), "utf8"))); for (let idx = 0; idx < 256; ++idx) { @@ -87,7 +87,7 @@ describe("Invitation Code Regex", () => { const codeStr = "sepolia+code123456@sendeth.org"; // const prefixLen = "sepolia+ACCOUNTKEY.0x".length; // const revealed = "123abc"; - const paddedStr = emailWalletUtils.padString(codeStr, 256); + const paddedStr = relayerUtils.padString(codeStr, 256); const circuitInputs = { msg: paddedStr, }; @@ -96,7 +96,7 @@ describe("Invitation Code Regex", () => { await circuit.checkConstraints(witness); // console.log(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = emailWalletUtils.extractInvitationCodeIdxes(codeStr)[0]; + const prefixIdxes = relayerUtils.extractInvitationCodeIdxes(codeStr)[0]; // const revealedStartIdx = emailWalletUtils.extractSubstrIdxes(codeStr, readFileSync(path.join(__dirname, "../src/regexes/invitation_code.json"), "utf8"))[0][0]; // console.log(emailWalletUtils.extractSubstrIdxes(codeStr, readFileSync(path.join(__dirname, "../src/regexes/invitation_code.json"), "utf8"))); for (let idx = 0; idx < 256; ++idx) { @@ -112,7 +112,7 @@ describe("Invitation Code Regex", () => { const codeStr = "Swap 0.1 ETH to DAI code 123abc"; // const prefixLen = "sepolia+ACCOUNTKEY.0x".length; // const revealed = "123abc"; - const paddedStr = emailWalletUtils.padString(codeStr, 256); + const paddedStr = relayerUtils.padString(codeStr, 256); const circuitInputs = { msg: paddedStr, }; @@ -121,7 +121,7 @@ describe("Invitation Code Regex", () => { await circuit.checkConstraints(witness); // console.log(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = emailWalletUtils.extractInvitationCodeWithPrefixIdxes(codeStr)[0]; + const prefixIdxes = relayerUtils.extractInvitationCodeWithPrefixIdxes(codeStr)[0]; // const revealedStartIdx = emailWalletUtils.extractSubstrIdxes(codeStr, readFileSync(path.join(__dirname, "../src/regexes/invitation_code.json"), "utf8"))[0][0]; // console.log(emailWalletUtils.extractSubstrIdxes(codeStr, readFileSync(path.join(__dirname, "../src/regexes/invitation_code.json"), "utf8"))); for (let idx = 0; idx < 256; ++idx) { @@ -137,7 +137,7 @@ describe("Invitation Code Regex", () => { const codeStr = "Re: Accept guardian request for 0x04884491560f38342C56E26BDD0fEAbb68E2d2FC Code 01eb9b204cc24c3baee11accc37d253a9c53e92b1a2cc07763475c135d575b76"; // const prefixLen = "sepolia+ACCOUNTKEY.0x".length; // const revealed = "123abc"; - const paddedStr = emailWalletUtils.padString(codeStr, 256); + const paddedStr = relayerUtils.padString(codeStr, 256); const circuitInputs = { msg: paddedStr, }; @@ -146,7 +146,7 @@ describe("Invitation Code Regex", () => { await circuit.checkConstraints(witness); // console.log(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = emailWalletUtils.extractInvitationCodeWithPrefixIdxes(codeStr)[0]; + const prefixIdxes = relayerUtils.extractInvitationCodeWithPrefixIdxes(codeStr)[0]; // const revealedStartIdx = emailWalletUtils.extractSubstrIdxes(codeStr, readFileSync(path.join(__dirname, "../src/regexes/invitation_code.json"), "utf8"))[0][0]; // console.log(emailWalletUtils.extractSubstrIdxes(codeStr, readFileSync(path.join(__dirname, "../src/regexes/invitation_code.json"), "utf8"))); for (let idx = 0; idx < 256; ++idx) { diff --git a/packages/circuits/tests/recipient_enabled.test.ts b/packages/circuits/tests/recipient_enabled.test.ts index 70c3a7a..8329f07 100644 --- a/packages/circuits/tests/recipient_enabled.test.ts +++ b/packages/circuits/tests/recipient_enabled.test.ts @@ -6,7 +6,7 @@ const wasm_tester = circom_tester.wasm; import * as path from "path"; const p = "21888242871839275222246405745257275088548364400416034343698204186575808495617"; const field = new ff.F1Field(p); -const emailWalletUtils = require("../../utils"); +const relayerUtils = require("../../utils"); const option = { include: path.join(__dirname, "../../../node_modules") }; @@ -19,9 +19,9 @@ describe("Email Auth", () => { it("Verify a sent email whose subject has an email address", async () => { const emailFilePath = path.join(__dirname, "./emails/email_auth_test1.eml"); const emailRaw = readFileSync(emailFilePath, "utf8"); - const parsedEmail = await emailWalletUtils.parseEmail(emailRaw); + const parsedEmail = await relayerUtils.parseEmail(emailRaw); console.log(parsedEmail.canonicalizedHeader); - const accountCode = await emailWalletUtils.genAccountCode(); + const accountCode = await relayerUtils.genAccountCode(); const emailAuthInput = await genEmailAuthInput(emailFilePath, accountCode); const recipientInput = await genRecipientInput(emailFilePath); const circuitInputs = { @@ -32,30 +32,30 @@ describe("Email Auth", () => { const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); const domainName = "gmail.com"; - const paddedDomain = emailWalletUtils.padString(domainName, 255); - const domainFields = emailWalletUtils.bytes2Fields(paddedDomain); + const paddedDomain = relayerUtils.padString(domainName, 255); + const domainFields = relayerUtils.bytes2Fields(paddedDomain); for (let idx = 0; idx < domainFields.length; ++idx) { expect(BigInt(domainFields[idx])).toEqual(witness[1 + idx]); } - const expectedPubKeyHash = emailWalletUtils.publicKeyHash(parsedEmail.publicKey); + const expectedPubKeyHash = relayerUtils.publicKeyHash(parsedEmail.publicKey); expect(BigInt(expectedPubKeyHash)).toEqual(witness[1 + domainFields.length]); - const expectedEmailNullifier = emailWalletUtils.emailNullifier(parsedEmail.signature); + const expectedEmailNullifier = relayerUtils.emailNullifier(parsedEmail.signature); expect(BigInt(expectedEmailNullifier)).toEqual(witness[1 + domainFields.length + 1]); const timestamp = 1694989812n; expect(timestamp).toEqual(witness[1 + domainFields.length + 2]); const maskedSubject = "Send 0.1 ETH to "; - const paddedMaskedSubject = emailWalletUtils.padString(maskedSubject, 605); - const maskedSubjectFields = emailWalletUtils.bytes2Fields(paddedMaskedSubject); + const paddedMaskedSubject = relayerUtils.padString(maskedSubject, 605); + const maskedSubjectFields = relayerUtils.bytes2Fields(paddedMaskedSubject); for (let idx = 0; idx < maskedSubjectFields.length; ++idx) { expect(BigInt(maskedSubjectFields[idx])).toEqual(witness[1 + domainFields.length + 3 + idx]); } const fromAddr = "suegamisora@gmail.com"; - const accountSalt = emailWalletUtils.accountSalt(fromAddr, accountCode); + const accountSalt = relayerUtils.accountSalt(fromAddr, accountCode); expect(BigInt(accountSalt)).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length]); expect(0n).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length + 1]); expect(1n).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length + 2]); const recipientEmailAddr = "alice@gmail.com"; - const emailAddrCommit = emailWalletUtils.emailAddrCommitWithSignature(recipientEmailAddr, parsedEmail.signature); + const emailAddrCommit = relayerUtils.emailAddrCommitWithSignature(recipientEmailAddr, parsedEmail.signature); expect(BigInt(emailAddrCommit)).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length + 3]); }); @@ -63,9 +63,9 @@ describe("Email Auth", () => { it("Verify a sent email whose from field has a dummy email address name", async () => { const emailFilePath = path.join(__dirname, "./emails/email_auth_test3.eml"); const emailRaw = readFileSync(emailFilePath, "utf8"); - const parsedEmail = await emailWalletUtils.parseEmail(emailRaw); + const parsedEmail = await relayerUtils.parseEmail(emailRaw); console.log(parsedEmail.canonicalizedHeader); - const accountCode = await emailWalletUtils.genAccountCode(); + const accountCode = await relayerUtils.genAccountCode(); const emailAuthInput = await genEmailAuthInput(emailFilePath, accountCode); const recipientInput = await genRecipientInput(emailFilePath); const circuitInputs = { @@ -76,39 +76,39 @@ describe("Email Auth", () => { const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); const domainName = "gmail.com"; - const paddedDomain = emailWalletUtils.padString(domainName, 255); - const domainFields = emailWalletUtils.bytes2Fields(paddedDomain); + const paddedDomain = relayerUtils.padString(domainName, 255); + const domainFields = relayerUtils.bytes2Fields(paddedDomain); for (let idx = 0; idx < domainFields.length; ++idx) { expect(BigInt(domainFields[idx])).toEqual(witness[1 + idx]); } - const expectedPubKeyHash = emailWalletUtils.publicKeyHash(parsedEmail.publicKey); + const expectedPubKeyHash = relayerUtils.publicKeyHash(parsedEmail.publicKey); expect(BigInt(expectedPubKeyHash)).toEqual(witness[1 + domainFields.length]); - const expectedEmailNullifier = emailWalletUtils.emailNullifier(parsedEmail.signature); + const expectedEmailNullifier = relayerUtils.emailNullifier(parsedEmail.signature); expect(BigInt(expectedEmailNullifier)).toEqual(witness[1 + domainFields.length + 1]); const timestamp = 1696965932n; expect(timestamp).toEqual(witness[1 + domainFields.length + 2]); const maskedSubject = "Send 1 ETH to "; - const paddedMaskedSubject = emailWalletUtils.padString(maskedSubject, 605); - const maskedSubjectFields = emailWalletUtils.bytes2Fields(paddedMaskedSubject); + const paddedMaskedSubject = relayerUtils.padString(maskedSubject, 605); + const maskedSubjectFields = relayerUtils.bytes2Fields(paddedMaskedSubject); for (let idx = 0; idx < maskedSubjectFields.length; ++idx) { expect(BigInt(maskedSubjectFields[idx])).toEqual(witness[1 + domainFields.length + 3 + idx]); } const fromAddr = "suegamisora@gmail.com"; - const accountSalt = emailWalletUtils.accountSalt(fromAddr, accountCode); + const accountSalt = relayerUtils.accountSalt(fromAddr, accountCode); expect(BigInt(accountSalt)).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length]); expect(0n).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length + 1]); expect(1n).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length + 2]); const recipientEmailAddr = "bob@example.com"; - const emailAddrCommit = emailWalletUtils.emailAddrCommitWithSignature(recipientEmailAddr, parsedEmail.signature); + const emailAddrCommit = relayerUtils.emailAddrCommitWithSignature(recipientEmailAddr, parsedEmail.signature); expect(BigInt(emailAddrCommit)).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length + 3]); }); it("Verify a sent email whose from field has a non-English name", async () => { const emailFilePath = path.join(__dirname, "./emails/email_auth_test4.eml"); const emailRaw = readFileSync(emailFilePath, "utf8"); - const parsedEmail = await emailWalletUtils.parseEmail(emailRaw); + const parsedEmail = await relayerUtils.parseEmail(emailRaw); console.log(parsedEmail.canonicalizedHeader); - const accountCode = await emailWalletUtils.genAccountCode(); + const accountCode = await relayerUtils.genAccountCode(); const emailAuthInput = await genEmailAuthInput(emailFilePath, accountCode); const recipientInput = await genRecipientInput(emailFilePath); const circuitInputs = { @@ -119,37 +119,37 @@ describe("Email Auth", () => { const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); const domainName = "gmail.com"; - const paddedDomain = emailWalletUtils.padString(domainName, 255); - const domainFields = emailWalletUtils.bytes2Fields(paddedDomain); + const paddedDomain = relayerUtils.padString(domainName, 255); + const domainFields = relayerUtils.bytes2Fields(paddedDomain); for (let idx = 0; idx < domainFields.length; ++idx) { expect(BigInt(domainFields[idx])).toEqual(witness[1 + idx]); } - const expectedPubKeyHash = emailWalletUtils.publicKeyHash(parsedEmail.publicKey); + const expectedPubKeyHash = relayerUtils.publicKeyHash(parsedEmail.publicKey); expect(BigInt(expectedPubKeyHash)).toEqual(witness[1 + domainFields.length]); - const expectedEmailNullifier = emailWalletUtils.emailNullifier(parsedEmail.signature); + const expectedEmailNullifier = relayerUtils.emailNullifier(parsedEmail.signature); expect(BigInt(expectedEmailNullifier)).toEqual(witness[1 + domainFields.length + 1]); const timestamp = 1696967028n; expect(timestamp).toEqual(witness[1 + domainFields.length + 2]); const maskedSubject = "Send 1 ETH to "; - const paddedMaskedSubject = emailWalletUtils.padString(maskedSubject, 605); - const maskedSubjectFields = emailWalletUtils.bytes2Fields(paddedMaskedSubject); + const paddedMaskedSubject = relayerUtils.padString(maskedSubject, 605); + const maskedSubjectFields = relayerUtils.bytes2Fields(paddedMaskedSubject); for (let idx = 0; idx < maskedSubjectFields.length; ++idx) { expect(BigInt(maskedSubjectFields[idx])).toEqual(witness[1 + domainFields.length + 3 + idx]); } const fromAddr = "suegamisora@gmail.com"; - const accountSalt = emailWalletUtils.accountSalt(fromAddr, accountCode); + const accountSalt = relayerUtils.accountSalt(fromAddr, accountCode); expect(BigInt(accountSalt)).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length]); expect(0n).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length + 1]); expect(1n).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length + 2]); const recipientEmailAddr = "bob@example.com"; - const emailAddrCommit = emailWalletUtils.emailAddrCommitWithSignature(recipientEmailAddr, parsedEmail.signature); + const emailAddrCommit = relayerUtils.emailAddrCommitWithSignature(recipientEmailAddr, parsedEmail.signature); expect(BigInt(emailAddrCommit)).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length + 3]); }); it("Verify a sent email whose subject has an invitation code", async () => { const emailFilePath = path.join(__dirname, "./emails/email_auth_test5.eml"); const emailRaw = readFileSync(emailFilePath, "utf8"); - const parsedEmail = await emailWalletUtils.parseEmail(emailRaw); + const parsedEmail = await relayerUtils.parseEmail(emailRaw); console.log(parsedEmail.canonicalizedHeader); const accountCode = "0x01eb9b204cc24c3baee11accc37d253a9c53e92b1a2cc07763475c135d575b76"; const emailAuthInput = await genEmailAuthInput(emailFilePath, accountCode); @@ -162,30 +162,30 @@ describe("Email Auth", () => { const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); const domainName = "gmail.com"; - const paddedDomain = emailWalletUtils.padString(domainName, 255); - const domainFields = emailWalletUtils.bytes2Fields(paddedDomain); + const paddedDomain = relayerUtils.padString(domainName, 255); + const domainFields = relayerUtils.bytes2Fields(paddedDomain); for (let idx = 0; idx < domainFields.length; ++idx) { expect(BigInt(domainFields[idx])).toEqual(witness[1 + idx]); } - const expectedPubKeyHash = emailWalletUtils.publicKeyHash(parsedEmail.publicKey); + const expectedPubKeyHash = relayerUtils.publicKeyHash(parsedEmail.publicKey); expect(BigInt(expectedPubKeyHash)).toEqual(witness[1 + domainFields.length]); - const expectedEmailNullifier = emailWalletUtils.emailNullifier(parsedEmail.signature); + const expectedEmailNullifier = relayerUtils.emailNullifier(parsedEmail.signature); expect(BigInt(expectedEmailNullifier)).toEqual(witness[1 + domainFields.length + 1]); const timestamp = 1707866192n; expect(timestamp).toEqual(witness[1 + domainFields.length + 2]); const maskedSubject = "Send 0.12 ETH to "; - const paddedMaskedSubject = emailWalletUtils.padString(maskedSubject, 605); - const maskedSubjectFields = emailWalletUtils.bytes2Fields(paddedMaskedSubject); + const paddedMaskedSubject = relayerUtils.padString(maskedSubject, 605); + const maskedSubjectFields = relayerUtils.bytes2Fields(paddedMaskedSubject); for (let idx = 0; idx < maskedSubjectFields.length; ++idx) { expect(BigInt(maskedSubjectFields[idx])).toEqual(witness[1 + domainFields.length + 3 + idx]); } const fromAddr = "suegamisora@gmail.com"; - const accountSalt = emailWalletUtils.accountSalt(fromAddr, accountCode); + const accountSalt = relayerUtils.accountSalt(fromAddr, accountCode); expect(BigInt(accountSalt)).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length]); expect(1n).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length + 1]); expect(1n).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length + 2]); const recipientEmailAddr = "alice@gmail.com"; - const emailAddrCommit = emailWalletUtils.emailAddrCommitWithSignature(recipientEmailAddr, parsedEmail.signature); + const emailAddrCommit = relayerUtils.emailAddrCommitWithSignature(recipientEmailAddr, parsedEmail.signature); expect(BigInt(emailAddrCommit)).toEqual(witness[1 + domainFields.length + 3 + maskedSubjectFields.length + 3]); }); }); \ No newline at end of file diff --git a/packages/contracts/test/EmailAccountRecoery.t.sol b/packages/contracts/test/EmailAccountRecovery.t.sol similarity index 100% rename from packages/contracts/test/EmailAccountRecoery.t.sol rename to packages/contracts/test/EmailAccountRecovery.t.sol diff --git a/packages/prover/Dockerfile b/packages/prover/Dockerfile index 97de9e0..6a5b5a3 100644 --- a/packages/prover/Dockerfile +++ b/packages/prover/Dockerfile @@ -14,11 +14,12 @@ RUN npm install -g n RUN n 18 RUN npm install -g yarn snarkjs -RUN git clone https://github.com/zkemail/email-wallet.git -WORKDIR /email-wallet/packages/prover +RUN git clone https://github.com/zkemail/ether-email-auth.git +WORKDIR /ether-email-auth/packages/prover RUN pip install -r requirements.txt RUN cp ./circom_proofgen.sh /root WORKDIR /root +RUN ls /root # RUN mkdir params # RUN cp /email-wallet/packages/prover/params/account_creation.wasm /root/params # RUN cp /email-wallet/packages/prover/params/account_init.wasm /root/params @@ -29,6 +30,7 @@ RUN mkdir params WORKDIR /root/params RUN gdown "https://drive.google.com/uc?id=1ky3XyabnBFwcyBoWBimhoePT9kbFyEBR" RUN unzip params.zip +RUN mv params/* /root/params WORKDIR /root RUN ls params # RUN mv build params diff --git a/packages/prover/modal_server.py b/packages/prover/modal_server.py index a107fbf..c15f566 100644 --- a/packages/prover/modal_server.py +++ b/packages/prover/modal_server.py @@ -37,4 +37,5 @@ def prove_email_auth(): ) proof = gen_email_auth_proof(str(nonce), False, input) return jsonify(proof) + return app diff --git a/packages/relayer/Cargo.toml b/packages/relayer/Cargo.toml index 8a1322a..b7f7935 100644 --- a/packages/relayer/Cargo.toml +++ b/packages/relayer/Cargo.toml @@ -26,7 +26,7 @@ lettre = { version = "0.10.4", features = ["tokio1", "tokio1-native-tls"] } ethers = { version = "2.0.10", features = ["abigen"] } relayer-utils = { path = "../utils" } futures = "0.3.28" -sqlx = { version = "0.7", features = ["postgres", "runtime-tokio"] } +sqlx = { version = "=0.7.3", features = ["postgres", "runtime-tokio"] } regex = "1.10.2" axum = "0.6.20" rand = "0.8.5" diff --git a/packages/relayer/eml_templates/acceptance_request.html b/packages/relayer/eml_templates/acceptance_request.html index 2d75a1d..f350817 100644 --- a/packages/relayer/eml_templates/acceptance_request.html +++ b/packages/relayer/eml_templates/acceptance_request.html @@ -104,7 +104,7 @@ " > Email Wallet Email Wallet Email Wallet Email Wallet Email Wallet Email Wallet Email Wallet Email Wallet function_name!()); let subject = parsed_email.get_subject_all()?; - let account_key_str = db + let account_code_str = db .get_invitation_code_from_email_addr(&guardian_email_addr) .await? .ok_or(anyhow!( @@ -66,10 +66,10 @@ pub async fn handle_email( if let Ok(invitation_code) = parsed_email.get_invitation_code() { trace!(LOG, "Email with account code"; "func" => function_name!()); - if account_key_str != invitation_code { + if account_code_str != invitation_code { return Err(anyhow!( - "Stored account key is not equal to one in the email. Stored: {}, Email: {}", - account_key_str, + "Stored account code is not equal to one in the email. Stored: {}, Email: {}", + account_code_str, invitation_code )); } @@ -105,7 +105,11 @@ pub async fn handle_email( let template_id = keccak256(encode(&tokens)); - let circuit_input = generate_email_auth_input(&email, &invitation_code).await?; + let circuit_input = generate_email_auth_input( + &email, + &AccountCode::from(hex2field(&format!("0x{}", &account_code_str))?), + ) + .await?; let (proof, public_signals) = generate_proof(&circuit_input, "email_auth", PROVER_ADDRESS.get().unwrap()).await?; @@ -230,7 +234,11 @@ pub async fn handle_email( let template_id = keccak256(encode(&tokens)); - let circuit_input = generate_email_auth_input(&email, &account_key_str).await?; + let circuit_input = generate_email_auth_input( + &email, + &AccountCode::from(hex2field(&format!("0x{}", &account_code_str))?), + ) + .await?; let (proof, public_signals) = generate_proof(&circuit_input, "email_auth", PROVER_ADDRESS.get().unwrap()).await?; @@ -348,7 +356,11 @@ pub async fn handle_email( let template_id = keccak256(encode(&tokens)); - let circuit_input = generate_email_auth_input(&email, &account_key_str).await?; + let circuit_input = generate_email_auth_input( + &email, + &AccountCode::from(hex2field(&format!("0x{}", &account_code_str))?), + ) + .await?; let (proof, public_signals) = generate_proof(&circuit_input, "email_auth", PROVER_ADDRESS.get().unwrap()).await?; diff --git a/packages/relayer/src/database.rs b/packages/relayer/src/database.rs index 4faa610..d166331 100644 --- a/packages/relayer/src/database.rs +++ b/packages/relayer/src/database.rs @@ -42,7 +42,7 @@ impl Database { pub async fn setup_database(&self) -> Result<()> { sqlx::query( - "CREATE TABLE IF NOT EXISTS codes ( + "CREATE TABLE IF NOT EXISTS credentials ( account_code TEXT PRIMARY KEY, wallet_eth_addr TEXT NOT NULL, guardian_email_addr TEXT NOT NULL, @@ -72,7 +72,7 @@ impl Database { #[named] pub(crate) async fn get_credentials(&self, account_code: &str) -> Result> { - let row = sqlx::query("SELECT * FROM codes WHERE account_code = $1") + let row = sqlx::query("SELECT * FROM credentials WHERE account_code = $1") .bind(account_code) .fetch_optional(&self.db) .await?; @@ -97,7 +97,7 @@ impl Database { } pub(crate) async fn is_email_registered(&self, email_addr: &str) -> bool { - let row = sqlx::query("SELECT * FROM codes WHERE guardian_email_addr = $1") + let row = sqlx::query("SELECT * FROM credentials WHERE guardian_email_addr = $1") .bind(email_addr) .fetch_optional(&self.db) .await @@ -110,7 +110,7 @@ impl Database { } pub(crate) async fn update_credentials(&self, row: &Credentials) -> Result<()> { - let res = sqlx::query("UPDATE codes SET wallet_eth_addr = $1, guardian_email_addr = $2, is_set = $3 WHERE account_code = $4") + let res = sqlx::query("UPDATE credentials SET wallet_eth_addr = $1, guardian_email_addr = $2, is_set = $3 WHERE account_code = $4") .bind(&row.wallet_eth_addr) .bind(&row.guardian_email_addr) .bind(row.is_set) @@ -124,7 +124,7 @@ impl Database { pub(crate) async fn insert_credentials(&self, row: &Credentials) -> Result<()> { info!(LOG, "insert row {:?}", row; "func" => function_name!()); let row = sqlx::query( - "INSERT INTO codes (account_code, wallet_eth_addr, guardian_email_addr, is_set) VALUES ($1, $2, $3, $4) RETURNING *", + "INSERT INTO credentials (account_code, wallet_eth_addr, guardian_email_addr, is_set) VALUES ($1, $2, $3, $4) RETURNING *", ) .bind(&row.account_code) .bind(&row.wallet_eth_addr) @@ -141,7 +141,7 @@ impl Database { } pub async fn is_guardian_set(&self, wallet_eth_addr: &str, guardian_email_addr: &str) -> bool { - let row = sqlx::query("SELECT * FROM codes WHERE wallet_eth_addr = $1 AND guardian_email_addr = $2 AND is_set = TRUE") + let row = sqlx::query("SELECT * FROM credentials WHERE wallet_eth_addr = $1 AND guardian_email_addr = $2 AND is_set = TRUE") .bind(wallet_eth_addr) .bind(guardian_email_addr) .fetch_optional(&self.db) @@ -210,7 +210,7 @@ impl Database { &self, email_addr: &str, ) -> Result> { - let row = sqlx::query("SELECT * FROM codes WHERE guardian_email_addr = $1") + let row = sqlx::query("SELECT * FROM credentials WHERE guardian_email_addr = $1") .bind(email_addr) .fetch_optional(&self.db) .await?; diff --git a/packages/relayer/src/utils/utils.rs b/packages/relayer/src/utils/utils.rs index c304281..efacb69 100644 --- a/packages/relayer/src/utils/utils.rs +++ b/packages/relayer/src/utils/utils.rs @@ -4,9 +4,8 @@ use crate::*; use ethers::abi::Token; use ethers::types::{Bytes, U256}; -use relayer_utils::*; -use ::serde::{Deserialize, Serialize}; +use ::serde::Deserialize; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; @@ -28,20 +27,6 @@ pub struct ProofJson { pi_c: Vec, } -#[derive(Serialize, Deserialize)] -struct EmailAuthInput { - padded_header: Vec, - public_key: Vec, - signature: Vec, - padded_header_len: String, - account_code: String, - from_addr_idx: usize, - subject_idx: usize, - domain_idx: usize, - timestamp_idx: usize, - code_idx: usize, -} - impl ProofJson { pub fn to_eth_bytes(&self) -> Result { let pi_a = Token::FixedArray(vec![ @@ -66,49 +51,6 @@ impl ProofJson { } } -pub async fn generate_email_auth_input(email: &str, account_key: &str) -> Result { - let parsed_email = ParsedEmail::new_from_raw_email(&email).await?; - let circuit_input_params = circuit::CircuitInputParams::new( - vec![], - parsed_email.canonicalized_header.as_bytes().to_vec(), - "".to_string(), - vec_u8_to_bigint(parsed_email.clone().signature), - vec_u8_to_bigint(parsed_email.clone().public_key), - None, - Some(1024), - Some(64), - Some(true), - ); - let email_circuit_inputs = circuit::generate_circuit_inputs(circuit_input_params); - - let from_addr_idx = parsed_email.get_from_addr_idxes().unwrap(); - let domain_idx = parsed_email.get_email_domain_idxes().unwrap(); - let subject_idx = parsed_email.get_subject_all_idxes().unwrap(); - let code_idx = match parsed_email.get_invitation_code_idxes() { - Ok(indexes) => indexes.0, - Err(_) => { - info!(LOG, "No invitation code in header"); - 0 - } - }; - let timestamp_idx = parsed_email.get_timestamp_idxes().unwrap(); - - let email_auth_input = EmailAuthInput { - padded_header: email_circuit_inputs.in_padded, - public_key: email_circuit_inputs.pubkey, - signature: email_circuit_inputs.signature, - padded_header_len: email_circuit_inputs.in_len_padded_bytes, - account_code: format!("0x{}", account_key.to_string()), - from_addr_idx: from_addr_idx.0, - subject_idx: subject_idx.0, - domain_idx: domain_idx.0, - timestamp_idx: timestamp_idx.0, - code_idx, - }; - - Ok(serde_json::to_string(&email_auth_input)?) -} - #[named] pub async fn generate_proof( input: &str, diff --git a/packages/utils/Cargo.toml b/packages/utils/Cargo.toml index a18523e..3c5a705 100644 --- a/packages/utils/Cargo.toml +++ b/packages/utils/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "relayer-utils" version = "0.1.0" -authors = ["Sora Suegami"] +authors = ["Sora Suegami", "Aditya Bisht"] license = "MIT" edition = "2018" exclude = ["index.node"] @@ -43,3 +43,8 @@ slog = "2.7.0" sha2 = "0.10.8" ethers = "2.0.14" # wasm-bindgen = { version = "0.2.90", default-features = false } + +[dependencies.neon] +version = "0.10" +default-features = false +features = ["napi-6", "channel-api", "promise-api"] diff --git a/packages/utils/src/circuit.rs b/packages/utils/src/circuit.rs index 584bc6c..b57a83d 100644 --- a/packages/utils/src/circuit.rs +++ b/packages/utils/src/circuit.rs @@ -1,14 +1,29 @@ use std::cmp; +use crate::*; +use anyhow::Result; use num_bigint::BigInt; - -use crate::{generate_partial_sha, sha256_pad, to_circom_bigint_bytes, uint8_array_to_char_array}; +use serde::{Deserialize, Serialize}; pub const MAX_HEADER_PADDED_BYTES: usize = 1024; pub const MAX_BODY_PADDED_BYTES: usize = 1536; pub const CIRCOM_BIGINT_N: usize = 121; pub const CIRCOM_BIGINT_K: usize = 17; +#[derive(Serialize, Deserialize)] +pub struct EmailAuthInput { + padded_header: Vec, + public_key: Vec, + signature: Vec, + padded_header_len: String, + account_code: String, + from_addr_idx: usize, + subject_idx: usize, + domain_idx: usize, + timestamp_idx: usize, + code_idx: usize, +} + pub struct CircuitInput { pub in_padded: Vec, pub pubkey: Vec, @@ -104,3 +119,65 @@ pub fn generate_circuit_inputs(params: CircuitInputParams) -> CircuitInput { } circuit_input } + +pub async fn generate_email_auth_input(email: &str, account_code: &AccountCode) -> Result { + let parsed_email = ParsedEmail::new_from_raw_email(&email).await?; + let circuit_input_params = circuit::CircuitInputParams::new( + vec![], + parsed_email.canonicalized_header.as_bytes().to_vec(), + "".to_string(), + vec_u8_to_bigint(parsed_email.clone().signature), + vec_u8_to_bigint(parsed_email.clone().public_key), + None, + Some(1024), + Some(64), + Some(true), + ); + let email_circuit_inputs = circuit::generate_circuit_inputs(circuit_input_params); + + let from_addr_idx = parsed_email.get_from_addr_idxes().unwrap().0; + let domain_idx = parsed_email.get_email_domain_idxes().unwrap().0; + let subject_idx = parsed_email.get_subject_all_idxes().unwrap().0; + let code_idx = match parsed_email.get_invitation_code_idxes() { + Ok(indexes) => indexes.0, + Err(_) => 0, + }; + let timestamp_idx = parsed_email.get_timestamp_idxes().unwrap().0; + + let email_auth_input = EmailAuthInput { + padded_header: email_circuit_inputs.in_padded, + public_key: email_circuit_inputs.pubkey, + signature: email_circuit_inputs.signature, + padded_header_len: email_circuit_inputs.in_len_padded_bytes, + account_code: field2hex(&account_code.0), + from_addr_idx: from_addr_idx, + subject_idx: subject_idx, + domain_idx: domain_idx, + timestamp_idx: timestamp_idx, + code_idx, + }; + + Ok(serde_json::to_string(&email_auth_input)?) +} + +pub fn generate_email_auth_input_node(mut cx: FunctionContext) -> JsResult { + let email = cx.argument::(0)?.value(&mut cx); + let account_code = cx.argument::(1)?.value(&mut cx); + let account_code = AccountCode::from(hex2field_node(&mut cx, &account_code)?); + let channel = cx.channel(); + let (deferred, promise) = cx.promise(); + let rt = runtime(&mut cx)?; + + rt.spawn(async move { + let email_auth_input = generate_email_auth_input(&email, &account_code).await; + deferred.settle_with(&channel, move |mut cx| match email_auth_input { + Ok(email_auth_input) => { + let email_auth_input = cx.string(email_auth_input); + Ok(email_auth_input) + } + Err(err) => cx.throw_error(format!("Could not generate email auth input: {}", err)), + }); + }); + + Ok(promise) +} diff --git a/packages/utils/src/converters.rs b/packages/utils/src/converters.rs index 194833e..ca25eb5 100644 --- a/packages/utils/src/converters.rs +++ b/packages/utils/src/converters.rs @@ -4,6 +4,7 @@ use anyhow; use ethers::types::U256; use halo2curves::ff::PrimeField; use itertools::Itertools; +use neon::prelude::*; use num_bigint::BigInt; use poseidon_rs::*; @@ -191,3 +192,30 @@ pub fn hex_to_u256(hex: &str) -> Result { array.copy_from_slice(&bytes); Ok(U256::from_big_endian(&array)) } + +pub fn hex2field_node(cx: &mut FunctionContext, input_strs: &str) -> NeonResult { + match hex2field(input_strs) { + Ok(field) => Ok(field), + Err(e) => cx.throw_error(e.to_string()), + } +} + +pub fn bytes2fields_node(mut cx: FunctionContext) -> JsResult { + let input_str = cx.argument::(0)?; + let input_vec = input_str.to_vec(&mut cx)?; + let mut input_bytes = vec![]; + for val in input_vec.into_iter() { + let val = match val.downcast::(&mut cx) { + Ok(v) => v.value(&mut cx), + Err(e) => return cx.throw_error(e.to_string()), + }; + input_bytes.push(val as u8); + } + let fields = bytes2fields(&input_bytes); + let js_array = JsArray::new(&mut cx, fields.len() as u32); + for (i, field) in fields.into_iter().enumerate() { + let field = cx.string(&field2hex(&field)); + js_array.set(&mut cx, i as u32, field)?; + } + Ok(js_array) +} diff --git a/packages/utils/src/cryptos.rs b/packages/utils/src/cryptos.rs index 85346f9..e4bcdb4 100644 --- a/packages/utils/src/cryptos.rs +++ b/packages/utils/src/cryptos.rs @@ -3,27 +3,14 @@ use std::error::Error; use crate::converters::*; use halo2curves::ff::Field; +use neon::prelude::*; use poseidon_rs::*; -use rand_core::RngCore; +use rand_core::{OsRng, RngCore}; use rsa::sha2::{Digest, Sha256}; pub use zk_regex_apis::padding::pad_string; pub const MAX_EMAIL_ADDR_BYTES: usize = 256; -#[derive(Debug, Clone, Copy)] -pub struct RelayerRand(pub Fr); - -impl RelayerRand { - pub fn new(mut r: R) -> Self { - Self(Fr::random(&mut r)) - } - - pub fn new_from_seed(seed: &[u8]) -> Result { - let value = poseidon_bytes(seed)?; - Ok(Self(value)) - } -} - #[derive(Debug, Clone)] pub struct PaddedEmailAddr { pub padded_bytes: Vec, @@ -33,9 +20,7 @@ pub struct PaddedEmailAddr { impl PaddedEmailAddr { pub fn from_email_addr(email_addr: &str) -> Self { let email_addr_len = email_addr.as_bytes().len(); - // let mut padded_bytes = email_addr.as_bytes().to_vec(); - // padded_bytes.append(&mut vec![0; MAX_EMAIL_ADDR_BYTES - email_addr_len]); - let padded_bytes = pad_string(email_addr, MAX_EMAIL_ADDR_BYTES); + let padded_bytes = pad_string(email_addr, MAX_EMAIL_ADDR_BYTES).to_vec(); Self { padded_bytes, email_addr_len, @@ -46,10 +31,6 @@ impl PaddedEmailAddr { bytes2fields(&self.padded_bytes) } - // pub fn to_pointer(&self, relayer_rand: &RelayerRand) -> Result { - // self.to_commitment(&relayer_rand.0) - // } - pub fn to_commitment(&self, rand: &Fr) -> Result { let mut inputs = vec![*rand]; inputs.append(&mut self.to_email_addr_fields()); @@ -72,9 +53,9 @@ pub fn extract_rand_from_signature(signature: &[u8]) -> Result(rng: R) -> Self { Self(Fr::random(rng)) } @@ -82,41 +63,20 @@ impl AccountKey { pub fn from(elem: Fr) -> Self { Self(elem) } - - // pub fn to_commitment( - // &self, - // email_addr: &PaddedEmailAddr, - // relayer_rand_hash: &Fr, - // ) -> Result { - // let mut inputs = vec![self.0]; - // inputs.append(&mut email_addr.to_email_addr_fields()); - // inputs.push(*relayer_rand_hash); - // poseidon_fields(&inputs) - // } - - // pub fn to_wallet_salt(&self, account_key: AccountKey) -> Result { - // let field = poseidon_fields(&[self.0, Fr::zero()])?; - // Ok(WalletSalt(field)) - // } - - // pub fn to_ext_account_salt(&self) -> Result { - // let field = poseidon_fields(&[self.0.clone(), Fr::one()])?; - // Ok(ExtAccountSalt(field)) - // } } #[derive(Debug, Clone, Copy)] -pub struct WalletSalt(pub Fr); +pub struct AccountSalt(pub Fr); -impl WalletSalt { +impl AccountSalt { pub fn new( email_addr: &PaddedEmailAddr, - account_key: AccountKey, + account_code: AccountCode, ) -> Result { let mut inputs = email_addr.to_email_addr_fields(); - inputs.push(account_key.0); + inputs.push(account_code.0); inputs.push(Fr::zero()); - Ok(WalletSalt(poseidon_fields(&inputs)?)) + Ok(Self(poseidon_fields(&inputs)?)) } } @@ -133,6 +93,113 @@ pub fn email_nullifier(signature: &[u8]) -> Result { poseidon_fields(&[sign_rand]) } +pub fn pad_email_addr_node(mut cx: FunctionContext) -> JsResult { + let email_addr = cx.argument::(0)?.value(&mut cx); + let padded_email_addr = PaddedEmailAddr::from_email_addr(&email_addr); + let padded_email_addr_bytes = + JsArray::new(&mut cx, padded_email_addr.padded_bytes.len() as u32); + for (idx, byte) in padded_email_addr.padded_bytes.into_iter().enumerate() { + let js_byte = cx.number(byte); + padded_email_addr_bytes.set(&mut cx, idx as u32, js_byte)?; + } + Ok(padded_email_addr_bytes) +} + +pub fn gen_account_code_node(mut cx: FunctionContext) -> JsResult { + let mut rng = OsRng; + let account_code = AccountCode::new(&mut rng); + let account_code_str = field2hex(&account_code.0); + Ok(cx.string(account_code_str)) +} + +pub fn account_salt_node(mut cx: FunctionContext) -> JsResult { + let email_addr = cx.argument::(0)?.value(&mut cx); + let padded_email_addr = PaddedEmailAddr::from_email_addr(&email_addr); + let account_code_str = cx.argument::(1)?.value(&mut cx); + let account_code = hex2field_node(&mut cx, &account_code_str)?; + let account_salt = match AccountSalt::new(&padded_email_addr, AccountCode(account_code)) { + Ok(account_salt) => account_salt, + Err(e) => return cx.throw_error(&format!("WalletSalt failed: {}", e)), + }; + let account_salt_str = field2hex(&account_salt.0); + Ok(cx.string(account_salt_str)) +} + +pub fn public_key_hash_node(mut cx: FunctionContext) -> JsResult { + let public_key_n = cx.argument::(0)?.value(&mut cx); + let mut public_key_n = match hex::decode(&public_key_n[2..]) { + Ok(bytes) => bytes, + Err(e) => return cx.throw_error(&format!("public_key_n is an invalid hex string: {}", e)), + }; + public_key_n.reverse(); + let hash_field = match public_key_hash(&public_key_n) { + Ok(hash_field) => hash_field, + Err(e) => return cx.throw_error(&format!("public_key_hash failed: {}", e)), + }; + let hash_str = field2hex(&hash_field); + Ok(cx.string(hash_str)) +} + +pub fn email_nullifier_node(mut cx: FunctionContext) -> JsResult { + let signature = cx.argument::(0)?.value(&mut cx); + let mut signature = match hex::decode(&signature[2..]) { + Ok(bytes) => bytes, + Err(e) => return cx.throw_error(&format!("signature is an invalid hex string: {}", e)), + }; + signature.reverse(); + let nullifier = match email_nullifier(&signature) { + Ok(nullifier) => nullifier, + Err(e) => return cx.throw_error(&format!("email_nullifier failed: {}", e)), + }; + let nullifier_str = field2hex(&nullifier); + Ok(cx.string(nullifier_str)) +} + +pub fn email_addr_commit_node(mut cx: FunctionContext) -> JsResult { + let email_addr = cx.argument::(0)?.value(&mut cx); + let rand = cx.argument::(1)?.value(&mut cx); + let rand = hex2field_node(&mut cx, &rand)?; + let padded_email_addr = PaddedEmailAddr::from_email_addr(&email_addr); + let email_addr_commit = match padded_email_addr.to_commitment(&rand) { + Ok(fr) => fr, + Err(e) => return cx.throw_error(&format!("EmailAddrCommit failed: {}", e)), + }; + let email_addr_commit_str = field2hex(&email_addr_commit); + Ok(cx.string(email_addr_commit_str)) +} + +pub fn email_addr_commit_with_signature_node(mut cx: FunctionContext) -> JsResult { + let email_addr = cx.argument::(0)?.value(&mut cx); + let signature = cx.argument::(1)?.value(&mut cx); + let signature = match hex::decode(&signature[2..]) { + Ok(bytes) => bytes, + Err(e) => return cx.throw_error(&format!("signature is an invalid hex string: {}", e)), + }; + // signature.reverse(); + let padded_email_addr = PaddedEmailAddr::from_email_addr(&email_addr); + let email_addr_commit = match padded_email_addr.to_commitment_with_signature(&signature) { + Ok(fr) => fr, + Err(e) => return cx.throw_error(&format!("EmailAddrCommit failed: {}", e)), + }; + let email_addr_commit_str = field2hex(&email_addr_commit); + Ok(cx.string(email_addr_commit_str)) +} + +pub fn extract_rand_from_signature_node(mut cx: FunctionContext) -> JsResult { + let signature = cx.argument::(0)?.value(&mut cx); + let signature = match hex::decode(&signature[2..]) { + Ok(bytes) => bytes, + Err(e) => return cx.throw_error(&format!("signature is an invalid hex string: {}", e)), + }; + // signature.reverse(); + let rand = match extract_rand_from_signature(&signature) { + Ok(fr) => fr, + Err(e) => return cx.throw_error(&format!("extract_rand_from_signature failed: {}", e)), + }; + let rand_str = field2hex(&rand); + Ok(cx.string(rand_str)) +} + pub fn sha256_pad(mut data: Vec, max_sha_bytes: usize) -> (Vec, usize) { let length_bits = data.len() * 8; // Convert length from bytes to bits let length_in_bytes = int64_to_bytes(length_bits as u64); diff --git a/packages/utils/src/lib.rs b/packages/utils/src/lib.rs index 95a12be..fc9bd13 100644 --- a/packages/utils/src/lib.rs +++ b/packages/utils/src/lib.rs @@ -2,8 +2,57 @@ pub mod circuit; pub mod converters; pub mod cryptos; pub mod parse_email; -use converters::*; -use cryptos::*; +pub mod regex; +pub mod statics; +pub use circuit::*; +pub(crate) use converters::*; +pub(crate) use cryptos::*; +pub(crate) use neon::prelude::*; +pub(crate) use parse_email::*; pub use poseidon_rs::*; +pub(crate) use regex::*; +pub(crate) use statics::*; pub use zk_regex_apis::extract_substrs::*; pub use zk_regex_apis::padding::*; + +#[neon::main] +fn main(mut cx: ModuleContext) -> NeonResult<()> { + cx.export_function("genEmailAuthInput", generate_email_auth_input_node)?; + cx.export_function("parseEmail", parse_email_node)?; + cx.export_function("padString", pad_string_node)?; + cx.export_function("bytes2Fields", bytes2fields_node)?; + cx.export_function("extractSubstrIdxes", extract_substr_idxes_node)?; + cx.export_function("extractEmailAddrIdxes", extract_email_addr_idxes_node)?; + cx.export_function("extractEmailDomainIdxes", extract_email_domain_idxes_node)?; + cx.export_function( + "extractEmailAddrWithNameIdxes", + extract_email_addr_with_name_idxes_node, + )?; + cx.export_function("extractFromAllIdxes", extract_from_all_idxes_node)?; + cx.export_function("extractFromAddrIdxes", extract_from_addr_idxes_node)?; + cx.export_function("extractSubjectAllIdxes", extract_subject_all_idxes_node)?; + cx.export_function("extractBodyHashIdxes", extract_body_hash_idxes_node)?; + cx.export_function("extractTimestampIdxes", extract_timestamp_idxes_node)?; + cx.export_function("extractTimestampInt", extract_timestamp_int_node)?; + cx.export_function("extractMessageIdIdxes", extract_message_id_idxes_node)?; + cx.export_function( + "extractInvitationCodeIdxes", + extract_invitation_code_idxes_node, + )?; + cx.export_function( + "extractInvitationCodeWithPrefixIdxes", + extract_invitation_code_with_prefix_idxes_node, + )?; + cx.export_function("padEmailAddr", pad_email_addr_node)?; + cx.export_function("genAccountCode", gen_account_code_node)?; + cx.export_function("accountSalt", account_salt_node)?; + cx.export_function("publicKeyHash", public_key_hash_node)?; + cx.export_function("emailNullifier", email_nullifier_node)?; + cx.export_function("emailAddrCommit", email_addr_commit_node)?; + cx.export_function( + "emailAddrCommitWithSignature", + email_addr_commit_with_signature_node, + )?; + cx.export_function("extractRandFromSignature", extract_rand_from_signature_node)?; + Ok(()) +} diff --git a/packages/utils/src/parse_email.rs b/packages/utils/src/parse_email.rs index e487247..ef06dc4 100644 --- a/packages/utils/src/parse_email.rs +++ b/packages/utils/src/parse_email.rs @@ -4,10 +4,12 @@ use anyhow::Result; use hex; use cfdkim::{canonicalize_signed_email, resolve_public_key}; +use neon::prelude::*; use rsa::traits::PublicKeyParts; - use serde::{Deserialize, Serialize}; use zk_regex_apis::extract_substrs::*; + +use crate::runtime; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ParsedEmail { pub canonicalized_header: String, @@ -139,3 +141,142 @@ impl ParsedEmail { Ok(str) } } + +pub fn parse_email_node(mut cx: FunctionContext) -> JsResult { + let raw_email = cx.argument::(0)?.value(&mut cx); + let channel = cx.channel(); + let (deferred, promise) = cx.promise(); + let rt = runtime(&mut cx)?; + + rt.spawn(async move { + let parsed_email = ParsedEmail::new_from_raw_email(&raw_email).await; + deferred.settle_with(&channel, move |mut cx| { + match parsed_email { + // Resolve the promise with the release date + Ok(parsed_email) => { + let signature_str = parsed_email.signature_string(); + let public_key_str = parsed_email.public_key_string(); + let obj = cx.empty_object(); + let canonicalized_header = cx.string(parsed_email.canonicalized_header); + obj.set(&mut cx, "canonicalizedHeader", canonicalized_header)?; + + let signature = cx.string(&signature_str); + obj.set(&mut cx, "signature", signature)?; + + let public_key = cx.string(&public_key_str); + obj.set(&mut cx, "publicKey", public_key)?; + + Ok(obj) + } + + // Reject the `Promise` if the version could not be found + Err(err) => cx.throw_error(format!("Could not parse the raw email: {}", err)), + } + }); + }); + + Ok(promise) +} + +pub fn extract_invitation_code_idxes_node(mut cx: FunctionContext) -> JsResult { + let input_str = cx.argument::(0)?.value(&mut cx); + let regex_config = serde_json::from_str(include_str!( + "../../circuits/src/regexes/invitation_code.json" + )) + .unwrap(); + let substr_idxes = match extract_substr_idxes(&input_str, ®ex_config) { + Ok(substr_idxes) => substr_idxes, + Err(e) => return cx.throw_error(e.to_string()), + }; + let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); + for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { + let start_end_array = JsArray::new(&mut cx, 2u32); + let start_idx = cx.number(*start_idx as f64); + start_end_array.set(&mut cx, 0, start_idx)?; + let end_idx = cx.number(*end_idx as f64); + start_end_array.set(&mut cx, 1, end_idx)?; + js_array.set(&mut cx, i as u32, start_end_array)?; + } + Ok(js_array) +} + +pub fn extract_invitation_code_with_prefix_idxes_node( + mut cx: FunctionContext, +) -> JsResult { + let input_str = cx.argument::(0)?.value(&mut cx); + let regex_config = serde_json::from_str(include_str!( + "../../circuits/src/regexes/invitation_code_with_prefix.json" + )) + .unwrap(); + let substr_idxes = match extract_substr_idxes(&input_str, ®ex_config) { + Ok(substr_idxes) => substr_idxes, + Err(e) => return cx.throw_error(e.to_string()), + }; + let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); + for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { + let start_end_array = JsArray::new(&mut cx, 2u32); + let start_idx = cx.number(*start_idx as f64); + start_end_array.set(&mut cx, 0, start_idx)?; + let end_idx = cx.number(*end_idx as f64); + start_end_array.set(&mut cx, 1, end_idx)?; + js_array.set(&mut cx, i as u32, start_end_array)?; + } + Ok(js_array) +} + +pub fn extract_timestamp_int_node(mut cx: FunctionContext) -> JsResult { + let input_str = cx.argument::(0)?.value(&mut cx); + let substr_idxes = match extract_timestamp_idxes(&input_str) { + Ok(substr_idxes) => substr_idxes, + Err(e) => return cx.throw_error(e.to_string()), + }; + let timestamp_str = &input_str[substr_idxes[0].0..substr_idxes[0].1]; + let timestamp_int = match timestamp_str.parse::() { + Ok(timestamp_int) => timestamp_int, + Err(e) => return cx.throw_error(e.to_string()), + }; + let timestamp_int = cx.number(timestamp_int as f64); + Ok(timestamp_int) +} + +#[cfg(test)] +mod test { + use super::*; + + #[tokio::test] + async fn test_extractions_from_email1() { + let raw_email = include_str!("../../circuits/tests/emails/email_auth_test1.eml"); + let parsed_email = ParsedEmail::new_from_raw_email(raw_email).await.unwrap(); + let from_addr = parsed_email.get_from_addr().unwrap(); + assert_eq!(from_addr, "suegamisora@gmail.com"); + let to_addr = parsed_email.get_to_addr().unwrap(); + assert_eq!(to_addr, "emailwallet.relayer@gmail.com"); + let email_domain = parsed_email.get_email_domain().unwrap(); + assert_eq!(email_domain, "gmail.com"); + let subject_all = parsed_email.get_subject_all().unwrap(); + assert_eq!(subject_all, "Send 0.1 ETH to alice@gmail.com"); + let timestamp = parsed_email.get_timestamp().unwrap(); + assert_eq!(timestamp, 1694989812); + let recipient = parsed_email.get_email_addr_in_subject().unwrap(); + assert_eq!(recipient, "alice@gmail.com"); + } + + #[tokio::test] + async fn test_extractions_from_email2() { + let raw_email = include_str!("../../circuits/tests/emails/email_auth_test5.eml"); + let parsed_email = ParsedEmail::new_from_raw_email(raw_email).await.unwrap(); + let from_addr = parsed_email.get_from_addr().unwrap(); + assert_eq!(from_addr, "suegamisora@gmail.com"); + let to_addr = parsed_email.get_to_addr().unwrap(); + assert_eq!(to_addr, "emailwallet.relayer@gmail.com"); + let email_domain = parsed_email.get_email_domain().unwrap(); + assert_eq!(email_domain, "gmail.com"); + let timestamp = parsed_email.get_timestamp().unwrap(); + assert_eq!(timestamp, 1707866192); + let invitation_code = parsed_email.get_invitation_code().unwrap(); + assert_eq!( + invitation_code, + "01eb9b204cc24c3baee11accc37d253a9c53e92b1a2cc07763475c135d575b76" + ); + } +} diff --git a/packages/utils/src/regex.rs b/packages/utils/src/regex.rs new file mode 100644 index 0000000..b9806e3 --- /dev/null +++ b/packages/utils/src/regex.rs @@ -0,0 +1,243 @@ +use neon::prelude::*; +pub use zk_regex_apis::extract_substrs::*; +pub use zk_regex_apis::padding::*; + +pub fn pad_string_node(mut cx: FunctionContext) -> JsResult { + let string = cx.argument::(0)?.value(&mut cx); + let padded_bytes_size = cx.argument::(1)?.value(&mut cx) as usize; + let padded_bytes = pad_string(&string, padded_bytes_size); + let padded_array = JsArray::new(&mut cx, padded_bytes_size as u32); + for (idx, byte) in padded_bytes.into_iter().enumerate() { + let js_byte = cx.number(byte); + padded_array.set(&mut cx, idx as u32, js_byte)?; + } + Ok(padded_array) +} + +pub fn extract_substr_idxes_node(mut cx: FunctionContext) -> JsResult { + let input_str = cx.argument::(0)?.value(&mut cx); + let regex_config_str = cx.argument::(1)?.value(&mut cx); + let regex_config = match serde_json::from_str::(®ex_config_str) { + Ok(regex_config) => regex_config, + Err(e) => return cx.throw_error(e.to_string()), + }; + let substr_idxes = match extract_substr_idxes(&input_str, ®ex_config) { + Ok(substr_idxes) => substr_idxes, + Err(e) => return cx.throw_error(e.to_string()), + }; + let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); + for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { + let start_end_array = JsArray::new(&mut cx, 2u32); + let start_idx = cx.number(*start_idx as f64); + start_end_array.set(&mut cx, 0, start_idx)?; + let end_idx = cx.number(*end_idx as f64); + start_end_array.set(&mut cx, 1, end_idx)?; + js_array.set(&mut cx, i as u32, start_end_array)?; + } + Ok(js_array) +} + +pub fn extract_email_addr_idxes_node(mut cx: FunctionContext) -> JsResult { + let input_str = cx.argument::(0)?.value(&mut cx); + let substr_idxes = match extract_email_addr_idxes(&input_str) { + Ok(substr_idxes) => substr_idxes, + Err(e) => return cx.throw_error(e.to_string()), + }; + let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); + for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { + let start_end_array = JsArray::new(&mut cx, 2u32); + let start_idx = cx.number(*start_idx as f64); + start_end_array.set(&mut cx, 0, start_idx)?; + let end_idx = cx.number(*end_idx as f64); + start_end_array.set(&mut cx, 1, end_idx)?; + js_array.set(&mut cx, i as u32, start_end_array)?; + } + Ok(js_array) +} + +pub fn extract_email_domain_idxes_node(mut cx: FunctionContext) -> JsResult { + let input_str = cx.argument::(0)?.value(&mut cx); + let substr_idxes = match extract_email_domain_idxes(&input_str) { + Ok(substr_idxes) => substr_idxes, + Err(e) => return cx.throw_error(e.to_string()), + }; + let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); + for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { + let start_end_array = JsArray::new(&mut cx, 2u32); + let start_idx = cx.number(*start_idx as f64); + start_end_array.set(&mut cx, 0, start_idx)?; + let end_idx = cx.number(*end_idx as f64); + start_end_array.set(&mut cx, 1, end_idx)?; + js_array.set(&mut cx, i as u32, start_end_array)?; + } + Ok(js_array) +} + +pub fn extract_email_addr_with_name_idxes_node(mut cx: FunctionContext) -> JsResult { + let input_str = cx.argument::(0)?.value(&mut cx); + let substr_idxes = match extract_email_addr_with_name_idxes(&input_str) { + Ok(substr_idxes) => substr_idxes, + Err(e) => return cx.throw_error(e.to_string()), + }; + let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); + for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { + let start_end_array = JsArray::new(&mut cx, 2u32); + let start_idx = cx.number(*start_idx as f64); + start_end_array.set(&mut cx, 0, start_idx)?; + let end_idx = cx.number(*end_idx as f64); + start_end_array.set(&mut cx, 1, end_idx)?; + js_array.set(&mut cx, i as u32, start_end_array)?; + } + Ok(js_array) +} + +pub fn extract_from_all_idxes_node(mut cx: FunctionContext) -> JsResult { + let input_str = cx.argument::(0)?.value(&mut cx); + let substr_idxes = match extract_from_all_idxes(&input_str) { + Ok(substr_idxes) => substr_idxes, + Err(e) => return cx.throw_error(e.to_string()), + }; + let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); + for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { + let start_end_array = JsArray::new(&mut cx, 2u32); + let start_idx = cx.number(*start_idx as f64); + start_end_array.set(&mut cx, 0, start_idx)?; + let end_idx = cx.number(*end_idx as f64); + start_end_array.set(&mut cx, 1, end_idx)?; + js_array.set(&mut cx, i as u32, start_end_array)?; + } + Ok(js_array) +} + +pub fn extract_from_addr_idxes_node(mut cx: FunctionContext) -> JsResult { + let input_str = cx.argument::(0)?.value(&mut cx); + let substr_idxes = match extract_from_addr_idxes(&input_str) { + Ok(substr_idxes) => substr_idxes, + Err(e) => return cx.throw_error(e.to_string()), + }; + let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); + for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { + let start_end_array = JsArray::new(&mut cx, 2u32); + let start_idx = cx.number(*start_idx as f64); + start_end_array.set(&mut cx, 0, start_idx)?; + let end_idx = cx.number(*end_idx as f64); + start_end_array.set(&mut cx, 1, end_idx)?; + js_array.set(&mut cx, i as u32, start_end_array)?; + } + Ok(js_array) +} + +pub fn extract_to_all_idxes_node(mut cx: FunctionContext) -> JsResult { + let input_str = cx.argument::(0)?.value(&mut cx); + + let substr_idxes = match extract_to_all_idxes(&input_str) { + Ok(substr_idxes) => substr_idxes, + Err(e) => return cx.throw_error(e.to_string()), + }; + + let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); + + for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { + let start_end_array = JsArray::new(&mut cx, 2u32); + + let start_idx = cx.number(*start_idx as f64); + start_end_array.set(&mut cx, 0, start_idx)?; + + let end_idx = cx.number(*end_idx as f64); + start_end_array.set(&mut cx, 1, end_idx)?; + + js_array.set(&mut cx, i as u32, start_end_array)?; + } + + Ok(js_array) +} + +pub fn extract_to_addr_idxes_node(mut cx: FunctionContext) -> JsResult { + let input_str = cx.argument::(0)?.value(&mut cx); + let substr_idxes = match extract_to_addr_idxes(&input_str) { + Ok(substr_idxes) => substr_idxes, + Err(e) => return cx.throw_error(e.to_string()), + }; + let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); + for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { + let start_end_array = JsArray::new(&mut cx, 2u32); + let start_idx = cx.number(*start_idx as f64); + start_end_array.set(&mut cx, 0, start_idx)?; + let end_idx = cx.number(*end_idx as f64); + start_end_array.set(&mut cx, 1, end_idx)?; + js_array.set(&mut cx, i as u32, start_end_array)?; + } + Ok(js_array) +} + +pub fn extract_subject_all_idxes_node(mut cx: FunctionContext) -> JsResult { + let input_str = cx.argument::(0)?.value(&mut cx); + let substr_idxes = match extract_subject_all_idxes(&input_str) { + Ok(substr_idxes) => substr_idxes, + Err(e) => return cx.throw_error(e.to_string()), + }; + let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); + for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { + let start_end_array = JsArray::new(&mut cx, 2u32); + let start_idx = cx.number(*start_idx as f64); + start_end_array.set(&mut cx, 0, start_idx)?; + let end_idx = cx.number(*end_idx as f64); + start_end_array.set(&mut cx, 1, end_idx)?; + js_array.set(&mut cx, i as u32, start_end_array)?; + } + Ok(js_array) +} + +pub fn extract_body_hash_idxes_node(mut cx: FunctionContext) -> JsResult { + let input_str = cx.argument::(0)?.value(&mut cx); + let substr_idxes = match extract_body_hash_idxes(&input_str) { + Ok(substr_idxes) => substr_idxes, + Err(e) => return cx.throw_error(e.to_string()), + }; + let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); + for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { + let start_end_array = JsArray::new(&mut cx, 2u32); + let start_idx = cx.number(*start_idx as f64); + start_end_array.set(&mut cx, 0, start_idx)?; + let end_idx = cx.number(*end_idx as f64); + start_end_array.set(&mut cx, 1, end_idx)?; + js_array.set(&mut cx, i as u32, start_end_array)?; + } + Ok(js_array) +} + +pub fn extract_timestamp_idxes_node(mut cx: FunctionContext) -> JsResult { + let input_str = cx.argument::(0)?.value(&mut cx); + let substr_idxes = match extract_timestamp_idxes(&input_str) { + Ok(substr_idxes) => substr_idxes, + Err(e) => return cx.throw_error(e.to_string()), + }; + let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); + for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { + let start_end_array = JsArray::new(&mut cx, 2u32); + let start_idx = cx.number(*start_idx as f64); + start_end_array.set(&mut cx, 0, start_idx)?; + let end_idx = cx.number(*end_idx as f64); + start_end_array.set(&mut cx, 1, end_idx)?; + js_array.set(&mut cx, i as u32, start_end_array)?; + } + Ok(js_array) +} + +pub fn extract_message_id_idxes_node(mut cx: FunctionContext) -> JsResult { + let input_str = cx.argument::(0)?.value(&mut cx); + let substr_idxes = match extract_message_id_idxes(&input_str) { + Ok(substr_idxes) => substr_idxes, + Err(e) => return cx.throw_error(e.to_string()), + }; + let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); + for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { + let start_end_array = JsArray::new(&mut cx, 2u32); + let start_idx = cx.number(*start_idx as f64); + start_end_array.set(&mut cx, 0, start_idx)?; + let end_idx = cx.number(*end_idx as f64); + start_end_array.set(&mut cx, 1, end_idx)?; + js_array.set(&mut cx, i as u32, start_end_array)?; + } + Ok(js_array) +} diff --git a/packages/utils/src/statics.rs b/packages/utils/src/statics.rs new file mode 100644 index 0000000..fe6c6a0 --- /dev/null +++ b/packages/utils/src/statics.rs @@ -0,0 +1,9 @@ +use neon::prelude::*; +use once_cell::sync::OnceCell; +use tokio::runtime::Runtime; + +pub fn runtime<'a, C: Context<'a>>(cx: &mut C) -> NeonResult<&'static Runtime> { + static RUNTIME: OnceCell = OnceCell::new(); + + RUNTIME.get_or_try_init(|| Runtime::new().or_else(|err| cx.throw_error(err.to_string()))) +}