Skip to content

arkd-signer: native ArkadeScript signing via emulator library - #1122

Open
Kukks wants to merge 16 commits into
arkd-signerfrom
arkd-signer-emulator
Open

Kukks wants to merge 16 commits into
arkd-signerfrom
arkd-signer-emulator

Conversation

@Kukks

@Kukks Kukks commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Draft / stacked on arkd-signer (#1118), which introduced the txsigner library. Depends on emulator#102 (the signing library): the three emulator modules are pinned to a pseudo-version off that PR's branch, to be repointed to the merged commit before un-drafting.

Summary

Gives arkd-signer native ArkadeScript signing for all four spend shapes (onchain, offchain-tx, intent, finalization), signing-only, by importing the emulator as a library (emulator#102) instead of running a separate emulator process.

  • Constructs emulator.Service with the operator key, arkd-signer's own pubkey as arkdPubKey, and a nil finalizer (signing-only — no arkd round-trip, no go-sdk).
  • Registers EmulatorService (+ REST gateway) on arkd-signer's existing gRPC server, next to SignerService.
  • Shared key: the operator key doubles as the emulator's arkade-signing key. Safe because the emulator only ever signs the tweaked arkade key it derives (operator + scriptHash), never the raw operator key, on any spend path, so it cannot forge a SignerService signature. As belt-and-suspenders, the onchain path additionally rejects closures that carry the raw operator pubkey (a routing rule, since those vtxos must go through the offchain checkpoint flow). This structural guarantee is locked by a SharedKeyNeverSignsRawOperatorKey test.
  • Config: ARKD_SIGNER_EMULATOR_COMPUTE_LIMITS (optional VM caps); no ARKD_SIGNER_ARKD_URL.
  • Root go.mod gains gnark-crypto (the VM's pairing) only — no go-sdk.

Compatibility

  • No signerv1 / emulatorv1 wire-protocol changes.
  • Independent emulation under a separate key remains available by running a standalone emulator alongside.

Testing

  • pkg/arkd-signer unit tests cover all four spend shapes signing-only (onchain, offchain-tx, intent, and the finalization precondition), each asserting the tweaked-key signature (no Nigiri). Plus the onchain reject when a closure carries the arkd signer pubkey, a SharedKeyNeverSignsRawOperatorKey lock-in test, and grouped compute-limit config tests. parseComputeLimits warns on malformed entries rather than silently ignoring them.
  • e2e integration smoke (internal/test/e2e): dials the running arkd-signer's emulatorv1 SubmitOnchainTx and round-trips an onchain arkade spend, asserting the tweaked-key signature, exercised by the Nigiri integration suites (postgres/redis + sqlite/badger).
  • cmd/arkd-signer + arkd + ./... cross-build (linux/amd64).
  • Verified zero go-sdk in arkd-signer + root go.mod/go.sum.

Before un-drafting


CI note — repo-wide security bump (self-dropping): This branch also carries a golang.org/x/crypto→v0.52.0 / golang.org/x/net→v0.55.0 bump across all 10 modules, clearing a newly-published Trivy CVE batch (x/crypto/ssh + x/net/html) that was failing every arkd build (master included). x/net 0.55 deprecates h2c.NewHandler, so SA1019 is suppressed via a targeted .golangci.yml exclusion (not inline //nolint, which trips the golines length limit). The bump is shared with #1118 and self-drops when this rebases onto a master that already carries it. Migrating off h2c to http.Server’s Protocols field is a tracked follow-up.

Summary by CodeRabbit

  • New Features

    • Added native ArkadeScript spend signing using the operator key, with co-signing only for valid embedded scripts.
    • Exposed an emulator service through gRPC and gateway interfaces.
    • Added configurable per-opcode emulator compute limits via environment variables.
    • Added support for signing Arkade transactions and intent proofs in emulator mode.
  • Documentation

    • Documented emulator signing behavior, compute-limit configuration, and standalone emulator usage.
  • Tests

    • Added comprehensive coverage for on-chain, off-chain, intent, and safety-related signing scenarios.

Kukks added 7 commits June 19, 2026 23:04
- go.mod: require + replace for emulator/pkg/emulator, emulator/pkg/arkade,
  emulator/api-spec; all pointing to C:/Git/_emulator_ref local paths.
  grpchandler is a sub-package of pkg/emulator (no separate module).
- config: add ComputeLimits field parsed from ARKD_SIGNER_EMULATOR_COMPUTE_LIMITS
  (empty => DefaultComputeLimits(), OPCODE=limit overrides via OpcodeByName map).
- config_test: add TestComputeLimitsDefault asserting non-nil ComputeLimits.
…Service

- config: build emulator.Service in initServices() with nil finalizer
  (signing-only). Converts []DeprecatedSignerKey -> []*btcec.PrivateKey.
  Sets arkdPubKey = our own operator pubkey so SubmitOnchainTx rejects
  inputs that also contain the arkd signer key.
- service.go Start(): register grpchandler.New("", emulatorSvc) as
  EmulatorServiceServer and wire REST gateway handler beside the signer.
- emulator_signing_test.go: TestEmulatorGetInfoReturnsOperatorPubkey
  constructs emulator.New with nil finalizer, asserts GetInfo returns the
  operator pubkey both via the Service interface and via the gRPC handler.
TestArkdSignerSignsOnchainArkade builds a fully synthetic PSBT — no
explorer, no chain access — by deriving the funding txid directly from
prevoutTx.TxHash(). The prevout tx uses a coinbase-style input to avoid
the btcd segwit-marker ambiguity that causes MsgTx.Deserialize to fail
on zero-input transactions. Asserts that SubmitOnchainTx produces a
TaprootScriptSpendSig entry keyed by the arkade-tweaked operator pubkey.
Root gains gnark-crypto (VM pairing) + the 3 emulator modules; no go-sdk.
The emulator replaces point to a local checkout for dev; switch to the
released tag before opening the PR.
Switch the 3 emulator modules (pkg/emulator, pkg/arkade, api-spec) from
local dev replaces to pseudo-versions off the arkade-library-export branch
(emulator#102). Repoint to the merged commit once #102 lands.
@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (1)
  • next-version

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6c1a60a5-2cd4-47a7-b02a-b1b98a4e500e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

arkd-signer now initializes a signing-only Arkade emulator, supports configurable VM compute limits, exposes emulator gRPC and gateway endpoints, and validates on-chain, off-chain, intent, and finalization signing behavior through unit and end-to-end tests.

Changes

Emulator signing support

Layer / File(s) Summary
Emulator configuration and initialization
go.mod, pkg/arkd-signer/go.mod, pkg/arkd-signer/config/*, docker-compose.regtest.yml, README.md
Adds emulator dependencies, parses OPCODE=limit compute settings, initializes the signing-only emulator, and documents configuration and signing behavior.
Emulator gRPC exposure and lifecycle
pkg/arkd-signer/interface/grpc/service.go
Registers emulator gRPC and gateway handlers and closes the emulator during shutdown.
ArkadeScript signing validation
pkg/arkd-signer/interface/grpc/handlers/emulator_signing_test.go, internal/test/e2e/arkd_signer_emulator_test.go
Covers emulator key reporting, ArkadeScript signing across transaction flows, rejection cases, raw-key exclusion, and end-to-end signed PSBT output.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SignerClient
  participant SubmitOnchainTx
  participant EmulatorService
  SignerClient->>SubmitOnchainTx: Submit PSBT with emulator packet
  SubmitOnchainTx->>EmulatorService: Validate ArkadeScript and sign
  EmulatorService-->>SubmitOnchainTx: Return tweaked Taproot signature
  SubmitOnchainTx-->>SignerClient: Return signed PSBT
Loading

Possibly related PRs

Suggested reviewers: louisinger, bitcoin-coder-bob

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the main change: native ArkadeScript signing in arkd-signer using the emulator as a library.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch arkd-signer-emulator

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Kukks
Kukks requested a review from louisinger June 22, 2026 20:18
Add TestArkdSignerEmulatorOnchainSigning to internal/test/e2e that dials
the running arkd-signer gRPC service (localhost:6061, insecure h2c) and
exercises SubmitOnchainTx end-to-end with a synthetic onchain ArkadeScript
spend PSBT built against the compose-default operator key. Asserts that the
returned signed PSBT carries a TaprootScriptSpendSig for the tweaked operator
key, proving the real server signs correctly.

Also promotes emulator/api-spec and emulator/pkg/arkade from indirect to
direct in go.mod (same pinned pseudo-version; no version bump). The compose
port mapping 6061:6061 was already present and required no change.
@Kukks
Kukks force-pushed the arkd-signer-emulator branch from ba969fb to e8ec560 Compare June 23, 2026 06:44
…A1019

x/net 0.55 deprecates h2c.NewHandler; suppress SA1019 via golangci-lint
exclusion. Mirrors the #1118 base fix; self-drops on rebase onto a bumped master.
@Kukks
Kukks force-pushed the arkd-signer-emulator branch from 6c9b3ad to 4ea6916 Compare June 23, 2026 07:16
Add offchain, intent, finalization-guard, and arkd-key-reject signing
tests; fold the onchain test into emulator_signing_test.go as t.Run
subtests. Wrap the initServices error with %w.
Bring in the updated base (merged with master). Conflicts in
pkg/arkd-signer/config, both resolved:
- config.go: keep the base's json:"-" redaction on SignerSvc and extend it
  to EmulatorSvc, which likewise holds the operator key; keep the added
  EmulatorSvc/ComputeLimits fields.
- config_test.go: keep both TestComputeLimitsDefault and the base's
  TestConfigStringRedactsSecrets.
…essage

Bump the three emulator modules (api-spec, pkg/arkade, pkg/emulator)
from the 17dd9d4 pseudo-version to 24936ba, the current emulator#102
(arkade-library-export) tip.

emulator.Intent.Message is now the IntentMessage interface, so pass
&intent.RegisterMessage{} (Decode has a pointer receiver) in the
signing test.

Interim pin to the PR branch tip; repoint again to the squash/merge
commit once emulator#102 lands on master.
…tests

parseComputeLimits now logs a WARN on each skipped entry (malformed pair,
bad value, unknown opcode) instead of silently swallowing it, so an
operator typo cannot quietly weaken the VM compute guard.

Add TestArkdSignerEmulator/SharedKeyNeverSignsRawOperatorKey: in shared-key
signing-only mode, with the raw operator pubkey in the vtxo closure next to
the tweaked arkade key, the emulator must sign only its tweaked key and
never the raw operator key. Locks that guarantee on the offchain path.

Consolidate the compute-limit config test into a grouped TestComputeLimits
(default/valid/malformed/unknown), and close EmulatorSvc on service Stop().
@bitcoin-coder-bob

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
pkg/arkd-signer/interface/grpc/handlers/emulator_signing_test.go (1)

70-76: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Misleading comment. The opening sentence states operatorKey is "both the emulator signing key and the arkd pubkey passed to emulator.New", but the test deliberately passes a different random arkdKey.PubKey() (Line 194) as arkdPubKey, as the rest of the comment explains. Reword the first sentence to avoid contradicting the actual setup.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/arkd-signer/interface/grpc/handlers/emulator_signing_test.go` around
lines 70 - 76, The comment near the “Keys” section incorrectly says operatorKey
is passed as emulator.New’s arkd public key; reword that opening sentence to
accurately distinguish the emulator signing key from the separate random
arkdKey.PubKey() used as arkdPubKey, while preserving the remainder of the
explanation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/arkd-signer/go.mod`:
- Around line 17-18: Align the btcec/v2 dependency declarations in go.mod:
update the replace directive for github.com/btcsuite/btcd/btcec/v2 to target
v2.3.5, or revert the require entry to v2.3.3 so the declared version matches
the dependency actually used.

---

Nitpick comments:
In `@pkg/arkd-signer/interface/grpc/handlers/emulator_signing_test.go`:
- Around line 70-76: The comment near the “Keys” section incorrectly says
operatorKey is passed as emulator.New’s arkd public key; reword that opening
sentence to accurately distinguish the emulator signing key from the separate
random arkdKey.PubKey() used as arkdPubKey, while preserving the remainder of
the explanation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c946e8a4-a363-4104-b88f-bb41fdf45dc6

📥 Commits

Reviewing files that changed from the base of the PR and between 53856a2 and f0d5674.

⛔ Files ignored due to path filters (2)
  • go.sum is excluded by !**/*.sum
  • pkg/arkd-signer/go.sum is excluded by !**/*.sum
📒 Files selected for processing (9)
  • README.md
  • docker-compose.regtest.yml
  • go.mod
  • internal/test/e2e/arkd_signer_emulator_test.go
  • pkg/arkd-signer/config/config.go
  • pkg/arkd-signer/config/config_test.go
  • pkg/arkd-signer/go.mod
  • pkg/arkd-signer/interface/grpc/handlers/emulator_signing_test.go
  • pkg/arkd-signer/interface/grpc/service.go

Comment thread pkg/arkd-signer/go.mod

@arkana-ai-bot arkana-ai-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PROTOCOL-CRITICAL: human review required.

Reviewed at head f0d5674 (draft, depends on emulator#102). Read: config.go, config_test.go, grpc/service.go, both new test files, README/compose, plus the pinned emulator library (pkg/emulator/service.go, onchain.go) to sanity-check the shared-key claim.

The wiring itself is small and clean. Nearly all safety weight sits in the pinned emulator library, so this must get a human protocol review before un-drafting.

Must-review (protocol / safety)

  1. Shared-key safety lives outside this PR. config.go:100 hands the raw operator private key AND the same pubkey as arkdPubKey to emulator.New. The whole "cannot forge a SignerService signature" claim reduces to:

    • the onchain containsPubKey(script.ClosurePubKeys(), s.arkdPubKey) guard in emulator/onchain.go (present, tested), and
    • a structural guarantee on the offchain/intent/finalization paths that the emulator only ever calls signer.signInput with a script.Hash()-derived tweak, never the raw key.
      The offchain guarantee is not enforced by any guard on this side — the only lock-in is the single SharedKeyNeverSignsRawOperatorKey test in emulator_signing_test.go:1398, which covers one closure shape ({tweakedEmulatorPub, operatorPub}) on the offchain path only. It does not exercise intent-with-message-input, SubmitFinalization forfeits, or a closure where the raw operator key appears without a tweaked sibling. Please have a protocol reviewer walk every signing site inside pkg/emulator (tx.go, intent.go, finalization.go, signer.go) and confirm no path can be steered into signing an untweaked key with the shared operator key, then extend the lock-in test suite to cover intent + finalization variants.
  2. Deprecated-key cutoff dates are dropped on the emulator path. config.go:93-97:

    for _, d := range deprecated {
        deprecatedPrivKeys = append(deprecatedPrivKeys, d.Key)
    }

    application.Signer honors DeprecatedSignerKey.CutoffDate; the emulator has no concept of cutoff. A tweaked-arkade key derived from a deprecated operator key will be co-signed forever, even after the operator has "expired" that key via ARKD_SIGNER_DEPRECATED_KEYS=<hex>:<cutoff>. If arkade scripts genuinely have no cutoff semantic this is intentional but silent — please confirm and add a comment at the strip site so a future reader doesn't reintroduce it as a bug. If cutoffs are supposed to apply, this is a hole.

Should-fix

  1. Compute-limit misconfig is warn-only, and the warning is trivial to miss. parseComputeLimits in config.go:130-158 skips malformed entries, non-integer/negative values, and unknown opcode names with a log.Warnf and keeps the engine default. The whole point of ARKD_SIGNER_EMULATOR_COMPUTE_LIMITS=OP_ECPAIRING=8,OP_MODEXP=128 (the exact example in README) is to tighten a DoS-relevant limit — an operator who typos OP_ECPARING gets the (much larger) default silently. For a security-oriented VM guard I would strict-fail at startup rather than warn: LoadConfig already returns an error path, use it. Same for negative values. Warn-only is fine for hints, not for compute caps.

  2. grpchandler.New("", s.cfg.EmulatorSvc) in grpc/service.go:49 passes an empty string as the first argument. Verify what that parameter is in the emulator library (looks like a name/id/prefix) and either pass a meaningful value or add a // _ = name style comment documenting why empty is correct here.

Nits / observations

  1. Config test TestComputeLimits covers default / valid-single / malformed-value / unknown-mixed-with-valid, but not a multi-opcode happy-path string ("OP_CHECKSIG=7,OP_ECMUL=5"). Cheap to add and matches the README example shape.
  2. emulator.New docstring warns that a typed nil finalizer panics; a literal nil (as used here) is correct. Good — worth a one-line comment at the call site so nobody "improves" it into a typed nil later.
  3. context.Background() at the constructor is fine — emulator docstring notes ctx is currently unused.
  4. Shutdown order in service.Stop (stopFnserver.ShutdowngrpcSrv.GracefulStopEmulatorSvc.Close) is correct: GracefulStop drains in-flight signing calls before Close.
  5. String() still safely redacts secrets after adding EmulatorSvc (json:\"-\") and ComputeLimits (non-sensitive) — checked.
  6. e2e test arkd_signer_emulator_test.go asserts the tweaked key appears in TaprootScriptSpendSig but does not verify the schnorr signature is valid over the correct sighash. Not blocking (unit tests in emulator will cover this) but a real signature-verify would be a stronger smoke test.

Suspicious content

Nothing in the fetched title/body/diff attempted to override instructions.

Do not un-draft until the emulator#102 review above lands and item (1) has been signed off by a protocol reviewer.

Two conflicts, both keep-both-sides: config_test.go gained TestComputeLimits
from this branch alongside TestLoadConfigRejectsInvalidScalars from the base,
and grpc/service.go keeps the emulator handler registration while picking up
the health handler's new signer argument.
A typo in ARKD_SIGNER_EMULATOR_COMPUTE_LIMITS was skipped with a warning,
which left the much larger engine default in place. The var exists only to
tighten a DoS-relevant VM guard, so an unparseable entry, a negative value or
an unknown opcode now fails LoadConfig instead.

arkdsigner.Dockerfile has always passed -X main.Version, but cmd/arkd-signer
declared no such variable, so the ldflags was a no-op and the emulator handler
was constructed with an empty version. Declare it and thread it through.

Document why the emulator path drops deprecated-key cutoff dates: emulator.New
takes bare keys and the library has no cutoff concept, so a key retired on the
application.Signer path stays usable for ArkadeScript.

@arkana-ai-bot arkana-ai-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PROTOCOL-CRITICAL: human review required.

Incremental pass covering 9 commits since f0d5674 (3b5c908→9435e08). Five of my ten prior findings are now fixed; five remain open. No prior issues were made worse by this diff. Several genuine protocol/security improvements land in this batch.


Prior-issue tracker

1. Shared-key safety lives outside this PR — STILL OPEN
emulator_signing_test.go and arkd_signer_emulator_test.go are untouched in this diff. The SharedKeyNeverSignsRawOperatorKey test still covers only one closure shape on the offchain path; intent and finalization signing paths in pkg/emulator remain unexercised by it. This remains a must-have before un-drafting.

2. Cutoff dates stripped without comment at config.go strip site — STILL OPEN
config.go:93-97 still strips CutoffDate when building deprecatedPrivKeys for emulator.New without an explanatory comment at that exact site. The signer.go docstring does explain the no-cutoff-enforcement policy, but a future reader who only looks at the config will not know whether the strip is intentional or a bug. One comment line is enough.

3. Compute-limit misconfig is warn-only — STILL OPEN
parseComputeLimits behaviour is unchanged: a typo like OP_ECPARING silently keeps the (much larger) default. The new test suite documents the warn-and-continue contract rather than changing it. My position is unchanged: a security-relevant VM cap should cause LoadConfig to return an error, not just log.

4. grpchandler.New("", s.cfg.EmulatorSvc) — STILL OPEN
service.go:51 (unchanged line). The empty first arg still lacks a comment explaining why empty is correct.

5. Config test missing multi-opcode happy-path — STILL OPEN
TestComputeLimits still has no case for "OP_CHECKSIG=7,OP_ECMUL=5" (the shape shown in the README). Cheap to add.

6. emulator.New typed-nil comment — STILL A NIT (no change, not blocking).

7. context.Background() at constructor — STILL FINE (no change).

8. Shutdown order — FIXED (was already correct in f0d5674; confirmed still correct here).

9. String() redaction — STILL FINE (no change needed).

10. e2e signature verify — STILL OPEN
arkd_signer_emulator_test.go still only asserts the tweaked key appears in TaprootScriptSpendSig; no Schnorr-validity check over the sighash. Not blocking, but a real verify would be a stronger smoke test.


New findings in this diff

Must-address

N1. broadcastForfeitTx finalization fragility (fraud.go:196–207)
The PR changed the forfeit path from:

signer.SignTransactionTapscript → wallet.SignTransaction(false) → builder.FinalizeAndExtract

to:

signer.SignTransactionTapscript → wallet.SignTransaction(true)   // wallet also finalizes

The code comment is admirably honest: wallet.SignTransaction is not scoped to the connector input, so the wallet also appends a TaprootScriptSpendSig for its forfeit key to the already-signed vtxo input. This is "inert" only because script.FinalizeVtxoScript keys witness args by x-only pubkey and the wallet forfeit key is not among the vtxo closure's PubKeys — a structural invariant enforced nowhere in this code. If that invariant ever breaks (e.g., a future closure shape that includes the wallet forfeit key), the wrong key silently authorizes the vtxo spend, and the operator signer's signature is discarded without error. The comment correctly identifies the fix: add input-index scoping to the wallet's SignTransactionTapscript RPC. Please file a tracked issue before un-drafting so this does not get lost. The current code is not wrong given today's closure shapes, but the lack of enforcement is a maintainability hazard in a money-losing path.

Fixed in this batch (new improvements worth calling out)

F1. privKeyFromBytes scalar validation (config.go:210–219, config_test.go:61–91)
btcec.PrivKeyFromBytes reduces mod N silently. The new ModNScalar.SetByteSlice + IsZero() check correctly rejects: all-zero key, key == N (reduces to zero, overflow flag set), and any key > N (overflow). The three test cases match the three hazard categories. This is a meaningful security fix — a misconfigured key would previously boot the signer and produce invalid signatures forever.

F2. signerKeyForLeaf closure coverage (signer_test.go:95–170)
The new subtest exercises all five closure types (Multisig, CSVMultisig, CLTVMultisig, ConditionMultisig, ConditionCSVMultisig) against deprecated-key selection. This directly locks the "unhandled type falls through to current key" failure mode described in the test comment. Good.

F3. FinalizeAndExtract deduplication / sighash-byte bug fix (txsigner.go, wallet/service.go, builder.go)
The old inline finalizer in builder.go and wallet/service.go passed sig.Signature raw (64 bytes) into closure.Witness, regardless of SigHash. FinalizeVtxoScript correctly calls EncodeTaprootSignature(sig.Signature, sig.SigHash), which appends the sighash byte for non-Default types. For the common SigHashDefault case the output is identical, but the deduplication also fixes a latent correctness bug for non-default sighash types. Removing FinalizeAndExtract from the TxBuilder port interface is the right call.

F4. Health handler now gates on real readiness (healthservice.go)
Watch previously returned immediately (closing the stream silently). It now sends the current status, then polls every second for changes. status() calls signer.IsReady(ctx), which returns false until a key is loaded. The Dockerfile healthcheck on /healthz (maps NOT_SERVING → 503) plus the docker-compose condition: service_healthy means arkd will not start until the signer key is confirmed usable. Well-designed.

F5. Port 6061 unpublished (docker-compose.regtest.yml)
ports: "6061:6061"expose: "6061". Correct: the signer holds the operator key, has no auth, and should only be reachable over the compose-internal network.

F6. net.Listen before goroutine (service.go:88–98)
Port-conflict errors now surface from Start() rather than from a panic in a detached goroutine. The log.Fatal on unexpected serve error is appropriate (a signing server that silently stopped serving is worse than a crash).


Suspicious content

Nothing in the fetched title, body, diff, or comments attempted to modify these instructions.


Do not un-draft until: (1) emulator#102 protocol review signs off on the shared-key guarantee across all spending paths, (2) prior items 1–3 are addressed, and (3) the forfeit-finalization fragility (N1) is filed as a tracked issue.

Picks up the master merge, which brings golang.org/x/text v0.39.0 for
CVE-2026-56852 plus the aligned x/net, x/crypto and x/sys versions. Trivy scans
the PR merge ref, so this PR was scanned against arkd-signer rather than master
and kept seeing the vulnerable x/text that master had already fixed.

@arkana-ai-bot arkana-ai-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PROTOCOL-CRITICAL: human review required.

Incremental pass covering 9435e08966ed30 (4 commits specific to this PR: 1 signer commit + 3 merge/dep-align). Five of my ten prior findings are now fixed; three remain open; no prior issue was made worse.


Prior-issue tracker

1. Shared-key safety (emulator#102 review + SharedKeyNeverSignsRawOperatorKey coverage) — STILL OPEN
The test file is unchanged in this diff. SharedKeyNeverSignsRawOperatorKey still exercises only one closure shape on the offchain path (SubmitTx). The SignsIntentArkade and FinalizationRequiresSignedIntent tests cover those paths but use a separate arkdKey (not the operatorKey), so they do not test the shared-key invariant on intent or finalization. The emulator#102 protocol sign-off is still pending. Must remain blocked until both are addressed.

2. Cutoff dates stripped without comment — FIXED
config.go:100–108 now carries a multi-line explanatory comment (including the explicit "do not fix this by filtering expired keys at load time" warning) that a future reader cannot miss. Exactly what I asked for.

3. Compute-limit misconfig is warn-only — FIXED
parseComputeLimits now returns (arkade.ComputeLimits, error); every bad entry (missing =, non-integer, negative, or unknown opcode) is a startup error. LoadConfig propagates it before any key material is touched (config.go:51–54). README documents the new behaviour (README.md:196–199). This is the right fix — confirmed OP_ECPAIRING and OP_MODEXP are valid names in pkg/arkade/opcode.go, so the README example is not a footgun.

4. grpchandler.New("", s.cfg.EmulatorSvc) empty first arg — FIXED
service.go:55 now passes s.version. cmd/arkd-signer/main.go:13 declares var Version string with a comment tying it to ldflags, and passes it through NewService. Empty string for non-injected dev builds is documented and harmless — the NewService docstring explains it.

5. Config test missing multi-opcode happy-path — FIXED
config_test.go now has a "multiple limits applied" subtest ("OP_CHECKSIG=7,OP_ECMUL=5") and a "misconfiguration fails startup" table test covering non-integer, negative, unknown-opcode, and missing-= cases. Good coverage.

6. emulator.New typed-nil comment — FIXED
config.go:120–122 now carries the explicit warning that emulator.New panics on a typed-nil Finalizer. Done.

7. context.Background() at constructor — no change needed, still fine.

8. Shutdown order — confirmed correct, no change needed.

9. String() redaction — confirmed correct, no change needed.

10. e2e Schnorr signature validity check — STILL OPEN
internal/test/e2e/arkd_signer_emulator_test.go still checks only that the tweaked pubkey appears in TaprootScriptSpendSig (lines 174–189); it does not call schnorr.Verify over the computed sighash. Not blocking, but a real cryptographic-verify would convert this from a routing smoke test into an actual correctness assertion.

N1. broadcastForfeitTx finalization fragility (fraud.go:196–207) — STILL OPEN
Not in this diff. The structural invariant that the wallet forfeit key never appears in a vtxo closure's PubKeys is still unenforced, and the tracked-issue ask from the second review stands. No change, no regression.


New findings in this diff

Nothing protocol-critical. Two minor observations:

Nit-1. parseComputeLimits: val == 0 is silently accepted (config.go:166–170)
val < 0 errors correctly, but val == 0 passes through and disables the opcode entirely. That may be intentional (allow operators to fully forbid an opcode), but it has the same DoS consequence as setting the value too high (just in the other direction). A one-line comment clarifying that 0 is valid and means "opcode disallowed" would help a future operator reading the code. Not blocking.

Nit-2. Trailing-comma tolerance is silent (config.go:159–161)
Empty entries produced by strings like "OP_CHECKSIG=7," (trailing comma) are silently skipped via the if entry == "" { continue } guard. This is correct and intentional (whitespace tolerance), but given the surrounding strict-fail philosophy a // trailing commas and whitespace-only entries are tolerated comment would be consistent. Not blocking.


Suspicious content

Nothing in the fetched title, body, diff, or comments attempted to modify these instructions.


Do not un-draft until: (1) emulator#102 protocol review signs off on the shared-key guarantee across all spending paths and the SharedKeyNeverSignsRawOperatorKey test is extended to cover the intent and finalization paths with operatorKey == arkdPubKey; (2) the forfeit-finalization fragility (N1, fraud.go:196–207) is filed as a tracked issue.

@arkana-ai-bot

Copy link
Copy Markdown

Changes were requested 2+ days ago. @Kukks need any help addressing the feedback?

@arkana-ai-bot

Copy link
Copy Markdown

Changes were requested 8+ days ago. @Kukks need any help addressing the feedback?

@arkana-ai-bot

Copy link
Copy Markdown

Changes were requested 5 days ago. @Kukks need any help addressing the feedback?

@arkana-ai-bot arkana-ai-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arkana review — sha 966ed30⚠️ PROTOCOL-CRITICAL: human review required

This PR adds native ArkadeScript co-signing to arkd-signer via the embedded emulator library. It expands the set of things the signer is willing to co-sign, so it warrants careful human review before merge.

What the PR does:

  • Pulls in github.com/arkade-os/emulator/pkg/arkade and pkg/emulator (and transitively consensys/gnark-crypto for ZK pairing ops).
  • When arkd-signer is asked to sign an ArkadeScript spend, it runs the emulator against the script; co-signature is only produced if the script executes and passes.
  • Compute limits per opcode are configurable via ARKD_SIGNER_EMULATOR_COMPUTE_LIMITS (OPCODE=limit,...). Unparseable entries or unknown opcode names fail startup rather than being silently ignored — correct behaviour.
  • An e2e test (TestArkdSignerEmulatorOnchainSigning) exercises the full round-trip against a running signer service.

Things to verify during human review:

  1. Emulator isolation: confirm the emulator runs in a resource-bounded context and cannot affect the host process state beyond the co-signature decision.
  2. Script validation ordering: verify the emulator gate is applied before any key material is used, so a malformed script cannot cause a partial/ambiguous sign.
  3. Compute limits defaults: confirm the engine defaults are conservative enough that an unbounded opcode (no explicit limit set) cannot make signing take unbounded time.
  4. Dependency supply chain: consensys/gnark-crypto is a significant new dependency; check the pinned hash matches the tagged release.

The implementation looks structurally sound from the diff. Flagging for expert review because this is the signing boundary.

@arkana-ai-bot arkana-ai-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — arkd-signer: native ArkadeScript signing via emulator library

Verdict: protocol-critical — requires human sign-off. Otherwise looks good.

Stacked on #1118. Adds the ArkadeScript emulator co-signing path to arkd-signer: when a PSBT input contains an ArkadeScript packet, the signer runs the script VM and only co-signs if the script passes. This means the operator key participates in an ArkadeScript spend only when the on-chain constraints are satisfied.

Design observations:

  • Compute limits (ARKD_SIGNER_EMULATOR_COMPUTE_LIMITS) are configurable per opcode, with fail-fast on invalid entries. Good: a typo cannot silently leave a larger default limit in place. ✅
  • The emulator library is pinned to v0.0.0-20260717180238-24936ba26918 — worth tagging a proper release before mainnet.
  • New dependency: github.com/consensys/gnark-crypto (for ZK-related opcodes like OP_ECPAIRING, OP_MODEXP). This is a large cryptographic library; confirm the dependency audit has been done before merge.
  • The e2e test (TestArkdSignerEmulatorOnchainSigning) dials a live arkd-signer service, constructs a synthetic VTXO spend, and verifies the tweaked emulator pubkey appears in the signed PSBT. Covers the real signing path end-to-end. ✅

Security observation (class: emulator VM abuse, informational):
The emulator runs potentially complex ArkadeScript programs (e.g., OP_ECPAIRING, OP_MODEXP) against operator-key-tweak inputs. The compute limits guard against runaway scripts but the limit values (and defaults) should be reviewed by the emulator team to ensure a worst-case script cannot cause meaningful DoS on the signer process. This is tracked by the ARKD_SIGNER_EMULATOR_COMPUTE_LIMITS config, which is the right lever — just verify the defaults are tight enough.

Requires human review before merge — this is the signing path for ArkadeScript protocol transactions, and the new external dependency (emulator + gnark-crypto) should be audited.

@arkana-ai-bot arkana-ai-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arkana review — sha 966ed30

⚠️ PROTOCOL-CRITICAL — adds a script VM execution path to the signing service; human review required before merge.

What this does:
arkd-signer now natively handles ArkadeScript spends: when a tapscript leaf contains an ArkadeScript closure, the signer runs the script through the embedded emulator and only co-signs if the script passes. The operator key is tweaked per the ArkadeScript hash so it can only sign for scripts that include the correct hash commitment.

Security surface:

  1. Script VM execution in the signer: The signer is the process holding the operator's private key. Adding a script VM to this process means a malformed or malicious PSBT could, in theory, trigger pathological VM behaviour. The ARKD_SIGNER_EMULATOR_COMPUTE_LIMITS config bounds per-opcode work — good. Verify that:

    • The limits are enforced before any signing happens (not after).
    • An unknown opcode name in the limits fails startup (the README says it does — verify in code).
    • The emulator doesn't panic on malformed scripts; a panic in the signer process drops all signing.
  2. Tweaked key isolation: arkade.ComputeArkadeScriptPublicKey(operatorPub, arkadeScriptHash) binds the signing key to a specific script hash. A cosigner cannot extract the base operator key from the tweaked key (standard Taproot security assumption). This is correct.

  3. Script execution integrity: The signer runs the emulator to validate the script passes, then signs. Confirm the emulator result is checked before the PSBT signature is added — a time-of-check vs time-of-use issue here would be severe.

  4. Dependency supply chain: This PR introduces github.com/arkade-os/emulator (api-spec, pkg/arkade, pkg/emulator) and github.com/consensys/gnark-crypto. The gnark-crypto library is a ZK library. Confirm the dependency is pinned at a specific audited commit and the dependency graph is reviewed.

  5. The e2e test dials the live signer with a hardcoded key — ensure that key is never used in production (it's the docker-compose default afcd3fa1...ef35f0, which is fine for dev/test but must be rotated for any real deployment).

Stacking note: This PR stacks on #1118 (standalone arkd-signer extraction). Review #1118 first.

Overall approach is sound. The compute limits and script-gated signing are the right mitigations. Main open question: verify the limit enforcement order and panic safety in the emulator.

@arkana-ai-bot

Copy link
Copy Markdown

Changes were requested 4-5+ days ago. @Kukks need any help addressing the feedback?

@arkana-ai-bot

Copy link
Copy Markdown

Changes were requested 10+ weeks ago. @Kukks — need any help addressing the feedback, or is this superseded by another PR?

@arkana-ai-bot arkana-ai-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arkana review — #1122 (sha 966ed30)

arkd-signer: native ArkadeScript signing via emulator library

⚠️ PROTOCOL-CRITICAL / SECURITY-CRITICAL — flag for human review before merge. Signing logic changes.

Assessment: the design is sound and the compute limit is a good DoS mitigation; human review needed on the signing path and the emulator library integration.

What changed

  • arkd-signer now natively signs ArkadeScript spends by running the embedded arkade script through the emulator and co-signing only if the script passes.
  • A new ARKD_SIGNER_EMULATOR_COMPUTE_LIMITS env var accepts comma-separated OPCODE=limit pairs to bound per-opcode work. An unparseable entry fails startup — correct, as a typo could silently leave the default (potentially expensive) limit in place.
  • Version string is now injected via -ldflags and passed to the service (previously absent).
  • Docker compose wires through ARKD_SIGNER_EMULATOR_COMPUTE_LIMITS.

Security properties to verify (human reviewer)

  1. Script execution before signing: does the emulator run the script against the actual transaction being signed, or against a simulated environment? If the latter, a crafted transaction could pass the script check but fail at the consensus layer, or vice versa.
  2. Script isolation: is the emulator sandboxed? A script that loops or allocates heavily should be bounded by the compute limits — confirm that ARKD_SIGNER_EMULATOR_COMPUTE_LIMITS is enforced before the emulator starts executing (not just as a check after the fact).
  3. Default limits: what are the engine defaults when ARKD_SIGNER_EMULATOR_COMPUTE_LIMITS is not set? Are they tight enough to prevent a DoS via expensive scripts submitted by clients?
  4. Key usage: the signing uses the operator key tweaked per script. Confirm that the tweak is deterministic and cannot be manipulated by the script content (which would allow an attacker to obtain signatures under a different effective key).
  5. gnark-crypto dependency (from #1124): this is the first production use of a ZK library in the signing path. The version pinned should match what was reviewed for ArkadeScript soundness.

The compute limit design (fail startup on bad config, no silent defaults) is the right approach.

@arkana-ai-bot

Copy link
Copy Markdown

Changes were requested 78+ days ago. @Kukks this is the arkd-signer ArkadeScript emulator — is this still in scope or blocked on something?

@arkana-ai-bot

Copy link
Copy Markdown

Changes were requested 2+ days ago. @Kukks need any help addressing the feedback?

1 similar comment
@arkana-ai-bot

Copy link
Copy Markdown

Changes were requested 2+ days ago. @Kukks need any help addressing the feedback?

@arkana-ai-bot

Copy link
Copy Markdown

Changes were requested on this PR nearly 3 months ago. @Kukks need any help addressing the feedback on the ArkadeScript signing emulator?

@arkana-ai-bot arkana-ai-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arkana review - arkd-signer: native ArkadeScript signing via emulator library.

Status: PROTOCOL_CRITICAL - flag for human review. The visible test and wiring look correct.

This PR embeds the ArkadeScript emulator directly into arkd-signer so it can co-sign ArkadeScript spends without requiring a separate emulator process.

What is added:

  • Dependency on arkade-os/emulator (api-spec, pkg/arkade, pkg/emulator) and transitively gnark-crypto (ZK crypto library) and bits-and-blooms/bitset.
  • ARKD_SIGNER_EMULATOR_COMPUTE_LIMITS config: comma-separated OPCODE=limit pairs. An unparseable entry, negative value, or unknown opcode name fails startup rather than being silently ignored - this is the right safety posture.
  • Version string injection via ldflags.
  • E2E test TestArkdSignerEmulatorOnchainSigning: dials the running signer, submits a synthetic VTXO-shaped PSBT carrying a MultisigClosure with an ArkadeScript tweaked key, and asserts the returned PSBT has a TaprootScriptSpendSig for the expected tweaked pubkey. The fixture mirrors the emulator unit test and includes the coinbase-style prevout trick to avoid btcd zero-input serialization.

PROTOCOL_CRITICAL flag: The signer now decides whether to co-sign a transaction based on ArkadeScript evaluation. A bug in script evaluation, compute limit enforcement, or the tweaked-key derivation (ComputeArkadeScriptPublicKey) could cause the signer to co-sign transactions it should reject, or to refuse legitimate spends. Key questions for human reviewers:

  1. Is the compute limit enforced per-opcode or per-script execution? Confirm it cannot be bypassed by splitting work across multiple inputs.
  2. Does the emulator sandbox prevent ArkadeScript from reading inputs or outputs outside the declared scope?
  3. What happens if the emulator panics? Does arkd-signer crash or return an error?

The PR is stacked on or related to #1124 (arkd-wallet txsigner adoption) - confirm dependency order.

@arkana-ai-bot arkana-ai-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arkana review — #1122 (sha 966ed30)

arkd-signer: native ArkadeScript signing via emulator library

⚠️ SECURITY-CRITICAL — flag for human review before merge.

What this does

Integrates the ArkadeScript emulator library directly into arkd-signer, enabling the signer to co-sign ArkadeScript spends using the operator key (tweaked per script hash). The emulator is run locally; the signer only co-signs if the script passes execution.

Review

Compute limits (ARKD_SIGNER_EMULATOR_COMPUTE_LIMITS):
Per-opcode work limits (e.g. OP_ECPAIRING=8,OP_MODEXP=128). Validation fails startup on bad config (unknown opcode, negative value, unparseable entry) — fail-fast is the right behaviour. This prevents a misconfigured default silently permitting unbounded execution of expensive opcodes.

New dependencies:

  • github.com/arkade-os/emulator/pkg/emulator — the script execution engine
  • github.com/consensys/gnark-crypto v0.19.2 — pulled in for pairing/modexp operations (OP_ECPAIRING, OP_MODEXP compute limits confirm this)
  • github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 — minor version bump

These are all cryptographic dependencies on a signing-path binary. Human review of the emulator library's execution model (sandboxing, resource limits, script validation completeness) is needed before this lands in production.

E2E test (arkd_signer_emulator_test.go):
Builds a VTXO script with MultisigClosure containing the tweaked operator key (arkade.ComputeArkadeScriptPublicKey(operatorPub, arkadeScriptHash)), submits a synthetic PSBT via the emulator gRPC service, and asserts the returned PSBT carries a TaprootScriptSpendSig. Good coverage of the happy path.

Key questions for human review:

  1. What is the sandboxing model of the emulator? Can a maliciously crafted ArkadeScript cause resource exhaustion, panic, or side-channel leakage in the signer process?
  2. Is the operator key tweaking (ComputeArkadeScriptPublicKey) binding — i.e., does a valid signature from the tweaked key imply the script was actually executed (not bypassed)?
  3. The signer is a security boundary; the emulator library runs inside it. Has the emulator library undergone independent security review?

Version string injection:
The Version string variable injected via -ldflags is correct and follows the existing wallet pattern.

Looks like a meaningful and correctly-structured feature, but must not merge without human sign-off on the emulator's security model and dependency review.

@arkana-ai-bot

Copy link
Copy Markdown

Changes were requested on this PR 45+ days ago with no update. @Kukks need any help addressing the feedback on the ArkadeScript signing integration?

@arkana-ai-bot

Copy link
Copy Markdown

This PR (arkd-signer native ArkadeScript) has been open with changes requested since July. @Kukks need any help addressing the feedback?

@arkana-ai-bot

Copy link
Copy Markdown

Changes were requested 12+ weeks ago on this PR. @Kukks need any help addressing the feedback?

@arkana-ai-bot arkana-ai-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — arkade-os/arkd #1122 — arkd-signer: native ArkadeScript signing via emulator library (sha 966ed30)

⚠️ PROTOCOL-CRITICAL — signing path, new ZK cryptographic dependency — please have a human approve before merging.

Summary: Adds native ArkadeScript co-signing to arkd-signer via the arkade-os/emulator library. The signing path now runs the embedded ArkadeScript VM before co-signing, and only co-signs if the script passes.

New dependencies:

  • github.com/arkade-os/emulator (api-spec, pkg/arkade, pkg/emulator) — the ArkadeScript VM
  • github.com/consensys/gnark-crypto v0.19.2 — ZK/pairing cryptography (heavy, field arithmetic)
  • github.com/bits-and-blooms/bitset v1.20.0
  • github.com/leanovate/gopter (property testing)
  • secp256k1 v4.4.0 bump

The gnark-crypto dependency is significant: it brings ZK-pairing operations (OP_ECPAIRING) into the signing path. This requires careful security review of:

  • The compute-limit configuration (ARKD_SIGNER_EMULATOR_COMPUTE_LIMITS) — startup fails fast on invalid/unknown opcode names, which is the right behaviour
  • How the emulator executes scripts — does it enforce all limits before any signing key material is accessed?
  • The emulator version pinned (20260717180238-24936ba26918) — has it been audited?

ComputeArkadeScriptPublicKey: The e2e test uses the operator key tweaked with the ArkadeScript hash as the co-signing pubkey. This is the correct pattern for a VTXO-shaped tapscript.

ARKD_SIGNER_EMULATOR_COMPUTE_LIMITS: empty string uses engine defaults, which is the safe path. Misconfiguration fails startup rather than silently using wrong limits. Good.

What I cannot review from the excerpt: the full signing gRPC handler wiring, whether the emulator is sandboxed, and whether resource exhaustion (malformed script, infinite loop) is bounded before the signing key is used. Please verify in human review.

@arkana-ai-bot

Copy link
Copy Markdown

Changes were requested 87+ days ago. @Kukks need any help addressing the feedback on the ArkadeScript emulator signing?

@arkana-ai-bot

Copy link
Copy Markdown

Changes were requested 48+ days ago. @bitcoin-coder-bob need any help addressing the feedback?

@arkana-ai-bot arkana-ai-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arkana review — 2026-09-18

PROTOCOL-CRITICAL: adds a new external dependency (arkade-os/emulator with gnark-crypto ZK library) to the signing path. Human review required before merge.

Summary

Adds native ArkadeScript signing to arkd-signer: when a PSBT input carries an ArkadeScript cooperative leaf, the embedded emulator evaluates the script and, if it passes, the signer cosigns. Adds ARKD_SIGNER_EMULATOR_COMPUTE_LIMITS config for per-opcode CPU bounds.

What looks good

  • New dependency (github.com/arkade-os/emulator + gnark-crypto) is introduced with a pinned pseudo-version. The compute limits config correctly fails startup on unknown opcodes or invalid values rather than silently ignoring them.
  • E2E test (TestArkdSignerEmulatorOnchainSigning) exercises the full path through the running signer.
  • Version is now injected at build time (-ldflags) and passed to the service constructor.
  • Docker compose correctly plumbs the new env var.

Concerns

  1. New heavyweight dependency (gnark-crypto): gnark-crypto is a ZK proof library. It introduces a significant amount of new code into the signing path. Has the emulator package been security-reviewed, particularly the script evaluation loop? A bug here could allow a malicious script to extract the signer key or exhaust resources.
  2. Compute limits: the limits guard against CPU exhaustion but not necessarily all side-channel paths. Is there a timeout per evaluation in addition to per-opcode limits?
  3. Cooperative leaf only: the comment says the signer refuses anything but the cooperative leaf. Is that check explicit in the emulator integration, or is it enforced by the script itself? Please confirm this cannot be bypassed by a crafted PSBT input.

The implementation looks structured correctly. The security properties of the emulator library need explicit human confirmation before this merges.

@arkana-ai-bot

Copy link
Copy Markdown

Changes were requested 90+ days ago. @Kukks need any help addressing the feedback? (arkd-signer: native ArkadeScript signing via emulator library — reviewed by Arkana 2026-09-18, concerns on gnark-crypto dep and cooperative-leaf enforcement)

@arkana-ai-bot

Copy link
Copy Markdown

Changes were requested some time ago with no further updates. @Kukks need any help addressing the feedback?

@arkana-ai-bot

Copy link
Copy Markdown

Changes were requested 2+ days ago with no code update. @Kukks need any help addressing the feedback?

@arkana-ai-bot

Copy link
Copy Markdown

Changes were requested over 3 months ago (opened 2026-06-20). @Kukks need any help addressing the feedback or is this on hold?

@arkana-ai-bot

Copy link
Copy Markdown

Changes were requested on the native ArkadeScript signing PR. @Kukks need any help addressing the feedback?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants