Skip to content

Instantly share code, notes, and snippets.

@emmansun
Last active October 22, 2021 02:22
Show Gist options
  • Save emmansun/276941d0bb41445db263c3b977dffe07 to your computer and use it in GitHub Desktop.
Save emmansun/276941d0bb41445db263c3b977dffe07 to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"math/bits"
)
// https://en.wikipedia.org/wiki/Rijndael_S-box
// AES's irreducible polynomial is x^8+x^4+x^3+x+1
func initAesSbox_1() []byte {
sbox := make([]byte, 256)
var p, q byte
p = 1
q = 1
/* 0 is a special case since it has no inverse */
sbox[0] = 0x63
for {
/* multiply p by 3 */
if p&0x80 == 0x80 {
p = p ^ (p << 1) ^ 0x1b
} else {
p = p ^ (p << 1)
}
/* divide q by 3 (equals multiplication by 0xf6) */
q ^= q << 1
q ^= q << 2
q ^= q << 4
if q&0x80 == 0x80 {
q ^= 0x09
}
/* compute the affine transformation */
xformated := q ^ bits.RotateLeft8(q, 1) ^ bits.RotateLeft8(q, 2) ^ bits.RotateLeft8(q, 3) ^ bits.RotateLeft8(q, 4)
sbox[p] = xformated ^ 0x63
if p == 1 {
break
}
}
return sbox
}
// https://merricx.github.io/aes-sbox/js/sbox.js
func initAesSbox_2() []byte {
tmp := make([]uint16, 256)
var x uint16
//generate elements of GF(2^8)
x = 1
for i := 0; i < 256; i++ {
tmp[i] = x
x ^= (x << 1) ^ ((x >> 7) * 0x11b) // {01}{1b}
}
sbox := make([]byte, 256)
sbox[0] = 0x63
for i := 0; i < 255; i++ {
// Take the multiplicative inverse
x = tmp[255-i]
// compute the affine transformation
x |= x << 8
x ^= (x >> 4) ^ (x >> 5) ^ (x >> 6) ^ (x >> 7)
sbox[tmp[i]] = byte(x ^ 0x63)
}
return sbox
}
// compute the SM4 affine transformation, matrix A=
// 1 1 0 1 0 0 1 1 b7
// 1 1 1 0 1 0 0 1 b6
// 1 1 1 1 0 1 0 0 b5
// 0 1 1 1 1 0 1 0 x b4
// 0 0 1 1 1 1 0 1 b3
// 1 0 0 1 1 1 1 0 b2
// 0 1 0 0 1 1 1 1 b1
// 1 0 1 0 0 1 1 1 b0
func sm4L(x byte) byte {
return x ^ bits.RotateLeft8(x, 1) ^ bits.RotateLeft8(x, 3) ^ bits.RotateLeft8(x, 6) ^ bits.RotateLeft8(x, 7) ^ 0xd3
}
// compute the SM4 inversed affine transformation, matrix A'=
// 1 0 1 0 0 0 0 1 b7
// 1 1 0 1 0 0 0 0 b6
// 0 1 1 0 1 0 0 0 b5
// 0 0 1 1 0 1 0 0 x b4
// 0 0 0 1 1 0 1 0 b3
// 0 0 0 0 1 1 0 1 b2
// 1 0 0 0 0 1 1 0 b1
// 0 1 0 0 0 0 1 1 b0
func sm4LInv(x byte) byte {
y := x ^ 0xd3
return y ^ bits.RotateLeft8(y, 2) ^ bits.RotateLeft8(y, 7)
}
// SM4's irreducible polynomial is x^8+x^7+x^6+x^5+x^4+x^2+1
// Sbox(x) = L(Inv(L(x)))
func initSm4Sbox_1() []byte {
sbox := make([]byte, 256)
var i, p, q byte
p = 1
q = 1
for {
/* multiply p by 3 */
if p&0x80 == 0x80 {
p = p ^ (p << 1) ^ 0xf5
} else {
p = p ^ (p << 1)
}
/* divide q by 3 (equals multiplication by 0xac) */
q ^= q << 1
q ^= q << 2
q ^= q << 4
if q&0x80 == 0x80 {
q ^= 0x53
}
i = sm4LInv(p)
/* compute the affine transformation */
sbox[i] = sm4L(q)
if p == 1 {
break
}
}
/* 0 is a special case since it has no inverse */
sbox[sm4LInv(0)] = sm4L(0)
return sbox
}
// SM4's irreducible polynomial is x^8+x^7+x^6+x^5+x^4+x^2+1
func initSm4Sbox_2() []byte {
reverseTable := make(map[byte]byte)
tmp := make([]uint16, 256)
var x uint16
//generate elements of GF(2^8)
x = 1
for i := 0; i < 256; i++ {
tmp[i] = x
reverseTable[byte(x)] = byte(i)
x ^= (x << 1) ^ ((x >> 7) * 0x1f5) // {01}{f5}
}
sbox := make([]byte, 256)
for i := 0; i < 256; i++ {
li := sm4L(byte(i))
if li == 0 {
sbox[i] = sm4L(0)
} else {
sbox[i] = sm4L(byte(tmp[255-reverseTable[li]]))
}
}
return sbox
}
// https://ppfocus.com/0/ed0cb869b.html
func initSm4SboxBasedAES() []byte {
Saes := initAesSbox_1()
sbox := make([]byte, 256)
var x byte
// Ssm4(x) = L(Saes(Mx+C1)) + C2
// L=[0b11111010, 0b01100100, 0b10110100, 0b00001010, 0b01000001, 0b11011101, 0b00000001, 0b11000001]
// L=[0xfa, 0x64, 0xb4, 0x0a, 0x41, 0xdd, 0x01, 0xc1]
// M=[0b10010110, 0b01000111, 0b11101001, 0b00111101, 0b11011110, 0b01100101, 0b10101100, 0b10100111]
// M=[0x96, 0x47, 0xe9, 0x3d, 0xde, 0x65, 0xac, 0xa7]
// C1=0x69
// C2=0x61
for i := 0; i < 256; i++ {
x = ((byte(bits.OnesCount8(byte(i)&0x96)) & 1) << 7) ^
((byte(bits.OnesCount8(byte(i)&0x47)) & 1) << 6) ^
((byte(bits.OnesCount8(byte(i)&0xe9)) & 1) << 5) ^
((byte(bits.OnesCount8(byte(i)&0x3d)) & 1) << 4) ^
((byte(bits.OnesCount8(byte(i)&0xde)) & 1) << 3) ^
((byte(bits.OnesCount8(byte(i)&0x65)) & 1) << 2) ^
((byte(bits.OnesCount8(byte(i)&0xac)) & 1) << 1) ^
((byte(bits.OnesCount8(byte(i)&0xa7)) & 1) << 0) ^ 0x69
x = Saes[x]
x = ((byte(bits.OnesCount8(byte(x)&0xfa)) & 1) << 7) ^
((byte(bits.OnesCount8(byte(x)&0x64)) & 1) << 6) ^
((byte(bits.OnesCount8(byte(x)&0xb4)) & 1) << 5) ^
((byte(bits.OnesCount8(byte(x)&0x0a)) & 1) << 4) ^
((byte(bits.OnesCount8(byte(x)&0x41)) & 1) << 3) ^
((byte(bits.OnesCount8(byte(x)&0xdd)) & 1) << 2) ^
((byte(bits.OnesCount8(byte(x)&0x01)) & 1) << 1) ^
((byte(bits.OnesCount8(byte(x)&0xc1)) & 1) << 0) ^ 0x61
sbox[i] = x
}
return sbox
}
var m1l = [16]byte{0x01, 0x07, 0x72, 0x74, 0xe4, 0xe2, 0x97, 0x91, 0x57, 0x51, 0x24, 0x22, 0xb2, 0xb4, 0xc1, 0xc7}
var m1h = [16]byte{0x00, 0xa2, 0x49, 0xeb, 0x09, 0xab, 0x40, 0xe2, 0x12, 0xb0, 0x5b, 0xf9, 0x1b, 0xb9, 0x52, 0xf0}
var m2l = [16]byte{0x34, 0x08, 0x9d, 0xa1, 0xce, 0xf2, 0x67, 0x5b, 0x82, 0xbe, 0x2b, 0x17, 0x78, 0x44, 0xd1, 0xed}
var m2h = [16]byte{0x00, 0xdc, 0xaf, 0x73, 0xdd, 0x01, 0x72, 0xae, 0xbf, 0x63, 0x10, 0xcc, 0x62, 0xbe, 0xcd, 0x11}
// https://github.com/emmansun/sm4ni
func initSm4SboxBasedAES_2() []byte {
Saes := initAesSbox_1()
sbox := make([]byte, 256)
var x byte
for i := 0; i < 256; i++ {
x = m1l[i&0xf] ^ m1h[i>>4]
x = Saes[x]
x = m2l[x&0xf] ^ m2h[x>>4]
sbox[i] = x
}
return sbox
}
func initSm4SboxBasedAES_3() []byte {
Saes := initAesSbox_1()
sbox := make([]byte, 256)
var x byte
// Ssm4(x) = L(Saes(Mx+C1)) + C2
// L=[0b11111110, 0b01010100, 0b10101111, 0b11011101, 0bffff0111, 0bffff1001, 0b10101100, 0b11100010]
// L=[0xfe, 0x54, 0xaf, 0xdd, 0xf7, 0xf9, 0xac, 0xe2]
// M=[0b00010100, 0b00101110, 0b00010110, 0b10001010, 0b01100000, 0b00001101, 0b10011011, 0b01100110]
// M=[0x14, 0x2e, 0x16, 0x8a, 0x60, 0x0d, 0x9b, 0x66]
// C1=0x01
// C2=0x34
for i := 0; i < 256; i++ {
x = ((byte(bits.OnesCount8(byte(i)&0x14)) & 1) << 7) ^
((byte(bits.OnesCount8(byte(i)&0x2e)) & 1) << 6) ^
((byte(bits.OnesCount8(byte(i)&0x16)) & 1) << 5) ^
((byte(bits.OnesCount8(byte(i)&0x8a)) & 1) << 4) ^
((byte(bits.OnesCount8(byte(i)&0x60)) & 1) << 3) ^
((byte(bits.OnesCount8(byte(i)&0x0d)) & 1) << 2) ^
((byte(bits.OnesCount8(byte(i)&0x9b)) & 1) << 1) ^
((byte(bits.OnesCount8(byte(i)&0x66)) & 1) << 0) ^ 0x01
x = Saes[x]
x = ((byte(bits.OnesCount8(byte(x)&0xfe)) & 1) << 7) ^
((byte(bits.OnesCount8(byte(x)&0x54)) & 1) << 6) ^
((byte(bits.OnesCount8(byte(x)&0xaf)) & 1) << 5) ^
((byte(bits.OnesCount8(byte(x)&0xdd)) & 1) << 4) ^
((byte(bits.OnesCount8(byte(x)&0xf7)) & 1) << 3) ^
((byte(bits.OnesCount8(byte(x)&0xf9)) & 1) << 2) ^
((byte(bits.OnesCount8(byte(x)&0xac)) & 1) << 1) ^
((byte(bits.OnesCount8(byte(x)&0xe2)) & 1) << 0) ^ 0x34
sbox[i] = x
}
return sbox
}
func printSbox(sbox []byte) {
for i := 0; i < len(sbox); i++ {
fmt.Printf("%02x ", sbox[i])
if i > 0 && (i+1)%16 == 0 {
fmt.Println()
}
}
}
func main() {
printSbox(initAesSbox_1())
fmt.Println()
printSbox(initAesSbox_2())
fmt.Println()
printSbox(initSm4Sbox_1())
fmt.Println()
printSbox(initSm4Sbox_2())
fmt.Println()
printSbox(initSm4SboxBasedAES())
fmt.Println()
printSbox(initSm4SboxBasedAES_2())
fmt.Println()
printSbox(initSm4SboxBasedAES_3())
fmt.Println()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment