Address
Purpose
An address is an extension to account IDs and other identifiers that facilitates sending and receiving of notes. It serves three main purposes explained in this section.
Communicating receiver information
An address is designed for the note receiver to communicate information about themselves to the sender.
The receiver can choose to disclose various pieces of information that control how the note itself is structured.
Consider a few examples that use different address mechanisms:
- The Pay-to-ID note: the note itself can only be consumed if the account ID encoded in the note details matches the ID of the account that tries to consume it. To receive a P2ID note, the receiver should communicate an
AddressId::AccountIdtype to the sender. - A "Pay-to-PoW" note that can only be consumed if the receiver can provide a valid seed such that the hash of the seed results in a value with n leading zero bits. The receiver communicates an
AddressId::PoWtype to the sender, which encodes the target number of leading zero bits (and a salt to avoid re-use of the same seed).* - A "Pay-to-Public-Key" note that stores a public (signature) key and checks if the receiver can provide a valid cryptographic signature for that key. The
AddressId::PublicKeytype must encode the public key.*
These different address mechanisms provide different levels of privacy and security:
AddressId::AccountId: the receiver is uniquely identifiable, but they are the only ones who can consume the note.AddressId::PoW: the receiver is not revealed publicly, but potentially many entities can consume the note. The receiver has an advantage by specifying the salt.AddressId::PublicKey: the receiverAccountIdis not revealed publicly, only their public key. A freshAddressId::PublicKeycan be used for receiving each note, resulting in increased privacy.
The "Pay-to-PoW" and "Pay-to-Public-Key" notes and the corresponding address types are for illustration purposes only. They are not part of the Miden library.
Communicating channel information
For notes which are sent privately, the sender needs to communicate the full note details to the receiver. This can be done via a side channel, such as a messenger, email, or via a QR code. We would like to avoid the necessity of operating two-way communication channels for each note. Rather, we operate under the assumption that once the receiver shares their Address (directly with the sender, or via a bulletin board, i.e. a one-way channel), they don't need to stay online and wait for the sender to send back the full note details.
Instead, our Miden client connects to a Note Transport Layer, which stores encrypted note details together with the associated public metadata for each note. The receiver can query the Note Transport Layer for NoteTags they are interested in. Typically, a NoteTag encodes a few leading bits (14 by default) of the receiver's AccountId. Querying the Note Transport Layer for 14-bit NoteTags reduces the receiver's privacy, but at the same time allows them to perform less work downloading and trial-decrypting the notes than if fewer bits were encoded.
With an Address, e.g. the AddressId::AccountId variant, the receiver could specify how many bits of their AccountId they want to disclose to the sender and thus choose their level of privacy.
Account interface discovery
An address allows the sender of the note to easily discover the interface of the receiving account. As explained in the account interface section, every account can have a different set of procedures that note scripts can call, which is the interface of the account. In order for the sender of a note to create a note that the receiver can consume, the sender needs to know the interface of the receiving account. This can be communicated via the address, which encodes a mapping of standard interfaces like the basic wallet.
If a sender wants to create a note, it is up to them to check whether the receiver account has an interface that it compatible with that note. The notion of an address doesn't exist at protocol level and so it is up to wallets or clients to implement this interface compatibility check.
Structure
An address consists of two parts:
- An identifier that determines what the address fundamentally points to, e.g. an account ID or, in the future, a public key.
- Routing parameters, that customize how a sender creates notes for the receiver, or in other words, how they are routed.
The separation between these two parts is represented by an underscore (_) in the encoded address:
mm1arp0azyk9jugtgpnnhle8daav58nczzr_qpgqqwcfx0p
| |
account ID routing parameters
Relationship to Identifiers
The routing parameters in an address can encode exactly one account interface, which is a deliberate limitation to keep the size of addresses small. Users can generate multiple addresses for the same identifier like account ID or public key, in order to communicate different interfaces to senders. In other words, there could be multiple different addresses that point to the same account, each encoding a different interface. So, the relationship from addresses to their underlying identifiers is n-to-1.
As an example, these two addresses contain the same account ID but different routing parameters:
mm1arp0azyk9jugtgpnnhle8daav58nczzr_qpgqqwcfx0p
mm1arp0azyk9jugtgpnnhle8daav58nczzr_qzsqqd4avz7
Address Types
The supported address types are:
AddressId::AccountId(type232): An address pointing to an account ID.- Choosing
232as the type byte means that all addresses that encode an account ID start withmm1a, whereaconveniently indicates "account".
- Choosing
Adding a public key-based address type is planned.
Routing Parameters
The supported routing parameters are detailed in this section.
Adding an encryption key routing parameter is planned.
Address Interface
The address interface informs the sender of the capabilities of the receiver account's interface.
The supported address interfaces are:
BasicWallet(type0): The standard basic wallet interface. See the account code docs for details.
Note Tag Length
The note tag length routing parameter allows specifying the length of the note tag that the sender should create. This parameter determines how many bits of the account ID are encoded into note tags of notes targeted to this address. This lets the owner of the account choose their level of privacy. A higher tag length makes the address ID more uniquely identifiable and reduces privacy, while a shorter length increases privacy at the cost of matching more notes published onchain.
Encoding
The two parts of an address are encoded as follows:
- The identifier is encoded in bech32. See the account ID encoding section for details.
- The routing parameters are encoded in bech32 as well, but without the HRP or
1separator.- This means the routing parameter string's alphabet is consistent with that of the address ID.
- It also means the routing parameters have their own checksum, which is important so address ID and routing parameters can be separated at any time without causing validation issues.