Skip to content

API Reference

User-facing functions and classes

DiffieHellmanMerkle

For secure key exchange across an unsecure (public) channel using Finite Field Diffie-Hellman-Merkle Key Exchange (RFC 7919)

Refer to

https://en.wikipedia.org/wiki/Diffie-Hellman_key_exchange#Cryptographic_explanation

Attributes:

Name Type Description
shared_modulus int

Publicly-shared modulus number (must be a prime number)

shared_base int

Publicly-shared base number

personal_secret int

Secret (non-public) number unique to this user

value_to_share int

Publicly-shared result of algorithmic calculation for this user (function of shared_modulus,shared_base and presonal_secret)

shared_secret int

Secure secret (non-public) number to use for encrypted communication

Source code in diffie_hellman_merkle/user.py
 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
class DiffieHellmanMerkle:
    """For secure key exchange across an unsecure (public) channel using Finite Field Diffie-Hellman-Merkle Key Exchange (RFC 7919)

    Refer to:
        https://en.wikipedia.org/wiki/Diffie-Hellman_key_exchange#Cryptographic_explanation

    Attributes:
        shared_modulus (int): Publicly-shared modulus number (must be a prime number)
        shared_base (int): Publicly-shared base number
        personal_secret (int): Secret (non-public) number unique to this user
        value_to_share (int): Publicly-shared result of algorithmic calculation for this user (function of `shared_modulus`,`shared_base` and `presonal_secret`)
        shared_secret (int): Secure secret (non-public) number to use for encrypted communication
    """

    def __init__(
        self,
        shared_modulus: int,
        shared_base: int,
        personal_secret: int,
    ):
        if not helpers.is_prime(shared_modulus):
            raise ValueError(
                f"shared_modulus must be a prime number ({shared_modulus} is not prime)"
            )
        if not helpers.g_is_primitive_root_modulo_p(g=shared_base, p=shared_modulus):
            raise ValueError(
                f"`shared_base` must be a primitive root modulo `shared_modulus`. Received shared_base={shared_base}, shared_modulus={shared_modulus}"
            )
        self.shared_modulus = shared_modulus
        self.shared_base = shared_base
        self.personal_secret = personal_secret
        self.value_to_share: int = helpers.modulo_exp(
            base=self.shared_base, exp=self.personal_secret, mod=self.shared_modulus
        )
        self.shared_secret: int | None = None

    def generate_shared_secret(
        self,
        received_value_to_share: int,
    ) -> None:
        """Computes a secret shared secret key

        Args:
            received_value_to_share (int): `value_to_share` received from the user that we wish to securely communicate with.

        Returns:
            None (does not return anything)
        """

        self.shared_secret = helpers.modulo_exp(
            base=received_value_to_share,
            exp=self.personal_secret,
            mod=self.shared_modulus,
        )

generate_shared_secret(received_value_to_share)

Computes a secret shared secret key

Parameters:

Name Type Description Default
received_value_to_share int

value_to_share received from the user that we wish to securely communicate with.

required

Returns:

Type Description
None

None (does not return anything)

Source code in diffie_hellman_merkle/user.py
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
def generate_shared_secret(
    self,
    received_value_to_share: int,
) -> None:
    """Computes a secret shared secret key

    Args:
        received_value_to_share (int): `value_to_share` received from the user that we wish to securely communicate with.

    Returns:
        None (does not return anything)
    """

    self.shared_secret = helpers.modulo_exp(
        base=received_value_to_share,
        exp=self.personal_secret,
        mod=self.shared_modulus,
    )

Internal (non-user-facing) helper functions and classes

  • is_prime(n: int) -> bool - Returns True if integer n is prime, otherwise False
  • g_is_primitive_root_modulo_p(g: int, p: int) -> bool - Returns True if g is primitive root modulo prime number p, otherwise False
  • modulo_exp(base: int, exp: int, mod: int) -> int - Memory-efficient calculation of the modulo of an exponentiated number (e.g. the value of 123^456)mod7

g_is_primitive_root_modulo_p(g, p)

