Rescue-Prime hash STARK 代码解析

1. 引言

前序博客有:

相关代码见:

Rescue-Prime hash STARK为例。
Rescue-Prime STARK 针对的场景为:

  • public info: h , H h,H h,H
  • private info: x x x
  • 待证明relation: h = H ( x ) h=H(x) h=H(x)

其中 H ( ∗ ) H(*) H() 为Rescue-Prime hash函数。

Rescue-Prime hash运算中涉及:

  • trace:witness信息,Rescue-Prime hash算法中每一轮的输入输出;
  • boundary constraints:公开信息,Rescue-Prime hash函数算法中第一轮的补0,以及最后的hash结果;
  • transition constraints(又称为AIR constraints):公开信息,Rescue-Prime hash算法中每一轮的函数运算。

2. Rescue-Prime hash函数

根据Alan Szepieniec等人2020年论文《Rescue-Prime: a Standard Specification (SoK)》可知,Rescue-Prime哈希函数主要参数有 ( p , m , c p , s ) (p,m,c_p,s) (p,m,cp,s)

  • p p p:定义了素数域 F p \mathbb{F}_p Fp p p p为素数且具有a binary expansion of at least 32 bits。
  • m m m:定义了哈希函数的state width。状态由 m > 1 m>1 m>1个field elements确定。
  • c p c_p cp:为arithmetic sponge的capacity。
    r p = m − c p r_p=m-c_p rp=mcp
    r p r_p rp:为该arithmetic sponge的rate,决定了Recue-XLIX permutation之间absorb的field elements数量。
  • 80 ≤ s ≤ 512 80\leq s\leq 512 80s512:为 target security level,以bits为单位。

此外,还有如下参数:

  • α 和 α − 1 \alpha和\alpha^{-1} αα1:为S-boxes的幂乘系数。对于所有的 x ∈ F p x\in\mathbb{F}_p xFp,有 ( x α ) α − 1 = x (x^{\alpha})^{\alpha^{-1}}=x (xα)α1=x成立。
  • M ∈ F p m × m M\in\mathbb{F}_p^{m\times m} MFpm×m:为 m × m m\times m m×m MDS矩阵。
  • N ∈ N N\in\mathbb{N} NN为round数,一个单一的Rescue-XLIX permutation中包含了 N N N个simpler base permutation迭代,这种simpler base permutation称为a round。
  • 2 m N 2mN 2mN个field elements { C i } i = 0 2 m N − 1 \{C_i\}_{i=0}^{2mN-1} {Ci}i=02mN1:round constants。

2.1 sponge函数

Rescue-Prime hash函数本质是将任意长的field elements序列 映射为 r p r_p rp个field elements:
f R ′ : F p ∗ → F p r p f_{R'}:\mathbb{F}_p^*\rightarrow \mathbb{F}_p^{r_p} fR:FpFprp
其在sponge构造中使用了Rescue-XLIX permutation。最终sponge函数会将任意长的序列 映射为 任意长的field elements序列:
f R ′ − s p o n g e : F p ∗ → F ⋆ f_{R'-sponge}:\mathbb{F}_p^*\rightarrow \mathbb{F}^\star fRsponge:FpF
然后对该sponge函数裁剪,仅获取其前 r p r_p rp个elements作为结果。

在sponge函数的evaluation过程中,包含了:

  • 1)a permutation f R X L I X : F p m → F p m f_{R^{XLIX}}:\mathbb{F}_p^m\rightarrow \mathbb{F}_p^m fRXLIX:FpmFpm
  • 2)具有 m m m个field elements的register,称为state。state的初始状态为全零序列 0 ∈ F p m \mathbf{0}\in\mathbb{F}_p^m 0Fpm
  • 3)two phases:absorbing phase以及squeezing phase。
    • 3.1)absorbing阶段:会重复以下流程,直到所有的input elements都吸收完毕:

      • 3.1.1)将input序列中的next r p r_p rp个elements 与 state的前 r p r_p rp个elements相加;
      • 3.1.2)以与 r p r_p rp个input elements相加后的state为输入,运用permutation f R X L I X f_{R^{XLIX}} fRXLIX,获得新的state。
    • 3.2)squeezing阶段:state的前 r p r_p rp个elements即为输出。理论上,可对state递归调用 f R X L I X f_{R^{XLIX}} fRXLIX获得任意长的output elements序列,不过本文限制为output elements数量最多为 r p r_p rp个。

以input elements长度为 2 ∗ r p 2*r_p 2rp为例,相应的absorbing阶段具有2次迭代,示意为:
在这里插入图片描述
填充Padding:当inputs为任意长度时,sponge函数需要进行填充操作——在inputs之后附加一个 1 ∈ F p 1\in\mathbb{F}_p 1Fp以及一堆 0 ∈ F p 0\in\mathbb{F}_p 0Fp,使得填充后的inputs长度为 r p r_p rp的整数倍。
相应的SageMath算法示例为:
在这里插入图片描述
在这里插入图片描述

2.2 Rescue-XLIX Permutation

