Skip to content

Instantly share code, notes, and snippets.

@delta1
Forked from tevador/jamtis.md
Created January 11, 2022 07:23
Show Gist options
  • Save delta1/ab784362c5de914ea9ed725979a6b3e8 to your computer and use it in GitHub Desktop.
Save delta1/ab784362c5de914ea9ed725979a6b3e8 to your computer and use it in GitHub Desktop.

JAMTIS

This document describes a new addressing scheme for Monero.

Chapters 1-2 are intended for general audience.

Chapters 3-7 contain technical specifications.

Table of Contents

1. Introduction

1.1 Why a new address format?

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.

1.2 Current Monero addresses

The CryptoNote-based addressing scheme [2] currently used by Monero has several issues:

  1. Addresses are not suitable as human-readable identifiers because they are long and case-sensitive.
  2. View-only wallets need key images to be imported to detect spent outputs [3].
  3. Too much information about the wallet is leaked when scanning is delegated to a third party.
  4. Generating subaddresses requires view access to the wallet. This is why many merchants prefer integrated addresses [4].
  5. Addresses are susceptible to man-in-the-middle (MITM) attacks [5].
  6. Subaddresses that belong to the same wallet can be linked via the Janus attack [6].

1.3 Jamtis

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].

2. Features

2.1 Address format

Jamtis addresses, when encoded as a string, start with the prefix xmr1 and typically consist of 168 characters. Example of an address: xmr1ma2qgc3yrp5yp99b6qdy9dstx7wqdyy3g9skore7wb1k1xbtt34mp48h5gmh1y13pispmqco3kujgs7cdpax2r4h5bwjgnbd25bf8x1f4detdeyfrh449upohy28kwroyxdunwxp5ufw9e2btuo5k2mfr5rd3hkbxj3h

There is no longer any "main address" - all Jamtis addresses are equivalent to a subaddress.

2.2 Recipient IDs

Jamtis introduces a short recipient identifier (RID) that can be calculated for every wallet and every address. RID consists of 25 alphanumeric characters that are separated by hyphens for better readability. The RID for the above address is regne-hwbna-u21gh-b54no-8x36q. 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.

2.3 Certified addresses

To protect from MITM attacks, Jamtis addresses can be optionally certified by the owner of the wallet. The main use cases are:

2.3.1 Identity verification

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.

2.3.2 Undeniable payments

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.

2.3.3 Online commerce

Dave runs an online shop at https://eshop.example.com. To assure his customers, he can create a special DNS record under the domain name eshop.example.com that validates his Monero public key and he can provide certified Monero addresses 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.

2.4 Light wallet scanning

Jamtis introduces new wallet tiers below view-only wallet. One of the new wallet tiers called "FindReceivedSimple" 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, this tier can also link outputs to those addresses. Possible use cases are:

2.4.1 Wallet component

A wallet can have a "FindReceivedSimple" 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).

2.4.2 Third party services

If the "FindReceivedSimple" 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.

2.5 Wallet tiers for merchants

Jamtis introduces new wallet tiers that are useful for merchants. Some of the new tiers provide account-level access only.

2.5.1 Account-address generator

This tier is intended for merchant point-of-sale terminals. It can generate subaddresses 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 subaddresses for other wallet accounts).

2.5.2 Account-payment validator

This wallet tier combines the account-address generator tier with the ability to also view payments received to the generated addresses. It is intended for validating paid orders. It cannot see outgoing payments, received change outputs or payments received to other wallet accounts.

2.5.3 Wallet-payment validator

This wallet tier is similar to the Account-payment validator, but it can see received payments for all wallet acounts. It cannot see outgoing payments or change outputs.

2.6 Full view-only wallets

Jamtis supports full view-only wallets that can identify spent outputs (unlike legacy view-only wallets), so they can display the correct wallet balance and list all incoming and outgoing transactions.

2.7 Janus attack mitigation

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.

3. Notation

3.1 Serialization

  1. Fixed-size integers are serialized in little endian byte order.
  2. Private keys are serialized as 256-bit integers.
  3. String constants are serialized in ASCII encoding and always include an implicit null byte at the end.
  4. 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.
  5. The operator || concatenates the serialized representations of its inputs.
  6. The function Padb(x) outputs x || 0x00 || 0x00 || ... || 0x00 where the number of padding zero bytes is such that the total length of the output is a multiple of b bytes.

