ECDH

Module for test ECDH implementations.

The crypto_condor.primitives.ECDH module can test implementations of the ECDH key exchange.

Test implementations

There are two types of test vectors available: those that provide the peer’s public key as the encoded coordinates of the point and those that provide it as a X.509 SubjectPublicKeyInfo field. Since the function signature is different, there is one test for each type.

crypto_condor.primitives.ECDH.test_exchange_point(exchange, curve, *, compliance=True, resilience=False)

Tests ECDH exchange with the peer’s public key as an uncompressed point.

Parameters:
  • exchange (ExchangePoint) – The implementation of the ExchangeCoord protocol to test.

  • curve (Curve) – The elliptic curve to use.

Keyword Arguments:
  • compliance – Whether to use compliance test vectors.

  • resilience – Whether to use resilience test vectors.

Returns:

A dictionary of results.

Return type:

ResultsDict

Example

Let’s test PyCryptodome over P-256. We need the ECC module to construct the keys and the DH module to actually perform the key exchange.

>>> from Crypto.Protocol import DH
>>> from Crypto.PublicKey import ECC

From crypto-condor we import the primitive.

>>> from crypto_condor.primitives import ECDH

We wrap the exchange in our function to match the ExchangePoint protocol.

>>> def exchange_point(secret: bytes, pub_point: bytes) -> bytes:
...     pk = ECC.import_key(pub_point, curve_name="P-256")
...     d = int.from_bytes(secret)
...     sk = ECC.construct(curve="P-256", d=d)
...     return DH.key_agreement(static_priv=sk, static_pub=pk, kdf=lambda x: x)

Then we call test_exchange_point().

>>> curve = ECDH.Curve.P256
>>> rd = ECDH.test_exchange_point(exchange_point, curve)
[P-256][NIST CAVP] Testing ExchangePoint ...
>>> assert rd.check()

Added in version TODO(version): This function roughly replaces test_exchange_nist.

crypto_condor.primitives.ECDH.test_exchange_x509(exchange, curve, *, compliance=True, resilience=False)

Tests ECDH exchange with the peer’s public X509 key.

Parameters:
Keyword Arguments:
  • compliance – Whether to use compliance test vectors.

  • resilience – Whether to use resilience test vectors.

Returns:

A dictionary of results.

Return type:

ResultsDict

Example

Let’s test PyCryptodome over P-256. We need the ECC module to construct the keys and the DH module to actually perform the key exchange.

>>> from Crypto.Protocol import DH
>>> from Crypto.PublicKey import ECC

From crypto-condor we import the primitive.

>>> from crypto_condor.primitives import ECDH

We wrap the exchange in our function to match the ExchangeX509 protocol.

>>> def exchange_x509(secret: bytes, pub_point: bytes) -> bytes:
...     pk = ECC.import_key(pub_point)
...     d = int.from_bytes(secret)
...     sk = ECC.construct(curve="P-256", d=d)
...     return DH.key_agreement(static_priv=sk, static_pub=pk, kdf=lambda x: x)

Then we call test_exchange_x509(). There are no NIST test vectors for this test so we use the resilience option.

>>> curve = ECDH.Curve.P256
>>> rd = ECDH.test_exchange_x509(exchange_x509, curve, resilience=True)
[P-256][Wycheproof] Testing ExchangeX509 ...
>>> assert rd.check()
crypto_condor.primitives.ECDH.test_exchange(ecdh, curve, *, compliance=True, resilience=False)

Tests an implementation of ECDH.

Parameters:
  • ecdh (ECDH) – The implementation to test. It must conform to the ECDH protocol.

  • curve (Curve) – The elliptic curve to use.

Keyword Arguments:
  • compliance – Whether to use NIST vectors.

  • resilience – Whether to use Wycheproof vectors.

Returns:

A dictionary of results.

Return type:

ResultsDict

Notes

Internally calls the test_exchange_nist() and test_exchange_wycheproof() functions.

Changed in version TODO(version): Returns ResultsDict instead of Results or None.

Deprecated since version TODO(version): The test vectors have been updated and the ECDH protocol is now deprecated. Use test_exchange_point() and test_exchange_x509() instead.

crypto_condor.primitives.ECDH.test_exchange_nist(ecdh, curve)

Tests ECDH exchange with NIST vectors.

Parameters:
  • ecdh (ECDH) – The implementation of the ECDH protocol to test.

  • curve (Curve) – The elliptic curve to use.

Returns:

A dictionary of results.

Return type:

ResultsDict

Changed in version TODO(version): Returns ResultsDict instead of Results or None.

Deprecated since version TODO(version): The test vectors have been updated and the ECDH protocol is now deprecated. Use test_exchange_point() and ExchangePoint instead.

crypto_condor.primitives.ECDH.test_exchange_wycheproof(ecdh, curve)

Tests ECDH.exchange with Wycheproof vectors.

Wycheproof vectors provide X509-encoded public keys.

