AirTags · Volume 2
AirTags Volume 2 — Theory I: BLE Advertising & the Find My Crowd-Sourced Network
The non-connectable advertising PDU, Apple's 0x004C/0x12 Find My data, the rotating NIST P-224 key chain, finder-side ECIES encryption, owner-side query-and-decrypt, and why a plain MAC scan can never follow the tag
2.1 About this Volume
This is the first of three theory volumes (Vols 2–4) and the most cryptography-heavy of the whole series. Vol 1 established the framing: a crowdsourced item tracker is a coin-cell BLE beacon with no GPS and no cellular, located by borrowing the GPS of every nearby phone on its find-network (Vol 1 §2), and Apple Find My is the largest of the four such networks (Vol 1 §3). This volume opens the lid on how the Apple Find My / “offline finding” mechanism actually works, at the level an EE wants: which advertising PDU, which bytes carry what, which curve, which key-derivation function, which encryption mode, and what the system can and cannot prove about your location.
The whole mechanism is a single, elegant trick repeated a few times a second: the tag shouts a rotating elliptic-curve public key into the air; any nearby Apple device that hears it encrypts its own GPS fix to that public key and uploads the ciphertext to Apple, indexed by a hash of the key; later, only the owner — who can recompute the matching private keys — pulls those ciphertexts and decrypts them. Apple stores the reports but holds no private keys and therefore cannot read a single location. That property is the reason the network was politically shippable at billion-device scale, and it is also the exact property that makes detecting an unwanted tag hard (Vol 12) — there is no stable identifier to latch onto.
What this volume covers, and what it defers. Here: the BLE advertising layer (§2), the byte-level Find My advertisement (§3), the rotating P-224 key chain (§4), the finder-side ECIES encryption (§5), the owner-side query-and-decrypt (§6), the zero-knowledge privacy model (§7), and the network-scale / detection consequences (§8). Deferred by design: the separated-state advertising behavior and the anti-stalking sound/alert timing live in Vol 4 (§4.4 here only sketches the state boundary); Ultra-Wideband Precision Finding — a completely separate radio at 6.5–8 GHz — is Vol 3; reusing this exact payload to build your own beacon is Vol 10; and exploiting this advertising signature to find a hidden tag is Vols 11–12. This volume is the shared foundation all of those build on.
Spec-sourced, and proud of the provenance. As of 2026-06-25 no AirTags are on the bench, so nothing here is a live capture. It does not need to be: the protocol is public and exhaustively reverse-engineered. The authoritative public analysis is Heinrich, Stute, Kornhuber & Hollick, “Who Can Find My Devices? Security and Privacy of Apple’s Crowd-Sourced Bluetooth Location Tracking System”, PoPETs / PETS 2021^[Alexander Heinrich, Milan Stute, Tim Kornhuber, Matthias Hollick. Proceedings on Privacy Enhancing Technologies (PoPETs) 2021(3), pp. 227–245. The paper that established the public understanding of Apple’s offline-finding system and the basis of OpenHaystack. DOI: 10.2478/popets-2021-0045.] from TU Darmstadt’s SEEMOO lab — the same work that produced OpenHaystack^[OpenHaystack, seemoo-lab — https://github.com/seemoo-lab/openhaystack. The reference open-source implementation of a Find My beacon + report-decryptor; the firmware and the macOS app are the canonical artifact for every byte-level claim in this volume.], the open-source framework that lets a generic BLE chip impersonate an AirTag and that you will flash yourself in Vol 10. Apple’s own Platform Security guide^[Apple, Apple Platform Security guide, “Find My security” / “Find My network” sections — https://support.apple.com/guide/security/. Apple’s own description of the rotating-key, end-to-end-encrypted design; confirms the cryptographic shape without giving byte offsets.] corroborates the cryptographic shape. Where a precise byte offset or constant matters, this volume states the value from OpenHaystack / PETS 2021 and flags that the source — not a bench capture — is the authority. A live
btmon/sniffer capture pass happens when tags arrive (per the spec’s bench trajectory).
2.2 The BLE advertising substrate
Before any of the Apple-specific structure makes sense, you need the BLE advertising layer it rides on. A Find My advert is, mechanically, an utterly ordinary Bluetooth Low Energy advertisement — the same primitive a fitness band or a beacon uses. Apple invented no new radio layer; it parasitized the most boring corner of the BLE spec, which is half of why the system is so cheap to run on a coin cell (Vol 1 §2.3) and so hard to distinguish from background BLE noise (Vol 12).
2.2.1 Advertising channels and the air interface
BLE (Bluetooth 4.0+, the relevant stack is in the Bluetooth Core Specification^[Bluetooth SIG, Bluetooth Core Specification v5.x, Vol 6 Part B (Link Layer) §2.3 advertising PDUs and §1.4 advertising channels. The PDU-type and address-type semantics cited throughout §2 are from this volume of the spec.]) splits the 2.4 GHz ISM band into 40 channels of 2 MHz each. Three of them — channels 37, 38, 39 at 2402, 2426, and 2480 MHz — are the primary advertising channels, deliberately spaced to dodge the three non-overlapping Wi-Fi channels (1/6/11). A legacy advertiser transmits the same advertising PDU on all three in quick succession (an “advertising event”); a scanner listens on one channel at a time and eventually catches it. This three-channel hop is why a BLE scanner sees the same advert arrive three times in a burst, and why RSSI-walk localization (Vol 12) has to average across them.
An AirTag in the field is a pure advertiser: it never scans, never connects (in the separated state), and spends almost all of its life asleep. It wakes, transmits one advertising event across 37/38/39, and sleeps again. That duty cycle is what stretches a CR2032 to ~1 year (Vol 1 §2.3); the power tree that enforces it is Vol 5.
BLE primary advertising channels (the only three a Find My tag uses)
════════════════════════════════════════════════════════════════════
2400 ────────────────────────────────────────────────────── 2483.5 MHz
│ ┌──┐ │
│ ▓▓│37│▓▓ ┌──┐ ┌──┐ │
──┴───┴──┴──────────┤38├──────────────────────────────┤39├─────┴──
2402 MHz └──┘ 2426 MHz └──┘ 2480 MHz
(data channels 0–36 fill the gaps between)
One "advertising event" = the same PDU sent on 37, then 38, then 39.
A scanner parked on one channel catches it on the next pass.
2.2.2 The non-connectable undirected advert
BLE legacy advertising defines four advertising-PDU types. The choice among them is semantically loaded — it tells every listening device what the advertiser will and will not do. Apple’s offline-finding advert is an ADV_NONCONN_IND: non-connectable, undirected, non-scannable. The link-layer header carries this as PDU type 0b0010. It is the most minimal, lowest-power option in the table: it broadcasts data to anyone, invites no connection, and answers no scan request.
Table 1 — 2.2 The non-connectable undirected advert
| PDU type | Name | Connectable? | Scannable? | Directed? | Find My uses it? |
|---|---|---|---|---|---|
0b0000 | ADV_IND | Yes | Yes | No | No |
0b0001 | ADV_DIRECT_IND | Yes | No | Yes | No |
0b0010 | ADV_NONCONN_IND | No | No | No | Yes (separated state) |
0b0110 | ADV_SCAN_IND | No | Yes | No | No |
The choice is deliberate on every axis. Non-connectable because a finder must never need to pair, handshake, or wake the tag — it just listens, so the tag never has to keep a receiver hot. Undirected because the tag is shouting to the whole world, not to one bonded peer. Non-scannable because there is nothing more to ask for: everything the finder needs is in the single 31-byte advertising payload. This is the cheapest possible BLE transaction, and it is one-directional: the tag transmits, full stop. (In the paired/nearby state — owner’s phone within Bluetooth range — the behavior differs, and a tag can present a connectable face for configuration; that state machine is Vol 4. In the wild, separated from its owner, it is ADV_NONCONN_IND.)
Why “non-connectable” is load-bearing for detection. Because the tag never accepts a connection in the wild, you cannot interrogate it over GATT, read a device-name characteristic, or fingerprint it by its services the way you would a smartwatch. Everything you can learn passively is in the advertisement bytes (§3). This is exactly why detection (Vol 12) is a passive-listening problem keyed on the advertising-data signature, not an active-connection problem — and why the only “active” read of a found tag is over NFC, not BLE (Vol 4, Vol 12).
2.2.3 The random static advertising address
Every BLE advertisement carries a 6-byte (48-bit) advertising address in its header. BLE defines several address types; the two high-order bits of the most-significant address byte encode which type it is. A random static address is signalled by those top two bits being set to 0b11. A random static address is allowed to be any value the device likes (it is “static” only in that it is not supposed to change within a power cycle, by the letter of the spec) — and Apple exploits exactly this freedom.
Here is the first piece of the central trick: the AirTag does not put a real, fixed MAC in the address field. It puts six bytes of its current rotating public key there, with the top two bits forced to 0b11 so the address validates as random-static. So the BLE “MAC address” you see in a scan is part of the cryptographic payload and changes every time the key rotates (~15 min, §4.3). There is no stable hardware identifier on the air at all. We finish reconstructing the full key in §3.3; the consequence for tracking is §8.2.
Table 2 — 2.3 The random static advertising address
| Address type | Top 2 bits of MSB | Meaning | Find My? |
|---|---|---|---|
| Public | (uses separate header flag) | IEEE-assigned OUI + serial | No |
| Random static | 0b11 | Fixed for a power cycle; otherwise arbitrary | Yes — holds key bytes |
| Resolvable private | 0b01 | Rotates; resolvable with an IRK | No |
| Non-resolvable private | 0b00 | Rotates; not resolvable | No |
2.2.4 Manufacturer-specific data and Apple ID 0x004C
The advertising payload is a sequence of length-tagged AD structures, each [length][AD-type][data…]. AD-type 0xFF is Manufacturer Specific Data, and its first two data bytes are a Company Identifier assigned by the Bluetooth SIG, transmitted little-endian. Apple’s company identifier is 0x004C, which appears on the air as the byte pair 4C 00.
This single 0xFF / 4C 00 prefix is the most over-loaded field in consumer BLE. Apple stuffs an entire zoo of sub-protocols behind it — distinguished by a third byte, an Apple-specific type — and they are everywhere: iBeacon, AirDrop, AirPods pairing, Handoff, Nearby, the “Find My” offline-finding advert, and more. The third byte is the demultiplexer.
Table 3 — 2.4 Manufacturer-specific data and Apple ID 0x004C
| Apple type byte | Sub-protocol | Notes |
|---|---|---|
0x02 | iBeacon | UUID + major/minor proximity beacon |
0x05 | AirDrop | short-contact advertisement |
0x07 | AirPods / proximity pairing | the pop-up-to-pair advert |
0x0C | Handoff | continuity between devices |
0x10 | Nearby | iOS activity / state nibble |
0x12 | Find My / offline finding | the AirTag separated-state advert — this volume |
So the full signature a detector keys on (Vol 12) is: an ADV_NONCONN_IND whose payload contains a Manufacturer-Specific-Data structure with company ID 4C 00 and Apple type 0x12. That triplet — FF, 4C 00, 12 — is the Find My fingerprint. Everything after it is the offline-finding-specific structure of §3.
2.3 The Find My advertisement, byte by byte
We now assemble the complete separated-state advertisement. The single best public reference for the exact bytes is the OpenHaystack firmware, whose advertising template is the de-facto specification for everyone outside Apple; the PETS 2021 paper documents the same structure analytically. The byte offsets and constants below are quoted from those sources.
2.3.1 Apple data type 0x12
The Find My AD structure sits inside the 0xFF Manufacturer-Specific-Data block, immediately after the 4C 00 company ID. It opens with the Apple type 0x12 and an Apple-internal length byte (0x19 = 25 decimal — the number of payload bytes that follow within this Apple sub-structure). After that come the offline-finding fields: a status byte, the bulk of the public key, the two recovered high bits of key byte 0, and a trailing hint byte. The total on-air AD payload is 31 bytes (a leading BLE length byte of 0x1E = 30, then 30 bytes).
2.3.2 The payload byte layout
This is the required byte-layout table. Offsets are within the advertising-data payload (the bytes after the BLE PDU header / advertising address). The 28-byte EC public key is split: byte 0 is reconstructed from two places, bytes 1–5 ride in the advertising address, and bytes 6–27 are inline here.
Table 4 — 3.2 The payload byte layout
| Offset | Len | Field | Value / contents | Source of authority |
|---|---|---|---|---|
| 0 | 1 | AD length | 0x1E (30 bytes follow) | BLE AD framing |
| 1 | 1 | AD type | 0xFF (Manufacturer Specific Data) | BLE Core Spec |
| 2–3 | 2 | Company ID | 4C 00 (Apple 0x004C, little-endian) | Bluetooth SIG assignment |
| 4 | 1 | Apple type | 0x12 (Find My / offline finding) | OpenHaystack / PETS 2021 |
| 5 | 1 | Apple length | 0x19 (25 bytes follow in this sub-structure) | OpenHaystack |
| 6 | 1 | Status byte | battery / maintained-state flags (0x00 on OpenHaystack) | OpenHaystack / PETS 2021 |
| 7–28 | 22 | Public key bytes [6 … 27] | the bulk of the advertised EC key | OpenHaystack |
| 29 | 1 | Public key byte 0, bits 6–7 | the two MSBs of key[0] (key[0] >> 6) | OpenHaystack |
| 30 | 1 | Hint byte | 0x00 in the separated/standalone case | OpenHaystack |
The arithmetic checks out: the Apple length 0x19 (25) covers offsets 6–30 inclusive — status (1) + key bytes 6–27 (22) + the recovered-high-bits byte (1) + the hint (1) = 25.
Treat the exact offsets as OpenHaystack/PETS, not gospel from a bench. The structure above is solid and reproduced across every public implementation, but Apple has never published a byte map, the status/hint byte semantics are partly inferred, and Apple has tweaked details across iOS releases. When tags reach the bench, a
btmon/nRF-sniffer capture (Vol 12 documents the toolchain) confirms the live layout. Until then: structure correct, individual byte semantics per the cited sources.
2.3.3 The split public key
The advertised object is a 28-byte elliptic-curve public key — specifically the 224-bit ($28 \times 8 = 224$) X-coordinate of a point on NIST P-224 (§4.1). It does not fit in the 31-byte advertising payload alongside all the framing, so Apple splits it across the advertising address and the payload, and recovers the two bits it has to sacrifice to the address-type field:
Reconstructing the 28-byte P-224 public key from one advertisement
══════════════════════════════════════════════════════════════════
BLE advertising ADDRESS (6 bytes, "random static")
┌────────┬────────┬────────┬────────┬────────┬────────┐
│ addr[0]│ addr[1]│ addr[2]│ addr[3]│ addr[4]│ addr[5]│
│ 11▒▒▒▒▒▒│ key[1] │ key[2] │ key[3] │ key[4] │ key[5] │
└───┬────┴───┬────┴────────┴────────┴────────┴────────┘
│ └──────────────► key[1..5] (5 bytes, verbatim)
│
│ top 2 bits forced to 0b11 (random-static marker) ──┐
└─ low 6 bits = key[0] bits 0..5 │
│
ADV PAYLOAD offset 29 ── key[0] bits 6..7 ────────────────┘
│
OR them together ──► key[0] (full byte)
ADV PAYLOAD offset 7..28 ──────────────────► key[6..27] (22 bytes)
key[0] (recombined) + key[1..5] (addr) + key[6..27] (payload)
= 28-byte P-224 public key
The receiver’s job is the inverse: take the six address bytes, mask off the top two bits of addr[0] and replace them with the two bits stored at payload offset 29 to recover the true key[0]; take key[1..5] straight from addr[1..5]; take key[6..27] from payload offsets 7–28; concatenate to get the 28-byte key. That key is the public half of the tag’s current rotating keypair $P_i$ (§4), and its SHA-256 hash is the index everyone uses to file and find reports (§5, §6).
2.3.4 The status and hint bytes
Two single-byte fields bracket the key and are the least-documented part of the advert. The status byte (offset 6) encodes the tag’s self-reported condition — most usefully a coarse battery level in its high bits, plus maintained/nearby state flags. OpenHaystack transmits 0x00 because a DIY beacon has nothing meaningful to report; a real AirTag populates it. The hint byte (offset 30) is 0x00 in the standalone separated case; its non-zero values relate to the owner-device/connected context and are not needed to recover the key or a location. Neither byte is required to decrypt a report — they are advisory — but a detector can read the battery nibble of a found tag passively, which is occasionally useful triage (Vol 12).
2.3.5 An annotated hexdump
Here is a complete separated-state Find My advertising frame as it would appear in a sniffer log, annotated field by field. The key bytes are filler (AA… for the address-resident bytes, BB… for the payload-resident bytes) to make the split legible; a real key is 28 random-looking bytes.
# ── BLE link-layer header (from the sniffer / btmon) ──
PDU type : ADV_NONCONN_IND (0b0010) # non-connectable, undirected
TxAdd : 1 (random address)
AdvA : C1 A1 A2 A3 A4 A5 # "address" = top-bits-set key[0] + key[1..5]
▲▲
└┴── 0xC1 = 0b11_000001 : top 2 bits = random-static marker;
low 6 bits = key[0] bits 0..5
# ── Advertising-data payload (31 bytes) ──
1E # [0] AD length = 30
FF # [1] AD type = Manufacturer Specific Data
4C 00 # [2-3] Company ID = 0x004C (Apple, little-endian)
12 # [4] Apple type = 0x12 (Find My / offline finding)
19 # [5] Apple length = 25
00 # [6] Status byte (battery/maintained flags; 0x00 here)
BB BB BB BB BB BB BB BB # [7-28] Public key bytes 6..27 (22 bytes)
BB BB BB BB BB BB BB BB
BB BB BB BB BB BB
02 # [29] key[0] bits 6..7 -> key[0] = (0x02<<6)|(0xC1&0x3F)
00 # [30] Hint byte (0x00, standalone separated case)
# ── Reconstructed public key (28 bytes) ──
# key[0] = (payload[29] << 6) | (AdvA[0] & 0x3F) = (0x02<<6)|0x01 = 0x81
# key[1-5] = AdvA[1..5] = A1 A2 A3 A4 A5
# key[6-27]= payload[7..28] = BB * 22
# index = SHA-256( 28-byte key ) -> the server lookup id (see §5, §6)
Reading that frame is the entire passive-detection primitive. A scanner that sees FF 4C 00 12 … knows it is looking at a Find My tag; it can recover the current public key and hash it; but — crucially — it learns nothing else, and the key it recovered will be gone in ~15 minutes (§4.3, §8.2).
2.4 The rotating P-224 key scheme
The advertisement carries a public key; this section is where that key comes from, why it rotates, and how the owner can predict the whole sequence while no one else can. This is the cryptographic heart of Find My.
2.4.1 Why NIST P-224
The curve is NIST P-224, equivalently secp224r1 — a 224-bit prime-field Weierstrass curve. It is a slightly unusual choice in 2026 (most new designs reach for Curve25519 / P-256), and the reason is almost certainly size on the air. A P-224 public key’s X-coordinate is exactly 28 bytes / 224 bits, which is the largest EC key that fits the offline-finding split of §3.3 inside a single legacy 31-byte BLE advertisement. A P-256 key would need 32 bytes for X alone and would not fit the address+payload budget without a second advertising frame. P-224 buys ~112-bit security — more than adequate for a location-privacy beacon whose keys live only ~15 minutes — in the smallest standard curve that clears it.
Table 5 — 4.1 Why NIST P-224
| Parameter | Value (NIST P-224 / secp224r1) |
|---|---|
| Field | prime $p = 2^{224} - 2^{96} + 1$ |
| Coordinate size | 28 bytes (224 bits) — sets the advert key size |
| Group order | $n$ (224-bit prime), the modulus for scalar math (§4.2) |
| Approx. security | ~112-bit |
| Public key on the air | 28-byte X-coordinate (split per §3.3) |
| Why not P-256 | 32-byte X would overflow the single-advert budget |
| Why not Curve25519 | not the form Apple’s scalar-diversification scheme uses |
2.4.2 The key-derivation chain
At pairing time (when you set up a tag, an interaction covered operationally in Vol 6), the owner’s device and the tag agree on the secret material that seeds everything: an initial symmetric secret $SK_0$ and a master beacon keypair $(d_0, P_0)$ where $P_0 = d_0 \cdot G$ on P-224. The tag stores enough to run the chain forward; the owner stores enough to recompute it. From then on the advertised keypair is deterministically derived per interval $i$ and never transmitted in private form.
The chain has two layers — a symmetric ratchet that produces per-interval secrets, and a scalar diversification that turns each secret into the actual advertising keypair^[The two-stage scheme — symmetric ratchet via ANSI X9.63 KDF (SHA-256), then scalar diversification $d_i = (d_0 \cdot u_i + v_i) \bmod n$ — is documented in Heinrich et al. (PETS 2021) §3 and implemented in OpenHaystack’s key-generation tooling. The KDF labels and exact concatenation are per those sources.]:
The Find My key-derivation chain (per advertising interval i)
════════════════════════════════════════════════════════════
pairing seed: SK0 , master keypair (d0, P0 = d0·G)
│
▼ symmetric ratchet (one step per interval)
SK0 ──KDF──► SK1 ──KDF──► SK2 ──KDF──► … ──► SKi
(SKi = ANSI-X9.63-KDF(SK(i-1), label="update", 32 bytes))
│
▼ scalar diversification
(ui, vi) = X9.63-KDF(SKi, label="diversify", 72B)
│ split into two 224-bit ints
▼
di = ( d0 · ui + vi ) mod n ← private key, interval i
Pi = di · G ← PUBLIC key, advertised
│
▼
advert(i) carries Pi ; report index = SHA-256(Pi)
The two properties that make this work are worth stating plainly:
- Forward secrecy of the ratchet. $SK_i$ is a one-way KDF output of $SK_{i-1}$. Recovering one interval’s symmetric secret does not reveal earlier ones. An attacker who somehow extracts $SK_i$ cannot roll the chain backward.
- Owner-only predictability. Only a party holding $d_0$ and $SK_0$ can compute $d_i$ (you need $d_0$ for the $d_0 \cdot u_i$ term). The tag advertises $P_i$ and could compute $d_i$ for itself, but it never transmits $d_i$; a finder or Apple sees only $P_i$. So only the owner can later decrypt, because only the owner can reconstruct the private key $d_i$ (§6).
Table 6 — 4.2 The key-derivation chain
| Symbol | What it is | Who can compute it | On the air? |
|---|---|---|---|
| $SK_0$ | initial symmetric secret (pairing) | tag, owner | No |
| $SK_i$ | per-interval symmetric secret (ratchet) | tag, owner | No |
| $(d_0, P_0)$ | master keypair (pairing) | tag, owner ($d_0$); $P_0$ derivable | No |
| $u_i, v_i$ | diversification scalars from $SK_i$ | tag, owner | No |
| $d_i$ | interval private key $=(d_0 u_i + v_i)\bmod n$ | tag, owner | No |
| $P_i = d_i G$ | interval public key | anyone who hears the advert | Yes |
| $\text{SHA-256}(P_i)$ | the report index | anyone with $P_i$ | derived |
In pseudocode, the owner-side regeneration of an interval keypair (the operation Vol 10 runs in OpenHaystack to make a beacon, and §6 runs to fetch reports):
# Owner-side: regenerate the keypair for interval i (P-224, illustrative)
# Authority: PETS 2021 §3 + OpenHaystack key-gen. Labels/encoding per those.
def kdf_x963(secret, label, out_len):
# ANSI X9.63 KDF with SHA-256: hash(secret || counter || label), concatenated
return ansi_x963_sha256(secret, shared_info=label, length=out_len)
def derive_interval(SK_prev, d0, n, G):
SK_i = kdf_x963(SK_prev, b"update", 32) # ratchet one step
uv = kdf_x963(SK_i, b"diversify", 72) # 2 * 36 bytes
u_i = int.from_bytes(uv[:36], "big") % n
v_i = int.from_bytes(uv[36:], "big") % n
d_i = (d0 * u_i + v_i) % n # interval private key
P_i = scalar_mult(d_i, G) # interval public key (advertised)
return SK_i, d_i, P_i
def index_of(P_i):
return sha256(P_i.x.to_bytes(28, "big")) # 28-byte X-coord -> report id
2.4.3 The rotation timeline
The advertised key $P_i$ changes roughly every 15 minutes while the tag is paired and in range of its owner — the PETS 2021 measurement and the value OpenHaystack/Macless-Haystack target. Each 15-minute slot advertises one key; over a day a tag burns through ~96 keys; over a week, ~672. Because the BLE address is part of the key (§3.3), the address rotates on the same 15-minute cadence — there is no underlying stable MAC that survives the rotation.
Key-rotation timeline (paired / in-range; ~15-min interval)
═══════════════════════════════════════════════════════════
t → 00:00 00:15 00:30 00:45 01:00 01:15
├──────────┼──────────┼──────────┼──────────┼──────────┤
key │ P0 │ P1 │ P2 │ P3 │ P4 │ …
addr │ addr(P0) │ addr(P1) │ addr(P2) │ addr(P3) │ addr(P4) │ …
└──────────┴──────────┴──────────┴──────────┴──────────┘
▲ each slot = a different 28-byte key = a different BLE address
▲ finder files reports under SHA-256(Pi) for whichever slot it heard
▲ owner recomputes P0..Pn for the whole window and queries every hash
A scanner watching one spot sees: A1A2.. then (15 min) D4E1.. then ...
— looks like a parade of DIFFERENT devices. (Detection problem: §8.2)
The owner does not have to be online or near the tag for this to work — the tag rotates autonomously on its own clock, and the owner recomputes the same sequence offline whenever they want to look (§6.1). The two clocks must merely agree on the interval boundaries, which they do because both derive the interval index $i$ from the same wall-clock epoch.
Anti-stalking posture — the rotation is also a stalker’s friend, which is the whole problem. The 15-minute key/address rotation is a genuine privacy win against third-party tracking of the owner — no one can follow you by your tag’s MAC. But it is exactly what makes a tag hidden in a victim’s bag hard to detect, because the victim’s phone also sees a churn of addresses and cannot trivially tell “one tag has followed me for an hour” from “a parade of strangers’ phones.” That tension is the bridge into the counter-surveillance half (Vol 4 sets up the separated-state behavior detectors exploit; Vols 11–12 are the detection workflows). This series is authored defensively — understanding and detection, never covert tracking; see
_shared/legal_ethics.md.
2.4.4 Paired versus separated state
Everything above describes the tag’s behavior in the wild, separated from its owner. The full picture is a small state machine: paired/nearby (owner’s device within BLE range — the tag and phone interact, advertising and connectability differ, and the anti-stalking clock is not running) versus separated (owner out of range for some threshold — the tag begins the offline-finding ADV_NONCONN_IND advertising of §2–§3, and after a delay starts the unwanted-tracking sound/alert behavior). The transition timing, the separated-state advertising changes, and the DULT anti-stalking sound are Vol 4’s subject — they are the literal bridge from the tracker half to the detection half, and duplicating them here would pre-empt that volume. For this volume it is enough to know: the byte-level advert of §3 and the key chain of §4 are the separated-state mechanism, and that is the state a hidden, unwanted tag spends its time in.
[FIGURE SLOT — Vol 2, § 4.4] A generic nRF52-series BLE module (e.g. an nRF52832 or nRF52840 dev/USB-dongle board) on a neutral surface — the silicon class that both Apple’s AirTag (nRF52832, per the teardown in Vol 5) and a DIY OpenHaystack beacon (Vol 10) are built on. Photographing the generic module keeps this license-clean and ties the abstract advertising theory to the real radio that emits it. Source: Photo Helper Commons search “nRF52840 dongle” / “nRF52832 module” (generic component class — CC-licensed). Caption when filled: “Figure 2.1 — A generic Nordic nRF52-class BLE module, the radio class that transmits the Find My advertisement dissected in §3 (the AirTag uses an nRF52832; an OpenHaystack beacon can use any nRF52). Photo: File:Name.jpg by
. . Via Wikimedia Commons.”
2.5 The finder path: encrypted, anonymous reports
A finder is any nearby Apple device — someone’s iPhone in a pocket, an iPad on a desk, a Mac (~1 billion of them, §8.1) — running the Find My daemon. It needs no app, no opt-in beyond the default network participation, and no knowledge of whose tag it is hearing. When it hears a Find My advert, it does a small, fixed amount of crypto and uploads one ciphertext. This is the step where location enters the system, and it is encrypted before it ever leaves the finder’s phone.
2.5.1 ECIES on P-224
The finder encrypts its location to the tag’s advertised public key $P_i$ using ECIES — the Elliptic Curve Integrated Encryption Scheme, a standard hybrid construction: an ephemeral ECDH key agreement to derive a one-time symmetric key, then authenticated symmetric encryption (AES-128-GCM) of the payload. Apple’s instantiation^[ECIES parameters — ephemeral ECDH on P-224, ANSI X9.63 KDF with SHA-256 keyed by the ephemeral public key, AES-GCM with a 16-byte tag — are documented in Heinrich et al. (PETS 2021) §3 and implemented in the OpenHaystack report-decryptor. AES key/IV split from the 32-byte KDF output is per the OpenHaystack implementation.]:
- Curve / agreement: ephemeral ECDH on NIST P-224. The finder generates a fresh ephemeral keypair $(d_e, P_e)$ per report.
- KDF: ANSI X9.63 KDF with SHA-256, with the ephemeral public key $P_e$ as the shared-info input, producing 32 bytes → split into a 16-byte AES key and a 16-byte IV/nonce.
- Cipher: AES-GCM (authenticated) over the location payload, producing ciphertext + a 16-byte authentication tag.
The defining feature is ephemerality: the finder’s long-term identity never touches the report. It mints a throwaway keypair, uses it once, attaches only the public ephemeral part to the report, and discards the private part. That is why the finder is anonymous — there is nothing in the uploaded report that links back to the finder’s Apple ID or device. Apple gets a ciphertext from “somewhere” with a self-contained ephemeral public key and cannot attribute it.
2.5.2 The encryption steps
This is the required ECIES encryption-step table — the exact sequence the finder runs, with the cryptographic primitive and the authority for each step.
Table 7 — 5.2 The encryption steps
| # | Step | Operation | Output | Authority |
|---|---|---|---|---|
| 1 | Recover key | Reassemble 28-byte $P_i$ from advert (address + payload) | $P_i$ (public point) | §3.3 |
| 2 | Ephemeral keygen | Generate fresh P-224 keypair | $(d_e,\ P_e)$ | PETS 2021 |
| 3 | ECDH | $S = d_e \cdot P_i$ (shared point) | shared secret (X-coord) | PETS 2021 |
| 4 | KDF | ANSI X9.63-KDF$_{\text{SHA-256}}(S_x,\ \text{sharedinfo}=P_e)$ → 32 B | 16 B AES key ‖ 16 B IV | OpenHaystack |
| 5 | Take fix | Read finder’s own GPS lat/lon + accuracy | location payload (plaintext) | PETS 2021 |
| 6 | Encrypt | AES-GCM(key, IV, payload) | ciphertext + 16 B tag | OpenHaystack |
| 7 | Assemble | $P_e$ ‖ ciphertext ‖ tag (+ timestamp/confidence) | encrypted report | §5.3 |
| 8 | Index | $\text{idx} = \text{SHA-256}(P_i)$ | server lookup key | §6.2 |
| 9 | Upload | POST {idx, encrypted report, timestamp} to Apple | (anonymous) | §5.3 |
The finder never learns the tag’s location is its own location-minus-a-few-meters; it never learns whose tag it is; it never keeps a copy; and Apple, receiving the upload, holds a ciphertext it cannot open. In pseudocode:
# Finder-side: encrypt this device's GPS fix to the tag's advertised key P_i
# Authority: PETS 2021 §3 + OpenHaystack. P-224 throughout.
def finder_encrypt(P_i_bytes, my_lat, my_lon, accuracy):
P_i = point_decompress_x(P_i_bytes) # 28-byte X -> curve point
d_e, P_e = gen_keypair_p224() # fresh ephemeral keypair
S = scalar_mult(d_e, P_i) # ECDH shared point
derived = kdf_x963(S.x.to_bytes(28,"big"), # ANSI X9.63 / SHA-256
shared_info=serialize(P_e), out_len=32)
aes_key, iv = derived[:16], derived[16:]
payload = pack_location(my_lat, my_lon, accuracy) # ~10 bytes (see §5.3)
ct, tag = aes_gcm_encrypt(aes_key, iv, payload)
report = serialize(P_e) + ct + tag # self-contained, anonymous
idx = sha256(P_i_bytes) # server index
upload(idx, report, timestamp=now()) # POST to Apple; no finder id
2.5.3 The uploaded report
The object that lands on Apple’s servers is a small, opaque blob filed under the key hash. Its public structure (from the OpenHaystack decryptor, which parses exactly what Apple returns) is approximately^[Report layout — 4-byte timestamp, 1-byte confidence, 57-byte ephemeral P-224 public key (uncompressed: 04 ‖ 28-byte X ‖ 28-byte Y), encrypted payload, 16-byte GCM tag — is the structure parsed by the OpenHaystack/Macless-Haystack report decryptors. Field sizes per those implementations.]:
Table 8 — The object that lands on Apple's servers is a small, opaque blob filed under the key hash. Its public structure (from the OpenHaystack decryptor, which parses exactly what Apple returns) is approximately^[Report layout — 4-byte timestamp, 1-byte confidence, 57-byte ephemeral P-224 public key (uncompressed: 04 ‖ 28-byte X ‖ 28-byte Y), encrypted payload, 16-byte GCM tag — is the structure parsed by the OpenHaystack/Macless-Haystack report decryptors. Field sizes per those implementations.]
| Field | Size | Contents | Encrypted? |
|---|---|---|---|
| Timestamp | 4 B | when the finder heard the tag | No (metadata) |
| Confidence | 1 B | finder’s confidence in the fix | No (metadata) |
| Ephemeral public key $P_e$ | 57 B | uncompressed P-224 point (04 ‖ X ‖ Y) | No (needed for ECDH) |
| Encrypted payload | ~10 B | the location ciphertext | Yes |
| GCM auth tag | 16 B | AES-GCM integrity tag | (authenticator) |
The plaintext inside the ~10-byte payload, once the owner decrypts it (§6.3), is the finder’s latitude and longitude (each a signed 32-bit integer, scaled — degrees × 10⁷), plus an accuracy/horizontal-uncertainty byte and a status byte. That is the entire location: the finder’s position at the moment it heard the tag, which — since BLE range is tens of metres — is a good proxy for the tag’s position. The tag itself never computed a position; it only shouted a key (Vol 1 §2.2, restated cryptographically).
2.6 The owner path: query and decrypt
The owner side is the mirror image of §4–§5, run offline and on demand. The owner’s device holds the pairing seeds $(SK_0, d_0)$ for each of its tags, so it can reconstruct the entire past sequence of keys and therefore both find the reports (by hash) and open them (by private key). Nothing here requires the tag to be present, online, or even still alive.
2.6.1 Recomputing the key window
To locate a tag over, say, the last 24 hours, the owner’s device runs the derivation chain of §4.2 forward across that window, generating every interval keypair $(d_i, P_i)$ for $i$ spanning the time range — ~96 keys for a day at 15-minute intervals. Because the chain is deterministic from the pairing seed and the wall-clock epoch, the owner reproduces exactly the keys the tag advertised, with no communication with the tag. This is the same derive_interval loop from §4.2, iterated.
# Owner-side: rebuild all keys for a time window, then fetch + decrypt
# Authority: PETS 2021 §3 + OpenHaystack / Macless-Haystack.
def locate(SK0, d0, n, G, t_start, t_end):
keys = {} # idx -> private key d_i
SK = SK0
for i in intervals_between(t_start, t_end): # ~96 per day @ 15 min
SK, d_i, P_i = derive_interval(SK, d0, n, G)
keys[ sha256(P_i.x.to_bytes(28,"big")) ] = d_i
reports = apple_fetch( list(keys.keys()) ) # §6.2: query by hash, batched
fixes = []
for r in reports:
d_i = keys[r.index]
fixes.append( owner_decrypt(d_i, r) ) # §6.3
return fixes # list of (lat, lon, time, acc)
2.6.2 Querying by hash
The owner’s device sends Apple the batch of SHA-256(P_i) hashes for the window and asks “do you have any reports filed under these indices?” Apple matches the hashes against its store and returns the encrypted reports — without ever knowing which physical tag these hashes belong to, because a hash of a rotating public key is itself an opaque, unlinkable token. From Apple’s vantage, an owner is asking about a pile of random-looking 32-byte values. (The query is authenticated to the owner’s iCloud account for rate-limiting and abuse-prevention, but the content of the query reveals nothing about which device or which tag.) This hash-indexed lookup is the join that makes the whole anonymous-finder design work: the finder filed under $\text{SHA-256}(P_i)$ without knowing the owner; the owner queries the same hash without telling Apple what it is.
2.6.3 Decrypting the reports
For each returned report, the owner takes the matching private key $d_i$ (it knows which, because it knows which hash maps to which $d_i$) and runs ECDH against the report’s ephemeral public key $P_e$ — the reciprocal of the finder’s step 3. ECDH is symmetric: $d_i \cdot P_e = d_e \cdot P_i = S$, the same shared point the finder derived. The same X9.63 KDF reproduces the same AES key + IV, and AES-GCM decrypts and authenticates the location.
# Owner-side: decrypt one report with the interval private key d_i
# Reciprocal of the finder's ECDH (d_i·P_e == d_e·P_i). Authority: OpenHaystack.
def owner_decrypt(d_i, report):
P_e = parse_ephemeral_pubkey(report) # 57-byte uncompressed point
S = scalar_mult(d_i, P_e) # SAME shared point as finder
derived = kdf_x963(S.x.to_bytes(28,"big"),
shared_info=serialize(P_e), out_len=32)
aes_key, iv = derived[:16], derived[16:]
payload = aes_gcm_decrypt(aes_key, iv,
report.ciphertext, report.tag) # raises on bad tag
lat = s32(payload[0:4]) / 1e7 # signed deg * 1e7
lon = s32(payload[4:8]) / 1e7
acc = payload[8] # horizontal accuracy
return (lat, lon, report.timestamp, acc)
The owner now has a list of (lat, lon, time, accuracy) fixes — every place a network finder happened to walk past the tag — which the Find My app renders as a location and a breadcrumb history. The AES-GCM tag verification is doing real work here: it guarantees that a returned report was genuinely encrypted by a finder to this key and was not tampered with in Apple’s store, which is what lets the owner trust a location Apple handed over but could not read.
2.7 The zero-knowledge privacy model
Stepping back from the bytes: the system is engineered so that the party who stores the data (Apple) cannot read it, and the party who contributes the data (the finder) cannot be identified. This section makes the knowledge boundaries explicit, because they are both the system’s headline privacy property and the root cause of the detection difficulty in Vol 12.
2.7.1 The knowledge matrix
Table 9 — 7.1 The knowledge matrix
| Fact | The tag | A finder (stranger’s phone) | Apple (the cloud) | The owner |
|---|---|---|---|---|
| Its own location | No | — | No | derived from reports |
| Current public key $P_i$ | Yes | Yes (from advert) | Yes (as hash index) | Yes (recomputed) |
| Interval private key $d_i$ | Yes | No | No | Yes |
| The decrypted location | No | its own GPS (the plaintext) | No (only ciphertext) | Yes |
| Which tag a report belongs to | — | No | No (only a key hash) | Yes |
| The finder’s identity | No | (itself) | No (ephemeral only) | No |
| The owner’s identity | bonded at pairing | No | account (for the query) | (itself) |
Read the two bold “No” columns as the design thesis: Apple cannot read locations (it never holds a private key $d_i$, only ciphertexts and opaque hashes) and the finder cannot be identified or linked to a tag (it contributes only an ephemeral public key and its encrypted fix). The tag itself is the most ignorant participant of all — it has never known where it is.
The zero-knowledge privacy model, stated once, plainly. Find My is end-to-end encrypted with the owner’s keys. The location is encrypted on the finder’s phone (§5) to a key only the owner can derive (§4), stored by Apple as ciphertext indexed by an unlinkable hash, and decrypted only on the owner’s device (§6). Apple is a zero-knowledge relay: it operates the world’s largest location database and is cryptographically incapable of reading any entry in it, or of telling which entries belong to the same tag, or of identifying who reported them. This is not a policy promise (“we choose not to look”) — it is a cryptographic one (“we cannot look”), and it is what made enrolling ~1 billion devices as silent finders (§8.1) defensible rather than a surveillance scandal. The DIY consequence — you can run your own beacon on this same infrastructure without Apple learning anything — is Vol 10; the detection consequence — you also can’t easily tell which tag is which — is §8.2 and Vol 12.
2.7.2 Trust boundaries and residual risks
The model is strong but not unconditional. The honest residual risks, for completeness:
- Metadata, not content. Apple sees report timestamps, the rate of uploads against a hash, and the querying account. It cannot read locations, but traffic-analysis-style metadata is not nothing; the design minimizes but does not zero it.
- The owner’s device is the keystone. All privacy rests on $(SK_0, d_0)$ never leaking from the owner’s device / iCloud Keychain. Compromise the owner’s Apple account and the whole location history opens. (This is the realistic attack surface, not the curve.)
- A finder hands over its own location. The finder is anonymous to Apple, but it did upload its GPS position (encrypted). The privacy guarantee protects the owner’s tag location end-to-end; the finder is trusting the protocol that its contribution is unlinkable.
- Curve longevity. P-224 at ~112-bit security is fine for 15-minute-lived keys today; it is not a curve you would pick for long-term secrets. The short key lifetime is part of why the modest curve is acceptable (§4.1).
- It is still a tracker. None of this crypto changes the fact that the device’s purpose is to be located. The privacy model protects the owner from Apple and from third parties — it does not protect a victim from an owner who plants a tag to stalk them. That threat is precisely what the detection half (Vols 11–14) and the anti-stalking behavior (Vol 4) exist to counter; see
_shared/legal_ethics.md.
2.8 Network scale and the detection problem
Two consequences of everything above close the volume: the scale that makes the network actually work, and the rotating-identifier property that makes a naive scan useless for catching a hidden tag — the single most important fact to carry into the detection half.
2.8.1 The billion-device network
A crowdsourced locate only works if a finder is statistically likely to pass near the tag. Apple’s advantage is brute scale: ~1 billion+ active Apple devices — every signed-in iPhone, iPad, and Mac — act as silent finders by default (Vol 1 §3.2). That density is why a lost bag in an airport three states away gets a fix within minutes: in any populated area, an Apple device walks past it constantly. No competing network matches it on the OS-default-on axis (Google’s Android network is comparable in raw device count but younger; Samsung and Tile are an order of magnitude or more smaller — Vol 1 §3.6).
Table 10 — 8.1 The billion-device network
| Network | Finder base | Default-on? | E2E-encrypted locations | Crypto detail |
|---|---|---|---|---|
| Apple Find My | ~1 B+ iPhone/iPad/Mac | Yes | Yes — owner-only (this volume) | rotating P-224 + ECIES |
| Google Find My Device | ~1 B+ Android 9+ | Yes | Yes | rotating keys (own scheme) |
| Samsung SmartThings Find | few hundred M Galaxy | Yes (Galaxy) | Yes | rotating keys |
| Tile / Life360 | tens of M app users | App opt-in | Historically weak | server-side, weaker |
The density also sets the report cadence the owner sees: in a city, a tag gets fresh reports every few minutes; in the wilderness, it may go dark for hours because no finder passes. The location history is a function of finder traffic, not of the tag doing anything differently.
2.8.2 Why a plain MAC scan cannot track a tag
This is the fact that the entire detection half (Vols 11–13) is organized around, and it falls directly out of §2.3, §3.3, and §4.3: the BLE address is part of the rotating key, so it changes every ~15 minutes, and there is no stable identifier underneath it.
What a fixed scanner sees from ONE tag sitting in a bag for an hour
══════════════════════════════════════════════════════════════════
wall clock BLE address seen looks like
────────── ──────────────── ──────────────────────────
00:00 C1:A1:A2:A3:A4:A5 device #1
00:15 D7:91:0B:2C:5E:88 device #2 ← SAME tag, new key
00:30 E2:44:F1:09:7A:1C device #3 ← SAME tag, new key
00:45 C9:3D:88:42:11:90 device #4 ← SAME tag, new key
01:00 F0:1A:6B:77:C4:32 device #5 ← SAME tag, new key
A MAC-tracking heuristic ("same address seen repeatedly = following me")
sees FIVE different devices and raises ZERO alarms. The tag is invisible
to address-based correlation by construction.
A detector that keys on a stable MAC — the obvious first idea — fails completely: it sees five strangers, not one stalker. What does work is keying on the Find My service-data signature (the FF 4C 00 12 … triplet of §2.4, which is constant across rotations) plus the separated-state advertising behavior (Vol 4), and then correlating those over time and motion — “an object emitting the Find My signature has stayed with me across locations” — rather than correlating addresses. This is a software problem the dedicated detectors (AirGuard, the OS-native alerts) solve and general-purpose BLE gear mostly does not, yet. The full treatment is Vol 12 (the key-rotation problem and how detectors beat it); the gear that can see the signature is Vol 13.
Why a plain MAC scan can’t track a Find My tag — the one-paragraph version. The address you see is the current public key (top two bits forced to mark it random-static, §2.3), and the key rotates every ~15 minutes (§4.3). So a tag presents a fresh, unrelated BLE address four times an hour, ~96 times a day, with nothing stable linking them. Address-based correlation — the foundation of naive BLE tracking and of every “block the MAC” defense — is defeated by construction. Detection must instead fingerprint the constant
0x004C / 0x12Find My signature and correlate it against your own motion over time, which is exactly the hard part the detection volumes (Vols 11–12) and the dedicated detectors are built around. Hold this thought: it is the reason the counter-surveillance half of this series is non-trivial.
2.8.3 The end-to-end signal flow
Pulling §3 through §6 into one picture — the required signal-flow diagram, tag advert → finder → Apple server → owner query/decrypt:
Find My offline-finding — end-to-end signal flow
════════════════════════════════════════════════
┌───────────────┐
│ LOST TAG │ derives keypair (d_i, P_i) from pairing seed (§4.2)
│ (separated) │ advertises ADV_NONCONN_IND carrying P_i, every ~2 s,
│ │ key/address rotates every ~15 min (§4.3)
└───────┬───────┘
│ (1) BLE advert: FF 4C 00 12 … + P_i (§3)
▼
┌───────────────┐ (2) recover P_i from advert (§3.3)
│ FINDER │ (3) take own GPS fix
│ stranger's │ (4) ECIES-encrypt fix to P_i (§5): ephemeral ECDH +
│ Apple device │ X9.63-KDF + AES-GCM -> P_e ‖ ciphertext ‖ tag
│ (~1B, §8.1) │ (5) idx = SHA-256(P_i)
└───────┬───────┘
│ (6) POST {idx, encrypted report, timestamp} ── anonymous
▼
┌───────────────────────────────┐
│ APPLE CLOUD │ stores ciphertext under idx.
│ zero-knowledge relay (§7): │ Cannot read location. Cannot link
│ holds ciphertext + key-hash │ reports to a tag. Cannot ID finder.
└───────────────┬───────────────┘
▲ (7) query: batch of SHA-256(P_i) for a time window (§6.2)
│ (8) return: matching encrypted reports
▼
┌───────────────────────────────┐
│ OWNER DEVICE │ recompute P_0..P_n + d_0..d_n for the
│ has pairing seed (SK0, d0) │ window (§6.1); query by hash (§6.2);
│ -> only party that can │ ECDH d_i·P_e -> AES-GCM decrypt (§6.3)
│ DECRYPT the location │ -> (lat, lon, time, accuracy)
└───────────────────────────────┘ -> rendered on the Find My map
Every arrow in that diagram is a place where the design refused to leak something: the finder uploads without identifying itself, Apple stores without reading, the owner queries without telling Apple what it is asking about, and the tag — the object being located — knows the least of anyone. That is the offline-finding system, end to end.
2.9 Cheatsheet updates
This volume’s contributions to the Vol 15 laminate-ready cheatsheet — the framing facts to carry without re-reading:
- The Find My signature.
ADV_NONCONN_INDwhose payload carries Manufacturer-Specific-DataFF, Apple company ID4C 00(=0x004C), Apple type0x12. ThatFF 4C 00 12 …triplet is the constant fingerprint a detector keys on; everything after it rotates. - The advert carries a public key, split. A 28-byte NIST P-224 (
secp224r1) public key: ~6 bytes in the BLE address (top 2 bits forced to0b11random-static), 22 bytes in the payload (offsets 7–28), plus the recovered 2 high bits of key byte 0 at offset 29, a status byte at offset 6, a hint byte at offset 30. (Exact offsets per OpenHaystack / PETS 2021, not a bench capture.) - Keys rotate ~every 15 minutes (paired/in-range). The BLE address is part of the key, so it rotates too — no stable MAC exists. ~96 keys/day.
- The key chain. Pairing seeds $(SK_0, d_0, P_0)$ → symmetric ratchet $SK_i = \text{KDF}(SK_{i-1})$ → scalar diversification $d_i = (d_0 u_i + v_i)\bmod n$, $P_i = d_i G$. Only the owner (holding $d_0, SK_0$) can recompute the private keys $d_i$.
- Finder path = ECIES. Recover $P_i$ → ephemeral ECDH on P-224 → ANSI X9.63-KDF (SHA-256) → AES-GCM encrypt the finder’s own GPS fix → upload {SHA-256($P_i$) index, $P_e$ ‖ ciphertext ‖ tag, timestamp}. Finder is anonymous (ephemeral key only).
- Owner path = recompute + query + decrypt. Rebuild $P_i$ for a time window, hash them, ask Apple for those indices, ECDH $d_i \cdot P_e$ → AES-GCM decrypt → (lat, lon, time, accuracy).
- Zero-knowledge relay. Apple stores ciphertext indexed by an unlinkable key-hash; it holds no private key, so it cannot read locations, cannot link reports to a tag, cannot identify finders. Cryptographic guarantee, not a policy.
- The tag knows the least. It has no GPS and never knows its own location — it only shouts a rotating key. The finders do the locating.
- The detection gotcha (carry this into Vols 11–12). A plain MAC scan sees ~96 different addresses/day from one tag and raises no alarm. Detect by the constant
0x004C/0x12signature + separated-state behavior correlated against your own motion, never by a stable address. - Scale. ~1 B+ Apple devices as default-on silent finders — the density that makes far-away locates work, and the reason the zero-knowledge design was a precondition for shipping it.
This is Volume 2 of a fifteen-volume series. Next: Vol 3 opens Theory II — Ultra-Wideband Precision Finding (Apple U1/U2, IEEE 802.15.4z, time-of-flight + angle-of-arrival ranging at 6.5–8 GHz), the completely separate radio that takes over once Find My has gotten you within BLE range. Then Vol 4 (Theory III — NFC, Lost Mode, and the separated-state / anti-stalking beaconing) is the bridge into the detection half, where the §8.2 “why a plain MAC scan fails” problem gets solved.