Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions examples/example_key_generation.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import argparse
import secrets

from pactus.crypto import CryptoConfig
from pactus.crypto.address import AddressType
Expand Down Expand Up @@ -34,21 +33,19 @@ def main() -> None:
match AddressType(args.address_type):
case AddressType.VALIDATOR:
# Generate a cryptographically secure IKM (Initial Keying Material).
ikm = secrets.token_bytes(32)
sec = BLSPrivateKey.key_gen(ikm)
sec = BLSPrivateKey.random()
pub = sec.public_key()
addr = pub.validator_address()
show(sec, pub, addr)

case AddressType.BLS_ACCOUNT:
ikm = secrets.token_bytes(32)
sec = BLSPrivateKey.key_gen(ikm)
sec = BLSPrivateKey.random()
pub = sec.public_key()
addr = pub.account_address()
show(sec, pub, addr)

case AddressType.ED25519_ACCOUNT:
sec = Ed25519PrivateKey.key_gen()
sec = Ed25519PrivateKey.random()
pub = sec.public_key()
addr = pub.account_address()
show(sec, pub, addr)
Expand Down
7 changes: 6 additions & 1 deletion pactus/crypto/bls/bls12_381/bls_sig_g1.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,15 @@ def _verify_aug(pk, sig, msg, ciphersuite, ver_fn=verify):


# signature aggregation
def aggregate(sigs):
def aggregate_sigs(sigs):
return reduce(point_add, sigs)


# public key aggregation
def aggregate_pubs(pubs):
return reduce(point_add, pubs)


# aggregate verification
def aggregate_verify(pks, msgs, sig, ciphersuite):
assert len(pks) == len(msgs), (
Expand Down
9 changes: 8 additions & 1 deletion pactus/crypto/bls/private_key.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import secrets
from math import ceil, log2

from pactus.crypto import CryptoConfig
Expand All @@ -24,7 +25,7 @@ def from_bytes(cls, buffer: bytes) -> PrivateKey:
return cls(int.from_bytes(buffer, "big") % curve_order)

@classmethod
def key_gen(cls, ikm: bytes, key_info: bytes = b"") -> PrivateKey:
def key_gen(cls, ikm: bytes = [], key_info: bytes = b"") -> PrivateKey:
salt = b"BLS-SIG-KEYGEN-SALT-"
sk = 0
while sk == 0:
Expand All @@ -36,6 +37,12 @@ def key_gen(cls, ikm: bytes, key_info: bytes = b"") -> PrivateKey:

return cls(sk)

@classmethod
def random(cls) -> PrivateKey:
ikm = secrets.token_bytes(32)

return cls.key_gen(ikm)

@classmethod
def from_string(cls, text: str) -> PrivateKey:
hrp, typ, data = utils.decode_to_base256_with_type(text)
Expand Down
9 changes: 8 additions & 1 deletion pactus/crypto/bls/public_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from pactus.crypto.address import Address, AddressType
from pactus.utils import utils

from .bls12_381.bls_sig_g1 import verify
from .bls12_381.bls_sig_g1 import aggregate_pubs, verify
from .bls12_381.serdesZ import deserialize, serialize
from .signature import DST, SIGNATURE_TYPE_BLS, Signature

Expand Down Expand Up @@ -39,6 +39,13 @@ def from_string(cls, text: str) -> PublicKey:

return cls(point_g2)

@classmethod
def aggregate(cls, pubs: list[PublicKey]) -> PublicKey:
point_g2s = []
point_g2s.extend(pub.point_g2 for pub in pubs)

return cls(aggregate_pubs(point_g2s))

def raw_bytes(self) -> bytes:
return serialize(self.point_g2)

Expand Down
6 changes: 3 additions & 3 deletions pactus/crypto/bls/signature.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from .bls12_381.bls_sig_g1 import aggregate
from .bls12_381.bls_sig_g1 import aggregate_sigs
from .bls12_381.serdesZ import deserialize, serialize

SIGNATURE_SIZE = 48
Expand All @@ -27,9 +27,9 @@ def from_string(cls, text: str) -> Signature:
@classmethod
def aggregate(cls, sigs: list[Signature]) -> Signature:
point_g1s = []
point_g1s.extend(sig for sig in sigs)
point_g1s.extend(sig.point_g1 for sig in sigs)

return cls(aggregate(point_g1s))
return cls(aggregate_sigs(point_g1s))

def raw_bytes(self) -> bytes:
return serialize(self.point_g1)
Expand Down
3 changes: 2 additions & 1 deletion pactus/crypto/ed25519/private_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ def from_bytes(cls, buffer: bytes) -> PrivateKey:
return cls(ed25519.Ed25519PrivateKey.from_private_bytes(buffer))

@classmethod
def key_gen(cls) -> PrivateKey:
def random(cls) -> PrivateKey:
sk = ed25519.Ed25519PrivateKey.generate()

return cls(sk)

@classmethod
Expand Down
28 changes: 28 additions & 0 deletions tests/test_crypto_bls.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,34 @@ def test_key_gen(self):
if test["sk"] != "Err":
self.fail(f"Test '{i}' failed. Unexpected error: {e}")

def test_aggregate_sig(self):
sig1 = BLSSignature.from_string(
"923d67a8624cbb7972b29328e15ec76cc846076ccf00a9e94d991c677846f334ae4ba4551396fbcd6d1cab7593baf3b7"
)
sig2 = BLSSignature.from_string(
"ab025936daaed80ca2f85a418c8a47c3d9f4137d7b7651ca52646260d2018e55628bba118d4993a3aa75de268d55e72b"
)

agg = BLSSignature.aggregate([sig1, sig2])
self.assertEqual(
agg.string(),
"ad747172697127cb08dda29a386e106eb24ab0edfbc044014c3bd7a5f583cc38b3a223ff2c1df9c0b4df110630e6946b",
)

def test_aggregate_pub(self):
pub1 = BLSPublicKey.from_string(
"public1p4u8hfytl2pj6l9rj0t54gxcdmna4hq52ncqkkqjf3arha5mlk3x4mzpyjkhmdl20jae7f65aamjrvqcvf4sudcapz52ctcwc8r9wz3z2gwxs38880cgvfy49ta5ssyjut05myd4zgmjqstggmetyuyg7v5jhx47a"
)
pub2 = BLSPublicKey.from_string(
"public1pkms34vh00p0jwpdrv6hpqzsx3u26v547948h38wzpp0vc7j408sdy5cql5w5s4rpz60jnzm8rqw4crcw00lgrjeqydpagwstfgdfd79p9yr6rlrr2edtjaqp0shreqxmx0sk4gwlz336hyvnzh7lquxgwcw5nynk"
)

agg = BLSPublicKey.aggregate([pub1, pub2])
self.assertEqual(
agg.string(),
"public1pk5pfgdfe9l6q8mc03wfksx2l4r0h3hrx309sjcyuaredzh5krsfh8a86fuk0kcv2nslcduwz3w0zyqlvv2d42ne04c87hha5dw7dc9r2au5l7vhrruud7wf9u5k4fzg5rma6n940uqgfpjph8d9yg20dzswk7wxj",
)


if __name__ == "__main__":
unittest.main()