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

# Digital Signature Module

> Learn how the Digital Signature Module detects signature replay attacks, forgery, and unauthorized access vulnerabilities in smart contracts.

## Overview

The Digital Signature Module analyzes how contracts handle cryptographic signatures, detecting vulnerabilities that could allow signature replay attacks, forgery, or unauthorized access.

## What Are Digital Signatures?

Digital signatures in blockchain provide:

* **Authentication**: Proof that a message came from a specific address
* **Integrity**: Assurance the message hasn't been altered
* **Non-repudiation**: Signer cannot deny signing

```solidity theme={null}
// Basic signature verification
function verify(
    bytes32 messageHash,
    bytes memory signature,
    address expectedSigner
) public pure returns (bool) {
    return recoverSigner(messageHash, signature) == expectedSigner;
}
```

## Common Vulnerabilities

### Signature Replay Attack

Using the same signature multiple times.

```solidity theme={null}
// VULNERABLE: No replay protection
function claim(uint256 amount, bytes memory signature) public {
    bytes32 hash = keccak256(abi.encodePacked(msg.sender, amount));
    require(verify(hash, signature, signer), "Invalid signature");
    _mint(msg.sender, amount);  // Can be called multiple times!
}
```

**Attack:** User claims rewards repeatedly with the same signature.

***

### Cross-Chain Replay

Signature valid on multiple chains.

```solidity theme={null}
// VULNERABLE: No chain ID in signature
function execute(address to, uint256 value, bytes memory signature) public {
    bytes32 hash = keccak256(abi.encodePacked(to, value));
    require(verify(hash, signature, owner), "Invalid signature");
    payable(to).transfer(value);
}
```

**Attack:** Signature from mainnet replayed on testnet or L2.

***

### Missing Nonce

No mechanism to invalidate old signatures.

```solidity theme={null}
// VULNERABLE: Signatures never expire
function withdraw(uint256 amount, bytes memory signature) public {
    bytes32 hash = keccak256(abi.encodePacked(msg.sender, amount));
    require(verify(hash, signature, admin), "Invalid");
    // No nonce - signature is valid forever
    _transfer(address(this), msg.sender, amount);
}
```

***

### Signature Malleability

ECDSA signatures can be modified while remaining valid.

```solidity theme={null}
// VULNERABLE: No malleability check
function verifySignature(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
    public pure returns (address)
{
    return ecrecover(hash, v, r, s);  // Malleable!
}
```

## Safe Patterns

### Nonce-Based Replay Protection

```solidity theme={null}
// SAFE: Nonce prevents replay
mapping(address => uint256) public nonces;

function claim(uint256 amount, uint256 nonce, bytes memory signature) public {
    require(nonce == nonces[msg.sender], "Invalid nonce");

    bytes32 hash = keccak256(abi.encodePacked(
        msg.sender,
        amount,
        nonce,
        block.chainid,  // Chain-specific
        address(this)   // Contract-specific
    ));

    require(verify(hash, signature, signer), "Invalid signature");
    nonces[msg.sender]++;  // Increment nonce
    _mint(msg.sender, amount);
}
```

### EIP-712 Typed Data

```solidity theme={null}
// SAFE: Structured, typed signing
bytes32 public constant CLAIM_TYPEHASH =
    keccak256("Claim(address recipient,uint256 amount,uint256 nonce)");

function claim(uint256 amount, uint256 nonce, bytes memory signature) public {
    bytes32 structHash = keccak256(abi.encode(
        CLAIM_TYPEHASH,
        msg.sender,
        amount,
        nonce
    ));

    bytes32 hash = _hashTypedDataV4(structHash);  // Includes domain separator
    address signer = ECDSA.recover(hash, signature);

    require(signer == authorizedSigner, "Invalid signature");
    require(nonce == nonces[msg.sender]++, "Invalid nonce");

    _mint(msg.sender, amount);
}
```

### OpenZeppelin ECDSA

```solidity theme={null}
// SAFE: Using audited library
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

using ECDSA for bytes32;

function verify(bytes32 hash, bytes memory signature) public view returns (bool) {
    // Handles malleability, returns address(0) on failure
    return hash.toEthSignedMessageHash().recover(signature) == trustedSigner;
}
```

## Detection Tags

| Tag                      | Severity | Description                         |
| ------------------------ | -------- | ----------------------------------- |
| `signature_replay`       | High     | No replay protection detected       |
| `missing_chainid`        | Medium   | Cross-chain replay possible         |
| `missing_nonce`          | High     | Signatures never invalidated        |
| `signature_malleability` | Medium   | Raw ecrecover without checks        |
| `weak_signature_scheme`  | Medium   | Non-standard signature verification |

## API Response Example

```json theme={null}
{
  "issues": [
    {
      "tag": "signature_replay",
      "severity": "high",
      "description": "Signature can be reused - no nonce or invalidation",
      "location": "claim(uint256,bytes)"
    },
    {
      "tag": "missing_chainid",
      "severity": "medium",
      "description": "Signature hash does not include chain ID",
      "location": "execute(address,uint256,bytes)"
    }
  ]
}
```

## Best Practices

* [ ] Include nonce in all signed messages
* [ ] Include `block.chainid` to prevent cross-chain replay
* [ ] Include contract address to prevent cross-contract replay
* [ ] Use EIP-712 for structured, typed signing
* [ ] Use OpenZeppelin's ECDSA library
* [ ] Mark used signatures/nonces as consumed
* [ ] Consider signature expiration timestamps