3.2 Hash functions

The function H(x) refers to the keccak-256 hash function. The following 4 other functions based on H are used:

  1. Hb(x) where b is an integer divisible by 8, refers to the hash function H with the output truncated to b bits (e.g. H32(x))
  2. Hs(x) refers to a "hash to scalar" function, which interprets the output of H as a serialized 256-bit integer and then reduces it modulo a prime number , which must be relatively close to a power of 2.
  3. Hp(x) refers to an unspecified "hash to point" function, which outputs elliptic curve points.
  4. The function KeyDerive(k, x), where k is a secret key, is defined as Hs(Pad136(k) || x)

3.3 Elliptic curve

This specification assumes the use of the ed25519 elliptic curve, which includes a cyclic subgroup 𝔾 of order ℓ = 2252 + 27742317777372353535851937790883648493.

  1. Uppercase letters usually refer to elements of 𝔾.
  2. Lowercase letters usually refer to elements of Z (scalars).
  3. Scalar multiplication is denoted by a space between the scalar and the group element, e.g. K = k G.
  4. 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 𝔾.

3.3.1 Base points

The following three base points are used:

Point Derivation Serialized (hex)
G generator of 𝔾 5866666666666666666666666666666666666666666666666666666666666666
U Hp("seraphis U") 126582dfc357b10ecb0ce0f12c26359f53c64d4900b7696c2c4b3f7dcab7f730
X Hp("seraphis X") 4017a126181c34b0774d590523a08346be4f42348eddd50eb7a441b571b2b613

3.4 Recoverable signatures

In order to save space, certified addrfesses use a recoverable Schnorr signature scheme specified in this section as a set of two functions SignIdent and RecoverIdent.

3.4.1 SignIdent

This function accepts two parameters: a private key k and an abitrary octet string data.

  1. Select a deterministic nonce r = KeyDerive(k, data || "SignIdent nonce")
  2. Calculate R = r G
  3. Calculate e = Hs(R || data)
  4. Calculate s = (e-1*k - r) mod ℓ

Return the tuple (R,s).

3.4.2 RecoverIdent

This function accepts two parameters: the signature tuple (R,s) and an abitrary octet string data.

  1. Calculate e = Hs(R || data)
  2. Calculate u = e*s mod ℓ
  3. Calculate K = u G + e R

Return K.

3.4.3 Security

If an adversary changes R or data, the resulting public key K will change unpredictably.

If an adversary replaces s with s' = (s + e-1*m) mod ℓ, the public key will change to K' = K + m G. For this reason, the private signing key k must never be constructed by adding an offset to an existing key.

3.5 Hash identifier

We define a HashIdent function that accepts an arbitrary octet string data and returns H128(data) encoded in base32 using the ID32 scheme [11].

4. Wallets

4.1 Wallet parameters

Each wallet consists of two main private keys and a timestamp:

Field Type Description
km private key wallet master key
kvb private key view-balance key
birthday timestamp date when the wallet was created

The master key km is required to spend money in the wallet and the view-balance key kvb provides full view-only access.

The birthday timestamp is important when restoring a wallet and determines the blockchain height where scanning for owned outputs should begin.

4.2 New wallets

4.2.1 Standard wallets

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. The key kvb is derived from the master key.

Field Derivation
km polyseed_key mod ℓ
kvb kvb = KeyDerive(km, "view-balance key")
birthday from Polyseed

4.2.2 Multisignature wallets

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.

Field Derivation
km setup ceremony
kvb setup ceremony
birthday setup ceremony

4.3 Migration of legacy wallets

Legacy pre-Seraphis wallets define two private keys:

  • private spend key ks
  • private view-key kv

4.3.1 Standard wallets

Legacy standard wallets can be migrated to the new scheme based on the following table:

Field Derivation
km km = ks
kvb kvb = KeyDerive(km, "view-balance key")
birthday entered manually

Legacy wallets cannot be migrated to Polyseed and will keep using the legacy 25-word seed.

4.3.2 Multisignature wallets

Legacy multisignature wallets can be migrated to the new scheme based on the following table:

Field Derivation
km km = ks
kvb kvb = kv
birthday entered manually

4.4 Additional private keys

There are additional private keys derived from kvb that segment the view-only access into various tiers.

