> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/circlefin/evm-cctp-contracts/llms.txt
> Use this file to discover all available pages before exploring further.

# Attestation Mechanism

> How CCTP uses cryptographic attestations to secure cross-chain messages

## What are Attestations?

Attestations are cryptographic signatures that prove a cross-chain message is legitimate. In CCTP, attestations serve as the security bridge between chains:

* **Burn Proof**: Attestation confirms tokens were actually burned on the source chain
* **Authorization**: Only valid attestations allow minting on the destination chain
* **Decentralization**: Multiple independent attesters must sign (m-of-n multisig)
* **Replay Prevention**: Each attestation is valid for exactly one (sourceDomain, nonce) pair

<Info>
  Without valid attestations, it's impossible to mint tokens on the destination chain, preventing unauthorized USDC creation.
</Info>

## Why Attestations Are Needed

Blockchains cannot natively communicate with each other. CCTP bridges this gap:

### The Problem

```mermaid theme={null}
graph LR
    A[Ethereum] -.->|❌ No direct communication| B[Avalanche]
    A -.->|❌ Cannot read state| B
```

Avalanche contracts cannot directly verify that USDC was burned on Ethereum. Without attestations:

* Anyone could claim to have burned tokens
* Malicious actors could mint unlimited USDC
* Cross-chain transfers would be impossible to trust

### The Solution

```mermaid theme={null}
graph TB
    A[Ethereum<br/>Burns USDC] -->|MessageSent event| C[Attestation Service]
    C -->|Signs message hash| C
    C -->|Provides attestation| D[User/Relayer]
    D -->|receiveMessage with attestation| B[Avalanche<br/>Mints USDC]
    B -->|Verifies signatures| B
```

Trusted attesters observe burns and provide cryptographic proof that minting is authorized.

## Attester Management

CCTP uses the `Attestable` role contract (see `src/roles/Attestable.sol:22`) to manage attesters:

### Attester Lifecycle

#### Enabling Attesters

Only the `attesterManager` can enable new attesters:

```solidity theme={null}
function enableAttester(address newAttester) public onlyAttesterManager {
    require(newAttester != address(0), "New attester must be nonzero");
    require(enabledAttesters.add(newAttester), "Attester already enabled");
    emit AttesterEnabled(newAttester);
}
```

**Requirements**:

* `newAttester` must not be zero address
* `newAttester` must not already be enabled
* Caller must be the attester manager

**Example**:

```javascript theme={null}
await messageTransmitter.methods
  .enableAttester('0x1234...')
  .send({ from: attesterManagerAddress });
```

#### Disabling Attesters

To disable a compromised or retired attester:

```solidity theme={null}
function disableAttester(address attester) external onlyAttesterManager {
    // Cannot disable if only 1 attester remains
    uint256 _numEnabledAttesters = getNumEnabledAttesters();
    require(_numEnabledAttesters > 1, "Too few enabled attesters");
    
    // Cannot disable if it would reduce below signature threshold
    require(
        _numEnabledAttesters > signatureThreshold,
        "Signature threshold is too low"
    );
    
    require(enabledAttesters.remove(attester), "Attester already disabled");
    emit AttesterDisabled(attester);
}
```

**Safety Checks**:

* At least 1 attester must remain enabled
* Number of enabled attesters must exceed signature threshold
* Ensures system remains operational after disabling

<Warning>
  **Security**: Disabling an attester does not invalidate existing attestations signed by that attester. Only future attestations are affected.
</Warning>

### Signature Threshold

The signature threshold determines how many attesters must sign each message (m in m-of-n multisig):

```solidity theme={null}
function setSignatureThreshold(
    uint256 newSignatureThreshold
) external onlyAttesterManager {
    require(newSignatureThreshold != 0, "Invalid signature threshold");
    
    // Threshold cannot exceed number of enabled attesters
    require(
        newSignatureThreshold <= enabledAttesters.length(),
        "New signature threshold too high"
    );
    
    require(
        newSignatureThreshold != signatureThreshold,
        "Signature threshold already set"
    );
    
    uint256 _oldSignatureThreshold = signatureThreshold;
    signatureThreshold = newSignatureThreshold;
    emit SignatureThresholdUpdated(_oldSignatureThreshold, newSignatureThreshold);
}
```

**Validation Rules**:

* Threshold must be at least 1
* Threshold cannot exceed number of enabled attesters
* Threshold must be different from current value

**Security Tradeoff**:

* **Higher threshold**: More secure (more attesters needed to compromise), but slower and less fault-tolerant
* **Lower threshold**: Faster and more fault-tolerant, but less secure

**Example Configuration**:

```
Enabled Attesters: 5
Signature Threshold: 3
Result: Any 3 of the 5 attesters can sign to authorize minting
```

### Attester Manager Role

The attester manager has exclusive control over the attester set:

```solidity theme={null}
function updateAttesterManager(
    address newAttesterManager
) external onlyOwner {
    _setAttesterManager(newAttesterManager);
}

function _setAttesterManager(address _newAttesterManager) internal {
    require(
        _newAttesterManager != address(0),
        "Invalid attester manager address"
    );
    address _oldAttesterManager = _attesterManager;
    _attesterManager = _newAttesterManager;
    emit AttesterManagerUpdated(_oldAttesterManager, _newAttesterManager);
}
```

