Skip to content

feat: hash and sign schnorr function#3509

Open
pavanjoshi914 wants to merge 3 commits intomasterfrom
sign-schnorr-message
Open

feat: hash and sign schnorr function#3509
pavanjoshi914 wants to merge 3 commits intomasterfrom
sign-schnorr-message

Conversation

@pavanjoshi914
Copy link
Contributor

@pavanjoshi914 pavanjoshi914 commented Mar 10, 2026

sign schnorr message function.
shows plaintext before signing in prompt
we have new function at provider level. but in backend we still use same signSchnorrOrPrompt furnction
if plaintext passed, hash and sign schnorr

Summary by CodeRabbit

  • New Features

    • Added direct message signing (plaintext) alongside existing hash-based signing.
    • Confirmation prompts now show the plaintext message when available, falling back to the hash if not.
  • Bug Fixes / Behavior

    • Permission prompts and "don't ask" choices now respect message vs. hash signing modes and apply remember settings appropriately.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 10, 2026

📝 Walkthrough

Walkthrough

Adds plaintext message signing alongside existing sigHash signing: request type allows an optional message, the UI shows plaintext when present, the background action branches on message vs sigHash, and new hashAndSignSchnorr methods perform message hashing+Schnorr signing.

Changes

Cohort / File(s) Summary
Types
src/types.ts
Make MessageSignSchnorr.args.sigHash optional and add optional message?: string to permit either sigHash or plaintext message signing.
UI Confirmation
src/app/screens/Nostr/ConfirmSignSchnorr.tsx
Read optional navState.args?.message and display plaintext if present, otherwise fall back to sigHash (now possibly undefined).
Action Handler
src/extension/background-script/actions/nostr/signSchnorrOrPrompt.ts
Branch into message-mode when message arg present; validate message or sigHash accordingly; derive isMessageMode/plaintext; use local permissionMethod variable for permission checks and grants; call appropriate signing path.
Core Nostr Implementation
src/extension/background-script/nostr/index.ts
Add async hashAndSignSchnorr(message: string): Promise<string> which UTF-8 encodes plaintext, computes SHA-256 via crypto.subtle.digest, signs the hash with Schnorr using the instance private key, and returns hex signature.
Provider API
src/extension/providers/nostr/index.ts
Add async hashAndSignSchnorr(message: string) that enables the provider and delegates to signSchnorrOrPrompt with { message }.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant NostrProvider
    participant ActionHandler as signSchnorrOrPrompt
    participant Nostr

    Client->>NostrProvider: hashAndSignSchnorr(plaintext)
    activate NostrProvider
    NostrProvider->>NostrProvider: enable()
    NostrProvider->>ActionHandler: execute("signSchnorrOrPrompt", { message })
    deactivate NostrProvider

    activate ActionHandler
    ActionHandler->>ActionHandler: Detect message mode (isMessageMode=true)
    ActionHandler->>ActionHandler: Validate plaintext
    ActionHandler->>ActionHandler: Check/request permissionMethod
    alt Permission Granted
        ActionHandler->>Nostr: hashAndSignSchnorr(plaintext)
        activate Nostr
        Nostr->>Nostr: TextEncoder -> bytes
        Nostr->>Nostr: crypto.subtle.digest("SHA-256")
        Nostr->>Nostr: schnorr.sign(hash, privateKey)
        Nostr-->>ActionHandler: signature (hex)
        deactivate Nostr
        ActionHandler-->>NostrProvider: signature
    else Permission Denied
        ActionHandler-->>NostrProvider: error
    end
    deactivate ActionHandler
    NostrProvider-->>Client: signature or error
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰
I nibble bytes and hum a tune,
Plaintext hops beneath the moon,
Hash then Schnorr—my little art,
Signatures born from carrot-heart,
Hooray for messages that start! 🥕✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description covers the core functionality but lacks structured detail following the repository template. Follow the template with explicit sections: 'Describe the changes', 'Type of change' (feat/fix), testing details, and checklist completion.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat: hash and sign schnorr function' accurately captures the main change—adding a new function to hash and sign Schnorr messages. It is concise, clear, and directly related to the primary objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sign-schnorr-message
📝 Coding Plan
  • Generate coding plan for human review comments

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 and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/app/screens/Nostr/ConfirmSignSchnorr.tsx (1)

97-102: ⚠️ Potential issue | 🟠 Major

Use a prompt view that preserves the exact message.

ContentMessage was fine for a fixed-length hash, but it is not safe for arbitrary plaintext here. In src/app/components/ContentMessage/index.tsx, Line 13 the body is clamped to 8 lines and only renders truthy content, so long messages can be truncated and empty messages disappear. It also does not preserve whitespace/newlines verbatim, which matters in a signing flow where users need to review the exact payload they are approving.

