Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switches hash-to-field to new v06 hash system #87

Merged
merged 12 commits into from
May 5, 2020
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pip install py_ecc

## BLS Signatures

`py_ecc` implements the [IETF BLS draft standard v0](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-00) with [hash-to-curve v5](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05) as per the inter-blockchain standardization agreement. The BLS standards specify [different ciphersuites](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-00#section-4.2) which each have different functionality to accommodate various use cases. The following ciphersuites are availible from this library:
`py_ecc` implements the [IETF BLS draft standard v0](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-00) with [hash-to-curve v6](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06) as per the inter-blockchain standardization agreement. The BLS standards specify [different ciphersuites](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-00#section-4.2) which each have different functionality to accommodate various use cases. The following ciphersuites are availible from this library:

- `G2Basic` also known as `BLS_SIG_BLS12381G2-SHA256-SSWU-RO-_NUL_`
- `G2MessageAugmentation` also known as `BLS_SIG_BLS12381G2-SHA256-SSWU-RO-_AUG_`
Expand Down
21 changes: 12 additions & 9 deletions py_ecc/bls/ciphersuites.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
big_endian_to_int,
ValidationError,
)
from hashlib import sha256

from py_ecc.fields import optimized_bls12_381_FQ12 as FQ12
from py_ecc.optimized_bls12_381 import (
Expand Down Expand Up @@ -44,6 +45,7 @@

class BaseG2Ciphersuite(abc.ABC):
DST = b''
xmd_hash_function = sha256

@staticmethod
def PrivToPub(privkey: int) -> BLSPubkey:
Expand All @@ -65,14 +67,15 @@ def KeyValidate(PK: BLSPubkey) -> bool:
return False
return True

@staticmethod
def _CoreSign(SK: int, message: bytes, DST: bytes) -> BLSSignature:
message_point = hash_to_G2(message, DST)
@classmethod
def _CoreSign(cls, SK: int, message: bytes, DST: bytes) -> BLSSignature:
message_point = hash_to_G2(message, DST, cls.xmd_hash_function)
signature_point = multiply(message_point, SK)
return G2_to_signature(signature_point)

@staticmethod
def _CoreVerify(PK: BLSPubkey, message: bytes, signature: BLSSignature, DST: bytes) -> bool:
@classmethod
def _CoreVerify(cls, PK: BLSPubkey, message: bytes,
signature: BLSSignature, DST: bytes) -> bool:
try:
signature_point = signature_to_G2(signature)
final_exponentiation = final_exponentiate(
Expand All @@ -81,7 +84,7 @@ def _CoreVerify(PK: BLSPubkey, message: bytes, signature: BLSSignature, DST: byt
G1,
final_exponentiate=False,
) * pairing(
hash_to_G2(message, DST),
hash_to_G2(message, DST, cls.xmd_hash_function),
neg(pubkey_to_G1(PK)),
final_exponentiate=False,
)
Expand All @@ -98,15 +101,15 @@ def Aggregate(signatures: Sequence[BLSSignature]) -> BLSSignature:
accumulator = add(accumulator, signature_point)
return G2_to_signature(accumulator)

@staticmethod
def _CoreAggregateVerify(pairs: Sequence[Tuple[BLSPubkey, bytes]],
@classmethod
def _CoreAggregateVerify(cls, pairs: Sequence[Tuple[BLSPubkey, bytes]],
signature: BLSSignature, DST: bytes) -> bool:
try:
signature_point = signature_to_G2(signature)
accumulator = FQ12.one()
for pk, message in pairs:
pubkey_point = pubkey_to_G1(pk)
message_point = hash_to_G2(message, DST)
message_point = hash_to_G2(message, DST, cls.xmd_hash_function)
accumulator *= pairing(message_point, pubkey_point, final_exponentiate=False)
accumulator *= pairing(signature_point, neg(G1), final_exponentiate=False)
return final_exponentiate(accumulator) == FQ12.one()
Expand Down
8 changes: 7 additions & 1 deletion py_ecc/bls/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,10 @@
POW_2_382 = 2**382
POW_2_383 = 2**383

HASH_TO_G2_L = 64

# Store all the possible single bytes for faster access in hash-to-field
ALL_BYTES = tuple(bytes([i]) for i in range(256))

# Paramaters for hashing to the field as specified in:
# https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-8.7
HASH_TO_FIELD_L = 64
40 changes: 35 additions & 5 deletions py_ecc/bls/hash.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import math
import hashlib
import hmac
from typing import Union
import math
from typing import (
Union,
)
from hashlib import sha256
from _hashlib import HASH

from .constants import (
ALL_BYTES,
)


def hkdf_extract(salt: Union[bytes, bytearray], ikm: Union[bytes, bytearray]) -> bytes:
Expand All @@ -10,7 +17,7 @@ def hkdf_extract(salt: Union[bytes, bytearray], ikm: Union[bytes, bytearray]) ->
https://tools.ietf.org/html/rfc5869
"""
return hmac.new(salt, ikm, hashlib.sha256).digest()
return hmac.new(salt, ikm, sha256).digest()


def hkdf_expand(prk: Union[bytes, bytearray], info: Union[bytes, bytearray], length: int) -> bytes:
Expand All @@ -30,8 +37,31 @@ def hkdf_expand(prk: Union[bytes, bytearray], info: Union[bytes, bytearray], len
text = previous + info + bytes([i + 1])

# T(i + 1) = HMAC(T(i) || info || i)
previous = bytearray(hmac.new(prk, text, hashlib.sha256).digest())
previous = bytearray(hmac.new(prk, text, sha256).digest())
okm.extend(previous)

# Return first `length` bytes.
return okm[:length]


def xor(a: bytes, b: bytes) -> bytes:
return bytes(_a ^ _b for _a, _b in zip(a, b))
CarlBeek marked this conversation as resolved.
Show resolved Hide resolved


def expand_message_xmd(msg: bytes, DST: bytes, len_in_bytes: int, hash_function: HASH) -> bytes:
b_in_bytes = hash_function().digest_size
r_in_bytes = hash_function().block_size
if len(DST) > 255:
raise ValueError('DST must be <= 255 bytes')
ell = math.ceil(len_in_bytes / b_in_bytes)
if ell > 255:
raise ValueError('invalid len in bytes for hash function')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to include both the value of ell and the limit value in this message.

DST_prime = ALL_BYTES[len(DST)] + DST # Prepend the length if the DST as a single byte
Z_pad = b'\x00' * r_in_bytes
l_i_b_str = len_in_bytes.to_bytes(2, 'big')
b_0 = hash_function(Z_pad + msg + l_i_b_str + b'\x00' + DST_prime).digest()
b = [hash_function(b_0 + b'\x01' + DST_prime).digest()]
for i in range(2, ell + 1):
b.append(hash_function(xor(b_0, b[i - 2]) + ALL_BYTES[i] + DST_prime).digest())
pseudo_random_bytes = b''.join(b)
return pseudo_random_bytes[:len_in_bytes]
65 changes: 33 additions & 32 deletions py_ecc/bls/hash_to_curve.py
Original file line number Diff line number Diff line change
@@ -1,74 +1,75 @@
from eth_utils import (
big_endian_to_int,
from typing import (
Tuple,
)
from _hashlib import HASH

from py_ecc.fields import (
optimized_bls12_381_FQ2 as FQ2,
)
from py_ecc.optimized_bls12_381 import (
add,
iso_map_G2,
field_modulus,
multiply_clear_cofactor_G2,
optimized_swu_G2,
)

from .constants import HASH_TO_G2_L
from .typing import (
G2Uncompressed,
)
from .hash import (
hkdf_expand,
hkdf_extract,
)
from .constants import HASH_TO_FIELD_L
from .hash import expand_message_xmd
from .typing import G2Uncompressed


# Hash to G2
def hash_to_G2(message: bytes, DST: bytes) -> G2Uncompressed:
def hash_to_G2(message: bytes, DST: bytes,
hash_function: HASH) -> G2Uncompressed:
"""
Convert a message to a point on G2 as defined here:
https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-3
https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-6.6.3
The idea is to first hash into FQ2 and then use SSWU to map the result into G2.
Contants and inputs follow the ciphersuite ``BLS12381G2-SHA256-SSWU-RO-`` defined here:
https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-8.9.2
Contants and inputs follow the ciphersuite ``BLS12381G2_XMD:SHA-256_SSWU_RO_`` defined here:
https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-8.7.2
"""
u0 = hash_to_base_FQ2(message, 0, DST)
u1 = hash_to_base_FQ2(message, 1, DST)
u0, u1 = hash_to_field_FQ2(message, 2, DST, hash_function)
q0 = map_to_curve_G2(u0)
q1 = map_to_curve_G2(u1)
r = add(q0, q1)
p = clear_cofactor_G2(r)
return p


def hash_to_base_FQ2(message: bytes, ctr: int, DST: bytes) -> FQ2:
def hash_to_field_FQ2(message: bytes, count: int,
DST: bytes, hash_function: HASH) -> Tuple[FQ2, ...]:
"""
Hash To Base for FQ2
Hash To Base Field for FQ2
Convert a message to a point in the finite field as defined here:
https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-5
https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.2
"""
m_prime = hkdf_extract(DST, message + b'\x00')
info_pfx = b'H2C' + bytes([ctr])
e = []

# for i in (1, ..., m), where m is the extension degree of FQ2
for i in range(1, 3):
info = info_pfx + bytes([i])
t = hkdf_expand(m_prime, info, HASH_TO_G2_L)
e.append(big_endian_to_int(t))

return FQ2(e)
M = 2 # m is the extension degree of FQ2
len_in_bytes = count * M * HASH_TO_FIELD_L
pseudo_random_bytes = expand_message_xmd(message, DST, len_in_bytes, hash_function)
u = []
for i in range(0, count):
e = []
for j in range(0, M):
elem_offset = HASH_TO_FIELD_L * (j + i * M)
tv = pseudo_random_bytes[elem_offset: elem_offset + HASH_TO_FIELD_L]
e.append(int.from_bytes(tv, 'big') % field_modulus)
u.append(FQ2(e))
return tuple(u)


def map_to_curve_G2(u: FQ2) -> G2Uncompressed:
"""
Map To Curve for G2
First, convert FQ2 point to a point on the 3-Isogeny curve.
SWU Map: https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-6.6.2
SWU Map: https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-6.6.3
Second, map 3-Isogeny curve to BLS12-381-G2 curve.
3-Isogeny Map: https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#appendix-C.3
3-Isogeny Map: https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#appendix-C.3
"""
(x, y, z) = optimized_swu_G2(u)
return iso_map_G2(x, y, z)
Expand Down
4 changes: 2 additions & 2 deletions py_ecc/fields/optimized_field_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ def sgn0_be(self: T_FQ) -> int:
sgn0_be(x) = -1 when x > -x
Defined here:
https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-4.1.1
https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-4.1.1
"""
if self.n == 0:
return 1
Expand Down Expand Up @@ -384,7 +384,7 @@ def sgn0_be(self: T_FQP) -> int:
sgn0_be(x) = -1 when x > -x
Defined here:
https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-4.1.1
https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-4.1.1
"""
sign = 0
for x_i in reversed(self.coeffs):
Expand Down
2 changes: 1 addition & 1 deletion py_ecc/optimized_bls12_381/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,5 @@

ISO_3_MAP_COEFFICIENTS = (ISO_3_X_NUMERATOR, ISO_3_X_DENOMINATOR, ISO_3_Y_NUMERATOR, ISO_3_Y_DENOMINATOR) # noqa: E501

# h_eff from https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-8.9.2
# h_eff from https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-8.7.2
H_EFF = 209869847837335686905080341498658477663839067235703451875306851526599783796572738804459333109033834234622528588876978987822447936461846631641690358257586228683615991308971558879306463436166481 # noqa: E501
41 changes: 17 additions & 24 deletions tests/bls/test_hash_to_curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
big_endian_to_int,
)
import pytest
from hashlib import sha256

from py_ecc.bls.hash_to_curve import hash_to_G2
from py_ecc.bls.constants import (
Expand All @@ -31,7 +32,7 @@
iso_map_G2,
)

DST = b'BLS_SIG_BLS12381G2-SHA256-SSWU-RO_POP_' # TODO: Switch out test for valid DST
DST = b'BLS12381G2_XMD:SHA-256_SSWU_RO_TESTGEN'


@pytest.mark.parametrize(
Expand Down Expand Up @@ -59,35 +60,27 @@ def test_iso_map_G2(iso_x, iso_y, iso_z, g2_x, g2_y):
assert g2_y == result_y


# Tests taken from: https://github.com/cfrg/draft-irtf-cfrg-hash-to-curve/blob/master/draft-irtf-cfrg-hash-to-curve.md#bls12381g2_xmdsha-256_sswu_ro_
@pytest.mark.parametrize('H', [sha256])
@pytest.mark.parametrize(
'msg,x,y',
[
(b'msg',
FQ2([int('7896efdac56b0f6cbd8c78841676d63fc733b692628687bf25273aa8a107bd8cb53bbdb705b551e239dffe019abd4df', 16), int('bd557eda8d16ab2cb2e71cca4d7b343985064daad04734e07da5cdda26610b59cdc0810a25276467d24b315bf7860e0', 16)]),
FQ2([int('1bdb6290cae9f30f263dd40f014b9f4406c3fbbc5fea47e2ebd45e42332553961eb53a15c09e5e090d7a7122dc6657', 16), int('18370459c44e799af8ef31634a683e340e79c3a06f912594d287a443620933b47a2a3e5ce4470539eae50f6d49b8ebd6', 16)])),
(b'01234567890123456789012345678901',
FQ2([int('16b7456df1dfa411b8be80c503864b0795b0b9a7674c05c00e7bdee5a75cbdeec633e16a104406ea626ea6845f5d19b5', 16), int('12ae54eeb3b4dc113d7e80302e51456224087955910479929bf912d89177aa050376960002a96fc6541ac041957f4b93', 16)]),
FQ2([int('1632fe9d91a984f30a7d9b3bab6583974a2ca55933d96cba85f39ddd61ea0129274f75ad7de29473adf3db676dcdb6a3', 16), int('8d5d3b670fca3661122b0ca5929e48f293a5a5c1261050c46b6a08eac3f7d1f5075e2139a63f98e717ecc7c2e00d042', 16)])),
(b'',
FQ2([int('c38e18c9ca92ad387cbfa0e9bd62e53e4f938006097a092d5e9f2c6f3963d78969e7631bf8d6a8a9aad36bc82d763c1', 16), int('23ebc431b239ee7606aad7cd4eee60bb70df3e5072ede86946ffaddb0584e1fcfcee9484869f41e09ab4d64b9e4a72a', 16)]),
FQ2([int('735ae5ca4a2320d820e15501ee79c42ff58a6f40e8549eada554e07c94b34b6634b6034f8735a7e4ac01db81b00f58e', 16), int('1687b6a2fb9e542426d508d4a58846c0e3496ede2e12f57f3358110874ba0011e2107e0742eeb6707682d5ddf319b6f6', 16)])),
(b'abcdefghijklmnopqrstuvwxyz',
FQ2([int('db85d0c792c586c6efb4126e98a8a8788d28187a6432cbdd57444a8c937ce20e0fc0774477150d31bfff83a050b530e', 16), int('13505f5cbb1503c7b1206edd31364a467f5159d741cffe8f443f2282b4adfcf5f1450bd2fe6127991ff60955b3b40015', 16)]),
FQ2([int('1738e4903e5618fcba965861c73d7c7a7544fabc9762ccdf9842dbba30566ce33047c3ff714ce8a10323bcac0ee88479', 16), int('d0df337706a8b4c367ea189d9e213f47455399ddf734358695e84ad09630a724082ad22dda74e6cd41378dbb89b0ebd', 16)])),
(b'\xff' * 100,
FQ2([int('a2b9bb7afda6e1c3cb2340aa679ce00469a14c651becd30fa231c83ab82d1b92db074058c3673daaaa2a113f0c3ea56', 16), int('e7fcdf25cf4465f58de593bf6445ec1cd164de346a27ed46314dcbb35a830650f5bb4d8049878d9a84a34013fa4fb11', 16)]),
FQ2([int('14f909c9fb9fb14c0e7455ed5306edaad40e7c57cdd719f59730db6ae64161db1f1a8159db4d97700fba7547920fe1a2', 16), int('1702a797d33e0c7b3fac012da0ef1960e0f4551f23ffee3e12dc36ac4acdd6d78bee97bad76689b8e70dac80449a626c', 16)])),
(b'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
FQ2([int('7e2b8b61562339640addfda3202f5d657aa77c143bf5bceda818525ba6f984eba2648528928d6c9680f752dd88d91e3', 16), int('1663cd7231bd9708bebe0be61baecf2b89ebaa658150696f5be2dbe0e092ec698c931e8795ac6319f1c5fdda5d14136a', 16)]),
FQ2([int('33d40a6eb88c11c6018fcc00489bc4b9dd700c20d1bab21ad463c5ee63ce671d199020ba743828d450da050f0385680', 16), int('10336a533d1e3564da20bffe87ebc82121cfbfad2e36ecb950c5e12d8552bf932f5f5e846a50e9706b21b0db6585a777', 16)])),
(b'e46b320165eec91e6344fa10340d5b3208304d6cad29d0d5aed18466d1d9d80e',
FQ2([int('119a71e0d20489cf8c5f82c51e879e7b344e53307b53be650df7f3f04907b75b71fdafe26e8d4e14e603440b09efe6f3', 16), int('e4ea193377da29537e8fe6f6f631adff10afaef2ea1eb2107d30d97358c1a19975e0a8bb62650ff90447cf5b3719c1d', 16)]),
FQ2([int('1142f2e077cc4230ee3cf07565ee626141ea9b86a79a0422d7f0e84c281ca09c5bbbe95f21e51285618c81d6dfda943d', 16), int('15e4da056552343eb519b3087962521d112c7e307d731373e8f1c72415306ccbc3c14fc6d68d61d2feeda3ea2e7729f', 16)])),
FQ2([0x0d3b02ee071b12d1e79138c3900ca3da7b8021ac462fe6ed68080dc9a5f1c5de46b7fe171e8b3e4e7537e7746757aeca, 0x0d4733459fead6a1f30e5f92df08ecfd0db9bcd0f3e2f2de0f00c8f45e081420aa4392eade61eade57d7a68474672fc1]),
FQ2([0x09cc6f7b3074f0c82510e65d8fc58f6033e03ba7358005a13e2bbd7f429b080f29731ef08c3780c9e3c746578b96b05c, 0x0011531b8e08900a4f6f612e1e27432961419ce6a5ee3ec904a53588982d36ec4ea37be80b6cb7d986b38faec67dbe44])),
(b'abc',
FQ2([0x0b6d276d0bfbddde617a9ab4c175b07c9c4aecad2cdd6cc9ca541b61334a69c58680ef5692bbad03d2f572838df32b66, 0x139e9d78ff6d9d163f979d14a64c5e57f82f1ef7e42ece338b571a9e92c0666f0f6bf1a5fc21e2d32bcb6432eab7037c]),
FQ2([0x022f9ee5d596d06c5f2f735c3c5f743978f79fd57bf7d4291e221227f490d3f276066de9f9edc89c57e048ef4cf0ef72, 0x14dd23517516a80d1d840e34f51dfb76946c7670fca0f36ad8ec9bde4ea82dfae119a21b076519bcc1c00152989a4d45])),
(b'abcdef0123456789',
FQ2([0x0ded52c30aace28d3e9cc5c1b47861ae4dd4e9cd17622e0f5b9d584af0397cd0e3bae80d4ee2d9d4b18c390f63154dfd, 0x046701a03f361a0b8392ca387585f7ee6534dcec9450a035e39dc37387d5ca079b9557447f7d9cad0bd9671cb65ada02]),
FQ2([0x07a5cf56c5ea1d69ad59c0e80cc16c0c1b27f02840b396eb0ea320f70e87f705c6fa70cfeb9719b14badbb058bec5a4c, 0x0674d1f7c9e8e84d8d7a07b40231257571c43160fd566e8d24459d17ca52f6068e1b63aaae5359d8869d4abc66de66b6])),
(b'a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
FQ2([0x0161130ef4aa2f60f751e6b3dd48ac6e994d2d2613897c5dd26945bc72f33cc2977e1255c3f2dc0f1440d15a71c29b40, 0x06db1818f132a61f5fe86d315faa8de4653049ac9cf7fbbc6d9987e5864d82a0156259d56192109bafddd5c30b9f01f5]),
FQ2([0x00f7fab0fedc978b974a38a1755244727b8a4eb31073653fa949594645ad181880d20ff0c91c4375b7e451fe803c9847, 0x0964d550ee8752b6db99555ffcd442b4185267f31e3d57435ea73896a7a9fe952bd67f90fd75f4413212ac9640a7672c])),
]
)
def test_hash_to_G2(msg, x, y):
point = hash_to_G2(msg, DST)

def test_hash_to_G2(msg, x, y, H):
point = hash_to_G2(msg, DST, H)
assert is_on_curve(point, b2)

# Affine
Expand Down