【论文阅读】 Privacy-Preserving Byzantine-Robust Federated Learning via Blockchain Systems

这是发表在2022 IEEE TRANSACTIONS ON INFORMATION FORENSICS AND SECURITY(TIFS)上的一篇文章

abstract

传统的联邦学习容易受到恶意客户端和服务器的中毒攻击,在本文中设计一个基于区块链系统的隐私保护拜占庭鲁棒联合学习(PBFL),我们使用余弦相似性来判断恶意客户端上传的恶意梯度。然后,我们采用全同态加密来提供安全的聚合(Finally, we use blockchain system to facilitate transparent processes and implementation of regulations)。最后,我们使用区块链系统来促进透明的流程和法规的实施。

主要贡献

1、我们通过使用完全同态加密(FHE)方案CKKS提供了一种隐私保护训练机制,它不仅大大降低了计算和通信开销,而且防止了攻击者窥探客户端的本地数据
2、我们通过余弦相似性去除恶意梯度,提供了一个可信的全局模型,该模型可以抵抗中毒攻击。
3、我们使用区块链来促进透明的流程和法规的执行。服务器执行链外计算并将结果上传到区块链,这实现了效率和可信度
4、实验比较

II. RELATED WORK

B. Blockchain-Based Federated Learning

传统的联邦学习严重依赖服务器的参与,导致单点故障
区块链去中心化来替换服务器,消除单点故障的威胁和服务器的恶意行为。
拉马南等人。【18】介绍了一个基于区块链的FL解决方案,名为BAFFLE,它使用智能合约(SC)来聚合本地模型。与传统方法相比,挡板避免了单点故障,降低了区块链FL的气体成本。同样,金等人。【37】提议的BlockFL,其中本地模型更新通过预先部署在区块链的智能合约进行交换和验证。BlockFL不仅克服了单点故障问题,还通过提供与训练样本大小成比例的激励,促进了更多设备和更大数量训练样本的集成。然而,上述解决方案通过智能合约聚合本地模型,这给区块链网络中的节点带来了沉重的计算和通信负担。此外,这些解决方案不能区分恶意梯度。为了解决这些问题,李等人。[33]提出了一个基于区块链的委员会共识联合学习框架(BFLC),有效地减少了共识计算量,防止了恶意攻击。然而,委员会的遴选标准是一个需要解决的问题。

III. PRELIMINARIES

A.Federated Learning

在标准的联邦学习设定中, n n n个客户 { C 1 , C 2 , . . . , C n } \{C_1,C_2,...,C_n\} {C1,C2,...,Cn} 每个客户端有一个本地的数据集 D j , j = 1 , 2 , 3 , . . . , n D_j,j=1,2,3,...,n Dj,j=1,2,3,...,n D = { D 1 , D 2 , . . . , D n } D=\{D_1,D_2,...,D_n\} D={D1,D2,...,Dn} 表示联合的数据集,第 i i i轮客户端 C j C_j Cj使用本地的数据集和从中央服务器接受的模型参数 w i − 1 w_{i-1} wi1来训练本地模型,优化的目标函数如等式(1)
在这里插入图片描述
x x x是训练数据, y y y是标签 L ( x , w , y ) L(x,w,y) L(x,w,y)是经验损失函数 ,中心聚合收到的来自客户端的参数如等式(2),其中 ζ i j = ∣ D j ∣ ∣ D ∣ \zeta_i^j=\frac{|D_j|}{|D|} ζij=DDj

B. Poisoning Attacks

众所周知,联合学习容易受到中毒攻击。在中毒攻击中,对手控制 κ κ κ客户端操纵局部模型,最终影响全局模型 w w w的准确性。根据对手的目标,中毒攻击可分为有针对性的攻击和无针对性的攻击。有针对性的攻击,如缩放攻击,只针对数据集中的一个或几个数据类别,同时保持其他类别数据的准确性。非目标攻击,如Krum攻击和Trim攻击,是无差别攻击,其目的是降低所有数据类别的准确性。

为了降低全局模型 w w w的准确性,通常根据对手的能力发起数据中毒攻击和模型中毒攻击。在数据中毒攻击(即标签翻转攻击)中,对手通过毒害设备的本地数据间接毒害全局模型。在模型中毒攻击中,对手可以直接操纵和控制设备与服务器之间通信的模型更新,这直接影响全局模型的准确性。因此,模型中毒攻击通常比数据中毒攻击对FL的影响更大。

