Hi 游客

更多精彩,请登录!

比特池塘 区块链前沿 正文

Neo中hash算法,加密算法使用介绍

深圳林妙可
201 0 0
区块链是基于加密算法,共识算法,p2p网络和经济激励的一个系统,加密算法在里面起到了非常关键的作用,总结一下Neo使用到的加密算法吧。
4 c( h, M. A9 J2 }. E
8 t8 V/ z& `% ]" M" s关于区块链中密码学的介绍,yeasy大牛的文章已经介绍的非常好,下文主要通过和Neo结合,加上一些自己的理解,去讲述一下加密算法的使用方法。
1 P) F, Z# J4 ], |& c4 N: H6 J" n* `7 S( _
Hash 算法+ I1 K8 b+ o# e# g

% b9 Y2 e! E9 T4 R, xHash (哈希或散列)算法是信息技术领域非常基础也非常重要的技术。它能任意长度的二进制值(明文)映射为较短的固定长度的二进制值(Hash 值),并且不同的明文很难映射为相同的 Hash 值。
3 t( p3 T1 h" i- i) ~$ l! W
5 D4 V/ E) W- X& c8 Yhash函数的作用
2 a/ V* w4 l3 \
, C% l: V+ ]) F5 K8 P5 _( M注意上一篇文章说明了如何将hash后的字符串保存到Neo的UInt256类型,其中一个前提就是结果集合在[0-15]之间。
8 Z# N, B1 t: g5 z, N  x" |  p% x$ \& m" K; X$ N
哈希完全不等于加密,很多时候开发人员都对用户表中的密码进行哈希后保存,实际上不叫做加密,只是相当于把密码的“特征指纹”保存下来,而对非法攻击者来说,在不知道真实的“密码”的情况下,得到有相同指纹的密码是极为困难的。  r% M1 ~: K. A0 c

* `# _; p2 p& H一个优秀的 hash 算法,将能实现:! |% w3 X9 T% r/ [+ f4 \; C
4 M4 U; j9 m7 J$ g  F2 W# T' [6 \
正向快速:给定明文和 hash 算法,在有限时间和有限资源内能计算出 hash 值。- @' R  q2 ]. g* o$ c1 [5 d

8 ?6 ^9 R+ W3 B/ Z4 ^& O逆向困难:给定(若干) hash 值,在有限时间内很难(基本不可能)逆推出明文。
3 }4 e4 U! y" m$ A8 I( e. f: L' a+ B$ Z& Z9 F+ e6 Z
输入敏感:原始输入信息修改一点信息,产生的 hash 值看起来应该都有很大不同。' b4 ~% a' E+ B( O
3 ^, U" W5 T3 c! C! b& y
冲突避免:很难找到两段内容不同的明文,使得它们的 hash 值一致(发生冲突)。% e. S0 A: E" ?/ v% n* Z# V

- i' X; D; r% R/ [" K" w5 {3 F7 `目前,一般认为 MD5 和 SHA1 已经不够安全,推荐至少使用 SHA2-256 算法。
5 p/ w  Y' \: U) q! ^. b' N- U% T6 t) |1 Z# {$ o" A
一般的,Hash 算法都是算力敏感型,意味着计算资源是瓶颈,主频越高的 CPU 进行 Hash 的速度也越快。
6 V8 ^. @* Q& p% n9 p7 |
' `! ^* p5 b$ I8 C也有一些 Hash 算法不是算力敏感的,例如 scrypt,需要大量的内存资源,节点不能通过简单的增加更多 CPU 来获得 hash 性能的提升。
& D$ A; c9 l0 v# p( k) h7 M6 I6 J6 m/ a
Neo中的hash算法2 I  N7 ]) j) k" K0 n
9 v5 A2 z% j1 k( n" F6 e
scrypt
# Y- f( \2 o. U6 F& u' E* o5 J/ v- W$ B& S
scrpyt算法是由著名的FreeBSD黑客 Colin Percival为他的备份服务 Tarsnap开发的,当初的设计是为了降低CPU负荷,尽量少的依赖cpu计算,利用CPU闲置时间进行计算,因此scrypt不仅计算所需时间长,而且占用的内存也多,使得并行计算多个摘要异常困难,因此利用rainbow table进行暴力攻击更加困难。scrypt没有在生产环境中大规模应用,并且缺乏仔细的审察和广泛的函数库支持。所以scrpyt一直没有推广开,但是由于其内存依赖的设计特别符合当时对抗专业矿机的设计,成为数字货币算法发展的一个主要应用方向。
/ v5 t: g8 m3 q- {) U) P9 z7 T2 \# a5 G
scrypt的参数  F6 A% j7 S" X# H, f

