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
4 changes: 2 additions & 2 deletions yarn-project/blob-lib/src/sponge_blob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ export class Poseidon2Sponge {
static fromBuffer(buffer: Buffer | BufferReader): Poseidon2Sponge {
const reader = BufferReader.asReader(buffer);
return new Poseidon2Sponge(
reader.readArray(3, Fr),
reader.readArray(4, Fr),
reader.readTuple(3, Fr),
reader.readTuple(4, Fr),
reader.readNumber(),
reader.readBoolean(),
);
Expand Down
35 changes: 29 additions & 6 deletions yarn-project/foundation/src/serialize/buffer_reader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,16 +286,39 @@ export class BufferReader {
}

/**
* Read an array of a fixed size with elements of type T from the buffer.
* The 'itemDeserializer' object should have a 'fromBuffer' method that takes a BufferReader instance as input,
* and returns an instance of the desired deserialized data type T.
* This method will call the 'fromBuffer' method for each element in the array and return the resulting array.
* Read an array from the buffer using lazy allocation (new Array + loop).
* Safe for use with untrusted sizes — does not pre-allocate memory proportional to size.
*
* @param size - The fixed number of elements in the array.
* @param size - The number of elements to read.
* @param itemDeserializer - An object with a 'fromBuffer' method to deserialize individual elements of type T.
* @returns An array of instances of type T.
*/
public readArray<T, N extends number>(
public readArray<T>(
size: number,
itemDeserializer: {
/**
* A function for deserializing data from a BufferReader instance.
*/
fromBuffer: (reader: BufferReader) => T;
},
): T[] {
const result = new Array<T>(size);
for (let i = 0; i < size; i++) {
result[i] = itemDeserializer.fromBuffer(this);
}
return result;
}

/**
* Read a fixed-size tuple from the buffer using dense allocation (Array.from).
* Only use with compile-time constant sizes — the size parameter MUST NOT come from untrusted input
* as Array.from pre-allocates memory proportional to size.
*
* @param size - The fixed number of elements (must be a compile-time constant).
* @param itemDeserializer - An object with a 'fromBuffer' method to deserialize individual elements of type T.
* @returns A densely-allocated tuple of instances of type T.
*/
public readTuple<T, N extends number>(
size: N,
itemDeserializer: {
/**
Expand Down
26 changes: 22 additions & 4 deletions yarn-project/foundation/src/serialize/field_reader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,30 @@ export class FieldReader {
* @param itemDeserializer - An object with a 'fromFields' method to deserialize individual elements of type T.
* @returns An array of instances of type T.
*/
public readArray<T, N extends number>(
/**
* Read an array from the field array using lazy allocation (new Array + loop).
* Safe for use with untrusted sizes.
*/
public readArray<T>(
size: number,
itemDeserializer: {
fromFields: (reader: FieldReader) => T;
},
): T[] {
const result = new Array<T>(size);
for (let i = 0; i < size; i++) {
result[i] = itemDeserializer.fromFields(this);
}
return result;
}

/**
* Read a fixed-size tuple from the field array using dense allocation (Array.from).
* Only use with compile-time constant sizes — the size parameter MUST NOT come from untrusted input.
*/
public readTuple<T, N extends number>(
size: N,
itemDeserializer: {
/**
* A function for deserializing data from a FieldReader instance.
*/
fromFields: (reader: FieldReader) => T;
},
): Tuple<T, N> {
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/foundation/src/trees/membership_witness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export class MembershipWitness<N extends number> {
static fromBuffer<N extends number>(buffer: Buffer | BufferReader, size: N): MembershipWitness<N> {
const reader = BufferReader.asReader(buffer);
const leafIndex = toBigIntBE(reader.readBytes(32));
const siblingPath = reader.readArray(size, Fr);
const siblingPath = reader.readArray(size, Fr) as Tuple<Fr, N>;
return new MembershipWitness(size, leafIndex, siblingPath);
}

Expand All @@ -108,7 +108,7 @@ export class MembershipWitness<N extends number> {
fromBuffer: (buffer: Buffer | BufferReader) => {
const reader = BufferReader.asReader(buffer);
const leafIndex = toBigIntBE(reader.readBytes(32));
const siblingPath = reader.readArray(size, Fr);
const siblingPath = reader.readArray(size, Fr) as Tuple<Fr, N>;
return new MembershipWitness(size, leafIndex, siblingPath);
},
};
Expand Down
12 changes: 6 additions & 6 deletions yarn-project/stdlib/src/avm/avm_accumulated_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,11 @@ export class AvmAccumulatedData {
static fromBuffer(buffer: Buffer | BufferReader) {
const reader = BufferReader.asReader(buffer);
return new this(
reader.readArray(MAX_NOTE_HASHES_PER_TX, Fr),
reader.readArray(MAX_NULLIFIERS_PER_TX, Fr),
reader.readArray(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message),
reader.readTuple(MAX_NOTE_HASHES_PER_TX, Fr),
reader.readTuple(MAX_NULLIFIERS_PER_TX, Fr),
reader.readTuple(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message),
reader.readObject(FlatPublicLogs),
reader.readArray(MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataWrite),
reader.readTuple(MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataWrite),
);
}

Expand All @@ -115,9 +115,9 @@ export class AvmAccumulatedData {
return new this(
reader.readFieldArray(MAX_NOTE_HASHES_PER_TX),
reader.readFieldArray(MAX_NULLIFIERS_PER_TX),
reader.readArray(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message),
reader.readTuple(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message),
reader.readObject(FlatPublicLogs),
reader.readArray(MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataWrite),
reader.readTuple(MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataWrite),
);
}

Expand Down
8 changes: 4 additions & 4 deletions yarn-project/stdlib/src/avm/avm_circuit_public_inputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ export class AvmCircuitPublicInputs {
reader.readObject(AztecAddress),
reader.readObject(Fr),
reader.readObject(PublicCallRequestArrayLengths),
reader.readArray(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest),
reader.readArray(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest),
reader.readTuple(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest),
reader.readTuple(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest),
reader.readObject(PublicCallRequest),
reader.readObject(PrivateToAvmAccumulatedDataArrayLengths),
reader.readObject(PrivateToAvmAccumulatedDataArrayLengths),
Expand Down Expand Up @@ -206,8 +206,8 @@ export class AvmCircuitPublicInputs {
AztecAddress.fromFields(reader),
reader.readField(),
PublicCallRequestArrayLengths.fromFields(reader),
reader.readArray(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest),
reader.readArray(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest),
reader.readTuple(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest),
reader.readTuple(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest),
PublicCallRequest.fromFields(reader),
PrivateToAvmAccumulatedDataArrayLengths.fromFields(reader),
PrivateToAvmAccumulatedDataArrayLengths.fromFields(reader),
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/stdlib/src/kernel/claimed_length_array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class ClaimedLengthArray<T extends Serializable, N extends number> {
arrayLength: N,
): ClaimedLengthArray<T, N> {
const reader = BufferReader.asReader(buffer);
const array = reader.readArray(arrayLength, deserializer);
const array = reader.readArray(arrayLength, deserializer) as Tuple<T, N>;
const claimedLength = reader.readNumber();
return new ClaimedLengthArray(array, claimedLength);
}
Expand All @@ -42,7 +42,7 @@ export class ClaimedLengthArray<T extends Serializable, N extends number> {
arrayLength: N,
): ClaimedLengthArray<T, N> {
const reader = FieldReader.asReader(fields);
const array = reader.readArray(arrayLength, deserializer);
const array = reader.readTuple(arrayLength, deserializer);
const claimedLength = reader.readU32();
return new ClaimedLengthArray(array, claimedLength);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,11 @@ export class PrivateKernelResetHints<
fromBuffer: buf =>
nullifierReadRequestHintsFromBuffer(buf, numNullifierReadRequestPending, numNullifierReadRequestSettled),
}),
reader.readArray(numKeyValidationHints, KeyValidationHint),
reader.readArray(numTransientDataSquashingHints, TransientDataSquashingHint),
reader.readArray(numKeyValidationHints, KeyValidationHint) as Tuple<KeyValidationHint, KEY_VALIDATION_HINTS_LEN>,
reader.readArray(numTransientDataSquashingHints, TransientDataSquashingHint) as Tuple<
TransientDataSquashingHint,
TRANSIENT_DATA_HINTS_LEN
>,
);
}
}
6 changes: 3 additions & 3 deletions yarn-project/stdlib/src/kernel/hints/read_request_hints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,11 @@ export class ReadRequestResetHints<
> {
const reader = BufferReader.asReader(buffer);
return new ReadRequestResetHints(
reader.readArray(readRequestLen, ReadRequestAction),
reader.readArray(numPendingReads, PendingReadHint),
reader.readArray(readRequestLen, ReadRequestAction) as Tuple<ReadRequestAction, READ_REQUEST_LEN>,
reader.readArray(numPendingReads, PendingReadHint) as Tuple<PendingReadHint, PENDING_READ_HINTS_LEN>,
reader.readArray(numSettledReads, {
fromBuffer: r => SettledReadHint.fromBuffer(r, treeHeight, leafPreimageFromBuffer),
}),
}) as Tuple<SettledReadHint<TREE_HEIGHT, LEAF_PREIMAGE>, SETTLED_READ_HINTS_LEN>,
);
}

Expand Down
6 changes: 3 additions & 3 deletions yarn-project/stdlib/src/kernel/padded_side_effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ export class PaddedSideEffects {
static fromBuffer(buffer: Buffer | BufferReader) {
const reader = BufferReader.asReader(buffer);
return new PaddedSideEffects(
reader.readArray(MAX_NOTE_HASHES_PER_TX, Fr),
reader.readArray(MAX_NULLIFIERS_PER_TX, Fr),
reader.readArray(MAX_PRIVATE_LOGS_PER_TX, PrivateLog),
reader.readTuple(MAX_NOTE_HASHES_PER_TX, Fr),
reader.readTuple(MAX_NULLIFIERS_PER_TX, Fr),
reader.readTuple(MAX_PRIVATE_LOGS_PER_TX, PrivateLog),
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export class PrivateToAvmAccumulatedData {
return new this(
reader.readFieldArray(MAX_NOTE_HASHES_PER_TX),
reader.readFieldArray(MAX_NULLIFIERS_PER_TX),
reader.readArray(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message),
reader.readTuple(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message),
);
}

Expand All @@ -94,9 +94,9 @@ export class PrivateToAvmAccumulatedData {
static fromBuffer(buffer: Buffer | BufferReader) {
const reader = BufferReader.asReader(buffer);
return new PrivateToAvmAccumulatedData(
reader.readArray(MAX_NOTE_HASHES_PER_TX, Fr),
reader.readArray(MAX_NULLIFIERS_PER_TX, Fr),
reader.readArray(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message),
reader.readTuple(MAX_NOTE_HASHES_PER_TX, Fr),
reader.readTuple(MAX_NULLIFIERS_PER_TX, Fr),
reader.readTuple(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message),
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ export class PrivateToPublicAccumulatedData {
return new this(
reader.readFieldArray(MAX_NOTE_HASHES_PER_TX),
reader.readFieldArray(MAX_NULLIFIERS_PER_TX),
reader.readArray(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message),
reader.readArray(MAX_PRIVATE_LOGS_PER_TX, PrivateLog),
reader.readArray(MAX_CONTRACT_CLASS_LOGS_PER_TX, ScopedLogHash),
reader.readArray(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest),
reader.readTuple(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message),
reader.readTuple(MAX_PRIVATE_LOGS_PER_TX, PrivateLog),
reader.readTuple(MAX_CONTRACT_CLASS_LOGS_PER_TX, ScopedLogHash),
reader.readTuple(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest),
);
}

Expand All @@ -76,12 +76,12 @@ export class PrivateToPublicAccumulatedData {
static fromBuffer(buffer: Buffer | BufferReader) {
const reader = BufferReader.asReader(buffer);
return new PrivateToPublicAccumulatedData(
reader.readArray(MAX_NOTE_HASHES_PER_TX, Fr),
reader.readArray(MAX_NULLIFIERS_PER_TX, Fr),
reader.readArray(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message),
reader.readArray(MAX_PRIVATE_LOGS_PER_TX, PrivateLog),
reader.readArray(MAX_CONTRACT_CLASS_LOGS_PER_TX, ScopedLogHash),
reader.readArray(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest),
reader.readTuple(MAX_NOTE_HASHES_PER_TX, Fr),
reader.readTuple(MAX_NULLIFIERS_PER_TX, Fr),
reader.readTuple(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message),
reader.readTuple(MAX_PRIVATE_LOGS_PER_TX, PrivateLog),
reader.readTuple(MAX_CONTRACT_CLASS_LOGS_PER_TX, ScopedLogHash),
reader.readTuple(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest),
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,11 @@ export class PrivateToRollupAccumulatedData {
static fromBuffer(buffer: Buffer | BufferReader): PrivateToRollupAccumulatedData {
const reader = BufferReader.asReader(buffer);
return new PrivateToRollupAccumulatedData(
reader.readArray(MAX_NOTE_HASHES_PER_TX, Fr),
reader.readArray(MAX_NULLIFIERS_PER_TX, Fr),
reader.readArray(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message),
reader.readArray(MAX_PRIVATE_LOGS_PER_TX, PrivateLog),
reader.readArray(MAX_CONTRACT_CLASS_LOGS_PER_TX, ScopedLogHash),
reader.readTuple(MAX_NOTE_HASHES_PER_TX, Fr),
reader.readTuple(MAX_NULLIFIERS_PER_TX, Fr),
reader.readTuple(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message),
reader.readTuple(MAX_PRIVATE_LOGS_PER_TX, PrivateLog),
reader.readTuple(MAX_CONTRACT_CLASS_LOGS_PER_TX, ScopedLogHash),
);
}

Expand Down
2 changes: 1 addition & 1 deletion yarn-project/stdlib/src/logs/private_log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export class PrivateLog {

static fromBuffer(buffer: Buffer | BufferReader) {
const reader = BufferReader.asReader(buffer);
return new PrivateLog(reader.readArray(PRIVATE_LOG_SIZE_IN_FIELDS, Fr), reader.readNumber());
return new PrivateLog(reader.readTuple(PRIVATE_LOG_SIZE_IN_FIELDS, Fr), reader.readNumber());
}

static random(tag = Fr.random()) {
Expand Down
12 changes: 11 additions & 1 deletion yarn-project/stdlib/src/logs/public_log.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { FLAT_PUBLIC_LOGS_PAYLOAD_LENGTH, PUBLIC_LOG_HEADER_LENGTH } from '@aztec/constants';
import {
FLAT_PUBLIC_LOGS_PAYLOAD_LENGTH,
MAX_PUBLIC_LOG_SIZE_IN_FIELDS,
PUBLIC_LOG_HEADER_LENGTH,
} from '@aztec/constants';
import type { FieldsOf } from '@aztec/foundation/array';
import { Fr } from '@aztec/foundation/curves/bn254';
import { type ZodFor, schemas } from '@aztec/foundation/schemas';
Expand Down Expand Up @@ -76,6 +80,9 @@ export class FlatPublicLogs {
static fromBuffer(buffer: Buffer | BufferReader) {
const reader = BufferReader.asReader(buffer);
const length = reader.readNumber();
if (length > FLAT_PUBLIC_LOGS_PAYLOAD_LENGTH) {
throw new Error(`FlatPublicLogs length ${length} exceeds maximum ${FLAT_PUBLIC_LOGS_PAYLOAD_LENGTH}`);
}
return this.fromUnpaddedPayload(reader.readArray(length, Fr));
}

Expand Down Expand Up @@ -171,6 +178,9 @@ export class PublicLog {
static fromBuffer(buffer: Buffer | BufferReader) {
const reader = BufferReader.asReader(buffer);
const fieldsLength = reader.readNumber();
if (fieldsLength > MAX_PUBLIC_LOG_SIZE_IN_FIELDS) {
throw new Error(`PublicLog fields length ${fieldsLength} exceeds maximum ${MAX_PUBLIC_LOG_SIZE_IN_FIELDS}`);
}
return new PublicLog(reader.readObject(AztecAddress), reader.readArray(fieldsLength, Fr));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export class ParityBasePrivateInputs {
*/
static fromBuffer(buffer: Buffer | BufferReader) {
const reader = BufferReader.asReader(buffer);
return new ParityBasePrivateInputs(reader.readArray(NUM_MSGS_PER_BASE_PARITY, Fr), Fr.fromBuffer(reader));
return new ParityBasePrivateInputs(reader.readTuple(NUM_MSGS_PER_BASE_PARITY, Fr), Fr.fromBuffer(reader));
}

/**
Expand Down
10 changes: 9 additions & 1 deletion yarn-project/stdlib/src/proofs/chonk_proof.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ export class ChonkProof {
static fromBuffer(buffer: Buffer | BufferReader): ChonkProof {
const reader = BufferReader.asReader(buffer);
const proofLength = reader.readNumber();
const proof = reader.readArray(proofLength, Fr);
if (proofLength !== CHONK_PROOF_LENGTH) {
throw new Error(`Invalid ChonkProof length from buffer: ${proofLength}, expected ${CHONK_PROOF_LENGTH}`);
}
const proof = reader.readArray(CHONK_PROOF_LENGTH, Fr);
return new ChonkProof(proof);
}

Expand Down Expand Up @@ -106,6 +109,11 @@ export class ChonkProofWithPublicInputs {
static fromBuffer(buffer: Buffer | BufferReader): ChonkProofWithPublicInputs {
const reader = BufferReader.asReader(buffer);
const proofLength = reader.readNumber();
if (proofLength < CHONK_PROOF_LENGTH) {
throw new Error(
`Invalid ChonkProofWithPublicInputs length from buffer: ${proofLength}, expected at least ${CHONK_PROOF_LENGTH}`,
);
}
const proof = reader.readArray(proofLength, Fr);
return new ChonkProofWithPublicInputs(proof);
}
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/stdlib/src/rollup/base_rollup_hints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export class PrivateBaseRollupHints {
reader.readObject(SpongeBlob),
reader.readObject(TreeSnapshotDiffHints),
reader.readObject(PublicDataTreeLeafPreimage),
reader.readArray(ARCHIVE_HEIGHT, Fr),
reader.readTuple(ARCHIVE_HEIGHT, Fr),
makeTuple(MAX_CONTRACT_CLASS_LOGS_PER_TX, () => reader.readObject(ContractClassLogFields)),
reader.readObject(BlockConstantData),
);
Expand Down Expand Up @@ -163,7 +163,7 @@ export class PublicBaseRollupHints {
return new PublicBaseRollupHints(
reader.readObject(SpongeBlob),
reader.readObject(AppendOnlyTreeSnapshot),
reader.readArray(ARCHIVE_HEIGHT, Fr),
reader.readTuple(ARCHIVE_HEIGHT, Fr),
makeTuple(MAX_CONTRACT_CLASS_LOGS_PER_TX, () => reader.readObject(ContractClassLogFields)),
);
}
Expand Down
Loading
Loading