1. 引言

STARK/SNARK中包含了大量的有限域运算,如:

  • STARK中包含了对 roots of unity domain D={1,ω,⋯,ω2k−1}D=\{1,\omega,\cdots,\omega^{2^k-1}\}D={1,ω,⋯,ω2k−1} 的批量 polynomial evaluation运算

除可通过CPU/GPU等硬件加速外,还有一些算法可实现加速。

  • CPU加速可参看:【监控CPU使用率用top

    • CPU指令集——AVX2
  • 采用CPU加速的密码学库有:

    • https://github.com/dalek-cryptography/ed25519-dalek
  • 采用GPU加速的密码学库有:【监控GPU使用率:NVIDIA GPU可用nvidia-smi;Intel GPU可用intel-gpu-tools;AMD GPU可用fglrx或RadeonTop。】

    • https://github.com/filecoin-project/bellperson
      以 520 core的GPU为例,其做multiexponentiation计算,与CPU的性能对比为:
$ RUST_LOG=info cargo test --features opencl -- --exact multiexp::gpu_multiexp_consistency --nocaptureCompiling bellperson v0.18.0 (/home/administrator/bellperson)Finished test [unoptimized + debuginfo] target(s) in 8.21sRunning unittests (target/debug/deps/bellperson-8b909898d5e3834a)running 1 test
[2021-12-16T08:53:13Z INFO  bellperson::gpu::utils] Device: Device { vendor: Nvidia, name: "Quadro P620", memory: 2097479680, pci_id: PciId(768), uuid: Some(148dcfa4-76fd-6819-dfb2-6199f912527f), opencl: Some(Device { vendor: Nvidia, name: "Quadro P620", memory: 2097479680, pci_id: PciId(768), uuid: Some(148dcfa4-76fd-6819-dfb2-6199f912527f), device: Device { id: 139725486794256 } }) }
Testing Multiexp for 1024 elements...
[2021-12-16T08:53:13Z INFO  bellperson::gpu::locks] GPU is available for Multiexp!
[2021-12-16T08:53:13Z INFO  bellperson::gpu::program] Using kernel on OpenCL.
[2021-12-16T08:53:13Z INFO  bellperson::gpu::multiexp] Multiexp: 1 working device(s) selected. (CPU utilization: 0)
[2021-12-16T08:53:13Z INFO  bellperson::gpu::multiexp] Multiexp: Device 0: Quadro P620 (Chunk-size: 894826)
[2021-12-16T08:53:13Z INFO  bellperson::multiexp] GPU Multiexp kernel instantiated!
GPU took 187ms.
CPU took 208ms.
Speedup: x1.1122994
============================
Testing Multiexp for 2048 elements...
GPU took 52ms.
CPU took 395ms.
Speedup: x7.5961537
============================
Testing Multiexp for 4096 elements...
GPU took 92ms.
CPU took 378ms.
Speedup: x4.1086955
============================
Testing Multiexp for 8192 elements...
GPU took 132ms.
CPU took 688ms.
Speedup: x5.212121
============================
Testing Multiexp for 16384 elements...
GPU took 237ms.
CPU took 1471ms.
Speedup: x6.206751
============================
Testing Multiexp for 32768 elements...
GPU took 281ms.
CPU took 2611ms.
Speedup: x9.291815
============================
Testing Multiexp for 65536 elements...
GPU took 454ms.
CPU took 6154ms.
Speedup: x13.555066
============================
test multiexp::gpu_multiexp_consistency ... ok

前序博客有:

  • 十分简明易懂的FFT(快速傅里叶变换)
  • Halo中的快速傅里叶(逆)变换算法(I)FFT

2. 采用FFT来加速roots of unity domain内的批量polynomial evaluation

有限域内的Fast Fourier Transform(FFT),又可称为Number Theory Transform (NTT)。FFT用于将多项式系数表示法,转换为点值表示法。

令多项式 f(X)=∑i=0dciXif(X)=\sum_{i=0}^{d}c_iX^if(X)=∑i=0d​ci​Xi的degree 不高于2k−12^k-12k−1,其系数ci∈Fpc_i\in\mathbb{F}_pci​∈Fp​。
令ω\omegaω为2k2^k2k-th root of unity,求以下所有polynomial evaluation 值:
(f(ωi))i=02k−1=(f(1),f(ω),f(ω2),…,f(ω2k−1))(f(\omega^i))_{i=0}^{2^k-1} = (f(1), f(\omega), f(\omega^2), \ldots, f(\omega^{2^k-1}))(f(ωi))i=02k−1​=(f(1),f(ω),f(ω2),…,f(ω2k−1))