Key Name Derivation Used to
kac account-creation key kac = KeyDerive(kvb, "account-creation key") provide wallet ID, create accounts, certify addr.
kfr find-received key kfr = KeyDerive(kvb, "find-received key") scan for received outputs
kai account key kai = KeyDerive(kac, "account key" || i) generate addresses for account i

The keys kac and kfr separate the view access into two tiers. The first one provides the ability to derive all public addresses that belong to the wallet and the latter is used to calculate the sender-receiver shared secret when scanning for received outputs.

Wallet addresses are grouped into 232 accounts and each account i has an associated private key kai that is used to derive all public addresses of that particular account. The keys kai are derived from the key kac when the specific account is created in the wallet.

4.5 Key hierarchy

The following figure shows the overall hierarchy of wallet keys. Note that the relationship between km and kvb only applies to standard (non-multisignature) wallets.

key hierarchy

4.6 Wallet access tiers

Tier Knowledge Off-chain capabilities On-chain capabilities
AddrGenAccnt kai generate public addresses for account i none
AddrGenAll kac generate public addresses for all accounts none
FindReceivedSimple kfr recognize all public wallet addresses eliminate 99.6% of non-owned outputs (up to § 5.3.5), link output to an address (except of change and self-spends)
ViewReceivedAccnt kai, kfr AC + FR FR + view received for account i except of change and self-spends (up to § 5.3.12)
ViewReceivedAll kac, kfr all view all received except of change and self-spends (up to § 5.3.12)
ViewAll kvb all view all
Master km all all

4.6.1 Account-address generator (AddrGenAccnt)

This wallet tier can only generate addresses for one wallet account. It can be used by merchants to generate addresses for customer orders on demand.

4.6.2 Wallet-address generator (AddrGenAll)

This wallet tier can generate addresses for all accounts and can certify accounts and addresses to prove they belong to the wallet.

4.6.3 Output scanning wallet (FindReceivedSimple)

Thanks to view tags, this tier can eliminate 99.6% of outputs that don't belong to the wallet. If provided with a list of wallet addresses, it can also link outputs to those addresses (but it cannot generate addresses on its own). This tier should provide a noticeable UX improvement with a limited impact on privacy. Possible use cases are:

  1. An always-online wallet component that filters out outputs in the blockchain. A higher-tier wallet can thus be synchronized 256x faster when it comes online.
  2. Third party scanning services. The service can preprocess the blockchain and provide a list of potential outputs with pre-calculated spend keys (up to § 5.2.4). This reduces the amount of data that a light wallet has to download by a factor of at least 256.

4.6.4 Account payment validator (ViewReceivedAccnt)

This level combines the tiers AC and FR and provides the wallet with the ability to view outputs received to one specific account (including amounts). It is intended for extended point of sale use (for example, it can detect that a specific order has been paid).

4.6.5 Wallet payment validator (ViewReceivedAll)

This level combines the tiers AR and FR. This wallet can see all incoming payments to the wallet, but cannot see any outgoing payments and change outputs. It can be used for payment processing or auditing purposes.

4.6.6 View-balance wallet (ViewAll)

This is a full view-only wallet than can see all incoming and outgoing payments (and thus can calculate the correct wallet balance).

4.6.7 Master wallet (Master)

This tier has full control of the wallet.

4.7 Wallet public keys

There are 3 global wallet 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 = kac G
Kfr find-received key Kfr = kfr G

The keys Ks and Kfr are required by lower wallet tiers.

For better UX when opening or restoring a wallet, the wallet is identified by HashIdent("Monero wallet ID" || KID).

5. Addresses

5.1 Address generation

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 = kaddri,j Kfr
  • K3i,j = kaddri,j G

The private keys kaddri,j and kxi,j are derived as follows:

Keys Name Derivation
kaddri,j address keys kaddri,j = KeyDerive(kai, "address key" || i || j)
kxi,j spend key extensions kxi,j = KeyDerive(kaddri,j, "key extension" || i || j)

All addresses contain 3 unique public keys and are thus unlinkable by default.

5.2 Sending to an address

When sending amount a to an address (K1, K2, K3), the sender does the following:

  1. Generate a random nonzero scalar r from Z.
  2. Calculate the ephemeral public key Ke = r K3
  3. Calculate the derived key Kd = 8*r K2
  4. Calculate the view tag v = H8("view tag", Kd)
  5. Calculate the shared secret q = Hs("sender-receiver secret", Kd)
  6. Derive a one-time output public key Ko = K1 + q X
  7. Calculate the blinding factor b = Hs("blind", q, r G)
  8. Encrypt the amount a~ = a XOR H64("amount", q, r G)
  9. Calculate the amount commitment C = b G + a H
  10. Output (Ke, v, Ko, a~, C)

