Skip to content

Commit 7697a02

Browse files
authored
Merge pull request #31 from brass75/issue_25/missing-typehints
Improve type hints and docstrings
2 parents 2b477d0 + 69de468 commit 7697a02

File tree

3 files changed

+199
-67
lines changed

3 files changed

+199
-67
lines changed

adafruit_atecc/adafruit_atecc.py

Lines changed: 103 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +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
50+
# to have this in a try/except to enable type hinting for the IDEs while
51+
# not breaking the runtime on the controller.
52+
try:
53+
from typing import Any, Sized, Optional
54+
from busio import I2C
55+
except ImportError:
56+
pass
57+
4858
from micropython import const
4959
from adafruit_bus_device.i2c_device import I2CDevice
5060
from adafruit_binascii import hexlify, unhexlify
@@ -154,12 +164,15 @@ class ATECC:
154164
CircuitPython interface for ATECCx08A Crypto Co-Processor Devices.
155165
"""
156166

157-
def __init__(self, i2c_bus, address=_REG_ATECC_DEVICE_ADDR, debug=False):
158-
"""Initializes an ATECC device.
167+
def __init__(
168+
self, i2c_bus: I2C, address: int = _REG_ATECC_DEVICE_ADDR, debug: bool = False
169+
):
170+
"""
171+
Initializes an ATECC device.
172+
159173
:param busio i2c_bus: I2C Bus object.
160174
:param int address: Device address, defaults to _ATECC_DEVICE_ADDR.
161175
:param bool debug: Library debugging enabled
162-
163176
"""
164177
self._debug = debug
165178
self._i2cbuf = bytearray(12)
@@ -248,7 +261,7 @@ def lock_all_zones(self):
248261
self.lock(0)
249262
self.lock(1)
250263

251-
def lock(self, zone):
264+
def lock(self, zone: int):
252265
"""Locks specific ATECC zones.
253266
:param int zone: ATECC zone to lock.
254267
"""
@@ -260,10 +273,13 @@ def lock(self, zone):
260273
assert res[0] == 0x00, "Failed locking ATECC!"
261274
self.idle()
262275

263-
def info(self, mode, param=None):
264-
"""Returns device state information
265-
:param int mode: Mode encoding, see Table 9-26.
276+
def info(self, mode: int, param: Optional[Any] = None) -> bytearray:
277+
"""
278+
Returns device state information
266279
280+
:param int mode: Mode encoding, see Table 9-26.
281+
:param param: Optional parameter
282+
:return: bytearray containing the response
267283
"""
268284
self.wakeup()
269285
if not param:
@@ -276,13 +292,15 @@ def info(self, mode, param=None):
276292
self.idle()
277293
return info_out
278294

279-
def nonce(self, data, mode=0, zero=0x0000):
280-
"""Generates a nonce by combining internally generated random number
295+
def nonce(self, data: bytearray, mode: int = 0, zero: int = 0x0000) -> bytearray:
296+
"""
297+
Generates a nonce by combining internally generated random number
281298
with an input value.
299+
282300
:param bytearray data: Input value from system or external.
283301
:param int mode: Controls the internal RNG and seed mechanism.
284302
:param int zero: Param2, see Table 9-35.
285-
303+
:return: bytearray containing the calculated nonce
286304
"""
287305
self.wakeup()
288306
if mode in (0x00, 0x01):
@@ -309,13 +327,15 @@ def nonce(self, data, mode=0, zero=0x0000):
309327
self.idle()
310328
return calculated_nonce
311329