解决方案有:

  • 1)最直观的方法是,依次计算每个evaluation值。【令N=2kN=2^kN=2k,算法复杂度为O(N2)O(N^2)O(N2)。】【interpolate、evaluate、divide等naive运算可参看:https://github.com/aszepieniec/stark-anatomy/blob/master/code/univariate.py】
  • 2)更明智的方法为,根据FFT的divide-and-conquer策略,将多项式分为奇数项和偶数项表示:【递归调用,令N=2kN=2^kN=2k,算法复杂度为O(N⋅log⁡N)O(N\cdot \log N)O(N⋅logN)。】【interpolate、evaluate、divide等借助FFT/IFFT加速运算可参看:https://github.com/aszepieniec/stark-anatomy/blob/master/code/ntt.py】
    f(X)=fE(X2)+X⋅fO(X2)f(X)=f_E(X^2)+X\cdot f_O(X^2)f(X)=fE​(X2)+X⋅fO​(X2)
    其中:
    fE(X2)=f(X)+f(−X)2=∑i=0d+12−1c2iX2if_E(X^2)=\frac{f(X)+f(-X)}{2}=\sum_{i=0}^{\frac{d+1}{2}-1}c_{2i}X^{2i}fE​(X2)=2f(X)+f(−X)​=∑i=02d+1​−1​c2i​X2i
    fO(X2)=f(X)−f(−X)2X=∑i=0d+12−1c2i+1X2if_O(X^2)=\frac{f(X)-f(-X)}{2X}=\sum_{i=0}^{\frac{d+1}{2}-1}c_{2i+1}X^{2i}fO​(X2)=2Xf(X)−f(−X)​=∑i=02d+1​−1​c2i+1​X2i
    从而有:
    f(ωi)=fE(ω2i)+ωi⋅fO(ω2i)f(\omega^i)=f_E(\omega^{2i})+\omega^i\cdot f_O(\omega^{2i})f(ωi)=fE​(ω2i)+ωi⋅fO​(ω2i)

递归调用,多项式系数cic_ici​为参数values,则调用ntt返回的即为(f(ωi))i=02k−1=(f(1),f(ω),f(ω2),…,f(ω2k−1))(f(\omega^i))_{i=0}^{2^k-1} = (f(1), f(\omega), f(\omega^2), \ldots, f(\omega^{2^k-1}))(f(ωi))i=02k−1​=(f(1),f(ω),f(ω2),…,f(ω2k−1)) evaluation值:【代码见:https://github.com/aszepieniec/stark-anatomy/blob/master/code/ntt.py】

def ntt( primitive_root, values ):assert(len(values) & (len(values) - 1) == 0), "cannot compute ntt of non-power-of-two sequence"if len(values) <= 1:return valuesfield = values[0].fieldassert(primitive_root^len(values) == field.one()), "primitive root must be nth root of unity, where n is len(values)"assert(primitive_root^(len(values)//2) != field.one()), "primitive root is not primitive nth root of unity, where n is len(values)"half = len(values) // 2odds = ntt(primitive_root^2, values[1::2])evens = ntt(primitive_root^2, values[::2])return [evens[i % half] + (primitive_root^i) * odds[i % half] for i in range(len(values))]

3. 采用IFFT来获取多项式系数

有限域内的Inverse Fast Fourier Transform(IFFT),又可称为Inverse Number Theory Transform (INTT)。FFT用于将点值表示法,转换为多项式系数表示法。

IFFT(FFT()),FFT之后再IFFT运算,得到的结果为原值。

def test_intt( ):field = Field.main()logn = 7n = 1 << lognprimitive_root = field.primitive_nth_root(n)values = [field.sample(os.urandom(1)) for i in range(n)]coeffs = ntt(primitive_root, values)values_again = intt(primitive_root, coeffs)assert(values == values_again), "inverse ntt is different from forward ntt"
def intt( primitive_root, values ):assert(len(values) & (len(values) - 1) == 0), "cannot compute intt of non-power-of-two sequence"if len(values) == 1:return valuesfield = values[0].fieldninv = FieldElement(len(values), field).inverse()# primitive_root.inverse()后再进行transformed_values = ntt(primitive_root.inverse(), values)# 乘以ninv后为实际系数。return [ninv*tv for tv in transformed_values]

4. 基于FFT和IFFT实现多项式fast multiplication

已知多项式f(X),g(X)f(X),g(X)f(X),g(X),求h(X)=f(X)⋅g(X)h(X) = f(X) \cdot g(X)h(X)=f(X)⋅g(X),其中有deg(h(X))<2k\mathsf{deg}(h(X)) < 2^kdeg(h(X))<2k:

  • 1)分别对f(X),g(X)f(X),g(X)f(X),g(X)进行FFT运算,获得相应的点值表示。
  • 2)将点值表示的f(X),g(X)f(X),g(X)f(X),g(X)逐个相乘,结果为h(X)h(X)h(X)的点值表示。
  • 3)将相乘后的点值进行IFFT运算,获得的为h(X)h(X)h(X)的系数。
