Skip to content
This repository was archived by the owner on Mar 10, 2026. It is now read-only.

Commit 1d990f3

Browse files
committed
Update protocol
1 parent ad81148 commit 1d990f3

File tree

10 files changed

+192
-113
lines changed

10 files changed

+192
-113
lines changed

core/constants.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@
3939
XCHACHA20POLY1305_SIZE_LEN = 3
4040
XCHACHA20POLY1305_MAX_RANODM_PAD = OTP_PAD_SIZE
4141

42+
CHACHA20POLY1305_NONCE_LEN = 12
43+
CHACHA20POLY1305_SIZE_LEN = 2
44+
CHACHA20POLY1305_MAX_RANODM_PAD = OTP_PAD_SIZE
45+
46+
4247

4348

4449
SMP_NONCE_LENGTH = 64
@@ -62,12 +67,12 @@
6267
ML_DSA_87_SIGN_LEN = 4627
6368

6469

65-
CLASSIC_MCELIECE_8_F_NAME = "Classic-McEliece-8192128f"
66-
CLASSIC_MCELIECE_8_F_SK_LEN = 14120
67-
CLASSIC_MCELIECE_8_F_PK_LEN = 1357824
68-
CLASSIC_MCELIECE_8_F_CT_LEN = 208
70+
CLASSIC_MCELIECE_8_NAME = "Classic-McEliece-8192128"
71+
CLASSIC_MCELIECE_8_SK_LEN = 14120
72+
CLASSIC_MCELIECE_8_PK_LEN = 1357824
73+
CLASSIC_MCELIECE_8_CT_LEN = 208
6974

70-
CLASSIC_MCELIECE_8_F_ROTATE_AT = 3 # Default OTP batches needed to be sent for a key rotation to occur
75+
CLASSIC_MCELIECE_8_ROTATE_AT = 3 # Default OTP batches needed to be sent for a key rotation to occur
7176

7277

7378

@@ -82,16 +87,16 @@
8287
"PK_LEN" : ML_DSA_87_PK_LEN,
8388
"SIGN_LEN": ML_DSA_87_SIGN_LEN
8489
},
85-
CLASSIC_MCELIECE_8_F_NAME: {
86-
"SK_LEN": CLASSIC_MCELIECE_8_F_SK_LEN,
87-
"PK_LEN": CLASSIC_MCELIECE_8_F_PK_LEN,
88-
"CT_LEN": CLASSIC_MCELIECE_8_F_CT_LEN
90+
CLASSIC_MCELIECE_8_NAME: {
91+
"SK_LEN": CLASSIC_MCELIECE_8_SK_LEN,
92+
"PK_LEN": CLASSIC_MCELIECE_8_PK_LEN,
93+
"CT_LEN": CLASSIC_MCELIECE_8_CT_LEN
8994
},
9095
}
9196

9297
# hash parameters
9398
ARGON2_MEMORY = 1 * 1024**3 # GB
94-
ARGON2_ITERS = 25
99+
ARGON2_ITERS = 3
95100
ARGON2_OUTPUT_LEN = 64 # bytes
96101
ARGON2_SALT_LEN = 16 # bytes (Must be always 16 for interoperability with implementations using libsodium.)
97102
ARGON2_LANES = 4

core/crypto.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
Post-quantum cryptographic operations for Coldwire.
55
66
Implements:
7-
- Key generation (ML-KEM-1024, ML-DSA-87, Classic-McEliece-8192128f)
7+
- Key generation (ML-KEM-1024, ML-DSA-87, Classic-McEliece-8192128)
88
- Signature creation and verification
99
- One-Time Pad (OTP) encryption with padding
1010
- Retrieving shared secrets from KEM chunks

