I'm using gosec to check if my code has any security flaws. But it is reporting the use of math/rand (Use of weak random number generator (math/rand instead of crypto/rand)) pkg in this code:
package main
import (
"fmt"
"math/rand"
)
func main() {
a := rand.Float64()
fmt.Println(a)
}
The problem is: crypto/rand does not have the option to get a random float: https://pkg.go.dev/crypto/rand
How can I do that?
Related
This question already has answers here:
Why this repeats the same random number?
(3 answers)
Closed 1 year ago.
I have a code:
package main
import ("fmt"
"math/rand"
"strconv"
)
func main() {
fmt.Println(strconv.Itoa(rand.Int()))
fmt.Println(strconv.Itoa(rand.Int()))
fmt.Println(strconv.Itoa(rand.Int()))
fmt.Println(strconv.Itoa(rand.Int()))
fmt.Println(strconv.Itoa(rand.Int()))
fmt.Println(strconv.Itoa(rand.Int()))
fmt.Println(strconv.Itoa(rand.Int()))
fmt.Println(strconv.Itoa(rand.Int()))
fmt.Println(strconv.Itoa(rand.Int()))
fmt.Println(strconv.Itoa(rand.Int()))
fmt.Println(strconv.Itoa(rand.Int()))
fmt.Println(strconv.Itoa(rand.Int()))
fmt.Println(strconv.Itoa(rand.Int()))
fmt.Println(strconv.Itoa(rand.Int()))
}
When I run it (go run code.go), I get every time same values:
5577006791947779410
8674665223082153551
6129484611666145821
4037200794235010051
3916589616287113937
6334824724549167320
605394647632969758
1443635317331776148
894385949183117216
2775422040480279449
4751997750760398084
7504504064263669287
1976235410884491574
3510942875414458836
Second try:
package main
import ("fmt"
"math/rand"
"strconv"
)
func main() {
fmt.Println(strconv.Itoa(rand.Intn(100)))
fmt.Println(strconv.Itoa(rand.Intn(100)))
fmt.Println(strconv.Itoa(rand.Intn(100)))
fmt.Println(strconv.Itoa(rand.Intn(100)))
fmt.Println(strconv.Itoa(rand.Intn(100)))
fmt.Println(strconv.Itoa(rand.Intn(100)))
fmt.Println(strconv.Itoa(rand.Intn(100)))
}
Same behaviour. Every time's
81
87
47
59
81
18
25
Is this a joke? Why it happens?
Here is no description about non-random same result.
I can see only pseudo-random term without explanation what that means.
Looks like even bash is more logical and stable...
This is a C way
You need to seed it. It says right in the docs
Random numbers are generated by a Source. Top-level functions, such as Float64 and Int, use a default shared Source that produces a deterministic sequence of values each time a program is run. Use the Seed function to initialize the default Source if different behavior is required for each run.
Generally
rand.Seed(time.Now().UnixNano())
You don't appear to have called Seed for math/rand before using the generator.
If Seed is not called, the generator behaves as if seeded by Seed(1). That is not a joke - actually for a PRNG to be deterministic and repeatable is desirable in many cases.
For different numbers, seed with a different value, such as time.Now().UnixNano().
Addition to the other answers, good explanation found about this in medium article go-how-are-random-numbers-generated
Go implements two packages to generate random numbers:
a pseudo-random number generator (PRNG) in the package math/rand cryptographic
pseudorandom number generator (CPRNG), implemented in crypto/rand
If both generate random numbers, your choice will be based on a
tradeoff between genuinely random numbers and performance.
As other answers explain, math/rand packages populate random numbers reading from a source. So if you need random numbers, you need to set random seed calling rand.Seed()
In other case you can use crypto/rand package to generate random numbers. It generates random numbers which can not be deterministic. But performance is bit lower than math/rand package.
I have added sample code below for that. you can run and see different out put here.
package main
import (
"crypto/rand"
"math/big"
)
func main() {
for i := 0; i < 4; i++ {
n, _ := rand.Int(rand.Reader, big.NewInt(100))
println(n.Int64())
}
}
The math library doesn't seem to have a Min function for float64. How would I get the smallest non-zero float64?
as #oliver-charlesworth says:
package main
import (
"fmt"
"math"
)
func main() {
fmt.Printf("%.12G", math.SmallestNonzeroFloat64)
}
https://play.golang.org/p/kRuIhalODGa
Output:
4.94065645841E-324
I'm new to Go and not sure why it prints the same number for rand.Intn(n int) int for every run:
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println(rand.Intn(10))
}
The docs says :
Intn returns, as an int, a non-negative pseudo-random number in [0,n) from the default Source. It panics if n <= 0.
And how do I properly seed the random number generation?
By calling the rand.Seed() function, passing it a (random) seed (typically the current unix timestamp). Quoting from math/rand package doc:
Top-level functions, such as Float64 and Int, use a default shared Source that produces a deterministic sequence of values each time a program is run. Use the Seed function to initialize the default Source if different behavior is required for each run.
Example:
rand.Seed(time.Now().UnixNano())
If rand.Seed() is not called, the generator behaves as if seeded by 1:
Seed uses the provided seed value to initialize the default Source to a deterministic state. If Seed is not called, the generator behaves as if seeded by Seed(1).
package main
import
(
"fmt"
"math/rand"
"time"
)
func randomGen(min, max int) int {
rand.Seed(time.Now().Unix())
return rand.Intn(max - min) + min
}
func main() {
randNum := randomGen(1, 10)
fmt.Println(randNum)
}
Under the package, math/rand, you can find a type Rand.
func New(src Source) *Rand - New returns a new Rand that uses random
values from src to generate other random values.
It actually needs a seed to generate it.
step 1: create a seed as a source using new Source.
time.Now().UnixNano() is used for the accuracy.
step 2: create a
type Rand from the seed
step 3: generate a random number.
Example:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
source := rand.NewSource(time.Now().UnixNano())
r := rand.New(source)
fmt.Println(r.Intn(100))
}
This is the code I'm working with:
package main
import "fmt"
import "math/rand"
func main() {
code := rand.Intn(900000)
fmt.Println(code)
}
It always returns 698081. I don't understand, what the is problem?
https://play.golang.org/p/XisNbqCZls
Edit:
I tried rand.Seed
package main
import "fmt"
import "time"
import "math/rand"
func main() {
rand.Seed(time.Now().UnixNano())
code := rand.Intn(900000)
fmt.Println(code)
}
There is no change. Now it always returns 452000
https://play.golang.org/p/E_Wfm5tOdH
https://play.golang.org/p/aVWIN1Eb84
A couple of reasons why you'll see the same result in the playground
Golang playground will cache the results
The time in the playground always starts at the same time to make the playground deterministic.
Last but not least, the rand package default seed is 1 which will make the result deterministic. If you place a rand.Seed(time.Now().UnixNano()) you'll receive different results at each execution. Note that this won't work on the playground for the second reason above.
I'm going through the Golang tutorial, and I am on this part
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println("My favorite number is", rand.Seed)
}
This returns My favorite number is 0xb1c20
I have been reading on https://golang.org/pkg/math/rand/#Seed but I'm still a bit confused as to how have it instead of show the hex show a string
math/rand.Seed is a function; you are printing the function's location in memory. You probably meant to do something like the following:
package main
import (
"fmt"
"math/rand"
)
func main() {
rand.Seed(234) // replace with your seed value, or set the seed based off
// of the current time
fmt.Println("My favorite number is", rand.Int())
}