Source code for petrelic.multiplicative.pairing

r"""
This module provides a Python wrapper around RELIC's pairings using a
multiplicative interface: operations in
:py:obj:`petrelic.multiplicative.pairings.G1`,
:py:obj:`petrelic.multiplicative.pairings.G2`, and
:py:obj:`petrelic.multiplicative.pairings.GT` are all written
multiplicatively.

Let's see how we can use this interface to implement the Boney-Lynn-Shacham
signature scheme for type III pairings. First we generate a private key:

>>> sk = G1.order().random()

which is a random integer modulo the group order. Note that for this setting,
all three groups have the same order. Next, we generate the corresponding public
key:

>>> pk = (G1.generator() ** sk, G2.generator() ** sk)

(For security in the type III setting, the first component is a necessary part
of the public key. It is not actually used in the scheme.) To sign a message
`m` we first hash it to the curve G1 using :py:meth:`G1.hash_to_point` and then
raise it to the power of the signing key `sk` to obtain a signature:

>>> m = b"Some message"
>>> signature = G1.hash_to_point(m) ** sk

Finally, we can use the pairing operator to verify the signature:

>>> signature.pair(G2.generator()) == G1.hash_to_point(m).pair(pk[1])
True

Indeed, the pairing operator is bilinear. For example:

>>> a, b = 13, 29
>>> A = G1.generator() ** a
>>> B = G2.generator() ** b
>>> A.pair(B) == G1.generator().pair(G2.generator()) ** (a * b)
True

"""

from petrelic.bindings import _FFI, _C
from petrelic.bn import Bn, force_Bn_other
from petrelic.native.pairing import NoAffineCoordinateForECPoint

import petrelic.native.pairing as native


[docs]class BilinearGroupPair: """ A bilinear group pair. Contains two origin groups G1, G2 and the image group GT. """ def __init__(self): """Initialise a bilinear group pair.""" self.GT = GT() self.G1 = G1() self.G2 = G2()
[docs] def groups(self): """ Returns the three groups in the following order : G1, G2, GT. """ return self.G1, self.G2, self.GT
[docs]class G1(native._G1Base): """G1 group.""" @classmethod def _element_type(cls): return G1Element # # Replicated functions, fixing doc strings #
[docs] @classmethod def order(cls): """Return the order of the group as a Bn large integer. Example: >>> generator = G1.generator() >>> neutral = G1.neutral_element() >>> order = G1.order() >>> generator ** order == neutral True """ return super().order()
[docs] @classmethod def generator(cls): """Return generator of the group. Example: >>> generator = G1.generator() >>> neutral = G1.neutral_element() >>> generator * neutral == generator True """ return super().generator()
[docs] @classmethod def neutral_element(cls): """Return the neutral element of the group G1. In this case, the point at infinity. Example: >>> generator = G1.generator() >>> neutral = G1.neutral_element() >>> generator * neutral == generator True """ return super().neutral_element()
# # Interface specific methods #
[docs] @classmethod def prod(cls, elems): """Efficient product of a number of elements In the current implementation this function is not optimized. Example: >>> elems = [ G1.generator() ** x for x in [10, 25, 13]] >>> G1.prod(elems) == G1.generator() ** (10 + 25 + 13) True """ res = cls.neutral_element() for el in elems: res *= el return res
[docs] @classmethod def wprod(cls, weights, elems): """Efficient weighted product of a number of elements In the current implementation this function is not optimized. Example: >>> weights = [1, 2, 3] >>> elems = [ G1.generator() ** x for x in [10, 25, 13]] >>> G1.wprod(weights, elems) == G1.generator() ** (1 * 10 + 2 * 25 + 3 * 13) True """ res = cls.neutral_element() for w, el in zip(weights, elems): res *= el ** w return res
# # Aliases #
[docs] @classmethod def unity(cls): """The unity element Alias for :py:meth:`G1.neutral_element` """ return cls.neutral_element()
[docs]class G1Element(native._G1ElementBase): """Element of the G1 group.""" group = G1
[docs] def pair(self, other): """Pair element with another element in G2 Computes the bilinear pairing between self and another element in :py:obj:`petrelic.multiplicative.pairing.G2`. Examples: >>> g1, g2 = G1.generator(), G2.generator() >>> a, b = 10, 50 >>> A, B = g1 ** a, g2 ** b >>> A.pair(B) == g1.pair(g2) ** (a * b) True >>> A.pair(g2) == g1.pair(g2 ** a) True >>> A.pair(g2) == g1.pair(g2) ** a True """ if not type(other) == G2Element: raise TypeError("Second parameter should be of type G2Element is {}".format(type(other))) res = GTElement() _C.pc_map(res.pt, self.pt, other.pt) return res
# # Unary operators #
[docs] def square(self): return native.G1Element.double(self)
[docs] def isquare(self): return native.G1Element.idouble(self)
# # Binary operators # def __mul__(self, other): return native.G1Element.__add__(self, other) def __imul__(self, other): return native.G1Element.__iadd__(self, other) def __truediv__(self, other): return native.G1Element.__sub__(self, other) def __itruediv__(self, other): return native.G1Element.__isub__(self, other) def __pow__(self, other): return native.G1Element.__mul__(self, other) def __ipow__(self, other): return native.G1Element.__imul__(self, other) # Copy documentation from native.GTElement square.__doc__ = native.GTElement.square.__doc__.replace("GT", "G1") isquare.__doc__ = native.GTElement.isquare.__doc__.replace("GT", "G1") __mul__.__doc__ = native.GTElement.__mul__.__doc__.replace("GT", "G1") __imul__.__doc__ = native.GTElement.__imul__.__doc__.replace("GT", "G1") __truediv__.__doc__ = native.GTElement.__truediv__.__doc__.replace("GT", "G1") __itruediv__.__doc__ = native.GTElement.__itruediv__.__doc__.replace("GT", "G1") __pow__.__doc__ = native.GTElement.__pow__.__doc__.replace("GT", "G1") __ipow__.__doc__ = native.GTElement.__ipow__.__doc__.replace("GT", "G1") # # Aliases # mul = __mul__ imul = __imul__ div = __truediv__ idiv = __itruediv__ __floordiv__ = __truediv__ __ifloordiv__ = __itruediv__ pow = __pow__ ipow = __ipow__
[docs]class G2(native._G2Base): @classmethod def _element_type(cls): return G2Element
[docs] @classmethod def prod(cls, elems): """Efficient product of a number of elements In the current implementation this function is not optimized. Example: >>> elems = [ G2.generator() ** x for x in [10, 25, 13]] >>> G2.prod(elems) == G2.generator() ** (10 + 25 + 13) True """ res = cls.neutral_element() for el in elems: res *= el return res
[docs] @classmethod def wprod(cls, weights, elems): """Efficient weighted product of a number of elements In the current implementation this function is not optimized. Example: >>> weights = [1, 2, 3] >>> elems = [ G2.generator() ** x for x in [10, 25, 13]] >>> G2.wprod(weights, elems) == G2.generator() ** (1 * 10 + 2 * 25 + 3 * 13) True """ res = cls.neutral_element() for w, el in zip(weights, elems): res *= el ** w return res
# # Aliases #
[docs] @classmethod def unity(cls): """The unity element Alias for :py:meth:`G2.neutral_element` """ return cls.neutral_element()
[docs]class G2Element(native._G2ElementBase): """Element of the G2 group.""" group = G2 # # Unary operators #
[docs] def square(self): return native.G2Element.double(self)
[docs] def isquare(self): return native.G2Element.idouble(self)
# # Binary operators # def __mul__(self, other): return native.G2Element.__add__(self, other) def __imul__(self, other): return native.G2Element.__iadd__(self, other) def __truediv__(self, other): return native.G2Element.__sub__(self, other) def __itruediv__(self, other): return native.G2Element.__isub__(self, other) def __pow__(self, other): return native.G2Element.__mul__(self, other) def __ipow__(self, other): return native.G2Element.__imul__(self, other) # Copy documentation from native.GTElement square.__doc__ = native.GTElement.square.__doc__.replace("GT", "G2") isquare.__doc__ = native.GTElement.isquare.__doc__.replace("GT", "G2") __mul__.__doc__ = native.GTElement.__mul__.__doc__.replace("GT", "G2") __imul__.__doc__ = native.GTElement.__imul__.__doc__.replace("GT", "G2") __truediv__.__doc__ = native.GTElement.__truediv__.__doc__.replace("GT", "G2") __itruediv__.__doc__ = native.GTElement.__itruediv__.__doc__.replace("GT", "G2") __pow__.__doc__ = native.GTElement.__pow__.__doc__.replace("GT", "G2") __ipow__.__doc__ = native.GTElement.__ipow__.__doc__.replace("GT", "G2") # # Aliases # mul = __mul__ imul = __imul__ div = __truediv__ idiv = __itruediv__ __floordiv__ = __truediv__ __ifloordiv__ = __itruediv__ pow = __pow__ ipow = __ipow__
[docs]class GT(native.GT): """GT group.""" @classmethod def _element_type(cls): return GTElement
[docs]class GTElement(native.GTElement): """GT element.""" group = GT