cslashm / ECPy

Apache License 2.0
38 stars 24 forks source link

Wrong EcSchnorr signatures on BRAINPOOL curves using LIBSECP variant #13

Closed Saltari closed 4 years ago

Saltari commented 4 years ago

Consider the following script:

import hashlib
import random
import sys

from ecpy.curves import Curve
from ecpy.keys import ECPrivateKey, ECPublicKey
from ecpy.ecschnorr  import ECSchnorr

def round8(v):
    v += 7
    return v-v%8

if __name__ == "__main__":
    CURVES = ["secp256k1", "secp256r1", "Brainpool-p256r1", "Brainpool-p256t1"]
    MODES = ["LIBSECP", "ISO", "ISOx", "BSI", "Z"]
    SUCCESS_LIMIT = 100
    hashname = "sha256"
    for curvename in CURVES:
        for modename in MODES:
            print(f"CURVE={curvename}, MODE={modename}, HASH={hashname}")
            i = 1
            while i < SUCCESS_LIMIT:
                hasher = eval(f"hashlib.{hashname}")()
                hasherclass = eval(f"hashlib.{hashname}")
                curveobj = Curve.get_curve(curvename)
                curvesize = round8(curveobj.size)//8
                signer = ECSchnorr(hasherclass, option=modename)
                d = random.randint(0, curveobj.order)
                priv_key = ECPrivateKey(d, curveobj)
                pub_key = priv_key.get_public_key()
                msg = random.randint(0, pow(2, 256))
                msg = msg.to_bytes(32, 'big')
                hasher.update(msg)
                msg = hasher.digest()
                sig_host = signer.sign(msg, priv_key)
                try:
                    assert(signer.verify(msg, sig_host, pub_key))
                except AssertionError:
                    print(f"failed at {i}th step")
                    break
                else:
                    i += 1

Giving the following output:

CURVE=secp256k1, MODE=LIBSECP, HASH=sha256
CURVE=secp256k1, MODE=ISO, HASH=sha256
CURVE=secp256k1, MODE=ISOx, HASH=sha256
CURVE=secp256k1, MODE=BSI, HASH=sha256
CURVE=secp256k1, MODE=Z, HASH=sha256
CURVE=secp256r1, MODE=LIBSECP, HASH=sha256
CURVE=secp256r1, MODE=ISO, HASH=sha256
CURVE=secp256r1, MODE=ISOx, HASH=sha256
CURVE=secp256r1, MODE=BSI, HASH=sha256
CURVE=secp256r1, MODE=Z, HASH=sha256
CURVE=Brainpool-p256r1, MODE=LIBSECP, HASH=sha256
failed at 1th step
CURVE=Brainpool-p256r1, MODE=ISO, HASH=sha256
CURVE=Brainpool-p256r1, MODE=ISOx, HASH=sha256
CURVE=Brainpool-p256r1, MODE=BSI, HASH=sha256
CURVE=Brainpool-p256r1, MODE=Z, HASH=sha256
CURVE=Brainpool-p256t1, MODE=LIBSECP, HASH=sha256
failed at 4th step
CURVE=Brainpool-p256t1, MODE=ISO, HASH=sha256
CURVE=Brainpool-p256t1, MODE=ISOx, HASH=sha256
CURVE=Brainpool-p256t1, MODE=BSI, HASH=sha256
CURVE=Brainpool-p256t1, MODE=Z, HASH=sha256

We mostly end up in the case where h > order and as a result the verfication function returns 0

cslashm commented 4 years ago

Thanks for reporting.

cslashm commented 4 years ago

Fixed in 1.1.0