Garbled Circuits介绍 - 5&6 Yao协议的实现 & 总结

前面几章我们介绍了混淆电路的基本概念、基础知识、Yao的混淆电路协议(也就是通用的混淆电路框架)以及混淆电路的优化,接下来我们来聊一聊混Yao协议的实现。文章可能会有一些小错误,另外文章所有图例、参考文献、表格需要均接前面的章节。若需要查看前面几章请点击下面的链接:

Garbled Circuits介绍 - 1 引言

Garbled Circuits介绍 - 2 基础知识

Garbled Circuits介绍 - 3 Yao的混淆电路协议

Garbled Circuits介绍 - 4 混淆电路的优化

5 Yao协议的实现

到目前为止,已经开发了各种基于Yao协议的实现。他们中的许多人利用Yao的协议来实现MPC应用,有些是隐私函数的计算(Private Function Evaluation,PFE)。在这一章节,我们将介绍一些使用Yao协议的通用MPC解决方案。

5.1 Pipelined实现 (FastGC)

存储整个混淆电路所需的内存通常是一个限制。Huang等人在他们的[18]框架中提出了流水线优化来减少所需的内存。混淆电路的产生和计算过程可以同时进行,无需将整个混淆电路保存在内存中,也无需在将整个混淆电路传输给 e v a l u a t o r evaluator evaluator之前进行准备,因此减少了整个Yao协议的运行时间。FastGC框架自动化了流水线实现(Pipelined Implementation),因此剩下的工作就是构建所需的电路[18]。

在计算开始时,电路结构由 g a r b l e r garbler garbler e v a l u a t o r evaluator evaluator实例化。在执行协议的过程中, g a r b l e r garbler garbler按拓扑结构的顺序对每个门进行混淆,一旦混淆完成就通过网络传输。当混淆后的门被 e v a l u a t o r evaluator evaluator接收时,它与相应的电路门相关联并被计算。一旦求值完成了,门就会被消除,这样内存的使用就会最小化。这个技术叫做流水线实现(pipelined implementation)。该实现减少了总的Yao协议运行时间,而代价是双方需要同时在线。

5.2 Garbled RAM

混淆随机存储器(Garbled RAM)的概念是由Lu和Ostrovsky在[48]中提出的。后来Gentry等人利用基于身份的加密方案[49](IBE)改进了它,并且在[50]中证明了它的安全性。它不同于Yao的混淆电路,因为它允许直接混淆RAM程序,而不需要把它转换成布尔电路。一个运行时间为 T T T的RAM程序可以转换为一个运行时间为 O ( T 3 ) O(T^3) O(T3)的图灵机,产生一个大小为 O ( T 3 l o g T ) O(T^3logT) O(T3logT)的布尔电路,而被混淆的RAM程序的大小和计算时间只与它在RAM上的运行时间成正比[50]。在这种情况下,高效的程序(如二进制搜索)在数据大小的次线性时间内运行,而它们的布尔电路则在数据大小的线性时间内运行。

像混淆电路一样,Garbled RAM包括一个混淆程序的 g a r b l e r garbler garbler,并把混淆程序发送给 e v a l u a t o r evaluator evaluator e v a l u a t o r evaluator evaluator用混淆后的输入来计算混淆程序,与Yao协议不同,输出的是RAM程序的实际输出。像混淆电路一样,Garbled RAM的目标是抗半诚实敌手。Gentry等人的Garbled RAM方案在[50]中被详细描述。

符号 P D ( x ) P^D(x) PD(x)表示一个RAM程序 P P P,访问包含数据的内存 D D D,并且输入 x x x。假设 D D D是一个被 e v a l u a t o r evaluator evaluator控制的巨大数据库, P P P作为对数据库具有读写访问权的数据库查询人员,并且其参数为 x x x值(就像在 D D D中, P P P搜索 x x x),这将有助于理解这些概念。

RAM程序 P P P可以表示为执行单个CPU步骤的CPU步进电路的集合。下面的等式CPU执行 j j j步骤的情况。 C C P U P C_{CPU}^P CCPUP的输入是当前CPU状态 s t a t e j state_{j} statej和一个它驻留在前一个循环中分配的内存位置 b j r e a d b_j^{read} bjread。他输出一个更新的状态 s t a t e j + 1 state_{j+1} statej+1,和接下来的读位置 i ( j + 1 ) r e a d i(j+1)^{read} i(j+1)read,一个写位置 i j + 1 r e a d i_{j+1}^{read} ij+1read(也可能是 ⊥ \bot ),一个比特 b j + 1 r e a d b_{j+1}^{read} bj+1read写入该位置。
C C P U P ( s t a t e j , b j r e a d , i j w r i t e , b j w r i t e ) = ( s t a t e j + 1 , b j + 1 r e a d , i j + 1 w r i t e , b j + 1 w r i t e ) C_{CPU}^P(state_j,b_j^{read},i_j^{write},b_j^{write})=(state_{j+1},b_{j+1}^{read},i_{j+1}^{write},b_{j+1}^{write}) CCPUP(statej,bjread,ijwrite,bjwrite)=(statej+1,bj+1read,ij+1write,bj+1write)

P D ( x ) P^D(x) PD(x)计算的开始,初始化状态 s t a t e 1 = x state_1=x state1=x b 0 r e a d = 0 b_0^{read}=0 b0read=0,接下来一步一步按照步骤执行。在步骤 j j j中,第一个 b j r e a d b_j^{read} bjread设置为 D [ i j r e a d ] D[i_j^{read}] D[ijread],并且如果 i j w r i t e ≠ ⊥ i_j^{write} \ne \bot ijwrite= D [ i j w r i t e ] D[i_j^{write}] D[ijwrite]被设置为 b j w r i t e b_j^{write} bjwrite。最后一个CPU步骤的输出是计算状态 y = P D ( x ) y=P^D(x) y=PD(x)的输出。如果 P P P不重写内存 D D D的任何值(即, i j w r i t e i_j^{write} ijwrite总为 ⊥ \bot ),则 P P P拥有只读权限。

Gentry等人提出了针对无保护内存访问(unprotected memory access,UMA)的安全方案,其中,内存的初始内容和 M e m A c c e s s MemAccess MemAccess的完整内存访问模式(包括内容)可以被入侵者学习[50]。他们还提出,对内存内容进行加密并应用不经意RAM就足以将任何带有UMA安全性的混淆RAM方案转换成提供完全安全性的方案。

5.2.1 Read-Only解决方案

内存的混淆由 D ˉ [ i ] \bar{D}[i] Dˉ[i]完成,每个 D ˉ [ i ] \bar{D}[i] Dˉ[i]对于公钥 ( i , b ) (i,b) (i,b)有一个IBE密钥 s k ( i , b ) sk_{(i,b)} sk(i,b),其中, i i i是索引, b b b D [ i ] D[i] D[i]的数据位数。 D ˉ [ i ] \bar{D}[i] Dˉ[i]的另一个功能是能够保留并被未来的程序使用。CPU的步骤 j j j的混淆输入 x ˉ j \bar{x}_j xˉj s t a t e j state_j statej的掩盖值, x ˉ 0 \bar{x}_0 xˉ0是输入 x ˉ \bar{x} xˉ的掩盖值。则上面的等式可以简化为 C C P U P ( s t a t e j , b j r e a d ) = ( s t a t e j + 1 , b j + 1 r e a d ) C_{CPU}^P(state_j,b_j^{read})=(state_{j+1},b_{j+1}^{read}) CCPUP(statej,bjread)=(statej+1,bj+1read)

