ECDH#
Module for test ECDH implementations.
The crypto_condor.primitives.ECDH
module can test implementations of the
ECDH key exchange with the test_exchange()
function.
Test implementations#
- crypto_condor.primitives.ECDH.test_exchange(ecdh, curve, *, compliance=True, resilience=False)#
Tests an implementation of ECDH.
- Parameters:
- Keyword Arguments:
compliance – Whether to use NIST vectors.
resilience – Whether to use Wycheproof vectors.
- Returns:
The results of testing with NIST and Wycheproof vectors, depending on the options used. Dictionary keys are
ECDH/test_exchange_nist/<curve name>
andECDH/test_exchange_wycheproof/<curve name>
. The dictionary can be empty if there are no vectors from the sources selected.- Return type:
Notes
Internally calls the
test_exchange_nist()
andtest_exchange_wycheproof()
functions.Example
Let’s test PyCryptodome’s implementation with NIST vectors on the P-192 curve.
>>> from Crypto.Protocol import DH >>> from Crypto.PublicKey import ECC >>> # Build a class that conforms to the ECDH protocol. >>> class MyEcdh: ... def exchange_nist( ... self, ... secret: int, ... pub_x: int, ... pub_y: int, ... pub_key: bytes ... ) -> bytes: ... # We can use the coordinates directly. ... pk = ECC.construct(curve="P-192", point_x=pub_x, point_y=pub_y) ... # And we only need the secret value to construct the private key. ... sk = ECC.construct(curve="P-192", d=secret) ... # We want the raw shared secret, so we use a KDF that does nothing. ... shared = DH.key_agreement( ... static_priv=sk, ... static_pub=pk, ... kdf=lambda x: x, ... ) ... return shared ... def exchange_wycheproof( ... self, ... secret, ... public_key, ... ) -> bytes: ... # We define the Wycheproof way to ensure the test is skipped if the ... # exception is raised. ... raise NotImplementedError
We can now test this implementation:
>>> from crypto_condor.primitives import ECDH >>> curve = ECDH.Curve("P-192") >>> rdict = ECDH.test_exchange(MyEcdh(), curve) [NIST] ...
We can check the result of testing with the NIST vectors.
>>> res = rdict["ECDH/test_exchange_nist/P-192"] >>> assert res.check()
Parameters#
- enum crypto_condor.primitives.ECDH.Curve(value)#
Elliptic curves supported for ECDH.
As shown below, not all curves have NIST and Wycheproof vectors. To determine whether a curve has a specific source programmatically, see
nist
andwycheproof
.# Curve
NIST
Wycheproof
P-224, P-256, P-384, P-521
Y
Y
B-283, B-409, B-571
Y
Y
K-283, K-409, K-571
Y
Y
P-192
Y
N
B-163, B-233
Y
N
K-163, K-233
Y
N
secp256k1
N
Y
brainpool*
N
Y
- Member Type:
str
Valid values are as follows:
- P192 = <Curve.P192: 'P-192'>#
- P224 = <Curve.P224: 'P-224'>#
- P256 = <Curve.P256: 'P-256'>#
- P384 = <Curve.P384: 'P-384'>#
- P521 = <Curve.P521: 'P-521'>#
- K163 = <Curve.K163: 'K-163'>#
- K233 = <Curve.K233: 'K-233'>#
- K283 = <Curve.K283: 'K-283'>#
- K409 = <Curve.K409: 'K-409'>#
- K571 = <Curve.K571: 'K-571'>#
- B163 = <Curve.B163: 'B-163'>#
- B233 = <Curve.B233: 'B-233'>#
- B283 = <Curve.B283: 'B-283'>#
- B409 = <Curve.B409: 'B-409'>#
- B571 = <Curve.B571: 'B-571'>#
- BRAINPOOLP224R1 = <Curve.BRAINPOOLP224R1: 'brainpoolP224r1'>#
- BRAINPOOLP256R1 = <Curve.BRAINPOOLP256R1: 'brainpoolP256r1'>#
- BRAINPOOLP320R1 = <Curve.BRAINPOOLP320R1: 'brainpoolP320r1'>#
- BRAINPOOLP384R1 = <Curve.BRAINPOOLP384R1: 'brainpoolP384r1'>#
- BRAINPOOLP512R1 = <Curve.BRAINPOOLP512R1: 'brainpoolP512r1'>#
- SECP256K1 = <Curve.SECP256K1: 'secp256k1'>#
The
Enum
and its members also have the following methods:- property nist: bool#
True if there are NIST vectors for this curve.
- property wycheproof: bool#
True if there are Wycheproof vectors for this curve.
- property ec_curve: EllipticCurve | None#
Returns an instance of the elliptic curve from
cryptography
.This property is intended for
test_exchange_nist()
to serialize the EC point to SEC1 format. As such, only curves for which there are NIST vectors are returned. Returns None otherwise.
Protocols#
- protocol crypto_condor.primitives.ECDH.ECDH#
Class that implements ECDH.
Implementations use one party’s private value and the other’s public key to perform their half of the key exchange.
There are two methods to implement which depend on the test vectors used:
exchange_nist()
uses NIST vectors which provide the public key by its coordinates, while the Wycheproof vectors used byexchange_wycheproof()
provide them encoded with X509.For compliance, use
exchange_nist()
.Classes that implement this protocol must have the following methods / attributes:
- exchange_nist(secret, pub_x, pub_y, pub_key)#
ECDH exchange with NIST vectors.
NIST vectors provide the public key as point coordinates. In case an implementation does not deal with coordinates, but at least can deal with an SEC1-encoded point (subset of X9.62), crypto-condor constructs and provided this encoded point. However, we recommend using the coordinates whenever possible.
- Parameters:
secret (int) – Party A’s secret value.
pub_x (int) – The x-coordinate of party B’s public key.
pub_y (int) – The y-coordinate of party B’s public key.
pub_key (bytes) – The public key as a SEC1-encoded point. It does not provide information on the curve used. Constructed by crypto-condor from the coordinates.
- Returns:
The shared key.
- Return type:
bytes
- exchange_wycheproof(secret, pub_key)#
ECDH exchange with Wycheproof vectors.
Wycheproof vectors provide the public key encoded with X509. This encoding includes information about the curve, along with the coordinates.
- Parameters:
secret (int) – Party A’s secret value.
pub_key (bytes) – Party B’s public key, encoded with X509.
- Returns:
The shared key.
- Return type:
bytes
Vectors#
- class crypto_condor.primitives.ECDH.EcdhVectors(curve, nist, wycheproof)#
Test vectors for ECDH.
Do not instantiate directly, use
load()
.Available vectors are defined by
Curve
.- Parameters:
curve (Curve) – The elliptic curve used for the test vectors.
nist (EcdhNistVectors | None) – NIST test vectors if they exist for the given curve, None otherwise.
wycheproof (EcdhWycheproofVectors | None) – Wycheproof test vectors if they exist for the given curve, None otherwise.
Wrappers#
- enum crypto_condor.primitives.ECDH.Wrapper(value)#
Supported languages for wrappers.
- Member Type:
str
Valid values are as follows:
- PYTHON = <Wrapper.PYTHON: 'Python'>#
- crypto_condor.primitives.ECDH.run_wrapper(wrapper, lang, curve, compliance=True, resilience=False)#
Runs a ECDH wrapper.
- Parameters:
- Returns:
The results of
test_exchange()
.- Raises:
FileNotFoundError – If the wrapper could not be found.
ValueError – If lang or curve are not valid values.
- Return type:
Example
>>> from crypto_condor.primitives import ECDH >>> from pathlib import Path >>> my_wrapper = Path("my_wrapper.py") >>> lang = ECDH.Wrapper.PYTHON >>> curve = ECDH.Curve.P192 >>> rdict = ECDH.run_wrapper(my_wrapper, lang, curve)
Internal tests#
- crypto_condor.primitives.ECDH.test_exchange_nist(ecdh, curve)#
Tests ECDH exchange with NIST vectors.
- Parameters:
- Returns:
The results of testing the implementation by computing the shared secret with the implementation and comparing it to the expected one. None if there are no NIST vectors for the given curve or the
exchange_nist
method is not implemented.- Return type:
Results | None
- crypto_condor.primitives.ECDH.test_exchange_wycheproof(ecdh, curve)#
Tests ECDH.exchange with Wycheproof vectors.
Wycheproof vectors provide X509-encoded public keys.
- Parameters:
- Returns:
The results of testing the implementation by computing the shared secret and comparing it to the expected one, or None if there are no Wycheproof vectors for the given curve.
- Return type:
Results | None
Internal runners#
- crypto_condor.primitives.ECDH.run_wrapper_python(wrapper, curve, compliance, resilience)#
Runs a Python wrapper of ECDH.
Imports the wrapper script and searches for a class named CC_ECDH. If found, it is passed to
test_exchange()
with the corresponding options.- Parameters:
wrapper (Path) – The wrapper to test. The path must be valid.
curve (Curve) – The elliptic curve to use.
compliance (bool) – Whether to use NIST vectors.
resilience (bool) – Whether to use Wycheproof vectors.
- Returns:
The results returned by
test_exchange()
.- Raises:
ModuleNotFoundError – If the module could not be loaded.
- Return type:
Internal vectors#
The following section describes the internal test vectors classes, which are protobuf Python classes.
Hint
The autodoc extension can’t properly document these clases so we include the
.proto
file to show the different fields each class has. IDEs should be able to
use the included .pyi
files to provide auto-completion and type checking.
- class crypto_condor.vectors._ECDH.ECDH_pb2.EcdhNistVectors#
Protobuf class that stores NIST test vectors. See the description below.
- class crypto_condor.vectors._ECDH.ECDH_pb2.EcdhWycheproofVectors#
Protobuf class that stores Wycheproof test vectors. See the description below.
syntax = "proto3";
package crypto_condor;
// A single NIST test for ECDH. The coordinates and private value are in bytes to ensure
// that they fit - the values used for e.g B-571 are roughly 70 bits long.
message EcdhNistTest {
// The test ID. It should be unique among tests for the same curve.
int32 count = 1;
// The peer's public x-coordinate.
bytes peer_x = 2;
// The peer's public y-coordinate.
bytes peer_y = 3;
// Our secret value.
bytes own_d = 4;
// Our public x-coordinate.
bytes own_x = 5;
// Our public y-coordinate.
bytes own_y = 6;
// The resulting shared secret.
bytes z = 7;
}
// NIST test vectors for a given curve.
message EcdhNistVectors {
// The name of the curve.
string curve = 1;
// A list of tests for this curve.
repeated EcdhNistTest tests = 2;
}
// A single Wycheproof test vector for ECDH. It is common to both types of tests
// (encoded point and encoded public key).
message EcdhWycheproofTest {
// Test ID. Should be unique in a file of vectors.
int32 id = 1;
// A comment describing what is being tested.
string comment = 2;
// The peer's public key - either an encoded point or an encoded public key. See the type
// of EcdhWycheproofGroup.
bytes public = 3;
// The private value. Stored as bytes to ensure it fits.
bytes private = 4;
// The resulting shared secret.
bytes shared = 5;
// The TestType.
string result = 6;
// Flags annotating this test.
repeated string flags = 7;
}
// A group of Wycheproof tests.
message EcdhWycheproofGroup {
// The name of the curve.
string curve = 1;
// The type of encoding used for the public key.
string encoding = 2;
// The type of test: either EcdhTest where the public key is wholly encoded, or
// EcdhEcpointTest where only the encoded coordinates are given.
string type = 3;
// A list of tests.
repeated EcdhWycheproofTest tests = 4;
}
// A file of Wycheproof test vectors for ECDH.
message EcdhWycheproofVectors {
// The algorithm - ECDH in this case.
string algorithm = 1;
// The version of the generator used - refer to Wycheproof.
string generator_version = 2;
// The total number of tests included in this file.
int32 number_of_tests = 3;
// Additional information about these tests.
string header = 4;
// Notes describing the flags that annotate the tests.
map<string, string> notes = 5;
// The JSON scheme of the original file.
string schema = 6;
// The groups of tests.
repeated EcdhWycheproofGroup groups = 7;
// The name of the source file.
string filename = 15;
}