Skip to content
Closed
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
98b9784
udpates to handshake registry
vezenovm May 14, 2026
27e5a5e
nargo fmt
vezenovm May 14, 2026
381858d
clean up bug repros and link to TODO
vezenovm May 14, 2026
fff3541
fmt
vezenovm May 14, 2026
3202ab1
constants test update
vezenovm May 14, 2026
49bfefc
switch to handshakes: Map<AztecAddress, Owned<PrivateMutable<Handshak…
vezenovm May 14, 2026
d00136d
remove old comment referencing issue
vezenovm May 14, 2026
76c025e
Update noir-projects/noir-contracts/contracts/message_discovery/hands…
vezenovm May 14, 2026
75554b1
pr comments, cleanup, additional tests
vezenovm May 15, 2026
9a451ef
extend sender tagging store and make a new oracle to get next constra…
vezenovm May 18, 2026
14d22ca
merge conflicts w/ fairies
vezenovm May 18, 2026
bfb03bf
fix: bump HashedValueTester capacities for new constrained-msg dom sep
AztecBot May 18, 2026
aa3d1e6
merge w/ fairies
vezenovm May 26, 2026
df3f982
test: bump HashedValueTester capacity for new constrained_msg_log_tag…
AztecBot May 26, 2026
36d355d
test cleanup
vezenovm May 26, 2026
3bad347
Merge remote-tracking branch 'origin/maxim/f-668-aztec-nr-extend-get_…
vezenovm May 26, 2026
f4b6e86
feat: calculate_secret_and_index constrained delivery helpery
vezenovm May 26, 2026
652d92d
Merge branch 'maxim/f-668-aztec-nr-extend-get_next_app_tag_as_sender-…
vezenovm May 26, 2026
f686408
Apply suggestion from @vezenovm
vezenovm May 26, 2026
37c3d0e
use compute_nullifier_existence_request
vezenovm May 26, 2026
0afe779
Merge remote-tracking branch 'origin/maxim/f-669-aztec-nr-calculate_s…
vezenovm May 26, 2026
a45d68a
verify that the index is reserved when sending multiple msgs within t…
vezenovm May 28, 2026
0ff7c94
merge w/ merge-train/fairies
vezenovm May 28, 2026
f7ef01f
cleanup
vezenovm May 28, 2026
3e89f16
fmt
vezenovm May 28, 2026
dd3de61
comment
vezenovm May 28, 2026
21f5920
Merge branch 'merge-train/fairies' into maxim/f-669-aztec-nr-calculat…
vezenovm May 28, 2026
9f44ac2
Merge branch 'merge-train/fairies' into maxim/f-669-aztec-nr-calculat…
vezenovm May 28, 2026
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
3 changes: 1 addition & 2 deletions barretenberg/cpp/src/barretenberg/aztec/aztec_constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,7 @@
#define AVM_EMITPUBLICLOG_DYN_DA_GAS 32
#define AVM_SSTORE_DYN_DA_GAS 64
#define AVM_WRITTEN_PUBLIC_DATA_SLOTS_TREE_HEIGHT 6
#define AVM_WRITTEN_PUBLIC_DATA_SLOTS_TREE_INITIAL_ROOT \
"0x13954b76f8ab76c38ab687731f802fc90e5d55e0592fa6f56d0a73024b3f8356"
#define AVM_WRITTEN_PUBLIC_DATA_SLOTS_TREE_INITIAL_ROOT "0x13954b76f8ab76c38ab687731f802fc90e5d55e0592fa6f56d0a73024b3f8356"
Comment thread
vezenovm marked this conversation as resolved.
Outdated
#define AVM_WRITTEN_PUBLIC_DATA_SLOTS_TREE_INITIAL_SIZE 1
#define AVM_RETRIEVED_BYTECODES_TREE_HEIGHT 5
#define AVM_RETRIEVED_BYTECODES_TREE_INITIAL_ROOT "0x0ff65ad321f05745d4c80e2e18e94241093d2e49017ff8cc151df4f207a43c12"
Expand Down
3 changes: 3 additions & 0 deletions noir-projects/aztec-nr/aztec/src/keys/ecdh_shared_secret.nr
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ pub fn derive_ecdh_shared_secret(secret: Scalar, public_key: EmbeddedCurvePoint)
/// Computes an app-siloed shared secret from a raw ECDH shared secret point and a contract address.
///
/// `s_app = h(DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET, S.x, S.y, contract_address)`
///
/// Public so that contracts holding a raw `EmbeddedCurvePoint` (e.g. the constrained-delivery handshake registry) can
/// reuse the canonical silo formula rather than re-inlining it and risking drift.
pub fn compute_app_siloed_shared_secret(shared_secret: EmbeddedCurvePoint, contract_address: AztecAddress) -> Field {
poseidon2_hash_with_separator(
[shared_secret.x, shared_secret.y, contract_address.to_field()],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//! Sender-side helpers for constrained message delivery.

use crate::context::{NullifierExistenceRequest, PrivateContext};
use crate::oracle::{call_utility_function::call_utility_function, notes::get_next_constrained_index};

use crate::protocol::{
abis::function_selector::FunctionSelector,
address::AztecAddress,
constants::DOM_SEP__CONSTRAINED_MSG_NULLIFIER,
hash::poseidon2_hash_with_separator,
traits::{Deserialize, ToField},
};

/// Resolves the app-siloed shared secret and next per-secret index for a constrained send.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Warning, boss-man likes the first line to be 10 words max

///
/// Wraps the registry calls needed by every constrained-delivery app: query the handshake registry for an
/// existing app-siloed secret, bootstrap a fresh handshake if there isn't one, and constrain the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// existing app-siloed secret, bootstrap a fresh handshake if there isn't one, and constrain the
/// existing app-siloed secret, bootstrap a fresh handshake if there isn't one, and constrain the

/// oracle-supplied secret. The returned `(secret, index)` pair is the input for the caller's tag derivation

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Shouldn't this be an index?

Suggested change
/// oracle-supplied secret. The returned `(secret, index)` pair is the input for the caller's tag derivation
/// oracle-supplied tagging index. The returned `(secret, index)` pair is the input for the caller's tag derivation

/// and nullifier emission.
///
/// ## Implementation Details
/// 1. Calls `HandshakeRegistry::get_app_siloed_secret` offchain (untrusted hint).
/// 2. On `None`, calls `HandshakeRegistry::non_interactive_handshake(sender, recipient)` to bootstrap and
/// returns `(secret, 0)`. The constrained return value of the private call is the source of truth for the
/// secret.
/// 3. On `Some(secret)`, reads the per-secret index hint via [`get_next_constrained_index`] (also untrusted),
/// then constrains:
/// - `index == 0`: calls `HandshakeRegistry::validate_handshake` to bind the secret to the registry's
/// current note. `PrivateMutable::get_note` inside `validate_handshake` nullifies the current handshake
/// note and emits a fresh one, so this branch already produces a per-call nullifier on the registry
/// note.
/// - `index > 0`: asserts the prior nullifier
/// `poseidon2_hash_with_separator([sender, recipient, secret, index - 1], DOM_SEP__CONSTRAINED_MSG_NULLIFIER)`
/// exists in the app's pending set / nullifier tree. The chain transitively constrains back to the
/// index-0 `validate_handshake`. The caller is expected to emit the matching nullifier alongside each
/// constrained send so subsequent calls can prove the chain.
pub fn calculate_secret_and_index(
context: &mut PrivateContext,
registry: AztecAddress,
sender: AztecAddress,
recipient: AztecAddress,
) -> (Field, u32) {
let caller = context.this_address();

// Safety: the returned `Option<Field>` is untrusted and is constrained below before being returned to the
// caller, either by performing a new handshake or by constraining the prior handshake's existence.
Comment on lines +47 to +48

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What about something like this?

// Safety: when the utility call returns no secret, we attempt to create a fresh handshake. Creating
  // a duplicate fails, so a forged empty response cannot hide an existing handshake. When the utility
  // call returns a secret, it is validated against the registry's stored handshake.

let maybe_secret: Option<Field> = unsafe {
let selector = comptime {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we somehow avoid the selector and to something like Registry::at(address).... Like we do for tokens. I'm concerned about a possible change in the function signature that would drift from this

FunctionSelector::from_signature("get_app_siloed_secret((Field),(Field),(Field))")
};
let returns = call_utility_function(
registry,
selector,
[sender.to_field(), recipient.to_field(), caller.to_field()],
);
Deserialize::deserialize(returns)
};

if maybe_secret.is_none() {
// Bootstrap: no handshake exists yet. The registry inserts a fresh note and returns the app-siloed
// secret to the caller. The constrained return is the source of truth for the secret, so no separate
// `validate_handshake` is needed.
// TODO(F-660): dispatch to `perform_handshake(sender, recipient, handshake_type)` once interactive
// handshakes are supported.
let selector = comptime {
FunctionSelector::from_signature("non_interactive_handshake((Field),(Field))")
};
let secret: Field = context
.call_private_function(registry, selector, [sender.to_field(), recipient.to_field()])
.get_preimage();
(secret, 0)
} else {
let secret = maybe_secret.unwrap_unchecked();

// Safety: the index is untrusted; the anchor branches below ensure the returned `(secret, index)` pair
// is bound to a real registry handshake before it leaves the helper.
let index = unsafe { get_next_constrained_index(secret) };

if index == 0 {
let selector = comptime {
FunctionSelector::from_signature("validate_handshake((Field),(Field),Field)")
};
let _ = context.call_private_function(
registry,
selector,
[sender.to_field(), recipient.to_field(), secret],
);
Comment on lines +90 to +97

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same with selector

} else {
let prev_nullifier = poseidon2_hash_with_separator(
[sender.to_field(), recipient.to_field(), secret, (index - 1) as Field],
DOM_SEP__CONSTRAINED_MSG_NULLIFIER,
);
Comment on lines +99 to +102

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We could probably have a helper function in this file for this, since we'll need to re-use it when we actually send a message

context.assert_nullifier_exists(NullifierExistenceRequest::for_pending(
prev_nullifier,
caller,
));
}

(secret, index)
}
}
Loading
Loading