init: v1.0.0
This commit is contained in:
+134
@@ -0,0 +1,134 @@
|
||||
package fpe
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"errors"
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/internal/xor"
|
||||
)
|
||||
|
||||
func rev[T any](X []T) {
|
||||
l := len(X) / 2
|
||||
for i := 0; i < l; i++ {
|
||||
t := X[i]
|
||||
X[i] = X[l-i-1]
|
||||
X[l-i-1] = t
|
||||
}
|
||||
}
|
||||
|
||||
// in = in0||in1||in2...
|
||||
// out0 = Enc(iv ^ in0)
|
||||
// out1 = Enc(out0 ^ in1)
|
||||
// ...
|
||||
// if iv == nil <==> iv = 0^16.
|
||||
func prf(res []byte, b cipher.Block, iv []byte, in []byte) []byte {
|
||||
xor.XorBytes(res, iv, in[:16])
|
||||
b.Encrypt(res, res)
|
||||
in = in[16:]
|
||||
|
||||
for len(in) > 0 {
|
||||
xor.XorBytes(res, res, in[:16])
|
||||
b.Encrypt(res, res)
|
||||
in = in[16:]
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
type FF1 struct {
|
||||
cipher.Block
|
||||
Alphabet
|
||||
}
|
||||
|
||||
func NewFF1(b cipher.Block, a Alphabet) FPE {
|
||||
return &FF1{
|
||||
Block: b,
|
||||
Alphabet: a,
|
||||
}
|
||||
}
|
||||
|
||||
func (f *FF1) round(P []byte, Q []byte, S []byte, A []Numeral, B []Numeral, i int, b int, d int, module *big.Int, isenc bool) {
|
||||
Q[len(Q)-b-1] = byte(i)
|
||||
f.Num(B).FillBytes(Q[len(Q)-b:])
|
||||
prf(S, f.Block, P, Q)
|
||||
for j := 1; j < (d+15)/16; j++ {
|
||||
Sj := S[16*j : 16*j+16]
|
||||
S[16*j+12] = byte(j >> 24)
|
||||
S[16*j+13] = byte(j >> 16)
|
||||
S[16*j+14] = byte(j >> 8)
|
||||
S[16*j+15] = byte(j)
|
||||
xor.XorBytes(Sj, S[:16], Sj)
|
||||
f.Block.Encrypt(Sj, Sj)
|
||||
}
|
||||
y := new(big.Int).SetBytes(S[:d])
|
||||
c := f.Num(A)
|
||||
if isenc {
|
||||
c.Add(c, y).Mod(c, module)
|
||||
} else {
|
||||
c.Sub(c, y).Mod(c, module)
|
||||
}
|
||||
f.Str(A, c)
|
||||
}
|
||||
|
||||
func (f *FF1) endecrypt(T []byte, X []Numeral, isEnc bool) ([]Numeral, error) {
|
||||
n := len(X)
|
||||
if n <= 2 {
|
||||
return nil, errors.New("input numeral string X must at least 2 characters")
|
||||
}
|
||||
|
||||
radix := f.Alphabet.Radix()
|
||||
t := len(T)
|
||||
u := n / 2
|
||||
v := n - u
|
||||
b := (int(math.Ceil(float64(v)*math.Log2(float64(radix)))) + 7) >> 3
|
||||
d := (b + 7) & (^3)
|
||||
P := []byte{
|
||||
1, 2, 1,
|
||||
0, byte(radix >> 8), byte(radix),
|
||||
10, byte(u),
|
||||
byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n),
|
||||
byte(t >> 24), byte(t >> 16), byte(t >> 8), byte(t),
|
||||
}
|
||||
f.Block.Encrypt(P, P)
|
||||
// make a copy of X
|
||||
res := make([]Numeral, len(X))
|
||||
copy(res, X)
|
||||
A := res[:u]
|
||||
B := res[u:]
|
||||
|
||||
// Q := append(make([]byte, 0, (b+t+1+15)&(^15)), T...)
|
||||
Q := make([]byte, (b+t+1+15)&(^15))
|
||||
copy(Q, T)
|
||||
S := make([]byte, (d+15)&(^15))
|
||||
|
||||
var moduleA, moduleB *big.Int
|
||||
radixBig := big.NewInt(int64(radix))
|
||||
// 如果输入X很大,这里的module会很大。
|
||||
moduleA = new(big.Int).Exp(radixBig, big.NewInt(int64(u)), nil)
|
||||
moduleB = moduleA
|
||||
if v > u {
|
||||
moduleB = radixBig.Mul(moduleB, radixBig)
|
||||
}
|
||||
|
||||
if isEnc {
|
||||
for i := 0; i < 10; i += 2 {
|
||||
f.round(P, Q, S, A, B, i, b, d, moduleA, true)
|
||||
f.round(P, Q, S, B, A, i+1, b, d, moduleB, true)
|
||||
}
|
||||
} else {
|
||||
for i := 9; i >= 0; i -= 2 {
|
||||
f.round(P, Q, S, B, A, i, b, d, moduleB, false)
|
||||
f.round(P, Q, S, A, B, i-1, b, d, moduleA, false)
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (f *FF1) Encrypt(T []byte, X []Numeral) ([]Numeral, error) {
|
||||
return f.endecrypt(T, X, true)
|
||||
}
|
||||
|
||||
func (f FF1) Decrypt(T []byte, X []Numeral) ([]Numeral, error) {
|
||||
return f.endecrypt(T, X, false)
|
||||
}
|
||||
Reference in New Issue
Block a user