> ## Documentation Index
> Fetch the complete documentation index at: https://ckbfans.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Sign Message

> Request an arbitrary message signature from the connected wallet and verify it. Works across all supported chain types: EVM, BTC, CKB, Nostr, and Doge.

CCC provides a unified message signing and verification API across all supported wallet types. The same code works whether the user is connected through MetaMask, JoyID, UniSat, OKX, Nostr, or a native CKB wallet — CCC handles the chain-specific encoding internally.

## How it works

When you call `signer.signMessage()`, CCC:

1. Encodes the message according to the connected chain's convention (e.g. EIP-191 for EVM, BIP-322 for BTC).
2. Asks the wallet to sign it.
3. Returns a `Signature` object containing the raw signature string, the signer's identity, and the sign type.

The static `ccc.Signer.verifyMessage()` method understands all supported sign types and dispatches to the correct verification function automatically.

## Supported sign types

| Sign type      | Wallets                        |
| -------------- | ------------------------------ |
| `EvmPersonal`  | MetaMask, OKX (EVM)            |
| `BtcEcdsa`     | UniSat, OKX (BTC), UTXO Global |
| `JoyId`        | JoyID                          |
| `NostrEvent`   | Nostr                          |
| `CkbSecp256k1` | CKB native wallets             |
| `DogeEcdsa`    | Doge wallets                   |

## Sign a message

Call `signer.signMessage()` with a string or byte array. The method returns a `Signature` object.

```typescript sign.ts theme={null}
import { ccc } from "@ckb-ccc/ccc";

const message = "Hello world";

// Sign the message with the connected wallet
const signature = await signer.signMessage(message);

console.log("Signature:", signature.signature);
console.log("Identity:", signature.identity);
console.log("Sign type:", signature.signType);
```

### The Signature object

| Field       | Type             | Description                                                             |
| ----------- | ---------------- | ----------------------------------------------------------------------- |
| `signature` | `string`         | The raw signature produced by the wallet.                               |
| `identity`  | `string`         | The signer's address or public key, used to verify ownership.           |
| `signType`  | `SignerSignType` | Identifies the signing algorithm so the verifier knows how to check it. |

## Verify a signature

### Static verification

Use the static `ccc.Signer.verifyMessage()` method when you have a `Signature` object and want to check it without a signer instance. This is useful on the server side or when verifying signatures from other users.

```typescript theme={null}
import { ccc } from "@ckb-ccc/ccc";

const isValid = await ccc.Signer.verifyMessage(message, signature);
console.log(`Verification result: ${isValid}`); // true or false
```

### Instance verification

Call `signer.verifyMessage()` on the signer instance when you want to check that the current signer produced the signature.

```typescript theme={null}
// Verify that the same signer produced the signature
const isValid = await signer.verifyMessage(message, signature);
```

Pass a raw string instead of a `Signature` object to verify a bare signature string using the current signer's sign type and identity:

```typescript theme={null}
const isValid = await signer.verifyMessage(message, signature.signature);
```

## Full example

```typescript sign.ts theme={null}
import { ccc } from "@ckb-ccc/ccc";

async function signAndVerify(signer: ccc.Signer) {
  const message = "Hello world";

  // Sign the message
  const signature = await signer.signMessage(message);
  console.log("Signature:", signature);

  // Verify with the correct message — should be true
  const valid = await ccc.Signer.verifyMessage(message, signature);
  console.log(`Verification should pass: ${valid}`);

  // Verify with a wrong message — should be false
  const invalid = await ccc.Signer.verifyMessage("Wrong message", signature);
  console.log(`Verification should fail: ${invalid}`);
}
```

## In a React component

```tsx sign-button.tsx theme={null}
"use client";

import { useState } from "react";
import { ccc } from "@ckb-ccc/connector-react";

export function SignButton() {
  const signer = ccc.useSigner();
  const [result, setResult] = useState<string | null>(null);

  async function handleSign() {
    if (!signer) return;

    const message = "Hello from CCC!";
    const signature = await signer.signMessage(message);

    const isValid = await ccc.Signer.verifyMessage(message, signature);
    setResult(isValid ? "Signature verified" : "Verification failed");
  }

  return (
    <div>
      <button onClick={handleSign} disabled={!signer}>
        Sign message
      </button>
      {result && <p>{result}</p>}
    </div>
  );
}
```

<Note>
  The `Signature` object must be serialized and stored if you want to verify it later (for example in a backend or on-chain). Serialize it with `JSON.stringify(signature)` and restore it with `JSON.parse()`.
</Note>

## Next steps

<CardGroup cols={2}>
  <Card title="Send CKB" icon="paper-plane" href="/guides/send-ckb">
    Move beyond signing messages and compose a full transfer transaction.
  </Card>

  <Card title="Connect Wallet" icon="wallet" href="/guides/connect-wallet">
    Learn how to set up the wallet connector and retrieve a signer.
  </Card>
</CardGroup>
