Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 07.10.2018, 21:36   #1
inozemcev
 
Регистрация: 07.10.2018
Сообщений: 4
По умолчанию Создание адреса для bitcoin Теория и Практика

Приветствую, хочу понять принцип создания адреса для биткоин экосистемы. В данном случае моя основная цель не соучастие в транзакциях или что-то в этом духе, а именно навык манипулирования данными на промежуточных этапах.

Моя основная цель, в действительности, научится манипулировать зашифрованными данными в клиент / серверных приложениях.

Поставил себе задачу полностью пройти процесс создания биткоин адреса.

Для манипуляций с шифрованием использую библиотеку Chilkat, а также отдельный скрипт для кодировки base68.

Итак, есть следующий код:

Код:
CkPrng fortuna;
const char *entropy = fortuna.getEntropy(32, "base64");
fortuna.AddEntropy(entropy, "base64");

// cout << string(entropy) << endl;
// 0210qtm3T9YoNlmMjRpiyzgVnawK2H6f1dusP1iP+38=
(Буду за пределами кода вносить ясность) В данном блоке генерируется массив чаров который используется для последующего создания ECDSA пары ключей.

Далее создаю private key:

Код:

CkEcc ecc;

//  Generate a random ECC private key on the secp256r1 curve.
//  Chilkat also supports other curves, such as secp384r1, secp521r1, and secp256k1.

CkPrivateKey *privKey = ecc.GenEccKey("secp256r1", fortuna);
if (privKey == 0) {
	cout << ecc.lastErrorText() << "\r\n";
	return;
}
Далее сохраняю ключ в .pem документе создаю публичный ключ и избавляюсь от ссылки на приватный ключ

Код:
success = privKey->SavePkcs8EncryptedPemFile(privatePass.c_str(), privatePath.c_str());
if (success != true) {
	cout << privKey->lastErrorText() << "\r\n";
	return trust;
}

CkPublicKey *pubKey = privKey->GetPublicKey();

delete privKey;
Точно также сохраняю публичный ключ в .pem файл

Код:
bool bPreferPkcs1 = false;
success = pubKey->SavePemFile(bPreferPkcs1, publicPath.c_str());
if (success != true) {
	cout << pubKey->lastErrorText() << "\r\n";
	return trust;
}
Теперь у меня есть публичный ключ и масса способов получить данные по этому ключу. На следующем шаге я должен передать массив из 65 байтов функции которая использует sha256 для генерации хеш функции.

И тут я на самом деле не совсем понимаю что именно я должен передать этой функции.

Я достал X и Y координаты публичного ключа из JSON склеил их в строку и передал ее, но я не уверен что это правильно.

Код:
CkJsonObject ckJson;
ckJson.Load(jwk);
ckJson.put_EmitCompact(false);

CkString xValue;
ckJson.StringOf("x", xValue);

CkString yValue;
ckJson.StringOf("y", yValue);
	
string ecdsaStr = string(xValue.getString()) + string(yValue.getString());

const char *sha256Str = 0;
crypt.put_HashAlgorithm("sha256");
		
sha256Str = crypt.hashStringENC(ecdsaStr.c_str());
И вот на этом шаге я совсем не уверен что передаю в sha256 корректные данные.
я пытаюсь вывести результат в cout но получаю что-то не совсем похожее на то что есть в исходном примере. А именно:

Код:
cout << "sha256: " << sha256Str << "\r\n";
// zu68LKfjotv+nm2qX4YROFajICbf2x1hy92YLixM8Q=
В оригинальном примере я должен был бы получить шестнадцатиричное число

Код:
0b7c28c9b7290c98d7438e70b3d3f7c848fbd7d1dc194ff83f4f7cc9b1378e98
Насколько я понимаю sha256 будет работать одинакого для любого потока и видимо я просто неправильно вывожу его уже в стрим поток. В итоге хочу научится выводить его именно в таком формате, а также хочу быть уверенным что отдаю алгоритму правильные данные.
inozemcev вне форума Ответить с цитированием
Старый 07.10.2018, 23:16   #2
Black Fregat
Программист
Участник клуба
 
Аватар для Black Fregat
 
Регистрация: 23.06.2009
Сообщений: 1,772
По умолчанию

Цитата:
Сообщение от inozemcev Посмотреть сообщение
ecc.GenEccKey("secp256r1", fortuna);
Почему вдруг secp256r1? Биткойн использует secp256k1

Цитата:
Сообщение от inozemcev Посмотреть сообщение
На следующем шаге я должен передать массив из 65 байтов функции которая использует sha256 для генерации хеш функции.
Именно так - один байт на тип точки (04) и следом X и Y. В двоичном виде.
Ваши манимупуляции со строковым представлением - не то..

Цитата:
Сообщение от inozemcev Посмотреть сообщение
В оригинальном примере я должен был бы получить шестнадцатиричное число
Библиотеке нужно указать шестнадцатиричный вывод:
Код:
crypt.put_EncodingMode("hex");
Black Fregat вне форума Ответить с цитированием
Старый 07.10.2018, 23:38   #3
inozemcev
 
