定义一个包含256个元素的字段


15

字段在数学是一组数字,与在其上定义,使得它们满足特定公理加法和乘法操作(Wikipedia中所述;也见下文)。

有限域可以包含p n个元素,其中p素数和n自然数。在这个挑战中,让我们接受p = 2n = 8,让我们创建一个包含256个元素的字段。

该字段的元素应为包含0和的范围内的连续整数1

  • -128 ... 127
  • 0 ... 255
  • 或任何其他此类范围

为抽象的“加法”和抽象的“乘法” 定义两个函数(或程序,如果更容易的话),a(x,y)m(x,y)使它们满足字段公理:

  • 一致性:a(x,y)m(x,y)时同参数调用产生相同的结果
  • 闭性:结果am在相关范围内的整数
  • 关联性:对于任何xy并且z在范围内a(a(x,y),z)等于a(x,a(y,z));一样m
  • 交换性:对于任何xy范围内的,a(x,y)是等于a(y,x); 一样m
  • 分布:对于任何xy并且z在范围内,m(x,a(y,z))等于a(m(x,y),m(x,z))
  • 中性元素:对于x范围内的任何元素,a(0,x)等于x,并且m(1,x)等于x
  • 否定:对于任何x在的范围内,存在着这样的ya(x,y)0
  • 逆:对于任何x≠0在的范围内,存在着这样的ym(x,y)1

名称am只是示例;您可以使用其他名称或未命名的函数。答案的分数是和的字节长度之am

如果您使用内置函数,也请用文字描述它产生的结果(例如,提供一个乘法表)。


3
@LeakyNun“ addition”只是满足上述属性的抽象操作。只要满足上述公理a(2,1) = 3,就没有必要a(2,1) = 5a与您习惯于使用有理数域的常用加法无关。
Martin Ender

2
换向环是微不足道的。一个领域...不是那么容易。
尼尔2016年

有什么问题a=+ m=×吗?
亚当

4
@Adám是的-如果m=×
-Sp3000

Answers:


4

Intel x86-64 + AVX-512 + GFNI,11个字节

add:
    C5 F0 57 C0     # vxorps     xmm0, xmm1, xmm0
    C3              # ret
mul:
    C4 E2 79 CF C1  # vgf2p8mulb xmm0, xmm0, xmm1
    C3              # ret

GF2P8MULB在Ice Lake CPU上使用新指令。

该指令将有限域GF(2 8)中的元素相乘,对第一源操作数中的一个字节(字段元素)和第二源操作数中的相应字节进行操作。场GF(2 8)用多项式表示形式,化简多项式x 8 + x 4 + x 3 + x + 1。


13

Python 2、11 + 45 = 56字节

加法(11字节):

int.__xor__

乘法(45字节):

m=lambda x,y:y and m(x*2^x/128*283,y/2)^y%2*x

输入范围内的输入数字[0 ... 255]。加法只是按位XOR,乘法是GF2中多项式与系数的乘积与俄罗斯农民的乘积。

并进行检查:

a=int.__xor__
m=lambda x,y:y and m(x*2^x/128*283,y/2)^y%2*x

for x in range(256):
    assert a(0,x) == a(x,0) == x
    assert m(1,x) == m(x,1) == x

    assert any(a(x,y) == 0 for y in range(256))

    if x != 0:
        assert any(m(x,y) == 1 for y in range(256))

    for y in range(256):
        assert 0 <= a(x,y) < 256
        assert 0 <= m(x,y) < 256
        assert a(x,y) == a(y,x)
        assert m(x,y) == m(y,x)

        for z in range(256):
            assert a(a(x,y),z) == a(x,a(y,z))
            assert m(m(x,y),z) == m(x,m(y,z))
            assert m(x,a(y,z)) == a(m(x,y), m(x,z))

我们其中一个人将不得不改变:P
Mego

@Mego Hah,嗯...我会尝试看看是否可以找到其他方法。可能很难被击败。
Sp3000

1
它基于哪个多项式?
feersum

1
@LSpice现在,我意识到我可以通过运行轻松找到多项式m(2,128),结果为27 = 283-256 ,因此您是正确的,多项式为x^8 + x^4 + x^3 + x + 1
feersum

1
@LSpice在Neil的回答中,他提供了一个Wikipedia页面作为该算法的源代码,因此也许每个人都可以读到。但无论如何,它是代码高尔夫最明显的选择,因为它是此表示形式中最小的8级不可约多项式。
feersum

6

JavaScript(ES6),10 + 49 = 59字节

a=(x,y)=>x^y
m=(x,y,p=0)=>x?m(x>>1,2*y^283*(y>>7),p^y*(x&1)):p

域是0 ...255 。


2
您可能应该指定要使用的范围。
Martin Ender

4

Hoon,22个字节

[dif pro]:(ga 8 283 3)

