Technical › Who received?

View tags

One byte that makes wallet scanning much faster

In short

Since August 2022 (hard fork v15), every output carries 1 byte — the view tag = the first byte of Keccak("view_tag" ‖ 8rA ‖ i). The wallet compares this byte first and only on a match (≈1 in 256) does the expensive check. Scanning gets about 40% faster.

The problem

To check whether an output is ours, the wallet does two expensive operations: 8·a·R (one per transaction) and Hs(…)·G + B (one per every output). The latter — a base-point multiplication plus an addition — is a noticeable share of sync time. And 99.99% of the time the answer is "not ours".

The solution

view_tag = Keccak256( "view_tag" ‖ 8·r·A ‖ i )[0]

The sender puts this byte next to the output. The recipient, having computed the shared secret 8·a·R, computes the same hash (cheap: a hash, not a curve operation) and compares the byte. No match — the output is definitely not ours, stop. Match — do the full check (in 1/256 of cases it will turn out to be a coincidence).

10,000 outputsin new blocks view tag matches?1 hash per output ~40 candidatesfull curve check ≈ 9,960 discarded without any curve operation

The cost

One extra byte per output. Privacy barely suffers: the view tag is computed from the shared secret known only to sender and recipient, so to outsiders it's a random byte. The only leak is to someone who knows the view key (e.g. a light-wallet server): the hash lets it discard others' outputs — but it could do that anyway.

In Carrot

In Carrot the view tag grows to 3 bytes and the key exchange moves to X25519 — scanning gets even faster and false positives become ~65,000 times rarer.