I now understand why some of the
bip340_test_vectors fail signature verification.
I would like to tweak these test vectors to check that signature verification fails for other test vectors. How do I do this?
Disclaimer: This is an educational exercise. This Python code is for testing and should not be used in production or with mainnet Bitcoin. A private key of
3 is absolutely insecure.
There are two Python files in the BIPs repo
test_vectors.py which you can view by cloning the BIPs repo.
git clone https://github.com/bitcoin/bips.git
These two files are in
If you run
python3 test-vectors.py from within the bip-0340 directory you will get the output and error messages that are in the CSV file
If you open
test-vectors.py with your text editor e.g.
you can edit any of the test vectors' secret key (private key), message, auxiliary randomness.
vector0 has the secret key
seckey = bytes_from_int(3)
You could change the secret from
seckey = bytes_from_int(4)
Save and close your text editor and then run
python3 test-vectors.py again.
This will generate an AssertionError.
Traceback (most recent call last):
File "test-vectors.py", line 253, in <module>
File "test-vectors.py", line 31, in vector0
There is an assert that checks that for a particular public key (X,Y) (calculated from the secret (private) key) the Y coordinate isn't square. This is a check implemented due to a previous design decision to use squaredness as the tiebreaker for two Y coordinates. The tiebreaker is now evenness rather than squaredness. This test is included to catch when an implementer is mistakenly using squaredness rather than evenness. In this case the public key has a square Y coordinate.
Every private key (scalar) maps to a single corresponding public key (point). In BIP 340 we restrict ourselves to public keys with an even Y coordinate. This could lead to only half of the public keys being valid and hence only half of the private keys being valid too. Instead we say that every private key has a public key and if
d.G has an odd Y coordinate we effectively sign with -d (the negated private key) instead.
Negated means taking the complement with the group order n
-m = n-m (mod n)
With that change you could say that every scalar is a valid private key but there are two private keys that map to the same public key. Only one private key maps to a public key with an even Y coordinate though. (Only one BIP 340 private key maps to a BIP 340 public key.)
Remember when you are finished experimenting you can use this to reset:
git reset --hard HEAD
This will discard the changes you have made and go back to the state of the code before you started experimenting.
Thanks to Pieter Wuille on IRC for some additions.