> ## 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.

# Security

> BLS12-381 security considerations and best practices

<Card title="Try it Live" icon="play" href="https://playground.tevm.sh?example=crypto/bls12381.ts">
  Run BLS12-381 examples in the interactive playground
</Card>

# Security Considerations

Security properties and best practices for BLS12-381 implementations.

## Security Level

**Target**: 128-bit classical security, 64-bit post-quantum security

| Attack            | Complexity                      |
| ----------------- | ------------------------------- |
| Discrete log (G1) | \~2^128                         |
| Discrete log (G2) | \~2^128                         |
| Pairing inversion | Computationally infeasible      |
| MOV attack        | Prevented (embedding degree 12) |

**Recommended usage**: Until 2030+ per NIST guidelines.

## Known Attack Vectors

### Rogue Key Attack

**Problem**: Adversary can construct malicious public key that causes aggregated signature verification to pass for messages they didn't sign.

**Attack**:

1. Honest user has public key `pk₁`
2. Adversary computes `pk₂ = G1 - pk₁` (where G1 is generator)
3. Aggregated key: `pk₁ + pk₂ = G1`
4. Adversary can forge signatures for the "aggregate"

**Mitigation**: Proof of Possession (PoP)

```zig theme={null}
// Each participant must prove knowledge of secret key
fn generateProofOfPossession(secret_key: Fr, public_key: G1Point) G2Point {
    // Sign the public key itself
    const pop_message = Bls12381.G2.hashToCurve(public_key.serialize(), "BLS_POP_");
    return Bls12381.G2.mul(pop_message, secret_key);
}

fn verifyProofOfPossession(public_key: G1Point, pop: G2Point) bool {
    const pop_message = Bls12381.G2.hashToCurve(public_key.serialize(), "BLS_POP_");
    return Bls12381.Pairing.verify(public_key, pop_message, pop);
}
```

### Subgroup Attack

**Problem**: Points not in the correct prime-order subgroup can break security.

**Mitigation**: Always validate points are in the correct subgroup:

```zig theme={null}
fn validateG1Point(point: G1Point) !void {
    // Check point is on curve
    if (!Bls12381.G1.isOnCurve(point)) {
        return error.PointNotOnCurve;
    }
    // Check point is in prime-order subgroup
    if (!Bls12381.G1.isInSubgroup(point)) {
        return error.PointNotInSubgroup;
    }
}
```

### Invalid Curve Attack

**Problem**: Accepting points from different curves enables key recovery.

**Mitigation**: Strict point validation before any operation.

## Side-Channel Resistance

### Constant-Time Operations

All operations must be constant-time to prevent timing attacks:

```zig theme={null}
// ✅ Constant-time scalar multiplication
fn scalarMul(point: G1Point, scalar: Fr) G1Point {
    // Double-and-add with constant iterations
    var result = G1Point.identity();
    var temp = point;

    for (0..256) |i| {
        // Constant-time conditional add
        const bit = (scalar >> i) & 1;
        result = constantTimeSelect(bit,
            Bls12381.G1.add(result, temp),
            result
        );
        temp = Bls12381.G1.double(temp);
    }
    return result;
}
```

### Memory Access Patterns

Avoid data-dependent memory access:

```zig theme={null}
// ❌ BAD: Variable-time lookup
fn badLookup(table: []G1Point, index: usize) G1Point {
    return table[index]; // Timing leak!
}

// ✅ GOOD: Constant-time lookup
fn constantTimeLookup(table: []G1Point, index: usize) G1Point {
    var result = G1Point.identity();
    for (table, 0..) |point, i| {
        const mask = constantTimeEquals(i, index);
        result = constantTimeSelect(mask, point, result);
    }
    return result;
}
```

## Implementation Checklist

### Point Validation

* [ ] Check point is on curve (satisfies curve equation)
* [ ] Check point is in prime-order subgroup
* [ ] Reject point at infinity where invalid
* [ ] Validate encoding format (compressed/uncompressed)

### Scalar Validation

* [ ] Check scalar is in valid range \[0, r-1]
* [ ] Reduce scalars modulo curve order
* [ ] Handle zero scalar correctly

### Signature Validation

* [ ] Verify signature is valid G2 point
* [ ] Check signature is in correct subgroup
* [ ] Validate against correct domain separator
* [ ] Reject malformed or oversized inputs

### Key Management

* [ ] Use cryptographically secure random number generator
* [ ] Implement proof of possession for aggregation
* [ ] Secure key storage (HSM recommended for validators)
* [ ] Key derivation follows EIP-2333

## Domain Separation

Always use distinct domain separators to prevent cross-protocol attacks:

```zig theme={null}
// Ethereum consensus domains
const DOMAIN_BEACON_PROPOSER = 0x00000000;
const DOMAIN_BEACON_ATTESTER = 0x01000000;
const DOMAIN_RANDAO = 0x02000000;
const DOMAIN_DEPOSIT = 0x03000000;
const DOMAIN_VOLUNTARY_EXIT = 0x04000000;
const DOMAIN_SYNC_COMMITTEE = 0x07000000;

fn computeDomain(domain_type: u32, fork_version: [4]u8, genesis_root: [32]u8) [32]u8 {
    const fork_data_root = hashTreeRoot(ForkData{
        .current_version = fork_version,
        .genesis_validators_root = genesis_root,
    });
    var domain: [32]u8 = undefined;
    @memcpy(domain[0..4], @bitCast([4]u8, domain_type));
    @memcpy(domain[4..32], fork_data_root[0..28]);
    return domain;
}
```

## Aggregation Security

### Safe Aggregation Rules

1. **Same message**: Only aggregate signatures over identical messages
2. **Proof of possession**: Require PoP before allowing key in aggregation
3. **Distinct signers**: Ensure no duplicate public keys
4. **Domain binding**: Include domain in signed message

### Unsafe Patterns

```zig theme={null}
// ❌ UNSAFE: Aggregating signatures over different messages
fn unsafeAggregate(sigs: []G2Point) G2Point {
    // This allows forgery attacks!
    return sumG2Points(sigs);
}

// ✅ SAFE: Only aggregate same-message signatures
fn safeAggregate(
    message: []const u8,
    public_keys: []G1Point,
    signatures: []G2Point,
) !AggregatedSignature {
    // Verify each signature first
    for (public_keys, signatures) |pk, sig| {
        if (!verify(pk, message, sig)) {
            return error.InvalidSignature;
        }
    }
    return AggregatedSignature{
        .public_keys = public_keys,
        .signature = sumG2Points(signatures),
    };
}
```

## Library Recommendations

### Production Use

**BLST** (Supranational) - Recommended for production:

* Audited by Trail of Bits, NCC Group
* Assembly-optimized
* Constant-time implementation
* Used by all major Ethereum consensus clients

### Testing Only

**Noble-BLS12-381** - Pure JavaScript for testing:

* Not constant-time
* Slower performance
* Useful for test vector generation

## Audit History

| Library | Auditor         | Date | Findings                 |
| ------- | --------------- | ---- | ------------------------ |
| BLST    | Trail of Bits   | 2020 | No critical issues       |
| BLST    | NCC Group       | 2021 | All issues resolved      |
| py\_ecc | Least Authority | 2020 | Reference implementation |

## Related

* [BLS12-381 Overview](/crypto/bls12-381) - Curve fundamentals
* [Usage Patterns](/crypto/bls12-381/usage-patterns) - Implementation patterns
* [Performance](/crypto/bls12-381/performance) - Benchmarks
