Skip to content

FastPQ

FastPQ - это Iroha Я ... STARK Проверка пути для выбранных эффектов исполнения. Это не заменяет нормальное выполнение транзакции или консенсус. Транзакции все еще проходят ISI, IVM, и Sumeragi как обычно; FastPQ Использует детерминистский свидетель исполнения и превращает поддерживаемые эффекты в доказательные партии.

В настоящее время интеграция хоста имеет три основных пути:

  • прозрачные цифровые трансферты активов, зафиксированные во время исполнения блоков
  • Nexus верифицированные релеи полосы, на обложке доказательства которых AXT находится связывающее устройство FastPQ
  • Прозрачные вспомогательные устройства для проверки сообщений SCCP, которые упаковывают доказательство FastPQ в открытый конверт с проверкой

Перевод пути свидетельства

Прозрачные числовые перечисления создают структурированную транскрипту передачи, когда инструкция мутирует балансы.

  • исходный счет, учетный счет назначения, определение активов и сумма
  • балансы отправителя и получателя до и после передачи;
  • хэш пункта входа транзакции, используемый в качестве хэша партии
  • справка о полномочиях, полученная из представляемого счета
  • Digest Poseidon для однодельтавых транскриптов

При передаче партии используется одна транскрипта с несколькими дельтами, в этом случае отсутствует дизест Poseidon.

При завершении блока Iroha группирует эти транскрипты на хэш-точку входа. Свидетель выполнения затем несет как первоначальные пакеты транскриптов, так и переходные партии FastPQ, подготовленные для проверки.

Каждая передача дельты становится двумя переходными рядами:

РынокФорма ключаПредварительная оценкаПосле стоимости
Дебет отправителяasset/<asset-definition>/<source-account>баланс отправителя добаланс отправителя после
Кредит получателяasset/<asset-definition>/<destination-account>баланс получателя добаланс получателя после

Цифровые значения нормализуются на целые свидетельские единицы. Значение отклоняется для партий FastPQ, если оно не может быть представлено как неотрицательное u64 в выбранной десятичной шкале.

Государственные взносы

Каждая партия перехода FastPQ содержит публичные вводы, которые связывают доказательство с контекстом блока и исполнения:

ВводЗначение .
dsidИдентификатор пространства данных , кодируемый как небольшие байты .
slotВремя создания блоков преобразовано в наносекунды
old_rootКорень родительского государства , полученный из свидетеля исполнения .
new_rootПослегосударственный корень , полученный от свидетеля исполнения .
perm_rootПриверженность Poseidon к разрешениям на активную роль
tx_set_hashHash над сортированными транзакциями и времени-триггер entrypoint hashes

Хост использует fastpq-lane-balanced в качестве канонического параметра для этих партий.

Математическая модель

В данном разделе описывается арифметика, выполняемая текущим Rust проверщиком и верификатором. Все полевые операции ниже находятся над первостепенным полем "Золотой кусок":

F=Fp,p=264232+1 F = \mathbb{F}_p,\qquad p = 2^{64} - 2^{32} + 1

FastPQ использует Poseidon2 F Для полевых обязательств губка имеет ширину t = 3, процентная ставка r = 2, и мощности 1. Хеш поглощает элементы поля в блоках скорости-2 и добавляет один элемент поля . 1 до окончательной пермутации:

HF(x0,,xm1)=Poseidon2F(x0,,xm1,1) H_F(x_0,\ldots,x_{m-1}) = \operatorname{Poseidon2}_F(x_0,\ldots,x_{m-1},1)

Байтные струи упакованы в 7-байтные маленькие эндианские конечности, поэтому каждая конечность находится строго ниже p:

pack(b)j=i=06b7j+i28i,0pack(b)j<p \operatorname{pack}(b)_j = \sum_{i=0}^{6} b_{7j+i}2^{8i},\qquad 0 \leq \operatorname{pack}(b)_j < p

Хеш-поле, разделенные по домену, представлены следующим образом:

HD(m)=HF(pack(D),pack(D),pack(m),pack(m)) H_D(m) = H_F( |\operatorname{pack}(D)|,\operatorname{pack}(D), |\operatorname{pack}(m)|,\operatorname{pack}(m) )

Для хэшей, которые начинаются с дигестов байт-домена, FastPQ отображает первые восемь маленьких байтов в поле:

seed(D)=le64(Hash(D)[0..8])modp \operatorname{seed}(D)= \operatorname{le64}(\operatorname{Hash}(D)[0..8])\bmod p

Здесь Hash означает iroha_crypto::Hash::new Iroha, 32-байтный перевод Blake2bVar, если формула не называет Poseidon2 или SHA-256.

Полевая арифметика

Код Rust представляет элементы поля как канонические значения u64 в [0,p). Добавление и вычитание:

a+Fb=(a+b)modp a +_F b = (a+b)\bmod p

aFb=(ab)modp a -_F b = (a-b)\bmod p

Умножение сначала вычисляет 128-битный продукт:

ab=lo+264hi a\cdot b = \operatorname{lo} + 2^{64}\operatorname{hi}

Затем Reduction Goldilocks использует идентификацию:

2642321(modp) 2^{64}\equiv2^{32}-1\pmod p

Если:

hi=hilo+232hihi \operatorname{hi}=\operatorname{hi}_{lo}+2^{32}\operatorname{hi}_{hi}

Затем редуктор вычисляет:

lo+232hilohilohihi(modp) \operatorname{lo} +2^{32}\operatorname{hi}_{lo} -\operatorname{hi}_{lo} -\operatorname{hi}_{hi} \pmod p

Использование условно добавляет или вычитает p до тех пор, пока результат не будет каноническим. Подписанные целые числа, такие как дельта баланса, встроены:

field(x)=xmodp,0field(x)<p \operatorname{field}(x)=x\bmod p,\qquad 0\leq\operatorname{field}(x)<p

