Remove nostr_signer_nsigner_set_nostr_index compatibility shim

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.
This commit is contained in:
Laan Tungir
2026-08-06 13:06:44 -04:00
parent 71a72dc7ed
commit c91670f7da
5 changed files with 35 additions and 62 deletions
+9 -14
View File
@@ -116,9 +116,10 @@ int nostr_signer_nsigner_set_auth(nostr_signer_t* signer,
* together for nostr_* verbs; set the role via the constructor and the path
* here. */
int nostr_signer_nsigner_set_role_path(nostr_signer_t* signer, const char* role_path);
/* Compatibility shim: expands NIP-06 index N into role="main" +
* role_path="m/44'/1237'/N'/0/0" and stores N as the derive index. */
int nostr_signer_nsigner_set_nostr_index(nostr_signer_t* signer, int nostr_index);
/* Set the algorithm derivation index used by the derive verb
* (nostr_signer_derive_hmac). The derive verb is algorithm-based and
* requires an explicit index (no default). Pass a negative value to clear. */
int nostr_signer_nsigner_set_derive_index(nostr_signer_t* signer, int index);
#endif
```
@@ -136,20 +137,14 @@ field is rejected by n_signer with `2008 role_required` / `2009 path_required`.
The bare `{"nostr_index":N}` selector is **removed** on the n_signer side
(error `2006 nostr_index_deprecated`); this library never emits it.
Two ways to set the selector:
1. **`nostr_signer_nsigner_set_role_path(signer, path)`** — explicit. Pass the
role name to the constructor and the full path here. This is the canonical
path for new code.
2. **`nostr_signer_nsigner_set_nostr_index(signer, N)`** — convenience. Expands
`N` into `role="main"` + `role_path="m/44'/1237'/N'/0/0"` and also stores `N`
as the algorithm `index` used by `nostr_signer_derive_hmac`. The signer must
have a `main` role whose template matches the expanded path.
Set the selector with **`nostr_signer_nsigner_set_role_path(signer, path)`** —
pass the role name to the constructor and the full path here. This is the only
way to select a key for `nostr_*` verbs.
For the algorithm-based `derive` verb (used by `nostr_signer_derive_hmac`), the
backend emits `{"algorithm":"secp256k1","index":N}`. The index comes from the
last `set_nostr_index` call; if unset, the request is sent without `index` and
n_signer rejects it with `missing_index`.
last `nostr_signer_nsigner_set_derive_index` call; if unset, the request is
sent without `index` and n_signer rejects it with `missing_index`.
### 2.2 Transport constructors + framed I/O + discovery (`nostr_core/nsigner_transport.h`)
+5 -26
View File
@@ -549,10 +549,8 @@ static int signer_remote_derive_hmac(nostr_signer_t* signer,
/* Build the options object with algorithm:"secp256k1" and the index.
* The derive verb is algorithm-based and requires an explicit index
* (no default). The index is set via nostr_signer_nsigner_set_nostr_index
* (which stores it in derive_index) or directly via a future
* set_derive_index helper. Without an index the signer rejects the
* request with missing_index. */
* (no default). The index is set via nostr_signer_nsigner_set_derive_index.
* Without an index the signer rejects the request with missing_index. */
opts = cJSON_CreateObject();
if (opts == NULL) {
cJSON_Delete(params);
@@ -1576,7 +1574,7 @@ int nostr_signer_nsigner_set_role_path(nostr_signer_t* signer, const char* role_
return NOSTR_SUCCESS;
}
int nostr_signer_nsigner_set_nostr_index(nostr_signer_t* signer, int nostr_index) {
int nostr_signer_nsigner_set_derive_index(nostr_signer_t* signer, int index) {
if (signer == NULL) {
return NOSTR_ERROR_INVALID_INPUT;
}
@@ -1585,30 +1583,11 @@ int nostr_signer_nsigner_set_nostr_index(nostr_signer_t* signer, int nostr_index
return NOSTR_ERROR_INVALID_INPUT;
}
if (nostr_index < 0) {
/* Clear the selector */
signer->u.remote.has_role_path = 0;
signer->u.remote.role_path[0] = '\0';
if (index < 0) {
signer->u.remote.has_derive_index = 0;
signer->u.remote.derive_index = -1;
} else {
/* Expand the NIP-06 index into role="main" + the full derivation path.
* n_signer no longer accepts a bare {"nostr_index":N}; it requires
* {"role":"main","role_path":"m/44'/1237'/N'/0/0"}. We also store N as
* the algorithm derive index so nostr_signer_derive_hmac works. */
const char* main_role = "main";
size_t rlen = strlen(main_role);
if (rlen >= sizeof(signer->u.remote.role)) {
return NOSTR_ERROR_INVALID_INPUT;
}
memcpy(signer->u.remote.role, main_role, rlen);
signer->u.remote.role[rlen] = '\0';
snprintf(signer->u.remote.role_path, sizeof(signer->u.remote.role_path),
"m/44'/1237'/%d'/0/0", nostr_index);
signer->u.remote.has_role_path = 1;
signer->u.remote.derive_index = nostr_index;
signer->u.remote.derive_index = index;
signer->u.remote.has_derive_index = 1;
}
+5 -8
View File
@@ -173,15 +173,12 @@ int nostr_signer_nsigner_set_auth(nostr_signer_t* signer,
*/
int nostr_signer_nsigner_set_role_path(nostr_signer_t* signer, const char* role_path);
/*
* Compatibility shim: expands the NIP-06 index N into role="main" and
* role_path="m/44'/1237'/N'/0/0" and stores N as the algorithm derive index.
* n_signer no longer accepts a bare {"nostr_index":N} selector, so this is
* the supported way to select a key by NIP-06 account index. The signer must
* have a "main" role registered whose template matches the expanded path.
* Pass a negative value to clear the selector. Returns NOSTR_SUCCESS or an
* error code.
* Set the algorithm derivation index used by the derive verb
* (nostr_signer_derive_hmac). The derive verb is algorithm-based and
* requires an explicit index (no default). Pass a negative value to clear.
* Returns NOSTR_SUCCESS or an error code.
*/
int nostr_signer_nsigner_set_nostr_index(nostr_signer_t* signer, int nostr_index);
int nostr_signer_nsigner_set_derive_index(nostr_signer_t* signer, int index);
#endif
#ifdef __cplusplus
+13 -11
View File
@@ -21,8 +21,10 @@ alone is rejected (`2008 role_required` / `2009 path_required`); a bare
### `nostr_core/nostr_signer.h`
- Documented the new `nostr_signer_nsigner_set_role_path` setter.
- Repurposed `nostr_signer_nsigner_set_nostr_index` as a compatibility shim
that expands N into `role="main"` + `role_path="m/44'/1237'/N'/0/0"`.
- Added `nostr_signer_nsigner_set_derive_index` for the derive verb's
algorithm index.
- **Removed** `nostr_signer_nsigner_set_nostr_index` (the compatibility shim).
Callers must now use `set_role_path` explicitly.
### `nostr_core/nostr_signer.c`
- Replaced the `remote` struct fields `nostr_index`/`has_nostr_index` with
@@ -33,10 +35,10 @@ alone is rejected (`2008 role_required` / `2009 path_required`); a bare
- Updated all three call sites (`get_public_key`, `sign_event`,
`encrypt_decrypt`) to the new signature.
- Rewrote `signer_remote_derive_hmac` to emit `{"algorithm":"secp256k1",
"index":N}` using `derive_index` (set by the `set_nostr_index` shim).
"index":N}` using `derive_index` (set by `set_derive_index`).
- Added `nostr_signer_nsigner_set_role_path`.
- Rewrote `nostr_signer_nsigner_set_nostr_index` to expand the NIP-06
template instead of storing a bare index.
- Added `nostr_signer_nsigner_set_derive_index`.
- **Removed** `nostr_signer_nsigner_set_nostr_index` (the compatibility shim).
- Added `<stdio.h>` for `snprintf`.
- `nostr_signer_free` now also zeroes `role_path`.
@@ -55,17 +57,17 @@ alone is rejected (`2008 role_required` / `2009 path_required`); a bare
- `make` builds clean.
- `nsigner_client_test` passes (mock transport round-trip with the new
selector).
- `grep -rn 'nostr_index' nostr_core/nostr_signer.c` returns no bare-selector
emission (only the compatibility-shim function name and its doc comment).
- `grep -rn 'nostr_index' nostr_core/nostr_signer.c` returns no matches
(the shim is removed).
## Downstream consumers still needing updates
These repos link `nostr_core_lib` and call `nostr_signer_nsigner_*`; the
`set_nostr_index` shim keeps them functional, but their UIs still expose only
an "index" input and should be updated to collect role + path explicitly:
These repos link `nostr_core_lib` and call `nostr_signer_nsigner_*`. The
`set_nostr_index` shim is **removed** — they must be updated to use
`set_role_path` explicitly:
- `sovereign_browser` — `src/login_dialog.c`, `src/agent_login.c`,
`src/key_store.c` (uses `set_nostr_index`; works via shim, UI needs role+path).
`src/key_store.c` (uses `set_nostr_index`; must switch to `set_role_path`).
- `nostr_terminal` — has its own hand-rolled `nsigner_client.c` that still
emits `{"nostr_index":N}` directly (NOT via this lib); must be rewritten
independently.
+3 -3
View File
@@ -15,9 +15,9 @@
> **Selector update:** n_signer removed the bare `nostr_index` selector and
> `index`-on-nostr-verbs. The only accepted selector for `nostr_*` verbs is now
> `{"role":"<name>","role_path":"<full-path>"}` sent together. This library
> emits both fields; `nostr_signer_nsigner_set_nostr_index` is retained as a
> compatibility shim that expands N into `role="main"` +
> `role_path="m/44'/1237'/N'/0/0"`. See `NSIGNER_INTEGRATION.md` §2.1.1.
> emits both fields. The `nostr_signer_nsigner_set_nostr_index` compatibility
> shim was removed; callers must use `nostr_signer_nsigner_set_role_path`
> explicitly. See `NSIGNER_INTEGRATION.md` §2.1.1.
>
> This plan originally described pulling the **caller-side** signer-integration glue out of per-project implementations and into `nostr_core_lib`,
> so any project that already links the library can sign **locally**, via a **running