Hello, my code produces a big.Int number as follows:
package main
import (
"fmt"
"crypto/sha256"
"math/big"
"golang.org/x/crypto/blake2b"
)
func main() {
test := "hello"
h := sha256.New()
s := fmt.Sprintf("%v", test)
sum := h.Sum([]byte(s))
hash := blake2b.Sum256(sum)
zz := new(big.Int)
zz.SetBytes(hash[:])
fmt.Println(zz)
}
I need to increment zz by one. Can someone suggest on how to do this most efficiently? I was thinking the most efficient way is to XOR the least significant bit in zz but I’m not sure how to do it in Go.
Thanks
Maybe it’s faster to use byte operations directly instead of bigInt.
The problem with not and neg is that they need to modify all bytes. While an increment may need to modify just a few bytes. Not sure why the OP need a bigInt.
Here is an increment applied on the byte slice:
i := len(hash)-1
for i >= 0 {
hash[i]++
if hash[i] != 0 {
break
}
i--
}
if i < 0 {
// overflows
}
// assign the resulting hash to a bigInt if needed.
It is very unlikely that the increment overflows because it can only occur when all bits are 1 in the initial number.
package main
import (
"fmt"
"math/big"
"strings"
)
func methodC(shasum string) string {
if shasum == "" {
return shasum
}
shasum = strings.ToLower(shasum)
s := []byte(shasum)
length := len(s)
index := 0
for i := 0; i < length; i++ {
index = length - 1 - i
x := &s[index : index+1][0]
// if char is 0xf, carry forward and continue
if *x == 102 {
*x = 48 // set to 0x0
continue
}
// if char is 0x9, increment to 0xa
if *x == 57 {
*x = 97 // set to 0xa
break
}
// char is within incremental range
*x += 1
break
}
return string(s)
}
func methodB(x *big.Int) {
x.Add(x, big.NewInt(1))
}
func methodA(x *big.Int) {
x.Not(x)
x.Neg(x)
}
func main() {
shasum := "8c32eeb180c961c5015ed69a1579e6ad98479c9509e5c524f096cdda5e1cf730"
zz := new(big.Int)
hash := []byte(shasum)
zz.SetBytes(hash[:])
fmt.Printf("BEFORE method A: %s\n", zz.String())
methodA(zz)
fmt.Printf("AFTER method A : %s\n", zz.String())
hash = []byte(shasum)
zz.SetBytes(hash[:])
fmt.Printf("BEFORE method B: %s\n", zz.String())
methodB(zz)
fmt.Printf("AFTER method B : %s\n", zz.String())
hash = []byte(shasum)
zz.SetBytes(hash[:])
fmt.Printf("BEFORE method C: %s\n", zz.String())
hash = []byte(methodC(shasum))
zz.SetBytes(hash[:])
fmt.Printf("AFTER method C: %s\n", zz.String())
}
// Output:
// BEFORE method A: 2953253003934257607559289743915026435532263105800530010414720734192461358425063874354789587599756988242021836199015574276107182587110732205759776721154864
// AFTER method A : 2953253003934257607559289743915026435532263105800530010414720734192461358425063874354789587599756988242021836199015574276107182587110732205759776721154865
// BEFORE method B: 2953253003934257607559289743915026435532263105800530010414720734192461358425063874354789587599756988242021836199015574276107182587110732205759776721154864
// AFTER method B : 2953253003934257607559289743915026435532263105800530010414720734192461358425063874354789587599756988242021836199015574276107182587110732205759776721154865
// BEFORE method C: 2953253003934257607559289743915026435532263105800530010414720734192461358425063874354789587599756988242021836199015574276107182587110732205759776721154864
// AFTER method C: 2953253003934257607559289743915026435532263105800530010414720734192461358425063874354789587599756988242021836199015574276107182587110732205759776721154865
Benchmark Code
package main
import (
"math/big"
"testing"
)
const (
shasum = "8c32eeb180c961c5015ed69a1579e6ad98479c9509e5c524f096cdda5e1cf730"
)
func BenchmarkMethodA(b *testing.B) {
tgt := new(big.Int)
for i := 0; i < b.N; i++ {
hash := []byte(shasum)
tgt.SetBytes(hash[:])
methodA(tgt)
}
}
func BenchmarkMethodB(b *testing.B) {
tgt := new(big.Int)
for i := 0; i < b.N; i++ {
hash := []byte(shasum)
tgt.SetBytes(hash[:])
methodB(tgt)
}
}
func BenchmarkMethodC(b *testing.B) {
tgt := new(big.Int)
for i := 0; i < b.N; i++ {
hash := []byte(methodC(shasum))
tgt.SetBytes(hash[:])
}
}
Also, I would avoid it since we’re re-inventing arithmetic stuff and it’s too complex. I tested the edge value 0x3f, the big.Int parsing does not agree although hex values agree to each other.
shasum := "8c32eeb180c961c5015ed69a1579e6ad98479c9509e5c524f096cdda5e1cf73f"
BEFORE method C: 2953253003934257607559289743915026435532263105800530010414720734192461358425063874354789587599756988242021836199015574276107182587110732205759776721154918
DEBUG BEFORE: 8c32eeb180c961c5015ed69a1579e6ad98479c9509e5c524f096cdda5e1cf73f
DEBUG AFTER : 8c32eeb180c961c5015ed69a1579e6ad98479c9509e5c524f096cdda5e1cf740
AFTER method C: 2953253003934257607559289743915026435532263105800530010414720734192461358425063874354789587599756988242021836199015574276107182587110732205759776721155120
Disclaimer to any other readers
I’m just experimenting []byte arithmetic operations out of curiosity. Please do not go all out flaming me that I do something paranoid or set some weird rules about math and processor again.
Thank you all for your replies. My goal is indeed to make an even number odd (so if it decrements it by one thats fine). Will try your proposals and come back with my findings
Done. Performance gained significantly. Here’s the new methodC. I opened the capitalized parameter because it needs to know when to switch from 0x9 to 0xA or 0xa if we avoid strings.ToLower(...).
Also, I’m still getting Big.Int inaccuracy after byte manipulations while the hex value is incremented correctly at edge cases. Can someone shed some light?
You might need to re-title the topic (Prefix: retitled - …). All current methods are not masking even/odd numbers, which is your true intention. Give me time to work it out.