core/trad_crypto.py

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
XCHACHA20POLY1305_NONCE_LEN,
1515
XCHACHA20POLY1305_SIZE_LEN,
1616
XCHACHA20POLY1305_MAX_RANODM_PAD,
17+
18+
CHACHA20POLY1305_NONCE_LEN,
19+
CHACHA20POLY1305_SIZE_LEN,
20+
CHACHA20POLY1305_MAX_RANODM_PAD,
21+
1722
ARGON2_ITERS,
1823
ARGON2_MEMORY,
1924
ARGON2_LANES,
@@ -92,7 +97,7 @@ def encrypt_xchacha20poly1305(key: bytes, plaintext: bytes, nonce: bytes = None,
9297
raise ValueError(f"Max_padding is less than 0! ({max_padding})")
9398

9499
if max_padding > 2 ** (XCHACHA20POLY1305_SIZE_LEN * 8) - 1:
95-
raise ValueError(f"Max_padding is more than ``XCHACHA20POLY1305_SIZE_LEN`! ({max_padding})")
100+
raise ValueError(f"Max_padding is more than `XCHACHA20POLY1305_SIZE_LEN`! ({max_padding})")
96101

97102
padding = secrets.token_bytes(secrets.randbelow(max_padding + 1))
98103
padding_length_bytes = len(padding).to_bytes(XCHACHA20POLY1305_SIZE_LEN, "big")
@@ -131,3 +136,72 @@ def decrypt_xchacha20poly1305(key: bytes, nonce: bytes, ciphertext: bytes) -> by
131136

132137

133138

139+
140+
141+
142+
#########
143+
144+
145+
146+
def encrypt_chacha20poly1305(key: bytes, plaintext: bytes, nonce: bytes = None, max_padding: int = XCHACHA20POLY1305_MAX_RANODM_PAD) -> tuple[bytes, bytes]:
147+
"""
148+
Encrypt plaintext using ChaCha20Poly1305.
149+
150+
A random nonce is generated for each encryption unless you specify one.
151+
152+
Args:
153+
key: A 32-byte ChaCha20Poly1305 key.
154+
plaintext: Data to encrypt.
155+
nonce: An (optional) nonce to be used.
156+
max_padding: an (optional) maximum padding limit number to message. Cannot be larger than what `XCHACHA20POLY1305_MAX_RANODM_PAD` could store. Set to 0 for no padding.
157+
Returns:
158+
A tuple (nonce, ciphertext) where:
159+
- nonce: The randomly generated nonce or the same given nonce.
160+
- ciphertext: The encrypted data including the authentication tag.
161+
"""
162+
if nonce is None:
163+
nonce = sha3_512(secrets.token_bytes(CHACHA20POLY1305_NONCE_LEN))[:CHACHA20POLY1305_NONCE_LEN]
164+
165+
if max_padding < 0:
166+
raise ValueError(f"Max_padding is less than 0! ({max_padding})")
167+
168+
if max_padding > 2 ** (CHACHA20POLY1305_SIZE_LEN * 8) - 1:
169+
raise ValueError(f"Max_padding is more than `CHACHA20POLY1305_SIZE_LEN`! ({max_padding})")
170+
171+
padding = secrets.token_bytes(secrets.randbelow(max_padding + 1))
172+
padding_length_bytes = len(padding).to_bytes(CHACHA20POLY1305_SIZE_LEN, "big")
173+
174+
padded_plaintext = padding_length_bytes + plaintext + padding
175+
176+
177+
ciphertext = bindings.crypto_aead_chacha20poly1305_ietf_encrypt(padded_plaintext, None, nonce, key)
178+
179+
return nonce, ciphertext
180+
181+
182+
def decrypt_chacha20poly1305(key: bytes, nonce: bytes, ciphertext: bytes) -> bytes:
183+
"""
184+
Decrypt ciphertext using ChaCha20Poly1305.
185+
186+
Raises an exception if authentication fails.
187+
188+
Args:
189+
key: The 32-byte ChaCha20Poly1305 key used for encryption.
190+
nonce: The nonce used during encryption.
191+
ciphertext: The encrypted data including the authentication tag.
192+
193+
Returns:
194+
The decrypted plaintext bytes with no padding.
195+
"""
196+
197+
padded_plaintext = bindings.crypto_aead_chacha20poly1305_ietf_decrypt(ciphertext, None, nonce, key)
198+
199+
padding_length = int.from_bytes(padded_plaintext[:CHACHA20POLY1305_SIZE_LEN], "big")
200+
201+
if padding_length < 0:
202+
raise ValueError(f"Negative padding length ({padding_length}), ciphertext likely corrupted, or key is invalid!")
203+
204+
return padded_plaintext[CHACHA20POLY1305_SIZE_LEN : -padding_length]
205+
206+
207+

logic/background_worker.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@
1313
SMP_TYPES,
1414
PFS_TYPES,
1515
MSG_TYPES,
16-
XCHACHA20POLY1305_NONCE_LEN
16+
CHACHA20POLY1305_NONCE_LEN
1717
)
1818
from core.crypto import (
1919
random_number_range
2020
)
2121
from core.trad_crypto import (
22-
decrypt_xchacha20poly1305
22+
decrypt_chacha20poly1305
2323
)
2424
from base64 import b64decode, urlsafe_b64encode
2525
import copy
@@ -174,11 +174,11 @@ def background_worker(user_data, user_data_lock, ui_queue, stop_flag):
174174

