Am I understanding how "math/rand" and "crypto/rand" work?

I am generating random codes with Go and they must be secure.

So according to my research I understood the following:

"math/rand"

-You always have to seed to get the randomness otherwise the results will follow the same sequence.
-It does not return errors so it is safe to use in production.
-There are functions that return errors but according to the documentation they will always be nil, which makes me speculate that it simply returns errors to meet the same signatures as “crypto/rand”

"crypto/rand"

-It will generate random values using the native API of the system, if the API fails an error will be returned so it is not safe to use it in production
-No seeding is necessary

Now another question, both versions generate random integers in a safe way? or in other words are they correct?

import (
	crand "crypto/rand"
	"math/big"
	// [...]
)

// [V1]
for key := 1; key <= aim; key++ {
	res, err := crand.Int(crand.Reader, big.NewInt(int64(32)))
	// [...]
}

// [V2]
cNum := big.NewInt(int64(32))
for key := 1; key <= aim; key++ {
	res, err := crand.Int(crand.Reader, cNum)
	// [...]
}

I have seen in many sites the V1 while the V2 I did it myself since to my understanding cNum will always have the same value during all the loop it seems to me a nonsense to calculate in each loop that static value.