( x ˉ j + 1 , i j + 1 r e a d , t r a n s l a t e j + 1 ) ← C ˉ C P U , j P ( x ˉ j , b ˉ j + 1 r e a d ) (\bar{x}_{j+1},i_{j+1}^{read},translate_{j+1})\leftarrow \bar{C}_{CPU,j}^P(\bar{x}_j,\bar{b}_{j+1}^{read}) (xˉj+1,ij+1read,translatej+1)CˉCPU,jP(xˉj,bˉj+1read)显示了混淆电路 C ˉ C P U , j P \bar{C}_{CPU,j}^P CˉCPU,jP的第 j j j步。在混淆CPU第 j j j步的问题是位置 b j r e a d b_j^{read} bjread是前一个周期的输出,所以它是未知的。令 b ˉ 0 j r e a d \bar{b}_{0j}^{read} bˉ0jread表示 b j r e a d b_{j}^{read} bjread F A L S E FALSE FALSE掩盖值, b ˉ 1 j r e a d \bar{b}_{1j}^{read} bˉ1jread表示 b j r e a d b_{j}^{read} bjread T R U E TRUE TRUE掩盖值。每个混淆步骤j输出一个转换映射, t r a n s l a t e j + 1 = ( c t 0 ( j + 1 ) , c t 1 ( j + 1 ) ) translate_{j+1}=(ct_{0(j+1)},ct_{1(j+1)}) translatej+1=(ct0(j+1),ct1(j+1)),其中 c t b ( j + 1 ) = E ( ( i j + 1 r e a d , b ) , r b j , b ˉ j + 1 r e a d ) ct_{b(j+1)}=E((i_{j+1}^{read},b),r_{bj},\bar{b}_{j+1}^{read}) ctb(j+1)=E((ij+1read,b),rbj,bˉj+1read),并由IBE计算,这样 e v a l u a t o r evaluator evaluator就能在步进电路 j j j中硬编码密钥 D ˉ [ i j + 1 r e a d ] \bar{D}[i_{j+1}^{read}] Dˉ[ij+1read] b ˉ 0 ( j + 1 ) r e a d \bar{b}_{0(j+1)}^{read} bˉ0(j+1)read r 0 j r_{0j} r0j r 1 j r_{1j} r1j知道 D [ i j + 1 r e a d ] D[i_{j+1}^{read}] D[ij+1read]的掩盖值而因为混淆过程不能直接知道。 i j + 1 r e a d i_{j+1}^{read} ij+1read不是保密的,因为目标是UMA安全,所以不需要掩盖。

每个混淆阶段 j j j从解密 c t b j ct_{bj} ctbj开始( e v a l u a t o r evaluator evaluator因为UMA安全可能知道解密哪个),得到 b ˉ b j r e a d \bar{b}_{bj}^{read} bˉbjread(除了第一个阶段,因为 b ˉ b j r e a d = ⊥ \bar{b}_{bj}^{read} = \bot bˉbjread=)。最后一轮直接输出 y = P D ( x ) y=P^D(x) y=PD(x)

5.2.2 写入内存