Посейдон2 Пермутация

Состояние пермутации Poseidon2:

x=(x0,x1,x2)F3 \mathbf{x}=(x_0,x_1,x_2)\in F^3

Его S-коробка:

S(x)=x5 S(x)=x^5

FastPQ использует четыре полные раунды, пятьдесят семь частичных раундов, затем еще четыре полных раунда. c_r = (c_{r,0}, c_{r,1}, c_{r,2}) является:

x=M[S(x0+cr,0)S(x1+cr,1)S(x2+cr,2)] \mathbf{x}' = M\cdot \begin{bmatrix} S(x_0+c_{r,0})\\ S(x_1+c_{r,1})\\ S(x_2+c_{r,2}) \end{bmatrix}

Частичный раунд:

x=M[S(x0+cr,0)x1+cr,1x2+cr,2] \mathbf{x}' = M\cdot \begin{bmatrix} S(x_0+c_{r,0})\\ x_1+c_{r,1}\\ x_2+c_{r,2} \end{bmatrix}

Все добавления и умножения находятся в F. Каноническая матрица MDS:

M=[0x982513a23d22b5920xa3115db8cf1d9c900x46ba684b9eee84b70xbe3dce25491db7680xfb0a6f731943519f0xfce5bd953cde18960xe624719c41eb1a090xd2221b0f1aa2ebc40x1ab5e60d03ad44bc] M= \begin{bmatrix} \texttt{0x982513a23d22b592} & \texttt{0xa3115db8cf1d9c90} & \texttt{0x46ba684b9eee84b7}\\ \texttt{0xbe3dce25491db768} & \texttt{0xfb0a6f731943519f} & \texttt{0xfce5bd953cde1896}\\ \texttt{0xe624719c41eb1a09} & \texttt{0xd2221b0f1aa2ebc4} & \texttt{0x1ab5e60d03ad44bc} \end{bmatrix}

Хеш-поле начинается с нулевого состояния. Для каждого полного блока со скоростью-2 (u,v):

(x0,x1,x2)Poseidon2(x0+u,x1+v,x2) (x_0,x_1,x_2)\leftarrow \operatorname{Poseidon2}(x_0+u,x_1+v,x_2)

В последнем блоке добавляется: 1 элемент накладки до последней пермутации. x_0.

Обязательность для публичных входов

Хост кодирует идентификатор пространства данных, записывая его значение u64 в первые восемь небольших байтов поля 16-байта:

dsid_bytes(d)[0..8]=le64(d),dsid_bytes(d)[8..16]=0 \operatorname{dsid\_bytes}(d)[0..8]=\operatorname{le64}(d), \qquad \operatorname{dsid\_bytes}(d)[8..16]=0

Время создания блоков преобразуется из миллисекунд в наносекунд:

slot=saturating_mul(creation_time_ms,1,000,000) \operatorname{slot}=\operatorname{saturating\_mul} (\operatorname{creation\_time\_ms},1{,}000{,}000)

Хеш-счет транзакции - это хэш байтового домена над сортированными хэшами входных точек:

tx_set_hash=Hash(fastpq:v1:tx_seth0hn1) \operatorname{tx\_set\_hash} = \operatorname{Hash}( \texttt{fastpq:v1:tx\_set}\|h_0\|\cdots\|h_{n-1} )

где h_i являются сортированными хэшами транзакций и входных точек времени-выбудителя. В доказательной публике IO, если perm_root или tx_set_hash все равно нулю, проверка заполняет значения обратного действия:

