45
45
"""
46
46
import time
47
47
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
+
48
58
from micropython import const
49
59
from adafruit_bus_device .i2c_device import I2CDevice
50
60
from adafruit_binascii import hexlify , unhexlify
@@ -154,12 +164,15 @@ class ATECC:
154
164
CircuitPython interface for ATECCx08A Crypto Co-Processor Devices.
155
165
"""
156
166
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
+
159
173
:param busio i2c_bus: I2C Bus object.
160
174
:param int address: Device address, defaults to _ATECC_DEVICE_ADDR.
161
175
:param bool debug: Library debugging enabled
162
-
163
176
"""
164
177
self ._debug = debug
165
178
self ._i2cbuf = bytearray (12 )
@@ -248,7 +261,7 @@ def lock_all_zones(self):
248
261
self .lock (0 )
249
262
self .lock (1 )
250
263
251
- def lock (self , zone ):
264
+ def lock (self , zone : int ):
252
265
"""Locks specific ATECC zones.
253
266
:param int zone: ATECC zone to lock.
254
267
"""
@@ -260,10 +273,13 @@ def lock(self, zone):
260
273
assert res [0 ] == 0x00 , "Failed locking ATECC!"
261
274
self .idle ()
262
275
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
266
279
280
+ :param int mode: Mode encoding, see Table 9-26.
281
+ :param param: Optional parameter
282
+ :return: bytearray containing the response
267
283
"""
268
284
self .wakeup ()
269
285
if not param :
@@ -276,13 +292,15 @@ def info(self, mode, param=None):
276
292
self .idle ()
277
293
return info_out
278
294
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
281
298
with an input value.
299
+
282
300
:param bytearray data: Input value from system or external.
283
301
:param int mode: Controls the internal RNG and seed mechanism.
284
302
:param int zero: Param2, see Table 9-35.
285
-
303
+ :return: bytearray containing the calculated nonce
286
304
"""
287
305
self .wakeup ()
288
306
if mode in (0x00 , 0x01 ):
@@ -309,13 +327,15 @@ def nonce(self, data, mode=0, zero=0x0000):
309
327
self .idle ()
310
328
return calculated_nonce
311
329
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
314
333
counters located on the device within the configuration zone.
315
334
The maximum value that the counter may have is 2,097,151.
335
+
316
336
:param int counter: Device's counter to increment.
317
337
:param bool increment_counter: Increments the value of the counter specified.
318
-
338
+ :return: bytearray with the count
319
339
"""
320
340
counter = 0x00
321
341
self .wakeup ()
@@ -331,18 +351,20 @@ def counter(self, counter=0, increment_counter=True):
331
351
self .idle ()
332
352
return count
333
353
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
+
336
358
:param int rnd_min: Minimum Random value to generate.
337
359
:param int rnd_max: Maximum random value to generate.
338
-
360
+ :return: Random integer
339
361
"""
340
362
if rnd_max :
341
363
rnd_min = 0
342
364
if rnd_min >= rnd_max :
343
365
return rnd_min
344
366
delta = rnd_max - rnd_min
345
- r = bytes (16 )
367
+ r = bytearray (16 )
346
368
r = self ._random (r )
347
369
data = 0
348
370
for i in enumerate (r ):
@@ -352,10 +374,12 @@ def random(self, rnd_min=0, rnd_max=0):
352
374
data = data % delta
353
375
return data + rnd_min
354
376
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 .
358
380
381
+ :param bytearray data: Response buffer.
382
+ :return: bytearray
359
383
"""
360
384
self .wakeup ()
361
385
data_len = len (data )
@@ -371,8 +395,9 @@ def _random(self, data):
371
395
return data
372
396
373
397
# 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
376
401
and the SHA context in memory.
377
402
This method MUST be called before sha_update or sha_digest
378
403
"""
@@ -385,11 +410,13 @@ def sha_start(self):
385
410
self .idle ()
386
411
return status
387
412
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
+
390
417
:param bytes message: Up to 64 bytes of data to be included
391
418
into the hash operation.
392
-
419
+ :return: bytearray containing the status
393
420
"""
394
421
self .wakeup ()
395
422
self ._send_command (OP_SHA , 0x01 , 64 , message )
@@ -400,12 +427,14 @@ def sha_update(self, message):
400
427
self .idle ()
401
428
return status
402
429
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
405
433
sha_update method so far.
434
+
406
435
:param bytearray message: Up to 64 bytes of data to be included
407
436
into the hash operation.
408
-
437
+ :return: bytearray containing the digest
409
438
"""
410
439
if not hasattr (message , "append" ) and message is not None :
411
440
message = pack ("B" , message )
@@ -422,11 +451,16 @@ def sha_digest(self, message=None):
422
451
self .idle ()
423
452
return digest
424
453
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
427
461
:param int slot_num: ECC slot (from 0 to 4).
428
462
:param bool private_key: Generates a private key if true.
429
-
463
+ :return: The requested key
430
464
"""
431
465
assert 0 <= slot_num <= 4 , "Provided slot must be between 0 and 4."
432
466
self .wakeup ()
@@ -440,11 +474,13 @@ def gen_key(self, key, slot_num, private_key=False):
440
474
self .idle ()
441
475
return key
442
476
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
+
445
481
:param int slot: Which ECC slot to use.
446
482
:param bytearray message: Message to be signed.
447
-
483
+ :return: bytearray containing the signature
448
484
"""
449
485
# Load the message digest into TempKey using Nonce (9.1.8)
450
486
self .nonce (message , 0x03 )
@@ -453,9 +489,12 @@ def ecdsa_sign(self, slot, message):
453
489
sig = self .sign (slot )
454
490
return sig
455
491
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
+
458
496
:param int slot_id: ECC slot containing key for use with signature.
497
+ :return: bytearray containing the signature
459
498
"""
460
499
self .wakeup ()
461
500
self ._send_command (0x41 , 0x80 , slot_id )
@@ -465,8 +504,10 @@ def sign(self, slot_id):
465
504
self .idle ()
466
505
return signature
467
506
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
+
470
511
:param bytearray data: Configuration data to-write
471
512
"""
472
513
# First 16 bytes of data are skipped, not writable
@@ -476,7 +517,14 @@ def write_config(self, data):
476
517
continue
477
518
self ._write (0 , i // 4 , data [i : i + 4 ])
478
519
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
+ """
480
528
self .wakeup ()
481
529
if len (buffer ) not in (4 , 32 ):
482
530
raise RuntimeError ("Only 4 or 32-byte writes supported." )
@@ -488,7 +536,14 @@ def _write(self, zone, address, buffer):
488
536
self ._get_response (status )
489
537
self .idle ()
490
538
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
+ """
492
547
self .wakeup ()
493
548
if len (buffer ) not in (4 , 32 ):
494
549
raise RuntimeError ("Only 4 and 32 byte reads supported" )
@@ -500,8 +555,12 @@ def _read(self, zone, address, buffer):
500
555
time .sleep (0.001 )
501
556
self .idle ()
502
557
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
+
505
564
:param byte opcode: The command Opcode
506
565
:param byte param_1: The first parameter
507
566
: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=""):
534
593
# small sleep
535
594
time .sleep (0.001 )
536
595
537
- def _get_response (self , buf , length = None , retries = 20 ):
596
+ def _get_response (self , buf : Sized , length : int = None , retries : int = 20 ) -> int :
538
597
self .wakeup ()
539
598
if length is None :
540
599
length = len (buf )
@@ -559,7 +618,7 @@ def _get_response(self, buf, length=None, retries=20):
559
618
return response [1 ]
560
619
561
620
@staticmethod
562
- def _at_crc (data , length = None ):
621
+ def _at_crc (data : Sized , length : int = None ) -> int :
563
622
if length is None :
564
623
length = len (data )
565
624
if not data or not length :
0 commit comments