diff --git a/README.md b/README.md index 96aeca5..1bf1dd1 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,11 @@ ## Overview -`bt-ddos-shield` is a Python package designed to address the critical issue of Distributed Denial-of-Service (DDoS) attacks in bittensor ecosystem. The project leverages encryption to protect communication between miners and validators, ensuring the IPs and ports of these nodes remain secure and hidden from malicious actors. This decentralized solution aims to eliminate the financial burden caused by traditional DDoS protection methods like WAF and Cloudflare, which are often costly and impractical for subnets handling large volumes of data. +`bt-ddos-shield` is a Python package designed to address the critical issue of Distributed Denial-of-Service (DDoS) attacks +in bittensor ecosystem. The project leverages encryption to protect communication between miners and validators, ensuring +the IPs and ports of these nodes remain secure and hidden from malicious actors. This decentralized solution aims to eliminate +the financial burden caused by traditional DDoS protection methods like WAF and Cloudflare, which are often costly and +impractical for subnets handling large volumes of data. ## Project Goals @@ -23,8 +27,32 @@ The goal of this project is to implement a distributed and decentralized system - Prevents IP address exposure by sharing encrypted connection data through a decentralized network of subtensors. 3. **Secure Message Exchange**: - - Validators can request the connection information of miners from the subtensor network. This information is validated and decrypted locally using the validator's private key. - + - Validators can request the connection information of miners from the subtensor network. This information is validated and + decrypted locally using the validator's private key. + +## Communication Flow + + + +![](./assets/diagrams/CommunicationFlow.svg) ## Installation ``` diff --git a/assets/diagrams/CommunicationFlow.svg b/assets/diagrams/CommunicationFlow.svg new file mode 100644 index 0000000..29814ea --- /dev/null +++ b/assets/diagrams/CommunicationFlow.svg @@ -0,0 +1,29 @@ +ValidatorValidatorMinerMinerGitHubGitHubStorageStorageBittensorBittensorGenerate Validator key-pairPublish public key along with HotKeyFetch Validator infoEncrypt Miner IP/Domain with Validator public keyAdd/update file with encrypted IPs/Domains for ValidatorsPublish file locationFetch file locationFetch Miner fileDecrypt Miner file entry encrypted for given ValidatorSend request using decrypted Miner IP/Domain \ No newline at end of file diff --git a/bt_ddos_shield/encryption.py b/bt_ddos_shield/encryption.py index a0a1d98..4737d52 100644 --- a/bt_ddos_shield/encryption.py +++ b/bt_ddos_shield/encryption.py @@ -11,11 +11,10 @@ class DecryptionError(Exception): class EncryptionManager: - def __init__(self): - pass + @staticmethod def encrypt_data( - self, public_key: str, data: dict, encoding: str = "utf-8" + public_key: str, data: dict, encoding: str = "utf-8" ) -> bytes: """ Encrypts the given data as a dictionary using the provided public key. @@ -23,7 +22,7 @@ def encrypt_data( Args: public_key (str): The public key in string format that will be used to encrypt the data. data (dict): The data to be encrypted, represented as a dictionary. - encoding (str): Encoding format for the string representation of the data (default: 'utf-8). + encoding (str): Encoding format for the string representation of the data (default: 'utf-8'). Returns: bytes: The encrypted data in bytes format. @@ -41,16 +40,17 @@ def encrypt_data( except Exception as e: raise EncryptionError(f"Encryption failed: {e}") + @staticmethod def decrypt_data( - self, private_key: str, encrypted_data: bytes, encoding: str = "utf-8" + private_key: str, encrypted_data: bytes, encoding: str = "utf-8" ) -> dict: """ Decrypts the given encrypted data using the provided private key. Args: - private_key (str): The private key in string format used for decription. + private_key (str): The private key in string format used for decryption. encrypted_data (bytes): The encrypted data to be decrypted. - encoding (str): Encoding format for the string representation of the data (default: 'utf-8). + encoding (str): Encoding format for the string representation of the data (default: 'utf-8'). Returns: dict: The decrypted data, converted back to a dictionary. @@ -67,4 +67,4 @@ def decrypt_data( decrypted_dict = json.loads(decrypted_str) return decrypted_dict except Exception as e: - raise DecryptionError(f"Decrption failed: {e}") + raise DecryptionError(f"Decryption failed: {e}") diff --git a/tests/test_encryption.py b/tests/test_encryption.py index 508e306..8c3711c 100644 --- a/tests/test_encryption.py +++ b/tests/test_encryption.py @@ -25,7 +25,7 @@ invalid_string_data = "invalid_data" # Pre-encrypt valid data for decryption tests. -pre_encrypted_data = EncryptionManager().encrypt_data( +pre_encrypted_data = EncryptionManager.encrypt_data( public_key=public_key, data=valid_test_data ) @@ -40,7 +40,7 @@ def test_encrypt_data_valid(self): Test encryption with valid public key and data. Ensures the returned encrypted data is of bytes type. """ - encrypted_data = EncryptionManager().encrypt_data( + encrypted_data = EncryptionManager.encrypt_data( public_key=public_key, data=valid_test_data ) assert isinstance( @@ -49,11 +49,11 @@ def test_encrypt_data_valid(self): def test_encrypt_data_invalid_public_key(self): """ - Test encryption with an invalid public key (string that doens't represent a valid key). + Test encryption with an invalid public key (string that doesn't represent a valid key). Expects EncryptionError to be raised. """ with pytest.raises(EncryptionError): - EncryptionManager().encrypt_data( + EncryptionManager.encrypt_data( public_key=invalid_string_data, data=valid_test_data ) @@ -63,17 +63,17 @@ def test_encrypt_data_invalid_data_type(self): Expects TypeError to be raised. """ with pytest.raises(TypeError): - EncryptionManager().encrypt_data( + EncryptionManager.encrypt_data( public_key=public_key, data=invalid_string_data ) def test_encrypt_data_invalid_public_key_type(self): """ Test encryption with a public key of invalid type (e.g., integer). - Exepcts TypeError to be raised. + Expects TypeError to be raised. """ with pytest.raises(TypeError): - EncryptionManager().encrypt_data( + EncryptionManager.encrypt_data( public_key=invalid_key_type, data=valid_test_data ) @@ -82,7 +82,7 @@ def test_encrypt_data_empty_data(self): Test encryption with an empty dictionary. Expects encryption to succeed and return data of type bytes. """ - encrypted_empty_data = EncryptionManager().encrypt_data( + encrypted_empty_data = EncryptionManager.encrypt_data( public_key=public_key, data=empty_data_dict ) assert isinstance( @@ -94,7 +94,7 @@ def test_decrypt_data_valid(self): Test decryption with valid private key and encrypted data. Ensures that the decrypted data matches the original dictionary. """ - decrypted_data = EncryptionManager().decrypt_data( + decrypted_data = EncryptionManager.decrypt_data( private_key=private_key, encrypted_data=pre_encrypted_data ) assert isinstance(decrypted_data, dict), "Decrypted data should be of type dict" @@ -107,10 +107,10 @@ def test_decrypt_data_empty_data(self): Test decryption with an empty dictionary. Expects that the decrypted data matches the original dictionary. """ - encrypted_empty_data = EncryptionManager().encrypt_data( + encrypted_empty_data = EncryptionManager.encrypt_data( public_key=public_key, data=empty_data_dict ) - decrypted_data = EncryptionManager().decrypt_data( + decrypted_data = EncryptionManager.decrypt_data( private_key=private_key, encrypted_data=encrypted_empty_data ) assert isinstance(decrypted_data, dict), "Decrypted data should be of type dict" @@ -120,11 +120,11 @@ def test_decrypt_data_empty_data(self): def test_decrypt_data_invalid_private_key(self): """ - Test decryption with an invalid private key (string that doesn't represnet a valid key). + Test decryption with an invalid private key (string that doesn't represent a valid key). Expects DecryptionError to be raised. """ with pytest.raises(DecryptionError): - EncryptionManager().decrypt_data( + EncryptionManager.decrypt_data( private_key=invalid_string_data, encrypted_data=pre_encrypted_data ) @@ -134,7 +134,7 @@ def test_decrypt_data_invalid_encrypted_data(self): Expects DecryptionError to be raised. """ with pytest.raises(DecryptionError): - EncryptionManager().decrypt_data( + EncryptionManager.decrypt_data( private_key=private_key, encrypted_data=non_encrypted_bytes ) @@ -144,7 +144,7 @@ def test_decrypt_data_invalid_private_key_type(self): Expects TypeError to be raised. """ with pytest.raises(TypeError): - EncryptionManager().decrypt_data( + EncryptionManager.decrypt_data( private_key=invalid_key_type, encrypted_data=pre_encrypted_data ) @@ -154,7 +154,7 @@ def test_decrypt_data_invalid_encrypted_data_type(self): Expects TypeError to be raised. """ with pytest.raises(TypeError): - EncryptionManager().decrypt_data( + EncryptionManager.decrypt_data( private_key=private_key, encrypted_data=invalid_key_type ) @@ -164,6 +164,6 @@ def test_decrypt_data_empty_encrypted_data(self): Expects DecryptionError to be raised. """ with pytest.raises(DecryptionError): - EncryptionManager().decrypt_data( + EncryptionManager.decrypt_data( private_key=private_key, encrypted_data=empty_byte )