Peter Surda
2e0f7755c6
- add blind signature functionality to pyelliptic as described in #1409 - add tests for blind signatures - PEP8 fixes for pyelliptic - some minor refactoring is necessary for further integration, this is just a minimal implementation to pass a test
180 lines
5.7 KiB
Python
180 lines
5.7 KiB
Python
#!/usr/bin/env python
|
|
"""
|
|
ECC blind signature functionality based on "An Efficient Blind Signature Scheme
|
|
Based on the Elliptic CurveDiscrete Logarithm Problem" by Morteza Nikooghadama
|
|
<mnikooghadam@sbu.ac.ir> and Ali Zakerolhosseini <a-zaker@sbu.ac.ir>,
|
|
http://www.isecure-journal.com/article_39171_47f9ec605dd3918c2793565ec21fcd7a.pdf
|
|
"""
|
|
|
|
# variable names are based on the math in the paper, so they don't conform
|
|
# to PEP8
|
|
# pylint: disable=invalid-name
|
|
|
|
from .openssl import OpenSSL
|
|
|
|
|
|
class ECCBlind(object): # pylint: disable=too-many-instance-attributes
|
|
"""
|
|
Class for ECC blind signature functionality
|
|
"""
|
|
|
|
# init
|
|
k = None
|
|
R = None
|
|
keypair = None
|
|
F = None
|
|
Q = None
|
|
a = None
|
|
b = None
|
|
c = None
|
|
binv = None
|
|
r = None
|
|
m = None
|
|
m_ = None
|
|
s_ = None
|
|
signature = None
|
|
|
|
@staticmethod
|
|
def ec_get_random(group, ctx):
|
|
"""
|
|
Random point from finite field
|
|
"""
|
|
order = OpenSSL.BN_new()
|
|
OpenSSL.EC_GROUP_get_order(group, order, ctx)
|
|
OpenSSL.BN_rand(order, OpenSSL.BN_num_bits(order), 0, 0)
|
|
return order
|
|
|
|
@staticmethod
|
|
def ec_invert(group, a, ctx):
|
|
"""
|
|
ECC inversion
|
|
"""
|
|
order = OpenSSL.BN_new()
|
|
OpenSSL.EC_GROUP_get_order(group, order, ctx)
|
|
inverse = OpenSSL.BN_mod_inverse(0, a, order, ctx)
|
|
return inverse
|
|
|
|
@staticmethod
|
|
def ec_gen_keypair(group, ctx):
|
|
"""
|
|
Generate an ECC keypair
|
|
"""
|
|
d = ECCBlind.ec_get_random(group, ctx)
|
|
Q = OpenSSL.EC_POINT_new(group)
|
|
OpenSSL.EC_POINT_mul(group, Q, d, 0, 0, 0)
|
|
return (d, Q)
|
|
|
|
def __init__(self, curve="secp256k1"):
|
|
self.group = OpenSSL.EC_GROUP_new_by_curve_name(OpenSSL.get_curve(curve))
|
|
self.ctx = OpenSSL.BN_CTX_new()
|
|
|
|
# Order n
|
|
self.n = OpenSSL.BN_new()
|
|
OpenSSL.EC_GROUP_get_order(self.group, self.n, self.ctx)
|
|
|
|
# Identity O (infinity)
|
|
self.iO = OpenSSL.EC_POINT_new(self.group)
|
|
OpenSSL.EC_POINT_set_to_infinity(self.group, self.iO)
|
|
|
|
# Generator G
|
|
self.G = OpenSSL.EC_GROUP_get0_generator(self.group)
|
|
|
|
# Certifier's pubkey
|
|
self.pubkey = (self.group, self.G, self.n)
|
|
|
|
def signer_init(self):
|
|
"""
|
|
Init signer
|
|
"""
|
|
# Signer: Random integer k
|
|
self.k = ECCBlind.ec_get_random(self.group, self.ctx)
|
|
|
|
# R = kG
|
|
self.R = OpenSSL.EC_POINT_new(self.group)
|
|
OpenSSL.EC_POINT_mul(self.group, self.R, self.k, 0, 0, 0)
|
|
|
|
def create_signing_request(self, msg):
|
|
"""
|
|
Requester creates a new signing request
|
|
"""
|
|
# new keypair
|
|
self.keypair = ECCBlind.ec_gen_keypair(self.group, self.ctx)
|
|
|
|
# Requester: 3 random blinding factors
|
|
self.F = OpenSSL.EC_POINT_new(self.group)
|
|
OpenSSL.EC_POINT_set_to_infinity(self.group, self.F)
|
|
temp = OpenSSL.EC_POINT_new(self.group)
|
|
self.Q = self.keypair[1]
|
|
abinv = OpenSSL.BN_new()
|
|
|
|
# F != O
|
|
while OpenSSL.EC_POINT_cmp(self.group, self.F, self.iO, self.ctx) == 0:
|
|
self.a = ECCBlind.ec_get_random(self.group, self.ctx)
|
|
self.b = ECCBlind.ec_get_random(self.group, self.ctx)
|
|
self.c = ECCBlind.ec_get_random(self.group, self.ctx)
|
|
|
|
# F = b^-1 * R...
|
|
self.binv = ECCBlind.ec_invert(self.group, self.b, self.ctx)
|
|
OpenSSL.EC_POINT_mul(self.group, temp, 0, self.R, self.binv, 0)
|
|
OpenSSL.EC_POINT_copy(self.F, temp)
|
|
|
|
# ... + a*b^-1 * Q...
|
|
OpenSSL.BN_mul(abinv, self.a, self.binv, self.ctx)
|
|
OpenSSL.EC_POINT_mul(self.group, temp, 0, self.Q, abinv, 0)
|
|
OpenSSL.EC_POINT_add(self.group, self.F, self.F, temp, 0)
|
|
|
|
# ... + c*G
|
|
OpenSSL.EC_POINT_mul(self.group, temp, 0, self.G, self.c, 0)
|
|
OpenSSL.EC_POINT_add(self.group, self.F, self.F, temp, 0)
|
|
|
|
# F = (x0, y0)
|
|
x0 = OpenSSL.BN_new()
|
|
y0 = OpenSSL.BN_new()
|
|
OpenSSL.EC_POINT_get_affine_coordinates_GFp(self.group, self.F, x0, y0,
|
|
self.ctx)
|
|
self.r = x0
|
|
|
|
# Requester: Blinding (m' = br(m) + a)
|
|
self.m = OpenSSL.BN_new()
|
|
OpenSSL.BN_bin2bn(msg, len(msg), self.m)
|
|
|
|
self.m_ = OpenSSL.BN_new()
|
|
OpenSSL.BN_mod_mul(self.m_, self.b, self.r, self.n, self.ctx)
|
|
OpenSSL.BN_mod_mul(self.m_, self.m_, self.m, self.n, self.ctx)
|
|
OpenSSL.BN_mod_add(self.m_, self.m_, self.a, self.n, self.ctx)
|
|
|
|
def blind_sign(self):
|
|
"""
|
|
Signer blind-signs the request
|
|
"""
|
|
self.s_ = OpenSSL.BN_new()
|
|
OpenSSL.BN_mod_mul(self.s_, self.keypair[0], self.m_, self.n, self.ctx)
|
|
OpenSSL.BN_mod_add(self.s_, self.s_, self.k, self.n, self.ctx)
|
|
|
|
def unblind(self):
|
|
"""
|
|
Requester unblinds the signature
|
|
"""
|
|
s = OpenSSL.BN_new()
|
|
OpenSSL.BN_mod_mul(s, self.binv, self.s_, self.n, self.ctx)
|
|
OpenSSL.BN_mod_add(s, s, self.c, self.n, self.ctx)
|
|
self.signature = (s, self.F)
|
|
|
|
def verify(self):
|
|
"""
|
|
Verify signature with certifier's pubkey
|
|
"""
|
|
lhs = OpenSSL.EC_POINT_new(self.group)
|
|
rhs = OpenSSL.EC_POINT_new(self.group)
|
|
|
|
OpenSSL.EC_POINT_mul(self.group, lhs, self.signature[0], 0, 0, 0)
|
|
OpenSSL.EC_POINT_mul(self.group, rhs, 0, self.Q, self.m, 0)
|
|
OpenSSL.EC_POINT_mul(self.group, rhs, 0, rhs, self.r, 0)
|
|
OpenSSL.EC_POINT_add(self.group, rhs, rhs, self.F, self.ctx)
|
|
|
|
retval = OpenSSL.EC_POINT_cmp(self.group, lhs, rhs, self.ctx)
|
|
if retval == -1:
|
|
raise RuntimeError("EC_POINT_cmp returned an error")
|
|
else:
|
|
return retval == 0
|