后量子签名:Fiat-Shamir(下篇)

书接上回

压缩技术

载荷规模对于实用化格签名算法很重要。不同参数下的 [Lyu12] 签名方案,固定 n = 512 n=512 n=512(安全级别约 128 128 128 比特),基于 SIS 问题的签名值规模为 70000 70000 70000 160000 160000 160000 比特,基于 LWE 问题的签名值规模为 14000 14000 14000 19000 19000 19000 比特,两者的公私钥规模为 2 20 2^{20} 220 2 23 2^{23} 223 比特。人们提出了多种压缩技术,降低公钥规模和签名值规模。

丢弃低阶比特

[GLP12] 将整数划分为高阶比特和低阶比特,观察到:如果加上一个较小的整数,则低阶比特加上较小整数几乎不会溢出,从而这保持了高阶比特不变。

定义 R : = Z p [ x ] / ( x n + 1 ) \mathcal R := \mathbb Z_p[x]/(x^n+1) R:=Zp[x]/(xn+1),其中元素的系数范围 [ − ( p − 1 ) / 2 , ( p − 1 ) / 2 ] [-(p-1)/2,(p-1)/2] [(p1)/2,(p1)/2]。再定义 R k \mathcal R_k Rk R \mathcal R R 的子集,它的系数范围是 [ − k , k ] [-k,k] [k,k]。令 y ∈ [ − ( p − 1 ) / 2 , ( p − 1 ) / 2 ] y \in [-(p-1)/2, (p-1)/2] y[(p1)/2,(p1)/2] 是任意整数,对于某正整数 k k k,分解它为 y = y ( 1 ) ( 2 k + 1 ) + y ( 0 ) y=y^{(1)}(2k+1) + y^{(0)} y=y(1)(2k+1)+y(0),易知这个分解是唯一的。对于环元素 y ∈ R y \in \mathcal R yR,对每个系数分别做分解,我们将 y ( 0 ) ∈ R k y^{(0)} \in \mathcal R_k y(0)Rk 叫做低阶比特(lower-order),将 y ( 1 ) y^{(1)} y(1) 叫做高阶比特(higher-order)。

对于任意的 z ∈ R k z \in \mathcal R_k zRk,均匀采样 y ← U R y \leftarrow_\mathcal U \mathcal R yUR,设置 2 n k / 2 > 1 2nk/2>1 2nk/2>1 使得 k k k 足够大,那么存在一个压缩算法,它以至少 0.98 0.98 0.98 的概率,输出另一个 z ′ ∈ R k z' \in \mathcal R_k zRk 使得 ( y + z ) ( 1 ) = ( y + z ′ ) ( 1 ) (y+z)^{(1)} = (y+z')^{(1)} (y+z)(1)=(y+z)(1),并且 z ′ z' z 的长度为 2 n + ⌈ log ⁡ ( 2 k + 1 ) ⌉ ⋅ 6 k n / p 2n+\lceil\log(2k+1)\rceil \cdot 6kn/p 2n+log(2k+1)⌉6kn/p,这远比 z z z 短的多。

压缩算法 C o m p r e s s ( y , z , p , k ) Compress(y,z,p,k) Compress(y,z,p,k) 定义为:

  • 对于 ∣ y [ i ] ∣ > ( p − 1 ) / 2 − k |y[i]|>(p-1)/2-k y[i]>(p1)/2k 的那些位置, y [ i ] + z [ i ] y[i]+z[i] y[i]+z[i] 可能需要模 p p p,因此不能压缩,设置 z ′ [ i ] = z [ i ] z'[i]=z[i] z[i]=z[i],表示为 11 z [ i ] 11z[i] 11z[i](前缀码),这需要 2 + log ⁡ 2 k 2+\log 2k 2+log2k 比特
  • 否则 y [ i ] + z [ i ] y[i]+z[i] y[i]+z[i] 的低阶比特进位也只会影响高阶比特加减一(高阶比特不进位),对于 y [ i ] ( 0 ) + z [ i ] > k y[i]^{(0)}+z[i]>k y[i](0)+z[i]>k 的那些系数设置 z ′ [ i ] = k z'[i]=k z[i]=k,对于 y [ i ] ( 0 ) + z [ i ] < − k y[i]^{(0)}+z[i]<-k y[i](0)+z[i]<k 的那些系数设置 z ′ [ i ] = − k z'[i]=-k z[i]=k,其他情况设置 z ′ [ i ] = 0 z'[i]=0 z[i]=0,分别表示为 00 , 01 , 10 00,01,10 00,01,10,这只需 2 2 2 比特
  • 记数未压缩系数的个数,如果大于 6 k n / p 6kn/p 6kn/p,那么输出 ⊥ \perp ,否则可以输出 z ′ z' z。由于 ∣ y [ i ] ∣ > ( p − 1 ) / 2 − k |y[i]|>(p-1)/2-k y[i]>(p1)/2k 的概率为 2 k / p 2k/p 2k/p,若设置 n ≫ 2 k / p n \gg 2k/p n2k/p 则输出 ⊥ \perp 的二项分布近似为参数 λ = 2 n k / p \lambda=2nk/p λ=2nk/p 的泊松分布(期望和方差都是 λ \lambda λ),根据高斯分布的三西格玛原则,未压缩的个数大于 6 k n / p 6kn/p 6kn/p 的概率至多为 2 % 2 \% 2%

