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

# Verify Signatures Without Wallet

> Verify message signatures using only a Spark address, without initializing a wallet.

Verify message signatures without creating a wallet instance. This is useful for readonly verification scenarios where you only have access to a Spark address.

## Use Case

When building applications that need to verify signatures but don't have access to wallet credentials:

* Readonly wallet views
* Signature verification services
* Cross-chain verification (verifying Spark signatures from other chains)
* Server-side verification without sensitive key material

## How It Works

Spark addresses encode the wallet's identity public key. You can extract this key using `decodeSparkAddress` and verify signatures directly with secp256k1.

## Implementation

```typescript theme={null}
import { decodeSparkAddress } from "@buildonspark/spark-sdk";
import * as secp256k1 from "@noble/secp256k1";

// Extract identity public key from Spark address
const { identityPublicKey } = decodeSparkAddress(address, network);

// Verify the signature
const isValid = secp256k1.verify(signature, message, identityPublicKey);
```

## Parameters

<ResponseField name="address" type="string" required>
  The Spark address to extract the identity public key from
</ResponseField>

<ResponseField name="network" type="NetworkType" required>
  The network type (`MAINNET`, `TESTNET`, `SIGNET`, `REGTEST`, or `LOCAL`)
</ResponseField>

<ResponseField name="signature" type="Uint8Array | string" required>
  The signature to verify
</ResponseField>

<ResponseField name="message" type="Uint8Array | string" required>
  The original message that was signed
</ResponseField>

## Full Example

```typescript theme={null}
import { decodeSparkAddress } from "@buildonspark/spark-sdk";
import type { NetworkType } from "@buildonspark/spark-sdk";
import * as secp256k1 from "@noble/secp256k1";
import { sha256 } from "@noble/hashes/sha256";

async function verifySparkSignature(
  address: string,
  message: string,
  signature: string,
  network: NetworkType = "MAINNET"
): Promise<boolean> {
  // Decode address to get identity public key
  const { identityPublicKey } = decodeSparkAddress(address, network);

  // Hash the message (signatures are typically over message hashes)
  const messageHash = sha256(new TextEncoder().encode(message));

  // Convert signature from hex if needed
  const sigBytes = typeof signature === "string"
    ? Uint8Array.from(Buffer.from(signature, "hex"))
    : signature;

  // Verify using secp256k1
  return secp256k1.verify(sigBytes, messageHash, identityPublicKey);
}

// Usage
const isValid = await verifySparkSignature(
  "sp1qw508d6qejxtdg4y5r3zarvary0c5xw7k...",
  "Hello, Spark!",
  "304402..."
);
console.log("Signature valid:", isValid);
```

## Key Points

<CardGroup cols={2}>
  <Card title="No Wallet Required" icon="key">
    `decodeSparkAddress` is exported directly from the SDK and doesn't require wallet initialization
  </Card>

  <Card title="Lightweight" icon="feather">
    Only needs the SDK and a secp256k1 library—no sensitive data or network calls
  </Card>
</CardGroup>

## Related

* [signMessageWithIdentityKey](/api-reference/wallet/sign-message-with-identity-key) - Sign messages with wallet
* [validateMessageWithIdentityKey](/api-reference/wallet/validate-message-with-identity-key) - Validate with wallet instance
* [getIdentityPublicKey](/api-reference/wallet/get-identity-public-key) - Get identity key from wallet
