Files
aitbc/tests/property_tests/test_crypto_properties.py
aitbc 2713951a1b
Some checks failed
API Endpoint Tests / test-api-endpoints (push) Successful in 17s
CLI Tests / test-cli (push) Failing after 3s
Cross-Node Transaction Testing / transaction-test (push) Successful in 3s
Deploy to Testnet / deploy-testnet (push) Has been cancelled
Multi-Node Stress Testing / stress-test (push) Has been cancelled
Node Failover Simulation / failover-test (push) Has been cancelled
Integration Tests / test-service-integration (push) Successful in 2m39s
Package Tests / Python package - aitbc-agent-sdk (push) Failing after 12s
Package Tests / Python package - aitbc-core (push) Successful in 12s
Package Tests / Python package - aitbc-crypto (push) Successful in 10s
Package Tests / Python package - aitbc-sdk (push) Failing after 7s
Package Tests / JavaScript package - aitbc-sdk-js (push) Successful in 6s
Package Tests / JavaScript package - aitbc-token (push) Successful in 14s
Python Tests / test-python (push) Failing after 9s
Security Scanning / security-scan (push) Successful in 15s
refactor: reorganize aitbc core library into subpackages
- Create aitbc/crypto/ subpackage (crypto.py, security.py)
- Create aitbc/utils/ subpackage (validation, time_utils, json_utils, paths, env)
- Create aitbc/network/ subpackage (http_client, web3_utils)
- Update all import statements across codebase
- Maintain backward compatibility with __init__.py exports
- Improve code organization and modularity
2026-05-09 12:25:14 +02:00

153 lines
5.7 KiB
Python

"""
Property-based tests for critical AITBC cryptographic functions using hypothesis.
Tests ensure that cryptographic operations maintain expected properties across random inputs.
"""
import pytest
from hypothesis import given, strategies as st, settings
from hypothesis.strategies import text, binary, integers
import json
from aitbc.crypto.crypto import (
derive_ethereum_address,
sign_transaction_hash,
verify_signature,
encrypt_private_key,
decrypt_private_key,
keccak256_hash,
sha256_hash,
generate_secure_random_bytes,
validate_ethereum_address,
generate_ethereum_private_key
)
class TestCryptoProperties:
"""Property-based tests for cryptographic functions"""
@given(st.binary(min_size=32, max_size=32))
@settings(max_examples=100)
def test_derive_address_deterministic(self, private_key_bytes):
"""Test that address derivation is deterministic for same private key"""
# Convert bytes to hex string
private_key_hex = private_key_bytes.hex()
# Derive address twice
address1 = derive_ethereum_address(private_key_hex)
address2 = derive_ethereum_address(private_key_hex)
# Should be identical
assert address1 == address2
@given(st.binary(min_size=32, max_size=32))
@settings(max_examples=50)
def test_derived_address_format(self, private_key_bytes):
"""Test that derived addresses have correct format"""
private_key_hex = private_key_bytes.hex()
address = derive_ethereum_address(private_key_hex)
# Address should be 42 characters (0x + 40 hex chars)
assert len(address) == 42
assert address.startswith('0x')
assert all(c in '0123456789abcdef' for c in address[2:])
@given(st.binary(min_size=32, max_size=32), st.binary(min_size=32, max_size=32))
@settings(max_examples=50)
def test_sign_verify_roundtrip(self, private_key_bytes, message_bytes):
"""Test that signing and verification are consistent"""
private_key_hex = private_key_bytes.hex()
message_hash = message_bytes.hex()
# Sign message
signature = sign_transaction_hash(message_hash, private_key_hex)
# Derive address from private key
address = derive_ethereum_address(private_key_hex)
# Verify signature
assert verify_signature(message_hash, signature, address)
@given(st.text(min_size=8, max_size=64), st.text(min_size=8, max_size=64))
@settings(max_examples=50)
def test_encrypt_decrypt_roundtrip(self, password, private_key):
"""Test that encryption and decryption are reversible"""
# Ensure private key is valid hex
private_key_hex = private_key.encode('utf-8').hex()[:64].ljust(64, '0')
# Encrypt
encrypted = encrypt_private_key(private_key_hex, password)
# Decrypt
decrypted = decrypt_private_key(encrypted, password)
# Should match original
assert decrypted == private_key_hex
@given(st.binary(min_size=1, max_size=1024))
@settings(max_examples=50)
def test_keccak256_deterministic(self, data):
"""Test that Keccak-256 hashing is deterministic"""
hash1 = keccak256_hash(data.hex())
hash2 = keccak256_hash(data.hex())
assert hash1 == hash2
@given(st.binary(min_size=1, max_size=1024))
@settings(max_examples=50)
def test_sha256_deterministic(self, data):
"""Test that SHA-256 hashing is deterministic"""
hash1 = sha256_hash(data.hex())
hash2 = sha256_hash(data.hex())
assert hash1 == hash2
@given(st.integers(min_value=16, max_value=128))
@settings(max_examples=50)
def test_random_bytes_length(self, length):
"""Test that random byte generation produces correct length"""
random_bytes = generate_secure_random_bytes(length)
# Should be 2*length hex characters
assert len(random_bytes) == length * 2
@given(st.integers(min_value=16, max_value=128))
@settings(max_examples=50)
def test_random_bytes_uniqueness(self, length):
"""Test that random byte generation produces unique values"""
random_bytes1 = generate_secure_random_bytes(length)
random_bytes2 = generate_secure_random_bytes(length)
# Should be different (extremely unlikely to be same)
assert random_bytes1 != random_bytes2
@given(st.binary(min_size=32, max_size=32))
@settings(max_examples=50)
def test_address_validation(self, private_key_bytes):
"""Test that derived addresses pass validation"""
private_key_hex = private_key_bytes.hex()
address = derive_ethereum_address(private_key_hex)
assert validate_ethereum_address(address)
@given(st.text(alphabet='0123456789abcdef', min_size=40, max_size=40))
@settings(max_examples=50)
def test_address_validation_format(self, hex_string):
"""Test address validation with various formats"""
# Valid format with 0x prefix
valid_address = '0x' + hex_string
assert validate_ethereum_address(valid_address)
# Invalid format without 0x prefix
invalid_address = hex_string
assert not validate_ethereum_address(invalid_address)
@settings(max_examples=10)
def test_private_key_generation_format(self):
"""Test that generated private keys have correct format"""
private_key = generate_ethereum_private_key()
# Should be 66 characters (0x + 64 hex chars)
assert len(private_key) == 66
assert private_key.startswith('0x')
assert all(c in '0123456789abcdef' for c in private_key[2:])