与Read-Only阶段类似,内存的混淆由 D ˉ [ i ] \bar{D}[i] Dˉ[i]完成,每个 D ˉ [ i ] \bar{D}[i] Dˉ[i]完对于公钥 ( u , i , b ) (u,i,b) (u,i,b)有一个时限IBE密钥 s k ( u , i , b ) sk_{(u,i,b)} sk(u,i,b),其中 u u u i i i上次一次写入的阶段。等式 C C P U P ( s t a t e j , b j r e a d , i j w r i t e , b j w r i t e ) = ( s t a t e j + 1 , b j + 1 r e a d , i j + 1 w r i t e , b j + 1 w r i t e ) C_{CPU}^P(state_j,b_j^{read},i_j^{write},b_j^{write})=(state_{j+1},b_{j+1}^{read},i_{j+1}^{write},b_{j+1}^{write}) CCPUP(statej,bjread,ijwrite,bjwrite)=(statej+1,bj+1read,ij+1write,bj+1write)在写的全阶段都要被计算。等式 ( x ˉ j + 1 , i j + 1 r e a d , t r a n s l a t e j + 1 , i j + 1 w r i t e , s k ( j + 1 , i , b ) ) ← (\bar{x}_{j+1},i_{j+1}^{read},translate_{j+1},i_{j+1}^{write},sk_{(j+1,i,b)})\leftarrow (xˉj+1,ij+1read,translatej+1,ij+1write,sk(j+1,i,b)) C ˉ C P U , j P ( x ˉ j , b ˉ j + 1 r e a d , i j w r i t e , s k ( j , i , b ) ) \bar{C}_{CPU,j}^P(\bar{x}_j,\bar{b}_{j+1}^{read},i_{j}^{write},sk_{(j,i,b)}) CˉCPU,jP(xˉj,bˉj+1read,ijwrite,sk(j,i,b))显示了混淆电路 C ˉ C P U , j P \bar{C}_{CPU,j}^P CˉCPU,jP表明了混淆电路的第 j j j步。与Read-Only阶段不同,阶段 j j j s k ( j , i , b ) sk_{(j,i,b)} sk(j,i,b)到内存地址 i j w r i t e i_{j}^{write} ijwrite(如果 i j w r i t e i_{j}^{write} ijwrite不为 ⊥ \bot ),输出 s k ( j + 1 , i , b ) sk_{(j+1,i,b)} sk(j+1,i,b)和下一阶段的输入地址 i j + 1 w r i t e i_{j+1}^{write} ij+1write。每个混淆阶段 j j j输出一个转换映射, t r a n s l a t e j + 1 = ( c t 0 ( j + 1 ) , c t 1 ( j + 1 ) ) translate_{j+1}=(ct_{0(j+1)},ct_{1(j+1)}) translatej+1=(ct0(j+1),ct1(j+1)),其中 c t b ( j + 1 ) = E ( ( u j + 1 , i j + 1 r e a d , b ) , r b j , b ˉ j + 1 r e a d ) ct_{b(j+1)}=E((u_{j+1},i_{j+1}^{read},b),r_{bj},\bar{b}_{j+1}^{read}) ctb(j+1)=E((uj+1,ij+1read,b),rbj,bˉj+1read),由时限IBE计算。在这里,假设存在一个多项式大小的电路 W r i t e T i m e WriteTime WriteTime u j + 1 = W r i t e T i m e ( j , x ˉ j , i j r e a d ) u_{j+1}=WriteTime(j,\bar{x}_j,i_j^{read}) uj+1=WriteTime(j,xˉj,ijread),并且阶段 j j j能调用它。与Read-Only阶段类似, e v a l u a t o r evaluator evaluator就能在步进电路 j j j中硬编码密钥 D ˉ [ i j + 1 r e a d ] \bar{D}[i_{j+1}^{read}] Dˉ[ij+1read] b ˉ 0 ( j + 1 ) r e a d \bar{b}_{0(j+1)^{read}} bˉ0(j+1)read b ˉ 1 ( j + 1 ) r e a d \bar{b}_{1(j+1)^{read}} bˉ1(j+1)read r 0 j r_{0j} r0j r 1 j r_{1j} r1j知道 D [ i j + 1 r e a d ] D[i_{j+1}^{read}] D[ij+1read]的掩盖值而因为混淆过程不能直接知道。 i j + 1 r e a d i_{j+1}^{read} ij+1read不是保密的,因为目标是UMA安全,所以不需要掩盖。 i j + 1 r e a d i_{j+1}^{read} ij+1read i j + 1 w r i t e i_{j+1}^{write} ij+1write因为UMA安全性是不保密的。

5.2.3 完全安全性

Gentry等人提出,任何只提供UMA的安全性和只支持程序执行与 W r i t e T i m e WriteTime WriteTime调用的混淆RAM方案都可以转换为一个完全安全的任意程序的混淆RAM方案[50]。该转换使用不经意的RAM(oblivious RAM,ORAM)(ORAM由Goldreich和Ostrovsky等人在[51]提出,允许用户隐藏其对远程存储器的访问模式。虽然敌手可以观察到所访问的物理存储位置,但是ORAM确保关于实际访问模式的任何信息都不会被获知[52]。)首先编译初始程序 P P P为一个新的程序 P ∗ P^* P P ∗ P^* P使用ORAM存储/访问它的内存。这确保了编译后的程序的内存内容和访问模式不会泄露任何关于原始程序的信息。一些ORAM方案已经确保编译后的程序提供 W r i t e T i m e WriteTime WriteTime调用。

5.3 JustGarble

在[53]中,Bellare等人提出了JustGarble框架,它的目标是优化任何电路的混淆。它完全是开源的,可以在http://cseweb.ucsd.edu/groups/justgarble免费下载。它使用128位的AES实现了P&P技术,不带GRR3技术的免费异或门技术,带GRR3的免费异或门技术。它使用同样的方式:混淆一个布尔电路,然后计算一个混淆电路。