A dedicated scrollable pre/whitespace-pre-wrap view would be safer here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/screens/Nostr/ConfirmSignSchnorr.tsx` around lines 97 - 102, Replace
the ContentMessage usage in ConfirmSignSchnorr.tsx with a dedicated preformatted
prompt view that preserves the exact message and is scrollable: stop using
ContentMessage (which clamps to 8 lines and drops falsy content in
src/app/components/ContentMessage/index.tsx) and instead render the payload
(plaintext || sigHash || "") inside a container that uses a <pre>-style
rendering (CSS white-space: pre-wrap or pre; overflow: auto; allow text
selection) so whitespace/newlines are preserved verbatim, long messages aren’t
truncated, and empty strings still render visibly for user review.
🧹 Nitpick comments (1)
src/types.ts (1)

564-565: Make the Schnorr payload shape mutually exclusive.

With both properties optional, {} and { sigHash, message } are both valid MessageSignSchnorr payloads. That pushes avoidable ambiguity into signSchnorrOrPrompt at runtime. An exclusive union keeps invalid request shapes out of the type system.

💡 Possible typing update
 export interface MessageSignSchnorr extends MessageDefault {
-  args: {
-    sigHash?: string;
-    message?: string;
-  };
+  args:
+    | {
+        sigHash: string;
+        message?: never;
+      }
+    | {
+        message: string;
+        sigHash?: never;
+      };
   action: "signSchnorr";
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/types.ts` around lines 564 - 565, The MessageSignSchnorr payload
currently allows both sigHash and message to be optional which permits ambiguous
shapes like {} or both fields present; update the MessageSignSchnorr type to an
exclusive union so callers must provide either a sigHash or a message but not
both (e.g., one branch declares sigHash: string with message?: never and the
other declares message: string with sigHash?: never) so signSchnorrOrPrompt and
related code can rely on a single valid shape at compile time.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/extension/background-script/actions/nostr/signSchnorrOrPrompt.ts`:
- Around line 26-35: The code uses !!plaintext to set isMessageMode which treats
an empty string as absent; instead detect presence of the field (e.g., check
whether "message" exists on message.args) to decide mode, then validate its type
only if provided. Update the logic in signSchnorrOrPrompt (look for plaintext,
isMessageMode, message.args.message and sigHash) so that isMessageMode =
("message" in message.args) or similar, and keep the existing type checks but
only run the string check for plaintext when the field is present; leave sigHash
validation for the hash mode unchanged.

---

Outside diff comments:
In `@src/app/screens/Nostr/ConfirmSignSchnorr.tsx`:
- Around line 97-102: Replace the ContentMessage usage in ConfirmSignSchnorr.tsx
with a dedicated preformatted prompt view that preserves the exact message and
is scrollable: stop using ContentMessage (which clamps to 8 lines and drops
falsy content in src/app/components/ContentMessage/index.tsx) and instead render
the payload (plaintext || sigHash || "") inside a container that uses a
<pre>-style rendering (CSS white-space: pre-wrap or pre; overflow: auto; allow
text selection) so whitespace/newlines are preserved verbatim, long messages
aren’t truncated, and empty strings still render visibly for user review.

---

Nitpick comments:
In `@src/types.ts`:
- Around line 564-565: The MessageSignSchnorr payload currently allows both
sigHash and message to be optional which permits ambiguous shapes like {} or
both fields present; update the MessageSignSchnorr type to an exclusive union so
callers must provide either a sigHash or a message but not both (e.g., one
branch declares sigHash: string with message?: never and the other declares
message: string with sigHash?: never) so signSchnorrOrPrompt and related code
can rely on a single valid shape at compile time.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fa3aa9d3-287a-4b94-a5dd-65ae573e2d28

📥 Commits

Reviewing files that changed from the base of the PR and between b611684 and 4911798.

📒 Files selected for processing (5)
  • src/app/screens/Nostr/ConfirmSignSchnorr.tsx
  • src/extension/background-script/actions/nostr/signSchnorrOrPrompt.ts
  • src/extension/background-script/nostr/index.ts
  • src/extension/providers/nostr/index.ts
  • src/types.ts

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/extension/background-script/actions/nostr/signSchnorrOrPrompt.ts (1)

69-72: ⚠️ Potential issue | 🟠 Major

Await the bulk permission writes before returning.

forEach(async ...) does not wait for addPermissionFor() to finish. DONT_ASK_ANY can return before all permissions are persisted, and any rejection here will be unhandled. The user-visible failure mode is that prompts may still appear after selecting "don't ask any".

💡 Suggested fix
       if (promptResponse.data.permissionOption == DONT_ASK_ANY) {
-        Object.values(PermissionMethodNostr).forEach(async (permission) => {
-          await addPermissionFor(permission, host, promptResponse.data.blocked);
-        });
+        await Promise.all(
+          Object.values(PermissionMethodNostr).map((permission) =>
+            addPermissionFor(permission, host, promptResponse.data.blocked)
+          )
+        );
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/extension/background-script/actions/nostr/signSchnorrOrPrompt.ts` around
lines 69 - 72, The current use of forEach with an async callback means
addPermissionFor calls for DONT_ASK_ANY (PermissionMethodNostr) are not awaited
and rejections are unhandled; change this to either map the
PermissionMethodNostr values to an array of promises and await Promise.all(...)
or use a for...of loop and await each addPermissionFor(permission, host,
promptResponse.data.blocked) so that all permission writes complete (and any
errors are caught/handled) before returning from signSchnorrOrPrompt.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/extension/background-script/actions/nostr/signSchnorrOrPrompt.ts`:
- Around line 69-72: The current use of forEach with an async callback means
addPermissionFor calls for DONT_ASK_ANY (PermissionMethodNostr) are not awaited
and rejections are unhandled; change this to either map the
PermissionMethodNostr values to an array of promises and await Promise.all(...)
or use a for...of loop and await each addPermissionFor(permission, host,
promptResponse.data.blocked) so that all permission writes complete (and any
errors are caught/handled) before returning from signSchnorrOrPrompt.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e1d3e47e-8f57-4e30-b8f7-a12b781c466c

📥 Commits

Reviewing files that changed from the base of the PR and between 4911798 and a9d1136.

📒 Files selected for processing (3)
  • src/extension/background-script/actions/nostr/signSchnorrOrPrompt.ts
  • src/extension/background-script/nostr/index.ts
  • src/extension/providers/nostr/index.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/extension/background-script/nostr/index.ts
  • src/extension/providers/nostr/index.ts

@pavanjoshi914 pavanjoshi914 changed the title feat: sign schnorr message function feat: hash and sign schnorr function Mar 13, 2026
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.

2 participants