def test_crack_prvkey() -> None: ec = CURVES["secp256k1"] q = 0x19E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725 x_Q = mult(q)[0] msg1_str = "Paolo is afraid of ephemeral random numbers" msg1 = hf(msg1_str.encode()).digest() k, _ = ssa._det_nonce(msg1, q) sig1 = ssa._sign(msg1, q, k) msg2_str = "and Paolo is right to be afraid" msg2 = hf(msg2_str.encode()).digest() # reuse same k sig2 = ssa._sign(msg2, q, k) qc, kc = ssa._crack_prvkey(msg1, sig1, msg2, sig2, x_Q) assert q in (qc, ec.n - qc) assert k in (kc, ec.n - kc) with pytest.raises(ValueError, match="not the same r in signatures"): ssa._crack_prvkey(msg1, sig1, msg2, (16, sig1[1]), x_Q) with pytest.raises(ValueError, match="identical signatures"): ssa._crack_prvkey(msg1, sig1, msg1, sig1, x_Q)
def test_crack_prvkey(self): q = 0x6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725DEADBEEF x_Q = mult(q)[0] k = 1010101010101010101 msg1 = "Paolo is afraid of ephemeral random numbers" msg1 = hf(msg1.encode()).digest() sig1 = ssa.sign(msg1, q, k) # print(f'\nmsg1: {msg1.hex().upper()}') # print(f' r1: {hex(sig1[0]).upper()}') # print(f' s1: {hex(sig1[1]).upper()}') msg2 = "and Paolo is right to be afraid" msg2 = hf(msg2.encode()).digest() sig2 = ssa.sign(msg2, q, k) # print(f'\nmsg2: {msg2.hex().upper()}') # print(f' r2: {hex(sig2[0]).upper()}') # print(f' s2: {hex(sig2[1]).upper()}') qc, kc = ssa.crack_prvkey(msg1, sig1, msg2, sig2, x_Q) self.assertIn(q, (qc, ec.n - qc)) self.assertIn(k, (kc, ec.n - kc)) self.assertRaises(ValueError, ssa.crack_prvkey, msg1, sig1, msg2, (16, sig1[1]), x_Q) self.assertRaises(ValueError, ssa.crack_prvkey, msg1, sig1, msg1, sig1, x_Q)
def test_ecssa(self): """Basic tests""" ec = secp256k1 q = 0x1 Q = mult(ec, q, ec.G) msg = hf('Satoshi Nakamoto'.encode()).digest() sig = ssa.sign(ec, hf, msg, q, None) # no source for the following... but # https://bitcointalk.org/index.php?topic=285142.40 # same r because of rfc6979 exp_sig = ( 0x934B1EA10A4B3C1757E2B0C017D0B6143CE3C9A7E6A4A49860D7A6AB210EE3D8, 0x2DF2423F70563E3C4BD0E00BDEF658081613858F110ECF937A2ED9190BF4A01A) self.assertEqual(sig[0], exp_sig[0]) self.assertEqual(sig[1], exp_sig[1]) ssa._verify(ec, hf, msg, Q, sig) self.assertTrue(ssa.verify(ec, hf, msg, Q, sig)) self.assertTrue(ssa._verify(ec, hf, msg, Q, sig)) fmsg = hf('Craig Wright'.encode()).digest() self.assertFalse(ssa.verify(ec, hf, fmsg, Q, sig)) self.assertFalse(ssa._verify(ec, hf, fmsg, Q, sig)) fssasig = (sig[0], sig[1], sig[1]) self.assertFalse(ssa.verify(ec, hf, msg, Q, fssasig)) self.assertRaises(TypeError, ssa._verify, ec, hf, msg, Q, fssasig) # y(sG - eP) is not a quadratic residue fq = 0x2 fQ = mult(ec, fq, ec.G) self.assertFalse(ssa.verify(ec, hf, msg, fQ, sig)) self.assertRaises(ValueError, ssa._verify, ec, hf, msg, fQ, sig) fq = 0x4 fQ = mult(ec, fq, ec.G) self.assertFalse(ssa.verify(ec, hf, msg, fQ, sig)) self.assertFalse(ssa._verify(ec, hf, msg, fQ, sig)) # not ec.pIsThreeModFour self.assertFalse(ssa.verify(secp224k1, hf, msg, Q, sig)) self.assertRaises(ValueError, ssa._verify, secp224k1, hf, msg, Q, sig) # verify: message of wrong size wrongmsg = msg[:-1] self.assertFalse(ssa.verify(ec, hf, wrongmsg, Q, sig)) self.assertRaises(ValueError, ssa._verify, ec, hf, wrongmsg, Q, sig) #ssa._verify(ec, hf, wrongmsg, Q, sig) # sign: message of wrong size self.assertRaises(ValueError, ssa.sign, ec, hf, wrongmsg, q, None) #ssa.sign(ec, hf, wrongmsg, q, None) # invalid (zero) challenge e self.assertRaises(ValueError, ssa._pubkey_recovery, ec, hf, 0, sig)
def assert_as_valid(msg: bytes, e0: bytes, s: SValues, pubk_rings: PubkeyRing) -> bool: ring_size = len(pubk_rings) m = _get_msg_format(msg, pubk_rings) e: SValues = defaultdict(list) e0bytes = m for i in range(ring_size): keys_size = len(pubk_rings[i]) e[i] = [0] * keys_size e[i][0] = int_from_bits(_hash(m, e0, i, 0), ec.nlen) % ec.n # edge case that cannot be reproduced in the test suite assert e[i][0] != 0, "implausibile signature failure" R = b"\0x00" for j in range(keys_size): T = double_mult(-e[i][j], pubk_rings[i][j], s[i][j], ec.G) R = bytes_from_point(T, ec) if j != len(pubk_rings[i]) - 1: h = _hash(m, R, i, j + 1) e[i][j + 1] = int_from_bits(h, ec.nlen) % ec.n # edge case that cannot be reproduced in the test suite assert e[i][j + 1] != 0, "implausibile signature failure" else: e0bytes += R e0_prime = hf(e0bytes).digest() return e0_prime == e0
def _get_msg_format(msg: bytes, pubk_rings: PubkeyRing) -> bytes: t = b"".join( b"".join(bytes_from_point(Q, ec) for Q in pubk_ring) for pubk_ring in pubk_rings.values() ) return hf(msg + t).digest()
def assert_as_valid(msg: Octets, e0: bytes, s: SValues, pubk_rings: PubkeyRing) -> bool: msg = bytes_from_octets(msg) m = _get_msg_format(msg, pubk_rings) ring_size = len(pubk_rings) e: SValues = defaultdict(list) e0bytes = m for i in range(ring_size): keys_size = len(pubk_rings[i]) e[i] = [0] * keys_size e[i][0] = int_from_bits(_hash(m, e0, i, 0), ec.nlen) % ec.n # edge case that cannot be reproduced in the test suite if e[i][0] == 0: err_msg = "implausibile signature failure" # pragma: no cover raise BTClibRuntimeError(err_msg) # pragma: no cover r = b"\0x00" for j in range(keys_size): t = double_mult(-e[i][j], pubk_rings[i][j], s[i][j], ec.G) r = bytes_from_point(t, ec) if j != len(pubk_rings[i]) - 1: h = _hash(m, r, i, j + 1) e[i][j + 1] = int_from_bits(h, ec.nlen) % ec.n # edge case that cannot be reproduced in the test suite if e[i][j + 1] == 0: err_msg = "implausibile signature failure" # pragma: no cover raise BTClibRuntimeError(err_msg) # pragma: no cover else: e0bytes += r e0_prime = hf(e0bytes).digest() return e0_prime == e0
def sign( msg: String, ks: Sequence[int], sign_key_idx: Sequence[int], sign_keys: Sequence[int], pubk_rings: PubkeyRing, ) -> Tuple[bytes, SValues]: """Borromean ring signature - signing algorithm https://github.com/ElementsProject/borromean-signatures-writeup https://github.com/Blockstream/borromean_paper/blob/master/borromean_draft_0.01_9ade1e49.pdf inputs: - msg: message to be signed (bytes) - sign_key_idx: list of indexes representing each signing key per ring - sign_keys: list containing the whole set of signing keys (one per ring) - pubk_rings: dictionary of sequences representing single rings of pubkeys """ if isinstance(msg, str): msg = msg.encode() m = _get_msg_format(msg, pubk_rings) e0bytes = m s: SValues = defaultdict(list) e: SValues = defaultdict(list) # step 1 for i, (pubk_ring, j_star, k) in enumerate(zip(pubk_rings.values(), sign_key_idx, ks)): keys_size = len(pubk_ring) s[i] = [0] * keys_size e[i] = [0] * keys_size start_idx = (j_star + 1) % keys_size R = bytes_from_point(mult(k), ec) if start_idx != 0: for j in range(start_idx, keys_size): s[i][j] = secrets.randbits(256) e[i][j] = int_from_bits(_hash(m, R, i, j), ec.nlen) % ec.n # edge case that cannot be reproduced in the test suite assert 0 < e[i][j] < ec.n, "implausibile signature failure" T = double_mult(-e[i][j], pubk_ring[j], s[i][j], ec.G) R = bytes_from_point(T, ec) e0bytes += R e0 = hf(e0bytes).digest() # step 2 for i, (j_star, k) in enumerate(zip(sign_key_idx, ks)): e[i][0] = int_from_bits(_hash(m, e0, i, 0), ec.nlen) % ec.n # edge case that cannot be reproduced in the test suite assert 0 < e[i][0] < ec.n, "implausibile signature failure" for j in range(1, j_star + 1): s[i][j - 1] = secrets.randbits(256) T = double_mult(-e[i][j - 1], pubk_rings[i][j - 1], s[i][j - 1], ec.G) R = bytes_from_point(T, ec) e[i][j] = int_from_bits(_hash(m, R, i, j), ec.nlen) % ec.n # edge case that cannot be reproduced in the test suite assert 0 < e[i][j] < ec.n, "implausibile signature failure" s[i][j_star] = k + sign_keys[i] * e[i][j_star] return e0, s
def _get_msg_format(msg: bytes, pubk_rings: PubkeyRing) -> bytes: m = msg rings = len(pubk_rings) for i in range(rings): for P in pubk_rings[i]: Pbytes = octets_from_point(P, True, ec) m += Pbytes return hf(m).digest()
def test_batch_validation() -> None: ec = CURVES["secp256k1"] hsize = hf().digest_size hlen = hsize * 8 ms = [] Qs = [] sigs = [] ms.append(secrets.randbits(hlen).to_bytes(hsize, "big")) q = 1 + secrets.randbelow(ec.n - 1) # bytes version Qs.append(mult(q, ec.G, ec)[0]) sigs.append(ssa._sign(ms[0], q, None, ec, hf)) # test with only 1 sig ssa._batch_verify(ms, Qs, sigs, ec, hf) for _ in range(3): m = secrets.randbits(hlen).to_bytes(hsize, "big") ms.append(m) q = 1 + secrets.randbelow(ec.n - 1) # Point version Qs.append(mult(q, ec.G, ec)[0]) sigs.append(ssa._sign(m, q, None, ec, hf)) ssa._batch_verify(ms, Qs, sigs, ec, hf) assert ssa.batch_verify(ms, Qs, sigs, ec, hf) ms.append(ms[0]) sigs.append(sigs[1]) Qs.append(Qs[0]) assert not ssa.batch_verify(ms, Qs, sigs, ec, hf) err_msg = "signature verification precondition failed" with pytest.raises(ValueError, match=err_msg): ssa._batch_verify(ms, Qs, sigs, ec, hf) sigs[-1] = sigs[0] # valid again ms[-1] = ms[0][:-1] err_msg = "invalid size: 31 bytes instead of 32" with pytest.raises(ValueError, match=err_msg): ssa._batch_verify(ms, Qs, sigs, ec, hf) ms[-1] = ms[0] # valid again ms.append(ms[0]) # add extra message err_msg = "mismatch between number of pubkeys " with pytest.raises(ValueError, match=err_msg): ssa._batch_verify(ms, Qs, sigs, ec, hf) ms.pop() # valid again sigs.append(sigs[0]) # add extra sig err_msg = "mismatch between number of pubkeys " with pytest.raises(ValueError, match=err_msg): ssa._batch_verify(ms, Qs, sigs, ec, hf) sigs.pop() # valid again err_msg = "field prime is not equal to 3 mod 4: " with pytest.raises(ValueError, match=err_msg): ssa._batch_verify(ms, Qs, sigs, CURVES["secp224k1"], hf)
def test_signature(self): """Basic tests""" q, x_Q = ssa.gen_keys() mhd = hf(b'Satoshi Nakamoto').digest() sig = ssa.sign(mhd, q, None) self.assertEqual(sig, ssa.deserialize(sig)) ssa._verify(mhd, x_Q, sig, ec, hf) self.assertTrue(ssa.verify(mhd, x_Q, sig)) fmhd = hf(b'Craig Wright').digest() self.assertRaises(AssertionError, ssa._verify, fmhd, x_Q, sig, ec, hf) fssasig = (sig[0], sig[1], sig[1]) self.assertRaises(ValueError, ssa._verify, mhd, x_Q, fssasig, ec, hf) # y(sG - eP) is not a quadratic residue _, fQ = ssa.gen_keys(0x2) self.assertRaises(AssertionError, ssa._verify, mhd, fQ, sig, ec, hf) _, fQ = ssa.gen_keys(0x4) self.assertRaises(AssertionError, ssa._verify, mhd, fQ, sig, ec, hf) # not ec.pIsThreeModFour self.assertRaises(ValueError, ssa._verify, mhd, x_Q, sig, secp224k1, hf) # verify: message of wrong size wrongmhd = mhd[:-1] self.assertRaises(ValueError, ssa._verify, wrongmhd, x_Q, sig, ec, hf) # ssa._verify(wrongmhd, x_Q, sig) # sign: message of wrong size self.assertRaises(ValueError, ssa.sign, wrongmhd, q, None) # ssa.sign(wrongmhd, q, None) # invalid (zero) challenge e self.assertRaises(ValueError, ssa._recover_pubkeys, 0, sig[0], sig[1], ec) # ssa._recover_pubkeys(0, sig) # not a BIP340 public key self.assertRaises(ValueError, ssa._to_bip340_point, ["not", "a BIP340", "public key"])
def test_ecssa(self): """Basic tests""" q = 0x1 Q = mult(q) mhd = hf(b'Satoshi Nakamoto').digest() sig = ssa.sign(mhd, q, None) ssa._verify(mhd, Q, sig, ec, hf) self.assertTrue(ssa.verify(mhd, Q, sig)) fmhd = hf(b'Craig Wright').digest() self.assertRaises(AssertionError, ssa._verify, fmhd, Q, sig, ec, hf) fssasig = (sig[0], sig[1], sig[1]) self.assertRaises(ValueError, ssa._verify, mhd, Q, fssasig, ec, hf) # y(sG - eP) is not a quadratic residue fq = 0x2 fQ = mult(fq) self.assertRaises(ValueError, ssa._verify, mhd, fQ, sig, ec, hf) fq = 0x4 fQ = mult(fq) self.assertRaises(AssertionError, ssa._verify, mhd, fQ, sig, ec, hf) # not ec.pIsThreeModFour self.assertRaises(ValueError, ssa._verify, mhd, Q, sig, secp224k1, hf) # verify: message of wrong size wrongmhd = mhd[:-1] self.assertRaises(ValueError, ssa._verify, wrongmhd, Q, sig, ec, hf) #ssa._verify(wrongmhd, Q, sig) # sign: message of wrong size self.assertRaises(ValueError, ssa.sign, wrongmhd, q, None) #ssa.sign(wrongmhd, q, None) # invalid (zero) challenge e self.assertRaises(ValueError, ssa._recover_pubkeys, 0, sig[0], sig[1], ec) #ssa._recover_pubkeys(0, sig) # not a BIP340 public key self.assertRaises(ValueError, ssa.to_bip340_pubkey_tuple, ["not", "a BIP340", "public key"])
def _magic_hash(msg: str) -> bytes: # Electrum does strip leading and trailing spaces; # bitcoin core does not # msg = msg.strip() m = hf() prefix = b'\x18Bitcoin Signed Message:\n' m.update(prefix) message = chr(len(msg)) + msg m.update(message.encode()) return m.digest()
def test_batch_validation(self): hsize = hf().digest_size hlen = hsize * 8 ms = [] Qs = [] sigs = [] ms.append(secrets.randbits(hlen).to_bytes(hsize, 'big')) q = 1 + secrets.randbelow(ec.n - 1) # bytes version Qs.append(mult(q, ec.G, ec)[0].to_bytes(ec.psize, 'big')) sigs.append(ssa.sign(ms[0], q, None, ec, hf)) # test with only 1 sig ssa._batch_verify(ms, Qs, sigs, ec, hf) for _ in range(3): mhd = secrets.randbits(hlen).to_bytes(hsize, 'big') ms.append(mhd) q = 1 + secrets.randbelow(ec.n - 1) # Point version Qs.append(mult(q, ec.G, ec)) sigs.append(ssa.sign(mhd, q, None, ec, hf)) ssa._batch_verify(ms, Qs, sigs, ec, hf) self.assertTrue(ssa.batch_verify(ms, Qs, sigs, ec, hf)) # invalid sig ms.append(ms[0]) sigs.append(sigs[1]) Qs.append(Qs[0]) self.assertFalse(ssa.batch_verify(ms, Qs, sigs, ec, hf)) self.assertRaises(AssertionError, ssa._batch_verify, ms, Qs, sigs, ec, hf) # ssa._batch_verify(ms, Qs, sigs, ec, hf) sigs[-1] = sigs[0] # valid again # Invalid size: 31 bytes instead of 32 ms[-1] = ms[0][:-1] self.assertRaises(ValueError, ssa._batch_verify, ms, Qs, sigs, ec, hf) # ssa._batch_verify(ms, Qs, sigs, ec, hf) ms[-1] = ms[0] # valid again # mismatch between number of pubkeys (5) and number of messages (6) ms.append(ms[0]) # add extra message self.assertRaises(ValueError, ssa._batch_verify, ms, Qs, sigs, ec, hf) # ssa._batch_verify(ms, Qs, sigs, ec, hf) ms.pop() # valid again # mismatch between number of pubkeys (5) and number of signatures (6) sigs.append(sigs[0]) # add extra sig self.assertRaises(ValueError, ssa._batch_verify, ms, Qs, sigs, ec, hf) # ssa._batch_verify(ms, Qs, sigs, ec, hf) sigs.pop() # valid again # field prime p is not equal to 3 (mod 4) self.assertRaises(ValueError, ssa._batch_verify, ms, Qs, sigs, secp224k1, hf)
def sign(msg: String, k: Sequence[int], sign_key_idx: Sequence[int], sign_keys: Sequence[int], pubk_rings: PubkeyRing) -> Tuple[bytes, SValues]: """Borromean ring signature - signing algorithm https://github.com/ElementsProject/borromean-signatures-writeup https://github.com/Blockstream/borromean_paper/blob/master/borromean_draft_0.01_9ade1e49.pdf inputs: - msg: message to be signed (bytes) - sign_key_idx: list of indexes representing each signing key per ring - sign_keys: list containing the whole set of signing keys (one per ring) - pubk_rings: dictionary of sequences representing single rings of pubkeys """ if isinstance(msg, str): msg = msg.encode() m = _get_msg_format(msg, pubk_rings) e0bytes = m s: SValues = defaultdict(list) e: SValues = defaultdict(list) ring_size = len(pubk_rings) # step 1 for i in range(ring_size): keys_size = len(pubk_rings[i]) s[i] = [0] * keys_size e[i] = [0] * keys_size j_star = sign_key_idx[i] start_idx = (j_star + 1) % keys_size R = bytes_from_point(mult(k[i]), ec) if start_idx != 0: for j in range(start_idx, keys_size): s[i][j] = random.getrandbits(256) e[i][j] = int_from_bits(_hash(m, R, i, j), ec.nlen) % ec.n assert 0 < e[i][j] < ec.n, "sign fail: how did you do that?!?" T = double_mult(-e[i][j], pubk_rings[i][j], s[i][j], ec.G) R = bytes_from_point(T, ec) e0bytes += R e0 = hf(e0bytes).digest() # step 2 for i in range(ring_size): e[i][0] = int_from_bits(_hash(m, e0, i, 0), ec.nlen) % ec.n assert 0 < e[i][0] < ec.n, "sign fail: how did you do that?!?" j_star = sign_key_idx[i] for j in range(1, j_star + 1): s[i][j - 1] = random.getrandbits(256) T = double_mult(-e[i][j - 1], pubk_rings[i][j - 1], s[i][j - 1], ec.G) R = bytes_from_point(T, ec) e[i][j] = int_from_bits(_hash(m, R, i, j), ec.nlen) % ec.n assert 0 < e[i][j] < ec.n, "sign fail: how did you do that?!?" s[i][j_star] = k[i] + sign_keys[i] * e[i][j_star] return e0, s
def test_batch_validation(self): ec = secp256k1 m = [] sig = [] Q = [] hsize = hf().digest_size hlen = hsize * 8 m.append(random.getrandbits(hlen).to_bytes(hsize, 'big')) q = (1 + random.getrandbits(ec.nlen)) % ec.n sig.append(ssa.sign(ec, hf, m[0], q)) Q.append(mult(ec, q, ec.G)) # test with only 1 sig self.assertTrue(ssa.batch_verify(ec, hf, m, Q, sig)) for i in range(1, 4): m.append(random.getrandbits(hlen).to_bytes(hsize, 'big')) q = (1 + random.getrandbits(ec.nlen)) % ec.n sig.append(ssa.sign(ec, hf, m[i], q)) Q.append(mult(ec, q, ec.G)) self.assertTrue(ssa.batch_verify(ec, hf, m, Q, sig)) # invalid sig m.append(m[0]) sig.append(sig[1]) Q.append(Q[0]) self.assertFalse(ssa.batch_verify(ec, hf, m, Q, sig)) #ssa._batch_verify(ec, hf, m, Q, sig) sig[-1] = sig[0] # valid again # invalid 31 bytes message m[-1] = m[0][:-1] self.assertFalse(ssa.batch_verify(ec, hf, m, Q, sig)) #ssa._batch_verify(ec, hf, m, Q, sig) m[-1] = m[0] # valid again # mismatch between number of pubkeys and number of messages m.append(m[0]) # add extra message self.assertRaises(ValueError, ssa._batch_verify, ec, hf, m, Q, sig) #ssa._batch_verify(ec, hf, m, Q, sig) m.pop() # valid again # mismatch between number of pubkeys and number of signatures sig.append(sig[0]) # add extra sig self.assertRaises(ValueError, ssa._batch_verify, ec, hf, m, Q, sig) #ssa._batch_verify(ec, hf, m, Q, sig) sig.pop() # valid again # curve prime p must be equal to 3 (mod 4) ec = secp224k1 self.assertRaises(ValueError, ssa._batch_verify, ec, hf, m, Q, sig)
def HashDir(Dir, File): import os from datetime import datetime from hashlib import md5 as hf from HashFile import HashFile from GetDirSize import GetDirSize tfmt = '%Y-%m-%d %H:%M:%S' outfile = open(File, 'w') t1 = datetime.now() outfile.write('Begin ' + t1.strftime(tfmt) + '\n') outfile.write(Dir + '\n') str1 = 'Name\tSize\tmdate' str1 += '\tMD5' outfile.write(str1 + '\n') dirsize = GetDirSize(Dir) hashd = hf() dsize = 0 fnum = 0 for root, subdirs, files in os.walk(Dir): for file in files: filefullpath = os.path.join(root, file) print('\n' + filefullpath, end=" ") filerelpath = os.path.relpath(filefullpath, Dir) fst = os.stat(filefullpath) str_fsize = '{:,}'.format(fst.st_size) print(str_fsize, end="") dsize += fst.st_size fnum += 1 ctime = datetime.fromtimestamp(fst.st_ctime) str_ctime = ctime.strftime(tfmt) mtime = datetime.fromtimestamp(fst.st_mtime) str_mtime = mtime.strftime(tfmt) hashf = HashFile(filefullpath) print(' %d' % (dsize / dirsize * 100.0) + '%') hashd.update(hashf.digest()) outfile.write(filerelpath + '\t' + str_fsize + '\t' + str_mtime + '\t' + hashf.hexdigest() + '\n') str_total = 'Total %d Files(\t' % (fnum) + '{:,}'.format( dsize) + '\t Bytes) \t' + hashd.hexdigest() print('\n\n' + str_total) outfile.write(str_total + '\n') t2 = datetime.now() outfile.write('Finished ' + t2.strftime(tfmt) + '\n') speed = dsize / ((t2 - t1).seconds + (t2 - t1).microseconds / 1e6) str_time = 'Total: ' + str(t2 - t1) + ' %.1fMB/s\n' % (speed / 2**20) print('\n' + str_time) outfile.write(str_time) outfile.close() print('Sum File: ' + File)
def test_signtocontract(self): prv = 0x1 pub = mult(ec, prv, ec.G) m = "to be signed".encode() c = "to be committed".encode() dsa_sig, dsa_receipt = ecdsa_commit_sign(c, ec, hf, m, prv, None) self.assertTrue(dsa.verify(ec, hf, m, pub, dsa_sig)) self.assertTrue(verify_commit(c, ec, hf, dsa_receipt)) # 32 bytes message for ECSSA m = hf(m).digest() ssa_sig, ssa_receipt = ecssa_commit_sign(c, ec, hf, m, prv, None) self.assertTrue(ssa.verify(ec, hf, m, pub, ssa_sig)) self.assertTrue(verify_commit(c, ec, hf, ssa_receipt))
def HashFile(filefullpath, block=2**20): f = open(filefullpath, 'rb') m = hf() i = 0 while True: i += 1 if i >= 10: sys.stdout.write('.') i = 0 data = f.read(block) if not data: break m.update(data) f.close() return m
def HashFile(filefullpath, block=2**20): from hashlib import md5 as hf import sys f = open(filefullpath, 'rb') h = hf() i = 0 while True: i += 1 if i >= 10: sys.stdout.write('.') i = 0 data = f.read(block) if not data: break h.update(data) f.close() return h
def HF1(ffp, block=2**20, Method='MD5'): from hashlib import md5 as hf import sys f = open(ffp, 'rb') h = hf() i = 0 while True: i += 1 if i >= 10: sys.stdout.write('.') i = 0 data = f.read(block) if not data: break h.update(data) f.close() return h.hexdigest()
def test_low_cardinality(self): """test low-cardinality curves for all msg/key pairs.""" # ec.n has to be prime to sign prime = [11, 13, 17, 19] # for dsa it is possible to directy iterate on all # possible values for e; # for ssa we have to iterate over all possible hash values hsize = hf().digest_size H = [i.to_bytes(hsize, 'big') for i in range(max(prime) * 4)] # only low card curves or it would take forever for ec in low_card_curves: if ec._p in prime: # only few curves or it would take too long # BIP340 Schnorr only applies to curve whose prime p = 3 %4 if not ec.pIsThreeModFour: self.assertRaises(ValueError, ssa.sign, H[0], 1, None, ec) continue for q in range(1, ec.n): # all possible private keys Q = mult(q, ec.G, ec) # public key if not ec.has_square_y(Q): q = ec.n - q for h in H: # all possible hashed messages k = ssa.k(h, q, ec, hf) K = mult(k, ec.G, ec) if not ec.has_square_y(K): k = ec.n - k x_K = K[0] try: c = ssa._challenge(x_K, Q[0], h, ec, hf) except Exception: pass else: s = (k + c * q) % ec.n sig = ssa.sign(h, q, None, ec) self.assertEqual((x_K, s), sig) # valid signature must validate self.assertIsNone(ssa._verify(h, Q, sig, ec, hf)) if c != 0: # FIXME x_Q = ssa._recover_pubkeys(c, x_K, s, ec) self.assertEqual(Q[0], x_Q)
def _verify(msg: bytes, e0: bytes, s: SValues, pubk_rings: PubkeyRing) -> bool: ring_size = len(pubk_rings) m = _get_msg_format(msg, pubk_rings) e: Dict[int, Sequence[int]] = defaultdict(list) e0bytes = m for i in range(ring_size): keys_size = len(pubk_rings[i]) e[i] = [0]*keys_size e[i][0] = int_from_bits(_hash(m, e0, i, 0), ec) assert e[i][0] != 0, "invalid sig: how did you do that?!?" R = b'\0x00' for j in range(keys_size): T = double_mult(-e[i][j], pubk_rings[i][j], s[i][j]) R = octets_from_point(T, True, ec) if j != len(pubk_rings[i])-1: e[i][j+1] = int_from_bits(_hash(m, R, i, j+1), ec) assert e[i][j+1] != 0, "invalid sig: how did you do that?!?" else: e0bytes += R e0_prime = hf(e0bytes).digest() return e0_prime == e0
def assert_as_valid(msg: bytes, e0: bytes, s: SValues, pubk_rings: PubkeyRing) -> bool: ring_size = len(pubk_rings) m = _get_msg_format(msg, pubk_rings) e: SValues = defaultdict(list) e0bytes = m for i in range(ring_size): keys_size = len(pubk_rings[i]) e[i] = [0] * keys_size e[i][0] = int_from_bits(_hash(m, e0, i, 0), ec.nlen) % ec.n assert e[i][0] != 0, "invalid sig: how did you do that?!?" R = b"\0x00" for j in range(keys_size): T = double_mult(-e[i][j], pubk_rings[i][j], s[i][j], ec.G) R = bytes_from_point(T, ec) if j != len(pubk_rings[i]) - 1: h = _hash(m, R, i, j + 1) e[i][j + 1] = int_from_bits(h, ec.nlen) % ec.n assert e[i][j + 1] != 0, "invalid sig: how did you do that?!?" else: e0bytes += R e0_prime = hf(e0bytes).digest() return e0_prime == e0
def test_batch_validation(self): ec = secp256k1 m = [] sig = [] Q = [] hsize = hf().digest_size hlen = hsize * 8 for i in range(10): m.append(random.getrandbits(hlen).to_bytes(hsize, 'big')) q = random.getrandbits(ec.nlen) % ec.n sig.append(ssa.sign(ec, hf, m[i], q)) Q.append(mult(ec, q, ec.G)) self.assertTrue(ssa.batch_verify(ec, hf, m, Q, sig)) m.append(m[0]) sig.append(sig[1]) # invalid Q.append(Q[0]) self.assertFalse(ssa.batch_verify(ec, hf, m, Q, sig)) sig[-1] = sig[0] # valid m[-1] = m[0][:-1] # invalid 31 bytes message self.assertFalse(ssa.batch_verify(ec, hf, m, Q, sig))
# # This file is part of btclib. It is subject to the license terms in the # LICENSE file found in the top-level directory of this distribution. # # No part of btclib including this file, may be copied, modified, propagated, # or distributed except according to the terms contained in the LICENSE file. """ Deterministic Wallet (Type-1) """ import random from hashlib import sha256 as hf from btclib.curve import mult from btclib.curves import secp256k1 as ec from btclib.utils import int_from_bits # master prvkey mprvkey = random.getrandbits(ec.nlen) % ec.n print('\nmaster private key =', hex(mprvkey)) mprvkey_bytes = mprvkey.to_bytes(ec.nlen, 'big') nKeys = 3 for i in range(nKeys): ibytes = i.to_bytes(ec.nlen, 'big') hd = hf(ibytes + mprvkey_bytes).digest() q = int_from_bits(ec, hd) Q = mult(ec, q, ec.G) print('\nprvkey#', i, ':', hex(q)) print('Pubkey#', i, ':', hex(Q[0])) print(' ', hex(Q[1]))
def _get_msg_format(msg: bytes, pubk_rings: PubkeyRing) -> bytes: rings = len(pubk_rings) for i in range(rings): for P in pubk_rings[i]: msg += bytes_from_point(P, ec) return hf(msg).digest()
def _hash(m: bytes, R: bytes, i: int, j: int) -> bytes: temp = m + R temp += i.to_bytes(4, byteorder='big') + j.to_bytes(4, byteorder='big') return hf(temp).digest()
def test_musig() -> None: """testing 3-of-3 MuSig. https://github.com/ElementsProject/secp256k1-zkp/blob/secp256k1-zkp/src/modules/musig/musig.md https://blockstream.com/2019/02/18/musig-a-new-multisignature-standard/ https://eprint.iacr.org/2018/068 https://blockstream.com/2018/01/23/musig-key-aggregation-schnorr-signatures.html https://medium.com/@snigirev.stepan/how-schnorr-signatures-may-improve-bitcoin-91655bcb4744 """ ec = CURVES["secp256k1"] m = hf(b"message to sign").digest() # the signers private and public keys, # including both the curve Point and the BIP340-Schnorr public key q1, x_Q1_int = ssa.gen_keys() x_Q1 = x_Q1_int.to_bytes(ec.psize, "big") q2, x_Q2_int = ssa.gen_keys() x_Q2 = x_Q2_int.to_bytes(ec.psize, "big") q3, x_Q3_int = ssa.gen_keys() x_Q3 = x_Q3_int.to_bytes(ec.psize, "big") # (non interactive) key setup # this is MuSig core: the rest is just Schnorr signature additivity # 1. lexicographic sorting of public keys keys: List[bytes] = [] keys.append(x_Q1) keys.append(x_Q2) keys.append(x_Q3) keys.sort() # 2. coefficients prefix = b"".join(keys) a1 = int_from_bits(hf(prefix + x_Q1).digest(), ec.nlen) % ec.n a2 = int_from_bits(hf(prefix + x_Q2).digest(), ec.nlen) % ec.n a3 = int_from_bits(hf(prefix + x_Q3).digest(), ec.nlen) % ec.n # 3. aggregated public key Q1 = mult(q1) Q2 = mult(q2) Q3 = mult(q3) Q = ec.add(double_mult(a1, Q1, a2, Q2), mult(a3, Q3)) if Q[1] % 2: # print("Q has been negated") a1 = ec.n - a1 # pragma: no cover a2 = ec.n - a2 # pragma: no cover a3 = ec.n - a3 # pragma: no cover # ready to sign: nonces and nonce commitments k1, _ = ssa.gen_keys() K1 = mult(k1) k2, _ = ssa.gen_keys() K2 = mult(k2) k3, _ = ssa.gen_keys() K3 = mult(k3) # exchange {K_i} (interactive) # computes s_i (non interactive) # WARNING: signers must exchange the nonces commitments {K_i} # before sharing {s_i} # same for all signers K = ec.add(ec.add(K1, K2), K3) if K[1] % 2: k1 = ec.n - k1 # pragma: no cover k2 = ec.n - k2 # pragma: no cover k3 = ec.n - k3 # pragma: no cover r = K[0] e = ssa._challenge(m, Q[0], r, ec, hf) s_1 = (k1 + e * a1 * q1) % ec.n s_2 = (k2 + e * a2 * q2) % ec.n s3 = (k3 + e * a3 * q3) % ec.n # exchange s_i (interactive) # finalize signature (non interactive) s = (s_1 + s_2 + s3) % ec.n sig = r, s # check signature is valid ssa._assert_as_valid(m, Q[0], sig, ec, hf)
mprvkey = 1 + secrets.randbelow(ec.n - 1) print(f"\nmaster prvkey: {hex(mprvkey).upper()}") # Master Pubkey: mpubkey = mult(mprvkey, ec.G) print(f"Master Pubkey: {hex(mpubkey[0]).upper()}") print(f" {hex(mpubkey[1]).upper()}") r = secrets.randbits(ec.nlen) print(f"\npublic random number: {hex(r).upper()}") rbytes = r.to_bytes(ec.nsize, "big") nKeys = 3 for i in range(nKeys): ibytes = i.to_bytes(ec.nsize, "big") hd = hf(ibytes + rbytes).digest() offset = int_from_bits(hd, ec.nlen) % ec.n q = (mprvkey + offset) % ec.n Q = mult(q, ec.G, ec) print(f"\nprvkey #{i}: {hex(q).upper()}") print(f"Pubkey #{i}: {hex(Q[0]).upper()}") print(f" {hex(Q[1]).upper()}") # Pubkeys could also be calculated without using prvkeys for i in range(nKeys): ibytes = i.to_bytes(ec.nsize, "big") hd = hf(ibytes + rbytes).digest() offset = int_from_bits(hd, ec.nlen) % ec.n Q = ec.add(mpubkey, mult(offset, ec.G, ec)) assert Q == mult((mprvkey + offset) % ec.n, ec.G, ec)
print(ec) q = 0x18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725 q = q % ec.n print("\n*** Key Generation:") print("prvkey: ", hex(q)) Q = mult(ec, q, ec.G) print("PubKey:", "02" if (Q[1] % 2 == 0) else "03", hex(Q[0])) print("\n*** Message to be signed") msg = "Paolo is afraid of ephemeral random numbers" print(msg) print("*** Hash digest of the message") msghd = hf(msg.encode()).digest() # hash(msg) must be transformed into an integer modulo ec.n: c = int.from_bytes(msghd, 'big') % ec.n assert c != 0 print(" c:", hex(c)) print("\n*** Sign Message") # ephemeral key k must be kept secret and never reused !!!!! # good choice: k = hf(q||c) # different for each msg, private because of q temp = q.to_bytes(32, 'big') + c.to_bytes(32, 'big') k_bytes = hf(temp).digest() k = int.from_bytes(k_bytes, 'big') % ec.n assert 0 < k < ec.n, "Invalid ephemeral key" print("eph k:", hex(k))