<!-- tempo-docs-context -->
> Source: [/docs/sdk/foundry/signature-verifier](https://tempo.xyz/developers/docs/sdk/foundry/signature-verifier.md)
> Section: [Get Started](https://tempo.xyz/developers/get-started.md). Choose a starting point, send a test payment, get testnet funds, connect a coding agent, find the SDKs and CLI, and use the resource guides to plan payment workflows, liquidity, provider selection, and partner integrations.
> [Documentation index](https://tempo.xyz/developers/llms.txt) · [Docs skill](https://tempo.xyz/developers/SKILL.md)

> Tempo MCP: Use `search`, `find_pages`, `read_page`, and `code` at `https://mcp.tempo.xyz` for Tempo and related documentation.
> If an indexed page is missing or reflects an older site, read this site’s [documentation index](https://tempo.xyz/developers/llms.txt) and Markdown pages directly.

# Signature Verification with Foundry

The [`SignatureVerifier` precompile](https://github.com/tempoxyz/tempo/blob/main/tips/tip-1020.md) is available on Tempo. It provides signature verification for secp256k1, P256, and WebAuthn through a single interface — no custom verifier contracts needed.

The Foundry project template for Tempo ships with a working example that demonstrates signature verification in a relayed mail contract. Initialize it with:

```bash
forge init --template tempo my-project && cd my-project
```

## How signature verification works in Foundry

The template's `Mail` contract supports two modes:

1. **Direct** — call `sendMail()` yourself (`msg.sender` is the sender).
2. **Relayed** — sign a mail off-chain and let anyone deliver it on-chain.

Relayed mode uses the `SignatureVerifier` precompile to verify the sender's signature. Unlike Ethereum's `ecrecover`, the precompile:

* Supports secp256k1, P256, and WebAuthn signature types
* Reverts on malformed or cryptographically invalid signatures; `verify` returns `false` when a valid signature belongs to a different signer
* Maintains forward compatibility with future Tempo account types

:::info[T6 keychain verification]
On T6 networks, `verifyKeychain(account, digest, signature)` checks an active access-key signature. `verifyKeychainAdmin(account, digest, signature)` checks a root-key or admin-key signature. Both require the V2 keychain signature encoding; neither checks token budgets or call scopes. Include chain ID, contract address, and account address in the digest you ask users or keys to sign.
:::

## Contract example

The key pattern is a single `verify()` or `recover()` call on the precompile:

```solidity
import {StdPrecompiles} from "tempo-std/StdPrecompiles.sol";

// Option 1: verify — returns true/false, reverts on malformed signatures
require(
    StdPrecompiles.SIGNATURE_VERIFIER.verify(from, hash, signature),
    "invalid signature"
);

// Option 2: recover — returns the signer address, reverts on malformed signatures
require(
    StdPrecompiles.SIGNATURE_VERIFIER.recover(hash, signature) == from,
    "invalid signature"
);
```

This excerpt from the template’s `Mail` contract combines verification with a per-sender nonce to prevent replay. The template defines the token, attachment type, and events:

```solidity
contract Mail {
    ITIP20 public token;
    mapping(address => uint256) public nonces;

    /// @notice Send mail on behalf of `from` using their off-chain Tempo signature.
    function sendMail(
        address from,
        address to,
        string memory message,
        Attachment memory attachment,
        bytes calldata signature
    ) external {
        bytes32 hash = getDigest(from, to, message, attachment);
        require(
            StdPrecompiles.SIGNATURE_VERIFIER.verify(from, hash, signature),
            "invalid signature"
        );
        nonces[from]++;
        token.transferFromWithMemo(from, to, attachment.amount, attachment.memo);
        emit MailSent(from, to, message, attachment);
    }

    function getDigest(address from, address to, string memory message, Attachment memory attachment)
        public view returns (bytes32)
    {
        return keccak256(
            abi.encode(address(this), block.chainid, from, to, message, attachment, nonces[from])
        );
    }
}
```

## Test signature verification in Foundry

The template includes tests for both signature types. Tempo support is enabled by the template's Foundry config. If you copy this pattern into an existing project, make sure `foundry.toml` enables Tempo mode:

```toml
[profile.default]
tempo = true
```

### secp256k1

```solidity
contract MailRelayTest is MailTest {
    uint256 internal constant ALICE_PK = 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80;

    function test_SendMailWithSecp256k1Signature() public {
        bytes32 digest = mail.getDigest(ALICE, BOB, message, attachment);
        (uint8 v, bytes32 r, bytes32 s) = vm.sign(ALICE_PK, digest);

        mail.sendMail(ALICE, BOB, message, attachment, abi.encodePacked(r, s, v));
        assertEq(mail.nonces(ALICE), 1);
    }
}
```

### P256

```solidity
uint256 internal constant CAROL_P256_PK = 0x1;

function setUp() public override {
    super.setUp();
    (uint256 x, uint256 y) = vm.publicKeyP256(CAROL_P256_PK);
    carolPubX = bytes32(x);
    carolPubY = bytes32(y);
    CAROL = address(uint160(uint256(keccak256(abi.encodePacked(x, y)))));
}

function test_SendMailWithP256Signature() public {
    bytes32 digest = mail.getDigest(CAROL, BOB, message, attachment);
    (bytes32 r, bytes32 s) = vm.signP256(CAROL_P256_PK, digest);
    s = _normalizeP256S(s); // low-s normalization required by the precompile

    bytes memory sig = abi.encodePacked(carolPubX, carolPubY, r, s);
    mail.sendMail(CAROL, BOB, message, attachment, sig);
    assertEq(mail.nonces(CAROL), 1);
}
```

## Run the tests

```bash
forge test -vvv
```

The secp256k1 and P256 relay tests use Tempo mode through the template's Foundry config.

## Related signature verification docs

* [Signature verification specification](https://github.com/tempoxyz/tempo/blob/main/tips/tip-1020.md)
* [T6 Network Upgrade](https://tempo.xyz/developers/docs/protocol/upgrades/t6)
* [Foundry for Tempo](https://tempo.xyz/developers/docs/sdk/foundry)