. c8 C6 t9 Y# R& @( B& K2 rhttps://stackoverflow.com/questi ... scrypt-work-factors/ H- e) Y; c# F+ F

; q! \9 o5 B' m/ eCpercival mentioned in his slides from 2009 something around
' H* t4 r/ @" S& f' J
' E' h" i$ R  P6 u0 Z: z& f  I(N = 2^14, r = 8, p = 1) for
* e& d) S4 j5 F+ F0 B5 Z/ `- E! u; e0 X. c& p; F" y2 f1 D- s+ T$ j
scrypt特点2 W! B" D" L, l4 e# E0 \9 ~

& Q! N+ j0 w( vscrpyt的出名主要是因为莱特币为了抵抗比特币矿机采用的一个算法,可以指定内存和cpu的使用量,可以用参数确定hash的时间。! |  U, J. M2 U3 B- C. e
3 Z" c0 a8 X% N  D" u
Neo中如何使用scrypt' U8 a4 j9 x! u" Q

  a* z( C* A! o* F* H, W: b// in NEP6Account
& L+ u3 a3 G3 Q9 h, d3 d% ]* q
- _* f+ n' y  d/ }8 ?  ?   public NEP6Account(NEP6Wallet wallet,
6 d6 y4 K  R, t5 w) a
- H1 K' P* c* o/ c/ H6 ~              UInt160 scriptHash, KeyPair key, string password)1 O3 j$ V; W+ K6 V$ V! D

' j( b( S1 [0 A% B            : this(wallet,: t: l8 Q2 g' y/ L! Z

% ^9 e: a5 `1 v  M! h              scriptHash," a0 H$ h6 g$ z* i; |# ~
" A/ N1 J2 l; ?# f, i/ q
              key.Export(password, wallet.Scrypt.N, wallet.Scrypt.R, wallet.Scrypt.P))9 R5 [1 R* \  _, e0 x" S4 ^% l( U
, e9 X9 ?0 ?0 K0 {! ?
        {
6 X- Z& C0 d' g& i( k  j6 t* d# P/ m2 `8 y) @! J! E4 s2 ]# T
            this.key = key;
+ P  N6 `' k( P5 L" ?9 b, I% x6 o3 q( Q( r% c6 N; Y
        }
% L1 v6 ?0 y6 b# A# K' l/ H" a& e- t4 L2 m+ j
// in class KeyPair
) I. ^- C& z, {+ H$ b0 L$ w4 I3 J; E) T9 G- ~5 V' ]" h
public string Export(string passphrase, int N = 16384, int r = 8, int p = 8)  M$ M8 D% d, v* y

/ a7 v) C2 J7 \$ M{. w: W6 j, l/ D% r( I
: i2 l4 }$ H0 h5 O
    using (Decrypt())
: p( M$ ?: _# ]0 H
" F- @0 a# g- W) W& l    {2 A+ z6 x  d  ]2 L: s. E: F
5 Q  \  X0 z% D
        UInt160 script_hash = Contract.$ ?8 Z( _6 J6 Q$ g& o( ?$ d

, d, g$ G! ^" ~            CreateSignatureRedeemScript(PublicKey).ToScriptHash();! Z$ ?0 V. X6 f) F5 L% a" B

% M% i. G' a% F        
; O5 }2 D" X7 J9 W! f
( q0 B4 |3 G# N+ C" y' b) W9 I        string address = Wallet.ToAddress(script_hash);; `/ o" `6 P7 l8 J- Y. E
' Q) K/ X) V/ K  E0 O% G% m
        byte[] addresshash = Encoding.ASCII.GetBytes(address)* ^5 K) g$ _& H2 Y2 V; `
% G: O) k+ X% @9 n
            .Sha256().Sha256().Take(4).ToArray();
% Y8 i, f- H& `0 ~+ ?+ y. n% j) v" r9 L8 D+ ^; X9 y
        
  [7 d9 ?& i0 o* ?0 d6 X. U- |; Q! r2 K# l6 M
        byte[] derivedkey = SCrypt.DeriveKey(
1 _% L. [% W$ J! E7 T
' i+ {; @# W, L4 W- m            Encoding.UTF8.GetBytes(passphrase), addresshash, N, r, p, 64);
" V0 z; f' W" r# E
  x$ g; z- I  y        + t, \9 |; h: E$ F9 s9 G6 \

: Y- b1 e8 k7 k: T) Z$ ~: C' `: @) f; M        byte[] derivedhalf1 = derivedkey.Take(32).ToArray();
" Q. j9 u) T; `' N) {& o/ b  d1 N- g$ }
        byte[] derivedhalf2 = derivedkey.Skip(32).ToArray();$ Q" P9 K1 M' Y+ A' P% T

) L7 R, O/ W- G- u# k" c* @        . P, C# _4 c7 v7 x0 J% B# q+ D

. k& u  T( q- p' |        byte[] encryptedkey = XOR(PrivateKey, derivedhalf1)( |4 t6 v7 H4 `+ ~% ~

! E" F6 h' {5 P3 r* r9 l; s            .AES256Encrypt(derivedhalf2);# ?! O' R( A* k* a2 M. I, d
+ I; n1 I- R% L3 B5 f
        , e) }( r* n8 E
+ w" `/ R% _# B! R9 E% T. u
        byte[] buffer = new byte[39];% s" P' g% }0 _

+ Z* W% ?. ?0 e( |& m% v        buffer[0] = 0x01;
8 c1 H/ c' u3 A4 r# D' I9 i+ i
9 [( E3 E. R9 _        buffer[1] = 0x42;9 ]4 h5 l9 u6 k. }: i/ c6 ]6 l/ ]
, q- ~* ^1 x' ]& H7 \9 E, R
        buffer[2] = 0xe0;% r: h* o/ Z* ^( d% e
# m: K! a0 z$ M4 q2 |3 q
        Buffer.BlockCopy(addresshash, 0, buffer, 3, addresshash.Length);
$ I+ v3 R" F9 @9 {6 D
( {) k2 z6 T* p/ S0 i        Buffer.BlockCopy(encryptedkey, 0, buffer, 7, encryptedkey.Length);+ S  ~4 ]& r, O) I( ^
2 }! }, ~2 x# ]* W: _; t5 b8 E
        return buffer.Base58CheckEncode();# k8 w& t& q3 g' B0 M8 F

