我正在尝试实现一个 PNRG (xorshift128+),它将在客户端 (Go) 和服务器 (Node) 上生成时进行匹配。
这是JS代码:
function xor128(aT, Gj) {
var SM = aT;
var tn = Gj;
return function() {
var Fv = SM;
Fv ^= Fv << 23;
Fv ^= Fv >> 17;
var RW = tn;
Fv ^= RW;
SM = RW;
Fv ^= RW >> 26;
tn = Fv;
return (SM + tn) % 4294967296;
};
}
buildKeyArray(section, max, seed) {
const randomNumberGenerator = xor128(section, seed);
const outputArray = [];
for (let index = 0; index < max; index++) {
const a = randomNumberGenerator()
outputArray.push(a & 255);
}
return outputArray;
}
这是我尝试实现的客户端(Go)代码:
type Xor128Generator struct {
SM uint32
tn uint32
}
func NewXor128Generator(aT, Gj uint32) *Xor128Generator {
return &Xor128Generator{SM: aT, tn: Gj}
}
func (x *Xor128Generator) Generate() uint32 {
Fv := x.SM
Fv ^= Fv << 23
Fv &= 0xFFFFFFFF // 32-bit wrap around
Fv ^= Fv >> 17
Fv &= 0xFFFFFFFF // 32-bit wrap around
RW := x.tn
Fv ^= RW
Fv &= 0xFFFFFFFF // 32-bit wrap around
x.SM = RW
Fv ^= RW >> 26
Fv &= 0xFFFFFFFF // 32-bit wrap around
x.tn = Fv
result := uint32(x.SM) + uint32(x.tn)
return uint32(result)
}
func (x *XorEncoder) buildKeyArray() []byte {
gen := NewXor128Generator(x.XorSection, x.Xor128Seed)
outputArray := make([]byte, x.Xor128Max)
for index := 0; index < x.Xor128Max; index++ {
var a = gen.Generate()
outputArray[index] = byte(a & 255)
}
return outputArray
}
问题是我的 Go 实现从 xor128 代码生成不同的数字。我理解这是因为 Node 使用 32 位整数,而 Go 使用 64 位整数。但是如何修复 Go 代码,使其与 JS 代码保持一致,并在两个平台上生成相同的数字。
需要明确的是,JS 代码正在生成正确的值,并且 Go 代码需要匹配。
您没有提供任何示例值,代码可能存在多个问题,但我会指出我发现的第一个问题。
考虑 javascript:
Fv ^= Fv << 23;
Fv ^= Fv >> 17;
如果
Fv << 23
的结果导致高位被设置,则Fv >> 17
将传播符号;在代码中可能更容易看到这一点(>>>
是一个无符号右移):
function dec2bin(dec) {
return (dec >>> 0).toString(2);
}
let Fv = 0b11000000000000000000000000000000
console.log(Fv >> 23, dec2bin(Fv >> 23));
console.log(Fv >>> 23, dec2bin(Fv >>> 23));
输出为:
-128 11111111111111111111111110000000
384 110000000
当您现在使用
^=
中的结果时,您可以看到符号传播将如何产生影响。
在你的 Go 代码中,你自始至终都在使用
uint32
;由于这是无符号的,移位运算不会传播符号,这将导致差异。让我们比较一下有符号整数和无符号整数的使用:
package main
import "fmt"
type Xor128Generator[T interface{ int32 | uint32 }] struct {
SM T
tn T
}
func (x *Xor128Generator[T]) Generate() T {
Fv := x.SM
Fv ^= Fv << 23
Fv ^= Fv >> 17
RW := x.tn
Fv ^= RW
x.SM = RW
Fv ^= RW >> 26
x.tn = Fv
return x.SM + x.tn
}
func main() {
u := Xor128Generator[uint32]{SM: 65535, tn: 1}
fmt.Println(u.Generate()) // output: 4286611519
i := Xor128Generator[int32]{SM: 65535, tn: 1}
fmt.Println(i.Generate()) // output: 8323135
}
第二个结果 (
int32
) 与您的 Javascript 输出相匹配(我运行了 console.log(xor128(65535,1)());
)。