Rescue-XLIX Permutation f R X L I X f_{R^{XLIX}} fRXLIX中包含了 N N N次Rescue-XLIX round函数迭代,单个round中包含了以下6步:

  • 1)S-box layer:对state中的每个元素进行power map ( ⋅ ) α (\cdot)^{\alpha} ()α
  • 2)Linear layer:将MDS矩阵 与 state进行 矩阵向量乘法运算。
  • 3)Constants injection:从round constants { C i } i = 0 2 m N − 1 \{C_i\}_{i=0}^{2mN-1} {Ci}i=02mN1中取next m m m constants,将其与state中的 m m m个元素分别相加。(state中共有 m m m个元素。)
  • 4)Inverse S-box layer:对state中的每个元素进行inverse power map ( ⋅ ) α − 1 (\cdot)^{\alpha^{-1}} ()α1
  • 5)Linear layer:将MDS矩阵 与 state进行 矩阵向量乘法运算。
  • 6)Constants injection:从round constants { C i } i = 0 2 m N − 1 \{C_i\}_{i=0}^{2mN-1} {Ci}i=02mN1中取next m m m constants,将其与state中的 m m m个元素分别相加。(state中共有 m m m个元素。)

m = 3 m=3 m=3为例,Rescue-XLIX permutation中第 i i i轮示意为:
在这里插入图片描述
相应的SageMath代码示例为:
在这里插入图片描述

2.3 MDS矩阵选择

g g g F p \mathbb{F}_p Fp的smallest primitive element,通常取 g = 2 g=2 g=2,基于此找到order为 p − 1 p-1 p1的最小 g g g。详细的生成算法参见SageMath代码:
在这里插入图片描述

2.4 round constants { C i } i = 0 2 m N − 1 \{C_i\}_{i=0}^{2mN-1} {Ci}i=02mN1选择

round constants { C i } i = 0 2 m N − 1 \{C_i\}_{i=0}^{2mN-1} {Ci}i=02mN1选择,见SageMath算法:
在这里插入图片描述

2.5 计算 α \alpha α α − 1 \alpha^{-1} α1

α \alpha α为the smallest integer that is coprime with p − 1 p-1 p1 α − 1 \alpha^{-1} α1为其multiplicative inverse in the ring Z / < p − 1 > \mathbb{Z}/<p-1> Z/<p1>
gcd ⁡ ( p − 1 , 3 ) = 1 \gcd(p-1,3)=1 gcd(p1,3)=1时,有 α = 3 , α − 1 = 2 p − 1 3 \alpha=3,\alpha^{-1}=\frac{2p-1}{3} α=3,α1=32p1
详细的SageMath算法为:
在这里插入图片描述

2.6 计算round数

∣ p ∣ ≥ 32 |p|\geq 32 p32 80 ≤ s ≤ 512 80\leq s\leq 512 80s512时,Gr¨obner basis攻击效率最高,要基于该攻击来选择round数。
详细SageMath算法见:
在这里插入图片描述

2.7 Rescue-Prime哈希算法

Rescue-Prime哈希SageMath算法见:
在这里插入图片描述

3. Rescue-Prime hash STARK证明

https://github.com/aszepieniec/stark-anatomy/blob/master/code/rescue_prime.py中的Rescue-Prime哈希函数实现为例,其设置input length固定为1, r b = 1 , m = 1 , c p = 1 , N = 27 , p = 407 ∗ ( 1 < < 119 ) + 1 r_b=1,m=1,c_p=1,N=27,p=407 * (1 << 119) + 1 rb=1,m=1,cp=1,N=27,p=407(1<<119)+1 等:【本例只需要一次absorb】