Cheon-Kim-Kim-Song (A FHE sheme)

CKKS允许在浮点数和向量上进行加密,有其独特的编码解码和重缩放机制。

在这里插入图片描述
在这里插入图片描述

智能合约

智能合约,是一段写在区块链上的代码,一旦某个事件触发合约中的条款,代码即自动执行。也就是说,满足条件就执行,不需要人为操控,区块链与智能合约十分的契合,因为区块链的很多特点,比如去中心化,数据的不可篡改等,可以从技术的角度,去解决陌生人之间的信任问题。

IV. PROBLEM FORMULATION

系统模型包括五个实体:密钥分发中心,客户端、求解者、验证者、区块链中心系统。
Key Generation Center (KGC):可信的权威中心,为客户端和验证者产生公钥私钥对;
Clients:数据拥有者,客户端拥有KGC提供的 ( p k k , s k k ) (pk_k,sk_k) (pkk,skk),目的是在公共的全局模型中收益。
Solver:拥有一个小而干净的数据集 D 0 D_0 D0的中央服务器,求解器,负责聚合客户端提交的所有梯度。
Verifier:一个非串通的中央服务器,与求解器合作,也拥有一对由 K G C KGC KGC产生的公钥私钥对 ( p k v , s k v ) (pk_v,sk_v) pkv,skv
Blockchain System:为了避免自私行为,中央服务器需要在SC(智能合约)上放置存款以获得潜在的惩罚。此外,结果需要上传到区块链,以实现透明的计算过程
整个系统实体的流程是:
首先,客户端进行归一化,使用 p k v pk_v pkv对本地梯度进行加密,求解器(Solver)和验证器(Verifie)进行多轮通信,以在不泄露隐私的情况下建立用户列表,其中客户端诚实地归一化梯度。通信过程在区块链中进行记录,求解器聚合用户列表中客户端的梯度,得到一个用 p k x pk_x pkx加密的全局模型,保存在区块链中。 求解器,验证器客户端都需要向智能合约支付押金。
在这里插入图片描述

B.问题定义

与传统的安全聚合场景不同,我们考虑了一个联合学习场景,其中包含 n n n个客户端中的 k k k恶意客户端。首先,我们将 k k k恶意客户端的知识和能力定义如下:
(1)恶意客户端可能保留自己的有毒数据,但无法访问其他诚实客户端的本地数据。
(2)恶意客户端可以获取加密的全局模型,并对其进行解密以获取信息。但是,无法观察到由单个诚实客户端上传的本地模型更新。
(3)恶意客户可以相互勾结,并有一个共同的目标,以扩大其恶意攻击的影响。
(4)恶意客户端可以发起有针对性的攻击,也可以发起无针对性的攻击。
恶意客户端会将全局模型引向错误的方向。
在这里插入图片描述
一个恶意的客户端也能影响全局模型的准确性。

C.威胁模型

K G C KGC KGC是诚实的第三方,求解器和验证器是不串通的,但是是诚实且好奇的,他们会诚实地执行既定的协议,但可能会好奇推断一些敏感信息。本文考虑两种客户类型: 1、从全局模型收益的诚实可获,上传本地数据集训练的真实梯度。2、恶意客户端上传恶意梯度,降低全局模型的准确性。造成的威胁如下:
中毒攻击:恶意客户端的目标是在不被检测到的情况下影响全局模型的性能。恶意客户端可以通过多种方式发起中毒攻击。例如,他/她改变数据的标签,并上传在有毒数据上训练的梯度。
数据泄露:由于梯度是客户端本地数据的映射,如果客户端直接上传明文梯度,攻击者可以在一定程度上推断或获取诚实客户端的原始信息,从而导致客户端数据泄漏。
推断攻击:在我们的方案中,求解器和 V e r i f i e r Verifier Verifier交换一些中间结果,以完成局部更新的聚合。因此,他们可能试图从中间结果中推断出敏感信息。

D.设计目标

