【问题标题】:How to perform addition and multiplication in F_{2^8}如何在 F_{2^8} 中进行加法和乘法运算
【发布时间】:2021-12-07 13:58:28
【问题描述】:

我想在 F_{2^8} 中执行加法和乘法

我目前有这段代码,它似乎适用于加法,但不适用于乘法;问题似乎是,当我以 100011011 取模(表示 x^8 + x^4 + x^3 + x + 1)时,它似乎没有这样做。另一个想法是使用 numpy.polynomial 但它不是那么直观。

def toBinary(self, n):
    return ''.join(str(1 & int(n) >> i) for i in range(8)[::-1])

def add(self, x, y):
    """
     "10111001" + "10010100" = "00101101"
    """

    if len(x)<8:
        self.add('0'+x,y)
    elif len(y)<8:
        self.add(x,'0'+y)

    try:
        a = int(x,2); b = int(y,2)
        z = int(x)+int(y)
        s = ''
    
        for i in str(z):
            if int(i)%2 == 0:
                s+='0'
            else:
                s+='1'
    except:
        return '00000000'

    return s
    
def multiply(self, x, y):
    """
    "10111001" * "10010100" = "10110010"
    """
    if len(x)<8:
        self.multiply('0'+x,y)
    elif len(y)<8:
        self.multiply(x,'0'+y)

    result = '00000000'

    result = '00000000'
    while y!= '00000000' :
        print(f'x:{x},y:{y},result:{result}')
        if int(y[-1]) == 1 :
            result = self.add(result ,x)
            y = self.add(y, '00000001')
        x = self.add(self.toBinary(int(x,2)<<1),'100011011')
        y = self.toBinary(int(y,2)>>1) #b = self.multiply(b,inverse('00000010'))
    return result

【问题讨论】:

  • 也许我不了解最新的术语,但什么是“F_{2^8}”?说代码不适用于乘法是一个问题。我们可以帮助解决具体的技术问题,而不是对代码或建议的开放式请求。请编辑您的问题以显示您迄今为止尝试过的内容,以及您需要帮助的具体问题。请参阅How To Ask a Good Question 页面,详细了解如何最好地帮助我们。
  • F_{2^8} 是一个 2^8 的 Gallois 字段,由每个字符串 8 位组成,我编码的算法是 Rijndael 算法的一个版本,使用模块化归约,但这一步失败了
  • 我更新了我的答案以包含一个 python 示例。

标签: python finite-field


【解决方案1】:

用于加法(与减法相同)、乘法、除法和逆运算的 Python 示例。假设输入参数为 8 位值,不检查除以 0。

def add(x, y):                  # add is xor
    return x^y

def sub(x, y):                  # sub is xor
    return x^y

def mpy(x, y):                  # mpy two 8 bit values
    p = 0b100011011             # mpy modulo x^8+x^4+x^3+x+1
    m = 0                       # m will be product
    for i in range(8):
        m = m << 1
        if m & 0b100000000:
            m = m ^ p
        if y & 0b010000000:
            m = m ^ x
        y = y << 1
    return m

def div(x, y):                   # divide using inverse
    return mpy(x, inv(y))        #  (no check for y = 0)

def inv(x):                      # x^254 = 1/x
    p=mpy(x,x)                   # p = x^2
    x=mpy(p,p)                   # x = x^4
    p=mpy(p,x)                   # p = x^(2+4)
    x=mpy(x,x)                   # x = x^8
    p=mpy(p,x)                   # p = x^(2+4+8)
    x=mpy(x,x)                   # x = x^16
    p=mpy(p,x)                   # p = x^(2+4+8+16)
    x=mpy(x,x)                   # x = x^32
    p=mpy(p,x)                   # p = x^(2+4+8+16+32)
    x=mpy(x,x)                   # x = x^64
    p=mpy(p,x)                   # p = x^(2+4+8+16+32+64)
    x=mpy(x,x)                   # x = x^128
    p=mpy(p,x)                   # p = x^(2+4+8+16+32+64+128)
    return p

print hex(add(0b01010101, 0b10101010))      # returns 0xff
print hex(mpy(0b01010101, 0b10101010))      # returns 0x59
print hex(div(0b01011001, 0b10101010))      # returns 0x55

对于 GF(2^n),加减都是 XOR。这意味着乘法是无进位的,除法是无借的。 X86 有一个用于 XMM 寄存器的无进位乘法 PCLMULQDQ。除以常数可以通过无进位乘以 2^64 / 常数并使用乘积的高 64 位来完成。逆常数是使用无借除法循环生成的。

原因是 GF(2^n) 元素是具有 1 位系数的多项式,(系数是 GF(2) 的元素)。

对于 GF(2^8),生成指数表和对数表会更简单。示例 C 代码:

#define POLY (0x11b)
/* all non-zero elements are powers of 3 for POLY == 0x11b */
typedef unsigned char BYTE;
/* ... */
static BYTE exp2[512];
static BYTE log2[256];
/* ... */
static void Tbli()
{
int i;
int b;
    b = 0x01;                   /* init exp2 table */
    for(i = 0; i < 512; i++){
        exp2[i] = (BYTE)b;
        b = (b << 1) ^ b;       /*  powers of 3 */
        if(b & 0x100)
            b ^= POLY;
    }

    log2[0] = 0xff;             /* init log2 table */
    for(i = 0; i < 255; i++)
        log2[exp2[i]] = (BYTE)i;
}
/* ... */
static BYTE GFMpy(BYTE m0, BYTE m1) /* multiply */
{
    if(0 == m0 || 0 == m1)
        return(0);
    return(exp2[log2[m0] + log2[m1]]);
}
/* ... */
static BYTE GFDiv(BYTE m0, BYTE m1) /* divide */
{
    if(0 == m0)
        return(0);
    return(exp2[log2[m0] + 255 - log2[m1]]);
}

【讨论】:

  • 示例 C 代码对于标记为 python 的问题并不真正有用。
  • @chepner - 认为它是 Python 的伪代码,并且 OP 可能不想使用表。答案的主要部分是示例代码之前的文本。
  • *(p1+*p0++) = d0; 实际上不是伪代码。要理解这一点,需要了解 C 的特定语法和语义,这与 Python 大不相同。
  • @kaya3 - 我更新了我的答案,使用索引而不是指针。还将 exp2[] 的大小增加到 512 以加快计算速度。
  • @chepner - 我更新了我的答案以包含 python 示例代码。
【解决方案2】:

我创建了一个 Python 包 galois,它在有限域上扩展了 NumPy 数组。使用GF(2^8) 非常简单,请参见下面的示例。

In [1]: import galois

In [2]: GF = galois.GF(2**8, irreducible_poly="x^8 + x^4 + x^3 + x + 1")

In [3]: print(GF.properties)
GF(2^8):
  characteristic: 2
  degree: 8
  order: 256
  irreducible_poly: x^8 + x^4 + x^3 + x + 1
  is_primitive_poly: False
  primitive_element: x + 1

# Your original values from your example
In [4]: a = GF(0b10111001); a
Out[4]: GF(185, order=2^8)

In [5]: b = GF(0b10010100); b
Out[5]: GF(148, order=2^8)

In [6]: c = a * b; c
Out[6]: GF(178, order=2^8)

# You can display the result as a polynomial over GF(2)
In [7]: GF.display("poly");

# This matches 0b10110010
In [8]: c
Out[8]: GF(x^7 + x^5 + x^4 + x, order=2^8)

您也可以使用数组。

In [12]: a = GF([1, 2, 3, 4]); a
Out[12]: GF([1, 2, 3, 4], order=2^8)

In [13]: b = GF([100, 110, 120, 130]); b
Out[13]: GF([100, 110, 120, 130], order=2^8)

In [14]: a * b
Out[14]: GF([100, 220, 136,  62], order=2^8)

它是开源的,因此您可以查看所有代码。这是GF(2^m) 中的乘法sn-p。所有输入都是整数。以下是如何使用具有特征 2 的整数执行“多项式乘法”。

    def _multiply_calculate(a, b, CHARACTERISTIC, DEGREE, IRREDUCIBLE_POLY):
        """
        a in GF(2^m), can be represented as a degree m-1 polynomial a(x) in GF(2)[x]
        b in GF(2^m), can be represented as a degree m-1 polynomial b(x) in GF(2)[x]
        p(x) in GF(2)[x] with degree m is the irreducible polynomial of GF(2^m)

        a * b = c
            = (a(x) * b(x)) % p(x) in GF(2)
            = c(x)
            = c
        """
        ORDER = CHARACTERISTIC**DEGREE

        # Re-order operands such that a > b so the while loop has less loops
        if b > a:
            a, b = b, a

        c = 0
        while b > 0:
            if b & 0b1:
                c ^= a  # Add a(x) to c(x)

            b >>= 1  # Divide b(x) by x
            a <<= 1  # Multiply a(x) by x
            if a >= ORDER:
                a ^= IRREDUCIBLE_POLY  # Compute a(x) % p(x)

        return c

同样的例子运行如下。

In [72]: _multiply_calculate(0b10111001, 0b10010100, 2, 8, 0b100011011)
Out[72]: 178

In [73]: bin(_multiply_calculate(0b10111001, 0b10010100, 2, 8, 0b100011011))
Out[73]: '0b10110010'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-07
    相关资源
    最近更新 更多