Skip to content

Commit

Permalink
fix: public data reads and writes verification (#8296)
Browse files Browse the repository at this point in the history
- Add counter to `PublicDataUpdateRequest` so that we can check the
ordering of the reads vs writes and verify that the reads are reading
the correct value, either in the tree or a newly updated value.
- Improve the algorithm for squashing writes.
- Build hints in noir.
  • Loading branch information
LeilaWang authored Sep 9, 2024
1 parent 9fe2c07 commit ae86347
Show file tree
Hide file tree
Showing 84 changed files with 2,534 additions and 2,784 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use dep::protocol_types::{
constants::PUBLIC_DATA_TREE_HEIGHT, public_data_tree_leaf_preimage::PublicDataTreeLeafPreimage,
utils::arr_copy_slice
};
use dep::protocol_types::{constants::PUBLIC_DATA_TREE_HEIGHT, data::PublicDataTreeLeafPreimage, utils::arr_copy_slice};

global LEAF_PREIMAGE_LENGTH: u32 = 4;
global PUBLIC_DATA_WITNESS: Field = 45;
Expand All @@ -18,7 +15,10 @@ unconstrained fn get_public_data_witness_oracle(
_public_data_tree_index: Field
) -> [Field; PUBLIC_DATA_WITNESS] {}

unconstrained pub fn get_public_data_witness(block_number: u32, public_data_tree_index: Field) -> PublicDataWitness {
unconstrained pub fn get_public_data_witness(
block_number: u32,
public_data_tree_index: Field
) -> PublicDataWitness {
let fields = get_public_data_witness_oracle(block_number, public_data_tree_index);
PublicDataWitness {
index: fields[0],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,47 @@
mod combine_data;
mod generate_output_hints;
mod generate_overridable_public_data_writes;
mod generate_public_data_leaves;

use crate::components::public_tail_output_composer::combine_data::combine_data;
use generate_output_hints::{LinkedIndexHint, OutputHints, SiloedNoteHashHint};

use crate::components::public_tail_output_composer::{combine_data::combine_data, generate_output_hints::generate_output_hints};
use dep::types::{
abis::{kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PublicKernelCircuitPublicInputs}},
partial_state_reference::PartialStateReference
data::PublicDataLeafHint, partial_state_reference::PartialStateReference
};

struct PublicTailOutputComposer {
struct PublicTailOutputComposer<let NUM_PUBLIC_DATA_LEAVES: u32> {
previous_kernel: PublicKernelCircuitPublicInputs,
start_state: PartialStateReference,
public_data_leaf_hints: [PublicDataLeafHint; NUM_PUBLIC_DATA_LEAVES],
}

impl PublicTailOutputComposer {
impl<let NUM_PUBLIC_DATA_LEAVES: u32> PublicTailOutputComposer<NUM_PUBLIC_DATA_LEAVES> {
pub fn new(
previous_kernel: PublicKernelCircuitPublicInputs,
start_state: PartialStateReference
start_state: PartialStateReference,
public_data_leaf_hints: [PublicDataLeafHint; NUM_PUBLIC_DATA_LEAVES]
) -> Self {
PublicTailOutputComposer { previous_kernel, start_state }
PublicTailOutputComposer { previous_kernel, start_state, public_data_leaf_hints }
}

pub fn finish(self) -> KernelCircuitPublicInputs {
pub fn finish(self) -> (KernelCircuitPublicInputs, OutputHints<NUM_PUBLIC_DATA_LEAVES>) {
let output_hints = generate_output_hints(self.previous_kernel, self.public_data_leaf_hints);

let end = combine_data(
self.previous_kernel.end_non_revertible,
self.previous_kernel.end
self.previous_kernel.end,
output_hints
);

KernelCircuitPublicInputs {
(KernelCircuitPublicInputs {
rollup_validation_requests: self.previous_kernel.validation_requests.for_rollup,
end,
constants: self.previous_kernel.constants,
start_state: self.start_state,
revert_code: self.previous_kernel.revert_code,
fee_payer: self.previous_kernel.fee_payer
}
}, output_hints)
}
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,22 @@
use crate::components::public_tail_output_composer::generate_output_hints::OutputHints;
use dep::types::{
abis::{
accumulated_data::{CombinedAccumulatedData, PublicAccumulatedData},
log_hash::{LogHash, ScopedLogHash}, nullifier::Nullifier
},
constants::MAX_NOTE_HASHES_PER_TX, hash::silo_note_hash,
utils::arrays::{array_merge, dedupe_array, sort_by_counter_asc}
};

unconstrained pub fn combine_data(
unconstrained pub fn combine_data<let NUM_PUBLIC_DATA_LEAVES: u32>(
non_revertible: PublicAccumulatedData,
revertible: PublicAccumulatedData
revertible: PublicAccumulatedData,
output_hints: OutputHints<NUM_PUBLIC_DATA_LEAVES>
) -> CombinedAccumulatedData {
let mut note_hashes = [0; MAX_NOTE_HASHES_PER_TX];
let sorted_unsiloed_note_hashes = sort_by_counter_asc(array_merge(non_revertible.note_hashes, revertible.note_hashes));
let tx_hash = non_revertible.nullifiers[0].value;
for i in 0..sorted_unsiloed_note_hashes.len() {
let note_hash = sorted_unsiloed_note_hashes[i];
note_hashes[i] = if note_hash.counter() == 0 {
// If counter is zero, the note hash is either empty or is emitted from private and has been siloed in private_kernel_tail_to_public.
note_hash.value()
} else {
silo_note_hash(note_hash, tx_hash, i)
};
}

let nullifiers = sort_by_counter_asc(array_merge(non_revertible.nullifiers, revertible.nullifiers)).map(|n: Nullifier| n.value);

let l2_to_l1_msgs = sort_by_counter_asc(array_merge(non_revertible.l2_to_l1_msgs, revertible.l2_to_l1_msgs));

let public_data_update_requests = dedupe_array(
array_merge(
non_revertible.public_data_update_requests,
revertible.public_data_update_requests
)
);
let public_data_update_requests = dedupe_array(output_hints.public_data_writes);

let note_encrypted_logs_hashes = sort_by_counter_asc(
array_merge(
Expand All @@ -60,7 +43,7 @@ unconstrained pub fn combine_data(
let unencrypted_log_preimages_length = unencrypted_logs_hashes.fold(0, |a, b: ScopedLogHash| a + b.log_hash.length);

CombinedAccumulatedData {
note_hashes,
note_hashes: output_hints.siloed_note_hashes,
nullifiers,
l2_to_l1_msgs,
note_encrypted_logs_hashes,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
use crate::components::public_tail_output_composer::{
generate_overridable_public_data_writes::{generate_overridable_public_data_writes, LinkedIndexHint},
generate_public_data_leaves::generate_public_data_leaves
};
use dep::types::{
abis::{
kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs,
public_data_write::OverridablePublicDataWrite
},
constants::{
MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, MAX_L2_TO_L1_MSGS_PER_TX,
MAX_UNENCRYPTED_LOGS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX,
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX
},
data::{OverridablePublicDataTreeLeaf, PublicDataLeafHint}, hash::silo_note_hash, traits::Empty,
utils::arrays::{array_merge, CombinedOrderHint, get_combined_order_hints_asc, sort_by_counter_asc, SortedResult}
};

struct SiloedNoteHashHint {
siloed_note_hash: Field,
index: u32,
}

impl Empty for SiloedNoteHashHint {
fn empty() -> Self {
SiloedNoteHashHint { siloed_note_hash: 0, index: 0 }
}
}

impl Eq for SiloedNoteHashHint {
fn eq(self, other: Self) -> bool {
(self.siloed_note_hash == other.siloed_note_hash) & (self.index == other.index)
}
}

struct OutputHints<let NUM_PUBLIC_DATA_LEAVES: u32> {
siloed_note_hashes: [Field; MAX_NOTE_HASHES_PER_TX],
siloed_note_hash_hints: [SiloedNoteHashHint; MAX_NOTE_HASHES_PER_TX],
sorted_note_hash_hints: [CombinedOrderHint; MAX_NOTE_HASHES_PER_TX],
sorted_nullifier_hints: [CombinedOrderHint; MAX_NULLIFIERS_PER_TX],
sorted_l2_to_l1_msg_hints: [CombinedOrderHint; MAX_L2_TO_L1_MSGS_PER_TX],
sorted_note_encrypted_log_hash_hints: [CombinedOrderHint; MAX_NOTE_ENCRYPTED_LOGS_PER_TX],
sorted_encrypted_log_hash_hints: [CombinedOrderHint; MAX_ENCRYPTED_LOGS_PER_TX],
sorted_unencrypted_log_hash_hints: [CombinedOrderHint; MAX_UNENCRYPTED_LOGS_PER_TX],
public_data_writes: [OverridablePublicDataWrite; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX],
public_data_leaves: [OverridablePublicDataTreeLeaf; NUM_PUBLIC_DATA_LEAVES],
unique_slot_index_hints: SortedResult<Field, NUM_PUBLIC_DATA_LEAVES>,
public_data_linked_index_hints: [LinkedIndexHint; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX],
}

unconstrained pub fn generate_output_hints<let NUM_PUBLIC_DATA_LEAVES: u32>(
previous_kernel: PublicKernelCircuitPublicInputs,
public_data_leaf_hints: [PublicDataLeafHint; NUM_PUBLIC_DATA_LEAVES]
) -> OutputHints<NUM_PUBLIC_DATA_LEAVES> {
let non_revertible = previous_kernel.end_non_revertible;
let revertible = previous_kernel.end;

// Note hashes.
let mut siloed_note_hashes = [0; MAX_NOTE_HASHES_PER_TX];
let mut siloed_note_hash_hints = [SiloedNoteHashHint::empty(); MAX_NOTE_HASHES_PER_TX];
let sorted_unsiloed_note_hashes = sort_by_counter_asc(array_merge(non_revertible.note_hashes, revertible.note_hashes));
let tx_hash = non_revertible.nullifiers[0].value;
for i in 0..sorted_unsiloed_note_hashes.len() {
let note_hash = sorted_unsiloed_note_hashes[i];
let siloed_note_hash = if note_hash.counter() == 0 {
// If counter is zero, the note hash is either empty or is emitted from private and has been siloed in private_kernel_tail_to_public.
note_hash.value()
} else {
silo_note_hash(note_hash, tx_hash, i)
};
siloed_note_hashes[i] = siloed_note_hash;
if siloed_note_hash != 0 {
siloed_note_hash_hints[i] = SiloedNoteHashHint { siloed_note_hash, index: i };
}
}

// Public data.
let combined_writes = array_merge(
previous_kernel.end_non_revertible.public_data_update_requests,
previous_kernel.end.public_data_update_requests
);
let (public_data_leaves, unique_slot_index_hints) = generate_public_data_leaves(
previous_kernel.validation_requests.public_data_reads,
combined_writes,
public_data_leaf_hints
);
let (public_data_writes, public_data_linked_index_hints) = generate_overridable_public_data_writes(combined_writes, public_data_leaves);

OutputHints {
siloed_note_hashes,
siloed_note_hash_hints,
sorted_note_hash_hints: get_combined_order_hints_asc(non_revertible.note_hashes, revertible.note_hashes),
sorted_nullifier_hints: get_combined_order_hints_asc(non_revertible.nullifiers, revertible.nullifiers),
sorted_l2_to_l1_msg_hints: get_combined_order_hints_asc(non_revertible.l2_to_l1_msgs, revertible.l2_to_l1_msgs),
sorted_note_encrypted_log_hash_hints: get_combined_order_hints_asc(
non_revertible.note_encrypted_logs_hashes,
revertible.note_encrypted_logs_hashes
),
sorted_encrypted_log_hash_hints: get_combined_order_hints_asc(
non_revertible.encrypted_logs_hashes,
revertible.encrypted_logs_hashes
),
sorted_unencrypted_log_hash_hints: get_combined_order_hints_asc(
non_revertible.unencrypted_logs_hashes,
revertible.unencrypted_logs_hashes
),
public_data_writes,
public_data_leaves,
unique_slot_index_hints,
public_data_linked_index_hints
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use dep::types::{
abis::{public_data_update_request::PublicDataUpdateRequest, public_data_write::OverridablePublicDataWrite},
data::OverridablePublicDataTreeLeaf, traits::Empty, utils::arrays::{array_length, find_index_hint}
};

struct LinkedIndexHint {
is_first_write: bool,
prev_index: u32,
}

impl Empty for LinkedIndexHint {
fn empty() -> Self {
LinkedIndexHint { is_first_write: false, prev_index: 0 }
}
}

unconstrained pub fn generate_overridable_public_data_writes<let NUM_WRITES: u32, let NUM_LEAVES: u32>(
public_data_writes: [PublicDataUpdateRequest; NUM_WRITES],
public_data_leaves: [OverridablePublicDataTreeLeaf; NUM_LEAVES]
) -> ([OverridablePublicDataWrite; NUM_WRITES], [LinkedIndexHint; NUM_WRITES]) {
let mut overridable_public_data_writes = [OverridablePublicDataWrite::empty(); NUM_WRITES];
let mut hints = [LinkedIndexHint::empty(); NUM_WRITES];

let writes_len = array_length(public_data_writes);
for i in 0..writes_len {
let write = public_data_writes[i];
let mut override_counter = 0;
let mut is_first_write = false;
let mut prev_index = 0;
let mut prev_counter = 0;

for j in 0..writes_len {
let other = public_data_writes[j];
if (j != i) & (other.leaf_slot == write.leaf_slot) {
if other.counter > write.counter {
if (override_counter == 0) | (other.counter < override_counter) {
override_counter = other.counter;
}
} else if other.counter < write.counter {
if other.counter > prev_counter {
prev_counter = other.counter;
prev_index = j;
}
}
}
}

if prev_counter == 0 {
is_first_write = true;
prev_index = find_index_hint(public_data_leaves, |leaf: OverridablePublicDataTreeLeaf| leaf.leaf.slot == write.leaf_slot);
}

overridable_public_data_writes[i] = OverridablePublicDataWrite { write, override_counter };
hints[i] = LinkedIndexHint { is_first_write, prev_index };
}

(overridable_public_data_writes, hints)
}
Loading

0 comments on commit ae86347

Please sign in to comment.