我们的目标是设计一个基于区块链的、保护隐私的FL方案,它可以抵抗中毒攻击,减少计算开销,并提供隐私保证。同时,我们的方案应该达到与FedAvg或FedSGD相同或几乎相同的精度。具体而言,我们致力于实现以下目标:
主要实现 鲁棒性,隐私性 效率性 准确性 可靠性

方案设计

本方案使用CKKS同态加密,通过实验比较相比于Pillier,CKKS具有更高的效率。
此外,我们还需要考虑恶意客户端可能会通过发送恶意梯度来扰乱训练过程,而“诚实但好奇”的中央服务器可能会推断出客户端的敏感信息。
在这里插入图片描述
C \mathcal{C} C 定义为根据我们的规则选择的诚实规范化客户端的集合 ∣ C ∣ |\mathcal{C}| C 是数量。
图4示出了我们的方案的概览。
每个客户端加密标准化本地的更新,发送给Solver(求解器),归一化的梯度放入集合 C \mathcal{C} C 并使用余弦相似性来进行判断诚实和恶意梯度。
具体方法: 在Solver中存储一个干净的小的数据集 D 0 D_0 D0(根数据集),并基于这个数据集维护一个全局模型 w 0 w_0 w0 如果 g j 0 g_j^0 gj0 g i j g_i^j gij 的余弦相似性小于0,那么客户端 C j C_j Cj 就是恶意的。一次Solver会在第 i i i轮丢弃 g i j g_i^j gij
梯度大小也会影响全局模型,万一客户端会用更大的梯度来增加他的影响,所以发送给Solver前需要进行归一化,然而恶意客户端可能会上传没有进行归一化的梯度。为了解决这个问题,方案引入一个不会串通的中心Solver。通过Solver与Verifier之间的通信,Solver获得诚实规范化的客户端集和用 p k x pk_x pkx加密的本地更新。最后,Solver聚合局部更新以获得全局模型。
为了防止中央服务器的恶意行为,降低单点故障的风险,用户列表 C \mathcal{C} C以及Solver和Verifier协同计算的中间结果需要保存到区块链。具体来说,Solver和Verifier向smart contract支付押金,鼓励他们进行正确的计算。此外,每次训练迭代的中间结果和加密的全局模型都保存到区块链,以便在中央服务器出现故障时及时回溯,增加了方案的可靠性.

B. Construction of PBFL

PBFL三个过程:本地计算、归一化判断、模型聚合。

本地计算

本地计算: 包括局部训练、归一化、加密和模型更新。
局部训练
在这里插入图片描述
在这里插入图片描述
归一化
聚合规则基于余弦相似度,为了使我们的聚合规则在密文中工作,我们在加密前规范化局部梯度。梯度视为方向向量。
对于每个客户端 C j C_j Cj 使用下列算式来归一化
在这里插入图片描述
每个客户端都需要在加密前标准化局部梯度。首先,规范化操作允许我们的聚合规则直接应用于密文,而无需任何更改。因为我们由于归一化把余弦相似度转换成向量的内积。第二,向量的大小相同,这减轻了恶意梯度的影响。这是基于这样一种直觉,即恶意客户端倾向于上传具有较大幅度的局部梯度,以便放大它们的影响。
加密
客户端 C j C_j Cj使用公钥 p k v pk_v pkv来加密 g ~ i j \tilde{g}_i^j g~ij(CKKS),梯度通常是有符号浮点数。如果使用另一种加密方案,如Paillier,我们首先需要量化和剪辑梯度值,然后单独加密每个值,这无疑会产生很高的计算开销。因此,我们使用CKKS来加密本地梯度。
将每一层的 g ~ i j \tilde{g}_i^j g~ij视作向量,具体的是每一个客户端使用Verifier的公钥 p k v pk_v pkv直接加密不同层的梯度。如果向量的长度过长,我们就多次加密,对于其余的向量我们加密一次
模型更新
客户端 C j C_j Cj从区块链下载最新的全局模型,使用私钥 s k x sk_x skx获取明文全局模型 w i − 1 w_{i-1} wi1 本地模型更新如下:
在这里插入图片描述
α \alpha α 是学习率

归一化判断