对于基于 RLWE 问题的 [Lyu12] 格签名,对于噪声 s 2 s_2 s2 的签名 z 2 = y 2 + s 2 c z_2=y_2+s_2c z2=y2+s2c 是个短向量,验签等式为 a z 1 + z 2 − t c az_1+z_2-tc az1+z2tc,因此可以执行 z 2 ′ ← C o m p r e s s ( a z 1 − t c , z 2 , p , r − v ) z_2' \leftarrow Compress(az_1-tc,z_2,p,r-v) z2Compress(az1tc,z2,p,rv),其中 R r \mathcal R_r Rr 是掩码 y y y 的范围, R v \mathcal R_v Rv s 1 c , s 2 c s_1c,s_2c s1c,s2c 的范围,那么根据 [Lyu09] 的均匀版本,当 z > r − v z > r-v z>rv 时需要拒绝样本,因此通过了的签名值大小至多为 r − v r-v rv。根据 z 2 ′ z_2' z2,容易计算出 ( a z 1 + z 2 ′ − t c ) ( 1 ) = ( a y 1 + y 2 ) ( 1 ) (az_1+z_2'-tc)^{(1)} = (ay_1+y_2)^{(1)} (az1+z2tc)(1)=(ay1+y2)(1),因此我们使用高阶比特来进行 RO 查询

  1. K e y G e n ( 1 λ ) KeyGen(1^\lambda) KeyGen(1λ):随机采样 s 1 , s 2 ← U R 1 s_1,s_2 \leftarrow_{\mathcal U} \mathcal R_1 s1,s2UR1(三元向量),随机采样 a ← U R a \leftarrow_{\mathcal U} \mathcal R aUR,计算 t ← a s 1 + s 2 ∈ R t \leftarrow as_1+s_2 \in \mathcal R tas1+s2R,公开参数为 a a a 私钥为 ( s 1 , s 2 ) (s_1,s_2) (s1,s2) 公钥为 t t t
  2. S i g n ( μ , a , ( s 1 , s 2 ) , t ) Sign(\mu,a,(s_1,s_2),t) Sign(μ,a,(s1,s2),t):均匀采样 y 1 , y 2 ← U R r y_1,y_2 \leftarrow_\mathcal U \mathcal R_r y1,y2URr,计算 c ← H ( ( a y 1 , y 2 ) ( 1 ) , μ ) c \leftarrow H((ay_1,y_2)^{(1)},\mu) cH((ay1,y2)(1),μ)(挑战重量为 κ \kappa κ),计算 z 1 ← y 1 + s 1 c z_1 \leftarrow y_1+s_1c z1y1+s1c 以及 z 2 ← y 2 + s 2 c z_2 \leftarrow y_2+s_2c z2y2+s2c,如果 z 1 , z 2 ∉ R r − κ z_1,z_2 \notin \mathcal R_{r-\kappa} z1,z2/Rrκ 那么重新执行( s 1 c , s 2 c s_1c,s_2c s1c,s2c 的系数规模为 κ \kappa κ)。然后执行 z 2 ′ ← C o m p r e s s ( a z 1 − t c , z 2 , p , r − κ ) z_2' \leftarrow Compress(az_1-tc,z_2,p,r-\kappa) z2Compress(az1tc,z2,p,rκ),如果返回值为 ⊥ \perp 则重新执行。最终输出签名值 ( c , z 1 , z 2 ′ ) (c,z_1,z_2') (c,z1,z2)
  3. V e r i f y ( μ , ( c , z 1 , z 2 ′ ) , a , t ) Verify(\mu,(c,z_1,z_2'),a,t) Verify(μ,(c,z1,z2),a,t):首先检查 z 1 , z 2 ∈ R r − κ z_1,z_2 \in \mathcal R_{r-\kappa} z1,z2Rrκ 是否满足,然后计算 H ( ( a z 1 + z 2 ′ − t c ) ( 1 ) , μ ) H((az_1+z_2'-tc)^{(1)},\mu) H((az1+z2tc)(1),μ) 判断是否等于 c c c

