test_blindsig.py
1 """ 2 Test for ECC blind signatures 3 """ 4 import os 5 import unittest 6 from hashlib import sha256 7 8 try: 9 from pyelliptic import ECCBlind, ECCBlindChain, OpenSSL 10 except ImportError: 11 from pybitmessage.pyelliptic import ECCBlind, ECCBlindChain, OpenSSL 12 13 # pylint: disable=protected-access 14 15 16 class TestBlindSig(unittest.TestCase): 17 """ 18 Test case for ECC blind signature 19 """ 20 def test_blind_sig(self): 21 """Test full sequence using a random certifier key and a random message""" 22 # See page 127 of the paper 23 # (1) Initialization 24 signer_obj = ECCBlind() 25 point_r = signer_obj.signer_init() 26 self.assertEqual(len(signer_obj.pubkey()), 35) 27 28 # (2) Request 29 requester_obj = ECCBlind(pubkey=signer_obj.pubkey()) 30 # only 64 byte messages are planned to be used in Bitmessage 31 msg = os.urandom(64) 32 msg_blinded = requester_obj.create_signing_request(point_r, msg) 33 self.assertEqual(len(msg_blinded), 32) 34 35 # check 36 self.assertNotEqual(sha256(msg).digest(), msg_blinded) 37 38 # (3) Signature Generation 39 signature_blinded = signer_obj.blind_sign(msg_blinded) 40 assert isinstance(signature_blinded, bytes) 41 self.assertEqual(len(signature_blinded), 32) 42 43 # (4) Extraction 44 signature = requester_obj.unblind(signature_blinded) 45 assert isinstance(signature, bytes) 46 self.assertEqual(len(signature), 65) 47 48 self.assertNotEqual(signature, signature_blinded) 49 50 # (5) Verification 51 verifier_obj = ECCBlind(pubkey=signer_obj.pubkey()) 52 self.assertTrue(verifier_obj.verify(msg, signature)) 53 54 def test_is_odd(self): 55 """Test our implementation of BN_is_odd""" 56 for _ in range(1024): 57 obj = ECCBlind() 58 x = OpenSSL.BN_new() 59 y = OpenSSL.BN_new() 60 OpenSSL.EC_POINT_get_affine_coordinates( 61 obj.group, obj.Q, x, y, None) 62 self.assertEqual(OpenSSL.BN_is_odd(y), 63 OpenSSL.BN_is_odd_compatible(y)) 64 65 def test_serialize_ec_point(self): 66 """Test EC point serialization/deserialization""" 67 for _ in range(1024): 68 try: 69 obj = ECCBlind() 70 obj2 = ECCBlind() 71 randompoint = obj.Q 72 serialized = obj._ec_point_serialize(randompoint) 73 secondpoint = obj2._ec_point_deserialize(serialized) 74 x0 = OpenSSL.BN_new() 75 y0 = OpenSSL.BN_new() 76 OpenSSL.EC_POINT_get_affine_coordinates(obj.group, 77 randompoint, x0, 78 y0, obj.ctx) 79 x1 = OpenSSL.BN_new() 80 y1 = OpenSSL.BN_new() 81 OpenSSL.EC_POINT_get_affine_coordinates(obj2.group, 82 secondpoint, x1, 83 y1, obj2.ctx) 84 85 self.assertEqual(OpenSSL.BN_cmp(y0, y1), 0) 86 self.assertEqual(OpenSSL.BN_cmp(x0, x1), 0) 87 self.assertEqual(OpenSSL.EC_POINT_cmp(obj.group, randompoint, 88 secondpoint, None), 0) 89 finally: 90 OpenSSL.BN_free(x0) 91 OpenSSL.BN_free(x1) 92 OpenSSL.BN_free(y0) 93 OpenSSL.BN_free(y1) 94 del obj 95 del obj2 96 97 def test_serialize_bn(self): 98 """Test Bignum serialization/deserialization""" 99 for _ in range(1024): 100 obj = ECCBlind() 101 obj2 = ECCBlind() 102 randomnum = obj.d 103 serialized = obj._bn_serialize(randomnum) 104 secondnum = obj2._bn_deserialize(serialized) 105 self.assertEqual(OpenSSL.BN_cmp(randomnum, secondnum), 0) 106 107 def test_blind_sig_many(self): 108 """Test a lot of blind signatures""" 109 for _ in range(1024): 110 self.test_blind_sig() 111 112 def test_blind_sig_value(self): 113 """Test blind signature value checking""" 114 signer_obj = ECCBlind(value=5) 115 point_r = signer_obj.signer_init() 116 requester_obj = ECCBlind(pubkey=signer_obj.pubkey()) 117 msg = os.urandom(64) 118 msg_blinded = requester_obj.create_signing_request(point_r, msg) 119 signature_blinded = signer_obj.blind_sign(msg_blinded) 120 signature = requester_obj.unblind(signature_blinded) 121 verifier_obj = ECCBlind(pubkey=signer_obj.pubkey()) 122 self.assertFalse(verifier_obj.verify(msg, signature, value=8)) 123 124 def test_blind_sig_expiration(self): 125 """Test blind signature expiration checking""" 126 signer_obj = ECCBlind(year=2020, month=1) 127 point_r = signer_obj.signer_init() 128 requester_obj = ECCBlind(pubkey=signer_obj.pubkey()) 129 msg = os.urandom(64) 130 msg_blinded = requester_obj.create_signing_request(point_r, msg) 131 signature_blinded = signer_obj.blind_sign(msg_blinded) 132 signature = requester_obj.unblind(signature_blinded) 133 verifier_obj = ECCBlind(pubkey=signer_obj.pubkey()) 134 self.assertFalse(verifier_obj.verify(msg, signature)) 135 136 def test_blind_sig_chain(self): # pylint: disable=too-many-locals 137 """Test blind signature chain using a random certifier key and a random message""" 138 139 test_levels = 4 140 msg = os.urandom(1024) 141 142 ca = ECCBlind() 143 signer_obj = ca 144 145 output = bytearray() 146 147 for level in range(test_levels): 148 if not level: 149 output.extend(ca.pubkey()) 150 requester_obj = ECCBlind(pubkey=signer_obj.pubkey()) 151 child_obj = ECCBlind() 152 point_r = signer_obj.signer_init() 153 pubkey = child_obj.pubkey() 154 155 if level == test_levels - 1: 156 msg_blinded = requester_obj.create_signing_request(point_r, 157 msg) 158 else: 159 msg_blinded = requester_obj.create_signing_request(point_r, 160 pubkey) 161 signature_blinded = signer_obj.blind_sign(msg_blinded) 162 signature = requester_obj.unblind(signature_blinded) 163 if level != test_levels - 1: 164 output.extend(pubkey) 165 output.extend(signature) 166 signer_obj = child_obj 167 verifychain = ECCBlindChain(ca=ca.pubkey(), chain=bytes(output)) 168 self.assertTrue(verifychain.verify(msg=msg, value=1)) 169 170 def test_blind_sig_chain_wrong_ca(self): # pylint: disable=too-many-locals 171 """Test blind signature chain with an unlisted ca""" 172 173 test_levels = 4 174 msg = os.urandom(1024) 175 176 ca = ECCBlind() 177 fake_ca = ECCBlind() 178 signer_obj = fake_ca 179 180 output = bytearray() 181 182 for level in range(test_levels): 183 requester_obj = ECCBlind(pubkey=signer_obj.pubkey()) 184 child_obj = ECCBlind() 185 if not level: 186 # unlisted CA, but a syntactically valid pubkey 187 output.extend(fake_ca.pubkey()) 188 point_r = signer_obj.signer_init() 189 pubkey = child_obj.pubkey() 190 191 if level == test_levels - 1: 192 msg_blinded = requester_obj.create_signing_request(point_r, 193 msg) 194 else: 195 msg_blinded = requester_obj.create_signing_request(point_r, 196 pubkey) 197 signature_blinded = signer_obj.blind_sign(msg_blinded) 198 signature = requester_obj.unblind(signature_blinded) 199 if level != test_levels - 1: 200 output.extend(pubkey) 201 output.extend(signature) 202 signer_obj = child_obj 203 verifychain = ECCBlindChain(ca=ca.pubkey(), chain=bytes(output)) 204 self.assertFalse(verifychain.verify(msg, 1)) 205 206 def test_blind_sig_chain_wrong_msg(self): # pylint: disable=too-many-locals 207 """Test blind signature chain with a fake message""" 208 209 test_levels = 4 210 msg = os.urandom(1024) 211 fake_msg = os.urandom(1024) 212 213 ca = ECCBlind() 214 signer_obj = ca 215 216 output = bytearray() 217 218 for level in range(test_levels): 219 if not level: 220 output.extend(ca.pubkey()) 221 requester_obj = ECCBlind(pubkey=signer_obj.pubkey()) 222 child_obj = ECCBlind() 223 point_r = signer_obj.signer_init() 224 pubkey = child_obj.pubkey() 225 226 if level == test_levels - 1: 227 msg_blinded = requester_obj.create_signing_request(point_r, 228 msg) 229 else: 230 msg_blinded = requester_obj.create_signing_request(point_r, 231 pubkey) 232 signature_blinded = signer_obj.blind_sign(msg_blinded) 233 signature = requester_obj.unblind(signature_blinded) 234 if level != test_levels - 1: 235 output.extend(pubkey) 236 output.extend(signature) 237 signer_obj = child_obj 238 verifychain = ECCBlindChain(ca=ca.pubkey(), chain=bytes(output)) 239 self.assertFalse(verifychain.verify(fake_msg, 1)) 240 241 def test_blind_sig_chain_wrong_intermediary(self): # pylint: disable=too-many-locals 242 """Test blind signature chain using a fake intermediary pubkey""" 243 244 test_levels = 4 245 msg = os.urandom(1024) 246 wrong_level = 2 247 248 ca = ECCBlind() 249 signer_obj = ca 250 fake_intermediary = ECCBlind() 251 252 output = bytearray() 253 254 for level in range(test_levels): 255 if not level: 256 output.extend(ca.pubkey()) 257 requester_obj = ECCBlind(pubkey=signer_obj.pubkey()) 258 child_obj = ECCBlind() 259 point_r = signer_obj.signer_init() 260 pubkey = child_obj.pubkey() 261 262 if level == test_levels - 1: 263 msg_blinded = requester_obj.create_signing_request(point_r, 264 msg) 265 else: 266 msg_blinded = requester_obj.create_signing_request(point_r, 267 pubkey) 268 signature_blinded = signer_obj.blind_sign(msg_blinded) 269 signature = requester_obj.unblind(signature_blinded) 270 if level == wrong_level: 271 output.extend(fake_intermediary.pubkey()) 272 elif level != test_levels - 1: 273 output.extend(pubkey) 274 output.extend(signature) 275 signer_obj = child_obj 276 verifychain = ECCBlindChain(ca=ca.pubkey(), chain=bytes(output)) 277 self.assertFalse(verifychain.verify(msg, 1))