def fast_multiply( lhs, rhs, primitive_root, root_order ):assert(primitive_root^root_order == primitive_root.field.one()), "supplied root does not have supplied order"assert(primitive_root^(root_order//2) != primitive_root.field.one()), "supplied root is not primitive root of supplied order"if lhs.is_zero() or rhs.is_zero():return Polynomial([])field = lhs.coefficients[0].fieldroot = primitive_rootorder = root_orderdegree = lhs.degree() + rhs.degree()if degree < 8: # 若degree较低,则直接进行多项式乘法运算。return lhs * rhswhile degree < order // 2: # 取离degree最近的2^k order和相应的2^k-th root。root = root^2order = order // 2lhs_coefficients = lhs.coefficients[:(lhs.degree()+1)]while len(lhs_coefficients) < order: # 若系数个数不足order,则补0lhs_coefficients += [field.zero()]rhs_coefficients = rhs.coefficients[:(rhs.degree()+1)]while len(rhs_coefficients) < order: # 若系数个数不足order,则补0rhs_coefficients += [field.zero()]#  1)分别对$f(X),g(X)$进行FFT运算,获得相应的点值表示。lhs_codeword = ntt(root, lhs_coefficients)rhs_codeword = ntt(root, rhs_coefficients)# 2)将点值表示的$f(X),g(X)$逐个相乘,结果为$h(X)$的点值表示。hadamard_product = [l * r for (l, r) in zip(lhs_codeword, rhs_codeword)]# 3)将相乘后的点值进行IFFT运算,获得的为$h(X)$的系数。product_coefficients = intt(root, hadamard_product)# 只需取product_coefficients数组中的前degree+1个值即可,后面的都是0。return Polynomial(product_coefficients[0:(degree+1)])

5. 基于fast multiplication 实现 fast zerofier

仍然借助divide-and-conquer思想,可递归调用fast_multiply来计算zerofiers(又名vanish polynomial):
z(X)=(X−1)(X−ω)⋯(X−ω2k−1)z(X)=(X-1)(X-\omega)\cdots(X-\omega^{2^k-1})z(X)=(X−1)(X−ω)⋯(X−ω2k−1)【roots of unity domain】

z(X)=(X−x0)(X−x1)⋯(X−xd)z(X)=(X-x_0)(X-x_1)\cdots(X-x_{d})z(X)=(X−x0​)(X−x1​)⋯(X−xd​)【任意domain】

详细的步骤为:

  • 1)将domain切分为左右两等份。
  • 2)分别对左右两份计算zerofiers。
  • 3)使用fast multiplication将zerofiers相乘。
