diff --git a/README.md b/README.md index 45dcc3b..7863f60 100644 --- a/README.md +++ b/README.md @@ -246,7 +246,30 @@ int_cipher_text, signature = build_string_input_text(plaintext, user_aes_key, se - `input_text`: A dictionary of the form { "ciphertext": { "value": int[] }, "signature": bytes[] } -### 9. `generate_rsa_keypair()` +### 9. `build_address_input_text(plaintext, user_aes_key, sender, contract, func_selector, signing_key)` + +**Purpose:** Builds input text by encrypting the plaintext and signing it. + +**Usage:** + +```python +int_cipher_text, signature = build_address_input_text(plaintext, user_aes_key, sender, contract, func_selector, signing_key) +``` + +**Parameters:** + +- `plaintext`: The plaintext message. +- `user_aes_key`: The user's AES key. +- `sender`: The sender's address. +- `contract`: The contract address. +- `func_selector`: The function selector. +- `signing_key`: The private key used for signing. + +**Returns:** + +- `input_text`: A dictionary of the form { "ciphertext": { "ct1": int, "ct2": int, "ct3": int }, "signature1": bytes, "signature2": bytes, "signature3": bytes } + +### 10. `generate_rsa_keypair()` **Purpose:** Generates an RSA key pair. @@ -261,7 +284,7 @@ private_key_bytes, public_key_bytes = generate_rsa_keypair() - `private_key_bytes`: The serialized private key. - `public_key_bytes`: The serialized public key. -### 10. `encrypt_rsa(public_key_bytes, plaintext)` +### 11. `encrypt_rsa(public_key_bytes, plaintext)` **Purpose:** Encrypts plaintext using RSA encryption with a provided public key. @@ -280,7 +303,7 @@ ciphertext = encrypt_rsa(public_key_bytes, plaintext) - `ciphertext`: The encrypted message. -### 11. `decrypt_rsa(private_key_bytes, ciphertext)` +### 12. `decrypt_rsa(private_key_bytes, ciphertext)` **Purpose:** Decrypts ciphertext using RSA decryption with a provided private key. @@ -299,7 +322,7 @@ plaintext = decrypt_rsa(private_key_bytes, ciphertext) - `plaintext`: The decrypted message. -### 12. `decrypt_uint(ciphertext, user_key)` +### 13. `decrypt_uint(ciphertext, user_key)` **Purpose:** Decrypts a value stored in a contract using a user key @@ -318,7 +341,7 @@ plaintext = decrypt_uint(ciphertext, user_key) - `result`: The decrypted value. -### 13. `decrypt_string(ciphertext, user_key)` +### 14. `decrypt_string(ciphertext, user_key)` **Purpose:** Decrypts a value stored in a contract using a user key @@ -337,6 +360,25 @@ plaintext = decrypt_string(ciphertext, user_key) - `result`: The decrypted value. +### 15. `decrypt_address(ciphertext, user_key)` + +**Purpose:** Decrypts a value stored in a contract and encrypted using a user key + +**Usage:** + +```python +plaintext = decrypt_string(ciphertext, user_key) +``` + +**Parameters:** + +- `ciphertext`: A dictionary of the form { "ct1": int, "ct2": int, "ct3": int } where each cell holds a portion of the address encrypted +- `userKey`: The user's AES key. + +**Returns:** + +- `result`: The decrypted address. + # Utilities (utils.py) Functions ### 1. `web3_connected(web3)` diff --git a/coti/crypto_utils.py b/coti/crypto_utils.py index 483d4f3..b5ac38d 100644 --- a/coti/crypto_utils.py +++ b/coti/crypto_utils.py @@ -6,6 +6,7 @@ from cryptography.hazmat.primitives.asymmetric import rsa from eth_keys import keys from math import ceil +from web3 import Web3 block_size = AES.block_size address_size = 20 @@ -153,6 +154,47 @@ def build_string_input_text(plaintext, user_aes_key, sender, contract, function_ return input_text +def build_address_input_text(plaintext, user_aes_key, sender, contract, function_selector, signing_key): + ct_int_1, sig_1 = build_input_text( + int(plaintext[2:18], 16), # bytes 1 - 8 + user_aes_key, + sender, + contract, + function_selector, + signing_key + ) + + ct_int_2, sig_2 = build_input_text( + int(plaintext[18:34], 16), # bytes 9 - 16 + user_aes_key, + sender, + contract, + function_selector, + signing_key + ) + + ct_int_3, sig_3 = build_input_text( + int(plaintext[34:42], 16), # bytes 17 - 20 + user_aes_key, + sender, + contract, + function_selector, + signing_key + ) + + input_text = { + 'ciphertext': { + 'ct1': ct_int_1, + 'ct2': ct_int_2, + 'ct3': ct_int_3 + }, + 'signature1': sig_1, + 'signature2': sig_2, + 'signature3': sig_3 + } + + return input_text + def decrypt_uint(ciphertext, user_key): # Convert ct to bytes (big-endian) @@ -194,6 +236,28 @@ def decrypt_string(ciphertext, user_key): return decrypted_string.strip('\0') +def decrypt_address(ciphertext, user_key): + if isinstance(ciphertext, list): # format when reading ciphertext from a state variable + __ciphertext = ciphertext + else: # format when reading ciphertext from an event + __ciphertext = list(ciphertext.values()) + + addr = '0x' + + decrypted = decrypt_uint(__ciphertext[0], user_key) + + addr += hex(decrypted)[2:].rjust(16, '0') # 8 bytes is 16 characters + + decrypted = decrypt_uint(__ciphertext[1], user_key) + + addr += hex(decrypted)[2:].rjust(16, '0') # 8 bytes is 16 characters + + decrypted = decrypt_uint(__ciphertext[2], user_key) + + addr += hex(decrypted)[2:].rjust(8, '0') # 4 bytes is 8 characters + + return Web3.to_checksum_address(addr) + def generate_rsa_keypair(): # Generate RSA key pair