From ecf813f77e5b1704ad6784184932827dc161b173 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Fri, 8 Nov 2024 15:31:12 +0000 Subject: [PATCH 1/3] feat: domain separate block proposals and attestations --- l1-contracts/src/core/Rollup.sol | 3 ++- .../src/core/libraries/crypto/SignatureLib.sol | 8 ++++++++ .../circuit-types/src/p2p/block_attestation.ts | 6 +++--- .../circuit-types/src/p2p/block_proposal.ts | 8 ++++---- .../circuit-types/src/p2p/consensus_payload.ts | 8 ++++---- yarn-project/circuit-types/src/p2p/mocks.ts | 16 +++++++++++----- .../circuit-types/src/p2p/signature_utils.ts | 15 ++++++++++----- .../p2p/src/mem_pools/attestation_pool/mocks.ts | 6 ++++-- .../src/publisher/l1-publisher.ts | 3 ++- .../src/duties/validation_service.ts | 4 ++-- 10 files changed, 50 insertions(+), 27 deletions(-) diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index d6f8b2c8577..ac9a5cd3eaa 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -468,7 +468,8 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup { // Decode and validate header HeaderLib.Header memory header = HeaderLib.decode(_header); - bytes32 digest = keccak256(abi.encode(_archive, _txHashes)); + uint8 domainSeperator = uint8(SignatureLib.SignatureDomainSeperator.blockAttestation); + bytes32 digest = keccak256(abi.encode(domainSeperator, _archive, _txHashes)); setupEpoch(); _validateHeader({ _header: header, diff --git a/l1-contracts/src/core/libraries/crypto/SignatureLib.sol b/l1-contracts/src/core/libraries/crypto/SignatureLib.sol index bcae500df8c..29e37357bc8 100644 --- a/l1-contracts/src/core/libraries/crypto/SignatureLib.sol +++ b/l1-contracts/src/core/libraries/crypto/SignatureLib.sol @@ -12,6 +12,14 @@ library SignatureLib { bytes32 s; } + /** + * @notice The domain seperator for the signatures + */ + enum SignatureDomainSeperator { + blockProposal, + blockAttestation + } + /** * @notice Verified a signature, throws if the signature is invalid or empty * diff --git a/yarn-project/circuit-types/src/p2p/block_attestation.ts b/yarn-project/circuit-types/src/p2p/block_attestation.ts index a847452f8b9..5b229d55af7 100644 --- a/yarn-project/circuit-types/src/p2p/block_attestation.ts +++ b/yarn-project/circuit-types/src/p2p/block_attestation.ts @@ -7,7 +7,7 @@ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { ConsensusPayload } from './consensus_payload.js'; import { Gossipable } from './gossipable.js'; -import { getHashedSignaturePayloadEthSignedMessage } from './signature_utils.js'; +import { getHashedSignaturePayloadEthSignedMessage, SignatureDomainSeperator } from './signature_utils.js'; import { TopicType, createTopicString } from './topic_type.js'; export class BlockAttestationHash extends Buffer32 { @@ -53,7 +53,7 @@ export class BlockAttestation extends Gossipable { getSender() { if (!this.sender) { // Recover the sender from the attestation - const hashed = getHashedSignaturePayloadEthSignedMessage(this.payload); + const hashed = getHashedSignaturePayloadEthSignedMessage(this.payload, SignatureDomainSeperator.blockAttestation); // Cache the sender for later use this.sender = recoverAddress(hashed, this.signature); } @@ -62,7 +62,7 @@ export class BlockAttestation extends Gossipable { } getPayload(): Buffer { - return this.payload.getPayloadToSign(); + return this.payload.getPayloadToSign(SignatureDomainSeperator.blockAttestation); } toBuffer(): Buffer { diff --git a/yarn-project/circuit-types/src/p2p/block_proposal.ts b/yarn-project/circuit-types/src/p2p/block_proposal.ts index 2733f03db19..e9268c86853 100644 --- a/yarn-project/circuit-types/src/p2p/block_proposal.ts +++ b/yarn-project/circuit-types/src/p2p/block_proposal.ts @@ -7,7 +7,7 @@ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { ConsensusPayload } from './consensus_payload.js'; import { Gossipable } from './gossipable.js'; -import { getHashedSignaturePayload, getHashedSignaturePayloadEthSignedMessage } from './signature_utils.js'; +import { getHashedSignaturePayload, getHashedSignaturePayloadEthSignedMessage, SignatureDomainSeperator } from './signature_utils.js'; import { TopicType, createTopicString } from './topic_type.js'; export class BlockProposalHash extends Buffer32 { @@ -49,7 +49,7 @@ export class BlockProposal extends Gossipable { payload: ConsensusPayload, payloadSigner: (payload: Buffer32) => Promise, ) { - const hashed = getHashedSignaturePayload(payload); + const hashed = getHashedSignaturePayload(payload, SignatureDomainSeperator.blockProposal); const sig = await payloadSigner(hashed); return new BlockProposal(payload, sig); @@ -60,7 +60,7 @@ export class BlockProposal extends Gossipable { */ getSender() { if (!this.sender) { - const hashed = getHashedSignaturePayloadEthSignedMessage(this.payload); + const hashed = getHashedSignaturePayloadEthSignedMessage(this.payload, SignatureDomainSeperator.blockProposal); // Cache the sender for later use this.sender = recoverAddress(hashed, this.signature); } @@ -69,7 +69,7 @@ export class BlockProposal extends Gossipable { } getPayload() { - return this.payload.getPayloadToSign(); + return this.payload.getPayloadToSign(SignatureDomainSeperator.blockProposal); } toBuffer(): Buffer { diff --git a/yarn-project/circuit-types/src/p2p/consensus_payload.ts b/yarn-project/circuit-types/src/p2p/consensus_payload.ts index d3d13f2d2d0..0b96939120f 100644 --- a/yarn-project/circuit-types/src/p2p/consensus_payload.ts +++ b/yarn-project/circuit-types/src/p2p/consensus_payload.ts @@ -6,7 +6,7 @@ import { type FieldsOf } from '@aztec/foundation/types'; import { encodeAbiParameters, parseAbiParameters } from 'viem'; import { TxHash } from '../tx/tx_hash.js'; -import { type Signable } from './signature_utils.js'; +import { SignatureDomainSeperator, type Signable } from './signature_utils.js'; export class ConsensusPayload implements Signable { private size: number | undefined; @@ -24,10 +24,10 @@ export class ConsensusPayload implements Signable { return [fields.header, fields.archive, fields.txHashes] as const; } - getPayloadToSign(): Buffer { - const abi = parseAbiParameters('bytes32, bytes32[]'); + getPayloadToSign(domainSeperator: SignatureDomainSeperator): Buffer { + const abi = parseAbiParameters('uint8, bytes32, bytes32[]'); const txArray = this.txHashes.map(tx => tx.to0xString()); - const encodedData = encodeAbiParameters(abi, [this.archive.toString(), txArray] as const); + const encodedData = encodeAbiParameters(abi, [domainSeperator, this.archive.toString(), txArray] as const); return Buffer.from(encodedData.slice(2), 'hex'); } diff --git a/yarn-project/circuit-types/src/p2p/mocks.ts b/yarn-project/circuit-types/src/p2p/mocks.ts index 0286c4207ed..e1287dc8672 100644 --- a/yarn-project/circuit-types/src/p2p/mocks.ts +++ b/yarn-project/circuit-types/src/p2p/mocks.ts @@ -7,7 +7,7 @@ import { TxHash } from '../tx/tx_hash.js'; import { BlockAttestation } from './block_attestation.js'; import { BlockProposal } from './block_proposal.js'; import { ConsensusPayload } from './consensus_payload.js'; -import { getHashedSignaturePayloadEthSignedMessage } from './signature_utils.js'; +import { getHashedSignaturePayloadEthSignedMessage, SignatureDomainSeperator } from './signature_utils.js'; export interface MakeConsensusPayloadOptions { signer?: Secp256k1Signer; @@ -16,7 +16,10 @@ export interface MakeConsensusPayloadOptions { txHashes?: TxHash[]; } -const makeAndSignConsensusPayload = (options?: MakeConsensusPayloadOptions) => { +const makeAndSignConsensusPayload = ( + domainSeperator: SignatureDomainSeperator, + options?: MakeConsensusPayloadOptions, +) => { const { signer = Secp256k1Signer.random(), header = makeHeader(1), @@ -30,19 +33,22 @@ const makeAndSignConsensusPayload = (options?: MakeConsensusPayloadOptions) => { txHashes, }); - const hash = getHashedSignaturePayloadEthSignedMessage(payload); + const hash = getHashedSignaturePayloadEthSignedMessage(payload, domainSeperator); const signature = signer.sign(hash); return { payload, signature }; }; export const makeBlockProposal = (options?: MakeConsensusPayloadOptions): BlockProposal => { - const { payload, signature } = makeAndSignConsensusPayload(options); + const { payload, signature } = makeAndSignConsensusPayload(SignatureDomainSeperator.blockProposal, options); return new BlockProposal(payload, signature); }; // TODO(https://github.com/AztecProtocol/aztec-packages/issues/8028) export const makeBlockAttestation = (options?: MakeConsensusPayloadOptions): BlockAttestation => { - const { payload, signature } = makeAndSignConsensusPayload(options); + const { payload, signature } = makeAndSignConsensusPayload( + SignatureDomainSeperator.blockAttestation, + options, + ); return new BlockAttestation(payload, signature); }; diff --git a/yarn-project/circuit-types/src/p2p/signature_utils.ts b/yarn-project/circuit-types/src/p2p/signature_utils.ts index b06cbdf5f92..5c70c1862d1 100644 --- a/yarn-project/circuit-types/src/p2p/signature_utils.ts +++ b/yarn-project/circuit-types/src/p2p/signature_utils.ts @@ -1,8 +1,13 @@ import { Buffer32 } from '@aztec/foundation/buffer'; import { keccak256, makeEthSignDigest } from '@aztec/foundation/crypto'; +export enum SignatureDomainSeperator { + blockProposal = 0, + blockAttestation = 1 +} + export interface Signable { - getPayloadToSign(): Buffer; + getPayloadToSign(domainSeperator: SignatureDomainSeperator): Buffer; } /** @@ -10,8 +15,8 @@ export interface Signable { * @param s - The `Signable` to sign * @returns The hashed payload for the signature of the `Signable` */ -export function getHashedSignaturePayload(s: Signable): Buffer32 { - return Buffer32.fromBuffer(keccak256(s.getPayloadToSign())); +export function getHashedSignaturePayload(s: Signable, domainSeperator: SignatureDomainSeperator): Buffer32 { + return Buffer32.fromBuffer(keccak256(s.getPayloadToSign(domainSeperator))); } /** @@ -19,7 +24,7 @@ export function getHashedSignaturePayload(s: Signable): Buffer32 { * @param s - the `Signable` to sign * @returns The hashed payload for the signature of the `Signable` as an Ethereum signed message */ -export function getHashedSignaturePayloadEthSignedMessage(s: Signable): Buffer32 { - const payload = getHashedSignaturePayload(s); +export function getHashedSignaturePayloadEthSignedMessage(s: Signable, domainSeperator: SignatureDomainSeperator): Buffer32 { + const payload = getHashedSignaturePayload(s, domainSeperator); return makeEthSignDigest(payload); } diff --git a/yarn-project/p2p/src/mem_pools/attestation_pool/mocks.ts b/yarn-project/p2p/src/mem_pools/attestation_pool/mocks.ts index bf75e7c3905..97bf92329b8 100644 --- a/yarn-project/p2p/src/mem_pools/attestation_pool/mocks.ts +++ b/yarn-project/p2p/src/mem_pools/attestation_pool/mocks.ts @@ -1,4 +1,4 @@ -import { BlockAttestation, ConsensusPayload, TxHash } from '@aztec/circuit-types'; +import { BlockAttestation, ConsensusPayload, SignatureDomainSeperator, TxHash } from '@aztec/circuit-types'; import { makeHeader } from '@aztec/circuits.js/testing'; import { Signature } from '@aztec/foundation/eth-signature'; import { Fr } from '@aztec/foundation/fields'; @@ -33,7 +33,9 @@ export const mockAttestation = async ( const payload = new ConsensusPayload(header, archive, txs); - const message: `0x${string}` = `0x${payload.getPayloadToSign().toString('hex')}`; + const message: `0x${string}` = `0x${payload + .getPayloadToSign(SignatureDomainSeperator.blockAttestation) + .toString('hex')}`; const sigString = await signer.signMessage({ message }); const signature = Signature.from0xString(sigString); diff --git a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts index 3a1fc87b18e..c3840e3963d 100644 --- a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts +++ b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts @@ -5,6 +5,7 @@ import { type L2Block, type TxHash, getHashedSignaturePayload, + SignatureDomainSeperator, } from '@aztec/circuit-types'; import { type L1PublishBlockStats, type L1PublishProofStats } from '@aztec/circuit-types/stats'; import { @@ -464,7 +465,7 @@ export class L1Publisher { const consensusPayload = new ConsensusPayload(block.header, block.archive.root, txHashes ?? []); - const digest = getHashedSignaturePayload(consensusPayload); + const digest = getHashedSignaturePayload(consensusPayload, SignatureDomainSeperator.blockAttestation); const proposeTxArgs = { header: block.header.toBuffer(), archive: block.archive.root.toBuffer(), diff --git a/yarn-project/validator-client/src/duties/validation_service.ts b/yarn-project/validator-client/src/duties/validation_service.ts index 55699c13d51..6bb9d279be9 100644 --- a/yarn-project/validator-client/src/duties/validation_service.ts +++ b/yarn-project/validator-client/src/duties/validation_service.ts @@ -1,4 +1,4 @@ -import { BlockAttestation, BlockProposal, ConsensusPayload, type TxHash } from '@aztec/circuit-types'; +import { BlockAttestation, BlockProposal, ConsensusPayload, SignatureDomainSeperator, type TxHash } from '@aztec/circuit-types'; import { type Header } from '@aztec/circuits.js'; import { Buffer32 } from '@aztec/foundation/buffer'; import { keccak256 } from '@aztec/foundation/crypto'; @@ -36,7 +36,7 @@ export class ValidationService { async attestToProposal(proposal: BlockProposal): Promise { // TODO(https://github.com/AztecProtocol/aztec-packages/issues/7961): check that the current validator is correct - const buf = Buffer32.fromBuffer(keccak256(proposal.getPayload())); + const buf = Buffer32.fromBuffer(keccak256(proposal.payload.getPayloadToSign(SignatureDomainSeperator.blockAttestation))); const sig = await this.keyStore.signMessage(buf); return new BlockAttestation(proposal.payload, sig); } From f3f91f1623dd992bad3d3854abcf6211b9dc58c2 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Fri, 8 Nov 2024 15:31:53 +0000 Subject: [PATCH 2/3] fmt --- .../circuit-types/src/p2p/block_attestation.ts | 2 +- yarn-project/circuit-types/src/p2p/block_proposal.ts | 6 +++++- .../circuit-types/src/p2p/consensus_payload.ts | 2 +- yarn-project/circuit-types/src/p2p/mocks.ts | 7 ++----- .../circuit-types/src/p2p/signature_utils.ts | 7 +++++-- .../sequencer-client/src/publisher/l1-publisher.ts | 2 +- .../src/duties/validation_service.ts | 12 ++++++++++-- 7 files changed, 25 insertions(+), 13 deletions(-) diff --git a/yarn-project/circuit-types/src/p2p/block_attestation.ts b/yarn-project/circuit-types/src/p2p/block_attestation.ts index 5b229d55af7..04ccfdf4d52 100644 --- a/yarn-project/circuit-types/src/p2p/block_attestation.ts +++ b/yarn-project/circuit-types/src/p2p/block_attestation.ts @@ -7,7 +7,7 @@ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { ConsensusPayload } from './consensus_payload.js'; import { Gossipable } from './gossipable.js'; -import { getHashedSignaturePayloadEthSignedMessage, SignatureDomainSeperator } from './signature_utils.js'; +import { SignatureDomainSeperator, getHashedSignaturePayloadEthSignedMessage } from './signature_utils.js'; import { TopicType, createTopicString } from './topic_type.js'; export class BlockAttestationHash extends Buffer32 { diff --git a/yarn-project/circuit-types/src/p2p/block_proposal.ts b/yarn-project/circuit-types/src/p2p/block_proposal.ts index e9268c86853..8e64f4c1fd9 100644 --- a/yarn-project/circuit-types/src/p2p/block_proposal.ts +++ b/yarn-project/circuit-types/src/p2p/block_proposal.ts @@ -7,7 +7,11 @@ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { ConsensusPayload } from './consensus_payload.js'; import { Gossipable } from './gossipable.js'; -import { getHashedSignaturePayload, getHashedSignaturePayloadEthSignedMessage, SignatureDomainSeperator } from './signature_utils.js'; +import { + SignatureDomainSeperator, + getHashedSignaturePayload, + getHashedSignaturePayloadEthSignedMessage, +} from './signature_utils.js'; import { TopicType, createTopicString } from './topic_type.js'; export class BlockProposalHash extends Buffer32 { diff --git a/yarn-project/circuit-types/src/p2p/consensus_payload.ts b/yarn-project/circuit-types/src/p2p/consensus_payload.ts index 0b96939120f..f6b70a5f354 100644 --- a/yarn-project/circuit-types/src/p2p/consensus_payload.ts +++ b/yarn-project/circuit-types/src/p2p/consensus_payload.ts @@ -6,7 +6,7 @@ import { type FieldsOf } from '@aztec/foundation/types'; import { encodeAbiParameters, parseAbiParameters } from 'viem'; import { TxHash } from '../tx/tx_hash.js'; -import { SignatureDomainSeperator, type Signable } from './signature_utils.js'; +import { type Signable, type SignatureDomainSeperator } from './signature_utils.js'; export class ConsensusPayload implements Signable { private size: number | undefined; diff --git a/yarn-project/circuit-types/src/p2p/mocks.ts b/yarn-project/circuit-types/src/p2p/mocks.ts index e1287dc8672..821d4fd3b4b 100644 --- a/yarn-project/circuit-types/src/p2p/mocks.ts +++ b/yarn-project/circuit-types/src/p2p/mocks.ts @@ -7,7 +7,7 @@ import { TxHash } from '../tx/tx_hash.js'; import { BlockAttestation } from './block_attestation.js'; import { BlockProposal } from './block_proposal.js'; import { ConsensusPayload } from './consensus_payload.js'; -import { getHashedSignaturePayloadEthSignedMessage, SignatureDomainSeperator } from './signature_utils.js'; +import { SignatureDomainSeperator, getHashedSignaturePayloadEthSignedMessage } from './signature_utils.js'; export interface MakeConsensusPayloadOptions { signer?: Secp256k1Signer; @@ -46,9 +46,6 @@ export const makeBlockProposal = (options?: MakeConsensusPayloadOptions): BlockP // TODO(https://github.com/AztecProtocol/aztec-packages/issues/8028) export const makeBlockAttestation = (options?: MakeConsensusPayloadOptions): BlockAttestation => { - const { payload, signature } = makeAndSignConsensusPayload( - SignatureDomainSeperator.blockAttestation, - options, - ); + const { payload, signature } = makeAndSignConsensusPayload(SignatureDomainSeperator.blockAttestation, options); return new BlockAttestation(payload, signature); }; diff --git a/yarn-project/circuit-types/src/p2p/signature_utils.ts b/yarn-project/circuit-types/src/p2p/signature_utils.ts index 5c70c1862d1..25e20ded5d8 100644 --- a/yarn-project/circuit-types/src/p2p/signature_utils.ts +++ b/yarn-project/circuit-types/src/p2p/signature_utils.ts @@ -3,7 +3,7 @@ import { keccak256, makeEthSignDigest } from '@aztec/foundation/crypto'; export enum SignatureDomainSeperator { blockProposal = 0, - blockAttestation = 1 + blockAttestation = 1, } export interface Signable { @@ -24,7 +24,10 @@ export function getHashedSignaturePayload(s: Signable, domainSeperator: Signatur * @param s - the `Signable` to sign * @returns The hashed payload for the signature of the `Signable` as an Ethereum signed message */ -export function getHashedSignaturePayloadEthSignedMessage(s: Signable, domainSeperator: SignatureDomainSeperator): Buffer32 { +export function getHashedSignaturePayloadEthSignedMessage( + s: Signable, + domainSeperator: SignatureDomainSeperator, +): Buffer32 { const payload = getHashedSignaturePayload(s, domainSeperator); return makeEthSignDigest(payload); } diff --git a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts index c3840e3963d..1553e4e07a5 100644 --- a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts +++ b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts @@ -3,9 +3,9 @@ import { type EpochProofClaim, type EpochProofQuote, type L2Block, + SignatureDomainSeperator, type TxHash, getHashedSignaturePayload, - SignatureDomainSeperator, } from '@aztec/circuit-types'; import { type L1PublishBlockStats, type L1PublishProofStats } from '@aztec/circuit-types/stats'; import { diff --git a/yarn-project/validator-client/src/duties/validation_service.ts b/yarn-project/validator-client/src/duties/validation_service.ts index 6bb9d279be9..ee5718b2e00 100644 --- a/yarn-project/validator-client/src/duties/validation_service.ts +++ b/yarn-project/validator-client/src/duties/validation_service.ts @@ -1,4 +1,10 @@ -import { BlockAttestation, BlockProposal, ConsensusPayload, SignatureDomainSeperator, type TxHash } from '@aztec/circuit-types'; +import { + BlockAttestation, + BlockProposal, + ConsensusPayload, + SignatureDomainSeperator, + type TxHash, +} from '@aztec/circuit-types'; import { type Header } from '@aztec/circuits.js'; import { Buffer32 } from '@aztec/foundation/buffer'; import { keccak256 } from '@aztec/foundation/crypto'; @@ -36,7 +42,9 @@ export class ValidationService { async attestToProposal(proposal: BlockProposal): Promise { // TODO(https://github.com/AztecProtocol/aztec-packages/issues/7961): check that the current validator is correct - const buf = Buffer32.fromBuffer(keccak256(proposal.payload.getPayloadToSign(SignatureDomainSeperator.blockAttestation))); + const buf = Buffer32.fromBuffer( + keccak256(proposal.payload.getPayloadToSign(SignatureDomainSeperator.blockAttestation)), + ); const sig = await this.keyStore.signMessage(buf); return new BlockAttestation(proposal.payload, sig); } From 4e12ba9b5f3be4241350c9169cc35a385b91d072 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Fri, 8 Nov 2024 16:03:00 +0000 Subject: [PATCH 3/3] fix --- l1-contracts/test/sparta/Sparta.t.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/l1-contracts/test/sparta/Sparta.t.sol b/l1-contracts/test/sparta/Sparta.t.sol index e892c5e54a5..caaac46645f 100644 --- a/l1-contracts/test/sparta/Sparta.t.sol +++ b/l1-contracts/test/sparta/Sparta.t.sol @@ -189,7 +189,8 @@ contract SpartaTest is DecoderBase { SignatureLib.Signature[] memory signatures = new SignatureLib.Signature[](_signatureCount); - bytes32 digest = keccak256(abi.encode(archive, txHashes)); + uint8 domainSeperator = uint8(SignatureLib.SignatureDomainSeperator.blockAttestation); + bytes32 digest = keccak256(abi.encode(domainSeperator, archive, txHashes)); for (uint256 i = 0; i < _signatureCount; i++) { signatures[i] = createSignature(validators[i], digest); }