init: v1.0.0
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
package fpe
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"xdx.jelly/xgcl/sm/sm4"
|
||||
)
|
||||
|
||||
// return the check code of id.
|
||||
func checkCodeOfID(id0 string) byte {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
// EncryptID 加密身份证号。最后一位为校验位。
|
||||
// key为SM4密钥,16字节
|
||||
// tweak随机数,任意长度,可明文保存。
|
||||
func EncryptID(id string, key []byte, tweak []byte) (string, error) {
|
||||
if len(id) != 18 {
|
||||
return "", errors.New("wrong id")
|
||||
}
|
||||
|
||||
if len(key) != 16 {
|
||||
return "", errors.New("wrong key")
|
||||
}
|
||||
b, err := sm4.NewCipher(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
f := NewFF1(b, Numeric)
|
||||
numerals, err := f.Encode(id[:len(id)-1])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
cipher, err := f.Encrypt(tweak, numerals)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
encryptedID, err := f.Decode(cipher)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// TODO: add the check code
|
||||
|
||||
return encryptedID, nil
|
||||
|
||||
}
|
||||
|
||||
// 加密纯数字的手机号
|
||||
func EncryptPhoneNumber(phoneNumber string, key []byte, tweak []byte) (string, error) {
|
||||
|
||||
panic("todo")
|
||||
}
|
||||
+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)
|
||||
}
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
// fpe is the Format-Preserving Encryption.
|
||||
package fpe
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Numeral = uint16
|
||||
|
||||
type Char = uint16
|
||||
|
||||
// Alphabet is the interface for an alphabet.
|
||||
type Alphabet interface {
|
||||
// fpe实际上是可对任意的字符表进行编码,比如JPEG2000,编码范围为0xff8f的序列,且不以0xff结尾。
|
||||
// 但是这里的Encode只处理utf-8的string
|
||||
Encode(s string) ([]Numeral, error)
|
||||
Decode(numString []Numeral) (string, error)
|
||||
|
||||
// 如果是二进制类的数据
|
||||
// EncodeBlob(b []byte) ([]Numeral, error)
|
||||
// DecodeBlob(numString []Numeral) ([]byte, error)
|
||||
|
||||
Radix() int
|
||||
Num(X []Numeral) *big.Int
|
||||
|
||||
// X = Str_radix^m(C)
|
||||
Str(X []Numeral, x *big.Int)
|
||||
}
|
||||
|
||||
var (
|
||||
// ASCII code 32-126, all printable characters.
|
||||
Printable = NewAlphabet(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~")
|
||||
Numeric = NewAlphabet("0123456789")
|
||||
Lower = NewAlphabet("abcdefghijklmnopqrstuvwxyz")
|
||||
Upper = NewAlphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
Alpha = NewAlphabet("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
NumAlpha = NewAlphabet("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
|
||||
)
|
||||
|
||||
type FPE interface {
|
||||
Encrypt(tweak []byte, X []Numeral) ([]Numeral, error)
|
||||
Decrypt(tweak []byte, X []Numeral) ([]Numeral, error)
|
||||
Alphabet
|
||||
}
|
||||
|
||||
// GenericAlphabet 可以处理asicc字符集
|
||||
type GenericAlphabet struct {
|
||||
tblBuf [128]Char
|
||||
tbl [][]Numeral
|
||||
|
||||
r Radix
|
||||
}
|
||||
|
||||
// Assume the characters in alphabet are all ASCII now.
|
||||
// Unicode characters not supported now.
|
||||
func NewAlphabet(alphabet string) Alphabet {
|
||||
r := len(alphabet)
|
||||
|
||||
res := &GenericAlphabet{}
|
||||
res.r.Set(r)
|
||||
|
||||
tblBuf := res.tblBuf
|
||||
for i := range tblBuf {
|
||||
tblBuf[i] = 128
|
||||
}
|
||||
for _, d := range alphabet {
|
||||
if d > 127 {
|
||||
panic("only ASCII characters are supported now")
|
||||
}
|
||||
tblBuf[d] = Char(d)
|
||||
}
|
||||
tbls := make([][]Numeral, 0)
|
||||
start := -1
|
||||
for i, d := range tblBuf {
|
||||
switch {
|
||||
case d == 128:
|
||||
if start >= 0 {
|
||||
tbls = append(tbls, tblBuf[start:i])
|
||||
start = -1
|
||||
}
|
||||
case d < 128:
|
||||
if start < 0 {
|
||||
start = i
|
||||
}
|
||||
}
|
||||
}
|
||||
res.tbl = tbls
|
||||
return res
|
||||
}
|
||||
|
||||
var numSwitch = false
|
||||
|
||||
// Num implements Alphabet.
|
||||
func (ga *GenericAlphabet) Num(X []Char) *big.Int {
|
||||
return ga.r.Num(X)
|
||||
}
|
||||
|
||||
// x should < radix^(lenX)
|
||||
func (ga *GenericAlphabet) Str(X []Numeral, x *big.Int) {
|
||||
ga.r.Str(X, x)
|
||||
}
|
||||
|
||||
// FromString implements Alphabet.
|
||||
func (ga *GenericAlphabet) Encode(s string) ([]Numeral, error) {
|
||||
res := make([]Numeral, 0, len(s))
|
||||
for _, c := range s {
|
||||
if c>>16 != 0 {
|
||||
return nil, fmt.Errorf("unsupported character %c", c)
|
||||
}
|
||||
|
||||
if idx := index(Char(c), ga.tbl); idx >= 0 {
|
||||
res = append(res, Numeral(idx))
|
||||
} else {
|
||||
return nil, errors.New("bad characters")
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// // Radix implements Alphabet.
|
||||
func (ga *GenericAlphabet) Radix() int {
|
||||
return int(ga.r.r)
|
||||
}
|
||||
|
||||
// ToString implements Alphabet.
|
||||
func (ga *GenericAlphabet) Decode(numString []Numeral) (string, error) {
|
||||
var sb strings.Builder
|
||||
radix := uint16(ga.r.r)
|
||||
for _, d := range numString {
|
||||
if d >= radix {
|
||||
return "", errors.New("bad numeric string")
|
||||
}
|
||||
if _, err := sb.WriteRune(rune(char(d, ga.tbl))); err != nil {
|
||||
return "", errors.New("bad rune")
|
||||
}
|
||||
}
|
||||
return sb.String(), nil
|
||||
}
|
||||
|
||||
var _ Alphabet = &GenericAlphabet{}
|
||||
|
||||
// tbls[i] are continuous Char
|
||||
// tbls[0][0], tbls[0][1], ..., tbls[0][n0],
|
||||
// tbls[1][0], tbls[1][1], ..., tbls[1][n1],
|
||||
// ...
|
||||
func index(c Char, tbls [][]Char) int {
|
||||
n := 0
|
||||
for _, tbl := range tbls {
|
||||
n0 := int(c) - int(tbl[0])
|
||||
if n0 >= 0 && n0 < len(tbl) {
|
||||
return n + n0
|
||||
}
|
||||
n += len(tbl)
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Assume n < radix
|
||||
func char(n Numeral, tbls [][]Char) Char {
|
||||
m := int(n)
|
||||
for _, tbl := range tbls {
|
||||
if m < len(tbl) {
|
||||
return tbl[m]
|
||||
}
|
||||
m -= len(tbl)
|
||||
}
|
||||
panic("numeric great than radix")
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
package fpe
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xdx.jelly/xgcl/grand"
|
||||
"xdx.jelly/xgcl/sm/sm4"
|
||||
)
|
||||
|
||||
func TestNum(t *testing.T) {
|
||||
N := 1000
|
||||
A := make([]Numeral, N)
|
||||
B := make([]Numeral, N)
|
||||
|
||||
for r := 2; r < 100; r++ {
|
||||
radix := NewRadix(r)
|
||||
for i := 1; i <= N; i++ {
|
||||
for j := 0; j < i; j++ {
|
||||
A[j] = Numeral(rand.Int31() % int32(r))
|
||||
}
|
||||
numSwitch = false
|
||||
a0 := radix.Num(A[:i])
|
||||
numSwitch = true
|
||||
a1 := radix.Num(A[:i])
|
||||
assert.Equal(t, a0.Cmp(a1), 0)
|
||||
|
||||
radix.Str(B[:i], a0)
|
||||
assert.Equal(t, A[:i], B[:i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStr(t *testing.T) {
|
||||
f := Alpha
|
||||
// 24948832942366750129003083595837476696096111951836798179448429117431251233398075403977925597490
|
||||
A := []Numeral{
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
}
|
||||
|
||||
for i := 20; i <= len(A); i++ {
|
||||
a := f.Num(A[:i])
|
||||
B := make([]Numeral, i)
|
||||
f.Str(B, a)
|
||||
for j := range B {
|
||||
if B[j] != A[j] {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkAlphabet-10 1158810 1020 ns/op 88 B/op 3 allocs/op
|
||||
// BenchmarkAlphabet-10 3776529 310.4 ns/op 96 B/op 4 allocs/op
|
||||
func BenchmarkNum(b *testing.B) {
|
||||
f := Alpha
|
||||
A := []Numeral{
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
f.Num(A)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkStr-10 556981 2130 ns/op 104 B/op 2 allocs/op
|
||||
// BenchmarkStr-10 3134851 382.2 ns/op 104 B/op 2 allocs/op
|
||||
func BenchmarkStr(b *testing.B) {
|
||||
f := Alpha
|
||||
A := []Numeral{
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
}
|
||||
|
||||
a := f.Num(A)
|
||||
B := make([]Numeral, len(A))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
f.Str(B, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFF1(t *testing.T) {
|
||||
// fmt.Printf("%x\n", ^uint64(15))
|
||||
// 密钥
|
||||
key := grand.GetRandom(16)
|
||||
// 使用SM4加密算法
|
||||
b, _ := sm4.NewCipher(key)
|
||||
// tweak
|
||||
T := grand.GetRandom(16)
|
||||
|
||||
// interface FPE
|
||||
f := NewFF1(b, NewAlphabet("abcdefghijklmnopqrstuvwxyz "))
|
||||
|
||||
plainString0 := "hello world"
|
||||
plain0, err := f.Encode(plainString0)
|
||||
assert.Nil(t, err)
|
||||
|
||||
cipher, err := f.Encrypt(T, plain0)
|
||||
assert.Nil(t, err)
|
||||
|
||||
cipherString, err := f.Decode(cipher)
|
||||
assert.Nil(t, err)
|
||||
|
||||
fmt.Println("Cipher string:", cipherString)
|
||||
plain1, err := f.Decrypt(T, cipher)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, plain0, plain1)
|
||||
plainString1, err := f.Decode(plain1)
|
||||
assert.Nil(t, err)
|
||||
|
||||
fmt.Println("Decrypt string:", plainString1)
|
||||
assert.Equal(t, plainString0, plainString1)
|
||||
}
|
||||
|
||||
// BenchmarkFF1-10 129781 8683 ns/op 4256 B/op 154 allocs/op
|
||||
// BenchmarkFF1-10 325104 3694 ns/op 2808 B/op 99 allocs/op
|
||||
func BenchmarkFF1(b *testing.B) {
|
||||
key := grand.GetRandom(16)
|
||||
block, _ := sm4.NewCipher(key)
|
||||
T := grand.GetRandom(16)
|
||||
f := NewFF1(block, Printable)
|
||||
|
||||
plainString0 := "hello world"
|
||||
plain0, _ := f.Encode(plainString0)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = f.Encrypt(T, plain0)
|
||||
}
|
||||
}
|
||||
|
||||
// // 密文长度 加密速率(MBps)
|
||||
// // 32 2.55
|
||||
// // 64 3.99
|
||||
// // 128 3.58
|
||||
// // 256 3.82
|
||||
// // 512 3.65
|
||||
// // 1024 3.15
|
||||
// // 2048 2.38
|
||||
// // 4096 1.58
|
||||
// // 8192 0.94
|
||||
func TestSpeed(t *testing.T) {
|
||||
key := grand.GetRandom(16)
|
||||
block, _ := sm4.NewCipher(key)
|
||||
T := grand.GetRandom(16)
|
||||
f := NewFF1(block, Printable)
|
||||
|
||||
fmt.Println("密文长度 加密速率(MBps)")
|
||||
for plainLen, cnt := 32, 10000; plainLen < 10000; plainLen, cnt = plainLen*2, cnt/2 {
|
||||
b := make([]byte, plainLen)
|
||||
for i := range b {
|
||||
b[i] = byte(rand.Uint32()%26 + 'a')
|
||||
}
|
||||
plain := string(b)
|
||||
|
||||
start := time.Now()
|
||||
for i := 0; i < cnt; i++ {
|
||||
n, _ := f.Encode(plain)
|
||||
_, _ = f.Encrypt(T, n)
|
||||
|
||||
}
|
||||
end := time.Now()
|
||||
elapsed := end.Sub(start)
|
||||
fmt.Printf("%4d %.2f\n", plainLen, float64(len(plain)*cnt)/(1024*1024*elapsed.Seconds()))
|
||||
}
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
package fpe
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
type Radix struct {
|
||||
r int
|
||||
|
||||
e int // the maximum number such that r^e is a uint64
|
||||
|
||||
rBig *big.Int // radix as big
|
||||
|
||||
reBig *big.Int // radix^e as big.Int, the same as rPowers[-1]
|
||||
|
||||
rPowers []big.Int // [r, r^2, ..., r^e]
|
||||
}
|
||||
|
||||
func NewRadix(r int) *Radix {
|
||||
radix := &Radix{}
|
||||
radix.Set(r)
|
||||
return radix
|
||||
}
|
||||
|
||||
func (r *Radix) Set(v int) {
|
||||
if v < 2 || v >= math.MaxUint16 {
|
||||
panic("radix overflow")
|
||||
}
|
||||
r.r = v
|
||||
r.e = 64 / bits.Len32(uint32(v))
|
||||
r.rPowers = make([]big.Int, r.e)
|
||||
r.rPowers[0].SetUint64(uint64(v))
|
||||
for i, vi := 1, uint64(v); i < r.e; i++ {
|
||||
vi *= uint64(v)
|
||||
r.rPowers[i].SetUint64(vi)
|
||||
}
|
||||
r.rBig = &r.rPowers[0]
|
||||
r.reBig = &r.rPowers[r.e-1]
|
||||
}
|
||||
|
||||
func (r *Radix) Radix() int {
|
||||
return r.r
|
||||
}
|
||||
|
||||
func (r *Radix) Num(X []Char) *big.Int {
|
||||
if false {
|
||||
radix := big.NewInt(int64(r.r))
|
||||
n := new(big.Int)
|
||||
for _, d := range X {
|
||||
n.Mul(n, radix)
|
||||
n.Add(n, big.NewInt(int64(d)))
|
||||
}
|
||||
return n
|
||||
} else {
|
||||
radix := uint64(r.r)
|
||||
l := len(X) % r.e
|
||||
|
||||
tail := uint64(0)
|
||||
for i := 0; i < l; i++ {
|
||||
tail *= uint64(radix)
|
||||
tail += uint64(X[i])
|
||||
}
|
||||
|
||||
n := new(big.Int).SetUint64(tail)
|
||||
for i := l; i < len(X); i += r.e {
|
||||
d := uint64(0)
|
||||
for j := 0; j < r.e; j++ {
|
||||
d = d*uint64(radix) + uint64(X[i+j])
|
||||
}
|
||||
|
||||
n.Mul(n, r.reBig)
|
||||
n.Add(n, new(big.Int).SetUint64(d))
|
||||
}
|
||||
return n
|
||||
}
|
||||
}
|
||||
|
||||
// x should < radix^(lenX)
|
||||
func (r *Radix) Str(X []Numeral, x *big.Int) {
|
||||
if false {
|
||||
n := len(X)
|
||||
radix := big.NewInt(int64(r.r))
|
||||
d := new(big.Int)
|
||||
xx := new(big.Int).Set(x) // make a copy
|
||||
for i := 0; i < n; i++ {
|
||||
xx, d = xx.DivMod(xx, radix, d)
|
||||
X[n-i-1] = Numeral(d.Int64())
|
||||
}
|
||||
// if xx is not zero, then the input x must too big
|
||||
if xx.Sign() != 0 {
|
||||
panic("x should less then radix^m")
|
||||
}
|
||||
} else {
|
||||
xx := new(big.Int).Set(x) // make a copy
|
||||
lx := len(X)
|
||||
radix := uint64(r.r)
|
||||
d := new(big.Int)
|
||||
|
||||
// the tail part
|
||||
m := lx % r.e
|
||||
if m > 0 {
|
||||
xx, d = xx.DivMod(xx, &r.rPowers[m-1], d)
|
||||
n := d.Uint64()
|
||||
for i := lx - 1; i >= lx-m; i-- {
|
||||
X[i] = Numeral(n % radix)
|
||||
n /= radix
|
||||
}
|
||||
}
|
||||
|
||||
for i := lx - m; i > 0; i -= r.e {
|
||||
xx, d = xx.DivMod(xx, r.reBig, d)
|
||||
n := d.Uint64()
|
||||
for j := i - 1; j >= i-r.e; j-- {
|
||||
X[j] = uint16(n % radix)
|
||||
n /= radix
|
||||
}
|
||||
}
|
||||
// if xx is not zero, then the input x must too big
|
||||
if xx.Sign() != 0 {
|
||||
panic("x should less then radix^m")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user