Skip to content

Commit a737878

Browse files
author
Dan Shernicoff
committed
Improve type hints and docstrings
1 parent 2b477d0 commit a737878

File tree

3 files changed

+170
-63
lines changed

3 files changed

+170
-63
lines changed

adafruit_atecc/adafruit_atecc.py

Lines changed: 95 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,16 @@
4545
"""
4646
import time
4747
from struct import pack
48+
49+
# Since the board may or may not have access to the typing library we need to have this in a try/except to enable type
50+
# hinting for the IDEs while not breaking the runtime on the controller.
51+
try:
52+
from typing import Any, Sized
53+
except ImportError:
54+
pass
55+
4856
from micropython import const
49-
from adafruit_bus_device.i2c_device import I2CDevice
57+
from adafruit_bus_device.i2c_device import I2CDevice, I2C
5058
from adafruit_binascii import hexlify, unhexlify
5159

5260
__version__ = "0.0.0+auto.0"
@@ -154,12 +162,13 @@ class ATECC:
154162
CircuitPython interface for ATECCx08A Crypto Co-Processor Devices.
155163
"""
156164

157-
def __init__(self, i2c_bus, address=_REG_ATECC_DEVICE_ADDR, debug=False):
158-
"""Initializes an ATECC device.
165+
def __init__(self, i2c_bus: I2C, address: int =_REG_ATECC_DEVICE_ADDR, debug: bool = False):
166+
"""
167+
Initializes an ATECC device.
168+
159169
:param busio i2c_bus: I2C Bus object.
160170
:param int address: Device address, defaults to _ATECC_DEVICE_ADDR.
161171
:param bool debug: Library debugging enabled
162-
163172
"""
164173
self._debug = debug
165174
self._i2cbuf = bytearray(12)
@@ -248,7 +257,7 @@ def lock_all_zones(self):
248257
self.lock(0)
249258
self.lock(1)
250259

251-
def lock(self, zone):
260+
def lock(self, zone: Any):
252261
"""Locks specific ATECC zones.
253262
:param int zone: ATECC zone to lock.
254263
"""
@@ -260,10 +269,13 @@ def lock(self, zone):
260269
assert res[0] == 0x00, "Failed locking ATECC!"
261270
self.idle()
262271

263-
def info(self, mode, param=None):
264-
"""Returns device state information
265-
:param int mode: Mode encoding, see Table 9-26.
272+
def info(self, mode: int, param: Any = None) -> bytearray:
273+
"""
274+
Returns device state information
266275
276+
:param int mode: Mode encoding, see Table 9-26.
277+
:param param: Optional parameter
278+
:return: bytearray containing the response
267279
"""
268280
self.wakeup()
269281
if not param:
@@ -276,13 +288,15 @@ def info(self, mode, param=None):
276288
self.idle()
277289
return info_out
278290

279-
def nonce(self, data, mode=0, zero=0x0000):
280-
"""Generates a nonce by combining internally generated random number
291+
def nonce(self, data: bytearray, mode: int = 0, zero: int = 0x0000) -> bytearray:
292+
"""
293+
Generates a nonce by combining internally generated random number
281294
with an input value.
295+
282296
:param bytearray data: Input value from system or external.
283297
:param int mode: Controls the internal RNG and seed mechanism.
284298
:param int zero: Param2, see Table 9-35.
285-
299+
:return: bytearray containing the calculated nonce
286300
"""
287301
self.wakeup()
288302
if mode in (0x00, 0x01):
@@ -309,13 +323,15 @@ def nonce(self, data, mode=0, zero=0x0000):
309323
self.idle()
310324
return calculated_nonce
311325

312-
def counter(self, counter=0, increment_counter=True):
313-
"""Reads the binary count value from one of the two monotonic
326+
def counter(self, counter: int = 0, increment_counter: bool = True) -> bytearray:
327+
"""
328+
Reads the binary count value from one of the two monotonic
314329
counters located on the device within the configuration zone.
315330
The maximum value that the counter may have is 2,097,151.
331+
316332
:param int counter: Device's counter to increment.
317333
:param bool increment_counter: Increments the value of the counter specified.
318-
334+
:return: bytearray with the count
319335
"""
320336
counter = 0x00
321337
self.wakeup()
@@ -331,18 +347,20 @@ def counter(self, counter=0, increment_counter=True):
331347
self.idle()
332348
return count
333349

