Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Doc/deprecations/pending-removal-in-3.21.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ Pending removal in Python 3.21
parameter or pass the dispatch type explicitly instead.
(Contributed by Bartosz Sławecki in :gh:`143465`.)

* :mod:`hashlib`:

* The tree hashing parameters of :func:`~hashlib.blake2b` and
:func:`~hashlib.blake2s`, namely *fanout*, *depth*, *leaf_size*,
*node_offset*, *node_depth*, *inner_size* and *last_node*, are
deprecated since Python 3.16 and slated for removal in Python 3.21.
(Contributed by Bénédikt Tran in :gh:`160333`.)

* :mod:`struct`:

* Soft-deprecated since Python 3.15, using ``'F'`` and ``'D'`` type codes are now
Expand Down
65 changes: 36 additions & 29 deletions Doc/library/hashlib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -452,35 +452,6 @@ BLAKE2s 32 32 8 8

These sizes are available as module `constants`_ described below.

Constructor functions also accept the following tree hashing parameters:

* *fanout*: fanout (0 to 255, 0 if unlimited, 1 in sequential mode).

* *depth*: maximal depth of tree (1 to 255, 255 if unlimited, 1 in
sequential mode).

* *leaf_size*: maximal byte length of leaf (0 to ``2**32-1``, 0 if unlimited or in
sequential mode).

* *node_offset*: node offset (0 to ``2**64-1`` for BLAKE2b, 0 to ``2**48-1`` for
BLAKE2s, 0 for the first, leftmost, leaf, or in sequential mode).

* *node_depth*: node depth (0 to 255, 0 for leaves, or in sequential mode).

* *inner_size*: inner digest size (0 to 64 for BLAKE2b, 0 to 32 for
BLAKE2s, 0 in sequential mode).

* *last_node*: boolean indicating whether the processed node is the last
one (``False`` for sequential mode).

.. figure:: hashlib-blake2-tree.png
:alt: Explanation of tree mode parameters.
:class: invert-in-dark-mode

See section 2.10 in `BLAKE2 specification
<https://www.blake2.net/blake2_20130129.pdf>`_ for comprehensive review of tree
hashing.


Constants
^^^^^^^^^
Expand Down Expand Up @@ -739,6 +710,42 @@ keys from a single one.
>>> print(b64encode(mac_key).decode('utf-8'))
G9GtHFE1YluXY1zWPlYk1e/nWfu0WSEb0KRcjhDeP/o=


Tree hashing
^^^^^^^^^^^^

.. deprecated-removed:: next 3.21
The tree hashing parameters are deprecated.

Constructor functions also accept the following tree hashing parameters:

* *fanout*: fanout (0 to 255, 0 if unlimited, 1 in sequential mode).

* *depth*: maximal depth of tree (1 to 255, 255 if unlimited, 1 in
sequential mode).

* *leaf_size*: maximal byte length of leaf (0 to ``2**32-1``, 0 if unlimited or in
sequential mode).

* *node_offset*: node offset (0 to ``2**64-1`` for BLAKE2b, 0 to ``2**48-1`` for
BLAKE2s, 0 for the first, leftmost, leaf, or in sequential mode).

* *node_depth*: node depth (0 to 255, 0 for leaves, or in sequential mode).

* *inner_size*: inner digest size (0 to 64 for BLAKE2b, 0 to 32 for
BLAKE2s, 0 in sequential mode).

* *last_node*: boolean indicating whether the processed node is the last
one (``False`` for sequential mode).

.. figure:: hashlib-blake2-tree.png
:alt: Explanation of tree mode parameters.
:class: invert-in-dark-mode

See section 2.10 in `BLAKE2 specification
<https://www.blake2.net/blake2_20130129.pdf>`_ for comprehensive review of tree
hashing.