def fast_zerofier( domain, primitive_root, root_order ):assert(primitive_root^root_order == primitive_root.field.one()), "supplied root does not have supplied order"assert(primitive_root^(root_order//2) != primitive_root.field.one()), "supplied root is not primitive root of supplied order"if len(domain) == 0:return Polynomial([])if len(domain) == 1:return Polynomial([-domain[0], primitive_root.field.one()])half = len(domain) // 2left = fast_zerofier(domain[:half], primitive_root, root_order)right = fast_zerofier(domain[half:], primitive_root, root_order)return fast_multiply(left, right, primitive_root, root_order)

6. 基于fast zerofier 实现 任意domain的fast evaluate

对任意domain {x0,x1,⋯,xd}\{x_0,x_1,\cdots,x_d\}{x0​,x1​,⋯,xd​},求evaluate f(X)f(X)f(X):
f(x0),f(x1),⋯,f(xd)f(x_0),f(x_1),\cdots, f(x_d)f(x0​),f(x1​),⋯,f(xd​)

根据Lagrange,可将f(X)f(X)f(X)表示为:
f(X)=∑i=0df(xi)∏j=0,j≠id(X−xj)∏j=0,j≠id(xi−xj)f(X)=\sum_{i=0}^{d}f(x_i)\frac{\prod_{j=0,j\neq i}^{d}(X-x_j)}{\prod_{j=0,j\neq i}^{d}(x_i-x_j)}f(X)=∑i=0d​f(xi​)∏j=0,j​=id​(xi​−xj​)∏j=0,j​=id​(X−xj​)​

计算[f(x0),f(x1),⋯,f(xd)][f(x_0),f(x_1),\cdots, f(x_d)][f(x0​),f(x1​),⋯,f(xd​)],相应的fast evaluate算法为:

def fast_evaluate( polynomial, domain, primitive_root, root_order ):assert(primitive_root^root_order == primitive_root.field.one()), "supplied root does not have supplied order"assert(primitive_root^(root_order//2) != primitive_root.field.one()), "supplied root is not primitive root of supplied order"if len(domain) == 0:return []if len(domain) == 1: # 返回值为数组。return [polynomial.evaluate(domain[0])]half = len(domain) // 2left_zerofier = fast_zerofier(domain[:half], primitive_root, root_order)right_zerofier = fast_zerofier(domain[half:], primitive_root, root_order)left = fast_evaluate(polynomial % left_zerofier, domain[:half], primitive_root, root_order)right = fast_evaluate(polynomial % right_zerofier, domain[half:], primitive_root, root_order)return left + right

7. 基于fast zerofier和fast evaluate 实现 fast interpolate

根据Lagrange,可将f(X)f(X)f(X)表示为:
f(X)=∑i=0df(xi)∏j=0,j≠id(xi−xj)∏j=0,j≠id(X−xj)f(X)=\sum_{i=0}^{d}\frac{f(x_i)}{\prod_{j=0,j\neq i}^{d}(x_i-x_j)}\prod_{j=0,j\neq i}^{d}(X-x_j)f(X)=∑i=0d​∏j=0,j​=id​(xi​−xj​)f(xi​)​∏j=0,j​=id​(X−xj​)

其中∏j=0,j≠id(xi−xj)\prod_{j=0,j\neq i}^{d}(x_i-x_j)∏j=0,j​=id​(xi​−xj​)对应为fast_interpolate算法中的left_offsetright offset变量:

def fast_interpolate( domain, values, primitive_root, root_order ):assert(primitive_root^root_order == primitive_root.field.one()), "supplied root does not have supplied order"assert(primitive_root^(root_order//2) != primitive_root.field.one()), "supplied root is not primitive root of supplied order"assert(len(domain) == len(values)), "cannot interpolate over domain of different length than values list"if len(domain) == 0:return Polynomial([])if len(domain) == 1:return Polynomial([values[0]])half = len(domain) // 2left_zerofier = fast_zerofier(domain[:half], primitive_root, root_order)right_zerofier = fast_zerofier(domain[half:], primitive_root, root_order)left_offset = fast_evaluate(right_zerofier, domain[:half], primitive_root, root_order)right_offset = fast_evaluate(left_zerofier, domain[half:], primitive_root, root_order)if not all(not v.is_zero() for v in left_offset):print("left_offset:", " ".join(str(v) for v in left_offset))left_targets = [n / d for (n,d) in zip(values[:half], left_offset)]right_targets = [n / d for (n,d) in zip(values[half:], right_offset)]left_interpolant = fast_interpolate(domain[:half], left_targets, primitive_root, root_order)right_interpolant = fast_interpolate(domain[half:], right_targets, primitive_root, root_order)return left_interpolant * right_zerofier + right_interpolant * left_zerofier

8. 基于FFT实现fast coset evaluate

所谓coset evaluate,是对多项式f(X)=∑i=02k−1ciXif(X)=\sum_{i=0}^{2^k-1}c_iX^if(X)=∑i=02k−1​ci​Xi,求:
f(g⋅1),f(g⋅ω),⋯,f(g⋅ω2k−1)f(g\cdot 1), f(g\cdot \omega), \cdots, f(g\cdot \omega^{2^k-1})f(g⋅1),f(g⋅ω),⋯,f(g⋅ω2k−1)
【对应为博客 STARK入门知识 4.3节 “Coset-FRI”。】

实际算法为:

  • 1)将多项式f(X)f(X)f(X) scale为f(g⋅X)=∑i=02k−1(ci⋅g)⋅Xif(g\cdot X)=\sum_{i=0}^{2^k-1}(c_i\cdot g)\cdot X^if(g⋅X)=∑i=02k−1​(ci​⋅g)⋅Xi。
  • 2)使用FFT对f(g⋅X)f(g\cdot X)f(g⋅X) 进行roots of unity domain内的批量polynomial evaluation。
def fast_coset_evaluate( polynomial, offset, generator, order ):scaled_polynomial = polynomial.scale(offset)values = ntt(generator, scaled_polynomial.coefficients + [offset.field.zero()] * (order - len(polynomial.coefficients)))return values

9. 利用FFT和IFFT实现fast coset divide

为求h(X)=f(X)z(X)h(X)=\frac{f(X)}{z(X)}h(X)=z(X)f(X)​,转为求h(g⋅X)=f(g⋅X)z(g⋅X)h(g\cdot X)=\frac{f(g\cdot X)}{z(g\cdot X)}h(g⋅X)=z(g⋅X)f(g⋅X)​,然后将h(g⋅X)h(g\cdot X)h(g⋅X)的系数除以ggg,即为h(X)h(X)h(X)的系数。

实际算法实现步骤为:

  • 1)分子分母系数都Scale
  • 2)NTT
  • 3)element-wise divide
  • 4)inverse NTT
  • 5)对求得的商系数unscale