Hoon已经具有++ga创建Galois字段的功能,供AES实现使用。这将返回两个函数的元组,而不是使用两个程序。

在域中运行 [0...255]

测试套件:

=+  f=(ga 8 283 3)
=+  n=(gulf 0 255)

=+  a=dif:f
=+  m=pro:f

=+  %+  turn  n
    |=  x/@
    ?>  =((a 0 x) x)
    ?>  =((m 1 x) x)
    ~&  outer+x

    %+  turn  n
      |=  y/@
      ?>  =((a x y) (a y x))
      ?>  &((lte 0 (a x y)) (lte (a x y) 255))
      ?>  &((lte 0 (m x y)) (lte (m x y) 255))

      %+  turn  n
        |=  z/@
        ?>  =((a (a x y) z) (a x (a y z)))
        ?>  =((m x (a y z)) (a (m x y) (m x z)))
        ~
"ok"

发布乘法表将是巨大的,因此这是一些随机测试用例:

20x148=229
61x189=143
111x239=181
163x36=29
193x40=1

1

IA-32机器代码,22个字节

“乘法”,18个字节:

33 c0 92 d1 e9 73 02 33 d0 d0 e0 73 02 34 1b 41
e2 f1

“加法”,4个字节:

92 33 c1 c3

这会延长规则范围:“乘法”代码缺少函数退出代码;它依赖于此后立即在内存中的“添加”代码,因此它可以“掉线”。我这样做是为了将代码大小减少1个字节。

源代码(可以由mlMS Visual Studio 汇编):

    TITLE   x

PUBLIC @m@8
PUBLIC @a@8

_TEXT   SEGMENT USE32
@m@8    PROC
    xor eax, eax;
    xchg eax, edx;
myloop:
    shr ecx, 1
    jnc sk1
    xor edx, eax
sk1:
    shl al, 1
    jnc sk2
    xor al, 1bh
sk2:
    inc ecx
    loop myloop
@m@8 endp

@a@8 proc
    xchg eax, edx;
    xor eax, ecx
    ret
@a@8    ENDP
_text ENDS
END

该算法是标准算法,涉及通常的多项式x^8 + x^4 + x^3 + x + 1,用十六进制数表示1b。“乘法”代码将结果累加到中edx。完成后,它进入加法码,然后将其移至eax(常规寄存器以保存返回值);在xorecx是一个空操作,因为在这一点上ecx被清除。

循环是一个独特的功能。而不是检查零

cmp ecx, 0
jne myloop

它使用专用loop指令。但是,此指令在将其与0进行比较之前会减小循环“计数器”。为了对此进行补偿,代码在使用该loop指令之前将其增加。


0

Mathematica 155字节

f[y_]:=Total[x^Reverse@Range[0,Log[2,y]]*RealDigits[y,2][[1]]];o[q_,c_,d_]:=FromDigits[Reverse@Mod[CoefficientList[PolynomialMod[q[f@c,f@d],f@283],x],2],2]

实作

(*
  in: o[Times, 202, 83]    out: 1
  in: o[Plus, 202, 83]     out: 153
*)

附加检查:

(*
  in: BitXor[202, 83]      out: 153
*)

更多:

(*
  in: o[Times, #, #2] & @@@ {{20, 148}, {61, 189}, {111, 239}, {163, 36}, {193, 40}}
  out: {229, 143, 181, 29, 1}
*)

注意:应该可以使用{283, 285, 299, 301, 313, 319, 333, 351, 355, 357, 361, 369, 375, 379, 391, 395, 397, 415, 419, 425, 433, 445, 451, 463, 471, 477, 487, 499, 501, 505}代替283


好吧,这里少了13个字节:(±y_:=Total[#&@@y~RealDigits~2x^Reverse@Range[0,2~Log~y]];p[q_,c_,d_]:=Fold[#+##&,Reverse@CoefficientList[q[±c,±d]~PolynomialMod~±283,x]~Mod~2]假设源是按照ISO 8859-1编码的)
Martin Ender

@MartinEnder不太确定如何实施您的建议
马丁

@martin您可以像以前一样使用它,我只是使用±代替fp代替o(当然,您可以将其保留为o,我只是用过,p以便可以测试它们两者),然后使用标准格式保存更多字节语法糖技巧。
Martin Ender

@MartinEnder可以±像上一样工作f,但不可以p……不知道我要去哪里错了
马丁

如果直接从注释中复制它,则无论您的浏览器在注释中显示换行符的任何位置,都可能会有一些无法打印的字符。复制后删除该位置附近的字符,然后重新输入。如果不这样做,我不知道是哪里的问题..
马丁安德

-1

Brainfuck,28个字符

幸运的是,标准的Brainfuck可以对256进行模运算。

加法:[->+<],假设输入位于磁带的前两个位置,则将输出置于位置0

乘法:[->[->+>+<<]>[-<+>]<<],假设输入位于磁带的前两个位置,则将输出置于位置3

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.