Files
xgcl/sm/sm4/experiment/gfx.go
T
2026-05-27 23:03:00 +08:00

125 lines
1.9 KiB
Go

package experiment
// ffe stands for finite field elements
type ffe struct {
v [8]byte
}
func NewFFE(in byte) *ffe {
r := new(ffe)
for i := 0; i < 8; i++ {
r.v[i] = (in >> i) & 1
}
return r
}
type gf256 struct {
f [9]byte
invertTable [256]byte
}
var sm4Field = &gf256{
f: [9]byte{1, 0, 1, 0, 1, 1, 1, 1, 1},
}
var aesField = &gf256{
f: [9]byte{1, 1, 0, 1, 1, 0, 0, 0, 1},
}
func (g *gf256) _add(u, v []byte) []byte {
l := len(u)
if l < len(v) {
l = len(v)
}
r := make([]byte, l)
copy(r, u)
for i := 0; i < len(v); i++ {
r[i] = r[i] ^ v[i]
}
return r
}
func (g *gf256) Add(u, v *ffe) *ffe {
r := new(ffe)
for i := 0; i < 8; i++ {
r.v[i] = u.v[i] ^ v.v[i]
}
return r
}
// return v*x^n
func (g *gf256) _mulxn(v []byte, n int) []byte {
buf := make([]byte, n, len(v)+n)
buf = append(buf, v[:]...)
return buf
}
func (g *gf256) reduce(v []byte) *ffe {
buf := append([]byte{}, v...)
for i := len(buf) - 1; i >= 8; i-- {
if buf[i] == 1 {
buf = g._add(buf, g._mulxn(g.f[:], i-8))
}
}
r := new(ffe)
copy(r.v[:], buf)
return r
}
// vmul return v1*v2 mod m
func (g *gf256) Mul(u, v *ffe) *ffe {
r := make([]byte, 16)
// copy(r, u.v[:])
for i := 0; i < 8; i++ {
if v.v[i] == 1 {
r = g._add(r, g._mulxn(u.v[:], i))
}
}
return g.reduce(r)
}
func (g *gf256) IsOne(v *ffe) bool {
if v.v[0] == 0 {
return false
}
for i := 1; i < len(v.v); i++ {
if v.v[i] != 0 {
return false
}
}
return true
}
func (g *gf256) makeInverseTable() {
g.invertTable[0] = 0
for i := 1; i < 256; i++ {
u := NewFFE(byte(i))
for j := 1; j < 256; j++ {
if g.IsOne(g.Mul(u, NewFFE(byte(j)))) {
g.invertTable[i] = byte(j)
break
}
}
}
}
func init() {
aesField.makeInverseTable()
sm4Field.makeInverseTable()
}
func (g *gf256) Invert(v *ffe) *ffe {
return NewFFE(g.invertTable[v.Byte()])
}
func (e *ffe) Byte() byte {
r := byte(0)
for i := 0; i < len(e.v); i++ {
r = r << 1
r = r | e.v[len(e.v)-1-i]
}
return r
}