6 n( H+ M6 a- I+ r1 C    }: A" H+ O) s* _5 i. x- M3 k

3 |* d- L, \9 o$ W0 g$ e5 Z}
4 \! P8 q- ~0 R
: l3 y$ u7 s! G, v9 B可见SCrypt.DeriveKey方法参与了加密密钥的生成过程。后面解密也必然使用到了这个hash算法。所以该hash算法参与了加密过程,而加密密钥用AES256Encrypt生成。可以确定的是,使用该算法的逆过程,可以解密出密钥来,这个比WIF要安全。  N3 s1 d1 ?6 A
; j- F/ G! ^2 O) q" c
Murmur31 W6 M, H" m9 h! Z1 C. ?
6 G0 C! c6 U. w* `* R! @
MurmurHash 是一种非加密型哈希函数,适用于一般的哈希检索操作。[1][2][3]由Austin Appleby在2008年发明,[4][5] 并出现了多个变种,[6] 都已经发布到了公有领域(public domain)。与其它流行的哈希函数相比,对于规律性较强的key,MurmurHash的随机分布特征表现更良好。[7]# x5 N% z, W* {) x1 h% F

' g* X8 j( x# D* E2 }+ _) jMurmur3特点2 Y9 h5 b& @' I  f0 J* P
' @5 b9 K/ d( e! g, m. J0 {4 }  z8 ^
1.碰撞率低
. }/ \0 O1 d/ q4 u% q- \6 H4 ?
. Y4 ~& r% K3 @+ \+ w, e, a% v; `) T2.计算速度快$ ?0 b& _, e2 M+ G1 i$ T. {8 E

. u7 E$ O- `3 }9 L3.擅长大文件的hash
5 T" }& k# R& s/ n+ n
% S( U2 T+ d. I' p6 pNeo中如何使用Murmur33 B( T9 K) j+ y5 c* @4 R+ ?5 v9 Z6 T
1 K/ v* e2 f: I
Neo中Murmur3
+ B& Z0 x' L8 J) E! v$ f8 ^# J, w0 }$ {7 r9 `+ J8 g5 J
Murmur3的具体算法,以后再研究,现在大致知道,Neo用Murmur3生成key,也在BloomFilter中使用了。) O  h2 u7 ?+ j! p7 E# ?8 A

