Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: hash logs inside circuit #5934

Merged
merged 38 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
5193d02
feat: WIP first commit - logs hashed inside contexts
MirandaWood Apr 22, 2024
47a036d
Merge remote-tracking branch 'origin' into mw/logs-hash
MirandaWood Apr 22, 2024
b945e63
chore: oh boy deployer addr here we go
MirandaWood Apr 22, 2024
f7346e0
feat: acc logs len in circuit, add docs and tests
MirandaWood Apr 23, 2024
00f5857
Merge remote-tracking branch 'origin' into mw/logs-hash
MirandaWood Apr 23, 2024
7b594ac
fix: fix deploy.nr after portal removal
MirandaWood Apr 23, 2024
a163af6
fix: strs as logs, generic size enc log returns
MirandaWood Apr 24, 2024
56c1505
Merge remote-tracking branch 'origin' into mw/logs-hash
MirandaWood Apr 24, 2024
ae9eae4
fix: make enc log len generic, replace slices with arrs
MirandaWood Apr 24, 2024
75ec074
Merge remote-tracking branch 'origin' into mw/logs-hash
MirandaWood Apr 24, 2024
0e903b8
Merge remote-tracking branch 'origin' into mw/logs-hash
MirandaWood Apr 24, 2024
ab41572
feat: impl strs for unenc logs, generate more trait impls
MirandaWood Apr 24, 2024
b5227f9
feat: track nested public logs with arr, link counter issue
MirandaWood Apr 26, 2024
533c4cc
Merge remote-tracking branch 'origin' into mw/logs-hash
MirandaWood Apr 26, 2024
beddeb9
fix: merge fixes
MirandaWood Apr 26, 2024
247de1e
feat: add logscache, tests, remove old hacks for logs sorting
MirandaWood Apr 29, 2024
4c80dab
Merge remote-tracking branch 'origin' into mw/logs-hash
MirandaWood Apr 29, 2024
19c7801
fix: merge issues
MirandaWood Apr 29, 2024
9dadba6
Merge remote-tracking branch 'origin' into mw/logs-hash
MirandaWood Apr 30, 2024
fd92b48
chore: increase test timeout + clarify comments
MirandaWood Apr 30, 2024
462ef24
Merge branch 'master' into mw/logs-hash
MirandaWood Apr 30, 2024
57f8b11
fix: merge fix
MirandaWood Apr 30, 2024
a922640
feat: address comments + fmt
MirandaWood Apr 30, 2024
5d465fd
feat: flat hash logs in tail/L1
MirandaWood May 1, 2024
d7a68bd
chore: fmt
MirandaWood May 1, 2024
547fd5b
Merge remote-tracking branch 'origin' into mw/logs-hash
MirandaWood May 1, 2024
e7cc4c4
feat: revert arr, track logs with counters, sort in exec. res.
MirandaWood May 1, 2024
bfc54a6
Merge remote-tracking branch 'origin' into mw/logs-hash
MirandaWood May 1, 2024
9af800e
Merge remote-tracking branch 'origin' into mw/logs-hash
MirandaWood May 1, 2024
4050be3
chore: remove redundant check + comments
MirandaWood May 1, 2024
2b25410
Merge remote-tracking branch 'origin' into mw/logs-hash
MirandaWood May 1, 2024
91c51e7
Merge remote-tracking branch 'origin' into mw/logs-hash
MirandaWood May 2, 2024
1726fb3
chore: remove comments, remove redundant .reverse
MirandaWood May 2, 2024
18b9057
Merge remote-tracking branch 'origin' into mw/logs-hash
MirandaWood May 2, 2024
e591c87
chore: moved nested logs tests now e2e_nested has been refactored
MirandaWood May 2, 2024
5cf5b5a
chore: fmt + update docs for 0.37 release
MirandaWood May 2, 2024
529241d
Merge remote-tracking branch 'origin' into mw/logs-hash
MirandaWood May 2, 2024
afa345f
Merge remote-tracking branch 'origin' into mw/logs-hash
MirandaWood May 2, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,9 @@ In the future we will allow emitting arbitrary information.
(If you currently emit arbitrary information, PXE will fail to decrypt, process and store this data, so it will not be queryable).
:::

### Import library

To emit encrypted logs first import the `emit_encrypted_log` utility function which wraps an [oracle](../oracles/main.md):

#include_code encrypted_import /noir-projects/aztec-nr/address-note/src/address_note.nr rust

### Call emit_encrypted_log

After importing, you can call the function:
To emit encrypted logs you don't need to import any library. You call the context method `emit_encrypted_log`:

#include_code encrypted /noir-projects/aztec-nr/address-note/src/address_note.nr rust

