rbcl module

Python library that bundles libsodium and provides wrappers for its Ristretto group functions.

This library exports wrappers for all libsodium functions related to the Ristretto group and random element generation, including all functions with names of the form crypto_scalarmult_* and relevant functions with names of the form randombytes*.

rbcl.rbcl.randombytes_SEEDBYTES: int

Length of seed for a pseudorandom byte sequence.

rbcl.rbcl.crypto_core_ristretto255_BYTES: int

Length of a byte sequence that represents a point.

rbcl.rbcl.crypto_core_ristretto255_HASHBYTES: int

Length of hash digest to use for creating a point.

rbcl.rbcl.crypto_core_ristretto255_NONREDUCEDSCALARBYTES: int

Length of a byte sequence that represents a scalar (possibly using a non-reduced representation).

rbcl.rbcl.crypto_core_ristretto255_SCALARBYTES: int

Length of a byte sequence that represents a scalar.

rbcl.rbcl.crypto_scalarmult_ristretto255_BYTES: int

Length of a byte sequence that represents a point (provided to – or returned by – a scalar-point multiplication function).

rbcl.rbcl.crypto_scalarmult_ristretto255_SCALARBYTES: int

Length of a byte sequence that represents a scalar (to be used as an input to a scalar-point multiplication function).

rbcl.rbcl.randombytes(length: int) bytes[source]

Return a bytes-like object of length length containing random bytes from a cryptographically suitable source of randomness.

Parameters

length – Length of bytes-like object to return.

>>> len(randombytes(14)) == 14
True
>>> r1 = randombytes(14)
>>> r2 = randombytes(14)
>>> r1 == r2 # Chances of equality succeeding are 1/(2^42).
False

An exception is raised if the input is not valid:

>>> randombytes('abc')
Traceback (most recent call last):
  ...
TypeError: length must be an integer
>>> randombytes(-1)
Traceback (most recent call last):
  ...
ValueError: length must be a non-negative integer
rbcl.rbcl.randombytes_buf_deterministic(length: int, seed: bytes) bytes[source]

Return a bytes-like object of length length containing pseudorandom bytes that have been deterministically generated from the supplied seed (a byte vector of length randombytes_SEEDBYTES).

Parameters
  • length – Length of bytes-like object to return.

  • seed – Seed to use for generating pseudorandom bytes.

The example below shows that the first 32 bytes from the stream of pseudorandom bytes seeded by b'p' * 32 are consistent across invocations:

>>> r1 = randombytes_buf_deterministic(32, b'p' * 32)
>>> r2 = randombytes_buf_deterministic(40, b'p' * 32)
>>> len(r1) == 32
True
>>> r1 == r2[:32]
True

An exception is raised if an input is not valid:

>>> randombytes_buf_deterministic('abc', b'p' * 32)
Traceback (most recent call last):
  ...
TypeError: length must be an integer
>>> randombytes_buf_deterministic(-1, b'p' * 32)
Traceback (most recent call last):
  ...
ValueError: length must be a non-negative integer
>>> try:
...     randombytes_buf_deterministic(32, 123)
... except TypeError as e:
...     str(e) == 'seed must be a bytes object of length ' + str(randombytes_SEEDBYTES)
True
>>> try:
...     randombytes_buf_deterministic(32, b'p'*16)
... except ValueError as e:
...     str(e) == 'seed must be a bytes object of length ' + str(randombytes_SEEDBYTES)
True
rbcl.rbcl.crypto_core_ristretto255_is_valid_point(p: bytes) bool[source]

Return a boolean indiciating whether p is a representation of a valid point on the main subgroup (in canonical form) and that the point does not have a small order.

Parameters

p – Byte vector of length crypto_core_ristretto255_BYTES.

>>> p = crypto_core_ristretto255_random()
>>> crypto_core_ristretto255_is_valid_point(p)
True

For this and other functions that operate on points, a descriptive exception is raised if an input is not valid:

>>> try:
...     crypto_core_ristretto255_is_valid_point(123)
... except TypeError as e:
...     str(e) == (
...         'point must be a bytes object of length ' +
...         str(crypto_core_ristretto255_BYTES)
...     )
True
>>> try:
...     crypto_core_ristretto255_is_valid_point(bytes([0, 0 ,0]))
... except ValueError as e:
...     str(e) == (
...         'point must be a bytes object of length ' +
...         str(crypto_core_ristretto255_BYTES)
...     )
True
rbcl.rbcl.crypto_core_ristretto255_random() bytes[source]

