Part 15 — QR / NFC Bootstrap & Secure Pairing Architecture
Reusable P2P Communication Platform
Status: Architecture specification
Part: 15 of 24
Primary language: Rust
Primary goals: secure device/contact bootstrap, QR and NFC pairing, short-lived invitations, offline pairing, authenticated key exchange, misbinding resistance, replay protection, multi-device identity integration, transport handoff, recovery safety, reusable across messaging/files/DTN/emergency/custom products
1. Purpose
Before two devices can communicate securely, they often need a trustworthy way to bootstrap identity.
Internet directories and usernames are useful, but they are not always available or desirable.
The platform should therefore support intentional physical bootstrap using:
QR code
NFC tap
manual short authentication string
numeric comparison
nearby BLE-assisted discovery
The bootstrap layer must support:
- linking a new device to an existing account
- adding a contact face-to-face
- secure file handoff
- offline pairing
- emergency/team provisioning
- headless node enrollment
- organization device provisioning
- cross-device trust establishment
The fundamental rule is:
QR/NFC bootstrap establishes cryptographic context; it must never silently bypass identity authorization.
2. Architectural Position
User Intent
↓
Bootstrap Session
↓
QR / NFC / Manual Verification
↓
Ephemeral Cryptographic Exchange
↓
Secure Nearby/Internet Session
↓
Identity Authentication
↓
Authorization
↓
Device / Contact / Capability Binding
Part 14 discovers nearby transport opportunities.
Part 15 provides intentional trust bootstrap.
Part 02 remains the authority for account/device identity.
3. Bootstrap Is Not Bulk Transport
QR and NFC should carry:
small bootstrap payload
not:
message history
large files
full certificates if avoidable
After bootstrap:
BLE
LAN
Wi-Fi Direct
Iroh
carries the actual protocol exchange.
4. Bootstrap Use Cases
Recommended explicit modes:
#![allow(unused)] fn main() { pub enum BootstrapPurpose { LinkOwnDevice, AddContact, PairForFileTransfer, EnrollOrganizationDevice, EnrollRelayNode, EmergencyTeamPairing, } }
Each mode has different authorization semantics.
5. Do Not Reuse One Generic Pairing Flow
For example:
Add Contact
does not grant:
account device authority
and:
Link Own Device
should not behave like casual nearby sharing.
Use purpose-specific state machines over common primitives.
6. Bootstrap Session ID
#![allow(unused)] fn main() { pub struct BootstrapSessionId([u8; 16]); }
Generated randomly and locally.
It scopes:
invitation
handshake
expiry
replay detection
diagnostics
7. Bootstrap Invitation
Conceptual:
#![allow(unused)] fn main() { pub struct BootstrapInvitation { pub version: u16, pub session_id: BootstrapSessionId, pub purpose: BootstrapPurpose, pub initiator_ephemeral_key: EphemeralPublicKey, pub rendezvous: Vec<RendezvousHint>, pub expires_at: Timestamp, pub nonce: BootstrapNonce, pub authenticator: Option<BootstrapAuthenticator>, } }
Keep payload bounded.
8. Invitation Must Be Short-Lived
Recommended semantics:
valid for minutes
single-use where possible
explicitly cancellable
Do not create permanent QR codes that authorize device linking.
9. Single-Use Invitation
Once successfully consumed:
mark used
Subsequent attempts:
reject
Persist consumption if replay could cross process restart.
10. Expiry
Invitation expires even if never used.
Expired invitation:
cannot establish new trust
11. Bootstrap Nonce
#![allow(unused)] fn main() { pub struct BootstrapNonce([u8; 16]); }
Provides uniqueness/freshness.
Do not derive security solely from session ID.
12. Ephemeral Key Pair
Each bootstrap session creates an ephemeral key pair.
EphemeralPrivateKey
EphemeralPublicKey
The private key:
never enters QR/NFC payload
13. Ephemeral Key Lifetime
Destroy after:
successful bootstrap
expiry
cancel
fatal error
Do not persist indefinitely.
14. QR Payload
QR should encode:
version
session ID
purpose
ephemeral public key
short rendezvous hints
expiry
integrity/authentication metadata
Use compact binary payload then a QR-safe encoding if required.
15. QR Encoding Format
Internal canonical representation may be Postcard.
Presentation layer can encode bytes as:
Base64url
Base32
custom URI wrapper
A human-readable URI form can help OS camera integration.
Example conceptually:
comm://pair/<encoded-bootstrap>
Exact URI becomes public protocol surface and must be versioned.
16. QR Size Discipline
QR payload should remain small.
Do not embed:
full history
large certificate chains
large profile metadata
If more data required, QR carries a capability/token to fetch it over the authenticated session.
17. NFC Payload
NFC can carry the same logical bootstrap invitation.
Use NDEF-compatible representation where needed by platform adapter.
Core Rust model remains identical.
18. QR and NFC Share One Semantic Format
Avoid:
QR protocol
NFC protocol
with separate security designs.
Instead:
BootstrapInvitation
↓
QR adapter
or
NFC adapter
19. Manual Code Fallback
When QR/NFC unavailable, support:
short authentication string
numeric comparison
Manual code should verify an already-established cryptographic handshake, not replace strong key exchange.
20. SAS
Short Authentication String:
derived from handshake transcript
Example:
482 917
Both users compare.
If equal:
approve
If different:
abort
21. SAS Security Principle
SAS must be derived from:
both ephemeral keys
session transcript
purpose
identities where known
not generated independently on each UI.
22. Emoji / Word Verification
Optional UX:
4 words
or
emoji sequence
can represent the same transcript-derived SAS.
Numeric comparison should remain available for accessibility/interoperability.
23. No "Accept Anyway"
If SAS mismatch:
abort
Do not provide a casual bypass button for high-trust operations like device linking.
24. QR Security Property
Scanning QR creates an out-of-band binding:
scanner received the initiator's bootstrap material
through a user-directed physical channel
The subsequent network session must prove possession of the matching ephemeral private key.
25. NFC Security Property
NFC offers intentional very-short-range interaction.
Still:
NFC proximity != account authorization
The cryptographic handshake and user approval remain required.
26. Bootstrap Channel Threats
Threats include:
QR replacement
camera scanning wrong code
screen capture
NFC relay
replay
stale invitation
session hijack
mismatched purpose
malicious nearby peer
Architecture must explicitly defend against these.
27. Purpose Binding
The invitation cryptographically binds:
BootstrapPurpose
An invitation for:
PairForFileTransfer
must not be usable as:
LinkOwnDevice
28. Session Binding
All subsequent handshake messages carry:
BootstrapSessionId
and bind into transcript.
29. Rendezvous Hints
QR/NFC may contain hints such as:
ephemeral proximity token
Iroh endpoint hint
LAN hint
BLE service hint
They help find the peer.
They are not trusted identity.
30. Minimal Rendezvous Disclosure
Prefer:
opaque temporary token
rather than stable addresses when possible.
31. Transport Selection
After QR/NFC scan:
candidate paths discovered
Part 03 selects:
LAN
BLE
Wi-Fi Direct
Iroh direct/relay
The pairing protocol is transport-independent.
32. Transport Handoff
Example:
QR scanned
↓
BLE session starts
↓
identity handshake
↓
Wi-Fi Direct becomes available
↓
remaining device-sync data moves to Wi-Fi
Bootstrap trust remains unchanged.
33. Offline Pairing
QR/NFC pairing must work with:
no Internet
provided devices can establish some local transport.
Example:
QR
+
BLE
or:
QR
+
LAN
34. Fully Offline Device Linking
Own-device linking can:
scan QR
authenticate locally
authorize device
issue device certificate/state event
transfer minimum account state
without central server.
Later both devices synchronize when Internet returns.
35. Own-Device Linking
This is the most security-sensitive bootstrap purpose.
Flow:
Existing trusted device
↓
Create Link Invitation
↓
New device scans
↓
Ephemeral secure handshake
↓
User verifies
↓
Existing device authorizes
↓
Device certificate/event committed
↓
New device becomes account member
36. Existing Device Authority
Only a device with appropriate Part 02 authority may approve new device.
Do not grant authority merely because it can display QR.
37. Link Authorization
#![allow(unused)] fn main() { pub struct DeviceLinkAuthorization { pub account_id: AccountId, pub new_device_key: DevicePublicKey, pub permissions: DevicePermissions, pub generation: u64, pub authorizer: DeviceId, } }
This is signed according to Part 02 identity architecture.
38. Commit Point
A device is not linked until:
signed device-add event/certificate
is durably committed
Scanning QR is not the commit point.
39. Interrupted Device Link
Crash before commit:
new device remains unlinked
Crash after commit:
recovery sees linked device
This integrates Part 09.
40. Half-Linked State Must Not Exist
Never allow:
new device has account secrets
but no durable authorization
Transfer sensitive account state only after or atomically around durable authorization according to security design.
41. Minimal Initial State
After authorization, transfer only what new device needs first:
account identity
device directory
current security state
configuration
Then optionally:
message history
blob metadata
42. History Policy
Part 02 device policy may specify:
future only
recent history
full history
selected conversations
Pairing UI should expose policy where appropriate.
43. New Device Key Generation
New device generates its own long-term device key locally.
Do not generate the new device's private key on the old device and transmit it.
44. Secure Storage Before Link
New device should verify:
hardware/OS secure storage available
where required, before final authorization.
45. Device Naming
Display name:
"Pixel 9"
"Work Laptop"
is metadata only.
Identity is cryptographic DeviceId/public key.
46. Permission Assignment
Own-device link may grant:
normal device
admin/link-authority
recovery authority
headless relay
Use least privilege.
47. Default Permissions
New personal device should not automatically gain every sensitive authority unless product deliberately chooses that model.
48. Device-Link Confirmation UX
Existing device shows:
Link new device?
Device type
Verification code
Requested permissions
New device shows matching verification.
49. Biometric / PIN Confirmation
For high-risk operations, existing device may require local:
PIN
biometric
OS authentication
before signing device authorization.
Platform adapter owns biometric UI; Rust owns authorization semantics.
50. Contact Bootstrap
Face-to-face contact addition is less privileged.
Flow:
Alice shows QR
Bob scans
secure handshake
both verify
exchange identity/contact cards
mark verified contact
No account-device authority is granted.
51. Mutual Contact Verification
Both sides should be able to verify.
Do not create asymmetric hidden trust accidentally.
52. Contact Trust Level
Possible:
#![allow(unused)] fn main() { pub enum ContactTrust { Unverified, VerifiedInPerson, VerifiedByExistingTrust, } }
This is application/security metadata.
53. Contact QR Privacy
A public contact QR may be intentionally shareable.
A private face-to-face QR should be short-lived.
Support separate modes.
54. Permanent Contact Code
If product supports public QR profile:
it must not grant high-trust device authorization
It can provide:
public identity key/contact handle
then communication still authenticates normally.
55. Temporary Pairing QR
Use for:
high-trust verification
with short expiry and one-time semantics.
56. File-Transfer Bootstrap
For ad-hoc nearby file share:
sender displays QR
receiver scans
session establishes
file offer starts
No permanent contact relationship required.
57. Ephemeral File Session
Can create:
session-only trust
with no saved contact after transfer.
58. File Session Authorization
Session permits:
receive offered file
not arbitrary messaging/account access.
59. Headless Node Enrollment
A headless relay/server may display:
terminal QR
or accept NFC/token.
Admin scans and approves:
node role
capabilities
organization
60. Node Enrollment Certificate
Issue a purpose-specific certificate/authorization.
Do not make headless relay a normal chat device unless intended.
61. Organization Enrollment
Enterprise may use:
signed enrollment QR
containing:
organization bootstrap
infrastructure profile
one-time enrollment capability
62. Organization Trust Anchor
Enrollment QR can carry:
organization root fingerprint
so device knows which organization infrastructure to trust.
63. Enrollment Server Optional
Organization flow may contact server if online.
Offline enrollment should remain possible where policy allows.
64. Emergency Team Pairing
During emergency deployment:
team leader
field devices
gateway nodes
can be provisioned rapidly through QR/NFC.
Use pre-defined roles and limited authority.
65. Bulk Provisioning
For many devices, one static QR should not grant unlimited permanent authorization.
Use:
signed enrollment batch token
usage limit
expiry
role constraints
66. Enrollment Token
#![allow(unused)] fn main() { pub struct EnrollmentToken { pub issuer: IdentityRef, pub role: EnrollmentRole, pub expires_at: Timestamp, pub max_uses: u32, pub nonce: [u8; 16], } }
Signed by authorized issuer.
67. Usage Counter
If offline multi-use enrollment exists, global usage enforcement is difficult.
For high assurance:
prefer single-use
or require online/authority reconciliation.
Document limits.
68. QR Replay Protection
Replay defenses:
short expiry
single-use session ID
ephemeral key
transcript binding
persisted consumed-session tombstone
69. Consumed Invitation Tombstone
Store:
BootstrapSessionId
consumed_at
for at least the invitation replay horizon.
70. Replay After Crash
Consumption marker must survive process crash before final UI completion if trust authorization was committed.
71. Invitation Cancellation
Initiator can cancel.
Persist cancellation if invitation remains externally visible.
72. Cancelled QR
Scanner may still possess screenshot.
Handshake checks invitation state and rejects.
73. Screenshot Risk
QR can be photographed.
Therefore security relies on:
expiry
one-time token
ephemeral proof
user verification
not physical secrecy alone.
74. QR Replacement Attack
Attacker may replace displayed QR with theirs.
Mitigation:
SAS comparison
trusted UI context
purpose display
For highest assurance, require both QR possession and transcript verification.
75. NFC Relay Attack
NFC can theoretically be relayed.
Do not treat NFC distance as absolute proof.
Use transcript verification for high-risk device linking.
76. Man-in-the-Middle Resistance
Handshake must authenticate both ephemeral contributions and bind them to out-of-band bootstrap material.
Use a vetted authenticated key exchange design.
Do not invent cryptographic primitives.
77. Noise-Like Handshake
A Noise-based or similarly vetted handshake framework is appropriate conceptually.
Exact pattern depends on known/unknown static keys.
Architecture requirement:
ephemeral forward secrecy
transcript authentication
identity binding
78. Crypto Agility
Handshake suite is negotiated only within safe allowed profiles.
Do not allow attacker-controlled downgrade.
Part 07 security negotiation applies.
79. Transcript
Canonical transcript includes:
bootstrap version
purpose
session ID
initiator ephemeral key
responder ephemeral key
identity keys
capability/session selections
as appropriate.
80. Transcript Hash
#![allow(unused)] fn main() { pub struct BootstrapTranscriptHash([u8; 32]); }
Used for:
SAS
confirmation
audit/debug identifiers
Do not expose raw secret inputs.
81. Confirmation Messages
Both peers exchange:
transcript confirmation
before final authorization.
This catches mismatched negotiation state.
82. Pairing State Machine
Created
↓
Advertised
↓
Scanned
↓
TransportConnecting
↓
Handshake
↓
VerificationPending
↓
AuthorizationPending
↓
Committing
↓
Completed
Terminal:
Cancelled
Expired
Rejected
Failed
83. Strict Transition Validation
Examples:
Completed → Handshake
invalid.
Expired → Completed
invalid.
Use explicit typed state transitions.
84. Verification Pending
For high-trust flow, neither side is authorized yet.
User confirmation required.
85. Authorization Pending
Cryptographic peer verified, but policy authorization still pending.
Example:
which device permissions?
86. Idempotent Completion
Repeated final confirmation message:
does not create duplicate device/contact
Stable session/device IDs ensure idempotency.
87. Timeout
Each stage has timeout:
scan
connect
handshake
verification
authorization
Avoid indefinitely-held pairing sessions.
88. Resource Limits
Part 08 limits:
active invitations
pending scans
pairing handshakes
verification sessions
89. Pairing Flood
Unknown nearby attackers may initiate many attempts.
Use:
rate limit
user-intent gate
temporary block
90. User-Intent Gate
High-trust linking should only be accepted when user explicitly put device into:
Link Device
mode.
Do not process unsolicited device-link attempts in background.
91. Pairing Window
Example:
pairing mode active 2 minutes
Then automatically closes.
Exact default configurable.
92. QR Scanner Boundary
Platform camera/scanner returns:
raw decoded payload
Rust core validates protocol.
Do not put trust decisions in UI scanner code.
93. Android Responsibilities
Kotlin may own:
camera integration
QR scanning surface
NFC reader/writer
biometric prompt
OS permission
Rust owns:
bootstrap state machine
crypto
expiry
authorization
identity events
94. iOS Responsibilities
Swift/platform adapter similarly owns:
camera
NFC
biometric
while Rust core owns semantics.
95. Desktop QR
Desktop can:
render QR
scan via camera if supported
import QR image explicitly
For security, importing an old screenshot still remains subject to expiry/single-use rules.
96. Terminal QR
Headless node can render QR as terminal blocks.
Useful for:
Raspberry Pi
server enrollment
97. Accessibility
Provide alternatives:
numeric code
copyable bootstrap code
manual verification
Do not require camera/NFC for all users.
98. Manual Bootstrap Code
A manual code can encode:
session locator
short token
but high-security trust still relies on cryptographic transcript confirmation.
99. Human Error
Design verification strings to minimize mistakes.
Avoid:
long hexadecimal fingerprints
as default UX.
Use them only advanced/debug.
100. Advanced Fingerprint
Security screen may expose:
full identity fingerprint
for manual expert verification.
101. Identity Fingerprint
Fingerprint should derive from stable identity public key, not display metadata.
102. Multi-Device Integration
New device linking updates:
device directory
account generation
permissions
Part 02 distributes the resulting signed state.
103. Device Revocation During Pairing
If authorizing device becomes revoked mid-session:
abort
before commit.
104. Account Generation Change
If account generation changes during pairing:
revalidate authorization
Do not commit using stale state.
105. Concurrent Device Links
Two authorized devices may link new devices concurrently.
Part 02 conflict/generation rules apply.
Bootstrap layer does not invent its own global serialization.
106. Capability Negotiation
After secure transport/session:
Part 07
determines available features.
Bootstrap payload should not carry full runtime capability state.
107. Proximity Integration
Part 14 provides:
BLE observation
Wi-Fi candidate
LAN candidate
after QR/NFC bootstrap.
108. Routing Integration
Part 03 chooses best path to continue pairing/state transfer.
109. File Integration
Ad-hoc QR file share uses Part 05 after ephemeral session authorization.
110. DTN Integration
DTN can distribute:
signed organization bootstrap announcement
but high-trust enrollment should still require explicit verification/authorization.
111. Offline Event Log
Part 04 records semantic transitions such as:
DeviceAdded
ContactVerified
NodeEnrolled
Do not journal every QR scan frame.
112. Crash Recovery
Part 09 handles:
pending invitation
consumed invitation
committed device event
orphan ephemeral state
Ephemeral handshake sessions can simply expire/restart if not committed.
113. Crash Before Scan
No effect.
114. Crash After Scan Before Authorization
Session expires/restarts.
No trust committed.
115. Crash During Authorization Commit
Database/event transaction defines outcome.
Recovery checks committed device/contact event.
116. Crash After Commit Before UI Success
Recovery shows paired state.
Do not ask user to pair again unnecessarily.
117. Invitation Persistence
Persist minimum data required for:
expiry
cancel
single-use
crash recovery
Private ephemeral key may be stored only if session recovery is explicitly desired and secure.
Simpler v1:
ephemeral session lost on crash
invitation cancelled/expired
for incomplete sessions.
118. Secure Secret Storage
Long-term keys use secure storage.
Short-lived ephemeral bootstrap private keys should remain memory-only where practical.
119. Pairing Audit
Security history may record:
new device linked
authorizing device
time
permissions
not QR payload.
120. Contact Audit
Optional:
verified in person
with timestamp.
Avoid storing exact physical location.
121. Organization Audit
Record:
enrollment issuer
role
device
policy version
122. Privacy
QR invitation may expose:
protocol presence
purpose
temporary routing hints
Minimize stable metadata.
123. No Personal Data in QR by Default
Avoid:
name
email
phone
organization details
unless user explicitly chose public contact-card QR.
124. Bootstrap Logging
Logs may include:
session-id hash
purpose
state
error
Never:
ephemeral private key
full invitation secret
SAS secret derivation material
125. Error Model
#![allow(unused)] fn main() { pub enum BootstrapError { InvalidPayload, UnsupportedVersion, Expired, AlreadyConsumed, Cancelled, PurposeMismatch, TransportUnavailable, HandshakeFailed, VerificationFailed, Unauthorized, IdentityChanged, ResourceDenied, SecureStoreUnavailable, Timeout, } }
126. User-Facing Errors
Map to:
This QR code expired.
This pairing request was already used.
Verification codes did not match.
This device is not authorized to add another device.
Nearby connection failed.
127. No Security Ambiguity
Do not show generic:
Something went wrong
for verification mismatch.
Make security failures clear.
128. QR Parser Fuzzing
Part 10 fuzz targets:
bootstrap envelope
URI parser
base encoding
version field
rendezvous hints
expiry
129. NFC Parser Fuzzing
Fuzz:
NDEF wrapper
bootstrap payload
truncation
duplicate records
unexpected record order
130. State-Machine Fuzzing
Generate:
scan
connect
verify
cancel
expire
approve
duplicate confirm
and assert valid transitions.
131. Replay Tests
Reuse same QR:
after successful pairing
Expected:
rejected
132. Expiry Test
Scan after expiration:
reject before trust
133. Purpose Confusion Test
Use file-transfer QR for device linking.
Expected:
PurposeMismatch
134. MITM Test
Swap responder ephemeral key.
Expected:
SAS/transcript mismatch
135. Wrong-Device Test
QR from Alice, network session from Mallory.
Expected:
proof-of-possession/transcript authentication fails
136. Screenshot Replay Test
Old screenshot after invitation consumed.
Expected:
AlreadyConsumed/Expired
137. Crash Test
Kill after authorization commit but before final response.
Restart:
paired exactly once
138. Concurrent Scan Test
Two scanners use same one-time invitation.
Only one succeeds.
139. Contact Pairing Test
Mutual verification creates contact trust but no device-link authority.
140. File Session Test
Ephemeral file pairing completes transfer without adding persistent contact.
141. Offline Test
No Internet.
QR + BLE/LAN still links device/contact according to policy.
142. Transport Switch Test
Pairing starts over BLE, continues over LAN/Wi-Fi.
Transcript/session identity remains valid.
143. Revocation Race Test
Authorizer revoked before commit.
Expected:
authorization fails
144. Account Generation Race
Account state advances mid-link.
Expected:
revalidate or restart authorization
145. Permission Test
Camera denied.
Manual/NFC alternatives remain available where supported.
146. NFC Disabled Test
QR/manual flow remains available.
147. Resource Flood Test
Thousands of fake pairing attempts.
Expected:
bounded memory
bounded handshakes
no prompt spam
148. Golden Vectors
Maintain stable vectors for:
BootstrapInvitationV1
transcript canonicalization
SAS derivation test inputs
enrollment tokens
Do not expose real secrets.
149. Cryptographic Test Vectors
Use upstream/reference vectors for cryptographic primitives.
Protocol-specific transcript vectors should be deterministic.
150. Suggested Crate Structure
crates/comm-bootstrap/
├── src/
│ ├── lib.rs
│ ├── invitation.rs
│ ├── purpose.rs
│ ├── session.rs
│ ├── state.rs
│ ├── transcript.rs
│ ├── sas.rs
│ ├── rendezvous.rs
│ ├── authorization.rs
│ ├── replay.rs
│ ├── enrollment.rs
│ ├── policy.rs
│ ├── diagnostics.rs
│ └── error.rs
└── Cargo.toml
Adapters:
comm-bootstrap-qr
comm-bootstrap-nfc
Platform UI adapters remain in:
comm-platform-android
comm-platform-ios
comm-ui
151. QR Adapter
Responsibilities:
canonical bytes
QR-safe encoding
URI wrapper
decode/validate framing
Does not authorize identity.
152. NFC Adapter
Responsibilities:
NDEF mapping
record validation
bootstrap bytes
Does not authorize identity.
153. Bootstrap Service API
#![allow(unused)] fn main() { pub trait BootstrapService { async fn create_invitation( &self, purpose: BootstrapPurpose, policy: BootstrapPolicy, ) -> Result<BootstrapInvitationHandle, BootstrapError>; async fn accept_invitation( &self, invitation: BootstrapInvitation, ) -> Result<BootstrapSessionHandle, BootstrapError>; } }
154. Invitation Handle
#![allow(unused)] fn main() { pub struct BootstrapInvitationHandle { pub session_id: BootstrapSessionId, } }
Operations:
render QR
write NFC
cancel
status
155. Session Handle
Operations:
verification code
approve
reject
status
High-level UI should not manipulate raw keys.
156. Bootstrap Policy
#![allow(unused)] fn main() { pub struct BootstrapPolicy { pub lifetime: Duration, pub single_use: bool, pub require_sas: bool, pub allowed_transports: TransportSet, } }
Purpose can impose stricter minimums.
157. Link-Device Policy
Recommended:
short lifetime
single use
SAS or strong out-of-band confirmation
explicit authorizer approval
158. Contact Policy
Could allow:
QR proof + mutual confirmation
with session-only or persistent trust choice.
159. File-Session Policy
Recommended:
short lifetime
single use
session-scoped authority
no account permissions
160. Enrollment Policy
Organization controls:
role
expiry
issuer
allowed infrastructure
161. UI Flow — Link Device
Existing device:
Settings
→ Devices
→ Link new device
→ QR displayed
New device:
Link existing account
→ Scan QR
→ Secure connection
→ Compare code
Both:
Confirm
Existing device:
Approve requested permissions
System:
Commit DeviceAdded
→ sync minimum state
162. UI Flow — Add Contact
Show My Verification QR
↓
Other user scans
↓
Both see identity + verification
↓
Confirm
↓
Contact marked Verified
163. UI Flow — Nearby File
Send nearby
→ Show/scan short-lived QR
→ connect
→ file offer
→ transfer
→ session expires
164. Dioxus Boundary
Dioxus owns:
screens
QR rendering component
verification UI
permission explanation
Rust bootstrap service owns all state/security.
165. Android Kotlin Boundary
Kotlin owns only:
camera plumbing
NFC APIs
biometric APIs
lifecycle integration
No trust logic.
166. Headless API
CLI:
comm link-device --show-qr
comm enroll-node --show-qr
Useful for server/embedded nodes.
167. Recovery CLI
Advanced:
comm bootstrap list-pending
comm bootstrap cancel <id>
No secret dump.
168. Diagnostics
Advanced view:
Purpose: LinkOwnDevice
State: VerificationPending
Expires in: 01:23
Transport: BLE
Peer identity: authenticated
Never display raw private key material.
169. Metrics
Safe metrics:
bootstrap started
completed
expired
verification failed
transport failed
purpose class
No QR token values.
170. Security Invariants
- QR/NFC alone never grants account authority.
- Invitation purpose cannot change.
- Expired invitations cannot authorize.
- Consumed single-use invitations cannot authorize twice.
- New device private key is generated on the new device.
- Device link requires an authorized existing identity.
- Device is linked only after durable signed authorization.
- SAS derives from the authenticated transcript.
- SAS mismatch is never bypassed silently.
- Transport switching does not change bootstrap identity.
- Crash after commit produces exactly one authorization.
- Ad-hoc file pairing cannot escalate into account access.
- Stable personal identity is not unnecessarily embedded in private QR/NFC payloads.
171. Initial Production Scope
Implement first:
BootstrapInvitationV1
QR encode/decode
short-lived single-use sessions
ephemeral key exchange
transcript hash
numeric SAS
own-device linking
face-to-face contact verification
ad-hoc file session
BLE/LAN/Iroh handoff
consumed-session tombstones
crash-safe authorization commit
Then:
NFC
organization enrollment
headless node enrollment
word/emoji SAS
Defer initially:
mass offline multi-use enrollment
complex proximity proofs
custom cryptographic handshake inventions
172. Implementation Phases
Phase 1 — Bootstrap Core
session ID
purpose
invitation
expiry
single-use
Phase 2 — QR
canonical encoding
QR wrapper
scanner integration
Phase 3 — Secure Handshake
ephemeral keys
transcript
SAS
confirmation
Phase 4 — Device Linking
authorization
DeviceAdded
minimum state sync
Phase 5 — Contact / File Sessions
verified contact
session-only file trust
Phase 6 — NFC
NDEF adapter
tap flow
Phase 7 — Organization / Headless
enrollment tokens
role policy
terminal QR
Phase 8 — Hardening
fuzzing
replay
MITM
crash
race
flood
real-device tests
173. Definition of Done
Part 15 is complete when:
- QR and NFC share one semantic bootstrap model
- bootstrap invitations are short-lived and bounded
- high-trust invitations can be single-use
- replay after successful use is rejected
- QR/NFC payload contains no private key
- a secure ephemeral handshake follows bootstrap
- transcript-derived SAS verification exists
- purpose confusion is cryptographically prevented
- device linking requires an already authorized device
- new device generates its own long-term private key
- DeviceAdded authorization is durable before device becomes trusted
- interrupted pairing cannot create a half-linked device
- contact verification cannot grant device authority
- ad-hoc file pairing can remain session-only
- pairing works without Internet when local transport exists
- pairing can move between BLE/LAN/Wi-Fi/Iroh paths
- Android/iOS camera/NFC code contains no trust policy
- consumed invitations survive crash/restart where required
- fuzz, replay, MITM, race, crash, flood, and offline tests exist
174. Relationship to Earlier Parts
Part 15 builds on:
01 — Protocol Extension System
02 — Multi-Device Identity
03 — Transport & Routing Policy Engine
04 — Offline Event Log
05 — Robust File / Blob Subsystem
06 — DTN / Store-Carry-Forward
07 — Capability Negotiation
08 — Resource Limits & Backpressure
09 — Crash Recovery
10 — Fuzzing & Protocol Test Suite
11 — Relay / Self-Hosted Infrastructure
12 — Multipath Networking
13 — Battery-Aware Scheduling
14 — Proximity Abstraction
It directly supports:
16 — Daemon & Headless Runtime
17 — Emergency Priority Architecture
18 — Network Diagnostics & Path Visualization
19 — C ABI / FFI
20 — Embedded Linux Node
22 — Third-Party Protocol Extensions
23 — External Interoperability Suite
24 — Plugin / Module Ecosystem
175. Final Architecture
USER INTENT
│
┌──────────┼───────────┐
│ │
Show QR NFC Tap
│ │
└──────────┬───────────┘
│
BootstrapInvitation
│
Ephemeral Key
│
Rendezvous
│
┌─────────────┼─────────────┐
│ │ │
BLE LAN Iroh
│ │ │
└─────────────┼─────────────┘
│
Secure Handshake
│
Transcript Hash
│
SAS Verification
│
Identity Binding
│
Authorization
│
Durable Domain Commit
┌──────────┼──────────┐
│ │ │
DeviceAdded Contact File Session
Verified
176. Final Principle
The bootstrap system should make this flow safe:
A new phone has no Internet.
The existing phone displays a QR code.
The new phone scans it.
The phones find each other over BLE.
They establish an ephemeral encrypted session.
Both screens show the same verification code.
The user confirms.
The existing authorized device signs and durably commits
the new device authorization.
Only then does the new phone receive account state.
Later Wi-Fi becomes available,
and history synchronization moves to the faster path.
The QR code is not the account credential.
NFC is not the account credential.
Physical proximity is not the account credential.
The actual trust chain is:
intentional bootstrap
+
authenticated cryptographic transcript
+
human/policy verification
+
authorized identity signature
+
durable commit
That separation is what makes QR/NFC pairing safe enough for a reusable, offline-capable, multi-device P2P communication platform.