├── .gitignore
├── LICENSE.txt
├── README.md
├── audits
├── Cypherstack-diagram.pdf
├── Cypherstack-v1.0.pdf
├── Cypherstack-v2.0-followup.pdf
└── README.md
├── carrot.md
├── finalize.sh
└── src
├── carrot_raw.md
├── dumb_citations.py
└── dumb_md_enumerate.py
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode
2 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2024, The Monero Project
2 |
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 |
11 | 2. Redistributions in binary form must reproduce the above copyright notice,
12 | this list of conditions and the following disclaimer in the documentation
13 | and/or other materials provided with the distribution.
14 |
15 | 3. Neither the name of the copyright holder nor the names of its contributors
16 | may be used to endorse or promote products derived from this software without
17 | specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Carrot
2 |
3 | ## Reading
4 |
5 | See `carrot.md`
6 |
7 | ## Contributing
8 |
9 | Make changes to the `carrot_raw.md` file in the `src/` folder
10 |
11 | ## Finalizing
12 |
13 | To finalize the document after making changes to `carrot_raw.md`, run `finalize.sh`. Finalizing adds section numbers, numbers citations, creates a reference table, etc. This will overwrite `carrot.md`.
14 |
--------------------------------------------------------------------------------
/audits/Cypherstack-diagram.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeffro256/carrot/a17bd68a842cca984c9e40b4bf9ea3b17176116c/audits/Cypherstack-diagram.pdf
--------------------------------------------------------------------------------
/audits/Cypherstack-v1.0.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeffro256/carrot/a17bd68a842cca984c9e40b4bf9ea3b17176116c/audits/Cypherstack-v1.0.pdf
--------------------------------------------------------------------------------
/audits/Cypherstack-v2.0-followup.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeffro256/carrot/a17bd68a842cca984c9e40b4bf9ea3b17176116c/audits/Cypherstack-v2.0-followup.pdf
--------------------------------------------------------------------------------
/audits/README.md:
--------------------------------------------------------------------------------
1 | # Audits
2 |
3 | ## Specification
4 |
5 | * Cypherstack, v1.0, 22 November 2024, https://github.com/cypherstack/carrot-audit
6 | * Cypherstack, v2.0, 10 September 2025
7 |
8 | ## Code
9 |
10 | N/A
11 |
12 |
--------------------------------------------------------------------------------
/carrot.md:
--------------------------------------------------------------------------------
1 | # Carrot
2 |
3 | Carrot (Cryptonote Address on Rerandomizable-RingCT-Output Transactions) is an addressing protocol for the upcoming FCMP++ upgrade to Monero which maintains backwards compatibility with existing addresses. It does this while bringing new privacy and usability features, such as outgoing view keys. Carrot is designed to be indistinguishable on-chain from another potential addressing protocol, Jamtis, which will justify some seemingly strange design choices later on in this document.
4 |
5 | ## 1. Background
6 |
7 | ### 1.1 Cryptonote Addresses, Integrated Addresses, and Subaddresses
8 |
9 | In 2013, the Cryptonote whitepaper [[1](https://github.com/monero-project/research-lab/blob/master/whitepaper/whitepaper.pdf)] introduced an addressing scheme which remains a crucial component of Monero's privacy model today, providing recipient unlinkability across transactions. Unlike Bitcoin, which uses transparent addresses, Monero's use of addresses ensures that all created transaction outputs cannot be attributed to any single receiver regardless of the number of times an address is reused, and without requiring interactivity.
10 |
11 | In the beginning, since there was only one address per wallet, a method was needed for receivers to differentiate their senders. *Payment IDs* [[2](https://www.getmonero.org/resources/moneropedia/paymentid.html)], an arbitrary 32 byte string attached to transactions, was the initial solution to this problem. The aim was that users sending funds would include a 32 byte message that gave the recipient user enough evidence to attribute that transaction to them. *Integrated addresses* improved the UX of these payment IDs by having the recipient's wallet generate and include them inside of addresses, which were automatically added to the transaction data by the sender's wallet. They were also shortened to 8 bytes. Wallets then started encrypting the payment IDs on-chain, and adding dummies if no payment IDs were used, which greatly improved privacy.
12 |
13 | In 2016, Monero iterated even further by introducing *subaddresses* [[3](https://github.com/monero-project/research-lab/issues/7)], an addressing scheme that existing wallets could adopt, allowing them to generate an arbitrary number of unlinkable receiving addresses without affecting scan speed.
14 |
15 | ### 1.2 FCMP++
16 |
17 | In order to tackle privacy shortcomings with Monero's ring signatures, there is a consensus protocol update planned called FCMP++, an abbreviation of "Full-Chain Membership Proofs + Spend Authorization + Linkability" [[4](https://gist.github.com/kayabaNerve/0e1f7719e5797c826b87249f21ab6f86)]. In contrast to ring signatures' relatively small decoy set size, FCMP++ enables all transaction outputs on the blockchain to be used as decoys for each input. FCMP++'s deterministic anonymity avoids almost all the undesirable edge cases and targeted attacks against ring signatures, as well as improving on it in the normal case. To read more about the FCMP++ upgrade, the original author [wrote a blog post](https://www.getmonero.org/2024/04/27/fcmps.html) outlining new features, academic work, etc.
18 |
19 | However, most relevant to Carrot, FCMP++ has a subtle, but powerful effect on how transaction outputs can be composed on-chain. This effect is dubbed "Rerandomization" and is already applied to amounts in Monero RingCT [[5](https://www.getmonero.org/resources/moneropedia/ringCT.html)] to make them confidential. Rerandomization in the context of FCMP++ opens the door for long-desired features, namely forward secrecy and outgoing view keys. Both of these features are described in greater detail in later sections.
20 |
21 | ### 1.3 Where Carrot fits in
22 |
23 | Carrot is an *addressing* protocol, designed to be a layer on top the *consensus* protocol FCMP++. In other words, FCMP++ dictates the rules that transactions must follow in order to be valid, whereas Carrot provides a shared framework for how to transmit funds and otherwise interact with addresses meaningfully on FCMP++ transactions. Carrot also contains a recommended wallet specification, detailing how to construct public and private keys in a way which best leverages FCMP++. A wallet with the Carrot key hierarchy can expect flexibility in how wallet functions can be compartmentalized, as well as unconditional forward secrecy for change outputs, etc.
24 |
25 | However, an equally important design consideration of Carrot is backwards compatibility. One can participate in the Carrot addressing protocol using preexisting Cryptonote addresses, subaddresses, and integrated addresses. No wallet key migration is required. Even without a migration, using the Carrot addressing protocol provides protection against the burning bug attack, conditional forward secrecy, etc. The exact breakdown of which wallets get which features is outlined in the following section. Furthermore, addresses generated by the new Carrot wallet key hierarchy will be of the same format as old addresses. Indeed, these new addresses will be computationally indistinguishable from old addresses, maintaining off-chain privacy and easing developer loads.
26 |
27 | ## 2. New Features
28 |
29 | ### 2.1 All wallets
30 |
31 | Carrot immediately brings these features to both newly generated wallets and existing wallets.
32 |
33 | #### 2.1.1 Address-conditional forward secrecy
34 |
35 | As a result of leveraging the FCMP++ consensus protocol, Carrot has the ability to hide all transaction details (sender, receiver, amount) from third-parties with the ability to break the security of elliptic curves (e.g. quantum computers), as long as the observer does not know receiver's addresses.
36 |
37 | #### 2.1.2 Janus attack mitigation
38 |
39 | A Janus attack [[6](https://web.getmonero.org/2019/10/18/subaddress-janus.html)] 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.
40 |
41 | Carrot prevents this attack by allowing the recipient to recognize a Janus output.
42 |
43 | #### 2.1.3 Stateless burning bug mitigation
44 |
45 | The burning bug [[7](https://www.getmonero.org/2018/09/25/a-post-mortum-of-the-burning-bug.html)] is a undesirable result of Monero's old scan process wherein if an exploiter creates a transaction with the same ephemeral pubkey, output pubkey, and transaction output index as an existing transaction, a recipient will scan both instances of these enotes as "owned" and interpret their balance as increasing. However, since key images are linked to output pubkeys, the receiver can only spend one of these enotes, "burning" the other. If the exploiter creates an enote with amount `a = 0`, and the receiver happens to spend that enote first, then the receiver burns all of the funds in their original enote with only a tiny fee cost to the exploiter!
46 |
47 | An initial patch [[8](https://github.com/monero-project/monero/pull/4438/files#diff-04cf14f64d2023c7f9cd7bd8e51dcb32ed400443c6a67535cb0105cfa2b62c3c)] was introduced secretly to catch when such an attempted attack occurred. However, this patch did not attempt to recover gracefully and instead simply stopped the wallet process with an error message. Further iterations of handling this bug automatically discarded all instances of duplicate output pubkeys which didn't have the greatest amount. However, all instances of burning bug handling in Monero Core require a complete view of all scanning history up to the current chain tip, which makes the workarounds somewhat fragile.
48 |
49 | The original Jamtis [[9](https://gist.github.com/tevador/50160d160d24cfc6c52ae02eb3d17024)] proposal by @tevador and the *Guaranteed Address* [[10](https://gist.github.com/kayabaNerve/8066c13f1fe1573286ba7a2fd79f6100)] proposal by @kayabaNerve were some of the first examples of addressing schemes where attempting a burn in this manner is inherently computationally intractable. These schemes somehow bind the output pubkey to an "input context" value, which is unique for every transaction. Thus, the receiver will only ever correctly determine an enote with a given output pubkey to be spendable for a single transaction, avoiding the burning bug without ever having to maintain a complete scan state.
50 |
51 | Carrot prevents this attack statelessly in the same manner.
52 |
53 | #### 2.1.4 Payment ID confirmation
54 |
55 | Payment IDs are confirmed by a cryptographic hash, which gives integrated address payment processors better guarantees, provides better UX, and allows many-output batched transactions to unambiguously include an integrated address destination.
56 |
57 | ### 2.2 New wallets only
58 |
59 | These features are only available to wallets generated with the newly defined account key hierarchy. Existing Monero wallets will not inherit these features, unfortunately.
60 |
61 | #### 2.2.1 Internal forward secrecy
62 |
63 | Enotes that are sent "internally" to one's own wallet will have all transactions details hidden (sender, receiver, amount) from third-parties with the ability to break the security of elliptic curves (e.g. quantum computers), even if the observer has knowledge of the receiver's addresses.
64 |
65 | #### 2.2.2 Address generator tier
66 |
67 | This tier is intended for merchant point-of-sale terminals. It can generate addresses on demand, but otherwise has no access to the wallet (i.e. it cannot recognize any payments in the blockchain).
68 |
69 | #### 2.2.3 Payment validator tier
70 |
71 | Carrot supports view-incoming-only wallets that can verify that an external payment was received into the wallet, without the ability to see where those payment enotes were spent, or spend it themselves. But unlike old Monero view-only wallets, a Carrot payment validator wallet cannot see *"internal"* change enotes.
72 |
73 | #### 2.2.4 Full view-only tier
74 |
75 | Carrot 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, without the ability to spend anything.
76 |
77 | ## 3. Notation
78 |
79 | ### 3.1 Miscellaneous definitions
80 |
81 | 1. The function `BytesToInt64(x)` deserializes a 64-bit little-endian integer from a 8-byte input.
82 | 1. The function `BytesToInt256(x)` deserializes a 256-bit little-endian integer from a 32-byte input.
83 | 1. The function `BytesToInt512(x)` deserializes a 512-bit little-endian integer from a 64-byte input.
84 | 1. The function `IntToBytes8(x)` serializes an integer into a little-endian encoded 1-byte output.
85 | 1. The function `IntToBytes32(x)` serializes an integer into a little-endian encoded 4-byte output.
86 | 1. The function `IntToBytes64(x)` serializes an integer into a little-endian encoded 8-byte output.
87 | 1. The function `IntToBytes256(x)` serializes an integer into a little-endian encoded 32-byte output.
88 | 1. The function `RandBytes(x)` generates a random x-byte string.
89 | 1. Concatenation is denoted by `||`.
90 | 1. Bit-wise XOR (exclusive-or) is denoted by `⊕`.
91 | 1. Python slice notation [[11](https://stackabuse.com/python-slice-notation-on-list/)] `X[:N]` is used to take the first `N` bytes of byte string `X`
92 |
93 | ### 3.2 Hash functions
94 |
95 | The function Hb(x)
with parameters `b, x`, refers to the Blake2b hash function [[12](https://eprint.iacr.org/2013/322.pdf)] initialized as follows:
96 |
97 | * The output length is set to `b` bytes.
98 | * Hashing is done in sequential mode.
99 | * The Personalization string is set to the ASCII value "Monero", padded with zero bytes.
100 | * The input `x` is hashed.
101 |
102 | The function `SecretDerive` is defined as:
103 |
104 | SecretDerive(x) = H32(x)
105 |
106 | The function `Keccak256(x)` refers to the Keccak function [[13](https://keccak.team/keccak.html)] parameterized with `r = 1088, c = 512, d = 256`.
107 |
108 | ### 3.3 Elliptic curves
109 |
110 | Two elliptic curves are used in this specification:
111 |
112 | 1. **Curve25519** - a Montgomery curve. Points on this curve include a cyclic subgroup 𝔾M.
113 | 1. **Ed25519** - a twisted Edwards curve. Points on this curve include a cyclic subgroup 𝔾E.
114 |
115 | Both curves are birationally equivalent, so the subgroups 𝔾M and 𝔾E have the same prime order ℓ = 2252 + 27742317777372353535851937790883648493
. The total number of points on each curve is `8ℓ`.
116 |
117 | #### 3.3.1 Curve25519
118 |
119 | The Montgomery curve Curve25519 [[14](https://cr.yp.to/ecdh/curve25519-20060209.pdf)] is used exclusively for the Diffie-Hellman key exchange with the private incoming view key. Only a single generator point `B`, where `x = 9`, is used.
120 |
121 | Elements of 𝔾M are denoted by `D`, and are serialized as their x-coordinate. As is convention for Curve25519, the y coordinate is assumed to be the even value that satisfies the Montgomery curve equation.
122 |
123 | Scalar-point multiplication is denoted by a space, e.g. D = d B
. In this specification, when we mention scalar-point multiplication, we always mean a "full" scalar multiplication, without "scalar clamping" [[15](https://neilmadden.blog/2020/05/28/whats-the-curve25519-clamping-all-about/)]. Most implementations of X25519 [[16](https://cr.yp.to/ecdh.html)], an ECDH algorithm on Curve25519, will "clamp" the scalar, treating some bits implicitly as always 0s or always 1s. Performing a clamped scalar-point multiplication will break completeness of the ECDH for existing Monero addresses, since the private view key could be any *unclamped* element of **F***ℓ*. Scalar clamping of the three least significant bits in X25519 is done to mitigate small subgroup attacks, but since we don't clamp, we must explicitly handle small subgroup attacks elsewhere [[17](https://datatracker.ietf.org/doc/html/rfc2785)].
124 |
125 | #### 3.3.2 Ed25519
126 |
127 | The twisted Edwards curve Ed25519 [[18](https://ed25519.cr.yp.to/ed25519-20110926.pdf)] is used for all other cryptographic operations on FCMP++. The following generators are used:
128 |
129 | |Point|Derivation|Serialized (hex)|
130 | |-----|----------|----------|
131 | | `G` | generator of 𝔾E | `5866666666666666666666666666666666666666666666666666666666666666`
132 | | `H` | Hp1(G)
| `8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94`
133 | | `T` | Hp2(Keccak256("Monero Generator T"))
| `966fc66b82cd56cf85eaec801c42845f5f408878d1561e00d3d7ded2794d094f`
134 |
135 | Here Hp1
and Hp2
refer to two hash-to-point functions on Ed25519.
136 |
137 | Elements of 𝔾E are denoted by `K` or `C` and are serialized as 256-bit integers, with the lower 255 bits being the y-coordinate of the corresponding Ed25519 point and the most significant bit being the parity of the x-coordinate. Scalar-point multiplication is denoted by a space, e.g. K = k G
.
138 |
139 | #### 3.3.3 Point conversion
140 |
141 | We define a function `ConvertPointE(K)` that can transform an Ed25519 curve point into a Curve25519 point, preserving group structure. The conversion is done with the equivalence `x = (v + 1) / (1 - v)`, where `v` is the Ed25519 y-coordinate and `x` is the Curve25519 x-coordinate. Notice that the x-coordinates of Ed25519 points and the y-coordinates of Curve25519 points are not considered. Since the y coordinate is ignored during serialization of Curve25519 points, the conversion should be unambiguous, with only one result.
142 |
143 | #### 3.3.4 Private keys
144 |
145 | Private keys for both curves are elements of the field **F***ℓ*. Private keys are derived using one of the following functions:
146 |
147 | * ScalarDerive(x) = BytesToInt512(H64(x)) mod ℓ
148 | * ScalarDeriveLegacy(x) = BytesToInt256(Keccak256(x)) mod ℓ
149 |
150 | ## 4. Rerandomizable RingCT abstraction
151 |
152 | Here we formally define an abstraction of the FCMP++ consensus layer called *Rerandomizable RingCT* which lays out the requirements that Carrot needs. All elliptic curve arithmetic occurs on Ed25519. When we use the term "list" in this section, we refer to a sequence of elements where the order of elements is encoded and preserved. Thus, the list `{A, B}` is distinct from the list `{B, A}`.
153 |
154 | ### 4.1 Creating a transaction output
155 |
156 | Transaction outputs are defined as the two points (Ko, Ca)
. To create a valid transaction output, the sender must know `z, a` such that Ca = z G + a H
where 0 ≤ a < 264
. Coinbase transactions have a plaintext integer amount `a` instead of the amount commitment Ca
, which is implied to be Ca = G + a H
.
157 |
158 | ### 4.2 Spending a transaction output
159 |
160 | To spend this output, the recipient must know `x, y, z, a` such that Ko = x G + y T
and Ca = z G + a H
where 0 ≤ a < 264
. Spending an output necessarily emits a *key image* (AKA *"linking tag"* or *"nullifier"*) L = x Hp2(Ko)
. All key images must be in the prime order subgroup 𝔾E.
161 |
162 | ### 4.3 Transaction model
163 |
164 | Transactions contain a list of outputs, a list of key images, and additional unstructured data. All key images must be unique within a transaction. Similarly, all output pubkeys must be unique within a transaction.
165 |
166 | ### 4.4 Ledger model
167 |
168 | The ledger can be modeled as an append-only list of transactions. Transactions can only contain key images of transaction outputs of "lower" positions within the ledger list. No two key images in the ledger may ever be equal to one another. In practice, the ledger will contain additional cryptographic proofs that verify the integrity of the data within each transaction, but those can largely be ignored for this addressing protocol.
169 |
170 | ## 5. Wallets
171 |
172 | ### 5.1 Legacy key hierarchy
173 |
174 | The following figure shows the overall hierarchy used for legacy wallet keys. Note that the private spend key ks
doesn't exist for multi-signature wallets.
175 |
176 | ```
177 | k_s (spend key)
178 | |
179 | |
180 | |
181 | +- k_v (view key)
182 | ```
183 |
184 | | Key | Name | Derivation | Used to |
185 | |---------------------------|-----------|----------------------------------------------------------------|---------|
186 | |ks
| spend key | random element of **F***ℓ* | calculate key images, spend enotes |
187 | |kv
| view key | kv = ScalarDeriveLegacy(ks)
| find and decode received enotes, generate addresses |
188 |
189 | ### 5.2 New key hierarchy
190 |
191 | The following figure shows the overall hierarchy one should use for new wallet keys. Users do not *have* to switch their key hierarchy in order to participate in the address protocol, but this hierarchy gives the best features and usability. Note that the master secret sm
doesn't exist for multi-signature wallets.
192 |
193 | ```
194 | s_m (master secret)
195 | |
196 | |
197 | |
198 | +- k_ps (prove-spend key)
199 | |
200 | |
201 | |
202 | +- s_vb (view-balance secret)
203 | |
204 | |
205 | |
206 | +- k_gi (generate-image key)
207 | |
208 | |
209 | |
210 | +- k_v (incoming view key)
211 | |
212 | |
213 | |
214 | +- s_ga (generate-address secret)
215 | ```
216 |
217 | | Key | Name | Derivation | Used to |
218 | |-----|------|------------|-------|
219 | |kps
| prove-spend key | kps = ScalarDerive("Carrot prove-spend key" \|\| sm)
| spend enotes |
220 | |svb
| view-balance secret | svb = SecretDerive("Carrot view-balance secret" \|\| sm)
| find and decode received and outgoing enotes |
221 | |kgi
| generate-image key | kgi = ScalarDerive("Carrot generate-image key" \|\| svb)
| generate key images |
222 | |kv
| incoming view key | kv = ScalarDerive("Carrot incoming view key" \|\| svb)
| find and decode received enotes |
223 | |sga
| generate-address secret | sga = SecretDerive("Carrot generate-address secret" \|\| svb)
| generate addresses |
224 |
225 | ### 5.3 New wallet public keys
226 |
227 | There are two global wallet public keys for the new private key hierarchy.
228 |
229 | | Key | Name | Value |
230 | |-----|------|-------|
231 | |Ks
| spend key | Ks = kgi G + kps T
|
232 | |Kv
| view key | Kv = kv Ks
|
233 |
234 | Note: for legacy key hierarchies, Ks = ks G
.
235 |
236 | ### 5.4 New wallet access tiers
237 |
238 | The new private key hierarchy enables the following useful wallet tiers:
239 |
240 | | Tier | Secret | Off-chain capabilities | On-chain capabilities |
241 | |------------------|-----------------------------|---------------------------|-----------------------|
242 | | Generate-Address | sga
| generate public addresses | none |
243 | | View-Received | kv | all | view received |
244 | | View-All | svb
| all | view all |
245 | | Master | sm
| all | all |
246 |
247 | #### 5.4.1 Generate-Address
248 |
249 | This wallet tier can generate public addresses for the wallet. It doesn't provide any blockchain access.
250 |
251 | #### 5.4.2 View-Received
252 |
253 | This tier provides the wallet with the ability to see all external payments and external change, but cannot see any internal enotes, nor where any enotes are spent.
254 |
255 | #### 5.4.3 View-All
256 |
257 | This is a full view-only wallet that can see all external and internal payment and change enotes, as well as where they are spent (and thus can calculate the correct wallet balance).
258 |
259 | #### 5.4.4 Master wallet (Master)
260 |
261 | This tier has full control of the wallet.
262 |
263 | ## 6. Addresses
264 |
265 | ### 6.1 Address generation
266 |
267 | There are two cryptographically distinct address types in Monero: Cryptonote and subaddress. Note that integrated addresses are derived exactly like a Cryptonote address, but they have an additional payment ID included. There can only be a maximum of one Cryptonote address per view key, referred to as the *main* address, but any number of subaddresses.
268 |
269 | By convention, subaddresses are generated from a "subaddress index", which is a tuple of two 32-bit unsigned integers (jmajor, jminor)
, which allows for 264 addresses. The reason for the distinction between jmajor
and jminor
is simply for UX reasons. The "major" index is used to make separate "accounts" per wallet, which is used to compartmentalize input selection, change outputs, etc. The subaddress index `(0, 0)` is used to designate the main address, even though the key derivation is different. For brevity's sake, we use the label `j` as shorthand for (jmajor, jminor)
and `0` as a shorthand for `(0, 0)`.
270 |
271 | Each Monero address derived from index `j` transmits information (is_main, Ksj, Kvj, pid)
, where `is_main` is a boolean flag which is `true` for Cryptonote addresses, and `false` for subaddresses.
272 |
273 | #### 6.1.1 Main address keys
274 |
275 | The two public keys of the main address are constructed as:
276 |
277 | * Ks0 = Ks
278 | * Kv0 = kv G
279 |
280 | #### 6.1.2 Subaddress keys (Legacy Hierarchy)
281 |
282 | Under the legacy key hierarchy, the two public keys of the subaddress at index `j` are constructed as:
283 |
284 | * ksub_extj = ScalarDeriveLegacy("SubAddr" \|\| IntToBytes8(0) \|\| kv \|\| IntToBytes32(jmajor) \|\| IntToBytes32(jminor))
285 | * Ksj = Ks + ksub_extj G
286 | * Kvj = kv Ksj
287 |
288 | Notice that generating new subaddresses this way requires knowledge of kv
which necessarily ties the ability to generate subaddresses to the ability to find owned enotes.
289 |
290 | #### 6.1.3 Subaddress keys (New Hierarchy)
291 |
292 | Under the new key hierarchy, the two public keys of the subaddress at index `j` are constructed as:
293 |
294 | * sgenj = SecretDerive("Carrot address index generator" \|\| sga \|\| IntToBytes32(jmajor) \|\| IntToBytes32(jminor))
295 | * ksub_scalj = ScalarDerive("Carrot subaddress scalar" \|\| sgenj \|\| Ks \|\| Kv \|\| IntToBytes32(jmajor) \|\| IntToBytes32(jminor))
296 | * Ksj = ksub_scalj Ks
297 | * Kvj = ksub_scalj Kv
298 |
299 | The address index generator sgenj
can be used to prove that the address was constructed from the index `j` and the public keys Ks
and Kv
without revealing sga
. Notice that, unlike the legacy derivation, the new subaddress derivation method does not require the private incoming view key kv
, only the generate-address secret sga
, which allows for private deferred address generation.
300 |
301 | ## 7. Addressing protocol
302 |
303 | ### 7.1 Transaction global fields
304 |
305 | #### 7.1.1 Payment ID
306 |
307 | A single 8-byte encrypted payment ID field is included in non-coinbase transactions for backwards compatibility with integrated addresses. Because only one encrypted payment ID pidenc
is included per transaction, senders can only send to one integrated addresses per transaction. When not sending to a legacy integrated address, `pid` is set to `nullpid`, the payment ID of all zero bytes.
308 |
309 | The payment ID `pid` is encrypted by exclusive or (XOR) with an encryption mask mpid
. The encryption mask is derived from the shared secrets of the payment enote.
310 |
311 | #### 7.1.2 Ephemeral public keys
312 |
313 | Every 2-output transaction has one ephemeral public key De
. Transactions with `N > 2` outputs have `N` ephemeral public keys (one for each output). Coinbase transactions always have one key per output.
314 |
315 | ### 7.2 Input Context
316 |
317 | For each transaction, we assign a value `input_context`, whose purpose is to be unique for every single transaction within a valid ledger. We define this value as follows:
318 |
319 | | transaction type | `input_context` |
320 | |----------------- |-------------------------------------------------- |
321 | | coinbase | "C" \|\| IntToBytes256(block height)
|
322 | | non-coinbase | "R" \|\| first spent key image
|
323 |
324 | This uniqueness is guaranteed by consensus rules: there is exactly one coinbase transaction per block height, and all key images are unique. Indirectly binding output pubkeys to this value helps to mitigate burning bugs.
325 |
326 | ### 7.3 Enote format
327 |
328 | Each enote represents an amount `a` and payment ID `pid` sent to an address (is_main, Ksj, Kvj)
.
329 |
330 | An enote contains the output public key Ko
, the 3-byte view tag `vt`, the amount commitment Ca
, encrypted Janus anchor anchorenc
, and encrypted amount aenc
. For coinbase transactions, the amount commitment Ca
is omitted and the amount is not encrypted.
331 |
332 | #### 7.3.1 The output pubkey
333 |
334 | The output pubkey, sometimes referred to as the "one-time address", is a part of the underlying Rerandomizable RingCT transaction output. Knowledge of the opening of this point allows for spending of the enote. Partial opening knowledge allows for calculating the key image of this enote, signalling in which location it was spent.
335 |
336 | #### 7.3.2 Amount commitment
337 |
338 | The amount commitment is also part of the underlying Rerandomizable RingCT transaction output. This Pederson commitment should open up to the decrypted value in aenc
and the blinding factor derived from the shared secret. Coinbase transactions have this field omitted.
339 |
340 | #### 7.3.3 Amount
341 |
342 | In non-coinbase transactions, the amount `a` is encrypted by exclusive or (XOR) with an encryption mask ma
. In coinbase transactions, `a` is included as part of the enote in plaintext.
343 |
344 | #### 7.3.4 View tags
345 |
346 | The view tag `vt` is the first 3 bytes of a hash of the ECDH exchange with the view key. This view tag is used to fail quickly in the scan process for enotes not intended for the current wallet. The bit size of 24 was chosen as the fixed size because of Jamtis requirements.
347 |
348 | #### 7.3.5 Janus anchor
349 |
350 | The Janus anchor `anchor` is a 16-byte encrypted array that provides protection against Janus attacks and small subgroup attacks on the main sender-receiver ECDH. The anchor is encrypted by exclusive or (XOR) with an encryption mask manchor
. In the case of normal transfers, anchor
is uniformly random, and used to re-derive the enote ephemeral private key de
and check the enote ephemeral pubkey De
is constructed properly. In *special* enotes, anchor
is set to an MAC of De
, authenticated by the private view key kv
. Both of these derivation-and-check paths should only pass if either A) the sender constructed the enotes in a way which does not allow for a Janus nor small subgroup attack or B) the sender knows the private view key, in which case they have no need to execute a Janus nor small subgroup attack.
351 |
352 | ### 7.4 Enote derivations
353 |
354 | The enote components are derived from the shared secrets ssr
and ssrctx
. The definitions of these secrets are described in a later section.
355 |
356 | #### 7.4.1 Intermediate Values
357 |
358 | | Symbol | Name | Derivation |
359 | |-----------|--------|-----------|
360 | |ka
|amount commitment blinding factor| ka = ScalarDerive("Carrot commitment mask" \|\| ssrctx \|\| a \|\| Ksj \|\| enote_type)
|
361 | |kgo
|output pubkey extension G| kgo = ScalarDerive("Carrot key extension G" \|\| ssrctx \|\| Ca)
|
362 | |kto
|output pubkey extension T| kto = ScalarDerive("Carrot key extension T" \|\| ssrctx \|\| Ca)
|
363 | |manchor
|encryption mask for `anchor`| manchor = SecretDerive("Carrot encryption mask anchor" \|\| ssrctx \|\| Ko)[:16]
|
364 | |ma
|encryption mask for `a`| ma = SecretDerive("Carrot encryption mask a" \|\| ssrctx \|\| Ko)[:8]
|
365 | |mpid
|encryption mask for `pid`| mpid = SecretDerive("Carrot encryption mask pid" \|\| ssrctx \|\| Ko)[:8]
|
366 | |anchornorm
|janus anchor, normal| anchornorm = RandBytes(16)
|
367 | |anchorsp
|janus anchor, special| anchorsp = SecretDerive("Carrot janus anchor special" \|\| De \|\| input_context \|\| Ko \|\| kv)[:16]
|
368 | |de
|ephemeral private key| de = ScalarDerive("Carrot sending key normal" \|\| anchornorm \|\| input_context \|\| Ksj \|\| pid)
|
369 |
370 | The variable `enote_type` is `"payment"` or `"change"` depending on the human-meaningful tag that a sender wants to express to the recipient. However, `enote_type` must be equal to `"payment"` for coinbase enotes.
371 |
372 | #### 7.4.2 Component Values
373 |
374 | | Symbol | Name | Derivation |
375 | |----------------------------------|-----------------------|------------|
376 | |Ko
| output pubkey | Ko = Ksj + kgo G + kto T
|
377 | |Ca
| amount commitment | Ca = ka G + a H
|
378 | |aenc
| encrypted amount | aenc = IntToBytes64(a) ⊕ ma
|
379 | |`vt` |view tag | vt = SecretDerive("Carrot view tag" \|\| ssr \|\| input_context \|\| Ko)[:3]
|
380 | |anchorenc
|encrypted Janus anchor | anchorenc = (anchorsp if special enote, else anchornorm) ⊕ manchor
|
381 | |pidenc
|encrypted payment ID | pidenc = pid ⊕ mpid
|
382 |
383 | The view tag binds to `input_context` so that an external observer (i.e. someone without knowledge of ssr
) cannot simply copy De
, Ko
, and `vt` into a new transaction to force a view tag match. Binding to `input_context` causes the view tag of a copied enote to match with the same probability as any random, unrelated enote.
384 |
385 | ### 7.5 Ephemeral public key
386 |
387 | The ephemeral pubkey De
, a Curve25519 point, for a given enote is constructed differently based on what type of address one is sending to, how many outputs are in the transaction, and whether we are deriving on the internal or external path. Here "special" means an *external self-send* enote in a 2-out transaction. "Normal" refers to non-special, external enotes.
388 |
389 | | Transfer Type | De
Derivation |
390 | |--------------------------|----------------------------------------------------------------------|
391 | | Normal, to main address | de B
|
392 | | Normal, to subaddress | de ConvertPointE(Ksj)
|
393 | | Internal | random element of 𝔾M |
394 | | Special | Deother
|
395 |
396 | Deother
refers to the ephemeral pubkey that would be derived on the *other* enote in a 2-out transaction. If both enotes in a 2-out transaction are "special", then no specific derivation of De
is required, and De
should be set to a random element of 𝔾M.
397 |
398 | ### 7.6 Sender-receiver shared secrets
399 |
400 | The shared secrets ssr
and ssrctx
are used to encrypt/extend all components of Carrot transactions. Most components (except the view tag for performance reasons) use ssrctx
to encrypt components.
401 |
402 | ssr
is derived the following ways:
403 |
404 | | | Derivation |
405 | |---------------------- | -------------------------------------------------------------------|
406 | |Sender, external |de ConvertPointE(Kvj
) |
407 | |Recipient, external |kv De
|
408 | |Internal |svb
|
409 |
410 | Then, ssrctx
is derived as ssrctx = SecretDerive("Carrot sender-receiver secret" \|\| ssr \|\| De \|\| input_context)
.
411 |
412 | ### 7.7 Janus outputs
413 |
414 | In case of a Janus attack, the recipient will derive different values of the enote ephemeral pubkey De
and Janus `anchor`, and thus will not recognize the output.
415 |
416 | ### 7.8 Self-send enotes
417 |
418 | Self-send enotes are any enote created by the wallet that the enote is also destined to.
419 |
420 | #### 7.8.1 Internal enotes
421 |
422 | Enotes which are destined for the sending wallet and use a symmetric secret instead of a ECDH exchange are called "internal enotes". The most common type are `"change"` enotes, but internal `"payment"` enotes are also possible. For typical 2-output transactions, an internal enote reuses the same value of De
as the other enote.
423 |
424 | As specified above, these enotes use svb
as the value for ssr
. The existence of internal enotes means that we have to effectively perform *two* types of balance recovery scan processes, external ssr
and internal ssr
. Note, however, that this does not necessarily make balance recovery twice as slow since one scalar-point multiplication and multiplication by eight in Ed25519 is significantly (~100x) slower than Blake2b hashing, and we get to skip those operations for internal scanning.
425 |
426 | #### 7.8.2 Special enotes
427 |
428 | Special enotes are external self-send enotes in a 2-out transaction. The sender employs different shared secret derivations and Janus anchor derivations than a regular external enote.
429 |
430 | #### 7.8.3 Mandatory self-send enote rule
431 |
432 | Every transaction that spends funds from the wallet must produce at least one self-send (not necessarily internal) enote, typically a change enote. If there is no change left, an enote is added with a zero amount. This ensures that all transactions relevant to the wallet have at least one output. This allows for remote-assist "light weight" wallet servers to serve *only* the transactions relevant to the wallet, including any transaction that has spent key images. This rule also helps to optimize full wallet multi-threaded scanning by reducing state reuse.
433 |
434 | #### 7.8.4 One payment, one change rule
435 |
436 | In a 2-out transaction with two internal or two special enotes, one enote's `enote_type` must be `"payment"`, and the other `"change"`.
437 |
438 | In 2-out transactions, the ephemeral pubkey De
is shared between enotes. `input_context` is also shared between the two enotes. Thus, if the two destination addresses share the same private view key kv
in a 2-out transaction, then ssrctx
will be the same and the derivation paths will lead both enotes to have the same output pubkey, which is A) not allowed, B) bad for privacy, and C) would burn funds if allowed. However, note that the output pubkey extensions kgo
and kto
bind to the amount commitment Ca
which in turn binds to `enote_type`. Thus, if we want our two enotes to have unique derivations, then the `enote_type` needs to be unique.
439 |
440 | ### 7.9 Coinbase transactions
441 |
442 | Coinbase transactions are not considered to be internal.
443 |
444 | Miners should continue the practice of only allowing main addresses for the destinations of coinbase transactions in Carrot. This is because, unlike normal enotes, coinbase enotes do not contain an amount commitment, and thus scanning a coinbase enote commitment has no "hard target". If subaddresses can be the destinations of coinbase transactions, then the scanner *must* have their subaddress table loaded and populated to correctly scan coinbase enotes. If only main addresses are allowed, then the scanner does not need the table and can instead simply check whether Ks0 ?= Ko - kgo G + kto T
.
445 |
446 | ## 8. Balance recovery
447 |
448 | ### 8.1 Enote Scan
449 |
450 | The enote scan process is a function which takes public enote information and returns successfully or not. If this enote scan returns successfully, we will be able to recover the address spend pubkey, amount, payment ID, and enote type. Additionally, a successful return guarantees that A) the enote is uniquely addressed to our account, B) Janus attacks are mitigated, and C) burning bug attacks due to duplicate output pubkeys are mitigated. Note, however, that a successful return does *NOT* guarantee that the enote is spendable (i.e. that the recipient will be able to recover `x, y` such that Ko = x G + y T
).
451 |
452 | The following values are part of the enote, and thus public: input_context, De, Ko, Ca, aenc, vt, anchorenc, pidenc
. By contrast, the following values are private to each scanner: kv, svb, and Ks
. For readability, we will denote public values with an underline in this section.
453 |
454 | We perform the scan process once with ssr = kv De
(external), and once with ssr = svb
(internal) if using the new key hierarchy.
455 |
456 | 1. Let vt' = SecretDerive("Carrot view tag" \|\| ssr \|\| input_context \|\| Ko)[:3]
457 | 1. If vt' ≠ vt
, then ABORT
458 | 1. Let ssrctx = SecretDerive("Carrot sender-receiver secret" \|\| ssr \|\| De \|\| input_context)
459 | 1. Let kgo' = ScalarDerive("Carrot key extension G" \|\| ssrctx \|\| Ca)
460 | 1. Let kto' = ScalarDerive("Carrot key extension T" \|\| ssrctx \|\| Ca)
461 | 1. Let Ksj' = Ko - kgo' G - kto' T
462 | 1. If a coinbase enote and Ksj' ≠ Ks
, then ABORT
463 | 1. Set `enote_type' = "payment"`
464 | 1. If a coinbase enote, then let `a' = a` and jump to step 19
465 | 1. Let ma = SecretDerive("Carrot encryption mask a" \|\| ssrctx \|\| Ko)[:8]
466 | 1. Let a' = BytesToInt64(aenc ⊕ ma)
467 | 1. Let ka' = ScalarDerive("Carrot commitment mask" \|\| ssrctx \|\| a' \|\| Ksj' \|\| enote_type')
468 | 1. Let Ca' = ka' G + a' H
469 | 1. If Ca' == Ca
, then jump to step 19
470 | 1. Set `enote_type' = "change"`
471 | 1. Let ka' = ScalarDerive("Carrot commitment mask" \|\| ssrctx \|\| a' \|\| Ksj' \|\| enote_type')
472 | 1. Let Ca' = ka' G + a' H
473 | 1. If Ca' ≠ Ca
, then ABORT
474 | 1. If Ksj'
is not in the *prime order* cyclic subgroup 𝔾E, then ABORT
475 | 1. If ssr == svb
(i.e. performing an internal scan), then jump to step 35
476 | 1. Let mpid = SecretDerive("Carrot encryption mask pid" \|\| ssrctx \|\| Ko)[:8]
477 | 1. Set pid' = pidenc ⊕ mpid
478 | 1. Let manchor = SecretDerive("Carrot encryption mask anchor" \|\| ssrctx \|\| Ko)[:16]
479 | 1. Let anchor' = anchorenc ⊕ manchor
480 | 1. If Ksj' == Ks
, then let Kbase = G
, else let Kbase = Ksj'
481 | 1. Let de' = ScalarDerive("Carrot sending key normal" \|\| anchor' \|\| input_context \|\| Ksj' \|\| pid')
482 | 1. Let De' = de' ConvertPointE(Kbase)
483 | 1. If De' == De
, then jump to step 35
484 | 1. Set `pid' = nullpid`
485 | 1. Let de' = ScalarDerive("Carrot sending key normal" \|\| anchor' \|\| input_context \|\| Ksj' \|\| pid')
486 | 1. Let De' = de' ConvertPointE(Kbase)
487 | 1. If De' == De
, then jump to step 35
488 | 1. Let anchorsp = SecretDerive("Carrot janus anchor special" \|\| De \|\| input_context \|\| Ko \|\| kv)[:16]
489 | 1. If anchor' ≠ anchorsp
, then ABORT
490 | 1. Return successfully!
491 |
492 | ### 8.2 Determining spendability and computing key images
493 |
494 | An enote is spendable if the computed nominal address spend pubkey Ksj'
from the enote scan process is one that the recipient knows how to derive. However, the enote scan process does not inform the sender how to derive the subaddress. One method of quickly checking whether a nominal address spend pubkey is derivable, and thus spendable, is a *subaddress table*. A subaddress table maps precomputed address spend pubkeys to their index `j`. Once the subaddress index for an enote is determined, we can begin computing the key image.
495 |
496 | #### 8.2.1 Legacy key hierarchy key images
497 |
498 | If `j ≠ 0`, then let ksub_extj = ScalarDeriveLegacy("SubAddr" \|\| IntToBytes8(0) \|\| kv \|\| IntToBytes32(jmajor) \|\| IntToBytes32(jminor))
, otherwise let ksub_extj = 0
.
499 |
500 | The key image is computed as: L = (ks + ksub_extj + kgo) Hp2(Ko)
.
501 |
502 | #### 8.2.2 New key hierarchy key images
503 |
504 | If `j ≠ 0`, then let ksub_scalj = ScalarDerive("Carrot subaddress scalar" \|\| sgenj \|\| Ks \|\| Kv \|\| IntToBytes32(jmajor) \|\| IntToBytes32(jminor))
, otherwise let ksub_scalj = 1
.
505 |
506 | The key image is computed as: L = (kgi * ksub_scalj + kgo) Hp2(Ko)
.
507 |
508 | ### 8.3 Handling key images and calculating balance
509 |
510 | If a scanner successfully scans any enote within a transaction, they should save all those key images indefinitely as "potentially spent". The rest of the ledger's key images can be discarded. Then, the key images for each enote should be calculated. The "unspent" enotes are determined as those whose key images is not within the set of potentially spent key images. The sum total of the amounts of these enotes is the current balance of the wallet, and the unspent enotes can be used in future input proofs.
511 |
512 | ## 9. Security properties
513 |
514 | Below are listed some security properties which are to hold for Carrot. Unless otherwise specified, it is assumed that no participant can efficiently solve the decisional Diffie-Hellman problem in Curve25519 and Ed25519 (i.e. the decisional Diffie-Hellman assumption [[19](https://crypto.stanford.edu/~dabo/pubs/papers/DDH.pdf)] holds).
515 |
516 | ### 9.1 Balance recovery security
517 |
518 | The term "honest receiver" below means an entity with certain private key material correctly executing the balance recovery instructions of the addressing protocol as described above. A receiver who correctly follows balance recovery instructions but lies to the sender whether they received funds is still considered "honest". Likewise, an "honest sender" is an entity who follows the sending instructions of the addressing protocol as described above.
519 |
520 | #### 9.1.1 Completeness
521 |
522 | An honest sender who sends amount `a` and payment ID `pid` to address (is_main, Ksj, Kvj)
, internally or externally, can be guaranteed that the honest receiver who derived that address will:
523 |
524 | 1. Recover the same a, pid, Ksj, Kvj
525 | 2. Recover `x, y, z` such that Ca = z G + a H
and Ko = x G + y T
526 |
527 | This is to be achieved without any other interactivity.
528 |
529 | #### 9.1.2 Spend Binding
530 |
531 | If an honest receiver recovers `x` and `y` for an enote such that Ko = x G + y T
, then it is guaranteed within a security factor that no other entity without knowledge of kps
(or ks
for legacy key hierarchies) will also be able to find `x` and `y`.
532 |
533 | #### 9.1.3 Enote Scan Binding
534 |
535 | No two honest receivers using different values of kv
for external scans or svb
for internal scans will both successfully return from the enote scan process given the same enote, even if that enote was constructed dishonestly.
536 |
537 | #### 9.1.4 Burning Bug Resistance
538 |
539 | For any Ko
, it is computationally intractable to find two unique values of `input_context` such that an honest receiver will determine both enotes to be spendable. Recall that spendability is determined as whether Ksj' = Ko - kgo G - kto T
is an address spend pubkey that the recipient knows how to derive from their account secrets.
540 |
541 | #### 9.1.5 Janus Attack Resistance
542 |
543 | There is no algorithm that, without knowledge of the recipient's private view key kv
, allows a sender to construct an enote using two or more honestly-derived non-integrated addresses which successfully passes the enote scan process when the two addresses where derived from the same account, but fails when the addresses are unrelated.
544 |
545 | More concretely, it is computationally intractable, without knowledge of the recipient's private view key kv
, to construct an external enote which successfully passes the enote scan process such that the recipient's computed nominal address spend pubkey Ksj' = Ko - kgo G - kto T
does not match the shared secret ssr = r ConvertPointE(Kvj')
for some sender-chosen `r`. This narrowed statement makes the informal assumption that using the address view spend pubkey for the Diffie-Hellman exchange and nominally recomputing its correct address spend pubkey leaves no room for a Janus attack.
546 |
547 | ### 9.2 Unlinkability
548 |
549 | #### 9.2.1 Computational Address-Address Unlinkability
550 |
551 | A third party cannot determine if two non-integrated addresses share the same kv
with any better probability than random guessing.
552 |
553 | #### 9.2.2 Computational Address-Enote Unlinkability
554 |
555 | A third party cannot determine if an address is the destination of an enote with any better probability than random guessing, even if they know the destination address.
556 |
557 | #### 9.2.3 Computational Enote-Enote Unlinkability
558 |
559 | A third party cannot determine if two enotes have the same destination address with any better probability than random guessing, even if they know the destination address.
560 |
561 | #### 9.2.4 Computational Enote-Key Image Unlinkability
562 |
563 | A third party cannot determine if any key image is *the* key image for any enote with any better probability than random guessing, even if they know the destination address.
564 |
565 | ### 9.3 Forward Secrecy
566 |
567 | Forward secrecy refers to the preservation of privacy properties of past transactions against a future adversary capable of solving the elliptic curve discrete logarithm problem (ECDLP), for example a quantum computer. We refer to an entity with this capability as a *SDLP* (Solver of the Discrete Log Problem). We assume that the properties of secure hash functions still apply to SDLPs (i.e. collision-resistance, preimage-resistance, one-way).
568 |
569 | #### 9.3.1 Address-Conditional Forward Secrecy
570 |
571 | A SDLP can learn no receiver or amount information about a transaction output, nor where it is spent, without knowing a receiver's public address.
572 |
573 | #### 9.3.2 Internal Forward Secrecy
574 |
575 | Even with knowledge of sga
, kps
, kgi
, kv
, a SDLP without explicit knowledge of svb
will not be able to discern where internal enotes are received, where/if they are spent, nor the amounts with any better probability than random guessing.
576 |
577 | ### 9.4 Indistinguishability
578 |
579 | We define multiple processes by which public value representations are created as "indistinguishable" if a SDLP, without knowledge of public addresses or private account keys, cannot determine by which process the public values were created with any better probability than random guessing. The processes in question are described below.
580 |
581 | #### 9.4.1 Transaction output random indistinguishability
582 |
583 | Carrot transaction outputs are indistinguishable from random transaction outputs. The Carrot transaction output process is described earlier in this document. The random transaction output process is modeled as follows:
584 |
585 | 1. Sample r1
and r2
independently from uniform integer distribution `[0, ℓ)`.
586 | 2. Set Ko = r1 G
587 | 3. Set Ca = r2 G
588 |
589 | #### 9.4.2 Ephemeral pubkey random indistinguishability
590 |
591 | Carrot ephemeral pubkeys are indistinguishable from random Curve25519 pubkeys. The Carrot ephemeral pubkey process is described earlier in this document. The random ephemeral pubkey process is modeled as follows:
592 |
593 | 1. Sample `r` from uniform integer distribution `[0, ℓ)`.
594 | 2. Set De = r B
595 |
596 | Note that in Carrot ephemeral pubkey construction, since the ephemeral private key de
, unlike the private view-incoming key, is derived from a random secret, without key clamping, multiplying by this unclamped key makes the resultant pubkey indistinguishable from a random pubkey.
597 |
598 | #### 9.4.3 Other enote component random indistinguishability
599 |
600 | The remaining Carrot enote components are indistinguishable from random byte strings. The Carrot enote process is described earlier in this document. The random enote byte string process is modeled as follows:
601 |
602 | 1. Sample aenc = RandBytes(8)
603 | 2. Sample anchorenc = RandBytes(16)
604 | 3. Sample vt = RandBytes(3)
605 | 4. Sample pidenc = RandBytes(8)
606 |
607 | ## 10. Credits
608 |
609 | Special thanks to everyone who commented and provided feedback on the original [Jamtis gist](https://gist.github.com/tevador/50160d160d24cfc6c52ae02eb3d17024). Many of the ideas were incorporated in this document.
610 |
611 | A *very* special thanks to @tevador, who wrote up the Jamtis and Jamtis-RCT specifications, which were the foundation of this document, containing most of the transaction protocol math.
612 |
613 | ## 11. Glossary
614 |
615 | - *Amount Commitment* - An elliptic curve point, in the form of a Pederson Commitment [[20](https://www.getmonero.org/resources/moneropedia/pedersen-commitment.html)], which is used to represent hidden amounts in transaction outputs in RingCT and FCMP++
616 | - *Burning Bug Attack* - An attack where an exploiter duplicates an output pubkey and tricks the recipient into accepting both, even though only one can be spent
617 | - *Coinbase Transaction* - A transaction which has no key images, and plaintext integer amounts instead of amount commitments in its outputs
618 | - *Cryptonote* - A cryptocurrency consensus protocol and addressing scheme which was the foundation for Monero's ledger interactions initially
619 | - *Cryptonote Address* - An address in the form described in the Cryptonote v2 whitepaper
620 | - *Enote* - A transaction output as well as the associated data required to scan it
621 | - *Ephemeral Public Key* - An elliptic curve point associated to transaction outputs in order to hide enote details through a Diffie-Hellman key exchange
622 | - *External Enote* - An enote which was constructed by performing an asymmetric Elliptic Curve Diffie-Hellman key exchange against an address, main or subaddress
623 | - *FCMP++* - A proposed cryptocurrency consensus protocol to upgrade Monero's RingCT consensus protocol
624 | - *Forward Secrecy* - The property of a cryptographic construction that information is hidden from an observer that can efficiently solve the Discrete Logarithm Problem
625 | - *Indistinguishability* - The property of multiple cryptographic constructions that the public values posted cannot be determined to the result of any single construction
626 | - *Input Content* - A unique value associated to each transaction used in the Carrot address protocol derivations to mitigate burning bug attacks
627 | - *Integrated Address* - A main address which additionally contains a payment ID
628 | - *Internal Enote* - An enote which was constructed using a symmetric shared secret, typically the view-balance secret
629 | - *Janus Anchor* - An enote component whose purpose is two fold in mitigating Janus attacks: act as an entropy source for deriving the ephemeral private key or act as an MAC validating the ephemeral pubkey
630 | - *Janus Attack* - An attack where an exploiter constructs an enote partially using two different addresses they suspect to belong to the same user such that the confirmation of that payment confirms the addresses are actually related
631 | - *Key Image* - An elliptic curve point emitted during a Rerandomizable RingCT spend proof, used during balance recovery to determine whether an enote has been spent yet
632 | - *Ledger* - An immutable, append-only list of transactions which is the shared medium of data exchange for different participants of the network
633 | - *Main Address* - same as *Cryptonote Address*
634 | - *MAC* - Message Authentication Code [[21](https://www.cs.princeton.edu/courses/archive/spr10/cos433/lec9new.pdf)]: some information that verifies that certain key material "authorized" a given message
635 | - *Monero* - A payment network, along with a cryptocurrency *XMR*, that historically utilizes a collection of consensus protocols on its ledger, namely: Cryptonote, RingCT, and FCMP++
636 | - *Payment ID* - An 8 byte array included with transaction data used to differentiate senders
637 | - *Rerandomizable RingCT* - An abstraction of FCMP++ defined in this document that allows the formalization of different security properties without knowledge of the underlying proving system
638 | - *RingCT* - A cryptocurrency consensus protocol that iterated on Cryptonote by introducing hidden amounts by way of amount commitments
639 | - *Self-send Enote* - An enote constructed by wallet intended to be received by the same wallet, either internal or external
640 | - *Special Enote* - An external self-send enote within a 2-output transaction
641 | - *Subaddress* - An address form introduced by Monero contributors which allows for a single wallet to generate an arbitrary number of unlinkable addresses without affecting scanning speed
642 | - *Transaction* - An atomic modification to the ledger containing key images, transaction outputs, and other unstructured data
643 | - *Transaction Output* - A distinct tuple of an elliptic curve point and amount commitment or plaintext amount which is contained in a list in a transaction
644 | - *View Tag* - A small enote component, calculated as a partial hash of the sender-receiver shared key, which is checked early in the balance recovery process to optimize scanning performance
645 | - *Wallet* - A collection of private key data, cached ledger state, and other information which is used to interact with the shared ledger
646 |
647 | ## 12. References
648 |
649 | 1. https://github.com/monero-project/research-lab/blob/master/whitepaper/whitepaper.pdf
650 | 1. https://www.getmonero.org/resources/moneropedia/paymentid.html
651 | 1. https://github.com/monero-project/research-lab/issues/7
652 | 1. https://gist.github.com/kayabaNerve/0e1f7719e5797c826b87249f21ab6f86
653 | 1. https://www.getmonero.org/resources/moneropedia/ringCT.html
654 | 1. https://web.getmonero.org/2019/10/18/subaddress-janus.html
655 | 1. https://www.getmonero.org/2018/09/25/a-post-mortum-of-the-burning-bug.html
656 | 1. https://github.com/monero-project/monero/pull/4438/files#diff-04cf14f64d2023c7f9cd7bd8e51dcb32ed400443c6a67535cb0105cfa2b62c3c
657 | 1. https://gist.github.com/tevador/50160d160d24cfc6c52ae02eb3d17024
658 | 1. https://gist.github.com/kayabaNerve/8066c13f1fe1573286ba7a2fd79f6100
659 | 1. https://stackabuse.com/python-slice-notation-on-list/
660 | 1. https://eprint.iacr.org/2013/322.pdf
661 | 1. https://keccak.team/keccak.html
662 | 1. https://cr.yp.to/ecdh/curve25519-20060209.pdf
663 | 1. https://neilmadden.blog/2020/05/28/whats-the-curve25519-clamping-all-about/
664 | 1. https://cr.yp.to/ecdh.html
665 | 1. https://datatracker.ietf.org/doc/html/rfc2785
666 | 1. https://ed25519.cr.yp.to/ed25519-20110926.pdf
667 | 1. https://crypto.stanford.edu/~dabo/pubs/papers/DDH.pdf
668 | 1. https://www.getmonero.org/resources/moneropedia/pedersen-commitment.html
669 | 1. https://www.cs.princeton.edu/courses/archive/spr10/cos433/lec9new.pdf
670 |
--------------------------------------------------------------------------------
/finalize.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/bash
2 |
3 | cd -- "$( dirname -- "$0" )"
4 | cd src
5 | ./dumb_md_enumerate.py carrot_raw.md | ./dumb_citations.py > ../carrot.md
6 |
7 |
--------------------------------------------------------------------------------
/src/carrot_raw.md:
--------------------------------------------------------------------------------
1 | # Carrot
2 |
3 | Carrot (Cryptonote Address on Rerandomizable-RingCT-Output Transactions) is an addressing protocol for the upcoming FCMP++ upgrade to Monero which maintains backwards compatibility with existing addresses. It does this while bringing new privacy and usability features, such as outgoing view keys. Carrot is designed to be indistinguishable on-chain from another potential addressing protocol, Jamtis, which will justify some seemingly strange design choices later on in this document.
4 |
5 | ## Background
6 |
7 | ### Cryptonote Addresses, Integrated Addresses, and Subaddresses
8 |
9 | In 2013, the Cryptonote whitepaper [[citation](https://github.com/monero-project/research-lab/blob/master/whitepaper/whitepaper.pdf)] introduced an addressing scheme which remains a crucial component of Monero's privacy model today, providing recipient unlinkability across transactions. Unlike Bitcoin, which uses transparent addresses, Monero's use of addresses ensures that all created transaction outputs cannot be attributed to any single receiver regardless of the number of times an address is reused, and without requiring interactivity.
10 |
11 | In the beginning, since there was only one address per wallet, a method was needed for receivers to differentiate their senders. *Payment IDs* [[citation](https://www.getmonero.org/resources/moneropedia/paymentid.html)], an arbitrary 32 byte string attached to transactions, was the initial solution to this problem. The aim was that users sending funds would include a 32 byte message that gave the recipient user enough evidence to attribute that transaction to them. *Integrated addresses* improved the UX of these payment IDs by having the recipient's wallet generate and include them inside of addresses, which were automatically added to the transaction data by the sender's wallet. They were also shortened to 8 bytes. Wallets then started encrypting the payment IDs on-chain, and adding dummies if no payment IDs were used, which greatly improved privacy.
12 |
13 | In 2016, Monero iterated even further by introducing *subaddresses* [[citation](https://github.com/monero-project/research-lab/issues/7)], an addressing scheme that existing wallets could adopt, allowing them to generate an arbitrary number of unlinkable receiving addresses without affecting scan speed.
14 |
15 | ### FCMP++
16 |
17 | In order to tackle privacy shortcomings with Monero's ring signatures, there is a consensus protocol update planned called FCMP++, an abbreviation of "Full-Chain Membership Proofs + Spend Authorization + Linkability" [[citation](https://gist.github.com/kayabaNerve/0e1f7719e5797c826b87249f21ab6f86)]. In contrast to ring signatures' relatively small decoy set size, FCMP++ enables all transaction outputs on the blockchain to be used as decoys for each input. FCMP++'s deterministic anonymity avoids almost all the undesirable edge cases and targeted attacks against ring signatures, as well as improving on it in the normal case. To read more about the FCMP++ upgrade, the original author [wrote a blog post](https://www.getmonero.org/2024/04/27/fcmps.html) outlining new features, academic work, etc.
18 |
19 | However, most relevant to Carrot, FCMP++ has a subtle, but powerful effect on how transaction outputs can be composed on-chain. This effect is dubbed "Rerandomization" and is already applied to amounts in Monero RingCT [[citation](https://www.getmonero.org/resources/moneropedia/ringCT.html)] to make them confidential. Rerandomization in the context of FCMP++ opens the door for long-desired features, namely forward secrecy and outgoing view keys. Both of these features are described in greater detail in later sections.
20 |
21 | ### Where Carrot fits in
22 |
23 | Carrot is an *addressing* protocol, designed to be a layer on top the *consensus* protocol FCMP++. In other words, FCMP++ dictates the rules that transactions must follow in order to be valid, whereas Carrot provides a shared framework for how to transmit funds and otherwise interact with addresses meaningfully on FCMP++ transactions. Carrot also contains a recommended wallet specification, detailing how to construct public and private keys in a way which best leverages FCMP++. A wallet with the Carrot key hierarchy can expect flexibility in how wallet functions can be compartmentalized, as well as unconditional forward secrecy for change outputs, etc.
24 |
25 | However, an equally important design consideration of Carrot is backwards compatibility. One can participate in the Carrot addressing protocol using preexisting Cryptonote addresses, subaddresses, and integrated addresses. No wallet key migration is required. Even without a migration, using the Carrot addressing protocol provides protection against the burning bug attack, conditional forward secrecy, etc. The exact breakdown of which wallets get which features is outlined in the following section. Furthermore, addresses generated by the new Carrot wallet key hierarchy will be of the same format as old addresses. Indeed, these new addresses will be computationally indistinguishable from old addresses, maintaining off-chain privacy and easing developer loads.
26 |
27 | ## New Features
28 |
29 | ### All wallets
30 |
31 | Carrot immediately brings these features to both newly generated wallets and existing wallets.
32 |
33 | #### Address-conditional forward secrecy
34 |
35 | As a result of leveraging the FCMP++ consensus protocol, Carrot has the ability to hide all transaction details (sender, receiver, amount) from third-parties with the ability to break the security of elliptic curves (e.g. quantum computers), as long as the observer does not know receiver's addresses.
36 |
37 | #### Janus attack mitigation
38 |
39 | A Janus attack [[citation](https://web.getmonero.org/2019/10/18/subaddress-janus.html)] 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.
40 |
41 | Carrot prevents this attack by allowing the recipient to recognize a Janus output.
42 |
43 | #### Stateless burning bug mitigation
44 |
45 | The burning bug [[citation](https://www.getmonero.org/2018/09/25/a-post-mortum-of-the-burning-bug.html)] is a undesirable result of Monero's old scan process wherein if an exploiter creates a transaction with the same ephemeral pubkey, output pubkey, and transaction output index as an existing transaction, a recipient will scan both instances of these enotes as "owned" and interpret their balance as increasing. However, since key images are linked to output pubkeys, the receiver can only spend one of these enotes, "burning" the other. If the exploiter creates an enote with amount `a = 0`, and the receiver happens to spend that enote first, then the receiver burns all of the funds in their original enote with only a tiny fee cost to the exploiter!
46 |
47 | An initial patch [[citation](https://github.com/monero-project/monero/pull/4438/files#diff-04cf14f64d2023c7f9cd7bd8e51dcb32ed400443c6a67535cb0105cfa2b62c3c)] was introduced secretly to catch when such an attempted attack occurred. However, this patch did not attempt to recover gracefully and instead simply stopped the wallet process with an error message. Further iterations of handling this bug automatically discarded all instances of duplicate output pubkeys which didn't have the greatest amount. However, all instances of burning bug handling in Monero Core require a complete view of all scanning history up to the current chain tip, which makes the workarounds somewhat fragile.
48 |
49 | The original Jamtis [[citation](https://gist.github.com/tevador/50160d160d24cfc6c52ae02eb3d17024)] proposal by @tevador and the *Guaranteed Address* [[citation](https://gist.github.com/kayabaNerve/8066c13f1fe1573286ba7a2fd79f6100)] proposal by @kayabaNerve were some of the first examples of addressing schemes where attempting a burn in this manner is inherently computationally intractable. These schemes somehow bind the output pubkey to an "input context" value, which is unique for every transaction. Thus, the receiver will only ever correctly determine an enote with a given output pubkey to be spendable for a single transaction, avoiding the burning bug without ever having to maintain a complete scan state.
50 |
51 | Carrot prevents this attack statelessly in the same manner.
52 |
53 | #### Payment ID confirmation
54 |
55 | Payment IDs are confirmed by a cryptographic hash, which gives integrated address payment processors better guarantees, provides better UX, and allows many-output batched transactions to unambiguously include an integrated address destination.
56 |
57 | ### New wallets only
58 |
59 | These features are only available to wallets generated with the newly defined account key hierarchy. Existing Monero wallets will not inherit these features, unfortunately.
60 |
61 | #### Internal forward secrecy
62 |
63 | Enotes that are sent "internally" to one's own wallet will have all transactions details hidden (sender, receiver, amount) from third-parties with the ability to break the security of elliptic curves (e.g. quantum computers), even if the observer has knowledge of the receiver's addresses.
64 |
65 | #### Address generator tier
66 |
67 | This tier is intended for merchant point-of-sale terminals. It can generate addresses on demand, but otherwise has no access to the wallet (i.e. it cannot recognize any payments in the blockchain).
68 |
69 | #### Payment validator tier
70 |
71 | Carrot supports view-incoming-only wallets that can verify that an external payment was received into the wallet, without the ability to see where those payment enotes were spent, or spend it themselves. But unlike old Monero view-only wallets, a Carrot payment validator wallet cannot see *"internal"* change enotes.
72 |
73 | #### Full view-only tier
74 |
75 | Carrot 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, without the ability to spend anything.
76 |
77 | ## Notation
78 |
79 | ### Miscellaneous definitions
80 |
81 | 1. The function `BytesToInt64(x)` deserializes a 64-bit little-endian integer from a 8-byte input.
82 | 1. The function `BytesToInt256(x)` deserializes a 256-bit little-endian integer from a 32-byte input.
83 | 1. The function `BytesToInt512(x)` deserializes a 512-bit little-endian integer from a 64-byte input.
84 | 1. The function `IntToBytes8(x)` serializes an integer into a little-endian encoded 1-byte output.
85 | 1. The function `IntToBytes32(x)` serializes an integer into a little-endian encoded 4-byte output.
86 | 1. The function `IntToBytes64(x)` serializes an integer into a little-endian encoded 8-byte output.
87 | 1. The function `IntToBytes256(x)` serializes an integer into a little-endian encoded 32-byte output.
88 | 1. The function `RandBytes(x)` generates a random x-byte string.
89 | 1. Concatenation is denoted by `||`.
90 | 1. Bit-wise XOR (exclusive-or) is denoted by `⊕`.
91 | 1. Python slice notation [[citation](https://stackabuse.com/python-slice-notation-on-list/)] `X[:N]` is used to take the first `N` bytes of byte string `X`
92 |
93 | ### Hash functions
94 |
95 | The function Hb(x)
with parameters `b, x`, refers to the Blake2b hash function [[citation](https://eprint.iacr.org/2013/322.pdf)] initialized as follows:
96 |
97 | * The output length is set to `b` bytes.
98 | * Hashing is done in sequential mode.
99 | * The Personalization string is set to the ASCII value "Monero", padded with zero bytes.
100 | * The input `x` is hashed.
101 |
102 | The function `SecretDerive` is defined as:
103 |
104 | SecretDerive(x) = H32(x)
105 |
106 | The function `Keccak256(x)` refers to the Keccak function [[citation](https://keccak.team/keccak.html)] parameterized with `r = 1088, c = 512, d = 256`.
107 |
108 | ### Elliptic curves
109 |
110 | Two elliptic curves are used in this specification:
111 |
112 | 1. **Curve25519** - a Montgomery curve. Points on this curve include a cyclic subgroup 𝔾M.
113 | 1. **Ed25519** - a twisted Edwards curve. Points on this curve include a cyclic subgroup 𝔾E.
114 |
115 | Both curves are birationally equivalent, so the subgroups 𝔾M and 𝔾E have the same prime order ℓ = 2252 + 27742317777372353535851937790883648493
. The total number of points on each curve is `8ℓ`.
116 |
117 | #### Curve25519
118 |
119 | The Montgomery curve Curve25519 [[citation](https://cr.yp.to/ecdh/curve25519-20060209.pdf)] is used exclusively for the Diffie-Hellman key exchange with the private incoming view key. Only a single generator point `B`, where `x = 9`, is used.
120 |
121 | Elements of 𝔾M are denoted by `D`, and are serialized as their x-coordinate. As is convention for Curve25519, the y coordinate is assumed to be the even value that satisfies the Montgomery curve equation.
122 |
123 | Scalar-point multiplication is denoted by a space, e.g. D = d B
. In this specification, when we mention scalar-point multiplication, we always mean a "full" scalar multiplication, without "scalar clamping" [[citation](https://neilmadden.blog/2020/05/28/whats-the-curve25519-clamping-all-about/)]. Most implementations of X25519 [[citation](https://cr.yp.to/ecdh.html)], an ECDH algorithm on Curve25519, will "clamp" the scalar, treating some bits implicitly as always 0s or always 1s. Performing a clamped scalar-point multiplication will break completeness of the ECDH for existing Monero addresses, since the private view key could be any *unclamped* element of **F***ℓ*. Scalar clamping of the three least significant bits in X25519 is done to mitigate small subgroup attacks, but since we don't clamp, we must explicitly handle small subgroup attacks elsewhere [[citation](https://datatracker.ietf.org/doc/html/rfc2785)].
124 |
125 | #### Ed25519
126 |
127 | The twisted Edwards curve Ed25519 [[citation](https://ed25519.cr.yp.to/ed25519-20110926.pdf)] is used for all other cryptographic operations on FCMP++. The following generators are used:
128 |
129 | |Point|Derivation|Serialized (hex)|
130 | |-----|----------|----------|
131 | | `G` | generator of 𝔾E | `5866666666666666666666666666666666666666666666666666666666666666`
132 | | `H` | Hp1(G)
| `8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94`
133 | | `T` | Hp2(Keccak256("Monero Generator T"))
| `966fc66b82cd56cf85eaec801c42845f5f408878d1561e00d3d7ded2794d094f`
134 |
135 | Here Hp1
and Hp2
refer to two hash-to-point functions on Ed25519.
136 |
137 | Elements of 𝔾E are denoted by `K` or `C` and are serialized as 256-bit integers, with the lower 255 bits being the y-coordinate of the corresponding Ed25519 point and the most significant bit being the parity of the x-coordinate. Scalar-point multiplication is denoted by a space, e.g. K = k G
.
138 |
139 | #### Point conversion
140 |
141 | We define a function `ConvertPointE(K)` that can transform an Ed25519 curve point into a Curve25519 point, preserving group structure. The conversion is done with the equivalence `x = (v + 1) / (1 - v)`, where `v` is the Ed25519 y-coordinate and `x` is the Curve25519 x-coordinate. Notice that the x-coordinates of Ed25519 points and the y-coordinates of Curve25519 points are not considered. Since the y coordinate is ignored during serialization of Curve25519 points, the conversion should be unambiguous, with only one result.
142 |
143 | #### Private keys
144 |
145 | Private keys for both curves are elements of the field **F***ℓ*. Private keys are derived using one of the following functions:
146 |
147 | * ScalarDerive(x) = BytesToInt512(H64(x)) mod ℓ
148 | * ScalarDeriveLegacy(x) = BytesToInt256(Keccak256(x)) mod ℓ
149 |
150 | ## Rerandomizable RingCT abstraction
151 |
152 | Here we formally define an abstraction of the FCMP++ consensus layer called *Rerandomizable RingCT* which lays out the requirements that Carrot needs. All elliptic curve arithmetic occurs on Ed25519. When we use the term "list" in this section, we refer to a sequence of elements where the order of elements is encoded and preserved. Thus, the list `{A, B}` is distinct from the list `{B, A}`.
153 |
154 | ### Creating a transaction output
155 |
156 | Transaction outputs are defined as the two points (Ko, Ca)
. To create a valid transaction output, the sender must know `z, a` such that Ca = z G + a H
where 0 ≤ a < 264
. Coinbase transactions have a plaintext integer amount `a` instead of the amount commitment Ca
, which is implied to be Ca = G + a H
.
157 |
158 | ### Spending a transaction output
159 |
160 | To spend this output, the recipient must know `x, y, z, a` such that Ko = x G + y T
and Ca = z G + a H
where 0 ≤ a < 264
. Spending an output necessarily emits a *key image* (AKA *"linking tag"* or *"nullifier"*) L = x Hp2(Ko)
. All key images must be in the prime order subgroup 𝔾E.
161 |
162 | ### Transaction model
163 |
164 | Transactions contain a list of outputs, a list of key images, and additional unstructured data. All key images must be unique within a transaction. Similarly, all output pubkeys must be unique within a transaction.
165 |
166 | ### Ledger model
167 |
168 | The ledger can be modeled as an append-only list of transactions. Transactions can only contain key images of transaction outputs of "lower" positions within the ledger list. No two key images in the ledger may ever be equal to one another. In practice, the ledger will contain additional cryptographic proofs that verify the integrity of the data within each transaction, but those can largely be ignored for this addressing protocol.
169 |
170 | ## Wallets
171 |
172 | ### Legacy key hierarchy
173 |
174 | The following figure shows the overall hierarchy used for legacy wallet keys. Note that the private spend key ks
doesn't exist for multi-signature wallets.
175 |
176 | ```
177 | k_s (spend key)
178 | |
179 | |
180 | |
181 | +- k_v (view key)
182 | ```
183 |
184 | | Key | Name | Derivation | Used to |
185 | |---------------------------|-----------|----------------------------------------------------------------|---------|
186 | |ks
| spend key | random element of **F***ℓ* | calculate key images, spend enotes |
187 | |kv
| view key | kv = ScalarDeriveLegacy(ks)
| find and decode received enotes, generate addresses |
188 |
189 | ### New key hierarchy
190 |
191 | The following figure shows the overall hierarchy one should use for new wallet keys. Users do not *have* to switch their key hierarchy in order to participate in the address protocol, but this hierarchy gives the best features and usability. Note that the master secret sm
doesn't exist for multi-signature wallets.
192 |
193 | ```
194 | s_m (master secret)
195 | |
196 | |
197 | |
198 | +- k_ps (prove-spend key)
199 | |
200 | |
201 | |
202 | +- s_vb (view-balance secret)
203 | |
204 | |
205 | |
206 | +- k_gi (generate-image key)
207 | |
208 | |
209 | |
210 | +- k_v (incoming view key)
211 | |
212 | |
213 | |
214 | +- s_ga (generate-address secret)
215 | ```
216 |
217 | | Key | Name | Derivation | Used to |
218 | |-----|------|------------|-------|
219 | |kps
| prove-spend key | kps = ScalarDerive("Carrot prove-spend key" \|\| sm)
| spend enotes |
220 | |svb
| view-balance secret | svb = SecretDerive("Carrot view-balance secret" \|\| sm)
| find and decode received and outgoing enotes |
221 | |kgi
| generate-image key | kgi = ScalarDerive("Carrot generate-image key" \|\| svb)
| generate key images |
222 | |kv
| incoming view key | kv = ScalarDerive("Carrot incoming view key" \|\| svb)
| find and decode received enotes |
223 | |sga
| generate-address secret | sga = SecretDerive("Carrot generate-address secret" \|\| svb)
| generate addresses |
224 |
225 | ### New wallet public keys
226 |
227 | There are two global wallet public keys for the new private key hierarchy.
228 |
229 | | Key | Name | Value |
230 | |-----|------|-------|
231 | |Ks
| spend key | Ks = kgi G + kps T
|
232 | |Kv
| view key | Kv = kv Ks
|
233 |
234 | Note: for legacy key hierarchies, Ks = ks G
.
235 |
236 | ### New wallet access tiers
237 |
238 | The new private key hierarchy enables the following useful wallet tiers:
239 |
240 | | Tier | Secret | Off-chain capabilities | On-chain capabilities |
241 | |------------------|-----------------------------|---------------------------|-----------------------|
242 | | Generate-Address | sga
| generate public addresses | none |
243 | | View-Received | kv | all | view received |
244 | | View-All | svb
| all | view all |
245 | | Master | sm
| all | all |
246 |
247 | #### Generate-Address
248 |
249 | This wallet tier can generate public addresses for the wallet. It doesn't provide any blockchain access.
250 |
251 | #### View-Received
252 |
253 | This tier provides the wallet with the ability to see all external payments and external change, but cannot see any internal enotes, nor where any enotes are spent.
254 |
255 | #### View-All
256 |
257 | This is a full view-only wallet that can see all external and internal payment and change enotes, as well as where they are spent (and thus can calculate the correct wallet balance).
258 |
259 | #### Master wallet (Master)
260 |
261 | This tier has full control of the wallet.
262 |
263 | ## Addresses
264 |
265 | ### Address generation
266 |
267 | There are two cryptographically distinct address types in Monero: Cryptonote and subaddress. Note that integrated addresses are derived exactly like a Cryptonote address, but they have an additional payment ID included. There can only be a maximum of one Cryptonote address per view key, referred to as the *main* address, but any number of subaddresses.
268 |
269 | By convention, subaddresses are generated from a "subaddress index", which is a tuple of two 32-bit unsigned integers (jmajor, jminor)
, which allows for 264 addresses. The reason for the distinction between jmajor
and jminor
is simply for UX reasons. The "major" index is used to make separate "accounts" per wallet, which is used to compartmentalize input selection, change outputs, etc. The subaddress index `(0, 0)` is used to designate the main address, even though the key derivation is different. For brevity's sake, we use the label `j` as shorthand for (jmajor, jminor)
and `0` as a shorthand for `(0, 0)`.
270 |
271 | Each Monero address derived from index `j` transmits information (is_main, Ksj, Kvj, pid)
, where `is_main` is a boolean flag which is `true` for Cryptonote addresses, and `false` for subaddresses.
272 |
273 | #### Main address keys
274 |
275 | The two public keys of the main address are constructed as:
276 |
277 | * Ks0 = Ks
278 | * Kv0 = kv G
279 |
280 | #### Subaddress keys (Legacy Hierarchy)
281 |
282 | Under the legacy key hierarchy, the two public keys of the subaddress at index `j` are constructed as:
283 |
284 | * ksub_extj = ScalarDeriveLegacy("SubAddr" \|\| IntToBytes8(0) \|\| kv \|\| IntToBytes32(jmajor) \|\| IntToBytes32(jminor))
285 | * Ksj = Ks + ksub_extj G
286 | * Kvj = kv Ksj
287 |
288 | Notice that generating new subaddresses this way requires knowledge of kv
which necessarily ties the ability to generate subaddresses to the ability to find owned enotes.
289 |
290 | #### Subaddress keys (New Hierarchy)
291 |
292 | Under the new key hierarchy, the two public keys of the subaddress at index `j` are constructed as:
293 |
294 | * sgenj = SecretDerive("Carrot address index generator" \|\| sga \|\| IntToBytes32(jmajor) \|\| IntToBytes32(jminor))
295 | * ksub_scalj = ScalarDerive("Carrot subaddress scalar" \|\| sgenj \|\| Ks \|\| Kv \|\| IntToBytes32(jmajor) \|\| IntToBytes32(jminor))
296 | * Ksj = ksub_scalj Ks
297 | * Kvj = ksub_scalj Kv
298 |
299 | The address index generator sgenj
can be used to prove that the address was constructed from the index `j` and the public keys Ks
and Kv
without revealing sga
. Notice that, unlike the legacy derivation, the new subaddress derivation method does not require the private incoming view key kv
, only the generate-address secret sga
, which allows for private deferred address generation.
300 |
301 | ## Addressing protocol
302 |
303 | ### Transaction global fields
304 |
305 | #### Payment ID
306 |
307 | A single 8-byte encrypted payment ID field is included in non-coinbase transactions for backwards compatibility with integrated addresses. Because only one encrypted payment ID pidenc
is included per transaction, senders can only send to one integrated addresses per transaction. When not sending to a legacy integrated address, `pid` is set to `nullpid`, the payment ID of all zero bytes.
308 |
309 | The payment ID `pid` is encrypted by exclusive or (XOR) with an encryption mask mpid
. The encryption mask is derived from the shared secrets of the payment enote.
310 |
311 | #### Ephemeral public keys
312 |
313 | Every 2-output transaction has one ephemeral public key De
. Transactions with `N > 2` outputs have `N` ephemeral public keys (one for each output). Coinbase transactions always have one key per output.
314 |
315 | ### Input Context
316 |
317 | For each transaction, we assign a value `input_context`, whose purpose is to be unique for every single transaction within a valid ledger. We define this value as follows:
318 |
319 | | transaction type | `input_context` |
320 | |----------------- |-------------------------------------------------- |
321 | | coinbase | "C" \|\| IntToBytes256(block height)
|
322 | | non-coinbase | "R" \|\| first spent key image
|
323 |
324 | This uniqueness is guaranteed by consensus rules: there is exactly one coinbase transaction per block height, and all key images are unique. Indirectly binding output pubkeys to this value helps to mitigate burning bugs.
325 |
326 | ### Enote format
327 |
328 | Each enote represents an amount `a` and payment ID `pid` sent to an address (is_main, Ksj, Kvj)
.
329 |
330 | An enote contains the output public key Ko
, the 3-byte view tag `vt`, the amount commitment Ca
, encrypted Janus anchor anchorenc
, and encrypted amount aenc
. For coinbase transactions, the amount commitment Ca
is omitted and the amount is not encrypted.
331 |
332 | #### The output pubkey
333 |
334 | The output pubkey, sometimes referred to as the "one-time address", is a part of the underlying Rerandomizable RingCT transaction output. Knowledge of the opening of this point allows for spending of the enote. Partial opening knowledge allows for calculating the key image of this enote, signalling in which location it was spent.
335 |
336 | #### Amount commitment
337 |
338 | The amount commitment is also part of the underlying Rerandomizable RingCT transaction output. This Pederson commitment should open up to the decrypted value in aenc
and the blinding factor derived from the shared secret. Coinbase transactions have this field omitted.
339 |
340 | #### Amount
341 |
342 | In non-coinbase transactions, the amount `a` is encrypted by exclusive or (XOR) with an encryption mask ma
. In coinbase transactions, `a` is included as part of the enote in plaintext.
343 |
344 | #### View tags
345 |
346 | The view tag `vt` is the first 3 bytes of a hash of the ECDH exchange with the view key. This view tag is used to fail quickly in the scan process for enotes not intended for the current wallet. The bit size of 24 was chosen as the fixed size because of Jamtis requirements.
347 |
348 | #### Janus anchor
349 |
350 | The Janus anchor `anchor` is a 16-byte encrypted array that provides protection against Janus attacks and small subgroup attacks on the main sender-receiver ECDH. The anchor is encrypted by exclusive or (XOR) with an encryption mask manchor
. In the case of normal transfers, anchor
is uniformly random, and used to re-derive the enote ephemeral private key de
and check the enote ephemeral pubkey De
is constructed properly. In *special* enotes, anchor
is set to an MAC of De
, authenticated by the private view key kv
. Both of these derivation-and-check paths should only pass if either A) the sender constructed the enotes in a way which does not allow for a Janus nor small subgroup attack or B) the sender knows the private view key, in which case they have no need to execute a Janus nor small subgroup attack.
351 |
352 | ### Enote derivations
353 |
354 | The enote components are derived from the shared secrets ssr
and ssrctx
. The definitions of these secrets are described in a later section.
355 |
356 | #### Intermediate Values
357 |
358 | | Symbol | Name | Derivation |
359 | |-----------|--------|-----------|
360 | |ka
|amount commitment blinding factor| ka = ScalarDerive("Carrot commitment mask" \|\| ssrctx \|\| a \|\| Ksj \|\| enote_type)
|
361 | |kgo
|output pubkey extension G| kgo = ScalarDerive("Carrot key extension G" \|\| ssrctx \|\| Ca)
|
362 | |kto
|output pubkey extension T| kto = ScalarDerive("Carrot key extension T" \|\| ssrctx \|\| Ca)
|
363 | |manchor
|encryption mask for `anchor`| manchor = SecretDerive("Carrot encryption mask anchor" \|\| ssrctx \|\| Ko)[:16]
|
364 | |ma
|encryption mask for `a`| ma = SecretDerive("Carrot encryption mask a" \|\| ssrctx \|\| Ko)[:8]
|
365 | |mpid
|encryption mask for `pid`| mpid = SecretDerive("Carrot encryption mask pid" \|\| ssrctx \|\| Ko)[:8]
|
366 | |anchornorm
|janus anchor, normal| anchornorm = RandBytes(16)
|
367 | |anchorsp
|janus anchor, special| anchorsp = SecretDerive("Carrot janus anchor special" \|\| De \|\| input_context \|\| Ko \|\| kv)[:16]
|
368 | |de
|ephemeral private key| de = ScalarDerive("Carrot sending key normal" \|\| anchornorm \|\| input_context \|\| Ksj \|\| pid)
|
369 |
370 | The variable `enote_type` is `"payment"` or `"change"` depending on the human-meaningful tag that a sender wants to express to the recipient. However, `enote_type` must be equal to `"payment"` for coinbase enotes.
371 |
372 | #### Component Values
373 |
374 | | Symbol | Name | Derivation |
375 | |----------------------------------|-----------------------|------------|
376 | |Ko
| output pubkey | Ko = Ksj + kgo G + kto T
|
377 | |Ca
| amount commitment | Ca = ka G + a H
|
378 | |aenc
| encrypted amount | aenc = IntToBytes64(a) ⊕ ma
|
379 | |`vt` |view tag | vt = SecretDerive("Carrot view tag" \|\| ssr \|\| input_context \|\| Ko)[:3]
|
380 | |anchorenc
|encrypted Janus anchor | anchorenc = (anchorsp if special enote, else anchornorm) ⊕ manchor
|
381 | |pidenc
|encrypted payment ID | pidenc = pid ⊕ mpid
|
382 |
383 | The view tag binds to `input_context` so that an external observer (i.e. someone without knowledge of ssr
) cannot simply copy De
, Ko
, and `vt` into a new transaction to force a view tag match. Binding to `input_context` causes the view tag of a copied enote to match with the same probability as any random, unrelated enote.
384 |
385 | ### Ephemeral public key
386 |
387 | The ephemeral pubkey De
, a Curve25519 point, for a given enote is constructed differently based on what type of address one is sending to, how many outputs are in the transaction, and whether we are deriving on the internal or external path. Here "special" means an *external self-send* enote in a 2-out transaction. "Normal" refers to non-special, external enotes.
388 |
389 | | Transfer Type | De
Derivation |
390 | |--------------------------|----------------------------------------------------------------------|
391 | | Normal, to main address | de B
|
392 | | Normal, to subaddress | de ConvertPointE(Ksj)
|
393 | | Internal | random element of 𝔾M |
394 | | Special | Deother
|
395 |
396 | Deother
refers to the ephemeral pubkey that would be derived on the *other* enote in a 2-out transaction. If both enotes in a 2-out transaction are "special", then no specific derivation of De
is required, and De
should be set to a random element of 𝔾M.
397 |
398 | ### Sender-receiver shared secrets
399 |
400 | The shared secrets ssr
and ssrctx
are used to encrypt/extend all components of Carrot transactions. Most components (except the view tag for performance reasons) use ssrctx
to encrypt components.
401 |
402 | ssr
is derived the following ways:
403 |
404 | | | Derivation |
405 | |---------------------- | -------------------------------------------------------------------|
406 | |Sender, external |de ConvertPointE(Kvj
) |
407 | |Recipient, external |kv De
|
408 | |Internal |svb
|
409 |
410 | Then, ssrctx
is derived as ssrctx = SecretDerive("Carrot sender-receiver secret" \|\| ssr \|\| De \|\| input_context)
.
411 |
412 | ### Janus outputs
413 |
414 | In case of a Janus attack, the recipient will derive different values of the enote ephemeral pubkey De
and Janus `anchor`, and thus will not recognize the output.
415 |
416 | ### Self-send enotes
417 |
418 | Self-send enotes are any enote created by the wallet that the enote is also destined to.
419 |
420 | #### Internal enotes
421 |
422 | Enotes which are destined for the sending wallet and use a symmetric secret instead of a ECDH exchange are called "internal enotes". The most common type are `"change"` enotes, but internal `"payment"` enotes are also possible. For typical 2-output transactions, an internal enote reuses the same value of De
as the other enote.
423 |
424 | As specified above, these enotes use svb
as the value for ssr
. The existence of internal enotes means that we have to effectively perform *two* types of balance recovery scan processes, external ssr
and internal ssr
. Note, however, that this does not necessarily make balance recovery twice as slow since one scalar-point multiplication and multiplication by eight in Ed25519 is significantly (~100x) slower than Blake2b hashing, and we get to skip those operations for internal scanning.
425 |
426 | #### Special enotes
427 |
428 | Special enotes are external self-send enotes in a 2-out transaction. The sender employs different shared secret derivations and Janus anchor derivations than a regular external enote.
429 |
430 | #### Mandatory self-send enote rule
431 |
432 | Every transaction that spends funds from the wallet must produce at least one self-send (not necessarily internal) enote, typically a change enote. If there is no change left, an enote is added with a zero amount. This ensures that all transactions relevant to the wallet have at least one output. This allows for remote-assist "light weight" wallet servers to serve *only* the transactions relevant to the wallet, including any transaction that has spent key images. This rule also helps to optimize full wallet multi-threaded scanning by reducing state reuse.
433 |
434 | #### One payment, one change rule
435 |
436 | In a 2-out transaction with two internal or two special enotes, one enote's `enote_type` must be `"payment"`, and the other `"change"`.
437 |
438 | In 2-out transactions, the ephemeral pubkey De
is shared between enotes. `input_context` is also shared between the two enotes. Thus, if the two destination addresses share the same private view key kv
in a 2-out transaction, then ssrctx
will be the same and the derivation paths will lead both enotes to have the same output pubkey, which is A) not allowed, B) bad for privacy, and C) would burn funds if allowed. However, note that the output pubkey extensions kgo
and kto
bind to the amount commitment Ca
which in turn binds to `enote_type`. Thus, if we want our two enotes to have unique derivations, then the `enote_type` needs to be unique.
439 |
440 | ### Coinbase transactions
441 |
442 | Coinbase transactions are not considered to be internal.
443 |
444 | Miners should continue the practice of only allowing main addresses for the destinations of coinbase transactions in Carrot. This is because, unlike normal enotes, coinbase enotes do not contain an amount commitment, and thus scanning a coinbase enote commitment has no "hard target". If subaddresses can be the destinations of coinbase transactions, then the scanner *must* have their subaddress table loaded and populated to correctly scan coinbase enotes. If only main addresses are allowed, then the scanner does not need the table and can instead simply check whether Ks0 ?= Ko - kgo G + kto T
.
445 |
446 | ## Balance recovery
447 |
448 | ### Enote Scan
449 |
450 | The enote scan process is a function which takes public enote information and returns successfully or not. If this enote scan returns successfully, we will be able to recover the address spend pubkey, amount, payment ID, and enote type. Additionally, a successful return guarantees that A) the enote is uniquely addressed to our account, B) Janus attacks are mitigated, and C) burning bug attacks due to duplicate output pubkeys are mitigated. Note, however, that a successful return does *NOT* guarantee that the enote is spendable (i.e. that the recipient will be able to recover `x, y` such that Ko = x G + y T
).
451 |
452 | The following values are part of the enote, and thus public: input_context, De, Ko, Ca, aenc, vt, anchorenc, pidenc
. By contrast, the following values are private to each scanner: kv, svb, and Ks
. For readability, we will denote public values with an underline in this section.
453 |
454 | We perform the scan process once with ssr = kv De
(external), and once with ssr = svb
(internal) if using the new key hierarchy.
455 |
456 | 1. Let vt' = SecretDerive("Carrot view tag" \|\| ssr \|\| input_context \|\| Ko)[:3]
457 | 1. If vt' ≠ vt
, then ABORT
458 | 1. Let ssrctx = SecretDerive("Carrot sender-receiver secret" \|\| ssr \|\| De \|\| input_context)
459 | 1. Let kgo' = ScalarDerive("Carrot key extension G" \|\| ssrctx \|\| Ca)
460 | 1. Let kto' = ScalarDerive("Carrot key extension T" \|\| ssrctx \|\| Ca)
461 | 1. Let Ksj' = Ko - kgo' G - kto' T
462 | 1. If a coinbase enote and Ksj' ≠ Ks
, then ABORT
463 | 1. Set `enote_type' = "payment"`
464 | 1. If a coinbase enote, then let `a' = a` and jump to step 19
465 | 1. Let ma = SecretDerive("Carrot encryption mask a" \|\| ssrctx \|\| Ko)[:8]
466 | 1. Let a' = BytesToInt64(aenc ⊕ ma)
467 | 1. Let ka' = ScalarDerive("Carrot commitment mask" \|\| ssrctx \|\| a' \|\| Ksj' \|\| enote_type')
468 | 1. Let Ca' = ka' G + a' H
469 | 1. If Ca' == Ca
, then jump to step 19
470 | 1. Set `enote_type' = "change"`
471 | 1. Let ka' = ScalarDerive("Carrot commitment mask" \|\| ssrctx \|\| a' \|\| Ksj' \|\| enote_type')
472 | 1. Let Ca' = ka' G + a' H
473 | 1. If Ca' ≠ Ca
, then ABORT
474 | 1. If Ksj'
is not in the *prime order* cyclic subgroup 𝔾E, then ABORT
475 | 1. If ssr == svb
(i.e. performing an internal scan), then jump to step 35
476 | 1. Let mpid = SecretDerive("Carrot encryption mask pid" \|\| ssrctx \|\| Ko)[:8]
477 | 1. Set pid' = pidenc ⊕ mpid
478 | 1. Let manchor = SecretDerive("Carrot encryption mask anchor" \|\| ssrctx \|\| Ko)[:16]
479 | 1. Let anchor' = anchorenc ⊕ manchor
480 | 1. If Ksj' == Ks
, then let Kbase = G
, else let Kbase = Ksj'
481 | 1. Let de' = ScalarDerive("Carrot sending key normal" \|\| anchor' \|\| input_context \|\| Ksj' \|\| pid')
482 | 1. Let De' = de' ConvertPointE(Kbase)
483 | 1. If De' == De
, then jump to step 35
484 | 1. Set `pid' = nullpid`
485 | 1. Let de' = ScalarDerive("Carrot sending key normal" \|\| anchor' \|\| input_context \|\| Ksj' \|\| pid')
486 | 1. Let De' = de' ConvertPointE(Kbase)
487 | 1. If De' == De
, then jump to step 35
488 | 1. Let anchorsp = SecretDerive("Carrot janus anchor special" \|\| De \|\| input_context \|\| Ko \|\| kv)[:16]
489 | 1. If anchor' ≠ anchorsp
, then ABORT
490 | 1. Return successfully!
491 |
492 | ### Determining spendability and computing key images
493 |
494 | An enote is spendable if the computed nominal address spend pubkey Ksj'
from the enote scan process is one that the recipient knows how to derive. However, the enote scan process does not inform the sender how to derive the subaddress. One method of quickly checking whether a nominal address spend pubkey is derivable, and thus spendable, is a *subaddress table*. A subaddress table maps precomputed address spend pubkeys to their index `j`. Once the subaddress index for an enote is determined, we can begin computing the key image.
495 |
496 | #### Legacy key hierarchy key images
497 |
498 | If `j ≠ 0`, then let ksub_extj = ScalarDeriveLegacy("SubAddr" \|\| IntToBytes8(0) \|\| kv \|\| IntToBytes32(jmajor) \|\| IntToBytes32(jminor))
, otherwise let ksub_extj = 0
.
499 |
500 | The key image is computed as: L = (ks + ksub_extj + kgo) Hp2(Ko)
.
501 |
502 | #### New key hierarchy key images
503 |
504 | If `j ≠ 0`, then let ksub_scalj = ScalarDerive("Carrot subaddress scalar" \|\| sgenj \|\| Ks \|\| Kv \|\| IntToBytes32(jmajor) \|\| IntToBytes32(jminor))
, otherwise let ksub_scalj = 1
.
505 |
506 | The key image is computed as: L = (kgi * ksub_scalj + kgo) Hp2(Ko)
.
507 |
508 | ### Handling key images and calculating balance
509 |
510 | If a scanner successfully scans any enote within a transaction, they should save all those key images indefinitely as "potentially spent". The rest of the ledger's key images can be discarded. Then, the key images for each enote should be calculated. The "unspent" enotes are determined as those whose key images is not within the set of potentially spent key images. The sum total of the amounts of these enotes is the current balance of the wallet, and the unspent enotes can be used in future input proofs.
511 |
512 | ## Security properties
513 |
514 | Below are listed some security properties which are to hold for Carrot. Unless otherwise specified, it is assumed that no participant can efficiently solve the decisional Diffie-Hellman problem in Curve25519 and Ed25519 (i.e. the decisional Diffie-Hellman assumption [[citation](https://crypto.stanford.edu/~dabo/pubs/papers/DDH.pdf)] holds).
515 |
516 | ### Balance recovery security
517 |
518 | The term "honest receiver" below means an entity with certain private key material correctly executing the balance recovery instructions of the addressing protocol as described above. A receiver who correctly follows balance recovery instructions but lies to the sender whether they received funds is still considered "honest". Likewise, an "honest sender" is an entity who follows the sending instructions of the addressing protocol as described above.
519 |
520 | #### Completeness
521 |
522 | An honest sender who sends amount `a` and payment ID `pid` to address (is_main, Ksj, Kvj)
, internally or externally, can be guaranteed that the honest receiver who derived that address will:
523 |
524 | 1. Recover the same a, pid, Ksj, Kvj
525 | 2. Recover `x, y, z` such that Ca = z G + a H
and Ko = x G + y T
526 |
527 | This is to be achieved without any other interactivity.
528 |
529 | #### Spend Binding
530 |
531 | If an honest receiver recovers `x` and `y` for an enote such that Ko = x G + y T
, then it is guaranteed within a security factor that no other entity without knowledge of kps
(or ks
for legacy key hierarchies) will also be able to find `x` and `y`.
532 |
533 | #### Enote Scan Binding
534 |
535 | No two honest receivers using different values of kv
for external scans or svb
for internal scans will both successfully return from the enote scan process given the same enote, even if that enote was constructed dishonestly.
536 |
537 | #### Burning Bug Resistance
538 |
539 | For any Ko
, it is computationally intractable to find two unique values of `input_context` such that an honest receiver will determine both enotes to be spendable. Recall that spendability is determined as whether Ksj' = Ko - kgo G - kto T
is an address spend pubkey that the recipient knows how to derive from their account secrets.
540 |
541 | #### Janus Attack Resistance
542 |
543 | There is no algorithm that, without knowledge of the recipient's private view key kv
, allows a sender to construct an enote using two or more honestly-derived non-integrated addresses which successfully passes the enote scan process when the two addresses where derived from the same account, but fails when the addresses are unrelated.
544 |
545 | More concretely, it is computationally intractable, without knowledge of the recipient's private view key kv
, to construct an external enote which successfully passes the enote scan process such that the recipient's computed nominal address spend pubkey Ksj' = Ko - kgo G - kto T
does not match the shared secret ssr = r ConvertPointE(Kvj')
for some sender-chosen `r`. This narrowed statement makes the informal assumption that using the address view spend pubkey for the Diffie-Hellman exchange and nominally recomputing its correct address spend pubkey leaves no room for a Janus attack.
546 |
547 | ### Unlinkability
548 |
549 | #### Computational Address-Address Unlinkability
550 |
551 | A third party cannot determine if two non-integrated addresses share the same kv
with any better probability than random guessing.
552 |
553 | #### Computational Address-Enote Unlinkability
554 |
555 | A third party cannot determine if an address is the destination of an enote with any better probability than random guessing, even if they know the destination address.
556 |
557 | #### Computational Enote-Enote Unlinkability
558 |
559 | A third party cannot determine if two enotes have the same destination address with any better probability than random guessing, even if they know the destination address.
560 |
561 | #### Computational Enote-Key Image Unlinkability
562 |
563 | A third party cannot determine if any key image is *the* key image for any enote with any better probability than random guessing, even if they know the destination address.
564 |
565 | ### Forward Secrecy
566 |
567 | Forward secrecy refers to the preservation of privacy properties of past transactions against a future adversary capable of solving the elliptic curve discrete logarithm problem (ECDLP), for example a quantum computer. We refer to an entity with this capability as a *SDLP* (Solver of the Discrete Log Problem). We assume that the properties of secure hash functions still apply to SDLPs (i.e. collision-resistance, preimage-resistance, one-way).
568 |
569 | #### Address-Conditional Forward Secrecy
570 |
571 | A SDLP can learn no receiver or amount information about a transaction output, nor where it is spent, without knowing a receiver's public address.
572 |
573 | #### Internal Forward Secrecy
574 |
575 | Even with knowledge of sga
, kps
, kgi
, kv
, a SDLP without explicit knowledge of svb
will not be able to discern where internal enotes are received, where/if they are spent, nor the amounts with any better probability than random guessing.
576 |
577 | ### Indistinguishability
578 |
579 | We define multiple processes by which public value representations are created as "indistinguishable" if a SDLP, without knowledge of public addresses or private account keys, cannot determine by which process the public values were created with any better probability than random guessing. The processes in question are described below.
580 |
581 | #### Transaction output random indistinguishability
582 |
583 | Carrot transaction outputs are indistinguishable from random transaction outputs. The Carrot transaction output process is described earlier in this document. The random transaction output process is modeled as follows:
584 |
585 | 1. Sample r1
and r2
independently from uniform integer distribution `[0, ℓ)`.
586 | 2. Set Ko = r1 G
587 | 3. Set Ca = r2 G
588 |
589 | #### Ephemeral pubkey random indistinguishability
590 |
591 | Carrot ephemeral pubkeys are indistinguishable from random Curve25519 pubkeys. The Carrot ephemeral pubkey process is described earlier in this document. The random ephemeral pubkey process is modeled as follows:
592 |
593 | 1. Sample `r` from uniform integer distribution `[0, ℓ)`.
594 | 2. Set De = r B
595 |
596 | Note that in Carrot ephemeral pubkey construction, since the ephemeral private key de
, unlike the private view-incoming key, is derived from a random secret, without key clamping, multiplying by this unclamped key makes the resultant pubkey indistinguishable from a random pubkey.
597 |
598 | #### Other enote component random indistinguishability
599 |
600 | The remaining Carrot enote components are indistinguishable from random byte strings. The Carrot enote process is described earlier in this document. The random enote byte string process is modeled as follows:
601 |
602 | 1. Sample aenc = RandBytes(8)
603 | 2. Sample anchorenc = RandBytes(16)
604 | 3. Sample vt = RandBytes(3)
605 | 4. Sample pidenc = RandBytes(8)
606 |
607 | ## Credits
608 |
609 | Special thanks to everyone who commented and provided feedback on the original [Jamtis gist](https://gist.github.com/tevador/50160d160d24cfc6c52ae02eb3d17024). Many of the ideas were incorporated in this document.
610 |
611 | A *very* special thanks to @tevador, who wrote up the Jamtis and Jamtis-RCT specifications, which were the foundation of this document, containing most of the transaction protocol math.
612 |
613 | ## Glossary
614 |
615 | - *Amount Commitment* - An elliptic curve point, in the form of a Pederson Commitment [[citation](https://www.getmonero.org/resources/moneropedia/pedersen-commitment.html)], which is used to represent hidden amounts in transaction outputs in RingCT and FCMP++
616 | - *Burning Bug Attack* - An attack where an exploiter duplicates an output pubkey and tricks the recipient into accepting both, even though only one can be spent
617 | - *Coinbase Transaction* - A transaction which has no key images, and plaintext integer amounts instead of amount commitments in its outputs
618 | - *Cryptonote* - A cryptocurrency consensus protocol and addressing scheme which was the foundation for Monero's ledger interactions initially
619 | - *Cryptonote Address* - An address in the form described in the Cryptonote v2 whitepaper
620 | - *Enote* - A transaction output as well as the associated data required to scan it
621 | - *Ephemeral Public Key* - An elliptic curve point associated to transaction outputs in order to hide enote details through a Diffie-Hellman key exchange
622 | - *External Enote* - An enote which was constructed by performing an asymmetric Elliptic Curve Diffie-Hellman key exchange against an address, main or subaddress
623 | - *FCMP++* - A proposed cryptocurrency consensus protocol to upgrade Monero's RingCT consensus protocol
624 | - *Forward Secrecy* - The property of a cryptographic construction that information is hidden from an observer that can efficiently solve the Discrete Logarithm Problem
625 | - *Indistinguishability* - The property of multiple cryptographic constructions that the public values posted cannot be determined to the result of any single construction
626 | - *Input Content* - A unique value associated to each transaction used in the Carrot address protocol derivations to mitigate burning bug attacks
627 | - *Integrated Address* - A main address which additionally contains a payment ID
628 | - *Internal Enote* - An enote which was constructed using a symmetric shared secret, typically the view-balance secret
629 | - *Janus Anchor* - An enote component whose purpose is two fold in mitigating Janus attacks: act as an entropy source for deriving the ephemeral private key or act as an MAC validating the ephemeral pubkey
630 | - *Janus Attack* - An attack where an exploiter constructs an enote partially using two different addresses they suspect to belong to the same user such that the confirmation of that payment confirms the addresses are actually related
631 | - *Key Image* - An elliptic curve point emitted during a Rerandomizable RingCT spend proof, used during balance recovery to determine whether an enote has been spent yet
632 | - *Ledger* - An immutable, append-only list of transactions which is the shared medium of data exchange for different participants of the network
633 | - *Main Address* - same as *Cryptonote Address*
634 | - *MAC* - Message Authentication Code [[citation](https://www.cs.princeton.edu/courses/archive/spr10/cos433/lec9new.pdf)]: some information that verifies that certain key material "authorized" a given message
635 | - *Monero* - A payment network, along with a cryptocurrency *XMR*, that historically utilizes a collection of consensus protocols on its ledger, namely: Cryptonote, RingCT, and FCMP++
636 | - *Payment ID* - An 8 byte array included with transaction data used to differentiate senders
637 | - *Rerandomizable RingCT* - An abstraction of FCMP++ defined in this document that allows the formalization of different security properties without knowledge of the underlying proving system
638 | - *RingCT* - A cryptocurrency consensus protocol that iterated on Cryptonote by introducing hidden amounts by way of amount commitments
639 | - *Self-send Enote* - An enote constructed by wallet intended to be received by the same wallet, either internal or external
640 | - *Special Enote* - An external self-send enote within a 2-output transaction
641 | - *Subaddress* - An address form introduced by Monero contributors which allows for a single wallet to generate an arbitrary number of unlinkable addresses without affecting scanning speed
642 | - *Transaction* - An atomic modification to the ledger containing key images, transaction outputs, and other unstructured data
643 | - *Transaction Output* - A distinct tuple of an elliptic curve point and amount commitment or plaintext amount which is contained in a list in a transaction
644 | - *View Tag* - A small enote component, calculated as a partial hash of the sender-receiver shared key, which is checked early in the balance recovery process to optimize scanning performance
645 | - *Wallet* - A collection of private key data, cached ledger state, and other information which is used to interact with the shared ledger
646 |
647 | ## References
648 |
649 | *INSERT REFERENCES HERE*
650 |
--------------------------------------------------------------------------------
/src/dumb_citations.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | import fileinput
4 | import re
5 | import sys
6 |
7 | """
8 | Converts `[citation](...)` markdown links into numbered `[X](...)` citation links and generates a
9 | reference table replacing the string "*INSERT REFERENCES HERE*".
10 | """
11 |
12 | def parse_citation_links(s, cit_no):
13 | CIT_LINK_PATTERN = r"\[citation\]\((.+?)\)"
14 | links = []
15 | m = re.search(CIT_LINK_PATTERN, s)
16 | while m:
17 | links.append(m.group(1))
18 | repl = f"[{cit_no}](\\1)"
19 | s = re.sub(CIT_LINK_PATTERN, repl, s, count=1)
20 | cit_no += 1
21 | m = re.search(CIT_LINK_PATTERN, s)
22 | return s, links
23 |
24 | def make_reference_table(links):
25 | return '\n'.join('1. ' + link for link in links)
26 |
27 | doc_links = []
28 | cit_no = 1
29 | for line in fileinput.input():
30 | processed_line, line_links = parse_citation_links(line, cit_no)
31 | doc_links.extend(line_links)
32 | cit_no += len(line_links)
33 | if '*INSERT REFERENCES HERE*' in processed_line:
34 | ref_table = make_reference_table(doc_links)
35 | processed_line = processed_line.replace('*INSERT REFERENCES HERE*', ref_table)
36 | print(processed_line, end='')
37 |
--------------------------------------------------------------------------------
/src/dumb_md_enumerate.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | import fileinput
4 | import sys
5 |
6 | """ Only supports ATX-style headers """
7 |
8 | def parse_header(s):
9 | dep = 0
10 | for c in s:
11 | if c != '#':
12 | break
13 | dep += 1
14 | return dep - 1, s[dep:].lstrip()
15 |
16 | header_stack = []
17 |
18 | for line in fileinput.input():
19 | hd, title = parse_header(line)
20 | if hd <= 0:
21 | print(line, end='')
22 | continue
23 | while hd >= len(header_stack):
24 | header_stack.append(0)
25 | header_stack[hd] += 1
26 | del header_stack[hd+1:]
27 | section_str = '.'.join(map(str, header_stack[1:])) + ('.' if len(header_stack) == 2 else '')
28 | print('{} {} {}'.format('#' * (hd + 1), section_str, title), end='')
29 |
--------------------------------------------------------------------------------