334-
def random(self, rnd_min=0, rnd_max=0):
335-
"""Generates a random number for use by the system.
350+
def random(self, rnd_min: int = 0, rnd_max: int = 0) -> int:
351+
"""
352+
Generates a random number for use by the system.
353+
336354
:param int rnd_min: Minimum Random value to generate.
337355
:param int rnd_max: Maximum random value to generate.
338-
356+
:return: Random integer
339357
"""
340358
if rnd_max:
341359
rnd_min = 0
342360
if rnd_min >= rnd_max:
343361
return rnd_min
344362
delta = rnd_max - rnd_min
345-
r = bytes(16)
363+
r = bytearray(16)
346364
r = self._random(r)
347365
data = 0
348366
for i in enumerate(r):
@@ -352,10 +370,12 @@ def random(self, rnd_min=0, rnd_max=0):
352370
data = data % delta
353371
return data + rnd_min
354372

355-
def _random(self, data):
356-
"""Initializes the random number generator and returns.
357-
:param bytearray data: Response buffer.
373+
def _random(self, data: bytearray) -> bytearray:
374+
"""
375+
Initializes the random number generator and returns.
358376
377+
:param bytearray data: Response buffer.
378+
:return: bytearray
359379
"""
360380
self.wakeup()
361381
data_len = len(data)
@@ -372,7 +392,8 @@ def _random(self, data):
372392

373393
# SHA-256 Commands
374394
def sha_start(self):
375-
"""Initializes the SHA-256 calculation engine
395+
"""
396+
Initializes the SHA-256 calculation engine
376397
and the SHA context in memory.
377398
This method MUST be called before sha_update or sha_digest
378399
"""
@@ -385,11 +406,13 @@ def sha_start(self):
385406
self.idle()
386407
return status
387408

388-
def sha_update(self, message):
389-
"""Appends bytes to the message. Can be repeatedly called.
409+
def sha_update(self, message: Any) -> bytearray:
410+
"""
411+
Appends bytes to the message. Can be repeatedly called.
412+
390413
:param bytes message: Up to 64 bytes of data to be included
391414
into the hash operation.
392-
415+
:return: bytearray containing the status
393416
"""
394417
self.wakeup()
395418
self._send_command(OP_SHA, 0x01, 64, message)
@@ -400,12 +423,14 @@ def sha_update(self, message):
400423
self.idle()
401424
return status
402425

403-
def sha_digest(self, message=None):
404-
"""Returns the digest of the data passed to the
426+
def sha_digest(self, message: bytearray = None) -> bytearray:
427+
"""
428+
Returns the digest of the data passed to the
405429
sha_update method so far.
430+
406431
:param bytearray message: Up to 64 bytes of data to be included
407432
into the hash operation.
408-
433+
:return: bytearray containing the digest
409434
"""
410435
if not hasattr(message, "append") and message is not None:
411436
message = pack("B", message)
@@ -422,11 +447,14 @@ def sha_digest(self, message=None):
422447
self.idle()
423448
return digest
424449

425-
def gen_key(self, key, slot_num, private_key=False):
426-
"""Generates a private or public key.
450+
def gen_key(self, key: bytearray, slot_num: int, private_key: bool = False) -> bytearray:
451+
"""
452+
Generates a private or public key.
453+
454+
:param key: Buffer to put the key into
427455
:param int slot_num: ECC slot (from 0 to 4).
428456
:param bool private_key: Generates a private key if true.
429-
457+
:return: The requested key
430458
"""
431459
assert 0 <= slot_num <= 4, "Provided slot must be between 0 and 4."
432460
self.wakeup()
@@ -440,11 +468,13 @@ def gen_key(self, key, slot_num, private_key=False):
440468
self.idle()
441469
return key
442470