175175
if contact_next_strand_key and contact_next_strand_nonce:
176176
try:
177-
blob_plaintext = decrypt_xchacha20poly1305(contact_next_strand_key, contact_next_strand_nonce, blob)
177+
blob_plaintext = decrypt_chacha20poly1305(contact_next_strand_key, contact_next_strand_nonce, blob)
178178

179179
contact_next_strand_key = blob_plaintext[:32]
180-
contact_next_strand_nonce = blob_plaintext[32:32 + XCHACHA20POLY1305_NONCE_LEN]
181-
blob_plaintext = blob_plaintext[32 + XCHACHA20POLY1305_NONCE_LEN:]
180+
contact_next_strand_nonce = blob_plaintext[32:32 + CHACHA20POLY1305_NONCE_LEN]
181+
blob_plaintext = blob_plaintext[32 + CHACHA20POLY1305_NONCE_LEN:]
182182

183183
with user_data_lock:
184184
user_data["contacts"][sender]["contact_next_strand_key"] = contact_next_strand_key

logic/contacts.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
from core.constants import (
77
ML_KEM_1024_NAME,
8-
CLASSIC_MCELIECE_8_F_NAME,
9-
CLASSIC_MCELIECE_8_F_ROTATE_AT
8+
CLASSIC_MCELIECE_8_NAME,
9+
CLASSIC_MCELIECE_8_ROTATE_AT
1010
)
1111

