Пишем блокчейн-блокнот на языке программирования C#
Рассказываем, для чего нужен блокчейн в программировании и как его используют, а также пишем небольшое приложение.


Иллюстрация: Merry Mary для Skillbox Media
Блокчейн — это последовательная цепочка блоков, которые защищены от подмены. А блок — это файл, содержащий информацию о предыдущих действиях, например транзакциях о переводе криптовалют. Но при этом ошибочно считать, что эта технология используется только в криптовалюте, — на самом деле применить блокчейн можно где угодно.
Разбираемся, что же такое блокчейн, и пишем приложение с его использованием.
Что такое хеширование
Прежде чем говорить про блокчейн, нужно разобраться, что такое хеширование.
Хеширование — это преобразование данных произвольной длины в битовую строку фиксированной длины. То есть мы можем взять любой текст, например книгу «451 градус по Фаренгейту», а потом зашифровать его с помощью специального алгоритма.
Каждый раз этот алгоритм будет преобразовывать текст в один и тот же хеш. Например, такой:
6de4c03655fdc3e982e3bfc4f055dae5064547e8b78ef951b80c94b657a5c684
Но если будет пропущена хотя бы одна запятая или какая-нибудь буква поменяет регистр, то хеш полностью изменится.
efdc5e0108e3906fea8c93efb1d9616b7a26aa26549c5d47a1b6c3fda8199ac9
Тут зашифрована та же строка, что и сверху, но в конце я убрал точку. Как видно, результат уже совсем не похож на исходный хеш.
Пока что единственный способ расшифровать хеш — перебор. Теоретически, чтобы найти верный вариант, нужно попробовать бесконечное количество комбинаций. Поэтому хеш применяют, чтобы защитить данные от взлома — даже если они будут утеряны или украдены.
Один из вариантов использования хешей — хранение паролей. Когда пользователь будет регистрироваться в системе, его данные будут храниться не в чистом виде, а в виде хеша.
Каждый раз, когда он будет вводить пароль, тот будет снова хешироваться, а уже потом сравниваться с тем, что записан в базе. Даже если кто-то взломает базу данных, он не узнает, какой пароль использовался. Всё, что он увидит, — это набор непонятных символов.
Как работает блокчейн
Теперь можно вернуться к блокчейну. Особенность каждого его блока — в том, что он не только захеширован, но и хранит информацию о предыдущем блоке.
Рассмотрим это на примере блокнота. Каждая запись в нём будет восприниматься как отдельный блок.
Допустим, есть вот такая первая запись:
Привет, это первая заметка!
Её хеш выглядит так:
7cb70ea12f13042dbfbbf492c20e943b2c62a1007a9921e36f5479f6aa748bc9
Вторая запись содержит в себе саму запись, а также хеш первой записи. То есть:
7cb70ea12f13042dbfbbf492c20e943b2c62a1007a9921e36f5479f6aa748bc9_разделитель_Привет, это вторая запись!
В таком виде заметка хешируется:
8af30f625141cd685dd3ad40f32b0046b562e4efd9746f8225f5a56543a0e50a
И этот хеш становится частью третьей записи.
Если мы изменим вторую запись, то её хеш станет совсем другим. Следовательно, он не будет совпадать с тем, что был записан в третью запись. То есть блокчейн позволяет нам создавать записи, которые невозможно изменить незаметно.
Теоретически можно подобрать строку, хеш которой будет совпадать с тем, который нужно заменить. Но, как уже говорилось выше, сделать это сложно, особенно если блоков очень много.
Чтобы обойти эту проблему, используется децентрализация. То есть блоки хранятся не на едином сервере, а на всех компьютерах, которые используют приложение на блокчейне.
Эта мера используется, например, в криптовалюте BitCoin. И если кто-то захочет её у вас украсть, ему придётся одновременно заменить блоки на всех компьютерах.
Для чего нужен блокчейн
Использовать эту технологию можно для чего угодно, а не только для криптовалюты. Например, можно хранить в блокчейне удостоверения личности. Это не позволит мошенникам использовать документы умерших людей, заменив в них фотографию.
Есть и другие варианты:
- В блокчейне можно хранить ставки — тогда ни букмекер, ни игрок не смогут обмануть друг друга.
- С помощью блокчейна можно проводить выборы — что исключит возможность фальсификации результатов.
- Можно заменить нотариуса блокчейном — и заверять документы без него.
Это далеко не весь список.
Не стоит думать, что такая система надёжна на 100%. Возможны ошибки в самом программном обеспечении, которые позволят воровать данные до того, как они будут захешированы.
Пишем приложение на блокчейне на C#
Чтобы лучше понимать, как работает блокчейн, напишем приложение с использованием этой технологии. Здесь будут приведены только самые важные части кода, поэтому реализация интерфейса останется за кадром. Если же вам интересно увидеть приложение полностью, его можно найти в этом репозитории на GitHub.
Начнём с создания класса, который представляет собой блок. Назовём его Note.
В своей работе он будет использовать преобразование строки в байты и обратно, а также шифрование, поэтому нужно подключить соответствующие пространства имён:
using System.Text;
using System.Security.Cryptography;
Теперь можно приступать к работе над самим классом:
///<Summary>Заметка для блокнота, который работает на блокчейне</Summary>
class Note
{
public static string Splitter = "_splitter_";
private string text;
private byte[] hash;
public Note(string text)
{
this.text = text;
this.hash = ComputeHash(text);
}
private byte[] ComputeHash(string text)
{
SHA256 sha = SHA256.Create(); //Создаём объект, который будет вычислять хеш
byte[] textBytes = Encoding.Default.GetBytes(text); //Преобразуем текст заметки в байты
return sha.ComputeHash(textBytes); //Возвращаем хеш
}
///<Summary>Полный текст заметки</Summary>
public string Text { get { return this.text; } }
///<Summary>Текст заметки без хеша прошлого блока</Summary>
public string ClearText
{
get
{
return this.text.Remove(0, this.text.IndexOf(Note.Splitter) + Note.Splitter.Length);
}
}
///<Summary>Хеш прошлого блока</Summary>
public string PreviousHash
{
get
{
return this.text.Remove(this.text.IndexOf(Note.Splitter));
}
}
///<Summary>Хеш текущего блока в виде строки</Summary>
public string HashString
{
get
{
//При каждом получении текущего хеша нужно считать его заново
//Так мы будем уверены, что он актуален
var hash = ComputeHash(this.text);
return Encoding.Default.GetString(hash);
}
}
///<Summary>Хеш в виде байтов</Summary>
public byte[] Hash { get { return this.hash; } }
}
Остаётся только написать программу, которая будет использовать эти блоки. Первым делом нужно создать список блоков:
List<Note> notes = new List<Note>(); //Список блоков
notes.Add(new Note "start" + Note.Splitter + "First note")); //Добавляем первую заметку
Потом — реализовать метод добавления новых блоков.
static void AddNote(string text, List<Note> notes)
{
notes.Add(new Note(notes[notes.Count - 1].HashString + Note.Splitter + text));
}
Когда пользователь вводит текст для новой заметки, он передаётся в метод AddNote().Там создаётся новый блок, который содержит текст вида
Хеш предыдущего блока_разделитель_текст заметки
Созданный блок тут же добавляется в список:

После того как будет создано несколько заметок, можно проверить список:

Здесь отображается только текст заметок, но, если посмотреть на полную информацию о них, можно увидеть, что они содержат в себе хеш прошлого блока:

Скриншот: Skillbox Media
Просматривать всё это вручную, чтобы проверить достоверность данных, нет смысла, потому что блоков может быть очень много. Вместо этого напишем метод валидации:
///<summary>Проверка подлинности блоков</summary>
static void ValidateNotes(List<Note> notes)
{
for(int i = 0; i < notes.Count; i++)
{
if(i == 0) //Не проверять первый блок
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("0 - Valid");
}
else
{
Console.ForegroundColor = ConsoleColor.White;
//Проверяем, соответствует ли хеш, записанный в текущий блок, хешу прошлого блока
if(@notes[i].PreviousHash == @notes[i - 1].HashString)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(i + " - Valid");
}
else
{
Console.WriteLine($"\n\n | {notes[i].PreviousHash} | {notes[i - 1].HashString} | \n\n");
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(i + " - Changed");
}
}
}
Console.WriteLine("\n");
}
Теперь можно проверить, всё ли в порядке с заметками, которые мы сохранили:

Если же в каком-нибудь блоке изменится хоть один символ, это сразу станет ясно. Поэтому такой блокнот — идеальный вариант для хранения долговых расписок и другой подобной информации.
Заключение
Это только малая часть того, что можно узнать по этой теме. Мы написали приложение, которое использует блокчейн, и использовали главный принцип блокчейна — последовательность хеширования данных.
Если же вы хотите изучить тему глубже, советую почитать статью на Habr. Там же есть ссылка на учебник по защите информации.