Below is a test case generator for the given problem statement "C: Equivalent Propositions". 

```python
import random

def tcgen():
    # Number of propositions (2 ≤ N ≤ 300)
    N = random.randint(2, 300)
    
    # Number of pieces of information (1 ≤ M ≤ N(N-1))
    M = random.randint(1, N * (N - 1))
    
    propositions = []
    for _ in range(M):
        # Choose two distinct propositions (1 ≤ a_i, b_i ≤ N, a_i ≠ b_i)
        a_i = random.randint(1, N)
        b_i = random.randint(1, N)
        while b_i == a_i:
            b_i = random.randint(1, N)
        
        propositions.append((a_i, b_i))
    
    return N, M, propositions

def format_test_case(N, M, propositions):
    result = f"{N} {M}\n"
    for a_i, b_i in propositions:
        result += f"{a_i} {b_i}\n"
    return result.strip()

# Generate a test case
N, M, propositions = tcgen()
print(format_test_case(N, M, propositions))
```

### Explanation:

1. **Number of Propositions (N)**: A random integer between 2 and 300.
2. **Number of Pieces of Information (M)**: A random integer between 1 and \(N \times (N - 1)\).
3. **Propositions Information (propositions)**: Generate \(M\) pairs \((a_i, b_i)\) such that \(1 \leq a_i, b_i \leq N\) and \(a_i \neq b_i\). This ensures that there is no self-dependency.
4. **Format Test Case**: Convert the generated values into the specified input format.

This generator creates random test cases that are compliant with the given problem statement.