Return a valid random point (represented as a byte vector of length crypto_core_ristretto255_BYTES).

>>> p = crypto_core_ristretto255_random()
>>> crypto_core_ristretto255_is_valid_point(p)
True
rbcl.rbcl.crypto_core_ristretto255_from_hash(h: bytes) bytes[source]

Map a 64-byte vector h (usually the output of a hash function) to a a point (represented as a byte vector of length crypto_core_ristretto255_BYTES).

Parameters

h – Byte vector of length crypto_core_ristretto255_HASHBYTES (usually representing a hash digest).

>>> p = crypto_core_ristretto255_from_hash(b'p'*64)
>>> crypto_core_ristretto255_is_valid_point(p)
True
rbcl.rbcl.crypto_core_ristretto255_add(p: bytes, q: bytes) bytes[source]

Add two points p and q and return their sum (represented as a byte vector of length crypto_core_ristretto255_BYTES).

Parameters

Addition of points is commutative:

>>> p = crypto_core_ristretto255_random()
>>> q = crypto_core_ristretto255_from_hash(b'p'*64)
>>> pq = crypto_core_ristretto255_add(p, q)
>>> qp = crypto_core_ristretto255_add(q, p)
>>> pq == qp
True
rbcl.rbcl.crypto_core_ristretto255_sub(p: bytes, q: bytes) bytes[source]

Subtract a point q from a point p and return their difference (represented as a byte vector of length crypto_core_ristretto255_BYTES).

Parameters

Subtraction between points is the inverse of point addition:

>>> p = crypto_core_ristretto255_from_hash(b'p'*64)
>>> q = crypto_core_ristretto255_random()
>>> masked = crypto_core_ristretto255_add(p, q)
>>> unmasked = crypto_core_ristretto255_sub(masked, q)
>>> p == unmasked
True
rbcl.rbcl.crypto_core_ristretto255_scalar_random() bytes[source]

Return a random scalar, represented as a byte vector of length crypto_core_ristretto255_SCALARBYTES.

>>> s = crypto_core_ristretto255_scalar_random()
>>> len(s) == crypto_core_ristretto255_SCALARBYTES
True

When interpreted as an integer, the scalar is guaranteed to be less than the order of the group (i.e., 2^252 + 27742317777372353535851937790883648493).

rbcl.rbcl.crypto_core_ristretto255_scalar_reduce(s: bytes) bytes[source]

Given a byte vector of length crypto_core_ristretto255_NONREDUCEDSCALARBYTES representing a scalar, return its reduced representation s modulo L (where L is the order of the main subgroup) as a byte vector of length crypto_core_ristretto255_SCALARBYTES .

Parameters

s – Byte vector of length crypto_core_ristretto255_NONREDUCEDSCALARBYTES representing a scalar.

In the example below, a large integer representing a scalar is reduced to a valid scalar:

>>> x = bytes.fromhex('FF' * 32)
>>> s = crypto_core_ristretto255_scalar_reduce(x)
>>> p = crypto_core_ristretto255_random()
>>> masked = crypto_scalarmult_ristretto255(s, p)
>>> s_inv = crypto_core_ristretto255_scalar_invert(s)
>>> unmasked = crypto_scalarmult_ristretto255(s_inv, masked)
>>> unmasked == p
True

For this and other functions that operate on points, a descriptive exception is raised if an input is not valid:

>>> try:
...     crypto_core_ristretto255_scalar_reduce(123)
... except TypeError as e:
...     str(e) == (
...         'scalar must be a bytes object of length ' +
...         str(crypto_core_ristretto255_SCALARBYTES)
...     )
True
>>> try:
...     crypto_core_ristretto255_scalar_reduce(bytes([0, 0 ,0]))
... except ValueError as e:
...     str(e) == (
...         'scalar must be a bytes object of length ' +
...         str(crypto_core_ristretto255_SCALARBYTES)
...     )
True
rbcl.rbcl.crypto_core_ristretto255_scalar_negate(s: bytes) bytes[source]

Return the additive inverse of the scalar s modulo L (i.e., a scalar t such that s + t == 0 modulo L, where L is the order of the main subgroup). The input and output are each represented as a byte vector of length crypto_core_ristretto255_SCALARBYTES.