Solver需要在从客户端接收梯度后确定梯度是否真正归一化。
在接收到加密的梯度 [  ⁣ [ g ~ i j ]  ⁣ ] p k v [\![\tilde{g}_i^j]\!]_{pk_v} [[g~ij]]pkv Solver 会计算 [  ⁣ [ g ~ i j ]  ⁣ ] p k v ⊙ [  ⁣ [ g ~ i j ]  ⁣ ] p k v [\![\tilde{g}_i^j]\!]_{pk_v}\odot[\![\tilde{g}_i^j]\!]_{pk_v} [[g~ij]]pkv[[g~ij]]pkv 发送给 Verifier , ⊙ \odot 代表内积
具体来说,CKKS使用多项式,因为与向量的标准计算相比,它在安全性和效率之间提供了良好的权衡。一旦消息被加密成几个多项式,CKKS提供了几个可以对其执行的操作,如加法、乘法和旋转。具体细节如下
假设 n ∗ n^* n 维度的向量 [  ⁣ [ g ~ i j ]  ⁣ ] p k v [\![\tilde{g}_i^j]\!]_{pk_v} [[g~ij]]pkv 表示为 [  ⁣ [ p 1 , p 2 . . . p n ∗ ]  ⁣ ] p k v [\![p_1,p_2...p_{n^*}]\!]_{pk_v} [[p1,p2...pn]]pkv,通过相乘获取内积 [  ⁣ [ p 1 2 , p 2 2 . . . p n ∗ 2 ]  ⁣ ] p k v [\![p_1^2,p_2^2...p_{n^*}^2]\!]_{pk_v} [[p12,p22...pn2]]pkv 旋转获得 [  ⁣ [ p 2 2 , p 3 2 . . . p n ∗ 2 , p 1 2 ]  ⁣ ] p k v [\![p_2^2,p_3^2...p_{n^*}^2,p_1^2]\!]_{pk_v} [[p22,p32...pn2,p12]]pkv 然后将这两个向量进行相加。重复旋转和相加的操作( n ∗ − 1 n^*-1 n1次), 获得 [  ⁣ [ r 1 , r 2 . . . r n ∗ ]  ⁣ ] p k v [\![r_1,r_2...r_{n^*}]\!]_{pk_v} [[r1,r2...rn]]pkv 显然 r 1 = p 1 2 + p 2 2 + p 3 2 + . . . p n ∗ 2 r_1=p_1^2+p_2^2+p_3^2+...p_{n^*}^2 r1=p12+p22+p32+...pn2 然后 将 [  ⁣ [ r 1 , r 2 . . . r n ∗ ]  ⁣ ] p k v [\![r_1,r_2...r_{n^*}]\!]_{pk_v} [[r1,r2...rn]]pkv [ 1 , 0 , 0 , . . . 0 ] [1,0,0,...0] [1,0,0,...0]相乘获得 [  ⁣ [ r 1 ]  ⁣ ] p k v = [  ⁣ [ g ~ i j ]  ⁣ ] p k v ⊙ [  ⁣ [ g ~ i j ]  ⁣ ] p k v [\![r_1]\!]_{pk_v}=[\![\tilde{g}_i^j]\!]_{pk_v}\odot[\![\tilde{g}_i^j]\!]_{pk_v} [[r1]]pkv=[[g~ij]]pkv[[g~ij]]pkv
在这里插入图片描述

模型聚合

在从Verifier接收到用户列表 C C C之后,Solver安全地聚合集合 C C C中的客户端上传的梯度。具体来说,求解器和Verifier首先安全地执行一个协议,该协议使Solver能够获得中间结果和用 p k x pk_x pkx加密的本地模型更新。然后,Solver根据预定义的聚合规则获取加密的全局模型,并将其上传到区块链。