丢弃噪声的证明

基于 LWE 的格签名,它的 z 1 z_1 z1 视为是关于秘密 S S S 的 PoK,而 z 2 z_2 z2 视为是关于噪声 E E E 的 PoK。[BG14] 观察到:因为噪声是短的,对于噪声的 PoK 可以隐含在对于秘密的 PoK 内,从而可以消除 z 2 z_2 z2 部分。

基于标准 LWE 的格签名的公钥为 ( A , T : = A S + E ) (A,T:=AS+E) (A,T:=AS+E),其中 S , E S,E S,E 的范数很小。令 z = y + S c z=y+Sc z=y+Sc(不取模)是对秘密的 PoK,挑战 c c c 是根据 v : = A y ( m o d q ) v:=Ay \pmod q v:=Ay(modq) 生成的。假设 E E E 是短的,那么 w : = A z − T c ≡ A y − E c w:=Az-Tc \equiv Ay-Ec w:=AzTcAyEc(取模)是 v v v 的近似,两者的高阶比特极大概率是相等的。[BG14] 使用 v v v w w w 的高阶比特来计算挑战 c c c,如果双方计算出的 c c c 相同,则隐含了 “ E E E 是短的” 这个 PoK

给定 d ∈ N d \in \mathbb N dN,对于 a ∈ Z a \in \mathbb Z aZ,定义低阶比特 [ a ] d : = a ( m o d 2 d ) [a]_d := a \pmod{2^d} [a]d:=a(mod2d),取值范围 ( − 2 d − 1 , 2 d − 1 ] (-2^{d-1},2^{d-1}] (2d1,2d1],定义高阶比特 ⌊ a ⌉ d : = ( a − [ a ] d ) / 2 d \lfloor a \rceil_d := (a-[a]_d)/2^d ad:=(a[a]d)/2d,可推广到向量和多项式上。定义分布 D S = D E D_S=D_E DS=DE 是相同标准差 σ S = σ E \sigma_S=\sigma_E σS=σE 的离散高斯分布,定义分布 D y D_y Dy D z D_z Dz 是不同宽度 B , B − U B,B-U B,BU的均匀分布。

  1. K e y G e n ( 1 λ ) KeyGen(1^\lambda) KeyGen(1λ):均匀采样 A ← U Z q m × n A \leftarrow_\mathcal U \mathbb Z_q^{m \times n} AUZqm×n,采样 S ← D S n × k S \leftarrow D_S^{n \times k} SDSn×k 以及 E ← D E m × k E \leftarrow D_E^{m \times k} EDEm×k,如果 ∃ i , j , ∣ E i j ∣ > τ σ E \exists i,j,|E_{ij}|>\tau\sigma_E i,j,Eij>τσE,那么重新采样。计算 T ≡ A S + E T \equiv AS+E TAS+E,公开参数为 A A A 私钥为 S S S 公钥为 T T T
  2. S i g n ( μ , A , S , T ) Sign(\mu,A,S,T) Sign(μ,A,S,T):采样 y ← D y n y \leftarrow D_y^n yDyn,计算 v ≡ A y ( m o d q ) v \equiv Ay \pmod q vAy(modq),计算 ρ = H ( ⌊ v ⌉ d , μ ) \rho=H(\lfloor v \rceil_d,\mu) ρ=H(⌊vd,μ) 并生成挑战 c = X O F ( ρ ) ∈ { − 1 , 0 , 1 } k c=XOF(\rho)\in \{-1,0,1\}^k c=XOF(ρ){1,0,1}k,计算 z = y + S c z=y+Sc z=y+Sc,计算 w ≡ A z − T c w \equiv Az-Tc wAzTc,如果 ∃ i , ∣ [ w i ] d ∣ > 2 d − 1 − τ σ E κ \exists i,|[w_i]_d| > 2^{d-1}-\tau\sigma_E\kappa i,[wi]d>2d1τσEκ 则重新执行(确保 w + E c w+Ec w+Ec 的低阶比特不发生进位),最后依照概率 min ⁡ ( D z n ( z ) M D y , S c n ( z ) , 1 ) \min\left(\dfrac{D_z^n(z)}{MD_{y,Sc}^n(z)},1\right) min(MDy,Scn(z)Dzn(z),1) 对签名值 ( ρ , z ) (\rho,z) (ρ,z) 拒绝采样。
  3. V e r i f y ( μ , ( c , z ) , A , T ) Verify(\mu,(c,z),A,T) Verify(μ,(c,z),A,T):生成挑战 c = X O F ( ρ ) c=XOF(\rho) c=XOF(ρ),计算 w ≡ A z − T c w \equiv Az-Tc wAzTc,重新生成计算 ρ ′ = H ( ⌊ w ⌉ d , μ ) \rho'=H(\lfloor w \rceil_d,\mu) ρ=H(⌊wd,μ),如果 ρ = ρ ′ \rho=\rho' ρ=ρ 并且 ∥ z ∥ ∈ D z \|z\| \in D_z zDz 那么接受此签名,否则拒绝。

