Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
benesjan committed Jun 18, 2024
1 parent a453d0e commit 12ddea2
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ describe('L1 Note Payload', () => {
it('decrypt a log as incoming', () => {
const recreated = L1NotePayload.decryptAsIncoming(encrypted, ivskM);

expect(recreated.toBuffer()).toEqual(payload.toBuffer());
expect(recreated!.toBuffer()).toEqual(payload.toBuffer());
});

it('decrypt a log as outgoing', () => {
const recreated = L1NotePayload.decryptAsOutgoing(encrypted, ovskM);

expect(recreated.toBuffer()).toEqual(payload.toBuffer());
expect(recreated!.toBuffer()).toEqual(payload.toBuffer());
});
});

Expand Down
38 changes: 35 additions & 3 deletions yarn-project/circuit-types/src/logs/l1_payload/l1_note_payload.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
import { AztecAddress, type GrumpkinPrivateKey, type KeyValidationRequest, type PublicKey } from '@aztec/circuits.js';
import { randomBytes } from '@aztec/foundation/crypto';
import { Fr } from '@aztec/foundation/fields';
import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';

import { EncryptedNoteLogIncomingBody } from './encrypted_log_incoming_body/index.js';
import { L1Payload } from './l1_payload.js';
import { Note } from './payload.js';

// Note type id can occupy only 4 bytes. The rest is 0 and is used to determine whether a note was successfully
// decrypted in tagged_log.ts
const NUM_BYTES_PER_NOTE_TYPE_ID = 4;

function isNoteTypeIdValid(noteTypeId: Fr): boolean {
const buf = noteTypeId.toBuffer();
// check that the first 28 bytes are zero
return !buf.subarray(0, Fr.SIZE_IN_BYTES - NUM_BYTES_PER_NOTE_TYPE_ID).some(x => x !== 0);
}

/**
* A class which wraps note data which is pushed on L1.
* @remarks This data is required to compute a nullifier/to spend a note. Along with that this class contains
Expand All @@ -31,6 +42,9 @@ export class L1NotePayload extends L1Payload {
public noteTypeId: Fr,
) {
super();
if (!isNoteTypeIdValid(noteTypeId)) {
throw new Error('NoteTypeId should occupy only 4 bytes');
}
}

/**
Expand Down Expand Up @@ -62,7 +76,13 @@ export class L1NotePayload extends L1Payload {
* @returns A random L1NotePayload object.
*/
static random(contract = AztecAddress.random()) {
return new L1NotePayload(Note.random(), contract, Fr.random(), Fr.random());
const noteTypeId = Fr.fromBuffer(
Buffer.concat([
Buffer.alloc(Fr.SIZE_IN_BYTES - NUM_BYTES_PER_NOTE_TYPE_ID),
randomBytes(NUM_BYTES_PER_NOTE_TYPE_ID),
]),
);
return new L1NotePayload(Note.random(), contract, Fr.random(), noteTypeId);
}

public encrypt(ephSk: GrumpkinPrivateKey, recipient: AztecAddress, ivpk: PublicKey, ovKeys: KeyValidationRequest) {
Expand Down Expand Up @@ -98,7 +118,13 @@ export class L1NotePayload extends L1Payload {
EncryptedNoteLogIncomingBody.fromCiphertext,
);

return new L1NotePayload(incomingBody.note, address, incomingBody.storageSlot, incomingBody.noteTypeId);
if (isNoteTypeIdValid(incomingBody.noteTypeId)) {
// We received valid note type id, hence the encryption was performed correctly
return new L1NotePayload(incomingBody.note, address, incomingBody.storageSlot, incomingBody.noteTypeId);
}

// We failed to decrypt the note, return undefined
return undefined;
}