1212
def generate_nickname_id(length: int = 4) -> str:
@@ -69,23 +69,23 @@ def save_contact(user_data: dict, user_data_lock, contact_id: str) -> None:
6969
},
7070
"ephemeral_keys": {
7171
"contact_public_keys": {
72-
CLASSIC_MCELIECE_8_F_NAME: None,
72+
CLASSIC_MCELIECE_8_NAME: None,
7373
ML_KEM_1024_NAME: None
7474
},
7575
"our_keys": {
76-
CLASSIC_MCELIECE_8_F_NAME: {
76+
CLASSIC_MCELIECE_8_NAME: {
7777
"public_key": None,
7878
"private_key": None,
7979
"rotation_counter": 0,
80-
"rotate_at": CLASSIC_MCELIECE_8_F_ROTATE_AT,
80+
"rotate_at": CLASSIC_MCELIECE_8_ROTATE_AT,
8181
},
8282
ML_KEM_1024_NAME: {
8383
"public_key": None,
8484
"private_key": None,
8585
},
8686
},
8787
"staged_keys": {
88-
CLASSIC_MCELIECE_8_F_NAME: {
88+
CLASSIC_MCELIECE_8_NAME: {
8989
"public_key": None,
9090
"private_key": None,
9191
},

logic/message.py

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
from logic.pfs import send_new_ephemeral_keys
1414
from core.trad_crypto import (
1515
sha3_512,
16-
encrypt_xchacha20poly1305,
17-
decrypt_xchacha20poly1305
16+
encrypt_chacha20poly1305
1817
)
1918
from core.crypto import (
2019
generate_shared_secrets,
@@ -33,9 +32,9 @@
3332
ML_KEM_1024_CT_LEN,
3433
ML_DSA_87_NAME,
3534
ML_DSA_87_SIGN_LEN,
36-
CLASSIC_MCELIECE_8_F_NAME,
37-
CLASSIC_MCELIECE_8_F_CT_LEN,
38-
XCHACHA20POLY1305_NONCE_LEN
35+
CLASSIC_MCELIECE_8_NAME,
36+
CLASSIC_MCELIECE_8_CT_LEN,
37+
CHACHA20POLY1305_NONCE_LEN
3938

4039
)
4140
from base64 import b64encode
@@ -57,7 +56,7 @@ def generate_and_send_pads(user_data, user_data_lock, contact_id: str, ui_queue)
5756
auth_token = user_data["token"]
5857

5958
contact_kyber_public_key = user_data["contacts"][contact_id]["ephemeral_keys"]["contact_public_keys"][ML_KEM_1024_NAME]
60-
contact_mceliece_public_key = user_data["contacts"][contact_id]["ephemeral_keys"]["contact_public_keys"][CLASSIC_MCELIECE_8_F_NAME]
59+
contact_mceliece_public_key = user_data["contacts"][contact_id]["ephemeral_keys"]["contact_public_keys"][CLASSIC_MCELIECE_8_NAME]
6160
our_lt_private_key = user_data["contacts"][contact_id]["lt_sign_keys"]["our_keys"]["private_key"]
6261

6362
our_next_strand_key = user_data["contacts"][contact_id]["our_next_strand_key"]
@@ -67,22 +66,22 @@ def generate_and_send_pads(user_data, user_data_lock, contact_id: str, ui_queue)
6766
session_headers = user_data["tmp"]["session_headers"]
6867

6968
kyber_ciphertext_blob , kyber_shared_secrets = generate_shared_secrets(contact_kyber_public_key, ML_KEM_1024_NAME)
70-
mceliece_ciphertext_blob, mceliece_shared_secrets = generate_shared_secrets(contact_mceliece_public_key, CLASSIC_MCELIECE_8_F_NAME)
69+
mceliece_ciphertext_blob, mceliece_shared_secrets = generate_shared_secrets(contact_mceliece_public_key, CLASSIC_MCELIECE_8_NAME)
7170

72-
xchacha_shared_secrets = b''
73-
while len(xchacha_shared_secrets) < OTP_PAD_SIZE:
74-
xchacha_shared_secrets += sha3_512(secrets.token_bytes(64))
71+
chacha_shared_secrets = b''
72+
while len(chacha_shared_secrets) < OTP_PAD_SIZE:
73+
chacha_shared_secrets += sha3_512(secrets.token_bytes(64))
7574

7675

7776
otp_batch_signature = create_signature(ML_DSA_87_NAME, kyber_ciphertext_blob + mceliece_ciphertext_blob, our_lt_private_key)
7877

7978
# Here, the strandkey is actually just added to make messages structure uniform and easier to process in implementations
8079
# once contact receives this, he will save this new random key, then, process the batch, and save the new key derived from the batch.
8180

82-
new_strand_nonce = sha3_512(secrets.token_bytes(XCHACHA20POLY1305_NONCE_LEN))[:XCHACHA20POLY1305_NONCE_LEN]
83-
_, ciphertext_blob = encrypt_xchacha20poly1305(
81+
new_strand_nonce = sha3_512(secrets.token_bytes(CHACHA20POLY1305_NONCE_LEN))[:CHACHA20POLY1305_NONCE_LEN]
82+
_, ciphertext_blob = encrypt_chacha20poly1305(
8483
our_next_strand_key,
85-
sha3_512(secrets.token_bytes(32))[:32] + new_strand_nonce + MSG_TYPES["MSG_BATCH"] + otp_batch_signature + kyber_ciphertext_blob + mceliece_ciphertext_blob + xchacha_shared_secrets,
84+
sha3_512(secrets.token_bytes(32))[:32] + new_strand_nonce + MSG_TYPES["MSG_BATCH"] + otp_batch_signature + kyber_ciphertext_blob + mceliece_ciphertext_blob + chacha_shared_secrets,
8685
nonce = our_next_strand_nonce
8786
)
8887

@@ -101,7 +100,7 @@ def generate_and_send_pads(user_data, user_data_lock, contact_id: str, ui_queue)
101100

102101
# XOR shared secrets together for hybrid encryption
103102
pads, _ = one_time_pad(kyber_shared_secrets, mceliece_shared_secrets)
104-
pads, _ = one_time_pad(pads, xchacha_shared_secrets)
103+
pads, _ = one_time_pad(pads, chacha_shared_secrets)
105104

106105
# Derive key from pad + truncate it.
107106
new_strand_key = pads[:32]
@@ -138,7 +137,7 @@ def send_message_processor(user_data, user_data_lock, contact_id: str, message:
138137
session_headers = user_data["tmp"]["session_headers"]
139138

140139
contact_kyber_public_key = user_data["contacts"][contact_id]["ephemeral_keys"]["contact_public_keys"][ML_KEM_1024_NAME]
141-
contact_mceliece_public_key = user_data["contacts"][contact_id]["ephemeral_keys"]["contact_public_keys"][CLASSIC_MCELIECE_8_F_NAME]
140+
contact_mceliece_public_key = user_data["contacts"][contact_id]["ephemeral_keys"]["contact_public_keys"][CLASSIC_MCELIECE_8_NAME]
142141

143142
our_pads = user_data["contacts"][contact_id]["our_pads"]
144143

@@ -197,7 +196,7 @@ def send_message_processor(user_data, user_data_lock, contact_id: str, message:
197196
# which would break all of our security
198197

199198
new_strand_key = sha3_512(secrets.token_bytes(32))[:32]
200-
new_strand_nonce = sha3_512(secrets.token_bytes(XCHACHA20POLY1305_NONCE_LEN))[:XCHACHA20POLY1305_NONCE_LEN]
199+
new_strand_nonce = sha3_512(secrets.token_bytes(CHACHA20POLY1305_NONCE_LEN))[:CHACHA20POLY1305_NONCE_LEN]
201200

202201
with user_data_lock:
203202
user_data["contacts"][contact_id]["our_pads"] = user_data["contacts"][contact_id]["our_pads"][len(message_encrypted):]
@@ -210,7 +209,7 @@ def send_message_processor(user_data, user_data_lock, contact_id: str, message:
210209

211210
save_account_data(user_data, user_data_lock)
212211

213-
_, ciphertext_blob = encrypt_xchacha20poly1305(
212+
_, ciphertext_blob = encrypt_chacha20poly1305(
214213
our_next_strand_key,
215214
new_strand_key + new_strand_nonce + MSG_TYPES["MSG_NEW"] + message_encrypted,
216215
nonce = our_next_strand_nonce
@@ -275,14 +274,14 @@ def messages_data_handler(user_data: dict, user_data_lock, user_data_copied: dic
275274

276275
# /32 because KEM shared_secret is 32 bytes, /64 because sha3_512 output is 64 bytes
277276

278-
if len(msgs_plaintext) != ( (ML_KEM_1024_CT_LEN + CLASSIC_MCELIECE_8_F_CT_LEN) * (OTP_PAD_SIZE // 32)) + (64 * (OTP_PAD_SIZE // 64)) + ML_DSA_87_SIGN_LEN + 1:
277+
if len(msgs_plaintext) != ( (ML_KEM_1024_CT_LEN + CLASSIC_MCELIECE_8_CT_LEN) * (OTP_PAD_SIZE // 32)) + (64 * (OTP_PAD_SIZE // 64)) + ML_DSA_87_SIGN_LEN + 1:
279278
logger.error("Contact (%s) gave us a otp batch message request with malformed strand plaintext length (%d)", contact_id, len(msgs_plaintext))
280279
return
281280

282281
otp_hashchain_signature = msgs_plaintext[1: ML_DSA_87_SIGN_LEN + 1]
283-
otp_hashchain_ciphertext = msgs_plaintext[ML_DSA_87_SIGN_LEN + 1: ML_DSA_87_SIGN_LEN + 1 + ((ML_KEM_1024_CT_LEN + CLASSIC_MCELIECE_8_F_CT_LEN) * (OTP_PAD_SIZE // 32))]
282+
otp_hashchain_ciphertext = msgs_plaintext[ML_DSA_87_SIGN_LEN + 1: ML_DSA_87_SIGN_LEN + 1 + ((ML_KEM_1024_CT_LEN + CLASSIC_MCELIECE_8_CT_LEN) * (OTP_PAD_SIZE // 32))]
284283

285-
xchacha_pads = msgs_plaintext[ML_DSA_87_SIGN_LEN + 1 + ((ML_KEM_1024_CT_LEN + CLASSIC_MCELIECE_8_F_CT_LEN) * (OTP_PAD_SIZE // 32)):]
284+
chacha_pads = msgs_plaintext[ML_DSA_87_SIGN_LEN + 1 + ((ML_KEM_1024_CT_LEN + CLASSIC_MCELIECE_8_CT_LEN) * (OTP_PAD_SIZE // 32)):]
286285

287286
try:
288287
valid_signature = verify_signature(ML_DSA_87_NAME, otp_hashchain_ciphertext, otp_hashchain_signature, contact_public_key)
@@ -294,7 +293,7 @@ def messages_data_handler(user_data: dict, user_data_lock, user_data_copied: dic
294293
return
295294

296295
our_kyber_key = user_data_copied["contacts"][contact_id]["ephemeral_keys"]["our_keys"][ML_KEM_1024_NAME]["private_key"]
297-
our_mceliece_key = user_data_copied["contacts"][contact_id]["ephemeral_keys"]["our_keys"][CLASSIC_MCELIECE_8_F_NAME]["private_key"]
296+
our_mceliece_key = user_data_copied["contacts"][contact_id]["ephemeral_keys"]["our_keys"][CLASSIC_MCELIECE_8_NAME]["private_key"]
298297

299298
try:
300299
contact_kyber_pads = decrypt_shared_secrets(otp_hashchain_ciphertext[:ML_KEM_1024_CT_LEN * (OTP_PAD_SIZE // 32)], our_kyber_key, ML_KEM_1024_NAME)
@@ -303,13 +302,13 @@ def messages_data_handler(user_data: dict, user_data_lock, user_data_copied: dic
303302
return
304303

305304
try:
306-
contact_mceliece_pads = decrypt_shared_secrets(otp_hashchain_ciphertext[ML_KEM_1024_CT_LEN * (OTP_PAD_SIZE // 32):], our_mceliece_key, CLASSIC_MCELIECE_8_F_NAME)
305+
contact_mceliece_pads = decrypt_shared_secrets(otp_hashchain_ciphertext[ML_KEM_1024_CT_LEN * (OTP_PAD_SIZE // 32):], our_mceliece_key, CLASSIC_MCELIECE_8_NAME)
307306
except Exception as e:
308307
logger.error("Failed to decrypt Classic-McEliece8192128's ciphertext from contact (%s), received error: %s", contact_id, str(e))
309308
return
310309

311310
contact_pads, _ = one_time_pad(contact_kyber_pads, contact_mceliece_pads)
312-
contact_pads, _ = one_time_pad(contact_pads, xchacha_pads)
311+
contact_pads, _ = one_time_pad(contact_pads, chacha_pads)
313312

314313
contact_next_strand_key = contact_pads[:32]
315314
contact_pads = contact_pads[32:]
@@ -320,11 +319,11 @@ def messages_data_handler(user_data: dict, user_data_lock, user_data_copied: dic
320319

321320
user_data["contacts"][contact_id]["contact_next_strand_key"] = contact_next_strand_key
322321

323-
user_data["contacts"][contact_id]["ephemeral_keys"]["our_keys"][CLASSIC_MCELIECE_8_F_NAME]["rotation_counter"] += 1
322+
user_data["contacts"][contact_id]["ephemeral_keys"]["our_keys"][CLASSIC_MCELIECE_8_NAME]["rotation_counter"] += 1
324323

325324
staged_kyber_private_key = bool(user_data["contacts"][contact_id]["ephemeral_keys"]["staged_keys"][ML_KEM_1024_NAME]["private_key"])
326325

327-
rotation_counter = user_data["contacts"][contact_id]["ephemeral_keys"]["our_keys"][CLASSIC_MCELIECE_8_F_NAME]["rotation_counter"]
326+
rotation_counter = user_data["contacts"][contact_id]["ephemeral_keys"]["our_keys"][CLASSIC_MCELIECE_8_NAME]["rotation_counter"]
328327

329328

330329
logger.debug("Incremented McEliece's rotation_counter by 1 (now is %d) for contact (%s)", rotation_counter, contact_id)

0 commit comments

Comments
 (0)