443-
def ecdsa_sign(self, slot, message):
444-
"""Generates and returns a signature using the ECDSA algorithm.
471+
def ecdsa_sign(self, slot: int, message: bytearray) -> bytearray:
472+
"""
473+
Generates and returns a signature using the ECDSA algorithm.
474+
445475
:param int slot: Which ECC slot to use.
446476
:param bytearray message: Message to be signed.
447-
477+
:return: bytearray containing the signature
448478
"""
449479
# Load the message digest into TempKey using Nonce (9.1.8)
450480
self.nonce(message, 0x03)
@@ -453,9 +483,12 @@ def ecdsa_sign(self, slot, message):
453483
sig = self.sign(slot)
454484
return sig
455485

456-
def sign(self, slot_id):
457-
"""Performs ECDSA signature calculation with key in provided slot.
486+
def sign(self, slot_id: int) -> bytearray:
487+
"""
488+
Performs ECDSA signature calculation with key in provided slot.
489+
458490
:param int slot_id: ECC slot containing key for use with signature.
491+
:return: bytearray containing the signature
459492
"""
460493
self.wakeup()
461494
self._send_command(0x41, 0x80, slot_id)
@@ -465,8 +498,10 @@ def sign(self, slot_id):
465498
self.idle()
466499
return signature
467500

468-
def write_config(self, data):
469-
"""Writes configuration data to the device's EEPROM.
501+
def write_config(self, data: bytearray):
502+
"""
503+
Writes configuration data to the device's EEPROM.
504+
470505
:param bytearray data: Configuration data to-write
471506
"""
472507
# First 16 bytes of data are skipped, not writable
@@ -476,7 +511,14 @@ def write_config(self, data):
476511
continue
477512
self._write(0, i // 4, data[i : i + 4])
478513

479-
def _write(self, zone, address, buffer):
514+
def _write(self, zone: Any, address: int, buffer: bytearray):
515+
"""
516+
Writes to the I2C
517+
518+
:param Any zone: Zone to send to
519+
:param int address: The address to send to
520+
:param bytearray buffer: The buffer to send
521+
"""
480522
self.wakeup()
481523
if len(buffer) not in (4, 32):
482524
raise RuntimeError("Only 4 or 32-byte writes supported.")
@@ -488,7 +530,14 @@ def _write(self, zone, address, buffer):
488530
self._get_response(status)
489531
self.idle()
490532

491-
def _read(self, zone, address, buffer):
533+
def _read(self, zone: Any, address: int, buffer: bytearray):
534+
"""
535+
Reads from the I2C
536+
537+
:param Any zone: Zone to read from
538+
:param int address: The address to read from
539+
:param bytearray buffer: The buffer to read to
540+
"""
492541
self.wakeup()
493542
if len(buffer) not in (4, 32):
494543
raise RuntimeError("Only 4 and 32 byte reads supported")
@@ -500,8 +549,10 @@ def _read(self, zone, address, buffer):
500549
time.sleep(0.001)
501550
self.idle()
502551

503-
def _send_command(self, opcode, param_1, param_2=0x00, data=""):
504-
"""Sends a security command packet over i2c.
552+
def _send_command(self, opcode: int, param_1: int, param_2: int = 0x00, data: Sized = ""):
553+
"""
554+
Sends a security command packet over i2c.
555+
505556
:param byte opcode: The command Opcode
506557
:param byte param_1: The first parameter
507558
:param byte param_2: The second parameter, can be two bytes.
@@ -534,7 +585,7 @@ def _send_command(self, opcode, param_1, param_2=0x00, data=""):
534585
# small sleep
535586
time.sleep(0.001)
536587

537-
def _get_response(self, buf, length=None, retries=20):
588+
def _get_response(self, buf: Sized, length: int = None, retries: int = 20) -> int:
538589
self.wakeup()
539590
if length is None:
540591
length = len(buf)
@@ -559,7 +610,7 @@ def _get_response(self, buf, length=None, retries=20):
559610
return response[1]
560611

561612
@staticmethod
562-
def _at_crc(data, length=None):
613+
def _at_crc(data: Sized, length: int = None) -> int:
563614
if length is None:
564615
length = len(data)
565616
if not data or not length:

0 commit comments

Comments
 (0)