class RescuePrime:
    def __init__( self ):
        self.p = 407 * (1 << 119) + 1
        self.field = Field(self.p)
        self.m = 2
        self.rate = 1
        self.capacity = 1
        self.N = 27
        self.alpha = 3
        self.alphainv = 180331931428153586757283157844700080811
        self.MDS = [[FieldElement(v, self.field) for v in [270497897142230380135924736767050121214, 4]],
                    [FieldElement(v, self.field) for v in [270497897142230380135924736767050121205, 13]]]
        self.MDSinv = [[FieldElement(v, self.field) for v in [210387253332845851216830350818816760948, 60110643809384528919094385948233360270]],
                       [FieldElement(v, self.field) for v in [90165965714076793378641578922350040407, 180331931428153586757283157844700080811]]]
        self.round_constants = [FieldElement(v, self.field) for v in [174420698556543096520990950387834928928,
                                        109797589356993153279775383318666383471,
                                        228209559001143551442223248324541026000,
                                        268065703411175077628483247596226793933,
                                        250145786294793103303712876509736552288,
                                        154077925986488943960463842753819802236,
                                        204351119916823989032262966063401835731,
                                        57645879694647124999765652767459586992,
                                        102595110702094480597072290517349480965,
                                        8547439040206095323896524760274454544,
                                        50572190394727023982626065566525285390,
                                        87212354645973284136664042673979287772,
                                        64194686442324278631544434661927384193,
                                        23568247650578792137833165499572533289,
                                        264007385962234849237916966106429729444,
                                        227358300354534643391164539784212796168,
                                        179708233992972292788270914486717436725,
                                        102544935062767739638603684272741145148,
                                        65916940568893052493361867756647855734,
                                        144640159807528060664543800548526463356,
                                        58854991566939066418297427463486407598,
                                        144030533171309201969715569323510469388,
                                        264508722432906572066373216583268225708,
                                        22822825100935314666408731317941213728,
                                        33847779135505989201180138242500409760,
                                        146019284593100673590036640208621384175,
                                        51518045467620803302456472369449375741,
                                        73980612169525564135758195254813968438,
                                        31385101081646507577789564023348734881,
                                        270440021758749482599657914695597186347,
                                        185230877992845332344172234234093900282,
                                        210581925261995303483700331833844461519,
                                        233206235520000865382510460029939548462,
                                        178264060478215643105832556466392228683,
                                        69838834175855952450551936238929375468,
                                        75130152423898813192534713014890860884,
                                        59548275327570508231574439445023390415,
                                        43940979610564284967906719248029560342,
                                        95698099945510403318638730212513975543,
                                        77477281413246683919638580088082585351,
                                        206782304337497407273753387483545866988,
                                        141354674678885463410629926929791411677,
                                        19199940390616847185791261689448703536,
                                        177613618019817222931832611307175416361,
                                        267907751104005095811361156810067173120,
                                        33296937002574626161968730356414562829,
                                        63869971087730263431297345514089710163,
                                        200481282361858638356211874793723910968,
                                        69328322389827264175963301685224506573,
                                        239701591437699235962505536113880102063,
                                        17960711445525398132996203513667829940,
                                        219475635972825920849300179026969104558,
                                        230038611061931950901316413728344422823,
                                        149446814906994196814403811767389273580,
                                        25535582028106779796087284957910475912,
                                        93289417880348777872263904150910422367,
                                        4779480286211196984451238384230810357,
                                        208762241641328369347598009494500117007,
                                        34228805619823025763071411313049761059,
                                        158261639460060679368122984607245246072,
                                        65048656051037025727800046057154042857,
                                        134082885477766198947293095565706395050,
                                        23967684755547703714152865513907888630,
                                        8509910504689758897218307536423349149,
                                        232305018091414643115319608123377855094,
                                        170072389454430682177687789261779760420,
                                        62135161769871915508973643543011377095,
                                        15206455074148527786017895403501783555,
                                        201789266626211748844060539344508876901,
                                        179184798347291033565902633932801007181,
                                        9615415305648972863990712807943643216,
                                        95833504353120759807903032286346974132,
                                        181975981662825791627439958531194157276,
                                        267590267548392311337348990085222348350,
                                        49899900194200760923895805362651210299,
                                        89154519171560176870922732825690870368,
                                        265649728290587561988835145059696796797,
                                        140583850659111280842212115981043548773,
                                        266613908274746297875734026718148328473,
                                        236645120614796645424209995934912005038,
                                        265994065390091692951198742962775551587,
                                        59082836245981276360468435361137847418,
                                        26520064393601763202002257967586372271,
                                        108781692876845940775123575518154991932,
                                        138658034947980464912436420092172339656,
                                        45127926643030464660360100330441456786,
                                        210648707238405606524318597107528368459,
                                        42375307814689058540930810881506327698,
                                        237653383836912953043082350232373669114,
                                        236638771475482562810484106048928039069,
                                        168366677297979943348866069441526047857,
                                        195301262267610361172900534545341678525,
                                        2123819604855435621395010720102555908,
                                        96986567016099155020743003059932893278,
                                        248057324456138589201107100302767574618,
                                        198550227406618432920989444844179399959,
                                        177812676254201468976352471992022853250,
                                        211374136170376198628213577084029234846,
                                        105785712445518775732830634260671010540,
                                        122179368175793934687780753063673096166,
                                        126848216361173160497844444214866193172,
                                        22264167580742653700039698161547403113,
                                        234275908658634858929918842923795514466,
                                        189409811294589697028796856023159619258,
                                        75017033107075630953974011872571911999,
                                        144945344860351075586575129489570116296,
                                        261991152616933455169437121254310265934,
                                        18450316039330448878816627264054416127]]

    def hash( self, input_element ):
        # absorb
        state = [input_element] + [self.field.zero()] * (self.m - 1)

        # permutation
        for r in range(self.N):
            
            # forward half-round
            # S-box
            for i in range(self.m):
                state[i] = state[i]^self.alpha
            # matrix
            temp = [self.field.zero() for i in range(self.m)]
            for i in range(self.m):
                for j in range(self.m):
                    temp[i] = temp[i] + self.MDS[i][j] * state[j]
            # constants
            state = [temp[i] + self.round_constants[2*r*self.m+i] for i in range(self.m)]

            # backward half-round
            # S-box
            for i in range(self.m):
                state[i] = state[i]^self.alphainv
            # matrix
            temp = [self.field.zero() for i in range(self.m)]
            for i in range(self.m):
                for j in range(self.m):
                    temp[i] = temp[i] + self.MDS[i][j] * state[j]
            # constants
            state = [temp[i] + self.round_constants[2*r*self.m+self.m+i] for i in range(self.m)]

        # squeeze
        return state[0]

