mirror of
https://github.com/block/buzz.git
synced 2026-10-30 05:51:46 +00:00
Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <wpfleger@block.xyz> Signed-off-by: Will Pfleger <wpfleger@squareup.com> Signed-off-by: Will Pfleger <wpfleger96@gmail.com> Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@sprout-oss.stage.blox.sqprod.co> Co-authored-by: npub1fgdl5qqnh3k3f2xkqrvt7cujalhm623x4s7fdjdj5yrtp5fzjl9qrjpucw <4a1bfa0013bc6d14a8d600d8bf6392efefbd2a26ac3c96c9b2a106b0d12297ca@sprout-oss.stage.blox.sqprod.co> Co-authored-by: npub16v54tttfqacx9ycvc3k0ut0npj564ahcuajzy6qjvh57ntmsf4uq4806j2 <d32955ad69077062930cc46cfe2df30ca9aaf6f8e76422681265e9e9af704d78@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Will Pfleger <wpfleger96@gmail.com>
81 lines
2.6 KiB
Rust
81 lines
2.6 KiB
Rust
//! NIP-AB device pairing — crypto primitives, message types, and error types.
|
|
//!
|
|
//! NIP-AB enables two Nostr devices to securely exchange a secret (e.g., an
|
|
//! `nsec` or a NIP-46 bunker connection string) over an untrusted relay, using:
|
|
//!
|
|
//! 1. **HKDF-SHA256** for all key derivation (session ID, SAS code, transcript hash).
|
|
//! 2. **ECDH** (via [`nostr::util::generate_shared_key`]) for the shared secret.
|
|
//! 3. **NIP-44 v2** for encrypting the message payloads.
|
|
//! 4. **Short Authentication String (SAS)** for out-of-band confirmation.
|
|
//!
|
|
//! # Module layout
|
|
//!
|
|
//! | Module | Contents |
|
|
//! |--------|----------|
|
|
//! | [`crypto`] | Pure HKDF derivation functions |
|
|
//! | [`types`] | Serde-serializable pairing message types |
|
|
//!
|
|
//! # Error handling
|
|
//!
|
|
//! All fallible operations in the pairing flow return [`PairingError`].
|
|
|
|
pub mod crypto;
|
|
pub mod qr;
|
|
pub mod session;
|
|
pub mod types;
|
|
|
|
pub use qr::QrPayload;
|
|
pub use session::{PairingSession, Role, SessionState};
|
|
pub use types::{AbortReason, PairingMessage, PayloadType};
|
|
|
|
use thiserror::Error;
|
|
|
|
/// Errors that can occur during a NIP-AB pairing session.
|
|
#[derive(Debug, Error)]
|
|
pub enum PairingError {
|
|
/// The scanned QR URI was not a valid NIP-AB pairing URI.
|
|
#[error("invalid QR URI: {0}")]
|
|
InvalidQr(String),
|
|
|
|
/// The session ID extracted from a message was not a valid 32-byte hex string.
|
|
#[error("invalid session ID")]
|
|
InvalidSessionId,
|
|
|
|
/// The SAS code shown on both devices did not match — session must be aborted.
|
|
#[error("SAS mismatch")]
|
|
SasMismatch,
|
|
|
|
/// The transcript hash received from the peer did not match the locally computed value.
|
|
#[error("transcript hash mismatch")]
|
|
TranscriptMismatch,
|
|
|
|
/// A message arrived out of sequence or with the wrong type for the current state.
|
|
#[error("unexpected message type: expected {expected}, got {got}")]
|
|
UnexpectedMessage {
|
|
/// The message type that was expected at this point in the protocol.
|
|
expected: String,
|
|
/// The message type that was actually received.
|
|
got: String,
|
|
},
|
|
|
|
/// The pairing session exceeded its time limit without completing.
|
|
#[error("session expired")]
|
|
SessionExpired,
|
|
|
|
/// NIP-44 encryption or decryption failed.
|
|
#[error("NIP-44 error: {0}")]
|
|
Nip44(#[from] nostr::nips::nip44::Error),
|
|
|
|
/// JSON serialization or deserialization failed.
|
|
#[error("JSON error: {0}")]
|
|
Json(#[from] serde_json::Error),
|
|
|
|
/// A public key string could not be parsed.
|
|
#[error("invalid pubkey: {0}")]
|
|
InvalidPubkey(String),
|
|
|
|
/// Event signing or construction failed.
|
|
#[error("event signing failed: {0}")]
|
|
SigningError(String),
|
|
}
|