JustGarble使用一个叫简单电路描述(Simple Circuit Description,SCD)的电路表示。一个SCD文件由值 n , m , q n,m,q n,m,q,和数组 A , B , G A,B,G A,B,G组成。如果 G G G不存在,文件就是一个拓扑电路表示。在JustGarble中,有构建电路的模块,混淆布尔电路的模块和计算混淆电路的模块。构建模块用于构建电路,允许电路在单个门或更高级别的门工作。SCD文件在构建电路时写成。利用 G a r b l e Garble Garble模块实现三种混淆方案给出的算法 G B G_B GB G a r b l e Garble Garble利用一个在SCD中描述为电路 f = ( n , m , q , A , B , G ) f=(n,m,q,A,B,G) f=(n,m,q,A,B,G)作为输入,并且输出混淆之后的表格P,该表格由相关电路 F = ( n , m , q , A , B , G , P ) F=(n,m,q,A,B,G,P) F=(n,m,q,A,B,G,P)组成。计算模块的输入是一个拓扑电路 f ˉ = ( n , m , q , A , B ) \bar{f}=(n,m,q,A,B) fˉ=(n,m,q,A,B),混淆表格 P P P需要被计算,混淆输入为 X X X。产生混淆的输出 Y Y Y。JustGarble还包含实现 D e D_e De的过程,将混淆的输出 Y Y Y映射到普通输出 y y y[53]。

JustGarble为36.5K个门优化的AES布尔电路实现了带GRR3的免费异或门技术,该布尔电路含有82%的 X O R XOR XOR门,导致每个门的大小为5.40字节(bytes per gate,bpg),计算时间为35.0个循环(cycles per gate,cpg),混淆时间为63.3cpg。不带GRR3的免费异或门技术利用同样的电路实现,然而,它的计算时间为23.2cpg,混淆时间为55.6 cpg,和11.5 bpg的大小。(在3.201 GHz处理器下,混淆电路为7.25 nsec/gate, g a r b l i n g garbling garbling为17.4 nsec/gate。)

5.4 ABY

ABY是一个2方计算框架(2PC),由Demmler等人在[37]中提出。大多数时候,MPC原语的混合(如GMW协议、YAO、HE等)与只使用其中一个实现相比,可能会产生更高效的实现。基于这个思想,ABY使用了算术共享、布尔共享和Yao共享。该框架的目标是实现半诚实模型中的安全性。ABY就像一台虚拟机,高级语言可以编译到它。变量可以是明文(即一方知道其价值,如输入和输出)或双方共享的秘密。ABY还允许在不同类型的共享之间进行有效的转换。框架的用户可以根据应用程序决定使用哪些共享。ABY代码可以在GitHub上找到:http://encrypto.de/code/ABY

5.5 Obliv-C

Obliv-C是由Zahur和Evans构建的C编程语言的扩展,具有安全的计算基础设施[54]。它支持各种C语言特性,如指针、类型定义、结构等,并提供了新的数据类型和结构,使程序运行在私有输入上。它是专门为可伸缩的MPC协议设计的,并通过简化实现来增强对新的MPC技术的研究,这样只需编写一个新的库就足够了,而不必为每种技术构建新的编译器。Obliv-C的源代码可以在https://oblivc.org找到。

5.6 ObliVM

Liu等人在[55]中提出了ObliVM作为MPC的编程框架。它提供了一种领域特定语言(ObliVM-lang),用于将程序编译成MPC协议所需的适当表示形式。它还为MPC基础结构提供了高级编程结构,非专业程序员也可以对其进行安全调整。ObliVM的源代码可以在http://oblivm.com找到。

5.7 Frigate

Frigate是由Mood等人设计的MPC的编译器和电路解释器[56]。它可以实现任何可以写成布尔电路的函数,并运行任何在布尔电路上运行的MPC原语。Frigate允许使用类似c语言的结构和操作符专门设计来有效地表示布尔电路。为了提高效率,编译器被设计成支持 X O R XOR XOR门,利用了Boyar等人的有四个 X O R XOR XOR门和一个 A N D AND AND门全加法器结构[57]。Frigate在编译、解释和执行时间方面也非常快。Frigate的源代码可以在https://bitbucket.org/bmood/frigaterelease找到。

5.8 混淆电路优化方案实现的比较

下面使用一个表格来表示优化技术实现的兼容性,分别用 √ √ × × ×表示兼容和不兼容。