Parameters

s – Byte vector of length crypto_core_ristretto255_SCALARBYTES representing a scalar.

All scalars have an additive inverse:

>>> s = crypto_core_ristretto255_scalar_random()
>>> t = crypto_core_ristretto255_scalar_negate(s)
>>> zero = crypto_core_ristretto255_scalar_add(s, t)
>>> s == crypto_core_ristretto255_scalar_add(s, zero)
True
rbcl.rbcl.crypto_core_ristretto255_scalar_complement(s: bytes) bytes[source]

Return the additive complement of the scalar s modulo L (i.e., a scalar t such that s + t == 1 modulo L, where L is the order of the main subgroup). The input and output are each represented as a byte vector of length crypto_core_ristretto255_SCALARBYTES.

Parameters

s – Byte vector of length crypto_core_ristretto255_SCALARBYTES representing a scalar.

All scalars have an additive complement:

>>> s = crypto_core_ristretto255_scalar_random()
>>> t = crypto_core_ristretto255_scalar_complement(s)
>>> one = crypto_core_ristretto255_scalar_add(s, t)
>>> p = crypto_core_ristretto255_random()
>>> p == crypto_scalarmult_ristretto255(one, p)
True
rbcl.rbcl.crypto_core_ristretto255_scalar_invert(s: bytes) bytes[source]

Return the multiplicative inverse of the scalar s modulo L (i.e., an integer t such that s * t == 1 modulo L, where L is the order of the main subgroup). The input and output are each represented as a byte vector of length crypto_core_ristretto255_SCALARBYTES.

Parameters

s – Byte vector of length crypto_core_ristretto255_SCALARBYTES representing a scalar.

All scalars have a multiplicative inverse:

>>> s = crypto_core_ristretto255_scalar_random()
>>> p = crypto_core_ristretto255_random()
>>> masked = crypto_scalarmult_ristretto255(s, p)
>>> s_inv = crypto_core_ristretto255_scalar_invert(s)
>>> unmasked = crypto_scalarmult_ristretto255(s_inv, masked)
>>> unmasked == p
True

If s is the zero scalar, an exception is raised.

>>> crypto_core_ristretto255_scalar_invert(bytes([0] * 32))
Traceback (most recent call last):
  ...
ValueError: scalar must not be zero
rbcl.rbcl.crypto_core_ristretto255_scalar_add(s: bytes, t: bytes) bytes[source]

Add two scalars s and t modulo L (where L is the order of the main subgroup) and return their scalar product (represented as a byte vector of length crypto_core_ristretto255_SCALARBYTES).

Parameters

Addition of scalars is commutative:

>>> s1 = crypto_core_ristretto255_scalar_random()
>>> s2 = crypto_core_ristretto255_scalar_random()
>>> s12 = crypto_core_ristretto255_scalar_add(s1, s2)
>>> s21 = crypto_core_ristretto255_scalar_add(s2, s1)
>>> s12 == s21
True
rbcl.rbcl.crypto_core_ristretto255_scalar_sub(s: bytes, t: bytes) bytes[source]

Subtract a scalar t from a scalar s modulo L (where L is the order of the main subgroup) and return their difference (represented as a byte vector of length crypto_core_ristretto255_SCALARBYTES).

Parameters

Subtraction between scalars is the inverse of scalar addition:

>>> s1 = crypto_core_ristretto255_scalar_random()
>>> s2 = crypto_core_ristretto255_scalar_random()
>>> s1_plus_s2 = crypto_core_ristretto255_scalar_add(s1, s2)
>>> s1 == crypto_core_ristretto255_scalar_sub(s1_plus_s2, s2)
True
rbcl.rbcl.crypto_core_ristretto255_scalar_mul(s: bytes, t: bytes) bytes[source]

Multiply two scalars s and t modulo L (where L is the order of the main subgroup) and return their scalar product (represented as a byte vector of length crypto_core_ristretto255_SCALARBYTES).

Parameters

Multiplication of two scalars is commutative:

>>> s1 = crypto_core_ristretto255_scalar_random()
>>> s2 = crypto_core_ristretto255_scalar_random()
>>> s1s2 = crypto_core_ristretto255_scalar_mul(s1, s2)
>>> s2s1 = crypto_core_ristretto255_scalar_mul(s2, s1)
>>> s1s2 == s2s1
True
rbcl.rbcl.crypto_scalarmult_ristretto255_base(s: bytes) bytes[source]

