Skip to content

Commit

Permalink
feat: use relayer/input-proof
Browse files Browse the repository at this point in the history
  • Loading branch information
rudy-6-4 committed Feb 25, 2025
1 parent f285261 commit d2fe2d2
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 74 deletions.
10 changes: 5 additions & 5 deletions src/sdk/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export type FhevmInstanceConfig = {
chainId?: number;
publicKey?: Uint8Array | null;
publicKeyId?: string | null;
gatewayUrl?: string;
relayerUrl?: string;
network?: Eip1193Provider;
networkUrl?: string;
publicParams?: PublicParams<Uint8Array> | null;
Expand Down Expand Up @@ -56,9 +56,9 @@ export const getChainId = async (
export const getTfheCompactPublicKey = async (
config: FhevmInstanceConfig,
): Promise<{ publicKey: TfheCompactPublicKey; publicKeyId: string }> => {
if (config.gatewayUrl && !config.publicKey) {
if (config.relayerUrl && !config.publicKey) {
const inputs = await getKeysFromGateway(
cleanURL(config.gatewayUrl),
cleanURL(config.relayerUrl),
config.publicKeyId,
);
return { publicKey: inputs.publicKey, publicKeyId: inputs.publicKeyId };
Expand All @@ -85,9 +85,9 @@ export const getTfheCompactPublicKey = async (
export const getPublicParams = async (
config: FhevmInstanceConfig,
): Promise<PublicParams> => {
if (config.gatewayUrl && !config.publicParams) {
if (config.relayerUrl && !config.publicParams) {
const inputs = await getKeysFromGateway(
cleanURL(config.gatewayUrl),
cleanURL(config.relayerUrl),
config.publicKeyId,
);
return inputs.publicParams;
Expand Down
33 changes: 13 additions & 20 deletions src/sdk/encrypt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,24 @@ import { createEncryptedInput } from './encrypt';
import { publicKey, publicKeyId, publicParams } from '../test';
import fetchMock from '@fetch-mock/core';

fetchMock.post('https://test-gateway.net/verify_proven_ct', {
const relayer_url = 'https://test-httpz-relayer';

fetchMock.post(`${relayer_url}/input-proof`, {
response: {
proof_of_storage: 'deadbeef',
handles: ['2323beef', '2234beef'],
kms_signatures: ['dead3232'],
coproc_signature: '1122beef',
signatures: ['dead3232'],
},
status: 'success',
});


describe('encrypt', () => {
it('encrypt/decrypt', async () => {
const input = createEncryptedInput(
'0x325ea1b59F28e9e1C51d3B5b47b7D3965CC5D8C8',
1234,
'https://test-gateway.net/',
relayer_url,
publicKey,
publicKeyId,
publicParams,
)(
'0x8ba1f109551bd432803012645ac136ddd64dba72',
Expand Down Expand Up @@ -55,9 +55,8 @@ describe('encrypt', () => {
const input = createEncryptedInput(
'0x325ea1b59F28e9e1C51d3B5b47b7D3965CC5D8C8',
1234,
'https://test-gateway.net/',
relayer_url,
publicKey,
publicKeyId,
publicParams,
)(
'0x8ba1f109551bd432803012645ac136ddd64dba72',
Expand All @@ -83,9 +82,8 @@ describe('encrypt', () => {
const input = createEncryptedInput(
'0x325ea1b59F28e9e1C51d3B5b47b7D3965CC5D8C8',
1234,
'https://test-gateway.net/',
relayer_url,
publicKey,
publicKeyId,
publicParams,
)(
'0x8ba1f109551bd432803012645ac136ddd64dba72',
Expand Down Expand Up @@ -114,19 +112,17 @@ describe('encrypt', () => {
createEncryptedInput(
'0x325ea1b59F28e9e1C51d3B5b47b7D3965CC5D8C8',
1234,
'https://test-gateway.net/',
relayer_url,
publicKey,
publicKeyId,
publicParams,
)('0xa5e1defb98EFe38EBb2D958CEe052410247F4c80', '0'),
).toThrow('User address is not a valid address.');
expect(() =>
createEncryptedInput(
'0x325ea1b59F28e9e1C51d3B5b47b7D3965CC5D8C8',
1234,
'https://test-gateway.net/',
relayer_url,
publicKey,
publicKeyId,
publicParams,
)('0x0', '0xa5e1defb98EFe38EBb2D958CEe052410247F4c80'),
).toThrow('Contract address is not a valid address.');
Expand All @@ -135,9 +131,8 @@ describe('encrypt', () => {
createEncryptedInput(
'0x325ea1b59F28e9e1C51d3B5b47b7D3965CC5D8C8',
1234,
'https://test-gateway.net/',
relayer_url,
publicKey,
publicKeyId,
publicParams,
)(
'0x8ba1f109551bd432803012645ac136ddd64dba72',
Expand All @@ -148,9 +143,8 @@ describe('encrypt', () => {
const input = createEncryptedInput(
'0x325ea1b59F28e9e1C51d3B5b47b7D3965CC5D8C8',
1234,
'https://test-gateway.net/',
relayer_url,
publicKey,
publicKeyId,
publicParams,
)(
'0x8ba1f109551bd432803012645ac136ddd64dba72',
Expand Down Expand Up @@ -195,9 +189,8 @@ describe('encrypt', () => {
const input2 = createEncryptedInput(
'0x325ea1b59F28e9e1C51d3B5b47b7D3965CC5D8C8',
1234,
'https://test-gateway.net/',
relayer_url,
publicKey,
publicKeyId,
publicParams,
)(
'0x8ba1f109551bd432803012645ac136ddd64dba72',
Expand Down
82 changes: 36 additions & 46 deletions src/sdk/encrypt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@ import { ENCRYPTION_TYPES } from './encryptionTypes';

type EncryptionTypes = keyof typeof ENCRYPTION_TYPES;

export type GatewayEncryptResponse = {
// defined in fhevm-relayer/src/input_http_listener.rs
export type HttpzRelayerInputProofResponse = {
response: {
proof_of_storage: string;
handles: string[];
kms_signatures: string[];
coproc_signature: string;
signatures: string[];
};
status: string;
};
Expand Down Expand Up @@ -81,17 +80,16 @@ export const createEncryptedInput =
(
aclContractAddress: string,
chainId: number,
gateway: string,
relayer_url: string,
tfheCompactPublicKey: TfheCompactPublicKey,
publicKeyId: string,
publicParams: PublicParams,
) =>
(contractAddress: string, callerAddress: string): ZKInput => {
(contractAddress: string, userAddress: string): ZKInput => {
if (!isAddress(contractAddress)) {
throw new Error('Contract address is not a valid address.');
}

if (!isAddress(callerAddress)) {
if (!isAddress(userAddress)) {
throw new Error('User address is not a valid address.');
}
const publicKey: TfheCompactPublicKey = tfheCompactPublicKey;
Expand All @@ -108,6 +106,7 @@ export const createEncryptedInput =
'Packing more than 256 variables in a single input ciphertext is unsupported',
);
};
relayer_url = (relayer_url.slice(-1) == "/") ? relayer_url.slice(0, -1) : relayer_url;
return {
addBool(value: boolean | number | bigint) {
if (value == null) throw new Error('Missing value');
Expand Down Expand Up @@ -247,7 +246,7 @@ export const createEncryptedInput =
const closestPP = this._getClosestPP();
const pp = publicParams[closestPP]!.publicParams;
const buffContract = fromHexString(contractAddress);
const buffUser = fromHexString(callerAddress);
const buffUser = fromHexString(userAddress);
const buffAcl = fromHexString(aclContractAddress);
const buffChainId = fromHexString(chainId.toString(16));
const auxData = new Uint8Array(
Expand All @@ -269,30 +268,33 @@ export const createEncryptedInput =
return ciphertext;
},
async _verify(ciphertext: Buffer) {
const closestPP = this._getClosestPP();
const ppId = publicParams[closestPP]!.publicParamsId;
const payload = {
contract_address: getAddress(contractAddress),
caller_address: getAddress(callerAddress),
ct_proof: ciphertext.toString('hex'),
key_id: publicKeyId,
crs_id: ppId,
contractAddress: getAddress(contractAddress),
userAddress: getAddress(userAddress),
ciphertextWithZkpok: ciphertext.toString('hex'),
contractChainId: chainId.toString(16),
};

const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
};

let json: GatewayEncryptResponse;
const url = `${relayer_url}/input-proof`;
let json: HttpzRelayerInputProofResponse;
try {
const response = await fetch(`${gateway}verify_proven_ct`, options);
json = await response.json();
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`Httpz-relayer didn't response correctly. Bad status ${response.statusText}. Content: ${await response.text()}`);
}
try {
json = await response.json();
} catch (e) {
throw new Error("Httpz-relayer didn't response correctly. Bad JSON.", { cause: e });
}
} catch (e) {
throw new Error("Gateway didn't response correctly", { cause: e });
throw new Error("Httpz-relayer didn't response correctly.", { cause: e });
}

// Note that the hex strings returned by the gateway do have have the 0x prefix
Expand All @@ -301,34 +303,22 @@ export const createEncryptedInput =
handles = json.response.handles.map(fromHexString);
}

const kmsSignatures = json.response.kms_signatures;
const signatures = json.response.signatures;

// inputProof is len(list_handles) + numSignersKMS + hashCT + list_handles + signatureCopro + signatureKMSSigners (1+1+32+NUM_HANDLES*32+65+65*numSignersKMS)
let inputProof = numberToHex(handles.length); // for coprocessor : numHandles + numSignersKMS + hashCT + list_handles + signatureCopro + signatureKMSSigners (total len : 1+1+32+NUM_HANDLES*32+65+65*numSignersKMS)
// for native : numHandles + numSignersKMS + list_handles + signatureKMSSigners + bundleCiphertext (total len : 1+1+NUM_HANDLES*32+65*numSignersKMS+bundleCiphertext.length)
const numSigners = kmsSignatures.length;
// inputProof is len(list_handles) + numSigners + hashCT + list_handles + signatureCopro + signatureSigners (1+1+32+NUM_HANDLES*32+65+65*numSigners)
let inputProof = numberToHex(handles.length); // for coprocessor : numHandles + numSigners + hashCT + list_handles + signatureCopro + signatureSigners (total len : 1+1+32+NUM_HANDLES*32+65+65*numSigners)
const numSigners = signatures.length;
inputProof += numberToHex(numSigners);
if (json.response.proof_of_storage) {
// coprocessor
const hash = createKeccakHash('keccak256')
.update(Buffer.from(ciphertext))
.digest();
inputProof += hash.toString('hex');
// coprocessor
const hash = createKeccakHash('keccak256')
.update(Buffer.from(ciphertext))
.digest();
inputProof += hash.toString('hex');

const listHandlesStr = handles.map((i) => toHexString(i));
listHandlesStr.map((handle) => (inputProof += handle));
inputProof += json.response.proof_of_storage;
const listHandlesStr = handles.map((i) => toHexString(i));
listHandlesStr.map((handle) => (inputProof += handle));

kmsSignatures.map((sigKMS) => (inputProof += sigKMS));
} else {
// native
const listHandlesStr = handles.map((i) => toHexString(i));
listHandlesStr.map((handle) => (inputProof += handle));

kmsSignatures.map((sigKMS) => (inputProof += sigKMS));

inputProof += toHexString(ciphertext);
}
signatures.map((signature) => (inputProof += signature));

return {
handles,
Expand Down
5 changes: 2 additions & 3 deletions src/sdk/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,16 @@ export const createInstance = async (
chainId,
kmsContractAddress,
aclContractAddress,
cleanURL(config.gatewayUrl),
cleanURL(config.relayerUrl),
provider,
);

return {
createEncryptedInput: createEncryptedInput(
aclContractAddress,
chainId,
cleanURL(config.gatewayUrl),
cleanURL(config.relayerUrl),
publicKeyData.publicKey,
publicKeyData.publicKeyId,
publicParamsData,
),
generateKeypair,
Expand Down

0 comments on commit d2fe2d2

Please # to comment.