feat: remove circuit dependent logic from circuit utils

This commit is contained in:
zkfriendly
2025-08-22 12:35:34 +02:00
parent e11b7801ec
commit 60e2711ab6
4 changed files with 12 additions and 166 deletions

View File

@@ -115,20 +115,6 @@ library CircuitUtils {
return fields;
}
/**
* @notice Packs a public key (as bytes) into field elements
* @param pubKeyBytes The public key bytes (encoded as uint256[17])
* @return fields The packed field elements
*/
function packPubKey(bytes memory pubKeyBytes) internal pure returns (uint256[] memory fields) {
uint256[17] memory pubKeyChunks = abi.decode(pubKeyBytes, (uint256[17]));
fields = new uint256[](17);
for (uint256 i = 0; i < 17; i++) {
fields[i] = pubKeyChunks[i];
}
return fields;
}
/**
* @notice Unpacks field elements back to bytes
* @param _pucSignals Array of public signals
@@ -223,108 +209,22 @@ library CircuitUtils {
return pubSignals[startIndex] == 1;
}
/**
* @notice Extracts miscellaneous data from public signals
* @param pubSignals Array of public signals
* @param startIndex Starting index of miscellaneous data
* @return miscellaneousData The miscellaneous data
*/
function unpackMiscellaneousData(
uint256[] calldata pubSignals,
uint256 startIndex
)
internal
pure
returns (bytes memory miscellaneousData)
{
uint256[17] memory pubKeyChunks;
for (uint256 i = 0; i < pubKeyChunks.length; i++) {
pubKeyChunks[i] = pubSignals[startIndex + i];
}
miscellaneousData = abi.encode(pubKeyChunks);
return miscellaneousData;
}
/**
* @notice Extracts the parts of an email address, replacing '@' with '$' and splitting by '.'
* @param email The email address to process
* @return The parts of the email address as a string array
*/
function extractEmailParts(string memory email) internal pure returns (string[] memory) {
bytes memory emailBytes = bytes(email);
bytes memory modifiedEmail = new bytes(emailBytes.length);
uint256 atIndex = 0;
for (uint256 i = 0; i < emailBytes.length; i++) {
if (emailBytes[i] == "@") {
modifiedEmail[i] = "$";
atIndex = i;
} else {
modifiedEmail[i] = emailBytes[i];
}
}
return _splitString(string(modifiedEmail), ".");
}
/**
* @notice Verifies that the email parts are dot separated and match the claimed email
* @param emailParts The parts of the email address dot separated
* @param email The complete email address
* @return True if the email parts are dot separated and match the claimed email, false otherwise
*/
function verifyEmailParts(string[] memory emailParts, string memory email) internal pure returns (bool) {
string memory composedEmail = "";
for (uint256 i = 0; i < emailParts.length; i++) {
composedEmail = string.concat(composedEmail, emailParts[i]);
if (i < emailParts.length - 1) {
composedEmail = string.concat(composedEmail, ".");
}
}
bytes memory emailBytes = bytes(email);
bytes memory composedEmailBytes = bytes(composedEmail);
// Ensure composedEmail and emailBytes have the same length
if (composedEmailBytes.length != emailBytes.length) {
return false;
}
// check if the email parts are dot separated and match the claimed email
// note since @ sign is not in ens encoding valid char set, we are arbitrarily replacing it with a $
for (uint256 i = 0; i < emailBytes.length; i++) {
bytes1 currentByte = emailBytes[i];
if (currentByte == "@") {
if (composedEmailBytes[i] != "$") {
return false;
}
} else if (currentByte != composedEmailBytes[i]) {
return false;
}
}
return true;
}
/**
* @notice Flattens multiple arrays of field elements into a single array of length 60
* @param inputs The arrays of field elements to flatten
* @return out The flattened array of length 60
*/
function flattenFields(uint256[][] memory inputs) internal pure returns (uint256[60] memory out) {
function flattenFields(uint256[][] memory inputs, uint256 outLength) internal pure returns (uint256[] memory out) {
out = new uint256[](outLength);
uint256 k = 0;
for (uint256 i = 0; i < inputs.length; i++) {
uint256[] memory arr = inputs[i];
for (uint256 j = 0; j < arr.length; j++) {
if (k >= 60) revert InvalidPubSignalsLength();
if (k >= outLength) revert InvalidPubSignalsLength();
out[k++] = arr[j];
}
}
if (k != 60) revert InvalidPubSignalsLength();
if (k != outLength) revert InvalidPubSignalsLength();
return out;
}

View File

@@ -1,50 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
import { Test } from "forge-std/Test.sol";
import { CircuitUtilsHelper } from "./_CircuitUtilsHelper.sol";
contract ExtractEmailPartsTest is Test {
CircuitUtilsHelper private _helper;
function setUp() public {
_helper = new CircuitUtilsHelper();
}
function test_simpleEmail() public view {
string memory email = "user@gmail.com";
string[] memory parts = _helper.callExtractEmailParts(email);
assertEq(parts.length, 2);
assertEq(parts[0], "user$gmail");
assertEq(parts[1], "com");
}
function test_emailWithSubdomain() public view {
string memory email = "user@sub.domain.com";
string[] memory parts = _helper.callExtractEmailParts(email);
assertEq(parts.length, 3);
assertEq(parts[0], "user$sub");
assertEq(parts[1], "domain");
assertEq(parts[2], "com");
}
function test_emailWithMultipleDots() public view {
string memory email = "user@domain.co.uk";
string[] memory parts = _helper.callExtractEmailParts(email);
assertEq(parts.length, 3);
assertEq(parts[0], "user$domain");
assertEq(parts[1], "co");
assertEq(parts[2], "uk");
}
function test_complexEmail() public view {
string memory email = "user.name+tag@sub.domain.co.uk";
string[] memory parts = _helper.callExtractEmailParts(email);
assertEq(parts.length, 5);
assertEq(parts[0], "user");
assertEq(parts[1], "name+tag$sub");
assertEq(parts[2], "domain");
assertEq(parts[3], "co");
assertEq(parts[4], "uk");
}
}

View File

@@ -23,7 +23,7 @@ contract FlattenFieldsTest is Test {
inputs[1][i] = i + 31;
}
vm.expectRevert(CircuitUtils.InvalidPubSignalsLength.selector);
_helper.callFlattenFields(inputs);
_helper.callFlattenFields(inputs, 60);
}
function test_expectRevert_tooFewElements() public {
@@ -37,13 +37,13 @@ contract FlattenFieldsTest is Test {
inputs[1][i] = i + 31;
}
vm.expectRevert(CircuitUtils.InvalidPubSignalsLength.selector);
_helper.callFlattenFields(inputs);
_helper.callFlattenFields(inputs, 60);
}
function test_zeroArrays() public {
uint256[][] memory inputs = new uint256[][](0);
vm.expectRevert(CircuitUtils.InvalidPubSignalsLength.selector);
_helper.callFlattenFields(inputs);
_helper.callFlattenFields(inputs, 60);
}
function test_singleArray() public view {
@@ -52,7 +52,7 @@ contract FlattenFieldsTest is Test {
for (uint256 i = 0; i < 60; i++) {
inputs[0][i] = i + 1;
}
uint256[60] memory result = _helper.callFlattenFields(inputs);
uint256[] memory result = _helper.callFlattenFields(inputs, 60);
for (uint256 i = 0; i < 60; i++) {
assertEq(result[i], i + 1);
}
@@ -68,7 +68,7 @@ contract FlattenFieldsTest is Test {
inputs[1][i] = i + 21;
inputs[2][i] = i + 41;
}
uint256[60] memory result = _helper.callFlattenFields(inputs);
uint256[] memory result = _helper.callFlattenFields(inputs, 60);
for (uint256 i = 0; i < 20; i++) {
assertEq(result[i], i + 1);
assertEq(result[i + 20], i + 21);
@@ -82,7 +82,7 @@ contract FlattenFieldsTest is Test {
inputs[i] = new uint256[](1);
inputs[i][0] = i + 1;
}
uint256[60] memory result = _helper.callFlattenFields(inputs);
uint256[] memory result = _helper.callFlattenFields(inputs, 60);
for (uint256 i = 0; i < 60; i++) {
assertEq(result[i], i + 1);
}

View File

@@ -16,12 +16,8 @@ contract CircuitUtilsHelper {
return CircuitUtils.extractCommandParamByIndex(template, command, index);
}
function callExtractEmailParts(string memory email) external pure returns (string[] memory) {
return CircuitUtils.extractEmailParts(email);
}
function callFlattenFields(uint256[][] memory inputs) external pure returns (uint256[60] memory) {
return CircuitUtils.flattenFields(inputs);
function callFlattenFields(uint256[][] memory inputs, uint256 outLength) external pure returns (uint256[] memory) {
return CircuitUtils.flattenFields(inputs, outLength);
}
function callPackBytes2Fields(bytes memory data, uint256 paddedSize) external pure returns (uint256[] memory) {