5.3 Receiving an output

The receiver does the following to examine a potential output (Ke, v, Ko, a~, C):

  1. Calculate the nominal derived key Kd' = 8*kfr Ke
  2. Calculate the nominal view tag v' = H8("view tag", Kd')
  3. If v' != v, abort.
  4. Calculate the nominal shared secret q' = Hs("sender-receiver secret", Kd')
  5. Calculate the nominal spend key Ks' = Ko - q' X
  6. Try to find indices i,j such that K1i,j = Ks' (this is usually done by a hashtable lookup).
  7. If no spend key is found, abort.
  8. Derive r' G = Ke / kaddri,j
  9. Decrypt the nominal amount a'= a~ XOR H64("amount", q, r' G)
  10. Calculate the nominal blinding factor b' = Hs("blind", q, r' G)
  11. Calculate the nominal amount commitment C' = b' G + a' H
  12. If C' != C, abort (possible Janus attack).
  13. Calculate the partial private spend key ksp = kvb + kxi,j + q
  14. Derive the linking tag Kt = (Ks - kvb X) / ksp
  15. Set the boolean s to the spend status of the linking tag Kt
  16. Output the private values (a, b, i, j, ksp, s)

5.4 Change and self-spends

Change outputs and self-spends are special because the sender is the same as the receiver. There are heuristics that can be applied by lower wallet tiers 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:

5.4.1 Output construction

  1. For change outputs, the shared secret from § 5.2.5 is calculated as q = Hs("change secret", kvb, Ke)
  2. For self-spends, the shared secret from § 5.2.5 is calculated as q = Hs("self-spend secret", kvb, Ke)
  3. The blinding factor from § 5.2.7 is calculated as b = Hs("blind", q)
  4. 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).

5.4.2 Output recognition

Change outputs and self-spends can only be detected wallet tiers VB and M 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.

5.5 Transaction size

Jamtis enables a small reduction in average transaction size (excluding any other Seraphis-related changes).

5.5.1 Transactions with 2 outputs

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.

5.5.2 Transactions with 3 or more outputs

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.

6. Address encoding

6.1 Address structure

An address has the following overall structure:

Field Size (bytes) Description
Header 6* human-readable address header (§ 6.2)
K1 32 address key 1
K2 32 address key 2
K3 32 address key 3
Certificate 65 or 133 for certified addresses (§ 6.3)
Checksum 8* (§ 6.4)

* The header and the checksum are already encoded in base32

6.2 Address header

The address starts with a human-readable header, which has the following format consisting of 6 alphanumeric characters:

"xmr" <version char> <network type char> <address type char>

Unlike the rest of the address, the header is never encoded and is the same for both the binary and textual representations. The string is not null terminated.

The software decoding an address shall abort if the first 3 bytes are not 0x78 0x6d 0x72 ("xmr").

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.

6.2.1 Version character

The version character is "1". The software decoding an address shall abort if a different character is encountered.

6.2.2 Network type

network char network type
"t" testnet
"s" stagenet
"m" mainnet

The software decoding an address shall abort if an invalid network character is encountered.

6.2.3 Address type

type char address type
"a" anonymous
"c" certified

The software decoding an address shall abort if an invalid address type character is encountered.

6.3 Certificate

All Jamtis addresses are by default unlinkable to the wallet that created them. However, the owner of the wallet may optionally attach a certificate that links the address to the wallet identity key KID. The certificate is present if the address type character in the address header is "c".

There are two types of certificates:

  1. Direct certificate: The address is directly certified by the account-creation key kac
  2. Indirect certificate: This is for wallet tiers AddrGenAccnt or ViewReceivedAccnt, which don't have access to the private key kac. The address is certified by the account key kai and the account public key Kai is certified by the account-creation key kac.

6.3.1 Direct certificates

Direct certificates are encoded in 65 bytes as follows:

Field Size (bytes) Value
Type 1 0xac
Signature 64 SignIdent(kac, "Monero certificate" || Header || K1 || K2 || K3 || 0xac )

When parsing a directly certified address, the wallet software can calculate the receiver's identity key as:

