def test_ecssa(self): prv = 0x1 pub = ec.pointMultiply(prv, ec.G) msg = 'Satoshi Nakamoto' ssasig = ecssa_sign(msg, prv) self.assertTrue(ecssa_verify(msg, ssasig, pub)) # malleability malleated_sig = (ssasig[0], ec.order - ssasig[1]) self.assertFalse(ecssa_verify(msg, malleated_sig, pub)) self.assertEqual(ecssa_pubkey_recovery(msg, ssasig), pub)
def test_ecssa_4(self): pub = tuple_from_Point(ec, "03DEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34") msg = bytes.fromhex("4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703") sig = (0x00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C63, 0x02A8DC32E64E86A333F20EF56EAC9BA30B7246D6D25E22ADB8C6BE1AEB08D49D) self.assertTrue(ecssa_verify(msg, sig, pub)) # malleability self.assertFalse(ecssa_verify(msg, (sig[0], ec.n - sig[1]), pub)) e = sha256(sig[0].to_bytes(32, byteorder="big") + bytes_from_Point(ec, pub, True) + msg).digest() self.assertEqual(ecssa_pubkey_recovery(e, sig), pub)
def test_ecssa_7(self): """Incorrect sig: negated s value""" pub = tuple_from_Point(ec, "0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798") msg = b'\x00' * 32 sig = (0x787A848E71043D280C50470E8E1532B2DD5D20EE912A45DBDD2BD1DFBF187EF6, 0x8FCE5677CE7A623CB20011225797CE7A8DE1DC6CCD4F754A47DA6C600E59543C) self.assertFalse(ecssa_verify(msg, sig, pub))
def test_ecssa_6(self): """Incorrect sig: negated message hash""" pub = tuple_from_Point(ec, "03FAC2114C2FBB091527EB7C64ECB11F8021CB45E8E7809D3C0938E4B8C0E5F84B") msg = bytes.fromhex("5E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C") sig = (0x00DA9B08172A9B6F0466A2DEFD817F2D7AB437E0D253CB5395A963866B3574BE, 0xD092F9D860F1776A1F7412AD8A1EB50DACCC222BC8C0E26B2056DF2F273EFDEC) self.assertFalse(ecssa_verify(msg, sig, pub))
def test_ecssa_5(self): """Incorrect sig: incorrect R residuosity""" pub = tuple_from_Point(ec, "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659") msg = bytes.fromhex("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89") sig = (0x2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D, 0xFA16AEE06609280A19B67A24E1977E4697712B5FD2943914ECD5F730901B4AB7) self.assertFalse(ecssa_verify(msg, sig, pub))
def test_ecssa_3(self): prv = 0xC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C7 pub = ec.pointMultiply(prv, ec.G) msg = bytes.fromhex("5E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C") expected_sig = (0x00DA9B08172A9B6F0466A2DEFD817F2D7AB437E0D253CB5395A963866B3574BE, 0x00880371D01766935B92D2AB4CD5C8A2A5837EC57FED7660773A05F0DE142380) eph_prv = int.from_bytes(sha256(prv.to_bytes(32, byteorder="big") + msg).digest(), byteorder="big") sig = ecssa_sign(msg, prv, eph_prv) self.assertTrue(ecssa_verify(msg, sig, pub)) # malleability self.assertFalse(ecssa_verify(msg, (sig[0], ec.n - sig[1]), pub)) self.assertEqual(sig, expected_sig) e = sha256(sig[0].to_bytes(32, byteorder="big") + bytes_from_Point(ec, pub, True) + msg).digest() self.assertEqual(ecssa_pubkey_recovery(e, sig), pub)
def test_ecssa_2(self): prv = 0xB7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF pub = ec.pointMultiply(prv, ec.G) msg = bytes.fromhex("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89") expected_sig = (0x2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D, 0x1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD) eph_prv = int.from_bytes(sha256(prv.to_bytes(32, byteorder="big") + msg).digest(), byteorder="big") sig = ecssa_sign(msg, prv, eph_prv) self.assertTrue(ecssa_verify(msg, sig, pub)) # malleability self.assertFalse(ecssa_verify(msg, (sig[0], ec.n - sig[1]), pub)) self.assertEqual(sig, expected_sig) e = sha256(sig[0].to_bytes(32, byteorder="big") + bytes_from_Point(ec, pub, True) + msg).digest() self.assertEqual(ecssa_pubkey_recovery(e, sig), pub)
def test_ecssa_8(self): """Incorrect sig: negated public key""" pub = tuple_from_Point(ec, "03DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659") msg = bytes.fromhex("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89") sig = (0x2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D, 0x1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD) self.assertFalse(ecssa_verify(msg, sig, pub))
def test_ecssa_1(self): prv = 0x1 pub = ec.pointMultiply(prv, ec.G) msg = b'\x00' * 32 expected_sig = (0x787A848E71043D280C50470E8E1532B2DD5D20EE912A45DBDD2BD1DFBF187EF6, 0x7031A98831859DC34DFFEEDDA86831842CCD0079E1F92AF177F7F22CC1DCED05) eph_prv = int.from_bytes(sha256(prv.to_bytes(32, byteorder="big") + msg).digest(), byteorder="big") sig = ecssa_sign(msg, prv, eph_prv) self.assertTrue(ecssa_verify(msg, sig, pub)) # malleability self.assertFalse(ecssa_verify(msg, (sig[0], ec.n - sig[1]), pub)) self.assertEqual(sig, expected_sig) e = sha256(sig[0].to_bytes(32, byteorder="big") + bytes_from_Point(ec, pub, True) + msg).digest() self.assertEqual(ecssa_pubkey_recovery(e, sig), pub)
def test_ecssamusig(self): msg = 'message to sign' m = sha256(msg.encode()).digest() # first signer (is the message needed here? maybe for rfc6979?) prv1 = int_from_Scalar( ec, '0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d92ad1d') Q1 = ec.pointMultiply(prv1, ec.G) HQ1 = int_from_hash( sha256(bytes_from_Point(ec, Q1, False)).digest(), ec.order) prv1 = HQ1 * prv1 eph_prv1 = 0x012a2a833eac4e67e06611aba01345b85cdd4f5ad44f72e369ef0dd640424dbb R1 = ec.pointMultiply(eph_prv1, ec.G) if R1[1] % 2 == 1: #must be even eph_prv1 = ec.order - eph_prv1 R1 = ec.pointMultiply(eph_prv1, ec.G) R1_x = R1[0] # second signer (is the message needed here? maybe for rfc6979?) prv2 = int_from_Scalar( ec, '0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d') Q2 = ec.pointMultiply(prv2, ec.G) HQ2 = int_from_hash( sha256(bytes_from_Point(ec, Q2, False)).digest(), ec.order) prv2 = HQ2 * prv2 eph_prv2 = 0x01a2a0d3eac4e67e06611aba01345b85cdd4f5ad44f72e369ef0dd640424dbdb R2 = ec.pointMultiply(eph_prv2, ec.G) if R2[1] % 2 == 1: #must be even eph_prv2 = ec.order - eph_prv2 R2 = ec.pointMultiply(eph_prv2, ec.G) R2_x = R2[0] ###################### # exchange Rx, compute s ###################### # first signer use R2_x R2_y_recovered = ec.y(R2_x, 0) R2_recovered = (R2_x, R2_y_recovered) R1_All = ec.pointAdd(R1, R2_recovered) if R1_All[1] % 2 == 1: # must be even eph_prv1 = ec.order - eph_prv1 R1_All_x = R1_All[0].to_bytes(32, 'big') e1 = int_from_hash(sha256(R1_All_x + m).digest(), ec.order) assert e1 != 0 and e1 < ec.order, "sign fail" s1 = (eph_prv1 - e1 * prv1) % ec.order # second signer use R1_x R1_y_recovered = ec.y(R1_x, 0) R1_recovered = (R1_x, R1_y_recovered) R2_All = ec.pointAdd(R2, R1_recovered) if R2_All[1] % 2 == 1: eph_prv2 = ec.order - eph_prv2 R2_All_x = R2_All[0].to_bytes(32, 'big') e2 = int_from_hash(sha256(R2_All_x + m).digest(), ec.order) assert e2 != 0 and e2 < ec.order, "sign fail" s2 = (eph_prv2 - e2 * prv2) % ec.order ###################### # combine signatures into a single signature ###################### # anyone can do the following assert R1_All_x == R2_All_x, "sign fail" R_All_x = R1_All[0] s_All = (s1 + s2) % ec.order ssasig = (R_All_x, s_All) Q_All = ec.pointAdd(ec.pointMultiply(HQ1, Q1), ec.pointMultiply(HQ2, Q2)) self.assertTrue(ecssa_verify(msg, ssasig, Q_All, sha256))
def test_ecssamusig(self): msg = 'message to sign' m = sha256(msg.encode()).digest() # first signer (is the message needed here? maybe for rfc6979?) prv1 = int_from_Scalar( ec, '0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d92ad1d') Q1 = ec.pointMultiply(prv1, ec.G) HQ1 = int_from_hash( sha256(bytes_from_Point(ec, Q1, False)).digest(), ec.n) prv1 = HQ1 * prv1 eph_prv1 = 0x012a2a833eac4e67e06611aba01345b85cdd4f5ad44f72e369ef0dd640424dbb R1 = ec.pointMultiply(eph_prv1, ec.G) R1_x = R1[0] # break the simmetry: any criteria could be used, jacobi is standard if ec.jacobi(R1[1]) != 1: eph_prv1 = ec.n - eph_prv1 R1 = R1_x, ec.yQuadraticResidue(R1_x, True) #R1 = ec.pointMultiply(eph_prv1, ec.G) # second signer (is the message needed here? maybe for rfc6979?) prv2 = int_from_Scalar( ec, '0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d') Q2 = ec.pointMultiply(prv2, ec.G) HQ2 = int_from_hash( sha256(bytes_from_Point(ec, Q2, False)).digest(), ec.n) prv2 = HQ2 * prv2 eph_prv2 = 0x01a2a0d3eac4e67e06611aba01345b85cdd4f5ad44f72e369ef0dd640424dbdb R2 = ec.pointMultiply(eph_prv2, ec.G) R2_x = R2[0] # break the simmetry: any criteria could be used, jacobi is standard if ec.jacobi(R2[1]) != 1: eph_prv2 = ec.n - eph_prv2 R2 = R2_x, ec.yQuadraticResidue(R2_x, True) #R2 = ec.pointMultiply(eph_prv2, ec.G) Q_All = ec.pointAdd(ec.pointMultiply(HQ1, Q1), ec.pointMultiply(HQ2, Q2)) # joint public key ######################## # exchange Rx, compute s # first signer use R2_x # break the simmetry: any criteria could be used, jacobi is standard y = ec.yQuadraticResidue(R2_x, True) R2_recovered = (R2_x, y) R1_All = ec.pointAdd(R1, R2_recovered) # break the simmetry: any criteria could be used, jacobi is standard if ec.jacobi(R1_All[1]) != 1: # no need to actually change R1_All[1], as it is not used anymore # let's fix eph_prv1 instead, as it is used later eph_prv1 = ec.n - eph_prv1 e1 = int_from_hash( sha256(R1_All[0].to_bytes(32, byteorder="big") + bytes_from_Point(ec, Q_All, True) + m).digest(), ec.n) assert e1 != 0 and e1 < ec.n, "sign fail" s1 = (eph_prv1 + e1 * prv1) % ec.n # second signer use R1_x # break the simmetry: any criteria could be used, jacobi is standard y = ec.yQuadraticResidue(R1_x, True) R1_recovered = (R1_x, y) R2_All = ec.pointAdd(R2, R1_recovered) # break the simmetry: any criteria could be used, jacobi is standard if ec.jacobi(R2_All[1]) != 1: # no need to actually change R2_All[1], as it is not used anymore # let's fix eph_prv2 instead, as it is used later eph_prv2 = ec.n - eph_prv2 e2 = int_from_hash( sha256(R2_All[0].to_bytes(32, byteorder="big") + bytes_from_Point(ec, Q_All, True) + m).digest(), ec.n) assert e2 != 0 and e2 < ec.n, "sign fail" s2 = (eph_prv2 + e2 * prv2) % ec.n ############################################ # combine signatures into a single signature # anyone can do the following assert R1_All[0] == R2_All[0], "sign fail" s_All = (s1 + s2) % ec.n ssasig = (R1_All[0], s_All) self.assertTrue(ecssa_verify(msg, ssasig, Q_All, sha256))