В этой серии из двух частей мы поговорим о том, как начать работу с библиотекой
libsnark. Мы рассмотрим два очень
полезных руководства и попутно дадим дополнительные комментарии.

Учебник Говарда Ву

Для новичка вашим первым портом захода должен стать превосходный
учебник одного из главных участников libsnark
— Говарда Ву. В README содержатся пошаговые инструкции по
созданию простого приложения, которое генерирует пример доказательства zk-SNARK (на основе
протокола Groth-16) и проверяет его. Хотя вы можете просто клонировать
репозиторий и перейти непосредственно к созданию и запуску приложения, очень
поучительно выполнить шаги, чтобы увидеть, как структурирован проект на основе libsnark
. В оставшейся части этого поста предполагается, что вам удалось собрать и запустить учебник.

Суть учебника

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

template<typename ppT>
bool run_r1cs_gg_ppzksnark(const r1cs_example<libff::Fr<ppT> > &example)
{
    r1cs_gg_ppzksnark_keypair<ppT> keypair =
    r1cs_gg_ppzksnark_generator<ppT>(example.constraint_system);
    r1cs_gg_ppzksnark_proof<ppT> proof =
    r1cs_gg_ppzksnark_prover<ppT>(keypair.pk,
                                    example.primary_input,
                                    example.auxiliary_input);
    const bool ans =
      r1cs_gg_ppzksnark_verifier_strong_IC<ppT>(keypair.vk,
                                                example.primary_input,
                                                proof);
    // ... etc.
}

Эти три вызова функций описывают основной рабочий процесс, общий для большинства протоколов zk-SNARK:

  1. Учитывая R1CS (система ограничений ранга 1) — здесь она называется example
    функция
    r1cs_gg_ppzksnark_generator генерирует keypair — одну для доказывающего, а другую
    для верификатора.
  2. Проверяющая берет свой ключ и вместе с входными данными example R1CS
    создает proof с r1cs_gg_ppzksnark_prover. Обратите внимание, что входные данные
    включают как общедоступные значения (primary_input — известны также проверяющему), так и
    частные «свидетельские» значения (auxiliary_input — не сообщаются проверяющему).
  3. Вместе с общедоступными входными данными и ключом проверки верификатор проверяет
    proof с r1cs_gg_ppzksnark_verifier_strong_IC, что должно возвращать
    истину, если proof действительно был предоставлен подтверждающим свидетельством.

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

libsnark функций

Здесь следует отметить, что конкретные используемые функции и типы будут
зависеть от ряда факторов. В данном случае мы работаем с Groth-16
zk-SNARK, который определяет, что следует использовать функции с префиксом r1cs_gg_ppzksnark_
.

На самом деле конкретная функция проверки, которую следует вызывать, зависит не менее чем от трех факторов:

  • Как уже упоминалось, SNARK для использования.
  • Ключ проверки – обработанные ключи, содержащие небольшое постоянное количество
    дополнительной предварительно вычисленной информации, позволяющей сократить время проверки.
    В этом случае верификатор называется онлайн верификатор.
  • Слабая и сильная согласованность входных данных (IC) — сильная IC означает, что количество
    первичных входных данных точно соответствует количеству входных данных системы ограничений
    , тогда как слабая IC ослабляет это требование.

В приведенном выше примере для проверки используется стандартный необработанный ключ с
строгой согласованностью ввода:

template<typename ppT>
bool r1cs_gg_ppzksnark_verifier_strong_IC(
  const r1cs_gg_ppzksnark_verification_key<ppT> &vk,
  const r1cs_gg_ppzksnark_primary_input<ppT> &primary_input,
  const r1cs_gg_ppzksnark_proof<ppT> &proof);

В качестве другого примера, тот же SNARK, но с обработанным ключом проверки и только слабой
непротиворечивостью ввода, вместо этого будет использовать следующую функцию проверки:

template<typename ppT>
bool r1cs_gg_ppzksnark_online_verifier_weak_IC(
  const r1cs_gg_ppzksnark_processed_verification_key<ppT> &pvk,
  const r1cs_gg_ppzksnark_primary_input<ppT> &input,
  const r1cs_gg_ppzksnark_proof<ppT> &proof);

Использование этого онлайн-верификатора предполагает некоторую дополнительную обработку стандартного
ключа проверки путем передачи его функции
r1cs_gg_ppzksnark_verifier_process_vk для создания
r1cs_gg_ppzksnark_processed_verification_key.

См. исходный код libsnark для более подробной информации.

Хотя руководство Говарда Ву показывает пример этого очень важного шаблона
работы с zk-SNARK, в нем мало говорится о том, как на самом деле происходит
создание объектов R1CS. Это (и многое другое) будет темой следующего поста.