3.1 execution trace表示

上述哈希运算,对应的execution trace表示为:【将absorb之后的state、以及Rescue-XLIX Permutation f R X L I X f_{R^{XLIX}} fRXLIX中每轮round函数执行后的state,记录在trace中。即trace中有 m m m个field elements】
【以下execution trace表示法,共有 N + 1 N+1 N+1条记录。】

	def trace( self, input_element ):
        trace = []

        # absorb
        state = [input_element] + [self.field.zero()] * (self.m - 1)

        # explicit copy to record state into trace
        trace += [[s for s in state]]

        # permutation
        for r in range(self.N):
            
            # forward half-round
            # S-box
            for i in range(self.m):
                state[i] = state[i]^self.alpha
            # matrix
            temp = [self.field.zero() for i in range(self.m)]
            for i in range(self.m):
                for j in range(self.m):
                    temp[i] = temp[i] + self.MDS[i][j] * state[j]
            # constants
            state = [temp[i] + self.round_constants[2*r*self.m+i] for i in range(self.m)]

            # backward half-round
            # S-box
            for i in range(self.m):
                state[i] = state[i]^self.alphainv
            # matrix
            temp = [self.field.zero() for i in range(self.m)]
            for i in range(self.m):
                for j in range(self.m):
                    temp[i] = temp[i] + self.MDS[i][j] * state[j]
            # constants
            state = [temp[i] + self.round_constants[2*r*self.m+self.m+i] for i in range(self.m)]
            
            # record state at this point, with explicit copy
            trace += [[s for s in state]]

        # squeeze
        # output = state[0]

        return trace

3.2 boundary constraints

以上execution trace表示法,共有 N + 1 N+1 N+1条记录,即总步数 T = N + 1 T=N+1 T=N+1
边界约束条件为:

  • 1)初始absorb时,即trace中的第一条记录,其capacity初始化为0。
  • 2)最后一轮时,即trace中的第 N + 1 N+1 N+1条记录,其第一个值即为指定的output element。
	def boundary_constraints( self, output_element ):
        constraints = []

        # at start, capacity is zero
        constraints += [(0, 1, self.field.zero())]

        # at end, rate part is the given output element
        constraints += [(self.N, 0, output_element)]

        return constraints

3.3 transition constraints(AIR)

以上execution trace表示法,共有 N + 1 N+1 N+1条记录,即总步数cycles T = N + 1 T=N+1 T=N+1
D t r a c e D_{trace} Dtrace为trace evaluation domain。 D t r a c e D_{trace} Dtrace的generator为 ο \omicron ο,其order为 2 k ≥ T + 1 2^k \geq T+1 2kT+1
D t r a c e = { ο i ∣ i ∈ Z } D_{trace} = \lbrace \omicron^i \vert i \in \mathbb{Z}\rbrace Dtrace={οiiZ}

本例中, T = 27 + 1 = 28 T=27+1=28 T=27+1=28,设置了co-linearity check等参数为:

	expansion_factor = 4
    num_colinearity_checks = 2
    security_level = 2

为实现zero-knowledge STARK,引入的randomizer数为:

self.num_randomizers = 4*num_colinearity_checks

transition_constraints_degree默认为2。
相应的trace evaluation domain 和 FRI evaluation domain参数为:

		randomized_trace_length = self.original_trace_length + self.num_randomizers # 28+8=36
        omicron_domain_length = 1 << len(bin(randomized_trace_length * transition_constraints_degree)[2:]) # 离(36*2)最近的2^k,从而结果为2^7=128。
        fri_domain_length = omicron_domain_length * expansion_factor