P&PGRR3Free XORGRR2FleXORHalf Gates
JustGarble (2013) √ √ √ √ √ √ × × × × × × × × ×
ABY (2015) √ √ √ √ √ √ × × × × × × × × ×
Obliv-C (2015) √ √ √ √ √ √ √ √ √ √ √ √
ObliVM (2015) √ √ √ √ √ √ × × × × × × × × ×
Frigate (2016) √ √ √ √ √ √ √ √ √ √ √ √

Obliv-C和Frigate使任何混淆电路优化成为可能,因为他们允许混淆方案的改变,尽管这些混淆电路技术不是内置的。另一方面,JustGarble、ABY和ObliVM不允许改变内置的混淆结构,因此,是有限的使用最先进的混淆电路优化技术。所有的框架都允许对编译进行优化,以减少奇数门的数量。我们可以推断Frigate是最佳的工作与混乱的电路,因为它提供了最大的优化选项,而最有效的一个。

6 总结

混淆电路可以应用在多方面,如私有函数加密、零知识证明、具有依赖键的消息安全性的加密、随机编码、安全外包、一次性的项目、多方安全计算等。本文内容大部分参考[14],少部分参考[58],并参考维基百科,百度百科等关于混淆电路、MPC的介绍和部分自己的理解编写而成。本文可以当作混淆电路的入门参考资料。

参考文献(接上篇)

[48]S. Lu and R. Ostrovsky. How to garble ram programs? In Advances in Cryptology– EUROCRYPT 2013: 32nd Annual International Conference on the Theory and Applications of Cryptographic Techniques, Athens, Greece, May 26-30, 2013. Proceedings, pages 719–734, 2013.

[49]D. Boneh and M. Franklin. Identity-based encryption from the weil pairing. In Proceedings of the 21st Annual International Cryptology Conference on Advances in Cryptology, CRYPTO ’01, pages 213–229, 2001.

[50]C. Gentry, S. Halevi, S. Lu, R. Ostrovsky, M. Raykova, and D. Wichs. Garbled ram revisited. In Advances in Cryptology – EUROCRYPT 2014: 33rd Annual International Conference on the Theory and Applications of Cryptographic Techniques, Copenhagen, Denmark, May 11-15, 2014. Proceedings, pages 405–422, 2014.

[51]O. Goldreich and R. Ostrovsky. Software protection and simulation on oblivious rams. J. ACM, 43(3):431–473, May 1996.

[52]E. Stefanov, M. van Dijk, E. Shi, C. Fletcher, L. Ren, X. Yu, and S. Devadas. Path oram: An extremely simple oblivious ram protocol. In Proceedings of the 2013 ACM SIGSAC Conference on Computer & Communications Security, CCS ’13, pages 299–310, 2013.

[53]M. Bellare, V. Hoang, S. Keelveedhi, and P. Rogaway. Efficient garbling from a fixed-key blockcipher. In Proceedings of the 2013 IEEE Symposium on Security and Privacy, SP ’13, pages 478–492, 2013.

[54]S. Zahur and D. Evans. Obliv-c: A language for extensible data-oblivious computation. IACR Cryptology ePrint Archive, 2015:1153, 2015.

[55]C. Liu, X. Wang, K. Nayak, Y. Huang, and E. Shi. Oblivm: A programming framework for secure computation. In 2015 IEEE Symposium on Security and Privacy, SP 2015, San Jose, CA, USA, May 17-21, 2015, pages 359–376, 2015.

[56]B. Mood, D. Gupta, H. Carter, K. Butler, and P. Traynor. Frigate: A validated, extensible, and efficient compiler and interpreter for secure computation. In IEEE European Symposium on Security and Privacy, EuroS&P 2016, Saarbrücken, Germany, March 21-24, 2016, 2016.

[57]J. Boyar, R. Peralta, and D. Pochuev. On the multiplicative complexity of boolean functions over the basis ( ∧ \land , ⊕ \oplus , 1). Theoretical Computer Science, 235(1):43 – 57, 2000.

[58]S. Yakoubov. A Gentle Introduction to Yao’s Garbled Circuits. Boston Univeristy, 2017.

如果有任何问题可以与我联系。
个人主页:https://www.mrccc.club/

微信公众号搜索:CHEN CONGCONG
CHEN CONGCONG微信公众号

微信小程序搜索:CHEN CONGCONG
CHEN CONGCONG微信小程序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值