Skip to content

Commit

Permalink
xmr: readme updates
Browse files Browse the repository at this point in the history
  • Loading branch information
ph4r05 committed Oct 17, 2018
1 parent ff15b46 commit 62411cd
Showing 1 changed file with 30 additions and 56 deletions.
86 changes: 30 additions & 56 deletions src/apps/monero/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ MAINTAINER = ...

AUTHOR = Dusan Klinec <dusan.klinec@gmail.com>

REVIEWER = ...
REVIEWER = Tomas Susanka <tomas.susanka@satoshilabs.com>,
Jan Pochyla <jan.pochyla@satoshilabs.com>,
Ondrej Vejpustek <ondrej.vejpustek@satoshilabs.com>

ADVISORS =

Expand Down Expand Up @@ -96,21 +98,16 @@ Main high level protocol logic is implemented in `apps/monero/protocol/` directo
The serialization in `apps/monero/xmr/serialize` is the cryptonote serialization format used to serialize data to blockchain.
The serialization was ported from Monero C++. Source comes from the library [monero-serialize].

Serialization scheme was inspired by protobuf serialization scheme. Later it was subject to optimizations as
scheme definition with `FIELDS` attribute was quite memory hungry. Serialization was refactred to specify
fields as a classmethod which is easier to `gc.collect()` after serialization is done compared to static `FIELDS`
which are not easy to deallocate.
Serialization scheme was inspired by protobuf serialization scheme.
Fields are specified as a classmethod which is easier to `gc.collect()` after serialization is done.

```python
@classmethod
def f_specs(cls):
return (("size", SizeT),)
```

Serialization works in `async/wait` manner, uses `reader/writer` interface as protobuf uses.

Moreover the serialization funtionality is encapsulated in so-called Archive object which encapsulates serialization logic.
Archive works in a symmetric way, i.e., the same API is used for serialization and deserialization.
Serialization is synchronous.


