"""
Python library that bundles `libsodium <https://github.com/jedisct1/libsodium>`__
and provides wrappers for its Ristretto group functions.
This library exports wrappers for all libsodium methods related to the Ristretto
group and random number generation, including all ``crypto_scalarmult_*`` methods
and the `randombytes*` methods.
"""
from __future__ import annotations
import doctest
import pathlib
from barriers import barriers
VALIDATION_ENABLED = 'site-packages' not in str(pathlib.Path(__file__).resolve())
safe = barriers(VALIDATION_ENABLED) @ globals()
try:
from rbcl import _sodium # pylint: disable=cyclic-import
except: # pylint: disable=bare-except # pragma: no cover
# Support for direct invocation in order to execute doctests.
import _sodium
crypto_scalarmult_ristretto255_BYTES: int = \
_sodium.lib.crypto_scalarmult_ristretto255_bytes()
crypto_scalarmult_ristretto255_SCALARBYTES: int = \
_sodium.lib.crypto_scalarmult_ristretto255_scalarbytes()
crypto_core_ristretto255_BYTES: int = \
_sodium.lib.crypto_core_ristretto255_bytes()
crypto_core_ristretto255_HASHBYTES: int = \
_sodium.lib.crypto_core_ristretto255_hashbytes()
crypto_core_ristretto255_NONREDUCEDSCALARBYTES: int = \
_sodium.lib.crypto_core_ristretto255_nonreducedscalarbytes()
crypto_core_ristretto255_SCALARBYTES: int = \
_sodium.lib.crypto_core_ristretto255_scalarbytes()
randombytes_SEEDBYTES: int = \
_sodium.lib.randombytes_seedbytes()
[docs]def crypto_core_ristretto255_is_valid_point(p): # (const unsigned char *p);
"""
Check if ``p`` represents a point on the ristretto255 curve, in canonical
form, on the main subgroup, and that the point doesn't have a small order.
>>> p = crypto_core_ristretto255_random()
>>> crypto_core_ristretto255_is_valid_point(p)
True
:param p: a :py:data:`.crypto_core_ristretto255_BYTES` long bytes sequence
representing a point on the ristretto255 curve
:type p: bytes
:return: point validity
:rtype: bool
"""
if not isinstance(p, bytes) or len(p) != crypto_core_ristretto255_BYTES:
raise TypeError(
'Point must be a ' + str(crypto_core_ristretto255_BYTES) +
'long bytes sequence'
) # pragma: no cover
rc = _sodium.lib.crypto_core_ristretto255_is_valid_point(p)
return rc == 1
[docs]def crypto_core_ristretto255_add(p, q):
"""
Add two points on the ristretto255 curve.
Example - Point addition commutes in L:
>>> x = crypto_core_ristretto255_random()
>>> y = crypto_core_ristretto255_from_hash(b'\x70'*64)
>>> z1 = crypto_core_ristretto255_add(x, y)
>>> z2 = crypto_core_ristretto255_add(y, x)
>>> z1 == z2
True
:param p: a :py:data:`.crypto_core_ristretto255_BYTES` long bytes sequence
representing a point on the ristretto255 curve
:type p: bytes
:param q: a :py:data:`.crypto_core_ristretto255_BYTES` long bytes sequence
representing a point on the ristretto255 curve
:type q: bytes
:return: a point on the ristretto255 curve represented as
a :py:data:`.crypto_core_ristretto255_BYTES` long bytes sequence
:rtype: bytes
"""
if (
not isinstance(p, bytes) or len(p) != crypto_core_ristretto255_BYTES or \
not isinstance(q, bytes) or len(q) != crypto_core_ristretto255_BYTES
):
raise TypeError(
f'Each integer must be a {crypto_core_ristretto255_BYTES} long bytes sequence'
) # pragma: no cover
r = _sodium.ffi.new('unsigned char[]', crypto_core_ristretto255_BYTES)
_sodium.lib.crypto_core_ristretto255_add(r, p, q)
return _sodium.ffi.buffer(r, crypto_core_ristretto255_BYTES)[:]
[docs]def crypto_core_ristretto255_sub(p, q):
"""
Subtract a point from another on the ristretto255 curve.
Example - Point subtraction is the inverse of addition:
>>> p = crypto_core_ristretto255_from_hash(b'\x70'*64)
>>> mask = crypto_core_ristretto255_random()
>>> masked = crypto_core_ristretto255_add(p, mask)
>>> unmasked = crypto_core_ristretto255_sub(masked, mask)
>>> p == unmasked
True
:param p: a :py:data:`.crypto_core_ristretto255_BYTES` long bytes sequence
representing a point on the ristretto255 curve
:type p: bytes
:param q: a :py:data:`.crypto_core_ristretto255_BYTES` long bytes sequence
representing a point on the ristretto255 curve
:type q: bytes
:return: a point on the ristretto255 curve represented as
a :py:data:`.crypto_core_ristretto255_BYTES` long bytes sequence
:rtype: bytes
"""
if (
not isinstance(p, bytes) or len(p) != crypto_core_ristretto255_BYTES or \
not isinstance(q, bytes) or len(q) != crypto_core_ristretto255_BYTES
):
raise TypeError(
f'Each integer must be a {crypto_core_ristretto255_BYTES} long bytes sequence'
) # pragma: no cover
r = _sodium.ffi.new('unsigned char[]', crypto_core_ristretto255_BYTES)
_sodium.lib.crypto_core_ristretto255_sub(r, p, q)
return _sodium.ffi.buffer(r, crypto_core_ristretto255_BYTES)[:]
[docs]def crypto_core_ristretto255_from_hash(h):
"""
Map a 64-byte vector ``h`` (usually the output of a hash function) to a ristretto255
group element (a point), and output its representation in bytes.
>>> p = crypto_core_ristretto255_from_hash(b'\x70'*64)
>>> crypto_core_ristretto255_is_valid_point(p)
True
:param h: a :py:data:`.crypto_core_ristretto255_HASHBYTES`
long bytes sequence ideally representing a hash digest
:type h: bytes
:return: an integer represented as a
:py:data:`.crypto_core_ristretto255_BYTES` long bytes sequence
:rtype: bytes
"""
if not isinstance(h, bytes) or len(
h) != crypto_core_ristretto255_HASHBYTES:
raise TypeError(
f'Each integer must be a {crypto_core_ristretto255_HASHBYTES} long bytes sequence'
) # pragma: no cover
r = _sodium.ffi.new('unsigned char[]', crypto_core_ristretto255_BYTES)
_sodium.lib.crypto_core_ristretto255_from_hash(r, h)
return _sodium.ffi.buffer(r, crypto_core_ristretto255_BYTES)[:]
[docs]def crypto_core_ristretto255_random():
"""
Returns a ristretto255 group element (point).
>>> p = crypto_core_ristretto255_random()
>>> crypto_core_ristretto255_is_valid_point(p)
True
:return: an integer represented as a
:py:data:`.crypto_core_ristretto255_BYTES` long bytes sequence
:rtype: bytes
"""
r = _sodium.ffi.new(
'unsigned char[]',
crypto_core_ristretto255_SCALARBYTES
)
_sodium.lib.crypto_core_ristretto255_random(r)
return _sodium.ffi.buffer(r, crypto_core_ristretto255_SCALARBYTES)[:]
[docs]def crypto_core_ristretto255_scalar_random(): # (unsigned char *r);
"""
Returns a :py:data:`.crypto_core_ristretto255_SCALARBYTES` byte long
representation of the scalar in the ``[0..L]`` interval, ``L`` being the
order of the group ``(2^252 + 27742317777372353535851937790883648493)``.
Example - All valid scalars have an 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
:return: an integer represented as a
:py:data:`.crypto_core_ristretto255_SCALARBYTES` long bytes sequence
:rtype: bytes
"""
r = _sodium.ffi.new(
'unsigned char[]',
crypto_core_ristretto255_SCALARBYTES
)
_sodium.lib.crypto_core_ristretto255_scalar_random(r)
return _sodium.ffi.buffer(r, crypto_core_ristretto255_SCALARBYTES)[:]
[docs]def crypto_core_ristretto255_scalar_invert(p):
"""
Return the multiplicative inverse of integer ``s`` modulo ``L``,
i.e an integer ``i`` such that ``s * i = 1 (mod L)``, where ``L``
is the order of the main subgroup.
Example - 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
Raises a ``RuntimeError`` if ``s`` is the integer zero.
:param s: a :py:data:`.crypto_core_ristretto255_SCALARBYTES`
long bytes sequence representing an integer
:type s: bytes
:return: an integer represented as a
:py:data:`.crypto_core_ristretto255_SCALARBYTES` long bytes sequence
:rtype: bytes
"""
if not isinstance(p, bytes) or len(
p) != crypto_core_ristretto255_SCALARBYTES:
raise TypeError(
f'Each integer must be a {crypto_core_ristretto255_SCALARBYTES} long bytes sequence'
) # pragma: no cover
r = _sodium.ffi.new(
'unsigned char[]',
crypto_core_ristretto255_SCALARBYTES
)
_sodium.lib.crypto_core_ristretto255_scalar_invert(r, p)
return _sodium.ffi.buffer(r, crypto_core_ristretto255_SCALARBYTES)[:]
[docs]def crypto_core_ristretto255_scalar_negate(p):
"""
Return the integer ``n`` such that ``s + n = 0 (mod L)``, where ``L``
is the order of the main subgroup.
Example - All scalars have an additive inverse:
>>> s = crypto_core_ristretto255_scalar_random()
>>> s_inv = crypto_core_ristretto255_scalar_negate(s)
>>> zero = crypto_core_ristretto255_scalar_add(s, s_inv)
>>> s == crypto_core_ristretto255_scalar_add(s, zero)
True
Example - Multiplication by zero is not defined in the subgroup {point * s | scalars s}:
>>> p = crypto_core_ristretto255_random()
>>> try:
... zero_p = crypto_scalarmult_ristretto255(zero, p)
... except RuntimeError as e:
... str(e) == '`n` cannot be larger than the size of ' + \
'the group or p^n is the identity element'
True
:param s: a :py:data:`.crypto_core_ristretto255_SCALARBYTES`
long bytes sequence representing an integer
:type s: bytes
:return: an integer represented as a
:py:data:`.crypto_core_ristretto255_SCALARBYTES` long bytes sequence
:rtype: bytes
"""
if not isinstance(p, bytes) or len(
p) != crypto_core_ristretto255_SCALARBYTES:
raise TypeError(
f'Each integer must be a {crypto_core_ristretto255_SCALARBYTES} long bytes sequence'
) # pragma: no cover
r = _sodium.ffi.new(
'unsigned char[]',
crypto_core_ristretto255_SCALARBYTES
)
_sodium.lib.crypto_core_ristretto255_scalar_negate(r, p)
return _sodium.ffi.buffer(r, crypto_core_ristretto255_SCALARBYTES)[:]
[docs]def crypto_core_ristretto255_scalar_complement(p):
"""
Return the complement of integer ``s`` modulo ``L``, i.e. an integer
``c`` such that ``s + c = 1 (mod L)``, where ``L`` is the order of
the main subgroup.
Example - All scalars have an additive complement:
>>> s = crypto_core_ristretto255_scalar_random()
>>> s_comp = crypto_core_ristretto255_scalar_complement(s)
>>> one = crypto_core_ristretto255_scalar_add(s, s_comp)
>>> p = crypto_core_ristretto255_random()
>>> p == crypto_scalarmult_ristretto255(one, p)
True
:param s: a :py:data:`.crypto_core_ristretto255_SCALARBYTES`
long bytes sequence representing an integer
:type s: bytes
:return: an integer represented as a
:py:data:`.crypto_core_ristretto255_SCALARBYTES` long bytes sequence
:rtype: bytes
"""
if not isinstance(p, bytes) or len(
p) != crypto_core_ristretto255_SCALARBYTES:
raise TypeError(
f'Each integer must be a {crypto_core_ristretto255_SCALARBYTES} long bytes sequence'
) # pragma: no cover
r = _sodium.ffi.new(
'unsigned char[]',
crypto_core_ristretto255_SCALARBYTES
)
_sodium.lib.crypto_core_ristretto255_scalar_complement(r, p)
return _sodium.ffi.buffer(r, crypto_core_ristretto255_SCALARBYTES)[:]
[docs]def crypto_core_ristretto255_scalar_add(p, q):
"""
Add integers ``p`` and ``q`` modulo ``L``, where ``L`` is the order of
the main subgroup.
Example - Addition of two 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
:param p: a :py:data:`.crypto_core_ristretto255_SCALARBYTES`
long bytes sequence representing an integer
:type p: bytes
:param q: a :py:data:`.crypto_core_ristretto255_SCALARBYTES`
long bytes sequence representing an integer
:type q: bytes
:return: an integer represented as a
:py:data:`.crypto_core_ristretto255_SCALARBYTES` long bytes sequence
:rtype: bytes
"""
if not isinstance(
p, bytes) or len(p) != crypto_core_ristretto255_SCALARBYTES or not isinstance(
q, bytes) or len(q) != crypto_core_ristretto255_SCALARBYTES:
raise TypeError(
f'Each integer must be a {crypto_core_ristretto255_SCALARBYTES} long bytes sequence'
) # pragma: no cover
r = _sodium.ffi.new(
'unsigned char[]',
crypto_core_ristretto255_SCALARBYTES
)
_sodium.lib.crypto_core_ristretto255_scalar_add(r, p, q)
return _sodium.ffi.buffer(r, crypto_core_ristretto255_SCALARBYTES)[:]
[docs]def crypto_core_ristretto255_scalar_sub(p, q):
"""
Subtract integers ``p`` and ``q`` modulo ``L``, where ``L`` is the
order of the main subgroup.
Example - Subtraction is the inverse of 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
:param p: a :py:data:`.crypto_core_ristretto255_SCALARBYTES`
long bytes sequence representing an integer
:type p: bytes
:param q: a :py:data:`.crypto_core_ristretto255_SCALARBYTES`
long bytes sequence representing an integer
:type q: bytes
:return: an integer represented as a
:py:data:`.crypto_core_ristretto255_SCALARBYTES` long bytes sequence
:rtype: bytes
"""
if not isinstance(
p, bytes) or len(p) != crypto_core_ristretto255_SCALARBYTES or not isinstance(
q, bytes) or len(q) != crypto_core_ristretto255_SCALARBYTES:
raise TypeError(
f'Each integer must be a {crypto_core_ristretto255_SCALARBYTES} long bytes sequence'
) # pragma: no cover
r = _sodium.ffi.new(
'unsigned char[]',
crypto_core_ristretto255_SCALARBYTES
)
_sodium.lib.crypto_core_ristretto255_scalar_sub(r, p, q)
return _sodium.ffi.buffer(r, crypto_core_ristretto255_SCALARBYTES)[:]
[docs]def crypto_core_ristretto255_scalar_mul(p, q):
"""
Multiply integers ``p`` and ``q`` modulo ``L``, where ``L`` is the
order of the main subgroup.
Example - 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
:param p: a :py:data:`.crypto_core_ristretto255_SCALARBYTES`
long bytes sequence representing an integer
:type p: bytes
:param q: a :py:data:`.crypto_core_ristretto255_SCALARBYTES`
long bytes sequence representing an integer
:type q: bytes
:return: an integer represented as a
:py:data:`.crypto_core_ristretto255_SCALARBYTES` long bytes sequence
:rtype: bytes
"""
if not isinstance(
p, bytes) or len(p) != crypto_core_ristretto255_SCALARBYTES or not isinstance(
q, bytes) or len(q) != crypto_core_ristretto255_SCALARBYTES:
raise TypeError(
f'Each integer must be a {crypto_core_ristretto255_SCALARBYTES} long bytes sequence'
) # pragma: no cover
r = _sodium.ffi.new(
'unsigned char[]',
crypto_core_ristretto255_SCALARBYTES
)
_sodium.lib.crypto_core_ristretto255_scalar_mul(r, p, q)
return _sodium.ffi.buffer(r, crypto_core_ristretto255_SCALARBYTES)[:]
[docs]def crypto_core_ristretto255_scalar_reduce(p):
"""
Reduce integer ``s`` to ``s`` modulo ``L``, where ``L`` is the order
of the main subgroup.
Example - Reduce a large value 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
:param s: a :py:data:`.crypto_core_ristretto255_NONREDUCEDSCALARBYTES`
long bytes sequence representing an integer
:type s: bytes
:return: an integer represented as a
:py:data:`.crypto_core_ristretto255_SCALARBYTES` long bytes sequence
:rtype: bytes
"""
if not isinstance(p, bytes) or len(
p) != crypto_core_ristretto255_SCALARBYTES:
raise TypeError(
f'Each integer must be a {crypto_core_ristretto255_SCALARBYTES} long bytes sequence'
) # pragma: no cover
r = _sodium.ffi.new(
'unsigned char[]',
crypto_core_ristretto255_SCALARBYTES
)
_sodium.lib.crypto_core_ristretto255_scalar_reduce(r, p)
return _sodium.ffi.buffer(r, crypto_core_ristretto255_SCALARBYTES)[:]
[docs]def crypto_scalarmult_ristretto255_base(n):
"""
Computes and returns the scalar product of a standard group element and an
integer ``n`` on the ristretto255 curve.
>>> s = crypto_core_ristretto255_scalar_random()
>>> gs = crypto_scalarmult_ristretto255_base(s)
>>> crypto_core_ristretto255_is_valid_point(gs)
True
:param n: a :py:data:`.crypto_scalarmult_ristretto255_SCALARBYTES` long bytes
sequence representing a scalar
:type n: bytes
:return: a point on the ristretto255 curve, represented as a
:py:data:`.crypto_scalarmult_ristretto255_BYTES` long bytes sequence
:rtype: bytes
"""
if not isinstance(n, bytes) or len(
n) != crypto_scalarmult_ristretto255_SCALARBYTES:
raise TypeError(
f'Input must be a {crypto_scalarmult_ristretto255_SCALARBYTES} long bytes sequence'
) # pragma: no cover
q = _sodium.ffi.new(
'unsigned char[]',
crypto_scalarmult_ristretto255_BYTES
)
if _sodium.lib.crypto_scalarmult_ristretto255_base(q, n) == -1:
raise RuntimeError(
'`n` cannot be larger than the size of the group or g^n is the identity element'
) # pragma: no cover
return _sodium.ffi.buffer(q, crypto_scalarmult_ristretto255_BYTES)[:]
[docs]def crypto_scalarmult_ristretto255_base_allow_scalar_zero(n):
"""
Computes and returns the scalar product of a standard group element and an
integer ``n`` on the ristretto255 curve. Zero-valued scalars are allowed.
>>> 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
:param n: a :py:data:`.crypto_scalarmult_ristretto255_SCALARBYTES` long bytes
sequence representing a scalar
:type n: bytes
:return: a point on the ristretto255 curve, represented as a
:py:data:`.crypto_scalarmult_ristretto255_BYTES` long bytes sequence
:rtype: bytes
"""
if not isinstance(n, bytes) or len(
n) != crypto_scalarmult_ristretto255_SCALARBYTES:
raise TypeError(
f'Input must be a {crypto_scalarmult_ristretto255_SCALARBYTES} long bytes sequence'
) # pragma: no cover
q = _sodium.ffi.new(
'unsigned char[]',
crypto_scalarmult_ristretto255_BYTES
)
# If ``-1``, then ``q`` remains cleared (``b'\0'*32``).
_sodium.lib.crypto_scalarmult_ristretto255_base(q, n)
return _sodium.ffi.buffer(q, crypto_scalarmult_ristretto255_BYTES)[:]
[docs]def crypto_scalarmult_ristretto255(n, p):
"""
Computes and returns the scalar product of a *clamped* integer ``n``
and the given group element on the ristretto255 curve.
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 setting
to one the bit in position 254.
Example - 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
:param n: a :py:data:`.crypto_scalarmult_ristretto255_SCALARBYTES` long bytes
sequence representing a scalar
:type n: bytes
:param p: a :py:data:`.crypto_scalarmult_ristretto255_BYTES` long bytes sequence
representing a point on the ristretto255 curve
:type p: bytes
:return: a point on the ristretto255 curve, represented as a
:py:data:`.crypto_scalarmult_ristretto255_BYTES` long bytes sequence
:rtype: bytes
"""
if not isinstance(n, bytes) or len(
n) != crypto_scalarmult_ristretto255_SCALARBYTES:
raise TypeError(
f'Input must be a {crypto_scalarmult_ristretto255_SCALARBYTES} long bytes sequence'
) # pragma: no cover
if not isinstance(p, bytes) or len(
p) != crypto_scalarmult_ristretto255_BYTES:
raise TypeError(
f'Input must be a {crypto_scalarmult_ristretto255_BYTES} long bytes sequence'
) # pragma: no cover
q = _sodium.ffi.new(
'unsigned char[]',
crypto_scalarmult_ristretto255_BYTES
)
if _sodium.lib.crypto_scalarmult_ristretto255(q, n, p) == -1:
raise RuntimeError(
'`n` cannot be larger than the size of the group or p^n is the identity element'
)
return _sodium.ffi.buffer(q, crypto_scalarmult_ristretto255_BYTES)[:]
[docs]@safe
def crypto_scalarmult_ristretto255_allow_scalar_zero(
n, p
): # pragma: no cover # The decorator recompiles this function body.
"""
Computes and returns the scalar product of a *clamped* integer ``n``
and the given group element on the ristretto255 curve.
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 setting
to one the bit in position 254. Zero-valued scalars are allowed.
Example - 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
Example - Multiplication by zero is allowed:
>>> zero_scalar, zero_point = bytes(32), bytes(32)
>>> crypto_scalarmult_ristretto255_allow_scalar_zero(zero_scalar, p) == zero_point
True
Example - The scalar being zero does not raise an error, but the point being invalid does:
>>> invalid_point = b'\1'*32
>>> crypto_scalarmult_ristretto255_allow_scalar_zero(zero_scalar, invalid_point)
Traceback (most recent call last):
...
TypeError: The second input must represent a valid Ristretto255 point
:param n: a :py:data:`.crypto_scalarmult_ristretto255_SCALARBYTES` long bytes
sequence representing a scalar
:type n: bytes
:param p: a :py:data:`.crypto_scalarmult_ristretto255_BYTES` long bytes sequence
representing a point on the ristretto255 curve
:type p: bytes
:return: a point on the ristretto255 curve, represented as a
:py:data:`.crypto_scalarmult_ristretto255_BYTES` long bytes sequence
:rtype: bytes
"""
if not isinstance(n, bytes) or len(n) != crypto_scalarmult_ristretto255_SCALARBYTES:
raise TypeError(
f'Input must be a {crypto_scalarmult_ristretto255_SCALARBYTES} long bytes sequence'
) # pragma: no cover
if not isinstance(p, bytes) or len(p) != crypto_scalarmult_ristretto255_BYTES:
raise TypeError(
f'Input must be a {crypto_scalarmult_ristretto255_BYTES} long bytes sequence'
) # pragma: no cover
safe # pylint: disable=pointless-statement # Marker for ``barriers`` decorator ``safe``.
if not crypto_core_ristretto255_is_valid_point(p):
raise TypeError('The second input must represent a valid Ristretto255 point')
q = _sodium.ffi.new(
'unsigned char[]',
crypto_scalarmult_ristretto255_BYTES
)
# If ``-1``, then ``q`` remains cleared (``b'\0'*32``).
_sodium.lib.crypto_scalarmult_ristretto255(q, n, p)
return _sodium.ffi.buffer(q, crypto_scalarmult_ristretto255_BYTES)[:]
[docs]def randombytes(size):
"""
Returns ``size`` number of random bytes from a cryptographically secure
random source.
>>> r1 = randombytes(14)
>>> r2 = randombytes(14)
>>> r1 == r2 # 2^42 chance of one-off event (i.e. equality)
False
:param size: int
:rtype: bytes
"""
buf = _sodium.ffi.new('unsigned char[]', size)
_sodium.lib.randombytes(buf, size)
return _sodium.ffi.buffer(buf, size)[:]
[docs]def randombytes_buf_deterministic(size, seed):
"""
Returns ``size`` number of deterministically generated pseudorandom bytes
from a seed
Example - Get the first 32 bytes from a stream seeded by 0x7070...70:
>>> r1 = randombytes_buf_deterministic(32, b'\x70'*32)
>>> r2 = randombytes_buf_deterministic(40, b'\x70'*32)
>>> r1 == r2[:32]
True
:param size: int
:param seed: bytes
:rtype: bytes
"""
if len(seed) != randombytes_SEEDBYTES:
raise TypeError( # pragma: no cover
'Deterministic random bytes must be generated from 32 bytes'
)
buf = _sodium.ffi.new('unsigned char[]', size)
_sodium.lib.randombytes_buf_deterministic(buf, size, seed)
return _sodium.ffi.buffer(buf, size)[:]
# Initializes sodium, picking the best implementations available for this
# machine.
def _sodium_init():
if _sodium.lib.sodium_init() == -1:
raise RuntimeError( # pragma: no cover
'libsodium error during initialization'
)
_sodium.ffi.init_once(_sodium_init, 'libsodium')
if __name__ == '__main__':
doctest.testmod() # pragma: no cover