# 只考虑了能整除干净的情况
def fast_coset_divide( lhs, rhs, offset, primitive_root, root_order ): # clean division only!assert(primitive_root^root_order == primitive_root.field.one()), "supplied root does not have supplied order"assert(primitive_root^(root_order//2) != primitive_root.field.one()), "supplied root is not primitive root of supplied order"assert(not rhs.is_zero()), "cannot divide by zero polynomial"if lhs.is_zero():return Polynomial([])assert(rhs.degree() <= lhs.degree()), "cannot divide by polynomial of larger degree"field = lhs.coefficients[0].fieldroot = primitive_rootorder = root_orderdegree = max(lhs.degree(),rhs.degree())if degree < 8:return lhs / rhswhile degree < order // 2:root = root^2order = order // 2# 1)分子分母系数都Scalescaled_lhs = lhs.scale(offset)scaled_rhs = rhs.scale(offset)lhs_coefficients = scaled_lhs.coefficients[:(lhs.degree()+1)]while len(lhs_coefficients) < order:lhs_coefficients += [field.zero()]rhs_coefficients = scaled_rhs.coefficients[:(rhs.degree()+1)]while len(rhs_coefficients) < order:rhs_coefficients += [field.zero()]# 2)NTTlhs_codeword = ntt(root, lhs_coefficients)rhs_codeword = ntt(root, rhs_coefficients)# 3)element-wise dividequotient_codeword = [l / r for (l, r) in zip(lhs_codeword, rhs_codeword)]# 4)inverse NTTscaled_quotient_coefficients = intt(root, quotient_codeword)# 只取scaled_quotient_coefficients数组中前(lhs.degree() - rhs.degree() + 1)个数,其余均为0scaled_quotient = Polynomial(scaled_quotient_coefficients[:(lhs.degree() - rhs.degree() + 1)])# 5)对求得的商系数unscalereturn scaled_quotient.scale(offset.inverse())

相应的测试用例为:

