4545"""
4646import time
4747from 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+
4856from micropython import const
49- from adafruit_bus_device .i2c_device import I2CDevice
57+ from adafruit_bus_device .i2c_device import I2CDevice , I2C
5058from 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