4545"""
4646import time
4747from 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+
4858from micropython import const
4959from adafruit_bus_device .i2c_device import I2CDevice
5060from 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