diff --git a/examples/CRISP/client/libs/crispWorker.js b/examples/CRISP/client/libs/crispWorker.js index a6f75705f5..c563523096 100755 --- a/examples/CRISP/client/libs/crispWorker.js +++ b/examples/CRISP/client/libs/crispWorker.js @@ -11,7 +11,7 @@ self.onmessage = async function (event) { switch (type) { case 'generate_proof': try { - const { voteId, publicKey, address, signature, previousCiphertext } = data + const { voteId, publicKey, address, signature, previousCiphertext, messageHash } = data // voteId is either 0 or 1, so we need to encode the vote accordingly. // We are adapting to the current CRISP application. @@ -32,6 +32,7 @@ self.onmessage = async function (event) { merkleLeaves, balance, previousCiphertext, + messageHash, }) const encodedProof = encodeSolidityProof(proof) diff --git a/examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts b/examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts index 4dd7cfac3d..e410272ebe 100644 --- a/examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts +++ b/examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts @@ -42,6 +42,7 @@ export type VoteManagementContextType = { publicKey: Uint8Array, address: string, signature: string, + messageHash: `0x${string}`, previousCiphertext?: Uint8Array, ) => Promise broadcastVote: (vote: BroadcastVoteRequest) => Promise diff --git a/examples/CRISP/client/src/hooks/voting/useVoteCasting.ts b/examples/CRISP/client/src/hooks/voting/useVoteCasting.ts index 4342ba7e1d..214868a140 100644 --- a/examples/CRISP/client/src/hooks/voting/useVoteCasting.ts +++ b/examples/CRISP/client/src/hooks/voting/useVoteCasting.ts @@ -6,6 +6,7 @@ import { useState, useCallback } from 'react' import { useNavigate } from 'react-router-dom' +import { hashMessage } from 'viem' import { useSignMessage } from 'wagmi' import { useVoteManagementContext } from '@/context/voteManagement' @@ -13,7 +14,7 @@ import { useNotificationAlertContext } from '@/context/NotificationAlert/Notific import { Poll } from '@/model/poll.model' import { BroadcastVoteRequest, VoteStateLite, VotingRound } from '@/model/vote.model' -import { encryptVote, SIGNATURE_MESSAGE } from '@crisp-e3/sdk' +import { encryptVote } from '@crisp-e3/sdk' export type VotingStep = 'idle' | 'signing' | 'encrypting' | 'generating_proof' | 'broadcasting' | 'confirming' | 'complete' | 'error' @@ -67,9 +68,9 @@ export const useVoteCasting = (customRoundState?: VoteStateLite | null, customVo const [stepMessage, setStepMessage] = useState('') const handleProofGeneration = useCallback( - async (vote: Poll, address: string, signature: string, previousCiphertext?: Uint8Array) => { + async (vote: Poll, address: string, signature: string, messageHash: `0x${string}`, previousCiphertext?: Uint8Array) => { if (!votingRound) throw new Error('No voting round available for proof generation') - return generateProof(BigInt(vote.value), new Uint8Array(votingRound.pk_bytes), address, signature, previousCiphertext) + return generateProof(BigInt(vote.value), new Uint8Array(votingRound.pk_bytes), address, signature, messageHash, previousCiphertext) }, [generateProof, votingRound], ) @@ -107,11 +108,12 @@ export const useVoteCasting = (customRoundState?: VoteStateLite | null, customVo setVotingStep('signing') setLastActiveStep('signing') setStepMessage('Please sign the message in your wallet...') - // const message = `Vote for round ${roundState.id}` + const message = `Vote for round ${roundState.id}` + const messageHash = hashMessage(message) let signature: string try { - signature = await signMessageAsync({ message: SIGNATURE_MESSAGE }) + signature = await signMessageAsync({ message }) // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (signError) { console.log('User rejected signature or signing failed') @@ -128,7 +130,7 @@ export const useVoteCasting = (customRoundState?: VoteStateLite | null, customVo // @todo get this from the contract or server const newEncryptionTemp = encryptVote({ yes: 0n, no: 0n }, new Uint8Array(votingRound!.pk_bytes)) const previousCiphertext = isVoteUpdate ? newEncryptionTemp : undefined - const encodedProof = await handleProofGeneration(pollSelected, user.address, signature, previousCiphertext) + const encodedProof = await handleProofGeneration(pollSelected, user.address, signature, messageHash, previousCiphertext) if (!encodedProof) { throw new Error('Failed to encrypt vote.') } @@ -215,6 +217,7 @@ export const useVoteCasting = (customRoundState?: VoteStateLite | null, customVo signMessageAsync, markVotedInRound, resetVotingState, + votingRound, ], ) diff --git a/examples/CRISP/client/src/hooks/wasm/useWebAssembly.tsx b/examples/CRISP/client/src/hooks/wasm/useWebAssembly.tsx index 4cd6eaed53..dcb9f6897a 100644 --- a/examples/CRISP/client/src/hooks/wasm/useWebAssembly.tsx +++ b/examples/CRISP/client/src/hooks/wasm/useWebAssembly.tsx @@ -28,6 +28,7 @@ export const useWebAssemblyHook = () => { publicKey: Uint8Array, address: string, signature: string, + messageHash: `0x${string}`, previousCiphertext?: Uint8Array, ): Promise => { if (!worker) { @@ -37,7 +38,7 @@ export const useWebAssemblyHook = () => { return new Promise((resolve, reject) => { setIsLoading(true) - worker.postMessage({ type: 'generate_proof', data: { voteId, publicKey, address, signature, previousCiphertext } }) + worker.postMessage({ type: 'generate_proof', data: { voteId, publicKey, address, signature, messageHash, previousCiphertext } }) worker.onmessage = async (event) => { const { type, success, encodedProof, error } = event.data if (type === 'generate_proof') { diff --git a/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts b/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts index 283697fd1d..67e5a9827d 100644 --- a/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts +++ b/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts @@ -13,6 +13,7 @@ import { getAddressFromSignature, encodeSolidityProof, generateMerkleTree, + SIGNATURE_MESSAGE_HASH, } from '@crisp-e3/sdk' import { expect } from 'chai' import { deployCRISPProgram, deployHonkVerifier, deployMockEnclave, ethers } from './utils' @@ -65,7 +66,7 @@ describe('CRISP Contracts', function () { const vote = { yes: 10n, no: 0n } const balance = 100n const signature = (await signer.signMessage(SIGNATURE_MESSAGE)) as `0x${string}` - const address = await getAddressFromSignature(signature) + const address = await getAddressFromSignature(signature, SIGNATURE_MESSAGE_HASH) const leaves = [...[10n, 20n, 30n], hashLeaf(address, balance)] const proof = await generateVoteProof({ @@ -74,6 +75,7 @@ describe('CRISP Contracts', function () { signature, merkleLeaves: leaves, balance, + messageHash: SIGNATURE_MESSAGE_HASH, }) const isValid = await honkVerifier.verify(proof.proof, proof.publicInputs) @@ -93,7 +95,7 @@ describe('CRISP Contracts', function () { const vote = { yes: 10n, no: 0n } const balance = 100n const signature = (await signer.signMessage(SIGNATURE_MESSAGE)) as `0x${string}` - const address = await getAddressFromSignature(signature) + const address = await getAddressFromSignature(signature, SIGNATURE_MESSAGE_HASH) const leaves = [...[10n, 20n, 30n], hashLeaf(address, balance)] const merkleTree = generateMerkleTree(leaves) @@ -103,6 +105,7 @@ describe('CRISP Contracts', function () { signature, merkleLeaves: leaves, balance, + messageHash: SIGNATURE_MESSAGE_HASH, }) const encodedProof = encodeSolidityProof(proof) diff --git a/examples/CRISP/packages/crisp-sdk/src/index.ts b/examples/CRISP/packages/crisp-sdk/src/index.ts index b121af9a15..98819cf6f5 100644 --- a/examples/CRISP/packages/crisp-sdk/src/index.ts +++ b/examples/CRISP/packages/crisp-sdk/src/index.ts @@ -6,7 +6,7 @@ export * from './token' export * from './state' -export { MERKLE_TREE_MAX_DEPTH, SIGNATURE_MESSAGE, MAXIMUM_VOTE_VALUE } from './constants' +export { MERKLE_TREE_MAX_DEPTH, SIGNATURE_MESSAGE, MAXIMUM_VOTE_VALUE, SIGNATURE_MESSAGE_HASH } from './constants' export { hashLeaf, generateMerkleProof, generateMerkleTree, getAddressFromSignature } from './utils' export { decodeTally, diff --git a/examples/CRISP/packages/crisp-sdk/src/types.ts b/examples/CRISP/packages/crisp-sdk/src/types.ts index 52a6209619..d0befa3d99 100644 --- a/examples/CRISP/packages/crisp-sdk/src/types.ts +++ b/examples/CRISP/packages/crisp-sdk/src/types.ts @@ -176,6 +176,7 @@ export type ProofInputs = { slotAddress: string previousCiphertext?: Uint8Array merkleProof: MerkleProof + messageHash?: `0x${string}` } export type MaskVoteProofInputs = { @@ -193,4 +194,5 @@ export type VoteProofInputs = { vote: Vote signature: `0x${string}` previousCiphertext?: Uint8Array + messageHash: `0x${string}` } diff --git a/examples/CRISP/packages/crisp-sdk/src/utils.ts b/examples/CRISP/packages/crisp-sdk/src/utils.ts index 7fff375fab..e6ceefd597 100644 --- a/examples/CRISP/packages/crisp-sdk/src/utils.ts +++ b/examples/CRISP/packages/crisp-sdk/src/utils.ts @@ -88,13 +88,14 @@ export const toBinary = (number: bigint): string => { */ export const extractSignatureComponents = async ( signature: `0x${string}`, + messageHash: `0x${string}` = SIGNATURE_MESSAGE_HASH, ): Promise<{ messageHash: Uint8Array publicKeyX: Uint8Array publicKeyY: Uint8Array signature: Uint8Array }> => { - const publicKey = await recoverPublicKey({ hash: SIGNATURE_MESSAGE_HASH, signature }) + const publicKey = await recoverPublicKey({ hash: messageHash, signature }) const publicKeyBytes = hexToBytes(publicKey) const publicKeyX = publicKeyBytes.slice(1, 33) const publicKeyY = publicKeyBytes.slice(33, 65) @@ -109,15 +110,15 @@ export const extractSignatureComponents = async ( signatureBytes.set(s, 32) return { - messageHash: hexToBytes(SIGNATURE_MESSAGE_HASH), + messageHash: hexToBytes(messageHash), publicKeyX: publicKeyX, publicKeyY: publicKeyY, signature: signatureBytes, } } -export const getAddressFromSignature = async (signature: `0x${string}`): Promise => { - const publicKey = await recoverPublicKey({ hash: SIGNATURE_MESSAGE_HASH, signature }) +export const getAddressFromSignature = async (signature: `0x${string}`, messageHash: `0x${string}`): Promise => { + const publicKey = await recoverPublicKey({ hash: messageHash, signature }) return publicKeyToAddress(publicKey) } diff --git a/examples/CRISP/packages/crisp-sdk/src/vote.ts b/examples/CRISP/packages/crisp-sdk/src/vote.ts index c641d006a7..5e9c984a9d 100644 --- a/examples/CRISP/packages/crisp-sdk/src/vote.ts +++ b/examples/CRISP/packages/crisp-sdk/src/vote.ts @@ -103,7 +103,10 @@ export const generateCircuitInputs = async (proofInputs: ProofInputs): Promise b.toString()) crispInputs.public_key_x = Array.from(publicKeyX).map((b) => b.toString()) @@ -151,7 +154,7 @@ export const generateVoteProof = async (voteProofInputs: VoteProofInputs) => { } // The address slot of an actual vote always is the address of the public key that signed the message. - const address = await getAddressFromSignature(voteProofInputs.signature) + const address = await getAddressFromSignature(voteProofInputs.signature, voteProofInputs.messageHash) const merkleProof = generateMerkleProof(voteProofInputs.balance, address, voteProofInputs.merkleLeaves) diff --git a/examples/CRISP/packages/crisp-sdk/tests/vote.test.ts b/examples/CRISP/packages/crisp-sdk/tests/vote.test.ts index 92d53aa663..af157ad528 100644 --- a/examples/CRISP/packages/crisp-sdk/tests/vote.test.ts +++ b/examples/CRISP/packages/crisp-sdk/tests/vote.test.ts @@ -241,6 +241,7 @@ describe('Vote', () => { signature, merkleLeaves: LEAVES, balance, + messageHash: SIGNATURE_MESSAGE_HASH, }) expect(proof).toBeDefined()