假设 w ∈ Z q m w \in \mathbb Z_q^m wZqm 是均匀的,那么 S i g n Sign Sign 中的条件 ∃ i , ∣ [ w i ] d ∣ > 2 d − 1 − τ σ E κ \exists i,|[w_i]_d| > 2^{d-1}-\tau\sigma_E\kappa i,[wi]d>2d1τσEκ 发生的概率为 ( 1 − τ σ E κ / 2 d − 1 ) m \left(1-\tau\sigma_E\kappa/2^{d-1}\right)^m (1τσEκ/2d1)m,为了降低 A y ≈ w + E c Ay \approx w+Ec Ayw+Ec 发生低阶比特进位的概率,选取 d d d 满足 2 d ≥ τ σ E κ m 2^d \ge \tau\sigma_E\kappa m 2dτσEκm。根据 [Lyu12] 的高斯尾部不等式,[BG14] 选取足够大的 τ \tau τ 使得 E i j ≥ τ σ E E_{ij} \ge \tau \sigma_E EijτσE 的概率可忽略([BG14] 设置 τ = 7 , P r = 2 − 34 \tau=7,Pr=2^{-34} τ=7,Pr=234),从而 ( E c ) i ≥ τ σ E κ (Ec)_i \ge \tau\sigma_E\kappa (Ec)iτσEκ 的概率可忽略。然而 E c Ec Ec 服从标准差 κ σ E \sqrt\kappa\sigma_E κ σE 的离散高斯分布,似乎选取边界 τ σ E κ m \tau\sigma_E\sqrt\kappa m τσEκ m 更合理些,设置 τ = 10 , P r = 2 − 100 \tau=10,Pr=2^{-100} τ=10,Pr=2100 或者 τ = 14 , P r = 2 − 140 \tau=14,Pr=2^{-140} τ=14,Pr=2140

签名值 ( ρ ∈ { 0 , 1 } λ , z ∈ D z n ) (\rho \in \{0,1\}^\lambda, z \in D_z^n) (ρ{0,1}λ,zDzn) 的大小,依赖于 n , D S , D y , κ n,D_S,D_y,\kappa n,DS,Dy,κ,并不依赖 m , k , d m,k,d m,k,d。因此可以选取 d d d 使得 q q q 仅略大于 2 d 2^d 2d 若干比特,只要保证 ⌊ v ⌉ d = ⌊ w ⌉ d \lfloor v \rceil_d=\lfloor w \rceil_d vd=wd 仍有足够高的熵即可。

压缩公钥