def test_divide( ):field = Field.main()logn = 6n = 1 << lognprimitive_root = field.primitive_nth_root(n)for trial in range(20):lhs_degree = int(os.urandom(1)[0]) % (n // 2)rhs_degree = int(os.urandom(1)[0]) % (n // 2)lhs = Polynomial([field.sample(os.urandom(17)) for i in range(lhs_degree+1)])rhs = Polynomial([field.sample(os.urandom(17)) for i in range(rhs_degree+1)])fast_product = fast_multiply(lhs, rhs, primitive_root, n)quotient = fast_coset_divide(fast_product, lhs, field.generator(), primitive_root, n)assert(quotient == rhs), "fast divide does not equal original factor"

参考资料

[1] Anatomy of a STARK, Part 6: Speeding Things Up
[2] Filecoin zk-SNARK Accelerating
[3] GPU-SNARKs
[4] Plonk with GPU acceleration
[5] ZKSwap GPU optimization

STARK/SNARK加速小技巧相关推荐

  1. 【Unity知识树】Unity编辑器加速小技巧

    Unity编辑器加速小技巧 运行游戏时不重新编译脚本 现象:每次运行游戏都会弹出一个重新加载脚本的框,耽误几秒钟时间. 提速技巧:勾选工程设置 > 编辑器 > Enter Play Mod ...

  2. 新技能get√​10个PS加速小技巧让你的PS不再卡

    如果你在处理较大尺寸的图片.使用像HDR.图像合成或者3D和视频等类似的功能,优化Photoshop的性能是非常关键的.这篇文章中,我会为大家介绍几种提高Photoshop性能的建议,使其在你的电脑上 ...

  3. V-Ray怎么快速渲染_渲染加速小技巧

    很多小伙伴在使用V-Ray渲染器的时候都想要更加快速的出图,今天Renderbus瑞云渲染就给大家分享一下V-Ray渲染加速的小技巧. 在了解渲染加速技巧之前,我们首先要了解渲染制作主要受两个因素影响 ...

  4. Windows电脑加速小技巧(VIP典藏版)

    Windows超实用技巧50篇博客(VIP典藏版) 目录 一.设置虚拟内存 二.清理优化桌面 三.设置开机启动项 四.加大内存条(有条件的可以) 五.系统盘换固态盘(有条件的可以) 六.Windows ...

  5. android手机如何加速,小技巧:如何给Android手机上的Chrome浏览器加速

    当你使用过Android版本的谷歌Chrome浏览器后,你可能会对花费大量时间等待加载.浏览器假死的经历印象深刻. 假如你习惯了使用谷歌Chrome浏览器,不愿意再更换其它浏览器,但又不得不去面对它占 ...

  6. 视频剪辑教程,加速小技巧,录好的所有视频增速快进

    最近有很多朋友在问,如何剪辑视频,比如说将录好的多个视频增速快进,该如何操作?今天小编给大家分享一个新的剪辑技巧,下面一起来试试吧. 需要哪些工具? 视频素材若干 怎么快速剪辑? 打开[媒体梦工厂], ...

  7. git clone 加速小技巧

    通过国内码云(或者其他代码平台)转存[比如码云就支持从github 拉取代码建仓库,码云自己转存又非常快],然后从国内平台地址clon,速度极快.

  8. abaqus如何并行计算_ABAQUS加速计算的小技巧

    本文结合查阅的资料(例如文末附上的参考文献[1].[2]),以及自己的实践经验,总结了一些ABAQUS计算中加快计算速度的小技巧,希望对初学者有所帮助. 1. 减少输出变量,增大输出步长 首先对输出的 ...

  9. python latex显示不出来_10 个加速Python数据分析的简单的小技巧

    一些小的技巧在编程领域可能会非常有用,在数据科学领域同样如此.数据科学爱好者 Parul Pandey 在近日发表了一篇博文,分享了在数据科学中非常实用的 10 个小技巧. 1.Profiling t ...

最新文章

  1. restful可以转发么_DRF使用超链接API实现真正RESTful
  2. 数据挖掘之关联分析三(规则的产生)
  3. CSMA/CD协议分析笔记
  4. 去除VScode中的黄色警告波浪线问题
  5. 有关国土的几个重大项目
  6. Linux内存管理之内存管理单元(MMU)(二)
  7. Spring boot Mybatis 整合(完整版)
  8. Welcome-to-Swift-05控制流(Control Flow )
  9. PHP判断浏览器类型和语言
  10. 拓端tecdat|R语言可视化探索BRFSS数据并逻辑回归Logistic回归预测中风
  11. 5个必考的大厂SQL面试题
  12. 微波雷达存在感应模组,智能微波感应开关,多普勒雷达原理应用
  13. ASP.NET Core使用微软官方类库实现汉字简繁切换以及转拼音
  14. java中intern_Java中的intern()方法是什么?
  15. 汉字读音表GB2312版 (共7809个汉字)
  16. 中级软件设计师刷题笔记
  17. 清华大学鲍橒计算机1999,《最强大脑》鲍橒:世界盲棋第一人的最强记忆
  18. matlab体会,Matlab心得体会
  19. Windows 10 ios download
  20. 科利转债上市价格预测

热门文章

  1. 电脑自带播放器怎么倍速播放视频
  2. Symfony2 ACLs
  3. 直流电机调速c语言源程序,直流电机调速源程序示例
  4. Android 集成Xposed框架
  5. 放置街灯(UVA 10859)
  6. 软考:头脑风暴与德尔菲法的区别(转)
  7. outlook从服务器中恢复已删除项目,Outlook 邮件误删,请问能否恢复?谢谢
  8. ESXI6.7安装补丁
  9. freemarer代码生成案例
  10. windows 介绍