Tree mode
"""""""""

Expand Down
8 changes: 8 additions & 0 deletions Doc/whatsnew/3.16.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,14 @@ New deprecations
instead.
(Contributed by Bartosz Sławecki in :gh:`143465`.)

* :mod:`hashlib`:

* The tree hashing parameters of :func:`~hashlib.blake2b` and
:func:`~hashlib.blake2s`, namely *fanout*, *depth*, *leaf_size*,
*node_offset*, *node_depth*, *inner_size* and *last_node*, are now
deprecated and slated for removal in Python 3.21.
(Contributed by Bénédikt Tran in :gh:`160333`.)

* :mod:`struct`:

* The ``'F'`` and ``'D'`` type codes, soft-deprecated since Python 3.15,
Expand Down
216 changes: 150 additions & 66 deletions Lib/test/test_hashlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from test.support.import_helper import import_fresh_module
from test.support import requires_resource
from test.support import threading_helper
from test.support import warnings_helper
from http.client import HTTPException


Expand Down Expand Up @@ -125,6 +126,27 @@ def read_vectors(hash_name):
)


def deprecated_blake2_tree_parameter(hash_name, name):
return re.escape(
f"Passing the argument {name!r} to _blake2.{hash_name}() is "
"deprecated. It will be removed in Python 3.21."
)


BLAKE2_TREE_PARAMETERS = (
'fanout', 'depth', 'leaf_size', 'node_offset',
'node_depth', 'inner_size', 'last_node',
)


def check_blake2_tree_parameters_deprecated(hash_name):
# each tree hashing parameter emits its own warning
return warnings_helper.check_warnings(*(
(deprecated_blake2_tree_parameter(hash_name, name), DeprecationWarning)
for name in BLAKE2_TREE_PARAMETERS
))


class HashLibTestCase(unittest.TestCase):
supported_hash_names = ( 'md5', 'MD5', 'sha1', 'SHA1',
'sha224', 'SHA224', 'sha256', 'SHA256',
Expand Down Expand Up @@ -865,53 +887,84 @@ def check_blake2(self, constructor, salt_size, person_size, key_size,
self.assertEqual(constructor().hexdigest(),
constructor(key=b'').hexdigest())

hash_name = constructor.__name__
msg = deprecated_blake2_tree_parameter(hash_name, 'fanout')
for i in range(0, 256):
constructor(fanout=i)
self.assertRaises(ValueError, constructor, fanout=-1)
self.assertRaises(ValueError, constructor, fanout=256)

with self.assertWarnsRegex(DeprecationWarning, msg):
constructor(fanout=i)
with self.assertWarnsRegex(DeprecationWarning, msg):
self.assertRaises(ValueError, constructor, fanout=-1)
with self.assertWarnsRegex(DeprecationWarning, msg):
self.assertRaises(ValueError, constructor, fanout=256)

msg = deprecated_blake2_tree_parameter(hash_name, 'depth')
for i in range(1, 256):
constructor(depth=i)
self.assertRaises(ValueError, constructor, depth=-1)
self.assertRaises(ValueError, constructor, depth=0)
self.assertRaises(ValueError, constructor, depth=256)

with self.assertWarnsRegex(DeprecationWarning, msg):
constructor(depth=i)
with self.assertWarnsRegex(DeprecationWarning, msg):
self.assertRaises(ValueError, constructor, depth=-1)
with self.assertWarnsRegex(DeprecationWarning, msg):
self.assertRaises(ValueError, constructor, depth=0)
with self.assertWarnsRegex(DeprecationWarning, msg):
self.assertRaises(ValueError, constructor, depth=256)

msg = deprecated_blake2_tree_parameter(hash_name, 'node_depth')
for i in range(0, 256):
constructor(node_depth=i)
self.assertRaises(ValueError, constructor, node_depth=-1)
self.assertRaises(ValueError, constructor, node_depth=256)

with self.assertWarnsRegex(DeprecationWarning, msg):
constructor(node_depth=i)
with self.assertWarnsRegex(DeprecationWarning, msg):
self.assertRaises(ValueError, constructor, node_depth=-1)
with self.assertWarnsRegex(DeprecationWarning, msg):
self.assertRaises(ValueError, constructor, node_depth=256)

msg = deprecated_blake2_tree_parameter(hash_name, 'inner_size')
for i in range(0, digest_size + 1):
constructor(inner_size=i)
self.assertRaises(ValueError, constructor, inner_size=-1)
self.assertRaises(ValueError, constructor, inner_size=digest_size+1)

constructor(leaf_size=0)
constructor(leaf_size=(1<<32)-1)
self.assertRaises(ValueError, constructor, leaf_size=-1)
self.assertRaises(OverflowError, constructor, leaf_size=1<<32)

constructor(node_offset=0)
constructor(node_offset=max_offset)
self.assertRaises(ValueError, constructor, node_offset=-1)
self.assertRaises(OverflowError, constructor, node_offset=max_offset+1)
with self.assertWarnsRegex(DeprecationWarning, msg):
constructor(inner_size=i)
with self.assertWarnsRegex(DeprecationWarning, msg):
self.assertRaises(ValueError, constructor, inner_size=-1)
with self.assertWarnsRegex(DeprecationWarning, msg):
self.assertRaises(ValueError, constructor,
inner_size=digest_size+1)

msg = deprecated_blake2_tree_parameter(hash_name, 'leaf_size')
with self.assertWarnsRegex(DeprecationWarning, msg):
constructor(leaf_size=0)
with self.assertWarnsRegex(DeprecationWarning, msg):
constructor(leaf_size=(1<<32)-1)
with self.assertWarnsRegex(DeprecationWarning, msg):
self.assertRaises(ValueError, constructor, leaf_size=-1)
with self.assertWarnsRegex(DeprecationWarning, msg):
self.assertRaises(OverflowError, constructor, leaf_size=1<<32)

msg = deprecated_blake2_tree_parameter(hash_name, 'node_offset')
with self.assertWarnsRegex(DeprecationWarning, msg):
constructor(node_offset=0)
with self.assertWarnsRegex(DeprecationWarning, msg):
constructor(node_offset=max_offset)
with self.assertWarnsRegex(DeprecationWarning, msg):
self.assertRaises(ValueError, constructor, node_offset=-1)
with self.assertWarnsRegex(DeprecationWarning, msg):
self.assertRaises(OverflowError, constructor,
node_offset=max_offset+1)

self.assertRaises(TypeError, constructor, '')

constructor(
b'',
key=b'',
salt=b'',
person=b'',
digest_size=17,
fanout=1,
depth=1,
leaf_size=256,
node_offset=512,
node_depth=1,
inner_size=7,
last_node=True
)
with check_blake2_tree_parameters_deprecated(hash_name):
constructor(
b'',
key=b'',
salt=b'',
person=b'',
digest_size=17,
fanout=1,
depth=1,
leaf_size=256,
node_offset=512,
node_depth=1,
inner_size=7,
last_node=True
)

def blake2_rfc7693(self, constructor, md_len, in_len):
def selftest_seq(length, seed):
Expand Down Expand Up @@ -960,19 +1013,20 @@ def test_case_blake2b_1(self):
def test_case_blake2b_all_parameters(self):
# This checks that all the parameters work in general, and also that
# parameter byte order doesn't get confused on big endian platforms.
self.check('blake2b', b"foo",
"920568b0c5873b2f0ab67bedb6cf1b2b",
digest_size=16,
key=b"bar",
salt=b"baz",
person=b"bing",
fanout=2,
depth=3,
leaf_size=4,
node_offset=5,
node_depth=6,
inner_size=7,
last_node=True)
with check_blake2_tree_parameters_deprecated('blake2b'):
self.check('blake2b', b"foo",
"920568b0c5873b2f0ab67bedb6cf1b2b",
digest_size=16,
key=b"bar",
salt=b"baz",
person=b"bing",
fanout=2,
depth=3,
leaf_size=4,
node_offset=5,
node_depth=6,
inner_size=7,
last_node=True)

@requires_blake2
def test_blake2b_vectors(self):
Expand Down Expand Up @@ -1003,26 +1057,56 @@ def test_case_blake2s_1(self):
def test_case_blake2s_all_parameters(self):
# This checks that all the parameters work in general, and also that
# parameter byte order doesn't get confused on big endian platforms.
self.check('blake2s', b"foo",
"bf2a8f7fe3c555012a6f8046e646bc75",
digest_size=16,
key=b"bar",
salt=b"baz",
person=b"bing",
fanout=2,
depth=3,
leaf_size=4,
node_offset=5,
node_depth=6,
inner_size=7,
last_node=True)
with check_blake2_tree_parameters_deprecated('blake2s'):
self.check('blake2s', b"foo",
"bf2a8f7fe3c555012a6f8046e646bc75",
digest_size=16,
key=b"bar",
salt=b"baz",
person=b"bing",
fanout=2,
depth=3,
leaf_size=4,
node_offset=5,
node_depth=6,
inner_size=7,
last_node=True)

@requires_blake2
def test_blake2s_vectors(self):
for msg, key, md in read_vectors('blake2s'):
key = bytes.fromhex(key)
self.check('blake2s', msg, md, key=key)

@requires_blake2
@support.subTests("name", ["blake2b", "blake2s"])
@support.subTests("parameter, value", [
("fanout", 1),
("depth", 1),
("leaf_size", 0),
("node_offset", 0),
("node_depth", 0),
("inner_size", 0),
("last_node", False),
])
def test_blake2_tree_parameter_deprecated(self, name, parameter, value):
constructor = getattr(hashlib, name)
msg = deprecated_blake2_tree_parameter(name, parameter)
kwargs = {parameter: value}
with self.assertWarnsRegex(DeprecationWarning, msg):
constructor(**kwargs)
with self.assertWarnsRegex(DeprecationWarning, msg):
hashlib.new(name, **kwargs)

@requires_blake2
@support.subTests("name", ["blake2b", "blake2s"])
def test_blake2_tree_parameters_omitted(self, name):
constructor = getattr(hashlib, name)
with warnings_helper.check_no_warnings(self,
category=DeprecationWarning):
constructor(b'data', digest_size=16, key=b'key')
hashlib.new(name, b'data', digest_size=16, key=b'key')

@requires_sha3
def test_case_sha3_224_0(self):
self.check('sha3_224', b"",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
:mod:`hashlib`: Passing the tree hashing parameters *fanout*, *depth*,
*leaf_size*, *node_offset*, *node_depth*, *inner_size* and *last_node* to
:func:`~hashlib.blake2b` and :func:`~hashlib.blake2s` is now deprecated and
slated for removal in Python 3.21. Patch by Bénédikt Tran.
Loading
Loading