Skip to content

Commit

Permalink
TxAuxData (#118)
Browse files Browse the repository at this point in the history
Co-authored-by: Charlie Lye <[email protected]>
  • Loading branch information
benesjan and charlielye authored Mar 29, 2023
1 parent 48544e9 commit 9598d54
Show file tree
Hide file tree
Showing 14 changed files with 131 additions and 82 deletions.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Grumpkin } from '@aztec/barretenberg.js/crypto';
import { BarretenbergWasm } from '@aztec/barretenberg.js/wasm';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { randomBytes } from '@aztec/foundation/crypto';
import { decryptBuffer, encryptBuffer } from './encrypt_buffer.js';

describe('encrypt buffer', () => {
it('convert to and from encrypted buffer', async () => {
const grumpkin = new Grumpkin(await BarretenbergWasm.new());
const data = randomBytes(253);
const ownerPrivKey = randomBytes(32);
const ownerPubKey = AztecAddress.fromBuffer(grumpkin.mul(Grumpkin.generator, ownerPrivKey));
const ephPrivKey = randomBytes(32);
const encrypted = encryptBuffer(data, ownerPubKey, ephPrivKey, grumpkin);
const decrypted = decryptBuffer(encrypted, ownerPrivKey, grumpkin);
expect(decrypted).not.toBeUndefined();
expect(decrypted).toEqual(data);
});

it('decrypting gibberish returns undefined', async () => {
const grumpkin = new Grumpkin(await BarretenbergWasm.new());
const data = randomBytes(253);
const ownerPrivKey = randomBytes(32);
const ephPrivKey = randomBytes(32);
const ownerPubKey = AztecAddress.fromBuffer(grumpkin.mul(Grumpkin.generator, ownerPrivKey));
const encrypted = encryptBuffer(data, ownerPubKey, ephPrivKey, grumpkin);

// Introduce gibberish.
const gibberish = Buffer.concat([randomBytes(8), encrypted.subarray(8)]);

const decrypted = decryptBuffer(gibberish, ownerPrivKey, grumpkin);
expect(decrypted).toBeUndefined();
});
});
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { createCipheriv, createDecipheriv } from 'browserify-cipher';
import { Grumpkin } from '@aztec/barretenberg.js/crypto';
import { numToUInt8 } from '@aztec/foundation/serialize';
import { NotePreImage } from './note_preimage.js';
import { sha256 } from '@aztec/foundation/crypto';
import { AztecAddress } from '@aztec/foundation/aztec-address';

Expand All @@ -12,29 +11,17 @@ function deriveAESSecret(ecdhPubKey: AztecAddress, ecdhPrivKey: Buffer, grumpkin
return hash;
}