**Responsibilities**:

* Enable new attesters
* Disable compromised attesters
* Adjust signature threshold

**Access Control**:

* Only contract owner can change attester manager
* Attester manager cannot transfer their own role

## Signature Verification

The core security mechanism is signature verification in `_verifyAttestationSignatures()` (see `src/roles/Attestable.sol:227`):

### Attestation Format

Attestations are concatenated 65-byte ECDSA signatures:

```
[signature1][signature2][signature3]...[signatureN]
│         ││         ││         │     │         │
│   65B   ││   65B   ││   65B   │ ... │   65B   │
│         ││         ││         │     │         │
└─────────┘└─────────┘└─────────┘     └─────────┘
```

Each 65-byte signature consists of:

* **r** (32 bytes): Signature component
* **s** (32 bytes): Signature component
* **v** (1 byte): Recovery ID

**Total Length**: `65 * signatureThreshold` bytes

### Verification Algorithm

```solidity theme={null}
function _verifyAttestationSignatures(
    bytes calldata _message,
    bytes calldata _attestation
) internal view {
    // 1. Validate attestation length
    require(
        _attestation.length == signatureLength * signatureThreshold,
        "Invalid attestation length"
    );
    
    // 2. Hash the message
    bytes32 _digest = keccak256(_message);
    
    // 3. Track last attester address (for ordering check)
    address _latestAttesterAddress = address(0);
    
    // 4. Verify each signature
    for (uint256 i = 0; i < signatureThreshold; ++i) {
        // Extract individual signature
        bytes memory _signature = _attestation[
            i * signatureLength : i * signatureLength + signatureLength
        ];
        
        // Recover signer address from signature
        address _recoveredAttester = _recoverAttesterSignature(
            _digest,
            _signature
        );
        
        // 5. Enforce increasing address order (prevents duplicates)
        require(
            _recoveredAttester > _latestAttesterAddress,
            "Invalid signature order or dupe"
        );
        
        // 6. Verify signer is enabled attester
        require(
            isEnabledAttester(_recoveredAttester),
            "Invalid signature: not attester"
        );
        
        _latestAttesterAddress = _recoveredAttester;
    }
}
```

### Verification Steps Explained

#### Step 1: Length Validation

Ensures attestation contains exactly the required number of signatures:

```solidity theme={null}
require(
    _attestation.length == 65 * signatureThreshold,
    "Invalid attestation length"
);
```

**Examples**:

* Threshold = 1: Attestation must be exactly 65 bytes
* Threshold = 3: Attestation must be exactly 195 bytes
* Threshold = 5: Attestation must be exactly 325 bytes

#### Step 2: Message Hashing

```solidity theme={null}
bytes32 _digest = keccak256(_message);
```

The complete message bytes (including all fields) are hashed. Attesters sign this hash, not the raw message.

#### Step 3-4: Signature Recovery

For each signature, recover the signer's address using ECDSA:

```solidity theme={null}
function _recoverAttesterSignature(
    bytes32 _digest,
    bytes memory _signature
) internal pure returns (address) {
    return ECDSA.recover(_digest, _signature);
}
```

Uses OpenZeppelin's `ECDSA.recover()` which:

1. Extracts v, r, s from signature
2. Performs elliptic curve point recovery
3. Returns the address that created the signature

#### Step 5: Increasing Address Order

**Critical Security Check**: Signatures must be ordered by ascending attester address:

```solidity theme={null}
require(
    _recoveredAttester > _latestAttesterAddress,
    "Invalid signature order or dupe"
);
```

**Why This Matters**:

* **Prevents Duplicate Signatures**: Same signature cannot be used twice (address would not increase)
* **Simplifies Verification**: O(n) complexity instead of O(n²) for checking duplicates
* **Canonical Format**: Only one valid ordering exists for any signature set

**Example**:

```
Valid:   [sig_0x1234] [sig_0x5678] [sig_0x9ABC]  ✓
Invalid: [sig_0x5678] [sig_0x1234] [sig_0x9ABC]  ✗ (wrong order)
Invalid: [sig_0x1234] [sig_0x1234] [sig_0x5678]  ✗ (duplicate)
```

#### Step 6: Attester Authorization

```solidity theme={null}
require(
    isEnabledAttester(_recoveredAttester),
    "Invalid signature: not attester"
);
```

Verifies the recovered address is currently in the enabled attester set. This prevents:

* Random addresses from providing signatures
* Disabled/retired attesters from authorizing transfers

### Complete Verification Example

