Skip to content

Commit

Permalink
add constants and typing
Browse files Browse the repository at this point in the history
  • Loading branch information
ChihChengLiang committed Mar 14, 2019
1 parent 55d4b10 commit b31df48
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 40 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,6 @@ com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

# Vscode
.vscode
17 changes: 10 additions & 7 deletions py_ecc/bls_api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@
from .typing import (
BLSPubkey,
BLSSignature,
G1Uncompressed,
G2Uncompressed,
Hash32,
)
from .utils import (
FQP_point_to_FQ2_point,
G1_to_pubkey,
G2_to_signature,
compress_G1,
Expand All @@ -47,19 +48,21 @@ def sign(message_hash: Hash32,


def privtopub(k: int) -> BLSPubkey:
return G1_to_pubkey(compress_G1(multiply(G1, k)))
return G1_to_pubkey(compress_G1(
multiply(G1Uncompressed(G1), k)
))


def verify(message_hash: Hash32, pubkey: BLSPubkey, signature: BLSSignature, domain: int) -> bool:
try:
final_exponentiation = final_exponentiate(
pairing(
FQP_point_to_FQ2_point(decompress_G2(signature_to_G2(signature))),
decompress_G2(signature_to_G2(signature)),
G1,
final_exponentiate=False,
) *
pairing(
FQP_point_to_FQ2_point(hash_to_G2(message_hash, domain)),
hash_to_G2(message_hash, domain),
neg(decompress_G1(pubkey_to_G1(pubkey))),
final_exponentiate=False,
)
Expand All @@ -70,14 +73,14 @@ def verify(message_hash: Hash32, pubkey: BLSPubkey, signature: BLSSignature, dom


def aggregate_signatures(signatures: Sequence[BLSSignature]) -> BLSSignature:
o = Z2
o = G2Uncompressed(Z2)
for s in signatures:
o = FQP_point_to_FQ2_point(add(o, decompress_G2(signature_to_G2(s))))
o = add(o, decompress_G2(signature_to_G2(s)))
return G2_to_signature(compress_G2(o))


def aggregate_pubkeys(pubkeys: Sequence[BLSPubkey]) -> BLSPubkey:
o = Z1
o = G1Uncompressed(Z1)
for p in pubkeys:
o = add(o, decompress_G1(pubkey_to_G1(p)))
return G1_to_pubkey(compress_G1(o))
Expand Down
6 changes: 6 additions & 0 deletions py_ecc/bls_api/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@


POW_2_381 = 2**381
POW_2_382 = 2**382
POW_2_383 = 2**383
POW_2_384 = 2**384
13 changes: 13 additions & 0 deletions py_ecc/bls_api/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,21 @@

from typing import (
NewType,
Tuple,
)
from py_ecc.optimized_bls12_381.optimized_field_elements import (
FQ,
FQ2,
)


Hash32 = NewType("Hash32", bytes)
BLSPubkey = NewType('BLSPubkey', bytes) # bytes48
BLSSignature = NewType('BLSSignature', bytes) # bytes96


G1Uncompressed = NewType('G1Uncompressed', Tuple[FQ, FQ, FQ])
G1Compressed = NewType('G1Compressed', int)

G2Uncompressed = NewType('G2Uncompressed', Tuple[FQ2, FQ2, FQ2])
G2Compressed = NewType('G2Compressed', Tuple[int, int])
69 changes: 36 additions & 33 deletions py_ecc/bls_api/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,18 @@
from .typing import (
BLSPubkey,
BLSSignature,
G1Compressed,
G1Uncompressed,
G2Compressed,
G2Uncompressed,
Hash32,
)
from .constants import (
POW_2_381,
POW_2_382,
POW_2_383,
POW_2_384,
)

G2_cofactor = 305502333931268344200999753193121504214466019254188142667664032982267604182971884026507427359259977847832272839041616661285803823378372096355777062779109 # noqa: E501
FQ2_order = q ** 2 - 1
Expand All @@ -40,15 +50,6 @@
#
# Helpers
#
def FQP_point_to_FQ2_point(pt: Tuple[FQP, FQP, FQP]) -> Tuple[FQ2, FQ2, FQ2]:
"""
Transform FQP to FQ2 for type hinting.
"""
return (
FQ2(pt[0].coeffs),
FQ2(pt[1].coeffs),
FQ2(pt[2].coeffs),
)


def modular_squareroot(value: FQ2) -> FQP:
Expand Down Expand Up @@ -79,7 +80,7 @@ def _get_x_coordinate(message_hash: Hash32, domain: int) -> FQ2:
return x_coordinate


def hash_to_G2(message_hash: Hash32, domain: int) -> Tuple[FQ2, FQ2, FQ2]:
def hash_to_G2(message_hash: Hash32, domain: int) -> G2Uncompressed:
x_coordinate = _get_x_coordinate(message_hash, domain)

# Test candidate y coordinates until a one is found
Expand All @@ -91,24 +92,24 @@ def hash_to_G2(message_hash: Hash32, domain: int) -> Tuple[FQ2, FQ2, FQ2]:
x_coordinate += FQ2([1, 0]) # Add 1 and try again

return multiply(
(x_coordinate, y_coordinate, FQ2([1, 0])),
G2_cofactor
G2Uncompressed((x_coordinate, y_coordinate, FQ2([1, 0]))),
G2_cofactor,
)


#
# G1
#
def compress_G1(pt: Tuple[FQ, FQ, FQ]) -> int:
def compress_G1(pt: G1Uncompressed) -> G1Compressed:
x, y = normalize(pt)
return x.n + 2**383 * (y.n % 2)
return x.n + POW_2_383 * (y.n % 2)


def decompress_G1(pt: int) -> Tuple[FQ, FQ, FQ]:
def decompress_G1(pt: G1Compressed) -> G1Uncompressed:
if pt == 0:
return (FQ(1), FQ(1), FQ(0))
x = pt % 2**383
y_mod_2 = pt // 2**383
return G1Uncompressed((FQ(1), FQ(1), FQ(0)))
x = pt % POW_2_383
y_mod_2 = pt // POW_2_383
y = pow((x**3 + b.n) % q, (q + 1) // 4, q)

if pow(y, 2, q) != (x**3 + b.n) % q:
Expand All @@ -117,40 +118,40 @@ def decompress_G1(pt: int) -> Tuple[FQ, FQ, FQ]:
)
if y % 2 != y_mod_2:
y = q - y
return (FQ(x), FQ(y), FQ(1))
return G1Uncompressed((FQ(x), FQ(y), FQ(1)))


def G1_to_pubkey(pt: int) -> BLSPubkey:
def G1_to_pubkey(pt: G1Compressed) -> BLSPubkey:
return BLSPubkey(pt.to_bytes(48, "big"))


def pubkey_to_G1(pubkey: BLSPubkey) -> int:
def pubkey_to_G1(pubkey: BLSPubkey) -> G1Compressed:
return big_endian_to_int(pubkey)

#
# G2
#


def compress_G2(pt: Tuple[FQP, FQP, FQP]) -> Tuple[int, int]:
def compress_G2(pt: G2Uncompressed) -> G2Compressed:
if not is_on_curve(pt, b2):
raise ValueError(
"The given point is not on the twisted curve over FQ**2"
)
x, y = normalize(pt)
return (
int(x.coeffs[0] + 2**383 * (y.coeffs[0] % 2)),
return G2Compressed((
int(x.coeffs[0] + POW_2_383 * (y.coeffs[0] % 2)),
int(x.coeffs[1])
)
))


def decompress_G2(p: Tuple[int, int]) -> Tuple[FQP, FQP, FQP]:
x1 = p[0] % 2**383
y1_mod_2 = p[0] // 2**383
def decompress_G2(p: G2Compressed) -> G2Uncompressed:
x1 = p[0] % POW_2_383
y1_mod_2 = p[0] // POW_2_383
x2 = p[1]
x = FQ2([x1, x2])
if x == FQ2([0, 0]):
return FQ2([1, 0]), FQ2([1, 0]), FQ2([0, 0])
return G2Uncompressed((FQ2([1, 0]), FQ2([1, 0]), FQ2([0, 0])))
y = modular_squareroot(x**3 + b2)
if y is None:
raise ValueError("Failed to find a modular squareroot")
Expand All @@ -160,15 +161,17 @@ def decompress_G2(p: Tuple[int, int]) -> Tuple[FQP, FQP, FQP]:
raise ValueError(
"The given point is not on the twisted curve over FQ**2"
)
return x, y, FQ2([1, 0])
return G2Uncompressed((x, y, FQ2([1, 0])))


def G2_to_signature(pt: Tuple[int, int]) -> BLSSignature:
def G2_to_signature(pt: G2Compressed) -> BLSSignature:
return BLSSignature(
pt[0].to_bytes(48, "big") +
pt[1].to_bytes(48, "big")
)


def signature_to_G2(signature: BLSSignature) -> Tuple[int, int]:
return (big_endian_to_int(signature[:48]), big_endian_to_int(signature[48:]))
def signature_to_G2(signature: BLSSignature) -> G2Compressed:
return G2Compressed(
(big_endian_to_int(signature[:48]), big_endian_to_int(signature[48:]))
)

0 comments on commit b31df48

Please sign in to comment.