### Protocols
Expand All @@ -125,16 +122,20 @@ with Chacha20Poly1305 with unique key (derived from the protocol step, message,

TREZOR builds the signed Monero transaction incrementally, i.e., one UTXO per round trip, one transaction output per roundtrip.

### Protocol wrapping messages
### Protocol workflow

Key image sync and transaction signing protocols are stateful.
Both protocols implement custom workflow managing the protocol state and state transitions explicitly.

Due to the dispatcher design we decided to use wrapping message for the multi-step protocols.
The top wrapping message contains sub-message field for each possible message in the protocol. In this way we can register
one simple dispatcher on the wrapping message and do the sub-message multiplexing in the code, hidden in the abstraction.
Entry to the protocol workflow is passed on the initial protocol message, i.e., only the initial protocol message
is registered via `wire.add()`. The workflow internally manages receiving / sending protocol messages.

Without wrapping message we would have to register each sub-message to the same handler and then de-multiplex it again
in the protocol logic which is error prone and duplicates the code. When changing the flow later it would be prone to errors.
Each finished protocol step specifies the next expected message set which helps to govern protocol state transitions,
i.e., exception is thrown if another message is received as expected.

Responses are not wrapped and each response has own wire ID. Response messages are not registered so we don't need wrapping.
As the protocols implement custom workflow the general package unimport in `wire` is not called which
could lead to memory problems as locally imported packages are not freed from memory on `gc.collect()`.
Thus protocols call unimport manually after processing the protocol messages.

Protobuf messages are following the convention `MoneroXRequest`, `MoneroXAck`.

Expand All @@ -147,7 +148,7 @@ generated by the cold wallet (KI proof).
KI sync is mainly needed to recover from some problem or when using a new hot-wallet (corruption of a wallet file or
using TREZOR on a different host).

The KI protocol has 3 steps. Wrapping message `MoneroKeyImageSyncRequest`.
The KI protocol has 3 steps.

### Init step

Expand All @@ -172,15 +173,8 @@ to the agent/hot-wallet so it can decrypt computed KIs and import it

For detailed description and rationale please refer to the [monero-doc].

TODO

- The wrapping message: `MoneroTransactionSignRequest`.
- The main multiplexor: `apps/monero/protocol/tsx_sign.py`
- The main signing logic is implemented in `apps/monero/protocol/tsx_sign_builder.py`
- State automaton watching correct state transitions: `apps/monero/protocol/tsx_sign_state.py`
- State hold between protocol messages: `apps/monero/protocol/tsx_sign_state_holder.py`. The state is externalized in the
dedicated class so the memory consumption is minimal between round trips.

- The protocol workflow `apps/monero/sign_tx.py`
- The protocol is implemented in `apps/monero/protocol/signing/`

### `MoneroTransactionInitRequest`:

Expand All @@ -191,7 +185,7 @@ After receiving this message:
- The TREZOR prompts user for verification of the destination addresses and amounts.
- Commitments are computed thus later potential deviations from transaction destinations are detected and signing aborts.
- Secrets for HMACs / encryption are computed, TX key is computed.
- Precomputes sub-addresses if needed.
- Precomputes required sub-addresses (init message indicates which sub-addresses are needed).

### `MoneroTransactionSetInputRequest`

Expand All @@ -207,16 +201,16 @@ This message caries permutation on the key images so they are sorted in the desi

### `MoneroTransactionInputViniRequest`

- Step needed to correctly hash all transaction inputs, in the right order computed in the previous step.
- Step needed to correctly hash all transaction inputs, in the right order (permutation computed in the previous step).
- Contains `MoneroTransactionSourceEntry` and `TxinToKey` computed in the previous step.
- TREZOR Computes `tx_prefix_hash` is part of the signed data.


### `MoneroTransactionAllInputsSetRequest`

- Sent after all inputs have been processed.
- Mainly used in the range proof offloading to the host. E.g., in case of batched Bulletproofs with more than 2 transaction outputs.
The message response can carry commitment masks so host can compute range proof correctly.
- Used in the range proof offloading to the host. E.g., in case of batched Bulletproofs with more than 2 transaction outputs.
The message response contains TREZOR-generated commitment masks so host can compute range proof correctly.

### `MoneroTransactionSetOutputRequest`

Expand All @@ -225,11 +219,6 @@ The message response can carry commitment masks so host can compute range proof
- TREZOR computes data related to transaction output, e.g., range proofs, ECDH info for the receiver, output public key.
- In case offloaded range proof is used the request can carry computed range proof.

### `MoneroTransactionRangeSigRequest`

- Optional protocol message that supports more complicated, several round-trips range proof offloading proposals as described in the [monero-doc].
- Not used with the basic range proof offloading where the whole range proof is computed on the host.

### `MoneroTransactionAllOutSetRequest`

Sent after all transaction outputs have been sent to the TREZOR for processing.
Expand Down Expand Up @@ -290,26 +279,6 @@ API provides basic functions for work with scalars and points and Monero specifi
The API is designed in such a way it is easy to work with Ed25519 as there is only one point format which is always
normed to avoid complications when chaining operations such as `scalarmult`s.

### Point normalization

Points in [trezor-core] are normed, i.e., `z=1`.

Normalization is mainly needed after `ge25519_scalarmult`, `ge25519_scalarmult_base_niels`,
which is already done in Monero code in [trezor-crypto].

if the norming is not performed, the operations could not be chained arbitrarily as the result is invalid.

Note:
Point normalization operation is typically performed when compressing coordinate point representation to the 32 B array
as `z` needs to be 1. It requires to compute inversion which is not for free.

On the other hand, the original Monero C++ code typically operates on 32 B keys by
decompressing and compressing it after each result so they are doing normalization in each step, basically.

There are some optimized chunks, e.g., range sig verification, which improves blockchain scanning
(still takes 3 days to verify the blockchain).
Optimized chunks are using different point representations to avoid redundant normalizations but in general cases,
it is not a performance issue for the sake of correct computation, easy development and maintenance.

### Range signatures

Expand All @@ -331,12 +300,17 @@ Using small and easily auditable & testable building blocks, such as ge25519_add
schemes in high level language is, in my opinion, a scalable and secure way to build the system.
Porting all Monero crypto schemes to C would be very time consuming and prone to errors.

Having access to low-level features also speeds up development of new features, such as multisigs / bulletproofs.
Having access to low-level features also speeds up development of new features, such as multisigs.

MLSAG may need to be slightly changed when implementing multisigs
(some preparations have been made already but we will see after this phase starts).

Bulletproof generation and verification is implemented, however the device can handle maximum 2 batched outputs
in the bulletproof due to high memory requirements (more on that in [monero-doc]). If number of outputs is larger
than 2 the offloading to host is required.

Bulletproof implementation is covered by unit tests, the proofs in unittest were generated by the Monero C++
implementation.



Expand Down

0 comments on commit 62411cd

Please sign in to comment.