Returns True if g is primitive root modulo prime number p, otherwise False

Examples:

>>> g_is_primitive_root_modulo_p(g=69, p=251)
False
>>> g_is_primitive_root_modulo_p(g=6, p=251)
True

Parameters:

Name Type Description Default
g int

The potential primitive root number

required
p int

The modulo prime number

required

Returns:

Type Description
bool

True if g is primitive root modulo prime number p, otherwise False

Source code in diffie_hellman_merkle/helpers.py
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
def g_is_primitive_root_modulo_p(g: int, p: int) -> bool:
    """Returns `True` if `g` is primitive root modulo prime number `p`, otherwise `False`

    Examples:
        >>> g_is_primitive_root_modulo_p(g=69, p=251)
        False
        >>> g_is_primitive_root_modulo_p(g=6, p=251)
        True

    Args:
        g (int): The potential primitive root number
        p (int): The modulo prime number

    Returns:
        (bool): `True` if `g` is primitive root modulo prime number `p`, otherwise `False`
    """
    for m in range(1, p - 1):
        if (p - 1) % m == 0 and modulo_exp(base=g, exp=m, mod=p) == 1:
            return False
    return True

is_prime(n)

Returns True if integer n is prime, otherwise False

This code is taken from a stack overflow answer

https://stackoverflow.com/questions/1801391/how-to-create-the-most-compact-mapping-n-→-isprimen-up-to-a-limit-n

Examples:

>>> is_prime(69)
False
>>> is_prime(440_817_757)
True

Parameters:

Name Type Description Default
n int

The integer to check (whether it is prime or not)

required

Returns:

Type Description
bool

True if n is prime, otherwise False

Source code in diffie_hellman_merkle/helpers.py
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
def is_prime(n: int) -> bool:
    """Returns `True` if integer `n` is prime, otherwise `False`

    This code is taken from a stack overflow answer:
        https://stackoverflow.com/questions/1801391/how-to-create-the-most-compact-mapping-n-→-isprimen-up-to-a-limit-n

    Examples:
        >>> is_prime(69)
        False
        >>> is_prime(440_817_757)
        True

    Args:
        n (int): The integer to check (whether it is prime or not)

    Returns:
        (bool): `True` if `n` is prime, otherwise `False`
    """
    if n == 2:
        return True
    if n == 3:
        return True
    if n % 2 == 0:
        return False
    if n % 3 == 0:
        return False

    i = 5
    w = 2

    while i * i <= n:
        if n % i == 0:
            return False

        i += w
        w = 6 - w

    return True

modulo_exp(base, exp, mod)

Memory-efficient calculation of the modulo of an exponentiated number e.g. the value of (123^456)mod7

This algorithm taken from the wikipedia article

https://en.wikipedia.org/wiki/Modular_exponentiation#Memory-efficient_method

Examples:

>>> modulo_exp(base=6, exp=9, mod=420)
216

Parameters:

Name Type Description Default
base int

The base number to be exponentiated

required
exp int

The number in the exponent

required
mod int

The modulus (divisor) in the modulo calculation

required

Returns:

Type Description
int

The final result of the modulo calculation

Source code in diffie_hellman_merkle/helpers.py
 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
def modulo_exp(base: int, exp: int, mod: int) -> int:
    r"""Memory-efficient calculation of the modulo of an exponentiated number
    e.g. the value of (123^456)mod7

    This algorithm taken from the wikipedia article:
        https://en.wikipedia.org/wiki/Modular_exponentiation#Memory-efficient_method

    Examples:
        >>> modulo_exp(base=6, exp=9, mod=420)
        216

    Args:
        base (int): The base number to be exponentiated
        exp (int): The number in the exponent
        mod (int): The modulus (divisor) in the modulo calculation

    Returns:
        (int): The final result of the modulo calculation
    """
    moving_solution: int = 1
    moving_exp: int = 0
    while moving_exp < exp:
        moving_exp += 1
        moving_solution = (base * moving_solution) % mod
    return moving_solution