<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Harper</title>
  
  <subtitle>Harper</subtitle>
  <link href="http://example.com/atom.xml" rel="self"/>
  
  <link href="http://example.com/"/>
  <updated>2024-05-11T11:54:20.649Z</updated>
  <id>http://example.com/</id>
  
  <author>
    <name>harper</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>BGV全同态加密</title>
    <link href="http://example.com/2024/05/11/BGV%E5%85%A8%E5%90%8C%E6%80%81%E5%8A%A0%E5%AF%86/"/>
    <id>http://example.com/2024/05/11/BGV%E5%85%A8%E5%90%8C%E6%80%81%E5%8A%A0%E5%AF%86/</id>
    <published>2024-05-11T11:02:40.000Z</published>
    <updated>2024-05-11T11:54:20.649Z</updated>
    
    <content type="html"><![CDATA[<h1 id="bgv全同态加密">BGV<strong>全同态加密</strong></h1><h2 id="方案描述">方案描述</h2><ul><li><p><strong>KeyGen</strong>(<spanclass="math inline">\(\lambda\)</span>)：根据预设的加密方案的安全性，选择一个安全参数<spanclass="math inline">\(\lambda\)</span>，安全参数的选择将影响密文模数<spanclass="math inline">\(q\)</span>和密文多项式的最高次数<spanclass="math inline">\(N\)</span>。在本文中，选择的参数满足128比特安全性。随机采样<spanclass="math inline">\(s \leftarrow \mathcal{R}_2\)</span>，<spanclass="math inline">\(a \leftarrow \mathcal{U}_{q_L}\)</span>和<spanclass="math inline">\(e \leftarrow\mathcal{X}\)</span>。之后，计算私钥<span class="math inline">\(sk =s\)</span>和公钥<span class="math inline">\(pk = (pk_1,pk_2) = ([-a\cdot s+te]_{q_L} , a)\)</span>。</p></li><li><p><strong>KeySwitchGen</strong>(<spanclass="math inline">\(sk\)</span>)：模交换能够让同态乘法的次数增加，而模交换需要依赖模交换密钥，首先随机采样多项式<spanclass="math inline">\(a \leftarrow \mathcal{U}_{q_L}\)</span>和<spanclass="math inline">\(e \leftarrow \mathcal{X}\)</span>。然后输出<spanclass="math inline">\(ks = (ks_1, ks_2) \equiv ([-a \cdot s + te + sk\cdot sk]_{q_L} , a)\)</span>作为模交换密钥。</p></li><li><p><strong>Enc</strong>(<spanclass="math inline">\(m,pk\)</span>)：给定输入消息<spanclass="math inline">\(m \in\mathcal{P}\)</span>，首先选择三个随机多项式：<spanclass="math inline">\(u \leftarrow \mathcal{R}_2\)</span>，<spanclass="math inline">\(e_1 \leftarrow \mathcal{X}\)</span>和<spanclass="math inline">\(e_2 \leftarrow\mathcal{X}\)</span>。然后加密器通过计算生成密文<spanclass="math inline">\(c\)</span>：<spanclass="math inline">\(c=(c_1,c_2)\equiv([pk_1 \cdotu+te_1+m]_{q_L},[pk_2 \cdot u+te_2]_{q_L}) \in\mathcal{C}\)</span>。</p></li><li><p><strong>Dec</strong>(<spanclass="math inline">\(c,sk\)</span>)：解密一个密文<spanclass="math inline">\(c\)</span>，需要在对应的模数链层次<spanclass="math inline">\(l\)</span>执行以下步骤：<spanclass="math inline">\(\mathrm{i)}\)</span> 计算<spanclass="math inline">\(m&#39; = [c_1 + c_2 \cdotsk]_{q_l}\)</span>，以及<spanclass="math inline">\(\mathrm{ii)}\)</span> 输出解密后的明文<spanclass="math inline">\(m = m&#39; \pmod{t}\)</span>。</p></li></ul><h2 id="计算模拟">计算模拟</h2><p>给出模拟代码</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">poly_mod_add</span>(<span class="hljs-params">poly1, poly2, mod</span>):<br>    <span class="hljs-string">&quot;&quot;&quot;多项式模环加法&quot;&quot;&quot;</span><br>    <span class="hljs-comment"># 确保 poly1 是较长的那个多项式</span><br>    <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(poly2) &gt; <span class="hljs-built_in">len</span>(poly1):<br>        poly1, poly2 = poly2, poly1<br>    <span class="hljs-comment"># 将较短的多项式补零</span><br>    poly2 += [<span class="hljs-number">0</span>] * (<span class="hljs-built_in">len</span>(poly1) - <span class="hljs-built_in">len</span>(poly2))<br>    <span class="hljs-comment"># 对应系数相加并取模</span><br>    result = [(a + b) % mod <span class="hljs-keyword">for</span> a, b <span class="hljs-keyword">in</span> <span class="hljs-built_in">zip</span>(poly1, poly2)]<br>    <span class="hljs-keyword">return</span> result<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">poly_mod_mult</span>(<span class="hljs-params">poly1, poly2, mod, N</span>):<br>    <span class="hljs-string">&quot;&quot;&quot;多项式模环乘法&quot;&quot;&quot;</span><br>    <span class="hljs-comment"># 初始化结果多项式</span><br>    result = [<span class="hljs-number">0</span>] * (<span class="hljs-built_in">len</span>(poly1) + <span class="hljs-built_in">len</span>(poly2) - <span class="hljs-number">1</span>)<br>    <span class="hljs-comment"># 对每个系数进行乘法和加法</span><br>    <span class="hljs-keyword">for</span> i, a <span class="hljs-keyword">in</span> <span class="hljs-built_in">enumerate</span>(poly1):<br>        <span class="hljs-keyword">for</span> j, b <span class="hljs-keyword">in</span> <span class="hljs-built_in">enumerate</span>(poly2):<br>            result[i + j] += a * b<br>            result[i + j] %= mod<br>    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(N):<br>        <span class="hljs-keyword">try</span>:<br>            result[i] = (result[i] - result[i+N]) % mod<br>        <span class="hljs-keyword">except</span>:<br>            <span class="hljs-keyword">break</span><br>    <span class="hljs-keyword">return</span> result[<span class="hljs-number">0</span>:N]<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">poly_mult_number</span>(<span class="hljs-params">poly, num,mod</span>):<br>    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-built_in">len</span>(poly)):<br>        poly[i] = (poly[i] * num) %mod<br>    <span class="hljs-keyword">return</span> poly<br><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">Gen_pk</span>(<span class="hljs-params">a,s,t,e,mod,N</span>):<br>    pk1 = poly_mod_mult(a,s,mod,N)<br>    pk1 = poly_mult_number(pk1,-<span class="hljs-number">1</span>,mod)<br>    pk1 = poly_mod_add(pk1,poly_mult_number(e,t,mod),mod)<br>    pk2 = a<br>    <span class="hljs-keyword">return</span> [pk1,pk2]<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">Enc</span>(<span class="hljs-params">pk,m,u,mod,N</span>):<br>    pk1 = pk[<span class="hljs-number">0</span>]<br>    pk2 = pk[<span class="hljs-number">1</span>]<br>    c1 = poly_mod_mult(pk1,u,mod,N)<br>    c1 = poly_mod_add(c1,m,mod)<br>    c1 = poly_mod_add(c1,poly_mult_number(e1,t,mod),mod)<br><br>    c2 = poly_mod_mult(pk2,u,mod,N)<br>    c2 = poly_mod_add(c2,poly_mult_number(e2,t,mod),mod)<br>    <span class="hljs-keyword">return</span> [c1,c2]<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">dec</span>(<span class="hljs-params">c,sk,mod,N,t</span>):<br>    temp = poly_mod_mult(c[<span class="hljs-number">1</span>],sk,mod,N)<br>    temp = poly_mod_add(c[<span class="hljs-number">0</span>],temp,mod)<br>    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-built_in">len</span>(temp)):<br>        temp[i] = temp[i] % t<br>    <span class="hljs-keyword">return</span> temp<br><span class="hljs-comment"># 示例使用</span><br>m = [-<span class="hljs-number">1</span>,<span class="hljs-number">2</span>]  <span class="hljs-comment"># 表示 2+x</span><br>a = [<span class="hljs-number">1</span>, <span class="hljs-number">1</span>]     <span class="hljs-comment"># 表示 1+x</span><br>s = [<span class="hljs-number">1</span>]<br>e = [<span class="hljs-number">2</span>,<span class="hljs-number">3</span>]<br>t = <span class="hljs-number">5</span><br>u = [<span class="hljs-number">0</span>,<span class="hljs-number">1</span>]<br>e1 = [<span class="hljs-number">3</span>,<span class="hljs-number">4</span>]<br>e2 = [<span class="hljs-number">5</span>,<span class="hljs-number">6</span>]<br>mod = <span class="hljs-number">133</span>            <span class="hljs-comment"># 模数</span><br>N = <span class="hljs-number">2</span><br><br><span class="hljs-comment"># # 计算多项式模环加法</span><br><span class="hljs-comment"># add_result = poly_mod_add(poly1, poly2, mod)</span><br><span class="hljs-comment"># print(&quot;多项式加法结果:&quot;, add_result)</span><br><span class="hljs-comment"># 计算多项式模环乘法</span><br><span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;原始明文:&quot;</span>,m)<br>pk = Gen_pk(a,s,t,e,mod,N)<br>sk = s<br><span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;公钥pk1:&quot;</span>, pk[<span class="hljs-number">0</span>])<br><span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;公钥pk2:&quot;</span>, pk[<span class="hljs-number">1</span>])<br>c = Enc(pk,m,u,mod,N)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;密文c1:&quot;</span>, c[<span class="hljs-number">0</span>])<br><span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;密文c2:&quot;</span>, c[<span class="hljs-number">1</span>])<br>result = dec(c,sk,mod,N,t)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;解密后的多项式&quot;</span>,result)<br></code></pre></td></tr></table></figure><h3 id="加密模拟">加密模拟</h3>]]></content>
    
    
    <summary type="html">最先进的全同态加密算法之一</summary>
    
    
    
    <category term="密码学" scheme="http://example.com/categories/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
    
    
    <category term="BGV" scheme="http://example.com/tags/BGV/"/>
    
  </entry>
  
  <entry>
    <title></title>
    <link href="http://example.com/2023/05/17/%E5%B8%B8%E7%94%A8python%E5%87%BD%E6%95%B0/"/>
    <id>http://example.com/2023/05/17/%E5%B8%B8%E7%94%A8python%E5%87%BD%E6%95%B0/</id>
    <published>2023-05-17T08:32:23.949Z</published>
    <updated>2023-05-17T12:10:49.484Z</updated>
    
    <content type="html"><![CDATA[<h1 id="常用python函数">常用python函数</h1><h2 id="sympy">sympy</h2><ul><li>sympy.mod_inverse(a,p)：模p下的逆元</li><li>sympy.totient(37)：输出某个数的Euler函数</li><li>sympy.gcd_list([4,6])：求最大公因数</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;常用python函数&quot;&gt;常用python函数&lt;/h1&gt;
&lt;h2 id=&quot;sympy&quot;&gt;sympy&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;sympy.mod_inverse(a,p)：模p下的逆元&lt;/li&gt;
&lt;li&gt;sympy.totient(37)：输出某个数的Eu</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title></title>
    <link href="http://example.com/2023/03/28/%E8%8D%89%E7%A8%BF/"/>
    <id>http://example.com/2023/03/28/%E8%8D%89%E7%A8%BF/</id>
    <published>2023-03-28T01:59:40.542Z</published>
    <updated>2023-06-15T13:02:11.893Z</updated>
    
    <content type="html"><![CDATA[<h1 id="同态加密算法bgv的优化">同态加密算法BGV的优化</h1><h2 id="基础知识">基础知识</h2><h3 id="单位根与分圆多项式">单位根与分圆多项式</h3><ul><li><p>有一个域<span class="math inline">\(F\)</span>,元素<spanclass="math inline">\(\omega \in F\)</span>如果满足<spanclass="math inline">\(\omega^m \equiv1\)</span>,那么w是m次单位根，如果找不到一个比<spanclass="math inline">\(m\)</span>更小的数<spanclass="math inline">\(m’\)</span>，使得<spanclass="math inline">\(\omega^{m&#39;} \equiv1\)</span>是F中最小次数的根，那么<spanclass="math inline">\(\omega\)</span>称为m次单位原根。</p></li><li><p>如果<spanclass="math inline">\(\omega\)</span>是m次原单位根，那么有如下两条性质</p><ul><li>性质1：对于唯一的一个<span class="math inline">\(j \in\mathbb{Z}_m\)</span>每一个m次单位根都能被写为<spanclass="math inline">\(\omega^j\)</span>，这是因为<spanclass="math inline">\(\omega^{jm} \equiv1\)</span>，所以也是m次单位根。</li><li>性质2：对于唯一的一个<span class="math inline">\(j \in\mathbb{Z}^*_m\)</span>，每一个m次单位原根都能被写为<spanclass="math inline">\(\omega^j\)</span>。这是因为<spanclass="math inline">\(\omega^j\)</span>是m次单位根，其次找不到比m还小的值使得<spanclass="math inline">\(\omega^{jm} \equiv1\)</span>成立（假设d|m，那么<span class="math inline">\(\omega^{d} \neq1\)</span>从而<span class="math inline">\(\omega^{jd} \neq1\)</span>，因为j和d互素，jd必不可能是m的倍数）。</li></ul></li><li><p>假设<span class="math inline">\(\omega = e^{2\pii/m}\)</span>是复数域的m次根，定义分圆多项式： <spanclass="math display">\[\Phi_m(X):=\prod\limits_{j\in\mathbb{Z}_m^*}(X-\omega^j)\in\mathbb{C}[X].\]</span> 有如下性质:</p><ul><li>分圆多项式有多项式次数<spanclass="math inline">\(\phi(m)\)</span>，j的个数是与m互素的个数</li><li><span class="math inline">\(\Phi_m(X)\in\mathbb{Z}[X]\)</span></li><li>分圆多项式在有理数域上不可约</li><li><spanclass="math inline">\(X^m-1=\prod\limits_{d|m}\Phi_d(X)\)</span>以及他的变式<spanclass="math inline">\(\Phi_m(X)=\dfrac{X^m-1}{\prod\limits_{d\midm}\Phi_d(X)}\)</span>。显然，如果m是个素数p，那么<spanclass="math inline">\(\Phi_{p}(x)=\frac{x^{p}-1}{x-1}=\sum^{p-1}_{i=0}{x^i}\)</span></li></ul></li></ul><h3 id="规范嵌入和无穷范数">规范嵌入和无穷范数</h3><p><strong>基本思想</strong>：定义<spanclass="math inline">\(\mathcal{A}:=\mathbb{Z}[X]/(\Phi_m(X))\)</span>，<spanclass="math inline">\(\omega\)</span>是一个m次单位原根，有一个多项式<spanclass="math inline">\(a=[f(X)\text{mod}\Phi_m(X)]\in\mathcal{A}\)</span>，我们可以清晰的定义<spanclass="math inline">\(\boldsymbol{a}(\omega^j):=f(\omega^j)\)</span>，而不用在乎<spanclass="math inline">\(f(X)\)</span>的具体取值(因为模了一个分圆多项式)。</p><ul><li>规范嵌入：多项式<spanclass="math inline">\(a\in\mathcal{A}\)</span>的规范嵌入是一个向量</li></ul><p><span class="math display">\[\operatorname{cannon}(\boldsymbol a):=\Big(\boldsymbola(\omega^j)\Big)_{j\in\mathbb Z_m^*}.\]</span></p><ul><li>无穷范数：使用常见的无穷范数作为多项式<span class="math inline">\(a\in\mathcal{A}\)</span>的大小（size），取规范嵌入后向量元素的最大值即可</li></ul><p><span class="math display">\[\quad\|\boldsymbol a\|:=\|\mathrm{cannon}(\boldsymbol a)\|_\infty =\max\{|\boldsymbol a(\omega^j)|:j\in\mathbb Z^*_m\},\]</span></p><h3 id="编码拉格朗日插值">编码——拉格朗日插值</h3><blockquote><p><strong>目前的困境：</strong>BGV的明文为一个<spanclass="math inline">\(N-1\)</span>次多项式m(x)，我们如何把<spanclass="math inline">\(N\)</span>个数值<spanclass="math inline">\((a_0,a_1,\dots,a_{N-1})\)</span>编码进一个明文多项式<spanclass="math inline">\(m_1(x)\)</span>，另外N个数值<spanclass="math inline">\((b_0,b_1,\dots,b_{N-1})\)</span>编码进多项式<spanclass="math inline">\(m_2(x)\)</span>。使得当明文多项式做多项式乘法后<spanclass="math inline">\(m(x) = m_1(x)*m_2(x)\)</span>，解码<spanclass="math inline">\(m(x)\)</span>得到的是对应数值的点乘形式<spanclass="math inline">\((a_0*b_0,a_1*b_1,\dots,a_{N-1}*b_{N-1})\)</span></p></blockquote><p><strong>先介绍一下拉格朗日插值：</strong></p><p>假设我们有一些已知点 <span class="math inline">\((x_i,y_i)\)</span>，我们想要找到一个函数 <spanclass="math inline">\(f(x)\)</span>，它在这些点上与 <spanclass="math inline">\(y_i\)</span>相等，同时在这些点之间光滑连续。拉格朗日插值的想法是使用一个多项式来近似这个函数，多项式的系数可以通过在这些点上求解一系列的线性方程来获得。</p><p>下面是一个使用拉格朗日插值计算多项式的示例。假设我们有三个点 <spanclass="math inline">\((0, 1)\)</span>，<span class="math inline">\((1,2)\)</span> 和 <span class="math inline">\((2,3)\)</span>。我们可以使用一个二次多项式来近似这些点，形式为 <spanclass="math inline">\(f(x) = a + bx +cx^2\)</span>。我们可以通过求解以下三个方程来确定多项式的系数： <spanclass="math display">\[\begin{matrix}f(0)=a+0b+0c=1\\ f(1)=a+1b+1c=2\\f(2)=a+2b+4c=3\end{matrix}\]</span></p><p>通过求解这些方程，我们可以得到多项式的系数 <spanclass="math inline">\(a = 1\)</span>，<span class="math inline">\(b =1\)</span> 和 <span class="math inline">\(c =-\frac{1}{2}\)</span>。因此，我们的多项式为 <spanclass="math inline">\(f(x) = 1 + x - \frac{1}{2}x^2\)</span>。</p><p>现在，我们可以将上述思想扩展到任意数量的点。具体来说，我们要使用一个<span class="math inline">\(n-1\)</span> 次多项式来拟合 <spanclass="math inline">\(n\)</span> 个已知点。设 <spanclass="math inline">\((x_i, y_i)\)</span> 是这些已知点中的第 <spanclass="math inline">\(i\)</span> 个点，我们的多项式可以写成以下形式：<span class="math display">\[f(x)=\sum_{i=1}^ny_iL_i(x)\quad\text{}\]</span></p><p>其中 <span class="math inline">\(L_i(x)\)</span>是拉格朗日基函数，定义为： <span class="math display">\[L_i(x)=\prod_{j=1,j\neq i}^n\frac{x-x_j}{x_i-x_j}\]</span></p><p>这个基函数的作用是将多项式 <span class="math inline">\(f(x)\)</span>在 <span class="math inline">\(x_i\)</span> 处变为 <spanclass="math inline">\(y_i\)</span>，同时在其他点处为零。因此，我们可以将多项式表示为所有基函数的线性组合。</p><p><strong>解决方案：</strong></p><p>假设多项式是在模<spanclass="math inline">\(q\)</span>意义下进行的，我们预计算出一个<spanclass="math inline">\(N\)</span>次原根<spanclass="math inline">\(\omega\)</span>满足<spanclass="math inline">\(\omega^N \equiv 1 \mod{q}\)</span>，我们选取N个点<span class="math display">\[(\omega^0,a_0),(\omega^1,a_1),\dots,(\omega^{N-1},a_{N-1})\]</span> 使用拉格朗日插值确定一个多项式<spanclass="math inline">\(m_1(x)\)</span>，同理对另外N个点 <spanclass="math display">\[(\omega^0,b_0),(\omega^1,b_1),\dots,(\omega^{N-1},b_{N-1})\]</span> 确定另一个多项式<spanclass="math inline">\(m_2(x)\)</span>，这样多项式乘法<spanclass="math inline">\(m(x) =m_1(x)*m_2(x)\)</span>后，代入N个横坐标值<spanclass="math inline">\((\omega^0,\dots,\omega^{N-1})\)</span>之后得到的纵坐标即为对应位数的点乘<spanclass="math inline">\((a_0*b_0,a_1*b_1,\dots,a_{N-1}*b_{N-1})\)</span></p><p><strong>注意：</strong></p><ul><li>为什么要选取<span class="math inline">\(N\)</span>次原根<spanclass="math inline">\(\omega\)</span> ?因为有良好的性质，即<spanclass="math inline">\((\omega^0,\dots,\omega^{N-1})\)</span>在模q意义下每个数都各不相同（如果相同那么<spanclass="math inline">\(\omega\)</span>不是<spanclass="math inline">\(N\)</span>次原根）</li><li>如何找<span class="math inline">\(N\)</span>次原根<spanclass="math inline">\(\omega\)</span>?首先找到一个模q的原根g，然后使用快速幂运算去计算<spanclass="math inline">\(g^{(q-1)/N}\)</span>即可得到<spanclass="math inline">\(\omega\)</span></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;同态加密算法bgv的优化&quot;&gt;同态加密算法BGV的优化&lt;/h1&gt;
&lt;h2 id=&quot;基础知识&quot;&gt;基础知识&lt;/h2&gt;
&lt;h3 id=&quot;单位根与分圆多项式&quot;&gt;单位根与分圆多项式&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;有一个域&lt;span class=&quot;math inli</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title></title>
    <link href="http://example.com/2023/03/09/seal%E5%BA%93%E4%BD%BF%E7%94%A8/"/>
    <id>http://example.com/2023/03/09/seal%E5%BA%93%E4%BD%BF%E7%94%A8/</id>
    <published>2023-03-09T07:08:17.128Z</published>
    <updated>2023-03-09T07:54:21.174Z</updated>
    
    <content type="html"><![CDATA[<h1 id="seal库bgv同态加密解析">seal库BGV同态加密解析</h1><h2 id="seal库参数设置">seal库参数设置</h2><p>先看seal库源码</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-type">const</span> map&lt;<span class="hljs-type">size_t</span>, vector&lt;Modulus&gt;&gt; &amp;<span class="hljs-built_in">GetDefaultCoeffModulus128</span>()<br>            &#123;<br>                <span class="hljs-type">static</span> <span class="hljs-type">const</span> map&lt;<span class="hljs-type">size_t</span>, vector&lt;Modulus&gt;&gt; default_coeff_modulus_128&#123;<br>                    <span class="hljs-comment">/*</span><br><span class="hljs-comment">                    Polynomial modulus: 1x^1024 + 1</span><br><span class="hljs-comment">                    Modulus count: 1</span><br><span class="hljs-comment">                    Total bit count: 27</span><br><span class="hljs-comment">                    */</span><br>                    &#123; <span class="hljs-number">1024</span>, &#123; <span class="hljs-number">0x7e00001</span> &#125; &#125;,<br><br>                    <span class="hljs-comment">/*</span><br><span class="hljs-comment">                    Polynomial modulus: 1x^2048 + 1</span><br><span class="hljs-comment">                    Modulus count: 1</span><br><span class="hljs-comment">                    Total bit count: 54</span><br><span class="hljs-comment">                    */</span><br>                    &#123; <span class="hljs-number">2048</span>, &#123; <span class="hljs-number">0x3fffffff000001</span> &#125; &#125;,<br><br>                    <span class="hljs-comment">/*</span><br><span class="hljs-comment">                    Polynomial modulus: 1x^4096 + 1</span><br><span class="hljs-comment">                    Modulus count: 3</span><br><span class="hljs-comment">                    Total bit count: 109 = 2 * 36 + 37</span><br><span class="hljs-comment">                    */</span><br>                    &#123; <span class="hljs-number">4096</span>, &#123; <span class="hljs-number">0xffffee001</span>, <span class="hljs-number">0xffffc4001</span>, <span class="hljs-number">0x1ffffe0001</span> &#125; &#125;,<br><br>                    <span class="hljs-comment">/*</span><br><span class="hljs-comment">                    Polynomial modulus: 1x^8192 + 1</span><br><span class="hljs-comment">                    Modulus count: 5</span><br><span class="hljs-comment">                    Total bit count: 218 = 2 * 43 + 3 * 44</span><br><span class="hljs-comment">                    */</span><br>                    &#123; <span class="hljs-number">8192</span>, &#123; <span class="hljs-number">0x7fffffd8001</span>, <span class="hljs-number">0x7fffffc8001</span>, <span class="hljs-number">0xfffffffc001</span>,                               <span class="hljs-number">0xffffff6c001</span>, <span class="hljs-number">0xfffffebc001</span> &#125; &#125;,<br><br>                    <span class="hljs-comment">/*</span><br><span class="hljs-comment">                    Polynomial modulus: 1x^16384 + 1</span><br><span class="hljs-comment">                    Modulus count: 9</span><br><span class="hljs-comment">                    Total bit count: 438 = 3 * 48 + 6 * 49</span><br><span class="hljs-comment">                    */</span><br>                    &#123; <span class="hljs-number">16384</span>,<br>                      &#123; <span class="hljs-number">0xfffffffd8001</span>, <span class="hljs-number">0xfffffffa0001</span>, <span class="hljs-number">0xfffffff00001</span>, <span class="hljs-number">0x1fffffff68001</span>, <span class="hljs-number">0x1fffffff50001</span>,<br>                        <span class="hljs-number">0x1ffffffee8001</span>, <span class="hljs-number">0x1ffffffea0001</span>, <span class="hljs-number">0x1ffffffe88001</span>, <span class="hljs-number">0x1ffffffe48001</span> &#125; &#125;,<br><br>                    <span class="hljs-comment">/*</span><br><span class="hljs-comment">                    Polynomial modulus: 1x^32768 + 1</span><br><span class="hljs-comment">                    Modulus count: 16</span><br><span class="hljs-comment">                    Total bit count: 881 = 15 * 55 + 56</span><br><span class="hljs-comment">                    */</span><br>                    &#123; <span class="hljs-number">32768</span>,<br>                      &#123; <span class="hljs-number">0x7fffffffe90001</span>, <span class="hljs-number">0x7fffffffbf0001</span>, <span class="hljs-number">0x7fffffffbd0001</span>, <span class="hljs-number">0x7fffffffba0001</span>, <span class="hljs-number">0x7fffffffaa0001</span>,<br>                        <span class="hljs-number">0x7fffffffa50001</span>, <span class="hljs-number">0x7fffffff9f0001</span>, <span class="hljs-number">0x7fffffff7e0001</span>, <span class="hljs-number">0x7fffffff770001</span>, <span class="hljs-number">0x7fffffff380001</span>,<br>                        <span class="hljs-number">0x7fffffff330001</span>, <span class="hljs-number">0x7fffffff2d0001</span>, <span class="hljs-number">0x7fffffff170001</span>, <span class="hljs-number">0x7fffffff150001</span>, <span class="hljs-number">0x7ffffffef00001</span>,<br>                        <span class="hljs-number">0xfffffffff70001</span> &#125; &#125;<br>                &#125;;<br><br>                <span class="hljs-keyword">return</span> default_coeff_modulus_128;<br>            &#125;<br><br></code></pre></td></tr></table></figure><p>这是BGV的128bit安全性参数设置，随着模多项式的次数<spanclass="math inline">\(n\)</span>不同，对应的密文模数的大小<spanclass="math inline">\(log(q)\)</span>也有调整，具体的公式可以按照下面的方法计算：<span class="math display">\[\lambda \approx -log(\cfrac{A*log(q)}{n})\cfrac{Bn}{logq} +C\sqrt{\cfrac{logq}{n}}log(\cfrac{n}{log(q)})\]</span> <imgsrc="C:\Users\24546\AppData\Roaming\Typora\typora-user-images\image-20230309155417529.png"alt="image-20230309155417529" /></p><h2 id="bgv噪声变化">BGV噪声变化</h2>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;seal库bgv同态加密解析&quot;&gt;seal库BGV同态加密解析&lt;/h1&gt;
&lt;h2 id=&quot;seal库参数设置&quot;&gt;seal库参数设置&lt;/h2&gt;
&lt;p&gt;先看seal库源码&lt;/p&gt;
&lt;figure class=&quot;highlight c++&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>NTT的实现及其加速</title>
    <link href="http://example.com/2022/12/14/NTT%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%8F%8A%E5%85%B6%E5%8A%A0%E9%80%9F/"/>
    <id>http://example.com/2022/12/14/NTT%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%8F%8A%E5%85%B6%E5%8A%A0%E9%80%9F/</id>
    <published>2022-12-14T03:31:21.000Z</published>
    <updated>2023-04-20T08:08:33.106Z</updated>
    
    <content type="html"><![CDATA[<h1 id="ntt的实现及其加速">NTT的实现及其加速</h1><h2 id="ntt快速数论变换原理">NTT快速数论变换原理</h2><h3 id="多项式相乘的困难">多项式相乘的困难</h3><p>假设有多项式A(x)，一共有n项,最高次项为<spanclass="math inline">\(x^{n-1}\)</span>,设其系数为<spanclass="math inline">\(a =(a[0],a[1],\cdots,a[n-1])\)</span>，类似的假设另一个多项式B(x),设其系数为<spanclass="math inline">\(b =(b[0],b[1],\cdots,b[n-1])\)</span>，如果想要将两个多项式相乘，很明显一共要乘<spanclass="math inline">\(n^2\)</span>次，能不能减少乘法的次数，使其复杂度比<spanclass="math inline">\(O(n^2)\)</span>更少呢？</p><h3id="基于fft快速傅里叶变换的多项式相乘">基于FFT(快速傅里叶变换)的多项式相乘</h3><p>把<spanclass="math inline">\(x=x_0\)</span>代入A(x)可以得到多项式在点x0处的值，类似的，我们代入n个这样的点$(x_0,x_1,,x_{n-1})<spanclass="math inline">\(,可以得到n个多项式取值\)</span>(A(x_0),A(x_1),,A(x_{n-1}))$，可以证明，仅通过这n个多项式取值，我们可以还原出原本的多项式。</p><blockquote><p>证明：</p><p>假设还原出的多项式不唯一，分别设为f(x)和g(x)，这个两个多项式的最高次为n-1,否则还原失败</p><p>令h(x) = f(x)-g(x) ，这个多项式的最高次至少为n-1</p><p>那么代入$(x_0,x_1,,x_{n-1})$个点，h(x)均等于0，即这个多项式有n个解</p><p>而即使在复数域上n-1次方程也至多有n-1个解，矛盾</p><p>故只能还原出唯一的一个多项式</p></blockquote><p>类似的，代入多项式B(x)得到$(B(x_0),B(x_1),,B(x_{n-1}))$，我们在进行下面的点乘操作得到 <spanclass="math display">\[(A(x_0)*B(x_0),A(x_1)*B(x_1),\cdots,A(x_{n-1})*B(x_{n-1}))\]</span>这是一个n维向量，按照这个向量还原多项式，我们就可以得到两个多项式的乘积<span class="math display">\[C(x) = A(x)*B(X)\]</span>注意这里的乘法为多项式乘法，这样多项式相乘就巧妙的转化为点乘，复杂度只有O(n)</p><p>但有个疑问，把点代入多项式计算不是也有计算量吗？这个算法快就是因为，我们可以设置点$(x_0,x_1,,x_{n-1})$，这些点经过精心设置，可以在计算例如A(x0)的时候很快。</p><h3 id="基于ct蝴蝶变换的ntt算法">基于CT蝴蝶变换的NTT算法</h3><p>注意这里的参数需要满足一些条件</p><ul><li><p><span class="math inline">\(q \equiv 1 \mod{2n}\)</span></p></li><li><p><span class="math inline">\(n = 2^k,k\in Z_+\)</span></p></li><li><p><spanclass="math inline">\(\psi\)</span>为模数q的2N次单位根，即满足<spanclass="math inline">\(\psi^{2n} \equiv 1 \mod{q}\)</span></p></li><li><p>数组$= (1,<sup>1,</sup>2,,^{n-1}) $</p></li><li><p>数组<span class="math inline">\(\psi_{rev}\)</span>是把数组<spanclass="math inline">\(\phi\)</span>按照bit-reversed顺序重新排列出来的，见下面的例子(多项式次数n= 8)</p><blockquote><p>X(0) = X(0,0,0) --&gt; X(0,0,0) = X(0)</p><p>X(1) = X(0,0,1) --&gt; X(1,0,0) = X(4)</p><p>X(2) = X(0,1,0) --&gt; X(0,1,0) = X(2)</p><p>X(3) = X(0,1,1) --&gt; X(1,1,0) = X(6)</p><p>以此类推</p></blockquote></li></ul><p>下面是蝴蝶变换算法</p><figure><imgsrc="C:\Users\24546\AppData\Roaming\Typora\typora-user-images\image-20221215122722792.png"alt="image-20221215122722792" /><figcaption aria-hidden="true">image-20221215122722792</figcaption></figure><h3 id="基于gs蝴蝶变换的ntt逆变换">基于GS蝴蝶变换的NTT逆变换</h3><figure><imgsrc="C:\Users\24546\AppData\Roaming\Typora\typora-user-images\image-20221215122822035.png"alt="image-20221215122822035" /><figcaption aria-hidden="true">image-20221215122822035</figcaption></figure><h3 id="ntt的一些性质">NTT的一些性质</h3><p>假设"$<spanclass="math inline">\(&quot;代表多项式乘法，&quot;\)</span>$"代表分量乘法</p><ul><li>NTT(a) + NTT(b) = NTT(a+b)</li><li>NTT(INTT(a)<span class="math inline">\(\cdot\)</span> INTT(b)) = a$$b</li><li></li></ul><h2 id="barrett-reduction-乘法取模加速">Barrett Reduction乘法取模加速</h2><h3 id="参考博客">参考博客</h3><ul><li><ahref="https://blog.csdn.net/YKRY35/article/details/79179285">(37条消息)大数取模运算Barrett reduction_YKRY35的博客-CSDN博客_大数取模</a></li><li><ahref="https://www.luogu.com.cn/blog/Sweetlemon/barrett-reduction">BarrettReduction 乘法取模加速 - Sweetlemon 的博客 - 洛谷博客(luogu.com.cn)</a></li></ul><p>Barrettreduction是一种求模运算的优化方法，它可以将求模运算的时间复杂度从O(n)降低到O(logn)。</p><h3 id="原理简述">原理简述</h3><p>一般来说，32位整数加法操作比乘法操作快得多，大概快3到8倍。而移位操作又比加法操作快10倍以上，核心思想就是把除法尽可能迁移到移位操作上。</p><p>我们（人工）计算取模，用的是 <span class="math display">\[r= a\bmod p=a-\left\lfloor \dfrac{a}{p} \right\rfloor *p\]</span></p><p>这个计算中有除法，在计算机组成原理中，两个32bit的数相除需要32次移位和32次加减法操作，开销比较大。</p><p>而两个32bit的数相乘只需要32次移位操作。我们希望能用乘法替换除法，计算出<span class="math display">\[q=\left\lfloor \dfrac{a}{p} \right\rfloor\]</span> 我们可以钦定一个整数 k，再弄出一个整数 m，使得 <spanclass="math display">\[\dfrac{m}{2^k}\approx\dfrac{1}{p}\]</span> 那么 q不就约等于$$了吗？这样除法运算就被拆成了一次乘法和k次位移，速度大大加快。</p><p>为了防止算出的商超过实际的商，我们一般取 <spanclass="math display">\[m=\left\lfloor \dfrac{2^k}{p} \right\rfloor\]</span> 这里，我们取 <span class="math display">\[k\ge \lceil 2\log_2 p \rceil\\]</span> 也就是使得$ 2<sup>kp</sup>2$。下面我们证明，这样取 k时，<spanclass="math inline">\(0\lea-pq&lt;p\)</span>，也就是我们稍后在计算余数<spanclass="math inline">\(a-pq\)</span>时，得到的答案<del>至多需要再做一次减法</del> 不需要再调整。</p><blockquote><p>下面是这样设置参数的合理性证明，证明<span class="math inline">\(0\lea-pq&lt;p\)</span>：</p><p>由于 <span class="math inline">\(q=\dfrac{am}{2^k}\)</span></p><p>因此 <spanclass="math inline">\(pq=\dfrac{apm}{2^k}，a-pq=\dfrac{a}{2^k}\cdot(2^k-pm)\)</span></p><p>第一点，由于<span class="math inline">\(2^k\approxp^2\)</span>，而a是模p意义下两个数的乘积，所以<spanclass="math inline">\(a&lt;p^2\)</span></p><p>于是有<spanclass="math inline">\(0&lt;\dfrac{a}{2^k}&lt;1\)</span></p><p>第二点，由于<span class="math inline">\(m=\left\lfloor \dfrac{2^k}{p}\right\rfloor\)</span></p><p>所以有$ -1 &lt; m $，进一步推出<spanclass="math inline">\(0\leq(2^k-pm)&lt;p\)</span></p><p>综上可以证明<span class="math inline">\(0\le a-pq&lt;p\)</span></p></blockquote><p>总结这个算法的流程如下：</p><ul><li>根据 p<em>p</em> 的规模选取合适的 k，一般要求 <spanclass="math inline">\(k\ge \lceil 2\log_2 p \rceil\)</span>。</li><li>根据 k,p 预处理出 <span class="math inline">\(m=\left\lfloor\dfrac{2^k}{p} \right\rfloor\)</span>。</li><li>实际计算时，用 <span class="math inline">\(q=\dfrac{a\cdotm}{2^k}\)</span>计算出商，再用$ r=a-pq$ 得出余数</li></ul><h3 id="c例子">c++例子</h3><p>下面是一个例子：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">RingMultiplier::mulModBarrett</span><span class="hljs-params">(<span class="hljs-type">uint64_t</span>&amp; r, <span class="hljs-type">uint64_t</span> a, <span class="hljs-type">uint64_t</span> b, <span class="hljs-type">uint64_t</span> p, <span class="hljs-type">uint64_t</span> pr)</span> </span><br><span class="hljs-function"></span>&#123;<br><span class="hljs-type">unsigned</span> __int128 mul = <span class="hljs-built_in">static_cast</span>&lt;<span class="hljs-type">unsigned</span> __int128&gt;(a) * b;<br><span class="hljs-type">uint64_t</span> abot = <span class="hljs-built_in">static_cast</span>&lt;<span class="hljs-type">uint64_t</span>&gt;(mul);<span class="hljs-comment">//只会返回a*b的低64位</span><br><span class="hljs-type">uint64_t</span> atop = <span class="hljs-built_in">static_cast</span>&lt;<span class="hljs-type">uint64_t</span>&gt;(mul &gt;&gt; <span class="hljs-number">64</span>);<span class="hljs-comment">//得到a*b的高64位</span><br><span class="hljs-type">unsigned</span> __int128 tmp = <span class="hljs-built_in">static_cast</span>&lt;<span class="hljs-type">unsigned</span> __int128&gt;(abot) * pr;<br>tmp &gt;&gt;= <span class="hljs-number">64</span>;<br>tmp += <span class="hljs-built_in">static_cast</span>&lt;<span class="hljs-type">unsigned</span> __int128&gt;(atop) * pr;<br>tmp &gt;&gt;= kbar2 - <span class="hljs-number">64</span>;<br>tmp *= p;<br>tmp = mul - tmp;<br>r = <span class="hljs-built_in">static_cast</span>&lt;<span class="hljs-type">uint64_t</span>&gt;(tmp);<br><span class="hljs-keyword">if</span>(r &gt;= p) r -= p;<br>&#125;<br></code></pre></td></tr></table></figure><p>这个函数主要用来计算r=(a*b) modp的结果，采用Barrett乘法算法，其中<spanclass="math inline">\(pr=2^{kbar2} /p\)</span>，kbar2是一个预设的常量，模数p的大约满足<spanclass="math inline">\(log_2p = 60\)</span>，所以这里的kbar2 =120,于是有<span class="math inline">\(pr \approx p\)</span>。</p><p>算法原理： <span class="math display">\[r = mul - \left\lfloor \dfrac{mul}{p}\right\rfloor*p \\=mul - mul*\dfrac{pr}{2^k}*p \quad where \quad r=2^k \quad and \quad pr= \dfrac{2^k}{p}\\这里把mul*pr/2^k变成如下操作,其中abot存放mul的低64位，atop存放高64位\\[(abot*pr)&gt;&gt;64+atop*pr]&gt;&gt;(kbar2-64) \\=[(abot*pr)+atop*pr*2^{64}]/(2^{kbar2})\\这样可以完成barrett的快速求余操作\]</span> 算法步骤：</p><ul><li>1）先把a*b的结果存到mul变量中，abot存放mul的低64位，atop存放高64位；</li><li>2）然后把abot乘以预设的pr，得到tmp，并右移64位；</li><li>3）再把atop乘以pr，再加到tmp上；</li><li>4）把tmp右移kbar2-64位，再乘以p；</li><li>5）最后求出mul-tmp，得到r；</li><li>6）最后判断r是否大于p，如果大于，则减去p，得到最终结果。</li></ul>]]></content>
    
    
    <summary type="html">难道需要我等你一辈子嘛？</summary>
    
    
    
    <category term="密码学" scheme="http://example.com/categories/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
    
    
    <category term="NTT" scheme="http://example.com/tags/NTT/"/>
    
  </entry>
  
  <entry>
    <title>sm2椭圆曲线公钥密码算法</title>
    <link href="http://example.com/2022/12/05/sm2%E6%A4%AD%E5%9C%86%E6%9B%B2%E7%BA%BF%E5%85%AC%E9%92%A5%E5%AF%86%E7%A0%81%E7%AE%97%E6%B3%95/"/>
    <id>http://example.com/2022/12/05/sm2%E6%A4%AD%E5%9C%86%E6%9B%B2%E7%BA%BF%E5%85%AC%E9%92%A5%E5%AF%86%E7%A0%81%E7%AE%97%E6%B3%95/</id>
    <published>2022-12-05T04:39:52.000Z</published>
    <updated>2023-05-17T15:31:52.010Z</updated>
    
    <content type="html"><![CDATA[<h1 id="sm2椭圆曲线公钥密码算法">sm2椭圆曲线公钥密码算法</h1><h2 id="背景">背景</h2><h3 id="国密算法介绍">国密算法介绍</h3><p>国密即国家密码局认定的国产密码算法。主要有SM1，SM2，SM3，SM4。<ahref="https://so.csdn.net/so/search?q=密钥&amp;spm=1001.2101.3001.7020">密钥</a>长度和分组长度均为128位。</p><ul><li><p>SM1为对称加密。其加密强度与AES相当。该算法不公开，调用该算法时，需要通过加密芯片的接口进行调用。</p></li><li><p>SM2为非对称加密，基于ECC。该算法已公开。由于该算法基于ECC，故其签名速度与秘钥生成速度都快于RSA。ECC256位（SM2采用的就是ECC 256位的一种）安全强度比RSA2048位高，但运算速度快于RSA。</p></li><li><p>SM3消息摘要。可以用MD5作为对比理解。该算法已公开。校验结果为256位。</p></li><li><p>SM4无线局域网标准的分组数据算法。对称加密，密钥长度和分组长度均为128位。</p></li></ul><p>由于SM1、SM4加解密的分组大小为128bit，故对消息进行加解密时，若消息长度过长，需要进行分组，要消息长度不足，则要进行填充。</p><h3 id="sm2算法简介">SM2算法简介</h3><p>SM2椭圆曲线公钥密码算法是我国自主设计的公钥密码算法，包括SM2-1椭圆曲线数字签名算法，SM2-2椭圆曲线密钥交换协议，SM2-3椭圆曲线公钥加密算法，分别用于实现数字签名密钥协商和数据加密等功能。SM2算法与RSA算法不同的是，SM2算法是基于椭圆曲线上点群离散对数难题，相对于RSA算法，256位的SM2密码强度已经比2048位的RSA密码强度要高。</p><p>sm2主要满足电子认证服务系统等应用需求。</p><h2 id="椭圆曲线介绍">椭圆曲线介绍</h2><ul><li><ahref="https://link.springer.com/content/pdf/10.1007/978-1-4939-1711-2.pdf">参考书籍</a></li></ul><h3 id="基本数学形式">基本数学形式</h3><p>椭圆曲线是下面方程的一组解： <span class="math display">\[Y^2 = X^3 + AX + B\]</span>这种类型的方程也被称为魏尔斯特拉斯方程，得名于19世纪对其进行广泛研究的数学家。下面给两个曲线的实例并画给出图片：<span class="math display">\[E1 : Y^2 = X^3 − 3X + 3 \;and\; E2 : Y ^2 = X^3 − 6X + 5\]</span> <img src="/2022/12/05/sm2%E6%A4%AD%E5%9C%86%E6%9B%B2%E7%BA%BF%E5%85%AC%E9%92%A5%E5%AF%86%E7%A0%81%E7%AE%97%E6%B3%95/%E6%A4%AD%E5%9C%86%E6%9B%B2%E7%BA%BF%E6%A0%B7%E4%BE%8B.png" class="椭圆曲线图"></p><figure><imgsrc="C:\Users\24546\AppData\Roaming\Typora\typora-user-images\image-20221205130657777.png"alt="1" /><figcaption aria-hidden="true">1</figcaption></figure><h3 id="实数域上椭圆曲线">实数域上椭圆曲线</h3><h4 id="加法运算">加法运算</h4><p>令E为如下椭圆曲线： <span class="math display">\[Y ^2 = X^3 − 15X + 18.\]</span> 点P = (7, 16) 和 Q = (1, 2)为椭圆曲线上的两点，并构成直线L:<span class="math display">\[L : Y = \frac{7}{3}X − 1/3.\]</span> 如下图所示，直线L和椭圆曲线E交于三个点P,Q,R</p><img src="/2022/12/05/sm2%E6%A4%AD%E5%9C%86%E6%9B%B2%E7%BA%BF%E5%85%AC%E9%92%A5%E5%AF%86%E7%A0%81%E7%AE%97%E6%B3%95/%E6%A4%AD%E5%9C%86%E6%9B%B2%E7%BA%BF%E4%BA%A4%E7%82%B9%E5%9B%BE.png" class="椭圆曲线交点图"><figure><imgsrc="C:\Users\24546\AppData\Roaming\Typora\typora-user-images\image-20221205131119418.png"alt="image-20221205131119418" /><figcaption aria-hidden="true">image-20221205131119418</figcaption></figure><p>点R关于x轴对称得到R',我们定义椭圆曲线d上的加法运算, <spanclass="math display">\[P \oplus Q = R&#39;,\]</span>和我们通常理解的加法不同，这里的加法是在曲线上进行的，也就是说给出两个点，相加一定可以得到椭圆曲线上的第三个点R'，这个点就是加法的结果。</p><h4 id="加法运算瓶颈无穷远点o">加法运算瓶颈——无穷远点O</h4><p>还是按照上面的图片，我们尝试做这样的加法 <spanclass="math display">\[R \oplus R&#39;=?\]</span>按照上一节的加法运算，直线RR‘应该和椭圆曲线交于三个点，但是这里没有第三个点，这时候该怎么办？数学家定义了一个无穷远点<spanclass="math inline">\(O\)</span>,并假设点<spanclass="math inline">\(O\)</span>也在椭圆曲线上，这样RR'就能交于椭圆曲线的点<spanclass="math inline">\(O\)</span>了,于是有 <span class="math display">\[R \oplus R&#39;=O.\]</span> 基于无穷远点有这样的性质</p><ul><li>无穷远点<spanclass="math inline">\(O\)</span>和椭圆曲线上任意点P的连线一定是垂直于x轴的</li></ul><p>结合之前的加法运算，于是有公式： <span class="math display">\[P \oplus O = P\]</span><font color='red'>这是不是很类似于一个零点，任何点加这个点都是其本身</font></p><p>除此之外，基于无穷远点还有如下性质 <span class="math display">\[P + O = O + P = P \; for \;all\; P ∈ E\\P + (−P) = O \; for \;all\; P ∈ E\\(P + Q) + R = P + (Q + R) \; for \;all\;P, Q, R ∈ E\\P + Q = Q + P  \; for \;all\; P, Q ∈ E\]</span>四条公式分别代表Albel群(交换群)的4条性质：存在零元，存在逆元，结合律，交换律</p><h4 id="加法运算公式">加法运算公式</h4><p>这里给一张图片，很好的讲述了加法的运算公式</p><figure><imgsrc="C:\Users\24546\AppData\Roaming\Typora\typora-user-images\image-20221205132805302.png"alt="1" /><figcaption aria-hidden="true">1</figcaption></figure><img src="/2022/12/05/sm2%E6%A4%AD%E5%9C%86%E6%9B%B2%E7%BA%BF%E5%85%AC%E9%92%A5%E5%AF%86%E7%A0%81%E7%AE%97%E6%B3%95/%E5%8A%A0%E6%B3%95%E8%BF%90%E7%AE%97%E6%B3%95%E5%88%99.png" class="加法运算法则"><h4 id="减法运算公式">减法运算公式</h4><p>定义负数元的概念：如果椭圆曲线上的一个点P=(a,b)，那么点P的负数元为<spanclass="math inline">\(\ominus P = (a,-b)\)</span></p><p>这样定义有很好的性质：</p><blockquote><ul><li><span class="math inline">\(P\ominus P = O\)</span></li></ul></blockquote><p>相当于实数域加减法的相反数的概念。</p><h3 id="有限域上椭圆曲线">有限域上椭圆曲线</h3><h4 id="有限域上椭圆曲线定义">有限域上椭圆曲线定义</h4><p>从上一节的介绍上可以看到，椭圆曲线上的加法运算构成一个群，所有的点可以是小数，也可以整数。那我们能不能加以限制，令椭圆曲线上的点全部都集中在某个域中呢？</p><p><strong>定义1.</strong>令<spanclass="math inline">\(p\)</span>是一个奇素数，在有限域<spanclass="math inline">\(\mathbb{F}_p\)</span>上的椭圆曲线有如下形式, <spanclass="math display">\[E : Y ^2 = X^3 + AX + B \;with\; A, B \in \mathbb{F}_p \;satisfying\;4A^3 + 27B^2 \neq 0\]</span> 这里<span class="math inline">\(4A^3 + 27B^2 \neq0\)</span>是保证椭圆曲线上没有奇异点。</p><p>则定义在有限域上的椭圆曲线坐标是集合. <span class="math display">\[E(\mathbb{F}_p) = \{(x, y) | x, y \in \mathbb{F}_p \; satisfying \; y^2= x^3 + Ax + B\}∪ \{O\}\]</span></p><blockquote><p>一个例子,考虑下面的椭圆曲线： <span class="math display">\[E(\mathbb{F}_{13}) : Y ^2 = X^3 + 3X + 8 \;over \;the \;field\;\mathbb{F}_{13}\]</span> 我们取X=0,得到<spanclass="math inline">\(Y^2=8\pmod{13}\)</span>，但我们解不出这个Y，因为方程无解</p><p>我们再取X = 1,得到<spanclass="math inline">\(Y^2=12\pmod{13}\)</span>，解出两个解Y=5或者Y=8，那么得到在<spanclass="math inline">\(E(\mathbb{F}_{13})\)</span>有两个点(1,5)和(1,8)</p><p>X遍历有限域<spanclass="math inline">\(\mathbb{F}_{13}\)</span>,我们可以用类似的方法得到下面所有点<span class="math display">\[E(\mathbb{F}_{13}) = \{O,(1, 5),(1, 8),(2, 3),(2, 10),(9, 6),(9, 7),(12,2),(12, 11)\}\]</span></p></blockquote><h4 id="有限域上椭圆曲线运算">有限域上椭圆曲线运算</h4><p>类似与实数域上的加法运算，有限域上椭圆曲线的运算，除法用模逆运算代替，所有运算均在有限域上进行（算完之后要模一个p）。这里还是举个例子</p><blockquote><p>椭圆曲线： <span class="math display">\[E(\mathbb{F}_p) = \{(x, y) | x, y \in \mathbb{F}_p \; satisfying \; y^2= x^3 + Ax + B\}∪ \{O\}\]</span> 计算P=(9,7)和Q=(1,8)的和 $$ λ = (y_2 − y_1)/(x_2 − x_1) = (8 −7)/(1 − 9) = 1/(-8) = 1/5 = 5^{-1} =8\</p><p>x_3 = λ^2 − x_1 − x_2 = 64 − 9 − 1 = 54 = 2\ y_3 = λ(x_1-x_3)-y_1 =8*(9-2) - 7 = 49 = 10 $$ 最终得到P+Q=(2,10)</p></blockquote><h3 id="椭圆曲线的一些名词">椭圆曲线的一些名词</h3><h4 id="椭圆曲线的阶">椭圆曲线的阶</h4><p>我们之前说到每个在有限域上的椭圆曲线都由有限个点组成。那么我们不禁要问：到底是多少个点？</p><p>首先，我们要定义一下在一个群有多少个点就叫做这个群的“阶”（order）【在此放上wiki<ahref="https://link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Order_(group_theory)">关于order的解释</a>】。</p><blockquote><p>椭圆曲线<span class="math inline">\(E(\mathbb{F}_{13}) : Y ^2 = X^3 +3X + 8 \;over \;the \;field\;\mathbb{F}_{13}\)</span>的阶为9，因为总共有9个点</p></blockquote><h4 id="椭圆曲线的基点">椭圆曲线的基点</h4><p>先介绍一下循环子群的概率，方便我们之后基点的讨论</p><h5 id="数乘和循环子群"><strong>数乘和循环子群</strong></h5><p>在实数域乘法的定义是： <span class="math display">\[nP=\underbrace{P+P+⋯+P}_{n个p}\]</span> 使用倍加运算可以实现，其时间复杂度我们之后再讨论</p><blockquote><p>举个例子：</p><p>已知椭圆曲线 <span class="math display">\[E(\mathbb{F}_p) = \{(x, y) | x, y \in \mathbb{F}_p \; satisfying \; y^2= x^3 + 3x + 8\}∪ \{O\}\]</span> 取其上一点P(9,7)，其倍点运算为：</p><ul><li><p>P = (9,7)</p></li><li><p>2P = (9,6)</p></li><li><p>3P = (1,12)</p></li><li><p>4P = (9,7)</p></li></ul></blockquote><p>可以看出，点P运算4次还是点P，这就是循环子群的概念，可以看出点P的运算结果可以构成一个有限的集合，这种群算方式可以看成群的运算，从而构成循环子群。</p><h5 id="基点的概念">基点的概念</h5><p>可以看出基点就是椭圆曲线上的一个点，基点有一个阶n，点加运算n次即可得到再次得到基点。</p><h5 id="基点的生成">基点的生成</h5><p>基点可以构成一个循环子群，sm2椭圆加密就是在这个子群上进行运算。</p><p>假设椭圆曲线的阶为N，对于椭圆曲线上的每一个点，我们都有<spanclass="math inline">\(NP =O\)</span>，同时基点G（其阶为n）也能构成一个元素个数的为n的子群，由群论的拉格朗日定理，一定有<spanclass="math inline">\(n|N\)</span>，我们设置一个辅因子<spanclass="math inline">\(h =N/n\)</span>，随机取椭圆曲线上的一点，可以看出点hP循环n次就是无穷远点，如果n为素数，那么点hp生成的子群阶就是n<span class="math display">\[n*h*p = O\]</span>通过下面的运算步骤，我们可以寻找到阶为n的椭圆曲线下的子群。</p><blockquote><ul><li>计算椭圆曲线的阶 N 。</li><li>选择一个阶为 n 的子群。n必须是素数且必须是 N 的因子。</li><li>计算辅因子 h=N/n 。</li><li>在曲线上选择一个随机的点 P 。</li><li>计算 G=hP 。</li><li>如果 G 是0，那么回到步骤4。否则我们就已经找到了阶为 n 和辅因子是 h的子群的基点。</li></ul></blockquote><h2 id="sm2国密算法流程介绍">sm2国密算法流程介绍</h2><p>最详尽的算法流程步骤请参见这个pdf：<ahref="https://oscca.gov.cn/sca/xxgk/2010-12/17/1002386/files/b791a9f908bb4803875ab6aeeb7b4e03.pdf">sm2技术文档</a>，本人在这里仅仅简单介绍一下流程和步骤，并讲解其中原理。其中流程中的一些符号不给予解释，文档里都有。</p><h3 id="加密算法">加密算法</h3><ul><li>A1：用随机数发生器产生随机数k∈[1,n-1]；</li><li>A2：计算椭圆曲线点C1=[k]G=(x1,y1)，按本文本第1部分4.2.8和4.2.4给出的细节，将C1的数据类型转换为比特串；</li><li>A3：计算椭圆曲线点S=[h]PB，若S是无穷远点，则报错并退出；</li><li>A4：计算椭圆曲线点[k]PB=(x2,y2)，将坐标x2、y2 的数据类型转换为比特串；</li><li>A5：计算t=KDF(x2 ∥ y2, klen)，若t为全0比特串，则返回A1；</li><li>A6：计算C2 = M ⊕ t；</li><li>A7：计算C3 = Hash(x2 ∥ M ∥ y2)；</li><li>A8：输出密文C = C1 ∥ C2 ∥ C3。</li></ul><p>其中KDF为密钥派生函数，函数原型为KDF(z,klen)可以根据比特串z，和长度klen，从而输出一个长度为klen的比特串。</p><p>下面给一个流程图</p><figure><imgsrc="C:\Users\24546\AppData\Roaming\Typora\typora-user-images\image-20221210202636498.png"alt="image-20221210202636498" /><figcaption aria-hidden="true">image-20221210202636498</figcaption></figure><h3 id="加密算法原理的一些理解">加密算法原理的一些理解</h3><ul><li><p>为什么随机数k范围是[1,n-1]，因为如果k=n，那么[k]G =O，这样的点G是无法用坐标表示出来的，也无法参加后面的运算</p></li><li><p>真正的密文在C2里，想要获取C2，必须用密钥派生函数KDF得到比特串t的值，而想要得到t的值，又必须计算<spanclass="math inline">\([k]P_B\)</span>，但是k是随机生成的，想要准确的获取k有两种方法。一种是从<spanclass="math inline">\([1,n-1]\)</span>遍历，要知道这样的遍历需要计算<spanclass="math inline">\(n*(n-1)/2\)</span>次加法运算，n一般是个很大的数（数量级为<spanclass="math inline">\(10^{78}\)</span>），这种计算量算到宇宙毁灭也算不出来。另一种是解方程<spanclass="math inline">\([x]G=(x_1,y_1)\)</span>，这就回到椭圆曲线上的困难问题<ahref="https://baike.baidu.com/item/ECDLP/3324859">ECDLP</a>，所以想要解密是十分的困难。</p></li><li><p>C2的长度为klen，即和密文的长度想当</p></li><li><p>C3是哈希函数，更多的是为验证接受到的密文是否出现改动</p></li></ul><h3 id="解密算法">解密算法</h3><p>设klen为密文中C2的比特长度。 为了对密文C=C1 ∥ C2 ∥ C3进行解密，作为解密者的用户B应实现以下运算步骤：</p><ul><li>B1：从C中取出比特串C1，将C1的数据类型转换为椭圆曲线上的点，验证C1是否满足椭圆曲线方程，若不满足则报错并退出；</li><li>B2：计算椭圆曲线点S=[h]C1，若S是无穷远点，则报错并退出；</li><li>B3：计算[dB]C1=(x2,y2)，将坐标x2、y2的数据类型转 换为比特串；</li><li>B4：计算t=KDF(x2 ∥ y2, klen)，若t为全0比特串，则报错并退出；</li><li>B5：从C中取出比特串C2，计算M′ = C2 ⊕ t；</li><li>B6：计算u = Hash(x2 ∥ M′ ∥ y2)，从C中取出比特串C3，若<spanclass="math inline">\(u \neq C3\)</span>则报错并退出；</li><li>B7：输出明文M′。</li></ul><p>还是给出一个流程图</p><figure><imgsrc="C:\Users\24546\AppData\Roaming\Typora\typora-user-images\image-20221210204747217.png"alt="image-20221210204747217" /><figcaption aria-hidden="true">image-20221210204747217</figcaption></figure><h3 id="解密算法的一些理解">解密算法的一些理解</h3><ul><li>为什么计算<spanclass="math inline">\([d_B]C_1=[d_B*k]G\)</span>即可得到加密流程中的(x2,y2)，要知道只有<spanclass="math inline">\([k]P_B=(x2,y2)\)</span>，理由是：</li></ul><p>密钥对的设定是有规则的，即<spanclass="math inline">\([d_B]G=P_B\)</span>，所以这里可以等价。试想一下，想要根据公钥PB得到私钥<spanclass="math inline">\(d_B\)</span>，又需要解一个ECDLP问题，sm2的安全性就基于此。</p><h2 id="python程序实现">Python程序实现</h2><p>sm2算法的实现有专门的库gmssl，调用其中的库即可实现加解密。</p><p>这里仿照gmssl库做出了一些改进，实现了sm2的加解密。</p><p>其中椭圆曲线参数的设定和基点的选择参照官方技术文档</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs python">基点G的阶:     FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123<br>素数p:        FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF<br>基点G横坐标:   32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7<br>基点G纵坐标:   bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0<br>椭圆曲线系数a: FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC<br>椭圆曲线系数b: 28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93<br></code></pre></td></tr></table></figure><p>代码实现如下</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> binascii<br><span class="hljs-keyword">from</span> random <span class="hljs-keyword">import</span> choice<br><span class="hljs-keyword">from</span> gmssl <span class="hljs-keyword">import</span> sm3,func<br><span class="hljs-keyword">import</span> base64<br><span class="hljs-comment"># 选择素域，设置椭圆曲线参数</span><br><br>default_ecc_table = \<br>&#123;<br>    <span class="hljs-string">&#x27;n&#x27;</span>: <span class="hljs-string">&#x27;FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123&#x27;</span>,<br>    <span class="hljs-string">&#x27;p&#x27;</span>: <span class="hljs-string">&#x27;FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF&#x27;</span>,<br>    <span class="hljs-string">&#x27;g_x&#x27;</span>: <span class="hljs-string">&#x27;32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7&#x27;</span>,<br>    <span class="hljs-string">&#x27;g_y&#x27;</span>: <span class="hljs-string">&#x27;bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0&#x27;</span>,<br>    <span class="hljs-string">&#x27;a&#x27;</span>: <span class="hljs-string">&#x27;FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC&#x27;</span>,<br>    <span class="hljs-string">&#x27;b&#x27;</span>: <span class="hljs-string">&#x27;28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93&#x27;</span>,<br>&#125;<br><br><span class="hljs-comment"># default_ecc_table = \</span><br><span class="hljs-comment"># &#123;</span><br><span class="hljs-comment">#     &#x27;n&#x27;: &#x27;1&#x27;,</span><br><span class="hljs-comment">#     &#x27;p&#x27;: &#x27;D&#x27;,</span><br><span class="hljs-comment">#     &#x27;g_x&#x27;: &#x27;1&#x27;,</span><br><span class="hljs-comment">#     &#x27;g_y&#x27;: &#x27;1&#x27;,</span><br><span class="hljs-comment">#     &#x27;a&#x27;: &#x27;3&#x27;,</span><br><span class="hljs-comment">#     &#x27;b&#x27;: &#x27;8&#x27;,</span><br><span class="hljs-comment"># &#125;</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">CryptSM2</span>(<span class="hljs-title class_ inherited__">object</span>):<br><br>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, private_key, public_key, ecc_table=default_ecc_table</span>):<br>        <span class="hljs-comment">#初始化函数，需要输入公钥和私钥</span><br>        self.private_key = private_key<br>        self.para_len = <span class="hljs-built_in">len</span>(ecc_table[<span class="hljs-string">&#x27;n&#x27;</span>])<br>        self.public_key = self.Str_coordinate_to_jacobian(public_key)<br>        self.ecc_a3 = (<br>            <span class="hljs-built_in">int</span>(ecc_table[<span class="hljs-string">&#x27;a&#x27;</span>], base=<span class="hljs-number">16</span>) + <span class="hljs-number">3</span>) % <span class="hljs-built_in">int</span>(ecc_table[<span class="hljs-string">&#x27;p&#x27;</span>], base=<span class="hljs-number">16</span>)<br>        self.ecc_table = ecc_table<br><br>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">double_point</span>(<span class="hljs-params">self, Point</span>):  <span class="hljs-comment"># 倍点</span><br>        l = <span class="hljs-built_in">len</span>(<span class="hljs-string">&#x27;&#x27;</span>.join(Point)) <span class="hljs-comment">#计算点的16进制长度 </span><br>        len_2 = <span class="hljs-number">2</span> * self.para_len<br>        x1 = <span class="hljs-built_in">int</span>(Point[<span class="hljs-number">0</span>], <span class="hljs-number">16</span>)<br>        y1 = <span class="hljs-built_in">int</span>(Point[<span class="hljs-number">1</span>], <span class="hljs-number">16</span>)<br>        z1 = <span class="hljs-built_in">int</span>(Point[<span class="hljs-number">2</span>], <span class="hljs-number">16</span>)<br><br>        p = <span class="hljs-built_in">int</span>(self.ecc_table[<span class="hljs-string">&#x27;p&#x27;</span>], base=<span class="hljs-number">16</span>)<br>        <span class="hljs-comment">#使用计算倍点的公式</span><br>        T6 = (z1 * z1) % p<br>        T2 = (y1 * y1) % p<br>        T3 = (x1 + T6) % p<br>        T4 = (x1 - T6) % p<br>        T1 = (T3 * T4) % p<br>        T3 = (y1 * z1) % p<br>        T4 = (T2 * <span class="hljs-number">8</span>) % p<br>        T5 = (x1 * T4) % p<br>        T1 = (T1 * <span class="hljs-number">3</span>) % p<br>        T6 = (T6 * T6) % p<br>        T6 = (self.ecc_a3 * T6) % p<br>        T1 = (T1 + T6) % p<br>        z3 = (T3 + T3) % p<br>        T3 = (T1 * T1) % p<br>        T2 = (T2 * T4) % p<br>        x3 = (T3 - T5) % p<br><br>        <span class="hljs-keyword">if</span> (T5 % <span class="hljs-number">2</span>) == <span class="hljs-number">1</span>:<br>            T4 = (T5 + ((T5 + p) &gt;&gt; <span class="hljs-number">1</span>) - T3) % p<br>        <span class="hljs-keyword">else</span>:<br>            T4 = (T5 + (T5 &gt;&gt; <span class="hljs-number">1</span>) - T3) % p<br><br>        T1 = (T1 * T4) % p<br>        y3 = (T1 - T2) % p<br><br>        form = <span class="hljs-string">&#x27;%%0%dx&#x27;</span> % self.para_len<br>        <span class="hljs-keyword">return</span> (form % x3, form % y3, form % z3)<br><br>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">add_point</span>(<span class="hljs-params">self, P1, P2</span>):  <span class="hljs-comment"># 点加函数，P2点为仿射坐标即z=1，P1为Jacobian加重射影坐标</span><br>        p = <span class="hljs-built_in">int</span>(self.ecc_table[<span class="hljs-string">&#x27;p&#x27;</span>], base=<span class="hljs-number">16</span>)<br>        X1 = <span class="hljs-built_in">int</span>(P1[<span class="hljs-number">0</span>], <span class="hljs-number">16</span>)<br>        Y1 = <span class="hljs-built_in">int</span>(P1[<span class="hljs-number">1</span>], <span class="hljs-number">16</span>)<br>        Z1 = <span class="hljs-built_in">int</span>(P1[<span class="hljs-number">2</span>],<span class="hljs-number">16</span>)<br><br>        x2 = <span class="hljs-built_in">int</span>(P2[<span class="hljs-number">0</span>], <span class="hljs-number">16</span>)<br>        y2 = <span class="hljs-built_in">int</span>(P2[<span class="hljs-number">1</span>], <span class="hljs-number">16</span>)<br><br>        T1 = (Z1 * Z1) % p<br>        T2 = (y2 * Z1) % p<br>        T3 = (x2 * T1) % p<br>        T1 = (T1 * T2) % p<br>        T2 = (T3 - X1) % p<br>        T3 = (T3 + X1) % p<br>        T4 = (T2 * T2) % p<br>        T1 = (T1 - Y1) % p<br>        Z3 = (Z1 * T2) % p<br>        T2 = (T2 * T4) % p<br>        T3 = (T3 * T4) % p<br>        T5 = (T1 * T1) % p<br>        T4 = (X1 * T4) % p<br>        X3 = (T5 - T3) % p<br>        T2 = (Y1 * T2) % p<br>        T3 = (T4 - X3) % p<br>        T1 = (T1 * T3) % p<br>        Y3 = (T1 - T2) % p<br><br><br>        form = <span class="hljs-string">&#x27;%%0%dx&#x27;</span> % self.para_len<br>        <br>        <span class="hljs-keyword">return</span> (form % X3, form % Y3, form % Z3)<br><br>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">kp</span>(<span class="hljs-params">self, k_int, Point_xy</span>):  <br>        <span class="hljs-comment"># kP运算，即k倍点的运算函数</span><br>        Point = Point_xy<br>        k = k_int<br>        mask_str = <span class="hljs-string">&#x27;8&#x27;</span><br>        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(self.para_len - <span class="hljs-number">1</span>):<br>            mask_str += <span class="hljs-string">&#x27;0&#x27;</span><br>        mask = <span class="hljs-built_in">int</span>(mask_str, <span class="hljs-number">16</span>)<br>        Temp = Point<br>        flag = <span class="hljs-literal">False</span><br>        <span class="hljs-keyword">for</span> n <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(self.para_len * <span class="hljs-number">4</span>): <span class="hljs-comment">#每个16进制4个bit</span><br>            <span class="hljs-keyword">if</span> (flag):<br>                Temp = self.double_point(Temp)<br>            <span class="hljs-keyword">if</span> (k &amp; mask) != <span class="hljs-number">0</span>: <span class="hljs-comment">#用与操作判断k的最高位是否为0</span><br>                <span class="hljs-keyword">if</span> (flag):<br>                    Temp = self.add_point(Temp, Point)<br>                <span class="hljs-keyword">else</span>:<br>                    flag = <span class="hljs-literal">True</span><br>                    Temp = Point<br>            k = k &lt;&lt; <span class="hljs-number">1</span><br>        <span class="hljs-keyword">return</span> self._convert_jacb_to_nor(Temp)<br>    <br>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">_convert_jacb_to_nor</span>(<span class="hljs-params">self, Point</span>): <span class="hljs-comment"># Jacobian加重射影坐标转换成仿射坐标</span><br>        len_2 = <span class="hljs-number">2</span> * self.para_len<br>        x = <span class="hljs-built_in">int</span>(Point[<span class="hljs-number">0</span>], <span class="hljs-number">16</span>)<br>        y = <span class="hljs-built_in">int</span>(Point[<span class="hljs-number">1</span>], <span class="hljs-number">16</span>)<br>        z = <span class="hljs-built_in">int</span>(Point[<span class="hljs-number">2</span>], <span class="hljs-number">16</span>)<br>        p = <span class="hljs-built_in">int</span>(self.ecc_table[<span class="hljs-string">&#x27;p&#x27;</span>], base=<span class="hljs-number">16</span>)<br>        z_inv = <span class="hljs-built_in">pow</span>(z, p - <span class="hljs-number">2</span>, p)<br>        z_invSquar = (z_inv * z_inv) % p<br>        z_invQube = (z_invSquar * z_inv) % p<br>        x_new = (x * z_invSquar) % p<br>        y_new = (y * z_invQube) % p<br>        z_new = (z * z_inv) % p<br>        <span class="hljs-keyword">if</span> z_new == <span class="hljs-number">1</span>:<br>            form = <span class="hljs-string">&#x27;%%0%dx&#x27;</span> % self.para_len<br>            <br>            <span class="hljs-keyword">return</span> (form % x_new, form % y_new, form % z_new)<br>        <span class="hljs-keyword">else</span>:<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span><br><br>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">encrypt</span>(<span class="hljs-params">self, data_str</span>):<br>        <span class="hljs-comment"># 加密函数，data消息字符串</span><br>        data = data_str.encode() <span class="hljs-comment">#将消息转化为bytes流</span><br>        msg = data.<span class="hljs-built_in">hex</span>() <span class="hljs-comment"># 消息转化为16进制字符串</span><br>        G = (self.ecc_table[<span class="hljs-string">&#x27;g_x&#x27;</span>],self.ecc_table[<span class="hljs-string">&#x27;g_y&#x27;</span>],<span class="hljs-string">&quot;1&quot;</span>)<br>        k = <span class="hljs-number">2</span><span class="hljs-comment">#int(func.random_hex(self.para_len),16) #1.产生随机数k \in [1,n-1]</span><br>        C1 = self.kp(k,G) <span class="hljs-comment">#2.计算[k]G = (x1,y1)</span><br>        C1 = self._convert_jacb_to_nor(C1)<br>        C1 = C1[<span class="hljs-number">0</span>]+C1[<span class="hljs-number">1</span>]<br>        xy = self.kp(k,self.public_key) <span class="hljs-comment">#3.计算点s = [k]pk</span><br>        x2 = xy[<span class="hljs-number">0</span>]<br>        y2 = xy[<span class="hljs-number">1</span>]<br>        m_len = <span class="hljs-built_in">len</span>(msg)<br>        t = sm3.sm3_kdf((x2+y2).encode(<span class="hljs-string">&#x27;utf8&#x27;</span>), m_len/<span class="hljs-number">2</span>)<span class="hljs-comment">#5.计算t = KDF(x2||y2,klen)</span><br>        <span class="hljs-keyword">if</span> <span class="hljs-built_in">int</span>(t,<span class="hljs-number">16</span>)==<span class="hljs-number">0</span>:<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span><br>        <span class="hljs-keyword">else</span>:<br>            form = <span class="hljs-string">&#x27;%%0%dx&#x27;</span> % m_len <span class="hljs-comment">#两个百分号代表%</span><br>            C2 = form % (<span class="hljs-built_in">int</span>(msg, <span class="hljs-number">16</span>) ^ <span class="hljs-built_in">int</span>(t, <span class="hljs-number">16</span>)) <span class="hljs-comment">#6.计算C2 = M 异或 t，C2的长度理应为消息M的长度</span><br>            C3 = sm3.sm3_hash([<br>                i <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">bytes</span>.fromhex(<span class="hljs-string">&#x27;%s%s%s&#x27;</span>% (x2,msg,y2))<span class="hljs-comment">#7.计算哈希函数C3 = Hash(x2 || M || y2)</span><br>            ])<br>            <span class="hljs-keyword">return</span> <span class="hljs-built_in">bytes</span>.fromhex(<span class="hljs-string">&#x27;%s%s%s&#x27;</span> % (C1,C3,C2))<br><br>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">decrypt</span>(<span class="hljs-params">self, data</span>):<br>            <span class="hljs-comment"># 解密函数，data密文（bytes）</span><br>            data = data.<span class="hljs-built_in">hex</span>()<br>            len_2 = <span class="hljs-number">2</span> * self.para_len<br>            len_3 = len_2 + <span class="hljs-number">64</span> <br>            C1 = self.Str_coordinate_to_jacobian(data[<span class="hljs-number">0</span>:len_2]) <span class="hljs-comment">#1.提取出C1,并转化为坐标点</span><br>            C3 = data[len_2:len_3]<br>            C2 = data[len_3:]<br>            xyz = self.kp(<span class="hljs-built_in">int</span>(self.private_key,<span class="hljs-number">16</span>),C1)<span class="hljs-comment">#3.计算[sk]C1 = (x2,y2)</span><br>            xy = self._convert_jacb_to_nor(xyz)<br>            <span class="hljs-comment"># print(&#x27;xy = %s&#x27; % xy)</span><br>            x2 = xy[<span class="hljs-number">0</span>]<br>            y2 = xy[<span class="hljs-number">1</span>]<br>            cl = <span class="hljs-built_in">len</span>(C2)<br>            t = sm3.sm3_kdf((x2+y2).encode(<span class="hljs-string">&#x27;utf8&#x27;</span>), cl/<span class="hljs-number">2</span>)<span class="hljs-comment">#4.计算t = KDF(x2||y2,klen)</span><br>            <span class="hljs-keyword">if</span> <span class="hljs-built_in">int</span>(t, <span class="hljs-number">16</span>) == <span class="hljs-number">0</span>:<br>                <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span><br>            <span class="hljs-keyword">else</span>:<br>                form = <span class="hljs-string">&#x27;%%0%dx&#x27;</span> % cl<br>                M = form % (<span class="hljs-built_in">int</span>(C2,<span class="hljs-number">16</span>) ^ <span class="hljs-built_in">int</span>(t,<span class="hljs-number">16</span>))<span class="hljs-comment">#5.恢复明文M = C2 异或 t</span><br>                u = sm3.sm3_hash([<br>                    i <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">bytes</span>.fromhex(<span class="hljs-string">&#x27;%s%s%s&#x27;</span>% (x2,M,y2))<br>                ])<br>                <span class="hljs-keyword">return</span> <span class="hljs-built_in">bytes</span>.fromhex(M)<br>    <br>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">Str_coordinate_to_jacobian</span>(<span class="hljs-params">self,Point_str</span>):<br>        Point = Point_str<br>        x = Point[<span class="hljs-number">0</span>:self.para_len]<br>        y = Point[self.para_len:<span class="hljs-number">2</span>*self.para_len]<br>        z = <span class="hljs-string">&quot;1&quot;</span><br>        <span class="hljs-keyword">return</span> (x,y,z)<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">&quot;__main__&quot;</span>:<br>    <span class="hljs-comment"># sm2的公私钥</span><br>    SM2_PRIVATE_KEY = <span class="hljs-string">&#x27;00B9AB0B828FF68872F21A837FC303668428DEA11DCD1B24429D0C99E24EED83D5&#x27;</span><br>    SM2_PUBLIC_KEY = <span class="hljs-string">&#x27;B9C9A6E04E9C91F7BA880429273747D7EF5DDEB0BB2FF6317EB00BEF331A83081A6994B8993F3F5D6EADDDB81872266C87C018FB4162F5AF347B483E24620207&#x27;</span><br>    operator = CryptSM2(SM2_PRIVATE_KEY,SM2_PUBLIC_KEY)<br>    c = operator.encrypt(<span class="hljs-string">&quot;网络空间安全&quot;</span>)<br>    <span class="hljs-built_in">print</span>(base64.b64encode(c))<br>    result = operator.decrypt(c).decode(encoding=<span class="hljs-string">&quot;utf-8&quot;</span>)<br>    <span class="hljs-built_in">print</span>(result)<br><br>    <span class="hljs-comment"># n = int(default_ecc_table[&#x27;n&#x27;],16)</span><br>    <span class="hljs-comment"># G = operator.Str_coordinate_to_jacobian(SM2_PRIVATE_KEY)</span><br>    <span class="hljs-comment"># print(operator.kp(n,G))</span><br>    <br></code></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">人民有信仰，国家有希望</summary>
    
    
    
    <category term="密码学" scheme="http://example.com/categories/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
    
    
    <category term="python" scheme="http://example.com/tags/python/"/>
    
    <category term="椭圆曲线加密算法" scheme="http://example.com/tags/%E6%A4%AD%E5%9C%86%E6%9B%B2%E7%BA%BF%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>python常用库(密码学)</title>
    <link href="http://example.com/2022/11/19/python%E5%B8%B8%E7%94%A8%E5%BA%93-%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
    <id>http://example.com/2022/11/19/python%E5%B8%B8%E7%94%A8%E5%BA%93-%E5%AF%86%E7%A0%81%E5%AD%A6/</id>
    <published>2022-11-19T10:51:45.000Z</published>
    <updated>2022-11-19T10:51:45.494Z</updated>
    
    <content type="html"><![CDATA[]]></content>
    
    
      
      
    <summary type="html">
</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>EIGamal加密算法</title>
    <link href="http://example.com/2022/11/18/EIGamal%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95/"/>
    <id>http://example.com/2022/11/18/EIGamal%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95/</id>
    <published>2022-11-18T04:41:14.000Z</published>
    <updated>2022-12-05T04:41:37.683Z</updated>
    
    <content type="html"><![CDATA[<h1 id="eigamal加密算法">EIGamal加密算法</h1><h2 id="背景介绍">背景介绍</h2><h3 id="dhdiffie-hellman算法">DH(Diffie-Hellman)算法</h3><p>DH算法用于在不安全的公共通道中协商密钥，安全性体现在：在有限域上计算离散代数非常困难。上两位大牛WhitfieldDiffie 和 Martin Hellman的照片：</p><img src="/2022/11/18/EIGamal%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95/DH_master.jpg" class="" title="大师"><p>算法描述：</p><blockquote><p>假定Alice和Bob期望在一个不安全的网络中协商一个共同的密钥，那么进行如下步骤：</p><ul><li>两人先说好大素数（质数）p和它的原始根g。</li><li>Alice随机产生一个数a，并计算<span class="math inline">\(y_A = g^a\mod p\)</span>, 发送给Bob。</li><li>Bob随机产生一个数b，并计算<span class="math inline">\(y_B= g^b \modp\)</span>，发送给Alice。</li></ul><p>此时， Alice手握Bob发过来的<spanclass="math inline">\(y_B\)</span>，结合自己产生的a，开始这样计算：</p><p><span class="math inline">\(y_B^a \mod p = (g^b \mod p)^a \mod p =g^{ab} \mod p\)</span>。</p><p>Bob也拿到了Alice发来的<spanclass="math inline">\(y_A\)</span>，同时结合自己的b，也开始计算：</p><p><span class="math inline">\(y_A^b \mod p = (g^a \mod p)^b \mod p =g^{ab} \mod g\)</span>。</p><p>这样Alice和Bob都得到了相同的密钥。</p></blockquote><img src="/2022/11/18/EIGamal%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95/DH.png" class="" title="DH密钥交换图解"><h3 id="eigamal诞生">EIGamal诞生</h3><p>ElGamal算法是由Tather ElGamal在1985年提出的，它是一种基于<ahref="https://so.csdn.net/so/search?q=离散&amp;spm=1001.2101.3001.7020">离散</a>对数难题的加密体系，与RAS算法一样，既能用于数据加密，也能用于数字签名。ElGamal算法是基于因数分解，而ElGamal算法是基于离散对数问题。与RSA算法相比，ElGamal算法哪怕是使用相同的私钥，对相同的明文进行加密，每次加密后得到的签名也各不相同，有效的防止了网络中可能出现的重放攻击。</p><ul><li>原文的链接：<ahref="https://link.springer.com/content/pdf/10.1007/3-540-39568-7_2.pdf">[Apublic key cryptosystem and a signature scheme based on discretelogarithms](https://ieeexplore.ieee.org/abstract/document/1057074/)</a></li></ul><p>这篇论文在谷歌学术上被引用了将近10000次，可以说有想当广泛的影响力，大家如果有时间可以欣赏一下作者是怎么行文的，EIGamal加密算法十分的简单，看看作者是如何将其扩充到9页，也是一种锻炼自己的方式嘿嘿。</p><h2 id="基于离散对数的数学难题">基于离散对数的数学难题</h2><h3 id="基本描述">基本描述</h3><p><strong>如果对于一个整数y和质数p的一个原根g，可以找到一个唯一的指数x，使得：</strong></p><p>$y=g^x $<strong>其中</strong> <spanclass="math inline">\(0≤x≤p−2\)</span><strong>成立，那么指数x称为y的以g为基数的模p的离散对数。</strong></p><p>离散对数难题是指：当已知一个大质数p和它的一个原根g，如果给定一个y，要计算x的值是相当困难的。</p><h3 id="针对不合理参数的破解方法">针对不合理参数的破解方法</h3><h4 id="当质数满足p-2n1">当质数满足<span class="math inline">\(p =2^n+1\)</span></h4><p>当<span class="math inline">\(p =2^n+1\)</span>,x可以被转化成二进制序列<spanclass="math inline">\(\{b_0,\dots,b_{n-1}\}\)</span>,其中<spanclass="math inline">\(b_i\in \{0,1\}\)</span>,有如下等式 <spanclass="math display">\[x = \sum_{i=0}^{n-1}{b_i*2^i}\]</span> 注意到，因为g是模数p的一个原根，所以集合<spanclass="math inline">\(\{g^i|i\in[0,p-2]\}=\{1,\dots,p-1\}\)</span>,两个集合即两个集合应该相等，由Euler小定理:<span class="math display">\[g^{p-1} \equiv 1 \pmod{p}\]</span> 那么对方程开方: <span class="math display">\[g^{(p-1)/2} \equiv -1 \pmod{p}\]</span> 为什么不是等于1呢，因为已经有<spanclass="math inline">\(g^0=1\)</span>了，<spanclass="math inline">\(g^{(p-1)/2}\)</span>不能和<spanclass="math inline">\(g^0\)</span>相等（集合<spanclass="math inline">\(\{g^i|i\in[0,p-2]\}\)</span>等于素数p的既约剩余系），所以只能等于-1</p><p>有了上面的基础，我们可以简单推导出下面的公式 <spanclass="math display">\[y^{(p-1)/2} \equiv (g^x)^{(p-1)/2} \equiv (-1)^x \pmod{p}\]</span> 根据x的二进制序列，当x的最低位</p><ul><li><span class="math inline">\(b_0=0\)</span>时，<spanclass="math inline">\(y^{(p-1)/2} \equiv 1 \pmod{p}\)</span></li><li><span class="math inline">\(b_0=1\)</span>时，<spanclass="math inline">\(y^{(p-1)/2} \equiv -1 \pmod{p}\)</span></li></ul><p>由此我们可以确定第一位<spanclass="math inline">\(b_0\)</span>的值，我们继续令<spanclass="math inline">\(z \equiv y*g^{(-b_0)}\equiv g^{x_1}\pmod{p}\)</span>,这里 <span class="math display">\[x_1 = \sum_{i=1}^{n-1}b_i*2^i\]</span> 如果<span class="math inline">\(b_1=0\)</span>那么<spanclass="math inline">\(x_1\)</span>是4的倍数而不是2的倍数，有下面的等式<span class="math display">\[z^{(p-1)/4} \pmod{p} \equiv\begin{equation}    \begin{cases}        +1,b_1=0\\        -1,b_0=1     \end{cases}\end{equation}\]</span> 由此我们有可以判断一位<spanclass="math inline">\(b_1\)</span>，以此类推，我们可以完全复原密文x</p><h4 id="当p没有大素数因子">当p没有大素数因子</h4><h2 id="eigamal流程介绍">EIGamal流程介绍</h2><h3 id="密钥产生">密钥产生</h3><ul><li>选取一个强素数<span class="math inline">\(p\)</span>，而且满足<spanclass="math inline">\(p-1\)</span>至少有一个很大的质因数（如果因子很小那么计算离散对数很简单）</li><li>素数<span class="math inline">\(p\)</span>的一个本原根<spanclass="math inline">\(g\)</span></li><li>随机选取整数<span class="math inline">\(a\)</span></li></ul><p>产生一个公钥<span class="math inline">\(pk =(p,g,g^a)\)</span>，私钥是随机选取的整数a</p><h3 id="加密">加密</h3><p>假设Alice想发送一个密文m给Bob</p><ul><li>随机选取一个数<span class="math inline">\(k\in[1,p-2]\)</span></li><li>计算<span class="math inline">\(c_1 = g^k \mod p\)</span></li><li>再计算<span class="math inline">\(c_2 = (g^a)^k*m \modp\)</span></li></ul><p>如此就计算出了密文，这是一对数<spanclass="math inline">\((c_1,c_2)\)</span>，并将其发送给Bob</p><h3 id="解密">解密</h3><p>Bob讲密文恢复成明文m</p><ul><li>计算<span class="math inline">\(v \equiv c_1^a\pmod{p}\)</span></li><li>计算<span class="math inline">\(m \equiv c_2*v^{-1}\pmod{p}\)</span></li></ul><blockquote><p>证明：</p><p><span class="math inline">\(m \equiv c_2*v^{-1} \pmod{p} \equivm*g^{ak}*(g^{ak})^{-1} \pmod{p} \equiv m \pmod{p}\)</span></p></blockquote><h2 id="python程序实现">python程序实现</h2><h3 id="参数生成">参数生成</h3><p>强素数满足p-1至少有一个大因子，可以用Crypto.Util.number里的函数<code>getStrongPrime()</code>，这样可以直接产生一个非常强的素数。但是这样有几个问题：</p><ul><li>这个函数随机生成的强素数的bit位数必须是128的倍数而且大于512。一方面导致了计算时间的增大，令一方面如果p太大可能导致不安全（比如<spanclass="math inline">\(g^a \mod p\)</span>可能在数值上就等于<spanclass="math inline">\(g^a\)</span>，而有些同学喜欢默认为原根就是2,3,5中的几个，如果a取的不是很大，我们可以直接开方，如果是整数那么这个就是我们要的a）</li><li>这个素数因为有大因子，在验证g是原根的时候，这几个大因子寻找十分困难，以至于时间很长很长</li></ul><p>下面给出一个解决方案：</p><blockquote><p>我们只需要p-1有一个大因子就行了，我们默认大因子为素数q和数字2，这样就有关系p= 2*q+1,如此一来，我们只需要验证p-1的两个因子即可判断是不是原根</p></blockquote><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">Gen_primitive_root</span>(<span class="hljs-params">p,q</span>):<br>    <span class="hljs-comment">#产生一个本原根，产生方法，从2，3，... ，p-1逐个选取</span><br>    <span class="hljs-comment">#选到2的时候，选取phi(p)的几个非1因子，比如phi(11)=10,10有因子2，5</span><br>    <span class="hljs-comment">#如果2的2次方和5次方都不等于1，那么一定2的10次方等于1，这时候2为本原根</span><br>    <span class="hljs-comment">#但，这样真的很慢很慢</span><br><br>    <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br>        candidate_root = random.randint(<span class="hljs-number">2</span>,p-<span class="hljs-number">2</span>)<br>        <span class="hljs-comment">#按照Gen_para生成的素数p只有两个素因子2和q</span><br>        <span class="hljs-keyword">if</span> gmpy2.powmod(candidate_root,<span class="hljs-number">2</span>,p)!=<span class="hljs-number">1</span> <span class="hljs-keyword">and</span>  gmpy2.powmod(candidate_root,q,p)!=<span class="hljs-number">1</span>:<br>            <span class="hljs-keyword">return</span> candidate_root     <br>        <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">Gen_para</span>(<span class="hljs-params">m</span>):<br>    digit = <span class="hljs-built_in">len</span>(<span class="hljs-built_in">str</span>(m))<br>    <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br>        <span class="hljs-comment">#这里是一个坑，尽量吧q的范围扩大一点，这样有更大的几率让2*q+1是一个素数</span><br>        q = sympy.randprime(<span class="hljs-number">10</span>**digit, <span class="hljs-number">10</span>**(digit+<span class="hljs-number">1</span>))<br>        p = <span class="hljs-number">2</span> * q + <span class="hljs-number">1</span><br>        <span class="hljs-keyword">if</span> sympy.isprime(q):<br>            <span class="hljs-keyword">if</span>  gmpy2.is_prime(p):<br>                <span class="hljs-keyword">break</span><br>    g = Gen_primitive_root(p,q)<br>    a = random.randint(<span class="hljs-number">2</span> , p-<span class="hljs-number">2</span>)<br>    <span class="hljs-keyword">return</span> [p,g,<span class="hljs-built_in">pow</span>(g,a,p)],a<br></code></pre></td></tr></table></figure><h3 id="加解密实现">加解密实现</h3><p>参数生成了之后加解密就没什么好说的了</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">encrypt</span>(<span class="hljs-params">m,pk</span>):<br>    k = random.randint(<span class="hljs-number">1</span>,p-<span class="hljs-number">2</span>)<br>    <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;参数k的值为:%d&quot;</span>%k)<br>    c1 = <span class="hljs-built_in">pow</span>(g,k,p)<br>    c2 = (<span class="hljs-built_in">pow</span>(g_a,k,p) * m)%p<br>    <span class="hljs-keyword">return</span>  c1,c2 <br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">decrypt</span>(<span class="hljs-params">c1,c2,sk</span>):<br>    v = <span class="hljs-built_in">pow</span>(c1,sk,p)<br>    m = c2*sympy.invert(v,p) % p<br>    <span class="hljs-keyword">return</span> m<br></code></pre></td></tr></table></figure><h3 id="完整代码">完整代码</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> random<br><span class="hljs-keyword">import</span> gmpy2<br><span class="hljs-keyword">import</span> sympy<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">Gen_primitive_root</span>(<span class="hljs-params">p,q</span>):<br>    <span class="hljs-comment">#产生一个本原根，产生方法，从2，3，... ，p-1逐个选取</span><br>    <span class="hljs-comment">#选到2的时候，选取phi(p)的几个非1因子，比如phi(11)=10,10有因子2，5</span><br>    <span class="hljs-comment">#如果2的2次方和5次方都不等于1，那么一定2的10次方等于1，这时候2为本原根</span><br>    <span class="hljs-comment">#但，这样真的很慢很慢</span><br><br>    <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br>        candidate_root = random.randint(<span class="hljs-number">2</span>,p-<span class="hljs-number">2</span>)<br>        <span class="hljs-comment">#按照Gen_para生成的素数p只有两个素因子2和q</span><br>        <span class="hljs-keyword">if</span> gmpy2.powmod(candidate_root,<span class="hljs-number">2</span>,p)!=<span class="hljs-number">1</span> <span class="hljs-keyword">and</span>  gmpy2.powmod(candidate_root,q,p)!=<span class="hljs-number">1</span>:<br>            <span class="hljs-keyword">return</span> candidate_root          <br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">Gen_para</span>(<span class="hljs-params">m</span>):<br>    digit = <span class="hljs-built_in">len</span>(<span class="hljs-built_in">str</span>(m))<br>    <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br>        <span class="hljs-comment">#这里是一个坑，尽量吧q的范围扩大一点，这样有更大的几率让2*q+1是一个素数</span><br>        q = sympy.randprime(<span class="hljs-number">10</span>**digit, <span class="hljs-number">10</span>**(digit+<span class="hljs-number">1</span>))<br>        p = <span class="hljs-number">2</span> * q + <span class="hljs-number">1</span><br>        <span class="hljs-keyword">if</span> sympy.isprime(q):<br>            <span class="hljs-keyword">if</span>  gmpy2.is_prime(p):<br>                <span class="hljs-keyword">break</span><br>    g = Gen_primitive_root(p,q)<br>    a = random.randint(<span class="hljs-number">2</span> , p-<span class="hljs-number">2</span>)<br>    <span class="hljs-keyword">return</span> [p,g,<span class="hljs-built_in">pow</span>(g,a,p)],a<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">encrypt</span>(<span class="hljs-params">m,pk</span>):<br>    k = random.randint(<span class="hljs-number">1</span>,p-<span class="hljs-number">2</span>)<br>    <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;参数k的值为:%d&quot;</span>%k)<br>    c1 = <span class="hljs-built_in">pow</span>(g,k,p)<br>    c2 = (<span class="hljs-built_in">pow</span>(g_a,k,p) * m)%p<br>    <span class="hljs-keyword">return</span>  c1,c2 <br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">decrypt</span>(<span class="hljs-params">c1,c2,sk</span>):<br>    v = <span class="hljs-built_in">pow</span>(c1,sk,p)<br>    m = c2*sympy.invert(v,p) % p<br>    <span class="hljs-keyword">return</span> m<br><br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">&quot;__main__&quot;</span>:<br>    file_name = <span class="hljs-string">&quot;secret0.txt&quot;</span><br>    f = <span class="hljs-built_in">open</span>(file_name)<br>    m = <span class="hljs-built_in">int</span>(f.readline())<br>    pk , sk = Gen_para(m)<br>    p,g,g_a = pk<br>    <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;素数p为%d&quot;</span>%p)<br>    <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;原根g为%d&quot;</span>%g)<br>    <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;参数g^a为%d&quot;</span>%g_a)<br>    c1 , c2 = encrypt(m,pk)<br>    <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;密文c1为%d&quot;</span>%c1)<br>    <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;密文c2为%d&quot;</span>%c2)<br>    m_d = decrypt(c1,c2,sk)<br>    <span class="hljs-keyword">if</span> m == m_d:<br>        <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;解密正确&quot;</span>)<br></code></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">基于离散对数难题的加密算法</summary>
    
    
    
    <category term="密码学" scheme="http://example.com/categories/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
    
    
    <category term="python" scheme="http://example.com/tags/python/"/>
    
    <category term="离散对数困难问题" scheme="http://example.com/tags/%E7%A6%BB%E6%95%A3%E5%AF%B9%E6%95%B0%E5%9B%B0%E9%9A%BE%E9%97%AE%E9%A2%98/"/>
    
  </entry>
  
  <entry>
    <title>中国剩余定理</title>
    <link href="http://example.com/2022/11/04/%E4%B8%AD%E5%9B%BD%E5%89%A9%E4%BD%99%E5%AE%9A%E7%90%86/"/>
    <id>http://example.com/2022/11/04/%E4%B8%AD%E5%9B%BD%E5%89%A9%E4%BD%99%E5%AE%9A%E7%90%86/</id>
    <published>2022-11-04T06:13:36.000Z</published>
    <updated>2023-05-17T12:40:48.563Z</updated>
    
    <content type="html"><![CDATA[<div class="hbe hbe-container" id="hexo-blog-encrypt" data-wpm="抱歉, 这个密码看着不太对, 请再试试." data-whm="抱歉, 这个文章不能被校验, 不过您还是能看看解密后的内容.">  <script id="hbeData" type="hbeData" data-hmacdigest="52ecfcddc66b46fb8fdcfbac72755ac64dbea39e9a849c6b993edadf930e0e76">e7de803e7160295f95749b4342f9c4f199704f8dc0becdf40f3554da5420de4532aa19bc708a71721d7d521d8adbcab972e0d8094acc4a6c2713920c6bdb706930582ff2ced985b568e5f9040272f035c591888683f2139365673e8b6cca6994da7113456872ae914d0f166735ba18efb5326b678e06406d79fb33f75e458bb1856afa60eb793ebca3012bd82fcb67c61a34e968e06d977fffcd8763a274f5702a7c66d6ddc98989e59feabbfe6d2f42ccee3fda24c98701f120483a21208f95bb43528bb32d7d8518853a27888d25d042bf090f7a34e57be2ccbcf3bf9473d98e0268bc305bb3be43e58ef9854e7bc65712b744bb24c64377acb44a65b6c1f19bcf786700acb844e1279c76ac7477573922dca2fe41556f330a270e2277e5fd1e161c1dc7e40a3f360db7621214a8681543e84e0320263c4a727e89bfe766cb3e5a7c01587a1b2d830f1ca0fe49c5a57e4184560dd96d934868bbf9d225d05672add777c38abe7210b47112c0a3193180bcba2f43e31c84b475e06d0c7faa938b27b81bfad01602fcfb6f466fe4597d55ff6338d51647e1cc8bdb70cfe9aa43511f2147d136e6e1e299cc78d0cfc898f43efc99436bc382c483dc17b95e3dcbc88bb0bfbed62c28bdd026a57f44757e7525841421d6a04679314122174bf3e5401af362316d0d9e835a04735ae90f82f5351c1874f600405d0d3da126d7578ddaf8cca5473864bc08db1d05df57684b520b93b513ba7da854e4b709b8fa1fe03ae4e8ed36a18f19d3eb003ccfcfddc0fa0fff5a2f5000f936ca901970540987c4a7e504c05df75882f948f1c663f42c623b1dcbf8e838964e596ffb28e99019766c40816f74db07fc1fe5f2a7c053dcfdb623a1e5ac7d27aa29c7755ade27e0e0eb235bb8ffa9cc1fed0c47758b27c5e3d7d094844820448133c0bdefa102e57789a431723c19483c75132db3564e6f4ae1b1ddca46f4c17ae29b158893cb57ec9b67e458b78be0ae651a0c3bf536bbd0573d499a0a1f6d8efa37fea523f28eada5091e70160f459cf736fb62d147d57232645e0b7ddfb042dffe63ff646fe32a7ed92a95e5d7c707ebdfa3be9b639cb381f749419e47f506eededca3dad236d68e3f4452e7bc995a0d0dee82eb142d1dee221434444c40fb69bdd1cc492e6b412b87281e4480029b26b2ffdd72feac829a57d7b95bba6a244a4ae6738b527aabe732a07bf40d5c95b4421154278d5ddfb503e710a8ccf60cee21b3f6ab6162d8401b95e409f537fce17ae5911f73c4278779bae8b7a2b38ac9012786825747cc4dc28e99096ee9443963bf9a0d6be0b034300e56dcc0bfda980bd342d503831c664c041629b35fd0289b33063a58cbcd58969d082b259b605f766ca37fc746adc4dd166d027be4c72b2845212d6372dd570325bd34a2f44d4da11228e2c58954222deff4bb625bfd678f392185cac3514f0d4d531b8fb8357598f367de6b7db300cf5f816e07692cd75b8f4c62265902fdc4b1712dff0e058fc2ca11f86a96b2356ad4ec2572eb03f0852f1915d656c7a1cb90c8cc06a01f6be5d9628d4671dd7e7ae4b0100d46d5a3eb7377b6593a0318d9982a65cb2d0374c084f6bf59952c034c233ee026bbad79766686148c9775de914eb714e6b5e8f755f769f63677dfb9dd50127cebac851a0774a9f1c7e350266542132639bdf101cb09a3d1ae58d50d472bd40800ad57452f678b806af8eec177dff0603f5b93cbe8073ac3798e61bc7614cd8689ffdae017a83545ee0311350e273f97d4f149ede9424d4a06a197c08ef9ea0f1d68502bae6313292fc2d4ea1362f95b566d6082bc41e6e08b02fd7dfb7c7e0c62d123469730be74dc6f571bcd966463037799d55a9c6136c1ce90f76c461cf328ed2405750aeb0ed40a90ace87b1272646ff0208d78d083cfa8379007c1dfde4d52814430d7d11b725f643923ea292eb223a705c23b8c783900d0f40967f3cccf5dd93969f75ea80628f1a8e41d91c4f90de979daaeaaf92a71dc007121fdc13e47db917ee6a3c479f6ecc90664fbdb8f51adeb37e03f155220b825b1866b6d5d5c36dd2f6a4bc409f000015531a123666944fe0484970fdbe84a4d26473addbceb9faae7a0521103a7e3433cc68d1b30ad55753b181516fc45a30d691747cadaa69eeab8aa32d29d791b4e5f66e6f2faab835c9913bd3fce8c7d1b09f7e62f5a25dc17328c92095e688ad17419d50e38e35600eb3ed44f3de0ed370eef280eeeee8022170c14975fad99306f6074e91a721ce9a29ce779d39a90629fbc4dd13a9272ce5b2810d62687c3567c18f11c99f242c20c41fbebd2d354f52ed16ef5493e68419230db4ccc572874d56152b1178ba332c8c5bf03b46df65729225fea17e2acb4d029a914d5bb45a3579b8bdf8358dd16e8aadbab8c5380140436b5c2ea77b7c50980c7913d09ccad75c2857b0efa76e730abab09bbd5f95825bb48b95c1eaf89bba3d11157ed706006a4a04f19d4742db069997f2258edf62f27a7b6a724971d76f3394095d18aed908b6d69813cdb44031b8554200e713833919cc54fcb5711d0227dae66ef35a35ad1e93bed7528a4cf620cb788a8a641b413cbc3ecb1514f6569b7eb2a2e9d903ab33311d3bac9147130d0651311f4c33e27900ecb6354a4eb3ccfbdf251476282ef15ca2864088c5fc4925c949740a0b17589c0ee47c5b503b2e624f816f0ea01a69d88ef6fba3d0294f2dc0f43a60bacfceee999803aeb7b5e0f1e436d4ab72aed092ff6e9d08b1329d96b729211a6fe3595eca1f5395919ef604e24722e911e4bc30c0d5f828b43b20ce7bc8816b5a005dc5ae3b4045f94167bcbb23aff5f835be629230691176db18519137884df058f625e9456fc111e8bb4370fad956697d0fecaba0fa1c473e2f134ae088c35d29db7ca82b9923a3a2e530ad3ae0d87493d3d8ffa1be671166b525658023da1fcf98e25b6af7b812468a8528f3cda055424625f95412acca145facc06229c2d98b0670483de84d844e40d26efafef20c078fc18ba48581eaaf9e5bc94c8e2072372a3d6408f83e2c28300055167b4dab42f34c5eaab97f2fb7c3c91ca0308e90059c2e0ccf3ce46b7d2894b566373eb76eeb0a495ad957ab50f9436c912deb9bd0079c80007ffccdc1ece997a50a4383b3d31ead377c03ebf3583d7586d697f75bb3ad8f5d74e0878a98627965235238731f8abdfc9e835d60fe7b7fe1195d9937bd97a47cf6579c98c305f5538865278984f02b092335e81847f8794afbae7fb5a6fd68adf9f01c15e6307fba2a66778d3f5b0c0e9f70a3a55cc46d77d4310a35a598f5ac94aa514e24451d4ee4c8090a49b5de8630ce954ea6194a0fcf89d95538da8004869d19443f449a29b94542cd86255c1f6412ee6169f7318885a9b164c9d7c18caae87efdf6f766d5247616e324688f1b9fbd11024018c20830c4d2fdb097713ee18732f3b9e8bc621ac72e373e46a01ff990a6d7f54fae9b969159555275ce52b077b3a85aa9db1454ff965a7353559e3751562d1f4a8242e074a9f8b51a48f0efbd5c3c1043557978ea95fc56460583a7c0de624efed0368eb0a922c31b8a1747e9b18b73cdf5de1dcd52886c56c3b377f8d59a728d6207da270d689359b72d67b8a54981c4bfa6afe905f079a8afd554aca52c65b7bb6d215cec022582313417b4cbd8df47ece00dbed9e103938693525dd02f4e34d5bcf849a7d44c3c5584f5287b81b2c1bfcafd3a6e8c305774e10355957a36419209b15cbb66a16345d6c284c51aaf6d3a1203c1c1dfeb36551d2d0e975a9c2e3620f99ef31e4809f80c23be4a3fee5453a66a4bf6c2a9501a4996c6aab42e2de86ac7bea03f2311808ee0409dd339939cd64f4d0c8beabd4f9e70cb6014cb4f32c6bee98f3469f474dfb34a5fd04e5d799fe44bd972ee2d272ec452b8f57d72b8aad505aab40e54c2b2f4e71d3bcdef5e1d1b1d5baf9661085930291b622a11e591e7431984a7c6619765812b2020d1afff9ab0ffb68537bb271ae087b5fd6e3171bc8ceeda67408740942d36dc3d5ce29c72d3579f94ffea1e0509636b03068d60b3e039d71965d424604b031a0786b2d4ad75c7a6a73260b5b77573290d5f0d82e9b858de4d5a85695eeea04da4d160e960e307011193329c290a0a719c75e4fd33f1942f020a49a93db21a84f3ea63c44094697fa648ae3895de25e0c45370dc991b3cd6c0b9d0acae3e5282902a2e2c9eb1fe9dacaf11ef3af708d3d7868d59d7ce05e3effe019ee72f3da61d8fcddd9b9e85c1ae54d3bb632b6d58ccc006468148ac094e998f17be6992fe896ef8d40b7101558aabba2757917d080aae19eca520ba71ca34b942cf58d565d7eeffba42fa1b627b6a79fd9073c3371d9e5c3abe02f2bdd79bab07474580a04d6704d4dff9c8267570ea92ce6ffd0ecf5296637c768762ec5936a437f028dfeafa9c14939a709316c34ec81014d21f53763437dddc9f99c0d28254e78dd463dbeadc223c0cf90581c4408719e78f4f0aa214df218db11769e12d83ed5bfd968efa0f73c3f4f42a929567d8a60a8bd426e82cb94f44de5e7956a3f78103a5fe075b55f7dc67e6f21037224016a4ef36db8a9fe9715f7835b659b1d61b5aaa38a57883b6acd9707496cf90d348820595e9137a867b94e9e00aec6de76a7dc3bed08b2bb3b3a32178bffd2c7e4838d254404f7c5d9c68df89883ae6eb2f8a9a7330bdd26cfbc454e47af84571967960d607aa7448bbbeb345b652d5dccc07ca821d6e1b11fcd2a5c5edcb15c0eaedfc63e6bf82a0a753dce26b2cb7be4a8ca3687e891779aca05529ae7b6a67dadbf2e61e1034fc928866e79c397955560f694b84f37edb883c4fef9ed01485e8305e6a53976b8d57726376a8259d273decf5a6e4087d0206e146374538ee583bf9841b31607e3b734ffa06070d95c54a757952d3d6996572f5c6aba5710d659b7410b3e8da8901cb88ea808d9cbf2051806e2e8c689398aa59344b21db695ac13a04383cc060a34049c716daed6ccc9733beeb9a23e77eca1044aa4c8a3291589c397ad3c820bfcf1c8003bee35f78a8879b957272be853307ed72997164d9b032567f49d6eb6844eb84860d7921ec2eb27597ac4311406d0e4b56f81d0acf28682b42a1eb12678d8ae9b3fb69c34d9585ec8cc6f6fb1c0e718ebd18c02906d67d54ae2369937f5a5258c800f6fdbd08864b671f3bb9044b88fc0b7306f84612f5237838e1e988feb827711c6c9bd377a241f61e7c77d53ed3e1107bd8bbf64af2eba2bad79c5e697e4ab9cb4cff3488723f0bb53bafe4a4d730f2789b677adfe02746b633f156eafb10c8c0dd29fe41beb5f3e2b3a3ebd7aaa715e229149e19c5309afcd67d4db3296e24de60720d2b1de1383092671a67d926a96c5026e9712ea3847bd86f0bde1ef8a4994829cf86bc8b9b2324534726807d62e7d2bc66d2df45075c409fe576ea97be550a5a8bdd665dc0bdf038b6b566018bf93dfd44d65e7b3ae9f6d1887ac62d30926f9e192d56e7b3a1d39775f6412d98c783315c0b01ba4e3fe2c5e0172bb2bf2ce65982520730b33ba8a375b7cadf4670beb8e2d3db98b152efe58ed37b13e4d3719371b257d2e31880b0dfc3cff03448c4bb38daccfd2ac519847c60270a1be10d285375fe94cd833d41f866116c8f29e50ee2804579be0e4d5a3ceff1c3f05ff53c03270bc19efad1346ee4af37b6d64dc4a7eec88b2b3ecc0c096fb65556e87a256a6d7eb6cf500813d244d310a2c02a4f5f4c3d635054325c5992fb174ee84ce069e9e917b8c49992e37c26144dd1680aef2c034e48aaf0d44a7adb1096dc27e9a7b18d74546ecade6447ae1eddce9619d405366fa263ca2f334d43c544dd0db2d8a0848d8fd056dbe47199e41fc4aa81a61c80263e68736002d82fb4611d13bc4608bd4ac48887edac77595c05930e2a3aa2f2174cb40ee3f784b3102837758d85763406fe77a1d16b2f75f189feba588deddb16dc74cb28a683784e622a3a8795f75f75fd510cc072158ce6144552c96f2d06f86a00b05df356f1ddfc9202d6c89ba5eec0c65424cc34fe6afa32d0e12a43253eb204cab862fe7fd1cd3b42fd4eb904af9ec15b7f0fd057137d60825719553d5dfebb9e630f246e7b05245df673a6e194205d153da0c3cc1d7bd691e9511f1fd6d41c85b8d0b1c084cb99f9930cc6c9c677bdb82d9bb565f7bf1e914a0bd5f80683f789b6bcc0eae17261dca481b162b806f7670867e89a660c69132c03086ac75497ccf1076cc32a37b0df4275eb959a57ed91c18e61e0fe5ba483a0e1d0293d8ad8e95093b126fb1e000ca35a5a03018cd175d9b814870132feb35aacfd1a40e5dd9f70b0ca4c2ffe39c56838a6f2ac1a71486f03f4007511e6d6ecd6ee53997b548e123d7ef87ab292b08f89daf455faa680d8c18a7d784348131d67f4abb11bb5207b6e9340478e9d7c237b7dcc687f14d02646372b7320cdad8cea66866b679328207d57039ec3f8ef995fd7c9df6dab00784b8191564e8035534d479b5980237563436766846dc25d927a5ac9c52ccb61a121bab404f4fac12f318b13d0e7f541f480f967d603d80744a279502a58c9af4facca3ae68be5600ca83a16f0ae2273b883b67dc7417c9182b34feb4d01f68a82659915028eb3be3943f641d859a334f28097c2943c9d572ee8b0da3b92c28391464a18b9fa2db6c283e7d0be885f61e63ef373fd8e0932c0b52724b4fac90743926e6c01f410252beb6d065f7bb9f1d28b2fc7b29499faa71451e6a0f221e479df1fe202fc069b9d049cbff51baf946a8bdfa76cafc485f10d600b2a3473d40b44e1560e17b551b198de9e02a79e7bee276f5865686947320ebcbb3233ffd66a80c8b2febba98f53f508f2c338932b3113216471633cfc31669701e57608fa7e2f8da3210976fd624cd4a664d92d115f82f687897873f9ce5be3ebeadeae8e9da7f5ee23c37d03ed232a09ce7ce173e98026335f72e0ac2f1e784b79230068dfe0342be471d60aa6bd85a0b774cf6e7504eb4b4c59cc84ab784e47abb091ff0354cffc25b3a47182fb65e2ac93409f109cfc4532b1dbb95c1d0f6a316a58a99e2805e9ce8adc6b0e306ac303f056df404b06924598714adc9c84c1ad8cdbed87e66d07a841dfa565b14a66b5c19fe78a2c360b4596c22f4cc4a2b443bee6fc7e3cc31b6004a52d25a5653c348ef16624f3a21c2278ea70eb6682b16f576db1d0cd6db61947b18215177f782d057dafb45d06e50d3e4f643ba9b6e99012d6cb7e665a98ea43e0b36f092c9106b58b3fbaa989ff3cd9e1432e0b63e9cfecbdf49df7035fbd59f5ad1912d7c8cff94dddd508320dfe61f6647bfa6364c09bd62be45d39161578291cc470900ef6a04b0527cbbb043f8d798fa2bf0add5e0bc178e0ff1f003a914cc600276ee05ec139360ec0d16597d5792b271583d3694aa1685a1225576b150fcd720f120a3a67e54298040b6dedba484043b2f0a8ff11af8d05f6e26c7261b75cb111a994867cb362034c5f9f586125b996361df1c0cefaf6effd2913a7219aa3c2d36098b220883de1c74362c1bc2768b53b58d01c95772801bea01ee8956efc68ed3edc04f5faf55f7f0640f41d31dc0559bcbc7f6969de1b136f040db157e7cdc97c7c9e54da69c7b643a538aa727084eb80fe96e72f699abd07b80db2715d70cb366d908e577d9956e7be6dc660f01ac78565e6d653a295f18a6b5e251dfa361d95de871e66209ca03e38aac9aabd95ed9037f91a085d500c672391dd397b31d0b30940d4992d6fc805d88680cd1a154876aafc081de6fe73ec39f6e901dbceecbaa5443b20ef3fa3023cb047a16594884297096b9806a83baf846d439f164c78038b1ecb512d68eb19cb49c09766ed1ce33eb4691d52ec32876da24503746867694d84c50dbe7ea78770fea42d4f25e253d711eae7d26bfaad55f13acaec57e41ae6c055ed94f887e53f7f23d53aa5f7334e522d20e945864e51d1fc42dd9e858d8d57505e50be623e53ae62df4d3b8851902650d06392a8078df01c5967ba538c28cf954351c7130b4dc5488c909d5701f339b4829d253e2d1f00a660531faa3f1f35fcb1fdc083ef0595227c29dfb413ae179b1c5c4852683c33b9f97f841901fef60ad028ced234934c0c3ed64e98fe3bedf9140a4dba9ce14d5b47418dbf2553dbc0f96812c458ed0f7354dd1de76b65264b98c46e5ffd17701b767f7445640b281d7caa4f66e3699b5b384e90f54c81ba99436e677cce00fa0fc40cfe5185cefce1a18fcfdec7c48004f77b7d77c4aacbc7be6f754ccd3725b975da0003c563d68fd78601912f41a70e30a2d9999efa37487075db9ca9a79175dbde41425be7431932bf44bd5c953b08420d1e89f72b651eb8577494845e2bb4e96236b36ea23bd723fa25a167f816745dca9fc188b1d83dc662d950e25faa2c12970767bf0f10acdf63282ec2e493d02bf5f7c91e0f155c3e3d9fd4d8bf977b1d2199128651d82347bd80961a613ea3df73fa7bb8b1b052b7837571da90cb439e9cc95b2a5dbb859331a2070fdb91dd8016966cd55f7e647b727f32e711b5d69bcdd0096195b038f5e1bea84b22bdbbf6652d4b0430f0b045949fd4bf3c46253766e087ab0c8f83bb2d6e3532e269e23a4fc146f8518e5953b23135ae47b38c1a1832ebb5f5c486a4cf0533eab7785e5c2df1779b6c2b0d5520e93b02921b9d7df22e07255ae8664cd27377bc607ebebca197ab7baa56a916cd0bdcd831ec600d84b6a63734f1d585989469f679c43ceb15db2a2bbe97728139011fd6c8dafc588f52fb49489784f935d8f3a1069be576423d0c8f54be4564f9d5d0c1891b84410431eb94b51945cc64ae51f3d285fb8601d30f33556f30b5926a7cc6aa5914b7ee99b6a88bf40473e0dc8a1576108fc581bea0efc92503ffcc70f07b0c6d391a80e86e37d94c2854dc6c00e34fe0ebd7a34f06bce6d5f5915d04556af0c2f7a228b553c4d05b60d685011e4c192012266e1316ac9b134379280be9b4daee9985ee41854834db906ea0702fc9edade392e7a8eee65380726e43d5720557b649832fa170b9fe11d630c41889c8ced7508530fec23c3a698af36d884e480d122638aa4ebce8db81e8e994540e567748ed1bc5d534c302589a27593e2d8c04ccbfb802452832e48215db1c28b87a89a895af5883f4699418fabd2e6dca91b452b65129ac1b779e7249e04d85b139f0f1a43c212f90af576920b9754a0173218ac248def0c38bad2ffbf6c092efb9f065cc973729fb9d5d0b0fd745eaba790181cf569a99cfb3e47e9b33f47efb5ecd03353923b1dba06798004efac6979c4a1a90d6b833be94c2d5b41fd01105110102ced405ebd9d7c3a7f40edd127af2dff1869027392b3f616439bc10274ff8a01c45e4097297599e246365595eccd411d5105657e313b8b666f40d51fa875d29da305ce6916f31e3696e32a2496156e3f474d498981171d755d21d1b0d83324284b93b9cfd8167cab09cc0e56e269a81ae5def551504fc07604d03db3e18ad14c083e990251f55da1f902deacad27781e9539b0cdd21641feafb1edd3b75a58270a72a89c4e6fc78c06d2cabde1571a01b1186a8160eee8d4f2b784c0c0478221d8f6f5721df56ecaab2d53a4256d168245b4f7d29422feb6b88f37b79f60299fe00cf174db15ae29b9e676acf651c392bda35a80aa4e09ee1a7e1498825ed49261e64a1545e7ee2abbd75e7fdbe8d0d57696a6f9062d11e96c7433eb3ddee2ff9947183793dc7fb8431fb41ded932439f890fbd86193885e5083bd254bacbe9b560920f36a6fc02a5819f53def4b6c884bfe9552aef685aec5268008e906434e905b0aa645fce4755fbbeb510b45191247d5035ecff1865fcb120228468c05dd987df9fc0f3d13804b403c4d93a117ad4d91b2e56ada594db5949f9c3b6788dee20b619b36e1bb1a5d2fd0cf193f021fd41ad5a03b0429a930c3b653f876872b2a63d78adcebeb2d55edbca6daa790a993d0706e7bbef84893e2caec72b211106188d00345c44517ec687094a41e47d678bec4ca690c0bbe5ecc0acae76c9a982f71eaeafaedf8d4888eeb5da4b548653cf5a862b63b495328a4b303d2c4c0641cc2857573d513cb1bf9f674247c525c78cad3b0c63c4be492c193dbb81919500d33a5b1cb83d897bb3c12321fb4b8a3109f9f244d560b86d3120f27b6e5482c57e4398192714f37f0cd9bb09617c82ab57e64b0139c63e767fa523e0143ccd9c3d8c268ab716f20cd2ae3dd9ab0466707b5b60de511e6f900fc8861dbdb85b25c93198e0b69121b2671a2d89f42549eca511587a3565a419f016236549d3594a27f27e1db880140a9f5f787f324647bd4d38bfe944012f1f0ba0ad609d7c933443d395070823521dd79ef3517804218a35b3e5a7936e9b6856e7661d19c2269c5f2a58a56c04d89a59ae84b150c53265827c6b345080d9dd37cf5446676b934e0b4d33c62ee481f4889343caf127854e09b1a2e11efffd1ca62e2f2d8684887b1f7ac8fce6c4b59f012ce5f1600ced9b02e3e119f63cc67de662440ebc29c913829f01f1c07986ebfd71f38c203496293c328d995e5876ba523fdbd30c7c8c7ee8a8d8b412a0ab9df218d32017c5a0873d230f905aabe67300740c4e93fe16ab3513464ab7efcdf1e409a57b2ed6a402ea99733e4082c7d09f3e8514070c51eccfffbba72e0b1707ced3d8426ca452b6ec912cc236adca9eafdff92a18b61b87987edac16f9ebba5ab5a4e4bf9456210cdb4ded717f1c4c40a378cd7a85a74279265ec46549dc892f5aa83eca3bf8615389dd717e4487465c3a7ea1d592ade0150338e7362f579074f308100c25118a7d954aa640b588a906d52c11ccb04f91b2bdf2ce5593fe727a94c168d3d7cb6ec83fc934f6635f07dc3caed5734228858b43d25caf7490db5cdadbcff00da4abc794349a5b2e44a8a1f3be4287f5226b391f2c3c9e69c8f4fa69c72c0d4c306fb8b78ffaa5967e44676c41e2dab43c9d0407c42f6a8a734608a7fedc3dd300dbd29d583eb1482c8f4c0672beb7cec6dc6630b24c697b4016b3ed5d05fa58c31b09398363fc9f507d169fa7964a6fa8d849b4b44724958ec4b6487eb027d9d965afe504423e8d6cb818b6e08def40097a121d68372e64ab34bee35005a280533485aaa5de02c47c07003580a4369b0105520561e563b922ca5b595bbb068b942dfd7511c9c15dc05906da2a3ef285e6f16c82e1689379f31ee61eec56e22b29a803501ca6fe15caf586604178b6c917a6a2134668edde7c1c2b4f8eb7ae6a165a5f91b3d0e73bfcb4c20b976608e3d0119c4889ac525ca38cd6591710554a5578f359210a3ba50ed4900a14a96a809eaa6763f9ae09a48b2dc9437d91aed5f625231e302e61cbfa108e4edb4d57307e8f99fd14d907c9f8fe533631298df3b72d57d8f6187c17cf4c53a0aa73968bf77c9e219601cad4ba5ee1e146e842d5ae1d484cbc9de728072199d83fbe9d695ebfa0c63dfeb020e487d19858862ed4dbb3f75dabb792be7689027119031217966614525e598bdf8cea5da5f5da13f5cf98ed85fecd5075de5b92e1cfa8e172db970a519e5b5cebf3744f4860c0d4690affa14af318eb07eab2087364d87ad59c03b5b808e229df086145f91a81575a2f985fe923924f024683d473620163381e03826832831834e73c6daf26e1f875d2a750bc14f39569d647c42066662393b7ca19a8b4dc23ca096a4dcf8647fc919dc515239dbb0be89aac904fb4fabe97a302e4ef6b5b71fa6d9edf724575e8f53bee7b5ff2a844cd70e86cbdab1b8e3bf9c48773aa960cbf289e7be16875130cdd18f8155318adbbbd9995d0c2f6f46970ae4e55f1985b31b94561bc126f10097fa240bffcfe63a0e0310d55cd601abdec8728a99d3c24f59ad80bf3e9b835ffec2ec8184394d13fa97cfcbb31f169890323a0a9a065c1fc46a774679e96b7664403fc02980c23e5dae5256a7290980373174edf56518c3114c1bde8fab16502f826ae1262cbf8136ae2891086c9b04dbab6cf348a1a0f6666297ba98382ab9646cd065395390f79f7eb51d618973c62979fcfc3fb0ee401994ef6059e5b7d49d4004c27ab964db8eb0412974f6c2824ea54ba870a3f83aa76af4fa8706ddcddc8cd36fd1ccf77bd538bba2eda4164b5ce291a8390344a4c3493848b4d2dff9cafebe635080696298b9d217aef329886eb441693ec8f1a6dea1a59fcaa04db17a37f81e6922ab978019b14cf03e81609882e9e3563dd04403be8447f4ab697e36626e731172c94fc56449a0d16a03f478aba144db76993bda6ba0789771a17ae1965ceed7cd076f2a9d0daf06d651956efa6ddf8562e7622d0535056c718f429439a5d4a5c2378f4caaff6c69a8e2258fd14fac32756f2a4c1726031343c75f4298154fec5e1d0f497a611101cf421505db25511a3930bc45c6161eac461cc36a4010bd88dfb5fee3ea9303950cb6dc3c001ead7885aff2e6ecc754dd81232ccad45f2dd734cb4974993ea6899aed2556fe95e62cc2da747e8a2868b0987ec345806feba8ee4693d033ab698484367abb4a34e372cf431d95c36af4c5ffa81f28dff4da9f40a9e97757b22cc93f6b3acfdb798f676a13854b42df3e9fad1f3d33e9026334586edc57f40de54986d3bea2a5ed3c3522540db764eeea67b2a78c644a5ef60cd075fbdd89d188e47a498f881baf8809f3860f03f5d6ab119638fce4afd4008987938f1a144d1fd6b756a15d8564b27c273ab03da950188c4731553c0b5508bf406b5392b41d24fa789feb4b02940b08a9469cdff24899b606c7ac22ab6a1454160ac25439c62f04880918ce684db3f2c2fd002a954b25767f1584797191111e8637ef4ee7ad285e22877784fb8f8fdcc9d199f4421bc510f958e5ab6f99b5a2f062369d1a4d83f401f7db4eb60b6a84266c94916f1c67805249f9146d59a8ed5097b8daea20e0b6b0c3c803d56cceb4171482f68157a3dc850239fa32c62e0047898cbdc8e7c08b334fa95216add66779bda204de1150b9cd0a6a8727cbc4d21f63e03966da83d527fb1ae829f6ce71860be35d0bde8fb8380d690c3571408e61b26c0e393200035f2af02cb44b56e3a83f7294ac54902d98529ab5b6234515f31691046153d6d2344a7331a59db90478623f24a18b433916ce9282de4df5fd75f8c78392c2cafb8a23732defb021a6d2ea69a36b30763ad85090dec4449102891d67e9ce5d6c252249cebbad92391d2dbb424d23da61d335ab130233547cbea079b19468045b4eb336bde1ace0ae7682590631d2bb9b9ad5708416d5812ee98b47a1122f918d5ce6bb5ec44f6ab6feb4b26cc6c963db385a709a58b4dd6ad1cbb333b4e154931a07b07075f5193af99ac48d628b5bb310451af5f821aa561414bb1e1d2bf5448344f0927ea74692223a3c1d8cebe17c2be30c53f4c63a7938f2c504e3eeedaca67f8cbd9dc9835381d00bc1ddb8b1c0c0e1330110786cb545355e91e1b4c5b4176c1dd6cc2f3e07ff23686bb6406f02f3b751f580db83ea12f08554d24a8572137caa0c7193f26e1f4780dec13bdf184a53bf28631643e1f9688a9c5fa26fa9554e4fd208b9ce2dc15cd269f1922b812d780adad3a3c12f6d67fb5c480b281269098d6b708d71b24b94ec112aff630ac6754a5c1cb9025902724cc1ccbb4a3ae9cb8e93aedecb4a633d5005c90903cb46ee1942621e82227e570273dce2d02f7e466943ae4fb656e2a02dfc5740dcb4d2ed1e05e3d8e9b0d90de56132cc30fcae67df49c843b429434169c124926d250e3f3204d511632a2af132207136425fc46357714eb96851f5487c00704c854439f69fd2389e1b3d6d024df78ad4bb49dbc4062b76a5007d01ec6608008c0ac827fd5ba221b54af654af767eaa6b4f4f082cb59cf76bdf76e4a5cca5f4a0345a8327437fcd76ae86d827c8ae70b9e952ca71eaf21bece0f4e3be84708c60797e0ec5a8c19440154f20b4728d781e411ce8e9af41128ab59552fe4503999857b00c7e6de095979a003a2fc12a733817017d16ddd540c9390317a3183cd5c2d5a607ce46628b2fda34ca632bd02961ae72462f5ab32399ce84177e73c5c5ba114bc5308f8ae81caab11c6e0a824241bfb9e6cef27dc1822060d6d2d4e8f368429bbefffe890513b7e3147c91dc9bcd6f33f3c569c50daa55fff08713c6dd8784a1c0fc714384d36437ad8b68362edf69ab2a2ecde8d92d1d8c1d691d1eddcba42de9e5bd4f212bb8d7ea283b7edce44b863527b8fb9dfbd3e71e2b6506d97af3a25dbace8279142d0ec76febc03a98e037e6536b4e5dbcb32f8de0957ae6b509a7bb576de148cf7c538ca7b903366d3eaff238fa4b20298dcfd3a2ebaa34e06707d6e4b8126a3d793f48f983a0a171471342dd2dbeed773ef53130fcfa1ab5b3db0dae2e69f3012a6f2c99f79c455f3cd63240ca188085a2d4e2a711da984175a2f23653bbb6a253ee1d07746a7cdb7fa1d4e6226a6095675b3b4e41c295aaabd5ae83f3d8ab1f07cbe9ca18d010afa35e66688dea59948a6ea7c657123c79911f6a054b9d9c61ab9dcd5652c651c8a7d4298846c4339f8088c0868a0734e1ebdb4ffc0a318fc6e9c13c1ec6974429c7061befca88096d168ee4e0488a336df76bb8ceb0cee6ea171513df7443b3985ef11a3c3a45bc622f61b6f2cef170687df1eb5595a27290cc9b5812f8986a39499f0f058d06290e0fc084424e4915e55f39a2a36987c59c0d52e6e0a09f3fea02f01ac2ace947bdfb8ba5eabf9caa10c704be440ad2a7da8b61cfa1d0126b465081c265112bfa61df9f6870961733859a49631ce94f998c0756c5f279136d52377e9ace3b5f0d848bcadbb686fe3deed982c7d670ccbf73ef619f6f99647344ad179fb5a674061ed4ad3a7afe5ebc77fb101b438bce7bd31a9a1c8058da9e3f54b2081cebd50cf1d4d2878e41152abc059a34c5734ec816baeb47be20a390d42a0a493bc0decd44e1e1e61f44abdb32ee1deca27c35f840ff6c77b86dc16cdeb65b81d7fcd71280c58439aec32dac47d74ba423896651c8fc116d729953c967fb93cbbdf982dab647a3c9af3722f338a5b7fd3c08a9dfbe6cf9eff6596f432df7375851451ff95058951c8110a511abf819c252b1f14acc4d09116201ea1777a587e00b6762dfbd539330226fb9d611bf7b19c05989541eda6101e6029b93505083abeab24447ff2b76d6a16e1bf9466c2512c7ea068495a276d0eac26e9239163cef57e88de92fae43119b1cfe66004d757627984075e0475413ebe277d3b2157dd0e7add41bb05dfea79ae90dcff3bc8d0447101bb512926ecd82d95d3b44e0669f7509a1a0e557bae3d83037598ff6dbd693c0c1a955e69d1fac446cca6539854c769d4e7a2ba1086cc7774731beaeae5c3608a1c252d2096901a430f2e2d905dfba1e8cd649420c31a2aa3e0ddd625f52c4cb5d73260a845cffca07923d12b081bd43a3951a0ab5914892383f7c9b0330cc1cbdaff1375152b15f5a8d28a6fd7513e918f8d5b4049ab0c506737fd49d1582f7cceab69d77a4e93d91a11ecdd1872fa9462dfd1a133911dea59dce61d7a43bc3980ce2e33800041db666f339a3c111c14dd03f74762f047a9557aa9d1d459d15e469344d43ab218f0ca52a276d2b28cb07cd1978a7b03811dac0a6d6dbe3ae8960e2851bef296732850455f46eefb444ec5035c77660f7f0b96b9d0828ec831d3bcc332a4c0d688b05db400741ffe9ab63d68c2c2e85010108a80f4bf01e19c3ae13ca8bea1eee111f6daa69f2f899f55d1a2f49f76076dbb0a30460b83cae5eeab86c6bf896225056f33cb5e113d4bb39a2e6ce867e5fe1ab6246499d64729c63445bd7f0048e5c1fefa36792bfd21363c23f25470f26b2372f441788c283e4d18d8f22bca86d3f314e8e7cca5b0d0fdf4ee40fbfed75c34b9ec8be46f6e9f6a8165e14c60145973f0fb18f7b5283a5328aaca44eef28d542f2471634414c1495d3b908f2920193cfb6713cdc18347fc8f37f0ac07710621ebda3af421d2de1ffff3f047d25201dc8482766f2870d4d7dac52655495f63342b7ba18ec4617b7f608bb9f8307477376359f0f5422006e80c0961aefe9bd0ffb852d4d6dce056e5bf3f550032dd3dff6afbcd059b00106e56a3be54893c4910ce85ca9fd38feeac51cfb9023f9d877c93e38e64c533b4095a68ff08dfd316cf69b089971a57c21cca90cbe32b09efbab2e46f1b4722556a781788ae6edaa0a4394216c473dae97f4972cc4e8828df70788c4661da7803805b4e73405dc9a9d91bfc0adc475042eea29ece9d6fe849aa1fb27e9dc45f55338234a0ee479c412d31c6d6de20ceae37b6890ca2bc00175045255de62210cd2b381147e343ed4888e9af0f2e178b9349a15912ebef244a4113b85f8d0c6373798e7a8780741a1b5de6d19d14b0a59aaaa0934e1f0a7caebab55575594823e9fe56e815ee0f618defccb4fec71491054f1cca400f440d254c3ca0812704f6e514fd54ca3e0b0fb9fca45a46ce1a3b703258947f20808a8f7fc3f18db82a5ca61d456156fbea05d1b6aa1e81d95ab0441300f540c7bf0bf9c8ab7cefba98cfd30cd2b866be4f3dd5e8c15079992f26e0b6624d09d850912d46a1513d0ca2b04f78ce016ccf885b003b344759c4edad2840b6a4dcdeb76749824326158d8a1870c7c23e311a026574d4eef722c7e6186fd06324e8167f138db5ba425fac4101ba2b087bc70df5ca9764f0e285ad9563cd560f3b9e6c0159be278f7b0ade45973ac4c381ae2e39a31147d45c9d7e850da68d9686a533c70c8e67e8b524eaead6e2030d8aa06eeea3c1bbbdf7645920a50f8f4f1b99474e44f1347e792eb096e9d1bc4cf7a86cff1f71d6e791cdb83bea22096fd5129963426573e560999eb7a41ec210c5d15857e33861f0cd800e6f398ad1d05b3ff5c21d7ca5371c57555006ac9c6a6b8be06fa913db0456cd0b550644903c00ac81e68737ba101f9b6421358bbd185d3014c72e93c246d734d9cdffc99cd7a52a5a07919875324c95e8ca3dccf3d5b732d1d0a01f6a0d834678e09d1efca383e1cc38017bab4cf2f601658db73cf454534eeca29a1872de259c0d18abc848e939ce16d85d8d98607e27dc1faed09b340ebaf40022af5e6e34c5d1530ca8e3ba2eb096b55767771510617b75c3fc287f6f6ec3962a085bb187a92181e00cf1536203d7e2a83d8b8ad396316eedefab78cd95f51bb22dfe39fe0825709c5540c086570fc993750e5733f06c51617508a0197dd9ff781e14d7cf8fd5701a8cab01c302de221245d008638c55cd4ce0ff0754400e43cf06f509333675fe8b6a0dceda8c16a9aaa43199517b474108aca1a272940e01ebdb7ed845d7772132cdcb3d1d1a652cb0ea7943d4b8b2955c11067ae61604429336ab47ae20a6bf05810b009d4f7d4d68d0ba3b89ffcd4eca81ce2ddac7e0443298c8d33d998946aead5730eb091d6396c27eabce210a8b6c62123085718c44ebf4482a6ff857e9d985fde3a27cba025689cd6236665fd534db50ca1fdfef0fb4885d3fc69ce5c052630650bf67e167903f77be977b7428acfb91ac086f13e12af66dfed0128cc87015bdf85fbdfafad1086cc46decff004a5f7343c73a7143587b3933d118a9fc2abd6f111b10186108f3b7ac94ca2b4a58f0603eced5ab47168ba7f66004e8fc48edb2a1b3a13969a35d43d62f555448f8a4cc5f5e57443ca6198e28a850c459c14f7a9afa4fcfba3a0fb89f96d23438d20138dd34dc0ca17bf698bfa16542ab2505091a843d092fa70f1a084a8847b2d02c33f38ea437ce08b035b7a55186ec4de30bdeac0d6defdcee2413e75a5e37beb3c19bb541fc3424c70c0d7c599a693782c9e8c05bb1be15db962479364bacabefadfadd27f0237b8f80fc0d1e09d55dae3aab435219b87c96fe981dc2097b55344796283a0273638c430e8d74930cc9331d237d5afbe1ca344182876ddec5da89b72244c1a136225dd6c513c5769697db4626a43aaceb678291c48b96e26409d042799abb5e41ced95421873dc24ad0efa45fa3406781cb53ccbba46c59d352cedeb2a9c2dddad0c5affc8c99b2ea1e22bf807d68257d4278ef4c4f6e389afbea49cbfbc33a5039e64544f9fad92c906bd763b268644a0b3afd5a3efda1f56d6f4d807108fd4ddb653a96547c83646e67d1270c494543fad3209c514c80b5b1a85dca8b5b67eab0f52b36cf6c4674f0c8cbaa07d848a8a38c85fc058e03a78b3efc9c318c2ecec864a0d7fcdfbe8b4d08a9571e8881be1176cf8c448dbd732b5b7561fb598065e1fefd77e1133e779ca923ace46b3919b55cce7a1ad1b4ac3a31e20cec8bdbc6fa2c972fba41a2943310371623882dc774b4bb3bdb2a614c94c0233b8b566c417b55a61faa6235ad7e6524e976241267188381fc24754db76fafe7c1d48dd065ad51113cb04ee6c27c5e292e646e0b0f7a030a6c300b13b892c3013a5b28fd4874c809924efdc8f65154e1ce5c183a32509ddb3eb64c1cd9082b03ba2c90d6419baba24dc4480cdb75e533c96714b8abf0b913676eac42ea54f5a7d8e66c435cd9dd5b009ac460c917291418f57c1ea3a014f96ffc4b42028a9af2f2d78bcbe9297aba389ad075c959795b439c6121cdc5c696a4c30fe20e9942eb4ef24e0cf9211a2ef843c42b5e4c5d65866d996a7931df25f6d8add971b4efc4807de1870a1ece8ffc4a83fb0f71e268fb5c53a26822b4c8e282330c2695425368c8c68f1286934385059247168e45123fffae83e1da21d7daccec512c4014ce1a2ac427b52370eb0f4158dbfcd5e8b91763c8c5d0aed400e737ceb12eefc5e0dae63a601a647341c1f2953caee7ef9a748b566d3f5456d6c898ee1ae1e66e9df20bddb163fdb738b831a4159c81296e91579e579709ea9fee49829ff241e11698bd1ab4d18ba33fd6346588ceb042a8e5f91bf9383a700f68a4202268df8b47432e2d82e9ecf940c37298fe0bec10004a1a6f8a268d98db307f8072874461e685d1a3daefb61f3e77b9e523fe42cebdb673c3566851b193f6129ae5d5491322658ee598b3d9977c6d9fcd20c902bd9964a1eff1bb2d81703d1eaaae79dd6488afccaad0793335bc8b0e05edf17e9cdaabc17765d9f006b7d5df45ecb9a7c0a18a4ee8392b07b0f6afad2a66b426dc7d64da6364a8400318eb39a992b6eeac46b401d9beb84b6f239b5199685c8a3de5a722801ec7c0df8f7da4580cea3523a97328f2ce75dacb20fc2a3495212d3d691c4aae41cdecdea531f0d42829fb540cb153205221e58c5c9a7534d2ea8ef02dd6b5ef20269a9e220657835dc3443b5255090f9f7950c79cad4456bc5331a66e7c88c8451b3415a9ad92fc8821ff15b9166bcbaf7664f781009be4b96e42b3bf876470b83cfbf516cf10a0787057c9d3b4180887f6bd6852943e1bd0df71475898af4b44ff0995ac1b4b919c9b79bcc53cd3fd59735e8085f1bfb092aad4cf46f432ca4f58e93598dcd2bec401e056b06c3fa3f955192debc55e8f646024cfac06a7bb3f5d80fa751a5a7dc6c052b2b075fc2661071f51510d3f35161385894eb49547d7f02064f569d9f98706cb2ccf926f16ca8fb0dc476d42c26178d476ddc5825358522bed7af130ebca6b78628b7c80e7d942db752819cb670bb705a55dc67de52dd2ee19de3dc0a3b3317f4eb78dd7b0c6e916621f0987e805ab6bdfe45488e1b4edd5944088743abd90f8ebd5c580c94d792c2d099e415ffdbcec37b274bd584a43e5a2c588a6823b5beaa67b1d2bc37e34aada81a62fa1c27e2e9eb55d2f0e873744cdefef755d1b8419556fdf00a9f29b1ab027daa06c3bc248d652665c844766a9ebe3825e8d35d921605542bab4e15b5b280a1b5262d0f67f41b5735ce642a06fce8c83d500985c434eb3f8f8f2e32b3636bc8e58a434143466a5313b367cceeff131945622d9a5d21eea69864839ba2f6d5d4ba3ba821df77cd6f65f39cde5f8c171bdff8efd9d50b76083aa2fd5e9dec0d35e29dd41f3d8c64ae1a2c0a00bd2e2d3519992d11730ed0dde1607d0a652c0273b954c1b709208201df9d2e8b2e7a3845bb3fa2da08d86275759e2657045d98b5876d359fa0708e753db68268061c4e69b0723ff1cd706a84717a691280adef09638a3e40c59f2489c774ab3f4067e6641cf15ede8b9618602fb0aea438b9b3c351ca9aac453832d45d0df0b3e951e37681169d4c45adf5bd318f5ecfa75132058d703ee798feb3ccd80e5e140e7387d93ea47f88dd62d86205a798c1bbd101a1e07bb76e67eaf3f9eaec767ba78019ae51e90fa262fb0cdcc7e0d613bae374b7934ed4b1c5870e37bb29251ab57682be886b2c1d6a973882d34dc2a06d8f643d86f926717825bf22e00c4d991ca7df8cf6b5b5e7151d4c254c44fc4e77edab920cb31f6ad831e2e96a7098924f8be69429821caf7897c26037b0762029a9341a817e2f780e32f325ec97ad5e74525b406bcfed694fa28c9b74748cf8d490ab78bc98d8c4a695ebb0283e970d97e1e56179bf46d31647909b6d082d133ba5ecc643981c6964581529e86f20f83e9c47647123cf5cd50418b1eec4efc28cbe7f2ea5614a878abb6e718d73243017242f1b2e59531d536473bc3cba2739c30f6c432c193b8ae6386c5f73e181eb1c5ed4ed7ce0f6af24016d553a669bc580130e7e3b04c734baa5150bdcc58b0943d72bb4bb471d4af37106d72f3b614eb5e220c2eab889b23837c3080158399fc47f7309bb8daae4fbb9ada7fff4dc7ec7958e835b862e7958a4fc95ffa635b10da41861bf8b7c5570f203d74685513094dde2d73f4b2ce455a44be9b208d4a4c3a249d5ffea9046c9b841c416ebb8244b16efaeb89b454f6215f05335df2b885c40a8d5fecd89849d5cd37814dea70b503ec3779431900a38999d2b8ce302cc64eaca1dcf2d24b516cb49ff77c370bc9514ebe5fd582a014a09190c34035d418d3655e81db68d39953be1a734acaf63a75bdf38a4579bf5f2960e6b402255f67b2ed2a7f191060174d3066bcc6a6679781a3d1804e5bde97ea8013a7c2a9587b8585a32300b0f27bc49e54c78303864fb8995758a972ea9e2a813d1fa5b22cbbc40f3d35fe1ae8dfedb5e0370f3c7cca799e4063f35248b559d0fef6fc19053eaaed548bf04a593e593e6484e60e83e11fc3da096ca8972da4ac9b43e49ef636cb6cbe0bb945ed23e951a124f0faa9491df41ddae883c65623495a7ee185405003b39ea6a6c84888cc9c4dd0dd61e0d9a52d0cdaf40603791325d8c9541d531cedaac891d7a41ac48cf50fdc1f27025cd89afc14a51ae86c679b7a8d91837ed45f103e327e7ec0dc54088226b33210f88e96b4033e472a4b06a97ad5ed6cadb3a9a1a736db0efc8124b3cec3d5727561ddc6bb47aaef86ad55b0b145e32b6e69480376ae6f38f36a0a2b267cace38924e39e725dee55612a93df95aa7df08f7d68d96cca038f139fff8538b2175a448acf80e65a99a0e68599142fa94a24d35de69f569f4c1dbef828e8ad3a2f6299e9d1618704859d228a41c055ac30e9d02e1a2ef6115dbede6e93876ae3f0739e8966ca16c2e01043086972fd381570b0729684dc3c134bc7f4369d4f150329f8b26c21d6c6490a04b021bfe8e4cc9e2a9357452469eb588aac8369111598d1134bf8b1810e547f3783150a13bc1e5a649f0a19827533f5685d07606b2962490af8fad6bec394bcdc81c88244cb392d34e43bfa374cbb9d8b53b9b5686b7ad4ddbfc2f522521ed2d4b17c08efab8c3e2eb67c075c56ab75cc77a1efe823a3c44511fecbcca6f18177cc65da083d7a23f9ad421967080da6a8b6a62fed15ac82c2cf722ac0c35ee775d85c434a40fb821d9f72d7d03d02240a4aac4e790a3bdd1bc8ba1ba6cda0d5577bc8f8177895a2cd5240eea657a3bfa42ffaf0bb9c0f5b6abeba8726a58d783cc9fd48bb498a165b7aa64afd881ded62faded17d05ada09cf7d4b7acdf2c82acfb7811d81f7a50223f4571c741763983d73cd215284427bd0611d565a015b4223262b137b216e475ea2a56c1f97ffc92642d1e8a8117ec64dc19cd73594530532ec487fe014214de526a6d341b0dd2593ebaf01f14e95177b135cdd6c941b9398cb6a38347eb683ab61a429e14c8d55089e537b6b206e6b497ebfdad1657fc279c31fcd4112bbe4a7ca52884f935c634346874242742aa4303bce7981c073cedf8507a496f324140fe9f8620caba4c112ee4a83ab142583e84e3868e0737952185437d0082f6baca78e7286a5d6309a36fbf60eb14a82dc5b29277fa01d599938af126676b54bb87ffce0e3d40e62a4d3fbc2e5fefca35bb15ba45c409ba9b596f5efaf089ccc275cd43b3a0ab04994795469bdd8eacab16659f016aeea298732092faded1d7cd09bbb1249080b56b0e71cc01473bcb9bbb0b050626cf1b5127cb97a94f6fe4ab524dd2a40d9f16443289c9c9816af0c66c08c4054e9f02886bac97b1d451c2e96dccc8f9988cd4ee6387b3efa472da896f2ac6a21701579c0a84d3486236dc1eb194e740a435d24c3454e2efc17c3fe32353a641a3ba8b42bae8bb111b02e763446b8d69bb81fe762acd606cee7b6ada3cf56db1fa12eb9ee55b30b1376c359ae88c0a061987f8a9772b2d066fa57d80a315986e8dc2abf8c5be5b87b872bbadebd4e9686fed0218c95a4972c679a3cf918f5c29c45c249d2a9525658e3eafc58f5d36f0edc994f90c8b9db34e31e2a3d8efea16d4d5bc4ae18cc446b21cb4f6217a303c8a60e6d9e98ec0135b61acce5381f6cfc6d95069d3f226efde0dd0dddf800c7f82a1daeecc747f9277ca3c7071cda6a78ff40a5b945222913766215edd1e9666396674f9aa159d922eb3fbe6e3fd25474839a96069523d88a72d1f8c63cfff2f2f09b120e0e54e31d038d0bb22b2b9c789181448de32a64b8f4edcd766054ece4fca3fa032bcf9bb0c2ce8a4da2c3b0d020f58fea1dc5216952858fe9a9c351f651339d877b0340640535a28006ce0347fbed76106270c366bf9c58a81697039b50592654e1f1a516fd52926b171d470cfe3da6cdfdb4bf4646333e09421ebdc8e2395ca54b81146081cef1743f306c7f3b2834c02c7e10c10f8206c4a7f4037dd2947573bb91c8be75e576925591755bee475cf723e74cc2683e2d0cf6317ecb74db67f0f1bf8c5bb104eb24dddeffa7a2c6f1e6490970cb2f4e4de20eb4d51e955282ec9d98f572e2c5a862794e16007d4332c367b8b1562dcf415f40f3269c05969e56b7034826e6eb22490d57aa34668608a05d282a80d9faceb9fbbbf644b671721f99364276e</script>  <div class="hbe hbe-content">    <div class="hbe hbe-input hbe-input-default">      <input class="hbe hbe-input-field hbe-input-field-default" type="password" id="hbePass">      <label class="hbe hbe-input-label hbe-input-label-default" for="hbePass">        <span class="hbe hbe-input-label-content hbe-input-label-content-default">您好, 这里需要密码.</span>      </label>    </div>  </div></div><script data-pjax src="/lib/hbe.js"></script><link href="/css/hbe.style.css" rel="stylesheet" type="text/css">]]></content>
    
    
    <summary type="html">来自遥远的东方的定理</summary>
    
    
    
    <category term="密码学" scheme="http://example.com/categories/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
    
    
    <category term="python" scheme="http://example.com/tags/python/"/>
    
  </entry>
  
  <entry>
    <title>RSA加密系统的20年</title>
    <link href="http://example.com/2022/10/29/RSA%E5%8A%A0%E5%AF%86%E7%B3%BB%E7%BB%9F%E7%9A%8420%E5%B9%B4/"/>
    <id>http://example.com/2022/10/29/RSA%E5%8A%A0%E5%AF%86%E7%B3%BB%E7%BB%9F%E7%9A%8420%E5%B9%B4/</id>
    <published>2022-10-29T11:21:48.000Z</published>
    <updated>2022-11-26T14:19:21.893Z</updated>
    
    <content type="html"><![CDATA[<h1 id="rsa加密系统的20年">RSA加密系统的20年</h1><p><strong>原文：<ahref="https://www.ams.org/notices/199902/boneh.pdf">Twenty Years ofAttacks on the RSA Cryptosystem</a></strong></p><p><strong>作者：Dan Boneh@Stanford University(<ahref="mailto:dabo@cs.stanford.edu">dabo@cs.stanford.edu</a>)</strong></p><p><strong>译者：Harper</strong></p><p>参考链接：</p><ul><li><ahref="https://ctf-wiki.org/crypto/asymmetric/rsa/rsa_coppersmith_attack/#boneh-and-durfee-attack">Coppersmith相关攻击 - CTF Wiki</a></li><li><a href="https://paper.seebug.org/727/">二十年以来对 RSA密码系统攻击综述</a></li></ul><h2 id="背景介绍">背景介绍</h2><p>RSA密码系统由Ron Rivest, Adi Shamir和LenAdleman发明，在1977年8月的《科学美国人》杂志上首次公布。密码系统最常用于提供隐私和确保数字数据的真实性。目前，RSA被部署在许多商业系统中。它被网络服务器和浏览器用来保护网络传输，它被用来确保电子邮件的私密性和真实性，它被用来保护远程登录会话，它是电子信用卡支付系统的核心。简而言之，RSA常用于需要考虑数字数据安全性的应用程序中。</p><img src="/2022/10/29/RSA%E5%8A%A0%E5%AF%86%E7%B3%BB%E7%BB%9F%E7%9A%8420%E5%B9%B4/RSA%E4%BD%9C%E8%80%85.png" class="RSA是1977年由罗纳德·李维斯特（Ron Rivest）、阿迪·萨莫尔（Adi Shamir）和伦纳德·阿德曼（Leonard Adleman）一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的"><h2 id="rsa加密算法">RSA加密算法</h2><p>我们遵循标准命名约定，使用Alice和Bob表示希望相互通信的两个通用方。我们使用Marvin来表示恶意的攻击者，希望窃听或篡改Alice和Bob之间的通信。</p><h3 id="参数设置">参数设置</h3><ul><li>两个质数<span class="math inline">\(p和q\)</span>，再计算得到<spanclass="math inline">\(N = p*q\)</span></li><li>一个随机整数<span class="math inline">\(e\in (1,φ(N))\)</span>,再计算<span class="math inline">\(d \equiv e^{-1}\pmod{\varphi(N)}\)</span></li><li>公钥pk = &lt;N,e&gt;</li><li>私钥sk = &lt;N,d&gt;</li></ul><h4 id="参数生成方法">参数生成方法</h4><p><strong>第一步，随机选择两个不相等的质数p和q。</strong></p><blockquote><p><strong>Alice</strong>选择了61和53。（实际应用中，这两个质数越大，就越难破解。）</p></blockquote><p><strong>第二步，计算p和q的乘积N。</strong></p><blockquote><p>Alice就把61和53相乘。</p><p>N = 61×53 = 3233</p></blockquote><p>N的长度就是密钥长度。3233写成二进制是110010100001，一共有12位，所以这个密钥就是12位。实际应用中，RSA密钥一般是1024位，重要场合则为2048位。</p><p><strong>第三步，计算N的欧拉函数φ(N)。</strong></p><blockquote><p>N是质数，则 φ(N)=N-1 N = p1 × p2 φ(N) = φ(p1p2) = φ(p1)φ(p2) =&gt;φ(N) = (p-1)(q-1)</p></blockquote><p>Alice算出φ(3233)等于60×52，即3120。</p><p><strong>第四步，随机选择一个整数e，条件是1&lt; e &lt; φ(N)，且e与φ(N)互质。</strong></p><p>Alice就在1到3120之间，随机选择了17。（实际应用中，常常选择65537。）</p><p><strong>第五步，计算e对于φ(N)的模反元素d。</strong></p><p>所谓”模反元素”就是指有一个整数d，可以使得ed被φ(N)除的余数为1,故<spanclass="math inline">\(d \equiv e^{-1} \pmod{\varphi(N)}\)</span></p><blockquote><p>ed ≡ 1 (mod φ(N))</p></blockquote><p>这个式子等价于</p><blockquote><p>ed - 1 = kφ(N)</p></blockquote><p>于是，找到模反元素d，实质上就是对下面这个二元一次方程求解，使用拓展欧几里得算法即可</p><blockquote><p>ex + φ(N)y = 1</p></blockquote><p><strong>第六步，将N和e封装成公钥，N和d封装成私钥。</strong></p><p>在Alice的例子中，N=3233，e=17，d=2753，所以公钥就是(3233,17)，私钥就是（3233, 2753）。</p><p>实际应用中，公钥和私钥的数据都采用<ahref="https://link.zhihu.com/?target=https%3A//zh.wikipedia.org/zh-cn/ASN.1">ASN.1</a>格式表达。</p><h3 id="加密">加密</h3><p>密文是一个整数m属于乘法群<spanclass="math inline">\(\mathbb{Z^*_{N}}\)</span>，即<spanclass="math inline">\(m \in \mathbb{Z^*_{N}}\)</span></p><p>计算密文ciphertext简称c，需要用到公钥pk=&lt;N,e&gt;</p><blockquote><p><span class="math inline">\(c \equiv m*e \pmod{N}\)</span></p></blockquote><p>Alice的公钥是 (3233,17)，Bob的m假设是65，那么可以算出下面的等式：</p><blockquote><p>65^17 ≡ 2790 (mod 3233)</p></blockquote><p>于是，c等于2790，Bob就把2790发给了Alice。</p><h4 id="参数生成的效率">参数生成的效率</h4><p>RSA密钥对的生成方法是随机选取两个<spanclass="math inline">\(\cfrac{n}{2}\)</span>位素数并将其相乘得到N。然后，对于给定的加密$e &lt; (N)<span class="math inline">\(，使用扩展欧氏算法计算\)</span>de^{-1} $。</p><p>由于素数集非常密集，因此可以快速生成一个随机的<spanclass="math inline">\(\cfrac{n}{2}\)</span>位素数，方法是选取随机的<spanclass="math inline">\(\cfrac{n}{2}\)</span>位整数并用<strong>概率素数检验(如Fermat素性检验法)</strong>来检验每个整数的素数。</p><p>总体来说，生成素数还是比较快的，openssl生成一个1024位的素数在毫秒级即可实现。</p><h3 id="解密">解密</h3><p>Alice拿到Bob发来的2790以后，就用自己的私钥(3233, 2753)进行解密。可以证明，下面的等式一定成立：</p><blockquote><p><span class="math inline">\(m \equiv c^d \pmod{N}\)</span></p></blockquote><p>也就是说，c的d次方除以N的余数为m。现在，c等于2790，私钥是(3233,2753)，那么，Alice算出</p><blockquote><p>2790^2753 ≡ 65 (mod 3233)</p></blockquote><p>因此，Alice知道了Bob加密前的原文就是65。</p><h3 id="解密正确性的证明">解密正确性的证明</h3><p>这里需要使用<ahref="https://zhuanlan.zhihu.com/p/35060143">Euler定理</a>,即</p><blockquote><p>如果正整数 n 和整数 a 互质，那么就有 <spanclass="math inline">\(a^{\varphi(n)}≡1\pmod{n})\)</span>其中<strong>欧拉函数</strong> φ(n) 是「小于 n 的正整数中和 n互质的数」的个数</p></blockquote><p>下面进入正式的证明过程</p><blockquote><p><span class="math display">\[c^d \equiv (m^e)^d \equiv m^{ed} \\\because e*d \equiv 1 \pmod{\varphi(N)} \\\therefore e*d=k*\varphi(N)+1 \; where \; k \in \mathbf{Z} \\\therefore m^{ed} \equiv m^{k*\varphi(N)+1} \equiv m^{k*\varphi(N)} *m\pmod{N} \\with\;the \; help \; of \; Euler \;theorem:m^{\varphi(N)} \equiv1\pmod{N}\\so: \; m^{ed} \equiv m^{k*\varphi(N)+1} \equiv m^{k*\varphi(N)} *m\equiv  1*m\equiv m \pmod{N}\]</span></p></blockquote><h3 id="安全性分析">安全性分析</h3><h4 id="数学难题-大整数的素数分解">数学难题-大整数的素数分解</h4><p>我们可以看到，如果不知道d，就没有办法从c求出m。而前面已经说过，要知道d就必须分解N，这是极难做到的，因为至今为止大整数的素数分解依然是一个难题，所以RSA算法保证了通信安全</p><h4 id="语义安全-semantic-security">语义安全-semantic security</h4><p>RSA不是一个语义安全的加密算法，所谓语义安全，我们不能从密文中获得任何关于明文的信息，比如一段话的第一个字母，一段话中某个数字出现的次数等等。</p><p>拿RSA举例，我们可以很简单的获得m在N上的雅各比符号</p><h2 id="基本攻击">基本攻击</h2><p>我们首先描述一些老的基本攻击，这些攻击说明了RSA的公然滥用情况。虽然存在许多这样的攻击，但我们仅举两个例子。</p><h3 id="common-modulus-共模">Common modulus-共模</h3><p>为了避免为每个用户生成不同的模数<spanclass="math inline">\(N=p*q\)</span>，人们可能希望一劳永逸地固定使用一个<spanclass="math inline">\(N\)</span>，所有用户都使用相同的<spanclass="math inline">\(N\)</span>。可信的中央机构可以向用户提供唯一的一对参数<spanclass="math inline">\(&lt;e_i,d_i&gt;\)</span>，用户从其中生成公钥<spanclass="math inline">\(&lt;N,e_i&gt;\)</span>和私钥<spanclass="math inline">\(&lt;N,d_i&gt;\)</span>。</p><p>乍一看，这似乎行得通：为Alice准备的密文<span class="math inline">\(c= m^{e_a} \pmod{N}\)</span>无法由Bob解密，因为Bob不知道<spanclass="math inline">\(d_a\)</span>。但是，这是不正确的，由此产生的系统是不安全的。事实上，Bob可以使用他自己的指数<spanclass="math inline">\(&lt;e_b,d_b&gt;\)</span>来分解模数<spanclass="math inline">\(N\)</span>。一旦被分解，Bob就可以从她的公钥中计算出Alice的私钥。Simmons的这一观察结果表明，RSA模不应被一个以上的实体使用。</p><h3 id="blinding-盲化">Blinding-盲化</h3><p>设<spanclass="math inline">\(&lt;N,d&gt;\)</span>是Bob的私钥，而<spanclass="math inline">\(&lt;N,e&gt;\)</span>是相应的公钥。假设攻击者Marvin想要Bob的签名<spanclass="math inline">\(m^d_{Bob} \pmod{N} \in\mathbb{Z^{\ast}_N}\)</span>。当然Bob不傻，他拒绝签署。但是Marvin可以尝试以下方法：他随机选择一个<spanclass="math inline">\(r \in \mathbb{Z^{\ast}_N}\)</span>并设<spanclass="math inline">\(m&#39; =r^e*m_{Bob}\)</span>。然后他让Bob在随机消息<spanclass="math inline">\(m&#39;\)</span>上签名。Bob可能愿意在看上去没什么问题的上签名，但是回想一下<spanclass="math inline">\(S&#39;=(m&#39;)^d\mod{N}\)</span>，Marvin现在简单地计算<span class="math inline">\(S =S&#39;/r\)</span>就得到Bob在初始上的签名<spanclass="math inline">\(S\)</span>。</p><p>事实上： <span class="math display">\[S^e = (S&#39;)^e/(r^e)=(M&#39;)^{ed}/r^e \equiv M&#39;/r^e = M \pmod{N}\]</span>这种称为盲化的技术使Marvin能够在他选择的消息上获得有效的签名，方法是让Bob在随机的"盲化"消息上签名。Bob不知道他实际在签名的是什么消息。由于大多数签名方案在签名之前对消息应用"单向散列"算法，因此此种攻击倒不是一个严重的问题。尽管我们将盲化描述为一种攻击，但它实际上是实现匿名数字现金所需的一个有用属性(可以用来购买商品的现金，但不会透露购买者的身份）</p><h2 id="low-private-exponent-低解密指数攻击">Low PrivateExponent-低解密指数攻击</h2><h3 id="理论">理论</h3><p>解密使用参数d，如果d非常小，那么可以用此方法进行解密。</p><p><strong>Theorem 2 (M. Wiener)</strong> 令 <spanclass="math inline">\(N = pq\)</span> ，这里 <spanclass="math inline">\(q &lt; p &lt; 2q\)</span> . 如果$ d &lt; 1/3N^{1/4}$ 。 给定私钥对<span class="math inline">\(&lt;N,e&gt;\)</span>，这里<span class="math inline">\(e*d = 1 \mod{\varphi(N)}\)</span> ,Marvin 可以快速的复原参数 <span class="math inline">\(d\)</span>.</p><blockquote><p>证明详见论文《<strong>TWENTY YEARS OF ATTACKS ON THE RSACRYPTOSYSTEM</strong>》</p><p>最后给出结论： <span class="math display">\[\left| \cfrac{e} {N} - \cfrac{k} {d} \right| \le \cfrac{1} {dN^{1/4} }&lt; \cfrac{1}  {2d^2} \\这里k满足：k\varphi(N)-ed=1\]</span></p></blockquote><p>这是一个经典的逼近关系，两个分数在约束内非常逼近。首先<spanclass="math inline">\(k\varphi(N)-ed=1\)</span>,所以<spanclass="math inline">\(gcd(k,d)=1\)</span>，即k和d互素，分数<spanclass="math inline">\(\cfrac{k}{d}\)</span>是一个最简分数。虽然d很小，但也只是相对于N（1024bits）比较小，实际上d也有上百比特的长度，所以<spanclass="math inline">\(\cfrac{1}{2d^2}\)</span>是一个很小的数，由上面的不等式得到<spanclass="math inline">\(\cfrac{e} {N}\)</span>是很接近于<spanclass="math inline">\(\cfrac{k} {d}\)</span>的。大致的思路就是在<spanclass="math inline">\(\cfrac{e}{N}\)</span>附近寻找一个小数，把小数按照分数的形式展开，分母就是我们想要找的参数<spanclass="math inline">\(d\)</span>，但实际上并没有这么简单(论文中使用连分数展开)。</p><p>由于通常都是1024位，因此<spanclass="math inline">\(d\)</span>必须至少256位长才能避免这种攻击。这对于诸如"智能卡"之类的低功耗设备来说是不幸的，因为小就能节省大量能耗。然而，并不是毫无办法。Wiener提出了许多能够实现快速解密并且不易受其攻击影响的技术</p><h3 id="代码">代码</h3><p>使用python库owiener实现</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> owiener<br>e = <span class="hljs-number">3047442173541658754667464233797118324917469250436575767227172319344577259865313428705759330024959317716760816959590728238918140105663188172228696589411452947738069773833351725455888549656717874059636289036277785342126992626060696063089487811946920569580454880169977542532087635095357205433679009382368108273</span><br><br>n = <span class="hljs-number">135568509670260054049994954417860747085442883428459182441559553532993752593294067458983143521109377661295622146963670193783017382697726454953197805014428888491744355387957923382241961401063461549210355871385000347645387907568135032087942016502668629010859519249039662555733548461551175133582871220209515648241</span><br><br>d = owiener.attack(e, n)<br><br>m=<span class="hljs-number">123123123123123123123123123123123113212312312312</span><br>c = <span class="hljs-built_in">pow</span>(m,e,n)<br>m_decrypted = <span class="hljs-built_in">pow</span>(c,d,n)<br><span class="hljs-built_in">print</span>(m_decrypted)<br></code></pre></td></tr></table></figure><p>计算得到d的值为</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-number">22299128035876669298809061693021648003426573977341841609779417036458441464337</span><br></code></pre></td></tr></table></figure><p>计算d的位数大概是<strong>254位</strong>,符合上面的分析，运算时间也是很快，用python基本秒出答案。</p><h2 id="low-private-exponent-低加密指数攻击">Low PrivateExponent-低加密指数攻击</h2><p>为了减少加密或签名验证时间，习惯上使用一个小的公共指数。 e的最小可能值为3，但为了击败某些攻击，建议使用<spanclass="math inline">\(e = 2^{16} + 1 =65537\)</span>。当使用65537时，签名验证需要 17 次乘法，而使用随机 <spanclass="math inline">\(e &lt; \varphi(N)\)</span> 时大约需要 1000次乘法。所以对使用小e的攻击连绵不绝。</p><h3 id="coppersmith理论">Coppersmith理论</h3><p>对低公共指数 RSA 最有效的攻击是基于 Coppersmith的一个定理。Coppersmith定理有很多应用，这里只介绍其中的一部分。想要破解RSA，实际上可以看成一个解决函数零点的问题：<span class="math display">\[x^e \equiv c \pmod{N}\]</span>解出这个函数，就是我们想要做的事情，后面关于多项式环的论述也都是基于这个思想。</p><h4 id="前置定理">前置定理</h4><p>首先介绍一个理论：</p><p><strong>Theorem 3 (Coppersmith)</strong> Let N be an integer and<span class="math inline">\(f \in \mathbb{Z}[x]\)</span> be a monicpolynomial of degree d. Set $X = N ^{ {d}- } $ for some <spanclass="math inline">\(\epsilon \ge 0\)</span>. Then, given $ &lt; N , f&gt; $ Marvin can effciently find all integers $| x_0 | &lt; X $satisfying $f (x_0 ) = 0 $. The running time is dominated by the time ittakes to run the LLL algorithm on a lattice of dimension O (w ) with<span class="math inline">\(w = min(\frac{1} {\epsilon},log_2N)\)</span>.</p><p><font color="red">该定理提供了一种算法，可以有效地找方程<spanclass="math inline">\(f(x) \equiv 0 \pmod{N}\)</span> 的所有小于 $X =N^{} $的根</font></p><p>再给出一个引理：</p><p>首先我们定义范数的概念，给出多项式<spanclass="math inline">\(h(x)=\sum{a_ix^i} \in\mathbb{Z}\)</span>,定义范数<span class="math inline">\(\|h\|^2 =\sum{|a_i|^2}\)</span></p><p><strong><em>Lemma 4</em></strong> <em>Let <spanclass="math inline">\(h(x) \in \mathbb{Z}\)</span> be a polynomial ofdegree d and let X be a positive integer. Suppose $|h(xX )| &lt; $ . If<span class="math inline">\(|x_0| &lt; X\)</span> satisfies <spanclass="math inline">\(h(x_0) = 0 \mod{N}\)</span> , then <spanclass="math inline">\(h(x_0) = 0\)</span> holds over theintegers.</em></p><p>这个引理告诉我们：<font color="red">如果满足前置条件，<spanclass="math inline">\(f(x) \equiv 0 \pmod{N}\)</span>的根，也是<spanclass="math inline">\(f(x)=0\)</span>在整数域上的根</font>，但实际上函数<spanclass="math inline">\(f(x)\)</span>一般都没有这么小的范数能满足前置条件。我们可以构造一个函数<spanclass="math inline">\(h(x)=g(x)*f(x)\)</span>，这个函数<spanclass="math inline">\(h(x)\)</span>应该有比较小的范数来满足前置条件。这相当于一个问题，找到<spanclass="math inline">\(f(x),xf(x),x^2f(x),\dots,x^rf(x)\)</span>的一个线性组合，这个线性组合就是函数<spanclass="math inline">\(h(x)\)</span>，且有较低的范数。</p><h4 id="解决方案">解决方案</h4><p>前面我们介绍过，想要找到函数<spanclass="math inline">\(h(x)\)</span>，实际上就是找一个线性组合，DanBoneh在论文中叙述了一个基于格中LLL算法的解决方案。大家可以细看论文(作者关于格的理论已经忘得差不多了)，以后咱再补充。</p><h3 id="hastad广播攻击">Hastad广播攻击</h3><p>所谓广播，就是一个人把消息发给很多人，这里我们假设假设 Bob希望将加密消息 M 发送给多个参与方 $P_1, P_2, ,P_K $。每一方都有自己的RSA 密钥 <span class="math inline">\(pk=&lt;N_i,e_i&gt;\)</span>。我们假设 M 小于所有的<span class="math inline">\(N_i\)</span>，即<span class="math inline">\(M&lt;min(N_1,N2, \dots ,N_K)\)</span>。为了发送 M，天真的Bob 使用每个公钥对其进行加密，并将第 i个密文发送给 第i个参与方<span class="math inline">\(P_i\)</span>。攻击者Marvin 可以在 Bob 视线之外窃听连接并收集 k 个被传输的密文。</p><p>为了便于大家理解，我们举一个例子来说明：</p><p>我们假定所有公共指数<spanclass="math inline">\(e_i=3\)</span>，如果参与方的个数<spanclass="math inline">\(K \ge3\)</span>那么marvin可以破解出明文M，事实上破解只需解下面一个方程即可：<span class="math display">\[\begin{equation}    \begin{cases}    C_1 \equiv M^3 \mod{N_1}\\    C_2 \equiv M^3 \mod{N_2}\\    C_3 \equiv M^3 \mod{N_3}    \end{cases}\end{equation}\]</span> 这里假定<spanclass="math inline">\(gcd(N_i,N_j)=1\)</span>，即任意两个N之间互素，否则我们可以用<spanclass="math inline">\(N_i/N_j\)</span>很简单的求出他们的公因子，从而复原出<spanclass="math inline">\(p和q\)</span>，这个假定是有意义的。对于上面的方程，我们使用中国剩余定理(CRT)解出结果即为明文。</p>]]></content>
    
    
    <summary type="html">它已经存在很久了，但我们仍然无法完全破解它</summary>
    
    
    
    <category term="密码学" scheme="http://example.com/categories/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
    
    
    <category term="RSA" scheme="http://example.com/tags/RSA/"/>
    
  </entry>
  
  <entry>
    <title>Fermat素性检验</title>
    <link href="http://example.com/2022/10/29/Fermat%E7%B4%A0%E6%80%A7%E6%A3%80%E9%AA%8C/"/>
    <id>http://example.com/2022/10/29/Fermat%E7%B4%A0%E6%80%A7%E6%A3%80%E9%AA%8C/</id>
    <published>2022-10-29T07:00:59.000Z</published>
    <updated>2022-12-05T04:40:55.189Z</updated>
    
    <content type="html"><![CDATA[<h1 id="fermat素性检验">Fermat素性检验</h1><h2 id="实验环境">实验环境</h2><blockquote><ul><li>电脑：联想拯救者R9000p</li><li>cpu：AMD Ryzen 7 5800H</li><li>内存：16GB</li><li>操作系统：windows11</li><li>python版本：3.10</li></ul></blockquote><p>目标：</p><ul><li>掌握python基本函数库的使用</li><li>熟悉抽象代数的基本定理如Fermat小定理的使用</li><li>理解Fermat素性检验的原理，并编程实现</li><li>测试一些大数，以一定概率检验其素性</li></ul><h2 id="fermat素性检验介绍">Fermat素性检验介绍</h2><h3 id="背景">背景</h3><p><strong>费马素性检验</strong>是一种素数判定法则，利用<ahref="https://baike.baidu.com/item/随机化算法/6233182?fromModule=lemma_inlink">随机化算法</a>判断一个数是<ahref="https://baike.baidu.com/item/合数/49186?fromModule=lemma_inlink">合数</a>还是<em>可能是</em>素数。</p><h3 id="fermat小定理">Fermat小定理</h3><p><span class="math display">\[对\forall(a,p)=1,p为质数\\\exists a^{p-1} \equiv 1 \pmod{p}\]</span></p><blockquote><p>证明：</p><p><spanclass="math inline">\(\{1,2,3,4...p-1\}\)</span>是p的既约剩余系</p><p><span class="math inline">\(\because a,p\)</span>互质</p><p><span class="math inline">\(\therefore \{a*1 , a*2 , a*3 , a*4,\dots,a*(p-1)\}\)</span>也为p的既约剩余系</p><p><span class="math inline">\(\therefore 1*2*3 \dots*(p-1)≡a*2*a*3*a......(p-1)*a \pmod{p}\)</span></p><p>化简得<span class="math inline">\(a^{p-1} \equiv 1\pmod{p}\)</span></p></blockquote><h3 id="fermat素性检验基本原理">Fermat素性检验基本原理</h3><p>根据<ahref="https://baike.baidu.com/item/费马小定理/4776158?fromModule=lemma_inlink">费马小定理</a>：如果<em>p</em>是素数，<spanclass="math inline">\(1\leq a \leq p-1\)</span></p><p>那么 <span class="math display">\[a^{p-1} \equiv 1 \pmod{p}\]</span>如果我们想知道<em>n</em>是否是素数，我们在中间选取<em>a</em>，看看上面等式是否成立。</p><ul><li>如果对于数值<em>a</em>等式不成立，那么<em>n</em>是合数。</li><li>如果有很多的<em>a</em>能够使等式成立，那么我们可以说<em>n</em>可能是素数，或者<ahref="https://baike.baidu.com/item/伪素数/9262664?fromModule=lemma_inlink">伪素数</a>。</li></ul><p>在我们检验过程中，有可能我们选取的<em>a</em>都能让等式成立，然而n却是合数，所以最终得到的结果是，<font color = "red">我们以一定概率确定p是否为素数</font></p><h3 id="fermat素性检验流程">Fermat素性检验流程</h3><p>给定奇整数 <span class="math inline">\(m\geq3\)</span> 和安全参数<span class="math inline">\(k=5\)</span> （1） 随机选取整数<spanclass="math inline">\(a\)</span>,令<span class="math inline">\(2\leq a\leq m-2\)</span> （2） 计算<span class="math inline">\(g=(a,m)\)</span>，如果<span class="math inline">\(g=1\)</span>，转（3）；否则，跳出，m为合数 （3） 计算<spanclass="math inline">\(r=a^{m-1}\pmod{m}\)</span>，如果r=1,m可能是素数，转（1）；否则，跳出，m为合数（4） 重复上述过程k次，如果每次得到m可能为素数，则m为素数的概率为<spanclass="math inline">\(1- \frac1{2^k}\)</span> 。</p><img src="/2022/10/29/Fermat%E7%B4%A0%E6%80%A7%E6%A3%80%E9%AA%8C/%E6%B5%81%E7%A8%8B%E5%9B%BE.png" class="流程图"><h2 id="python代码">python代码</h2><p>需要导入math模块求最大公因数</p><p>需要导入random模块来产生随机数</p><p>求<span class="math inline">\(r=a^{m-1}\pmod{m}\)</span>必须使用pow(a,num-1,num)函数一边乘法一边取模运算速度较快，不能先算<spanclass="math inline">\(a^{m-1}\)</span>再取模，否则时间太长算不出来</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> math<br><span class="hljs-keyword">import</span> random<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">is_prime</span>(<span class="hljs-params">num, k=<span class="hljs-number">7</span></span>):<br>    <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(k):<br>        a=random.randrange(<span class="hljs-number">2</span>,num-<span class="hljs-number">2</span>)<br>        <span class="hljs-keyword">if</span> math.gcd(a, num)!=<span class="hljs-number">1</span>:<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>, <span class="hljs-number">1</span>-(<span class="hljs-number">0.2</span>)**k<br>        <span class="hljs-keyword">if</span> <span class="hljs-built_in">pow</span>(a,num-<span class="hljs-number">1</span>,num)!=<span class="hljs-number">1</span>:<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span> , <span class="hljs-number">1</span>-(<span class="hljs-number">0.2</span>)**k<br>    <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span> , <span class="hljs-number">1</span>-(<span class="hljs-number">0.2</span>)**k<br>m1 = <span class="hljs-number">743476040059754298379331647007684224429004972336533937786799284757790400765316630522369642718204165253922832684184615021404737105614714107158733905598636152327037707290538422718453498125366750918857659068838460954633737911274770976191590193809661578032117496009853673140977556559136466107768672598883924301125589893895001253674886100289402530711221893</span><br>m2 = <span class="hljs-number">5434520625653357625890820149570485819447986258433769976634917091398967074086679540928507095017715540385352266035820823142060119390272763774034231321959236056764511968630360067353876686142517564224926196131349204754111599877101485686283117193149781387816214484583521923017500621725053392290279263586984207169423800476914654441473576611460323772832328657</span><br>m3 = <span class="hljs-number">876147742992673125957404768949712978720573116974723188491435550196169965040848206868200084918233743662847668000971402407461887306389122707315529364807593342507936022301657320206278702095378618110195051280478534126716517153056984269659532882692418682262081495725304483536777013188527470348249542840277926802938912332306310470632601156641005608958891</span><br>m4 = <span class="hljs-number">9876147742992673125957404768949712978720573116974723188491435550196169965040848206868200084918233743662847668000971402407461887306389122707315529364807593342507936022301657320206278702095378618110195051280478534126716517153056984269659532882692418682262081495725304483536777013188527470348249542840277926802938912332306310470632601156641005608958891</span><br><br>result , pr = is_prime(m4)<br><span class="hljs-keyword">if</span> result:<br>    <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;该数以&quot;</span>,pr*<span class="hljs-number">100</span>,<span class="hljs-string">&quot;%的概率判定为素数&quot;</span>)<br><span class="hljs-keyword">else</span>:<br>    <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;该数不是素数&quot;</span>)<br></code></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">不确定的东西让人痛苦不已</summary>
    
    
    
    <category term="密码学" scheme="http://example.com/categories/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
    
    
    <category term="python" scheme="http://example.com/tags/python/"/>
    
  </entry>
  
  <entry>
    <title>latex常用数学公式</title>
    <link href="http://example.com/2022/10/25/latex%E5%B8%B8%E7%94%A8%E6%95%B0%E5%AD%A6%E5%85%AC%E5%BC%8F/"/>
    <id>http://example.com/2022/10/25/latex%E5%B8%B8%E7%94%A8%E6%95%B0%E5%AD%A6%E5%85%AC%E5%BC%8F/</id>
    <published>2022-10-25T03:57:26.000Z</published>
    <updated>2022-12-05T05:18:33.310Z</updated>
    
    <content type="html"><![CDATA[<h1 id="latex常用数学公式">latex常用数学公式</h1><p>最近需要写一些文档，里面会有大量的公式，写出好看的公式的过程真的很治愈:cat:,这一期博客主要来介绍一些常用的latex公式，内容很干。<font color = "red">自己用markdown写的公式，渲染出来都是对的，但是放到博客上不知道怎么回事有一些奇奇怪怪的错误</font>，大家直接粘贴代码就行。</p><p>参考： https://artofproblemsolving.com/wiki/index.php/LaTeX:Symbolshttps://artofproblemsolving.com/wiki/index.php/LaTeX:Commands</p><h2 id="各种类型的符号表">各种类型的符号表</h2><h3 id="数集符号">数集符号</h3><table style="width:100%;"><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\mathbb{R}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\mathbf{R}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\mathcal{R}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\mathfrak{R}\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\mathbb{Z}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\mathbf{Z}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\mathcal{Z}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\mathfrak{Z}\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\mathbb{Q}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\mathbf{Q}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\mathcal{Q}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\mathfrak{Q}\)</span></td><td style="text-align: center;"></td></tr></tbody></table><h3 id="操作符">操作符</h3><table style="width:100%;"><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><spanclass="math display">\[\pm\]</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\mp\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\times\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math display">\[\div\]</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\cdot\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\ast\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math display">\[\star\]</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\dagger\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\ddagger\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math display">\[\amalg\]</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\cap\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\cup\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\uplus\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\sqcap\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\sqcup\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\vee\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\wedge\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\oplus\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\ominus\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\otimes\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\circ\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\bullet\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\diamond\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\lhd\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\rhd\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\unlhd\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\unrhd\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\oslash\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\odot\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\bigcirc\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\triangleleft\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Diamond\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\bigtriangleup\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\bigtriangledown\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Box\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\triangleright\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\setminus\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\wr\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\sqrt{x}\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(x^{\circ}\)</span></td><td style="text-align: center;">x^{}</td><td style="text-align: center;"><spanclass="math inline">\(\triangledown\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\sqrt[n]{x}\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(a^x\)</span></td><td style="text-align: center;">a^x</td><td style="text-align: center;"><spanclass="math inline">\(a^{xyz}\)</span></td><td style="text-align: center;">a^{xyz}</td><td style="text-align: center;"><spanclass="math inline">\(a_x\)</span></td><td style="text-align: center;">a_x</td></tr></tbody></table><h3 id="关系符号">关系符号</h3><table style="width:100%;"><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\le\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\ge\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\neq\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\sim\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\ll\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\gg\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\doteq\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\simeq\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\subset\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\supset\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\approx\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\asymp\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\subseteq\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\supseteq\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\cong\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\smile\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\sqsubset\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\sqsupset\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\equiv\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\frown\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\sqsubseteq\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\sqsupseteq\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\propto\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\bowtie\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\in\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\ni\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\prec\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\succ\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\vdash\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\dashv\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\preceq\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\succeq\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\models\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\perp\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\parallel\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\mid\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\bumpeq\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td></tr></tbody></table><p>关系符号前面加一个n，就可以变成这些关系符号的反义</p><table><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\nmid\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\nleq\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\ngeq\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\nsim\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\ncong\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\nparallel\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\not&lt;\)</span></td><td style="text-align: center;">&lt;</td><td style="text-align: center;"><spanclass="math inline">\(\not&gt;\)</span></td><td style="text-align: center;">&gt;</td><td style="text-align: center;"><spanclass="math inline">\(\not=\)</span></td><td style="text-align: center;">= or or </td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\not\le\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\not\ge\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\not\sim\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><span class="math inline">\(\not\approx\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\not\cong\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\not\equiv\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\not\parallel\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\nless\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\ngtr\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\lneq\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\gneq\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\lnsim\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\lneqq\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\gneqq\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td></tr></tbody></table><h3 id="希腊字母">希腊字母</h3><table><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\alpha\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\beta\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\gamma\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\delta\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\epsilon\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\varepsilon\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\zeta\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\eta\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\theta\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\vartheta\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\iota\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\kappa\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\lambda\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\mu\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\nu\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\xi\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\pi\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\varpi\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\rho\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\varrho\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\sigma\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\varsigma\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\tau\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\upsilon\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\phi\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\varphi\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\chi\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\psi\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\omega\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td></tr></tbody></table><p>一些大写的希腊字母</p><table style="width:100%;"><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\Gamma\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Delta\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Theta\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Lambda\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\Xi\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Pi\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Sigma\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Upsilon\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\Phi\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Psi\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Omega\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td></tr></tbody></table><h3 id="箭头">箭头</h3><table><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\gets\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\to\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\leftarrow\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Leftarrow\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\rightarrow\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Rightarrow\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\leftrightarrow\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Leftrightarrow\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\mapsto\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\hookleftarrow\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\leftharpoonup\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\leftharpoondown\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\rightleftharpoons\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\longleftarrow\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\Longleftarrow\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\longrightarrow\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\Longrightarrow\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\longleftrightarrow\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\Longleftrightarrow\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\longmapsto\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\hookrightarrow\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\rightharpoonup\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\rightharpoondown\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\leadsto\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\uparrow\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Uparrow\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\downarrow\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Downarrow\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\updownarrow\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Updownarrow\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\nearrow\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\searrow\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\swarrow\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\nwarrow\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\overrightarrow{AB}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\overleftarrow{AB}\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\overleftrightarrow{AB}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td></tr></tbody></table><h3 id="一些奇奇怪怪的点">一些奇奇怪怪的点</h3><table><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\cdot\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\vdots\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\dots\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\ddots\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\cdots\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td></tr></tbody></table><h3 id="字母上的强调符号">字母上的强调符号</h3><table><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\hat{x}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\check{x}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\dot{x}\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\breve{x}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\acute{x}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\ddot{x}\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\grave{x}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\tilde{x}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\mathring{x}\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\bar{x}\)</span></td><td style="text-align: center;">{x}</td><td style="text-align: center;"><spanclass="math inline">\(\vec{x}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td></tr></tbody></table><p>当对 <span class="math inline">\(i\)</span>和<spanclass="math inline">\(j\)</span>应用强调符号时，可以使用：</p><table><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\vec{\jmath}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\tilde{\imath}\)</span></td><td style="text-align: center;"></td></tr></tbody></table><p>和 有一个更宽的版本，<spanclass="math inline">\(\hat{7+x}\)</span>和<spanclass="math inline">\(\widehat{7+x}\)</span>两种箭头是有区别的：</p><table><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\widehat{7+x}\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\widetilde{abc}\)</span></td><td style="text-align: center;"></td></tr></tbody></table><h3 id="其他一些奇怪的符号">其他一些奇怪的符号</h3><table><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\infty\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\triangle\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\angle\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\aleph\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\hbar\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\imath\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\jmath\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\ell\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\wp\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\Re\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Im\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\mho\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\prime\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\emptyset\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\nabla\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\surd\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\partial\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\top\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\bot\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\vdash\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\dashv\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\forall\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\exists\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\neg\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\flat\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\natural\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\sharp\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\backslash\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Box\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Diamond\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\clubsuit\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\diamondsuit\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\heartsuit\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\spadesuit\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Join\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\blacksquare\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\diamondsuit\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\mathbb{R}\)</span></td><td style="text-align: center;"> (represents all real numbers)</td><td style="text-align: center;"><spanclass="math inline">\(\checkmark\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\heartsuit\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\in\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\cup\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\S\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\P\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Vdash\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\vDash\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td></tr></tbody></table><h3 id="括号">括号</h3><p>In mathematics, sometimes we need to enclose expressions in brackets,braces or parentheses. Some of these work just as you'd imagine inLaTeX; type ( and ) for parentheses, [ and ] for brackets, and | and |for absolute value. However, other symbols have special commands:</p><table><thead><tr class="header"><th style="text-align: left;">Symbol</th><th style="text-align: left;">Command</th><th style="text-align: left;">Symbol</th><th style="text-align: left;">Command</th><th style="text-align: left;">Symbol</th><th style="text-align: left;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: left;"><spanclass="math display">\[\{\]</span></td><td style="text-align: left;">{</td><td style="text-align: left;"><spanclass="math display">\[\}\]</span></td><td style="text-align: left;">}</td><td style="text-align: left;"><spanclass="math inline">\(\|\)</span></td><td style="text-align: left;">|</td></tr><tr class="even"><td style="text-align: left;"><spanclass="math inline">\(\backslash\)</span></td><td style="text-align: left;"></td><td style="text-align: left;"><spanclass="math inline">\(\lfloor\)</span></td><td style="text-align: left;"></td><td style="text-align: left;"><spanclass="math inline">\(\rfloor\)</span></td><td style="text-align: left;"></td></tr><tr class="odd"><td style="text-align: left;"><spanclass="math inline">\(\lceil\)</span></td><td style="text-align: left;"></td><td style="text-align: left;"><spanclass="math inline">\(\rceil\)</span></td><td style="text-align: left;"></td><td style="text-align: left;"><spanclass="math inline">\(\langle\)</span></td><td style="text-align: left;"></td></tr><tr class="even"><td style="text-align: left;"><spanclass="math inline">\(\rangle\)</span></td><td style="text-align: left;"></td><td style="text-align: left;"></td><td style="text-align: left;"></td><td style="text-align: left;"></td><td style="text-align: left;"></td></tr></tbody></table><h2 id="编写数学公式">编写数学公式</h2><h3 id="下标和上标">下标和上标</h3><p>下标和上标（例如指数）可以分别使用下划线_和箭头^符号。</p><table><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(2^{2}\)</span></td><td style="text-align: center;">2^2</td><td style="text-align: center;"><span class="math inline">\(\textstylea_i\)</span></td><td style="text-align: center;">a_i</td></tr><tr class="even"><td style="text-align: center;"><span class="math inline">\(\textstyle2^{23}\)</span></td><td style="text-align: center;">2^{23}</td><td style="text-align: center;"><span class="math inline">\(\textstylen_{i-1}\)</span></td><td style="text-align: center;">n_{i-1}</td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(a^{i+1}_3\)</span></td><td style="text-align: center;">a^{i+1}_3</td><td style="text-align: center;"><spanclass="math inline">\(x^{3^2}\)</span></td><td style="text-align: center;">x^{3^2}</td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(2^{a_i}\)</span></td><td style="text-align: center;">2^{a_i}</td><td style="text-align: center;"><spanclass="math inline">\(2^a_i\)</span></td><td style="text-align: center;">2^a_i</td></tr></tbody></table><h3 id="分式">分式</h3><p>使用来进行渲染</p><table><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><span class="math inline">\(\frac{1}{2}\)</span></td><td style="text-align: center;"> or </td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\frac{2}{x+2}\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\frac{1+\frac{1}{x}}{3x + 2}\)</span></td><td style="text-align: center;"></td></tr></tbody></table><p>如果分号比较多，建议用，看起来更大也舒服很多</p><table><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\cfrac{2}{1+\cfrac{2}{1+\cfrac{2}{1+\cfrac{2}{1}}}}\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\frac{2}{1+\frac{2}{1+\frac{2}{1+\frac{2}{1}}}}\)</span></td><td style="text-align: center;"></td></tr></tbody></table><h3id="累加累乘求极限求对数一类的符号">累加，累乘，求极限，求对数一类的符号</h3><p>分别使用命令、、。要表示下限和上限，或对数的底，使用_和^的方式与下标和上标相同。</p><table><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><span class="math inline">\(\textstyle\sum_{i=1}^{\infty}\frac{1}{i}\)</span></td><td style="text-align: center;">_{i=1}^{}</td></tr><tr class="even"><td style="text-align: center;"><span class="math inline">\(\textstyle\prod_{n=1}^5\frac{n}{n-1}\)</span></td><td style="text-align: center;">_{n=1}^5</td></tr><tr class="odd"><td style="text-align: center;"><span class="math inline">\(\textstyle\lim_{x\to\infty}\frac{1}{x}\)</span></td><td style="text-align: center;">_{x}</td></tr><tr class="even"><td style="text-align: center;"><span class="math inline">\(\textstyle\lim\limits_{x\to\infty}\frac{1}{x}\)</span></td><td style="text-align: center;">_{x}</td></tr><tr class="odd"><td style="text-align: center;"><span class="math inline">\(\textstyle\log_n n^2\)</span></td><td style="text-align: center;">_n n^2</td></tr></tbody></table><p>其中一些符号在latex的显示模式下更漂亮：</p><table><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><imgsrc="https://latex.artofproblemsolving.com/3/6/6/3668f57e794d7f20c001ff9776563d1b5e03dfaa.png"alt="\sum_{i=1}^{\infty}\frac{1}{i}" /></td><td style="text-align: center;">_{i=1}^{}</td></tr><tr class="even"><td style="text-align: center;"><imgsrc="https://latex.artofproblemsolving.com/3/8/6/38620f28e72b9e630220f8b9c5d90a077e9f140c.png"alt="\prod_{n=1}^5\frac{n}{n-1}" /></td><td style="text-align: center;">_{n=1}^5</td></tr><tr class="odd"><td style="text-align: center;"><imgsrc="https://latex.artofproblemsolving.com/2/d/b/2db126637f5c59d21b8686443b38eb82bfee3935.png"alt="\lim_{x\to\infty}\frac{1}{x}" /></td><td style="text-align: center;">_{x}</td></tr></tbody></table><h3 id="模运算符号">模运算符号</h3><table><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><span class="math inline">\(9\equiv 3\bmod{6}\)</span></td><td style="text-align: center;">9 </td></tr><tr class="even"><td style="text-align: center;"><span class="math inline">\(9\equiv 3\pmod{6}\)</span></td><td style="text-align: center;">9 </td></tr><tr class="odd"><td style="text-align: center;"><span class="math inline">\(9\equiv 3\mod{6}\)</span></td><td style="text-align: center;">9 </td></tr><tr class="even"><td style="text-align: center;"><span class="math inline">\(9\equiv3\pod{6}\)</span></td><td style="text-align: center;">9 </td></tr></tbody></table><h3 id="三角函数">三角函数</h3><table style="width:100%;"><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><span class="math inline">\(\textstyle\cos\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><span class="math inline">\(\textstyle\sin\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><span class="math inline">\(\textstyle\tan\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\sec\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><span class="math inline">\(\textstyle\textstyle \csc\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><span class="math inline">\(\textstyle\cot\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><span class="math inline">\(\textstyle\arccos\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><span class="math inline">\(\textstyle\arcsin\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><span class="math inline">\(\textstyle\arctan\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><span class="math inline">\(\textstyle\cosh\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><span class="math inline">\(\textstyle\sinh\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><span class="math inline">\(\textstyle\tanh\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><span class="math inline">\(\textstyle\coth\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td></tr></tbody></table><h3 id="矩阵">矩阵</h3><p>我们可以使用\begin｛array｝…\end｛array｝命令构建数组或矩阵，并使用</p><h3 id="其他符号">其他符号</h3><table><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\arg\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\textstyle\deg\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\textstyle\det\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\dim\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\textstyle\exp\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\textstyle\gcd\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\hom\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\inf\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\ker\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\textstyle\lg\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\liminf\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\limsup\)</span></td><td style="text-align: center;"></td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\textstyle\max\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\textstyle\min\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"><spanclass="math inline">\(\Pr\)</span></td><td style="text-align: center;"></td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\sup\)</span></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td></tr></tbody></table><p>其中一些命令的下标方式与求和、乘积和对数相同。有些渲染在显示模式和常规数学模式下不同。</p><table style="width:100%;"><thead><tr class="header"><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th><th style="text-align: center;">Symbol</th><th style="text-align: center;">Command</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\dim_x\)</span></td><td style="text-align: center;">_x</td><td style="text-align: center;"><spanclass="math inline">\(\textstyle\gcd_x\)</span></td><td style="text-align: center;">_x</td><td style="text-align: center;"><spanclass="math inline">\(\inf_x\)</span></td><td style="text-align: center;">_x</td></tr><tr class="even"><td style="text-align: center;"><spanclass="math inline">\(\liminf_x\)</span></td><td style="text-align: center;">_x</td><td style="text-align: center;"><spanclass="math inline">\(\limsup_x\)</span></td><td style="text-align: center;">_x</td><td style="text-align: center;"><spanclass="math inline">\(\textstyle\max_x\)</span></td><td style="text-align: center;">_x</td></tr><tr class="odd"><td style="text-align: center;"><spanclass="math inline">\(\textstyle\min_x\)</span></td><td style="text-align: center;">_x</td><td style="text-align: center;"><spanclass="math inline">\(\Pr_x\)</span></td><td style="text-align: center;">_x</td><td style="text-align: center;"><spanclass="math inline">\(\sup_x\)</span></td><td style="text-align: center;">_x</td></tr></tbody></table><h2 id="矩阵-1">矩阵</h2><p>把矩阵单独放在一个板块是因为矩阵有很多花招，很多很多不同的表示</p><h3 id="数字周围无符号">1. 数字周围无符号</h3><h4 id="数字周围无符号-1">数字周围无符号</h4><p><span class="math display">\[\begin{matrix}    1&amp;0\\    0&amp;1\end{matrix}\]</span></p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>&#123;matrix&#125;<br>    1<span class="hljs-built_in">&amp;</span>0<span class="hljs-keyword">\\</span><br>    0<span class="hljs-built_in">&amp;</span>1<br><span class="hljs-keyword">\end</span>&#123;matrix&#125;<br></code></pre></td></tr></table></figure><h4 id="小括号p">小括号+p</h4><p><span class="math display">\[\begin{pmatrix}    1&amp;0\\    0&amp;1\end{pmatrix}\]</span></p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>&#123;pmatrix&#125;<br>    1<span class="hljs-built_in">&amp;</span>0<span class="hljs-keyword">\\</span><br>    0<span class="hljs-built_in">&amp;</span>1<br><span class="hljs-keyword">\end</span>&#123;pmatrix&#125;<br></code></pre></td></tr></table></figure><h4 id="中括号b">中括号+b</h4><p><span class="math display">\[\begin{bmatrix}    1&amp;0\\    0&amp;1\end{bmatrix}\]</span></p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>&#123;bmatrix&#125;<br>    1<span class="hljs-built_in">&amp;</span>0<span class="hljs-keyword">\\</span><br>    0<span class="hljs-built_in">&amp;</span>1<br><span class="hljs-keyword">\end</span>&#123;bmatrix&#125;<br></code></pre></td></tr></table></figure><h4 id="大括号b">大括号+B</h4><p><span class="math display">\[\begin{Bmatrix}    1&amp;0\\    0&amp;1\end{Bmatrix}\]</span></p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>&#123;Bmatrix&#125;<br>    1<span class="hljs-built_in">&amp;</span>0<span class="hljs-keyword">\\</span><br>    0<span class="hljs-built_in">&amp;</span>1<br><span class="hljs-keyword">\end</span>&#123;Bmatrix&#125;<br></code></pre></td></tr></table></figure><h4 id="单竖线v">单竖线+v</h4><p><span class="math display">\[\begin{vmatrix}    1&amp;0\\    0&amp;1\end{vmatrix}\]</span></p><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs ruby">\<span class="hljs-keyword">begin</span>&#123;vmatrix&#125;<br>    <span class="hljs-number">1</span>&amp;<span class="hljs-number">0</span>\\<br>    <span class="hljs-number">0</span>&amp;<span class="hljs-number">1</span><br>\<span class="hljs-keyword">end</span>&#123;vmatrix&#125;<br></code></pre></td></tr></table></figure><h4 id="双竖线v">双竖线+V</h4><p><span class="math display">\[\begin{Vmatrix}    1&amp;0\\    0&amp;1\end{Vmatrix}\]</span></p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>&#123;Vmatrix&#125;<br>    1<span class="hljs-built_in">&amp;</span>0<span class="hljs-keyword">\\</span><br>    0<span class="hljs-built_in">&amp;</span>1<br><span class="hljs-keyword">\end</span>&#123;Vmatrix&#125;<br></code></pre></td></tr></table></figure><h3 id="省略号">省略号</h3><p>使用 <code>\dots</code>水平 <code>\vdots</code> 竖直<code>\ddots</code>倾斜<code>\hdotsfor&#123;&#125;</code>跨列省略号。大括号中填共几列 如： <spanclass="math display">\[\begin{bmatrix}a_{11} &amp; \dots &amp; a_{1n}\\&amp;\ddots &amp; \vdots \\a_{n1}&amp; &amp; a_{nn}\end{bmatrix}\]</span></p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-built_in">$</span><span class="hljs-built_in">$</span><br><span class="hljs-keyword">\begin</span>&#123;bmatrix&#125;<br>a<span class="hljs-built_in">_</span>&#123;11&#125; <span class="hljs-built_in">&amp;</span> <span class="hljs-keyword">\dots</span> <span class="hljs-built_in">&amp;</span> a<span class="hljs-built_in">_</span>&#123;1n&#125;<span class="hljs-keyword">\\</span><br><span class="hljs-built_in">&amp;</span><span class="hljs-keyword">\ddots</span> <span class="hljs-built_in">&amp;</span> <span class="hljs-keyword">\vdots</span> <span class="hljs-keyword">\\</span><br>a<span class="hljs-built_in">_</span>&#123;n1&#125;<span class="hljs-built_in">&amp;</span> <span class="hljs-built_in">&amp;</span> a<span class="hljs-built_in">_</span>&#123;nn&#125;<br><span class="hljs-keyword">\end</span>&#123;bmatrix&#125;<br><span class="hljs-built_in">$</span><span class="hljs-built_in">$</span><br></code></pre></td></tr></table></figure><h3 id="分块矩阵">分块矩阵</h3><p><span class="math display">\[\begin{bmatrix}\begin{matrix}1&amp;0\\0&amp;1\end{matrix}&amp; \text{\Large 0}\\\text{\Large 0}&amp;\begin{matrix}1&amp;0\\0&amp;1\end{matrix}\end{bmatrix}\]</span></p><blockquote><p><code>\Large 0</code>是比普通的零要大一些的</p></blockquote><p>上面矩阵的代码为：</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-built_in">$</span><span class="hljs-built_in">$</span><br><span class="hljs-keyword">\begin</span>&#123;bmatrix&#125;<br><span class="hljs-keyword">\begin</span>&#123;matrix&#125;1<span class="hljs-built_in">&amp;</span>0<span class="hljs-keyword">\\</span>0<span class="hljs-built_in">&amp;</span>1<span class="hljs-keyword">\end</span>&#123;matrix&#125;<span class="hljs-built_in">&amp;</span> <span class="hljs-keyword">\text</span>&#123;<span class="hljs-keyword">\Large</span> 0&#125;<span class="hljs-keyword">\\</span><br><span class="hljs-keyword">\text</span>&#123;<span class="hljs-keyword">\Large</span> 0&#125;<span class="hljs-built_in">&amp;</span><span class="hljs-keyword">\begin</span>&#123;matrix&#125;1<span class="hljs-built_in">&amp;</span>0<span class="hljs-keyword">\\</span>0<span class="hljs-built_in">&amp;</span>1<span class="hljs-keyword">\end</span>&#123;matrix&#125;<br><span class="hljs-keyword">\end</span>&#123;bmatrix&#125;<br><span class="hljs-built_in">$</span><span class="hljs-built_in">$</span><br></code></pre></td></tr></table></figure><blockquote><p><code>\text</code>是在数学编辑模式下临时使用文本编辑，在公式中输入汉字都要使用此标签。分块矩阵就是矩阵的嵌套，仔细阅读代码就能理解。</p></blockquote><h3 id="三角矩阵">三角矩阵</h3><p><span class="math display">\[\begin{bmatrix}a_{11}&amp;a_{12} &amp; \dots &amp; a_{1n}\\&amp;a_{22}&amp;\dots&amp;a_{2n}\\&amp;&amp;\ddots&amp;\vdots\\&amp;{\huge 0}&amp;&amp;a_{nn}\end{bmatrix}\]</span></p><p>具体代码如下</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-built_in">$</span><span class="hljs-built_in">$</span><br><span class="hljs-keyword">\begin</span>&#123;bmatrix&#125;<br>a<span class="hljs-built_in">_</span>&#123;11&#125;<span class="hljs-built_in">&amp;</span>a<span class="hljs-built_in">_</span>&#123;12&#125; <span class="hljs-built_in">&amp;</span> <span class="hljs-keyword">\dots</span> <span class="hljs-built_in">&amp;</span> a<span class="hljs-built_in">_</span>&#123;1n&#125;<span class="hljs-keyword">\\</span><br><span class="hljs-built_in">&amp;</span>a<span class="hljs-built_in">_</span>&#123;22&#125;<span class="hljs-built_in">&amp;</span><span class="hljs-keyword">\dots</span><span class="hljs-built_in">&amp;</span>a<span class="hljs-built_in">_</span>&#123;2n&#125;<span class="hljs-keyword">\\</span><br><span class="hljs-built_in">&amp;</span><span class="hljs-built_in">&amp;</span><span class="hljs-keyword">\ddots</span><span class="hljs-built_in">&amp;</span><span class="hljs-keyword">\vdots</span><span class="hljs-keyword">\\</span><br><span class="hljs-built_in">&amp;</span>&#123;<span class="hljs-keyword">\huge</span> 0&#125;<span class="hljs-built_in">&amp;</span><span class="hljs-built_in">&amp;</span>a<span class="hljs-built_in">_</span>&#123;nn&#125;<br><span class="hljs-keyword">\end</span>&#123;bmatrix&#125;<br><span class="hljs-built_in">$</span><span class="hljs-built_in">$</span><br></code></pre></td></tr></table></figure><h3 id="方程组">方程组</h3><p>方程组四舍五入也算半个矩阵吧 <span class="math display">\[\begin{equation}    \begin{cases}        l_{11}y_{1} = 1 \\        l_{21}y_{1} + l_{22}y_{2} = 0 \\        l_{31}y_{1} + l_{32}y_{2} + l_{33}y_{3} = 0 \\        l_{41}y_{1} + l_ {42}y_{2} + l_{43}y_{3} + l_{44}y_{4} = 0     \end{cases}\end{equation}\]</span></p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-built_in">$</span><span class="hljs-built_in">$</span><br><span class="hljs-keyword">\begin</span>&#123;equation&#125;<br>    <span class="hljs-keyword">\begin</span>&#123;cases&#125;<br>        l<span class="hljs-built_in">_</span>&#123;11&#125;y<span class="hljs-built_in">_</span>&#123;1&#125; = 1 <span class="hljs-keyword">\\</span><br>        l<span class="hljs-built_in">_</span>&#123;21&#125;y<span class="hljs-built_in">_</span>&#123;1&#125; + l<span class="hljs-built_in">_</span>&#123;22&#125;y<span class="hljs-built_in">_</span>&#123;2&#125; = 0 <span class="hljs-keyword">\\</span> <br>        l<span class="hljs-built_in">_</span>&#123;31&#125;y<span class="hljs-built_in">_</span>&#123;1&#125; + l<span class="hljs-built_in">_</span>&#123;32&#125;y<span class="hljs-built_in">_</span>&#123;2&#125; + l<span class="hljs-built_in">_</span>&#123;33&#125;y<span class="hljs-built_in">_</span>&#123;3&#125; = 0 <span class="hljs-keyword">\\</span><br>        l<span class="hljs-built_in">_</span>&#123;41&#125;y<span class="hljs-built_in">_</span>&#123;1&#125; + l<span class="hljs-built_in">_</span> &#123;42&#125;y<span class="hljs-built_in">_</span>&#123;2&#125; + l<span class="hljs-built_in">_</span>&#123;43&#125;y<span class="hljs-built_in">_</span>&#123;3&#125; + l<span class="hljs-built_in">_</span>&#123;44&#125;y<span class="hljs-built_in">_</span>&#123;4&#125; = 0<br>     <span class="hljs-keyword">\end</span>&#123;cases&#125;<br><span class="hljs-keyword">\end</span>&#123;equation&#125;<br><span class="hljs-built_in">$</span><span class="hljs-built_in">$</span><br></code></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">写出好看的公式，生活会更有趣</summary>
    
    
    
    <category term="笔记" scheme="http://example.com/categories/%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="latex" scheme="http://example.com/tags/latex/"/>
    
  </entry>
  
  <entry>
    <title>ubuntu安装openssl库</title>
    <link href="http://example.com/2022/10/21/ubuntu%E5%AE%89%E8%A3%85openssl%E5%BA%93/"/>
    <id>http://example.com/2022/10/21/ubuntu%E5%AE%89%E8%A3%85openssl%E5%BA%93/</id>
    <published>2022-10-21T07:25:40.000Z</published>
    <updated>2022-10-21T09:07:42.262Z</updated>
    
    <content type="html"><![CDATA[<h1 id="ubuntu18.04安装openssl库">ubuntu18.04安装openssl库</h1><p>opensssl库是常用的加密函数库，主要有以下加密算法</p><blockquote><p>加密算法</p><ul><li>对称加密：指加密和解密使用相同密钥的加密算法。对称加密算法的优点在于加解密的高速度和使用长密钥时的难破解性。常见的对称加密算法：DES、3DES、DESX、AES、RC4、RC5、RC6等</li><li>非对称加密：指加密和解密使用不同密钥的加密算法，也称为公私钥加密。常见的非对称加密算法：RSA、DSA（数字签名用）等</li><li>Hash算法：Hash算法它是一种单向算法，用户可以通过Hash算法对目标信息生成一段特定长度的唯一的Hash值，却不能通过这个Hash值逆向获得目标信息。常见的Hash算法：MD2、MD4、MD5、SHA、SHA-1等</li></ul></blockquote><p>下面介绍openssl库的安装</p><h2 id="安装方法">安装方法</h2><h3 id="打开命令行终端">打开命令行终端</h3><p>新手的话按ctrl+alt+t即可</p><h3 id="更新下载编译器-make-和-gcc">更新/下载编译器 make 和 gcc</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo apt install make gcc<br>sudo apt update<br>sudo apt upgrade<br></code></pre></td></tr></table></figure><h3 id="下载openssl安装包">下载OpenSSL安装包</h3><p>以版本openssl-1.1.1q版本为例，想要其他版本请到官网下载指定版本：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo wget https://www.openssl.org/source/openssl-1.1.1b.tar.gz<br></code></pre></td></tr></table></figure><h3 id="解压缩">解压缩</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo tar -zxf openssl-1.1.1b.tar.gz &amp;&amp; <span class="hljs-built_in">cd</span> openssl-1.1.1b<br></code></pre></td></tr></table></figure><h3 id="编译安装">编译安装</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo ./config shared<br>sudo make<br>sudo make install<br></code></pre></td></tr></table></figure><h3 id="修改默认路径">修改默认路径</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo <span class="hljs-built_in">ln</span> -s /usr/local/bin/openssl /usr/bin/openssl<br>sudo ldconfig<br></code></pre></td></tr></table></figure><h3 id="检查版本">检查版本</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">openssl version<br></code></pre></td></tr></table></figure><p>如果到这一步能输出版本信息</p><img src="/2022/10/21/ubuntu%E5%AE%89%E8%A3%85openssl%E5%BA%93/%E7%BB%93%E6%9E%9C%E8%BE%93%E5%87%BA.png" class="" title="版本信息"><h2 id="结果测试">结果测试</h2><h3 id="测试代码">测试代码</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span><span class="hljs-string">&lt;stdio.h&gt;</span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span><span class="hljs-string">&lt;sys/time.h&gt;</span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span><span class="hljs-string">&lt;openssl/bn.h&gt;</span></span><br><span class="hljs-keyword">struct</span> <span class="hljs-title class_">timeval</span> timestart, timeend ;<br><span class="hljs-type">float</span> timeuse_encrypt = <span class="hljs-number">0</span> , timeuse_decrypt = <span class="hljs-number">0</span>, timeuse_add = <span class="hljs-number">0</span> , timeuse_mul = <span class="hljs-number">0</span> , timeuse = <span class="hljs-number">0</span> ;<br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>&#123;   BN_CTX *ctx = <span class="hljs-built_in">BN_CTX_new</span>();<br>    <span class="hljs-built_in">BN_CTX_start</span>(ctx);<br>    BIGNUM *r1 = <span class="hljs-built_in">BN_CTX_get</span>(ctx);<br>    BIGNUM *r2 = <span class="hljs-built_in">BN_CTX_get</span>(ctx);<br>    BIGNUM *n = <span class="hljs-built_in">BN_CTX_get</span>(ctx);<br>    BIGNUM *tmp = <span class="hljs-built_in">BN_CTX_get</span>(ctx);<br>    BIGNUM *dv = <span class="hljs-built_in">BN_CTX_get</span>(ctx);<br>    BIGNUM *rem = <span class="hljs-built_in">BN_CTX_get</span>(ctx);<br>    <span class="hljs-built_in">BN_rand</span>(r1, <span class="hljs-number">236896</span> , <span class="hljs-number">0</span>, <span class="hljs-number">0</span>);<br>    <span class="hljs-built_in">BN_rand</span>(r2, <span class="hljs-number">236896</span> , <span class="hljs-number">0</span>, <span class="hljs-number">0</span>);<br>    <span class="hljs-built_in">BN_rand</span>(n, <span class="hljs-number">236896</span> , <span class="hljs-number">0</span>, <span class="hljs-number">0</span>);<br>    <br>    <span class="hljs-built_in">gettimeofday</span>(&amp;timestart, <span class="hljs-literal">NULL</span>);<span class="hljs-comment">//160*236896</span><br>    <span class="hljs-built_in">BN_mod_mul</span>(tmp , r1 , r2 , n  , ctx);<span class="hljs-comment">//a mod q = a/q*q</span><br>    <span class="hljs-built_in">gettimeofday</span>(&amp;timeend, <span class="hljs-literal">NULL</span>);<br>    timeuse = <span class="hljs-number">1000000</span> * (timeend.tv_sec - timestart.tv_sec) + timeend.tv_usec - timestart.tv_usec;<br>    <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;\nmod mul time:%f ms\n&quot;</span>, timeuse / <span class="hljs-number">1000</span>);<br>    <br>    <span class="hljs-built_in">gettimeofday</span>(&amp;timestart, <span class="hljs-literal">NULL</span>);<span class="hljs-comment">//160*236896</span><br>    <span class="hljs-built_in">BN_mul</span>(tmp , r1 , r2  , ctx);<span class="hljs-comment">//a mod q = a/q*q</span><br>    <span class="hljs-built_in">gettimeofday</span>(&amp;timeend, <span class="hljs-literal">NULL</span>);<br>    timeuse = <span class="hljs-number">1000000</span> * (timeend.tv_sec - timestart.tv_sec) + timeend.tv_usec - timestart.tv_usec;<br>    <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;\nmul time:%f ms\n&quot;</span>, timeuse / <span class="hljs-number">1000</span>);<br><br>    <span class="hljs-built_in">gettimeofday</span>(&amp;timestart, <span class="hljs-literal">NULL</span>);<span class="hljs-comment">//160*236896</span><br>    <span class="hljs-built_in">BN_div</span>(dv , rem , tmp ,n , ctx);<span class="hljs-comment">//r1*r2/n</span><br>    <span class="hljs-built_in">gettimeofday</span>(&amp;timeend, <span class="hljs-literal">NULL</span>);<br>    timeuse = <span class="hljs-number">1000000</span> * (timeend.tv_sec - timestart.tv_sec) + timeend.tv_usec - timestart.tv_usec;<br>    <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;\ndiv time:%f ms\n&quot;</span>, timeuse / <span class="hljs-number">1000</span>);<br>    <br>    <span class="hljs-built_in">gettimeofday</span>(&amp;timestart, <span class="hljs-literal">NULL</span>);<span class="hljs-comment">//160*236896</span><br>    <span class="hljs-built_in">BN_mod</span>(tmp , tmp , n  , ctx);<span class="hljs-comment">//r1*r2/n mod q = a/q*q</span><br>    <span class="hljs-built_in">gettimeofday</span>(&amp;timeend, <span class="hljs-literal">NULL</span>);<br>    timeuse = <span class="hljs-number">1000000</span> * (timeend.tv_sec - timestart.tv_sec) + timeend.tv_usec - timestart.tv_usec;<br>    <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;\nmod time:%f ms\n&quot;</span>, timeuse / <span class="hljs-number">1000</span>);<br>    <span class="hljs-built_in">BN_CTX_end</span>(ctx);<br>    <span class="hljs-built_in">BN_CTX_free</span>(ctx);<br>    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="编译运行">编译运行</h3><p>输入如下指令可以编译运行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">gcc test.c -lcrypto<br>./a.out<br></code></pre></td></tr></table></figure><p>可以看到如下输出结果</p><img src="/2022/10/21/ubuntu%E5%AE%89%E8%A3%85openssl%E5%BA%93/%E6%B5%8B%E8%AF%95%E7%BB%93%E6%9E%9C.png" class="" title="测试结果">]]></content>
    
    
    <summary type="html">突然间，哈桑的声音在我脑海中响起：为你，千千万万遍。哈桑，那个兔唇的哈桑，那个追风筝的人</summary>
    
    
    
    <category term="密码学" scheme="http://example.com/categories/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
    
    
    <category term="linux操作系统" scheme="http://example.com/tags/linux%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"/>
    
    <category term="环境配置" scheme="http://example.com/tags/%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/"/>
    
    <category term="c++" scheme="http://example.com/tags/c/"/>
    
  </entry>
  
  <entry>
    <title>分组密码小笔记</title>
    <link href="http://example.com/2022/10/18/%E5%88%86%E7%BB%84%E5%AF%86%E7%A0%81%E5%B0%8F%E7%AC%94%E8%AE%B0/"/>
    <id>http://example.com/2022/10/18/%E5%88%86%E7%BB%84%E5%AF%86%E7%A0%81%E5%B0%8F%E7%AC%94%E8%AE%B0/</id>
    <published>2022-10-18T06:16:14.000Z</published>
    <updated>2024-12-03T16:26:37.596Z</updated>
    
    <content type="html"><![CDATA[<h1 id="分组密码">分组密码</h1><p>这学期学习现代密码学，密码的各种加密方式有很多细节，还有大体的框架，浅浅做个笔记记录一下，以后可以随时回顾。</p><p>参考博客：</p><ul><li><ahref="https://blog.csdn.net/qq_28205153/article/details/55798628#commentBox">AES加密算法的详细介绍与实现</a></li><li><ahref="https://www.cnblogs.com/starwolf/p/3365834.html">AES五种加密模式（CBC、ECB、CTR、OCF、CFB)</a></li></ul><h2 id="des">DES</h2><h2 id="aes">AES</h2><h3 id="aes简介">AES简介</h3><p>高级加密标准(AES,Advanced Encryption Standard)为最常见的对称<ahref="https://so.csdn.net/so/search?q=加密算法&amp;spm=1001.2101.3001.7020">加密算法</a>(微信小程序加密传输就是用这个加密算法的)。对称加密算法也就是加密和解密用相同的密钥，具体的加密流程如下图：<imgsrc="https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwMjE5MDgyOTA5Njg4?x-oss-process=image/format,png"alt="加密流程图" /> 下面简单介绍下各个部分的作用与意义：</p><ul><li>明文P</li></ul><blockquote><p>没有经过加密的数据。</p></blockquote><ul><li>密钥K</li></ul><blockquote><p>用来加密明文的密码，在对称加密算法中，加密与解密的<ahref="https://so.csdn.net/so/search?q=密钥&amp;spm=1001.2101.3001.7020">密钥</a>是相同的。密钥为接收方与发送方协商产生，但不可以直接在网络上传输，否则会导致密钥泄漏，通常是通过非对称加密算法加密密钥，然后再通过网络传输给对方，或者直接面对面商量密钥。密钥是绝对不可以泄漏的，否则会被攻击者还原密文，窃取机密数据。</p></blockquote><ul><li>AES加密函数</li></ul><blockquote><p>设<ahref="https://so.csdn.net/so/search?q=AES加密&amp;spm=1001.2101.3001.7020">AES加密</a>函数为E，则C = E(K,P),其中P为明文，K为密钥，C为密文。也就是说，把明文P和密钥K作为加密函数的参数输入，则加密函数E会输出密文C。</p></blockquote><ul><li>密文C</li></ul><blockquote><p>经加密函数处理后的数据</p></blockquote><ul><li>AES解密函数</li></ul><blockquote><p>设AES解密函数为D，则 P = D(K,C),其中C为密文，K为密钥，P为明文。也就是说，把密文C和密钥K作为解密函数的参数输入，则解密函数会输出明文P。</p></blockquote><p>在这里简单介绍下对称加密算法与非对称加密算法的区别。</p><ul><li>对称加密算法</li></ul><blockquote><p>加密和解密用到的密钥是相同的，这种加密方式加密速度非常快，适合经常发送数据的场合。缺点是密钥的传输比较麻烦。</p></blockquote><ul><li>非对称加密算法</li></ul><blockquote><p>加密和解密用的密钥是不同的，这种加密方式是用数学上的难解问题构造的，通常加密解密的速度比较慢，适合偶尔发送数据的场合。优点是密钥传输方便。常见的非对称加密算法为RSA、ECC和EIGamal。</p></blockquote><p>实际中，一般是通过RSA<ahref="https://so.csdn.net/so/search?q=加密&amp;spm=1001.2101.3001.7020">加密</a>AES的密钥，传输到接收方，接收方解密得到AES密钥，然后发送方和接收方用AES密钥来通信。</p><p>本文下面AES原理的介绍参考自《现代密码学教程》，AES的实现在介绍完原理后开始。</p><h3 id="aes的基本结构">AES的基本结构</h3><p>AES为分组密码，分组密码也就是把明文分成一组一组的，每组长度相等，每次加密一组数据，直到加密完整个明文。在AES标准规范中，分组长度只能是128位，也就是说，每个分组为16个字节（每个字节8位）。密钥的长度可以使用128位、192位或256位。密钥的长度不同，推荐加密轮数也不同，如下表所示：</p><table><thead><tr class="header"><th style="text-align: center;">AES</th><th style="text-align: center;">密钥长度（单位byte)</th><th style="text-align: center;">分组长度(单位byte)</th><th style="text-align: center;">加密轮数</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;">AES-128</td><td style="text-align: center;">16</td><td style="text-align: center;">16</td><td style="text-align: center;">10</td></tr><tr class="even"><td style="text-align: center;">AES-192</td><td style="text-align: center;">24</td><td style="text-align: center;">16</td><td style="text-align: center;">12</td></tr><tr class="odd"><td style="text-align: center;">AES-256</td><td style="text-align: center;">32</td><td style="text-align: center;">16</td><td style="text-align: center;">14</td></tr></tbody></table><p>轮数在下面介绍，这里实现的是AES-128，也就是密钥的长度为128位，加密轮数为10轮。上面说到，AES的加密公式为C =E(K,P)，在加密函数E中，会执行一个轮函数，并且执行10次这个轮函数，这个轮函数的前9次执行的操作是一样的，只有第10次有所不同。也就是说，一个明文分组会被加密10轮。AES的核心就是实现一轮中的所有操作。</p><p>AES的处理单位是字节，128位的输入明文分组P和输入密钥K都被分成16个字节，分别记为：</p><p><span class="math inline">\(P = P0\;P1 \dots P15\)</span></p><p><span class="math inline">\(K = K0\;K1 \dots K15\)</span></p><p>如，明文分组为P =abcdefghijklmnop,其中的字符a对应P0，p对应P15。一般地，明文分组用字节为单位的正方形矩阵描述，称为状态矩阵。在算法的每一轮中，状态矩阵的内容不断发生变化，最后的结果作为密文输出。该矩阵中字节的排列顺序为从上到下、从左至右依次排列，如下图所示：<imgsrc="https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwMjE5MTMyNTQ4OTA2?x-oss-process=image/format,png"alt="state" /></p><p>现在假设明文分组P为"abcdefghijklmnop"，则对应上面生成的状态矩阵图如下：<imgsrc="https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwMjE5MTM0NzIyODEy?x-oss-process=image/format,png"alt="state2" />上图中，0x61为字符a的十六进制表示。可以看到，明文经过AES加密后，已经面目全非。</p><ul><li>128位密钥也是用字节为单位的矩阵表示，矩阵的每一列被称为1个32位比特字。</li><li>通过密钥编排函数该密钥矩阵被扩展成一个44个字组成的序列<spanclass="math inline">\(W[0],W[1], …,W[43]\)</span>,序列中每个元素的大小为32bit</li><li>该序列的前4个元素<spanclass="math inline">\(W[0],W[1],W[2],W[3]\)</span>是原始密钥，用于加密运算中的初始密钥加（下面介绍）</li><li>后面40个字分为10组，每组4个字（128比特）分别用于10轮加密运算中的轮密钥加，如下图所示：<imgsrc="https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwMjE5MTUyNjM4MzI0?x-oss-process=image/format,png"alt="keystate" /> 上图中，设K = “abcdefghijklmnop”，则<spanclass="math inline">\(K0 = a, K15 = p, W[0] = K0 |K1| K2 |K3 =“abcd”\)</span>。</li></ul><p>AES的整体结构如下图所示，其中的W[0,3]是指W[0]、W[1]、W[2]和W[3]串联组成的128位密钥。加密的第1轮到第9轮的轮函数一样，包括<font color="red">4个操作：字节代换、行位移、列混合和轮密钥加</font>。最后一轮迭代不执行列混合。另外，在第一轮迭代之前，先将明文和原始密钥进行一次异或加密操作。<imgsrc="https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwMjE5MTYxMjAyNDg1?x-oss-process=image/format,png"alt="aes_struct" />上图也展示了AES解密过程，解密过程仍为10轮，每一轮的操作是加密操作的逆操作。由于AES的4个轮操作都是可逆的，因此，解密操作的一轮就是顺序执行逆行移位、逆字节代换、轮密钥加和逆列混合。同加密操作类似，最后一轮不执行逆列混合，在第1轮解密之前，要执行1次密钥加操作。</p><p>下面分别介绍AES中一轮的4个操作阶段，这4分操作阶段使输入位得到充分的混淆。</p><h3 id="aes加解密具体流程">AES加解密具体流程</h3><h4 id="字节代换">字节代换</h4><p>把该字节的高4位作为行值，低4位作为列值，取出S盒中对应的元素作为输出</p><h5 id="字节代换操作">字节代换操作</h5><p>AES的字节代换其实就是一个简单的查表操作。AES定义了一个S盒和一个逆S盒。AES的S盒：</p><table><thead><tr class="header"><th>行/列</th><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>8</th><th>9</th><th>A</th><th>B</th><th>C</th><th>D</th><th>E</th><th>F</th></tr></thead><tbody><tr class="odd"><td>0</td><td>0x63</td><td>0x7c</td><td>0x77</td><td>0x7b</td><td>0xf2</td><td>0x6b</td><td>0x6f</td><td>0xc5</td><td>0x30</td><td>0x01</td><td>0x67</td><td>0x2b</td><td>0xfe</td><td>0xd7</td><td>0xab</td><td>0x76</td></tr><tr class="even"><td>1</td><td>0xca</td><td>0x82</td><td>0xc9</td><td>0x7d</td><td>0xfa</td><td>0x59</td><td>0x47</td><td>0xf0</td><td>0xad</td><td>0xd4</td><td>0xa2</td><td>0xaf</td><td>0x9c</td><td>0xa4</td><td>0x72</td><td>0xc0</td></tr><tr class="odd"><td>2</td><td>0xb7</td><td>0xfd</td><td>0x93</td><td>0x26</td><td>0x36</td><td>0x3f</td><td>0xf7</td><td>0xcc</td><td>0x34</td><td>0xa5</td><td>0xe5</td><td>0xf1</td><td>0x71</td><td>0xd8</td><td>0x31</td><td>0x15</td></tr><tr class="even"><td>3</td><td>0x04</td><td>0xc7</td><td>0x23</td><td>0xc3</td><td>0x18</td><td>0x96</td><td>0x05</td><td>0x9a</td><td>0x07</td><td>0x12</td><td>0x80</td><td>0xe2</td><td>0xeb</td><td>0x27</td><td>0xb2</td><td>0x75</td></tr><tr class="odd"><td>4</td><td>0x09</td><td>0x83</td><td>0x2c</td><td>0x1a</td><td>0x1b</td><td>0x6e</td><td>0x5a</td><td>0xa0</td><td>0x52</td><td>0x3b</td><td>0xd6</td><td>0xb3</td><td>0x29</td><td>0xe3</td><td>0x2f</td><td>0x84</td></tr><tr class="even"><td>5</td><td>0x53</td><td>0xd1</td><td>0x00</td><td>0xed</td><td>0x20</td><td>0xfc</td><td>0xb1</td><td>0x5b</td><td>0x6a</td><td>0xcb</td><td>0xbe</td><td>0x39</td><td>0x4a</td><td>0x4c</td><td>0x58</td><td>0xcf</td></tr><tr class="odd"><td>6</td><td>0xd0</td><td>0xef</td><td>0xaa</td><td>0xfb</td><td>0x43</td><td>0x4d</td><td>0x33</td><td>0x85</td><td>0x45</td><td>0xf9</td><td>0x02</td><td>0x7f</td><td>0x50</td><td>0x3c</td><td>0x9f</td><td>0xa8</td></tr><tr class="even"><td>7</td><td>0x51</td><td>0xa3</td><td>0x40</td><td>0x8f</td><td>0x92</td><td>0x9d</td><td>0x38</td><td>0xf5</td><td>0xbc</td><td>0xb6</td><td>0xda</td><td>0x21</td><td>0x10</td><td>0xff</td><td>0xf3</td><td>0xd2</td></tr><tr class="odd"><td>8</td><td>0xcd</td><td>0x0c</td><td>0x13</td><td>0xec</td><td>0x5f</td><td>0x97</td><td>0x44</td><td>0x17</td><td>0xc4</td><td>0xa7</td><td>0x7e</td><td>0x3d</td><td>0x64</td><td>0x5d</td><td>0x19</td><td>0x73</td></tr><tr class="even"><td>9</td><td>0x60</td><td>0x81</td><td>0x4f</td><td>0xdc</td><td>0x22</td><td>0x2a</td><td>0x90</td><td>0x88</td><td>0x46</td><td>0xee</td><td>0xb8</td><td>0x14</td><td>0xde</td><td>0x5e</td><td>0x0b</td><td>0xdb</td></tr><tr class="odd"><td>A</td><td>0xe0</td><td>0x32</td><td>0x3a</td><td>0x0a</td><td>0x49</td><td>0x06</td><td>0x24</td><td>0x5c</td><td>0xc2</td><td>0xd3</td><td>0xac</td><td>0x62</td><td>0x91</td><td>0x95</td><td>0xe4</td><td>0x79</td></tr><tr class="even"><td>B</td><td>0xe7</td><td>0xc8</td><td>0x37</td><td>0x6d</td><td>0x8d</td><td>0xd5</td><td>0x4e</td><td>0xa9</td><td>0x6c</td><td>0x56</td><td>0xf4</td><td>0xea</td><td>0x65</td><td>0x7a</td><td>0xae</td><td>0x08</td></tr><tr class="odd"><td>C</td><td>0xba</td><td>0x78</td><td>0x25</td><td>0x2e</td><td>0x1c</td><td>0xa6</td><td>0xb4</td><td>0xc6</td><td>0xe8</td><td>0xdd</td><td>0x74</td><td>0x1f</td><td>0x4b</td><td>0xbd</td><td>0x8b</td><td>0x8a</td></tr><tr class="even"><td>D</td><td>0x70</td><td>0x3e</td><td>0xb5</td><td>0x66</td><td>0x48</td><td>0x03</td><td>0xf6</td><td>0x0e</td><td>0x61</td><td>0x35</td><td>0x57</td><td>0xb9</td><td>0x86</td><td>0xc1</td><td>0x1d</td><td>0x9e</td></tr><tr class="odd"><td>E</td><td>0xe1</td><td>0xf8</td><td>0x98</td><td>0x11</td><td>0x69</td><td>0xd9</td><td>0x8e</td><td>0x94</td><td>0x9b</td><td>0x1e</td><td>0x87</td><td>0xe9</td><td>0xce</td><td>0x55</td><td>0x28</td><td>0xdf</td></tr><tr class="even"><td>F</td><td>0x8c</td><td>0xa1</td><td>0x89</td><td>0x0d</td><td>0xbf</td><td>0xe6</td><td>0x42</td><td>0x68</td><td>0x41</td><td>0x99</td><td>0x2d</td><td>0x0f</td><td>0xb0</td><td>0x54</td><td>0xbb</td><td>0x16</td></tr></tbody></table><p>状态矩阵中的元素按照下面的方式映射为一个新的字节：把该字节的高4位作为行值，低4位作为列值，取出S盒或者逆S盒中对应的行的元素作为输出。例如，加密时，输出的字节S1为0x12,则查S盒的第0x01行和0x02列，得到值0xc9,然后替换S1原有的0x12为0xc9。状态矩阵经字节代换后的图如下：<imgsrc="https://img-blog.csdnimg.cn/20181213112210707.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4MjA1MTUz,size_16,color_FFFFFF,t_70"alt="字节变换" /></p><h5 id="字节代换逆操作">字节代换逆操作</h5><p>逆字节代换也就是查逆S盒来变换，逆S盒如下：</p><table><thead><tr class="header"><th>列 行</th><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>8</th><th>9</th><th>A</th><th>B</th><th>C</th><th>D</th><th>E</th><th>F</th></tr></thead><tbody><tr class="odd"><td>0</td><td>0x52</td><td>0x09</td><td>0x6a</td><td>0xd5</td><td>0x30</td><td>0x36</td><td>0xa5</td><td>0x38</td><td>0xbf</td><td>0x40</td><td>0xa3</td><td>0x9e</td><td>0x81</td><td>0xf3</td><td>0xd7</td><td>0xfb</td></tr><tr class="even"><td>1</td><td>0x7c</td><td>0xe3</td><td>0x39</td><td>0x82</td><td>0x9b</td><td>0x2f</td><td>0xff</td><td>0x87</td><td>0x34</td><td>0x8e</td><td>0x43</td><td>0x44</td><td>0xc4</td><td>0xde</td><td>0xe9</td><td>0xcb</td></tr><tr class="odd"><td>2</td><td>0x54</td><td>0x7b</td><td>0x94</td><td>0x32</td><td>0xa6</td><td>0xc2</td><td>0x23</td><td>0x3d</td><td>0xee</td><td>0x4c</td><td>0x95</td><td>0x0b</td><td>0x42</td><td>0xfa</td><td>0xc3</td><td>0x4e</td></tr><tr class="even"><td>3</td><td>0x08</td><td>0x2e</td><td>0xa1</td><td>0x66</td><td>0x28</td><td>0xd9</td><td>0x24</td><td>0xb2</td><td>0x76</td><td>0x5b</td><td>0xa2</td><td>0x49</td><td>0x6d</td><td>0x8b</td><td>0xd1</td><td>0x25</td></tr><tr class="odd"><td>4</td><td>0x72</td><td>0xf8</td><td>0xf6</td><td>0x64</td><td>0x86</td><td>0x68</td><td>0x98</td><td>0x16</td><td>0xd4</td><td>0xa4</td><td>0x5c</td><td>0xcc</td><td>0x5d</td><td>0x65</td><td>0xb6</td><td>0x92</td></tr><tr class="even"><td>5</td><td>0x6c</td><td>0x70</td><td>0x48</td><td>0x50</td><td>0xfd</td><td>0xed</td><td>0xb9</td><td>0xda</td><td>0x5e</td><td>0x15</td><td>0x46</td><td>0x57</td><td>0xa7</td><td>0x8d</td><td>0x9d</td><td>0x84</td></tr><tr class="odd"><td>6</td><td>0x90</td><td>0xd8</td><td>0xab</td><td>0x00</td><td>0x8c</td><td>0xbc</td><td>0xd3</td><td>0x0a</td><td>0xf7</td><td>0xe4</td><td>0x58</td><td>0x05</td><td>0xb8</td><td>0xb3</td><td>0x45</td><td>0x06</td></tr><tr class="even"><td>7</td><td>0xd0</td><td>0x2c</td><td>0x1e</td><td>0x8f</td><td>0xca</td><td>0x3f</td><td>0x0f</td><td>0x02</td><td>0xc1</td><td>0xaf</td><td>0xbd</td><td>0x03</td><td>0x01</td><td>0x13</td><td>0x8a</td><td>0x6b</td></tr><tr class="odd"><td>8</td><td>0x3a</td><td>0x91</td><td>0x11</td><td>0x41</td><td>0x4f</td><td>0x67</td><td>0xdc</td><td>0xea</td><td>0x97</td><td>0xf2</td><td>0xcf</td><td>0xce</td><td>0xf0</td><td>0xb4</td><td>0xe6</td><td>0x73</td></tr><tr class="even"><td>9</td><td>0x96</td><td>0xac</td><td>0x74</td><td>0x22</td><td>0xe7</td><td>0xad</td><td>0x35</td><td>0x85</td><td>0xe2</td><td>0xf9</td><td>0x37</td><td>0xe8</td><td>0x1c</td><td>0x75</td><td>0xdf</td><td>0x6e</td></tr><tr class="odd"><td>A</td><td>0x47</td><td>0xf1</td><td>0x1a</td><td>0x71</td><td>0x1d</td><td>0x29</td><td>0xc5</td><td>0x89</td><td>0x6f</td><td>0xb7</td><td>0x62</td><td>0x0e</td><td>0xaa</td><td>0x18</td><td>0xbe</td><td>0x1b</td></tr><tr class="even"><td>B</td><td>0xfc</td><td>0x56</td><td>0x3e</td><td>0x4b</td><td>0xc6</td><td>0xd2</td><td>0x79</td><td>0x20</td><td>0x9a</td><td>0xdb</td><td>0xc0</td><td>0xfe</td><td>0x78</td><td>0xcd</td><td>0x5a</td><td>0xf4</td></tr><tr class="odd"><td>C</td><td>0x1f</td><td>0xdd</td><td>0xa8</td><td>0x33</td><td>0x88</td><td>0x07</td><td>0xc7</td><td>0x31</td><td>0xb1</td><td>0x12</td><td>0x10</td><td>0x59</td><td>0x27</td><td>0x80</td><td>0xec</td><td>0x5f</td></tr><tr class="even"><td>D</td><td>0x60</td><td>0x51</td><td>0x7f</td><td>0xa9</td><td>0x19</td><td>0xb5</td><td>0x4a</td><td>0x0d</td><td>0x2d</td><td>0xe5</td><td>0x7a</td><td>0x9f</td><td>0x93</td><td>0xc9</td><td>0x9c</td><td>0xef</td></tr><tr class="odd"><td>E</td><td>0xa0</td><td>0xe0</td><td>0x3b</td><td>0x4d</td><td>0xae</td><td>0x2a</td><td>0xf5</td><td>0xb0</td><td>0xc8</td><td>0xeb</td><td>0xbb</td><td>0x3c</td><td>0x83</td><td>0x53</td><td>0x99</td><td>0x61</td></tr><tr class="even"><td>F</td><td>0x17</td><td>0x2b</td><td>0x04</td><td>0x7e</td><td>0xba</td><td>0x77</td><td>0xd6</td><td>0x26</td><td>0xe1</td><td>0x69</td><td>0x14</td><td>0x63</td><td>0x55</td><td>0x21</td><td>0x0c</td><td>0x7d</td></tr></tbody></table><h4 id="行移位">行移位</h4><h5 id="行移位操作">行移位操作</h5><p>行移位是一个简单的左循环移位操作。当密钥长度为128比特时，状态矩阵的第0行左移0字节，第1行左移1字节，第2行左移2字节，第3行左移3字节，如下图所示：<imgsrc="https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwMjE5MTc0MDE1MTY3?x-oss-process=image/format,png"alt="shiftRows" /></p><h5 id="行移位的逆变换">行移位的逆变换</h5><p>行移位的逆变换是将状态矩阵中的每一行执行相反的移位操作，例如AES-128中，状态矩阵的第0行右移0字节，第1行右移1字节，第2行右移2字节，第3行右移3字节。</p><h4 id="列混合">列混合</h4><h5 id="列混合操作">列混合操作</h5><p>列混合变换是通过矩阵相乘来实现的，经行移位后的状态矩阵与固定的矩阵相乘，得到混淆后的状态矩阵，如下图的公式所示：<imgsrc="https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwMjE5MjAzMzQ2NDM2?x-oss-process=image/format,png"alt="col" /></p><p>状态矩阵中的第j列(0 ≤j≤3)的列混合可以表示为下图所示： <imgsrc="https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwMjE5MjAzNzQyNTE2?x-oss-process=image/format,png"alt="col2" /></p><p>其中，矩阵元素的乘法和加法都是定义在基于<spanclass="math inline">\(GF(2^8)\)</span>上的二元运算,并不是通常意义上的乘法和加法。这里涉及到一些信息安全上的数学知识，不过不懂这些知识也行。其实这种二元运算的加法等价于两个字节的异或，乘法则复杂一点。对于一个8位的二进制数来说，使用域上的乘法乘以(00000010)等价于左移1位(低位补0)后，再根据情况同(00011011)进行异或运算，设<spanclass="math inline">\(S1 = (a7 ,a6, a5, a4, a3, a2,a1,a0)\)</span>，刚<span class="math inline">\(0x02 *S1\)</span>如下图所示： $$ (00000010)* (a7 ,a6, a5, a4, a3, a2 ,a1,a0)=<span class="math display">\[\begin{equation}    \begin{cases}       (a6, a5, a4, a3, a2 ,a1,a0) ,a_7 = 0\\       (a6, a5, a4, a3, a2 ,a1,a0) \oplus (00011011),a_7 = 1\\            \end{cases}\end{equation}\]</span> $$</p><p>也就是说，如果a7为1，则进行异或运算，否则不进行。类似地，乘以(00000100)可以拆分成两次乘以(00000010)的运算： <imgsrc="https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwMjE5MjA1NjAxNjgz?x-oss-process=image/format,png"alt="col4" /> 乘以(0000 0011)可以拆分成先分别乘以(0000 0001)和(00000010)，再将两个乘积异或： <imgsrc="https://img-blog.csdnimg.cn/20210216120331436.png#pic_center" /></p><p>因此，我们只需要实现乘以2的函数，其他数值的乘法都可以通过组合来实现。下面举个具体的例子,输入的状态矩阵如下：</p><table><tbody><tr class="odd"><td>C9</td><td>E5</td><td>FD</td><td>2B</td></tr><tr class="even"><td>7A</td><td>F2</td><td>78</td><td>6E</td></tr><tr class="odd"><td>63</td><td>9C</td><td>26</td><td>67</td></tr><tr class="even"><td>B0</td><td>A7</td><td>82</td><td>E5</td></tr></tbody></table><p>下面，进行列混合运算： 以第一列的运算为例： <imgsrc="https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwMjE5MjEzNzQ3OTY1?x-oss-process=image/format,png"alt="col7" /> 其它列的计算就不列举了，列混合后生成的新状态矩阵如下：</p><table><tbody><tr class="odd"><td>D4</td><td>E7</td><td>CD</td><td>66</td></tr><tr class="even"><td>28</td><td>02</td><td>E5</td><td>BB</td></tr><tr class="odd"><td>BE</td><td>C6</td><td>D6</td><td>BF</td></tr><tr class="even"><td>22</td><td>0F</td><td>DF</td><td>A5</td></tr></tbody></table><h5 id="列混合逆运算">列混合逆运算</h5><p>逆向列混合变换可由下图的矩阵乘法定义： <imgsrc="https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwMjE5MjExMTM5NzUy?x-oss-process=image/format,png"alt="col6" /> 可以验证，逆变换矩阵同正变换矩阵的乘积恰好为单位矩阵。</p><h4 id="轮密钥加">轮密钥加</h4><p>轮密钥加是将128位轮密钥Ki同状态矩阵中的数据进行逐位异或操作，如下图所示。其中，密钥Ki中每个字W[4i],W[4i+1],W[4i+2],W[4i+3]为32位比特字，包含4个字节，他们的生成算法下面在下面介绍。轮密钥加过程可以看成是字逐位异或的结果，也可以看成字节级别或者位级别的操作。也就是说，可以看成S0S1 S2 S3 组成的32位字与W[4i]的异或运算。 <imgsrc="https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwMjIwMDgwNTEyMDg2?x-oss-process=image/format,png"alt="roundadd" />轮密钥加的逆运算同正向的轮密钥加运算完全一致，这是因为异或的逆操作是其自身。轮密钥加非常简单，但却能够影响S数组中的每一位。</p><h4 id="密钥扩展">密钥扩展</h4><p>AES首先将初始密钥输入到一个4*4的状态矩阵中，如下图所示。 <imgsrc="https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwMjIwMDgyMzE2NzM2?x-oss-process=image/format,png"alt="keyextends" /></p><ul><li><p>这个4*4矩阵的每一列的4个字节组成一个字，矩阵4列的4个字依次命名为W[0]、W[1]、W[2]和W[3]，它们构成一个以字为单位的数组W。例如，设密钥K为"abcdefghijklmnop",则K0= ‘a’,K1 = ‘b’, K2 = ‘c’,K3 = ‘d’,W[0] = “abcd”。</p></li><li><p>接着，对W数组扩充40个新列，构成总共44列的扩展密钥数组。新列以如下的递归方式产生：</p><ul><li><p>1.如果i不是4的倍数，那么第i列由如下等式确定： <spanclass="math inline">\(W[i]=W[i-4]⨁W[i-1]\)</span></p></li><li><p>2.如果i是4的倍数，那么第i列由如下等式确定： <spanclass="math inline">\(W[i]=W[i-4]⨁T(W[i-1])\)</span>其中，T是一个有点复杂的函数。函数T由3部分组成：字循环、字节代换和轮常量异或，这3部分的作用分别如下。</p><ul><li>a.字循环：将1个字中的4个字节循环左移1个字节。即将输入字[b0, b1, b2,b3]变换成[b1,b2,b3,b0]。</li><li>b.字节代换：对字循环的结果使用S盒进行字节代换。</li><li>c.轮常量异或：将前两步的结果同轮常量<spanclass="math inline">\(Rcon[j]\)</span>进行异或，其中<spanclass="math inline">\(j\)</span>表示轮数。轮常量<spanclass="math inline">\(Rcon[j]\)</span>是一个字，其值见下表。</li></ul></li></ul></li></ul><table style="width:100%;"><thead><tr class="header"><th>j</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th></tr></thead><tbody><tr class="odd"><td>Rcon[j]</td><td>01 00 00 00</td><td>02 00 00 00</td><td>04 00 00 00</td><td>08 00 00 00</td><td>10 00 00 00</td></tr><tr class="even"><td>j</td><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td></tr><tr class="odd"><td>Rcon[j]</td><td>20 00 00 00</td><td>40 00 00 00</td><td>80 00 00 00</td><td>1B 00 00 00</td><td>36 00 00 00</td></tr></tbody></table><p>下面举个例子：</p><blockquote><p>设初始的128位密钥为： 3C A1 0B 21 57 F0 19 16 90 2E 13 80 AC C1 07 BD那么4个初始值为： W[0] = 3C A1 0B 21 W[1] = 57 F0 19 16 W[2] = 90 2E 1380 W[3] = AC C1 07 BD</p><p>下面求扩展的第1轮的子密钥(W[4],W[5],W[6],W[7])。由于4是4的倍数，所以： W[4] = W[0] ⨁ T(W[3])</p><p>T(W[3])的计算步骤如下：</p><ul><li>循环地将W[3]的元素移位：AC C1 07 BD变成C1 07 BD AC;</li><li>将 C1 07 BD AC 作为S盒的输入，输出为78 C5 7A 91;</li><li>将78 C5 7A 91与第一轮轮常量Rcon[1]进行异或运算，将得到79 C5 7A91，因此，T(W[3])=79 C5 7A 91，故 W[4] = 3C A1 0B 21 ⨁ 79 C5 7A 91 = 4564 71 B0 其余的3个子密钥段的计算如下： W[5] = W[1] ⨁ W[4] = 57 F0 19 16⨁ 45 64 71 B0 = 12 94 68 A6 W[6] = W[2] ⨁ W[5] =90 2E 13 80 ⨁ 12 94 68A6 = 82 BA 7B 26 W[7] = W[3] ⨁ W[6] = AC C1 07 BD ⨁ 82 BA 7B 26 = 2E 7B7C 9B 所以，第一轮的密钥为 45 64 71 B0 12 94 68 A6 82 BA 7B 26 2E 7B 7C9B。</li></ul></blockquote><h3 id="aes解密">AES解密</h3><p>在文章开始的图中，有AES解密的流程图，可以对应那个流程图来进行解密。下面介绍的是另一种等价的解密模式，流程图如下图所示。这种等价的解密模式使得解密过程各个变换的使用顺序同加密过程的顺序一致，只是用逆变换取代原来的变换。<imgsrc="https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwMjIwMDk0ODUzNjIw?x-oss-process=image/format,png"alt="deaes" /></p><h3 id="aes四种加密模式">AES四种加密模式</h3><p>分组密码有五种工作体制：1.电码本模式（Electronic Codebook Book(ECB)）；2.密码分组链接模式（Cipher Block Chaining(CBC)）；3.计算器模式（Counter (CTR)）；4.输出反馈模式（Output FeedBack(OFB)）。</p><h4 id="电码本模式ecb"><strong>电码本模式</strong>（ECB）</h4><p>将整个明文分成若干段相同的小段，然后对每一小段进行加密</p><p>优点：</p><ul><li>操作简单，易于实现；分组独立，易于并行；误差不会被传送。——简单，可并行，不传送误差。</li></ul><p>缺点：</p><ul><li>掩盖不了明文结构信息，难以抵抗统计分析攻击。——可对明文进行主动攻击。</li></ul><figure><imgsrc="https://images0.cnblogs.com/blog/480062/201310/12232452-d3e3ba87a6b24b49b6f57d41b341ea96.png"alt="img" /><figcaption aria-hidden="true">img</figcaption></figure><figure><imgsrc="https://blog.mimvp.com/wp-content/uploads/2018/06/aes-jia-mi-suan-fa-de-wu-zhong-jia-mi-mo-shi-011-700x418.jpg"alt="img" /><figcaption aria-hidden="true">img</figcaption></figure><h4 id="密码分组链模式cbc"><strong>密码分组链模式</strong>（CBC）</h4><p>先将明文切分成若干小段，然后每一小段与初始块或者上一段的密文段进行异或运算后，再与密钥进行加密</p><p><strong>优点</strong>：</p><ul><li>能掩盖明文结构信息，保证相同密文可得不同明文，所以不容易主动攻击，安全性好于ECB，适合传输长度长的报文，是SSL和IPSec的标准。</li></ul><p><strong>缺点</strong>：</p><ul><li>不利于并行计算；</li><li>传递误差——前一个出错则后续全错；</li><li>第一个明文块需要与一个初始化向量IV进行抑或，初始化向量IV的选取比较复杂。</li></ul><p><strong>初始化IV的选取方式</strong>：固定IV，计数器IV，随机IV（只能得到伪随机数，用的最多），瞬时IV（难以得到瞬时值）</p><figure><imgsrc="https://blog.mimvp.com/wp-content/uploads/2018/06/aes-jia-mi-suan-fa-de-wu-zhong-jia-mi-mo-shi-02.png"alt="img" /><figcaption aria-hidden="true">img</figcaption></figure><p><strong>IV是做什么用的呢？</strong></p><p>初始向量IV（InitializationVector）它的作用和MD5的“加盐”有些类似，目的是防止同样的明文块始终加密成同样的密文块。</p><h4 id="输出反馈模式ofb"><strong>输出反馈模式</strong>（OFB）</h4><p>密码算法的输出（指密码key而不是密文）会反馈到密码算法的输入中，OFB模式并不是通过密码算法对明文直接加密，而是通过将明文分组和密码算法的输出进行XOR来产生密文分组。</p><p><strong>优点</strong>：</p><ul><li>隐藏了明文模式；结合了分组加密和流密码（分组密码转化为流模式）；可以及时加密传送小于分组的数据。</li></ul><p><strong>缺点</strong>：</p><ul><li>不利于并行计算；需要生成秘钥流；对明文的主动攻击是可能的。</li></ul><figure><imgsrc="https://blog.mimvp.com/wp-content/uploads/2018/06/aes-jia-mi-suan-fa-de-wu-zhong-jia-mi-mo-shi-03.png"alt="img" /><figcaption aria-hidden="true">img</figcaption></figure><h4 id="计数器模式ctr">计数器模式（CTR）</h4><p>完全的流模式，将瞬时值与计数器连接起来，然后对此进行加密产生密钥流的一个密钥块，再进行XOR操作</p><p>优点：</p><ul><li>不泄露明文；仅需实现加密函数；无需填充；可并行计算。</li></ul><p>缺点：</p><ul><li>需要瞬时值IV，难以保证IV的唯一性。</li></ul><figure><imgsrc="https://blog.mimvp.com/wp-content/uploads/2018/06/aes-jia-mi-suan-fa-de-wu-zhong-jia-mi-mo-shi-04.jpg"alt="img" /><figcaption aria-hidden="true">img</figcaption></figure><p><strong>对比CBC和CTR</strong></p><p>1）CBC需要填充；CTR不用填充。</p><p>2）CBC不可并行；CTR可并行速度快。</p><p>3）CBC需要实现加密和解密函数；CTR实现简单，仅需实现加密函数。</p><p>4）鲁棒性：CBC强于CTR——使用重复瞬时值，CBC会泄露初始明文块，CTR会泄露所有信息。</p><p>如果有好的瞬时值选择策略，采用CTR，否则采用CBC。</p><p>如加密成绩单，可选用CTR，因为学号唯一，可作为瞬时值。</p>]]></content>
    
    
    <summary type="html">永远不要试图尝试自己设计密码--Dan Boneh</summary>
    
    
    
    <category term="笔记" scheme="http://example.com/categories/%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="分组密码" scheme="http://example.com/tags/%E5%88%86%E7%BB%84%E5%AF%86%E7%A0%81/"/>
    
  </entry>
  
  <entry>
    <title>编译配置SGX-SSL</title>
    <link href="http://example.com/2022/10/11/Ubuntu18.04%E7%BC%96%E8%AF%91%E9%85%8D%E7%BD%AESGX-SSL%EF%BC%88SGX%E6%94%AF%E6%8C%81%E7%9A%84openssl%E5%87%BD%E6%95%B0%E5%BA%93%EF%BC%89/"/>
    <id>http://example.com/2022/10/11/Ubuntu18.04%E7%BC%96%E8%AF%91%E9%85%8D%E7%BD%AESGX-SSL%EF%BC%88SGX%E6%94%AF%E6%8C%81%E7%9A%84openssl%E5%87%BD%E6%95%B0%E5%BA%93%EF%BC%89/</id>
    <published>2022-10-11T12:34:51.000Z</published>
    <updated>2022-10-25T04:01:28.322Z</updated>
    
    <content type="html"><![CDATA[<h1id="编译配置sgx-sslsgx支持的openssl函数库">编译配置SGX-SSL（SGX支持的openssl函数库）</h1><p>由于在sgx中需要对超级大的整数进行操作，于是引入openssl库，下面是一些安装步骤，主要参考的了官方github给出的教程：</p><ul><li><ahref="https://github.com/intel/intel-sgx-ssl">intel/intel-sgx-ssl:Intel® Software Guard Extensions SSL (github.com)</a></li></ul><h2 id="所用的电脑配置">所用的电脑配置</h2><blockquote><ul><li><p>电脑：联想Thinkpad E14</p></li><li><p>操作系统：ubuntu18.04</p></li><li><p>处理器：i5-10210U</p></li><li><p>内存：8G</p></li><li><p>硬盘：1TB</p></li><li><p>在电脑BIOS中<strong>启用</strong>IntelSGX。重装系统不会更改BIOS中的设置，所以即使重装系统，IntelSGX也会一直保持启用状态。</p></li><li><p>安装如下工具：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo apt-get install gcc git cpuid<br></code></pre></td></tr></table></figure></li></ul></blockquote><h2 id="正式开始配置">正式开始配置</h2><h3 id="预备">预备</h3><ul><li>Perl</li><li>Toolchain（需要的工具，参照我的上一个博客<ahref="https://harper.city/2022/10/04/intel-sgx%E9%85%8D%E7%BD%AE/">安装sgxsdk</a>，执行下面的指令之后可以看到这些工具的路径）</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo <span class="hljs-built_in">cp</span> external/toolset/&#123;current_distr&#125;/&#123;as,ld,ld.gold,objdump&#125; /usr/local/bin<br><span class="hljs-built_in">which</span> as ld ld.gold objdump<br></code></pre></td></tr></table></figure><ul><li>Intel SGX driver、SDK和PSW</li><li>准备好OpenSSL源码压缩包openssl-${version}.tar.gz。本博客使用的是openssl-1.1.1q版本，之前计划使用openssl-1.1.1p版本，<font color = "red">但是编译的时候报错让我使用openssl-1.1.1q版本</font>，随着时间的推移官方的更新可能之后还需要其他版本，大家自行辨别。</li></ul><h3 id="下载sgx-ssl项目">下载sgx-ssl项目</h3><p>从GitHub拉取intel-sgx-ssl项目，这个网站也是可以访问的</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">git <span class="hljs-built_in">clone</span> https://github.com/intel/intel-sgx-ssl<br></code></pre></td></tr></table></figure><h3 id="下载openssl压缩包">下载openssl压缩包</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cd</span> intel-sgx-ssl/openssl_source<br>wget https://openssl.org/source/openssl-1.1.1q.tar.gz<br></code></pre></td></tr></table></figure><p>这样openssl-1.1.1q.tar.gz压缩包就到了/intel-sgx-ssl/openssl_source/目录下</p><h3 id="编译并安装">编译并安装</h3><p>我们现在在openssl_source目录，下面进入linux目录Linux/directory</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cd</span> ../Linux<br><span class="hljs-built_in">source</span> /opt/intel/sgxsdk/environment  //这里应填写sgx的安装路径，我的是/opt/intel/sgxsdk/<br></code></pre></td></tr></table></figure><p>使得sgx开发环境生效。 无脑编译安装</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">make all <span class="hljs-built_in">test</span><br>sudo make install<br></code></pre></td></tr></table></figure><p>安装完毕，可以在/opt/intel/sgxssl/找到编译好的库函数。</p>]]></content>
    
    
    <summary type="html">Hope is a dangerous thing. Hope can drive a man insane.       ——《肖申克的救赎》</summary>
    
    
    
    <category term="环境配置" scheme="http://example.com/categories/%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/"/>
    
    
    <category term="sgx" scheme="http://example.com/tags/sgx/"/>
    
    <category term="linux操作系统" scheme="http://example.com/tags/linux%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"/>
    
  </entry>
  
  <entry>
    <title>hexo配置博客心路历程</title>
    <link href="http://example.com/2022/10/07/trash/hexo%E9%85%8D%E7%BD%AE%E5%8D%9A%E5%AE%A2%E5%BF%83%E8%B7%AF%E5%8E%86%E7%A8%8B/"/>
    <id>http://example.com/2022/10/07/trash/hexo%E9%85%8D%E7%BD%AE%E5%8D%9A%E5%AE%A2%E5%BF%83%E8%B7%AF%E5%8E%86%E7%A8%8B/</id>
    <published>2022-10-07T15:09:12.000Z</published>
    <updated>2022-10-11T13:44:24.042Z</updated>
    
    <content type="html"><![CDATA[<p><ahref="https://linzeen.me/2022/07/24/mac样式代码块教程/">Hexo-Fluid实现mac-panel风格代码块- LINZEEN's Gossip Blog</a></p><p><ahref="https://forsure.live/customize-some-effects-for-hexofluid/#Mac风格代码块4">为Hexo-Fluid自定义一些效果- ForSure's Blog</a></p><p><ahref="https://blog.yleao.com/2018/0902/hexo上的aplayer应用.html">hexo上的aplayer应用| Y's BLOG (yleao.com)</a></p><p><ahref="https://blog.csdn.net/qq_41380292/article/details/121886741">(25条消息)hexo博客fluid主题添加aplayer组件_ccjoffrey的博客-CSDN博客_fluid主题</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;&lt;a
href=&quot;https://linzeen.me/2022/07/24/mac样式代码块教程/&quot;&gt;Hexo-Fluid实现mac-panel风格代码块
- LINZEEN&#39;s Gossip Blog&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a
href=&quot;https://fo</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>现代密码学作业10.7</title>
    <link href="http://example.com/2022/10/06/%E7%8E%B0%E4%BB%A3%E5%AF%86%E7%A0%81%E5%AD%A6%E4%BD%9C%E4%B8%9A10-7/"/>
    <id>http://example.com/2022/10/06/%E7%8E%B0%E4%BB%A3%E5%AF%86%E7%A0%81%E5%AD%A6%E4%BD%9C%E4%B8%9A10-7/</id>
    <published>2022-10-06T14:16:35.000Z</published>
    <updated>2022-10-29T07:04:42.617Z</updated>
    
    <content type="html"><![CDATA[<div class="hbe hbe-container" id="hexo-blog-encrypt" data-wpm="抱歉, 这个密码看着不太对, 请再试试." data-whm="抱歉, 这个文章不能被校验, 不过您还是能看看解密后的内容.">  <script id="hbeData" type="hbeData" data-hmacdigest="e31df612879ce3d8c1f6d6952fd06fd761e7377bffa174e86051f862cd2e2f22">e7de803e7160295f95749b4342f9c4f1dd62793d7b44b60d3b02552a0e435b54ca54956c8878b466f50658931f206c22a6fb180cc04bae09fcd1a2167eacc913f29b2fc4315a75d6ad70f01e852201d9f042325495d9856b2f1416063810277f2c25b88785c127711089ca6142b6ae1e03d3fc16973e5f5b4400c0820d4efcc2f6e869a49e1fe36813dc963b3f30671fa1922847f54601885bd69877bbc70487a2f0450811484daab0f49271b328aeff6798f08f15bc79103bda474956767e11223295c66cbbc26ea27cefa09678afba9639a908825e08b3b1b635d755db2397fb4b1a7ea22efb70d6bcb5253a88d9b73523c055bf84c1c4d1d75ccb9af712df233d32a0609662fddfd10a65b82783e094518029692f7b729485233c21f20131bf61ccbe079a2993012675e499fd011a2e736a7463556228cb9c3d573e739f1d615bbc052b0f4120c72d8e471dc504597931148cf4c15571250a552c2bf20026580acd9fc5acff25d761c2dbb43fa95a7764771193f0c3dfe4549d908e7e3b78695d9628ec7969f570837179b351af9cf88772aa03fbe0adadec32322911e4c6287ed4fd27eb170e51737210bae17f42d02e98eb2238b35d0934fbf901a7452fea6ec201b9d53900e799e25676ecf7939aaf8cf909330e6054453e891c3ffc8339a313bd858c44d00a52ec4aa36167015e760ecda2578506dff0f645d9254c313445fdc6ce855bcdc56445018161411d7a91b95e8e492ce703b51d81abd27aad29ffbe4406d0b24a629fcfcf6d81a0d515a3f241c421c7a60a73a1f179ab82b13f588eda07bb20355e36401d491639e6b64c2a31e184c664b89450faa59104598e47898891119c818723f567d278a5fccc4b58f303f048351b942fe38043c44f656a9542364994c67df42235ecc07f08277b04cd26f6a4b291251a735386cdc120fb9f09d94c9f3b32ed954ac93ec3da4c6a80e93e8f233663cbb1bc0a7f8b9b6dd776f1d7323b0d91aec00bd2024ee1e4987bc35d1f8de81613805a3a68ce5ce05c9f674ef22602cb36117b108d9e27803cc6473e22b2bc457439bd1a154f577d34be6dcf8788c07ab064f141a83dafb75cc7da65124cc2826013e054dfc36da9a853c9b775bfada7e9adb93187039ac256a57fbc4ca9d9f4132dd4e0a59b6f4465aea30f814c39ed5005082be72c0f1cb9907e660abdb3d1e96865ca417b47cd56dcb7b25659d030da23d4334ed64479ea668172d1b4798dbcfcfbadf5300d8b09b5790f273f4406ed1486e705ccb5066f27e6e99fc3cd3796b08014df5aa1aaa569f09b14143b419f7a0fdeca9435621a9c770dabe83b149b125d325a4bb66f39d9bbf3994f0f3a20b3ea154ed5dfe6260a824f34dfeca88b00cfcfcedd8a74a4c6d08d6fddbb8e5166b31567addea98573cb274133a7c1566e8f840fa09dd43d9019540c26ce2527aaab976ef423f8c591429b62e9f39f504774ddc0fb7217ebe852c346817f449a39c264976644c7eb929a9905909eae08e0a5d26651c327a8421e83e565234dba2f69efce35a62bcd317634cdc6d56b136cbb4ed26f0e9b72a3b4868d80276c0a2f5cdb6c5487f44a89e44cc93d82248180027d0b93bedc282d70ac36bcc3bf006861a469a0b69f5f7804bc84bb90d47db6e44b3d866ab71ecdac49d9029f65d83a37fb6887e2e3daade0ddac011ae2bc70b5bd220a08ea1565cf34f0dcf99ce5dc5b3c5c556adbe9eb683029d48285d23540fc25cdc1db8b9b7b244bc9337af19bb5837b0925d31c4f49784d60a0cb28e122c1d3d5522f8e10a4ee52ef4e4ca6b520d4227c5072f0e1cd0efafc542d0ffb5a07c0413d05790d634cec555e9cf2d6b4ba105f12fc29766474b23edc92249c7d3116f79a2f35aa2521178f6c9af570c9211b816c0e2a910a3d67639613714206715ef901fc23c3ad73ce0b0102909f9dc8afa6a42bd4b327f385988c1d0f4d48793c7a280ca4820a3a8733b18c280c6d60ddadc17e299862d345f7262ae7d85dd5d457fa690b3976d40e523f90ab4d465493983209fc50e8f28f7e6b36b00241ffa9a79a243c5d34e724caddea3b9b3ac1bd65d1ef83c6a489aa021919561f43a542fd06890c5b70a511535c05e00c7bca00dc14e4c45efb3e871fe1f001e32067de4379055f2b4f9f6599c2b0378e29382bc99d5b95e67e1c372bb75afb500436846a357b544c0a036ecf94ac31092f51d8a5cd99f06751b52c4a0cb59c1693d5ea1219baf592016e0f3488940bd8bf9c7ba46ec098bdc1f3554ba736133ada09effced6ca9da84d95d9078ca97bdf8d4712579c9952dd76d45a5d106af914a4862cc4f52bfbea6a0f336ee6989308c91042cf6ffe79a4215354e4de546d5b0b991f2abeac40e8c1b5107c3f8bf071fabc30342a09ecf9e9b3c1ab7fc75314c94be4fca979f83fcb44752da08c9ec1bc203dd104b2ba98794e4dcb73bcf73ba3f47e05d9207259b0fb252a5d37c836898e34e2a3f1cd657d192c1708931ee515ca309c4afe07416afc121522bb8828514fbdcc9e86c8f8c451ed01bfc795de7a0d1b9152d622cd88e4042bc44c56843c7d08f4b9120a99c20ade4cfc323eb87c5134ea74d10806c2c70980ae28c3d28261143aa31c897666b291241969cf6b6d968e63ca3d414f99b39635d49688a423fb088c56bd9a21a4bac835c79c208181cb8c6eb3cc644c971d9c8165b27e3aadb01b82d69519a726a19cc9fe59e07b1bd5cc8c90bf705c39b05345afce6a7829a76e06096075262861dd298fa4d3f2abe91e8a67ec61cc3d52ac305696ef3f63e96bde6513b75deaee31a5619067d022a570e6849fe49d7fa3d11917c0db8287dcf35bba47e099b886483d56b9b5f8644e4322e83b3783a687fcce52e4cf7f04bceb1da774b3a596d2b73d533bb4c83a71b6e4ef0ed57d526a44e47dfeaa2eb1ccd248dd423e9ab74c8c4cc5d7d2dd32d374349509f88fb30ef637ffe36ccfe7a625dc804c16e8f1f767ccfb8716c743cbbc64f787ec3107b4da4a8b432ab809af504ff94b76b99d6d47854f12e6c5ffbe5598f0422f332cd97feeead45fd905f04cb5abe900da68b45df7192f43d0756171eb56cc1c026c2f61c055e395865b827da706f42b5c1f680ff5950a4f6b8dd940db8bcfb69e554c50c8966a10dd54b1f6a68167427afc853228ed33ed7d3479d5e5aaea6abd173cda80f14da226ac9a68327aa594bddbc41296448bcf228d45f70237d44650e262988b9f7071687880bf89d4544ac0f87ec537c25f0a93ef021f9f80aaaf1239e6170810723dad1bb088635ba5010aab08e22ab1fee836c5b0510095873d7d638e748d588309c8d751d2c67b93bae84f03454ea639681f0468b442e2d681c5efab78d12bc426ab7e119bcf5cd2688559304d79b1aae8c7a857e32d3bd6c9ff0e945a893ad6bbad9d813131d738c2299e1e002fa9b40ea17bff38b226328f394f04362197bb02d990948eadf0f04acddc22b90cf6d48fef805324c3a65510bd69f7b641578b190e31eaa0175237f33d1deaec73b4157e55204491573fbaf2bc20808d4e2a682f5eb1800a72f98b4d409ca35cf086bc6c8ea3212a003148e0e34485b3a5902270547b9d7ea650cc879430195b7fe8c745bf3734df75b4b5298f16ab75a2545e35fdc74a61e689e85e64f04d998f810357e82ee94d68f1396709fecd1ff19019e023e181d896c2b87fc2c8e1e4e60d52a97dc8dfe1ef9bfae5e7c45ef9f177745f43823ef381de43fda0197b97b4a1f6f54bc3a528de834fd9c7af0330636e03ca57c45348017ce562115c138a40a226b3819e435412f137feb1e978a0a83c93567524a01178b05ac7a7e25aaa191fded52fa42d193538b6797aa4236d6673c8132e99427f5cb1e0c47d9251f89d17e1b227031c9a7f4af2c8f6626489fca5364f6014ab4d6b45dd229eb8de3d9aac6c39c20d6b531dd7824771fb545a186c552bf98d359e3f6fce634cb8821bc3f14b0d5f8dad468d34f9e2f7c6ba1d7bc3027d7de8c890e688412fcd54714b1a8bd4016d8a6b49b3d4f27a89dc1349c0c3e80ebfeced5e8547d500c295e25cb3bb70df6c32bac3b8efbdc07a2c41777a148acac409d5fc6e54daeadf3ef6a36b3174981463f568db1796e584da84d4072d812140a19aaaa25d475dd0745e5b23fe97e79fd75f91bdabb7f45b7850e39fc08cf95ebac1fe3e2aaf6cfada1807d4854b351431a2c2152b871749b3f8a9c41c56b290fbb73edf58d0a823fe9660719c4f1eae002b1142501067dc12bee5f308db03ab3a3119bdbdc9156b827157b43b0d6018e2cce393cd3314dab8d2aaffa21396e01187762576140ad2985f9a95dae6a4615ab3d9db2cf758e29977e2a02414b60df36479ad739871b6a1ccb64db5ba649cc45eee9775da80055bd495c5f7526788b36060812ef21568675a9d99079bffa44d6deacae1e216feeaf7f5ecaeed670ee7d077fd50ed5076df37090a98bb44f6327d2e6051fd4ccac57908d2a313a4dd361b5b72f8a57aa272c9819b1362793b75a40d423b9bf2540f8601d5ff3dd23b52871f0f503c61cf1fa7668b017913364f5e56920c64704b1a1e89799108476148b516e2de078765e33533ad083b1f4bbf40d743235456b1fd9316eccb19ac570884a2c85603e24d9841a376bbabda7aa588be8c9a29368fbca8cd641db837aa35ed247d39df4ed627bb24254a536ad0a67948eddcfaefbcb2407ad6edb0ce97f9317b85f7f14ceca7ec6dd5c0aa0c5fb524d939265b93cbfa9e823aac173d71a0c233c1dcc4aadd248a7e81d19daf51826a61d991b0b82df1250531aa0f51a58cca1954e8759e4722af40408a20036fd71115bb2e5ea4b73ae7d8f1aff5669bad5eca3321ac8d2fd75a4bc00e5815ebfd56d3a2e0af5ca93cce1fa540bdfa93e37e7256b9e69e2d62de33079c4f5674929ec69ded6ea80495637b380a3867633e53c880f1eff1520385251eee33ad504597ebd36952cede6db75355bdba52d1e268360bacdf73ea6778e98ac97f80afe6819d2763257d255e7c0e4b2f803d32ecf1f43672bcb75ff2fe8ed3012828bb565c34de87f53f86c3ddef43f68d5e12be055b8f0d45b27c5bc71ad5e5aaf4ed00b249931ffbeb9121e5f7ff5018ba892dd728c29d2b62e571d8125a3d19085a533aa7957d2f8c22ef7c8b4f59d01ac6909f4b28644c31232ebc64801dc2d50706cb1d199feabd11c5cc77359f7b61606d77f86c25762469d917735c52075f6f154b7754eb1360d0159eeb61f5f104d046d469a6893290df80cd18d24cd8566caad51457a41631bb81c15b744f27f46b6a955a94c5f4af40683f956ca686ef3be9aee50fe3ba68f9378561340429546ba1117ff4020c6c67c4d7b7e50086c5db7746edada66fa9cec1254cc1683b56440ea86c353f4cd551badcdf680a9ce440e3cf9fc418bf47509ff6c27298451b0fdc0a7673eb3429e3ecb2c0dcd1b11d729313416b88873ce8c90b2dff4ccb7f3ac10c8e16b7c771b4c5579ce9ae4a0ac0bfbb17cc0e07e4461d302a0886785ec8b0b03ae8cf60b77ec22f8e85e8cf6bbddca8efecfa737a88d4e5c69f1aa980bd07986fea9b68734c3ac7a1bf016d8733de78b116cb747e6e6d0ed9ccc20fb35edce3dfc1a9776832de286c8349539f2c62fba9f6bd006e54d851c84c1fb105ad647905e1300a2e376e0dd4d3b99d0ebe693ab5c631135a7039e339a8549d915aca3a5494f347ad265bab5b8c73de62b396e95f2410b658d85035268749769b25b7533031687bf49cf8c1d3a5f1d3e33f127b1f4d1d6a87a61ac06b188891706638664be35840c6681ce569189362385a681b6eb92f35c32254ee1c0972a3d90f4e42350dd539bb00f6c8c16635910f5ca25e921210cb7326379ce79b278866d0065b2720ca557d46f505f4a15b3fd4bc5d476234d8f8867f6f03ce95d68ad7f8b576e457f3ce24248201023d6b86fcf01c2d8be2af8d2f34a2611f8e7a637f3d2bd2db09cb691a5c4479f1cbc74e3835dd3cdd7056acff5324abd6a9e72d5c037719bf286a823d9cdf82c382a6b4aa930309f68071d3d700d7aaf4057aa1faf71d9f142e8026dc2fc10712b8e947b0cd38d143f4525cde544c47ad73cb9ea9f752d8702be31f8aaae9dc7a4831d4f3ea195dad9fab33c1c6086b0ab5a1a99914b6b3a63560f6f87599f39d9a1fb61f357eb7055675a15ecb4ca9e83135213b1187b91564103971cde09a963686cf7f589bbf7ebea00404439e087311a2f4a55b40308dc533fdadcd52ae48332b72d478869318687e19e426d4e601a8bd7b7c322a04b63a7662f80c46540404c463094440da9fd3a67ea78d49bc2f28895a71c29fc6a3e25fad1eadbc5eacace8ca1372b2170c05b377381c3bacf045ea5aef4d6fc72353a87b355fb30f4788b116ff53d26e485254b21dd6c43818e13467240042da9e9716a5ab397d75464f78c3fd3d01089672382cbefe8f81388e7677c974d211186bd248656220a41e0d1a5b9cbbac17efea36856f6b71c4b749e97babea6f8e6b419823fc957fcdf1e6dce1deaaf095413cd98e002b000c2b6a3cd59e01991c26518dd2b0ed3de885ce027d732c13d19d41db0f7ebb3924f71aca94bbb35e981de27418af2278c47ab6aacda18a101902233a83bf1882cf9b840f52154e30593bb96aa4c398730cf8390ffa3c3bad9fb368c232624cb2e15c5c9c2dc41157119a795ba98a6a8412d238826096c913ca6adb05c5fb4a5342af64bfae340b328e9dbf94605160dc0d2bb610bdf07cafe71c4be1ad29aecd8ef4b95d416286df6a860e761c9dc08cbfc2e9d32d9811667cb28d2ffc98345067d97220853f6229923e8136249cb8518b16a5427c6d2d0c010c1e3bd1ef422870dd0943056f35e6732e30a1f84782d5bd4d9b786cd08c82a27e93da4865e40e9e75a63e7ee2acf7c7829d653ac5f4443f8606af99637a1bfbaa90bc42e79f99c7ae15adcc0d7c3843be2654262d606a1bc1553eb640bdf2031ccfc2c1806e237337c67ab22813925028e29840a9b4c70de2e2544effdf9c28a71037e0d2bc82bfbb2c4145a8cff172d005391c17c05e0c9749273a346ed6764958392438dbefacc81346c4560868e9c71b58d73041d4deb9cf4a2e951caf4344ae15fd3c5f3244b96adb5c6d533d7d7f1e4f53d9b56e5edbd2b4964ca387b78c7d963814329bd17d83a0f246015ac7ca8cc092041be95b7ebc9c41b1d7d81e8848d646931cff5ee66dcf962b2f10b9dfa695c6863fe3946b44684e5ebb5edd3d3cd858684a464bca981c0093193ab94ae6325a2cf786f69727dc3194e4afacc206df947b89d243da7f3fcbae9e4d598a42ce59635c6826eca41afa35cc4a05f15a7e76c1089260ac2129ac05a565de0182a4a618b0a5e79be8a1c0928196f3a1aa7b79fb5cae3b2a0b89e59e8aad41d893920d79d75e8361cbd0e895a4aa6073c0f5761f111649598ee83f4c70e8b46f9e2f80fb1e7a026e5381d36d03f0357e215817fb82507005a1543cd75877ccbcb48d4ccce3d4b6520fc0b6f4afbea44297ec6da3fa65fd0a5070dcda58ad5907698f77a9dc288c48e3110dc52361e99d4430ddfb16ee9d37e6db08ed8f19e1d95f5a28f725289bbab52a858e4249fa5b0cbf7a5e3f56ab89fe7d24b4c93a05d35ea78e8666b9c9a0f4ec38992915c5c987d280bb9ea02dce867d8b36573d6cc7a5e087c8ec2f15c56c9bbc617e8ba64f7e5749f621f7f87328d0e4eb34018a88026d2a162f27a474bcb9ec82c3553a43720bcd2b299ca686c51ba9d0f077303a06836a700695d61766571ffd0a2af8b79baf1bf84285c91b3c697bc172a6c3923b734ccb898e0037a885cd543f4918e6219baff657e691ef6acb9b22c09c142f31c5c0b048f06bb3c2bd06a6d3273effc5afcab74f9cad9e63587089289ff403d600689c6ad615b2b7e21438c573c6813bfeed6d3493d7641b5118a54cfa1b5d0bbd829bce8af758de12bfb02d5e8104b6bd8a2167d1e2fbcceb86f8dcdf8dfaef643502992d77df0d04e629ec75c004c017038b671c46f23e83e583d4b0fbf721c514af658fddff967754d637d0f64109950ca0b6af9f32c868cb8574088b504a7267841ac7742962ab8e34c5e6aaae0b616663fd070505b4688ba0b4f86ad563a7f63fb5980520bd18b1ff6aa9bb20ad342191e4eb6f2c76a0759329476c56b25b48537daf458c6fc382312694c3c3c8ea499b6c7d5f8ef3923df79cf73aed9ba610d9a06eabeeae7dfe2a7078b62235726c1cf1c27c848c94a718cb0342fd9ad1c69ccd829c551648ddfa07e23b67c38079d6c3b339407e19f79f5b1e098daa3ced1b52f1c328cf08f04de6aa9dc7838350847bfef9621ab0cf81fd161cc09be79f2233ec587350c94afb3430c9d805e8c1bc83d0598453569d1b59cd43d1904e416f86d0ff55e89424c4401e606bc71a283105dfb529306876ca57161d569a5ed7689e37f4f4cbb5b89905dc5c47608a90c4afe7b8d3a19dc23f5b1d0e1f5582f3906655baf417db12ff074e14453ef53938828b6cc109f3656f3ea2fcf5f1f3f71b414eb88f86afebd423493e35eb1414044c7875124f76d034fbb8759bb71e6544a03386c2da86bbafc8eeca971057af93e1a604dd2a90e93edfd4153b6f0b9e682e4e4ea45f078a7dc3165ef1a4038fb5c0eaf79cca464aca4020b59c3630e59d0077d0e8c5e4b47595adb9a3b2ec614943a9e87e213f344246dad490af7cb1b6b4ab13abd55ae03d0c9b0907e2b4bfb4114d12d98714de5810b7ffce86ac4287cccad8f3f7ca4dc1f050779a265d07c0777c1a1e56b609127f5c30249aa0b322cdcb1c2dc9415fb524fc548fde426bd8e6543490b56660e4bbb5bf71408c2953e5a0db52c485883a6a0cf94d7d3c335821812c6c7fdcdf3f9349a77c2016217c81224c5dda3eabbcd19b7277b2a3cef1636a59076b4bc8cb05da6e155ebad265960e6834b79308cceb9a68d9836ac205b55d16c1dab102092f9b33a0a8884041f9b21cdd55ce80ccffbb167aa28e8f4bb29fde5a334667c0c33c5e27e949f201a1f77ef18df7bdd20ac019c94c46294dc9233f1873e0d1d6dcae53b3ca7523ffe6e311dbbacad573ff5c0c5144c614479acd90299c0e637ce26000319abdcf171587c107792953f9102059f317a50071d851ebe531872cb581d0b803a35d9259a5999f76e649929b56eeebf8c74180fdb3e16368e48c5f53fe26fb79add38fedce8453d037a3ede62da0a84c502965e2845c772b9dd3ee8f32460119dbd75a6515bcfbeba8458f851064f3098363ea63028e40d5af1736c64c3bc623685a8624a619463251df16e60a3e424b26dc7fa5531f878ece30f68711c0fe8f6afd3243a98a0bd7b53199802516cbdfec8831afd66058ad76a6e8d51248de747ecb9716c072d640d02ead4658b4568b1d5334363db9317aa5ca7b8f133b136fbc9191914d285b9dadac5da8c3acfa32b231189fb8180227647e3802df363fdbff845bf45fc376d80fb214ca905aa7902b5c57213c1007a8d19fc3a635b4533d7afc1ea3b081ee3bfcb508604927cd28b0fbe087ad5ed7d05bebf32077f2990f1b0f29d3de96e7f0242f3bcbc96697a6005533c924cf2b0a83c6ff85b62b502c3e15c6e49e34a0842b253f18424e58c2f8d7bc56bc1d139c58dab3dc7a8fae5c2b8edc3faa36057a382bcccb7ae50dc0f0049b62858f232cec2e4632b0cec06e0d2edc40809e45151162fd1adc98a2c82735e896c1c523de45b9b2e6d7a8fc246345e733ee744350055637c8fe20ae4a008fcde8e64e8b929b636d86f40eda511e57047b47d2ff2860ff064fedf229817a6f6dd7a3dacc15e36b15c00d0fa6c9371613cd63867caf9b672113ac96b3079ccb4a22605998720464b60dba2373e32e73ca92b05bf64beaba7337e89bf049f48b8b06240e590394bc534b1849e2fe443ca4eca75a90d51b414cb99525192837000f222c8515d2c0ba08e97edc446ede01b0e866af74a434dab3b5273fabcdc5d9c6a557335f4aca2d6943e00aa04faae54476c36880460d2489526b269241fb9a3cbf106d78897b5e1a0984d9b591c266549955d87a4f9a6f92aed9110045cdbc96ca7aa24ccabe1a45283e2738fa86ecc7de9338b1dc3b48f0c774843b00a5dcb84915d3eb76e9a67e49ec4d3d084c0bc39768793301b018f6f2d24b5b8770b0fd124cdc9f3889475c246dc59402df300f416f04640b771214e8a7651ea3d5c2d36804eccfe79b74835668bb7a8470e76c5732702770dfc350998466e94837ce4bc7d70e77482b946f811de093ea9ee7ffdfca657f424a870ecf7ac2fa1ae04819fec94efb76aa77cca7c127d2e42df3a5e95dd54c8e67b8b50ce1cc91e5793de5113fc6a26aca3264fdb98639a4fcc1322e8f1d6b670c7c0f9cf3a8d5d56e107222dac3fe64c50d0010cda7088077e34f20b188a901d66b19ef5b878b1c23c8b6d3b9fd0dfb4265146040f41507bd238b3422fe3642a62208bb203da00714907e211edb1f8a35ee00c3110989e0b8ea3b6494e03df700b0a5340edd5df1d9bf3fcde30aa9f2da0f6c5f8bd20b9d29456960a17c727f2c1d4a11d9672bf01ebff16fbb288f1b33a9f61fa1bf38a8770be56a58d7e1a881d109eb19b06e3ba1062b784de8f9c308cd9b333178da2a398d682b9bf8532b206abe3361cdb7b24d4e09832c9e077496ff961ed115a017f5d49702bad7077ee19cc0276fa2db63bc3de0686f1c298fd4f58ed863a7382db52fe3870fa289c5b091fa45edd85dc0a6b47eb20821460fd18f870bb1466d7279c99be7aa64da5bfd05f9faf46ba1866a02c0f140ad0aa21d81f17dd3ae58249810fd9449fb8499ead80407ff1edbe07ec5489311ac796bbc3ffe409556e0a6f55638dba7cf2812d74bd5fbfd1ac2f1bb500881cbcd38e21e685f326d92337669991394296b559fb26a5fe8a79d2ed5265aafef7375ed81e83c18ef13194c4c9ce210aab5ffed4fde087176a9c55b8f5f900bd05eaea4641294703a11e9395cbf37e36afd45ed4026189e7ef95f8d13596c2bd2c932663be8886476b1370eaeda2d58ba36a261dfdbf6a828a3d7b11117852d33f201a0fb0150a0e406b9312abb37f0e7f4098f325bfafe7c0ffc79c7e62e2a4dfb7176a770824860691437a247d54d3eca3f3c0a0c83be4bd58351d4199f7c6cf11eff7a1c560e91158e7ae0b156dd76097d5d273ba12a3426782c92533fe62259ecd6d09603abea5db00a542c320bea0f45c4ecbe7465fa03b5381aa5b1a9a14de8ce85393a945c6b4a88ea62ef01e47ec924b6c0db1153d644061c764cb1923818f6ab2411010588efbc29b216cc4d670e55dc2cd6511597266d76598dda7ed1f003c5dbefcb88319ac57018bd4897d60fa4a9ac80a4914bc0947b6b3f71761f123150a97d7e258694adfc983d1e49da5e09e1375e2507654e93427ee07ec15f33e827bf0d5cbeb23a95d193e576b97113485fcbe7a4edbf4435d80e08bad6a6cb7b59aeb27d7b556d19ac77726cd4547364b233c20320b4cea7ae2aa41200afd53e758b0ea1da926a06764c8be654ffe37889065813ffb6a3ffb7a3a4839b75ba53a6fb8e89639a7b502049d28225967c5c90bb677e22f962bc61fc0b92603a4bb1b375c5518533f5869343ca861a53d7269490b05da6d361c443aa9b5e7a4e14c006dc0b62ad49c922e21f308509892b478d659e19a1496c206ec36b23b743ff40dc2b1f6ec02785507531e970ab7e6f154b04ff58b1eb836ab827a1de679d2dd2fa8584f938f2c406bd927c8956ec71275f6b719360faf3fc0c96afdca0fe18036947882bbf678df78bae9e9ad48736bd96782b88edd91e13aada3d83714f2f5b042bfec17fcfd51d05107f8c1c38e89156e015c204020b8a8b5baf21d289a241bc3547834a7b47a4d6ca5f682e640c61f57a498254bce56fb766935d09488ed26bc49e71fe992b4cdf98e6bb9bb8598c6f1ececfd50e8a80edfa5237a7104ad0e886d99a1feab9382e21a4f95ef51a0b10cf5a4144219d12b78bac9111e4da12a29563d6a7261723352b3f2da28fdd4ecc29be96ebfd3678edbda27ba6c2050a8fee1bbeeb2044d67a7db317edfedd96a1e741b13a94c64d5952a61640e52deb26cab5b4ef52f2eaf7c002d12efee7f60da5b32e833b0f4fa5eb9dcfb925ed93bbaa2ac7f95e52bb3b85b4e68339e741d14bc2b7673c9e38604b4aa748bec051acca2ae56dd60aeb76ea63a98097a249fe0d57c9c76046a88c923c59c33024d07e201daf9ab1e465b973b0a2e36d98c71063f232cd32681a03410aa68ab31424030174cdc1ca98f5752b8bc26b9a2f8f57863b7ccf983a1afc6a6fe5669c1ac80f1f240cb00ce275735e4b966be96dd4655691f225da09fdc26393f082a916780dff903da1a114da6d097cc835875933776b9f7d9798c2af7c8a00258a94617d26aedc86291b48563e731afbfa21ec113d05c55975cb48c290824981945f974d7b014886ca7c9b4e3402a4d9ced8f69034e561d74f982482686504f149d7eebd175b33cb50b3e878c5a9028518ceb24d66bf422e3419658e031e4733a145ae35a079fd9b4fa15f3bc820ec0374372b3e60d2cc95620c76bdbeda88f1fed5260ae3f349527b625d1dfeec17bde86f424c3b93f82d21ba1f5769bc6c0e9ac081d6bb417c32f97b8eeb10e3e2c18da4db9ea3dc896b52c057098b35d3753195aa7047ca6132e0d5ca1a01b072476b1b11594767ca1e77dd6745cc1da2c7d57a3f99aab1b3efa3fda25a8aadfecbd360c445fd18f1aa31e4e4686ac52a0c4274e8fe7946de02f831a36af2e8312b66ad6069505e6025ebe6c6fb4003212cd14c4900c6f01616068ef9bb6cb543dad626129ca7bed40d0e7dabeaaa6a7ef4e47d5dc1bcb36ad19446d5fd1d0c8ba102ea2b63f46d0d42a04ee0ee71e96ba1e380534634b2e3720eca73a8d8635ccdbfcf5e8057ca1ffb3962a2af18d2e640e6af580ecc47abd1b5d6a96fd6da1fb13635cd8478d70c04efdf81f49bd913041535d4a4afd4dd97db54d88c0e4395536fe9a1c40a430780aff9cee9e190f48dcf65b950a2b70c480b2cb22b184d54d924f71cac8bbb49532ffc45933729a2485f859e3b7d249bdc9be60751747edf5c1cba153c40f17efa775185d6de7f9536b9d19cf4b35bcfc1b90800c294b13b4fe17044b1094d7015f763844df8cdaad6fab8f0f01ca83e32a49fba540560e25946b8c89ebe4bb71b660521fc64ae42db81dedff9db016621669f314899afc8e0ebc6502e7451f521969c22fc3b5f4c4bf9823ce47760f501f16b1d121da98774d5f873527d3bedb9012a0693d02c7ba2d50440325a7cdfd841bda3b50baa3b75bed091af225c7c37c0e9b976c05c14eba6de8d146e4e787fe2e2a3b5fc1dbc37a500929dd3fd9b1bfcf34c1af5a83aa8fbd79d3e89b8931d76180a5ae98a7be5786d58db984d64c28f9842e2082acb6d6a60dd56a2ce0dd388a7f68e311729c13c86705c2c3576b843dc40ec3bfe009f7d5d8fdfa8d6be0be54b5eeaaf1b74c0a721af790cdc210a9230cfd549dcaf3692b9a8c18a08215e16efa7894cef611c866130d7ad65185169a1da54a56dcedbe41e855dd51cefd379baf91921b95ce7d0f4ac450f6489cb1a5466388b8c076a7c78472a237367386ab18c647999e7068fb4c8829766c91f1b0b38cecd33cfde0f98467fe97c78fc9bc01bb027f4b8f6b17250307586d17a8f186cc40032428e295f80237493c10c4f7bb26fab3b292cb393d100c34bd68e66030bcc0c2b653993899903c2965280c88b731e166c8d751182bc95b8ed358814948b8202019f21bd05b12cd327fe2cd8b6c8f769046c609748c0e6591df2f614664af2cd920054310bd45023e6d93ef6aa0ffb47bd01caa957ddce745858d227f308ed3a196c41a4af5c8e4b0725a6014b7fac36813164f1a53b705d32b054a6568c5c9099305591b073b3d6d09cc3d45d15176ac9e54e47b2fbf2df0df127f7929c89d545f0d5ba1a23b9717de6cbc0787f2d7b37bb5a318bcbf772d5a9e71c978227d3bbf79b9d308ee550b8f909bda279eaf99cd4f5b4aec6e289dc1bf83f69c5981fc4576bb9910ce472863b719f11a56fcec0bb9cddc2fa38610655b8867eb5c0fdb26203695ad1593783649cdf415559dd7b774712f5125d09dc7a0e168461daa4dcf4a1c82c30e67511049191062b4353cd7aa3fa72fec22fbdbe5f8d3d0d30cddc6bd775eb281497d3fb68ddea0367361f725cf9c62ff3371604427c6aceb13fd997902f210b9fe0a8590523770be021ab95b6838318cbf709ebc705eaef8c85fa661dbe586a08dfd418c41d6ea94e6f10bcd0421543b26fe300d1ad98b32b7a35bc18261a473dd04711047e0dac49795100b619172f250e301b7f5698b0eac814ac0af07672190f4debfb162c29c2570e1ee548f2bfcb7c00ddb86cd38177db45831593211f46aac2b6a9e29318520792693df8c34df5787a9147b69340b95b185ecc8b0eccc6d2a22afec4d7db1cbbd76b220de0c1ce4d824694ce0c7cda62c7d2638e880bc6a3685477bbcfa74221595f4ccadb1e2a3057a5279ebb704c83aff2aa5682f02c7a8ef796ef5616f70ac1997b614cc74eb84f16f20277652c4ac7081e879fdb6e3ae435006bcbf17e2cbb089431598080b92dfb840ce62c6b304f1efde07d5ecdb594585d70021dc8e6673e4cbe2423696d4ba29ea0504ab9b63cfed25826b74474625bc3ba2753b59d13d20d71ed1492ded2b3546694069f8b8872e316c5247a8371ad890c418c55a8bb3efc99ca2557f720b62f80c3bdd143f5f500982bcfde5895cd2c7554c6178a39ea3dd4523b10a04afdb297228b83ae82f8735e0a9a277c227c1175da026d134162ea19e4f617e09d8d0725e4a10b6805219af006eb85a7557d83e9dd65bca649ab4c6ae7fd4ce4d278db8a9829e330fac23753ed968f06cb23c1ea366724fd6dfdcc0a13c14ff55ea7f1ecbdcc2574810b4a511eb05e8b57422765db92dd4892d753735d564593f8fe1207f310473b86e7425333e97c2b91904097e5b1be0afdf38fe03868446c472e177dad8570b60f6344360fa18a5e541f291022be3a8506df09dafade354e65e473708665d97122f2e4c2e495123de1dd60a479c166146a2111d0cc3f29efa2f7c15957d4ac8927614c96b3c29da7e170ef9e5a7f1c652fca9d1df058b017974a5ff83a19dd41598af6dc49abdeeb3d3183d75e22ccd40141ca6609e08afec5aba12bbe9feeafe0f49e71428ce9dd3113275a270ddcbd3e52bd0a3f6617502034f2e2dcc9c6ad097dd9c9252f744c6603bd64e47578c52fddc2485722fbe3c78bc464216d76e27d9e2bccf0c46906d1d3e622d6cd5438bb38312277a4de57ddffc0a3fd0ffb36e5b9146ff9dfbe3ab1715a700475399cd188a456eb7dcd6d25253a55f5c28f2c96e4e69fe7b12bf7139ea38c168c77344bb48700276aac2d30e9c7680f2b0e3c47b9b6f8f59f26ab3cfe6e8cf9581bb2a07b41201eb2f4ef852ce931c793f15c57ca24688a87ab7172ee6117a002f5787034597ae5d96272c22ecf69cb0e1d56603d2fc9c61610b9c67f998f28fde36f0c5</script>  <div class="hbe hbe-content">    <div class="hbe hbe-input hbe-input-default">      <input class="hbe hbe-input-field hbe-input-field-default" type="password" id="hbePass">      <label class="hbe hbe-input-label hbe-input-label-default" for="hbePass">        <span class="hbe hbe-input-label-content hbe-input-label-content-default">您好, 这里需要密码.</span>      </label>    </div>  </div></div><script data-pjax src="/lib/hbe.js"></script><link href="/css/hbe.style.css" rel="stylesheet" type="text/css">]]></content>
    
    
    <summary type="html">有东西被加密了, 请输入密码查看.</summary>
    
    
    
    <category term="作业" scheme="http://example.com/categories/%E4%BD%9C%E4%B8%9A/"/>
    
    
  </entry>
  
  <entry>
    <title>intel sgx开发环境配置</title>
    <link href="http://example.com/2022/10/04/intel-sgx%E9%85%8D%E7%BD%AE/"/>
    <id>http://example.com/2022/10/04/intel-sgx%E9%85%8D%E7%BD%AE/</id>
    <published>2022-10-04T14:50:03.000Z</published>
    <updated>2022-10-25T04:01:07.841Z</updated>
    
    <content type="html"><![CDATA[<h1 id="sgx的开发环境配置">sgx的开发环境配置</h1><h2 id="参考的文献博客">参考的文献&amp;博客</h2><ul><li><p><ahref="https://flxdu.cn/2022/04/08/Intel-R-SGX环境在Ubuntu-18-04的安装/">Intel(R)SGX环境在Ubuntu 18.04的安装 | 小木槌 (flxdu.cn)</a></p></li><li><p><ahref="https://blog.csdn.net/cyLee_/article/details/90245344">Ubuntu18.04安装Intel SGX 2.3.1</a></p></li><li><p><ahref="https://blog.csdn.net/cyLee_/article/details/90200470">Ubuntu16.04下Intel SGX SDK环境搭建（硬件不支持情况）</a></p></li><li><p><ahref="https://github.com/intel/linux-sgx">github上非常非常详细的英语教程</a></p></li></ul><p>主要参考了第一个博客，但是最最详细的是第四个github上的教程，只不过是全英文的有很多linux和sgx方面的专业名词对小白不是很友好。本人主要引用了第一个博客的内容，第一个博客的博主写的很详细，但是本人自己配置的时候还是出现了很多很多意想不到的问题，本博客针对可能出现的问题进行补充和说明。</p><h2 id="本人所用的配置">本人所用的配置</h2><h3 id="电脑环境">电脑环境</h3><p>由于现在用的电脑是锐龙处理器，而且没有trustzone，所以使用很久没用的、尘封已久的老、但是跟了我一年的老电脑。操作系统用的是ubuntu（鬼知道重装系统用了多久的时间），装完之后开机要很久，也不知道是不是坏了。</p><blockquote><ul><li><p>电脑：联想Thinkpad E14</p></li><li><p>操作系统：ubuntu18.04</p></li><li><p>处理器：i5-10210U</p></li><li><p>内存：8G</p></li><li><p>硬盘：1TB</p></li><li><p>在电脑BIOS中<strong>启用</strong>IntelSGX。重装系统不会更改BIOS中的设置，所以即使重装系统，IntelSGX也会一直保持启用状态。</p></li><li><p>安装如下工具：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo apt-get install gcc git cpuid<br></code></pre></td></tr></table></figure></li></ul></blockquote><h3 id="检查硬件情况">检查硬件情况</h3><p>这是Intel官方给出来的方法：<ahref="https://www.intel.cn/content/www/cn/zh/support/articles/000057420/software/intel-security-products.html">如何确定英特尔®Software Guard Extensions （英特尔® SGX） 处理器是否支持 DCAP 和FLC</a></p><p>在终端执行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">cpuid | grep -i sgx<br></code></pre></td></tr></table></figure><p>如果看到</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">SGX: Software Guard Extensions supported = <span class="hljs-literal">true</span><br>SGX_LC: SGX launch config supported = <span class="hljs-literal">false</span><br></code></pre></td></tr></table></figure><p>说明本博客安装方法适合你硬件情况。</p><h2 id="安装intelr-sgx环境">安装Intel(R) SGX环境</h2><p>安装共有3大步，分别是：</p><ul><li>安装Intel(R) SGX Driver</li><li>安装Intel(R) SGX SDK</li><li>安装Intel(R) SGX PSW</li></ul><h3 id="安装intelr-sgx-driver">安装Intel(R) SGX Driver</h3><p>安装一些工具</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo apt-get install make<br></code></pre></td></tr></table></figure><p>检查系统内核头文件是否与现有内核匹配：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">dpkg-query -s linux-headers-$(<span class="hljs-built_in">uname</span> -r)<br></code></pre></td></tr></table></figure><p>如果看到<code>Status: install ok installed</code>说明没有问题</p><p>否则要安装匹配的内核头文件：<code>sudo apt-get install linux-headers-$(uname -r)</code></p><p>克隆仓库：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">git <span class="hljs-built_in">clone</span> https://github.com/intel/linux-sgx-driver.git<br></code></pre></td></tr></table></figure><p>编译Intel(R) SGX Driver</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cd</span> linux-sgx-driver &amp;&amp; make<br></code></pre></td></tr></table></figure><p>编译完后，依次执行如下命令进行安装</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo <span class="hljs-built_in">mkdir</span> -p <span class="hljs-string">&quot;/lib/modules/&quot;</span>`<span class="hljs-built_in">uname</span> -r`<span class="hljs-string">&quot;/kernel/drivers/intel/sgx&quot;</span>    <br>sudo <span class="hljs-built_in">cp</span> isgx.ko <span class="hljs-string">&quot;/lib/modules/&quot;</span>`<span class="hljs-built_in">uname</span> -r`<span class="hljs-string">&quot;/kernel/drivers/intel/sgx&quot;</span>    <br>sudo sh -c <span class="hljs-string">&quot;cat /etc/modules | grep -Fxq isgx || echo isgx &gt;&gt; /etc/modules&quot;</span>    <br>sudo /sbin/depmod<br>sudo /sbin/modprobe isgx<br></code></pre></td></tr></table></figure><p>至此Intel(R) SGX Driver安装完成。</p><h3 id="安装intelr-sgx-sdk">安装Intel(R) SGX SDK</h3><p>安装一些工具</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo apt-get install build-essential python ocaml ocamlbuild automake autoconf libtool wget python libssl-dev git cmake perl libcurl4-openssl-dev protobuf-compiler libprotobuf-dev debhelper reprepro unzip<br></code></pre></td></tr></table></figure><p>注意这里安装工具可能报错如下</p><img src="/2022/10/04/intel-sgx%E9%85%8D%E7%BD%AE/debhelper%E6%8A%A5%E9%94%99.png" class="" title="安装工具报错"><p><font color="red">这是因为某些软件包需要保持现状，安装可能会破坏原有的软件包依赖关系，所以要安装这个软件包，必须调节软件包之间的相关关系</font>,给个解决的<ahref="https://blog.csdn.net/weixin_45348389/article/details/122913923">方法链接</a>,简单来说就是用aptitude来代替apt安装，aptitude能解决软件中的依赖关系。</p><p>克隆仓库：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">git <span class="hljs-built_in">clone</span> https://github.com/intel/linux-sgx.git<br></code></pre></td></tr></table></figure><h4 id="预编译">预编译</h4><p>此步会克隆几个GitHub，请走代理（不走代理针的好慢好慢）：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cd</span> linux-sgx &amp;&amp; make preparation<br></code></pre></td></tr></table></figure><p>将预编译出的文件拷贝至系统路径下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo <span class="hljs-built_in">cp</span> ~/linux-sgx/external/toolset/ubuntu18.04/* /usr/local/bin<br></code></pre></td></tr></table></figure><p>执行如下命令检查是否拷贝成功，如果成功会输出路径：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">which</span> ar as ld objcopy objdump ranlib<br></code></pre></td></tr></table></figure><h4 id="编译intelr-sgx-sdk">编译Intel(R) SGX SDK</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">make sdk<br></code></pre></td></tr></table></figure><p>此步会输出大约五万行内容（真的时间巨长，等吧），请耐心等待。</p><p>最后没有报错，说明编译成功。</p><h4 id="编译intelr-sgx-sdk安装器">编译Intel(R) SGX SDK安装器</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">make sdk_install_pkg<br></code></pre></td></tr></table></figure><p>此步会输出大约五万行内容（这个时间也很长啊，都看了好多视频了），请耐心等待。</p><p>编译完成后会输出<code>Generated sdk installer: ./linux/installer/bin/sgx_linux_x64_sdk_xxx.bin</code>。</p><h4 id="安装intelr-sgx-sdk-1">安装Intel(R) SGX SDK</h4><p>首先我们先创建一个目录，作为SDK的安装目录</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">mkdir</span> -p ~/linux-sgx-install-path<br></code></pre></td></tr></table></figure><p>此步xxx要改为编译Intel(R) SGXSDK安装器最后的输出，在目录<code>linux-sgx/linux/installer/bin</code>下可以看到此文件</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cd</span> linux/installer/bin &amp;&amp; ./sgx_linux_x64_sdk_xxx.bin --prefix ~/linux-sgx-install-path<br></code></pre></td></tr></table></figure><p>根据安装最后的提示输出刷新环境变量</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">source</span> ~/linux-sgx-install-path/sgxsdk/environment<br></code></pre></td></tr></table></figure><p>SDK安装完成。</p><p>此时进入<code>linux-sgx-install-path/SampleCode</code>下尝试样例代码是不会成功的，需要安装PSW之后才可运行样例。</p><h3 id="安装intelr-sgx-psw">安装Intel(R) SGX PSW</h3><h4 id="编译intelr-sgx-psw">编译Intel(R) SGX PSW</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cd</span> ~/linux-sgx &amp;&amp; make psw<br></code></pre></td></tr></table></figure><p>注意把linux-sgx-install-path下的sgxsdk文件夹移动到根目录下的/opt/intel目录里，再执行上面的这一条指令。此步会输出大约一千行内容，请耐心等待。</p><h4 id="编译intelr-sgx-sdk安装器-1">编译Intel(R) SGX SDK安装器</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cd</span> ~/linux-sgx &amp;&amp; make deb_psw_pkg<br></code></pre></td></tr></table></figure><p>此步会输出大约八千行内容，请耐心等待。</p><h4 id="添加本地软件源">添加本地软件源</h4><p>按照github上的英文教程，需要先生成sgx_debian_local_repo文件夹，最后在~/linux-sgx/linux/installer/deb目录下可以看见这个文件夹，输入如下指令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">make deb_local_repo<br></code></pre></td></tr></table></figure><p>需要将本地路径追加到软件源文件中，使用<code>sudo vi /etc/apt/sources.list</code>编辑文件，将下面内容添加到文件末尾，<font color = "red">注意：你需要把PATH_TO_LOCAL_REPO替换成<code>~/linux-sgx/linux/installer/deb/sgx_debian_local_repo</code>的绝对路径</font>，注意这里的路径需要自己根据自己的位置设置，建议改成绝对路径，我的添加方式如下，大家自己添加的时候注意改成自己的路径哦！</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">deb [trusted=<span class="hljs-built_in">yes</span> <span class="hljs-built_in">arch</span>=amd64] file:/home/harper/inux-sgx/linux/installer/deb/sgx_debian_local_repo bionic main<br></code></pre></td></tr></table></figure><p>添加完之后，刷新软件源</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo apt-get update<br></code></pre></td></tr></table></figure><h4 id="安装intelr-sgx-psw-1">安装Intel(R) SGX PSW</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo apt-get install libsgx-launch libsgx-urts libsgx-epid libsgx-quote-ex libsgx-dcap-ql<br></code></pre></td></tr></table></figure><p>如果现在去测试样例，会报错<code>failed to load enclave</code>，Intel给出<ahref="https://www.intel.com/content/www/us/en/support/articles/000057836/software/intel-security-products.html">解决方案</a>，要启动aesmd服务。</p><h3 id="启动aesmd服务">启动aesmd服务</h3><p>启动</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo systemctl start aesmd<br></code></pre></td></tr></table></figure><p>查看aesmd服务启动状态</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cat</span> /var/log/syslog | grep -i aesm<br></code></pre></td></tr></table></figure><p>设置aesmd服务开机启动</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo systemctl <span class="hljs-built_in">enable</span> aesmd<br></code></pre></td></tr></table></figure><h2 id="安装测试">安装测试</h2><h3 id="测试本地认证">测试本地认证</h3><p>我们使用SDK给出的样例代码<code>LocalAttestation</code>对安装情况进行测试</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cd</span> ~/linux-sgx-install-path/sgxsdk/SampleCode/LocalAttestation <br></code></pre></td></tr></table></figure><p>编译样例代码</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">make<br></code></pre></td></tr></table></figure><p>执行样例</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">./bin/app<br></code></pre></td></tr></table></figure><p>如果看到如下输出，说明安装成功</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs bash">succeed to load enclaves.<br>succeed to establish secure channel.<br>Succeed to exchange secure message...<br>Succeed to close Session...<br></code></pre></td></tr></table></figure><p>我自己跑出来是显示没有成功（狗头），应该是aesmd服务出了点问题，大家可以测试下面的enclave样例</p><h3 id="测试enclave样例">测试enclave样例</h3><p>我们运行enclave代码</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cd</span> /opt/intel/sgxsdk/SampleCode/SampleEnclave<br></code></pre></td></tr></table></figure><p>编译代码</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo make<br></code></pre></td></tr></table></figure><p>执行代码</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">./app<br></code></pre></td></tr></table></figure><p>看到如下输出证明安装成功</p><img src="/2022/10/04/intel-sgx%E9%85%8D%E7%BD%AE/%E8%BF%90%E8%A1%8C%E6%88%90%E5%8A%9F.png" class="" title=".&#x2F;app运行结果">]]></content>
    
    
    <summary type="html">一个合格的程序员，敢于配置各种各样复杂的环境</summary>
    
    
    
    <category term="环境配置" scheme="http://example.com/categories/%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/"/>
    
    
    <category term="sgx" scheme="http://example.com/tags/sgx/"/>
    
    <category term="linux操作系统" scheme="http://example.com/tags/linux%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"/>
    
  </entry>
  
  <entry>
    <title>数据库笔记</title>
    <link href="http://example.com/2022/10/03/%E6%95%B0%E6%8D%AE%E5%BA%93%E7%AC%94%E8%AE%B0/"/>
    <id>http://example.com/2022/10/03/%E6%95%B0%E6%8D%AE%E5%BA%93%E7%AC%94%E8%AE%B0/</id>
    <published>2022-10-03T08:00:23.000Z</published>
    <updated>2022-10-25T08:17:08.023Z</updated>
    
    <content type="html"><![CDATA[<h2 id="数据库的安装和使用">数据库的安装和使用</h2><h3 id="安装教程">安装教程</h3><ul><li><a href="https://zhuanlan.zhihu.com/p/37152572">知乎教程</a></li></ul><h3 id="使用教程">使用教程</h3><ul><li><ahref="https://www.bilibili.com/video/BV1Kr4y1i7ru?p=4&amp;spm_id_from=pageDriver">mysql软件的使用</a></li></ul><h2 id="数据库基本语法">数据库基本语法</h2><h3 id="数据库层次结构">数据库层次结构</h3><img src="/2022/10/03/%E6%95%B0%E6%8D%AE%E5%BA%93%E7%AC%94%E8%AE%B0/1.png" class="" title="数据库层次结构"><h3 id="启动">启动</h3><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql">mysql <span class="hljs-operator">-</span>u root <span class="hljs-operator">-</span>p<br></code></pre></td></tr></table></figure><h3 id="数据库的创建">数据库的创建</h3><p>创建基本的一个学生-课程数据库</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs sql">CREAT DATABASE student_course;<br>USE student_course;<br></code></pre></td></tr></table></figure><h3 id="表操作">表操作</h3><h4 id="基本数据类型">基本数据类型</h4><p><strong>数值类型</strong></p><table style="width:100%;"><thead><tr class="header"><th>TINYINT</th><th>1 Bytes</th><th>(-128，127)</th><th>(0，255)</th><th>小整数值</th></tr></thead><tbody><tr class="odd"><td>SMALLINT</td><td>2 Bytes</td><td>(-32 768，32 767)</td><td>(0，65 535)</td><td>大整数值</td></tr><tr class="even"><td>MEDIUMINT</td><td>3 Bytes</td><td>(-8 388 608，8 388 607)</td><td>(0，16 777 215)</td><td>大整数值</td></tr><tr class="odd"><td>INT或INTEGER</td><td>4 Bytes</td><td>(-2 147 483 648，2 147 483 647)</td><td>(0，4 294 967 295)</td><td>大整数值</td></tr><tr class="even"><td>BIGINT</td><td>8 Bytes</td><td>(-9,223,372,036,854,775,808，9 223 372 036 854 775 807)</td><td>(0，18 446 744 073 709 551 615)</td><td>极大整数值</td></tr><tr class="odd"><td>FLOAT</td><td>4 Bytes</td><td>(-3.402 823 466 E+38，-1.175 494 351 E-38)，0，(1.175 494 351E-38，3.402 823 466 351 E+38)</td><td>0，(1.175 494 351 E-38，3.402 823 466 E+38)</td><td>单精度 浮点数值</td></tr><tr class="even"><td>DOUBLE</td><td>8 Bytes</td><td>(-1.797 693 134 862 315 7 E+308，-2.225 073 858 507 201 4E-308)，0，(2.225 073 858 507 201 4 E-308，1.797 693 134 862 315 7E+308)</td><td>0，(2.225 073 858 507 201 4 E-308，1.797 693 134 862 315 7E+308)</td><td>双精度 浮点数值</td></tr><tr class="odd"><td>DECIMAL</td><td>对DECIMAL(M,D) ，如果M&gt;D，为M+2否则为D+2</td><td>依赖于M和D的值</td><td>依赖于M和D的值</td><td>小数值</td></tr></tbody></table><p><strong>日期和时间类型</strong></p><p>表示时间值的日期和时间类型为DATETIME、DATE、TIMESTAMP、TIME和YEAR。</p><p>每个时间类型有一个有效值范围和一个"零"值，当指定不合法的MySQL不能表示的值时使用"零"值。</p><p>TIMESTAMP类型有专有的自动更新特性，将在后面描述。</p><table><thead><tr class="header"><th style="text-align: left;">类型</th><th style="text-align: left;">大小 ( bytes)</th><th style="text-align: left;">范围</th><th style="text-align: left;">格式</th><th style="text-align: left;">用途</th></tr></thead><tbody><tr class="odd"><td style="text-align: left;">DATE</td><td style="text-align: left;">3</td><td style="text-align: left;">1000-01-01/9999-12-31</td><td style="text-align: left;">YYYY-MM-DD</td><td style="text-align: left;">日期值</td></tr><tr class="even"><td style="text-align: left;">TIME</td><td style="text-align: left;">3</td><td style="text-align: left;">'-838:59:59'/'838:59:59'</td><td style="text-align: left;">HH:MM:SS</td><td style="text-align: left;">时间值或持续时间</td></tr><tr class="odd"><td style="text-align: left;">YEAR</td><td style="text-align: left;">1</td><td style="text-align: left;">1901/2155</td><td style="text-align: left;">YYYY</td><td style="text-align: left;">年份值</td></tr><tr class="even"><td style="text-align: left;">DATETIME</td><td style="text-align: left;">8</td><td style="text-align: left;">1000-01-01 00:00:00/9999-12-3123:59:59</td><td style="text-align: left;">YYYY-MM-DD HH:MM:SS</td><td style="text-align: left;">混合日期和时间值</td></tr><tr class="odd"><td style="text-align: left;">TIMESTAMP</td><td style="text-align: left;">4</td><td style="text-align: left;">1970-01-01 00:00:00/2038结束时间是第<strong>2147483647</strong> 秒，北京时间 <strong>2038-1-1911:14:07</strong>，格林尼治时间 2038年1月19日 凌晨 03:14:07</td><td style="text-align: left;">YYYYMMDD HHMMSS</td><td style="text-align: left;">混合日期和时间值，时间戳</td></tr></tbody></table><p><strong>字符串类型</strong></p><p>字符串类型指CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET。该节描述了这些类型如何工作以及如何在查询中使用这些类型。</p><table><thead><tr class="header"><th style="text-align: left;">类型</th><th style="text-align: left;">大小</th><th style="text-align: left;">用途</th></tr></thead><tbody><tr class="odd"><td style="text-align: left;">CHAR</td><td style="text-align: left;">0-255 bytes</td><td style="text-align: left;">定长字符串</td></tr><tr class="even"><td style="text-align: left;">VARCHAR</td><td style="text-align: left;">0-65535 bytes</td><td style="text-align: left;">变长字符串</td></tr><tr class="odd"><td style="text-align: left;">TINYBLOB</td><td style="text-align: left;">0-255 bytes</td><td style="text-align: left;">不超过 255 个字符的二进制字符串</td></tr><tr class="even"><td style="text-align: left;">TINYTEXT</td><td style="text-align: left;">0-255 bytes</td><td style="text-align: left;">短文本字符串</td></tr><tr class="odd"><td style="text-align: left;">BLOB</td><td style="text-align: left;">0-65 535 bytes</td><td style="text-align: left;">二进制形式的长文本数据</td></tr><tr class="even"><td style="text-align: left;">TEXT</td><td style="text-align: left;">0-65 535 bytes</td><td style="text-align: left;">长文本数据</td></tr><tr class="odd"><td style="text-align: left;">MEDIUMBLOB</td><td style="text-align: left;">0-16 777 215 bytes</td><td style="text-align: left;">二进制形式的中等长度文本数据</td></tr><tr class="even"><td style="text-align: left;">MEDIUMTEXT</td><td style="text-align: left;">0-16 777 215 bytes</td><td style="text-align: left;">中等长度文本数据</td></tr><tr class="odd"><td style="text-align: left;">LONGBLOB</td><td style="text-align: left;">0-4 294 967 295 bytes</td><td style="text-align: left;">二进制形式的极大文本数据</td></tr><tr class="even"><td style="text-align: left;">LONGTEXT</td><td style="text-align: left;">0-4 294 967 295 bytes</td><td style="text-align: left;">极大文本数据</td></tr></tbody></table><p><strong>注意</strong>：char(n) 和 varchar(n) 中括号中 n代表字符的个数，并不代表字节个数，比如 CHAR(30) 就可以存储 30个字符。</p><p>CHAR 和 VARCHAR类型类似，但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。</p><p>BINARY 和 VARBINARY 类似于 CHAR 和VARCHAR，不同的是它们包含二进制字符串而不要非二进制字符串。也就是说，它们包含字节字符串而不是字符字符串。这说明它们没有字符集，并且排序和比较基于列值字节的数值值。</p><p>BLOB 是一个二进制大对象，可以容纳可变数量的数据。有 4 种 BLOB类型：TINYBLOB、BLOB、MEDIUMBLOB 和LONGBLOB。它们区别在于可容纳存储范围不同。</p><p>有 4 种 TEXT 类型：TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。对应的这 4种 BLOB 类型，可存储的最大长度不同，可根据实际情况选择。</p><h4 id="创建一个表和删除一个表">创建一个表和删除一个表</h4><p>创建</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs sql">mysql<span class="hljs-operator">&gt;</span> <span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> student<br>    <span class="hljs-operator">-</span><span class="hljs-operator">&gt;</span> (Sno <span class="hljs-type">CHAR</span>(<span class="hljs-number">9</span>) <span class="hljs-keyword">PRIMARY</span> KEY,<br>    <span class="hljs-operator">-</span><span class="hljs-operator">&gt;</span> Sname <span class="hljs-type">CHAR</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">UNIQUE</span>,<br>    <span class="hljs-operator">-</span><span class="hljs-operator">&gt;</span> Ssex <span class="hljs-type">CHAR</span>(<span class="hljs-number">2</span>),<br>    <span class="hljs-operator">-</span><span class="hljs-operator">&gt;</span> Sage <span class="hljs-type">SMALLINT</span>,<br>    <span class="hljs-operator">-</span><span class="hljs-operator">&gt;</span> Sdept <span class="hljs-type">CHAR</span>(<span class="hljs-number">20</span>)<br>    <span class="hljs-operator">-</span><span class="hljs-operator">&gt;</span> );<br></code></pre></td></tr></table></figure><p>删除</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> student;<br></code></pre></td></tr></table></figure><p>修改表名</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> student RENAME stu;<br></code></pre></td></tr></table></figure><p>修改列名</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> SC<br>CHANGE Crade Grade <span class="hljs-type">SMALLINT</span>;<br></code></pre></td></tr></table></figure><h4 id="表增删改查">表——增删改查</h4><h5 id="增">增</h5><p>可以用两种方式编写INSERT INTO语句。</p><p>第一种方法指定列名和要插入的值：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> table_name (column1, column2, column3, ...)<br><span class="hljs-keyword">VALUES</span> (value1, value2, value3, ...); <br></code></pre></td></tr></table></figure><p>如果要为表的所有列添加值，则无需在SQL查询中指定列名。但是，请确保值的顺序与表中的列的顺序相同。INSERTINTO语法如下：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> table_name<br><span class="hljs-keyword">VALUES</span> (value1, value2, value3, ...); <br></code></pre></td></tr></table></figure><p>代码举例(一定注意：字符型数据需要加引号)：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> student (Sno,Sname,Ssex,Sage,Sdept)     <span class="hljs-keyword">values</span>     (&quot;201215121&quot;,&quot;李勇&quot;,&quot;男&quot;,<span class="hljs-number">20</span>,&quot;CS&quot;);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> student (Sno,Sname,Ssex,Sage,Sdept)     <span class="hljs-keyword">values</span>     (&quot;201215122&quot;,&quot;刘晨&quot;,&quot;女&quot;,<span class="hljs-number">19</span>,&quot;CS&quot;);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> student (Sno,Sname,Ssex,Sage,Sdept)     <span class="hljs-keyword">values</span>     (&quot;201215123&quot;,&quot;王敏&quot;,&quot;女&quot;,<span class="hljs-number">18</span>,&quot;MA&quot;);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> student (Sno,Sname,Ssex,Sage,Sdept)     <span class="hljs-keyword">values</span>     (&quot;201215125&quot;,&quot;张立&quot;,&quot;男&quot;,<span class="hljs-number">19</span>,&quot;IS&quot;);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> SC      <span class="hljs-keyword">values</span>     (&quot;201215121&quot;,&quot;1&quot;,<span class="hljs-number">92</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> SC      <span class="hljs-keyword">values</span>     (&quot;201215121&quot;,&quot;2&quot;,<span class="hljs-number">85</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> SC      <span class="hljs-keyword">values</span>     (&quot;201215121&quot;,&quot;3&quot;,<span class="hljs-number">88</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> SC      <span class="hljs-keyword">values</span>     (&quot;201215122&quot;,&quot;2&quot;,<span class="hljs-number">90</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> SC      <span class="hljs-keyword">values</span>     (&quot;201215122&quot;,&quot;3&quot;,<span class="hljs-number">80</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> course      <span class="hljs-keyword">values</span>     (&quot;1&quot;,&quot;数据库&quot;,&quot;5&quot;,<span class="hljs-number">4</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> course      <span class="hljs-keyword">values</span>     (&quot;2&quot;,&quot;数学&quot;,&quot;NULL&quot;,<span class="hljs-number">2</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> course      <span class="hljs-keyword">values</span>     (&quot;3&quot;,&quot;信息系统&quot;,&quot;1&quot;,<span class="hljs-number">4</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> course      <span class="hljs-keyword">values</span>     (&quot;4&quot;,&quot;操作系统&quot;,&quot;6&quot;,<span class="hljs-number">3</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> course      <span class="hljs-keyword">values</span>     (&quot;5&quot;,&quot;数据结构&quot;,&quot;7&quot;,<span class="hljs-number">4</span>);<br></code></pre></td></tr></table></figure><p>最后得到如下几个表：</p><div data-align="center">student</div><table><thead><tr class="header"><th style="text-align: center;">Sno</th><th style="text-align: center;">Sname</th><th style="text-align: center;">Ssex</th><th style="text-align: center;">Sage</th><th style="text-align: center;">Sdept</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;">201215121</td><td style="text-align: center;">李勇</td><td style="text-align: center;">男</td><td style="text-align: center;">20</td><td style="text-align: center;">CS</td></tr><tr class="even"><td style="text-align: center;">201215122</td><td style="text-align: center;">刘晨</td><td style="text-align: center;">女</td><td style="text-align: center;">19</td><td style="text-align: center;">CS</td></tr><tr class="odd"><td style="text-align: center;">201215123</td><td style="text-align: center;">王敏</td><td style="text-align: center;">女</td><td style="text-align: center;">18</td><td style="text-align: center;">MA</td></tr><tr class="even"><td style="text-align: center;">201215125</td><td style="text-align: center;">张立</td><td style="text-align: center;">男</td><td style="text-align: center;">19</td><td style="text-align: center;">IS</td></tr></tbody></table><div data-align="center">course</div><table><thead><tr class="header"><th style="text-align: center;">Cno</th><th style="text-align: center;">Cname</th><th style="text-align: center;">Cpno</th><th style="text-align: center;">Ccredit</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;">1</td><td style="text-align: center;">数据库</td><td style="text-align: center;">5</td><td style="text-align: center;">4</td></tr><tr class="even"><td style="text-align: center;">2</td><td style="text-align: center;">数学</td><td style="text-align: center;">NULL</td><td style="text-align: center;">2</td></tr><tr class="odd"><td style="text-align: center;">3</td><td style="text-align: center;">信息系统</td><td style="text-align: center;">1</td><td style="text-align: center;">4</td></tr><tr class="even"><td style="text-align: center;">4</td><td style="text-align: center;">操作系统</td><td style="text-align: center;">6</td><td style="text-align: center;">3</td></tr><tr class="odd"><td style="text-align: center;">5</td><td style="text-align: center;">数据结构</td><td style="text-align: center;">7</td><td style="text-align: center;">4</td></tr></tbody></table><table><thead><tr class="header"><th style="text-align: center;">Sno</th><th style="text-align: center;">Cno</th><th style="text-align: center;">Grade</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;">201215121</td><td style="text-align: center;">1</td><td style="text-align: center;">92</td></tr><tr class="even"><td style="text-align: center;">201215121</td><td style="text-align: center;">2</td><td style="text-align: center;">85</td></tr><tr class="odd"><td style="text-align: center;">201215121</td><td style="text-align: center;">3</td><td style="text-align: center;">88</td></tr><tr class="even"><td style="text-align: center;">201215122</td><td style="text-align: center;">2</td><td style="text-align: center;">90</td></tr><tr class="odd"><td style="text-align: center;">201215122</td><td style="text-align: center;">3</td><td style="text-align: center;">80</td></tr></tbody></table><p>还有一种插入方式，需要学习select语句，直接把语句放到下面</p><p>对于每一个系，求学生的平均年龄，并把结果放到数据库里</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> Dept_age<br>(<br>sdept <span class="hljs-type">char</span>(<span class="hljs-number">15</span>)<br>avg_age <span class="hljs-type">smallint</span><br>);<br><span class="hljs-keyword">insert</span> <br><span class="hljs-keyword">into</span> dept_age(sdept,avg_age)<br><span class="hljs-keyword">select</span> sdept , <span class="hljs-built_in">avg</span>(sage)<br><span class="hljs-keyword">from</span> student <br><span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> sdept;<br></code></pre></td></tr></table></figure><h5 id="删">删</h5><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> course <span class="hljs-keyword">WHERE</span> Cno <span class="hljs-operator">=</span> <span class="hljs-number">22</span>;<br></code></pre></td></tr></table></figure><p>这里的where子句可以配合一些列其他句子使用，如exists,in等等</p><h5 id="改">改</h5><p>让我们先想想有什么需要修改？</p><p>对于列来说：</p><ul><li>增加新的一列</li></ul><p>增加入学时间</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> Student <span class="hljs-keyword">ADD</span> S_entrance <span class="hljs-type">DATE</span>;<br></code></pre></td></tr></table></figure><ul><li>修改原有列的数据类型(使用MODIFY或者CHANGE)或者增加约束条件</li></ul><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> Student MODIFY S_entrance <span class="hljs-type">INT</span>;<br><span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> Student <span class="hljs-keyword">ADD</span>  <span class="hljs-keyword">UNIQUE</span>(S_entrance);<br></code></pre></td></tr></table></figure><ul><li>删除列和<ahref="%5Bmysql%20删除约束_MySQL中的约束,添加约束,删除约束,以及其他修饰_衣锦夜行的李公子的博客-CSDN博客%5D(https://blog.csdn.net/weixin_35731579/article/details/113116120)">删除约束条件</a></li></ul><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> Student <span class="hljs-keyword">DROP</span> INDEX S_entrance;<br><span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> Student <span class="hljs-keyword">DROP</span> <span class="hljs-keyword">COLUMN</span> S_entrance;<br></code></pre></td></tr></table></figure><p>对于行来说：</p><ul><li>修改一行中已有的数据(使用SET语句)</li></ul><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">UPDATE</span> course <span class="hljs-keyword">SET</span> Cno <span class="hljs-operator">=</span> <span class="hljs-string">&#x27;100&#x27;</span> <span class="hljs-keyword">where</span> Cno <span class="hljs-operator">=</span> <span class="hljs-string">&#x27;1&#x27;</span>;<br><span class="hljs-keyword">SELECT</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">from</span> course;<br></code></pre></td></tr></table></figure><p>这里的where子句可以配合一些列其他句子使用，如exists,in等等</p><h5 id="查">查</h5><p>使用where子句和列名可以实现查找(查找是一个大块，内容很复杂，后面再介绍)</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> Sno,Ssex <span class="hljs-keyword">from</span> student;<br><span class="hljs-keyword">SELECT</span> Sno 学号,Ssex 性别 <span class="hljs-keyword">from</span> student;<br></code></pre></td></tr></table></figure><table><thead><tr class="header"><th>学号</th><th>性别</th></tr></thead><tbody><tr class="odd"><td>201215122</td><td>女</td></tr><tr class="even"><td>201215123</td><td>女</td></tr><tr class="odd"><td>201215125</td><td>男</td></tr></tbody></table><p>如果这样查输出奇怪的东西（sql注入可能用到）</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> <span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span> <span class="hljs-keyword">from</span> student;<br></code></pre></td></tr></table></figure><table><thead><tr class="header"><th>1</th><th>2</th><th>3</th></tr></thead><tbody><tr class="odd"><td>1</td><td>2</td><td>3</td></tr><tr class="even"><td>1</td><td>2</td><td>3</td></tr><tr class="odd"><td>1</td><td>2</td><td>3</td></tr></tbody></table><h4 id="索引的创建">索引的创建</h4><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs sql">use student_course;<br><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">UNIQUE</span> INDEX stusno <span class="hljs-keyword">ON</span> student(Sno);<br></code></pre></td></tr></table></figure><h3 id="数据查询cry">数据查询:cry:</h3><h4 id="单表查询">单表查询</h4><p><spanid="jump4"><strong>例1：</strong>查询全体学生的姓名、出生年份和所在院系，要求用小写字母表示系名</span></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> Sname NAME,&quot;Year of Birth:&quot; , <span class="hljs-number">2022</span> <span class="hljs-operator">-</span> Sage BIRTHDAY ,  <span class="hljs-built_in">LOWER</span>(Sdept) <span class="hljs-keyword">FROM</span> student;<br></code></pre></td></tr></table></figure><p>可以看到这里的可以制定别名，同时想要查找的列可以用一个表达式表示 2022- Sage</p><p><strong>例2：</strong>查询选修了课程的学生学号（去掉重复项）</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">DISTINCT</span> Sno <span class="hljs-keyword">FROM</span> SC;<br></code></pre></td></tr></table></figure><p>使用distinct子句来保证结果唯一</p><p><strong>例3：</strong>查询计算机系的全体学生</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">DISTINCT</span> Sname <span class="hljs-keyword">FROM</span>  student<br><span class="hljs-keyword">WHERE</span> Sdept <span class="hljs-operator">=</span> <span class="hljs-string">&#x27;CS&#x27;</span>;<br></code></pre></td></tr></table></figure><p>这里使用了where子句，这是一个很强大的功能：</p><div data-align="center">WHERE子句常用查询条件表</div><table><thead><tr class="header"><th style="text-align: center;">查询条件</th><th style="text-align: center;">谓词</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;">比较</td><td style="text-align: center;">= , &gt; , &lt; , &gt;= , &lt;= , != ,&lt;&gt; , !&gt; , !&lt; , ; NOT + 上述比较符</td></tr><tr class="even"><td style="text-align: center;">确定范围</td><td style="text-align: center;">BETWEEN AND , NOT BETWEEN AND</td></tr><tr class="odd"><td style="text-align: center;">确定集合</td><td style="text-align: center;">IN , NOT ,IN</td></tr><tr class="even"><td style="text-align: center;">字符匹配</td><td style="text-align: center;">LIKE , NOT LIKE</td></tr><tr class="odd"><td style="text-align: center;">空值</td><td style="text-align: center;">IS NULL , IS NOT NULL</td></tr><tr class="even"><td style="text-align: center;">多重条件（逻辑运算）</td><td style="text-align: center;">AND , OR , NOT</td></tr></tbody></table><p><strong>例4：</strong>查询计算机系(CS)和数学(MA)系中年龄在19~20之间的学生姓名</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> Sname <span class="hljs-keyword">FROM</span> student <br><span class="hljs-keyword">where</span> Sdept <span class="hljs-keyword">IN</span> (<span class="hljs-string">&#x27;CS&#x27;</span>,<span class="hljs-string">&#x27;MA&#x27;</span>) <span class="hljs-keyword">AND</span> Sage <span class="hljs-keyword">BETWEEN</span> <span class="hljs-number">19</span> <span class="hljs-keyword">AND</span> <span class="hljs-number">20</span>;<br></code></pre></td></tr></table></figure><p>这里between and也可以用=&lt;20 AND &gt;=19代替</p><p><strong>例5：</strong>查询名字中课程名中含有下划线的课程</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> course      <span class="hljs-keyword">values</span>     (&quot;9&quot;,&quot;DB_course&quot;,&quot;7&quot;,<span class="hljs-number">4</span>);<br><span class="hljs-keyword">select</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">from</span> course<br><span class="hljs-keyword">where</span> Cname <span class="hljs-keyword">LIKE</span> <span class="hljs-string">&#x27;%\_%&#x27;</span> ;<br></code></pre></td></tr></table></figure><p>这里使用了LIKE进行字符匹配：</p><ul><li>%（百分号）代表任意长度（可以为0）的字符串</li><li>_(下划线)代表任意单个字符</li></ul><p><font color = red>注意：字符集为ASCII时，一个汉字需要两个_；当字符集为GBK时只需要一个_</font></p><p><strong>例6：</strong>查询全体学生情况，查询结果按照系号升序，同一系中的学生按照年龄降序</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">FROM</span> student<br><span class="hljs-keyword">ORDER</span> <span class="hljs-keyword">BY</span> Sdept , Sage <span class="hljs-keyword">DESC</span>;<br></code></pre></td></tr></table></figure><p>用DESC来进行降序</p><p><strong>例7：</strong>查询选修了课程的学生人数</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> <span class="hljs-built_in">COUNT</span>(<span class="hljs-keyword">DISTINCT</span> Sno)<br><span class="hljs-keyword">FROM</span> SC;<br></code></pre></td></tr></table></figure><p>返回一个表只有一个值：</p><table><thead><tr class="header"><th style="text-align: center;">COUNT(DISTINCT Sno)</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;">2</td></tr></tbody></table><p>注意这里必须使用distinct语句，默认是all即全部行都要统计</p><p><strong>例8：</strong>查询各个课程号及相应的选课人数</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> Cno , <span class="hljs-built_in">COUNT</span>(Sno)<br><span class="hljs-keyword">FROM</span> SC<br><span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">BY</span> Cno;<br></code></pre></td></tr></table></figure><p>GROUP把课程号相同的学生分到一组，然后COUNT函数统计每一组的Sno结果，输出如下结果：</p><table><thead><tr class="header"><th style="text-align: center;">Cno</th><th style="text-align: center;">COUNT(Sno)</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;">1</td><td style="text-align: center;">1</td></tr><tr class="even"><td style="text-align: center;">2</td><td style="text-align: center;">2</td></tr><tr class="odd"><td style="text-align: center;">3</td><td style="text-align: center;">2</td></tr></tbody></table><p>如果GROUP不配合COUNT,AVG（这些函数对于一个表只返回一个值）使用，那么返回这样的结果：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> <span class="hljs-operator">*</span><br><span class="hljs-keyword">FROM</span> SC<br><span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">BY</span> Cno;<br></code></pre></td></tr></table></figure><p>输出的结果只有不同Cno的第一个行</p><table><thead><tr class="header"><th style="text-align: center;">Sno</th><th style="text-align: center;">Cno</th><th style="text-align: center;">Grade</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;">201215121</td><td style="text-align: center;">1</td><td style="text-align: center;">92</td></tr><tr class="even"><td style="text-align: center;">201215121</td><td style="text-align: center;">2</td><td style="text-align: center;">85</td></tr><tr class="odd"><td style="text-align: center;">201215121</td><td style="text-align: center;">3</td><td style="text-align: center;">88</td></tr></tbody></table><p><strong>例9：</strong>查询选修了三门及以上课程的学生学号</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> Sno ,<span class="hljs-built_in">count</span>(Cno) <span class="hljs-keyword">from</span> sc<br><span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> Sno<br><span class="hljs-keyword">having</span> <span class="hljs-built_in">count</span>(Cno)<span class="hljs-operator">&gt;=</span><span class="hljs-number">3</span>;<br></code></pre></td></tr></table></figure><p>注意这里不能用where子句，where子句作用于基本表或者视图；</p><p>而having短语作用于组，从中选择满足条件的组；</p><h4 id="连接查询">连接查询</h4><h5 id="等值连接与非等值连接"><spanid="jump1">等值连接与非等值连接</span></h5><p><strong>例1：</strong>查询每个学生及其选修课程的情况</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> student.<span class="hljs-operator">*</span> , sc.<span class="hljs-operator">*</span> <br><span class="hljs-keyword">FROM</span> student,sc<br><span class="hljs-keyword">where</span> student.sno <span class="hljs-operator">=</span> sc.sno;<br></code></pre></td></tr></table></figure><p>这里是一个等值连接，如果建立了索引这里的速度会更快</p><p><strong>例2：</strong>查询选修了2号课程且成绩在90分及以上的所有学生的学号和姓名</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> student.Sno ,student.sname <br><span class="hljs-keyword">from</span> student , sc<br><span class="hljs-keyword">where</span> student.Sno <span class="hljs-operator">=</span> sc.sno <br><span class="hljs-keyword">and</span> sc.cno <span class="hljs-operator">=</span> <span class="hljs-string">&#x27;2&#x27;</span><br><span class="hljs-keyword">and</span> sc.grade<span class="hljs-operator">&gt;=</span><span class="hljs-number">90</span>;<br></code></pre></td></tr></table></figure><p>为什么要用student.sno而不是直接用sno，因为SELECT student.* , sc.*返回的值是两个表的笛卡尔积，包括两个sno分别是student.sno和sc.sno，这里只需要提取student.sno</p><h5 id="自身连接">自身连接</h5><p><strong>例1：</strong>查询每一门课的间接先修课(先修课的先修课)</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> a.cno 课程号, b.cpno 该课程先修课的先修课<br><span class="hljs-keyword">from</span> course a,course b<br><span class="hljs-keyword">where</span> a.cpno <span class="hljs-operator">=</span> b.cno;<br></code></pre></td></tr></table></figure><h5 id="外连接">外连接</h5><p><strong>例1：</strong>查询每个学生及其选修课程的情况</p><p>类比<ahref="#jump1">2.5.2.1</a>中,会发现返回的结果里面没有学号为201215123的同学，因为他们被开除了没有选课，但是我们又希望显示他们的选课结果，用NULL表示，这里就需要用到外连接，而且是左外连接</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> <span class="hljs-operator">*</span> <br><span class="hljs-keyword">from</span> student <span class="hljs-keyword">left</span> <span class="hljs-keyword">outer</span> <span class="hljs-keyword">join</span> sc <span class="hljs-keyword">on</span> (student.sno <span class="hljs-operator">=</span> sc.sno);<br></code></pre></td></tr></table></figure><p>这样就能显示啦！:happy:</p><ul><li>左外连接列出左边关系中的所有元组</li><li>右外连接列出右边关系中的所有元组</li></ul><h5 id="多表连接">多表连接</h5><p><strong>例1：</strong>查询每个学生的学号，姓名，选修的课程名及名称</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> student.sno , student.sname , course.cname<br><span class="hljs-keyword">from</span> student , sc, course<br><span class="hljs-keyword">where</span> student.sno <span class="hljs-operator">=</span> sc.sno<br><span class="hljs-keyword">and</span> sc.cno <span class="hljs-operator">=</span> course.cno;<br></code></pre></td></tr></table></figure><p>这样还是显示不了没选课的人，需要用到外连接才能实现，我们暂时先不讨论</p><h4 id="嵌套查询">嵌套查询</h4><p>sql语句中，一个SELECT-FROM-WHERE语句为一个<code>查询块</code>。将一个查询块嵌入到另一个查询块的where子句中或者having短语中的查询成为嵌套</p><h5 id="带有in谓词子查询">带有IN谓词子查询</h5><p><strong>例1：</strong>查询与“刘晨”在同一个系学习的学生的名字</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> sname<br><span class="hljs-keyword">from</span> student<br><span class="hljs-keyword">where</span> sdept <span class="hljs-keyword">in</span><br>(<span class="hljs-keyword">select</span> sdept <br><span class="hljs-keyword">from</span> student <br><span class="hljs-keyword">where</span> sname <span class="hljs-operator">=</span> &quot;刘晨&quot;);<br></code></pre></td></tr></table></figure><p><strong>例2：</strong>查询选修了课程名为“信息系统”的学生学号和姓名</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> sname <br><span class="hljs-keyword">from</span> student<br><span class="hljs-keyword">where</span> sno <span class="hljs-keyword">in</span><br>(<br><span class="hljs-keyword">select</span> sno<br><span class="hljs-keyword">from</span> sc<br><span class="hljs-keyword">where</span> cno <span class="hljs-keyword">in</span><br>(<br><span class="hljs-keyword">select</span> cno <br><span class="hljs-keyword">from</span> course<br><span class="hljs-keyword">where</span> cname <span class="hljs-operator">=</span> &quot;信息系统&quot;<br>)<br>    );<br></code></pre></td></tr></table></figure><h5 id="带有比较运算符的子查询">带有比较运算符的子查询</h5><p>父子查询之间用比较运算符连接</p><p><spanid="jump3"><strong>例1：</strong>找出每个学生超过他自己选修课程平均成绩的课程号 </span></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> cno<br><span class="hljs-keyword">from</span> sc x<br><span class="hljs-keyword">where</span> grade <span class="hljs-operator">&gt;</span><br>(<br>    <span class="hljs-keyword">select</span> <span class="hljs-built_in">avg</span>(grade)<br>    <span class="hljs-keyword">from</span> sc y<br><span class="hljs-keyword">where</span> y.sno <span class="hljs-operator">=</span> x.sno<br>);<br></code></pre></td></tr></table></figure><p>可能有点难理解，我们把语句的底层实现过程拆分成下面三个步骤：</p><blockquote><p>1.从外层查询中取出sc的一个元组x，将元组x的Sno值(201215121)传给内层查询</p><p>select avg(grade)</p><p>from sc y</p><p>where y.sno = '201215121';</p><p>2.执行内层查询，得到88(近似值)，用该值代替内层查询，得到外层查询</p><p>3.遍历所有元组，把重复的值去掉</p></blockquote><p>需要注意，这里的子查询为<font color = red><code >相关子查询</code></font>，和之前的例子不一样，内层查询和外层是相关的，所以在实现上内层查询不是一次返回多个值，而是返回一个值（88），这一个值只对应sc的第一行，第二行依旧按照如此进行查询。</p><h5id="带有anysome或者all谓词的子查询">带有ANY(SOME)或者ALL谓词的子查询</h5><p>望文生义，如果内层查询返回一组数，那么使用any或者all来修饰，同时配合运算比较符号来查询，例如</p><p>&gt;any 表示大于子查询结果中的某个值</p><p><strong>例1：</strong>查询非计算机科学系中比计算机系<font color = red>任意</font>一个学生年龄小的学生姓名和年龄</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> sname,sage<br><span class="hljs-keyword">from</span> student <br><span class="hljs-keyword">where</span> sdept <span class="hljs-operator">!=</span> &quot;CS&quot;<br><span class="hljs-keyword">and</span> sage<span class="hljs-operator">&lt;</span><span class="hljs-keyword">any</span><br>(<br><span class="hljs-keyword">select</span> sage <br><span class="hljs-keyword">from</span> student<br><span class="hljs-keyword">where</span> sdept <span class="hljs-operator">=</span> &quot;CS&quot;<br>);<br></code></pre></td></tr></table></figure><p><strong>例2：</strong>查询非计算机科学系中比计算机系<font color = red>所有</font>一个学生年龄小的学生姓名和年龄</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> sname,sage<br><span class="hljs-keyword">from</span> student <br><span class="hljs-keyword">where</span> sdept <span class="hljs-operator">!=</span> &quot;CS&quot;<br><span class="hljs-keyword">and</span> sage<span class="hljs-operator">&lt;</span><span class="hljs-keyword">all</span><br>(<br><span class="hljs-keyword">select</span> sage <br><span class="hljs-keyword">from</span> student<br><span class="hljs-keyword">where</span> sdept <span class="hljs-operator">=</span> &quot;CS&quot;<br>);<br></code></pre></td></tr></table></figure><h5 id="带有exists谓词的子查询">带有EXISTS谓词的子查询</h5><p>exists代表存在量词<spanclass="math display">\[\exists\]</span>。带有exists谓词的子查询不返回任何数据，只产生逻辑值true和false</p><p><strong>例1：</strong>查询选修了1号课程的学生姓名</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> sname<br><span class="hljs-keyword">from</span> student<br><span class="hljs-keyword">where</span> <span class="hljs-keyword">exists</span><br>(<br><span class="hljs-keyword">select</span> <span class="hljs-operator">*</span><br>    <span class="hljs-keyword">from</span> sc<br>    <span class="hljs-keyword">where</span> sc.sno <span class="hljs-operator">=</span> student.sno<br>    <span class="hljs-keyword">and</span> sc.cno <span class="hljs-operator">=</span> &quot;1&quot;<br>);<br></code></pre></td></tr></table></figure><p>这也是一个相关子查询，第一次只传一个元组进入内层（这时学号为201215121），然后在sc表中找出学号为201215121的人选择的1号课程，返回如果有值，那么返回true，如果是空值，返回false。直至外层元组全部检索完。</p><p><ahref="%5BMySQL中的EXISTS用法%20-%20知乎%20(zhihu.com)%5D(https://zhuanlan.zhihu.com/p/351922940)"><strong>EXISTS执行顺序</strong></a></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">FROM</span> A <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">EXISTS</span> (<span class="hljs-keyword">SELECT</span> <span class="hljs-number">1</span> <span class="hljs-keyword">FROM</span> B <span class="hljs-keyword">WHERE</span> B.id <span class="hljs-operator">=</span> A.id); <br></code></pre></td></tr></table></figure><p>1、首先执行一次外部查询，并缓存结果集，如 SELECT * FROM A</p><p>2、遍历外部查询结果集的每一行记录R，代入子查询中作为条件进行查询，如SELECT 1 FROM B WHERE B.id = A.id</p><p>3、如果子查询有返回结果，则EXISTS子句返回TRUE，这一行R可作为外部查询的结果行，否则不能作为结果</p><p><strong>例2</strong>：<spanid="jump2">查询选修了全部课程的学生姓名</span>&gt;</p><p>注意mysql里面没有全程量词<spanclass="math display">\[\forall\]</span>，但是可以用存在量词和非来等价替换</p><p>​<br /><span class="math display">\[(\forall x)P\equiv \neg(\exists x (\neg P))\]</span></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> sname<br><span class="hljs-keyword">from</span> student<br><span class="hljs-keyword">where</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">exists</span><br><span class="hljs-comment">/*遍历student的每一行，看是否这一行满足下面存在语句，如代入第一行的学生201215121*/</span><br>(<span class="hljs-comment">/*查找学生201215121所有的没有选的课程，从course表中查找*/</span><br><span class="hljs-keyword">select</span> <span class="hljs-operator">*</span> <br>    <span class="hljs-keyword">from</span> course<br>    <span class="hljs-keyword">where</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">exists</span> <br>    <span class="hljs-comment">/*遍历每一个课程，看这个课程是否没有被选，如代入第一行的课程“数据库”，其cno = 1*/</span><br>    (<br>        <span class="hljs-comment">/*现在学生和课程名都确定了，在sc表中看这个课程学生选择了没有*/</span><br><span class="hljs-keyword">select</span> <span class="hljs-operator">*</span><br>        <span class="hljs-keyword">from</span> sc<br>        <span class="hljs-keyword">where</span> student.sno <span class="hljs-operator">=</span> sc.sno<span class="hljs-comment">/*这里的student.sno可以替换为201215121*/</span><br>        <span class="hljs-keyword">and</span> course.cno <span class="hljs-operator">=</span> sc.cno<span class="hljs-comment">/*这里的course.cno可以替换为1*/</span><br>    )<br>);<br></code></pre></td></tr></table></figure><p><strong>例3：</strong>查询至少选修了学生201215122选修的全部课程的学生号码</p><p>本查询可以用逻辑蕴涵来表达:对于学号为x的学生，对于所有的课程y，只要201215122学生选修了课程y，那么就有学生x选修了课程y</p><p>形式化如下：</p><p>用p表示谓词：学生201215122选修了课程y</p><p>用q表示谓词：学生x选修了课程y</p><p>则上述查询为 ： <span class="math display">\[(\forall y)p \rightarrow q\]</span> SQL语言中没有蕴涵的逻辑运算，但是可以通过<spanclass="math inline">\(\exists\)</span>和<spanclass="math inline">\(\neg\)</span>来等价替换 <spanclass="math display">\[p \rightarrow q \equiv \neg p \vee q\]</span> 加上前置的条件完成的转换为： <span class="math display">\[(\forall y)p \rightarrow q \equiv \neg (\exists y)(\neg(\neg p \vee q))\equiv\neg (\exists y)(p \wedge \neg q)\]</span>表达的意思为：不存在这样的课程y，学生201215122选修了y，而学生x没有选</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> <span class="hljs-keyword">distinct</span> sno<br><span class="hljs-keyword">from</span> sc scx<br><span class="hljs-keyword">where</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">exists</span><br><span class="hljs-comment">/*遍历sc的每一个学生，如代入第一行的学生201215121*/</span><br>(<br><span class="hljs-comment">/*学生已经确定了，看是否存在这样的课程y，学生201215122选修了y，而学生x没有选*/</span><br><span class="hljs-keyword">select</span> <span class="hljs-operator">*</span> <br><span class="hljs-keyword">from</span> sc scy<br><span class="hljs-keyword">where</span> scy.sno <span class="hljs-operator">=</span> &quot;201215122&quot;<br><span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">exists</span><br><span class="hljs-comment">/*遍历学生201215122的每一个课程，看是否还有学生x没有选的*/</span><br>(<br><span class="hljs-comment">/*学生确定了，课程确定了，看这个学生选了这个课程没有，用not exists实现，不能用!=*/</span><br><span class="hljs-keyword">select</span> <span class="hljs-operator">*</span><br><span class="hljs-keyword">from</span> sc scz<br><span class="hljs-keyword">where</span> scz.sno <span class="hljs-operator">=</span> scx.sno<br><span class="hljs-keyword">and</span> scy.cno <span class="hljs-operator">=</span> scz.cno<br>)<br>);<br></code></pre></td></tr></table></figure><p>仿造<a href="#jump2"><strong>例2</strong></a>的另一种解法，</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> sno<br><span class="hljs-keyword">from</span> student <br><span class="hljs-keyword">where</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">exists</span><br>(<br><span class="hljs-keyword">select</span> <span class="hljs-operator">*</span><br><span class="hljs-keyword">from</span> sc<br><span class="hljs-keyword">where</span> sc.sno <span class="hljs-operator">=</span> &quot;201215122&quot;<br><span class="hljs-keyword">and</span> sc.cno <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> <br>(<br><span class="hljs-keyword">select</span> cno<br><span class="hljs-keyword">from</span> sc<br><span class="hljs-keyword">where</span> sc.sno <span class="hljs-operator">=</span> student.sno<br>)<br>);<br></code></pre></td></tr></table></figure><h4 id="集合查询">集合查询</h4><p>select语句的查询结果是元组的集合，所以多个select语句的结果可以进行结合操作。集合操作主要包括并操作union、交操作intersect和差操作except。</p><p><font color = red>注意：参加集合操作的各查询结果的列数必须相同；对应的数据类型也必须相同</font></p><p><strong>例1：</strong>查询计算机科学系的学生及年龄不大于19岁的学生</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> <span class="hljs-operator">*</span><br><span class="hljs-keyword">from</span> student<br><span class="hljs-keyword">where</span> sdept <span class="hljs-operator">=</span> <span class="hljs-string">&#x27;CS&#x27;</span><br><span class="hljs-keyword">union</span><br><span class="hljs-keyword">select</span> <span class="hljs-operator">*</span><br><span class="hljs-keyword">from</span> student<br><span class="hljs-keyword">where</span> sage<span class="hljs-operator">&lt;=</span><span class="hljs-number">19</span>;<br></code></pre></td></tr></table></figure><p>实际上使用union将多个查询结果合并起来，系统会自动去掉重复的元组。如果要保留，使用unionall操作符。</p><p><strong>例2：</strong>查询选修了课程1或者选修了课程2的学生的姓名</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> sname<br><span class="hljs-keyword">from</span> student<br><span class="hljs-keyword">where</span> <span class="hljs-keyword">exists</span><br>(<br><span class="hljs-keyword">select</span> <span class="hljs-operator">*</span><br><span class="hljs-keyword">from</span> sc<br><span class="hljs-keyword">where</span> student.sno <span class="hljs-operator">=</span> sc.sno<br><span class="hljs-keyword">and</span> sc.cno <span class="hljs-operator">=</span> <span class="hljs-string">&#x27;1&#x27;</span><br><span class="hljs-keyword">union</span><br><span class="hljs-keyword">select</span> <span class="hljs-operator">*</span><br><span class="hljs-keyword">from</span> sc<br><span class="hljs-keyword">where</span> student.sno <span class="hljs-operator">=</span> sc.sno<br><span class="hljs-keyword">and</span> sc.cno <span class="hljs-operator">=</span> <span class="hljs-string">&#x27;2&#x27;</span><br>);<br></code></pre></td></tr></table></figure><p>实际上这个union等价于下面的语句</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> sname<br><span class="hljs-keyword">from</span> student<br><span class="hljs-keyword">where</span> <span class="hljs-keyword">exists</span><br>(<br><span class="hljs-keyword">select</span> <span class="hljs-operator">*</span><br><span class="hljs-keyword">from</span> sc<br><span class="hljs-keyword">where</span> student.sno <span class="hljs-operator">=</span> sc.sno<br><span class="hljs-keyword">and</span> (sc.cno <span class="hljs-operator">=</span> <span class="hljs-string">&#x27;1&#x27;</span> <span class="hljs-keyword">or</span> sc.cno <span class="hljs-operator">=</span> <span class="hljs-string">&#x27;2&#x27;</span>)<br>);<br></code></pre></td></tr></table></figure><p><strong>例3：</strong>查询计算机科学系的学生与年龄不大于19岁的学生的交集</p><p>有些数据库语言是没有intersect交集的操作，可以使用in语句来等价替换，如下面的例子</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> <span class="hljs-operator">*</span><br><span class="hljs-keyword">from</span> student<br><span class="hljs-keyword">where</span> sdept <span class="hljs-operator">=</span> <span class="hljs-string">&#x27;CS&#x27;</span><br><span class="hljs-keyword">and</span> sno <span class="hljs-keyword">in</span><br>(<br><span class="hljs-keyword">select</span> sno <br><span class="hljs-keyword">from</span> student<br><span class="hljs-keyword">where</span> sage <span class="hljs-operator">&lt;</span> <span class="hljs-number">19</span><br>);<br></code></pre></td></tr></table></figure><p>解释一下这个语句：一个元组即满足属性sdept ='cs'又满足in中的条件，年龄不大于19</p><p>如果不能理解，还可以用and语句来实现</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> <span class="hljs-operator">*</span><br><span class="hljs-keyword">from</span> student<br><span class="hljs-keyword">where</span> sdept <span class="hljs-operator">=</span> <span class="hljs-string">&#x27;CS&#x27;</span><br><span class="hljs-keyword">and</span> sage<span class="hljs-operator">&lt;=</span><span class="hljs-number">19</span>;<br></code></pre></td></tr></table></figure><p><strong>例4：</strong>查询计算机科学系的学生与年龄不大于19岁的学生的差集</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> <span class="hljs-operator">*</span><br><span class="hljs-keyword">from</span> student<br><span class="hljs-keyword">where</span> sdept <span class="hljs-operator">=</span> <span class="hljs-string">&#x27;CS&#x27;</span><br><span class="hljs-keyword">and</span> sno <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span><br>(<br><span class="hljs-keyword">select</span> sno <br><span class="hljs-keyword">from</span> student<br><span class="hljs-keyword">where</span> sage <span class="hljs-operator">&lt;</span> <span class="hljs-number">19</span><br>);<br></code></pre></td></tr></table></figure><h4 id="基于派生词的查询">基于派生词的查询</h4><p>子查询不仅可以出现在where子句中，<strong>还可以出现在from子句中</strong>，这是子查询生成的临时派生表成为主查询的查询对象。</p><p><strong>例1：</strong><ahref="#jump3">找出每个学生超过他自己选修课程平均成绩的课程号</a></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> sno , cno<br><span class="hljs-keyword">from</span> sc , <br>(<br><span class="hljs-keyword">select</span> sno , <span class="hljs-built_in">avg</span>(grade)<br><span class="hljs-keyword">from</span> sc <br><span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> sno<br>) <br><span class="hljs-keyword">as</span> avg_sc(avg_sno , avg_grade)<br><span class="hljs-keyword">where</span> sc.grade<span class="hljs-operator">&gt;</span>avg_sc.avg_grade<br><span class="hljs-keyword">and</span> sc.sno <span class="hljs-operator">=</span> avg_sc.avg_sno;<br></code></pre></td></tr></table></figure><p>这种派生的方法实际上是把两个表连接了起来，如果原有的两个表的行列数分别为(m1,n1)和(m2,n2),则得到的规模为(m1*m2,n1+n2)</p><h4 id="select语句的一般格式">select语句的一般格式</h4><p>select语句是mysql的核心语句，一般有如下格式：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> [<span class="hljs-keyword">all</span> <span class="hljs-operator">|</span> <span class="hljs-keyword">distinct</span>] <span class="hljs-operator">&lt;</span>目标列表达式<span class="hljs-operator">&gt;</span> [别名] , ……<br><span class="hljs-keyword">from</span> <span class="hljs-operator">&lt;</span>表名或者视图名<span class="hljs-operator">&gt;</span> [别名] , […… <span class="hljs-operator">|</span> (<span class="hljs-operator">&lt;</span><span class="hljs-keyword">select</span>派生<span class="hljs-operator">&gt;</span> [<span class="hljs-keyword">as</span>] <span class="hljs-operator">&lt;</span>别名<span class="hljs-operator">&gt;</span>)<br>[<span class="hljs-keyword">where</span> <span class="hljs-operator">&lt;</span>条件表达式<span class="hljs-operator">&gt;</span>]<br>[<span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> <span class="hljs-operator">&lt;</span>列名<span class="hljs-operator">&gt;</span> [<span class="hljs-keyword">having</span> <span class="hljs-operator">&lt;</span>条件表达式<span class="hljs-operator">&gt;</span>]]<br>[<span class="hljs-keyword">order</span> <span class="hljs-keyword">by</span> <span class="hljs-operator">&lt;&gt;</span>列名 [<span class="hljs-keyword">ASC</span> <span class="hljs-operator">|</span> <span class="hljs-keyword">DESC</span>]]<br></code></pre></td></tr></table></figure><h5 id="目标列表达式的可选格式">目标列表达式的可选格式</h5><ul><li><ul><li></li></ul></li><li><表名>.*</li><li>count([distinct | all] *)</li><li>[<表名>.]<属性列表达式></li></ul><p>其中属性列表达式可以由属性列、作用于属性列的聚集函数和常量的任意算数运算(+，-，*，/)组成的运算公式，<ahref="#jump4">见例题</a></p><h5 id="聚集函数的一般形式">聚集函数的一般形式</h5><p><span class="math display">\[\begin{Bmatrix}count\\sum\\avg\\  max\\min\end{Bmatrix}=({\,} [{\,}distinct {\,} | {\,} all{\,}] {\,}  *)\]</span></p><h5id="where子句的条件表达式的可选格式">where子句的条件表达式的可选格式</h5><p>(1)其中 <span class="math inline">\(\theta\)</span> 为比较符号 <spanclass="math display">\[&lt;属性列名&gt; \theta\begin{Bmatrix}&lt;属性列名&gt;\\&lt;常量&gt;\\{\,} [{\,}distinct {\,} | {\,} all{\,}] {\,} (select语句)\end{Bmatrix}\]</span></p><ol start="2" type="1"><li><p><span class="math display">\[&lt;属性列名&gt; [NOT]{\,} between\begin{Bmatrix}&lt;属性列名&gt;\\&lt;常量&gt;\\{\,} [{\,}distinct {\,} | {\,} all{\,}] {\,} (select语句)\end{Bmatrix}{\,}and{\,}\begin{Bmatrix}&lt;属性列名&gt;\\&lt;常量&gt;\\{\,} [{\,}distinct {\,} | {\,} all{\,}] {\,} (select语句)\end{Bmatrix}\]</span></p></li><li><p><span class="math display">\[&lt;属性列名&gt; [NOT]{\,} in\begin{Bmatrix}(&lt;值1&gt;[{\,},{\,}[值2]{\,}]\cdots)\\(select语句)\end{Bmatrix}\]</span></p></li><li><p><span class="math display">\[&lt;属性列名&gt; [not] {\,}{\,} like &lt;匹配串&gt;\]</span></p></li><li><p><span class="math display">\[&lt;属性列名&gt; is {\,}{\,}[not] {\,}{\,} null\]</span></p></li><li><p><span class="math display">\[not {\quad} exists{\quad} (select语句)\]</span></p></li><li><p><span class="math display">\[&lt;条件表达式&gt;\begin{Bmatrix}AND\\\\OR\end{Bmatrix}{\,}and{\,}\begin{bmatrix}\begin{Bmatrix}AND\\\\OR\end{Bmatrix}&amp; &lt;条件表达式&gt;\end{bmatrix}\]</span></p></li></ol><h3 id="视图">视图</h3><h4 id="定义视图">定义视图</h4><h5 id="建立视图">建立视图</h5><p>使用create view 命令建立视图，一般的格式为:</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">create</span> <span class="hljs-keyword">view</span><span class="hljs-operator">&lt;</span>视图名<span class="hljs-operator">&gt;</span> [(列名)...]<br><span class="hljs-keyword">as</span> <span class="hljs-operator">&lt;</span>子查询<span class="hljs-operator">&gt;</span><br>[<span class="hljs-keyword">with</span> <span class="hljs-keyword">check</span> option];<br></code></pre></td></tr></table></figure><p>with checkoption表示对视图进行update、insert和delete操作时要保证更新、插入或删除的行满足视图定义中的谓词条件。</p><p><strong>例1：</strong>建立信息系学生的视图，并要求进行修改和插入操作时仍需保证该视图只有信息系的学生</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">create</span> <span class="hljs-keyword">view</span> IS_Student<br><span class="hljs-keyword">as</span><br><span class="hljs-keyword">select</span> sno , sname , sage<br><span class="hljs-keyword">from</span> student<br><span class="hljs-keyword">where</span> sdept <span class="hljs-operator">=</span> &quot;IS&quot;<br><span class="hljs-keyword">with</span> <span class="hljs-keyword">check</span> option;<br></code></pre></td></tr></table></figure><p>执行createview语句的结果<code>只是把视图的定义存入数据字典，并不执行其中的select语句</code>。只是在对视图查询的时候，才按视图的定义从基本表中将数据查出。所以，如果基本表的结构被破坏，视图可能不会正常工作。</p><p><strong>例2：</strong>建立信息系选修了一号课程的学生的视图(包括学生、姓名、成绩)</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">create</span> <span class="hljs-keyword">view</span> is_s1(sno,sname,grade)<br><span class="hljs-keyword">as</span> <br><span class="hljs-keyword">select</span> student.sno , sname , grade<br><span class="hljs-keyword">from</span> student , sc<br><span class="hljs-keyword">where</span> student.sdept <span class="hljs-operator">=</span> &quot;IS&quot;<br><span class="hljs-keyword">and</span> student.sno <span class="hljs-operator">=</span> sc.sno<br><span class="hljs-keyword">and</span> sc.cno  <span class="hljs-operator">=</span> &quot;1&quot;<br><span class="hljs-keyword">with</span> <span class="hljs-keyword">check</span> option;<br></code></pre></td></tr></table></figure><p><strong>例3：</strong>将学生的学号以及平均成绩定义为一个视图</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">create</span> <span class="hljs-keyword">view</span> s_g(sno ,gavg)<br><span class="hljs-keyword">as</span> <br><span class="hljs-keyword">select</span> sno ,<span class="hljs-built_in">avg</span>(grade)<br><span class="hljs-keyword">from</span> sc<br><span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> sno;<br></code></pre></td></tr></table></figure><h5 id="删除视图">删除视图</h5><p><strong>例1：</strong>删除视图is_s1</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">drop</span> <span class="hljs-keyword">view</span> is_s1;<br></code></pre></td></tr></table></figure><p>如果在is_s1视图的基础上建立了其他视图，那么这里是不能删除成功的，在后方插入cascade指令可以把和is_s1级联的视图同时删除</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">drop</span> <span class="hljs-keyword">view</span> is_s1 cascade;<br></code></pre></td></tr></table></figure><h4 id="查询视图">查询视图</h4><p><strong>例1：</strong>在s_g视图中查询平均成绩在90分以上的学生学号和平均成绩</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">select</span> <span class="hljs-operator">*</span><br><span class="hljs-keyword">from</span> s_g<br><span class="hljs-keyword">where</span> <span class="hljs-built_in">avg</span>(gavg)<span class="hljs-operator">&gt;=</span><span class="hljs-number">90</span>;<br></code></pre></td></tr></table></figure><p>但是会报错，invalid use of groupfunction，因为s_g底层是group聚集函数组成的，不能使用where语句</p>]]></content>
    
    
    <summary type="html">harper的数据库小笔记，参考的书籍《数据库系统概论》——王珊</summary>
    
    
    
    <category term="笔记" scheme="http://example.com/categories/%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="mysql" scheme="http://example.com/tags/mysql/"/>
    
  </entry>
  
  <entry>
    <title>第一篇博客</title>
    <link href="http://example.com/2022/10/03/%E7%AC%AC%E4%B8%80%E7%AF%87%E5%8D%9A%E5%AE%A2/"/>
    <id>http://example.com/2022/10/03/%E7%AC%AC%E4%B8%80%E7%AF%87%E5%8D%9A%E5%AE%A2/</id>
    <published>2022-10-03T04:42:58.634Z</published>
    <updated>2022-10-29T07:02:57.745Z</updated>
    
    <content type="html"><![CDATA[<p>终于搭建好博客了，以后会在这里发布一些文章，同时分享一些自己的生活。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;终于搭建好博客了，以后会在这里发布一些文章，同时分享一些自己的生活。&lt;/p&gt;

</summary>
      
    
    
    
    <category term="学习" scheme="http://example.com/categories/%E5%AD%A6%E4%B9%A0/"/>
    
    
    <category term="mysql" scheme="http://example.com/tags/mysql/"/>
    
  </entry>
  
</feed>
