22// Copyright 2024 Aztec Labs.
33pragma solidity ^ 0.8.27 ;
44
5+ import {Errors} from "@aztec/core/libraries/Errors.sol " ;
56import {Signature, SignatureLib} from "@aztec/shared/libraries/SignatureLib.sol " ;
67
78/**
@@ -71,7 +72,7 @@ library AttestationLib {
7172 returns (Signature memory )
7273 {
7374 bytes memory signaturesOrAddresses = _attestations.signaturesOrAddresses;
74- require (isSignature (_attestations, _index), " Not a signature at this index " );
75+ require (isSignature (_attestations, _index), Errors. AttestationLib__NotASignatureAtIndex (_index) );
7576
7677 uint256 dataPtr;
7778 assembly {
@@ -105,7 +106,7 @@ library AttestationLib {
105106 */
106107 function getAddress (CommitteeAttestations memory _attestations , uint256 _index ) internal pure returns (address ) {
107108 bytes memory signaturesOrAddresses = _attestations.signaturesOrAddresses;
108- require (! isSignature (_attestations, _index), " A signature at this index " );
109+ require (! isSignature (_attestations, _index), Errors. AttestationLib__NotAnAddressAtIndex (_index) );
109110
110111 uint256 dataPtr;
111112 assembly {
@@ -126,9 +127,56 @@ library AttestationLib {
126127 return addr;
127128 }
128129
130+ /**
131+ * @notice Assert that the size of `_attestations` is as expected, throw otherwise
132+ *
133+ * @custom:reverts SignatureIndicesSizeMismatch if the signature indices have a wrong size
134+ * @custom:reverts SignaturesOrAddressesSizeMismatch if the signatures or addresses object has wrong size
135+ *
136+ * @param _attestations - The attestation struct
137+ * @param _expectedCount - The expected size of the validator set
138+ */
139+ function assertSizes (CommitteeAttestations memory _attestations , uint256 _expectedCount ) internal pure {
140+ // Count signatures (1s) and addresses (0s) from bitmap
141+ uint256 signatureCount = 0 ;
142+ uint256 addressCount = 0 ;
143+ uint256 bitmapBytes = (_expectedCount + 7 ) / 8 ; // Round up to nearest byte
144+ require (
145+ bitmapBytes == _attestations.signatureIndices.length ,
146+ Errors.AttestationLib__SignatureIndicesSizeMismatch (bitmapBytes, _attestations.signatureIndices.length )
147+ );
148+
149+ for (uint256 i = 0 ; i < _expectedCount; i++ ) {
150+ uint256 byteIndex = i / 8 ;
151+ uint256 bitIndex = 7 - (i % 8 );
152+ uint8 bitMask = uint8 (1 << bitIndex);
153+
154+ if (uint8 (_attestations.signatureIndices[byteIndex]) & bitMask != 0 ) {
155+ signatureCount++ ;
156+ } else {
157+ addressCount++ ;
158+ }
159+ }
160+
161+ // Calculate expected size
162+ uint256 sizeOfSignaturesAndAddresses = (signatureCount * SIGNATURE_LENGTH) + (addressCount * ADDRESS_LENGTH);
163+
164+ // Validate actual size matches expected
165+ require (
166+ sizeOfSignaturesAndAddresses == _attestations.signaturesOrAddresses.length ,
167+ Errors.AttestationLib__SignaturesOrAddressesSizeMismatch (
168+ sizeOfSignaturesAndAddresses, _attestations.signaturesOrAddresses.length
169+ )
170+ );
171+ }
172+
129173 /**
130174 * Recovers the committee from the addresses in the attestations and signers.
131175 *
176+ * @custom:reverts SignatureIndicesSizeMismatch if the signature indices have a wrong size
177+ * @custom:reverts OutOfBounds throws if reading data beyond the `_attestations`
178+ * @custom:reverts SignaturesOrAddressesSizeMismatch if the signatures or addresses object has wrong size
179+ *
132180 * @param _attestations - The committee attestations
133181 * @param _signers The addresses of the committee members that signed the attestations. Provided in order to not have
134182 * to recover them from their attestations' signatures (and hence save gas). The addresses of the non-signing
@@ -141,8 +189,14 @@ library AttestationLib {
141189 address [] memory _signers ,
142190 uint256 _length
143191 ) internal pure returns (address [] memory ) {
192+ uint256 bitmapBytes = (_length + 7 ) / 8 ; // Round up to nearest byte
193+ require (
194+ bitmapBytes == _attestations.signatureIndices.length ,
195+ Errors.AttestationLib__SignatureIndicesSizeMismatch (bitmapBytes, _attestations.signatureIndices.length )
196+ );
197+
198+ // To get a ref that we can easily use with the assembly down below.
144199 bytes memory signaturesOrAddresses = _attestations.signaturesOrAddresses;
145- bytes memory signatureIndices = _attestations.signatureIndices;
146200 address [] memory addresses = new address [](_length);
147201
148202 uint256 signersIndex;
@@ -154,12 +208,13 @@ library AttestationLib {
154208 // Skip length
155209 dataPtr := add (signaturesOrAddresses, 0x20 )
156210 }
211+ uint256 offset = dataPtr;
157212
158213 for (uint256 i = 0 ; i < _length; ++ i) {
159214 // Load new byte every 8 iterations
160215 if (i % 8 == 0 ) {
161216 uint256 byteIndex = i / 8 ;
162- currentByte = uint8 (signatureIndices[byteIndex]);
217+ currentByte = uint8 (_attestations. signatureIndices[byteIndex]);
163218 bitMask = 128 ; // 0b10000000
164219 }
165220
@@ -180,6 +235,23 @@ library AttestationLib {
180235 }
181236 }
182237
238+ // Ensure that the reads were within the boundaries of the data.
239+ // As `dataPtr` will always be increasing (and unlikely to wrap around because it would require insane size)
240+ // we can just check that the last dataPtr value is inside the limit, as all the others would be as well then.
241+ uint256 upperLimit = offset + _attestations.signaturesOrAddresses.length ;
242+ // As the offset was added already part of both values, we can subtract to give a more meaningful error.
243+ require (dataPtr <= upperLimit, Errors.AttestationLib__OutOfBounds (dataPtr - offset, upperLimit - offset));
244+
245+ // Ensure that the size of data provided actually matches what we expect
246+ uint256 sizeOfSignaturesAndAddresses =
247+ (signersIndex * SIGNATURE_LENGTH) + ((_length - signersIndex) * ADDRESS_LENGTH);
248+ require (
249+ sizeOfSignaturesAndAddresses == _attestations.signaturesOrAddresses.length ,
250+ Errors.AttestationLib__SignaturesOrAddressesSizeMismatch (
251+ sizeOfSignaturesAndAddresses, _attestations.signaturesOrAddresses.length
252+ )
253+ );
254+
183255 return addresses;
184256 }
185257
0 commit comments