Throwaway research spike (spike/ branch, outside pub workspace, no prod deps touched). Validates the open Block 2 decisions before committing a funded round: 1. Deterministic one-way secp256k1 (Nostr) key derived from the Ğ1 root seed via HKDF — user still backs up ONE thing. Reproducible + signs (BIP340). 2. OfferTransport abstraction over Nostr NIP-99 (kind 30402); Offer stays inventory/location-agnostic, geohash coarsened on the wire (tested). 3. publish->discover-by-geohash proven end-to-end against an in-process hermetic mini-relay (~34ms round-trip). Findings + risks + recommendation in docs/design/spike-block2-findings.md. Block 1 suite untouched. 14 tests green, analyzer clean.
32 lines
1,011 B
Dart
32 lines
1,011 B
Dart
import 'dart:typed_data';
|
|
|
|
import 'package:crypto/crypto.dart';
|
|
|
|
/// Minimal, self-contained HKDF-SHA256 (RFC 5869), synchronous.
|
|
///
|
|
/// Spike-local so the derivation stays pure Dart and easy to reason about. In
|
|
/// production this would reuse `commons_core`'s `Hkdf` (the `cryptography`
|
|
/// package already ships one — see backup_box.dart), keyed by a domain string.
|
|
Uint8List hkdfSha256({
|
|
required List<int> ikm,
|
|
required String info,
|
|
List<int> salt = const [],
|
|
int length = 32,
|
|
}) {
|
|
// Extract.
|
|
final actualSalt = salt.isEmpty ? Uint8List(32) : salt; // HashLen zeros
|
|
final prk = Hmac(sha256, actualSalt).convert(ikm).bytes;
|
|
|
|
// Expand.
|
|
final infoBytes = info.codeUnits;
|
|
final out = <int>[];
|
|
var previous = <int>[];
|
|
var counter = 1;
|
|
while (out.length < length) {
|
|
final input = <int>[...previous, ...infoBytes, counter];
|
|
previous = Hmac(sha256, prk).convert(input).bytes;
|
|
out.addAll(previous);
|
|
counter++;
|
|
}
|
|
return Uint8List.fromList(out.sublist(0, length));
|
|
}
|