Skip to content

Commit 7b8181b

Browse files
author
Roman
committed
add timelock module
1 parent 044a495 commit 7b8181b

File tree

1 file changed

+131
-0
lines changed

1 file changed

+131
-0
lines changed

bittensor/core/timelock.py

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import struct
2+
import time
3+
from typing import Optional, Union
4+
5+
from bittensor_commit_reveal import (
6+
encrypt as _btr_encrypt,
7+
decrypt as _btr_decrypt,
8+
get_latest_round,
9+
get_reveal_round_signature,
10+
)
11+
12+
TLE_ENCRYPTED_DATA_SUFFIX = b"AES_GCM_"
13+
14+
15+
def encrypt(
16+
data: Union[bytes, str], n_blocks: int, block_time: Union[int, float] = 12.0
17+
) -> tuple[bytes, int]:
18+
"""Encrypts data using TimeLock Encryption
19+
20+
Arguments:
21+
data: Any bytes data to be encrypted.
22+
n_blocks: Number of blocks to encrypt.
23+
block_time: Time in seconds for each block. Default is `12.0` seconds.
24+
25+
Returns:
26+
tuple: A tuple containing the encrypted data and reveal TimeLock reveal round.
27+
28+
Raises:
29+
PyValueError: If failed to encrypt data.
30+
31+
Usage:
32+
data = "From Cortex to Bittensor"
33+
34+
# default usage
35+
encrypted_data, reveal_round = encrypt(data, 10)
36+
37+
# passing block_time for fast-blocks node
38+
encrypted_data, reveal_round = encrypt(data, 15, block_time=0.25)
39+
40+
encrypted_data, reveal_round = encrypt(data, 5)
41+
42+
43+
Note:
44+
For using this function with fast-blocks node you need to set block_time to 0.25 seconds.
45+
data, round = encrypt(data, n_blocks, block_time=0.25)
46+
"""
47+
if isinstance(data, str):
48+
data = data.encode()
49+
return _btr_encrypt(data, n_blocks, block_time)
50+
51+
52+
def decrypt(
53+
encrypted_data: bytes, no_errors: bool = True, return_str: bool = False
54+
) -> Optional[Union[bytes, str]]:
55+
"""Decrypts encrypted data using TimeLock Decryption
56+
57+
Arguments:
58+
encrypted_data: Encrypted data to be decrypted.
59+
no_errors: If True, no errors will be raised during decryption.
60+
return_str: convert decrypted data to string if `True`. Default is `False`.
61+
62+
Returns:
63+
decrypted_data: Decrypted data, when reveled round is reached.
64+
65+
Usage:
66+
# default usage
67+
decrypted_data = decrypt(encrypted_data)
68+
69+
# passing no_errors=False for raising errors during decryption
70+
decrypted_data = decrypt(encrypted_data, no_errors=False)
71+
72+
# passing return_str=True for returning decrypted data as string
73+
decrypted_data = decrypt(encrypted_data, return_str=True)
74+
"""
75+
result = _btr_decrypt(encrypted_data, no_errors)
76+
if result is None:
77+
return None
78+
if return_str:
79+
return result.decode()
80+
return result
81+
82+
83+
def wait_reveal_and_decrypt(
84+
encrypted_data: bytes,
85+
reveal_round: Optional[int] = None,
86+
no_errors: bool = True,
87+
return_str: bool = False,
88+
) -> bytes:
89+
"""
90+
Waits for reveal round and decrypts data using TimeLock Decryption.
91+
92+
Arguments:
93+
encrypted_data: Encrypted data to be decrypted.
94+
reveal_round: Reveal round to wait for. If None, will be parsed from encrypted data.
95+
no_errors: If True, no errors will be raised during decryption.
96+
return_str: convert decrypted data to string if `True`. Default is `False`.
97+
98+
Raises:
99+
struct.error: If failed to parse reveal round from encrypted data.
100+
TypeError: If reveal_round is None or wrong type.
101+
IndexError: If provided encrypted_data does not contain reveal round.
102+
103+
Returns:
104+
bytes: Decrypted data.
105+
106+
Usage:
107+
import bittensor as bt
108+
encrypted, reveal_round = bt.timelock.encrypt("Cortex is power", 3)
109+
"""
110+
if reveal_round is None:
111+
try:
112+
reveal_round = struct.unpack(
113+
"<Q", encrypted_data.split(TLE_ENCRYPTED_DATA_SUFFIX)[-1]
114+
)[0]
115+
except (struct.error, TypeError, IndexError):
116+
raise ValueError("Failed to parse reveal round from encrypted data.")
117+
118+
while get_latest_round() <= reveal_round:
119+
# sleep Drand QuickNet period time (3 sec)
120+
time.sleep(3)
121+
122+
return decrypt(encrypted_data, no_errors, return_str)
123+
124+
125+
__all__ = [
126+
"decrypt",
127+
"encrypt",
128+
"get_latest_round",
129+
"get_reveal_round_signature",
130+
"wait_reveal_and_decrypt",
131+
]

0 commit comments

Comments
 (0)