perm_root={032,if there are no permission hashesHash(fastpq:v1:perm_rootp0pn1),otherwise \operatorname{perm\_root} = \begin{cases} 0^{32},& \text{if there are no permission hashes}\\ \operatorname{Hash}(\texttt{fastpq:v1:perm\_root}\|p_0\|\cdots\|p_{n-1}), & \text{otherwise} \end{cases}

tx_set_hashfallback=Hash(fastpq:v1:tx_setordering_hash) \operatorname{tx\_set\_hash}_{fallback} = \operatorname{Hash}(\texttt{fastpq:v1:tx\_set}\|\operatorname{ordering\_hash})

Цифровая нормализация

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

s=max(scale(a),scale(f0),scale(f1),scale(t0),scale(t1)) s = \max( \operatorname{scale}(a), \operatorname{scale}(f_0), \operatorname{scale}(f_1), \operatorname{scale}(t_0), \operatorname{scale}(t_1) )

Значение Numeric с мантиссами m и шкалой q принимается только при условии, что m >= 0 и q <= s. Его свидетельское значение FastPQ:

norms(m,q)=m10sq \operatorname{norm}_s(m,q)=m\cdot10^{s-q}

Нормализованный результат должен соответствовать u64.

Канонический порядок

Перед строительством следов партия сортируется по переходному клавишу, рангу работы и индексу первоначального вставления:

r(Transfer)=0,r(Mint)=1,r(Burn)=2,r(RoleGrant)=3,r(RoleRevoke)=4,r(MetaSet)=5 r(\operatorname{Transfer})=0,\quad r(\operatorname{Mint})=1,\quad r(\operatorname{Burn})=2,\quad r(\operatorname{RoleGrant})=3,\quad r(\operatorname{RoleRevoke})=4,\quad r(\operatorname{MetaSet})=5

Обязанность заказа представляет собой хэширование поля Poseidon2 над доменом fastpq:v1:ordering и кодированием Norito сортированных переходов:

ordering_hash=HF(P(Do),P(Do),P(E(T)),P(E(T))) \operatorname{ordering\_hash} = H_F( |P(D_o)|,P(D_o),|P(E(T^\star))|,P(E(T^\star)) )

где P представляет собой упаковку 7 байтов, E - кодирование Norito, D_o - fastpq:v1:ordering, а T* - сортированный переходный список.

Уравнения передачи

Для суммы передачи a, баланса отправителя f и баланса получателя t, FastPQ подтверждает нормированные значения свидетелей перед созданием следа:

f0a f_0 \geq a

f1=f0a f_1 = f_0 - a

t1=t0+a t_1 = t_0 + a

Затем переходные строки кодируют:

Δsender=f1f0=a \Delta_{\text{sender}} = f_1 - f_0 = -a

Δreceiver=t1t0=a \Delta_{\text{receiver}} = t_1 - t_0 = a

Внутри следа, подписанные дельты сокращаются до F:

δi=(postiprei)modp \delta_i = (\operatorname{post}_i - \operatorname{pre}_i)\bmod p

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

dtransfer=PoseidonHashBytes(E(from)E(to)E(asset)E(a)batch_hash) d_{\text{transfer}} = \operatorname{PoseidonHashBytes}( E(\text{from})\|E(\text{to})\|E(\text{asset})\|E(a)\|\text{batch\_hash} )

Для транскриптов многодельта-передач текущий формат требует отсутствия этого высокого уровня переваривания.

Приемный орган переписывает транскрипты передачи:

dauthority=Hash(iroha:fastpq:v1:authority|E(authority_account)) d_{\text{authority}} = \operatorname{Hash}(\texttt{iroha:fastpq:v1:authority|}\|E(\text{authority\_account}))

Ряд следов

Пусть сортированный переходный список содержит n реальные строки. Длина следа - следующая сила двух:

N=2log2(max(1,n)) N = 2^{\lceil\log_2(\max(1,n))\rceil}

Ряды 0..n-1 активны; ряды n..N-1 - это ряды заполнения. Каждый реальный ряд имеет один набор выбора операции:

sactive=stransfer+smint+sburn+srole_grant+srole_revoke+smeta_set s_{\text{active}} = s_{\text{transfer}}+ s_{\text{mint}}+ s_{\text{burn}}+ s_{\text{role\_grant}}+ s_{\text{role\_revoke}}+ s_{\text{meta\_set}}

Все колонки выборщика - булевые:

s(s1)=0 s(s-1)=0

Поисковые строки разрешения - это точные строки предоставления роли и отзыва роли:

sperm=srole_grant+srole_revoke s_{\text{perm}} = s_{\text{role\_grant}} + s_{\text{role\_revoke}}

Для рядов численных операций:

δi=value_newi,0value_oldi,0 \delta_i = \operatorname{value\_new}_{i,0} - \operatorname{value\_old}_{i,0}

Строитель также следит за дельтами на активы:

Ri(a)=Ri1(a)+δifor transfer, mint, and burn rows of asset a R_i(a)=R_{i-1}(a)+\delta_i \quad\text{for transfer, mint, and burn rows of asset }a

Только строки мят и сгорания обновляют счетчик подачи:

Si(a)=Si1(a)+{δi,if row i is mint or burn0,otherwise S_i(a)=S_{i-1}(a)+ \begin{cases} \delta_i,& \text{if row }i\text{ is mint or burn}\\ 0,& \text{otherwise} \end{cases}

Метаданные и колонны следов пространства данных являются хэшами полей, полученными до материализации ряда:

metadata_hash={0,if metadata is emptyHD(E(metadata)),otherwise \operatorname{metadata\_hash} = \begin{cases} 0,& \text{if metadata is empty}\\ H_D(E(\text{metadata})),& \text{otherwise} \end{cases}

dsid_trace=HD(public_input_dsid) \operatorname{dsid\_trace}=H_D(\operatorname{public\_input\_dsid})

Хаш метаданных, хаш пространства данных и слот стабильны по смежным строкам следов:

metadata_hashi=metadata_hashi+1 \operatorname{metadata\_hash}_i=\operatorname{metadata\_hash}_{i+1}

dsidi=dsidi+1 \operatorname{dsid}_i=\operatorname{dsid}_{i+1}

sloti=sloti+1 \operatorname{slot}_i=\operatorname{slot}_{i+1}

Перенос столбцов Меркель

Если отсутствует доказательство хоста, проверка синтезирует детерминистический путь из клавиши строки, предварительного баланса и того, является ли ряд стороной отправителя или приемника.

Для синтетических путей ароматная соль fastpq:smt:from для линий отправителя и fastpq:smt:to для линий приемника:

K=Hash(fastpq:smt:key|saltkey) K = \operatorname{Hash}(\texttt{fastpq:smt:key|}\|\operatorname{salt}\|\operatorname{key})

V=Hash(fastpq:smt:value|saltle64(balance)) V = \operatorname{Hash}(\texttt{fastpq:smt:value|}\|\operatorname{salt}\|\operatorname{le64}(\operatorname{balance}))

b=bit(K) b_\ell = \operatorname{bit}_\ell(K)

s=Hash(fastpq:smt:sibling|le64()Kle64(balance)salt) s_\ell = \operatorname{Hash}( \texttt{fastpq:smt:sibling|}\| \operatorname{le64}(\ell)\|K\|\operatorname{le64}(\operatorname{balance})\|\operatorname{salt} )

Синтетический лист и внутренние узлы являются:

L=Hash(fastpq:smt:leaf|KV) L = \operatorname{Hash}( \texttt{fastpq:smt:leaf|}\| K\|V )

N+1=Hash(fastpq:smt:node|leftright) N_{\ell+1} = \operatorname{Hash}( \texttt{fastpq:smt:node|}\| \operatorname{left}_\ell\| \operatorname{right}_\ell )

Следы записывают кусочек . b_l, брат и сестра s_l, входный узел x_l, и выходный узел x_{l+1} На каждом уровне, с соглашением кода:

(left,right)={(s,x),b=0(x,s),b=1 (\operatorname{left}_\ell,\operatorname{right}_\ell)= \begin{cases} (s_\ell,x_\ell),& b_\ell=0\\ (x_\ell,s_\ell),& b_\ell=1 \end{cases}

Хаши разрешения

Разделы предоставления и отмены роли расшифровывают свидетель разрешения:

hperm=HF(P(role_idpermission_idepochle)) h_{\text{perm}} = H_F(P(\operatorname{role\_id}\|\operatorname{permission\_id}\|\operatorname{epoch}_{le}))

Таблица разрешений хоста сортирует записи по батам роли, батам разрешения и батам эпохи, затем создает дерево Poseidon2 Merkle:

M0[j]=hperm,j M_0[j]=h_{\text{perm},j}

Mk+1[j]=HF(seed(fastpq:v1:poseidon_node),Mk[2j],Mk[2j+1]) M_{k+1}[j] = H_F(\operatorname{seed}(\texttt{fastpq:v1:poseidon\_node}),M_k[2j],M_k[2j+1])

Уровни необычной ширины дублируют последний элемент.

Отслеживание обязательств

Для каждой колонки следов c, FastPQ сначала интерполирует значения колонны над доменой следов и хэширует вектор коэффициента:

Cc=HF(seed(fastpq:v1:trace:column:c),coeffs(c)) C_c = H_F( \operatorname{seed}(\texttt{fastpq:v1:trace:column:}c), \operatorname{coeffs}(c) )

Корень следа - корень Посейдона2 Меркеля над обязательствами столбцов:

Rtrace=MerkleRoot(C0,,Cm1) R_{\text{trace}} = \operatorname{MerkleRoot}(C_0,\ldots,C_{m-1})

Окончательное обязательство отслеживания - это хэш байта над доменом, набором параметров, формой отслеживаний, дигестом колонки и корнем отслеживание:

commitment=Hash(len(Dc)Dclen(parameter)parameternNmC0Cm1Rtrace) \operatorname{commitment} = \operatorname{Hash}( \operatorname{len}(D_c)\|D_c\| \operatorname{len}(\text{parameter})\|\text{parameter}\| n\|N\|m\|C_0\|\cdots\|C_{m-1}\|R_{\text{trace}} )

где D_c является fastpq:v1:trace_commitment.

Состав AIR

Значение составления V1 AIR представляет собой линейную комбинацию местных остатков ряда.

α0,α1F \alpha_0,\alpha_1 \in F

Для каждой соседней пары рядов (i,i+1) проверка вычисляет:

Ai=jαjmod2ρi,j A_i=\sum_j \alpha_{j\bmod2}\rho_{i,j}

Остатки rho следуют в кодовом порядке:

ρ=s(s1)for each selector column \rho=s(s-1) \quad\text{for each selector column}

ρ=sactive(stransfer+smint+sburn+srole_grant+srole_revoke+smeta_set) \rho = s_{\text{active}} - (s_{\text{transfer}}+s_{\text{mint}}+s_{\text{burn}}+ s_{\text{role\_grant}}+s_{\text{role\_revoke}}+s_{\text{meta\_set}})

ρ=sperm(srole_grant+srole_revoke) \rho = s_{\text{perm}}-(s_{\text{role\_grant}}+s_{\text{role\_revoke}})

ρ=sactive,i+1(1sactive,i) \rho = s_{\text{active},i+1}(1-s_{\text{active},i})

Для рядов с числовыми колонками:

ρ=(stransfer+smint+sburn)((value_new0value_old0)δ) \rho = (s_{\text{transfer}}+s_{\text{mint}}+s_{\text{burn}}) \cdot ((\operatorname{value\_new}_{0}-\operatorname{value\_old}_{0})-\delta)

И для стабильных бачек контекстных колонк:

ρ=metadata_hashimetadata_hashi+1 \rho = \operatorname{metadata\_hash}_i-\operatorname{metadata\_hash}_{i+1}

ρ=dsididsidi+1 \rho = \operatorname{dsid}_i-\operatorname{dsid}_{i+1}

ρ=slotisloti+1 \rho = \operatorname{slot}_i-\operatorname{slot}_{i+1}

Проверщик пересчитывает A_i для откровенных рядов из выборки и проверяет его по отношению к стоимости состава, обязавшейся в соответствии с корнем Merkle соединения AIR.

Продукт поиска

Аккумулятор поиска разрешений использует задачу Fiat-Shamir gamma. При оценке расширения низкой степени s_perm и perm_hash работающий продукт:

z0=1 z_0=1

zi+1={zi(wi+γ),sperm,i0zi,sperm,i=0 z_{i+1}= \begin{cases} z_i\cdot(w_i+\gamma),& s_{\text{perm},i}\ne0\\ z_i,& s_{\text{perm},i}=0 \end{cases}

Доказательства:

lookup_grand_product=HF(z0,z1,) \operatorname{lookup\_grand\_product}=H_F(z_0,z_1,\ldots)

Низкое расширение

Пусть omega_T является генератором домена следов, omega_E - генератором доменов оценки и g - конфигурированным косетом. Для колонны следов с значениями v_i интерполяция дает коэффициенты a_j, такие, чтобы:

f(ωTi)=vi f(\omega_T^i)=v_i

Увеличение низкой степени оценивает один и тот же полиномиал на косе:

LDEf(i)=f(gωEi) \operatorname{LDE}_f(i)=f(g\cdot\omega_E^i)

Использование вычисляет это, умножая коэффициенты на полномочия косетного компенсирования до FFT:

aj=ajgj a'_j = a_j g^j

а затем оценивать a' на домене оценки.

В настоящее время CPU FFT - это итеративная трансформация радикс-2 Кули-Туки над бит-обратными входами. L, полудлина H=L/2, и корень стадии:

ωL=ωN/L \omega_L=\omega^{N/L}

каждый бабочек вычисляет:

u=xj u=x_j

v=xj+HωLj v=x_{j+H}\cdot\omega_L^j

xj=u+v,xj+H=uv x_j'=u+v,\qquad x_{j+H}'=u-v

Обратная FFT выполняет ту же трансформацию, что и omega^{-1} и масштабирует по размеру обратного домена:

IFFT(x)=N1FFTω1(x) \operatorname{IFFT}(x)=N^{-1}\cdot\operatorname{FFT}_{\omega^{-1}}(x)

Корни каталога проверяются перед использованием:

ω2k=1 \omega^{2^k}=1

ω2k11(k>0) \omega^{2^{k-1}}\ne1\qquad(k>0)

Для более мелких доменов, полученных из кореня каталога, генератор является:

ω=ωmax2kmax \omega_{\ell}=\omega_{\max}^{2^{k_{\max}-\ell}}

Ряд и листья

После LDE, FastPQ hashes на каждом ряду по всем LDE колонки. m колонки:

ri=HF(i,m,xi,0,xi,1,,xi,m1) r_i = H_F(i,m,x_{i,0},x_{i,1},\ldots,x_{i,m-1})

Если хаши ряда по-прежнему находятся в домене следов, а не в домене оценки, провер интерполирует и расширяет одну колонку хаша ряда с помощью того же процесса coset LDE.

Мерклские открытия

Значения LDE группируются в части:

Blde=8fri_arity B_{\text{lde}}=8\cdot\operatorname{fri\_arity}

Каждый кусок листа:

Lj=HD(jvjBvjB+B1) L_j=H_D(j\|v_{jB}\|\cdots\|v_{jB+B-1})

Родители Меркл:

Pj=HF(seed(fastpq:v1:trace:node),L2j,L2j+1) P_j = H_F(\operatorname{seed}(\texttt{fastpq:v1:trace:node}),L_{2j},L_{2j+1})

Нередкие уровни дублируют последний узел. Пути запроса проверяются путем хэширования слева или справа в соответствии с паритностью индекса листа запроса на каждом уровне.

Для листья с индексом i путь (s_0,\ldots,s_{d-1}) проверяется против корня R повторением:

y0=Li y_0=L_i

yk+1={HF(seed(fastpq:v1:trace:node),yk,sk),i/2k0(mod2)HF(seed(fastpq:v1:trace:node),sk,yk),i/2k1(mod2) y_{k+1}= \begin{cases} H_F(\operatorname{seed}(\texttt{fastpq:v1:trace:node}),y_k,s_k), & \lfloor i/2^k\rfloor \equiv 0 \pmod 2\\ H_F(\operatorname{seed}(\texttt{fastpq:v1:trace:node}),s_k,y_k), & \lfloor i/2^k\rfloor \equiv 1 \pmod 2 \end{cases}

Проверка проходит только тогда, когда:

yd=R y_d=R

AIR листья ряда следов:

Liair=HD(imxi,0xi,m1) L^{\text{air}}_i = H_D(i\|m\|x_{i,0}\|\cdots\|x_{i,m-1})

AIR составные листья:

Licomp=HD(iAi) L^{\text{comp}}_i = H_D(i\|A_i)

Открытие запроса LDE также проверяет, присутствует ли значение, открываемое на индексе оценки i, в его аутентифицированной части:

chunk_index=iBlde \operatorname{chunk\_index}=\left\lfloor\frac{i}{B_{\text{lde}}}\right\rfloor

chunk_offset=imodBlde \operatorname{chunk\_offset}=i\bmod B_{\text{lde}}

chunk[chunk_offset]=vi \operatorname{chunk}[\operatorname{chunk\_offset}]=v_i

FRI Складка

FRI обязуется AIR оценки состава. Для каждого раунда l транскрипты пробивают вызов beta_l. Слой заполняется на множественное количество арности, повторяя последнее значение. Каждая группа размером с arity складывается в:

yl+1,j=k=0a1yl,ja+kβlk y_{l+1,j} = \sum_{k=0}^{a-1} y_{l,ja+k}\beta_l^k

где a представляет собой значение FRI. Проверщик проверяет для каждой выбранной образцом цепочки запросов:

yl+1,i/a=k=0a1yl,i/aa+kβlk y_{l+1,\lfloor i/a\rfloor} = \sum_{k=0}^{a-1} y_{l,\lfloor i/a\rfloor a+k}\beta_l^k

и удостоверяет подлинность каждой открытой группы FRI по соответствующему корню слоя FRI.

Транскрипция Fiat-Shamir

Канонический каталог параметров маркирует хэш транскрипта как SHA3-256. Нынешняя реализация провера и верификатора выводит байты вызова с iroha_crypto::Hash::new, который является 32-байтомным дигестом Blake2bVar, а затем уменьшает первые восемь небольших эндианских байтов на F:

χ(tag)=le64(Hash(statelen(tag)tag)[0..8])modp \chi(\text{tag}) = \operatorname{le64}(\operatorname{Hash}(\text{state}\|\operatorname{len}(\text{tag})\|\text{tag})[0..8]) \bmod p

Призывы вызова добавляют полный перевод к состоянию транскрипта.

  1. публичная IO, протокольная версия, параметровая версия и название параметра;
  2. LDE корень и корень следов
  3. gamma
  4. Составные проблемы AIR alpha_0, alpha_1
  5. AIR корень следов и корень состава AIR
  6. поиск грандиозный продукт
  7. Корни слоев FRI и вызовы beta_l
  8. индексы запросов с выборкой

Запросная выборка продолжает рисовать 32-байтные дигесты вызова и читать их в виде небольших отрезков u64 до тех пор, пока она не получит запрошенное количество уникальных индексов:

q=le64(digest chunk)modNeval q = \operatorname{le64}(\text{digest chunk})\bmod N_{\text{eval}}

Образец сборки возвращается в сортированном порядке.

Повторное воспроизведение проверки

В первую очередь проверяющий пересчитывает обязательство партии:

commitmentexpected=trace_commitment(params,batch) \operatorname{commitment}_{expected} =\operatorname{trace\_commitment}(\operatorname{params},\operatorname{batch})

и требует:

commitmentexpected=proof.trace_commitment \operatorname{commitment}_{expected} =\operatorname{proof.trace\_commitment}

Он также восстанавливает общественность IO:

PublicIO=(dsid,slot,old_root,new_root,perm_root,tx_set_hash,ordering_hash,permission_hashes) \operatorname{PublicIO}= (\operatorname{dsid},\operatorname{slot},\operatorname{old\_root}, \operatorname{new\_root},\operatorname{perm\_root}, \operatorname{tx\_set\_hash},\operatorname{ordering\_hash}, \operatorname{permission\_hashes})

Каждое поле должно соответствовать публичному IO байту за байтом доказательства. Затем проверяющий восстанавливает ту же транскрипт и получает такую же:

γ,α0,α1,β0,,β1,q0,,qt1 \gamma,\quad \alpha_0,\alpha_1,\quad \beta_0,\ldots,\beta_{\ell-1},\quad q_0,\ldots,q_{t-1}

Для каждого запроса, сделанного по образцу q, он проверяет:

MerkleVerify(Rlde,Lq/Blde,q/Blde,πlde) \operatorname{MerkleVerify}( R_{\text{lde}}, L_{\lfloor q/B_{\text{lde}}\rfloor}, \lfloor q/B_{\text{lde}}\rfloor, \pi_{\text{lde}} )

MerkleVerify(Rair,Lqair,q,πair,current) \operatorname{MerkleVerify}( R_{\text{air}}, L^{\text{air}}_q, q, \pi_{\text{air,current}} )

MerkleVerify(Rair,Lq+1modNevalair,q+1modNeval,πair,next) \operatorname{MerkleVerify}( R_{\text{air}}, L^{\text{air}}_{q+1\bmod N_{\text{eval}}}, q+1\bmod N_{\text{eval}}, \pi_{\text{air,next}} )

и:

Aq=AIRComposition(rowq,rowq+1,α0,α1) A_q = \operatorname{AIRComposition}( \operatorname{row}_q,\operatorname{row}_{q+1},\alpha_0,\alpha_1 )

В настоящее время AIR открытие композиции должно быть удостоверено под R_air_composition. В настоящее время FRI цепь затем начинается с того же A_q и должны завершаться в завершенном завершении FRI лист под терминалом FRI корень.

Что проверяет Притча

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

Для переводных транскриптов проверки на стороне провизора включают:

  • баланс отправителя не должен поступать ниже
  • sender_after должен быть равен sender_before - amount
  • receiver_after должен быть равен receiver_before + amount
  • Перепись должна охватывать каждый переводный ряд в партии.
  • Digest Poseidon с одной дельтой, если присутствует, должен соответствовать предварительным изображениям транскрипта.
  • при условии, что детерминированные синтетические доказательства должны расшифровываться в виде версии 1; отсутствующие пути заполнены детерминистическими синтетическими доказательствами

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

Проверка Лейна

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

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

По проезжей части строят проверку:

text
parameter = "fastpq-lane-balanced"
execution_mode = auto | cpu | gpu
poseidon_mode = auto | cpu | gpu

auto позволяет проверяющему выбрать доступный бэкэнд. cpu Пин исполнение к CPU. gpu предпочитает GPU исполнение, с CPU fallback, когда обратный конец не может использовать запрашиваемые ядра.

Проверка

FastPQ проверка доказательств восстанавливает каноническую партию обязательства и заменяет общественную транскрипцию. Проверщик проверяет версию протокола, версию параметров, пределы воспроизведения, обязательства по отслеживанию, публичные вводы, пробные отверстия Merkle, AIR открытия, и FRI цепочка запросов.

Ограничения повторяния по умолчанию включают:

ОграничениеПо умолчанию
Переходные строки256
Размер полного груза партии256 KiB
FRI слои16
Вопросы открытия128

Nexus Проверенные реле

Nexus AXT свидетельские конверты могут включать в себя AxtFastpqBinding. Когда RegisterVerifiedLaneRelay исполняет, Iroha:

  1. проверяет обложку релевого полоса и материалы прочности FastPQ
  2. проверяет пространство данных и корень манифестирования
  3. декодирует оболочку доказательств AXT
  4. требует fastpq_binding
  5. восстанавливает партию FastPQ из этой связки
  6. декодирует встроенное доказательство FastPQ
  7. вызовет проверяющего FastPQ на перестроенную партию и доказательство

В случае успешной проверки Iroha сохраняет VerifiedLaneRelayRecord, содержащий ссылку на реле, оригинальную конвертку, хеш-нагрузку доказательства, высоту проверки, корень манифестирования и связывание FastPQ.

В линейных релевых конвертах также есть компактный FastPQ доказательный материал. Материал представляет собой перечисление идентификатора полосы, идентификатора пространства данных, высоты блока, высоты проверки, хэширования заголовков блоков, хэширование расчетов и корня манифеста. Слияние эстафеты допускается только в том случае, если у него есть как доказательный материал QC, так и действительный FastPQ.

AXT Обязательная математика

Для Nexus AXT конверты, AxtFastpqBinding пустые параметры по умолчанию для fastpq-lane-balanced; пустой идентификатор проверщика и версия по умолчанию fastpq и v1; тип заявления сокращается и уменьшается.

Публичные входы AXT FastPQ представляют собой определённые байт-хаши:

dsid=dsid_bytes(source_dsid) \operatorname{dsid}=\operatorname{dsid\_bytes}(\operatorname{source\_dsid})

slot=le64(source_tx_commitment[0..8]) \operatorname{slot}=\operatorname{le64}(\operatorname{source\_tx\_commitment}[0..8])

old_root=Hash(fastpq-json:old_rootsource_tx_commitmentpolicy_commitmenteffect_type) \operatorname{old\_root} = \operatorname{Hash}( \texttt{fastpq-json:old\_root}\| \operatorname{source\_tx\_commitment}\| \operatorname{policy\_commitment}\| \operatorname{effect\_type} )

new_root=Hash(fastpq-json:new_rootsource_tx_commitmentclaim_digesteffect_type) \operatorname{new\_root} = \operatorname{Hash}( \texttt{fastpq-json:new\_root}\| \operatorname{source\_tx\_commitment}\| \operatorname{claim\_digest}\| \operatorname{effect\_type} )

perm_root=Hash(fastpq-json:perm_rootpolicy_commitmentverifier_idverifier_version) \operatorname{perm\_root} = \operatorname{Hash}( \texttt{fastpq-json:perm\_root}\| \operatorname{policy\_commitment}\| \operatorname{verifier\_id}\| \operatorname{verifier\_version} )

tx_set_hash=Hash(fastpq-json:tx_set_hashsource_tx_commitmentclaim_digestwitness_commitment) \operatorname{tx\_set\_hash} = \operatorname{Hash}( \texttt{fastpq-json:tx\_set\_hash}\| \operatorname{source\_tx\_commitment}\| \operatorname{claim\_digest}\| \operatorname{witness\_commitment} )

Переходные ключи AXT:

key(prefix,x,y)=prefix/x/y \operatorname{key}(\operatorname{prefix},x,y)= \operatorname{prefix}\|\texttt{/}\|x\|\texttt{/}\|y

В заявке authorization вставляется строка "дополнительная часть":

role_id=claim_digest \operatorname{role\_id}=\operatorname{claim\_digest}

permission_id=witness_commitment \operatorname{permission\_id}=\operatorname{witness\_commitment}

epoch=le64(policy_commitment[0..8]) \operatorname{epoch}= \operatorname{le64}(\operatorname{policy\_commitment}[0..8])

и ряд метаданных, обязывающий политику выдачи разрешений. В заявке compliance вводятся две строки метаданных: одна для политики, а другая - для целевых пространств.

Для tx_predicate и value_conservation используется выраженная величина эффекта, если связь содержит положительную сумму источника или назначения. В противном случае код получает ограниченную детерминирующую величину:

bounded(d,min,span)=min+(le64(d[0..8])modmax(span,1)) \operatorname{bounded}(d,\min,\operatorname{span}) = \min + (\operatorname{le64}(d[0..8])\bmod\max(\operatorname{span},1))

Затем используются те же уравнения передачи:

sender_after=sender_beforea \operatorname{sender\_after}=\operatorname{sender\_before}-a

receiver_after=receiver_before+a \operatorname{receiver\_after}=\operatorname{receiver\_before}+a

Синтетические идентификаторы учетной записи отправителя и получателя генерируются из ключевых семян:

seed=Hash(labelentropy)[0..32] \operatorname{seed}= \operatorname{Hash}(\operatorname{label}\|\operatorname{entropy})[0..32]

Хеш для передачи партии:

batch_hash=Hash(labelcorridorsource_tx_commitmentclaim_digest) \operatorname{batch\_hash} = \operatorname{Hash}( \operatorname{label}\| \operatorname{corridor}\| \operatorname{source\_tx\_commitment}\| \operatorname{claim\_digest} )

Манифест партии AXT переводится как SHA-256 над кодированием Norito канонического связывающего устройства:

manifest_digest=SHA256(E(canonical_binding)) \operatorname{manifest\_digest} = \operatorname{SHA256}(E(\operatorname{canonical\_binding}))

SCCP Прозрачное подтверждение сообщения

В помощном ящике SCCP также используется FastPQ для прозрачных доказательств передачи сообщений с перекрестной цепочкой. Этот путь отделен от фоновой полосы проверки irohad. Он создает партию FastPQ непосредственно из пакета доказательств сообщений SCCP и манифеста, а затем заворачивает полученное доказательство для открытой проверки.

В партии SCCP используются fastpq-lane-balanced и три перехода метаданных:

Ключ .Операция
sccp:transparent:v1:statementMetaSet
sccp:transparent:v1:contextMetaSet
sccp:transparent:v1:payloadMetaSet

Его публичные вводы получены из прозрачного внутреннего доказательства SCCP:

FastPQ входSCCP источник
dsidПервые 16 байтов переваривания Blake2b над заявлением hash
slotВысота завершения
old_rootНагрузка на загрузку
new_rootКорень обязательства
perm_rootХеш-блок окончательности
tx_set_hashЗаявление хэш

Канонические кодеры SCCP записывают целые числа небольшим эндианом и кодируют массивы байтов переменной длины, как:

vec(x)=le32(x)x \operatorname{vec}(x)=\operatorname{le32}(|x|)\|x

Прозрачная последовательность публичных вводных байтов является:

P=versionmessage_idpayload_hashle32(target_domain)commitment_rootle64(finality_height)finality_block_hash P = \operatorname{version}\| \operatorname{message\_id}\| \operatorname{payload\_hash}\| \operatorname{le32}(\operatorname{target\_domain})\| \operatorname{commitment\_root}\| \operatorname{le64}(\operatorname{finality\_height})\| \operatorname{finality\_block\_hash}

Прозрачные байты заявления - это конкаценация версии, семейства цепочек, локальных и контрагентных доменов, модель безопасности, управление якорем, кодек учетной записи, модель окончательности, целевая цель верификатора, семья бэкэнд-верификатора, поля длиной префиксированной цепочки/бэкэнд/манифеста, хэш с обязательным назначением; Ключ к кодеку учетной записи, тип полезной нагрузки, публичные байты ввода и хэш полезной загрузки.

statement_hash=Blake2bVar32(sccp:transparent:statement:v1statement) \operatorname{statement\_hash} = \operatorname{Blake2bVar}_{32}( \texttt{sccp:transparent:statement:v1}\|\operatorname{statement} )

Идентификатор пространства данных FastPQ для этого пути доказательства - это первые шестнадцать байтов другого префиксированного диджета Blake2b:

dsid=Blake2bVar32(sccp:transparent:fastpq:dsid:v1statement_hash)[0..16] \operatorname{dsid} = \operatorname{Blake2bVar}_{32}( \texttt{sccp:transparent:fastpq:dsid:v1}\|\operatorname{statement\_hash} )[0..16]

партия SCCP FastPQ является точно:

(sccp:transparent:v1:statement,,statement,MetaSet) (\texttt{sccp:transparent:v1:statement},\varnothing,\operatorname{statement},\operatorname{MetaSet})

(sccp:transparent:v1:context,,E(inner_proof),MetaSet) (\texttt{sccp:transparent:v1:context},\varnothing,E(\operatorname{inner\_proof}),\operatorname{MetaSet})

(sccp:transparent:v1:payload,,canonical_payload,MetaSet) (\texttt{sccp:transparent:v1:payload},\varnothing,\operatorname{canonical\_payload},\operatorname{MetaSet})

Затем сортировка по тому же правилу заказа FastPQ.

В настоящее время OpenVerify обязательства проверщика SHA-256 на SCCP имя задней части сообщения и канонический FastPQ описатель верификатора:

vk_hash=SHA256(message_backendverifier_descriptor) \operatorname{vk\_hash} = \operatorname{SHA256}( \operatorname{message\_backend}\|\operatorname{verifier\_descriptor} )

Сырье FastPQ доказательство Norito-кодируются в StarkFriOpenProofV1, Затем упакованный в OpenVerifyEnvelope с задней панелью Stark. SCCP проверка восстанавливает то же самое FastPQ партия из пакета и манифеста, проверяет метаданные открытого конверта верификации, и обращается к FastPQ верификатор на перестроенной партии и доказательство.

Параметровые наборы

Канонный каталог параметров раскрывает два набора параметров. В настоящее время проездная полоса проводника использует fastpq-lane-balanced.

ПараметрЦель .ПолеХашиFRI
fastpq-lane-balancedсбалансированная пропускная способностьЗолотолосы квадратное расширениеОбязательства Poseidon2, каталог SHA3Арита 8, взрыв, 8, 46 вопросов
fastpq-lane-latencyтрассы с чувствительным к задержкеЗолотолосы квадратное расширениеОбязательства Poseidon2, каталог SHA3Аритет 16, взрыв 16, 34 запроса

Оба целятся на 128-битную безопасность и используют размер домена отслеживания 2^16. Код воспроизведения транскрипта Rust V1 в настоящее время выводит байты задачи Fiat-Shamir с помощью iroha_crypto::Hash::new вместо того, чтобы прямо призывать SHA3-256.

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

Постоянно .fastpq-lane-balancedfastpq-lane-latency
target_security128128
grinding_bits2321
trace_log_size1616
trace_root0x002a247f81c6f8500x6a9f4eb38fb9b892
lde_log_size1920
lde_root0x60263388dbbf9b2a0x9c9c3a571b6f89ac
permutation_size65,53665,536
lookup_log_size1920
omega_coset0x6af325e825ad5c180x3a5fd4171e3c3a4d
fri_arity816
fri_blowup816
fri_max_reductions86
fri_queries4634

Конфигурация

Конфигурация FastPQ размещена под zk.fastpq.

toml
[zk.fastpq]
execution_mode = "auto"
poseidon_mode = "auto"

# Optional telemetry labels.
device_class = "apple-m4"
chip_family = "m4"
gpu_kind = "integrated"

# Optional Metal backend tuning.
metal_queue_fanout = 3
metal_queue_column_threshold = 24
metal_max_in_flight = 5
metal_threadgroup_width = 128
metal_trace = false
metal_debug_enum = false
metal_debug_fused = false

Те же маркировки выполнения и телеметрии могут быть отменены на irohad:

shell
irohad --fastpq-execution-mode auto
irohad --fastpq-poseidon-mode cpu
irohad --fastpq-device-class apple-m4
irohad --fastpq-chip-family m4
irohad --fastpq-gpu-kind integrated

Окружающие переменные также поддерживаются для полей конфигурации. FastPQ-специфические переменные включают:

  • FASTPQ_EXECUTION_MODE
  • FASTPQ_POSEIDON_MODE
  • FASTPQ_DEVICE_CLASS
  • FASTPQ_CHIP_FAMILY
  • FASTPQ_GPU_KIND
  • FASTPQ_METAL_QUEUE_FANOUT
  • FASTPQ_METAL_COLUMN_THRESHOLD
  • FASTPQ_METAL_MAX_IN_FLIGHT
  • FASTPQ_METAL_THREADGROUP
  • FASTPQ_METAL_TRACE
  • FASTPQ_DEBUG_METAL_ENUM
  • FASTPQ_DEBUG_FUSED

Показатели

При включении телеметрии FastPQ экспортирует показатели для выбора бэкэнда и поведения металла в течение времени выполнения:

МетрическийЗначение .
fastpq_execution_mode_totalЗапрошенный и решенный режим выполнения по бакетам заднего кода и ярлыкам устройств
fastpq_poseidon_pipeline_totalЗапрошенный и решенный путь трубопровода " Посейдон "
fastpq_metal_queue_depthМеталловой лимит очереди, максимальное количество в полете, количество отправки и окно выборки образцов
fastpq_metal_queue_ratioМеталлическая очередь занята и соотношения перекрытия
fastpq_zero_fill_duration_msПродолжительность заполнения хоста для металлических путей
fastpq_zero_fill_bandwidth_gbpsВыделенная нулевая полоса пропускания

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