"""Pure-Python AES-256 CTR DRBG implementation.

This implements NIST SP 800-90A Rev. 1 CTR_DRBG using AES-256.
Used for generating deterministic test vectors (KATs).

Reference: NIST SP 800-90A Rev. 1
"""

from .aes import AES256


class AES256_CTR_DRBG:
    """AES-256 CTR_DRBG for deterministic random generation."""
    
    def __init__(self, seed: bytes):
        """Initialize DRBG with seed material.
        
        Args:
            seed: Seed material (48 bytes for AES-256 CTR_DRBG)
        """
        if len(seed) != 48:
            raise ValueError("Seed must be 48 bytes for AES-256 CTR_DRBG")
        
        # Initialize working state
        self._key = bytes(32)  # 256-bit key
        self._v = bytes(16)     # 128-bit counter
        
        # Instantiate with seed
        self._update(seed)
    
    def _update(self, provided_data: bytes):
        """Update internal state.
        
        Args:
            provided_data: 48 bytes of data to mix into state
        """
        if len(provided_data) != 48:
            raise ValueError("provided_data must be 48 bytes")
        
        # Generate 48 bytes using current key and counter
        temp = b""
        cipher = AES256(self._key)
        
        for _ in range(3):  # 3 blocks = 48 bytes
            # Increment counter
            v_int = int.from_bytes(self._v, 'big')
            v_int = (v_int + 1) % (2**128)
            self._v = v_int.to_bytes(16, 'big')
            
            # Encrypt counter
            block = cipher.encrypt_block(self._v)
            temp += block
        
        # XOR with provided data
        temp_xor = bytes(a ^ b for a, b in zip(temp, provided_data))
        
        # Update key and V
        self._key = temp_xor[:32]
        self._v = temp_xor[32:48]
    
    def generate(self, num_bytes: int, additional_input: bytes = None) -> bytes:
        """Generate random bytes.
        
        Args:
            num_bytes: Number of bytes to generate
            additional_input: Optional additional input (must be 48 bytes if provided)
        
        Returns:
            Generated random bytes
        """
        if additional_input is None:
            additional_input = bytes(48)
        elif len(additional_input) != 48:
            raise ValueError("additional_input must be 48 bytes if provided")
        
        # Update with additional input
        if additional_input != bytes(48):
            self._update(additional_input)
        
        # Generate output
        output = b""
        cipher = AES256(self._key)
        
        blocks_needed = (num_bytes + 15) // 16
        for _ in range(blocks_needed):
            # Increment counter
            v_int = int.from_bytes(self._v, 'big')
            v_int = (v_int + 1) % (2**128)
            self._v = v_int.to_bytes(16, 'big')
            
            # Encrypt counter
            block = cipher.encrypt_block(self._v)
            output += block
        
        # Update state
        self._update(additional_input)
        
        # Return requested number of bytes
        return output[:num_bytes]


def drbg_generate(seed: bytes, length: int) -> bytes:
    """Generate deterministic random bytes from seed.
    
    Args:
        seed: 48-byte seed
        length: Number of bytes to generate
    
    Returns:
        Generated bytes
    """
    drbg = AES256_CTR_DRBG(seed)
    return drbg.generate(length)


# Self-test
if __name__ == "__main__":
    # Test vector (simplified)
    seed = b"0" * 48
    drbg = AES256_CTR_DRBG(seed)
    output = drbg.generate(32)
    
    # Verify determinism
    drbg2 = AES256_CTR_DRBG(seed)
    output2 = drbg2.generate(32)
    
    assert output == output2, "DRBG output not deterministic"
    assert len(output) == 32, f"Expected 32 bytes, got {len(output)}"
    
    print(f"DRBG self-test passed")
    print(f"Sample output: {output.hex()[:64]}...")