采用标准技术,仅发送 PRG 种子来取代发送整个矩阵 A A A,这可以大幅降低公钥载荷大小。此时,公钥中主要部分是矩阵 T T T,[Dilithium] 采用了激进的公钥压缩策略,将矩阵 T T T 分为高阶比特 T 1 T_1 T1 和低阶比特 T 0 T_0 T0,然后将 T 1 T_1 T1 作为公钥。然而,这导致的一个问题是,由于验签者缺少了 T 0 T_0 T0 会导致存在误差,但是这个误差可能会导致进位,于是 w w w v v v 的高阶比特不相同,验签无法通过。

定义 a , b ∈ Z q a,b \in \mathbb Z_q a,bZq 的距离为 min ⁡ ( ∣ a − b ∣ , ∣ ∣ ) \min(|a-b|,||) min(ab,∣∣)。整数 r ∈ Z q r \in \mathbb Z_q rZq 分解为 r = r 1 2 d + r 0 r=r_12^d+r_0 r=r12d+r0,那么对于 r 1 ′ ≠ r 1 r_1' \neq r_1 r1=r1 的两个数 r 1 ′ 2 d ≠ r 1 2 d r_1'2^d \neq r_12^d r12d=r12d,它们的距离至少为 2 d 2^d 2d,但是对于边界的两个数 0 0 0 ⌊ q / 2 d ⌋ ⋅ 2 d \lfloor q/2^d \rfloor \cdot 2^d q/2d2d,它们的距离可能会非常小,[GLP12] 的解决办法是对于边界点不执行压缩。而 [Dilithium] 采用了另外一种分解方案:选择 α \alpha α 满足 α ∣ q − 1 \alpha|q-1 αq1,做分解 r = r 1 α + r 0 r=r_1 \alpha+r_0 r=r1α+r0,那么 r 1 α r_1\alpha r1α 的取值范围是 { 0 , α , 2 α , ⋯   , q − 1 } \{0,\alpha,2\alpha,\cdots,q-1\} {0,α,2α,,q1},边界点之间的距离为 1 1 1,只要我们丢弃 q − 1 q-1 q1(把它舍入到 0 0 0),那么这个集合中所有点的距离就都会大于等于 α \alpha α 了。对于任意的 z ∈ [ − α / 2 , α / 2 ) z \in [-\alpha/2,\alpha/2) z[α/2,α/2),加和 r + z r+z r+z 至多导致 r r r高阶比特加减一(取模 m = ( q − 1 ) α m=(q-1)\alpha m=(q1)α 的意义下),不会出现 [GLP12] 遇到边界情况高阶比特剧烈变化的情况。

[Dilithium] 定义了如下的分解函数以及提示信息

  • D e c o m p o s e q ( r , α ) Decompose_q(r,\alpha) Decomposeq(r,α):计算 r ∈ [ 0 , q ) r \in [0,q) r[0,q),再计算 r 0 : = r ( m o d α ) r_0:=r \pmod \alpha r0:=r(modα) 属于 [ − α / 2 , α / 2 ) [-\alpha/2,\alpha/2) [α/2,α/2),如果 r − r 0 = q − 1 r-r_0=q-1 rr0=q1 那么设置 r 1 : = 0 , r 0 : = r 0 − 1 r_1:=0,r_0:=r_0-1 r1:=0,r0:=r01(将 q − 1 q-1 q1 舍入到 0 0 0),否则设置 r 1 : = ( r − r 0 ) / α r_1:=(r-r_0)/\alpha r1:=(rr0)/α,最终输出 ( r 1 , r 0 ) (r_1,r_0) (r1,r0),其中 r 1 r_1 r1 记为 H i g h B i t s q ( r , α ) HighBits_q(r,\alpha) HighBitsq(r,α) r 0 r_0 r0 记为 L o w B i t s q ( r , α ) LowBits_q(r,\alpha) LowBitsq(r,α)
  • M a k e H i n t q ( z , r , α ) MakeHint_q(z,r,\alpha) MakeHintq(z,r,α):计算 r 1 : = H i g h B i t s q ( r , α ) r_1:=HighBits_q(r,\alpha) r1:=HighBitsq(r,α) v 1 : = H i g h B i t s q ( r + z , α ) v_1 := HighBits_q(r+z,\alpha) v1:=HighBitsq(r+z,α),当 r 1 ≠ v 1 r_1 \neq v_1 r1=v1 时输出 1 1 1,否则输出 0 0 0,这判断了 r + z r+z r+z 是否出现低阶比特进位/借位
  • U s e H i n t q ( h , r , α ) UseHint_q(h,r,\alpha) UseHintq(h,r,α):计算 m : = ( q − 1 ) / α m:=(q-1)/\alpha m:=(q1)/α,计算 ( r 1 , r 0 ) : = D e c o m p o s e q ( r , α ) (r_1,r_0):=Decompose_q(r,\alpha) (r1,r0):=Decomposeq(r,α),当 h = 1 h=1 h=1 并且 r 0 > 0 r_0>0 r0>0 时输出 r 1 + 1 ( m o d m ) r_1+1 \pmod m r1+1(modm),当 h = 1 h=1 h=1 并且 r 0 ≤ 0 r_0\le0 r00 时输出 r 1 − 1 ( m o d m ) r_1-1 \pmod m r11(modm),当 h = 0 h=0 h=0 时直接输出 r 1 r_1 r1,这利用提示信息 h h h 计算 r + z r+z r+z 的高阶比特,容易验证 U s e H i n t ( M a k e H i n t ( z , r ) , r ) = H i g h B i t s ( r + z ) UseHint(MakeHint(z,r),r) = HighBits(r+z) UseHint(MakeHint(z,r),r)=HighBits(r+z)

