- 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 testpython3android
parent
f180b1a5b0
commit
2e0f7755c6
7 changed files with 394 additions and 51 deletions
@ -0,0 +1,179 @@ |
||||
#!/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 |
@ -0,0 +1,22 @@ |
||||
""" |
||||
Test for ECC blind signatures |
||||
""" |
||||
import os |
||||
import unittest |
||||
|
||||
from src.pyelliptic.eccblind import ECCBlind |
||||
|
||||
|
||||
class TestBlindSig(unittest.TestCase): |
||||
""" |
||||
Test case for ECC blind signature |
||||
""" |
||||
def test_blind_sig(self): |
||||
"""Test full sequence using a random certifier key and a random message""" |
||||
blind_sig = ECCBlind() |
||||
blind_sig.signer_init() |
||||
msg = os.urandom(64) |
||||
blind_sig.create_signing_request(msg) |
||||
blind_sig.blind_sign() |
||||
blind_sig.unblind() |
||||
self.assertTrue(blind_sig.verify()) |
Loading…
Reference in new issue