-
Notifications
You must be signed in to change notification settings - Fork 1
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
Add UIP-7: Noble Forwarding #11
Draft
zbuc
wants to merge
1
commit into
main
Choose a base branch
from
uip_6_noble
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
| uip | 7 | | ||
| -------------- | ------------------------------------------------------------------------- | | ||
| title | Noble Forwarding Address Design | | ||
| description | Specification of generation of Penumbra-linked Noble forwarding addresses | | ||
| author | Chris Czub <chris@penumbralabs.xyz> | | ||
| discussions-to | <https://forum.penumbra.zone> | | ||
| status | Draft | | ||
| type | Standards Track | | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @hdevalence do you have opinions on whether this should be Standards Track or Informational? /cc @cronokirby |
||
| consensus | No | | ||
| created | 2024-11-11 | | ||
|
||
## Abstract | ||
|
||
Noble Signerless Forwarding, implemented by Noble as the `x/forwarding` module, provides the capability to permissionlessly create Noble accounts that will automatically transfer deposited funds via IBC to a deterministically derived associated address on another chain. This UIP specifies a mechanism through which Penumbra wallet implementations can produce one-time-use Noble forwarding addresses associated with the wallet's sub-accounts. | ||
|
||
## Motivation | ||
|
||
Supporting Noble Signerless Forwarding allows Penumbra users to easily interact with services that support Noble, without the service needing to IBC handshake with Penumbra or integrate any Penumbra APIs. | ||
|
||
By programmatically producing deterministic one-time-use forwarding addresses, transaction linkability is made more difficult, providing users enhanced privacy by default with straightforward usability. | ||
|
||
## Specification | ||
|
||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. | ||
|
||
Penumbra implementations **SHOULD** implement the address format and registration process as described within this document to ensure cross-client consistency. As this is entirely implemented in the client and non-consensus, this suggestion is unenforceable but **SHOULD NOT** be violated if the client implementation supports registering for Noble Signerless Forwarding. | ||
|
||
### Penumbra Noble Forwarding Address Index Format | ||
|
||
Every Noble forwarding address has a one-to-one relationship with a Penumbra address. Penumbra addresses used for Noble forwarding use a special address index format to avoid collisions with regular Penumbra addresses: | ||
|
||
``` | ||
LE32(account) + [0xFF; 10] + LE16(sequence number) | ||
``` | ||
|
||
The first four bytes **MUST** consist of the little-endian encoding of the associated Penumbra account number. | ||
|
||
The next ten bytes (the first ten bytes of the address index's randomizer) **MUST** all be `0xFF`, to indicate the address index is used for Noble. | ||
|
||
The final two bytes (the last two bytes of the randomizer) **MUST** be the little-endian encoding of the Noble sequence number. | ||
|
||
This address index can then be used with the wallet's FVK to generate a payment address. | ||
|
||
Reference Rust implementation: | ||
|
||
```rust | ||
fn get_forwarding_address_for_sequence( | ||
sequence: u16, | ||
account: Option<u32>, | ||
fvk: &FullViewingKey, | ||
) -> Address { | ||
// Noble Randomizer: [0xff; 10] followed by LE16(sequence) | ||
let mut randomizer: [u8; 12] = [0xff; 12]; | ||
let seq_bytes = sequence.to_le_bytes(); | ||
randomizer[10..].copy_from_slice(&seq_bytes); | ||
|
||
let index = AddressIndex { | ||
account: account.unwrap_or_default(), | ||
randomizer, | ||
}; | ||
|
||
let (address, _dtk) = fvk.incoming().payment_address(index.into()); | ||
|
||
address | ||
} | ||
``` | ||
|
||
#### The Sequence Number | ||
|
||
Each Penumbra address used for Noble forwarding has two bytes reserved for a sequence number. The sequence number **SHOULD** count from decimal 0 to 65,535. If the maximum sequence number has been reached, it is **OPTIONAL** to reuse random sequence numbers, otherwise the user **SHOULD** be informed to use a different Penumbra account index for subsequent Noble forwarding transactions. | ||
|
||
### Noble Address Format | ||
|
||
Noble forwarding addresses are deterministically generated from a Penumbra address and the IBC channel associated with Penumbra stored on Noble. The display representation of a Noble forwarding address is as a Bech32 encoding with the prefix `noble` and **MUST BE** 44 characters long. | ||
|
||
The input for the Bech32 encoding is a series of bytes consisting of `sha256(sha256("forwarding") + channel + recipient)` with the first twelve bytes discarded. | ||
|
||
`channel` is the channel associated with Penumbra on the Noble side (for example, "channel-221") and `recipient` is the Bech32m encoded Penumbra address associated with the forwarding address index. | ||
|
||
Reference Rust implementation: | ||
|
||
```rust | ||
|
||
impl NobleForwardingAddress { | ||
pub fn bytes(&self) -> Vec<u8> { | ||
// Based on https://github.com/noble-assets/forwarding/blob/main/x/forwarding/types/account.go#L17 | ||
let channel = self.channel.clone(); // "channel-221" | ||
let recipient = self.recipient.clone(); // the penumbra address derived from the address index, "penumbra18..." | ||
let bz = format!("{channel}{recipient}").as_bytes().to_owned(); | ||
let th = Sha256::digest("forwarding".as_bytes()); | ||
let mut hasher = Sha256::new(); | ||
hasher.update(th); | ||
hasher.update(bz); | ||
|
||
// This constructs the account bytes for the Noble forwarding address | ||
// Only use bytes 12 and on: | ||
hasher.finalize()[12..].to_vec() | ||
} | ||
} | ||
|
||
impl Display for NobleForwardingAddress { | ||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||
let addr_bytes = &self.bytes(); | ||
|
||
write!( | ||
f, | ||
"{}", | ||
bech32str::encode(&addr_bytes, "noble", bech32str::Bech32) | ||
) | ||
} | ||
} | ||
``` | ||
|
||
### Generating the Noble Address | ||
|
||
The process to generate the displayed Noble address for a given Penumbra address is: | ||
|
||
1. Determine the sequence number | ||
2. Generate the Penumbra address associated with the sequence number | ||
3. Encode the Penumbra address as a Noble forwarding address | ||
|
||
### Determining the Sequence Number | ||
|
||
The next unused sequence number **SHOULD** be determined via binary search using the response of submitting registration transactions to Noble as an oracle. | ||
|
||
If binary search fails and every sequence number has been used, the implementor **MAY** choose to reuse addresses by selecting random sequence numbers, otherwise the user **SHOULD** be informed to use a different account to continue receiving unused forwarding addresses. | ||
|
||
Submitting a `RegisterAccount` transaction to Noble results in one of several responses: | ||
|
||
- The Noble address needs funds deposited before it can be registered | ||
- The Noble address was previously unregistered as a forwarding address, and registration was successful | ||
- The Noble address was already registered as a forwarding address | ||
|
||
In the process of binary search, the first sequence number `n` which results in a "needs funds deposited" response (with the `n-1` sequence number either being previously registered or `-1`) indicates the next sequence number that should be used for forwarding. | ||
|
||
### Registering the Noble Forwarding Address | ||
|
||
Once the next sequence number has been determined, the user **SHOULD** be displayed the associated Bech32-encoded Noble address, along with a message prompting them to make their deposit to the Noble address. | ||
|
||
The client **SHOULD** also begin optimistically submitting `RegisterAccount` transactions to Noble at this time until receiving a successful registration response, with exponential backoff for retries. When the Noble address receives funds, a subsequent `RegisterAccount` transaction should succeed, retries are no longer necessary, and the user can be notified that their forwarding transaction was successful. | ||
|
||
## Rationale | ||
|
||
### Address Index Format | ||
|
||
Using a fixed substring of ten `0xFF` bytes in the address index's randomizer balances unlikelihood of collision with other addresses while allowing `2^16 - 1` one-time-use forwarding addresses to be associated with each account. | ||
|
||
### Binary Search of Noble Responses | ||
|
||
By performing binary search of Noble responses to `RegisterAccount` transactions it is possible to statelessly determine the next available sequence number. The lack of state tracking makes cross-client compatibility easier to achieve. | ||
|
||
## Security Considerations | ||
|
||
Noble's permissionless registration process is safe because the receiver address and channel is embedded within the Noble address, meaning Noble forwarding addresses are self authenticating. | ||
|
||
## Privacy Considerations | ||
|
||
Forwarding address unlinkability was a design consideration that motivated single-use forwarding addresses. A user may use multiple distinct and unlinkable forwarding addresses that all deposit to the same Penumbra account. | ||
|
||
Privacy may be degraded and users subject to profiling and linkability if the same forwarding address is used for deposits repeatedly. For this reason, it is not suggested that sequence numbers are re-used, and if they are, users **SHOULD** be notified prior to display and prompted to use a different account. | ||
|
||
## Copyright | ||
|
||
Copyright and related rights waived via [CC0](https://github.com/celestiaorg/UIPs/blob/main/LICENSE). |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forum URL should be https://forum.penumbra.zone/t/pre-uip-noble-address-forwarding/125