KID = RecoverIdent((R,s), "Monero certificate" || Header || K1 || K2 || K3 || 0xac)

6.3.2 Indirect certificates

Indirect certificates are encoded in 133 bytes as follows:

Field Size (bytes) Value
Type 1 0x1a
Signature 1 64 SignIdent(kai, "Monero certificate" || Header || K1 || K2 || K3 || 0x1a )
Validity 4 32-bit unsigned Unix timestamp
Signature 2 64 SignIdent(kac, "Monero certificate" || Kai || Validity || 0xac )

Recovering the receiver's identity key from an indirect certificate is a 3-step process:

  1. Check that the Validity timestamp is in the future. If not, the software should abort.
  2. Calculate Ka = RecoverIdent((R,s), "Monero certificate" || Header || K1 || K2 || K3 || 0x1a) using the first signature tuple
  3. Calculate KID = RecoverIdent((R,s), "Monero certificate" || Ka || Validity || 0xac) using the second signature tuple

6.4 Checksum

The purpose of the checksum is to detect accidental corruption of the address. The checksum consists of 8 characters and is calculated using a BCH code [14] with a degree-8 polynomial. The checksum can detect all errors affecting 4 or fewer characters and will fail to detect more errors with a chance of less than 1 in 1012. [TODO: Specify the BCH polynomial.]

6.5 Binary-to-text encoding

An address can be encoded into a string as follows:

address_string = header + base32(data) + checksum

where header is the 6-character human-readable header string (already in base32), data refers to the 3 address public keys followed by an optional certificate and checksum is the 8-character checksum (already in base32). The base32 encoding uses the character set ybndrfg8ejkmcpqxot1uwis2a345h769.

6.5.1 Address length

Address type length
anonymous 168
directly certified 272
indirectly certified 381

6.5.2 QR Codes

While the canonical form of an address is lower case, when encoding an address into a QR code, the address should be converted to upper case to take advantage of the more efficient alphanumeric encoding mode.

6.6 Recipient authentication

6.6.1 Recipient identifiers

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 depednding on the address type:

Address type RID
anonymous HashIdent("Monero RID" || Header || K1 || K2 || K3)
certified HashIdent("Monero RID" || KID)

6.6.2 Validating an RID

There are 4 ways how an RID may be validated when sending to an address:

  1. It may be already present in the sender's address book.
  2. 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.
  3. The user may enter a domain name (e.g. example.com) and the RID is validated by performing a TXT DNS lookup of a subdomain equal to the RID (e.g. regne-hwbna-u21gh-b54no-8x36q.example.com). [TODO: Specify the contents of the TXT field.]
  4. The user may enter an onion address and the public key is decoded from the onion address (v3 onion addresses encode an ed25519 public key that's also usable in Monero) and compared to the address public key.

6.6.3 Authentication workflow

When sending to an address, wallet software should follow this authentication workflow:

  1. The address is parsed and verified that it's well-formed.
  2. The RID is calculated.
  3. 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.
  4. The user is presented with a "recipient validation dialog", where they are asked to enter an RID or a domain name.
  5. 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 7.
  6. If the RID doesn't match the address, no DNS record was found or the user dismisses the dialog, the RID is displayed with a red cross mark as "unverified".
  7. The user is asked to enter the remaining payment parameters.

7. Test vectors

TODO

References

  1. https://github.com/UkoeHB/Seraphis
  2. https://bytecoin.org/old/whitepaper.pdf
  3. https://www.getmonero.org/resources/user-guides/view_only.html
  4. monero-project/meta#299 (comment)
  5. https://www.reddit.com/r/Monero/comments/mcvuxc/beware_crypto_stealing_malware/
  6. https://web.getmonero.org/2019/10/18/subaddress-janus.html
  7. https://github.com/tevador/polyseed
  8. monero-project/monero#7889
  9. https://www.getmonero.org/resources/user-guides/prove-payment.html
  10. monero-project/research-lab#73
  11. https://github.com/tevador/id32
  12. https://gist.github.com/tevador/50160d160d24cfc6c52ae02eb3d17024#gistcomment-4006358
  13. https://github.com/monero-project/monero/blob/319b831e65437f1c8e5ff4b4cb9be03f091f6fc6/src/common/base58.cpp#L157
  14. https://en.wikipedia.org/wiki/BCH_code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment