Транзакции между скрытыми адресами

Ariel Gabizon | Ноябрь 29, 2016

В предыдущей статье, которая называется ‘Структура транзакций Zcash’ , мы в общих чертах рассмотрели схему работы транзакций Zcash. Это сделано для того, чтобы у вас было примерное понимание о механизме защиты частной информации при проведении транзакций Zcash и о том, какое место в этом процессе занимает доказательство с нулевым разглашением. Эта статья полностью посвящена осуществлению транзакций между закрытыми адресами (которые также называют z-addrs).

Чтобы сфокусироваться на аспекте сохранения конфиденциальности, давайте пока отложим в сторону все, что связано с установлением согласованности при помощи доказательства работы и блокчейна и сконцентрируем внимание на конкретном узле, который правильно вычислил список непотраченных исходящих транзакций.

Для начала давайте вспомним, как этот список выглядит в блокчейне биткоина. Каждый неизрасходованный «выход» транзакции (UTXO) можно представить в виде ‘банкноты’, которая имеет некоторые характеристики: адрес/публичный ключ (PK) своего обладателя и количество BTC, которое ей соответствует. Для наглядности, давайте представим, что каждая такая банкнота равна 1 BTC, а каждый адрес содержит не более одной такой банкноты (Note). Таким образом, в каждый данный момент времени база данных узла состоит из списка неизрасходованных банкнот, каждая из которых может быть описана адресом ее владельца. Например, база данных может выглядеть так.

Note1= (PK1), Note2= (PK2), Note3= (PK3)

Предположим, PK1 является адресом Алисы, и она хочет отправить 1 BTC на адрес Боба PK4. На все узлы она отправляет сообщение следующего содержания: «Переместить 1 BTC с адреса PK1 на адрес PK4. Она подписывает сообщение закрытым ключом (sk1), который соответствует PK1, и таким образом убеждает узел, что она имеет право на перемещение денег с адреса PK1. Как только узел проверит достоверность подписи и наличие 1 BTC на адресе PK1, его база данных обновится и будет выглядеть следующим образом:

Note4= (PK4), Note2= (PK2), Note3= (PK3)

Теперь давайте представим, что у каждой банкноты также есть рандомный ‘серийный номер’ (типа уникального индекса) r. Вскоре вы увидите, какую важную роль он играет в защите конфиденциальности. Таким образом, база данных может выглядеть так:

Note1=(PK1,r1), Note2= (PK1,r2), Note3= (PK2,r3)

Очевидно, что для сохранения конфиденциальности важно чтобы на узле хранились только «зашифрованные данные», или хэши (HASH), банкнот, а не сами банкноты.

H1=HASH(Note1), H2=HASH(Note2), H3= HASH(Note3)

Не менее важно и то, что хэш банкноты остается в базе данных узла даже после того, как она израсходована. Таким образом, создается база данных не просто неизрасходованных банкнот, а всех банкнот, которые когда-либо существовали.

На этом этапе главная задача отличить израсходованные банкноты от неизрасходованных, при этом не нарушая конфиденциальности пользователей. И здесь самое время поговорить об «обнуляторах» (nullifiernf). Это ни что иное, как список хеш-кодов серийных номеров уже израсходованных банкнот. На каждом узле кроме хешей банкнот хранится и «обнулятор». Например, после того как банкнота Note2 будет потрачена, в базе данных это будет выглядеть так:

Хеш банкноты«Обнулятор»
H1= HASH(Note1)nf1= HASH(r2)
H2= HASH(Note2)
H3= HASH(Note3)

Как происходит транзакция

Теперь предположим, что у Алисы есть Note1 и она хочет отправить это Бобу, публичный ключ которого PK4. Хоть для Zcash это не является принципиально важным условием, но для наглядности мы представим, что Алиса и Боб используют частный канал. По сути, Алиса сделает свою банкноту недействительной, опубликовав ее «обнулятор», и в то же самое время создаст новую действующую банкноту, которая будет принадлежать Бобу.

Если быть точнее, она выполняет следующие действия.

  1. Она выбирает новый рандомный серийный номер r4 и определяет новую банкноту как Note4= ( PK4, r4).
  2. Она лично посылает Note4 Бобу.
  3. Далее она посылает «обнулятор» Note1, nf2= HASH(r1) для каждого узла.
  4. Далее она отправляет хэш новой банкноты H4= HASH(Note4) для каждого узла.

Теперь, когда узел получил nf2 и H4 он начинает проверять, была ли соответствующая банкнота nf2 уже потрачена. Это делается очень просто: узел проверяет, существует ли соответствующий «обнулятор». Если он не существует, то узел добавляет nf2 в список «обнуляторов» и добавляет H4 в список хешированных банкнот, тем самым подтверждая транзакцию между Алисой и Бобом.

Хеш банкноты«Обнулятор»
H1= HASH(Note1)nf1= HASH(r2)
H2= HASH(Note2)nf2= HASH(r1)
H3= HASH(Note3)
H4= HASH(Note4)

…но секундочку, мы же проверили и узнали, что Note1 не была потрачена ранее… но мы не проверили, принадлежит ли она Алисе. На самом деле, мы не проверили, является ли она вообще ‘настоящей’, а точнее, содержится ли ее хеш в хеш-таблице узла. Чтобы решить эту проблему простым способом, Алисе нужно вместо хеша опубликовать Note1, но тогда она не сможет сохранить конфиденциальность.

И тут на помощь спешит алгоритм доказательства с нулевым разглашением (π).

В дополнение к шагам, описанным выше, Алиса опубликует строку доказательства π, чтобы убедить узлы, что кто бы ни опубликовал эту транзакцию, знает значения PK1sk1, и r1 следовательно:

  1. Хеш-код банкноты Note1= (PK1r1находится в списке хешированных банкнот.
  2. sk1 является закрытым ключом, соответствующим PK1 (таким образом тот, кто знает его, является полноправным обладателем Note1).
  3. Хеш r1 является nf2 (следовательно, если nf2 — что, как мы знаем, является «обнулятором» Note1 — не содержится в списке «обнуляторов», Note1 остается неизрасходованной).

По своим свойствам доказательство с нулевым разглашением обеспечивает, что π не раскроет никакой информации о PK1, sk1 или r1.

Основные моменты, где мы упростили содержание и опустили детали

Хотелось бы отметить, что мы очень сильно упростили описание этого процесса, и рекомендуем ознакомиться со спецификацией к протоколу , где все подробно описано.

Вот основные моменты, которые мы опустили:

  1. Хешированные банкноты должны храниться не просто в виде списка, а в виде дерева Меркла. Это играет огромную роль для эффективной работы доказательств с нулевым разглашением. Более того, необходимо хранить скрытое вычисление и связывающее обязательство банкноты, а не просто ее хеш-код.
  2. Обнулятор должен быть вычислен более сложным путем, нежели описанным нами, чтобы обеспечить конфиденциальность получателя по отношению к отправителю.
  3. Мы не описали, как отбросить необходимость в частном канале между отправителем и получателем.

Комментировать статью: