<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
    <channel>
        <title>zongyue blog</title>
        <link>http://zongyue.top:8090</link>
            <description>Email: zongyuewang@gmail.com
<br/>
wechat: creed00001111</description>
        <language>zh-CN</language>
                <item>
                    <title>
                        <![CDATA[
                            OT和OT-Extension
                        ]]>
                    </title>
                    <link>http://zongyue.top:8090/archives/ot%E5%92%8Cot-extension</link>
                    <content:encoded>
                        <![CDATA[
                                <h2 id="ot">OT</h2>
<p>OT 是双方的交互协议，交互双方为Sender和Receiver。Sender有两个消息${m_0, m_1}$，Receiver选择$b\in\{0,1\}$，完成Sender将$m_b$发送给Receiver。<br />
但Sender并不知道Receiver选择了其中哪一个，而Receiver也无法获取另一个消息的信息。<br />
一个典型的<strong>1 out of 2 OT</strong>如下图所示：<br />
<img src="http://zongyue.top:8090/upload/2021/11/1outof2OT-f83ec9f0e6024b03bd60a90e52e204b7.png" alt="1outof2OT.png" /><br />
此外，还有OT的一些变体，比如：</p>
<ul>
<li><strong>Rabin's OT</strong> Sender有1个消息m，Receiver以$\frac{1}{2}$的概率获得m或者噪声；</li>
<li><strong>1 out of N OT</strong> Sender有$N$个消息，Receiver选择$b\in\{0,1,\cdots N\}$；</li>
<li><strong>k out of N OT</strong> Sender有$N$个消息，Receiver选择${b_1, b_2, \cdots b_k }, b_i \in \{0,1,\cdots N\}$；</li>
</ul>
<p>以上的OT变体均可以通过<strong>1 out of 2 OT</strong> 实现。我们介绍一下如何使用<strong>1 out of 2 OT</strong> 构造<strong>1 out of N OT</strong>。</p>
<p>假设Sender有4个消息$\{m_0,m_1,m_2,m_3\}$，希望实现一个<strong>1 out of 4 OT</strong>：</p>
<ul>
<li>Sender和Receiver完成两个<strong>1 out of 2 OT</strong>，传递$\{k_0, k_1\}$和${k_{0}', k_{1}'}$，Reciver选择$b_0, b_1$拿到$k_{b_0}$和$k_{b_1}$;</li>
<li>Sender将${m_0,m_1,m_2,m_3}$加密到${c_0,c_1,c_2,c_3}$，分别使用密钥$\{[k_0,k_{0}'], [k_0,k_{1}'],[k_1,k_{0}'],[k_1,k_{1}']\}$。加密可以简单使用$c_0 = m_0 \oplus F_{k_0}(00)) \oplus F_{k_{0}'}(00)$，$c_1 =m_1 \oplus F_{k_0}(01))\oplus F_{k_{1}'}(01)$以此类推。这里不能简单的使用$\oplus k_i$，因为这样Receiver可获得$c_0\oplus c_1\oplus c_2\oplus c_3 = m_0\oplus m_1\oplus m_2\oplus m_3$，有信息泄漏;</li>
<li>Sender将${c_0,c_1,c_2,c_3}$发送给Receiver，则Receiver只能解密$b_0 b_1$对应密文；</li>
</ul>
<h2 id="ot-的构造">OT 的构造</h2>
<p>OT可以通过Diff-Hellman进行构造，如下所示：<br />
<img src="http://zongyue.top:8090/upload/2021/11/OT-Diffie-Hellman-4d34ba39710b448087d73c6b4c5d9e01.png" alt="OTDiffieHellman.png" /><br />
Bob 作为Receiver，选择c，Alice 作为sender，发送$M_0$或$M_1$</p>
<h2 id="ot-extension">OT Extension</h2>
<p>Sender和Receiver希望进行 $k$ 次OT，每次传递$l$ bit 的消息，通过 $k$ 次$l$ bit 的 OT，可以完成。而OT Extension可以大大增大传输效率。通过OT Extension，可以仅进行 $\lambda$ 次 $k$ bit的OT，就可以实现。该论文发表在CRYPTO 2003,&quot;Extending Oblivious Transfer Efficiently&quot;.</p>
<h3 id="magic-方法">magic 方法</h3>
<ol>
<li>首先假设有一种 magic 方法，可以实现以下结果：<br />
<img src="http://zongyue.top:8090/upload/2021/11/Clipboard_2021-09-12-10-03-32-99919f69fa8749c38a38bd03c0207d93.png" alt="Clipboard_20210912100332.png" /></li>
</ol>
<ul>
<li>Alice (Sender) 选择一个随机的长度为 $\lambda$ 的数 $S$</li>
<li>Bob (Receiver) 随机生成一个 $k$ 行， $\lambda$ 列的矩阵 $T$，每一个元素均为1 bit</li>
<li>通过 magic 方法，Alice 可以拿到矩阵 $Q$，其中，根据 Bob 的选择<br />
$\{b_0,b_1,\cdots b_k\}$, $b_i \in \{0, 1\}$<br />
$$<br />
Q_i=<br />
\begin{cases}<br />
T_i,\quad &amp;if \quad  b_i=0\\<br />
T_i\oplus S,\quad &amp; if \quad b_i=1<br />
\end{cases}<br />
$$</li>
</ul>
<ol start="2">
<li><span i_0="">通过这个 magic 方法，Alice 可将消息对 $m_</span><span i_1="">, m_</span><span i_0="">$ 使用 $m_</span><span i_1=""> \oplus H(i, Q_i)$ 和 $m_</span> \oplus H(i, Q_i\oplus S)$ 进行加密，$Q_i$ 和 $Q_i\oplus S$ 中有一个是$T_i$，而Bob不知道 $S$，所以只能恢复他选择的这个消息。<br />
<img src="http://zongyue.top:8090/upload/2021/11/Clipboard_2021-09-12-16-46-23-f5a987c78b754d79b90f479df3de9454.png" alt="Clipboard_20210912164623.png" /><br />
这样就完成了$k$ 次，$l$ bit 的消息的OT。</li>
</ol>
<h3 id="如何实现-magic-方法">如何实现 magic 方法</h3>
<ol>
<li>Bob生成矩阵$T$，Alice生成$S$</li>
<li>Bob 作为 Sender，Alice 作为Receiver，完成 $\lambda$ 次 OT，其中消息Alice根据$s_i$选择接受$T^i$或者$T^i\oplus B$，$B$为Bob的选择向量。<br />
<img src="http://zongyue.top:8090/upload/2021/11/Clipboard_2021-09-12-17-08-03-dc6f5aa418c74eedbdb742189c25fb2f.png" alt="Clipboard_20210912170803.png" /><br />
这样就完成了magic 方法，可以按下图进行分析：<br />
<img src="http://zongyue.top:8090/upload/2021/11/Clipboard_2021-09-12-17-10-58-1cf0f748a91044e396e368537eecd831.png" alt="Clipboard_20210912171058.png" /></li>
</ol>
<h2 id="参考视频">参考视频</h2>
<p><a href="https://www.youtube.com/watch?v=hP22X0T_-s4">https://www.youtube.com/watch?v=hP22X0T_-s4</a><br />
<a href="https://www.youtube.com/watch?v=VY3HlyCucPI">https://www.youtube.com/watch?v=VY3HlyCucPI</a></p>

                        ]]>
                    </content:encoded>
                    <pubDate>Nov 3, 2021 10:52:25 AM</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[
                            RSA 算法和Montgomery 模乘
                        ]]>
                    </title>
                    <link>http://zongyue.top:8090/archives/montgomery%E6%A8%A1%E4%B9%98%E5%92%8Crsa%E7%AE%97%E6%B3%95%E5%AE%9E%E7%8E%B0</link>
                    <content:encoded>
                        <![CDATA[
                                <h2 id="rsa-算法">RSA 算法</h2>
<p>RSA 算法由密码学由Ron Rivest、Adi Shamir 和 Leonard Adleman在1977年提出。其数学结构简单易懂，直到今天仍是最广泛使用的公钥密码算法。<br />
<img src="http://zongyue.top:8090/upload/2020/2/shamir-rivest-adleman-79b1e44bab1c4941890786f571455030.jpg" alt="shamirrivestadleman.jpg" /><br />
RSA 算法利用了大整数分解这一数学难题。消息接收者生成$n = p \times q$，其中$p$和$q$均为大素数。计算$ed \equiv 1 \mod n$，其中 $e$ 为公钥，一般取 $65537$，$d$ 为私钥。消息接收者将$n$ 和 $e$进行公开。</p>
<ul>
<li>消息发送者加密消息时，计算密文$c \equiv m^e \mod (p-1)(q-1)$，</li>
<li>消息接收者可通过计算$m \equiv c^d \mod n$ 恢复消息 $m$。</li>
</ul>
<p>当然，在实际使用时，RSA 算法并非这么简单，还需要考虑填充等结构，以避免一些攻击，如<a href="https://asecuritysite.com/encryption/c_c3">Bleichenbacher's attack</a> 等。</p>
<p>一般来说，RSA 的公钥 $n$ 较大，通常为1024 bit、2048 bit、4096 bit，也就是RSA-1024、RSA-2048 和 RSA-4096。在实现时，RSA 会涉及三类大数运算:1.大数乘法 2.大数取模 3.大数模幂。这三类计算在实现时均有相应的算法来进行优化。其中，大数乘法和取模可以和合并为模乘运算，一般采用大名鼎鼎的Montgomery 模乘算法。</p>
<h2 id="montgomery模乘">Montgomery模乘</h2>
<p>模运算是大数运算中最费时间的一种。模运算实际上是算除法，在运算时，一般需要做试除，导致除法的计算复杂度比乘法要高。因此，我们希望在实现的时候尽量避免乘法。</p>
<p>Montgomery 在论文<a href="https://pdfs.semanticscholar.org/fee0/5046051e8888a75b24426a5263d970470478.pdf">&quot;Modular Multiplication Without Trial Division&quot;</a>中提出一种计算模乘的方法，将除$n$操作可转化为移位操作，有效的降低了实现复杂度。该算法是目前实现RSA最常用的模乘实现。</p>
<p>Montgomery模乘实际上由模约减和模乘两部分组成，下面我们分别进行介绍。</p>
<h3 id="montgomery模约减算法">Montgomery模约减算法</h3>
<p>模约减算法$R(\cdot)$定义为：$\forall x \in [0, n^2)$ 计算 $R(x) = xr^{-1} \mod n$，其中$r &gt; n$ 且 $gcd(n, r) = 1$。</p>
<p>计算算法如下：</p>
<ol>
<li>计算 $s = xk \mod r$，其中$k = \frac{r(r^{-1} \mod n)-1}{n}$;</li>
<li>计算 $t = x + sn$。注意，$x&lt;n^2&lt;rn$，$sn&lt;rn$，故$t&lt;2nr$。这里$t$还有一个重要特性：$t \equiv 0 \mod r$，也就是$t$是$r$的整数倍。可按下式进行证明：<br />
$$x+sn \equiv x+xkn \equiv x(1+kn) \equiv x(rr{-1})\equiv 0 \mod r;$$</li>
<li>计算$u = \frac{t}{r}$，可知$u \equiv tr^{-1} \mod n$；</li>
<li>由 $t&lt;2nr$ 可知$u&lt;2n$。如果$u&lt;n$，则直接返回$u$即为$R(x)$结果；否则返回$u-n$。</li>
</ol>
<p>从上面计算方法可以看出，我们可以将 $\mod n$ 的操作转化为 $\mod r$，除 $r$ 和 减法。特别的，可以取$r = 2^b$，这样在计算机内实现时，模和除 $r$ 均可很快计算得出。这也是Montgomery模乘算法的精髓。</p>
<h3 id="montgomery模乘-1">Montgomery模乘</h3>
<p>和普通模计算 $a\times b \mod n$ 不同，Montgomery模乘首先计算的是 $abr \mod n$。通过Montgomery 模约减算法，可以简单的通过如下方式计算:</p>
<ol>
<li>计算$c \equiv ar \mod n$ 和 $\equiv br \mod n$；</li>
<li>计算$c \times d$，然后通过Montgomery 模约减算法计算$e = R(c \times d)$ 即为$abr \mod n$；</li>
<li>输出$er^{-1} \mod n$。</li>
</ol>
<p>p.s. 对于$x$，$xr \mod n$一般称为$x$的 Montgomery 表示。</p>
<h3 id="montgomery模乘总结">Montgomery模乘总结</h3>
<p>计算可以将计算 $a\times b \mod n$ 总结如下：<br />
<strong>1. 初始化计算</strong></p>
<ul>
<li>选择$r &gt; n$，且 $gcd(r, n) = 1$</li>
<li>计算$k =  \frac{r(r^{-1} \mod n)-1}{n}$</li>
</ul>
<p><strong>2. 转化为 Montgomery 表示</strong></p>
<ul>
<li>计算$c \equiv ar \mod n$ 和 $d \equiv br \mod n$</li>
</ul>
<p><strong>3. 计算 $abr \mod n$</strong></p>
<ul>
<li>$x = cd$</li>
<li>$s = xk \mod r$</li>
<li>$t = x + sn$</li>
<li>$u = \frac{t}{r}$</li>
<li>若 $u&lt;n$ 输出 $e=u$，否则输出 $e = u-n$</li>
</ul>
<p><strong>4.从Montgomery 表示转化为一般表示</strong></p>
<ul>
<li>$er^{-1} \mod n$</li>
</ul>
<h3 id="montgomery-模乘之于rsa-算法">Montgomery 模乘之于RSA 算法</h3>
<p>虽然在计算过程中没有$\mod n$相关操作，但在初始化和最后的转化中，还是会进行 $\mod n$ 的操作。这样计算模乘看上去并没有降低计算的复杂程度。然而，在 RSA 算法中，存在一系列的模乘运算，这些模乘运算是连续进行的。如最著名的平方乘算法，就是把模幂运算分解成一系列的模乘和模方操作。另外，我们也不难发现，在Montgomery 模乘输出的结果$e$，其实正是 $ab \mod n$ 的 Montgomery 表示。那么对于计算 $c^d \mod n$ 这样的模幂，我们可以首先完成<strong>1.初始化计算</strong> 和 <strong>2.将 $m$ 转化为 Montgomery 表示</strong>，套用平方乘等算法，始终使用Montgomery 表示来计算模乘，最后统一进行<strong>4.从Montgomery 表示转化为一般表示</strong>。这样可以避免中间过程进行$\mod n$运算从而大大减小计算的复杂程度。Bingo！</p>
<h2 id="参考">参考：</h2>
<p><a href="https://www.nayuki.io/page/montgomery-reduction-algorithm">https://www.nayuki.io/page/montgomery-reduction-algorithm</a><br />
<a href="http://www.doc88.com/p-7428222580849.html">http://www.doc88.com/p-7428222580849.html</a></p>

                        ]]>
                    </content:encoded>
                    <pubDate>Feb 10, 2020 6:20:45 PM</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[
                            AES 和 SM4 的 S 盒生成方法简介
                        ]]>
                    </title>
                    <link>http://zongyue.top:8090/archives/aes%E5%92%8Csm4%E7%9A%84s%E7%9B%92%E7%94%9F%E6%88%90%E6%96%B9%E6%B3%95%E7%AE%80%E4%BB%8B</link>
                    <content:encoded>
                        <![CDATA[
                                <h2 id="aes-s盒">AES S盒</h2>
<h3 id="原理">原理</h3>
<p>AES的S盒是定义在$GF(2^8)$（不可约多项式$x^8+x^4+x^3+x+1$），其表达式为$S(x) = Ax^{-1}+c$，具体如下：<br />
$$<br />
\begin{equation}<br />
\left(<br />
\begin{array}{c}<br />
s_7 \\<br />
s_6 \\<br />
s_5 \\<br />
s_4 \\<br />
s_3 \\<br />
s_2 \\<br />
s_1 \\<br />
s_0 \\<br />
\end{array}<br />
\right)=<br />
\left(<br />
\begin{array}{cccccccc}<br />
1 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 0 &amp; 0 &amp; 0\\<br />
0 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 0 &amp; 0\\<br />
0 &amp; 0 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 0\\<br />
0 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 1\\<br />
1 &amp; 0 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 1 &amp; 1\\<br />
1 &amp; 1 &amp; 0 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 1\\<br />
1 &amp; 1 &amp; 1 &amp; 0 &amp; 0 &amp; 0 &amp; 1 &amp; 1\\<br />
1 &amp; 1 &amp; 1 &amp; 1 &amp; 0 &amp; 0 &amp; 0 &amp; 1\\<br />
\end{array}<br />
\right)<br />
\end{equation}\cdot<br />
\left(<br />
\begin{array}{c}<br />
x_7 \\<br />
x_6 \\<br />
x_5 \\<br />
x_4 \\<br />
x_3 \\<br />
x_2 \\<br />
x_1 \\<br />
x_0 \\<br />
\end{array}<br />
\right)+<br />
\left(<br />
\begin{array}{c}<br />
0 \\<br />
1 \\<br />
1 \\<br />
0 \\<br />
0 \\<br />
0 \\<br />
1 \\<br />
1 \\<br />
\end{array}<br />
\right)<br />
$$</p>
<p>该表示是将一个字节（8 bits）看成$GF(2^8)$上的一个元素。将$GF(2^8)$看成向量空间，其上任何一个元素均可由该向量空间的一组基表示。在AES的定义使用多项式基:假设$A$为多项式$x^8+x^4+x^3+x+1$的根，即$A^8+A^4+A^3+A+1=0$。那么任何一个元素$x$可以表示为$x = x_7A^7+x_6A^6+x_5A^5+x_4A^4+x_3A^3+x_2A^2+x_1A+x_0$</p>
<h3 id="生成">生成</h3>
<p>下面我们尝试利用<code>pyfinite</code>生成 AES 的 S 盒。</p>
<pre><code class="language-python">from pyfinite import ffield

gen = 0b100011011
F = ffield.FField(8, gen, useLUT=0) # 这里一定要写useLUT=0，不然会出问题。。。

A = [0b10001111, 0b11000111, 0b11100011, 0b11110001, 0b11111000, 0b01111100, 0b00111110, 0b00011111]

def aes_sbox_gen(x):
    '''
    输入x，输出S(x)
    '''
    x_inv = F.Inverse(x)
    y = 0
    for i, a in enumerate(A):
        if(x_inv&amp;(1&lt;&lt;(7-i))):
            y ^= a  # 若该bit为1，则异或相应列
    return y^0x63

sbox = []
for i in range(256):
    sbox.append(aes_sbox_gen(i))  # 生成sbox
</code></pre>
<h2 id="sm4-s盒">SM4 S盒</h2>
<h3 id="生成-1">生成</h3>
<p>在SM4官方文档中，仅仅给出了S盒的定义。进行学术搜索，发现各个论文上对SM4 S盒的生成方法描述各有不同。比较靠谱的一篇描述为<a href="http://www.iaeng.org/publication/WCECS2017/WCECS2017_pp21-25.pdf">S-box Optimization for SM4 Algorithm</a>，结合GMSSL中关于SM4 bitslice的实现<a href="https://github.com/guanzhi/GmSSL/blob/master/crypto/sms4/sm4_bs.c">sm4_bs.c</a>，我们可以得出：SM4 S盒同样定义在$GF(2^8)$上。与AES有所不同，该$GF(2^8)$采用的不可约多项式为$x^8+x^7+x^6+x^5+x^4+x^2+1$，生成方式为$S(x) = A(Ax+c)^{-1}+c$，其中：<br />
$$<br />
\begin{equation}<br />
A = \left(<br />
\begin{array}{cccccccc}<br />
1 &amp; 1 &amp; 0 &amp; 1 &amp; 0 &amp; 0 &amp; 1 &amp; 1\\<br />
1 &amp; 1 &amp; 1 &amp; 0 &amp; 1 &amp; 0 &amp; 0 &amp; 1\\<br />
1 &amp; 1 &amp; 1 &amp; 1 &amp; 0 &amp; 1 &amp; 0 &amp; 0\\<br />
0 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 0 &amp; 1 &amp; 0\\<br />
0 &amp; 0 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 0 &amp; 1\\<br />
1 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 0\\<br />
0 &amp; 1 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 1 &amp; 1\\<br />
1 &amp; 0 &amp; 1 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 1\\<br />
\end{array}<br />
\right),<br />
c = \left(<br />
\begin{array}{c}<br />
1 \\<br />
1 \\<br />
0 \\<br />
1 \\<br />
0 \\<br />
0 \\<br />
1 \\<br />
1 \\<br />
\end{array}<br />
\right)<br />
\end{equation}<br />
$$</p>
<p>SM4的S盒生成也是采用了多项式基的表示，同AES。</p>
<pre><code class="language-python">from pyfinite import ffield

gen = 0b111110101
F = ffield.FField(8, gen, useLUT=0) # 这里一定要写useLUT=0，不然会出问题。。。

A = [0b11100101, 0b11110010, 0b01111001, 0b10111100, 0b01011110, 0b00101111, 0b10010111, 0b11001011]

def sm4_sbox_gen(x):
    '''
    输入x，输出S(x)
    '''
    y = 0
    for i, a in enumerate(A):
        if(x&amp;(1&lt;&lt;(7-i))):
            y ^= a  # 若该bit为1，则异或相应列, y=Ax
    y ^= 0xd3
    y_inv = F.Inverse(y) # (Ax+c)^(-1)
    z = 0
    for i, a in enumerate(A):
        if(y_inv&amp;(1&lt;&lt;(7-i))):
            z ^= a  # 若该bit为1，则异或相应列, z=A(Ax+c)^(-1)
    return z^0xd3

sbox = []
for i in range(256):
    sbox.append(sm4_sbox_gen(i))  # 生成sbox
</code></pre>

                        ]]>
                    </content:encoded>
                    <pubDate>Feb 8, 2020 12:34:29 AM</pubDate>
                </item>
                <item>
                    <title>
                        <![CDATA[
                            AES 和 SM4 S 盒复合域实现方法
                        ]]>
                    </title>
                    <link>http://zongyue.top:8090/archives/aes%E5%92%8Csm4s%E7%9B%92%E5%A4%8D%E5%90%88%E5%9F%9F%E5%AE%9E%E7%8E%B0%E6%96%B9%E6%B3%95</link>
                    <content:encoded>
                        <![CDATA[
                                <h2 id="背景">背景</h2>
<p>是的，你没看错。本文要讲一下如何实现 AES 和 SM4 的 S 盒实现。你可能好奇，S 盒实现有什么好讲的，<code>c</code> 语言一个<code>unsigned int Sbox[256] = {...}</code>，<code>verilog</code>一个<code>always case xxx:</code>解决问题。没错，查表实现是S盒最基本的实现方法。高端一点的查表，可以将 S 盒的实现结合线性变换（AES 的 MixColumn，SM4 的 $L$）形成 $8\rightarrow 32$的大表 T-Table 进行加速，例如<a href="https://github.com/openssl/openssl/blob/master/crypto/aes/aes_x86core.c">openssl的查表实现</a>。</p>
<p>其实，我们本文将探讨一种不通过查表，只是通过逻辑运算的 S 盒实现方法。</p>
<p>AES 和 SM4 的 S 盒都是由 $GF(2^8)$ 有限域上的运算进行生成的。我们可以直接基于其实现方法，对 S 盒进行计算实现。在 AES 和 SM4 的 S 盒生成公式中，均设计在 $GF(2^8)$ 的求逆运算，该运算比较耗时。有限域中求逆运算可以转化幂运算，例如 AES 的 S 盒可以表达为：<br />
$$S(x) = 63 + 05x^{254} + 09x^{253} + F9x^{251} + 25x^{247} + 01x^{223} + B5x^{191} + 8Fx^{127}.$$<br />
该运算定义在$GF(2^8)$上，直接实现同样较为复杂。</p>
<p>还有一种方法，是使用布尔函数对 S 盒进行表达，利用布尔函数进行实现。该方法其实可以看作$GF(2)$上的表达。<a href="https://pdfs.semanticscholar.org/420b/0ba5d2948383fdabd95c9347043415df143e.pdf">On Deviations of the AES S-box when Represented as Vector Valued Boolean Function</a>对 AES 的 S 盒进行了分析，得到其布尔函数表达式，例如，其中第0比特可表示为：<br />
<img src="http://zongyue.top:8090/upload/2020/2/aes-sbox-bit-5a397795f1e649a0b34b56f6e3c00ab3.png" alt="aessboxbit.png" /></p>
<p>布尔函数非常复杂，直接利用布尔函数表达式也不是一个好的思路。</p>
<p>D.Canright在<a href="https://calhoun.nps.edu/bitstream/handle/10945/791/NPS-MA-04-001.pdf?sequence=1&amp;isAllowed=y">A Very Compact Rijndael S-box</a>一文中，提出一种实现思路：基于复合域进行实现。文章提出该方法实现在资源有限情况下的该类 S 盒的实现方式，后该方法被用于构造掩码实现（抵抗DPA攻击）和bitslice实现上。本文将对这个方法进行介绍。</p>
<h2 id="原理">原理</h2>
<p>AES 和 SM4 的 S 盒生成都是基于$GF(2^8)$进行构造的，利用逆运算和仿射变换(affine)。仿射变换本身就能表示成逻辑运算，我们重点关注求逆运算。AES 和 SM4 的表达都是基于多项式基，以 AES 的有限域为例，假设$A$为多项式$x^8+x^4+x^3+x+1$的根，即$A^8+A^4+A^3+A+1=0$。那么任何一个元素$x$可以表示为$x = x_7A^7+x_6A^6+x_5A^5+x_4A^4+x_3A^3+x_2A^2+x_1A+x_0$。这种做法是将$GF(2^8)$直接看作$GF(2)$的8次扩域。我们也可以不这么看，将$GF(2^8)$看成$GF(2^4)$的2次扩域，$GF(2^{4})$可以进一步看作$GF(2^2)$的2次扩域，再进一步$GF(2^2)$可以看作$GF(2)$的2次扩域。而$GF(2^8)$的求逆运算，可以通过数学表达式，转换为$GF(2^4)$的求逆和一些乘、加操作。这些操作可以进一步向下转化。下面我们详细说明一下。</p>
<p>$K = GF(q^n)$为$GF(q)$的n次扩域，$\beta$ 为多项式的根，那么多项式基为$\{ 1,\beta,\beta^2, \ldots, \beta^{n-1} \}$，任何一个元素$x$，可以表示为$x = x_{n-1}\beta^{n-1}+\ldots+x_1\beta+x_0$，这也是AES 和 SM4 所采用的基表示方式。此外，除了多项式基以外，域的表达方式还可以使用正规基进行表达，正规基为$\{\beta, \beta^q, \beta^{q^2}, \ldots, \beta^{q^{n-1}}\}$，正规基使用了多项式的全部根。</p>
<p>$GF(2^8)$，可以看作$GF(2^4)$的2次扩域，也就是在$GF(2^4)$上寻找一个不可约二次多项式，$r(y) = y^2 + \tau y +\upsilon$，其中，$\tau$ 和 $\upsilon$ 为 $GF(2^4)$ 的元素。设 $Y$ 为 $r(y)$ 的根，则 $GF(2^8)$ 元素的多项式基为 ${Y, 1}$，正规基为${Y, Y^{16}}$。Canright在文章中讨论了多项式基和正规基两种方式，我们这里只看正规基。对于$GF(2^8)$的元素 $g = \gamma_1 Y^{16} + \gamma_0 Y$，求逆 $d = \delta_1 Y^{16} + \delta_0 Y$，$\gamma_i$ 和 $\delta_i$ 都是$GF(2^4)$的元素, $gd = 1$，待定系数求解，可得出<br />
$$<br />
\left\{<br />
\begin{align}<br />
\delta_1 &amp;= [\gamma_1 \gamma_0 \tau^2 + (\gamma_1^2 + \gamma_0^2)\upsilon]^{-1}\gamma_0 \\<br />
\delta_0 &amp;= [\gamma_1 \gamma_0 \tau^2 + (\gamma_1^2 + \gamma_0^2)\upsilon]^{-1}\gamma_1<br />
\end{align}<br />
\right.<br />
$$<br />
文内有详细推导方法，不再赘述。观察系数，其达到的效果就是，$GF(2^8)$的求逆运算，转化成为$GF(2^4)$的乘法、平方和求逆，特别的，可以选择不可约多项式为$r(y) = y^2 + y + \upsilon$，也就是 $\tau$ 取1来降低求解复杂度，这样，对$g = \gamma_1 Y^{16} + \gamma_0 Y$的求逆可简化为如下图：<br />
<img src="http://zongyue.top:8090/upload/2020/2/GF256_inv-cb9b9381b45e45ab92af16291cee5485.png" alt="GF256_inv.png" /></p>
<p>同样，$GF(2^4)$可以看作$GF(2^2)$的二次扩域，也就是在$GF(2^2)$寻找一个不可约二次多项式，$s(z) = z^2 + Tz + N$，设$Z$ 为该多项式的根，取正规基$\{Z^4, Z\}$。和$GF(2^8)$计算方法相同，可计算$GF(2^4)$元素$\upsilon = \Gamma_1 Z^4+\Gamma_0 Z$ 的逆为$\delta = \Delta Z^4 + \Delta Z$，其中，</p>
<p>$$<br />
\left\{<br />
\begin{align}<br />
\Delta_1 &amp;= [\Gamma_1 \Gamma_0 T^2 + (\Gamma_1^2 + \Gamma_0^2)N]^{-1}\Gamma_0 \<br />
\Delta_0 &amp;= [\Gamma_1 \Gamma_0 T^2 + (\Gamma_1^2 + \Gamma_0^2)N]^{-1}\Gamma_1<br />
\end{align}<br />
\right.<br />
$$</p>
<p>也可以取$T = 1$降低复杂度，那么在$GF(2^4)$求逆运算如下图所示：<br />
<img src="http://zongyue.top:8090/upload/2020/2/GF16_inv-7a5ed55e2efe46238e16e0c26022c57f.png" alt="GF16_inv.png" /></p>
<p>在$GF(2^8)$求逆时，也涉及到了$GF(2^4)$的乘法。$GF(2^4)$的乘法$\upsilon\delta = (\Gamma_1 Z^4+\Gamma_0 Z)(\Delta_1 Z^4 + \Delta_0 Z)$可按照如下公式计算：</p>
<p>$$<br />
\left\{<br />
\begin{align}<br />
\Phi &amp;= N(\Gamma_1+\Gamma_0)(\Delta_1+\Delta_0) \\<br />
\upsilon\delta&amp;= [\Phi+\Gamma_1\Delta_1]Z^4+[\Phi+\Gamma_0\Delta_0]Z<br />
\end{align}<br />
\right.<br />
$$</p>
<p>如下图：</p>
<p><img src="http://zongyue.top:8090/upload/2020/2/GF16_mul-647eaf7a9e6f4e63a439f9ab364cb48e.png" alt="GF16_mul.png" /></p>
<p>进一步，$GF(2^2)$可以看作$GF(2)$的二次扩域，在$GF(2)$上的不可约多项式只有$t(\omega) = \omega^2+\omega+1$,取正规基${W^2, W}$，则$\Gamma = g_1W^2+g_0W$，逆为$\Delta = d_1W^2+d_0W$，其中，<br />
$$<br />
\left\{<br />
\begin{align}<br />
d_1 &amp;= g_0 \\<br />
d_0 &amp;= g_1<br />
\end{align}<br />
\right.<br />
$$<br />
$GF(2^2)$的乘法，$\Gamma\Delta = (g_1W^2+g_0W)(d_1W^2+d_0W)$，计算如下：<br />
$$<br />
\left\{<br />
\begin{align}<br />
f &amp;= (g_1+g_0)(d_1+d_0) \\<br />
\upsilon\delta&amp;= [f+g_1d_1]W^2+[f+g_0d_0]W<br />
\end{align}<br />
\right.<br />
$$<br />
如下图：<br />
<img src="http://zongyue.top:8090/upload/2020/2/GF4_mul-cea30fdf90704223a60ed41099073551.png" alt="GF4_mul.png" /></p>
<p>将$GF(2^8)$进行转化，我们还有一些操作未介绍，包括 $\upsilon\gamma^2$、$N\Gamma^2$ 和 $N\Gamma$。这些值可通过选择不同的 $\upsilon$ 和 $N$ 进行简化。文章详细讨论了选取的方法。我们直接给结论：</p>
<ul>
<li>对于$GF(2^2)$，不可约多项式为$t(\omega) = \omega^2+\omega+1$，正规基$\{W^2, W\}$</li>
<li>对于$GF(2^4)/GF(2^2)$，不可约多项式为$s(z) = z^2 + z + N$，$N = W^2$，正规基${Z^4, Z}$，$N(g_1W^2+g_2W)^2 = W^2(g_1W^2+g_2W) = g_1W^2+(g_1+g_0)W$</li>
<li>对于$GF(2^8)/GF(2^4)$，不可约多项式为$r(y) = y^2 + y +\upsilon$，$\upsilon = N^2Z$，如此，$\upsilon(AZ^4+BZ)^2 = (A+B)^2Z^4+N^2B^2$</li>
</ul>
<p>复合域下，实际上是以$$[(b_7w^2 + b_6w)z^4 + (b_5w^2 + b_4w)z]y^{16} + [(b_3w^2 + b_2w)z^4 + (b_1w^2 + b_0w)z]y =\\ b_7w^2z^4y^{16} + b_6wz^4y^{16} + b_5w^2zy^{16} + b_4wzy^{16} + b_3w^2z^4y + b_2wz^4y + b_1w^2zy + b_0wzy$$表示$GF(2^8)$的一个元素。<br />
而 S 盒的输入是以多项式基表示进行输入的。要利用复合域进行运算，需要将输入表示进行转换。以线性空间的角度看，这复合域表示相当于是给$GF(2^8)$找了一组新基。两组基有如下关系：<br />
$$g_7A^7+g_6A^6+g_5A^5+g_4A^4+g_3A^3+g_2A^2+g_1A+g_0 \\= b_7w^2z^4y^{16} + b_6wz^4y^{16} + b_5w^2zy^{16} + b_4wzy^{16} + b_3w^2z^4y + b_2wz^4y + b_1w^2zy + b_0wzy$$<br />
找到$w^2z^4y^{16}$等在多项式基下的表示，形成矩阵X：<br />
$$<br />
\left(<br />
\begin{array}{c}<br />
g_7\\ g_6 \\ g_5\\ g_4 \\ g_3 \\ g_2\\ g_1 \\ g_0<br />
\end{array}<br />
\right) =<br />
X<br />
\left(<br />
\begin{array}{c}<br />
b_7\\ b_6 \\ b_5\\ b_4 \\ b_3 \\ b_2\\ b_1 \\ b_0<br />
\end{array}<br />
\right)<br />
$$<br />
计算$X^{-1}$，乘以多项式基下的表示即可得到复合域基下的表示。S盒计算完成后，再进行反变换即可。</p>
<h2 id="aes-s盒实现方法">AES S盒实现方法</h2>
<p>AES的S盒是定义在$GF(2^8)$（不可约多项式$x^8+x^4+x^3+x+1$），其表达式为$S(x) = Ax^{-1}+c$，具体如下：<br />
$$<br />
\begin{equation}<br />
\left(<br />
\begin{array}{c}<br />
s_7 \\<br />
s_6 \\<br />
s_5 \\<br />
s_4 \\<br />
s_3 \\<br />
s_2 \\<br />
s_1 \\<br />
s_0 \\<br />
\end{array}<br />
\right) =<br />
\left(<br />
\begin{array}{cccccccc}<br />
1 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 0 &amp; 0 &amp; 0\\<br />
0 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 0 &amp; 0\\<br />
0 &amp; 0 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 0\\<br />
0 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 1\\<br />
1 &amp; 0 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 1 &amp; 1\\<br />
1 &amp; 1 &amp; 0 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 1\\<br />
1 &amp; 1 &amp; 1 &amp; 0 &amp; 0 &amp; 0 &amp; 1 &amp; 1\\<br />
1 &amp; 1 &amp; 1 &amp; 1 &amp; 0 &amp; 0 &amp; 0 &amp; 1\\<br />
\end{array}<br />
\right) \cdot<br />
\left(<br />
\begin{array}{c}<br />
x_7 \\<br />
x_6 \\<br />
x_5 \\<br />
x_4 \\<br />
x_3 \\<br />
x_2 \\<br />
x_1 \\<br />
x_0 \\<br />
\end{array}<br />
\right) +<br />
\left(<br />
\begin{array}{c}<br />
0 \\<br />
1 \\<br />
1 \\<br />
0 \\<br />
0 \\<br />
0 \\<br />
1 \\<br />
1 \\<br />
\end{array}<br />
\right)<br />
\end{equation}<br />
$$</p>
<h3 id="求矩阵x和逆">求矩阵X和逆</h3>
<p>求 $X$ 和 $X^{-1}$，我们需要计算 $w$，$z$ 和 $y$，计算 $w^2z^4y^{16}$等一系列系数值。Canright在文章中给出了 $GF(2^8)$ 生成元 $B$ 的 对数表，方便计算。这里我们直接通过搜索进行计算。</p>
<pre><code class="language-python">from pyfinite import ffield

gen = 0b100011011
F = ffield.FField(8, gen, useLUT=0) # 这里一定要写useLUT=0，不然会出问题。。。

def field_pow2(x, F): #计算在F域上的平方
    return F.Multiply(x, x)

def field_pow3(x, F): #计算在F域上的三次方
    return F.Multiply(x, field_pow2(x, F))

def field_pow4(x, F): #计算在F域上的四次方
    return field_pow2(field_pow2(x, F), F)
</code></pre>
<ol>
<li>首先，搜索$GF(2^2)$的正规基$\{W^2, W\}$，我们求出其在$GF(2^8)$下多项式基的表示。</li>
</ol>
<pre><code class="language-python">for i in range(256):
    if field_pow2(i, F)^i^1 == 0: # 搜索 w^2+w+1 = 0的根
        print(hex(i))
</code></pre>
<p>我们可得到，$W = 0xbd$，$W^2 = 0xbc$（一定要注意，这是$GF(2^8)$的多项式基表示）<br />
2. 然后，搜索$GF(2^4)/GF(2^2)$的正规基${Z^4, Z}$，我们求出其在$GF(2^8)$下多项式基的表示。$s(z) = z^2 + z + N$，$N = W^2 = 0xbc$</p>
<pre><code class="language-python">for i in range(256):
    if field_pow2(i, F)^i^0xbc == 0: # 搜索 z^2+z+0xbc = 0的根
        print(hex(i))
</code></pre>
<p>于是我们又得到，$Z = 0x5c$，$Z^4 = 0x5d$<br />
3. 最后，搜索$GF(2^8)/GF(2^4)$的正规基$\{Y^{16}, Y\}$，我们求出其在$GF(2^8)$下多项式基的表示。$r(y) = y^2 + y +\upsilon$，$\upsilon = N^2Z$</p>
<pre><code class="language-python">u = F.Multiply(field_pow2(0xbc, F), 0x5c)
for i in range(256):
    if field_pow2(i, F)^i^0xec == 0: # 搜索 z^2+z+0xbc = 0的根
        print(hex(i))
</code></pre>
<p>于是我们又得到，$Y= 0xff$，$Y^{16} = 0xfe$</p>
<pre><code class="language-python">w = 0xbd
w_2 = 0xbc
z = 0x5c
z_4 = 0x5d
y = 0xff
y_16 = 0xfe
w_2_z_4_y_16 = F.Multiply(F.Multiply(w_2, z_4), y_16)
w_z_4_y_16 = F.Multiply(F.Multiply(w, z_4), y_16)
w_2_z_y_16 = F.Multiply(F.Multiply(w_2, z), y_16)
w_z_y_16 = F.Multiply(F.Multiply(w, z), y_16)
w_2_z_4_y = F.Multiply(F.Multiply(w_2, z_4), y)
w_z_4_y = F.Multiply(F.Multiply(w, z_4), y)
w_2_z_y = F.Multiply(F.Multiply(w_2, z), y)
w_z_y = F.Multiply(F.Multiply(w, z), y)
print('w_2_z_4_y_16\t', hex(w_2_z_4_y_16))
print('w_z_4_y_16\t', hex(w_z_4_y_16))
print('w_2_z_y_16\t', hex(w_2_z_y_16))
print('w_z_y_16\t', hex(w_z_y_16))
print('w_2_z_4_y\t', hex(w_2_z_4_y))
print('w_z_4_y\t\t', hex(w_z_4_y))
print('w_2_z_y\t\t', hex(w_2_z_y))
print('w_z_y\t\t', hex(w_z_y))
</code></pre>
<ol start="4">
<li>得到多项式基在复合域基下表示如下：<br />
$$<br />
\left(<br />
\begin{array}{c}<br />
g_7\\ g_6 \\ g_5\\ g_4 \\ g_3 \\ g_2\\ g_1 \\ g_0<br />
\end{array}<br />
\right) =<br />
\left(<br />
\begin{array}{cccccccc}<br />
0 &amp; 0 &amp; 0 &amp; 1 &amp; 0 &amp; 0 &amp; 1 &amp; 0 \\<br />
1 &amp; 1 &amp; 1 &amp; 0 &amp; 1 &amp; 0 &amp; 1 &amp; 1 \\<br />
1 &amp; 1 &amp; 1 &amp; 0 &amp; 1 &amp; 1 &amp; 0 &amp; 1 \\<br />
0 &amp; 1 &amp; 0 &amp; 0 &amp; 0 &amp; 0 &amp; 1 &amp; 0 \\<br />
0 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 0 \\<br />
1 &amp; 0 &amp; 1 &amp; 1 &amp; 0 &amp; 0 &amp; 1 &amp; 0 \\<br />
0 &amp; 0 &amp; 1 &amp; 0 &amp; 0 &amp; 0 &amp; 1 &amp; 0 \\<br />
0 &amp; 0 &amp; 0 &amp; 0 &amp; 0 &amp; 1 &amp; 0 &amp; 0<br />
\end{array}<br />
\right)<br />
\left(<br />
\begin{array}{c}<br />
b_7\\ b_6 \\ b_5\\ b_4 \\ b_3 \\ b_2\\ b_1 \\ b_0<br />
\end{array}<br />
\right)<br />
$$<br />
求$X^{-1}$，可得到复合域基下多项式基的表示：</li>
</ol>
<pre><code class="language-python">from pyfinite import genericmatrix

XOR = lambda x,y: x^y
AND = lambda x,y: x&amp;y
DIV = lambda x,y: x 
m = genericmatrix.GenericMatrix(size=(8, 8),zeroElement=0,identityElement=1,add=XOR,mul=AND,sub=XOR,div=DIV)

m.SetRow(0, [0, 0, 0, 1, 0, 0, 1, 0])
m.SetRow(1, [1, 1, 1, 0, 1, 0, 1, 1])
m.SetRow(2, [1, 1, 1, 0, 1, 1, 0, 1])
m.SetRow(3, [0, 1, 0, 0, 0, 0, 1, 0])
m.SetRow(4, [0, 1, 1, 1, 1, 1, 1, 0])
m.SetRow(5, [1, 0, 1, 1, 0, 0, 1, 0])
m.SetRow(6, [0, 0, 1, 0, 0, 0, 1, 0])
m.SetRow(7, [0, 0, 0, 0, 0, 1, 0, 0])
print(m)

print(m.Inverse())
</code></pre>
<p>$$<br />
\left(<br />
\begin{array}{c}<br />
b_7\\ b_6 \\ b_5\\ b_4 \\ b_3 \\ b_2\\ b_1 \\ b_0<br />
\end{array}<br />
\right) =<br />
\left(<br />
\begin{array}{cccccccc}<br />
1 &amp; 1 &amp; 1 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 1\\<br />
0 &amp; 1 &amp; 1 &amp; 1 &amp; 0 &amp; 0 &amp; 0 &amp; 1\\<br />
0 &amp; 1 &amp; 1 &amp; 0 &amp; 0 &amp; 0 &amp; 1 &amp; 1\\<br />
1 &amp; 1 &amp; 1 &amp; 0 &amp; 0 &amp; 0 &amp; 0 &amp; 1\\<br />
1 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 0 &amp; 1 &amp; 1\\<br />
0 &amp; 0 &amp; 0 &amp; 0 &amp; 0 &amp; 0 &amp; 0 &amp; 1\\<br />
0 &amp; 1 &amp; 1 &amp; 0 &amp; 0 &amp; 0 &amp; 0 &amp; 1\\<br />
0 &amp; 1 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 1 &amp; 1<br />
\end{array}<br />
\right)<br />
\left(<br />
\begin{array}{c}<br />
g_7\\ g_6 \\ g_5\\ g_4 \\ g_3 \\ g_2\\ g_1 \\ g_0<br />
\end{array}<br />
\right)<br />
$$</p>
<h3 id="具体函数实现">具体函数实现</h3>
<h4 id="基础函数定义">基础函数定义</h4>
<pre><code class="language-python">g2b = [0b10011000, 0b11110011, 0b11110010, 0b01001000, 0b00001001, 0b10000001, 0b10101001, 0b11111111]
b2g = [0b01100100, 0b01111000, 0b01101110, 0b10001100, 0b01101000, 0b00101001, 0b11011110, 0b01100000]

def G4_mul(x, y):
    '''
    GF(2^2)的乘法运算，正规基{W^2, W}
    '''
    a = (x &amp; 0x02)&gt;&gt;1
    b = x &amp; 0x01
    c = (y &amp; 0x02)&gt;&gt;1
    d = y &amp; 0x01
    e = (a ^ b) &amp; (c ^ d)
    return (((a &amp; c) ^ e) &lt;&lt; 1)|((b &amp; d) ^ e)

def G4_mul_N(x):
    '''
    GF(2^2)的乘N操作，N = W^2
    '''
    a = (x &amp; 0x02)&gt;&gt;1
    b = x &amp; 0x01
    p = b
    q = a ^ b
    return (p&lt;&lt;1)|q

def G4_mul_N2(x):
    '''
    GF(2^2)的乘N^2操作，N = W^2
    '''
    a = (x &amp; 0x02)&gt;&gt;1
    b = x &amp; 0x01
    return ((a ^ b)&lt;&lt;1)|a

def G4_inv(x):
    '''
    GF(2^2)的求逆操作，该操作和GF(2^2)的平方操作等价
    '''
    a = (x &amp; 0x02)&gt;&gt;1
    b = x &amp; 0x01
    return (b&lt;&lt;1)|a

def G16_mul(x, y):
    '''
    GF(2^4)的乘法操作，正规基{Z^4, Z}
    '''
    a = (x &amp; 0xc)&gt;&gt;2
    b = x &amp; 0x03
    c = (y &amp; 0xc)&gt;&gt;2
    d = y &amp; 0x03
    e = G4_mul(a ^ b, c ^ d)
    e = G4_mul_N(e)
    p = G4_mul(a, c) ^ e
    q = G4_mul(b, d) ^ e
    return (p&lt;&lt;2) | q

def G16_sq_mul_u(x):
    '''
    GF(2^4)的平方后乘u操作, u = N^2Z, N = W^2
    '''
    a = (x &amp; 0xc)&gt;&gt;2
    b = x &amp; 0x03
    p = G4_inv(a ^ b) # G4平方和求逆等价
    q = G4_mul_N2(G4_inv(b)) 
    return (p&lt;&lt;2)|q

def G16_inv(x):
    '''
    GF(2^4)的求逆操作
    '''
    a = (x &amp; 0xc)&gt;&gt;2
    b = x &amp; 0x03
    c = G4_mul_N(G4_inv(a ^ b))
    d = G4_mul(a, b)
    e = G4_inv(c ^ d)
    p = G4_mul(e, b)
    q = G4_mul(e, a)
    return (p&lt;&lt;2)|q

def G256_inv(x):
    '''
    GF(2^8)的求逆操作
    '''
    a = (x &amp; 0xF0)&gt;&gt;4
    b = x &amp; 0x0F
    c = G16_sq_mul_u(a ^ b)
    d = G16_mul(a, b)
    e = G16_inv(c ^ d)
    p = G16_mul(e, b)
    q = G16_mul(e, a)
    return (p&lt;&lt;4)|q

def G256_new_basis(x, b):
    '''
    x在新基b下的表示
    '''
    y = 0
    for i in range(8):
        if x &amp; (1&lt;&lt;(7-i)):
            y ^= b[i]
    return y
</code></pre>
<h4 id="计算s盒输出值">计算S盒输出值</h4>
<pre><code class="language-python">A = [0b10001111, 0b11000111, 0b11100011, 0b11110001, 0b11111000, 0b01111100, 0b00111110, 0b00011111] #仿射变换矩阵乘

def AES_SBOX(x):
    t = G256_new_basis(x, g2b)
    t = G256_inv(t)
    t = G256_new_basis(t, b2g)
    t = G256_new_basis(t, A) #仿射变换乘
    return t ^ 0x63

sbox = []
for i in range(256):
    sbox.append(AES_SBOX(i))  # 生成sbox

for i,s in enumerate(sbox):
    print(f'%02x'%s,', ', end='')
    if (i+1)%16==0:
        print()
</code></pre>
<h2 id="sm4-s盒实现方法">SM4 S盒实现方法</h2>
<p>SM4 的 S 盒和 AES 不同， 定义在$GF(2^8)$采用的不可约多项式为$x^8+x^7+x^6+x^5+x^4+x^2+1$，生成方式为$S(x) = A(Ax+c)^{-1}+c$，其中：<br />
$$<br />
\begin{equation}<br />
A =<br />
\left(<br />
\begin{array}{cccccccc}<br />
1 &amp; 1 &amp; 0 &amp; 1 &amp; 0 &amp; 0 &amp; 1 &amp; 1\\<br />
1 &amp; 1 &amp; 1 &amp; 0 &amp; 1 &amp; 0 &amp; 0 &amp; 1\\<br />
1 &amp; 1 &amp; 1 &amp; 1 &amp; 0 &amp; 1 &amp; 0 &amp; 0\\<br />
0 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 0 &amp; 1 &amp; 0\\<br />
0 &amp; 0 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 0 &amp; 1\\<br />
1 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 0\\<br />
0 &amp; 1 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 1 &amp; 1\\<br />
1 &amp; 0 &amp; 1 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 1\\<br />
\end{array}<br />
\right) %右括号<br />
,<br />
c =<br />
\left(<br />
\begin{array}{c}<br />
1 \\<br />
1 \\<br />
0 \\<br />
1 \\<br />
0 \\<br />
0 \\<br />
1 \\<br />
1 \\<br />
\end{array}<br />
\right)<br />
\end{equation}<br />
$$</p>
<h3 id="求矩阵x和逆-1">求矩阵X和逆</h3>
<p>不可约多项式不同，$X$ 矩阵也不相同。下面我们为 SM4 求 $X$ 和 $X^{-1}$，我们需要计算 $w$，$z$ 和 $y$，计算 $w^2z^4y^{16}$等一系列系数值</p>
<pre><code class="language-python">from pyfinite import ffield

gen = 0b111110101
F = ffield.FField(8, gen, useLUT=0) # 这里一定要写useLUT=0，不然会出问题。。。
</code></pre>
<ol>
<li>首先，搜索$GF(2^2)$的正规基$\{W^2, W\}$，我们求出其在$GF(2^8)$下多项式基的表示。</li>
</ol>
<pre><code class="language-python">for i in range(256):
    if field_pow2(i, F)^i^1 == 0: # 搜索 w^2+w+1 = 0的根
        print(hex(i))
</code></pre>
<p>我们得到，$W = 0x5d$，$W^2 = 0x5c$（一定要注意，这是$GF(2^8)$的多项式基表示）</p>
<ol start="2">
<li>然后，搜索$GF(2^4)/GF(2^2)$的正规基${Z^4, Z}$，我们求出其在$GF(2^8)$下多项式基的表示。$s(z) = z^2 + z + N$，$N = W^2 = 0x5c$</li>
</ol>
<pre><code class="language-python">for i in range(256):
    if field_pow2(i, F)^i^0x5c == 0: # 搜索 z^2+z+0x5c = 0的根
        print(hex(i))
</code></pre>
<p>于是我们又得到，$Z = 0x0c$，$Z^4 = 0x0d$</p>
<ol start="3">
<li>最后，搜索$GF(2^8)/GF(2^4)$的正规基${Y^{16}, Y}$，我们求出其在$GF(2^8)$下多项式基的表示。$r(y) = y^2 + y +\upsilon$，$\upsilon = N^2Z$</li>
</ol>
<pre><code class="language-python">u = F.Multiply(field_pow2(0x5c, F), 0x0c)
for i in range(256):
    if field_pow2(i, F)^i^0x76 == 0: # 搜索 z^2+z+0x76 = 0的根
        print(hex(i))
</code></pre>
<p>于是我们又得到，$Y= 0xef$，$Y^{16} = 0xee$</p>
<pre><code class="language-python">w = 0x5d
w_2 = 0x5c
z = 0x0c
z_4 = 0x0d
y = 0xef
y_16 = 0xee
w_2_z_4_y_16 = F.Multiply(F.Multiply(w_2, z_4), y_16)
w_z_4_y_16 = F.Multiply(F.Multiply(w, z_4), y_16)
w_2_z_y_16 = F.Multiply(F.Multiply(w_2, z), y_16)
w_z_y_16 = F.Multiply(F.Multiply(w, z), y_16)
w_2_z_4_y = F.Multiply(F.Multiply(w_2, z_4), y)
w_z_4_y = F.Multiply(F.Multiply(w, z_4), y)
w_2_z_y = F.Multiply(F.Multiply(w_2, z), y)
w_z_y = F.Multiply(F.Multiply(w, z), y)

print('w_2_z_4_y_16\t', hex(w_2_z_4_y_16))
print('w_z_4_y_16\t', hex(w_z_4_y_16))
print('w_2_z_y_16\t', hex(w_2_z_y_16))
print('w_z_y_16\t', hex(w_z_y_16))
print('w_2_z_4_y\t', hex(w_2_z_4_y))
print('w_z_4_y\t\t', hex(w_z_4_y))
print('w_2_z_y\t\t', hex(w_2_z_y))
print('w_z_y\t\t', hex(w_z_y))
</code></pre>
<ol start="4">
<li>得到多项式基在复合域基下表示如下：<br />
$$<br />
\left(<br />
\begin{array}{c}<br />
g_7\\ g_6 \\ g_5\\ g_4 \\ g_3 \\ g_2\\ g_1 \\ g_0<br />
\end{array}<br />
\right)<br />
=<br />
\left(<br />
\begin{array}{cccccccc}<br />
1 &amp; 1 &amp; 0 &amp; 1 &amp; 1 &amp; 1 &amp; 0 &amp; 1 \\<br />
1 &amp; 1 &amp; 1 &amp; 0 &amp; 1 &amp; 1 &amp; 0 &amp; 1 \\<br />
1 &amp; 1 &amp; 0 &amp; 1 &amp; 0 &amp; 0 &amp; 1 &amp; 0 \\<br />
1 &amp; 0 &amp; 1 &amp; 0 &amp; 1 &amp; 0 &amp; 0 &amp; 1 \\<br />
0 &amp; 1 &amp; 0 &amp; 0 &amp; 0 &amp; 0 &amp; 1 &amp; 0 \\<br />
1 &amp; 1 &amp; 1 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 1 \\<br />
0 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 0 \\<br />
0 &amp; 0 &amp; 0 &amp; 0 &amp; 0 &amp; 1 &amp; 0 &amp; 0<br />
\end{array}<br />
\right)<br />
\left(<br />
\begin{array}{c}<br />
b_7\\ b_6 \\ b_5\\ b_4 \\ b_3 \\ b_2\\ b_1 \\ b_0<br />
\end{array}<br />
\right)<br />
$$<br />
求$X^{-1}$，可得到复合域基下多项式基的表示：</li>
</ol>
<pre><code class="language-python">from pyfinite import genericmatrix

XOR = lambda x,y: x^y
AND = lambda x,y: x&amp;y
DIV = lambda x,y: x 
m = genericmatrix.GenericMatrix(size=(8, 8),zeroElement=0,identityElement=1,add=XOR,mul=AND,sub=XOR,div=DIV)

m.SetRow(0, [1, 1, 0, 1, 1, 1, 0, 1])
m.SetRow(1, [1, 1, 1, 0, 1, 1, 0, 1])
m.SetRow(2, [1, 1, 0, 1, 0, 0, 1, 0])
m.SetRow(3, [1, 0, 1, 0, 1, 0, 0, 1])
m.SetRow(4, [0, 1, 0, 0, 0, 0, 1, 0])
m.SetRow(5, [1, 1, 1, 0, 0, 1, 1, 1])
m.SetRow(6, [0, 0, 0, 1, 1, 1, 1, 0])
m.SetRow(7, [0, 0, 0, 0, 0, 1, 0, 0])
print(m)
print(m.Inverse())
</code></pre>
<h3 id="具体函数实现-1">具体函数实现</h3>
<h4 id="基础函数定义-1">基础函数定义</h4>
<p>SM4 和 AES 采用的复合域结构相同，其基础函数也相同。仅定义X矩阵即可。</p>
<pre><code class="language-python">g2b = [0b00100001, 0b11010011, 0b10000001, 0b01001010, 0b10001010, 0b10111001, 0b10110000, 0b11111111]
b2g = [0xf4, 0xec, 0x54, 0xa2, 0xd2, 0xc7, 0x2e, 0xd4]
</code></pre>
<h4 id="计算s盒输出值-1">计算S盒输出值</h4>
<pre><code class="language-python">A = [0b11100101, 0b11110010, 0b01111001, 0b10111100, 0b01011110, 0b00101111, 0b10010111, 0b11001011]
def SM4_SBOX(x):
    t = G256_new_basis(x, A)
    t ^= 0xd3
    t = G256_new_basis(t, g2b)
    t = G256_inv(t)
    t = G256_new_basis(t, b2g)
    t = G256_new_basis(t, A) #仿射变换乘
    return t ^ 0xd3

sbox = []
for i in range(256):
    sbox.append(SM4_SBOX(i))  # 生成sbox

for i,s in enumerate(sbox):
    print(f'%02x'%s,', ', end='')
    if (i+1)%16==0:
        print()
</code></pre>
<h2 id="推广结论">推广结论</h2>
<p>通过 AES 和 SM4 的 S 盒复合域实现，我们不难发现，在复合域上，AES 和 SM4 的求逆运算过程相同，而除此之外，其他操作都是线性的仿射变换。那么我们能不能通过 AES 的 S 盒计算 SM4 的 S 盒输出呢？也就是，$S_{sm4}(x) = L(S_{aes}(Mx+C_1)) + C_2$，下面我们尝试进行推导。</p>
<p>假设复合域求逆运算为$f$，则:</p>
<p>$$<br />
\begin{align}<br />
S_{aes}(x) = A_{aes}X_{aes}f(X^{-1}_{aes}x)+0x63 &amp;\Rightarrow f(X^{-1}_{aes}x) = X^{-1}_{aes}A_{aes}^{-1}(S_{aes}(x) + 0x63) \\<br />
&amp; \Rightarrow f(x) = X^{-1}_{aes}A_{aes}^{-1}(S_{aes}(X_{aes}x) + 0x63)<br />
\end{align}<br />
$$<br />
由此得出：<br />
$$<br />
\begin{align}<br />
&amp;S_{sm4}(x) = A_{sm4}X_{sm4}f(X^{-1}_{sm4}(A_{sm4}x+0xd3))+0xd3 \Rightarrow \\ &amp;S_{sm4}(x) = A_{sm4}X_{sm4}X^{-1}_{aes}A_{aes}^{-1}(S_{aes}(X_{aes}(X^{-1}_{sm4}(A_{sm4}x+0xd3))) + 0x63) +0xd3<br />
\end{align}<br />
$$<br />
由此可得出，<br />
$$<br />
\begin{align}<br />
&amp;M = X_{aes}X^{-1}_{sm4}A_{sm4}\\ &amp;C_1 = X_{aes}X^{-1}_{sm4}0xd3 \\ &amp;L = A_{sm4}X_{sm4}X^{-1}_{aes}A^{-1}_{aes} \\ &amp;C_2 = A_{sm4}X_{sm4}X^{-1}_{aes}A^{-1}_{aes}0x63+0xd3<br />
\end{align}<br />
$$</p>
<pre><code class="language-python">XOR = lambda x,y: x^y
AND = lambda x,y: x&amp;y
DIV = lambda x,y: x 
X_aes = genericmatrix.GenericMatrix(size=(8, 8),zeroElement=0,identityElement=1,add=XOR,mul=AND,sub=XOR,div=DIV)
X_sm4 = genericmatrix.GenericMatrix(size=(8, 8),zeroElement=0,identityElement=1,add=XOR,mul=AND,sub=XOR,div=DIV)
A_aes = genericmatrix.GenericMatrix(size=(8, 8),zeroElement=0,identityElement=1,add=XOR,mul=AND,sub=XOR,div=DIV)
A_sm4 = genericmatrix.GenericMatrix(size=(8, 8),zeroElement=0,identityElement=1,add=XOR,mul=AND,sub=XOR,div=DIV)
c_aes = genericmatrix.GenericMatrix(size=(8, 1),zeroElement=0,identityElement=1,add=XOR,mul=AND,sub=XOR,div=DIV)
c_sm4 = genericmatrix.GenericMatrix(size=(8, 1),zeroElement=0,identityElement=1,add=XOR,mul=AND,sub=XOR,div=DIV)

X_aes.SetRow(0, [0, 0, 0, 1, 0, 0, 1, 0])
X_aes.SetRow(1, [1, 1, 1, 0, 1, 0, 1, 1])
X_aes.SetRow(2, [1, 1, 1, 0, 1, 1, 0, 1])
X_aes.SetRow(3, [0, 1, 0, 0, 0, 0, 1, 0])
X_aes.SetRow(4, [0, 1, 1, 1, 1, 1, 1, 0])
X_aes.SetRow(5, [1, 0, 1, 1, 0, 0, 1, 0])
X_aes.SetRow(6, [0, 0, 1, 0, 0, 0, 1, 0])
X_aes.SetRow(7, [0, 0, 0, 0, 0, 1, 0, 0])
print(X_aes)

X_aes_inv = X_aes.Inverse()
X_aes_inv

X_sm4.SetRow(0, [1, 1, 0, 1, 1, 1, 0, 1])
X_sm4.SetRow(1, [1, 1, 1, 0, 1, 1, 0, 1])
X_sm4.SetRow(2, [1, 1, 0, 1, 0, 0, 1, 0])
X_sm4.SetRow(3, [1, 0, 1, 0, 1, 0, 0, 1])
X_sm4.SetRow(4, [0, 1, 0, 0, 0, 0, 1, 0])
X_sm4.SetRow(5, [1, 1, 1, 0, 0, 1, 1, 1])
X_sm4.SetRow(6, [0, 0, 0, 1, 1, 1, 1, 0])
X_sm4.SetRow(7, [0, 0, 0, 0, 0, 1, 0, 0])
print(X_sm4)

X_sm4_inv = X_sm4.Inverse()
X_sm4_inv

A_aes.SetRow(0, [1, 1, 1, 1, 1, 0, 0, 0])
A_aes.SetRow(1, [0, 1, 1, 1, 1, 1, 0, 0])
A_aes.SetRow(2, [0, 0, 1, 1, 1, 1, 1, 0])
A_aes.SetRow(3, [0, 0, 0, 1, 1, 1, 1, 1])
A_aes.SetRow(4, [1, 0, 0, 0, 1, 1, 1, 1])
A_aes.SetRow(5, [1, 1, 0, 0, 0, 1, 1, 1])
A_aes.SetRow(6, [1, 1, 1, 0, 0, 0, 1, 1])
A_aes.SetRow(7, [1, 1, 1, 1, 0, 0, 0, 1])
print(A_aes)

A_aes_inv = A_aes.Inverse()

A_sm4.SetRow(0, [1, 1, 0, 1, 0, 0, 1, 1])
A_sm4.SetRow(1, [1, 1, 1, 0, 1, 0, 0, 1])
A_sm4.SetRow(2, [1, 1, 1, 1, 0, 1, 0, 0])
A_sm4.SetRow(3, [0, 1, 1, 1, 1, 0, 1, 0])
A_sm4.SetRow(4, [0, 0, 1, 1, 1, 1, 0, 1])
A_sm4.SetRow(5, [1, 0, 0, 1, 1, 1, 1, 0])
A_sm4.SetRow(6, [0, 1, 0, 0, 1, 1, 1, 1])
A_sm4.SetRow(7, [1, 0, 1, 0, 0, 1, 1, 1])
print(A_sm4)

A_sm4_inv = A_sm4.Inverse()

M = X_aes*X_sm4_inv*A_sm4
print(M)

A = [0, 1, 1, 0, 0, 0, 1, 1]
for i in range(8):
    c_aes.SetRow(i, [A[i]])
print(c_aes)

A = [1, 1, 0, 1, 0, 0, 1, 1]
for i in range(8):
    c_sm4.SetRow(i, [A[i]])
print(c_sm4)

C1 = X_aes*(X_sm4_inv*c_sm4)
print(C1)

L = A_sm4*X_sm4*X_aes_inv*A_aes_inv
print(L)
</code></pre>
<p>因此，<br />
$$<br />
S_{sm4}(x) =<br />
\left(<br />
\begin{array}{cccccccc}<br />
1 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 0 &amp; 1 &amp; 0\\<br />
0 &amp; 1 &amp; 1 &amp; 0 &amp; 0 &amp; 1 &amp; 0 &amp; 0\\<br />
1 &amp; 0 &amp; 1 &amp; 1 &amp; 0 &amp; 1 &amp; 0 &amp; 0\\<br />
0 &amp; 0 &amp; 0 &amp; 0 &amp; 1 &amp; 0 &amp; 1 &amp; 0\\<br />
0 &amp; 1 &amp; 0 &amp; 0 &amp; 0 &amp; 0 &amp; 0 &amp; 1\\<br />
1 &amp; 1 &amp; 0 &amp; 1 &amp; 1 &amp; 1 &amp; 0 &amp; 1\\<br />
0 &amp; 0 &amp; 0 &amp; 0 &amp; 0 &amp; 0 &amp; 0 &amp; 1\\<br />
1 &amp; 1 &amp; 0 &amp; 0 &amp; 0 &amp; 0 &amp; 0 &amp; 1\\<br />
\end{array}<br />
\right)<br />
S_{aes}(<br />
\left(<br />
\begin{array}{cccccccc}<br />
1 &amp; 0 &amp; 0 &amp; 1 &amp; 0 &amp; 1 &amp; 1 &amp; 0\\<br />
0 &amp; 1 &amp; 0 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 1\\<br />
1 &amp; 1 &amp; 1 &amp; 0 &amp; 1 &amp; 0 &amp; 0 &amp; 1\\<br />
0 &amp; 0 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 0 &amp; 1\\<br />
1 &amp; 1 &amp; 0 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 0\\<br />
0 &amp; 1 &amp; 1 &amp; 0 &amp; 0 &amp; 1 &amp; 0 &amp; 1\\<br />
1 &amp; 0 &amp; 1 &amp; 0 &amp; 1 &amp; 1 &amp; 0 &amp; 0\\<br />
1 &amp; 0 &amp; 1 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 1\\<br />
\end{array}<br />
\right)x+<br />
\left(<br />
\begin{array}{c}<br />
0\\<br />
1\\<br />
1\\<br />
0\\<br />
1\\<br />
0\\<br />
0\\<br />
1\\<br />
\end{array}<br />
\right)<br />
)+<br />
\left(<br />
\begin{array}{c}<br />
0\\<br />
1\\<br />
1\\<br />
0\\<br />
0\\<br />
0\\<br />
0\\<br />
1\\<br />
\end{array}<br />
\right)<br />
$$</p>
<p>可以进行程序验证如下：</p>
<pre><code class="language-python">L = [0b10100101, 0b11001101, 0b11100000, 0b10100100, 0b10010100, 0b01100100, 0b10010000, 0b00001111]
M = [0b10101011, 0b01101100, 0b00110111, 0b10011000, 0b00111010, 0b11011111, 0b11001001, 0b01110101]
c1 = 0x69
c2 = 0x61

SBOX_AES = [0x63 , 0x7c , 0x77 , 0x7b , 0xf2 , 0x6b , 0x6f , 0xc5 , 0x30 , 0x01 , 0x67 , 0x2b , 0xfe , 0xd7 , 0xab , 0x76 , 
0xca , 0x82 , 0xc9 , 0x7d , 0xfa , 0x59 , 0x47 , 0xf0 , 0xad , 0xd4 , 0xa2 , 0xaf , 0x9c , 0xa4 , 0x72 , 0xc0 , 
0xb7 , 0xfd , 0x93 , 0x26 , 0x36 , 0x3f , 0xf7 , 0xcc , 0x34 , 0xa5 , 0xe5 , 0xf1 , 0x71 , 0xd8 , 0x31 , 0x15 , 
0x04 , 0xc7 , 0x23 , 0xc3 , 0x18 , 0x96 , 0x05 , 0x9a , 0x07 , 0x12 , 0x80 , 0xe2 , 0xeb , 0x27 , 0xb2 , 0x75 , 
0x09 , 0x83 , 0x2c , 0x1a , 0x1b , 0x6e , 0x5a , 0xa0 , 0x52 , 0x3b , 0xd6 , 0xb3 , 0x29 , 0xe3 , 0x2f , 0x84 , 
0x53 , 0xd1 , 0x00 , 0xed , 0x20 , 0xfc , 0xb1 , 0x5b , 0x6a , 0xcb , 0xbe , 0x39 , 0x4a , 0x4c , 0x58 , 0xcf , 
0xd0 , 0xef , 0xaa , 0xfb , 0x43 , 0x4d , 0x33 , 0x85 , 0x45 , 0xf9 , 0x02 , 0x7f , 0x50 , 0x3c , 0x9f , 0xa8 , 
0x51 , 0xa3 , 0x40 , 0x8f , 0x92 , 0x9d , 0x38 , 0xf5 , 0xbc , 0xb6 , 0xda , 0x21 , 0x10 , 0xff , 0xf3 , 0xd2 , 
0xcd , 0x0c , 0x13 , 0xec , 0x5f , 0x97 , 0x44 , 0x17 , 0xc4 , 0xa7 , 0x7e , 0x3d , 0x64 , 0x5d , 0x19 , 0x73 , 
0x60 , 0x81 , 0x4f , 0xdc , 0x22 , 0x2a , 0x90 , 0x88 , 0x46 , 0xee , 0xb8 , 0x14 , 0xde , 0x5e , 0x0b , 0xdb , 
0xe0 , 0x32 , 0x3a , 0x0a , 0x49 , 0x06 , 0x24 , 0x5c , 0xc2 , 0xd3 , 0xac , 0x62 , 0x91 , 0x95 , 0xe4 , 0x79 , 
0xe7 , 0xc8 , 0x37 , 0x6d , 0x8d , 0xd5 , 0x4e , 0xa9 , 0x6c , 0x56 , 0xf4 , 0xea , 0x65 , 0x7a , 0xae , 0x08 , 
0xba , 0x78 , 0x25 , 0x2e , 0x1c , 0xa6 , 0xb4 , 0xc6 , 0xe8 , 0xdd , 0x74 , 0x1f , 0x4b , 0xbd , 0x8b , 0x8a , 
0x70 , 0x3e , 0xb5 , 0x66 , 0x48 , 0x03 , 0xf6 , 0x0e , 0x61 , 0x35 , 0x57 , 0xb9 , 0x86 , 0xc1 , 0x1d , 0x9e , 
0xe1 , 0xf8 , 0x98 , 0x11 , 0x69 , 0xd9 , 0x8e , 0x94 , 0x9b , 0x1e , 0x87 , 0xe9 , 0xce , 0x55 , 0x28 , 0xdf , 
0x8c , 0xa1 , 0x89 , 0x0d , 0xbf , 0xe6 , 0x42 , 0x68 , 0x41 , 0x99 , 0x2d , 0x0f , 0xb0 , 0x54 , 0xbb , 0x16]

def SM4_SBOX_CALC_WITH_AES(x):
    t = G256_new_basis(x, M)
    t ^= c1
    t = SBOX_AES[t]
    t = G256_new_basis(t, L)
    t ^= c2
    return t

sbox = []
for i in range(256):
    sbox.append(SM4_SBOX_CALC_WITH_AES(i))  # 生成sbox

for i,s in enumerate(sbox):
    print(f'%02x'%s,', ', end='')
    if (i+1)%16==0:
        print()
</code></pre>
<h2 id="总结">总结</h2>
<p>对 AES 和 SM4 来说，我们都可以把仿射变换和基变换操作的矩阵乘结合起来，简化对应的计算过程，从而减少运算。利用这一思想，我们可以对 AES 和 SM4 的 bit直接进行逻辑运算，避免查表操作。在硬件实现时，可利用该方法构造资源非常受限情况下的S盒实现。在软件上，该方法在抵抗cache攻击方面有效果，同时，我们可以使用bitslice并行技术进行加速。</p>
<p>此外，SM4 的 S 盒可由 AES 表示得出，这一点在 CPU 有 AES 的指令集时，可将 SM4 的 S 盒运算转化为 AES 的 S 盒运算进行加速。</p>

                        ]]>
                    </content:encoded>
                    <pubDate>Feb 7, 2020 10:00:32 PM</pubDate>
                </item>
    </channel>
</rss>