Регистрация: 07.10.2018
Сообщений: 4
По умолчанию

Цитата:
Почему вдруг secp256r1? Биткойн использует secp256k1
Подправил.

Цитата:
Именно так - один байт на тип точки (04) и следом X и Y. В двоичном виде. Ваши манимупуляции со строковым представлением - не то..
Пока до сих пор не понимаю что делать с публичным ключем. Функций достаточно много, есть массив байтов, например. Пробовал сделать из него, но мне кажется это тоже неверный вариант. У массива слишком длинный вывод.

Код:
CkByteData byteData;
pubKey->GetDer(bPreferPkcs1, byteData);

const char *sha256Str = 0;
crypt.put_HashAlgorithm("sha256");
crypt.put_EncodingMode("hex");
sha256Str = crypt.hashStringENC(byteData.getEncoded("hex"));
Цитата:
Библиотеке нужно указать шестнадцатиричный вывод:
Код:
crypt.put_EncodingMode("hex");
Помогло благодарю.
inozemcev вне форума Ответить с цитированием
Старый 07.10.2018, 23:47   #4
Black Fregat
Программист
Участник клуба
 
Аватар для Black Fregat
 
Регистрация: 23.06.2009
Сообщений: 1,772
По умолчанию

Цитата:
Сообщение от inozemcev Посмотреть сообщение
У массива слишком длинный вывод.
Покажите пример
Black Fregat вне форума Ответить с цитированием
Старый 08.10.2018, 00:11   #5
inozemcev
 
Регистрация: 07.10.2018
Сообщений: 4
По умолчанию

Цитата:
Сообщение от Black Fregat Посмотреть сообщение
Покажите пример
Код:
CkByteData byteData;
pubKey->GetDer(bPreferPkcs1, byteData);

cout << "bytedata: " << byteData.getEncoded("hex") << endl;
cout << "syzeof bytedata: " << sizeof(byteData.getEncoded("hex")) << endl;
cout << "strlen bytedata: " << strlen(byteData.getEncoded("hex")) << endl;

const char *sha256Str = 0;
crypt.put_HashAlgorithm("sha256");
crypt.put_EncodingMode("hex");
sha256Str = crypt.hashStringENC(byteData.getEncoded("hex"));
Изображения
Тип файла: jpg Screenshot_85.jpg (62.1 Кб, 94 просмотров)
inozemcev вне форума Ответить с цитированием
Старый 08.10.2018, 00:37   #6
Black Fregat
Программист
Участник клуба
 
Аватар для Black Fregat
 
Регистрация: 23.06.2009
Сообщений: 1,772
По умолчанию

Публичный ключ, скорее всего, это 65 последних байт блока, начиная с 04 5C 67 BF DA
Black Fregat вне форума Ответить с цитированием
Старый 08.10.2018, 01:03   #7
inozemcev
 
Регистрация: 07.10.2018
Сообщений: 4
По умолчанию

Цитата:
Сообщение от Black Fregat Посмотреть сообщение
Публичный ключ, скорее всего, это 65 последних байт блока, начиная с 04 5C 67 BF DA
Вы правы. Я создал новые ключи несколько раз. Каждый раз список байтов начинающийся с 04 находился в самом конце. И каждый раз в списке было ровно 65 байт.

Получается теперь мне нужно распарсить этот массив из извлечь последние 65 байт?
Изображения
Тип файла: png Screenshot_86.png (5.8 Кб, 73 просмотров)
inozemcev вне форума Ответить с цитированием
Старый 08.10.2018, 01:26   #8
Black Fregat
Программист
Участник клуба
 
Аватар для Black Fregat
 
Регистрация: 23.06.2009
Сообщений: 1,772
По умолчанию

Думаю, что да. Скорее всего, одинаковые действия всегда приведут к одинаковой структуре контейнера ASN.1
К сожалению, распарзить весь контейнер по картинке и пытаться не буду, лень считать байты
Но часть, содержащая публичный ключ, начинается с заголовка 03 42 00 04
Цитата:
As another example, a public key is encoded as a bit string:

03 42 00 04 da 15 df a8 21 8a 6a dc 69 d9 4d c6 b8 e3 3b 2a 92 26 62 41 94 9a 81 79 fc 9c 3f 3f 65 b0 94 a1 f9 31 b4 0b 79 14 eb ea 95 13 5b d5 b5 26 e5 57 4e ef 89 11 fb 51 0c 2d 23 4e 4e 62 74 9f 5b 79

Here, the tag is 03(BIT STRING), the length is 42(16) or 66(10). The fist byte of the value is 00, which means there are 0 padding bits at the end. The actual bits of the bit string are encoded in the 65 bytes that follow, starting with 04(16) and ending with 79(16).
Black Fregat вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
теория и практика, взаимодействие PHP и ajax Hattak Помощь студентам 0 19.05.2016 10:45
Теория и Практика Delphi MainUnit.pas Общие вопросы Delphi 5 08.06.2013 07:22
Практика для программиста. romus2102 Помощь студентам 0 06.02.2013 19:57
Управление шаговым двигателем. Теория и практика. Mixasik Компьютерное железо 5 22.12.2010 11:56