transition constraints约束表达的基本流程为:

  • 1)基于trace evaluation domain D t r a c e D_{trace} Dtrace,对Rescue-XLIX Permutation f R X L I X f_{R^{XLIX}} fRXLIX中每轮round函数执行时的 2 ∗ m 2*m 2m个round constants参数进行插值,获得相应的first_step_constants(多变量)多项式表示 以及 second_step_constants(多变量)多项式表示。
    def round_constants_polynomials( self, omicron ):
        first_step_constants = []
        for i in range(self.m):
            domain = [omicron^r for r in range(0, self.N)]
            values = [self.round_constants[2*r*self.m+i] for r in range(0, self.N)]
            univariate = Polynomial.interpolate_domain(domain, values)
            multivariate = MPolynomial.lift(univariate, 0)
            first_step_constants += [multivariate]
        second_step_constants = []
        for i in range(self.m):
            domain = [omicron^r for r in range(0, self.N)]
            values = [self.field.zero()] * self.N
            #for r in range(self.N):
            #    print("len(round_constants):", len(self.round_constants), " but grabbing index:", 2*r*self.m+self.m+i, "for r=", r, "for m=", self.m, "for i=", i)
            #    values[r] = self.round_constants[2*r*self.m + self.m + i]
            values = [self.round_constants[2*r*self.m+self.m+i] for r in range(self.N)]
            univariate = Polynomial.interpolate_domain(domain, values)
            multivariate = MPolynomial.lift(univariate, 0)
            second_step_constants += [multivariate]
    
  • 2)以具有 2 m + 1 2m+1 2m+1个变量的多项式transition polynomials c ( X ) = p ( cycle_index , prev_state 1 , ⋯   , prev_state m , next_state 1 , ⋯   , next_state m ) \mathbf{c}(X)=\mathbf{p}(\text{cycle\_index}, \text{prev\_state}_1,\cdots,\text{prev\_state}_m,\text{next\_state}_1,\cdots,\text{next\_state}_m) c(X)=p(cycle_index,prev_state1,,prev_statem,next_state1,,next_statem)来表示,对于permutation内每个round函数的取值,其满足 p ( cycle_index , prev_state 1 , ⋯   , prev_state m , next_state 1 , ⋯   , next_state m ) = 0 \mathbf{p}(\text{cycle\_index}, \text{prev\_state}_1,\cdots,\text{prev\_state}_m,\text{next\_state}_1,\cdots,\text{next\_state}_m)=\mathbf{0} p(cycle_index,prev_state1,,prev_statem,next_state1,,next_statem)=0。对 c ( X ) \mathbf{c}(X) c(X)的AIR表示为:
    	air = []
        for i in range(self.m):
            # compute left hand side symbolically
            # lhs = sum(MPolynomial.constant(self.MDS[i][k]) * (previous_state[k]^self.alpha) for k in range(self.m)) + first_step_constants[i]
            lhs = MPolynomial.constant(self.field.zero())
            for k in range(self.m):
                lhs = lhs + MPolynomial.constant(self.MDS[i][k]) * (previous_state[k]^self.alpha)
            lhs = lhs + first_step_constants[i]
    
            # compute right hand side symbolically
            # rhs = sum(MPolynomial.constant(self.MDSinv[i][k]) * (next_state[k] - second_step_constants[k]) for k in range(self.m))^self.alpha
            rhs = MPolynomial.constant(self.field.zero())
            for k in range(self.m):
                rhs = rhs + MPolynomial.constant(self.MDSinv[i][k]) * (next_state[k] - second_step_constants[k])
            rhs = rhs^self.alpha
    
            # equate left and right hand sides
            air += [lhs-rhs]
    
    

3.4 生成STARK证明

基于execution trace、boundary constraints、transition constraints(AIR),基于FRI evaluation domain,调用stark.prove生成STARK证明。

# prove
trace = rp.trace(input_element)
air = rp.transition_constraints(stark.omicron)
boundary = rp.boundary_constraints(output_element)
proof = stark.prove(trace, air, boundary)

