我正在从多个字符串计算sha256。我以特定方式将它们转换为字节片,并将它们全部附加在一起,然后使用内置库计算哈希。但是,根据是否在计算sha256之前打印出切片,我会获得不同的结果。在操场上测试时,我无法复制它。
可以看到经过测试的代码,并可以在https://play.golang.org/p/z8XKx-p9huG上运行,在两种情况下,它实际上都可以提供相同的结果。
func getHash(input1 string, input2hex string, input3hex string, input4 string) (string, error) { input1bytes := []byte(input1) firstHalfinput1Bytes := input1bytes[:8] secondHalfinput1Bytes := input1bytes[8:16] input4Bytes := []byte(input4) input3Bytes, err := hex.DecodeString(input3hex) if err != nil { fmt.Println("err " + err.Error()) } input2Bytes, err := hex.DecodeString(input2hex) if err != nil { fmt.Println("err " + err.Error()) } fullHashInputBytes := append(firstHalfinput1Bytes, input2Bytes...) // THIS IS THE OPTIONAL PRINT WHICH CHANGES OUTPUT LOCALLY: fmt.Println("fullHashInputBytes", fullHashInputBytes) fullHashInputBytes = append(fullHashInputBytes, secondHalfinput1Bytes...) fullHashInputBytes = append(fullHashInputBytes, input3Bytes...) fullHashInputBytes = append(fullHashInputBytes, input4Bytes...) sha256 := sha256.Sum256(fullHashInputBytes) for i := 0; i < 8; i++ { sha256[i+16] ^= sha256[i+24] } hash := hex.EncodeToString(sha256[:24]) fmt.Println("hash", hash) return hash, nil }
操场上的日志是
Hello, playground fullHashInputBytes [84 72 73 83 73 83 78 79 30 0 22 121 57 203 102 148 210 196 34 172 210 8 160 7] hash 0161d9de8dd815ca9f4e1c7bb8684562542cc24b1026321c hash 0161d9de8dd815ca9f4e1c7bb8684562542cc24b1026321c
但是如果我在本地运行完全相同的代码(只需将其复制粘贴到main.go中,然后执行go run main.goor go build .和和./test),我会得到
go run main.go
go build .
./test
Hello, playground fullHashInputBytes [84 72 73 83 73 83 78 79 30 0 22 121 57 203 102 148 210 196 34 172 210 8 160 7] hash 0161d9de8dd815ca9f4e1c7bb8684562542cc24b1026321c hash d2de4ffb4e8790b8fd1ceeba726436fd97875a5740c27b47
我使用的是go版本,1.13.4但与存在相同的问题1.10.4。在本地计算机上以及在将其部署到服务器时,我也会遇到相同的问题。
1.13.4
1.10.4
这是因为您fullHashInputBytes通过添加到firstHalfinput1Bytesfirst 来创建:
fullHashInputBytes
firstHalfinput1Bytes
fullHashInputBytes := append(firstHalfinput1Bytes, input2Bytes...)
这是其中的一部分input1bytes:
input1bytes
firstHalfinput1Bytes := input1bytes[:8]
因此,第一个附录可能会覆盖input1bytes索引高于7 的at的内容,实际上是以下内容secondHalfinput1Bytes:
secondHalfinput1Bytes
secondHalfinput1Bytes := input1bytes[8:16]
因此,稍后还要添加secondHalfinput1Bytes到时fullHashInputBytes,可能最终会添加不同的内容。
这很可能不是您想要的。
如果您做到“干净”:
var fullHashInputBytes []byte fullHashInputBytes = append(fullHashInputBytes, firstHalfinput1Bytes...) fullHashInputBytes = append(fullHashInputBytes, input2Bytes...) // OPTIONAL print doesn't change anything: fmt.Println("fullHashInputBytes", fullHashInputBytes) // ...rest of your appends...
如果在本地或Go Playground上运行,则输出将相同。
您的第一个追加input1bytes是否被覆盖取决于该追加是否可以“就地”执行而不必分配新的后备数组,这取决于firstHalfinput1Bytes“”从input1bytes以下继承的容量:
input1bytes := []byte(input1) fmt.Println(cap(input1bytes))
该转换 []byte(input)只保证拥有的字节input1,但该规范并没有规定所产生的切片的容量有多大应该的。它可能取决于平台/体系结构。在Go Playground上,上述转换导致capacity = 16我在本地amd64建筑上得到capacity = 32。
[]byte(input)
input1
capacity = 16
amd64
capacity = 32
最后一件:[]byte(input)转换结果切片所使用的容量可能取决于您对结果切片的处理方式。如果将其传递给编译器,则编译器可能会决定使用较低的容量,fmt.Println()因为这表明片可能会逃逸。再次,由编译器做出的决定是您无法控制的。
fmt.Println()
不要依靠这种东西,不要编写依赖于转换结果片的容量的代码。以“干净”的方式进行:不要追加到firstHalfinput1Bytes新的切片上。