/**
Expand All @@ -124,7 +150,13 @@ export class L1NotePayload extends L1Payload {
EncryptedNoteLogIncomingBody.fromCiphertext,
);

return new L1NotePayload(incomingBody.note, address, incomingBody.storageSlot, incomingBody.noteTypeId);
if (isNoteTypeIdValid(incomingBody.noteTypeId)) {
// We received valid note type id, hence the encryption was performed correctly
return new L1NotePayload(incomingBody.note, address, incomingBody.storageSlot, incomingBody.noteTypeId);
}

// We failed to decrypt the note, return undefined
return undefined;
}

public equals(other: L1NotePayload) {
Expand Down
60 changes: 34 additions & 26 deletions yarn-project/circuit-types/src/logs/l1_payload/tagged_log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,26 +78,30 @@ export class TaggedLog<Payload extends L1NotePayload | L1EventPayload> {
ivsk: GrumpkinPrivateKey,
payloadType: typeof L1NotePayload | typeof L1EventPayload = L1NotePayload,
): TaggedLog<L1NotePayload | L1EventPayload> | undefined {
// Right now heavily abusing that we will likely fail if bad decryption
// as some field will likely end up not being in the field etc.
try {
if (payloadType === L1EventPayload) {
if (payloadType === L1EventPayload) {
// Right now heavily abusing that we will likely fail if bad decryption
// as some field will likely end up not being in the field etc.
try {
const reader = BufferReader.asReader((data as EncryptedL2Log).data);
const incomingTag = Fr.fromBuffer(reader);
const outgoingTag = Fr.fromBuffer(reader);
// We must pass the entire encrypted log in. The tags are not stripped here from the original data
const payload = L1EventPayload.decryptAsIncoming(data as EncryptedL2Log, ivsk);
return new TaggedLog(payload, incomingTag, outgoingTag);
} else {
const input = Buffer.isBuffer(data) ? data : Buffer.from((data as bigint[]).map((x: bigint) => Number(x)));
const reader = BufferReader.asReader(input);
const incomingTag = Fr.fromBuffer(reader);
const outgoingTag = Fr.fromBuffer(reader);
const payload = L1NotePayload.decryptAsIncoming(reader.readToEnd(), ivsk);
return new TaggedLog(payload, incomingTag, outgoingTag);
} catch (e) {
return;
}
} else {
const input = Buffer.isBuffer(data) ? data : Buffer.from((data as bigint[]).map((x: bigint) => Number(x)));
const reader = BufferReader.asReader(input);
const incomingTag = Fr.fromBuffer(reader);
const outgoingTag = Fr.fromBuffer(reader);
const payload = L1NotePayload.decryptAsIncoming(reader.readToEnd(), ivsk);
if (!payload) {
// We failed to decrypt the note, return undefined
return;
}
} catch (e) {
return;
return new TaggedLog(payload, incomingTag, outgoingTag);
}
}

Expand All @@ -116,25 +120,29 @@ export class TaggedLog<Payload extends L1NotePayload | L1EventPayload> {
ovsk: GrumpkinPrivateKey,
payloadType: typeof L1NotePayload | typeof L1EventPayload = L1NotePayload,
) {
// Right now heavily abusing that we will likely fail if bad decryption
// as some field will likely end up not being in the field etc.
try {
if (payloadType === L1EventPayload) {
if (payloadType === L1EventPayload) {
// Right now heavily abusing that we will likely fail if bad decryption
// as some field will likely end up not being in the field etc.
try {
const reader = BufferReader.asReader((data as EncryptedL2Log).data);
const incomingTag = Fr.fromBuffer(reader);
const outgoingTag = Fr.fromBuffer(reader);
const payload = L1EventPayload.decryptAsOutgoing(data as EncryptedL2Log, ovsk);
return new TaggedLog(payload, incomingTag, outgoingTag);
} else {
const input = Buffer.isBuffer(data) ? data : Buffer.from((data as bigint[]).map((x: bigint) => Number(x)));
const reader = BufferReader.asReader(input);
const incomingTag = Fr.fromBuffer(reader);
const outgoingTag = Fr.fromBuffer(reader);
const payload = L1NotePayload.decryptAsOutgoing(reader.readToEnd(), ovsk);
return new TaggedLog(payload, incomingTag, outgoingTag);
} catch (e) {
return;
}
} else {
const input = Buffer.isBuffer(data) ? data : Buffer.from((data as bigint[]).map((x: bigint) => Number(x)));
const reader = BufferReader.asReader(input);
const incomingTag = Fr.fromBuffer(reader);
const outgoingTag = Fr.fromBuffer(reader);
const payload = L1NotePayload.decryptAsOutgoing(reader.readToEnd(), ovsk);
if (!payload) {
// We failed to decrypt the note, return undefined
return;
}
} catch (e) {
return;
return new TaggedLog(payload, incomingTag, outgoingTag);
}
}
}
23 changes: 11 additions & 12 deletions yarn-project/pxe/src/note_processor/note_processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,18 +151,17 @@ export class NoteProcessor {
const outgoingTaggedNote = TaggedLog.decryptAsOutgoing(log.data, ovskM)!;

if (incomingTaggedNote || outgoingTaggedNote) {
// TODO(#7053): Re-enable this check
// if (
// incomingTaggedNote &&
// outgoingTaggedNote &&
// !incomingTaggedNote.payload.equals(outgoingTaggedNote.payload)
// ) {
// throw new Error(
// `Incoming and outgoing note payloads do not match. Incoming: ${JSON.stringify(
// incomingTaggedNote.payload,
// )}, Outgoing: ${JSON.stringify(outgoingTaggedNote.payload)}`,
// );
// }
if (
incomingTaggedNote &&
outgoingTaggedNote &&
!incomingTaggedNote.payload.equals(outgoingTaggedNote.payload)
) {
throw new Error(
`Incoming and outgoing note payloads do not match. Incoming: ${JSON.stringify(
incomingTaggedNote.payload,
)}, Outgoing: ${JSON.stringify(outgoingTaggedNote.payload)}`,
);
}

const payload = incomingTaggedNote?.payload || outgoingTaggedNote?.payload;

Expand Down

0 comments on commit 12ddea2

Please sign in to comment.