Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion examples/CRISP/client/libs/crispWorker.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -32,6 +32,7 @@ self.onmessage = async function (event) {
merkleLeaves,
balance,
previousCiphertext,
messageHash,
})
const encodedProof = encodeSolidityProof(proof)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export type VoteManagementContextType = {
publicKey: Uint8Array,
address: string,
signature: string,
messageHash: `0x${string}`,
previousCiphertext?: Uint8Array,
) => Promise<string | undefined>
broadcastVote: (vote: BroadcastVoteRequest) => Promise<BroadcastVoteResponse | undefined>
Expand Down
15 changes: 9 additions & 6 deletions examples/CRISP/client/src/hooks/voting/useVoteCasting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@

import { useState, useCallback } from 'react'
import { useNavigate } from 'react-router-dom'
import { hashMessage } from 'viem'
import { useSignMessage } from 'wagmi'

import { useVoteManagementContext } from '@/context/voteManagement'
import { useNotificationAlertContext } from '@/context/NotificationAlert/NotificationAlert.context.tsx'
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'

Expand Down Expand Up @@ -67,9 +68,9 @@ export const useVoteCasting = (customRoundState?: VoteStateLite | null, customVo
const [stepMessage, setStepMessage] = useState<string>('')

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],
)
Expand Down Expand Up @@ -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')
Expand All @@ -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.')
}
Expand Down Expand Up @@ -215,6 +217,7 @@ export const useVoteCasting = (customRoundState?: VoteStateLite | null, customVo
signMessageAsync,
markVotedInRound,
resetVotingState,
votingRound,
],
)

Expand Down
3 changes: 2 additions & 1 deletion examples/CRISP/client/src/hooks/wasm/useWebAssembly.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const useWebAssemblyHook = () => {
publicKey: Uint8Array,
address: string,
signature: string,
messageHash: `0x${string}`,
previousCiphertext?: Uint8Array,
): Promise<string | undefined> => {
if (!worker) {
Expand All @@ -37,7 +38,7 @@ export const useWebAssemblyHook = () => {

return new Promise<string | undefined>((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') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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({
Expand All @@ -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)
Expand All @@ -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)

Expand All @@ -103,6 +105,7 @@ describe('CRISP Contracts', function () {
signature,
merkleLeaves: leaves,
balance,
messageHash: SIGNATURE_MESSAGE_HASH,
})

const encodedProof = encodeSolidityProof(proof)
Expand Down
2 changes: 1 addition & 1 deletion examples/CRISP/packages/crisp-sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions examples/CRISP/packages/crisp-sdk/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ export type ProofInputs = {
slotAddress: string
previousCiphertext?: Uint8Array
merkleProof: MerkleProof
messageHash?: `0x${string}`
}

export type MaskVoteProofInputs = {
Expand All @@ -193,4 +194,5 @@ export type VoteProofInputs = {
vote: Vote
signature: `0x${string}`
previousCiphertext?: Uint8Array
messageHash: `0x${string}`
}
9 changes: 5 additions & 4 deletions examples/CRISP/packages/crisp-sdk/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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<string> => {
const publicKey = await recoverPublicKey({ hash: SIGNATURE_MESSAGE_HASH, signature })
export const getAddressFromSignature = async (signature: `0x${string}`, messageHash: `0x${string}`): Promise<string> => {
const publicKey = await recoverPublicKey({ hash: messageHash, signature })

return publicKeyToAddress(publicKey)
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Expand Down
7 changes: 5 additions & 2 deletions examples/CRISP/packages/crisp-sdk/src/vote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,10 @@ export const generateCircuitInputs = async (proofInputs: ProofInputs): Promise<C
encodedVote,
)

const { messageHash, publicKeyX, publicKeyY, signature } = await extractSignatureComponents(proofInputs.signature)
const { messageHash, publicKeyX, publicKeyY, signature } = await extractSignatureComponents(
proofInputs.signature,
proofInputs.messageHash,
)

crispInputs.hashed_message = Array.from(messageHash).map((b) => b.toString())
crispInputs.public_key_x = Array.from(publicKeyX).map((b) => b.toString())
Expand Down Expand Up @@ -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)

Expand Down
1 change: 1 addition & 0 deletions examples/CRISP/packages/crisp-sdk/tests/vote.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ describe('Vote', () => {
signature,
merkleLeaves: LEAVES,
balance,
messageHash: SIGNATURE_MESSAGE_HASH,
})

expect(proof).toBeDefined()
Expand Down
Loading