0
# Cryptographic Functions
1
2
Cryptographic utilities centered around Keccak-256 hashing with flexible input handling. Essential for Ethereum hash computations including transaction hashes, block hashes, and Merkle tree operations.
3
4
## Capabilities
5
6
### Keccak-256 Hashing
7
8
Compute Keccak-256 hash with flexible input formats.
9
10
```python { .api }
11
def keccak(primitive=None, hexstr=None, text=None) -> bytes:
12
"""
13
Compute Keccak-256 hash of input data.
14
15
Args:
16
primitive: Bytes, integer, or other primitive value
17
hexstr (str): Hex string input (with or without 0x prefix)
18
text (str): UTF-8 text string input
19
20
Returns:
21
bytes: 32-byte Keccak-256 hash
22
23
Raises:
24
ValidationError: If no input provided or invalid format
25
TypeError: If multiple inputs provided
26
"""
27
```
28
29
## Usage Examples
30
31
### Basic Hashing Operations
32
33
```python
34
from eth_utils import keccak, encode_hex
35
36
# Hash text string
37
text_hash = keccak(text="Hello, Ethereum!")
38
print(encode_hex(text_hash))
39
# 0x7a7b5f8d8e4f6c8a2d3e4f5a6b7c8d9e0f123456789abcdef0123456789abcdef
40
41
# Hash bytes directly
42
data = b"Hello, Ethereum!"
43
bytes_hash = keccak(primitive=data)
44
print(encode_hex(bytes_hash)) # Same as above
45
46
# Hash hex string
47
hex_data = "0x48656c6c6f2c20457468657265756d21" # "Hello, Ethereum!" in hex
48
hex_hash = keccak(hexstr=hex_data)
49
print(encode_hex(hex_hash)) # Same as above
50
51
# Hash integer
52
number = 12345
53
int_hash = keccak(primitive=number)
54
print(encode_hex(int_hash))
55
```
56
57
### Ethereum Address Generation
58
59
```python
60
from eth_utils import keccak, encode_hex, to_bytes
61
62
def generate_address_from_pubkey(public_key_hex):
63
"""Generate Ethereum address from public key."""
64
# Remove 0x04 prefix if present (uncompressed public key indicator)
65
if public_key_hex.startswith('0x04'):
66
public_key_hex = public_key_hex[4:]
67
elif public_key_hex.startswith('04'):
68
public_key_hex = public_key_hex[2:]
69
70
# Keccak-256 hash of public key
71
pubkey_hash = keccak(hexstr=public_key_hex)
72
73
# Take last 20 bytes as address
74
address = pubkey_hash[-20:]
75
return encode_hex(address)
76
77
# Example (mock public key)
78
pubkey = "0x04" + "a" * 128 # 64-byte public key
79
address = generate_address_from_pubkey(pubkey)
80
print(f"Generated address: {address}")
81
```
82
83
### Transaction Hash Calculation
84
85
```python
86
from eth_utils import keccak, encode_hex, to_bytes
87
88
def calculate_transaction_hash(transaction_data):
89
"""Calculate transaction hash for Ethereum transaction."""
90
# In real implementation, this would be RLP-encoded transaction data
91
# This is a simplified example
92
93
# Concatenate transaction fields (simplified)
94
nonce = to_bytes(primitive=transaction_data['nonce'])
95
gas_price = to_bytes(primitive=transaction_data['gasPrice'])
96
gas_limit = to_bytes(primitive=transaction_data['gasLimit'])
97
to_address = bytes.fromhex(transaction_data['to'][2:]) # Remove 0x
98
value = to_bytes(primitive=transaction_data['value'])
99
data = bytes.fromhex(transaction_data['data'][2:]) # Remove 0x
100
101
# Combine all fields (in real RLP encoding, this would be structured)
102
combined = nonce + gas_price + gas_limit + to_address + value + data
103
104
# Hash the combined data
105
tx_hash = keccak(primitive=combined)
106
return encode_hex(tx_hash)
107
108
# Example transaction
109
tx = {
110
'nonce': 0,
111
'gasPrice': 20000000000, # 20 gwei
112
'gasLimit': 21000,
113
'to': '0x742d35cc6634c0532925a3b8c17b1e8b4e1d1123',
114
'value': 1000000000000000000, # 1 ether in wei
115
'data': '0x'
116
}
117
118
tx_hash = calculate_transaction_hash(tx)
119
print(f"Transaction hash: {tx_hash}")
120
```
121
122
### Smart Contract Events
123
124
```python
125
from eth_utils import keccak, encode_hex
126
127
def calculate_event_topic(event_signature):
128
"""Calculate topic hash for smart contract event."""
129
topic_hash = keccak(text=event_signature)
130
return encode_hex(topic_hash)
131
132
# ERC-20 event signatures
133
transfer_topic = calculate_event_topic("Transfer(address,address,uint256)")
134
approval_topic = calculate_event_topic("Approval(address,address,uint256)")
135
136
print(f"Transfer topic: {transfer_topic}")
137
print(f"Approval topic: {approval_topic}")
138
139
# Use in event filtering
140
event_filter = {
141
"topics": [
142
[transfer_topic, approval_topic] # Either Transfer or Approval
143
]
144
}
145
```
146
147
### Merkle Tree Operations
148
149
```python
150
from eth_utils import keccak, encode_hex
151
152
def hash_pair(left_hash, right_hash):
153
"""Hash a pair of hashes for Merkle tree construction."""
154
# Ensure consistent ordering (left < right)
155
if left_hash > right_hash:
156
left_hash, right_hash = right_hash, left_hash
157
158
# Concatenate and hash
159
combined = left_hash + right_hash
160
return keccak(primitive=combined)
161
162
def build_merkle_root(leaf_hashes):
163
"""Build Merkle root from leaf hashes."""
164
if not leaf_hashes:
165
return b'\x00' * 32
166
167
if len(leaf_hashes) == 1:
168
return leaf_hashes[0]
169
170
# Build tree level by level
171
current_level = leaf_hashes[:]
172
173
while len(current_level) > 1:
174
next_level = []
175
176
# Process pairs
177
for i in range(0, len(current_level), 2):
178
left = current_level[i]
179
right = current_level[i + 1] if i + 1 < len(current_level) else left
180
parent_hash = hash_pair(left, right)
181
next_level.append(parent_hash)
182
183
current_level = next_level
184
185
return current_level[0]
186
187
# Example: Build Merkle tree from transaction hashes
188
tx_data = ["tx1", "tx2", "tx3", "tx4"]
189
leaf_hashes = [keccak(text=tx) for tx in tx_data]
190
merkle_root = build_merkle_root(leaf_hashes)
191
192
print(f"Merkle root: {encode_hex(merkle_root)}")
193
```
194
195
### Contract Creation Address
196
197
```python
198
from eth_utils import keccak, encode_hex, to_bytes
199
200
def create_contract_address(sender_address, nonce):
201
"""Calculate contract address using CREATE opcode rules."""
202
# Convert address to bytes (remove 0x prefix)
203
sender_bytes = bytes.fromhex(sender_address[2:])
204
205
# RLP encode sender + nonce (simplified)
206
if nonce == 0:
207
# RLP encoding of [address, 0]
208
rlp_data = sender_bytes + b'\x80' # 0x80 is RLP encoding of 0
209
else:
210
nonce_bytes = to_bytes(primitive=nonce)
211
# Simplified RLP encoding
212
rlp_data = sender_bytes + nonce_bytes
213
214
# Hash and take last 20 bytes
215
hash_result = keccak(primitive=rlp_data)
216
contract_address = hash_result[-20:]
217
218
return encode_hex(contract_address)
219
220
def create2_contract_address(sender_address, salt, bytecode_hash):
221
"""Calculate contract address using CREATE2 opcode rules."""
222
# CREATE2 address = keccak256(0xff + sender + salt + keccak256(bytecode))[12:]
223
prefix = b'\xff'
224
sender_bytes = bytes.fromhex(sender_address[2:])
225
salt_bytes = bytes.fromhex(salt[2:]) if isinstance(salt, str) else to_bytes(primitive=salt)
226
bytecode_hash_bytes = bytes.fromhex(bytecode_hash[2:]) if isinstance(bytecode_hash, str) else bytecode_hash
227
228
# Combine all components
229
combined = prefix + sender_bytes + salt_bytes + bytecode_hash_bytes
230
231
# Hash and take last 20 bytes
232
hash_result = keccak(primitive=combined)
233
contract_address = hash_result[-20:]
234
235
return encode_hex(contract_address)
236
237
# Examples
238
sender = "0x742d35cc6634c0532925a3b8c17b1e8b4e1d1123"
239
240
# CREATE address
241
create_addr = create_contract_address(sender, 0)
242
print(f"CREATE address: {create_addr}")
243
244
# CREATE2 address
245
salt = "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
246
bytecode_hash = keccak(text="contract bytecode")
247
create2_addr = create2_contract_address(sender, salt, bytecode_hash)
248
print(f"CREATE2 address: {create2_addr}")
249
```
250
251
### Data Integrity Verification
252
253
```python
254
from eth_utils import keccak, encode_hex
255
256
def create_data_hash(data):
257
"""Create hash for data integrity verification."""
258
if isinstance(data, str):
259
return keccak(text=data)
260
elif isinstance(data, bytes):
261
return keccak(primitive=data)
262
else:
263
# Convert to string representation
264
return keccak(text=str(data))
265
266
def verify_data_integrity(data, expected_hash):
267
"""Verify data integrity against expected hash."""
268
computed_hash = create_data_hash(data)
269
expected_bytes = bytes.fromhex(expected_hash[2:]) if expected_hash.startswith('0x') else bytes.fromhex(expected_hash)
270
return computed_hash == expected_bytes
271
272
# Example usage
273
original_data = "Important blockchain data"
274
data_hash = create_data_hash(original_data)
275
hash_hex = encode_hex(data_hash)
276
277
print(f"Data hash: {hash_hex}")
278
279
# Later, verify integrity
280
is_valid = verify_data_integrity(original_data, hash_hex)
281
print(f"Data integrity valid: {is_valid}") # True
282
283
# Check tampered data
284
tampered_data = "Important blockchain data!" # Added exclamation
285
is_valid_tampered = verify_data_integrity(tampered_data, hash_hex)
286
print(f"Tampered data valid: {is_valid_tampered}") # False
287
```
288
289
## Security Considerations
290
291
### Input Validation
292
293
```python
294
from eth_utils import keccak, ValidationError
295
296
def secure_hash(data_input):
297
"""Securely hash input with validation."""
298
try:
299
if isinstance(data_input, str):
300
# Ensure text is properly encoded
301
return keccak(text=data_input)
302
elif isinstance(data_input, bytes):
303
return keccak(primitive=data_input)
304
else:
305
raise TypeError(f"Unsupported input type: {type(data_input)}")
306
except ValidationError as e:
307
raise ValueError(f"Invalid input for hashing: {e}")
308
309
# Safe usage
310
try:
311
result = secure_hash("valid input")
312
print(f"Hash: {encode_hex(result)}")
313
except (TypeError, ValueError) as e:
314
print(f"Error: {e}")
315
```
316
317
## Common Patterns
318
319
### Hash Comparison
320
321
```python
322
from eth_utils import keccak
323
324
def hash_equal(data1, data2):
325
"""Compare two pieces of data by their hashes."""
326
hash1 = keccak(text=data1) if isinstance(data1, str) else keccak(primitive=data1)
327
hash2 = keccak(text=data2) if isinstance(data2, str) else keccak(primitive=data2)
328
return hash1 == hash2
329
330
# Constant-time comparison for security
331
def secure_hash_compare(hash1, hash2):
332
"""Securely compare two hashes in constant time."""
333
if len(hash1) != len(hash2):
334
return False
335
336
result = 0
337
for a, b in zip(hash1, hash2):
338
result |= a ^ b
339
340
return result == 0
341
```