Код
#статьи

Пишем блокчейн-блокнот на языке программирования 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

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

Скриншот: Skillbox Media

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

Хеш выглядит немного иначе, потому что конвертируется сразу в строку, а не в шестнадцатеричное число
Скриншот: 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");
}

Теперь можно проверить, всё ли в порядке с заметками, которые мы сохранили:

Скриншот: Skillbox Media

Если же в каком-нибудь блоке изменится хоть один символ, это сразу станет ясно. Поэтому такой блокнот — идеальный вариант для хранения долговых расписок и другой подобной информации.

Заключение

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

Если же вы хотите изучить тему глубже, советую почитать статью на Habr. Там же есть ссылка на учебник по защите информации.



Понравилась статья?
Да

Пользуясь нашим сайтом, вы соглашаетесь с тем, что мы используем cookies 🍪

Ссылка скопирована