From 08e679edc617cb9dbe3582354b21470111b57227 Mon Sep 17 00:00:00 2001 From: brentru Date: Thu, 26 Dec 2019 17:08:26 -0500 Subject: [PATCH 1/4] update license, example, add sha1 module --- LICENSE | 22 +++++ adafruit_hashlib/_sha1.py | 176 +++++++++++++++++++++++++++++++-- examples/hashlib_simpletest.py | 23 ++++- 3 files changed, 211 insertions(+), 10 deletions(-) mode change 100644 => 100755 examples/hashlib_simpletest.py diff --git a/LICENSE b/LICENSE index 4542ec6..38edcd9 100644 --- a/LICENSE +++ b/LICENSE @@ -21,3 +21,25 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +The MIT License (MIT) + +Copyright (c) 2013-2015 AJ Alt + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/adafruit_hashlib/_sha1.py b/adafruit_hashlib/_sha1.py index 3e4a624..45dac29 100755 --- a/adafruit_hashlib/_sha1.py +++ b/adafruit_hashlib/_sha1.py @@ -1,7 +1,7 @@ - # The MIT License (MIT) # -# Brent Rubell for Adafruit Industries, 2019 +# Copyright (c) 2013-2015 AJ Alt +# Modified by Brent Rubell for Adafruit Industries, 2019 # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -24,10 +24,174 @@ `_sha1.py` ====================================================== SHA1 Hash Algorithm. -* Author(s): Brent Rubell + +Pure-Python implementation by AJ Alt +https://github.com/ajalt/python-sha1/blob/master/sha1.py + +Modified by Brent Rubell, 2019 + +* Author(s): AJ Alt, Brent Rubell """ +import struct +from micropython import const +from io import BytesIO + +SHA_BLOCKSIZE = 64 +SHA_DIGESTSIZE = 20 + +# initial hash value [5.3.1] +K0 = const(0x5A827999) +K1 = const(0x6ED9EBA1) +K2 = const(0x8F1BBCDC) +K3 = const(0xCA62C1D6) + +def _getbuf(s): + if isinstance(s, str): + return s.encode('ascii') + return bytes(s) + + +def _left_rotate(n, b): + """Left rotate a 32-bit integer, n, by b bits. + :param int n: 32-bit integer + :param int b: Desired rotation amount, in bits. + """ + return ((n << b) | (n >> (32 - b))) & 0xffffffff + + +def _hash_computation(chunk, h0, h1, h2, h3, h4): + """Processes 64-bit chunk of data and returns new digest variables. + Per FIPS [6.1.2] + :param bytes bytearray chunk: 64-bit bytearray + :param list h_tuple: List of hash values for the chunk + """ + assert len(chunk) == 64, "Chunk should be 64-bits" + + w = [0] * 80 + + # Break chunk into sixteen 4-byte big-endian words w[i] + for i in range(16): + w[i] = struct.unpack(b'>I', chunk[i * 4:i * 4 + 4])[0] + + # Extend the sixteen 4-byte words into eighty 4-byte words + for i in range(16, 80): + w[i] = _left_rotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1) + + # Init. hash values for chunk + a = h0 + b = h1 + c = h2 + d = h3 + e = h4 + + for i in range(80): + if 0 <= i <= 19: + # Use alternative 1 for f from FIPS PB 180-1 to avoid bitwise not + f = d ^ (b & (c ^ d)) + k = K0 + elif 20 <= i <= 39: + f = b ^ c ^ d + k = K1 + elif 40 <= i <= 59: + f = (b & c) | (b & d) | (c & d) + k = K2 + elif 60 <= i <= 79: + f = b ^ c ^ d + k = K3 + + a, b, c, d, e = ((_left_rotate(a, 5) + f + e + k + w[i]) & 0xffffffff, + a, _left_rotate(b, 30), c, d) + + # Add to chunk's hash result so far + h0 = (h0 + a) & 0xffffffff + h1 = (h1 + b) & 0xffffffff + h2 = (h2 + c) & 0xffffffff + h3 = (h3 + d) & 0xffffffff + h4 = (h4 + e) & 0xffffffff + + return h0, h1, h2, h3, h4 + + # pylint: disable=too-few-public-methods, invalid-name class sha1(): - """SHA1 hash algorithm.""" - def __init__(self, s=None): - raise NotImplementedError("SHA1 digests not currently implemented in this module.") + digest_size = SHA_DIGESTSIZE + block_size = SHA_BLOCKSIZE + name = "sha1" + def __init__(self, s=None): + """Construct a SHA-1 hash object. + + """ + # Initial Digest Variables + self._h = (0x67452301, + 0xEFCDAB89, + 0x98BADCFE, + 0x10325476, + 0xC3D2E1F0) + + self._unprocessed = b'' + self._msg_byte_len = 0 + + def _create_digest(self): + """Returns finalized digest variables for the data processed so far. + + """ + # pre-processing + message = self._unprocessed + message_len = self._msg_byte_len + len(message) + + # add trailing '1' bit (+ 0's padding) to string [§5.1.1] + message += b'\x80' + + # append 0 <= k < 512 bits '0', so that the resulting message length (in bytes) + # is congruent to 56 (mod 64) + message += b'\x00' * ((56 - (message_len + 1) % 64) % 64) + + + # append ml, the original message length, as a 64-bit big-endian integer. + message_bit_length = message_len * 8 + message += struct.pack(b'>Q', message_bit_length) + + # Process the final chunk + # At this point, the length of the message is either 64 or 128 bytes. + h = _hash_computation(message[:64], *self._h) + if len(message) == 64: + return h + return _hash_computation(message[64:], *h) + + def update(self, data): + """Updates the hash object with bytes-like object, data. + :param bytes data: bytearray or bytes object + + """ + # if we get a string, convert to a bytearray objects + data = _getbuf(data) + + # switch input to bytesio api for easier reading + if isinstance(data, (bytes, bytearray)): + data = BytesIO(data) + + # Try to build a chunk out of the unprocessed data, if any + chunk = self._unprocessed + data.read(64 - len(self._unprocessed)) + + while len(chunk) == 64: + self._h = _hash_computation(chunk, *self._h) + self._msg_byte_len += 64 + # read the next 64 bytes + chunk = data.read(64) + + self._unprocessed = chunk + return self + + def digest(self): + """Returns the digest of the data passed to the update() + method so far. + + """ + return b''.join(struct.pack(b'>I', h) for h in self._create_digest()) + + def hexdigest(self): + """Like digest() except the digest is returned as a string object of + double length, containing only hexadecimal digits. + + """ + return ''.join(['%.2x' % i for i in self.digest()]) \ No newline at end of file diff --git a/examples/hashlib_simpletest.py b/examples/hashlib_simpletest.py old mode 100644 new mode 100755 index ee55755..f097e9c --- a/examples/hashlib_simpletest.py +++ b/examples/hashlib_simpletest.py @@ -4,6 +4,21 @@ # Bytes-to-encode byte_string = b"CircuitPython" +# Create a SHA-224 message +print("--SHA1--") +m = hashlib.sha1() +# Update the hash object with byte_string +m.update(byte_string) +# Obtain the digest, digest size, and block size +print( + "Msg Digest: {}\nMsg Digest Size: {}\nMsg Block Size: {}".format( + m.hexdigest(), m.digest_size, m.block_size)) +# Validate the digest against CPython3 hashlib-sha1 +assert ( + m.hexdigest() == "62c6e222ccd72f21b8ce0c61f42860d6c70954c0" +), "Digest does not match expected string." + + # Create a SHA-224 message print("--SHA224--") m = hashlib.sha224() @@ -13,7 +28,7 @@ print( "Msg Digest: {}\nMsg Digest Size: {}\nMsg Block Size: {}".format( m.hexdigest(), m.digest_size, m.block_size)) -# Validate the digest +# Validate the digest against CPython hashlib-sha224 assert ( m.hexdigest() == "744535a10879be6b18bbcdd135032891346f530a7845d580f7869f36" ), "Digest does not match expected string." @@ -26,7 +41,7 @@ # Obtain the digest, digest size, and block size print("Msg Digest: {}\nMsg Digest Size: {}\nMsg Block Size: {}".format( m.hexdigest(), m.digest_size, m.block_size)) -# Validate the digest +# Validate the digest against CPython hashlib-sha256 assert ( m.hexdigest() == "3ce8334ca39e66afb9c37d571da4caad68ab4a8bcbd6d584f75e4268e36c0954" ), "Digest does not match expected string." @@ -39,7 +54,7 @@ # Obtain the digest, digest size, and block size print("Msg Digest: {}\nMsg Digest Size: {}\nMsg Block Size: {}".format( m.hexdigest(), m.digest_size, m.block_size)) -# Validate the digest +# Validate the digest against CPython hashlib-sha384 assert ( m.hexdigest() == "7a12f0815f5511b8ba52c67922d1ae86dfd9bfcc4e0799ad89a9f01fc526c8f074ddb5948c06db9893536f2e65c7621b" ), "Digest does not match expected string." @@ -52,7 +67,7 @@ # Obtain the digest, digest size, and block size print("Msg Digest: {}\nMsg Digest Size: {}\nMsg Block Size: {}".format( m.hexdigest(), m.digest_size, m.block_size)) -# Validate the digest +# Validate the digest against CPython hashlib-sha512 assert ( m.hexdigest() == "20a88a9b04aa490e457f8980e57331bc85c4d6ca30735a9e502f817e74011a9ece07078e53adf70c232ac91f6c79d4cd6cc69426cd77535645fe9016a71122c2" ), "Digest does not match expected string." From f7d064075b2045c84cc235ce72d5b2ef60c440f7 Mon Sep 17 00:00:00 2001 From: brentru Date: Thu, 26 Dec 2019 17:15:02 -0500 Subject: [PATCH 2/4] lintin --- adafruit_hashlib/_sha1.py | 287 +++++++++++++++++++------------------- 1 file changed, 147 insertions(+), 140 deletions(-) diff --git a/adafruit_hashlib/_sha1.py b/adafruit_hashlib/_sha1.py index 45dac29..fd33432 100755 --- a/adafruit_hashlib/_sha1.py +++ b/adafruit_hashlib/_sha1.py @@ -33,8 +33,9 @@ * Author(s): AJ Alt, Brent Rubell """ import struct -from micropython import const from io import BytesIO +from micropython import const + SHA_BLOCKSIZE = 64 SHA_DIGESTSIZE = 20 @@ -45,153 +46,159 @@ K2 = const(0x8F1BBCDC) K3 = const(0xCA62C1D6) -def _getbuf(s): - if isinstance(s, str): - return s.encode('ascii') - return bytes(s) +def _getbuf(data): + """Converts data into ascii, + returns bytes of data + """ + if isinstance(data, str): + return data.encode('ascii') + return bytes(data) def _left_rotate(n, b): - """Left rotate a 32-bit integer, n, by b bits. - :param int n: 32-bit integer - :param int b: Desired rotation amount, in bits. - """ - return ((n << b) | (n >> (32 - b))) & 0xffffffff - + """Left rotate a 32-bit integer, n, by b bits. + :param int n: 32-bit integer + :param int b: Desired rotation amount, in bits. + """ + return ((n << b) | (n >> (32 - b))) & 0xffffffff +# pylint: disable=invalid-name, too-many-arguments def _hash_computation(chunk, h0, h1, h2, h3, h4): - """Processes 64-bit chunk of data and returns new digest variables. - Per FIPS [6.1.2] - :param bytes bytearray chunk: 64-bit bytearray - :param list h_tuple: List of hash values for the chunk - """ - assert len(chunk) == 64, "Chunk should be 64-bits" - - w = [0] * 80 - - # Break chunk into sixteen 4-byte big-endian words w[i] - for i in range(16): - w[i] = struct.unpack(b'>I', chunk[i * 4:i * 4 + 4])[0] - - # Extend the sixteen 4-byte words into eighty 4-byte words - for i in range(16, 80): - w[i] = _left_rotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1) - - # Init. hash values for chunk - a = h0 - b = h1 - c = h2 - d = h3 - e = h4 - - for i in range(80): - if 0 <= i <= 19: - # Use alternative 1 for f from FIPS PB 180-1 to avoid bitwise not - f = d ^ (b & (c ^ d)) - k = K0 - elif 20 <= i <= 39: - f = b ^ c ^ d - k = K1 - elif 40 <= i <= 59: - f = (b & c) | (b & d) | (c & d) - k = K2 - elif 60 <= i <= 79: - f = b ^ c ^ d - k = K3 - - a, b, c, d, e = ((_left_rotate(a, 5) + f + e + k + w[i]) & 0xffffffff, - a, _left_rotate(b, 30), c, d) - - # Add to chunk's hash result so far - h0 = (h0 + a) & 0xffffffff - h1 = (h1 + b) & 0xffffffff - h2 = (h2 + c) & 0xffffffff - h3 = (h3 + d) & 0xffffffff - h4 = (h4 + e) & 0xffffffff - - return h0, h1, h2, h3, h4 + """Processes 64-bit chunk of data and returns new digest variables. + Per FIPS [6.1.2] + :param bytes bytearray chunk: 64-bit bytearray + :param list h_tuple: List of hash values for the chunk + """ + assert len(chunk) == 64, "Chunk should be 64-bits" + + w = [0] * 80 + + # Break chunk into sixteen 4-byte big-endian words w[i] + for i in range(16): + w[i] = struct.unpack(b'>I', chunk[i * 4:i * 4 + 4])[0] + + # Extend the sixteen 4-byte words into eighty 4-byte words + for i in range(16, 80): + w[i] = _left_rotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1) + + # Init. hash values for chunk + a = h0 + b = h1 + c = h2 + d = h3 + e = h4 + + for i in range(80): + if 0 <= i <= 19: + # Use alternative 1 for f from FIPS PB 180-1 to avoid bitwise not + f = d ^ (b & (c ^ d)) + k = K0 + elif 20 <= i <= 39: + f = b ^ c ^ d + k = K1 + elif 40 <= i <= 59: + f = (b & c) | (b & d) | (c & d) + k = K2 + elif 60 <= i <= 79: + f = b ^ c ^ d + k = K3 + + a, b, c, d, e = ((_left_rotate(a, 5) + f + e + k + w[i]) & 0xffffffff, + a, _left_rotate(b, 30), c, d) + + # Add to chunk's hash result so far + h0 = (h0 + a) & 0xffffffff + h1 = (h1 + b) & 0xffffffff + h2 = (h2 + c) & 0xffffffff + h3 = (h3 + d) & 0xffffffff + h4 = (h4 + e) & 0xffffffff + + return h0, h1, h2, h3, h4 # pylint: disable=too-few-public-methods, invalid-name class sha1(): - digest_size = SHA_DIGESTSIZE - block_size = SHA_BLOCKSIZE - name = "sha1" - def __init__(self, s=None): - """Construct a SHA-1 hash object. - - """ - # Initial Digest Variables - self._h = (0x67452301, - 0xEFCDAB89, - 0x98BADCFE, - 0x10325476, - 0xC3D2E1F0) - - self._unprocessed = b'' - self._msg_byte_len = 0 - - def _create_digest(self): - """Returns finalized digest variables for the data processed so far. - - """ - # pre-processing - message = self._unprocessed - message_len = self._msg_byte_len + len(message) - - # add trailing '1' bit (+ 0's padding) to string [§5.1.1] - message += b'\x80' - - # append 0 <= k < 512 bits '0', so that the resulting message length (in bytes) - # is congruent to 56 (mod 64) - message += b'\x00' * ((56 - (message_len + 1) % 64) % 64) - - - # append ml, the original message length, as a 64-bit big-endian integer. - message_bit_length = message_len * 8 - message += struct.pack(b'>Q', message_bit_length) - - # Process the final chunk - # At this point, the length of the message is either 64 or 128 bytes. - h = _hash_computation(message[:64], *self._h) - if len(message) == 64: - return h - return _hash_computation(message[64:], *h) - - def update(self, data): - """Updates the hash object with bytes-like object, data. - :param bytes data: bytearray or bytes object - - """ - # if we get a string, convert to a bytearray objects - data = _getbuf(data) - - # switch input to bytesio api for easier reading - if isinstance(data, (bytes, bytearray)): - data = BytesIO(data) - - # Try to build a chunk out of the unprocessed data, if any - chunk = self._unprocessed + data.read(64 - len(self._unprocessed)) - - while len(chunk) == 64: - self._h = _hash_computation(chunk, *self._h) - self._msg_byte_len += 64 - # read the next 64 bytes - chunk = data.read(64) - - self._unprocessed = chunk - return self - - def digest(self): - """Returns the digest of the data passed to the update() - method so far. - - """ - return b''.join(struct.pack(b'>I', h) for h in self._create_digest()) - - def hexdigest(self): - """Like digest() except the digest is returned as a string object of - double length, containing only hexadecimal digits. + """SHA-1 Hash Object """ - return ''.join(['%.2x' % i for i in self.digest()]) \ No newline at end of file + digest_size = SHA_DIGESTSIZE + block_size = SHA_BLOCKSIZE + name = "sha1" + def __init__(self): + """Construct a SHA-1 hash object. + + """ + # Initial Digest Variables + self._h = (0x67452301, + 0xEFCDAB89, + 0x98BADCFE, + 0x10325476, + 0xC3D2E1F0) + + self._unprocessed = b'' + self._msg_byte_len = 0 + + def _create_digest(self): + """Returns finalized digest variables for the data processed so far. + + """ + # pre-processing + message = self._unprocessed + message_len = self._msg_byte_len + len(message) + + # add trailing '1' bit (+ 0's padding) to string [§5.1.1] + message += b'\x80' + + # append 0 <= k < 512 bits '0', so that the resulting message length (in bytes) + # is congruent to 56 (mod 64) + message += b'\x00' * ((56 - (message_len + 1) % 64) % 64) + + + # append ml, the original message length, as a 64-bit big-endian integer. + message_bit_length = message_len * 8 + message += struct.pack(b'>Q', message_bit_length) + + # Process the final chunk + # At this point, the length of the message is either 64 or 128 bytes. + h = _hash_computation(message[:64], *self._h) + if len(message) == 64: + return h + return _hash_computation(message[64:], *h) + + def update(self, data): + """Updates the hash object with bytes-like object, data. + :param bytes data: bytearray or bytes object + + """ + # if we get a string, convert to a bytearray objects + data = _getbuf(data) + + # switch input to bytesio api for easier reading + if isinstance(data, (bytes, bytearray)): + data = BytesIO(data) + + # Try to build a chunk out of the unprocessed data, if any + chunk = self._unprocessed + data.read(64 - len(self._unprocessed)) + + while len(chunk) == 64: + self._h = _hash_computation(chunk, *self._h) + self._msg_byte_len += 64 + # read the next 64 bytes + chunk = data.read(64) + + self._unprocessed = chunk + return self + + def digest(self): + """Returns the digest of the data passed to the update() + method so far. + + """ + return b''.join(struct.pack(b'>I', h) for h in self._create_digest()) + + def hexdigest(self): + """Like digest() except the digest is returned as a string object of + double length, containing only hexadecimal digits. + + """ + return ''.join(['%.2x' % i for i in self.digest()]) From 87ba91dda3ca1410705080e84b63fba5181985e8 Mon Sep 17 00:00:00 2001 From: brentru Date: Thu, 26 Dec 2019 17:22:56 -0500 Subject: [PATCH 3/4] add docstrings, nicer comments --- adafruit_hashlib/_sha1.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/adafruit_hashlib/_sha1.py b/adafruit_hashlib/_sha1.py index fd33432..d3bfd7e 100755 --- a/adafruit_hashlib/_sha1.py +++ b/adafruit_hashlib/_sha1.py @@ -36,11 +36,11 @@ from io import BytesIO from micropython import const - +# SHA Block size and message digest sizes, in bytes. SHA_BLOCKSIZE = 64 SHA_DIGESTSIZE = 20 -# initial hash value [5.3.1] +# initial hash value [FIPS 5.3.1] K0 = const(0x5A827999) K1 = const(0x6ED9EBA1) K2 = const(0x8F1BBCDC) @@ -48,7 +48,9 @@ def _getbuf(data): """Converts data into ascii, - returns bytes of data + returns bytes of data. + :param str bytes bytearray data: Data to convert. + """ if isinstance(data, str): return data.encode('ascii') @@ -59,6 +61,7 @@ def _left_rotate(n, b): """Left rotate a 32-bit integer, n, by b bits. :param int n: 32-bit integer :param int b: Desired rotation amount, in bits. + """ return ((n << b) | (n >> (32 - b))) & 0xffffffff @@ -68,8 +71,9 @@ def _hash_computation(chunk, h0, h1, h2, h3, h4): Per FIPS [6.1.2] :param bytes bytearray chunk: 64-bit bytearray :param list h_tuple: List of hash values for the chunk + """ - assert len(chunk) == 64, "Chunk should be 64-bits" + assert len(chunk) == 64, "Chunk size should be 64-bits" w = [0] * 80 @@ -126,7 +130,7 @@ class sha1(): name = "sha1" def __init__(self): """Construct a SHA-1 hash object. - + :param bytes data: data to process """ # Initial Digest Variables self._h = (0x67452301, @@ -135,7 +139,11 @@ def __init__(self): 0x10325476, 0xC3D2E1F0) + # bytes object with 0 <= len < 64 used to store the end of the message + # if the message length is not congruent to 64 self._unprocessed = b'' + + # Length in bytes of all data that has been processed so far self._msg_byte_len = 0 def _create_digest(self): @@ -146,20 +154,18 @@ def _create_digest(self): message = self._unprocessed message_len = self._msg_byte_len + len(message) - # add trailing '1' bit (+ 0's padding) to string [§5.1.1] + # add trailing '1' bit (+ 0's padding) to string [FIPS 5.1.1] message += b'\x80' # append 0 <= k < 512 bits '0', so that the resulting message length (in bytes) # is congruent to 56 (mod 64) message += b'\x00' * ((56 - (message_len + 1) % 64) % 64) - # append ml, the original message length, as a 64-bit big-endian integer. message_bit_length = message_len * 8 message += struct.pack(b'>Q', message_bit_length) # Process the final chunk - # At this point, the length of the message is either 64 or 128 bytes. h = _hash_computation(message[:64], *self._h) if len(message) == 64: return h @@ -173,7 +179,7 @@ def update(self, data): # if we get a string, convert to a bytearray objects data = _getbuf(data) - # switch input to bytesio api for easier reading + # Use BytesIO for stream-like reading if isinstance(data, (bytes, bytearray)): data = BytesIO(data) @@ -182,6 +188,7 @@ def update(self, data): while len(chunk) == 64: self._h = _hash_computation(chunk, *self._h) + # increase the length of the message by 64 bytes self._msg_byte_len += 64 # read the next 64 bytes chunk = data.read(64) From 37818a2137cc093b93cb9d2642a15fdbdbbdf8bb Mon Sep 17 00:00:00 2001 From: brentru Date: Thu, 26 Dec 2019 17:26:47 -0500 Subject: [PATCH 4/4] fix typo --- examples/hashlib_simpletest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/hashlib_simpletest.py b/examples/hashlib_simpletest.py index f097e9c..1c5016b 100755 --- a/examples/hashlib_simpletest.py +++ b/examples/hashlib_simpletest.py @@ -4,7 +4,7 @@ # Bytes-to-encode byte_string = b"CircuitPython" -# Create a SHA-224 message +# Create a SHA-1 message print("--SHA1--") m = hashlib.sha1() # Update the hash object with byte_string