312-
def counter(self, counter=0, increment_counter=True):
313-
"""Reads the binary count value from one of the two monotonic
330+
def counter(self, counter: int = 0, increment_counter: bool = True) -> bytearray:
331+
"""
332+
Reads the binary count value from one of the two monotonic
314333
counters located on the device within the configuration zone.
315334
The maximum value that the counter may have is 2,097,151.
335+
316336
:param int counter: Device's counter to increment.
317337
:param bool increment_counter: Increments the value of the counter specified.
318-
338+
:return: bytearray with the count
319339
"""
320340
counter = 0x00
321341
self.wakeup()
@@ -331,18 +351,20 @@ def counter(self, counter=0, increment_counter=True):
331351
self.idle()
332352
return count
333353

334-
def random(self, rnd_min=0, rnd_max=0):
335-
"""Generates a random number for use by the system.
354+
def random(self, rnd_min: int = 0, rnd_max: int = 0) -> int:
355+
"""
356+
Generates a random number for use by the system.
357+
336358
:param int rnd_min: Minimum Random value to generate.
337359
:param int rnd_max: Maximum random value to generate.
338-
360+
:return: Random integer
339361
"""
340362
if rnd_max:
341363
rnd_min = 0
342364
if rnd_min >= rnd_max:
343365
return rnd_min
344366
delta = rnd_max - rnd_min
345-
r = bytes(16)
367+
r = bytearray(16)
346368
r = self._random(r)
347369
data = 0
348370
for i in enumerate(r):
@@ -352,10 +374,12 @@ def random(self, rnd_min=0, rnd_max=0):
352374
data = data % delta
353375
return data + rnd_min
354376

355-
def _random(self, data):
356-
"""Initializes the random number generator and returns.
357-
:param bytearray data: Response buffer.
377+
def _random(self, data: bytearray) -> bytearray:
378+
"""
379+
Initializes the random number generator and returns.
358380
381+
:param bytearray data: Response buffer.
382+
:return: bytearray
359383
"""
360384
self.wakeup()
361385
data_len = len(data)
@@ -371,8 +395,9 @@ def _random(self, data):
371395
return data
372396

373397
# SHA-256 Commands
374-
def sha_start(self):
375-
"""Initializes the SHA-256 calculation engine
398+
def sha_start(self) -> bytearray:
399+
"""
400+
Initializes the SHA-256 calculation engine
376401
and the SHA context in memory.
377402
This method MUST be called before sha_update or sha_digest
378403
"""
@@ -385,11 +410,13 @@ def sha_start(self):
385410
self.idle()
386411
return status
387412

388-
def sha_update(self, message):
389-
"""Appends bytes to the message. Can be repeatedly called.
413+
def sha_update(self, message: bytes) -> bytearray:
414+
"""
415+
Appends bytes to the message. Can be repeatedly called.
416+
390417
:param bytes message: Up to 64 bytes of data to be included
391418
into the hash operation.
392-
419+
:return: bytearray containing the status
393420
"""
394421
self.wakeup()
395422
self._send_command(OP_SHA, 0x01, 64, message)
@@ -400,12 +427,14 @@ def sha_update(self, message):
400427
self.idle()
401428
return status
402429

403-
def sha_digest(self, message=None):
404-
"""Returns the digest of the data passed to the
430+
def sha_digest(self, message: bytearray = None) -> bytearray:
431+
"""
432+
Returns the digest of the data passed to the
405433
sha_update method so far.
434+
406435
:param bytearray message: Up to 64 bytes of data to be included
407436
into the hash operation.
408-
437+
:return: bytearray containing the digest
409438
"""
410439
if not hasattr(message, "append") and message is not None:
411440
message = pack("B", message)
@@ -422,11 +451,16 @@ def sha_digest(self, message=None):
422451
self.idle()
423452
return digest
424453

425-
def gen_key(self, key, slot_num, private_key=False):
426-
"""Generates a private or public key.
454+
def gen_key(
455+
self, key: bytearray, slot_num: int, private_key: bool = False
456+
) -> bytearray:
457+
"""
458+
Generates a private or public key.
459+
460+
:param key: Buffer to put the key into
427461
:param int slot_num: ECC slot (from 0 to 4).
428462
:param bool private_key: Generates a private key if true.
429-
463+
:return: The requested key
430464
"""
431465
assert 0 <= slot_num <= 4, "Provided slot must be between 0 and 4."
432466
self.wakeup()
@@ -440,11 +474,13 @@ def gen_key(self, key, slot_num, private_key=False):
440474
self.idle()
441475
return key
442476

443-
def ecdsa_sign(self, slot, message):
444-
"""Generates and returns a signature using the ECDSA algorithm.
477+
def ecdsa_sign(self, slot: int, message: bytearray) -> bytearray:
478+
"""
479+
Generates and returns a signature using the ECDSA algorithm.
480+
445481
:param int slot: Which ECC slot to use.
446482
:param bytearray message: Message to be signed.
447-
483+
:return: bytearray containing the signature
448484
"""
449485
# Load the message digest into TempKey using Nonce (9.1.8)
450486
self.nonce(message, 0x03)
@@ -453,9 +489,12 @@ def ecdsa_sign(self, slot, message):
453489
sig = self.sign(slot)
454490
return sig
455491

