class EC_key_pair: """EC 256k1, 256r1 or Ed 25519 key pair""" def __init__(self, pv_key_int, curve): """An EllipticCurvePrivateKey object""" self.curve = curve if self.curve == "K1": curveobj = K1_CURVE elif self.curve == "R1": curveobj = R1_CURVE if self.curve == "K1" or self.curve == "R1": # K1 or R1 if pv_key_int < 0: # No private key provided, generating self.key_obj = ec.generate_private_key( curveobj, backends.default_backend()) else: # Create a key pair from the provided key integer self.key_obj = ec.derive_private_key( pv_key_int, curveobj, backends.default_backend()) elif self.curve == "ED": if pv_key_int < 0: # No private key provided, generating seed_bytes = random_generator() else: # Create a key pair from the provided key integer seed_bytes = pv_key_int.to_bytes(32, "big") self.key_obj = SigningKey(seed_bytes, RawEncoder) else: raise ValueError("ECkeypair must be K1, R1 or ED") def pv_int(self): """output private key as a integer, only for 256k1/r1""" if self.curve == "ED": raise ValueError( "ECkeypair pv_int can only be used for R1 or K1 key.") return self.key_obj.private_numbers().private_value def ser256(self): """output private key as bytes""" if self.curve == "K1" or self.curve == "R1": return self.pv_int().to_bytes(32, "big") return self.key_obj._seed def sign(self, data): """Sign data, in DER format. For r1 and k1 : sign pre-hashed data (256 bits). For Ed25519 : sign full message data. """ if self.curve == "K1" or self.curve == "R1": sign_alg = ec.ECDSA(utils.Prehashed(hashes.SHA256())) return makeup_sig(self.key_obj.sign(data, sign_alg), self.curve) # Ed25519 return self.key_obj.sign(data, RawEncoder).signature def get_public_key(self, compressed=False): """public key output X962 from the private key object""" if self.curve == "K1" or self.curve == "R1": # X962 PublicKey out_format = (serialization.PublicFormat.CompressedPoint if compressed else serialization.PublicFormat.UncompressedPoint) return self.key_obj.public_key().public_bytes( serialization.Encoding.X962, out_format) # Ed25519 : 32 bytes public key return self.key_obj.verify_key.encode(RawEncoder) def ecdh(self, peer_pub_key): """Compute a ECDH key exchange.""" if self.curve == "ED": raise ValueError( "ECkeypair pv_int can only be used for R1 or K1 key.") if self.curve == "K1": curveobj = K1_CURVE elif self.curve == "R1": curveobj = R1_CURVE public_key = ec.EllipticCurvePublicKey.from_encoded_point( curveobj, peer_pub_key) shared_key = self.key_obj.exchange(ec.ECDH(), public_key) return shared_key