Table of Contents

Interface IRemoteSignerTransport

Namespace
NArk.Abstractions.Wallets
Assembly
NArk.Abstractions.dll

Transport abstraction over a remote signer. Mirrors IArkadeWalletSigner but adds a walletId argument to every call so a single transport instance can serve multiple wallets (e.g. a multi-user server-side signing service, an HWI bridge, or a browser-extension wallet shared across tabs).

public interface IRemoteSignerTransport

Remarks

Register an implementation in DI alongside any wallet whose Secret is null/empty (i.e. no local signing material). The default IWalletProvider implementation probes KnowsWalletAsync(string, CancellationToken) to decide whether such a wallet is remote-signed (signer is a IArkadeWalletSigner proxy over this transport) or watch-only (GetSignerAsync(string, CancellationToken) returns null). Capability is answered by this interface, not by a flag on the wallet record.

The MuSig2 nonce flow keeps the secret half on the transport side: GenerateNoncesAsync(string, OutputDescriptor, MusigContext, string, CancellationToken) returns only the public nonce, the implementation retains the secret half indexed by walletId + sessionId, and SignMusigAsync(string, OutputDescriptor, MusigContext, string, CancellationToken) consumes it on use. Implementations need an eviction policy for abandoned nonces (TTL or bounded count) so the store does not grow without bound — the SDK-side IArkadeWalletSigner contract requires SignMusig to throw if no matching nonce is found.

Methods

GenerateNoncesAsync(string, OutputDescriptor, MusigContext, string, CancellationToken)

Generates a fresh MuSig2 nonce pair for the supplied context, retains the secret half on the transport side indexed by walletId + sessionId, and returns the public half so the caller can complete nonce aggregation with cosigners. The secret half never crosses the transport boundary — that is the cryptographic claim of remote signing.

Task<MusigPubNonce> GenerateNoncesAsync(string walletId, OutputDescriptor descriptor, MusigContext context, string sessionId, CancellationToken cancellationToken = default)

Parameters

walletId string

The wallet whose key contributes the nonce.

descriptor OutputDescriptor

The descriptor identifying the signing key.

context MusigContext

The MuSig2 context the nonce is generated for.

sessionId string

A caller-supplied identifier unique to this signing operation, used to correlate this nonce with the matching SignMusigAsync(string, OutputDescriptor, MusigContext, string, CancellationToken) call. Typically a transaction identifier (txid).

cancellationToken CancellationToken

Cancellation token.

Returns

Task<MusigPubNonce>

GetPubKeyAsync(string, OutputDescriptor, CancellationToken)

Gets the compressed public key for the given descriptor, preserving parity.

Task<ECPubKey> GetPubKeyAsync(string walletId, OutputDescriptor descriptor, CancellationToken cancellationToken = default)

Parameters

walletId string

The wallet whose key is being requested.

descriptor OutputDescriptor

The descriptor identifying the key to return.

cancellationToken CancellationToken

Cancellation token.

Returns

Task<ECPubKey>

KnowsWalletAsync(string, CancellationToken)

Indicates whether this transport can sign for the given wallet. Used by the wallet provider to distinguish remote-signed wallets from watch-only ones when the wallet has no local Secret: true → produce a remote-signer proxy; false → fall through to watch-only (signer = null).

Task<bool> KnowsWalletAsync(string walletId, CancellationToken cancellationToken = default)

Parameters

walletId string
cancellationToken CancellationToken

Returns

Task<bool>

SignAsync(string, OutputDescriptor, uint256, CancellationToken)

Produces a BIP-340 Schnorr signature over hash using the descriptor's private key, returning the x-only pubkey alongside the signature.

Task<(ECXOnlyPubKey, SecpSchnorrSignature)> SignAsync(string walletId, OutputDescriptor descriptor, uint256 hash, CancellationToken cancellationToken = default)

Parameters

walletId string

The wallet whose key signs.

descriptor OutputDescriptor

The descriptor identifying the signing key.

hash uint256

The 32-byte hash to sign.

cancellationToken CancellationToken

Cancellation token.

Returns

Task<(ECXOnlyPubKey, SecpSchnorrSignature)>

Remarks

Implementations MUST sign with aux_rand set to 32 zero bytes so the signature is deterministic per (key, hash).

The requirement is about what a signature may be used FOR, not only about signing. Anything that derives a secret from one — a swap preimage being the case this SDK has shipped — needs the same descriptor and the same wallet to reproduce it exactly, or a restored wallet re-derives a different secret and cannot spend what the old one committed to. The in-box signing sources honour this; a transport that does not is not interchangeable with them, however valid its signatures are on their own terms.

In NBitcoin.Secp256k1, use ECPrivKey.SignBIP340(msg, new byte[32]) — the no-auxData overload SignBIP340(msg) draws from the system RNG on every call and is therefore non-deterministic.

Implementations that randomise aux_rand (e.g. for side-channel resistance on a hardware signer) break that contract, and a wallet on such a transport cannot rebuild from its seed any secret that was derived from a signature.

SignMusigAsync(string, OutputDescriptor, MusigContext, string, CancellationToken)

Produces a MuSig2 partial signature for the given context using the descriptor's private key and the secret nonce the transport retained when GenerateNoncesAsync(string, OutputDescriptor, MusigContext, string, CancellationToken) was called for the same sessionId. The secret nonce is consumed on this call.

Task<MusigPartialSignature> SignMusigAsync(string walletId, OutputDescriptor descriptor, MusigContext context, string sessionId, CancellationToken cancellationToken = default)

Parameters

walletId string

The wallet whose key signs.

descriptor OutputDescriptor

The descriptor identifying the signing key.

context MusigContext

The MuSig2 context (cosigner set + sighash) the nonce was generated for.

sessionId string

The same session identifier that was passed to GenerateNoncesAsync(string, OutputDescriptor, MusigContext, string, CancellationToken).

cancellationToken CancellationToken

Cancellation token.

Returns

Task<MusigPartialSignature>

Exceptions

InvalidOperationException

No secret nonce is stored for walletId + sessionId (it was never generated, was already consumed, or has been evicted by the transport's eviction policy).