456-
def sign(self, slot_id):
457-
"""Performs ECDSA signature calculation with key in provided slot.
492+
def sign(self, slot_id: int) -> bytearray:
493+
"""
494+
Performs ECDSA signature calculation with key in provided slot.
495+
458496
:param int slot_id: ECC slot containing key for use with signature.
497+
:return: bytearray containing the signature
459498
"""
460499
self.wakeup()
461500
self._send_command(0x41, 0x80, slot_id)
@@ -465,8 +504,10 @@ def sign(self, slot_id):
465504
self.idle()
466505
return signature
467506

468-
def write_config(self, data):
469-
"""Writes configuration data to the device's EEPROM.
507+
def write_config(self, data: bytearray):
508+
"""
509+
Writes configuration data to the device's EEPROM.
510+
470511
:param bytearray data: Configuration data to-write
471512
"""
472513
# First 16 bytes of data are skipped, not writable
@@ -476,7 +517,14 @@ def write_config(self, data):
476517
continue
477518
self._write(0, i // 4, data[i : i + 4])
478519

479-
def _write(self, zone, address, buffer):
520+
def _write(self, zone: Any, address: int, buffer: bytearray):
521+
"""
522+
Writes to the I2C
523+
524+
:param Any zone: Zone to send to
525+
:param int address: The address to send to
526+
:param bytearray buffer: The buffer to send
527+
"""
480528
self.wakeup()
481529
if len(buffer) not in (4, 32):
482530
raise RuntimeError("Only 4 or 32-byte writes supported.")
@@ -488,7 +536,14 @@ def _write(self, zone, address, buffer):
488536
self._get_response(status)
489537
self.idle()
490538

491-
def _read(self, zone, address, buffer):
539+
def _read(self, zone: int, address: int, buffer: bytearray):
540+
"""
541+
Reads from the I2C
542+
543+
:param int zone: Zone to read from
544+
:param int address: The address to read from
545+
:param bytearray buffer: The buffer to read to
546+
"""
492547
self.wakeup()
493548
if len(buffer) not in (4, 32):
494549
raise RuntimeError("Only 4 and 32 byte reads supported")
@@ -500,8 +555,12 @@ def _read(self, zone, address, buffer):
500555
time.sleep(0.001)
501556
self.idle()
502557

503-
def _send_command(self, opcode, param_1, param_2=0x00, data=""):
504-
"""Sends a security command packet over i2c.
558+
def _send_command(
559+
self, opcode: int, param_1: int, param_2: int = 0x00, data: Sized = ""
560+
):
561+
"""
562+
Sends a security command packet over i2c.
563+
505564
:param byte opcode: The command Opcode
506565
:param byte param_1: The first parameter
507566
:param byte param_2: The second parameter, can be two bytes.
@@ -534,7 +593,7 @@ def _send_command(self, opcode, param_1, param_2=0x00, data=""):
534593
# small sleep
535594
time.sleep(0.001)
536595

537-
def _get_response(self, buf, length=None, retries=20):
596+
def _get_response(self, buf: Sized, length: int = None, retries: int = 20) -> int:
538597
self.wakeup()
539598
if length is None:
540599
length = len(buf)
@@ -559,7 +618,7 @@ def _get_response(self, buf, length=None, retries=20):
559618
return response[1]
560619

561620
@staticmethod
562-
def _at_crc(data, length=None):
621+
def _at_crc(data: Sized, length: int = None) -> int:
563622
if length is None:
564623
length = len(data)
565624
if not data or not length:

0 commit comments

Comments
 (0)