Skip to content

Commit

Permalink
refactor: using poseidon2 when computing a nullifier (#5906)
Browse files Browse the repository at this point in the history
Fixes #5832
Fixes #1205
  • Loading branch information
benesjan authored Apr 24, 2024
1 parent 348b34f commit 3a10e5e
Show file tree
Hide file tree
Showing 56 changed files with 274 additions and 237 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ A message that is sent from L1 to L2.
| `sender` | `L1Actor` | The actor on L1 that is sending the message. |
| `recipient` | `L2Actor` | The actor on L2 that is to receive the message. |
| `content` | `field (~254 bits)` | The field element containing the content to be sent to L2. |
| `secretHash` | `field (~254 bits)` | The hash of a secret pre-image that must be known to consume the message on L2. Use the [`computeMessageSecretHash`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/utils/secrets.ts) to compute it from a secret. |
| `secretHash` | `field (~254 bits)` | The hash of a secret pre-image that must be known to consume the message on L2. Use [`computeSecretHash`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/utils/secrets.ts) to compute it from a secret. |

## `L2ToL1Message`

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/developers/contracts/references/portals/inbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Sends a message from L1 to L2.
| -------------- | ------- | ----------- |
| Recipient | `L2Actor` | The recipient of the message. This **MUST** match the rollup version and an Aztec contract that is **attached** to the contract making this call. If the recipient is not attached to the caller, the message cannot be consumed by it. |
| Content | `field` (~254 bits) | The content of the message. This is the data that will be passed to the recipient. The content is limited to be a single field for rollup purposes. If the content is small enough it can just be passed along, otherwise it should be hashed and the hash passed along (you can use our [`Hash`](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/libraries/Hash.sol) utilities with `sha256ToField` functions) |
| Secret Hash | `field` (~254 bits) | A hash of a secret that is used when consuming the message on L2. Keep this preimage a secret to make the consumption private. To consume the message the caller must know the pre-image (the value that was hashed) - so make sure your app keeps track of the pre-images! Use the [`computeMessageSecretHash`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/utils/secrets.ts) to compute it from a secret. |
| Secret Hash | `field` (~254 bits) | A hash of a secret that is used when consuming the message on L2. Keep this preimage a secret to make the consumption private. To consume the message the caller must know the pre-image (the value that was hashed) - so make sure your app keeps track of the pre-images! Use [`computeSecretHash`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/utils/secrets.ts) to compute it from a secret. |
| ReturnValue | `bytes32` | The message hash, used as an identifier |

#### Edge cases
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ When sending messages, we need to specify quite a bit of information beyond just
| Name | Type | Description |
| ----------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Recipient | `L2Actor` | The message recipient. This **MUST** match the rollup version and an Aztec contract that is **attached** to the contract making this call. If the recipient is not attached to the caller, the message cannot be consumed by it. |
| Secret Hash | `field` (~254 bits) | A hash of a secret that is used when consuming the message on L2. Keep this preimage a secret to make the consumption private. To consume the message the caller must know the pre-image (the value that was hashed) - so make sure your app keeps track of the pre-images! Use the [`computeMessageSecretHash`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/utils/secrets.ts) to compute it from a secret. |
| Secret Hash | `field` (~254 bits) | A hash of a secret that is used when consuming the message on L2. Keep this preimage a secret to make the consumption private. To consume the message the caller must know the pre-image (the value that was hashed) - so make sure your app keeps track of the pre-images! Use [`computeSecretHash`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/utils/secrets.ts) to compute it from a secret. |
| Content | `field` (~254 bits) | The content of the message. This is the data that will be passed to the recipient. The content is limited to be a single field. If the content is small enough it can just be passed along, otherwise it should be hashed and the hash passed along (you can use our [`Hash`](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/libraries/Hash.sol) utilities with `sha256ToField` functions)

With all that information at hand, we can call the `sendL2Message` function on the Inbox. The function will return a `field` (inside `bytes32`) that is the hash of the message. This hash can be used as an identifier to spot when your message has been included in a rollup block.
Expand Down Expand Up @@ -56,7 +56,7 @@ In Solidity, you can use our `Hash.sha256ToField()` method:

#include_code deposit_public l1-contracts/test/portals/TokenPortal.sol solidity

The `secret_hash` uses the pederson hash which fits in a field element. You can use the utility method `computeMessageSecretHash()`in `@aztec/aztec.js` npm package to generate a secret and its corresponding hash.
The `secret_hash` uses the pederson hash which fits in a field element. You can use the utility method `computeSecretHash()`in `@aztec/aztec.js` npm package to generate a secret and its corresponding hash.

After the transaction has been mined, the message is consumed, a nullifier is emitted and the tokens have been minted on Aztec and are ready for claiming.

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/developers/tutorials/writing_dapp/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
ExtendedNote,
Fr,
Note,
computeMessageSecretHash,
computeSecretHash,
createPXEClient,
waitForPXE,
} from "@aztec/aztec.js";
Expand Down
18 changes: 9 additions & 9 deletions noir-projects/aztec-nr/address-note/src/address_note.nr
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
use dep::aztec::log::emit_encrypted_log;
// docs:end:encrypted_import
use dep::aztec::{
protocol_types::{address::AztecAddress, traits::Empty},
protocol_types::{address::AztecAddress, traits::Empty, constants::GENERATOR_INDEX__NOTE_NULLIFIER},
note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption},
oracle::{unsafe_rand::unsafe_rand, nullifier_key::get_app_nullifier_secret_key, get_public_key::get_public_key},
hash::pedersen_hash, context::PrivateContext
context::PrivateContext, hash::poseidon2_hash
};