Parameters:
  • ecdh (ECDH) – The implementation to test.

  • curve (Curve) – The elliptic curve to use.

Returns:

A dictionary of results.

Return type:

ResultsDict

Changed in version TODO(version): Returns ResultsDict instead of Results or None.

Deprecated since version TODO(version): The test vectors have been updated and the ECDH protocol is now deprecated. Use test_exchange_x509() and ExchangeX509 instead.

Parameters

enum crypto_condor.primitives.ECDH.Curve(value)

Elliptic curves supported for ECDH.

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:

classmethod from_name(name)

Gets Curve instance from the name of the curve.

Intended to be used by the wrappers, as hyphens are not allowed in function names, so for example P256 is the P-256 curve.

get_ec_name()

Gets the curve name for cryptography’s ec module.

This method is intended for test vectors that provide the public key as coordinates, and thus require converting them to a public key or encoded point.

Returns:

The curve name.

Return type:

str

Protocols

protocol crypto_condor.primitives.ECDH.ExchangePoint

Represents a function that performs ECDH using an uncompresed point.

The function must behave live __call__() to be tested with test_exchange_point().

Classes that implement this protocol must have the following methods / attributes:

__call__(secret, pub_point)

Performs ECDH key exchange using the peer’s uncompresed point.

Parameters:
  • secret (bytes) – Party A’s secret value.

  • pub_point (bytes) – Party B’s public key as an uncompressed point.

Returns:

The shared secret.

Return type:

bytes

protocol crypto_condor.primitives.ECDH.ExchangeX509

Represents a function that performs ECDH using public coordinates.

The function must behave live __call__() to be tested with test_exchange_x509().

Classes that implement this protocol must have the following methods / attributes:

__call__(secret, pub_key)

Performs ECDH key exchange using the peer’s X509 public key.

Parameters:
  • secret (bytes) – Party A’s secret value.

  • pub_key (bytes) – Party B’s public X509 key.

Returns:

The shared secret.

Return type:

bytes

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 by exchange_wycheproof() provide them encoded with X509.

For compliance, use exchange_nist().

Deprecated since version TODO(version): The test vectors have been changed so the protocols have been updated to match. ECDH is replaced by ExchangePoint and ExchangeX509.

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

Run a wrapper

crypto_condor.primitives.ECDH.test_wrapper(wrapper, compliance, resilience)

Runs a ECDH wrapper.

Parameters:
  • wrapper (Path) – The wrapper to test.

  • compliance (bool) – Whether to use NIST vectors.

  • resilience (bool) – Whether to use Wycheproof vectors.

Returns:

The results of test_exchange_point() and test_exchange_x509() in a single dictionary.

Raises:
  • FileNotFoundError – If the wrapper could not be found.

  • ModuleNotFoundError – If the wrapper could not be loaded.

Return type:

ResultsDict

crypto_condor.primitives.ECDH.test_wrapper_python(wrapper, compliance, resilience)

Runs a Python wrapper of ECDH.

Parameters:
  • wrapper (Path) – The wrapper to test. The path must be valid.

  • compliance (bool) – Whether to use compliance test vectors.

  • resilience (bool) – Whether to use resilience test vectors.

Returns:

The results of test_exchange_point() and test_exchange_x509() in a single dictionary.

Raises:

ModuleNotFoundError – If the wrapper could not be loaded.

Return type:

ResultsDict

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.

syntax = "proto3";

package crypto_condor;

// A single ECDH test.
//
// A test for a single key exchange with the private key derived from the private value
// ``d`` and the public key. The public key can be either a X.509 SubjectPublicKeyInfo
// or the uncompressed coordinates of the point.
//
// The ``ss`` and ``d`` fields are required. One of ``peer_point`` and ``peer_x509`` are
// also required.
message EcdhTest {
	// The test ID, unique in its set of vectors.
	int32 id = 1;
	// The type of test. One of: valid, invalid, acceptable.
	string type = 2;
	// A comment on the test.
	string comment = 3;
	// Flags that categorize this test.
	repeated string flags = 4;

	// The resulting shared secret.
	bytes ss = 5;
	// The private value of party A.
	bytes d = 6;

	oneof oneof_pk {
		// The peer's public key point.
		bytes peer_point = 7;
		// The peer's public X509 key.
		bytes peer_x509 = 8;

	}
}

// A set of ECDH test vectors.
//
// It is categorized by its `curve` and `public_type` fields.
message EcdhVectors {
	// The source of the test vectors.
	string source = 1;
	// Description of the source.
	string source_desc = 2;
	// The URL of the source.
	string source_url = 3;
	// Whether these are compliance test vectors or not.
	bool compliance = 4;
	// A dictionary of test flags and their description.
    map<string, string> notes = 5;
	// The test vectors.
	repeated EcdhTest tests = 6;

	// The elliptic curve used for these vectors.
    string curve = 7;
	// The type of public key available. One of: "x509", "point".
	string public_type = 8;
}