/**
* Returns the AES encrypted "viewing key".
* [AES: [32 bytes value][4 bytes assetId][4 bytes accountRequired][32 bytes creatorPubKey]] [64 bytes ephPubKey]
* @param data = { value, assetId, accountRequired, creatorPubKey };
* @param ownerPubKey - the public key contained within a value note
* @param ephPrivKey - a random field element (also used alongside the ownerPubKey in deriving a value note's secret)
*/
export function encryptNotePreimage(
data: NotePreImage,
ownerPubKey: AztecAddress,
ephPrivKey: Buffer,
grumpkin: Grumpkin,
) {
export function encryptBuffer(data: Buffer, ownerPubKey: AztecAddress, ephPrivKey: Buffer, grumpkin: Grumpkin) {
const ephPubKey = grumpkin.mul(Grumpkin.generator, ephPrivKey);
const aesSecret = deriveAESSecret(ownerPubKey, ephPrivKey, grumpkin);
const aesKey = aesSecret.subarray(0, 16);
const iv = aesSecret.subarray(16, 32);
const cipher = createCipheriv('aes-128-cbc', aesKey, iv);
const plaintext = Buffer.concat([iv.subarray(0, 8), data.toBuffer()]);
const plaintext = Buffer.concat([iv.subarray(0, 8), data]);
return Buffer.concat([cipher.update(plaintext), cipher.final(), ephPubKey]);
}

export function decryptNotePreimage(data: Buffer, ownerPrivKey: Buffer, grumpkin: Grumpkin) {
export function decryptBuffer(data: Buffer, ownerPrivKey: Buffer, grumpkin: Grumpkin) {
const ephPubKey = new AztecAddress(data.subarray(-64));
const aesSecret = deriveAESSecret(ephPubKey, ownerPrivKey, grumpkin);
const aesKey = aesSecret.subarray(0, 16);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './note_preimage.js';
export * from './encrypt_buffer.js';
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Fr } from '@aztec/foundation/fields';
import { NotePreimage } from './note_preimage.js';

describe('note_preimage', () => {
it('convert to and from buffer', () => {
const fields = Array.from({ length: 5 }).map(() => Fr.random());
const notePreImage = new NotePreimage(fields);
const buf = notePreImage.toBuffer();
expect(NotePreimage.fromBuffer(buf)).toEqual(notePreImage);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Fr } from '@aztec/foundation/fields';
import { Vector } from '@aztec/circuits.js';
import { BufferReader } from '@aztec/foundation/serialize';

export class NotePreimage extends Vector<Fr> {
static fromBuffer(buffer: Buffer | BufferReader) {
const reader = BufferReader.asReader(buffer);
return new NotePreimage(reader.readVector(Fr));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Grumpkin } from '@aztec/barretenberg.js/crypto';
import { BarretenbergWasm } from '@aztec/barretenberg.js/wasm';
import { AztecAddress, randomBytes } from '@aztec/foundation';
import { Fr } from '@aztec/foundation/fields';
import { NotePreimage } from './note_preimage.js';
import { TxAuxData } from './tx_aux_data.js';

const randomTxAuxData = () => {
const fields = Array.from({ length: 5 }).map(() => Fr.random());
const notePreImage = new NotePreimage(fields);
const contractAddress = AztecAddress.random();
const storageSlot = Fr.random();
return new TxAuxData(notePreImage, contractAddress, storageSlot);
};

describe('tx_aux_data', () => {
it('convert to and from buffer', () => {
const txAuxData = randomTxAuxData();
const buf = txAuxData.toBuffer();
expect(TxAuxData.fromBuffer(buf)).toEqual(txAuxData);
});

it('convert to and from encrypted buffer', async () => {
const grumpkin = new Grumpkin(await BarretenbergWasm.new());
const txAuxData = randomTxAuxData();
const ownerPrivKey = randomBytes(32);
const ownerPubKey = AztecAddress.fromBuffer(grumpkin.mul(Grumpkin.generator, ownerPrivKey));
const ephPrivKey = randomBytes(32);
const encrypted = txAuxData.toEncryptedBuffer(ownerPubKey, ephPrivKey, grumpkin);
const decrypted = TxAuxData.fromEncryptedBuffer(encrypted, ownerPrivKey, grumpkin);
expect(decrypted).not.toBeUndefined();
expect(decrypted).toEqual(txAuxData);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Fr } from '@aztec/foundation/fields';
import { AztecAddress } from '@aztec/circuits.js';
import { BufferReader } from '@aztec/foundation/serialize';
import { NotePreimage } from './note_preimage.js';
import { serializeToBuffer } from '@aztec/circuits.js/utils';
import { decryptBuffer, encryptBuffer } from './encrypt_buffer.js';
import { Grumpkin } from '@aztec/barretenberg.js/crypto';

export class TxAuxData {
constructor(public notePreImage: NotePreimage, public contractAddress: AztecAddress, public storageSlot: Fr) {}

static fromBuffer(buffer: Buffer | BufferReader) {
const reader = BufferReader.asReader(buffer);
return new TxAuxData(reader.readObject(NotePreimage), reader.readObject(AztecAddress), reader.readFr());
}

toBuffer() {
return serializeToBuffer([this.notePreImage, this.contractAddress, this.storageSlot]);
}

public toEncryptedBuffer(ownerPubKey: AztecAddress, ephPrivKey: Buffer, grumpkin: Grumpkin) {
return encryptBuffer(this.toBuffer(), ownerPubKey, ephPrivKey, grumpkin);
}

static fromEncryptedBuffer(data: Buffer, ownerPrivKey: Buffer, grumpkin: Grumpkin) {
const buf = decryptBuffer(data, ownerPrivKey, grumpkin);
if (!buf) {
return;
}
return TxAuxData.fromBuffer(buf);
}
}
4 changes: 2 additions & 2 deletions yarn-project/aztec-rpc/src/database/note_dao.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { AztecAddress, Fr } from '@aztec/circuits.js';
import { NotePreImage } from '../aztec_rpc_server/note_preimage/note_preimage.js';
import { NotePreimage } from '../aztec_rpc_server/tx_aux_data/note_preimage.js';

export interface NoteDao {
// Properties from the encrypted note
contractAddress: AztecAddress;
contractSlot: Fr;
notePreimage: NotePreImage;
notePreimage: NotePreimage;
// Computed properties
nullifier: Fr;
// The location in the tree
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/aztec-rpc/src/simulator_oracle/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export class SimulatorOracle implements DBOracle {
async getNotes(contractAddress: AztecAddress, storageSlot: Fr): Promise<NoteLoadOracleInputs[]> {
const noteDaos = await this.db.getNotes(contractAddress, storageSlot);
return noteDaos.map(noteDao => ({
note: noteDao.notePreimage.fields,
note: noteDao.notePreimage.items,
siblingPath: [], // TODO get this from node
index: noteDao.index,
}));
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/foundation/src/aztec-address/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ export class AztecAddress {

static fromBuffer(bufferOrReader: Buffer | BufferReader) {
const reader = BufferReader.asReader(bufferOrReader);
return new AztecAddress(reader.readBytes(AztecAddress.SIZE_IN_BYTES));
return new AztecAddress(reader.readBytes(this.SIZE_IN_BYTES));
}

public static fromString(address: string) {
return new AztecAddress(Buffer.from(address.replace(/^0x/i, ''), 'hex'));
}

public static random() {
return new AztecAddress(randomBytes(AztecAddress.SIZE_IN_BYTES));
return new AztecAddress(randomBytes(this.SIZE_IN_BYTES));
}

public equals(rhs: AztecAddress) {
Expand Down

0 comments on commit 9598d54

Please sign in to comment.