`probe unlock` — the experiment §2.3.3 ends on, not an implementation. The pod offers a compressed P-256 point and gives up on us when we do not answer; the paddle bits freeze while the D-pad keeps reporting. What a working client writes back is the half no capture has, and the public descriptions are all of the older Play hardware — different message types, an uncompressed key, a different channel. But the offer looks like the handshake we already know, moved into a protobuf envelope: its field 2 is `0x02030000`, and `RESPONSE_START` — the pod's confirmed cleartext reply marker — is `[0x02, 0x03]`. That makes the client side a short list rather than a search, and the device is a perfect oracle: either a paddle edge arrives after the cliff or one does not, every run, in two minutes. So the command sends one candidate per run — `ours` (00 09, what we already write), `play` (01 02, the 2023 client marker), `echo` (02 03, in case field 2 names the suite rather than the speaker) — and reports HELD, FAILED or INCONCLUSIVE. Omitting `--candidate` answers nothing and measures the cliff this pod actually has, which is the control every result needs. The verdict deliberately refuses to call a failure from silence: it needs the D-pad still reporting while the paddles do not, because a pod nobody touched proves nothing and a dropped link is void rather than negative. Field 3 of the offer — 40 or 60 bytes, unexplained — is omitted from the reply. If it is load-bearing no candidate will hold, and that is a finding too. p256 is a dependency of the probe alone. The app takes no crypto dependency on a guess. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
27 lines
898 B
TOML
27 lines
898 B
TOML
[package]
|
|
name = "bikecontrol-probe"
|
|
version.workspace = true
|
|
edition.workspace = true
|
|
license.workspace = true
|
|
|
|
[[bin]]
|
|
name = "probe"
|
|
path = "src/main.rs"
|
|
|
|
[dependencies]
|
|
bikecontrol-core = { workspace = true }
|
|
bikecontrol-ble = { workspace = true }
|
|
btleplug = { workspace = true }
|
|
tokio = { workspace = true, features = ["full"] }
|
|
futures = { workspace = true }
|
|
uuid = { workspace = true }
|
|
anyhow = { workspace = true }
|
|
tracing = { workspace = true }
|
|
tracing-subscriber = { workspace = true }
|
|
# Protocol discovery only (§9): the pod offers a compressed P-256 point and we
|
|
# need a real one to answer with. Pure Rust, and deliberately confined to the
|
|
# probe until an unlock candidate is proven — the app takes no crypto
|
|
# dependency on a guess.
|
|
p256 = { version = "0.13", default-features = false, features = ["ecdh", "arithmetic"] }
|
|
rand_core = { version = "0.6", features = ["getrandom"] }
|