This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Provide Python implementation of operator.compare_digest()
Type: enhancement Stage: resolved
Components: Versions: Python 3.5
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: christian.heimes, pitrou, rhettinger, serhiy.storchaka, terry.reedy, vstinner, zach.ware
Priority: normal Keywords:

Created on 2013-10-14 11:30 by christian.heimes, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Messages (11)
msg199868 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2013-10-14 11:30
The operator module doesn't have a Python implementation of _compare_digest. This code mimicks the C code:

def _compare_digest(a, b):
    if isinstance(a, str) and isinstance(b, str):
        a = a.encode("ascii")
        b = b.encode("ascii")
    a = memoryview(a)
    len_a = len(a)
    right = memoryview(b)
    len_b = len(right)
    if len_a == len_b:
        result = 0
        left = a
    # loop count depends on length of b
    if len_a != len_b:
        result = 1
        left = b
    for l, r in zip(left, right):
        result |= l ^ r
    return result == 0
msg199870 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2013-10-14 11:33
#15061 explains why the function is not implemented in Python :)
msg199875 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2013-10-14 11:48
It explains why the function isn't implemented in Python, it doesn't say that there shouldn't be a best-effort Python fallback.

All in all, Christian's version looks reasonable. All arithmetic is done on small ints, so there shouldn't be a strong data-dependent timing issue.
msg200286 - (view) Author: Zachary Ware (zach.ware) * (Python committer) Date: 2013-10-18 17:20
Even after reading through #15061, I still wonder why _compare_digest is in _operator at all.  It makes even less sense to me to put a Python implementation in operator; shouldn't the Python implementation be in the module that actually uses it?

Branching from the recent discussion[1] about where to place a PBKDF2 wrapper, it would make the most sense to me to move hmac into hashlib as suggested and move _compare_digest into hashlib's C somewhere.

For the record, the reason I didn't try to implement a _compare_digest in operator.py in the first place was because #15061 made it pretty clear that operator.c was just a convenient place to stick the function, not that it was supposed to actually be part of the operator module.
msg200287 - (view) Author: Zachary Ware (zach.ware) * (Python committer) Date: 2013-10-18 17:21
Oops, forgot to provide the [1] link...

[1] https://mail.python.org/pipermail/python-dev/2013-October/129477.html
msg200333 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2013-10-18 23:38
-1
"The operator module exports a set of efficient functions corresponding to the intrinsic operators of Python." As far as I know, _compare_digest does not correspond to any operator.
msg200412 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2013-10-19 12:52
it's in the _operator module because we needed a place to put it that is *always* available. The C backend for the hashlib module is only available on platforms with OpenSSL (hence the internal name Modules/_hashopenssl.c).

The operator module already contains additional stuff like attrgetter() or itemgetter(). compare_digest is a special case of __eq__ with limited data types and a constant timing algorithm.
msg200454 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2013-10-19 17:59
attrgetter and itemgetter are partial versions of getattr (. operator) and op.getitem ([] operator). I see now that _compare_digest might have more clearly been named _eq_strng_slow ;-). ('Compare' implies to me a -1, 0, 1 return.)

Are you planning to leave the initial '_' and if so, would this function be documented?
msg200694 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2013-10-21 04:11
Sorry Christian, but I think this just clutter's the operator module.  I agree with Terry that it doesn't belong here.   

The hashlib module might be a better choice.  That's where I would start looking for it if I needed a function like this.
msg221359 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2014-06-23 14:33
Ping?
msg404486 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2021-10-20 16:14
There is no agreement where to put the function. In the past seven years nobody else has requested a pure Python implementation, too. I'm closing my feature request as rejected.
History
Date User Action Args
2022-04-11 14:57:52adminsetgithub: 63458
2021-10-20 16:14:35christian.heimessetstatus: open -> closed
resolution: rejected
messages: + msg404486

stage: needs patch -> resolved
2014-06-23 14:33:37vstinnersetmessages: + msg221359
versions: + Python 3.5, - Python 3.4
2013-10-21 04:11:43rhettingersetnosy: + rhettinger
messages: + msg200694
2013-10-19 17:59:51terry.reedysetmessages: + msg200454
2013-10-19 12:52:39christian.heimessetmessages: + msg200412
2013-10-18 23:38:47terry.reedysetnosy: + terry.reedy
messages: + msg200333
2013-10-18 17:21:39zach.waresetmessages: + msg200287
2013-10-18 17:20:37zach.waresetnosy: + zach.ware
messages: + msg200286
2013-10-14 11:48:47pitrousetmessages: + msg199875
2013-10-14 11:33:16vstinnersetnosy: + vstinner
messages: + msg199870
2013-10-14 11:30:56christian.heimescreate