feat(companion): backup envelope + NIP-46 signer crypto in the native core

Extends archy-fips-core with the two companion-release features' crypto
(#128, #139), same JNI-over-JSON contract as the mesh surface:

backup.rs — the ADR-005 encrypted-backup envelope, byte-compatible with
the node's backup code (Argon2id default params + ChaCha20-Poly1305,
blob = base64(salt||nonce||ct)); decrypt ignores extra envelope fields
so node backups read here too. Round-trip, tamper, wrong-passphrase and
cross-shape tests included.

nostr.rs — the phone-side remote-signer crypto: nsec/npub bech32 keys,
BIP340 schnorr event signing (NIP-01 id serialization), NIP-44 v2
payloads (HKDF-SHA256 + ChaCha20 + HMAC-SHA256, both padding prefixes),
NIP-04 fallback, nostrconnect:// parsing with repeated relay params.
Verified against the official NIP-44 vectors (conversation keys, message
keys, padded lengths, byte-exact encrypt vectors), the BIP-340 reference
sign vectors, and round-trip/tamper/failure tests. secp256k1 0.29 note:
Keypair::public_key() is the 33-byte compressed key — x-only pubkeys
must go through .x_only_public_key().0 (one real bug the vectors caught).

JNI glue adds com.archipelago.app.NativeCore: backupEncrypt/Decrypt,
nostrGenerateSecret/SecretFromAny/ParseConnectUri/SignEvent and the
NIP-44/NIP-04 cipher pairs. Android arm64 build verified via cargo-ndk
(7.2 MB .so, +0.4 MB for both modules). Host: cargo test 23/23, clippy clean.
This commit is contained in:
Dorian
2026-08-31 13:29:36 +01:00
parent 12c853da45
commit 57e31eb192
6 changed files with 1621 additions and 3 deletions
+29
View File
@@ -37,6 +37,35 @@ tracing = "0.1"
# fcntl: force the VpnService TUN fd into blocking mode (see mesh::start).
libc = "0.2"
# ── Companion backup (#128) ───────────────────────────────────────────────
# ADR-005 envelope: the SAME crates and blob layout as the node's backup code
# (core/archipelago/src/backup/identity.rs) — Argon2id KDF + ChaCha20-Poly1305
# AEAD — applied to the companion's own JSON payload. Do not diverge from
# those parameters: a companion backup and a node backup must decrypt with
# the same code path on either side.
argon2 = "0.5"
chacha20poly1305 = "0.10"
base64 = "0.22"
# ── NIP-46 remote signer (#139) ───────────────────────────────────────────
# BIP340 schnorr signing + secp256k1 ECDH (NIP-44/NIP-04 conversation keys).
# Audited libsecp256k1 via cc; cargo-ndk provides the NDK clang on Android.
secp256k1 = "0.29"
# NIP-44 v2: HKDF-SHA256 (conversation/message keys) + HMAC-SHA256 (MAC).
sha2 = "0.10"
hmac = "0.12"
hkdf = "0.12"
# NIP-44 v2 stream cipher (raw ChaCha20, RFC 8439 — NOT the AEAD).
chacha20 = "0.9"
# NIP-04 fallback (deprecated in the spec but still sent by real clients):
# AES-256-CBC, key = raw ECDH x-coordinate.
aes = "0.8"
cbc = { version = "0.1", features = ["alloc"] }
# npub/nsec (bech32, BIP173 variant — NOT Bech32m).
bech32 = "0.11"
# nostrconnect:// URI parsing (repeated relay params + percent-decoding).
url = "2.5"
# The JNI surface only exists on Android; host builds skip it and drive the
# mesh module directly (tests).
[target.'cfg(target_os = "android")'.dependencies]