Путаница вокруг добавления точек на secp256k1
Я использую https://github.com/HareInWeed/gec для добавления точек на secp256k1. Код ниже добавляет две точки на кривую secp256k1 и отображает результаты.
#include <gec/utils/macros.hpp>
#include <gec/bigint.hpp>
#include <gec/curve.hpp>
#include <iostream>
// g++ testing.cpp -O3
using namespace gec::bigint::literal; // use the bigint literal
// use uint64 x 4 to store a single element on finite field
using Bigint256 = gec::bigint::ArrayBE<uint64_t, 4>;
// define parameters required by montgomery multiplication:
GEC_DEF_GLOBAL(MOD, Bigint256, // cardinality of finite field
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f_int);
constexpr Bigint256::LimbT MOD_P = // -MOD^-1 mod 2^64
0xd838091dd2253531ull;
GEC_DEF_GLOBAL(RR, Bigint256, // 2^512 mod MOD
0x01000007a2000e90a1_int);
GEC_DEF_GLOBAL(ONE_R, Bigint256, // 2^256 mod MOD
0x1000003d1_int);
// define the finite field type
using Field = GEC_BASE_FIELD(Bigint256, MOD, MOD_P, RR, ONE_R);
// define parameters required by montgomery multiplication:
GEC_DEF_GLOBAL(CARD, Bigint256, // cardinality of the elliptic curve
0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141_int);
constexpr Bigint256::LimbT CARD_P = // -CARD^-1 mod 2^64
0x4b0dff665588b13full;
GEC_DEF_GLOBAL(CARD_RR, Bigint256, // 2^512 mod CARD
0x9d671cd581c69bc5e697f5e45bcd07c6741496c20e7cf878896cf21467d7d140_int);
GEC_DEF_GLOBAL(CARD_ONE_R, Bigint256, // 2^256 mod CARD
0x14551231950b75fc4402da1732fc9bebf_int);
// define the scalar type
using Scalar = GEC_BASE_FIELD(Bigint256, CARD, CARD_P, CARD_RR, CARD_ONE_R);
// parameters of the elliptic curve, in montgomery form
const Field A(0); // = A * 2^256 mod MOD
const Field B(0x700001ab7_int); // = B * 2^256 mod MOD
// define the curve with Jacobian coordinate
using Secp256k1_ = GEC_CURVE(gec::curve::JacobianCurve, Field, A, B);
// use the specialized implementation for curves whose A = 0 to boost performance
using Secp256k1 = GEC_CURVE_B(gec::curve::JacobianCurve, Field, B);
// define the generator, in montgomery form
const Secp256k1 GEN(
Field(0x9981e643e9089f48979f48c033fd129c231e295329bc66dbd7362e5a487e2097_int),
Field(0xcf3f851fd4a582d670b6b59aac19c1368dfc5d5d1f1dc64db15ea6d2d3dbabe2_int),
Field(0x1000003d1_int)
);
int main()
{
Secp256k1 p1, p2, p3;
Secp256k1::mul(p1, 1, GEN);
Secp256k1::mul(p2, 2, GEN);
Secp256k1::add(p3, p1, p2);
std::cout << p3;
return 0;
}
Когда p1 = GEN и p2 = GEN, мы получаем p3 следующим образом
Secp256k1 p1, p2, p3;
Secp256k1::mul(p1, 1, GEN);
Secp256k1::mul(p2, 1, GEN);
Secp256k1::add(p3, p1, p2);
std::cout << p3;
{0x7c75dd9524177d59 3c03889b8dcd9b1c b05fb7d2a3da7fe8 ba9f29b104e7db13,
0x55debb381f4ad034 cc27cb48a46449aa a87d43fdb563384b 1cd20838e6fddc9f,
0x9e7f0a3fa94b05ac e16d6b355833826d 1bf8baba3e3b8c9b 62bd4da6a7b75b95}
Когда мы просто вычисляем 2*GEN, мы получаем разное значение! Этого не должно произойти!
Secp256k1 p1;
Secp256k1::mul(p1, 2, GEN);
cout << p1;
{0x0000000000000000 0000000000000000 0000000000000000 0000000000000000,
0x0000000000000000 0000000000000000 0000000000000000 0000000000000000,
0x0000000000000000 0000000000000000 0000000000000000 0000000000000000}
То же самое для 3*GEN.
Secp256k1 p1;
Secp256k1::mul(p1, 3, GEN);
cout << p1;
{0x0000000000000000 0000000000000000 0000000000000000 0000000000000000,
0x0000000000000000 0000000000000000 0000000000000000 0000000000000000,
0x0000000000000000 0000000000000000 0000000000000000 0000000000000000}
Когда p1 = 1 GEN и p2 = 2GEN, мы получаем разные значения.
Secp256k1 p1, p2, p3;
Secp256k1::mul(p1, 1, GEN);
Secp256k1::mul(p2, 2, GEN);
Secp256k1::add(p3, p1, p2);
cout << p3;
{0x9981e643e9089f48 979f48c033fd129c 231e295329bc66db d7362e5a487e2097,
0xcf3f851fd4a582d6 70b6b59aac19c136 8dfc5d5d1f1dc64d b15ea6d2d3dbabe2,
0x0000000000000000 0000000000000000 0000000000000000 00000001000003d1}
Когда p1 = 4 GEN, p2 = 7GEN и когда p1 = 5 GEN, p2 = 6GEN, мы получаем разные значения.
Secp256k1 p1, p2, p3;
Secp256k1::mul(p1, 4, GEN);
Secp256k1::mul(p2, 7, GEN);
Secp256k1::add(p3, p1, p2);
cout << p3;
{0x1fb5dd34380d1e8d df3cf8dcfacd3c43 5d532ba6446d8835 a4e1b7ee985a3ad2,
0xa6a243e38cd1de5c 8bd5ab69e2291ed0 2073df16b7be047a 58dcce5a9df4f0bd,
0x64d172d2254b1eb3 179345a5659e730e 814a734b032e6909 61fa5d4503c4cc2e}
Secp256k1 p1, p2, p3;
Secp256k1::mul(p1, 5, GEN);
Secp256k1::mul(p2, 6, GEN);
Secp256k1::add(p3, p1, p2);
cout << p3;
{0xd942c4c06e83a9f5 e120c1290faf9e8a 2ef18b316e0d17c5 e6e5daacca8fff58,
0xf0bfc458cf399c0c 11715c0681eb3d2d 2ad8303fdd3fa737 92cefd0dbf159625,
0xcc7ba9867d26b3fd 23553b5204634b6d 4c8e97ec206fa6ae 0dbc34de96615f6f}
Предполагается, что они должны быть такими же, как и при проверке в форме кривой Вейерштрасса.
Когда p1=4GEN и p2=6GEN, мы получаем
Secp256k1 p1, p2, p3;
Secp256k1::mul(p1, 4, GEN);
Secp256k1::mul(p2, 6, GEN);
Secp256k1::add(p3, p1, p2);
cout << p3;
{0xde7053edb5e85ddf 98953ed4b0f65454 adae855e9701f282 4d4b2f91dc02ee5a,
0xe6eb4afe1dc5fd6f f3f9a41b4ceb756f 00dcf2d8ebd0c6aa 93ee5d50600bc498,
0x4bebd311ef1b73d3 271587b52ae56b5e 23fd07dec301cf5b f779ca1675b48117}
Но когда p1=6GEN и p2=4GEN, мы получаем
Secp256k1 p1, p2, p3;
Secp256k1::mul(p1, 6, GEN);
Secp256k1::mul(p2, 4, GEN);
Secp256k1::add(p3, p1, p2);
cout << p3;
{0xde7053edb5e85ddf 98953ed4b0f65454 adae855e9701f282 4d4b2f91dc02ee5a,
0x1914b501e23a0290 0c065be4b3148a90 ff230d27142f3955 6c11a2ae9ff43797,
0xb4142cee10e48c2c d8ea784ad51a94a1 dc02f8213cfe30a4 088635e88a4b7b18}
Обратите внимание, что первые строки одинаковы..
Вопрос: Может ли кто-нибудь помочь мне разобраться с этой путаницей? Кто-нибудь может объяснить, что происходит? Есть ли ошибка в коде? Какая-то постоянная не в порядке?
Знайте, что в функциональности этих очков нет ничего особенного. Думайте о них как о сложении чисел. 0 должно быть 0. 4+7 должно быть равно 5+6.