def test_bip340_vectors(self): """BIP340 (Schnorr) test vectors https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv """ fname = "bip340_test_vectors.csv" filename = path.join(path.dirname(__file__), "test_data", fname) with open(filename, newline='') as csvfile: reader = csv.reader(csvfile) # skip column headers while checking that there are 7 columns _, _, _, _, _, _, _ = reader.__next__() for row in reader: (index, seckey, pubkey, mhd, sig, result, comment) = row errmsg = f"Test vector #{int(index)}" if seckey != '': seckey = bytes.fromhex(seckey) _, pubkey_actual = ssa.gen_keys(seckey) self.assertEqual(pubkey, hex(pubkey_actual).upper()[2:], errmsg) sig_actual = ssa.serialize(*ssa.sign(mhd, seckey)) self.assertEqual(sig, sig_actual.hex().upper(), errmsg) result = result == 'TRUE' if comment: errmsg += ": " + comment result_actual = ssa.verify(mhd, pubkey, sig) self.assertEqual(result, result_actual, errmsg)
def test_bip340_vectors() -> None: """BIP340 (Schnorr) test vectors. https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv """ fname = "bip340_test_vectors.csv" filename = path.join(path.dirname(__file__), "test_data", fname) with open(filename, newline="") as csvfile: reader = csv.reader(csvfile) # skip column headers while checking that there are 7 columns _, _, _, _, _, _, _ = reader.__next__() for row in reader: (index, seckey, pubkey, m, sig, result, comment) = row err_msg = f"Test vector #{int(index)}" if seckey != "": _, pubkey_actual = ssa.gen_keys(seckey) assert pubkey == hex(pubkey_actual).upper()[2:], err_msg sig_actual = ssa.serialize(*ssa._sign(m, seckey)) assert sig == sig_actual.hex().upper(), err_msg if comment: err_msg += ": " + comment # TODO what's worng with xor-ing ? # assert (result == "TRUE") ^ ssa._verify(m, pubkey, sig), err_msg if result == "TRUE": assert ssa._verify(m, pubkey, sig), err_msg else: assert not ssa._verify(m, pubkey, sig), err_msg
def test_invalid_schnorr(): sighash = bytes.fromhex("00" * 32) sig = ssa.serialize(*ssa._sign(sighash, 1)) pubkey = bytes_from_point(mult(1)) pubkey_hash = hash256(pubkey) script = Script([ [0x00, 0x00, pubkey], [0x01, 0x00, sig], [0x02, 0x00, pubkey_hash], # push pubkey_hash [0x03, 0x02, b"\x00"], # hash of pub key from unlocking script [0xFF, 0x01, b"\x03\x02"], # check equality [0xFF, 0x04, b"\xff"], # exit if not equal [0xFF, 0x03, b"\x00\x01"], # schnorr verify [0xFF, 0x04, b"\xff"], ] # exit if not equal]) # push signature ) assert script.execute(memory={0x100: sighash})
def test_signature() -> None: ec = CURVES["secp256k1"] msg = "Satoshi Nakamoto" q, x_Q = ssa.gen_keys(0x01) sig = ssa.sign(msg, q) ssa.assert_as_valid(msg, x_Q, sig) assert ssa.verify(msg, x_Q, sig) assert sig == ssa.deserialize(sig) ssa.assert_as_valid(msg, x_Q, sig) ssa.assert_as_valid(msg, x_Q, ssa.serialize(*sig)) ssa.assert_as_valid(msg, x_Q, ssa.serialize(*sig).hex()) msg_fake = "Craig Wright" assert not ssa.verify(msg_fake, x_Q, sig) err_msg = r"y_K is odd|signature verification failed" with pytest.raises(BTClibRuntimeError, match=err_msg): ssa.assert_as_valid(msg_fake, x_Q, sig) _, x_Q_fake = ssa.gen_keys(0x02) assert not ssa.verify(msg, x_Q_fake, sig) with pytest.raises(BTClibRuntimeError, match=err_msg): ssa.assert_as_valid(msg, x_Q_fake, sig) _, x_Q_fake = ssa.gen_keys(0x4) assert not ssa.verify(msg, x_Q_fake, sig) with pytest.raises(BTClibRuntimeError, match=err_msg): ssa.assert_as_valid(msg, x_Q_fake, sig) err_msg = "not a BIP340 public key" with pytest.raises(BTClibValueError, match=err_msg): ssa.assert_as_valid(msg, INF, sig) # type: ignore with pytest.raises(BTClibValueError, match=err_msg): ssa.point_from_bip340pubkey(INF) # type: ignore sig_fake = (sig[0], sig[1], sig[1]) assert not ssa.verify(msg, x_Q, sig_fake) # type: ignore err_msg = "too many values to unpack " with pytest.raises(ValueError, match=err_msg): ssa.assert_as_valid(msg, x_Q, sig_fake) # type: ignore sig_invalid = ec.p, sig[1] assert not ssa.verify(msg, x_Q, sig_invalid) err_msg = "x-coordinate not in 0..p-1: " with pytest.raises(BTClibValueError, match=err_msg): ssa.assert_as_valid(msg, x_Q, sig_invalid) sig_invalid = sig[0], ec.p assert not ssa.verify(msg, x_Q, sig_invalid) err_msg = "scalar s not in 0..n-1: " with pytest.raises(BTClibValueError, match=err_msg): ssa.assert_as_valid(msg, x_Q, sig_invalid) m_fake = b"\x00" * 31 err_msg = "invalid size: 31 bytes instead of 32" with pytest.raises(BTClibValueError, match=err_msg): ssa._assert_as_valid(m_fake, x_Q, sig) with pytest.raises(BTClibValueError, match=err_msg): ssa._sign(m_fake, q) err_msg = "private key not in 1..n-1: " with pytest.raises(BTClibValueError, match=err_msg): ssa.sign(msg, 0) # ephemeral key not in 1..n-1 err_msg = "private key not in 1..n-1: " with pytest.raises(BTClibValueError, match=err_msg): ssa._sign(reduce_to_hlen(msg, hf), q, 0) with pytest.raises(BTClibValueError, match=err_msg): ssa._sign(reduce_to_hlen(msg, hf), q, ec.n) err_msg = "invalid zero challenge" with pytest.raises(BTClibValueError, match=err_msg): ssa.__recover_pubkey(0, sig[0], sig[1], ec)
def unlock_p2pkh(sighash, prvkey): sig = ssa.serialize(*ssa._sign(sighash, prvkey)) pubkey = bytes_from_point(mult(prvkey)) return Script( [[0x00, OP_PUSHDATA, pubkey], [0x01, OP_PUSHDATA, sig]] ) # push signature