Skip to content

Commit

Permalink
feat: FieldNote (AztecProtocol#3037)
Browse files Browse the repository at this point in the history
1. Fixes AztecProtocol#2948
2. Removed redundant dependency from `TokenContract`.
3. No camel case in `TestContract`
  • Loading branch information
benesjan authored Oct 31, 2023
1 parent db67aa1 commit 3d1ffd0
Show file tree
Hide file tree
Showing 10 changed files with 257 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,10 @@ describe('Private Execution test suite', () => {

beforeAll(async () => {
// These args should match the ones hardcoded in importer contract
const dummyNote = { amount: 1, secretHash: 2 };
const deepStruct = { aField: 1, aBool: true, aNote: dummyNote, manyNotes: [dummyNote, dummyNote, dummyNote] };
// eslint-disable-next-line camelcase
const dummyNote = { amount: 1, secret_hash: 2 };
// eslint-disable-next-line camelcase
const deepStruct = { a_field: 1, a_bool: true, a_note: dummyNote, many_notes: [dummyNote, dummyNote, dummyNote] };
args = [1, true, 1, [1, 2], dummyNote, deepStruct];
testCodeGenArtifact = getFunctionArtifact(TestContractArtifact, 'test_code_gen');
const serializedArgs = encodeArguments(testCodeGenArtifact, args);
Expand Down
8 changes: 8 additions & 0 deletions yarn-project/aztec-nr/field-note/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "field_note"
authors = ["aztec-labs"]
compiler_version = "0.7.1"
type = "lib"

[dependencies]
aztec = { path = "../aztec" }
90 changes: 90 additions & 0 deletions yarn-project/aztec-nr/field-note/src/field_note.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use dep::aztec::{
note::{
note_header::NoteHeader,
note_interface::NoteInterface,
},
hash::pedersen_hash,
context::PrivateContext,
};

global FIELD_NOTE_LEN: Field = 1;

// A note which stores a field and is expected to be passed around using the `addNote` function.
// WARNING: This Note is not private as it does not contain randomness and hence it can be easy to perform preimage
// attack on it.
struct FieldNote {
value: Field,
header: NoteHeader,
}

impl FieldNote {
pub fn new(value: Field) -> Self {
FieldNote {
value,
header: NoteHeader::empty(),
}
}

pub fn serialize(self) -> [Field; FIELD_NOTE_LEN]{
[self.value]
}

pub fn deserialize(preimage: [Field; FIELD_NOTE_LEN]) -> Self {
FieldNote {
value: preimage[0],
header: NoteHeader::empty(),
}
}

pub fn compute_note_hash(self) -> Field {
// TODO(#1205) Should use a non-zero generator index.
pedersen_hash(self.serialize(), 0)
}

pub fn compute_nullifier(self) -> Field {
// This note is expected to be shared between users and for this reason can't be nullified using a secret.
0
}

pub fn set_header(&mut self, header: NoteHeader) {
self.header = header;
}
}

fn deserialize(preimage: [Field; FIELD_NOTE_LEN]) -> FieldNote {
FieldNote::deserialize(preimage)
}

fn serialize(note: FieldNote) -> [Field; FIELD_NOTE_LEN]{
note.serialize()
}

fn compute_note_hash(note: FieldNote) -> Field {
note.compute_note_hash()
}

fn compute_nullifier(note: FieldNote) -> Field {
note.compute_nullifier()
}

fn get_header(note: FieldNote) -> NoteHeader {
note.header
}

fn set_header(note: &mut FieldNote, header: NoteHeader) {
note.set_header(header);
}

fn broadcast(context: &mut PrivateContext, slot: Field, note: FieldNote) {
assert(false, "FieldNote does not support broadcast. Add it to PXE directly using the `.addNote` function.");
}

global FieldNoteMethods = NoteInterface {
deserialize,
serialize,
compute_note_hash,
compute_nullifier,
get_header,
set_header,
broadcast,
};
1 change: 1 addition & 0 deletions yarn-project/aztec-nr/field-note/src/lib.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mod field_note;
24 changes: 22 additions & 2 deletions yarn-project/end-to-end/src/e2e_non_contract_account.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { siloNullifier } from '@aztec/circuits.js/abis';
import { DebugLogger } from '@aztec/foundation/log';
import { toBigInt } from '@aztec/foundation/serialize';
import { TestContract } from '@aztec/noir-contracts/types';
import { AztecNode, PXE, TxStatus } from '@aztec/types';
import { AztecNode, NotePreimage, PXE, TxStatus } from '@aztec/types';

import { setup } from './fixtures/utils.js';

Expand All @@ -17,9 +17,9 @@ describe('e2e_non_contract_account', () => {
let logger: DebugLogger;

let contract: TestContract;
let wallet: Wallet;

beforeEach(async () => {
let wallet: Wallet;
({ teardown, aztecNode, pxe, wallet, logger } = await setup(1));
nonContractAccountWallet = new SignerlessWallet(pxe);

Expand Down Expand Up @@ -59,4 +59,24 @@ describe('e2e_non_contract_account', () => {
const msgSender = toBigInt(logs[0].log.data);
expect(msgSender).toBe(0n);
}, 120_000);

// Note: This test doesn't really belong here as it doesn't have anything to do with non-contract accounts. I needed
// to test the FieldNote functionality and it doesn't really fit anywhere else. Creating a separate e2e test for this
// seems wasteful. Move this test if a better place is found.
it('can set and get a constant', async () => {
const value = 123n;

const receipt = await contract.methods.set_constant(value).send().wait({ interval: 0.1 });

// check that 1 commitment was created
const tx = await pxe.getTx(receipt.txHash);
const nonZeroCommitments = tx?.newCommitments.filter(c => c.value > 0);
expect(nonZeroCommitments?.length).toBe(1);

// Add the note
const preimage = new NotePreimage([new Fr(value)]);
await wallet.addNote(wallet.getCompleteAddress().address, contract.address, new Fr(1), preimage, receipt.txHash);

expect(await contract.methods.get_constant().view()).toEqual(value);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@ contract ImportTest {
true,
1 as u32,
[1, 2],
AStructTestCodeGenStruct { amount: 1, secretHash: 2 },
AStructTestCodeGenStruct { amount: 1, secret_hash: 2 },
ADeepStructTestCodeGenStruct {
aField: 1,
aBool: true,
aNote: ANoteADeepStructTestCodeGenStruct { amount: 1, secretHash: 2 },
manyNotes: [
ManyNotesADeepStructTestCodeGenStruct { amount: 1, secretHash: 2 },
ManyNotesADeepStructTestCodeGenStruct { amount: 1, secretHash: 2 },
ManyNotesADeepStructTestCodeGenStruct { amount: 1, secretHash: 2 },
a_field: 1,
a_bool: true,
a_note: ANoteADeepStructTestCodeGenStruct { amount: 1, secret_hash: 2 },
many_notes: [
ManyNotesADeepStructTestCodeGenStruct { amount: 1, secret_hash: 2 },
ManyNotesADeepStructTestCodeGenStruct { amount: 1, secret_hash: 2 },
ManyNotesADeepStructTestCodeGenStruct { amount: 1, secret_hash: 2 },
]
}
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ type = "contract"

[dependencies]
aztec = { path = "../../../../aztec-nr/aztec" }
field_note = { path = "../../../../aztec-nr/field-note" }
token_portal_content_hash_lib = { path = "../token_portal_content_hash_lib" }
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,24 @@ use dep::aztec::constants_gen::RETURN_VALUES_LENGTH;

struct AStructTestCodeGenStruct {
amount: Field,
secretHash: Field,
secret_hash: Field,
}

struct ADeepStructTestCodeGenStruct {
aField: Field,
aBool: bool,
aNote: ANoteADeepStructTestCodeGenStruct,
manyNotes: [ManyNotesADeepStructTestCodeGenStruct;3],
a_field: Field,
a_bool: bool,
a_note: ANoteADeepStructTestCodeGenStruct,
many_notes: [ManyNotesADeepStructTestCodeGenStruct;3],
}

struct ANoteADeepStructTestCodeGenStruct {
amount: Field,
secretHash: Field,
secret_hash: Field,
}

struct ManyNotesADeepStructTestCodeGenStruct {
amount: Field,
secretHash: Field,
secret_hash: Field,
}


Expand Down Expand Up @@ -83,11 +83,11 @@ impl TestPrivateContextInterface {
self,
context: &mut PrivateContext,
amount: Field,
secretHash: Field
secret_hash: Field
) {
let mut serialized_args = [0; 2];
serialized_args[0] = amount;
serialized_args[1] = secretHash;
serialized_args[1] = secret_hash;

context.call_public_function(self.address, 0x9749ca06, serialized_args)
}
Expand All @@ -97,11 +97,11 @@ impl TestPrivateContextInterface {
self,
context: &mut PrivateContext,
amount: Field,
secretHash: Field
secret_hash: Field
) {
let mut serialized_args = [0; 2];
serialized_args[0] = amount;
serialized_args[1] = secretHash;
serialized_args[1] = secret_hash;

context.call_public_function(self.address, 0xdf02db8d, serialized_args)
}
Expand Down Expand Up @@ -197,34 +197,46 @@ impl TestPrivateContextInterface {
}


pub fn set_constant(
self,
context: &mut PrivateContext,
value: Field
) -> [Field; RETURN_VALUES_LENGTH] {
let mut serialized_args = [0; 1];
serialized_args[0] = value;

context.call_private_function(self.address, 0x1b3b9e18, serialized_args)
}


pub fn test_code_gen(
self,
context: &mut PrivateContext,
aField: Field,
aBool: bool,
aNumber: u32,
anArray: [Field;2],
aStruct: AStructTestCodeGenStruct,
aDeepStruct: ADeepStructTestCodeGenStruct
a_field: Field,
a_bool: bool,
a_number: u32,
an_array: [Field;2],
a_struct: AStructTestCodeGenStruct,
a_deep_struct: ADeepStructTestCodeGenStruct
) -> [Field; RETURN_VALUES_LENGTH] {
let mut serialized_args = [0; 17];
serialized_args[0] = aField;
serialized_args[1] = aBool as Field;
serialized_args[2] = aNumber as Field;
serialized_args[3] = anArray[0];
serialized_args[4] = anArray[1];
serialized_args[5] = aStruct.amount;
serialized_args[6] = aStruct.secretHash;
serialized_args[7] = aDeepStruct.aField;
serialized_args[8] = aDeepStruct.aBool as Field;
serialized_args[9] = aDeepStruct.aNote.amount;
serialized_args[10] = aDeepStruct.aNote.secretHash;
serialized_args[11] = aDeepStruct.manyNotes[0].amount;
serialized_args[12] = aDeepStruct.manyNotes[0].secretHash;
serialized_args[13] = aDeepStruct.manyNotes[1].amount;
serialized_args[14] = aDeepStruct.manyNotes[1].secretHash;
serialized_args[15] = aDeepStruct.manyNotes[2].amount;
serialized_args[16] = aDeepStruct.manyNotes[2].secretHash;
serialized_args[0] = a_field;
serialized_args[1] = a_bool as Field;
serialized_args[2] = a_number as Field;
serialized_args[3] = an_array[0];
serialized_args[4] = an_array[1];
serialized_args[5] = a_struct.amount;
serialized_args[6] = a_struct.secret_hash;
serialized_args[7] = a_deep_struct.a_field;
serialized_args[8] = a_deep_struct.a_bool as Field;
serialized_args[9] = a_deep_struct.a_note.amount;
serialized_args[10] = a_deep_struct.a_note.secret_hash;
serialized_args[11] = a_deep_struct.many_notes[0].amount;
serialized_args[12] = a_deep_struct.many_notes[0].secret_hash;
serialized_args[13] = a_deep_struct.many_notes[1].amount;
serialized_args[14] = a_deep_struct.many_notes[1].secret_hash;
serialized_args[15] = a_deep_struct.many_notes[2].amount;
serialized_args[16] = a_deep_struct.many_notes[2].secret_hash;

context.call_private_function(self.address, 0x0f054f9b, serialized_args)
}
Expand Down Expand Up @@ -270,11 +282,11 @@ impl TestPublicContextInterface {
self,
context: PublicContext,
amount: Field,
secretHash: Field
secret_hash: Field
) -> [Field; RETURN_VALUES_LENGTH] {
let mut serialized_args = [0; 2];
serialized_args[0] = amount;
serialized_args[1] = secretHash;
serialized_args[1] = secret_hash;

context.call_public_function(self.address, 0x9749ca06, serialized_args)
}
Expand All @@ -284,11 +296,11 @@ impl TestPublicContextInterface {
self,
context: PublicContext,
amount: Field,
secretHash: Field
secret_hash: Field
) -> [Field; RETURN_VALUES_LENGTH] {
let mut serialized_args = [0; 2];
serialized_args[0] = amount;
serialized_args[1] = secretHash;
serialized_args[1] = secret_hash;

context.call_public_function(self.address, 0xdf02db8d, serialized_args)
}
Expand Down
Loading

0 comments on commit 3d1ffd0

Please sign in to comment.