num_registers实际就是Rescue-Prime的state width,本例中为2。
num_randomizers = 4*num_colinearity_checks
生成STARK proof的基本流程为:

  • 1)在trace中附加num_randomiers行随机值,以实现zero-knowledge:
    	# concatenate randomizers
        for k in range(self.num_randomizers):
            trace = trace + [[self.field.sample(os.urandom(17)) for s in range(self.num_registers)]]
    
  • 2)基于附加了随机值之后的trace,构建trace domain和trace polynomials:
    	# interpolate
        trace_domain = [self.omicron^i for i in range(len(trace))]
        trace_polynomials = []
        for s in range(self.num_registers):
            single_trace = [trace[c][s] for c in range(len(trace))]
            trace_polynomials = trace_polynomials + [Polynomial.interpolate_domain(trace_domain, single_trace)]	
    
  • 3)所谓boundary constraints,是指对trace中特定行特定列寄存器值的约束,如本例的boundary constraints为:
    boundary = rp.boundary_constraints(output_element)
    # -------------------
    def boundary_constraints( self, output_element ):
        constraints = []
    
        # at start, capacity is zero
        constraints += [(0, 1, self.field.zero())]
    
        # at end, rate part is the given output element
        constraints += [(self.N, 0, output_element)]
    
        return constraints
    
    boundary constraints的组成格式为(trace_row, trace_column, register_value),基于trace domain,只取boundary中该列包含的行的domain和value值,逐列插值获得boundary polynomials:
    def boundary_interpolants( self, boundary ):
        interpolants = []
        for s in range(self.num_registers):
            points = [(c,v) for c, r, v in boundary if r == s]
            domain = [self.omicron^c for c,v in points]
            values = [v for c,v in points]
            interpolants = interpolants + [Polynomial.interpolate_domain(domain, values)]
        return interpolants
    
  • 4)根据boundary constraints,获取各列boundary polynomial对应的zerofier 多项式:
    def zerofier_domain( domain ):
        field = domain[0].field
        x = Polynomial([field.zero(), field.one()])
        acc = Polynomial([field.one()])
        for d in domain:
            acc = acc * (x - Polynomial([d]))
        return acc
    
  • 5)逐列,(trace_polynomial - boundary_polynomial) / zerofier,获得boundary_quotient多项式:
    	# subtract boundary interpolants and divide out boundary zerofiers
        boundary_quotients = []
        for s in range(self.num_registers):
            interpolant = self.boundary_interpolants(boundary)[s]
            zerofier = self.boundary_zerofiers(boundary)[s]
            quotient = (trace_polynomials[s] - interpolant) / zerofier
            boundary_quotients += [quotient]
    
  • 6)接下来,采用FRI协议来证明以上boundary_quotient结果是多项式。
    FRI evaluation domain为Coset-FRI,取值为:
    fri_domain_length = omicron_domain_length * expansion_factor
    self.omega = self.field.primitive_nth_root(fri_domain_length)
    self.generator = self.field.generator()
    self.fri = Fri(self.generator, self.omega, fri_domain_length, self.expansion_factor, self.num_colinearity_checks)
    
    fri_domain = self.fri.eval_domain()
    # --------------
    def eval_domain( self ):
        return [self.offset * (self.omega^i) for i in range(self.domain_length)]
    
  • 7)逐列,基于FRI evaluation domain,对每个boundary quotient多项式进行commit:
    	# commit to boundary quotients
        boundary_quotient_codewords = []
        boundary_quotient_Merkle_roots = []
        for s in range(self.num_registers):
            boundary_quotient_codewords = boundary_quotient_codewords + [boundary_quotients[s].evaluate_domain(fri_domain)]
            merkle_root = Merkle.commit(boundary_quotient_codewords[s])
            proof_stream.push(merkle_root)
    
  • 8)将trace_polynomials及其偏移多项式放入多项式数组point中,格式为 [ X , t 1 ( X ) , t 2 ( X ) , ⋯   , t m ( X ) , t 1 ( ο ⋅ X ) , t 2 ( ο ⋅ X ) , ⋯   , t m ( ο ⋅ X ) ] [X, t_1(X), t_2(X),\cdots, t_m(X), t_1(\omicron \cdot X), t_2(\omicron \cdot X), \cdots, t_m(\omicron\cdot X)] [X,t1(X),t2(X),,tm(X),t1(οX),t2(οX),,tm(οX)] 2 m + 1 2m+1 2m+1项:【若tp=t(X),则tp.scale(w)=t(wX)。】
    point = [Polynomial([self.field.zero(), self.field.one()])] + trace_polynomials + [tp.scale(self.omicron) for tp in trace_polynomials]
    
  • 9)针对transition constraints,相应的transition polynomials表示为: c ( X ) = p ( X , t 0 ( X ) ) , … , t m − 1 ( X ) , t 0 ( ο ⋅ X ) , … , t m − 1 ( ο ⋅ X ) ) \mathbf{c}(X) = \mathbf{p}(X, t_0(X)), \ldots, t_{\mathsf{m}-1}(X), t_0(\omicron \cdot X), \ldots, t_{\mathsf{m}-1}(\omicron \cdot X)) c(X)=p(X,t0(X)),,tm1(X),t0(οX),,tm1(οX)),逐列,对transition polynomial进行symbolically evaluate:
    	# symbolically evaluate transition constraints
        point = [Polynomial([self.field.zero(), self.field.one()])] + trace_polynomials + [tp.scale(self.omicron) for tp in trace_polynomials]
        transition_polynomials = [a.evaluate_symbolic(point) for a in transition_constraints]
    
  • 10)对未附加随机值的所有有效trace行(本例为 0   N 0~N 0 N行,不包含后续附加的8行随机值),基于trace domain构建transition_zerofier:
    self.original_trace_length = num_cycles
    
    def transition_zerofier( self ):
        domain = self.omicron_domain[0:(self.original_trace_length-1)]
        return Polynomial.zerofier_domain(domain)
    
  • 11)逐列,transition_polynomial / transition_zerofier,获得transition_quotient多项式:
    # divide out zerofier
    transition_quotients = [tp / self.transition_zerofier() for tp in transition_polynomials]
    
  • 12)为实现zero-knowledge,引入degree为self.max_degree(transition_constraints)的随机多项式randomizer_polynomial(来对transition polynomials进行hide),并对其进行commit:
    	# commit to randomizer polynomial
        randomizer_polynomial = Polynomial([self.field.sample(os.urandom(17)) for i in range(self.max_degree(transition_constraints)+1)])
        randomizer_codeword = randomizer_polynomial.evaluate_domain(fri_domain) 
        randomizer_root = Merkle.commit(randomizer_codeword)
        proof_stream.push(randomizer_root)
    
  • 13)获取随机weight值(为randomizer多项式提供1个随机weight值;为每个transition_quotient多项式提供2个随机weight值;为每个boundary_quotient多项式提供2个随机weight值):
    # get weights for nonlinear combination
    #  - 1 randomizer
    #  - 2 for every transition quotient
    #  - 2 for every boundary quotient
    weights = self.sample_weights(1 + 2*len(transition_quotients) + 2*len(boundary_quotients), proof_stream.prover_fiat_shamir())
    
    def sample_weights( self, number, randomness ):
        return [self.field.sample(blake2b(randomness + bytes(i)).digest()) for i in range(0, number)]
    
  • 14)要求每个transition_quotient多项式的degree与期待值相符:
    assert([tq.degree() for tq in transition_quotients] == self.transition_quotient_degree_bounds(transition_constraints)), "transition quotient degrees do not match with expectation"
    
  • 15)将randomizer_polynomial与所有的transition_quotient及其偏移多项式、所有的boundary_quotient及其偏移多项式非线性组合(各多项式分别乘以不同的weight)在一起:
     	# compute terms of nonlinear combination polynomial
        x = Polynomial([self.field.zero(), self.field.one()])
        max_degree = self.max_degree(transition_constraints)
        terms = []
        terms += [randomizer_polynomial]
        for i in range(len(transition_quotients)):
            terms += [transition_quotients[i]]
            shift = max_degree - self.transition_quotient_degree_bounds(transition_constraints)[i]
            terms += [(x^shift) * transition_quotients[i]]
        for i in range(self.num_registers):
            terms += [boundary_quotients[i]]
            shift = max_degree - self.boundary_quotient_degree_bounds(len(trace), boundary)[i]
            terms += [(x^shift) * boundary_quotients[i]]
    	
    	# take weighted sum
        # combination = sum(weights[i] * terms[i] for all i)
        combination = reduce(lambda a, b : a+b, [Polynomial([weights[i]]) * terms[i] for i in range(len(terms))], Polynomial([]))
    
  • 16)对非线性weighted组合后的多项式combination,基于FRI evaluation domain计算相应的codeword,并调用FRI协议证明“非线性weighted组合后的combination确实是low-degree多项式”:【其中Prover会提供针对combination多项式,相应query indices的leaf及其相应的Merkle证明:】
    # compute matching codeword
        combined_codeword = combination.evaluate_domain(fri_domain)
    
        # prove low degree of combination polynomial, and collect indices
        indices = self.fri.prove(combined_codeword, proof_stream)
    
  • 17)针对相同的query indices,Prover还需提供之前所commit的boundary多项式 以及 randomizer多项式 相应的leaf和Merkle证明:
    	# process indices
        duplicated_indices = [i for i in indices] + [(i + self.expansion_factor) % self.fri.domain_length for i in indices]
        quadrupled_indices = [i for i in duplicated_indices] + [(i + (self.fri.domain_length // 2)) % self.fri.domain_length for i in duplicated_indices]
        quadrupled_indices.sort()
    
        # open indicated positions in the boundary quotient codewords
        for bqc in boundary_quotient_codewords:
            for i in quadrupled_indices:
                proof_stream.push(bqc[i])
                path = Merkle.open(i, bqc)
                proof_stream.push(path)
    
        # ... as well as in the randomizer
        for i in quadrupled_indices:
            proof_stream.push(randomizer_codeword[i])
            path = Merkle.open(i, randomizer_codeword)
            proof_stream.push(path)
    
  • 18)最终的proof为对proof_stream的序列化:
    # the final proof is just the serialized stream
        return proof_stream.serialize()
    

3.5 验证STARK证明

Rescue-Prime hash运算中涉及:

  • trace:witness信息,Rescue-Prime hash算法中每一轮的输入输出;
  • boundary constraints:公开信息,Rescue-Prime hash函数算法中第一轮的补0,以及最后的hash结果;
  • transition constraints(又称为AIR constraints):公开信息,Rescue-Prime hash算法中每一轮的函数运算。

因此,验证STARK证明的输入有:

  • proof:STARK证明
  • air:transition constraints(又称为AIR constraints)
  • boundary:boundary constraints
# verify
verdict = stark.verify(proof, air, boundary)
# -----
def verify( self, proof, transition_constraints, boundary, proof_stream=None ):
。。。。。。

验证STARK证明的基本流程为:

  • 1)基于boundary constraints中的最大index,推断出相应的trace length:
    # infer trace length from boundary conditions
    original_trace_length = 1 + max(c for c, r, v in boundary)
    randomized_trace_length = original_trace_length + self.num_randomizers
    
  • 2)对proof进行反序列化:
    	# deserialize with right proof stream
        if proof_stream == None:
            proof_stream = ProofStream()
        proof_stream = proof_stream.deserialize(proof)
    
  • 3)读取各boundary quotient merkle root 和 randomizer多项式的merkle root,基于这些root派生出相应的weights信息:
    	# get Merkle roots of boundary quotient codewords
        boundary_quotient_roots = []
        for s in range(self.num_registers):
            boundary_quotient_roots = boundary_quotient_roots + [proof_stream.pull()]
    
        # get Merkle root of randomizer polynomial
        randomizer_root = proof_stream.pull()
    
        # get weights for nonlinear combination
        weights = self.sample_weights(1 + 2*len(transition_constraints) + 2*len(self.boundary_interpolants(boundary)), proof_stream.verifier_fiat_shamir())
    
  • 4)调用FRI协议,验证非线性weighted组合后的combination多项式为low-degree多项式:【返回的polynomial_values([indices/values])后续要进行polynomial evaluate检查。indices为所query的位置 】
    	# verify low degree of combination polynomial
        polynomial_values = []
        verifier_accepts = self.fri.verify(proof_stream, polynomial_values)
        polynomial_values.sort(key=lambda iv : iv[0])
        if not verifier_accepts:
            return False
    
        indices = [i for i,v in polynomial_values]
        values = [v for i,v in polynomial_values]
    
  • 5)对所有query的indices位置,验证各boundary_quotient的merkle证明成立:
    	# read and verify leafs, which are elements of boundary quotient codewords
        duplicated_indices = [i for i in indices] + [(i + self.expansion_factor) % self.fri.domain_length for i in indices]
        duplicated_indices.sort()
        leafs = []
        for r in range(len(boundary_quotient_roots)):
            leafs = leafs + [dict()]
            for i in duplicated_indices:
                leafs[r][i] = proof_stream.pull()
                path = proof_stream.pull()
                verifier_accepts = verifier_accepts and Merkle.verify(boundary_quotient_roots[r], i, path, leafs[r][i])
                if not verifier_accepts:
                    return False
    
  • 6)对所有query的indices位置,验证randomizer多项式的merkle证明成立:
    	# read and verify randomizer leafs
        randomizer = dict()
        for i in duplicated_indices:
            randomizer[i] = proof_stream.pull()
            path = proof_stream.pull()
            verifier_accepts = verifier_accepts and Merkle.verify(randomizer_root, i, path, randomizer[i])
            if not verifier_accepts:
                return False
    
  • 7)针对 各boundary_quotient多项式 以及 randomizer多项式 query所公开的leaf value,结合weights参数 和 transition constraints(为公开信息,可获得各transition_quotients),重构combination evaluate值,验证其与self.fri.verify返回的values值是否匹配:
    	# verify leafs of combination polynomial
        for i in range(len(indices)):
            current_index = indices[i] # do need i
    
            # get trace values by applying a correction to the boundary quotient values (which are the leafs)
            domain_current_index = self.generator * (self.omega^current_index)
            next_index = (current_index + self.expansion_factor) % self.fri.domain_length
            domain_next_index = self.generator * (self.omega^next_index)
            current_trace = [self.field.zero() for s in range(self.num_registers)]
            next_trace = [self.field.zero() for s in range(self.num_registers)]
            for s in range(self.num_registers):
                zerofier = self.boundary_zerofiers(boundary)[s]
                interpolant = self.boundary_interpolants(boundary)[s]
    
                current_trace[s] = leafs[s][current_index] * zerofier.evaluate(domain_current_index) + interpolant.evaluate(domain_current_index)
                next_trace[s] = leafs[s][next_index] * zerofier.evaluate(domain_next_index) + interpolant.evaluate(domain_next_index)
    
            point = [domain_current_index] + current_trace + next_trace
            transition_constraints_values = [transition_constraints[s].evaluate(point) for s in range(len(transition_constraints))]
    
            # compute nonlinear combination
            counter = 0
            terms = []
            terms += [randomizer[current_index]]
            for s in range(len(transition_constraints_values)):
                tcv = transition_constraints_values[s]
                quotient = tcv / self.transition_zerofier().evaluate(domain_current_index)
                terms += [quotient]
                shift = self.max_degree(transition_constraints) - self.transition_quotient_degree_bounds(transition_constraints)[s]
                terms += [quotient * (domain_current_index^shift)]
            for s in range(self.num_registers):
                bqv = leafs[s][current_index] # boundary quotient value
                terms += [bqv]
                shift = self.max_degree(transition_constraints) - self.boundary_quotient_degree_bounds(randomized_trace_length, boundary)[s]
                terms += [bqv * (domain_current_index^shift)]
            combination = reduce(lambda a, b : a+b, [terms[j] * weights[j] for j in range(len(terms))], self.field.zero())
    
            # verify against combination polynomial value
            verifier_accepts = verifier_accepts and (combination == values[i])
            if not verifier_accepts:
                return False
    

参考资料

[1] Anatomy of a STARK, Part 5: A Rescue-Prime STARK

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Ansible Rescue是一种用于处理故障和恢复的方法。可以使用Ansible Rescue来重新安装操作系统、修复配置文件、恢复数据等。在Ansible中,可以通过编写一个playbook来定义Rescue任务,该playbook包含了需要执行的一系列任务。在执行Rescue任务时,Ansible会评估任务的返回代码,以确定任务是成功还是失败。当任务失败时,Ansible会立即中止play的其余部分,并跳过所有后续任务。此外,还可以使用Ansible的fail模块来强制任务失败,以便进行特定的处理。例如,可以编写一个任务来运行用户创建脚本,并在脚本输出中检查是否缺少密码,如果缺少密码,则使用fail模块报告脚本失败。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [install-arch-linux-server:提供一个命令,通过运行的 Ubuntu live 在服务器上格式化和安装 arch linux](https://download.csdn.net/download/weixin_42157567/19894698)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [ansible实施处理程序和处理失败任务](https://blog.csdn.net/weixin_58130165/article/details/119143078)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值