Class PreimageProvisioning
- Namespace
- NArk.ArkadeIntents.Lightning
- Assembly
- NArk.ArkadeIntents.dll
Deterministic claim preimages for the RFQ corridors: a preimage derived from the swap's own claim key, so the seed re-derives what storage may lose.
public static class PreimageProvisioning
- Inheritance
-
PreimageProvisioning
- Inherited Members
Remarks
The scheme is the reference client's, byte for byte: the message is
TAG ‖ xonly(32) ‖ u32le(index) (or TAG ‖ xonly(32) ‖ salt(32) when the descriptor
repeats across swaps), the preimage is sha256(sign_det(sha256(message))), and the
signature is BIP-340 with aux_rand = 0 — the convention every local signing source in
this SDK already honours, and the one Arkade-Boltz-Preimage-v1 uses on the Boltz
corridor. Same (key, salt-or-index) → same signature → same preimage, so a restored wallet
re-derives the claim secret from the contract's own descriptor.
The tag is protocol-scoped and versioned, and deliberately distinct from the Boltz one: a shared tag would let one wallet key derive one preimage for both corridors. Any Arkade SDK implementing the same scheme produces the same preimage, so artifacts are recoverable across implementations.
Fields
PreimageIndex
The derivation index. Unsalted derivation is only safe when the key belongs to one swap, so the index stays pinned; kept a constant for cross-SDK vectors.
public const uint PreimageIndex = 0
Field Value
PreimageTag
Domain separator for the per-artifact derivation — exactly as the reference writes it.
public const string PreimageTag = "Arkade-RFQ-Preimage-v1"
Field Value
SaltedPreimageTag
Domain separator for the salted derivation, used when the descriptor repeats.
public const string SaltedPreimageTag = "Arkade-Contract-Preimage-Salted-v1"
Field Value
Methods
BuildPreimageMessage(byte[], uint)
TAG ‖ xonly(32) ‖ u32le(index) — the message that gets BIP-340 signed.
public static byte[] BuildPreimageMessage(byte[] xOnlyPubKey, uint index)
Parameters
Returns
- byte[]
Remarks
Anchored on the canonical x-only key rather than the descriptor string: a restore reconstructs a bare descriptor that serialises differently from the signing descriptor used at creation, and only the key agrees across both.
BuildSaltedPreimageMessage(byte[], byte[])
TAG ‖ xonly(32) ‖ salt(32) — the salted message that gets BIP-340 signed.
public static byte[] BuildSaltedPreimageMessage(byte[] xOnlyPubKey, byte[] salt)
Parameters
Returns
- byte[]
Remarks
The salt replaces the pinned index as the source of per-swap uniqueness, which is what lets a key that repeats across swaps still derive a distinct preimage for each. It is public: knowing it yields nothing without the seed.
DerivePreimageAsync(IArkadeWalletSigner, OutputDescriptor, byte[]?, CancellationToken)
sha256(sign_det(sha256(TAG ‖ xonly ‖ index))), or its salted variant when
salt is given — where the signing key and the message key are the same
descriptor.
public static Task<byte[]> DerivePreimageAsync(IArkadeWalletSigner signer, OutputDescriptor descriptor, byte[]? salt, CancellationToken cancellationToken = default)
Parameters
signerIArkadeWalletSignerThe wallet's signer; determinism is the
aux_rand = 0convention.descriptorOutputDescriptorThe swap's claim descriptor — the key that signs and the key in the message.
saltbyte[]Per-swap uniqueness for a repeating descriptor;
nullfor an HD child.cancellationTokenCancellationTokenCancels the signing round trip.
Returns
IsPerArtifactDescriptor(OutputDescriptor)
True when the descriptor names one swap — an HD child, which carries a derivation path. A
bare tr(pubkey) is the same key every time it is handed out, so anything deriving
per-swap secrets must branch on this, never on the wallet's type.
public static bool IsPerArtifactDescriptor(OutputDescriptor descriptor)
Parameters
descriptorOutputDescriptor