Skip to main content

Pairing Methods

Pairing establishes mutual trust between two devices using a shared secret. cairn supports three pairing methods: PIN, QR code, and link. One peer initiates the pairing, and the other responds.

PIN Pairing

The most common method. The initiator generates a short PIN code and displays it. The responder types it in.

Initiator: Generate PIN

let pairing_data = node.pair_generate_pin().await?;
println!("PIN: {}", pairing_data.pin); // e.g., "A1B2-C3D4"
println!("Waiting for peer...");
// Blocks until the responder enters the PIN
let peer_id = pairing_data.peer_id;
println!("Paired with: {}", peer_id);

Responder: Enter PIN

The responder enters the PIN displayed by the initiator.

let peer_id = node.pair_enter_pin("A1B2-C3D4").await?;
println!("Paired with: {}", peer_id);

QR Code Pairing

The initiator generates QR data that the responder scans with a camera. This is useful for mobile-to-mobile or mobile-to-desktop pairing where typing a PIN is inconvenient.

Generating the QR Code

cairn provides the raw QR data string. Use a QR code library to render it as an image:

LanguageLibraryInstall
Rustqrcodecargo add qrcode
TypeScriptqrcodenpm install qrcode
Gogithub.com/skip2/go-qrcodego get github.com/skip2/go-qrcode
Pythonqrcodepip install qrcode
PHPendroid/qr-codecomposer require endroid/qr-code
use qrcode::QrCode;

let qr_data = node.pair_generate_qr().await?;
let code = QrCode::new(&qr_data.data)?;
let image = code.render::<char>().build();
println!("{}", image);
println!("Waiting for peer to scan...");
let peer_id = qr_data.peer_id;

Scanning the QR Code

The responder scans the QR code and passes the decoded data to cairn:

let peer_id = node.pair_scan_qr(&scanned_data).await?;
println!("Paired with: {}", peer_id);

The initiator generates a URI that can be shared via any channel (email, SMS, chat). The responder opens the link to complete pairing. This is useful for remote pairing when devices are not physically together.

let link_data = node.pair_generate_link().await?;
println!("Pairing link: {}", link_data.uri);
println!("Share this link with your peer.");
let peer_id = link_data.peer_id;
let peer_id = node.pair_from_link(&uri).await?;
println!("Paired with: {}", peer_id);

Choosing a Pairing Method

MethodBest ForRequires
PINSame room, quick pairingVisual/verbal contact
QRMobile devices, camera availableCamera + display
LinkRemote pairing, devices not co-locatedMessaging channel

All three methods provide the same level of security. The choice depends on the user experience you want to provide.

How it works: SPAKE2

All three pairing methods use SPAKE2 (Simple Password Authenticated Key Exchange) under the hood.

  1. Shared secret derivation: The PIN, QR data, or link URI contains a shared secret that both peers know.

  2. SPAKE2 exchange: Both parties perform a SPAKE2 handshake using the shared secret. SPAKE2 is designed so that neither party reveals the secret during the exchange -- even if an attacker observes every message, they cannot determine the secret or derive the session key.

  3. Noise XX bootstrap: The shared key from SPAKE2 is used to authenticate the initial Noise XX handshake, which establishes the encrypted session with forward secrecy via the Double Ratchet protocol.

This means that even a short 8-character PIN provides strong security: an attacker who intercepts the pairing exchange cannot brute-force the PIN from the observed messages.