Expand Down
13 changes: 12 additions & 1 deletion docs/docs/misc/migration_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ Aztec is in full-speed development. Literally every version breaks compatibility

## 0.36.0

### [Aztec.nr] Emmiting encrypted logs

The `emit_encrypted_log` function is now a context method.

```diff
- use dep::aztec::log::emit_encrypted_log;
- use dep::aztec::logs::emit_encrypted_log;

- emit_encrypted_log(context, log1);
+ context.emit_encrypted_log(log1);
```
## `FieldNote` removed

`FieldNote` only existed for testing purposes, and was not a note type that should be used in any real application. Its name unfortunately led users to think that it was a note type suitable to store a `Field` value, which it wasn't.
Expand Down Expand Up @@ -171,7 +182,7 @@ Note that gas limits are not yet enforced. For now, it is suggested you use `dep

Note that this is not required when enqueuing a public function from a private one, since top-level enqueued public functions will always consume all gas available for the transaction, as it is not possible to handle any out-of-gas errors.

### [Aztec.nr] Emmiting unencrypted logs
### [Aztec.nr] Emitting unencrypted logs

The `emit_unencrypted_logs` function is now a context method.

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/protocol-specs/logs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Logs on Aztec are similar to logs on Ethereum, enabling smart contracts to conve

### Hash Function

The protocol uses **SHA256** as the hash function for logs, and then reduces the 256-bit result to 253 bits for representation as a field element.
The protocol uses **SHA256** as the hash function for logs, and then reduces the 256-bit result to 248 bits for representation as a field element.

<!-- TODO: explicitly detail how the truncation is being done, so that we can check that it is secure. -->

Expand Down
6 changes: 1 addition & 5 deletions noir-projects/aztec-nr/address-note/src/address_note.nr
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
// docs:start:encrypted_import
use dep::aztec::log::emit_encrypted_log;
// docs:end:encrypted_import
use dep::aztec::{
protocol_types::{address::AztecAddress, traits::Empty, constants::GENERATOR_INDEX__NOTE_NULLIFIER},
note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption},
Expand Down Expand Up @@ -45,8 +42,7 @@ impl NoteInterface<ADDRESS_NOTE_LEN> for AddressNote {
fn broadcast(self, context: &mut PrivateContext, slot: Field) {
let encryption_pub_key = get_public_key(self.owner);
// docs:start:encrypted
emit_encrypted_log(
context,
context.emit_encrypted_log(
(*context).this_address(),
slot,
Self::get_note_type_id(),
Expand Down
2 changes: 1 addition & 1 deletion noir-projects/aztec-nr/aztec/src/context/avm_context.nr
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ impl PublicContextInterface for AvmContext {
nullifier_exists(unsiloed_nullifier, address.to_field()) == 1
}

fn emit_unencrypted_log<T>(&mut self, log: T) {
fn emit_unencrypted_log<T,N,M>(&mut self, log: T) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AVM context and interface was only changed to allow the public and private contexts to use traits in logs_traits (these define fixed lengths for many types, so we can sha hash inside the circuit). These don't need to be carried over!

let event_selector = 5; // Matches current PublicContext.
self.emit_unencrypted_log(event_selector, log);
}
Expand Down
2 changes: 1 addition & 1 deletion noir-projects/aztec-nr/aztec/src/context/interface.nr
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ trait PublicContextInterface {
fn fee_per_l2_gas(self) -> Field;
fn message_portal(&mut self, recipient: EthAddress, content: Field);
fn consume_l1_to_l2_message(&mut self, content: Field, secret: Field, sender: EthAddress, leaf_index: Field);
fn emit_unencrypted_log<T>(&mut self, log: T);
fn emit_unencrypted_log<T,N,M>(&mut self, log: T);
fn call_public_function<RETURNS_COUNT>(
self: &mut Self,
contract_address: AztecAddress,
Expand Down
127 changes: 95 additions & 32 deletions noir-projects/aztec-nr/aztec/src/context/private_context.nr
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use crate::{
context::{inputs::PrivateContextInputs, interface::ContextInterface},
messaging::process_l1_to_l2_message, hash::{hash_args_array, ArgsHasher},
messaging::process_l1_to_l2_message,
hash::{hash_args_array, ArgsHasher, compute_encrypted_log_hash, compute_unencrypted_log_hash},
oracle::{
arguments, returns, call_private_function::call_private_function_internal,
enqueue_public_function_call::enqueue_public_function_call_internal, header::get_header_at,
logs::emit_encrypted_log, logs_traits::{LensForEncryptedLog, ToBytesForUnencryptedLog},
nullifier_key::{get_nullifier_keys, NullifierKeys}
}
};
Expand All @@ -28,14 +30,11 @@ use dep::protocol_types::{
MAX_ENCRYPTED_LOGS_PER_CALL, MAX_UNENCRYPTED_LOGS_PER_CALL
},
contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest},
grumpkin_private_key::GrumpkinPrivateKey, header::Header,
grumpkin_private_key::GrumpkinPrivateKey, grumpkin_point::GrumpkinPoint, header::Header,
messaging::l2_to_l1_message::L2ToL1Message, utils::reader::Reader,
traits::{is_empty, Deserialize, Empty}
};

// TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165)
// use dep::std::collections::vec::Vec;

// When finished, one can call .finish() to convert back to the abi
struct PrivateContext {
// docs:start:private-context
Expand All @@ -44,8 +43,8 @@ struct PrivateContext {

min_revertible_side_effect_counter: u32,

args_hash : Field,
return_hash : Field,
args_hash: Field,
return_hash: Field,

max_block_number: MaxBlockNumber,

Expand All @@ -64,9 +63,10 @@ struct PrivateContext {
// Header of a block whose state is used during private execution (not the block the transaction is included in).
historical_header: Header,

// TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165)
encrypted_logs_hashes: BoundedVec<SideEffect, MAX_ENCRYPTED_LOGS_PER_CALL>,
unencrypted_logs_hashes: BoundedVec<SideEffect, MAX_UNENCRYPTED_LOGS_PER_CALL>,
encrypted_log_preimages_length: Field,
unencrypted_log_preimages_length: Field,
// encrypted_logs_preimages: Vec<Field>,
// unencrypted_logs_preimages: Vec<Field>,

Expand Down Expand Up @@ -132,9 +132,10 @@ impl PrivateContext {
private_call_stack_hashes: BoundedVec::new(),
public_call_stack_hashes: BoundedVec::new(),
new_l2_to_l1_msgs: BoundedVec::new(),
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165)
encrypted_logs_hashes: BoundedVec::new(),
unencrypted_logs_hashes: BoundedVec::new(),
encrypted_log_preimages_length: 0,
unencrypted_log_preimages_length: 0,
// encrypted_logs_preimages: Vec::new(),
// unencrypted_logs_preimages: Vec::new(),
nullifier_key: Option::none()
Expand All @@ -159,11 +160,7 @@ impl PrivateContext {
}

pub fn finish(self) -> PrivateCircuitPublicInputs {
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165)
let encrypted_log_preimages_length = 0;
let unencrypted_log_preimages_length = 0;

let priv_circuit_pub_inputs = PrivateCircuitPublicInputs {
PrivateCircuitPublicInputs {
call_context: self.inputs.call_context,
args_hash: self.args_hash,
returns_hash: self.return_hash,
Expand All @@ -181,13 +178,11 @@ impl PrivateContext {
end_side_effect_counter: self.side_effect_counter,
encrypted_logs_hashes: self.encrypted_logs_hashes.storage,
unencrypted_logs_hashes: self.unencrypted_logs_hashes.storage,
encrypted_log_preimages_length,
unencrypted_log_preimages_length,
encrypted_log_preimages_length: self.encrypted_log_preimages_length + 4,
unencrypted_log_preimages_length: self.unencrypted_log_preimages_length + 4,
historical_header: self.historical_header,
tx_context: self.inputs.tx_context
};

priv_circuit_pub_inputs
}
}

pub fn end_setup(&mut self) {
Expand Down Expand Up @@ -258,25 +253,74 @@ impl PrivateContext {
}
// docs:end:consume_l1_to_l2_message

pub fn push_encrypted_log(&mut self, log_hash: Field) {
let side_effect = SideEffect { value: log_hash, counter: self.side_effect_counter };
self.encrypted_logs_hashes.push(side_effect);
self.side_effect_counter = self.side_effect_counter + 1;
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165)
}

// TODO: We might want to remove this since emitting unencrypted logs from private functions is violating privacy.
// --> might be a better approach to force devs to make a public function call that emits the log if needed then
// it would be less easy to accidentally leak information.
// If we decide to keep this function around would make sense to wait for traits and then merge it with emit_unencrypted_log.
pub fn emit_unencrypted_log<T>(&mut self, log: T) {
pub fn emit_unencrypted_log<T, N, M>(&mut self, log: T) where T: ToBytesForUnencryptedLog<N, M> {
let event_selector = 5; // TODO: compute actual event selector.
let log_hash = emit_unencrypted_log_private_internal(self.this_address(), event_selector, log);

let contract_address = self.this_address();
let log_slice = log.to_be_bytes_arr();
let log_hash = compute_unencrypted_log_hash(
contract_address,
event_selector,
log,
);
let side_effect = SideEffect { value: log_hash, counter: self.side_effect_counter };
self.unencrypted_logs_hashes.push(side_effect);
self.side_effect_counter = self.side_effect_counter + 1;
// 44 = addr (32) + selector (4) + raw log len (4) + processed log len (4)
self.unencrypted_log_preimages_length = self.unencrypted_log_preimages_length + 44 + log_slice.len().to_field();
MirandaWood marked this conversation as resolved.
Show resolved Hide resolved
// call oracle
let _void = emit_unencrypted_log_private_internal(contract_address, event_selector, log);
}

// This fn exists separately from emit_unencrypted_log because sha hashing the preimage
// is too large to compile (16,200 fields, 518,400 bytes) => the oracle hashes it
// It is ONLY used with contract_class_registerer_contract since we already assert correctness:
// - Contract class -> we will commit to the packed bytecode (currently a TODO)
// - Private function -> we provide a membership proof
// - Unconstrained function -> we provide a membership proof
// Ordinary logs are not protected by the above so this fn shouldn't be called by anything else
pub fn emit_contract_class_unencrypted_log<N>(&mut self, log: [Field; N]) {
let event_selector = 5; // TODO: compute actual event selector.
let contract_address = self.this_address();
let log_hash = emit_contract_class_unencrypted_log_private_internal(
contract_address,
event_selector,
log
);
let side_effect = SideEffect { value: log_hash, counter: self.side_effect_counter };
self.unencrypted_logs_hashes.push(side_effect);
self.side_effect_counter = self.side_effect_counter + 1;
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165)
// 44 = addr (32) + selector (4) + raw log len (4) + processed log len (4)
self.unencrypted_log_preimages_length = self.unencrypted_log_preimages_length + 44 + N*32;
}

pub fn emit_encrypted_log<N, M, L>(
&mut self,
contract_address: AztecAddress,
storage_slot: Field,
note_type_id: Field,
encryption_pub_key: GrumpkinPoint,
preimage: [Field; N]
) where [Field; N]: LensForEncryptedLog<N, M, L> {
// TODO(1139): perform encryption in the circuit
// The oracle call should come last, but we require the encrypted value for now
let encrypted_log: [Field; M] = emit_encrypted_log(
contract_address,
storage_slot,
note_type_id,
encryption_pub_key,
preimage
);
let log_hash = compute_encrypted_log_hash(encrypted_log);
let side_effect = SideEffect { value: log_hash, counter: self.side_effect_counter };
self.encrypted_logs_hashes.push(side_effect);
self.side_effect_counter = self.side_effect_counter + 1;
let encrypted_log_byte_len = 112 + 32*(N + 3);
// + processed log len (4)
self.encrypted_log_preimages_length = self.encrypted_log_preimages_length + encrypted_log_byte_len + 4;
}

pub fn call_private_function<ARGS_COUNT>(
Expand Down Expand Up @@ -546,8 +590,8 @@ impl Empty for PrivateContext {
inputs: PrivateContextInputs::empty(),
side_effect_counter: 0 as u32,
min_revertible_side_effect_counter: 0 as u32,
args_hash : 0,
return_hash : 0,
args_hash: 0,
return_hash: 0,
max_block_number: MaxBlockNumber::empty(),
note_hash_read_requests: BoundedVec::new(),
nullifier_read_requests: BoundedVec::new(),
Expand All @@ -560,6 +604,8 @@ impl Empty for PrivateContext {
historical_header: Header::empty(),
encrypted_logs_hashes: BoundedVec::new(),
unencrypted_logs_hashes: BoundedVec::new(),
encrypted_log_preimages_length: 0,
unencrypted_log_preimages_length: 0,
nullifier_key: Option::none(),
}
}
Expand Down Expand Up @@ -609,3 +655,20 @@ unconstrained pub fn emit_unencrypted_log_private_internal<T>(
// https://github.com/AztecProtocol/aztec-packages/issues/885
emit_unencrypted_log_oracle_private(contract_address, event_selector, message)
}

#[oracle(emitContractClassUnencryptedLog)]
LeilaWang marked this conversation as resolved.
Show resolved Hide resolved
fn emit_contract_class_unencrypted_log_private<N>(
contract_address: AztecAddress,
event_selector: Field,
message: [Field; N]
) -> Field {}


unconstrained pub fn emit_contract_class_unencrypted_log_private_internal<N>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't need to be public.

contract_address: AztecAddress,
event_selector: Field,
message: [Field; N]
) -> Field {
emit_contract_class_unencrypted_log_private(contract_address, event_selector, message)
}

Loading
Loading