This document describes a new addressing scheme for Monero.
Chapters 1-2 are intended for general audience.
Chapters 3-8 contain technical specifications.
- 1. Introduction
- 2. Features
- 3. Notation
- 4. Wallets
- 5. Addresses
- 6. Wallet tiers
- 7. Address encoding
- 8. Test vectors
- References
Sometime in 2023, Monero plans to adopt a new transaction protocol called Seraphis [1], which enables much larger ring sizes than the current RingCT protocol. However, due to a different key image construction, Seraphis is not compatible with CryptoNote addresses. This means that each user will need to generate a new set of addresses from their existing private keys. This provides a unique opportunity to vastly improve the addressing scheme used by Monero.
The CryptoNote-based addressing scheme [2] currently used by Monero has several issues:
- Addresses are not suitable as human-readable identifiers because they are long and case-sensitive.
- View-only wallets need key images to be imported to detect spent outputs [3].
- Too much information about the wallet is leaked when scanning is delegated to a third party.
- Generating subaddresses requires view access to the wallet. This is why many merchants prefer integrated addresses [4].
- Addresses are susceptible to man-in-the-middle (MITM) attacks [5].
- Subaddresses that belong to the same wallet can be linked via the Janus attack [6].
Jamtis is a new addressing scheme that was developed specifically for Seraphis and tackles all of the shortcomings of CryptoNote addresses that were mentioned above. Additionally, Jamtis incorporates two other changes related to addresses to take advantage of this large upgrade opportunity:
- A new 16-word mnemonic scheme called Polyseed [7] that will replace the legacy 25-word seed for new wallets.
- The removal of integrated addresses and payment IDs [8].
Jamtis addresses, when encoded as a string, start with the prefix xmr
and consist of 142 or more base58 characters. Example of an address: xmred2JmtmdKYheeD3fTsYGphSEcMM8z95mNA52W8anhmByRenUpEzNEoHdvqGTWR6L2jWvXmadABC1b3KyMfznQ2XJgwZSwCFiELJMwG4mc2xjGn5N8keKEMgS15DsGdG7MGYEDxBrhjs
There is no longer any "main address" - all Jamtis addresses are equivalent to a subaddress.
Jamtis introduces a short recipient identifier (RID) that can be calculated for every wallet and every address. RID consists of 25 case-insensitive alphanumeric characters that are separated by hyphens for better readability. The RID for the above address is h8eug-w77qs-aaf7m-ww63i-hn33c
. Instead of comparing long addresses, users can compare the much shorter RID. RIDs are also suitable to be communicated via phone calls, text messages or handwriting to confirm a recipient's address. This allows the address itself to be transferred via an insecure channel.
Addresses can encode metadata such as an amount, timestamp or a short description. Such addresses can be referred to as Monero invoices. For example, the following address encodes an amount of 0.001 XMR and the message "THIS IS A TEST PAYMENT": xmrhtx7H1uwbArRUAVNjfwTYAj5kmXKCgZcR6jtGnjB8eMH3RihMnhos4f6Gz7gbj5pgNdbxr5xuPAjRT9xcRL2X9ta5ShB2sQbiMDVvECXbUXLp4cLYQTJAJ36gRKXZaTfEtfJd1oQFJSpZ2fSp1YgZHWzGh4za35MQYJQ
.
A Monero invoice can be transformed into a payment URI by replacing the xmr
prefix with the monero:
URI scheme: monero:htx7H1uwbArRUAVNjfwTYAj5kmXKCgZcR6jtGnjB8eMH3RihMnhos4f6Gz7gbj5pgNdbxr5xuPAjRT9xcRL2X9ta5ShB2sQbiMDVvECXbUXLp4cLYQTJAJ36gRKXZaTfEtfJd1oQFJSpZ2fSp1YgZHWzGh4za35MQYJQ
.
Payment URIs can be used online as clickable links in the web browser and if a protocol handler has been installed, the address wlll be sent directly to the wallet software.
Thanks to a more efficient metadata encoding, Jamtis payment URI QR codes have similar sizes to legacy payment URI QR codes. Additionally, Jamtis supports a binary format for Monero invoices, which can be used by specialized applications and results in smaller QR codes.
To protect from MITM attacks, Jamtis addresses can be optionally signed by the owner of the address. The main use cases are:
When Alice and Bob meet, Bob can write his RID on a piece of paper and give it to Alice. When Bob sends Alice a Monero invoice in the future, Alice will know the address belongs to Bob because it is signed with a key that matches the RID Bob gave her.
When proving a payment [9], Alice can convince Charlie that the address she made a payment to belongs to Bob, because the address was signed by Bob's key. If the address were not signed, Bob could claim that the address is not his, but Alice's own address.
Dave runs an online shop at https://eshop.example.com. To assure his customers, he can create a special DNS record on the domain name eshop.example.com that contains his Monero public key and he can provide signed Monero invoices to all his customers. When shopping at Dave's website, Alice can feel safe to send her Monero to the provided address, because her wallet software will confirm that the address is owned by the domain eshop.example.com.
Jamtis introduces a new wallet tier below "view-only wallet". This access tier (also called "Tier 1") is intended for wallet-scanning and only has the ability to calculate view tags [10]. It cannot generate wallet addresses or decode output amounts.
View tags can be used to eliminate 99.6% of outputs that don't belong to the wallet. If provided with a list of wallet addresses, Tier 1 can also link outputs to those addresses. Possible use cases are:
A wallet can have a Tier 1 component that stays connected to the network at all times and filters out outputs in the blockchain. The full wallet can thus be synchronized at least 256x faster when it comes online (it only needs to check outputs with a matching view tag).
If the Tier 1 private key is provided to a 3rd party, it can preprocess the blockchain and provide a list of potential outputs. This reduces the amount of data that a light wallet has to download by a factor of at least 256. The third party will not learn which outputs actually belong to the wallet and will not see output amounts.
Jamtis view-only wallets (also called "Tier 2") provide access to all wallet features except of the ability to spend. Notably, they can identify spent outputs (unlike legacy view-only wallets), so they can display the correct wallet balance and list all incoming and outgoing transactions.
Jamtis introduces a new wallet type for merchants. Merchant wallets use a slightly different key derivation that allows for two additional wallet access tiers:
This tier (also called "Tier 0") is intended for merchant point-of-sale terminals. It can generate addresses for a specific account on demand, but otherwise has no access to the wallet (i.e. it cannot recognize any payments in the blockchain or generate addresses for other wallet accounts).
This wallet tier (also called "Tier 1.5") combines Tier 0 (generating addresses) with the ability to also view payments received to the generated addresses. It is intended for extended point of sale use (for example, it can detect that a specific order has been paid). It cannot see outgoing payments, received change outputs or payments received to other wallet accounts.
Janus attack is a targeted attack that aims to determine if two addresses A, B belong to the same wallet. Janus outputs are crafted in such a way that they appear to the recipient as being received to the wallet address B, while secretly using a key from address A. If the recipient confirms the receipt of the payment, the sender learns that they own both addresses A and B.
Jamtis prevents this attack by allowing the recipient to recognize a Janus output.
Merchant wallets can only detect a Janus attack that aims to link two addresses from different accounts. Addresses of merchant wallets that belong to the same account are already linkable off-chain.
- Fixed-size integers are serialized in little endian byte order.
- Private keys are serialized as 256-bit integers.
- String constants are serialized in ASCII encoding and always include an implicit null byte at the end.
- Elliptic curve points are serialized as 256-bit integers, with the lower 255 bits being the y-coordinate of the point and the most significant bit being the parity of the x-coordinate.
The function H(...)
refers to the keccak-256 hash function. It accepts an arbitrary number of arguments, which are serialized and concatenated before hashing. The following 3 other hash functions based on H
are used:
Hb(...)
whereb
is an integer divisible by 8, refers to the hash functionH
with the output truncated tob
bits (e.g.H32(...)
)Hs(...)
refers to a "hash to scalar" function, which interprets the output ofH
as a serialized 256-bit integer and then reduces it modulo a prime numberℓ
, which must be relatively close to a power of 2.Hp(...)
refers to an unspecified "hash to point" function, which outputs elliptic curve points.
This specification assumes the use of the ed25519 elliptic curve, which includes a cyclic subgroup 𝔾
of order ℓ = 2252 + 27742317777372353535851937790883648493
.
- Uppercase letters usually refer to elements of
𝔾
. - Lowercase letters usually refer to elements of
Zℓ
(scalars). - Scalar multiplication is denoted by a space between the scalar and the group element, e.g.
K = k G
. - Scalar multiplication may be prepended with the number
8
, which means that the point is also multiplied by the ed25519 cofactor to ensure the result belongs to the group𝔾
.
The following three base points are used:
Point | Derivation | Serialized (hex) |
---|---|---|
G |
curve generator | 5866666666666666666666666666666666666666666666666666666666666666 |
U |
Hp("seraphis U") |
126582dfc357b10ecb0ce0f12c26359f53c64d4900b7696c2c4b3f7dcab7f730 |
X |
Hp("seraphis X") |
4017a126181c34b0774d590523a08346be4f42348eddd50eb7a441b571b2b613 |
Each wallet consists of three private keys, a timestamp and a boolean flag:
Field | Type | Description |
---|---|---|
km |
private key | wallet master key |
kvb |
private key | view-balance key |
kfr |
private key | find-received key |
created_on |
timestamp | date when the wallet was created |
merchant |
boolean | whether this is a merchant-type wallet |
The master key km
is required to spend money in the wallet ("Tier 3" access). The view-balance key kvb
provides full view-only access ("Tier 2"). Finally, the find-received key kfr
provides the ability to calculate the sender-receiver shared secret ("Tier 1" access).
The created_on
timestamp is important when restoring a wallet and determines the blockchain height where scanning for owned outputs should begin. The merchant
flag determines if this is a merchant wallet (affects the way addresses are derived).
Standard Jamtis wallets are generated as a 16-word Polyseed mnemonic [7], which contains a secret seed value used to derive the wallet master key and also encodes the date when the wallet was created and the merchant flag. The keys kvb
and kfr
are derived from the master key.
Field | Derivation |
---|---|
km |
polyseed_key mod ℓ |
kvb |
kvb = Hs("view-balance key", km) |
kfr |
kfr = Hs("find-received key", kvb) |
created_on |
from Polyseed |
merchant |
from Polyseed |
Multisignature wallets are generated in a setup ceremony, where all the signers collectively generate the wallet master key km
and the view-balance key kvb
. The find-received key is derived from the view-balance key.
Field | Derivation |
---|---|
km |
setup ceremony |
kvb |
setup ceremony |
kfr |
kfr = Hs("find-received key", kvb) |
created_on |
setup ceremony |
merchant |
setup ceremony |
Legacy pre-Seraphis wallets define two private keys:
- private spend key
ks
- private view-key
kv
Legacy standard wallets can be migrated to the new scheme based on the following table:
Field | Derivation |
---|---|
km |
km = ks |
kvb |
kvb = Hs("view-balance key", km) |
kfr |
kfr = Hs("find-received key", kvb) |
created_on |
entered manually |
merchant |
entered manually |
Legacy wallets cannot be migrated to Polyseed and will keep using the legacy 25-word seed.
Legacy multisignature wallets can be migrated to the new scheme based on the following table:
Field | Derivation |
---|---|
km |
km = ks |
kvb |
kvb = kv |
kfr |
kfr = Hs("find-received key", kvb) |
created_on |
entered manually |
merchant |
entered manually |
There are 3 global public keys. These keys are not usually published.
Key | Name | Value |
---|---|---|
Ks |
wallet spend key | Ks = kvb X + km U |
KID |
wallet identity key | KID = kvb G |
Kfr |
find-received key | Kfr = kfr G |
The keys Ks
and Kfr
are required by lower wallet tiers. The wallet identity key KID
can be optionally published and used to prove that addresses belong to a specific wallet (§ 7.4).
For better UX when opening or restoring a wallet, the wallet is identified by the hash value H128("Monero RID", KID)
encoded in base-32 using the ID32 scheme [11].
Each address is generated from two 32-bit indices i,j
, where i
is the index of the account and j
is the index of the address within the account.
Each Jamtis address encodes three public keys:
K1i,j = Ks + kxi,j X
K2i,j = kai,j Kfr
K3i,j = kai,j G
The private keys kai,j
and kxi,j
are derived as follows:
Keys | Name | Derivation if(merchant) |
Derivation if(!merchant) |
---|---|---|---|
kai,j |
authentication keys | kai = Hs("auth key", kvb, i) |
kai,j = Hs("auth key", kvb, i, j) |
kxi,j |
spend key extensions | kxi,j = Hs("key extension", kai, j) |
kxi,j = Hs("key extension", kvb, i, j) |
Note that for merchant wallets, the authentication keys kai
don't depend on the index j
, so they are the same for all addresses of a given account. This also means that merchant addresses with the same index i
are easily linkable off-chain (they share the same public keys K2
and K3
).
When sending amount a
to an address (K1, K2, K3)
, the sender does the following:
- Generate a random nonzero scalar
r
fromZℓ
. - Calculate the ephemeral public key
Ke = r K3
- Calculate the derived key
Kd = 8*r K2
- Calculate the view tag
v = H8("view tag", Kd)
- Calculate the shared secret
q = Hs("sender-receiver secret", Kd)
- Derive a one-time output public key
Ko = K1 + q X
- Calculate the blinding factor
b = Hs("blind", q, r G)
- Encrypt the amount
a~ = a XOR H64("amount", q, r G)
- Calculate the amount commitment
C = b G + a H
- Output
(Ke, v, Ko, a~, C)
The receiver does the following to examine a potential output (Ke, v, Ko, a~, C)
:
- Calculate the nominal derived key
Kd' = 8*kfr Ke
- Calculate the nominal view tag
v' = H8("view tag", Kd')
- If
v' != v
, abort. - Calculate the nominal shared secret
q' = Hs("sender-receiver secret", Kd')
- Calculate the nominal spend key
Ks' = Ko - q' X
- Try to find indices
i,j
such thatK1i,j = Ks'
(this is usually done by a hashtable lookup). - If no spend key is found, abort.
- Derive
r' G = Ke / kai(,j)
- Decrypt the nominal amount
a'= a~ XOR H64("amount", q, r' G)
- Calculate the nominal blinding factor
b' = Hs("blind", q, r' G)
- Calculate the nominal amount commitment
C' = b' G + a' H
- If
C' != C
, abort (possible Janus attack). - Calculate the partial private spend key
ksp = kvb + kxi,j + q
- Derive the linking tag
Kt = (Ks - kvb X) / ksp
- Set the boolean
s
to the spend status of the linking tagKt
- Output the private values
(a, b, i, j, ksp, s)
Change outputs and self-spends are special because the sender is the same as the receiver. There are heuristics that can be applied by Tier 1 wallets to recognize when outputs are being spent based on the presence of outputs that send funds back to the wallet [12].
To protect from such attacks, the output construction and recognition is modified for change and self-spends as follows:
- For change outputs, the shared secret from § 5.2.5 is calculated as
q = Hs("change secret", kvb, Ke)
- For self-spends, the shared secret from § 5.2.5 is calculated as
q = Hs("self-spend secret", kvb, Ke)
- The blinding factor from § 5.2.7 is calculated as
b = Hs("blind", q)
- The encrypted amount from § 5.2.8 is calculated as
a~ = a XOR H64("amount", q)
The distinction between change outputs and self-spends is done to preserve the transaction history (self-spends should be visible in the history, change outputs not).
Change outputs and self-spends can only be detected by Tier 2+ wallets because it requires the private key kvb
. Whenever an output with a matching view tag is discovered in a transaction that spends a previous wallet output, the shared secret calculation from § 5.3.4 is replaced with the modified calculation from § 5.4.1. The wallet will first try to find the key corresponding to a change output and if that fails, it will try the key corresponding to a self-spend.
Jamtis enables a small reduction in average transaction size (excluding any other Seraphis-related changes).
The encrypted payment ID can be removed from all 2-output transactions, saving 9 bytes (this includes the TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID
tag and the actual 64-bit payment ID).
Transactions with 2 outputs only need one value of Ke
(§ 5.2.2) as the change output can use the same value. This public key can use the existing TX_EXTRA_TAG_PUBKEY
field.
Since there are no "main" addresses anymore, the TX_EXTRA_TAG_PUBKEY
field can be removed from transactions with 3 or more outputs, saving 33 bytes.
Transactions with 3 or more outputs will need one value of Ke
(§ 5.2.2) per output. These public keys can use the existing TX_EXTRA_TAG_ADDITIONAL_PUBKEYS
field.
Tier | Knowledge | Off-chain capabilities | On-chain capabilities |
---|---|---|---|
0* | kai, Ks, Kfr |
generate and sign addresses for account i |
none |
1 | kfr |
recognize all wallet addresses (but cannot generate them) | eliminate 99.6% of non-owned outputs (up to § 5.3.5), link output to an address (except of change and self-spends) |
1.5* | kfr, kai, Ks |
Tier 0 + Tier 1 | Tier 1 + view received for account i (up to § 5.3.12) |
2 | kvb, Ks |
recognize and generate all addresses, certify Tier 0* | view wallet balance (up to § 5.3.16), including change and self-spends |
3 | km |
Tier 2 | Tier 2 + spend |
* Merchant wallets only
An address has the following overall structure:
Field | Size (bytes) | Description |
---|---|---|
Header | 1 | network type, metadata content, signature type (§ 7.2) |
K1 |
32 | address spend key |
K2 |
32 | address exchange key |
Metadata | 0-190 | optional amount, timestamp and description (§ 7.3) |
Signature | 32-132 | (§ 7.4) |
Checksum | 4 | (§ 7.5) |
The 1-byte header has the format of 1NNMMMSS
, where NN
is the 2-bit network type identifier, MMM
are the metadata flags and SS
is the 2-bit signature type identifier. The most significant bit of the header byte is always 1
, which allows for easy disambiguation from the legacy Monero address, which always starts with a 0
bit.
NN |
network type |
---|---|
00 |
invalid |
01 |
testnet |
10 |
stagenet |
11 |
mainnet |
The invalid network type 00
can be used in the future to extend the header to more than 1 byte, if needed.
The metadata flags MMM
simply indicate if the field is present in the address (1
for present, 0
for omitted).
bit position | field |
---|---|
0 | amount |
1 | timestamp |
2 | description |
There are 4 address signature types:
SS |
signature type | description |
---|---|---|
00 |
none | the address is not signed |
01 |
local signature | the address is signed with kai(,j) |
10 |
global signature | the address is signed with kvb |
11 |
local signature with a certificate | the address is signed with kai(,j) , K3 is signed with kvb |
If this field is not present, the wallet software should prompt the user to enter an amount. If present, the amount is displayed and confirmed by the user.
Because typical payment amounts tend to have a low number of significant digits, the amount in atomic units is encoded as a = (v + 1) * 10e
, where e
is a 4-bit exponent value (0-15) and v
is encoded as a varint in little endian format, with the first byte encoding 3 bits and each additional byte encoding 7 bits (the 9th byte encodes full 8 bits). Values with 3 significant digits, such as 1.23 XMR, can be encoded in just 2 bytes. Zero amount cannot be encoded (the amount field should be omitted instead).
The timestamp generally means the date until when the address is valid. If the date is present and is in the past, the user should be notified that the address has expired. This field can be used as a 'due date' for invoices.
The timestamp is encoded in Unix format as a 32-bit unsigned integer.
The description is an arbitrary text describing the purpose of the payment. The permitted set of characters is: 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ @%,+-./:
and the maximum supported length is 256 characters.
The description is encoded with length - 1
in a single byte and then encoding pairs of characters with 11-bit symbols (5.5 bits per character). This works because 442 < 211
. To encode a pair of characters c1, c2
, they are first converted to their corresponding base-44 values v1, v2
and then encoded as the 11-bit number 44 * v2 + v1
. If the description contains an odd number of characters, the string is padded with a space character before encoding (this space can be removed when decoding based on the length prefix). An empty string cannot be encoded (the description field should be omitted instead).
The interpretation of the signature field depends on the signature type specified in the address header.
If no signature was specified, then this field is simply the encoding of the public key K3
.
Local signature means that all the data preceding the signature field are signed with the private key kai(,j)
. The signature is encoded as (R, s)
, where:
r = Hs("signature nonce", kai(,j), data)
is a pseudorandom nonceR = r G
s = r + Hs("Monero address signature", data) * kai(,j)
The sender can recover the required public key as K3 = (s G - R) / H("Monero address signature", data)
.
Global signature means that all the data preceding the signature field and the key K3
are signed with the private key kvb
. The signature is encoded as (K3, R, s)
, where:
r = Hs("signature nonce", kvb, data)
is a pseudorandom nonceR = r G
s = r + Hs("Monero address signature", data, K3) * kvb
The sender can recover the wallet identity key as KID = (s G - R) / Hs("Monero address signature", data, K3)
and use it to authenticate the recipient.
This variant is like the local signature, except the local signing key K3
is certified by the wallet-global key kvb
. The signature field is the following tuple: (R1, s1, t, R2, s2
), where:
r1 = Hs("signature nonce", kai(,j), data)
is a pseudorandom nonce generated by the local signerR1 = r1 G
s1 = r1 + Hs("Monero address signature", data) * kai(,j)
t
is a timestamp limiting the validity of the certificate (32-bit unsigned integer)r2 = Hs("signature nonce", kvb, K3, t)
is a pseudorandom nonce generated by the global signerR2 = r2 G
s2 = r2 + Hs("Monero address certificate", K3, t) * kvb
The public keys can be recovered from the signatures in similar ways as above. If the timestamp t
is in the past, the signature should be treated as a local signature instead.
The purpose of the checksum is to prevent accidental corruption of the address. The checksum is calculated as a hash H32("Monero address checksum", data)
, where data refers to all the preceding parts of the address.
An address can be encoded into a string as follows:
address_string = "xmr" + base58(address_binary)
The "xmr" prefix serves as a disambiguation from legacy addresses that start with "4" or "8". Additionally, base58 strings that start with the character x
are invalid due to overflow [13], so legacy Monero software can never accidentally decode a Jamtis address.
Because addresses are bulky and opaque, Jamtis defines a concise, more human-friendly identifier for each address, called the Recipient identifier (RID). RIDs are calculated as H128("Monero RID", input)
and encoded using the ID32 scheme [11]. The input
depends on the address signature type:
signature type | input |
---|---|
none | whole address except of the checksum |
local | K3 |
global | KID |
local with certificate | KID |
A local signature with a certificate that has expired is considered to be just a local signature (RID is calculated from K3
).
There are 4 ways how an RID may be validated when sending to an address:
- It may be already present in the sender's address book.
- It may be entered manually by the user. In this case, it's best to obtain the RID from the receiver using a different communication channel than the one used to transfer the address.
- The user may enter a domain name and the corresponding public key is extracted from a DNS TXT record.
- The user may enter an onion address and the corresponding public key is decoded from the onion address (v3 onion addresses encode an ed25519 public key that's also usable in Monero).
When sending to an address, wallet software should follow this authentication workflow:
- The address is parsed and verified that it's well-formed.
- If the address timestamp is present and the address is expired, the user is notified and given the option to continue or abort. (Note: this validation applies to the timestamp from the Metadata section, not the certificate timestamp).
- The RID is calculated.
- If the RID is present in the local address book, the recipient's name is loaded and displayed with a green check mark. Skip to step 8.
- The user is presented with a "recipient validation dialog", where they are asked to enter an RID or a domain name.
- If the address RID matches the one that was entered or obtained via DNS or the onion domain, the RID is displayed as validated with a yellow check mark. Skip to step 8.
- If the RID doesn't match the address, no DNS record was found or the user dismisses the dialog, the recipients RID is displayed with a red cross mark as "unverified".
- The address amount and description are displayed, if present. If the amount is missing, the user is asked to enter it.
The test vectors in this section are for a new wallet restored from the Polyseed phrase: mask solution glory route degree near mirror vessel coast rain fee basic detail asthma course idle
.
a86pw-bdm77-jejzs-sd4ky-qr6g5
Address (0,0)
, no metadata, no signature
e0 eb f6 77 a3 05 f1 76 e1 0b 3c bd 06 fd 3e a2
96 de 3b 68 6f e6 97 cd 36 38 f3 ee 03 b1 59 9c
93 61 a2 fa 27 fd cc 88 dc c7 67 f6 c9 f9 8b 78
b2 e5 c6 ee b9 b9 e6 8e 0d e9 ad c3 a7 93 fd 89
ee ca 2b 49 cf 48 14 5b 7d 2a 4e 02 e6 59 79 83
1a 17 c7 44 83 83 44 16 19 3d a0 95 16 47 a2 8f
72 cb e1 0b fe
(101 bytes)
xmred2JmtmdKYheeD3fTsYGphSEcMM8z95mNA52W8anhmByRenUpEzNEoHdvqGTWR6L2jWvXmadABC1b3KyMfznQ2XJgwZSwCFiELJMwG4mc2xjGn5N8keKEMgS15DsGdG7MGYEDxBrhjs
(142 characters)
RID: h8eug-w77qs-aaf7m-ww63i-hn33c
Address (0,1)
, amount 0.001
, locally signed
f1 7f d6 94 15 32 94 b3 92 49 60 ec 2b aa 4e 07
fb 97 79 6e fa 70 a2 0e 22 50 42 03 bd eb 52 84
0e 81 56 b4 3c b3 1e ac 1f 8a 6e 53 71 6a e4 c7
da d5 79 e5 1a d6 c2 70 9c 5e 08 31 06 3d 61 ef
1a 90 ee 8d 2c 45 d8 d6 69 19 85 51 47 80 8a 3d
4b f3 64 eb 65 2d 57 3c 90 a9 68 c5 77 f4 fd 7b
d6 1c b8 8a b6 94 a4 ca 66 95 56 db bc de 66 9e
5b 61 b7 2f 1a 7b 59 53 36 ba 56 9a 29 30 23 60
1b 0b 97 6e ee 5d
(134 bytes)
xmrhPr6EbTTmNJRUAVNjfwTYAj5kmXKCgZcR6jtGnjB8eMH3RihMnhos4f6Gz7gbj5pgNdbxr5xuPAjRT9xcRL2X9ta5Sj3MEWonwfJabis2wohsSDhpR4piQXSKRCQDPNEFvnvcpA5L7KyWUyJABrGgqV2VbGHWz6f5SMuLA9vtFkAt5iX1EU8YSoVN
(188 characters)
RID: htgin-5gs6p-u7kwx-t9dii-cakhz
Address (1,1)
, amount 0.09
, description TEST ADDRESS3
, locally signed
f5 1b cf 35 a1 55 d4 3d b5 36 44 9b 4e b6 3d 4b
24 f4 93 7e 48 e7 9c 64 02 26 11 94 85 b1 38 51
09 66 ee 32 64 dd 00 1a 53 54 83 d0 c7 c3 57 c3
3d a1 9d 74 e1 30 ff 58 74 ce e8 45 fe 00 36 92
33 a8 01 0c 85 c2 28 77 92 34 28 76 ce 18 4a 5c
e4 54 7b 42 4e d4 1d 2f 62 62 57 36 5f cd fe 47
5c 50 94 06 fd 29 7c 3f 76 50 0e 73 be f8 b9 e5
69 12 65 35 e3 32 c9 d5 5e 5a 69 71 8c 52 4a 7a
86 51 9c 12 b0 79 7c 77 12 82 2c ca b8 0e 2e 23
28 f8
(146 bytes)
xmrhzrvZxUYMzUXJz2ddDEu1t7BWnCNSnJ5Z1Mr23Sha8Ti2aDHkiRFWTKEwQbAFDCgbUBJuFd5HmpQfLYBoGX8cdhB9e8ZxgUhze2RTMrAosLfG7fC63vAGLBXtHTT4tJBn2jQGSZzSGASqNeLnnLHHqdbm6JaL4WcnVG9SGnLx4fQwz81PU4WWQzJ1YS46ZE2NGvsv247q
(204 characters)
RID: ax7sb-1kd5a-fchxd-qz7bz-fkuue
Address (1,2)
, no metadata, globally signed
e2 bd 23 81 13 c1 e9 7f 68 ad 88 1e eb d9 3d b4
89 f9 0f a2 1b 3e 00 36 75 08 5c f3 26 76 ac af
28 3f b7 01 41 4e 07 d3 4f 77 93 77 b8 ec 5f 7c
c1 b2 10 fb 17 5f 86 91 34 84 c2 78 c6 d9 5e a1
63 59 f4 4f c3 f1 81 70 99 ba 9e d5 14 be a5 14
c5 3a d0 3a 24 69 d8 ba 5f 98 61 4b 89 72 2f f5
e4 cd a5 f8 9c 76 d5 0d 98 78 9b 5a ca c0 7d c8
45 b1 89 58 36 10 f4 d3 6f ff 0b 6d 86 84 d7 23
5e 9d c7 a1 16 5f 3c 81 0c 95 ce 6f 75 6e aa c4
d0 f6 ff 35 ba 82 43 2d b6 44 be 6f 92 45 03 a8
0c ee c1 ac d5
(165 bytes)
xmrevejeNTBpQWJWWNN18Mds1Q5WaLq1wqN5LaN5m1idpSz7jTwxizJJbcEHvxiYk5HkFZQ6CgAGZVfv9nVmzewKBCkHcqJof7k46BSiN6bqJLny9ZzNnJak1VtmGzPpp5ragoNfGgNL6YPVwaSWAL995YVhqCf7dQaSod3pKjWEmbqe2scGpu2AGyEGpQ376LZhT52bmbxDoC4EFnhiXVEX3KkWwvP2TdM4sv
(230 characters)
RID: a86pw-bdm77-jejzs-sd4ky-qr6g5
The test vectors in this section are for a non-merchant legacy wallet restored from the seed whipped patio problems aztec jaws joyous daytime pitched psychic sawmill gumball factual abbey unwind chlorine exotic number ditch fountain farming timber haggled anecdote assorted haggled
.
7ucci-9q61x-cz6ir-848di-sype5
Address (0,0)
, no metadata, no signature
e0 92 a2 e7 16 85 21 0c f2 d8 68 34 a1 29 e4 50
3e 93 60 5b 0f 7e b1 9d 80 02 ab 84 3e fe 11 fe
6f bb 2f 37 13 c7 79 6e 5d e8 e7 34 8d 20 75 77
8f f1 88 8a 40 49 37 20 9f 88 7c 3a 83 15 0c 90
78 29 5a 19 de ed 8a a0 19 14 17 ee e0 97 c7 24
15 1c 07 b9 d7 32 d0 b2 53 88 43 0f 5a 17 7b ed
81 9a 61 b4 cc
(101 bytes)
xmreZdyPtmpsaKhcuS43FSVh9BU4dUxqoYDzNQry9rraupqKgw5v3BSQUDGi3TujUJ6viR5S4nn1q46sTgfwRisYu8KM6icEsrpbif5CHysqC7brb4XnjbTvQqZBEyNKuDK2HT2Fd5SzH1
(142 characters)
RID: bnu8d-s8d1e-hda8s-3s97m-63tor
Address (0,1)
, no metadata, globally signed
e2 6a 64 4e 52 4d 25 63 23 7c 8b 36 0c 49 ca ae
8a 7c fd 59 0e c3 7a de 38 d7 03 fb 45 85 b9 a0
8e ae 1f d9 bf 62 bd 7b 6e 25 f9 51 a1 64 02 d9
3d d6 28 85 16 de 57 9d c3 bc 05 bb 5b 8f 34 ab
b7 91 67 00 d6 62 fc d5 32 65 88 b1 32 c2 8b 3a
b3 df 46 8e c9 2a df 02 2f e2 80 9e fd a1 c5 3c
79 4d 04 01 86 49 ea e1 f2 a5 e9 ee 02 db d2 da
ee ce 6c 8d 06 bf 47 50 6e 36 cb 32 21 2f a0 5c
21 b9 98 d8 f2 89 2d f1 fa 72 bc 71 49 85 0e 9e
77 6a bf 2d 24 25 0f a4 1c 4c a6 61 8d 60 ae f6
05 83 24 00 cb
(165 bytes)
xmresWs2koGPgW6wGHPuyPkS9QAWYfbDJMQqAWRG5KkxxymQsBESz1GySzKRaTTuFS6sABLtjroTah1vZjsRuak2Wr6XhqgWtnsRKa9RuoJFYyW33X5z9nT4fR9s91YTJWXp1CfMHmfgPhE7EGhazT9PGUL6dgwioMcJtqWPKSDRfZHNKA36eB8UEpGjweitfM6gP7YUuLyVfnvsZoWT5jYJmDacZuf1d55d2a
(230 characters)
RID: 7ucci-9q61x-cz6ir-848di-sype5
- https://github.com/UkoeHB/Seraphis
- https://bytecoin.org/old/whitepaper.pdf
- https://www.getmonero.org/resources/user-guides/view_only.html
- monero-project/meta#299 (comment)
- https://www.reddit.com/r/Monero/comments/mcvuxc/beware_crypto_stealing_malware/
- https://web.getmonero.org/2019/10/18/subaddress-janus.html
- https://github.com/tevador/polyseed
- monero-project/monero#7889
- https://www.getmonero.org/resources/user-guides/prove-payment.html
- monero-project/research-lab#73
- https://github.com/tevador/id32
- https://gist.github.com/tevador/50160d160d24cfc6c52ae02eb3d17024#gistcomment-4006358
- https://github.com/monero-project/monero/blob/319b831e65437f1c8e5ff4b4cb9be03f091f6fc6/src/common/base58.cpp#L157
How is this rule enforced?
Imagine the following scenario:
Mallory registers at an exchange and is provided with a deposit address. She crafts a 2-output transaction without change, sending both outputs to the deposit address, each output worth 1000 XMR. In order to do this, she needs to provide inputs with a total sum of exactly 2000 XMR + fee, but that should not be hard to do.
Unless the exchange has a wallet that is aware of the burning bug, Mallory will be credited with 2000 XMR and can proceed to withdraw the funds back to her custody. However, the exchange will later realize that only one of the 1000 XMR outputs can be spent. This scam can be repeated until the wallet of the exchange is completely drained. It only costs some tx fees.
Relying on all wallet implementations to be able to detect this bug is not going to work, so there are basically two solutions:
K_o
within each transaction as a consensus rule.K_o
.Is this a consensus rule or just a recommendation for tx builders?