global ADDRESS_NOTE_LEN: Field = 3;
Expand All @@ -19,26 +19,26 @@ struct AddressNote {
randomness: Field,
}

impl NoteInterface<ADDRESS_NOTE_LEN> for AddressNote {
impl NoteInterface<ADDRESS_NOTE_LEN> for AddressNote {

fn compute_nullifier(self, context: &mut PrivateContext) -> Field {
let note_hash_for_nullify = compute_note_hash_for_consumption(self);
let secret = context.request_app_nullifier_secret_key(self.owner);
// TODO(#1205) Should use a non-zero generator index.
pedersen_hash([
poseidon2_hash([
note_hash_for_nullify,
secret,
],0)
GENERATOR_INDEX__NOTE_NULLIFIER as Field,
])
}

fn compute_nullifier_without_context(self) -> Field {
let note_hash_for_nullify = compute_note_hash_for_consumption(self);
let secret = get_app_nullifier_secret_key(self.owner);
// TODO(#1205) Should use a non-zero generator index.
pedersen_hash([
poseidon2_hash([
note_hash_for_nullify,
secret,
],0)
GENERATOR_INDEX__NOTE_NULLIFIER as Field,
])
}

// Broadcasts the note as an encrypted log on L1.
Expand Down
7 changes: 3 additions & 4 deletions noir-projects/aztec-nr/aztec/src/hash.nr
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
use dep::protocol_types::{
address::{AztecAddress, EthAddress},
constants::{
GENERATOR_INDEX__L1_TO_L2_MESSAGE_SECRET, GENERATOR_INDEX__NULLIFIER, ARGS_HASH_CHUNK_COUNT,
GENERATOR_INDEX__SECRET_HASH, GENERATOR_INDEX__MESSAGE_NULLIFIER, ARGS_HASH_CHUNK_COUNT,
GENERATOR_INDEX__FUNCTION_ARGS, ARGS_HASH_CHUNK_LENGTH
},
traits::Hash, hash::{pedersen_hash, poseidon2_hash, silo_nullifier, sha256_to_field}
};

pub fn compute_secret_hash(secret: Field) -> Field {
// TODO(#1205) This is probably not the right index to use
pedersen_hash([secret], GENERATOR_INDEX__L1_TO_L2_MESSAGE_SECRET)
pedersen_hash([secret], GENERATOR_INDEX__SECRET_HASH)
}

pub fn compute_message_hash(
Expand Down Expand Up @@ -45,7 +44,7 @@ pub fn compute_message_hash(
pub fn compute_message_nullifier(message_hash: Field, secret: Field, leaf_index: Field) -> Field {
pedersen_hash(
[message_hash, secret, leaf_index],
GENERATOR_INDEX__NULLIFIER
GENERATOR_INDEX__MESSAGE_NULLIFIER
)
}

Expand Down
11 changes: 8 additions & 3 deletions noir-projects/aztec-nr/aztec/src/note/utils.nr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ use crate::{context::PrivateContext, note::{note_header::NoteHeader, note_interf

use dep::protocol_types::{
address::AztecAddress,
constants::{GENERATOR_INDEX__OUTER_NULLIFIER, GENERATOR_INDEX__UNIQUE_NOTE_HASH, GENERATOR_INDEX__SILOED_NOTE_HASH},
constants::{
GENERATOR_INDEX__OUTER_NULLIFIER, GENERATOR_INDEX__UNIQUE_NOTE_HASH,
GENERATOR_INDEX__SILOED_NOTE_HASH, GENERATOR_INDEX__INNER_NOTE_HASH
},
hash::pedersen_hash, utils::arr_copy_slice
};

Expand All @@ -20,8 +23,10 @@ fn compute_inner_note_hash<Note, N>(note: Note) -> Field where Note: NoteInterfa
let header = note.get_header();
let note_hash = note.compute_note_content_hash();

// TODO(#1205) Do we need a generator index here?
pedersen_hash([header.storage_slot, note_hash], 0)
pedersen_hash(
[header.storage_slot, note_hash],
GENERATOR_INDEX__INNER_NOTE_HASH
)
}

fn compute_siloed_note_hash<Note, N>(note_with_header: Note) -> Field where Note: NoteInterface<N> {
Expand Down
2 changes: 1 addition & 1 deletion noir-projects/aztec-nr/aztec/src/prelude.nr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
state_vars::{
map::Map, private_immutable::PrivateImmutable, private_mutable::PrivateMutable,
public_immutable::PublicImmutable, public_mutable::PublicMutable, private_set::PrivateSet,
shared_immutable::SharedImmutable, storage::Storable
shared_immutable::SharedImmutable, shared_mutable::SharedMutable, storage::Storable
},
log::emit_encrypted_log, context::{PrivateContext, PackedReturns, FunctionReturns},
note::{
Expand Down
19 changes: 11 additions & 8 deletions noir-projects/aztec-nr/value-note/src/value_note.nr
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use dep::aztec::{
protocol_types::{address::AztecAddress, traits::{Deserialize, Serialize}},
protocol_types::{
address::AztecAddress, traits::{Deserialize, Serialize},
constants::GENERATOR_INDEX__NOTE_NULLIFIER
},
note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption},
oracle::{unsafe_rand::unsafe_rand, nullifier_key::get_app_nullifier_secret_key, get_public_key::get_public_key},
log::emit_encrypted_log, hash::pedersen_hash, context::PrivateContext
log::emit_encrypted_log, hash::poseidon2_hash, context::PrivateContext
};

global VALUE_NOTE_LEN: Field = 3; // 3 plus a header.
Expand All @@ -22,23 +25,23 @@ impl NoteInterface<VALUE_NOTE_LEN> for ValueNote {
fn compute_nullifier(self, context: &mut PrivateContext) -> Field {
let note_hash_for_nullify = compute_note_hash_for_consumption(self);
let secret = context.request_app_nullifier_secret_key(self.owner);
// TODO(#1205) Should use a non-zero generator index.
pedersen_hash([
poseidon2_hash([
note_hash_for_nullify,
secret,
],0)
GENERATOR_INDEX__NOTE_NULLIFIER as Field,
])
}

// docs:end:nullifier

fn compute_nullifier_without_context(self) -> Field {
let note_hash_for_nullify = compute_note_hash_for_consumption(self);
let secret = get_app_nullifier_secret_key(self.owner);
// TODO(#1205) Should use a non-zero generator index.
pedersen_hash([
poseidon2_hash([
note_hash_for_nullify,
secret,
],0)
GENERATOR_INDEX__NOTE_NULLIFIER as Field,
])
}

// Broadcasts the note as an encrypted log on L1.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use dep::aztec::prelude::{AztecAddress, PrivateContext, NoteHeader, emit_encrypted_log, NoteInterface};
use dep::aztec::{
note::utils::compute_note_hash_for_consumption, hash::pedersen_hash,
protocol_types::constants::GENERATOR_INDEX__NOTE_NULLIFIER, note::utils::compute_note_hash_for_consumption,
hash::poseidon2_hash,
oracle::{nullifier_key::get_app_nullifier_secret_key, get_public_key::get_public_key}
};

Expand All @@ -17,23 +18,23 @@ struct SubscriptionNote {

impl NoteInterface<SUBSCRIPTION_NOTE_LEN> for SubscriptionNote {
fn compute_nullifier(self, context: &mut PrivateContext) -> Field {
let unique_siloed_note_hash = compute_note_hash_for_consumption(self);
let note_hash_for_nullify = compute_note_hash_for_consumption(self);
let secret = context.request_app_nullifier_secret_key(self.owner);
// TODO(#1205) Should use a non-zero generator index.
pedersen_hash([
unique_siloed_note_hash,
poseidon2_hash([
note_hash_for_nullify,
secret,
],0)
GENERATOR_INDEX__NOTE_NULLIFIER as Field,
])
}

fn compute_nullifier_without_context(self) -> Field {
let unique_siloed_note_hash = compute_note_hash_for_consumption(self);
let note_hash_for_nullify = compute_note_hash_for_consumption(self);
let secret = get_app_nullifier_secret_key(self.owner);
// TODO(#1205) Should use a non-zero generator index.
pedersen_hash([
unique_siloed_note_hash,
poseidon2_hash([
note_hash_for_nullify,
secret,
],0)
GENERATOR_INDEX__NOTE_NULLIFIER as Field,
])
}

// Broadcasts the note as an encrypted log on L1.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use dep::aztec::prelude::{AztecAddress, NoteInterface, NoteHeader, PrivateContex
use dep::aztec::{
note::{utils::compute_note_hash_for_consumption},
oracle::{nullifier_key::get_app_nullifier_secret_key, get_public_key::get_public_key},
hash::pedersen_hash, protocol_types::traits::Empty
hash::poseidon2_hash, protocol_types::{traits::Empty, constants::GENERATOR_INDEX__NOTE_NULLIFIER},
};

// Shows how to create a custom note
Expand All @@ -28,19 +28,21 @@ impl NoteInterface<CARD_NOTE_LEN> for CardNote {
fn compute_nullifier(self, context: &mut PrivateContext) -> Field {
let note_hash_for_nullify = compute_note_hash_for_consumption(self);
let secret = context.request_app_nullifier_secret_key(self.owner);
pedersen_hash([
poseidon2_hash([
note_hash_for_nullify,
secret,
],0)
GENERATOR_INDEX__NOTE_NULLIFIER as Field,
])
}

fn compute_nullifier_without_context(self) -> Field {
let note_hash_for_nullify = compute_note_hash_for_consumption(self);
let secret = get_app_nullifier_secret_key(self.owner);
pedersen_hash([
poseidon2_hash([
note_hash_for_nullify,
secret,
],0)
GENERATOR_INDEX__NOTE_NULLIFIER as Field,
])
}

// Broadcasts the note as an encrypted log on L1.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use dep::aztec::prelude::{
use dep::aztec::{
note::utils::compute_note_hash_for_consumption,
oracle::{nullifier_key::get_app_nullifier_secret_key, get_public_key::get_public_key},
hash::pedersen_hash
hash::poseidon2_hash, protocol_types::constants::GENERATOR_INDEX__NOTE_NULLIFIER,
};

global ECDSA_PUBLIC_KEY_NOTE_LEN: Field = 5;
Expand Down Expand Up @@ -67,23 +67,23 @@ impl NoteInterface<ECDSA_PUBLIC_KEY_NOTE_LEN> for EcdsaPublicKeyNote {
}

fn compute_nullifier(self, context: &mut PrivateContext) -> Field {
let unique_siloed_note_hash = compute_note_hash_for_consumption(self);
let note_hash_for_nullify = compute_note_hash_for_consumption(self);
let secret = context.request_app_nullifier_secret_key(self.owner);
// TODO(#1205) Should use a non-zero generator index.
pedersen_hash([
unique_siloed_note_hash,
poseidon2_hash([
note_hash_for_nullify,
secret,
],0)
GENERATOR_INDEX__NOTE_NULLIFIER as Field,
])
}

fn compute_nullifier_without_context(self) -> Field {
let unique_siloed_note_hash = compute_note_hash_for_consumption(self);
let note_hash_for_nullify = compute_note_hash_for_consumption(self);
let secret = get_app_nullifier_secret_key(self.owner);
// TODO(#1205) Should use a non-zero generator index.
pedersen_hash([
unique_siloed_note_hash,
poseidon2_hash([
note_hash_for_nullify,
secret,
],0)
GENERATOR_INDEX__NOTE_NULLIFIER as Field,
])
}

// Broadcasts the note as an encrypted log on L1.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ mod lib;

contract GasToken {
use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}};
use dep::aztec::{hash::compute_secret_hash, state_vars::{SharedImmutable, PublicMutable, Map}};
use dep::aztec::state_vars::{SharedImmutable, PublicMutable, Map};

use crate::lib::{calculate_fee, get_bridge_gas_msg_hash};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use dep::aztec::prelude::{AztecAddress, NoteHeader, NoteInterface, PrivateContext, emit_encrypted_log};
use dep::aztec::{
note::utils::compute_note_hash_for_consumption, hash::pedersen_hash,
oracle::{nullifier_key::get_app_nullifier_secret_key, get_public_key::get_public_key}
note::utils::compute_note_hash_for_consumption, hash::poseidon2_hash,
oracle::{nullifier_key::get_app_nullifier_secret_key, get_public_key::get_public_key},
protocol_types::constants::GENERATOR_INDEX__NOTE_NULLIFIER,
};

global PUBLIC_KEY_NOTE_LEN: Field = 3;
Expand All @@ -17,23 +18,23 @@ struct PublicKeyNote {

impl NoteInterface<PUBLIC_KEY_NOTE_LEN> for PublicKeyNote {
fn compute_nullifier(self, context: &mut PrivateContext) -> Field {
let unique_siloed_note_hash = compute_note_hash_for_consumption(self);
let note_hash_for_nullify = compute_note_hash_for_consumption(self);
let secret = context.request_app_nullifier_secret_key(self.owner);
// TODO(#1205) Should use a non-zero generator index.
pedersen_hash([
unique_siloed_note_hash,
poseidon2_hash([
note_hash_for_nullify,
secret,
],0)
GENERATOR_INDEX__NOTE_NULLIFIER as Field,
])
}

fn compute_nullifier_without_context(self) -> Field {
let unique_siloed_note_hash = compute_note_hash_for_consumption(self);
let note_hash_for_nullify = compute_note_hash_for_consumption(self);
let secret = get_app_nullifier_secret_key(self.owner);
// TODO(#1205) Should use a non-zero generator index.
pedersen_hash([
unique_siloed_note_hash,
poseidon2_hash([
note_hash_for_nullify,
secret,
],0)
GENERATOR_INDEX__NOTE_NULLIFIER as Field,
])
}

// Broadcasts the note as an encrypted log on L1.
Expand Down
Loading

0 comments on commit 3a10e5e

Please sign in to comment.