Skip to content

Latest commit

 

History

History
479 lines (368 loc) · 13 KB

File metadata and controls

479 lines (368 loc) · 13 KB

✅ Vote Validation Guide

Overview

This guide explains the comprehensive validation system that ensures election integrity in the Blockchain Voting System.


Validation Layers

The system uses multi-layer validation to prevent invalid votes:

┌─────────────────────────────────────┐
│ Layer 1: Field Validation          │  Vote.isValid()
├─────────────────────────────────────┤
│ Layer 2: Format Validation         │  VoteValidator
├─────────────────────────────────────┤
│ Layer 3: Duplicate Detection       │  Blockchain.hasVoterVoted()
├─────────────────────────────────────┤
│ Layer 4: Block-Level Check         │  Block.hasVoter()
├─────────────────────────────────────┤
│ Layer 5: Hash Integrity            │  Block.isValid()
└─────────────────────────────────────┘

Layer 1: Field Validation

What It Checks

  • Voter ID is not empty
  • Candidate name is not empty
  • Fields don't contain only whitespace

Code Location

Vote::isValid() in Vote.cpp

Example Valid Votes

✅ Vote("VOTER-001", "Alice Johnson")
✅ Vote("ABC123", "Bob Smith")
✅ Vote("temp_voter_42", "Charlie Davis")

Example Invalid Votes

❌ Vote("", "Alice Johnson")          // Empty voter ID
❌ Vote("VOTER-001", "")              // Empty candidate
❌ Vote("   ", "Bob Smith")           // Whitespace-only voter ID
❌ Vote("VOTER-002", "   ")           // Whitespace-only candidate

Error Messages

✗ Vote rejected: Invalid vote data (empty fields)

Layer 2: Format Validation

What It Checks (VoteValidator)

Voter ID Rules

  • Minimum length: 3 characters
  • Maximum length: 50 characters
  • Allowed characters:
    • Alphanumeric (A-Z, a-z, 0-9)
    • Hyphen (-)
    • Underscore (_)
    • Space ( )

Candidate Name Rules

  • Minimum length: 2 characters
  • Maximum length: 100 characters
  • Allowed characters: Same as voter ID

Code Location

VoteValidator::validateVote() in VoteValidator.cpp

Example Valid Inputs

✅ VoteValidator::validateVoterID("ABC")              // Min length
✅ VoteValidator::validateVoterID("VOTER-123")        // With hyphen
✅ VoteValidator::validateVoterID("temp_user_001")    // With underscore
✅ VoteValidator::validateCandidate("Jo")             // Min length
✅ VoteValidator::validateCandidate("Alice Johnson")  // With space

Example Invalid Inputs

❌ VoteValidator::validateVoterID("AB")               // Too short
❌ VoteValidator::validateVoterID("A!B")              // Invalid char
❌ VoteValidator::validateVoterID("")                 // Empty
❌ VoteValidator::validateCandidate("X")              // Too short
❌ VoteValidator::validateCandidate("Alice@Email")    // Invalid char

Error Messages

✗ Voter ID too short (minimum 3 characters)
✗ Voter ID too long (maximum 50 characters)
✗ Voter ID contains invalid characters
✗ Candidate name too short (minimum 2 characters)
✗ Candidate name too long (maximum 100 characters)

Layer 3: Cross-Chain Duplicate Detection

What It Checks

  • Scans entire blockchain for duplicate voter IDs
  • Prevents the same voter from voting multiple times
  • Critical security feature for election integrity

Code Location

Blockchain::hasVoterVoted() in Blockchain.cpp

How It Works