两方计算: Sover首先会计算 [  ⁣ [ g ~ i 0 ]  ⁣ ] p k v [\![\tilde{g}_i^0]\!]_{pk_v} [[g~i0]]pkv [  ⁣ [ g ~ i j ]  ⁣ ] p k v [\![\tilde{g}_i^j]\!]_{pk_v} [[g~ij]]pkv 的余弦相似度,然后与Verifier进行通信。我们的聚合规则依赖诚实的根节点 D 0 D_0 D0 和相关的模型 w 0 w^0 w0,这也是用来决策全局模型的期望更新方向,所以与 g i 0 g_i^0 gi0更相似的方向在聚合的时候会有更大的权重
D 0 D_0 D0 数据集的可以通过手动标记来实现,收集可信的根数据集 D 0 D_0 D0和手动标记成本通常是solver可以承受的
在这里插入图片描述
在第 i i i轮迭代的时候,Solver 在数据集 D 0 D_0 D0上训练,获得梯度更新 g i 0 g_i^0 gi0 然后使用 g ~ i 0 = g i 0 / ∣ ∣ g i 0 ∣ ∣ \tilde{g}_i^0=g_i^0/||g^0_i|| g~i0=gi0/∣∣gi0∣∣ 归一化。Solver加密获得 [  ⁣ [ g ~ i 0 ]  ⁣ ] p k v [\![\tilde{g}_i^0]\!]_{pk_v} [[g~i0]]pkv,接着由上述算式计算余弦相似度。其中 C j C_j Cj获得 g ~ i j = [ p 1 , p 2 , . . . p n ∗ ] \tilde{g}_i^j=[p_1,p_2,...p_{n^*}] g~ij=[p1,p2,...pn],Solver获得 g ~ i 0 = [ q 1 , q 2 , . . . q n ∗ ] \tilde{g}_i^0=[q_1,q_2,...q_{n^*}] g~i0=[q1,q2,...qn] 加密后 梯度是 [  ⁣ [ p 1 , p 2 , . . . p n ∗ ]  ⁣ ] p k v [\![p_1,p_2,...p_{n^*}]\!]_{pk_v} [[p1,p2,...pn]]pkv [  ⁣ [ q 1 , q 2 , . . . q n ∗ ]  ⁣ ] p k v [\![q_1,q_2,...q_{n^*}]\!]_{pk_v} [[q1,q2,...qn]]pkv,因为进行了归一化的操作,两个向量的余弦相似度的计算变成内积的计算。
在这里插入图片描述
c s i j cs_i^j csij 衡量了 [  ⁣ [ g ~ i 0 ]  ⁣ ] p k v [\![\tilde{g}_i^0]\!]_{pk_v} [[g~i0]]pkv [  ⁣ [ g ~ i j ]  ⁣ ] p k v [\![\tilde{g}_i^j]\!]_{pk_v} [[g~ij]]pkv的相似度,负值代表方向与跟数据集的梯度方向相反,会对全局模型产生负面影响
所以这里使用Relu函数用于限制列表 C C C中的梯度

max函数理解

