June 3

Confidential balances в Solana

Еще давно в солане появился Token 2022 - стандарт spl токена, с расширяемой логикой(extensions). Там есть такие же функции на передачу, минт, заморозку, разморозку, сжигание, но в них можешь добавлять еще действия: комиссию (как это сделали в something.cool), проверку на вайтлист, интерест модель, нон трансферабл токенсы, и множество других штук (https://solana.com/ru/docs/tokens/extensions). Недавно запустили расширение с confidential transactions.

Это особенность, благодаря которой скрывается баланс у юзера, а также скрывается размер транзакции (перевода, минта и сжигания). По сути единственное что будет видно это вызов функций (и упоминание програм), а все что происходит внутри скрыто (как в zcash с их z layer). И единственные кто могут увидеть свои балансы это сами юзеры, а также возможное отдельное лицо, называемое аудитором, который может смотреть с помощью определенного приватного ключа.

Математика внутри

Для начала пойдем в то как оно работает. Чтобы скрыть балансы и переводы и все остальное, используется шифрование public key (по сути своей как и работают все блокчейны с публичным и приватным ключом).

Есть алгоритм ElGamal, и в базовой версии он работает следующим образом - зашифрованные числа можно умножать, при этом после расшифровки финального числа оно равно обычному перемножению. a*b = c = decrypt(enc(a) * enc(b)). Основная защита данного алгоритма в дискретном логарифме.

В Solana же используется Twisted ElGamal, позволяющий складывать зашифрованные числа. a+b = c = decrypt( enc(a) * enc(b))

Зная публичный ключ человека, которому мы передаем баланс, мы можем зашифровать число, которое мы передаем, с помощью публичного ключа данного человека. И можем к этому зашифрованному балансу прибавить другое зашифрованное число, его же публичным ключом, и тем самым произвести увеличение его баланса. А это же число, которое хотим передать, зашифруем у себя своим публичным ключом, и вычтем у себя.

При этом, одним twisted ElGamal дело не заканчивается, внутри сети же никто ничего не знает, а значит есть сопутствующие данные и проверки.

Доказательство валидного перевода

В рамках обычного спл очень легко проверить изменение балансов и этим занимаются валидаторы. Тут же идея что этого не увидит никто, а значит нужно доказать что такой перевод имеет место быть, для этого используются zero knowledge proofs:

  1. Range proof - доказываем, что числа (после трансфера и сам трансфер) находятся в 0<=x<=2^48 (отсюда и информация в дешифрование twisted ElGamal что эти числа легко перебрать(относительно))
  2. Validity proof - здесь мы доказываем, что числа (для сложения и вычитания) зашифрованы валидно. При этом не раскрывается ни сама сумма, ни оставшийся баланс.
  3. Equality proof - Пруф того что все зашифрованные числа равны (в незашифрованном виде)

Генерация ключей

Для использования шифрований нужно как-то сгенерировать эти ключи, а они отличаются от стандартного шифрования в солане (построенного на эллиптической кривой ed25519), а значит нужно сгенерировать новые ключи и управлять ими.

  1. Они генерируются на базе твоего приватного ключа под твой аккаунт, не под каждый минт. Результат подписи с сидом "ElGamalSecretKey" идет как сид в генератор случайных чисел и на базе него мы получаем приватный ключ (а от него и публичный). Полностью детерминированная система.
  2. Единственная сложность шифра twisted ElGamal состоит в том что при дешифровке числа, ты получаешь не само число, а g^private_number (поэтому он и называется скрученный, и позволяющий делать операцию сложения) а значит, каждый раз проводить вычисления чтобы посмотреть баланс. Каждый раз вычислять его неудобно и долго, поэтому было добавлено еще одно число в сам аккаунт, но уже зашифрованное AES (шифр nist). Данный шифр позволяет хранить числа зашифрованными, и всегда легко и быстро понимать чему они равны и только юзер сможет это прочитать (и изменить). Для этого нужно знать ключ от данного AES шифра, и ключ генерируется аналогично как для twisted ElGamal, только тут сидом является "AeKey".

"Аудитор" в токене

  1. Так как сама по себе солана есть компания из us, она не может сделать одностороннюю зашифрованную систему. Аудитор, в рамках spl ct, это такой наблюдатель со стороны, который может посмотреть баланс юзеров (зашифрованный публичным ключом аудитора). На этом его возможности заканчиваются.
  2. Принцип работы следующий: при каждом обновлении баланса(трансфере, минте, берне), кроме того чтобы обновить свой зашифрованный баланс своим публичным ключом и чужой(если трансфер), также ты обновляешь свой и чужой баланс, зашифрованный уже публичным ключом аудитора. Используется одно число для двух балансов, так как шифруется публичным ключом аудитора,
  3. А уже сам аудитор может расшифровать, но это опция, а не необходимость, и далеко не на каждый токен такое нужно(но для любого большого, а-ля shielded usdt, думаю нужно, иначе вопросы возникнут).

Гарантия консистентности

Так как используются zero-knowledge proofs, то получается, что пока ты создаешь пруфы, отправляешь транзу, и она попадает в блок, тебя могут кто-то обогнать и увеличить твой баланс. А твоя транзакция этого не учитывает и пруфы упадут.

Поэтому существует разделение баланса в виде pending (ожидающий) и available(доступный). В рамках транзакции от своего аккаунта ты всегда используешь доступный баланс, и если уж тебе надо то ты можешь сам обновить свой баланс транзакцией apply. В этой же транзакции обновляется и AES баланс, так как он показывает только available баланс и может обновляться только самим юзером.

Что в итоге:

  1. Spl token 2022 расширение с confidential transfers. В рамках данного расширения, балансы скрываются гомоморфным шифрованием twisted ElGamal, позволяющим складывать скрытые числа.
  2. Для проверки данных чисел в момент транзакций используется zero knowledge proofs (validity proof(легитимность транзакции), range proof(легитимность размера трансфера), equality proof(проверка на одинаковое шифрование)).
  3. Есть публичный ключ "аудитора", хранящийся в токене, с помощью которого "аудитор" может посмотреть чужие балансы, но не влиять на них.
  4. Чтобы гарантировать консистентность балансов при действиях, используется разделение балансов на доступные (на которые влияет сам пользователь) и ожидающие(куда перечисляют токены другие адреса).
  5. Для упрощения вычислять скрытый баланс аккаунта используются AES шифрованные балансы, которые не позволяют гомоморфно складывать шифр тексты, но позволяют хранить и быстро шифровать и расшифровывать для быстрого доступа к балансу.
  6. Все ключи, используемые в twisted ElGamal и AES, привязываются к приватному ключу аккаунта, а не к токену(минту) и вычисляются детерминированно. По 1 связке на каждый аккаунт.