Source code for pymavryk.michelson.types.bls

from typing import cast

from py_ecc import optimized_bls12_381 as bls12_381
from py_ecc.bls.constants import POW_2_382
from py_ecc.bls.typing import G1Uncompressed
from py_ecc.bls.typing import G2Uncompressed
from py_ecc.fields import optimized_bls12_381_FQ as FQ
from py_ecc.fields import optimized_bls12_381_FQ2 as FQ2

from pymavryk.michelson.micheline import parse_micheline_literal
from pymavryk.michelson.types.core import BytesType
from pymavryk.michelson.types.core import IntType


[docs]class BLS12_381_FrType(IntType, prim='bls12_381_fr'): modulus = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001 def __init__(self, value: int): super(BLS12_381_FrType, self).__init__() self.value = value
[docs] @staticmethod def bytes_to_int(value: bytes) -> int: assert len(value) <= 32, f'expected no more than 32 bytes, got {len(value)}' return int.from_bytes(value, 'little')
[docs] @classmethod def from_value(cls, value: int) -> 'BLS12_381_FrType': return cls(value % cls.modulus)
[docs] @classmethod def from_python_object(cls, py_obj) -> 'BLS12_381_FrType': if isinstance(py_obj, int): value = py_obj elif isinstance(py_obj, bytes): value = cls.bytes_to_int(py_obj) elif isinstance(py_obj, str): if py_obj.startswith('0x'): py_obj = py_obj[2:] value = cls.bytes_to_int(bytes.fromhex(py_obj)) else: raise AssertionError(f'unexpected value {py_obj}') return cls.from_value(value)
[docs] @classmethod def from_micheline_value(cls, val_expr) -> 'IntType': value = parse_micheline_literal( val_expr, { 'int': int, 'bytes': lambda x: cls.bytes_to_int(bytes.fromhex(x)), }, ) return cls.from_value(value)
[docs] def to_micheline_value(self, mode='readable', lazy_diff=False): if mode == 'readable': return {'int': str(self.value)} else: return {'bytes': self.value.to_bytes(32, 'little').hex()}
[docs] def to_python_object(self, try_unpack=False, lazy_diff=False, comparable=False): assert not comparable, f'{self.prim} is not comparable' return super(BLS12_381_FrType, self).to_python_object()
[docs]class BLS12_381_G1Type(BytesType, prim='bls12_381_g1'):
[docs] @classmethod def from_value(cls, value: bytes): assert len(value) == 96, f'expected 98 bytes, got {len(value)}' return cls(value)
[docs] @classmethod def from_point(cls, point: G1Uncompressed) -> 'BLS12_381_G1Type': if bls12_381.is_inf(point): x, y = POW_2_382, 0 else: x_pt, y_pt = bls12_381.normalize(point) x, y = x_pt.n, y_pt.n value = x.to_bytes(48, 'big') + y.to_bytes(48, 'big') return cls.from_value(value)
[docs] def to_point(self) -> G1Uncompressed: x = int.from_bytes(self.value[:48], 'big') y = int.from_bytes(self.value[48:], 'big') point = FQ(x), FQ(y), FQ(1) return cast(G1Uncompressed, point)
[docs] def to_python_object(self, try_unpack=False, lazy_diff=False, comparable=False): assert not comparable, f'{self.prim} is not comparable' return super(BLS12_381_G1Type, self).to_python_object()
[docs]class BLS12_381_G2Type(BytesType, prim='bls12_381_g2'):
[docs] @classmethod def from_value(cls, value: bytes): assert len(value) == 192, f'expected 98 bytes, got {len(value)}' return cls(value)
[docs] @classmethod def from_point(cls, point: G2Uncompressed) -> 'BLS12_381_G2Type': if bls12_381.is_inf(point): x_re, x_im, y_re, y_im = 0, POW_2_382, 0, 0 else: x, y = bls12_381.normalize(point) x_re, x_im = x.coeffs y_re, y_im = y.coeffs value = ( x_im.to_bytes(48, 'big') + x_re.to_bytes(48, 'big') + y_im.to_bytes(48, 'big') + y_re.to_bytes(48, 'big') ) return cls(value)
[docs] def to_point(self) -> G2Uncompressed: x_im = int.from_bytes(self.value[:48], 'big') x_re = int.from_bytes(self.value[48:96], 'big') y_im = int.from_bytes(self.value[96:144], 'big') y_re = int.from_bytes(self.value[144:192], 'big') point = FQ2([x_re, x_im]), FQ2([y_re, y_im]), FQ2([1, 0]) return cast(G2Uncompressed, point)
[docs] def to_python_object(self, try_unpack=False, lazy_diff=False, comparable=False): assert not comparable, f'{self.prim} is not comparable' return super(BLS12_381_G2Type, self).to_python_object()