Numerical method for comparison on homomorphically encrypted numbers
使用ReLu函数需要同态下的密文比较,文章中选择了来自2019亚密的论文《Numerical method for comparison on homomorphically encrypted numbers> 中的算法。 经过组会老师的提醒,我会后也去找了论文的相关部分的算法看。这里面其实首先涉及到对正实数的平方根的计算,原论文先提出 S q r t ( x ; d ) Sqrt(x;d) Sqrt(x;d)算法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ydBrsOzr-1679397343958)(./pic/20230321_sqrt.png)]
论文中指出上述算法的输出即 S q r t ( x ; d ) Sqrt(x;d) Sqrt(x;d)相对于 x \sqrt{x} x 有界于 ( 1 − x 4 ) 2 d + 1 (1-\frac{x}{4})^{2d+1} (14x)2d+1 通常这个误差是负的,也就是说 S q r t ( x ; d ) Sqrt(x;d) Sqrt(x;d)通常小于 x \sqrt{x} x .
证明: 因为 − 1 ≤ b 0 ≤ 0 -1\leq b_0\leq0 1b00 对所有的 n ∈ N n\in \mathbb{N} nN可以得到 − 1 ≤ b n ≤ 0 -1\leq b_n\leq0 1bn0 所以有 ∣ b n + 1 ∣ = ∣ b n ∣ ⋅ ∣ b n ( b n − 3 ) 4 ∣ ≤ ∣ b n ∣ |b_{n+1}|=|b_n|·|\frac{b_n(b_n-3)}{4}|\leq|b_n| bn+1=bn4bn(bn3)bn 所以 ∣ b n + 1 ∣ ≤ ∣ b n ∣ 2 ⋅ ( 1 − x 4 ) |b_{n+1}|\leq |b_n|^2·(1-\frac{x}{4}) bn+1bn2(14x) 得到 ∣ b n ∣ |b_n| bn ∣ b n + 1 ∣ |b_{n+1}| bn+1的递推关系式,递推可得:
∣ b d ∣ ≤ ∣ b 0 ∣ 2 d ⋅ ( 1 − x 4 ) 2 d − 1 < ( 1 − x 4 ) 2 d − 1 |b_d|\leq |b_0|^{2^d}·(1-\frac{x}{4})^{2^d-1}<(1-\frac{x}{4})^{2^d-1} bdb02d(14x)2d1<(14x)2d1,
b n b_n bn a n a_n an的定义可以得到等式 x ( 1 + b n ) = a n 2 x(1+b_n)=a_n^2 x(1+bn)=an2 进一步得到关系:
∣ a n − x x ∣ = 1 − 1 + b n < ∣ b n ∣ |\frac{a_n-\sqrt{x}}{\sqrt{x}}|=1-\sqrt{1+b_n}<|b_n| x anx =11+bn <bn
所以取一个大整数d,误差就会很小,所以算法 x \sqrt{x} x 的正确性可以得到验证。
max算法
这一部分也比较好理解,对于求 m i n ( a , b ) min(a,b) min(a,b) m a x ( a , b ) max(a,b) max(a,b) 由下列的关系:
m i n ( a , b ) = a + b 2 − ∣ a − b ∣ 2 = a + b 2 − ( a − b ) 2 2 min(a,b)=\frac{a+b}{2}-\frac{|a-b|}{2}=\frac{a+b}{2}-\frac{\sqrt{(a-b)^2}}{2} min(a,b)=2a+b2ab=2a+b2(ab)2
m a x ( a , b ) = a + b 2 + ∣ a − b ∣ 2 = a + b 2 + ( a − b ) 2 2 max(a,b)=\frac{a+b}{2}+\frac{|a-b|}{2}=\frac{a+b}{2}+\frac{\sqrt{(a-b)^2}}{2} max(a,b)=2a+b+2ab=2a+b+2(ab)2
正确性验证,也比较好得到,对于 m a x max max的条件下,分 a > = b a>=b a>=b a < b a<b a<b的情况讨论下,分别可以得到 m a x ( a , b ) max(a,b) max(a,b)分别等于 a 2 + a 2 \frac{a}{2}+\frac{a}{2} 2a+2a b 2 + b 2 \frac{b}{2}+\frac{b}{2} 2b+2b
所以最终可以得到:
在这里插入图片描述
最终的算法如论文中给出
在这里插入图片描述
总结:这里的设计思路可以参考,由顶会(亚密)上的同态密文比较算法入手,因为满足算法所需要的范围,改造ReLu函数,这也不失为一种增加创新点的思路。
给出了密文下Relu函数的计算。
在这里插入图片描述
有在[0,1]范围内同态密文的数值比较方法,但是余弦相似度是落在[-1,1] ,可以加上 [  ⁣ [ 1 ]  ⁣ ] [\![1]\!] [[1]] 然后乘1/2,于是0就是变成了1/2 ,更改 ReLU函数为ReLU’
在这里插入图片描述
在获得客户端所有的分数以后,Solver与Verifier一起工作在不泄露隐私的情况下获得模型聚合所需要的值。
在这里插入图片描述
在先前的工作中,双服务器用于密文层级的比较,在这个系统中有也可以实现。如果在密文层级实现 G e t P a r a m GetParam GetParam中ReLu函数,掩盖 c s i j cs_i^j csij下列情况可能发生。(1)双服务器架构可能回推断出 c j i j cj_i^j cjij的符号,这对客户端不利。(2)两个服务器的通信代价可能会增加
先前的工作已经比较方便的实现密文层级的操作。在本方案中使用 M a x Max Max算法实现ReLU函数,有效的保护客户端的隐私减少通信总和

聚合:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

此外,Solver和Verifier都需要在联合训练开始前向smart contract提交存款,并在任务结束时获得客户端存款的奖励。因为我们认为财务激励机制促使服务器进行正确的计算,而不是提交无意义或恶意的结果。

关于上述过程的数据流:在这里插入图片描述

总结:
在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值