[Dilithium] 基于 MLWE 问题,公开参数为 A ∈ R q k × l A \in \mathcal R_q^{k \times l} ARqk×l,私钥是一对短向量 ( s 1 ∈ R q l , s 2 ∈ R q k ) (s_1 \in \mathcal R_q^l, s_2 \in \mathcal R_q^k) (s1Rql,s2Rqk),计算 t = A s 1 + s 2 ∈ R q k t=As_1+s_2 \in \mathcal R_q^k t=As1+s2Rqk,对它执行 [GLP12] 的那种压缩方案 t = t 1 2 d + t 0 t=t_12^d+t_0 t=t12d+t0,然后将高阶比特 t 1 t_1 t1 作为公钥。签名算法采用 [BG14] 的方案,承诺值是高阶比特 ( A y ) ( 1 ) (Ay)^{(1)} (Ay)(1),用它去询问 RO 生成挑战 c ∈ R q c \in \mathcal R_q cRq,签名值为 z = y + c s 1 ∈ R q l z=y+cs_1 \in \mathcal R_q^l z=y+cs1Rql。验证者持有 t 1 t_1 t1,因为 t − t 1 2 d = t 0 ≤ 2 d − 1 t-t_12^d=t_0 \le 2^{d-1} tt12d=t02d1,所以可以计算 A z − t c Az-tc Aztc 的近似值
A z − c ⋅ t 1 2 d ≡ A ( y + c s 1 ) − c ( t − t 0 ) ≡ A y − c s 2 + c t 0 ≡ ( A z − t c ) + c t 0 \begin{aligned} Az-c\cdot t_12^d &\equiv A(y+cs_1) - c(t-t_0)\\ &\equiv Ay-cs_2+ct_0\\ &\equiv (Az-tc) + ct_0 \end{aligned} Azct12dA(y+cs1)c(tt0)Aycs2+ct0(Aztc)+ct0
两者之间的差值为 − c t 0 -ct_0 ct0,这可能会导致低阶比特进位改变高阶比特。我们使用 M a k e H i n t q ( − c t 0 , A z − c ⋅ t 1 2 d , α ) MakeHint_q(-ct_0,Az-c\cdot t_12^d,\alpha) MakeHintq(ct0,Azct12d,α) 产生提示信息 h ∈ { 0 , 1 } k n h \in \{0,1\}^{kn} h{0,1}kn,然后再使用 U s e H i n t ( h , A z − c ⋅ t 1 2 d , α ) UseHint(h,Az-c \cdot t_12^d,\alpha) UseHint(h,Azct12d,α) 正确计算出 A z − t c Az-tc Aztc 的高阶比特。[Dilithium] 启发式地约束 h h h 的重量为 w w w,如果超重了则重新执行,这使得传输 h h h 只需发送位置信息即可,规模仅为 w log ⁡ ( k n ) w \log(kn) wlog(kn) 比特。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值