mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-07-07 04:08:44 +00:00
Finalmask: Add Sudoku (TCP & UDP) (#5685)
https://github.com/SUDOKU-ASCII/sudoku/issues/23#issuecomment-3859972396
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
package sudoku
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
var perm4 = [24][4]byte{
|
||||
{0, 1, 2, 3},
|
||||
{0, 1, 3, 2},
|
||||
{0, 2, 1, 3},
|
||||
{0, 2, 3, 1},
|
||||
{0, 3, 1, 2},
|
||||
{0, 3, 2, 1},
|
||||
{1, 0, 2, 3},
|
||||
{1, 0, 3, 2},
|
||||
{1, 2, 0, 3},
|
||||
{1, 2, 3, 0},
|
||||
{1, 3, 0, 2},
|
||||
{1, 3, 2, 0},
|
||||
{2, 0, 1, 3},
|
||||
{2, 0, 3, 1},
|
||||
{2, 1, 0, 3},
|
||||
{2, 1, 3, 0},
|
||||
{2, 3, 0, 1},
|
||||
{2, 3, 1, 0},
|
||||
{3, 0, 1, 2},
|
||||
{3, 0, 2, 1},
|
||||
{3, 1, 0, 2},
|
||||
{3, 1, 2, 0},
|
||||
{3, 2, 0, 1},
|
||||
{3, 2, 1, 0},
|
||||
}
|
||||
|
||||
type codec struct {
|
||||
tables []*table
|
||||
rng *rand.Rand
|
||||
paddingChance int
|
||||
tableIndex int
|
||||
}
|
||||
|
||||
func newCodec(tables []*table, pMin, pMax int) *codec {
|
||||
if len(tables) == 0 {
|
||||
tables = nil
|
||||
}
|
||||
rng := newSeededRand()
|
||||
return &codec{
|
||||
tables: tables,
|
||||
rng: rng,
|
||||
paddingChance: pickPaddingChance(rng, pMin, pMax),
|
||||
}
|
||||
}
|
||||
|
||||
func pickPaddingChance(rng *rand.Rand, pMin, pMax int) int {
|
||||
if pMin < 0 {
|
||||
pMin = 0
|
||||
}
|
||||
if pMax < pMin {
|
||||
pMax = pMin
|
||||
}
|
||||
if pMin > 100 {
|
||||
pMin = 100
|
||||
}
|
||||
if pMax > 100 {
|
||||
pMax = 100
|
||||
}
|
||||
if pMax == pMin {
|
||||
return pMin
|
||||
}
|
||||
return pMin + rng.Intn(pMax-pMin+1)
|
||||
}
|
||||
|
||||
func (c *codec) shouldPad() bool {
|
||||
if c.paddingChance <= 0 {
|
||||
return false
|
||||
}
|
||||
if c.paddingChance >= 100 {
|
||||
return true
|
||||
}
|
||||
return c.rng.Intn(100) < c.paddingChance
|
||||
}
|
||||
|
||||
func (c *codec) currentTable() *table {
|
||||
if len(c.tables) == 0 {
|
||||
return nil
|
||||
}
|
||||
return c.tables[c.tableIndex%len(c.tables)]
|
||||
}
|
||||
|
||||
func (c *codec) randomPadding(t *table) byte {
|
||||
pool := t.layout.paddingPool
|
||||
return pool[c.rng.Intn(len(pool))]
|
||||
}
|
||||
|
||||
func (c *codec) encode(in []byte) ([]byte, error) {
|
||||
if len(in) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
out := make([]byte, 0, len(in)*6+8)
|
||||
for _, b := range in {
|
||||
t := c.currentTable()
|
||||
if t == nil {
|
||||
return nil, fmt.Errorf("sudoku table set missing")
|
||||
}
|
||||
if c.shouldPad() {
|
||||
out = append(out, c.randomPadding(t))
|
||||
}
|
||||
|
||||
enc := t.encode[b]
|
||||
if len(enc) == 0 {
|
||||
return nil, fmt.Errorf("sudoku encode table missing for byte %d", b)
|
||||
}
|
||||
|
||||
hints := enc[c.rng.Intn(len(enc))]
|
||||
perm := perm4[c.rng.Intn(len(perm4))]
|
||||
for _, idx := range perm {
|
||||
if c.shouldPad() {
|
||||
out = append(out, c.randomPadding(t))
|
||||
}
|
||||
out = append(out, hints[idx])
|
||||
}
|
||||
c.tableIndex++
|
||||
}
|
||||
|
||||
if c.shouldPad() {
|
||||
if t := c.currentTable(); t != nil {
|
||||
out = append(out, c.randomPadding(t))
|
||||
}
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func decodeBytes(tables []*table, tableIndex *int, in []byte, hintBuf []byte, out []byte) ([]byte, []byte, error) {
|
||||
if len(tables) == 0 {
|
||||
return hintBuf, out, fmt.Errorf("sudoku table set missing")
|
||||
}
|
||||
for _, b := range in {
|
||||
t := tables[*tableIndex%len(tables)]
|
||||
if !t.layout.isHint(b) {
|
||||
continue
|
||||
}
|
||||
|
||||
hintBuf = append(hintBuf, b)
|
||||
if len(hintBuf) < 4 {
|
||||
continue
|
||||
}
|
||||
|
||||
keyBytes := sort4([4]byte{hintBuf[0], hintBuf[1], hintBuf[2], hintBuf[3]})
|
||||
key := packKey(keyBytes)
|
||||
decoded, ok := t.decode[key]
|
||||
if !ok {
|
||||
return hintBuf[:0], out, fmt.Errorf("invalid sudoku hint tuple")
|
||||
}
|
||||
|
||||
out = append(out, decoded)
|
||||
hintBuf = hintBuf[:0]
|
||||
*tableIndex++
|
||||
}
|
||||
|
||||
return hintBuf, out, nil
|
||||
}
|
||||
Reference in New Issue
Block a user