Я тут почитал про цифровую подпись еще. Подписывание сообщение у большинства нормальных людей проходит следующим образом:
1. Берем случайное целое k число от 1 до n-1 где n - порядок группы (в биткоине 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4141)
2. Вычисляем
P = k*G = random(1, 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4140) * 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798 483ADA77 26A3C465 5DA4FBFC 0E1108A8 FD17B448 A6855419 9C47D08F FB10D4B8
3. Из результата вычислений пункта 2 (из числа P) берем первые 32 байта - это типа координата X точки P или назовем это X
p4. Вычисляем первые 32 байта подписи
r = Xp mod n = первые32байта(k*G) mod n = первые32байта(random(1, 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4140) * 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798 483ADA77 26A3C465 5DA4FBFC 0E1108A8 FD17B448 A6855419 9C47D08F FB10D4B8) mod 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4141
5. Вычисляем вторые 32 байта подписи. Только тут понадобится сообщение и приватный ключ подписывающего.
5.1. Хэшируем сообщение
z = sha256(message)
5.2. Вычисляем "мультипликативную инверсию" числа k. Для этого надо решить уравнение
( k
-1 * k ) mod n = 1
или
( k-1 * random(1, 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4140) ) mod 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4141 = 1
Я хз, как это уравнение решать, но как-то оно довольно быстро решается и из него находят k
-15.3 Вычисляем вторую часть подписи с помощью закрытого ключа D
as = k-1 * (z + Da * r) mod n = k-1 * (sha256(message) + Da * первые32байта(random(1, 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4140) * 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798 483ADA77 26A3C465 5DA4FBFC 0E1108A8 FD17B448 A6855419 9C47D08F FB10D4B8) mod 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4141
Такой вот неочевидный алгоритм, кто-то его придумал и он работает. Как видно в алгоритме участвуют два секретных ключа: случайное число k и приватный ключ D
a.
Алярм 1: если кто-то узнает или подберет k, то он вычислит приватный ключ D
a !!!111
Da = r-1 * (s * k - z) mod n = первые32байта_подписи-1 * (вторые32байта_подписи * k - sha256(message)) mod 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4140
Алярм2: если подписать два разных сообщения с одним и тем же (не случайным) k, то опять можно вычислить приватный ключ D
a !!!111
Сначала вычисляем k
k = (z1 - z2) * (s1 - s2)-1 mod n = (sha256(message1) - sha256(message2)) * (вторые32байта_подписи1 - вторые32байта_подписи2)-1 mod 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4140
Ну а когда вычислим k, то см. Алярм1.
А теперь на сладкое: большинство программ и сервисов для одних и тех же приватного ключа и сообщения, на выходе всегда дают разную валидную цифровую подпись. Оно и понятно, ибо в алгоритме k - должно быть случайным...
А вот биткоин всегда дает одну и туже подпись для одинаковых сообщений и приватного ключа! То есть число k в биткоине не случайное, а вычисляемое.
Я когда это понял, даже офигел: как так, биткоин не следует стандарту? Но порывшись в исходниках разных либ и самого битка обнаружил, что все таки есть еще один стандарт который называется "Deterministic ECDSA"
https://tools.ietf.org/html/rfc6979#section-3Если коротко, то там предлагается алгоритм, как вычислить k используя приватный ключ и входящий хэш сообщения.
Самое интересное: функции проверки подписи вообще пофиг на k. Поэтому сообщение или транзакцию биткоина можно подписать сторонним сервисом и эта подпись будет валидной при проверке.
Кстати, насколько я понял, сообщения и транзакции клиент биткоина тоже подписывает по разному...
Перед тем как хэшировать сообщение, к сообщению добавляется "магическая фраза" типа "Bitcoin signed message\n". А перед тем как хэшировать транзакцию никаких магических фраз не добавляется. Думаю это такая защита для дурака: чтобы никто не мог с помощью кошелька вместо сообщения подписать транзакцию ))