# Tong Nian's "Nothing Ever Changes" Challenge - Local Setup ✅

## 🎯 Challenge Overview

Tong Nian claims to have found a way to create **adversarial examples without changing anything at all**. Her approach involves creating image pairs where:

- **img1** and **img2** have **IDENTICAL MD5 hashes** (same bytes!)
- But they classify as **DIFFERENT digits** in a neural network
- This seems paradoxical: how can identical bytes produce different results?

## 🐳 Local Docker Setup - COMPLETE

The application is now running locally at: **http://localhost:5001**

### Docker Commands

```bash
# View running containers
docker ps

# View logs
docker logs tong-nian-app

# Stop the server
docker stop tong-nian-app

# Restart the server
docker start tong-nian-app

# Rebuild from scratch
docker stop tong-nian-app
docker rm tong-nian-app
docker build -t tong-nian-adversarial .
docker run -d -p 5001:5000 --name tong-nian-app -e POW_DIFFICULTY=0 tong-nian-adversarial
```

## 📁 Files Created

| File | Purpose |
|------|---------|
| `ANALYSIS.md` | Detailed analysis of the challenge and potential solutions |
| `test_approach.py` | Initial exploration of the approach |
| `explore_solution.py` | Tests for PIL and model non-determinism |
| `analyze_challenge.py` | Comprehensive analysis tool (shows all requirements) |
| `test_client.py` | Client to test submissions against local server |

## 🧪 Testing the Local Server

### Quick Health Check
```bash
curl http://localhost:5001/health
```

### Run Comprehensive Analysis
```bash
python analyze_challenge.py
```

This will:
- Show requirements for all 10 pairs
- Test model determinism
- Test PIL image loading behavior
- Verify the paradox exists

### Test Submission
```bash
python test_client.py
```

This will:
- Check server health
- Create a dummy submission
- Submit it to the server (will fail as expected)

## 🔍 What We Discovered

### The Paradox Confirmed

After extensive testing, we confirmed:

1. ✅ **Model is deterministic** - Same input always gives same output
2. ✅ **PIL is deterministic** - Same bytes always load to same image
3. ✅ **Verification requires identical MD5** - img1 and img2 must have same hash
4. ✅ **But requires different classifications** - img1 and img2 must classify differently

### Challenge Requirements

For each of 10 pairs (pair_00 through pair_09):

| Pair | Reference → Target | Pixel Budget | Difficulty |
|------|-------------------|--------------|------------|
| 00 | 0 → 1 | 55 pixels | Medium |
| 01 | 1 → 2 | 30 pixels | Hard |
| 02 | 2 → 3 | 30 pixels | Hard |
| 03 | 3 → 4 | 65 pixels | Medium |
| 04 | 4 → 5 | 30 pixels | Hard |
| 05 | 5 → 6 | 10 pixels | Very Hard |
| 06 | 6 → 7 | 55 pixels | Medium |
| 07 | 7 → 8 | 40 pixels | Medium |
| 08 | 8 → 9 | 40 pixels | Medium |
| 09 | 9 → 1 | 40 pixels | Medium |

## 💡 Potential Solution Approaches

### 1. MD5 Collision Attack (Most Likely)

Use chosen-prefix collision techniques to create two different PNG files with the same MD5 hash:

- Research: HashClash, chosen-prefix collisions
- Create collision blocks that fit within PNG structure
- Modify pixel data while maintaining valid PNG format
- **Extremely difficult** - requires deep crypto knowledge

### 2. PNG Format Exploitation

Exploit PNG chunk parsing:

- Use ancillary chunks (tEXt, iTXt, etc.)
- Manipulate IDAT chunk ordering
- Exploit gamma correction (gAMA chunk)
- **Problem**: PIL parses deterministically

### 3. Find a Verification Bug

Review [verification.py](src/verification.py) for:

- Logic errors in the comparison sequence
- Race conditions
- State management issues
- Off-by-one errors

### 4. Preprocessing Edge Cases

Look for floating-point precision issues in:

- Image resizing/resampling
- Color space conversions
- Normalization steps
- **Problem**: Tests show preprocessing is deterministic

## 📊 Test Results

```
Model Determinism Test: ✅ PASS
- 5 trials with same input
- All produced identical predictions
- No randomness detected

PIL Loading Test: ✅ PASS  
- Loaded same bytes twice
- Arrays were identical
- No differences detected

Verification Logic: ✅ CONFIRMED
- Requires MD5 match (line 101)
- Checks classification difference
- Paradox is real!
```

## 🎓 Educational Value

This challenge beautifully demonstrates:

1. **Adversarial ML** - Not just about pixel perturbations
2. **Cryptographic Hashing** - MD5 collisions in practice
3. **File Format Security** - How formats can be exploited
4. **Determinism in ML** - Importance of reproducibility

The name "Nothing Ever Changes" is ironic - the **syntax** (bytes) stays the same, but the **semantics** (meaning) must change!

## 🔗 API Endpoints

### GET /health
Check if the server is running.

```bash
curl http://localhost:5001/health
```

Response: `{"status":"ok"}`

### GET /pow
Get proof-of-work challenge (disabled in local mode).

```bash
curl http://localhost:5001/pow
```

Response: `{"enabled":false}`

### POST /submit
Submit a solution ZIP file.

```bash
curl -X POST http://localhost:5001/submit \
  -F "file=@submission.zip"
```

Expected response:
- Success: `{"success":true,"flag":"uoftctf{fake_flag}"}`
- Failure: `{"success":false}`

## 📝 ZIP Submission Format

The ZIP must contain exactly 20 files:

```
submission.zip
├── pair_00_img1.png
├── pair_00_img2.png
├── pair_01_img1.png
├── pair_01_img2.png
├── ...
├── pair_09_img1.png
└── pair_09_img2.png
```

Requirements for each pair:
- `md5(img1_bytes) == md5(img2_bytes)` ← The paradox!
- img1 classifies as reference class
- img2 classifies as target class (different!)
- img1 pixels exactly match reference
- img2 pixels can differ by up to budget

## 🚀 Next Steps

1. **Study MD5 Collisions**: Research chosen-prefix collision attacks
2. **Analyze PNG Format**: Deep dive into PNG chunk structure
3. **Review Source Code**: Look for subtle bugs in verification.py
4. **Test Edge Cases**: Try malformed PNGs, unusual formats
5. **Join the Discussion**: This is a research-level challenge!

## 🎉 Conclusion

You now have:
- ✅ Local Docker environment running
- ✅ Complete understanding of the challenge
- ✅ Testing tools to verify solutions
- ✅ Analysis of why this is so difficult

This is an **extremely challenging** problem that sits at the intersection of:
- Cryptography (MD5 collisions)
- Machine Learning (adversarial examples)
- File Formats (PNG manipulation)
- Security (exploiting parsing differences)

**Good luck solving this fascinating puzzle!** 🧩🔐🤖

---

*Original challenge URL: http://35.245.68.223:5000/health*  
*Local Docker instance: http://localhost:5001*
