import ctypes.util
import os
import platform
from .bignum import bignum_type_for_library
NID_X9_62_prime256v1 = 415
NID_secp256k1 = 714
[docs]class BignumContext(ctypes.Structure):
pass
[docs]def set_api(library, api_info):
for f_name, argtypes, restype in api_info:
f = getattr(library, f_name)
f.argtypes = argtypes
f.restype = restype
[docs]def load_library():
system = platform.system()
PYCOIN_LIBCRYPTO_PATH = os.getenv("PYCOIN_LIBCRYPTO_PATH")
if PYCOIN_LIBCRYPTO_PATH:
library_path = PYCOIN_LIBCRYPTO_PATH
elif system == 'Windows':
if platform.architecture()[0] == '64bit':
library_path = ctypes.util.find_library('libeay64')
else:
library_path = ctypes.util.find_library('libeay32')
else:
# on Mac OS 10.15.1 trying to load "libcrypto" crashes
# but crypto.0.9.8 works, so try to load that one first
for p in ["crypto.0.9.8", "crypto"]:
library_path = ctypes.util.find_library(p)
if library_path:
break
if library_path is None:
return None
library = ctypes.CDLL(library_path)
library.BignumType = bignum_type_for_library(library)
BN_P = ctypes.POINTER(library.BignumType)
BN_CTX = ctypes.POINTER(BignumContext)
BIGNUM_API = [
("BN_new", [], BN_P),
("BN_set_word", [BN_P, ctypes.c_ulong], ctypes.c_int),
("BN_clear_free", [BN_P], None),
("BN_bin2bn", [ctypes.c_char_p, ctypes.c_int, BN_P], BN_P),
("BN_mod_inverse", [BN_P, BN_P, BN_P, BN_CTX], BN_P),
("BN_CTX_new", [], BN_CTX),
("BN_CTX_free", [BN_CTX], None),
("BN_mpi2bn", [ctypes.c_char_p, ctypes.c_int, BN_P], BN_P),
]
ECC_API = [
("EC_GROUP_new_by_curve_name", [ctypes.c_int], ctypes.c_void_p),
("EC_POINT_new", [ctypes.c_void_p], ctypes.c_void_p), # TODO: make this a EC_POINT type
("EC_POINT_free", [ctypes.c_void_p], None),
("EC_POINT_set_affine_coordinates_GFp",
[ctypes.c_void_p, ctypes.c_void_p, BN_P, BN_P, BN_CTX], ctypes.c_int),
("EC_POINT_get_affine_coordinates_GFp",
[ctypes.c_void_p, ctypes.c_void_p, BN_P, BN_P, BN_CTX], ctypes.c_int),
("EC_POINT_mul",
[ctypes.c_void_p, ctypes.c_void_p, BN_P, ctypes.c_void_p, BN_P, BN_CTX], ctypes.c_int),
]
set_api(library, BIGNUM_API)
set_api(library, ECC_API)
return library
OpenSSL = load_library()
[docs]def create_OpenSSLOptimizations(curve_id):
class noop:
pass
native = os.getenv("PYCOIN_NATIVE")
if native and native.lower() != "openssl":
return noop
if not OpenSSL:
return noop
class Optimizations:
if OpenSSL:
openssl_group = OpenSSL.EC_GROUP_new_by_curve_name(curve_id)
def multiply(self, p, e):
"Use OpenSSL to perform point multiplication."
if e == 0 or p == self._infinity:
return self._infinity
bn_x = OpenSSL.BignumType(p[0])
bn_y = OpenSSL.BignumType(p[1])
bn_n = OpenSSL.BignumType(e)
ctx = OpenSSL.BN_CTX_new()
ec_result = OpenSSL.EC_POINT_new(self.openssl_group)
ec_point = OpenSSL.EC_POINT_new(self.openssl_group)
OpenSSL.EC_POINT_set_affine_coordinates_GFp(self.openssl_group, ec_point, bn_x, bn_y, ctx)
OpenSSL.EC_POINT_mul(self.openssl_group, ec_result, None, ec_point, bn_n, ctx)
OpenSSL.EC_POINT_get_affine_coordinates_GFp(self.openssl_group, ec_result, bn_x, bn_y, ctx)
OpenSSL.EC_POINT_free(ec_point)
OpenSSL.EC_POINT_free(ec_result)
OpenSSL.BN_CTX_free(ctx)
return self.Point(bn_x.to_int(), bn_y.to_int())
def raw_mul(self, e):
"""Multiply the generator by an integer."""
return self.multiply(self, e)
def inverse_mod(self, a, p):
ctx = OpenSSL.BN_CTX_new()
a1 = OpenSSL.BignumType(a)
OpenSSL.BN_mod_inverse(a1, a1, OpenSSL.BignumType(p), ctx)
OpenSSL.BN_CTX_free(ctx)
return a1.to_int()
return Optimizations