2 r# |( x3 T7 t+ URIPEMD-1609 x" N6 _! w" k5 j5 {- W: Q, A
: n5 e* f# m$ V* T' D- h! q: D
Neo中用这个算法来生成短一点的hash值,script hash就是用了这个算法。
3 j" n- {9 s% ^! V
; |. V0 s: @4 m0 z; `" Y// in neo-compiler/neo/neo/Core/Helper.cs0 d) p: d# @9 o3 A) p' l" ~" z
; o+ z7 f: c$ z. m
public static UInt160 ToScriptHash(this byte[] script)$ D/ O& t: a) d. [7 \
6 j% }* T* w. J3 Q/ @
        {
/ a2 k* K! l5 l0 S% M4 A- B2 t2 v' P  t
            return new UInt160(Crypto.Default.Hash160(script));
  @5 _# B1 X' @- Y8 Y, I2 C- f7 T% u8 o4 r/ s5 V6 O
        }
& i: C3 ~9 \2 d" K0 X/ t" X
' H4 q! L5 f1 x- ?4 c4 w" v8 MRIPEMD-160算法的特点7 E8 v% a! V% G3 D, D

' c( M) D4 D( u" ?$ n4 @$ m6 SRIPEMD-160能表现出理想的 雪崩效应 (例如将 d 改成 c,即微小的变化就能产生一个完全不同的哈希值):' S% W6 {3 H! ]0 ~( Y

6 t7 R4 G7 s$ j2 V0 P0 O6 V0 n加密算法体系
0 g3 o+ ?3 Y# B' t* l, h4 T) U6 T" l$ o6 |
现代加密算法的典型组件包括:加解密算法、加密密钥、解密密钥。其中,加解密算法自身是固定不变的,一般是公开可见的;密钥则往往每次不同,并且需要保护起来,一般来说,对同一种算法,密钥长度越长,则加密强度越大。9 R+ f4 N6 ?4 Q! h! t
% P) X9 @+ \" a5 R
加密过程中,通过加密算法和加密密钥,对明文进行加密,获得密文。1 w( S5 ?1 N3 W

. T7 }* D3 h+ q$ @$ c解密过程中,通过解密算法和解密密钥,对密文进行解密,获得明文。
2 O+ L( R4 I2 U, s$ N% ]# P9 J* H; w$ V& S0 a
根据加解密的密钥是否相同,算法可以分为对称加密(symmetric cryptography,又称公共密钥加密,common-key cryptography)和非对称加密(asymmetric cryptography,又称公钥加密,public-key cryptography)。两种模式适用于不同的需求,恰好形成互补,很多时候也可以组合使用,形成混合加密机制。, w/ l; Q7 Y9 s' o8 ^

# @6 A7 |/ }$ e+ W4 X' T并非所有加密算法的强度都可以从数学上进行证明。公认的高强度加密算法是在经过长时间各方面实践论证后,被大家所认可,不代表其不存在漏洞。但任何时候,自行发明加密算法都是一种不太明智的行为。7 i$ L7 l/ z# M5 ^
6 |1 o) x4 [/ ^5 G0 g$ _
对称加密$ s0 b; B3 X- O/ Y+ ]* J; I0 U2 u6 I

+ }% X8 s" l3 c  l( I7 C+ s' v顾名思义,加解密的密钥是相同的。9 h* `' e4 R+ ^; E$ ~; K
6 u+ s; {( g" H! w. H& T
对称加密优缺点, U. p" \! ]1 v; a3 n% V9 Z

( l% ?# q% E+ Y0 O$ D优点是加解密效率高(速度快,空间占用小),加密强度高。( u, E* J' j7 W" Q  O
3 \/ |( s" G1 P; ?
缺点是参与多方都需要持有密钥,一旦有人泄露则安全性被破坏;另外如何在不安全通道下分发密钥也是个问题。* A# N+ j0 R: e( a

. B5 {! N1 n" z. e. g适用于大量数据的加解密;不能用于签名场景;需要提前分发密钥。; Z. ^. m8 a& [8 c$ O3 Z, ^; w8 a$ b; o$ J
% x: P- P: P, ^7 d
对称加密实现
# T& O2 }, {, A  C) W/ u6 c8 L5 t4 L; G! G6 ?
对称密码从实现原理上可以分为两种:分组密码和序列密码。前者将明文切分为定长数据块作为加密单位,应用最为广泛。后者则只对一个字节进行加密,且密码不断变化,只用在一些特定领域,如数字媒介的加密等。
# M& g) M; @/ w- s5 t- p5 N! H1 r3 M2 I6 G% ~! F7 h
代表算法包括 DES、3DES、AES、IDEA 等。/ X8 b) I3 G9 P/ x" F. k6 |

8 O8 k$ p9 r* W. i( xDES(Data Encryption Standard):经典的分组加密算法,1977 年由美国联邦信息处理标准(FIPS)所采用 FIPS-46-3,将 64 位明文加密为 64 位的密文,其密钥长度为 56 位 + 8 位校验。现在已经很容易被暴力破解。
. D, N* e: }( C" Q5 L0 N
7 E6 O0 P- H  D4 E  H7 \3DES:三重 DES 操作:加密 –> 解密 –> 加密,处理过程和加密强度优于 DES,但现在也被认为不够安全。* Q9 z/ {0 i" m  Q3 @

5 _! K  X8 x" _! `% zAES(Advanced Encryption Standard):美国国家标准研究所(NIST)采用取代 DES 成为对称加密实现的标准,1997~2000 年 NIST 从 15 个候选算法中评选 Rijndael 算法(由比利时密码学家 Joan Daemon 和 Vincent Rijmen 发明)作为 AES,标准为 FIPS-197。AES 也是分组算法,分组长度为 128、192、256 位三种。AES 的优势在于处理速度快,整个过程可以数学化描述,目前尚未有有效的破解手段。
- L. r2 G- D- f, U$ k  ^0 v% n, p) Y
注:分组加密每次只能处理固定长度的明文,因此过长的内容需要采用一定模式进行加密,《实用密码学》中推荐使用 密文分组链接(Cipher Block Chain,CBC)、计数器(Counter,CTR)模式。
8 ?) N) _, n+ L2 @" N' v" j* U6 X* Y" D6 I, x
Neo中的AES
7 [! C1 y: I! q5 b% y
* e+ t# a4 Q0 u+ S- }在钱包的加解密中,使用了该算法。
" e" V- j4 P5 v6 O
4 D4 \. Z& E: n4 J下图的代码在/neo/Wallets/Wallet.cs中,NEP是neo enhancement proposal的意思。参数nep2就是符合这个格式的一个Neo钱包文件。
6 ~  @  S) J0 P" [- B3 d+ [6 H
1 k( T' T# u/ p" W. c拿到私钥+ s8 b# \) G* B2 E
% ~) Q& }' ]- H. z. g+ G. S
具体的过程,后面再仔细研究分享出来。
: v& p) x" x: @0 [. f3 j+ s
" e* E8 V: f6 M- ~) x; @( e6 {非对称加密
4 m7 B! g+ H) _
. B. n( e0 V3 |- ^% O非对称加密是现代密码学历史上最为伟大的发明,可以很好的解决对称加密需要的提前分发密钥问题。顾名思义,加密密钥和解密密钥是不同的,分别称为公钥和私钥。公钥一般是公开的,人人可获取的,私钥一般是个人自己持有,不能被他人获取。
6 S: d! U4 L" M* d. E. X; N7 [0 x+ t1 J" a, R+ Z2 z
非对称加密优缺点
: T( d. q; {" P7 i) X+ x2 h8 V  x4 b6 W
优点是公私钥分开,不安全通道也可使用。% r5 A0 c% i% r' Y6 E# q% z- A  j
, w, g/ h( M- G* w
缺点是加解密速度慢,一般比对称加解密算法慢两到三个数量级;同时加密强度相比对称加密要差。
* t5 w" x; A" p0 W; Y) \0 W8 |) B% u& o5 u# K2 z
非对称加密代表算法
% h' ?6 u8 s$ V9 D2 {
, p/ A, k1 G+ V3 E! H' q非对称加密算法的安全性往往需要基于数学问题来保障,目前主要有基于大数质因子分解、离散对数、椭圆曲线等几种思路。
; [: L, P* A; H' `% @, q, |  a/ Y9 j( ^
代表算法包括:RSA、ElGamal、椭圆曲线(Elliptic Curve Crytosystems,ECC)系列算法。! r& F* P8 ~  T6 y

+ F, y$ i* o  W6 x  o6 }RSA:经典的公钥算法,1978 年由 Ron Rivest、Adi Shamir、Leonard Adleman 共同提出,三人于 2002 年获得图灵奖。算法利用了对大数进行质因子分解困难的特性,但目前还没有数学证明两者难度等价,或许存在未知算法在不进行大数分解的前提下解密。( V$ U8 B" L1 L4 [  {: \

1 b3 [( ?9 L: x7 W! d' bDiffie-Hellman 密钥交换:基于离散对数无法快速求解,可以在不安全的通道上,双方协商一个公共密钥。
0 k# C$ a* ^( A6 Q8 S, ]! M- K- |' j  S" i
ElGamal:由 Taher ElGamal 设计,利用了模运算下求离散对数困难的特性。被应用在 PGP 等安全工具中。) k8 m, m  ~( N, U5 g
3 j! F) o: X3 ?1 A' g) d7 u4 f
椭圆曲线算法(Elliptic curve cryptography,ECC):现代备受关注的算法系列,基于对椭圆曲线上特定点进行特殊乘法逆运算难以计算的特性。最早在 1985 年由 Neal Koblitz 和 Victor Miller 分别独立提出。ECC 系列算法一般被认为具备较高的安全性,但加解密计算过程往往比较费时。一般适用于签名场景或密钥协商,不适于大量数据的加解密。! x- q" |. `4 J: n: f6 f, ~+ C

9 e2 e# z$ d/ l; `RSA 算法等已被认为不够安全,一般推荐采用椭圆曲线系列算法。4 N8 U' G/ b- ^" D, a
8 x3 x. v/ x  K, i2 m6 S2 h
Neo中的数字签名算法
% j) {8 F4 o* I* V, j* R
2 ?( m8 h+ Z" B" y3 ?+ z  M在Neo中,也使用了非对称加密算法,我们通过代码来看看是如何使用的。: H! n4 {* c- |& e/ t" `
8 l% J- `+ |6 C. P. L0 c
public virtual WalletAccount Import(X509Certificate2 cert)2 J( K9 X* |+ N2 n  y( v
( R$ G' L( a( h3 [
        {
# D: j6 [1 c- x  [4 [* z3 A
5 q$ B) c1 ~3 M            byte[] privateKey;3 P! w" C  m4 s9 e7 d, Y% H+ n+ U
# M! v5 T( k7 x- l, T% d
            using (ECDsa ecdsa = cert.GetECDsaPrivateKey())3 x7 Y; h  Q9 s5 y

# T. b& j6 A/ X! t5 D  ]            {
, v, t& e9 K: q+ u5 d& k1 b1 ?! \* k) h' m% p
                privateKey = ecdsa.ExportParameters(true).D;/ Z. d3 P6 M. |6 @& z6 J# g

. S. F. z' z, O$ ~7 ]4 Q            }& Q& R( r/ Y7 h

) ]2 J8 c& b( B5 e. p8 B            WalletAccount account = CreateAccount(privateKey);
  H& a- H  s* n) h- [
% E" R4 j9 [: g1 |2 I            Array.Clear(privateKey, 0, privateKey.Length);
3 V. G6 \; s6 m1 x# m6 y( `7 `6 e+ z% z
            return account;
( q8 N; H# [+ q- `: T$ t0 m5 c: s* a" F- y5 }
        }
, l' p! I" [. e: C$ [9 n9 y( C* _, H
X509Certificate2是数字证书,和我们在https里面使用的是一样的,从里面拿出私钥后,创建钱包。
6 r0 s7 O8 Q& b* s: K/ \
0 m% v$ v% ~% u- J总结+ E3 O4 `7 N# I+ b  c) {

( F, G$ D6 Q* }目前只是简单的介绍了一下Neo中加密算法的使用情况,这些加密算法的原理和实现也是很有意思的,后面看看怎么实现的,再分享出来。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

深圳林妙可 初中生
  • 粉丝

    0

  • 关注

    0

  • 主题

    33