1. Receive new vote with voter ID "VOTER-001"
2. Scan Genesis Block (Block #0) - No votes
3. Scan Block #1 - Check all votes for "VOTER-001"
4. Scan Block #2 - Check all votes for "VOTER-001"
   ↓ Found! "VOTER-001" already voted in Block #2
5. REJECT the new vote

Time Complexity

  • Current: O(n × m) where n=blocks, m=votes/block
  • Optimized: O(1) with hash set (see COMPLEXITY_ANALYSIS.md)

Example Scenario

Block #1:

Vote("VOTER-001", "Alice Johnson")  ✅ Accepted (first vote)
Vote("VOTER-002", "Bob Smith")      ✅ Accepted (first vote)

Block #2 (Later):

Vote("VOTER-001", "Charlie Davis")  ❌ REJECTED - Already voted in Block #1
Vote("VOTER-003", "Alice Johnson")  ✅ Accepted (first vote)

Error Messages

✗ Vote rejected: Voter VOTER-001 has already voted in the blockchain

Layer 4: Block-Level Duplicate Check

What It Checks

  • Prevents duplicate voter IDs within the same pending block
  • Catches attempts to vote twice before block is sealed

Code Location

Block::hasVoter() in Block.cpp

Example Scenario

Pending Block #5:

pendingBlock.addVote(Vote("VOTER-100", "Alice"))  ✅ Accepted
pendingBlock.addVote(Vote("VOTER-101", "Bob"))    ✅ Accepted
pendingBlock.addVote(Vote("VOTER-100", "Charlie")) ❌ REJECTED - Duplicate in this block!

Error Messages

✗ Vote rejected: Voter VOTER-100 already voted in this pending block

Layer 5: Hash Integrity Validation

What It Checks

  • Block's stored hash matches its calculated hash
  • Detects any tampering with block data
  • Ensures cryptographic integrity

Code Location

Block::isValid() in Block.cpp

How It Works

1. Get stored hash: "a1b2c3..."
2. Recalculate hash from current block data
3. Compare: stored == calculated?
   ✅ Match → Block is valid
   ❌ Mismatch → Block tampered!

Example Tampering Detection

// Original block
Block block1(1, "0");
block1.addVote(Vote("VOTER-001", "Alice"));
// Hash: a1b2c3d4e5f6...

// Someone tries to modify the vote (after adding to chain)
// Change "Alice" to "Bob"
block1.isValid();  // ❌ Returns false - hash mismatch!

Error Messages

✗ Block #2 has invalid hash!

Complete Validation Flow

Adding a Vote: Step-by-Step

Vote newVote("VOTER-123", "Alice Johnson");
Block pendingBlock(5, previousHash);
Blockchain chain;

// Step 1: Field Validation
if (!newVote.isValid()) {
    return;  // ❌ REJECT: Empty fields
}

// Step 2: Format Validation
ValidationResult result = VoteValidator::validateVote(
    newVote.getVoterTempID(), 
    newVote.getCandidate()
);
if (!result.isValid) {
    std::cerr << result.errorMessage;
    return;  // ❌ REJECT: Invalid format
}

// Step 3: Cross-Chain Duplicate Check
if (chain.hasVoterVoted("VOTER-123")) {
    return;  // ❌ REJECT: Already voted in blockchain
}

// Step 4: Block-Level Duplicate Check
if (pendingBlock.hasVoter("VOTER-123")) {
    return;  // ❌ REJECT: Already in this block
}

// Step 5: Add Vote (triggers hash recalculation)
pendingBlock.addVote(newVote);  // ✅ ACCEPTED

// Step 6: Seal Block and Add to Chain
chain.addBlock(pendingBlock);

// Step 7: Validate Chain Integrity
if (chain.isChainValid()) {
    // ✅ SUCCESS: Vote is now permanently recorded
}

Test Cases

Test Suite 1: Valid Votes

✅ Normal vote: Vote("VOTER-001", "Alice Johnson")
✅ Minimum length: Vote("ABC", "Jo")
✅ With special chars: Vote("VOTER_123-A", "Bob Smith-Jr")
✅ Maximum length: Vote("X" * 50, "Y" * 100)

Test Suite 2: Invalid Field Values

❌ Empty voter ID: Vote("", "Alice")
❌ Empty candidate: Vote("VOTER-001", "")
❌ Whitespace voter: Vote("   ", "Alice")
❌ Whitespace candidate: Vote("VOTER-001", "   ")
❌ Too short voter: Vote("AB", "Alice")
❌ Too short candidate: Vote("VOTER-001", "A")
❌ Invalid characters: Vote("VOTER@001", "Alice")

Test Suite 3: Duplicate Detection (Cross-Block)

// Block #1
✅ Vote("VOTER-001", "Alice")

// Block #2
❌ Vote("VOTER-001", "Bob")  // Duplicate voter ID
✅ Vote("VOTER-002", "Alice")  // Different voter, same candidate OK

Test Suite 4: Duplicate Detection (Same Block)

Block pendingBlock;
✅ Vote("VOTER-001", "Alice")
❌ Vote("VOTER-001", "Bob")  // Same block duplicate
✅ Vote("VOTER-002", "Alice")

Test Suite 5: Hash Integrity

Block block1(1, "0");
block1.addVote(Vote("VOTER-001", "Alice"));

✅ block1.isValid()  // Returns true

// Tamper with vote (simulate attack)
block1.votes[0].candidate = "Bob";

❌ block1.isValid()  // Returns false - hash mismatch

Running Tests

Quick Test

make test
# or
./voting_system

Comprehensive Test Output

============================================================
  TEST 1: Valid Votes
============================================================
✓ Vote accepted: VOTER-A1B2C3 -> Alice Johnson
✓ Vote accepted: VOTER-D4E5F6 -> Bob Smith
✓ All valid votes accepted successfully

============================================================
  TEST 2: Invalid Vote Fields
============================================================
✗ Vote rejected: Invalid vote data (empty fields)
✗ Vote rejected: Invalid vote data (empty fields)
✗ All invalid votes correctly rejected

============================================================
  TEST 3: Duplicate Vote Detection
============================================================
✓ Vote accepted: VOTER-001 -> Alice Johnson
✓ Vote accepted: VOTER-002 -> Bob Smith
✗ Vote rejected: Voter VOTER-001 has already voted in the blockchain
✓ Duplicate detection working correctly

Security Guarantees

What This System Prevents

Empty Votes: Cannot cast vote without voter ID or candidate
Double Voting: One voter ID = one vote maximum
Malformed Data: Length and character restrictions
Data Tampering: Hash verification detects modifications
Replay Attacks: Timestamps and chain position prevent reuse

What This System Allows

Anonymous Voting: Temporary IDs don't reveal identity
Multiple Votes for Same Candidate: Different voters can choose same candidate
Immutable Audit Trail: Complete voting history preserved
Transparent Verification: Anyone can validate the chain


Best Practices

For Developers

  1. Always validate before adding: Use addVoteToPendingBlock() instead of direct addVote()
  2. Check return values: Methods return bool to indicate success/failure
  3. Validate entire chain: Call isChainValid() periodically
  4. Log rejections: Track invalid votes for security auditing

For System Administrators

  1. Monitor rejection rate: High rejection rate may indicate attack
  2. Regular chain validation: Ensure integrity hasn't been compromised
  3. Backup blockchain: Immutable data should be preserved
  4. Review validation rules: Adjust length limits based on requirements

Customizing Validation Rules

Changing Length Constraints

Edit VoteValidator.h:

class VoteValidator {
public:
    // Customize these values
    static const size_t MIN_VOTER_ID_LENGTH = 5;      // Changed from 3
    static const size_t MAX_VOTER_ID_LENGTH = 100;    // Changed from 50
    static const size_t MIN_CANDIDATE_LENGTH = 3;     // Changed from 2
    static const size_t MAX_CANDIDATE_LENGTH = 200;   // Changed from 100
};

Adding Custom Validation

Add to VoteValidator.cpp:

bool VoteValidator::validateCustomRule(const std::string& voterId) {
    // Example: Must start with "VOTER-"
    if (voterId.substr(0, 6) != "VOTER-") {
        return false;
    }
    return true;
}

Debugging Validation Issues

Common Issues

Issue: "Vote rejected but looks valid"

// Check for hidden whitespace
Vote vote("VOTER-001 ", "Alice");  // Trailing space!

Solution: Trim input before creating Vote

std::string trimmed = trim(input);  // Remove leading/trailing whitespace
Vote vote(trimmed, candidate);

Issue: "Duplicate rejection seems wrong"

// Case sensitivity matters!
Vote("VOTER-001", "Alice")  // Different from
Vote("voter-001", "Alice")  // Different voter ID

Solution: Normalize voter IDs (e.g., uppercase)


Performance Considerations

Validation Speed

Operation Time Notes
Field validation <1μs String checks
Format validation <10μs Length + character checks
Duplicate check (current) O(n×m) Scans full chain
Duplicate check (optimized) O(1) With hash set
Hash validation <1ms SHA-256 calculation

Optimization Recommendation

For elections with >1,000 voters, implement hash set optimization (see COMPLEXITY_ANALYSIS.md) to reduce duplicate checking from O(n×m) to O(1).


Conclusion

The multi-layer validation system ensures:

  • Data integrity through field and format validation
  • Election integrity through duplicate detection
  • Cryptographic security through hash verification
  • Transparency through clear error messages

This comprehensive approach makes the blockchain voting system secure and reliable for real-world elections.