The shim expanded NIP-06 index N into role=main + role_path=m/44'/1237'/N'/0/0
client-side. It is removed — callers must now use
nostr_signer_nsigner_set_role_path explicitly.
Added nostr_signer_nsigner_set_derive_index for the derive verb's algorithm
index (previously set as a side effect of the shim).
Updated NSIGNER_INTEGRATION.md and plan docs to reflect the removal.
Tests: 8/8 pass.
- nostr_signer_nsigner_from_transport: made public (was static) so callers
who open their own transport can create a signer from it.
- nostr_signer_nsigner_from_client: new constructor that creates a signer
from an already-created low-level nsigner_client_t. Lets callers use both
the high-level typed wrappers and the low-level nsigner_client_call for
raw passthrough on the same connection.
- nostr_signer_last_error: returns the raw n_signer RPC error message
(e.g. 'path_not_allowed', 'unknown_role') from the last failed call.
Delegates to nsigner_client_last_error for the remote backend.
- Forward declarations for nsigner_transport_t and nsigner_client_t added
to nostr_signer.h so the new constructors can be declared without
pulling in the transport/client headers.
The high-level nostr_signer_t API only covered 6 of n_signer's 16 verbs
(the Nostr protocol verbs + derive_hmac). The other 10 (get_info,
get_public_key algorithm-based, sign, verify, encapsulate, decapsulate,
derive_shared_secret, otp encrypt/decrypt, mine_event) had no library
wrapper — clients had to drop down to the low-level nsigner_client_call
and hand-build cJSON params.
This adds typed wrappers for all 10:
- nostr_signer_get_info
- nostr_signer_get_public_key_alg
- nostr_signer_sign / nostr_signer_verify
- nostr_signer_encapsulate / nostr_signer_decapsulate
- nostr_signer_derive_shared_secret
- nostr_signer_otp_encrypt / nostr_signer_otp_decrypt
- nostr_signer_mine_event
The local backend returns NOSTR_ERROR_NOT_SUPPORTED for all 10 (they
require signer-side PQ crypto / OTP pads / key derivation the local
backend doesn't hold). The remote nsigner backend builds the correct
wire params and parses the result.
Also adds NOSTR_ERROR_NOT_SUPPORTED (-40) to nostr_common.h.
Tests: 2 new tests in nsigner_client_test.c — local-backend
NOT_SUPPORTED check for all 10 verbs, and a mock-transport test
verifying nostr_signer_sign emits the correct wire request. 8/8 pass.
n_signer removed the bare nostr_index selector (error 2006) and index-on-
nostr-verbs (error 2007). The only accepted selector for nostr_* verbs is
now {"role","role_path"} sent together (2008/2009 if either is missing).
The remote signer backend was emitting {"nostr_index":N} or {"role"}
alone -- both now invalid. This commit:
- Replaces remote struct fields nostr_index/has_nostr_index with
role_path[128]/has_role_path plus derive_index/has_derive_index
- Rewrites signer_remote_params_with_selector to emit both role and
role_path in the options object
- Updates all three call sites (get_public_key, sign_event, encrypt_decrypt)
- Rewrites signer_remote_derive_hmac to emit {algorithm,index} using
derive_index
- Adds nostr_signer_nsigner_set_role_path setter
- Repurposes nostr_signer_nsigner_set_nostr_index as a compatibility shim
that expands N into role=main + role_path=m/44'/1237'/N'/0/0
- Updates nsigner_client_test to send and assert the role+role_path selector
- Updates NSIGNER_INTEGRATION.md (new section 2.1.1) and plan docs
Builds clean (38/39 tests; nip34_test failure is pre-existing/unrelated).
nsigner_client_test 6/6 pass, signer_modules_test 26/26 pass.
The 50ms receive timeout was too short for relays that need time to
process a REQ query before responding. The pool's query_sync already
uses 1000ms. This matches that behavior to avoid premature timeouts.
Pass NOTICE and CLOSED message content to the callback so callers
can see what the relay actually said (e.g. auth-required, restricted,
rate-limited). Previously these messages were silently ignored.
The 8KB buffer was too small for large Nostr events (e.g. long-form
content in kind 30023). The pool's query_sync already uses 256KB.
This matches that size to avoid truncation when using the standalone
synchronous query functions for backfill.
Rescued from uncommitted work in sovereign_browser/nostr_core_lib:
- nostr_signer_derive_hmac(): deterministic MAC over caller data using the
signer's secp256k1 private key. Local backend computes HMAC-SHA256 directly;
remote nsigner backend calls the 'derive' verb (algorithm:'secp256k1').
- nsigner_transport_list_serial(): enumerate /dev/ttyUSB* (FTDI/CH340/CP210x/
PL2303 USB-serial adapters) in addition to /dev/ttyACM* CDC-ACM devices.
- tests/nsigner_client_test.c: local derive_hmac reference-match test.