Skip to content

Commit

Permalink
chore: add comment around privacy-leaking singletons
Browse files Browse the repository at this point in the history
  • Loading branch information
LHerskind committed Jan 24, 2024
1 parent ee317e6 commit 2e7cd34
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 4 deletions.
12 changes: 10 additions & 2 deletions docs/docs/dev_docs/contracts/syntax/storage/main.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,11 @@ As part of the initialization of the `Storage` struct, the `Singleton` is create

As mentioned, the Singleton is initialized to create the first note and value.

When this function is called, a nullifier of the storage slot is created, preventing this Singleton from being initialized again. If an `owner` is specified, the nullifier will be hashed with the owner's secret key. It's crucial to provide an owner if the Singleton is associated with an account. Initializing it without an owner may inadvertently reveal important information about the owner's intention.
When this function is called, a nullifier of the storage slot is created, preventing this Singleton from being initialized again.

:::danger Privacy-Leak
Beware that because this nullifier is created only from the storage slot without randomness it is "leaky". This means that if the storage slot depends on the an address then it is possible to link the nullifier to the address. For example, if the singleton is part of a `map` with an `AztecAddress` as the key then the nullifier will be linked to the address.
:::

Unlike public states, which have a default initial value of `0` (or many zeros, in the case of a struct, array or map), a private state (of type `Singleton`, `ImmutableSingleton` or `Set`) does not have a default initial value. The `initialize` method (or `insert`, in the case of a `Set`) must be called.

Expand Down Expand Up @@ -338,7 +342,11 @@ As part of the initialization of the `Storage` struct, the `Singleton` is create

### `initialize`

When this function is invoked, it creates a nullifier for the storage slot, ensuring that the ImmutableSingleton cannot be initialized again. If an owner is specified, the nullifier will be hashed with the owner's secret key. It is crucial to provide an owner if the ImmutableSingleton is linked to an account; initializing it without one may inadvertently disclose sensitive information about the owner's intent.
When this function is invoked, it creates a nullifier for the storage slot, ensuring that the ImmutableSingleton cannot be initialized again.

:::danger Privacy-Leak
Beware that because this nullifier is created only from the storage slot without randomness it is "leaky". This means that if the storage slot depends on the an address then it is possible to link the nullifier to the address. For example, if the singleton is part of a `map` with an `AztecAddress` as the key then the nullifier will be linked to the address.
:::

Set the value of an ImmutableSingleton by calling the `initialize` method:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,18 @@ impl<Note, N> ImmutableSingleton<Note, N> {
note_interface: NoteInterface<Note, N>,
) -> Self {
assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1.");
ImmutableSingleton {
Self {
context: context.private,
storage_slot,
note_interface,
}
}
// docs:end:new

// The following computation is leaky - the storage slot can easily be "guessed" by an adversary
// by looking at the nullifier in the transaction data.
// This is especially dangerous for `maps` because the storage slot is often also identifies the
// actor that is executing the transaction. e.g, `map.at(msg.sender)` will leak `msg.sender`.
pub fn compute_initialization_nullifier(self) -> Field {
pedersen_hash([self.storage_slot], GENERATOR_INDEX__INITIALIZATION_NULLIFIER)
}
Expand Down
6 changes: 5 additions & 1 deletion yarn-project/aztec-nr/aztec/src/state_vars/singleton.nr
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,18 @@ impl<Note, N> Singleton<Note, N> {
note_interface: NoteInterface<Note, N>,
) -> Self {
assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1.");
Singleton {
Self {
context: context.private,
storage_slot,
note_interface,
}
}
// docs:end:new

// The following computation is leaky - the storage slot can easily be "guessed" by an adversary
// by looking at the nullifier in the transaction data.
// This is especially dangerous for `maps` because the storage slot is often also identifies the
// actor that is executing the transaction. e.g, `map.at(msg.sender)` will leak `msg.sender`.
pub fn compute_initialization_nullifier(self) -> Field {
pedersen_hash([self.storage_slot], GENERATOR_INDEX__INITIALIZATION_NULLIFIER)
}
Expand Down

0 comments on commit 2e7cd34

Please sign in to comment.