Compute and return the product (represented as a byte vector of length crypto_scalarmult_ristretto255_BYTES) of a standard group element and a scalar s.

Parameters

s – Byte vector of length crypto_scalarmult_ristretto255_SCALARBYTES representing a scalar.

>>> s = crypto_core_ristretto255_scalar_random()
>>> gs = crypto_scalarmult_ristretto255_base(s)
>>> crypto_core_ristretto255_is_valid_point(gs)
True
rbcl.rbcl.crypto_scalarmult_ristretto255_base_allow_scalar_zero(s: bytes) bytes[source]

Compute and return the product (represented as a byte vector of length crypto_scalarmult_ristretto255_BYTES) of a standard group element and a scalar s. Zero-valued scalars are permitted.

Parameters

s – Byte vector of length crypto_scalarmult_ristretto255_SCALARBYTES representing a scalar.

>>> s = crypto_core_ristretto255_scalar_random()
>>> gs = crypto_scalarmult_ristretto255_base_allow_scalar_zero(s)
>>> crypto_core_ristretto255_is_valid_point(gs)
True
>>> crypto_scalarmult_ristretto255_base_allow_scalar_zero(
...     crypto_core_ristretto255_scalar_sub(s, s)
... ) == crypto_core_ristretto255_sub(gs, gs)
True
rbcl.rbcl.crypto_scalarmult_ristretto255(s: bytes, p: bytes) bytes[source]

Compute and return the product (represented as a byte vector of length crypto_scalarmult_ristretto255_BYTES) of a clamped integer s and the provided point (i.e., group element).

Parameters

The scalar is clamped, as done in the public key generation case, by setting to zero the bits in position [0, 1, 2, 255] and by setting to 1 the bit in position 254.

Scalar multiplication is an invertible operation:

>>> s = crypto_core_ristretto255_scalar_random()
>>> p = crypto_core_ristretto255_random()
>>> masked = crypto_scalarmult_ristretto255(s, p)
>>> s_inv = crypto_core_ristretto255_scalar_invert(s)
>>> unmasked = crypto_scalarmult_ristretto255(s_inv, masked)
>>> unmasked == p
True

Multiplication by the zero scalar is not defined in the subgroup consisting of products of valid points and scalars:

>>> p = crypto_core_ristretto255_random()
>>> s = crypto_core_ristretto255_scalar_random()
>>> t = crypto_core_ristretto255_scalar_negate(s)
>>> zero = crypto_core_ristretto255_scalar_add(s, t)
>>> try:
...     crypto_scalarmult_ristretto255(zero, p)
... except RuntimeError as e:
...     str(e) == (
...         'input cannot be larger than the size of the group and ' +
...         'cannot yield the identity element when applied as an exponent'
...     )
True
rbcl.rbcl.crypto_scalarmult_ristretto255_allow_scalar_zero(s: bytes, p: bytes) bytes[source]

Compute and return the product (represented as a byte vector of length crypto_scalarmult_ristretto255_BYTES) of a clamped integer s and the provided point (i.e., group element).

Parameters

The scalar is clamped, as done in the public key generation case, by setting to zero the bits in position [0, 1, 2, 255] and by setting to 1 the bit in position 254. Zero-valued scalars are permitted.

Scalar multiplication is an invertible operation:

>>> s = crypto_core_ristretto255_scalar_random()
>>> p = crypto_core_ristretto255_random()
>>> masked = crypto_scalarmult_ristretto255_allow_scalar_zero(s, p)
>>> s_inv = crypto_core_ristretto255_scalar_invert(s)
>>> unmasked = crypto_scalarmult_ristretto255_allow_scalar_zero(s_inv, masked)
>>> unmasked == p
True

Multiplication by the zero scalar is permitted:

>>> zero_scalar, zero_point = bytes(32), bytes(32)
>>> crypto_scalarmult_ristretto255_allow_scalar_zero(zero_scalar, p) == zero_point
True

While the scalar input can be zero, the provided point must be valid:

>>> invalid_point = b'' * 32
>>> crypto_scalarmult_ristretto255_allow_scalar_zero(zero_scalar, invalid_point)
Traceback (most recent call last):
  ...
TypeError: second input must represent a valid point