```javascript theme={null}
// Example: 3-of-5 multisig (threshold = 3, enabled = 5)

const enabledAttesters = [
  '0x0000...1111',  // Attester 1
  '0x0000...2222',  // Attester 2
  '0x0000...3333',  // Attester 3
  '0x0000...4444',  // Attester 4
  '0x0000...5555'   // Attester 5
];

// Valid attestation: signatures from attesters 1, 3, and 5 (in order)
const validAttestation = 
  signature_from_0x0000_1111 +  // 65 bytes
  signature_from_0x0000_3333 +  // 65 bytes
  signature_from_0x0000_5555;   // 65 bytes
// Total: 195 bytes

// Invalid: wrong order
const invalidAttestation = 
  signature_from_0x0000_3333 +  // ✗ Not in ascending order
  signature_from_0x0000_1111 +
  signature_from_0x0000_5555;

// Invalid: duplicate
const invalidAttestation2 = 
  signature_from_0x0000_1111 +  // ✗ Duplicate signature
  signature_from_0x0000_1111 +
  signature_from_0x0000_3333;

// Invalid: unauthorized signer
const invalidAttestation3 = 
  signature_from_0x0000_1111 +
  signature_from_0x0000_6666 +  // ✗ Not an enabled attester
  signature_from_0x0000_3333;
```

## Attestation Service Architecture

Circle operates the off-chain attestation service:

### Service Responsibilities

1. **Event Monitoring**: Listen for `MessageSent` events on all supported chains
2. **Validation**:
   * Verify transaction confirmation and finality
   * Check burn amount is within limits
   * Validate destination domain is supported
   * Confirm source contract is legitimate TokenMessenger
3. **Signing**: Generate signatures with authorized attester keys
4. **API**: Provide attestations via REST API with rate limiting
5. **Observability**: Log all attestations for audit trails

### Attestation API

**Endpoint**:

```
GET https://iris-api.circle.com/attestations/{messageHash}
```

**Request**:

```bash theme={null}
curl https://iris-api.circle.com/attestations/0xabc123...
```

**Response - Pending**:

```json theme={null}
{
  "status": "pending"
}
```

**Response - Complete**:

```json theme={null}
{
  "status": "complete",
  "attestation": "0x1234567890abcdef..."
}
```

**Rate Limits**:

* Maximum 1 request per second per IP
* Exceeding limit returns HTTP 429

<Tip>
  **Best Practice**: Poll with exponential backoff (2s, 4s, 8s, 16s...) to respect rate limits and reduce unnecessary requests.
</Tip>

## Security Considerations

### Attester Key Management

**Critical**: Attester private keys are the root of CCTP security

* **Hardware Security Modules (HSMs)**: Keys stored in tamper-resistant hardware
* **Multi-Party Computation (MPC)**: Distributed key generation and signing
* **Key Rotation**: Periodic rotation of attester keys
* **Separation**: Each attester key held by independent party

### Threshold Selection

Choosing the right threshold balances security and availability:

**Example Scenarios**:

| Enabled | Threshold | Security Level | Fault Tolerance      |
| ------- | --------- | -------------- | -------------------- |
| 3       | 2         | Moderate       | 1 attester can fail  |
| 5       | 3         | High           | 2 attesters can fail |
| 7       | 5         | Very High      | 2 attesters can fail |
| 9       | 7         | Maximum        | 2 attesters can fail |

**Recommendation**: Set threshold to at least `floor(n/2) + 1` where n is number of enabled attesters (Byzantine fault tolerance).

### Attack Vectors and Mitigations

#### Replay Attacks

**Attack**: Reuse valid attestation to mint tokens multiple times

**Mitigation**: Nonce tracking in MessageTransmitter

```solidity theme={null}
require(usedNonces[_sourceAndNonce] == 0, "Nonce already used");
usedNonces[_sourceAndNonce] = 1;
```

#### Signature Malleability

**Attack**: Modify signature to create alternative valid signature for same message

**Mitigation**:

* ECDSA library validates signature format
* Increasing address order requirement ensures canonical representation

#### Attester Compromise

**Attack**: Compromise m attesters to authorize fraudulent mints

**Mitigation**:

* Geographic distribution of attesters
* Different security vendors for each attester
* Regular security audits
* Ability to quickly disable compromised attesters

#### Front-Running

**Attack**: Monitor mempool and submit `receiveMessage` before intended recipient

**Mitigation**: Use `depositForBurnWithCaller()` to restrict who can complete transfer

## Monitoring and Observability

### Key Metrics

**Attestation Service**:

* Average attestation time
* Success/failure rate
* API request rate and errors

**On-Chain**:

* Number of enabled attesters: `getNumEnabledAttesters()`
* Current threshold: `signatureThreshold`
* Attester manager: `attesterManager()`

### Events

```solidity theme={null}
event AttesterEnabled(address indexed attester);
event AttesterDisabled(address indexed attester);
event SignatureThresholdUpdated(uint256 oldThreshold, uint256 newThreshold);
event AttesterManagerUpdated(address indexed previousManager, address indexed newManager);
```

Monitor these events to track attester set changes and detect anomalies.

## Next Steps

<CardGroup cols={2}>
  <Card title="Message Flow" icon="arrow-right-arrow-left" href="/concepts/message-flow">
    See how attestations fit into the complete transfer flow
  </Card>

  <Card title="Quickstart" icon="rocket" href="/quickstart">
    Build your first integration with attestations
  </Card>
</CardGroup>
