ristretto module
This module exports the classes point
and
scalar
for representing points and scalars. It
also exports the two wrapper classes/namespaces
python
and sodium
that encapsulate pure-Python and shared/dynamic library variants of the
above (respectively) and also include low-level operations that correspond
more directly to the functions found in the underlying libraries.
Under all conditions, the wrapper class
python
is defined and encapsulates a pure-Python variant of every class exported by this module as a whole. It also includes pure-Python variants of low-level operations that correspond to functions found in the underlying libraries.If a shared/dynamic library instance of the libsodium library is found on the system (and successfully loaded at the time this module is imported) or the optional rbcl package is installed, then the wrapper class
sodium
is defined. Otherwise, the exported variablesodium
is assignedNone
.If a dynamic/shared library instance is loaded, all classes exported by this module correspond to the variants defined within
sodium
. Otherwise, they correspond to the variants defined withinpython
.
For most users, the classes point
and
scalar
should be sufficient. When using the
low-level operations that correspond to a specific implementation (e.g.,
oblivious.ristretto.sodium.add
), users are responsible for ensuring
that inputs have the type and/or representation appropriate for that
operation.
- class oblivious.ristretto.point(bs: Optional[bytes] = None)[source]
Bases:
bytes
Class for representing a point. Because this class is derived from
bytes
, it inherits methods such asbytes.hex
andbytes.fromhex
.>>> len(point.random()) 32 >>> p = point.hash('123'.encode()) >>> p.hex() '047f39a6c6dd156531a25fa605f017d4bec13b0b6c42f0e9b641c8ee73359c5f' >>> point.fromhex(p.hex()) == p True
- classmethod random() oblivious.ristretto.point [source]
Return random point object.
>>> len(point.random()) 32
- classmethod bytes(bs: bytes) oblivious.ristretto.point [source]
Return the point object obtained by transforming the supplied bytes-like object.
>>> p = point.bytes(hashlib.sha512('123'.encode()).digest()) >>> p.hex() '047f39a6c6dd156531a25fa605f017d4bec13b0b6c42f0e9b641c8ee73359c5f'
- classmethod hash(bs: bytes) oblivious.ristretto.point [source]
Return point object by hashing supplied bytes-like object.
>>> point.hash('123'.encode()).hex() '047f39a6c6dd156531a25fa605f017d4bec13b0b6c42f0e9b641c8ee73359c5f'
- classmethod base(s: oblivious.ristretto.scalar) Optional[oblivious.ristretto.point] [source]
Return base point multiplied by supplied scalar if the scalar is valid; otherwise, return
None
.>>> point.base(scalar.hash('123'.encode())).hex() '4c207a5377f3badf358914f20b505cd1e2a6396720a9c240e5aff522e2446005'
Use of the scalar corresponding to the zero residue is permitted.
>>> p = point() >>> point.base(scalar.from_int(0)) + p == p True
- classmethod from_bytes(bs: bytes) oblivious.ristretto.point [source]
Return the instance corresponding to the supplied bytes-like object.
>>> p = point.bytes(hashlib.sha512('123'.encode()).digest()) >>> p == point.from_bytes(p.to_bytes()) True
- classmethod from_base64(s: str) oblivious.ristretto.point [source]
Construct an instance from its Base64 UTF-8 string representation.
>>> point.from_base64('hoVaKq3oIlxEndP2Nqv3Rdbmiu4iinZE6Iwo+kcKAik=').hex() '86855a2aade8225c449dd3f636abf745d6e68aee228a7644e88c28fa470a0229'
- canonical() oblivious.ristretto.point [source]
Normalize the representation of this instance into its canonical form.
>>> p = point.hash('123'.encode()) >>> p.canonical() == p True
- __mul__(other: Any) NoReturn [source]
A point cannot be a left-hand argument for a multiplication operation.
>>> point() * scalar() Traceback (most recent call last): ... TypeError: point must be on right-hand side of multiplication operator
- __rmul__(other: Any) NoReturn [source]
This functionality is implemented exclusively in the method
scalar.__mul__
, as that method pre-empts this method when the second argument has the correct type (i.e., it is ascalar
instance). This method is included so that an exception can be raised if an incorrect argument is supplied.>>> p = point.hash('123'.encode()) >>> 2 * p Traceback (most recent call last): ... TypeError: point can only be multiplied by a scalar
- __add__(other: oblivious.ristretto.point) Optional[oblivious.ristretto.point] [source]
Return the sum of this instance and another point.
>>> p = point.hash('123'.encode()) >>> q = point.hash('456'.encode()) >>> (p + q).hex() '7076739c9df665d416e68b9512f5513bf1d0181a2aacefdeb1b7244528a4dd77' >>> p + (q - q) == p True
- __sub__(other: oblivious.ristretto.point) Optional[oblivious.ristretto.point] [source]
Return the result of subtracting another point from this instance.
>>> p = point.hash('123'.encode()) >>> q = point.hash('456'.encode()) >>> (p - q).hex() '1a3199ca7debfe31a90171696d8bab91b99eb23a541b822a7061b09776e1046c' >>> p - p == point.base(scalar.from_int(0)) True
- __neg__() oblivious.ristretto.point [source]
Return the negation of this instance.
>>> p = point.hash('123'.encode()) >>> q = point.hash('456'.encode()) >>> ((p + q) + (-q)) == p True
- class oblivious.ristretto.scalar(bs: Optional[bytes] = None)[source]
Bases:
bytes
Class for representing a scalar. Because this class is derived from
bytes
, it inherits methods such asbytes.hex
andbytes.fromhex
.>>> len(scalar.random()) 32 >>> s = scalar.hash('123'.encode()) >>> s.hex() 'a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27a03' >>> scalar.fromhex(s.hex()) == s True
- classmethod random() oblivious.ristretto.scalar [source]
Return random non-zero scalar object.
>>> len(scalar.random()) 32
- classmethod bytes(bs: bytes) Optional[oblivious.ristretto.scalar] [source]
Return scalar object obtained by transforming supplied bytes-like object if it is possible to do; otherwise, return
None
.>>> s = python.scl() >>> t = scalar.bytes(s) >>> s.hex() == t.hex() True
- classmethod hash(bs: bytes) oblivious.ristretto.scalar [source]
Return scalar object by hashing supplied bytes-like object.
>>> scalar.hash('123'.encode()).hex() 'a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27a03'
- classmethod from_int(i: int) oblivious.ristretto.scalar [source]
Construct an instance from its integer (i.e., residue) representation.
>>> p = point() >>> zero = scalar.from_int(0) >>> zero * p == p - p True >>> one = scalar.from_int(1) >>> one * p == p True >>> two = scalar.from_int(2) >>> two * p == p + p True
Negative integers are supported (and automatically converted into their corresponding least nonnegative residues).
>>> q = point() >>> p - p == scalar.from_int(0) * p True >>> q - p - p == q + (scalar.from_int(-2) * p) True
- classmethod from_bytes(bs: bytes) Optional[oblivious.ristretto.scalar] [source]
Return the instance corresponding to the supplied bytes-like object.
>>> s = python.scl() >>> t = scalar.from_bytes(s) >>> s.hex() == t.hex() True
- classmethod from_base64(s: str) oblivious.ristretto.scalar [source]
Construct an instance from its Base64 UTF-8 string representation.
>>> scalar.from_base64('MS0MkTD2kVO+yfXQOGqVE160XuvxMK9fH+0cbtFfJQA=').hex() '312d0c9130f69153bec9f5d0386a95135eb45eebf130af5f1fed1c6ed15f2500'
- __invert__() oblivious.ristretto.scalar [source]
Return the inverse of this instance (modulo
2**252 + 27742317777372353535851937790883648493
).>>> s = scalar() >>> p = point() >>> ((~s) * (s * p)) == p True
The scalar corresponding to the zero residue cannot be inverted.
>>> ~scalar.from_int(0) Traceback (most recent call last): ... ValueError: cannot invert scalar corresponding to zero
- __mul__(other: Union[oblivious.ristretto.scalar, oblivious.ristretto.point]) Union[oblivious.ristretto.scalar, oblivious.ristretto.point] [source]
Multiply the supplied scalar or point by this instance.
>>> p = point.hash('123'.encode()) >>> s = scalar.hash('456'.encode()) >>> (s * p).hex() 'f61b377aa86050aaa88c90f4a4a0f1e36b0000cf46f6a34232c2f1da7a799f16' >>> p = point.from_base64('hoVaKq3oIlxEndP2Nqv3Rdbmiu4iinZE6Iwo+kcKAik=') >>> s = scalar.from_base64('MS0MkTD2kVO+yfXQOGqVE160XuvxMK9fH+0cbtFfJQA=') >>> (s * s).hex() 'd4aecf034f60edc5cb32cdd5a4be6d069959aa9fd133c51c9dcfd960ee865e0f' >>> isinstance(s * s, scalar) True >>> (s * p).hex() '2208082412921a67f42ea399748190d2b889228372509f2f2d9929813d074e1b' >>> isinstance(s * p, point) True
Multiplying any point or scalar by the scalar corresponding to the zero residue yields the point or scalar corresponding to zero.
>>> scalar.from_int(0) * point() == p - p True >>> scalar.from_int(0) * scalar() == scalar.from_int(0) True
Any attempt to multiply a value or object of an incompatible type by this instance raises an exception.
>>> s * 2 Traceback (most recent call last): ... TypeError: multiplication by a scalar is defined only for scalars and points
- __rmul__(other: Union[oblivious.ristretto.scalar, oblivious.ristretto.point])[source]
A scalar cannot be on the right-hand side of a non-scalar.
>>> point() * scalar() Traceback (most recent call last): ... TypeError: point must be on right-hand side of multiplication operator
- to_bytes() bytes [source]
Return the bytes-like object that represents this instance.
>>> s = scalar() >>> s.to_bytes() == s True
- __int__() int [source]
Return the integer (i.e., least nonnegative residue) representation of this instance.
>>> s = scalar() >>> int(s * (~s)) 1
- class oblivious.ristretto.python[source]
Bases:
object
Wrapper class for pure-Python implementations of primitive operations.
This class encapsulates pure-Python variants of all low-level operations and of both classes exported by this module:
python.scl
,python.rnd
,python.inv
,python.smu
,python.pnt
,python.bas
,python.can
,python.mul
,python.add
,python.sub
,python.neg
,python.point
, andpython.scalar
. For example, you can perform addition of points using the pure-Python point addition implementation.>>> p = python.pnt() >>> q = python.pnt() >>> python.add(p, q) == python.add(q, p) True
Pure-Python variants of the
python.point
andpython.scalar
classes always employ pure-Python implementations of operations when their methods are invoked.>>> p = python.point() >>> q = python.point() >>> p + q == q + p True
Nevertheless, all bytes-like objects,
point
objects, andscalar
objects accepted and emitted by the various operations and class methods inpython
are compatible with those accepted and emitted by the operations and class methods insodium
.- static pnt(h: Optional[bytes] = None) bytes [source]
Return point from 64-byte vector (normally obtained via hashing).
>>> p = python.pnt(hashlib.sha512('123'.encode()).digest()) >>> p.hex() '047f39a6c6dd156531a25fa605f017d4bec13b0b6c42f0e9b641c8ee73359c5f'
- static bas(s: bytes) bytes [source]
Return base point multiplied by supplied scalar.
>>> python.bas(scalar.hash('123'.encode())).hex() '4c207a5377f3badf358914f20b505cd1e2a6396720a9c240e5aff522e2446005'
- static can(p: bytes) bytes [source]
Normalize the representation of a point into its canonical form.
>>> p = point.hash('123'.encode()) >>> python.can(p) == p True
- static mul(s: bytes, p: bytes) bytes [source]
Multiply the point by the supplied scalar and return the result.
>>> p = python.pnt(hashlib.sha512('123'.encode()).digest()) >>> s = python.scl(bytes.fromhex( ... '35c141f1c2c43543de9d188805a210abca3cd39a1e986304991ceded42b11709' ... )) >>> python.mul(s, p).hex() '183a06e0fe6af5d7913afb40baefc4dd52ae718fee77a3a0af8777c89fe16210'
- static add(p: bytes, q: bytes) bytes [source]
Return sum of the supplied points.
>>> p = point.hash('123'.encode()) >>> q = point.hash('456'.encode()) >>> python.add(p, q).hex() '7076739c9df665d416e68b9512f5513bf1d0181a2aacefdeb1b7244528a4dd77'
- static sub(p: bytes, q: bytes) bytes [source]
Return result of subtracting second point from first point.
>>> p = point.hash('123'.encode()) >>> q = point.hash('456'.encode()) >>> python.sub(p, q).hex() '1a3199ca7debfe31a90171696d8bab91b99eb23a541b822a7061b09776e1046c'
- static neg(p: bytes) bytes [source]
Return the additive inverse of a point.
>>> p = point.hash('123'.encode()) >>> q = point.hash('456'.encode()) >>> python.add(python.neg(p), python.add(p, q)) == q True
- classmethod scl(s: Optional[bytes] = None) Optional[bytes] [source]
Return supplied byte vector if it is a valid scalar; otherwise, return
None
. If no byte vector is supplied, return a random scalar.>>> s = python.scl() >>> t = python.scl(s) >>> s == t True >>> python.scl(bytes([255] * 32)) is None True
- static inv(s: bytes) bytes [source]
Return the inverse of a scalar (modulo
2**252 + 27742317777372353535851937790883648493
).>>> s = python.scl() >>> p = python.pnt() >>> python.mul(python.inv(s), python.mul(s, p)) == p True
- class oblivious.ristretto.sodium[source]
Bases:
object
Wrapper class for binary implementations of primitive operations.
When this module is imported, it makes a number of attempts to locate an instance of the shared/dynamic library file of the libsodium library on the host system. The sequence of attempts is listed below, in order.
1. It uses
ctypes.util.find_library
to look for'sodium'
or'libsodium'
.It attempts to find a file
libsodium.so
orlibsodium.dll
in the paths specified by thePATH
andLD_LIBRARY_PATH
environment variables.If the rbcl package is installed, it reverts to the compiled subset of libsodium included in that package.
If all of the above fail, then
sodium
is assigned the valueNone
and all classes exported by this module default to their pure-Python variants (i.e., those encapsulated withinpython
). To confirm that a dynamic/shared library has been found when this module is imported, evaluate the expressionsodium is not None
.If a shared/dynamic library file has been loaded successfully, this class encapsulates shared/dynamic library variants of both classes exported by this module and of all the underlying low-level operations:
sodium.scl
,sodium.rnd
,sodium.inv
,sodium.smu
,sodium.pnt
,sodium.bas
,sodium.can
,sodium.mul
,sodium.add
,sodium.sub
,sodium.neg
,sodium.point
, andsodium.scalar
. For example, you can perform addition of points using the point addition implementation found in the libsodium shared/dynamic library found on the host system.>>> p = sodium.pnt() >>> q = sodium.pnt() >>> sodium.add(p, q) == sodium.add(q, p) True
Methods found in the shared/dynamic library variants of the
point
andscalar
classes are wrappers for the shared/dynamic library implementations of the underlying operations.>>> p = sodium.point() >>> q = sodium.point() >>> p + q == q + p True
Nevertheless, all bytes-like objects,
point
objects, andscalar
objects accepted and emitted by the various operations and class methods insodium
are compatible with those accepted and emitted by the operations and class methods inpython
.- static pnt(h: Optional[bytes] = None) bytes [source]
Construct a point from its 64-byte vector representation (normally obtained via hashing).
>>> p = sodium.pnt(hashlib.sha512('123'.encode()).digest()) >>> p.hex() '047f39a6c6dd156531a25fa605f017d4bec13b0b6c42f0e9b641c8ee73359c5f'
- static bas(s: bytes) bytes [source]
Return the base point multiplied by the supplied scalar.
>>> sodium.bas(scalar.hash('123'.encode())).hex() '4c207a5377f3badf358914f20b505cd1e2a6396720a9c240e5aff522e2446005'
- static can(p: bytes) bytes [source]
Normalize the representation of a point into its canonical form.
>>> p = point.hash('123'.encode()) >>> sodium.can(p) == p True
- static mul(s: bytes, p: bytes) bytes [source]
Multiply a point by a scalar and return the result.
>>> p = sodium.pnt(hashlib.sha512('123'.encode()).digest()) >>> s = sodium.scl(bytes.fromhex( ... '35c141f1c2c43543de9d188805a210abca3cd39a1e986304991ceded42b11709' ... )) >>> sodium.mul(s, p).hex() '183a06e0fe6af5d7913afb40baefc4dd52ae718fee77a3a0af8777c89fe16210'
- static add(p: bytes, q: bytes) bytes [source]
Return the sum of the supplied points.
>>> p = point.hash('123'.encode()) >>> q = point.hash('456'.encode()) >>> sodium.add(p, q).hex() '7076739c9df665d416e68b9512f5513bf1d0181a2aacefdeb1b7244528a4dd77'
- static sub(p: bytes, q: bytes) bytes [source]
Return the result of subtracting the right-hand point from the left-hand point.
>>> p = point.hash('123'.encode()) >>> q = point.hash('456'.encode()) >>> sodium.sub(p, q).hex() '1a3199ca7debfe31a90171696d8bab91b99eb23a541b822a7061b09776e1046c'
- static neg(p: bytes) bytes [source]
Return the additive inverse of a point.
>>> p = point.hash('123'.encode()) >>> q = point.hash('456'.encode()) >>> sodium.add(sodium.neg(p), sodium.add(p, q)) == q True
- classmethod scl(s: Optional[bytes] = None) Optional[bytes] [source]
Return supplied byte vector if it is a valid scalar; otherwise, return
None
. If no byte vector is supplied, return a random scalar.>>> s = sodium.scl() >>> t = sodium.scl(s) >>> s == t True >>> sodium.scl(bytes([255] * 32)) is None True
- static inv(s: bytes) bytes [source]
Return the inverse of a scalar (modulo
2**252 + 27742317777372353535851937790883648493
).>>> s = sodium.scl() >>> p = sodium.pnt() >>> sodium.mul(sodium.inv(s), sodium.mul(s, p)) == p True