Skip to content

Make Ecdsa.verify() more flexible #15

@windsurfer1122

Description

@windsurfer1122

Issue:
Having the conversion to "byte string", the hashing plus conversion to integer inside the Ecdsa.verify() function is highly unflexible and can be performing badly.
There are multiple reasons why you want to do this outside Ecdsa.verify().

One example is huge data that you want to hash in parts and not to keep completely in memory.
With the current implementation of Ecdsa.verify() this is not possible.
Another example would be verifying the ECDSA signature multiple times with different public keys, then all the conversions are done multiple times which is wasting performance.

Suggestion:
Create a new function called Ecdsa.verifyNumber() that directly takes an integer value "numberMessage" as a parameter def verifyNumber(cls, numberMessage, signature, publicKey), which skips all these conversions (typically for "prehashed" values).
Additionally enhance the existing Ecdsa.verify() function to handle different variable types of the message parameter.

Ecdsa.sign() could profit from the same changes.

Code (not tested, but shall be compatible with Python 3 and 2.7)

## Python 2 future-compatible workarounds: (see: http://python-future.org/compatible_idioms.html)
## interpret long as int, support int.from_bytes()
from builtins import int
## support bytes()
from builtins import bytes

...
    @classmethod
    def verifyNumber(cls, numberMessage, signature, publicKey):
        curve = publicKey.curve
        sigR = signature.r
        sigS = signature.s
        inv = Math.inv(sigS, curve.N)
        u1 = Math.multiply(curve.G, n=(numberMessage * inv) % curve.N, A=curve.A, P=curve.P, N=curve.N)
        u2 = Math.multiply(publicKey.point, n=(sigR * inv) % curve.N, A=curve.A, P=curve.P, N=curve.N)
        add = Math.add(u1, u2, P=curve.P, A=curve.A)
        return sigR == add.x

    @classmethod
    def verify(cls, message, signature, publicKey, hashfunc=sha256):
        if isinstance(message, int):
            numberMessage = message
        elif isinstance(message, bytes) \
        or isinstance(message, bytearray):
            if not hashfunc is None:
                hashMessage = hashfunc(message).digest()
            else:
                hashMessage = message
            # TODO: numberMessage = int.from_bytes(hashMessage, byteorder="big")
            numberMessage = BinaryAscii.numberFromString(hashMessage)
        else:
            hashMessage = hashfunc(toBytes(message)).digest()
            # TODO: numberMessage = int.from_bytes(hashMessage, byteorder="big")
            numberMessage = BinaryAscii.numberFromString(hashMessage)
        #
        return verifyNumber(numberMessage, signature, publicKey)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions