aboutsummaryrefslogtreecommitdiff
path: root/test/ec/test_signature.py
blob: a61876bac6497383b7bda5ab2ba78d694298b37c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import json

import pytest
from importlib_resources import files

import test.data.ec
from pyecsca.ec.coordinates import AffineCoordinateModel
from pyecsca.ec.mod import mod
from pyecsca.ec.mult import LTRMultiplier
from pyecsca.ec.params import get_params
from pyecsca.ec.point import Point
from pyecsca.ec.signature import (
    Signature,
    SignatureResult,
    ECDSA_NONE,
    ECDSA_SHA1,
    ECDSA_SHA224,
    ECDSA_SHA256,
    ECDSA_SHA384,
    ECDSA_SHA512,
)


@pytest.fixture()
def add(secp128r1):
    return secp128r1.curve.coordinate_model.formulas["add-2007-bl"]


@pytest.fixture()
def mult(secp128r1, add):
    dbl = secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
    return LTRMultiplier(add, dbl)


@pytest.fixture()
def keypair(secp128r1, mult):
    priv = mod(0xDEADBEEF, secp128r1.order)
    mult.init(secp128r1, secp128r1.generator)
    pub = mult.multiply(int(priv))
    return priv, pub


@pytest.fixture()
def msg():
    return 0xCAFEBABE.to_bytes(4, byteorder="big")


@pytest.mark.parametrize("algo",
                         [
                             ECDSA_SHA1,
                             ECDSA_SHA224,
                             ECDSA_SHA256,
                             ECDSA_SHA384,
                             ECDSA_SHA512,
                         ])
def test_all(secp128r1, mult, keypair, msg, add, algo):
    priv, pub = keypair
    signer = algo(mult, secp128r1, privkey=keypair[0])
    assert signer.can_sign
    sig = signer.sign_data(msg)
    verifier = algo(mult, secp128r1, add=add, pubkey=pub)
    assert verifier.can_verify
    assert verifier.verify_data(sig, msg)

    none = ECDSA_NONE(
        mult, secp128r1, add=add, pubkey=pub, privkey=priv
    )
    digest = signer.hash_algo(msg).digest()
    sig = none.sign_hash(digest)
    assert none.verify_hash(sig, digest)


def test_cannot(secp128r1, add, mult, keypair):
    priv, pub = keypair
    ok = ECDSA_NONE(
        mult, secp128r1, add=add, pubkey=pub, privkey=priv
    )
    data = b"aaaa"
    sig = ok.sign_data(data)

    no_priv = ECDSA_NONE(mult, secp128r1, pubkey=pub)
    with pytest.raises(RuntimeError):
        no_priv.sign_data(data)
    with pytest.raises(RuntimeError):
        no_priv.sign_hash(data)
    no_pubadd = ECDSA_NONE(mult, secp128r1, privkey=priv)
    with pytest.raises(RuntimeError):
        no_pubadd.verify_data(sig, data)
    with pytest.raises(RuntimeError):
        no_pubadd.verify_hash(sig, data)

    with pytest.raises(ValueError):
        Signature(mult, secp128r1)


@pytest.mark.parametrize("algo",
                         [
                             ECDSA_SHA1,
                             ECDSA_SHA224,
                             ECDSA_SHA256,
                             ECDSA_SHA384,
                             ECDSA_SHA512,
                         ])
def test_fixed_nonce(secp128r1, mult, keypair, msg, add, algo):
    priv, pub = keypair
    signer = algo(mult, secp128r1, privkey=priv)
    sig_one = signer.sign_data(msg, nonce=0xABCDEF)
    sig_other = signer.sign_data(msg, nonce=0xABCDEF)
    verifier = algo(mult, secp128r1, add=add, pubkey=pub)
    assert verifier.verify_data(sig_one, msg)
    assert verifier.verify_data(sig_other, msg)
    assert sig_one == sig_other


def test_der():
    sig = SignatureResult(0xAAAAA, 0xBBBBB)
    assert sig == SignatureResult.from_DER(sig.to_DER())
    assert sig != "abc"


def test_ecdsa_nist():
    with files(test.data.ec).joinpath("ecdsa_tv.json").open("r") as f:
        nist_data = json.load(f)

    P192 = get_params("nist", "P-192", "projective")
    affine_model = AffineCoordinateModel(P192.curve.model)
    add = P192.curve.coordinate_model.formulas["add-2015-rcb"]
    dbl = P192.curve.coordinate_model.formulas["dbl-2015-rcb"]
    mult = LTRMultiplier(add, dbl)
    priv = mod(int(nist_data["priv"], 16), P192.order)

    pub_affine = Point(affine_model,
                       x=mod(int(nist_data["pub"]["x"], 16), P192.curve.prime),
                       y=mod(int(nist_data["pub"]["y"], 16), P192.curve.prime))
    pub = pub_affine.to_model(P192.curve.coordinate_model, P192.curve)

    signer = ECDSA_SHA1(mult, P192, add, pub, priv)

    nonce = int(nist_data["k"], 16)
    data = bytes.fromhex(nist_data["msg"])
    signature = signer.sign_hash(data, nonce=nonce)
    assert signature.r == int(nist_data["signature"]["r"], 16)
    assert signature.s == int(nist_data["signature"]["s"], 16)
    assert signer.verify_hash(signature, data)