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

# Validation

> Validation

<Card title="Try it Live" icon="play" href="https://playground.tevm.sh?example=primitives/authorization.ts">
  Run Authorization examples in the interactive playground
</Card>

# Validation

Authorization structure and signature validation.

## validate

Validate authorization structure and signature parameters.

```typescript theme={null}
Authorization.validate.call(auth: Authorization.Item): void
```

**Parameters:**

* `auth`: Authorization to validate

**Throws:** `Authorization.ValidationError` if invalid

**Validation Checks:**

1. Chain ID must be non-zero
2. Address cannot be zero address
3. yParity must be 0 or 1
4. Signature r must be non-zero
5. Signature s must be non-zero
6. r must be \< SECP256K1\_N (curve order)
7. s must be ≤ SECP256K1\_HALF\_N (prevents malleable signatures)

## Basic Usage

```typescript theme={null}
import { Authorization } from 'tevm';

const auth: Authorization.Item = {
  chainId: 1n,
  address: contractAddress,
  nonce: 0n,
  yParity: 0,
  r: 0x123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdefn,
  s: 0x0edcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210n
};

try {
  Authorization.validate.call(auth);
  console.log('Authorization is valid');
} catch (e) {
  if (e instanceof Authorization.ValidationError) {
    console.error(`Invalid: ${e.message}`);
  }
}
```

## Validation Errors

### ValidationError

```typescript theme={null}
class ValidationError extends Error {
  name: 'ValidationError';
}
```

**Error Messages:**

* `"Chain ID must be non-zero"` - chainId is 0
* `"Address cannot be zero address"` - address is 0x0000...0000
* `"yParity must be 0 or 1"` - yParity not 0 or 1
* `"Signature r cannot be zero"` - r is 0
* `"Signature s cannot be zero"` - s is 0
* `"Signature r must be less than curve order"` - r >= SECP256K1\_N
* `"Signature s too high (malleable signature)"` - s > SECP256K1\_HALF\_N

## Validation Rules

### Chain ID

Chain ID must be non-zero to indicate which chain authorization is valid on.

```typescript theme={null}
// Valid
const auth = { chainId: 1n, ... };  // Mainnet
const auth = { chainId: 137n, ... };  // Polygon

// Invalid
const auth = { chainId: 0n, ... };  // Throws ValidationError
```

**Rationale:** Zero chain ID is reserved and indicates invalid authorization.

### Zero Address

Address cannot be zero address (0x0000...0000).

```typescript theme={null}
// Valid
const auth = {
  address: Address('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb2'),
  ...
};

// Invalid
const auth = {
  address: Address.zero(),  // Throws ValidationError
  ...
};
```

**Rationale:** Zero address has no code and delegation would be meaningless.

### yParity

yParity must be 0 or 1 (ECDSA signature parity bit).

```typescript theme={null}
// Valid
const auth = { yParity: 0, ... };
const auth = { yParity: 1, ... };

// Invalid
const auth = { yParity: 2, ... };  // Throws ValidationError
const auth = { yParity: 27, ... };  // Throws ValidationError (use 0/1, not 27/28)
```

**Rationale:** ECDSA signatures have two possible y-coordinates (even/odd). yParity indicates which.

### Signature r

Signature r must be non-zero and less than curve order.

```typescript theme={null}
// Valid
const auth = {
  r: 0x123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdefn,
  ...
};

// Invalid
const auth = { r: 0n, ... };  // Throws ValidationError

// Invalid (r >= SECP256K1_N)
const auth = {
  r: 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n,
  ...
};  // Throws ValidationError
```

**Rationale:** r is ECDSA signature component and must be in valid range \[1, N-1].

### Signature s

Signature s must be non-zero and at most SECP256K1\_HALF\_N.

```typescript theme={null}
// Valid (s <= N/2)
const auth = {
  s: 0x0edcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210n,
  ...
};

// Invalid (s = 0)
const auth = { s: 0n, ... };  // Throws ValidationError

// Invalid (s > N/2 - malleable)
const auth = {
  s: 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n,
  ...
};  // Throws ValidationError
```

**Rationale:** Restricting s ≤ N/2 prevents signature malleability. For any valid signature (r, s), there exists another valid signature (r, -s mod N). Requiring s ≤ N/2 ensures only one canonical signature.

## Malleability Prevention

### What is Signature Malleability?

ECDSA signatures have inherent malleability: given valid signature (r, s), signature (r, N - s) is also valid for same message.

Without malleability protection:

```typescript theme={null}
// Both signatures are valid for same authorization
const sig1 = { r, s: 0x123n, v: 0 };
const sig2 = { r, s: SECP256K1_N - 0x123n, v: 1 };
```

### Protection

`validate()` rejects high s values:

```typescript theme={null}
import { Authorization } from 'tevm';

const auth = {
  chainId: 1n,
  address: contractAddress,
  nonce: 0n,
  yParity: 1,
  r: 0x123n,
  s: 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364000n  // High s
};

// Throws: "Signature s too high (malleable signature)"
Authorization.validate.call(auth);
```

### Normalizing High s

If you receive signature with high s, normalize it:

```typescript theme={null}
function normalizeSignature(r: bigint, s: bigint, v: number): {
  r: bigint;
  s: bigint;
  v: number;
} {
  const SECP256K1_N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n;
  const SECP256K1_HALF_N = SECP256K1_N >> 1n;

  if (s > SECP256K1_HALF_N) {
    return {
      r,
      s: SECP256K1_N - s,
      v: v === 0 ? 1 : 0  // Flip parity
    };
  }

  return { r, s, v };
}
```

## Validation Patterns

### Validate Before Processing

Always validate before any operations:

```typescript theme={null}
import { Authorization } from 'tevm';

function processAuthorization(auth: Authorization.Item): void {
  // Validate first
  Authorization.validate.call(auth);

  // Then process
  const authority = Authorization.verify.call(auth);
  const gas = Authorization.getGasCost.call(auth, false);

  console.log(`Authority: ${authority}, Gas: ${gas}`);
}
```

### Batch Validation

Validate entire authorization list:

```typescript theme={null}
import { Authorization } from 'tevm';

function validateAuthList(authList: Authorization.Item[]): {
  valid: Authorization.Item[];
  invalid: Array<{ auth: Authorization.Item; error: string }>;
} {
  const valid: Authorization.Item[] = [];
  const invalid: Array<{ auth: Authorization.Item; error: string }> = [];

  for (const auth of authList) {
    try {
      Authorization.validate.call(auth);
      valid.push(auth);
    } catch (e) {
      if (e instanceof Authorization.ValidationError) {
        invalid.push({ auth, error: e.message });
      } else {
        invalid.push({ auth, error: String(e) });
      }
    }
  }

  return { valid, invalid };
}

const { valid, invalid } = validateAuthList(authList);
console.log(`Valid: ${valid.length}, Invalid: ${invalid.length}`);
```

### Early Validation

Validate as soon as authorization is received:

```typescript theme={null}
import { Authorization } from 'tevm';

class AuthorizationQueue {
  private queue: Authorization.Item[] = [];

  add(auth: Authorization.Item): void {
    // Validate immediately
    Authorization.validate.call(auth);

    // Only add valid authorizations
    this.queue.push(auth);
  }

  processAll(): void {
    // All items in queue are pre-validated
    for (const auth of this.queue) {
      this.process(auth);
    }
  }

  private process(auth: Authorization.Item): void {
    // No need to validate again
    const authority = Authorization.verify.call(auth);
    console.log(`Processing: ${authority}`);
  }
}
```

### Validation with Type Guards

Combine type guards with validation:

```typescript theme={null}
import { Authorization } from 'tevm';

function validateUnknown(data: unknown): Authorization.Item {
  // First check type
  if (!Authorization.isItem(data)) {
    throw new Error('Not an authorization item');
  }

  // Then validate structure
  Authorization.validate.call(data);

  return data;
}

const auth = validateUnknown(apiResponse);
```

### Error Handling

Handle specific validation errors:

```typescript theme={null}
import { Authorization } from 'tevm';

function validateWithHandling(auth: Authorization.Item): boolean {
  try {
    Authorization.validate.call(auth);
    return true;
  } catch (e) {
    if (!(e instanceof Authorization.ValidationError)) {
      throw e;  // Re-throw non-validation errors
    }

    // Handle specific errors
    if (e.message.includes('Chain ID')) {
      console.error('Invalid chain ID');
    } else if (e.message.includes('Address')) {
      console.error('Invalid address');
    } else if (e.message.includes('malleable')) {
      console.error('Signature malleability detected');
    } else {
      console.error(`Validation failed: ${e.message}`);
    }

    return false;
  }
}
```

## Performance

### Validation Cost

Validation is O(1) with constant-time checks:

```typescript theme={null}
// All checks are constant time
- chainId !== 0n          // O(1)
- address.every()         // O(20) = O(1)
- yParity === 0 || 1      // O(1)
- r !== 0n                // O(1)
- s !== 0n                // O(1)
- r < SECP256K1_N         // O(1)
- s <= SECP256K1_HALF_N   // O(1)
```

### Optimization

Validation is already optimized. For batch validation, consider:

```typescript theme={null}
// Sequential validation
for (const auth of authList) {
  Authorization.validate.call(auth);
}

// Stop on first error
function validateAll(authList: Authorization.Item[]): void {
  for (const auth of authList) {
    Authorization.validate.call(auth);  // Throws on first error
  }
}

// Collect all errors
function validateAllWithErrors(authList: Authorization.Item[]): string[] {
  const errors: string[] = [];
  for (const auth of authList) {
    try {
      Authorization.validate.call(auth);
    } catch (e) {
      if (e instanceof Authorization.ValidationError) {
        errors.push(e.message);
      }
    }
  }
  return errors;
}
```

## Testing

### Valid Authorization

```typescript theme={null}
import { Authorization, Address } from 'tevm';

const validAuth: Authorization.Item = {
  chainId: 1n,
  address: Address('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb2'),
  nonce: 0n,
  yParity: 0,
  r: 0x123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdefn,
  s: 0x0edcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210n
};

// Should not throw
Authorization.validate.call(validAuth);
```

### Invalid Cases

```typescript theme={null}
import { Authorization } from 'tevm';

// Zero chain ID
expect(() => {
  Authorization.validate.call({ ...validAuth, chainId: 0n });
}).toThrow('Chain ID must be non-zero');

// Zero address
expect(() => {
  Authorization.validate.call({ ...validAuth, address: Address.zero() });
}).toThrow('Address cannot be zero address');

// Invalid yParity
expect(() => {
  Authorization.validate.call({ ...validAuth, yParity: 2 });
}).toThrow('yParity must be 0 or 1');

// Zero r
expect(() => {
  Authorization.validate.call({ ...validAuth, r: 0n });
}).toThrow('Signature r cannot be zero');

// Zero s
expect(() => {
  Authorization.validate.call({ ...validAuth, s: 0n });
}).toThrow('Signature s cannot be zero');

// High s (malleable)
expect(() => {
  Authorization.validate.call({
    ...validAuth,
    s: Authorization.SECP256K1_HALF_N + 1n
  });
}).toThrow('Signature s too high (malleable signature)');
```

## See Also

* [Constructors](./constructors) - Type guards and creation
* [Signing](./signing) - Creating valid signatures
* [Verification](./signing.mdx#verify) - Recovering signer
* [Constants](./index.mdx#constants) - SECP256K1\_N and SECP256K1\_HALF\_N
