github.com/richardwilkes/toolbox@v1.121.0/xmath/rand/random.go (about) 1 // Copyright (c) 2016-2024 by Richard A. Wilkes. All rights reserved. 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, version 2.0. If a copy of the MPL was not distributed with 5 // this file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 // 7 // This Source Code Form is "Incompatible With Secondary Licenses", as 8 // defined by the Mozilla Public License, version 2.0. 9 10 // Package rand provides a Randomizer based upon the crypto/rand package. 11 package rand 12 13 import ( 14 "crypto/rand" 15 mrnd "math/rand/v2" 16 ) 17 18 var cryptoRandInstance = &cryptoRand{} 19 20 // Randomizer defines a source of random integer values. 21 type Randomizer interface { 22 // Intn returns a non-negative random number from 0 to n-1. If n <= 0, the implementation should return 0. 23 Intn(n int) int 24 } 25 26 // NewCryptoRand returns a Randomizer based on the crypto/rand package. This method returns a shared singleton instance 27 // and does not allocate. 28 func NewCryptoRand() Randomizer { 29 return cryptoRandInstance 30 } 31 32 type cryptoRand struct{} 33 34 func (r *cryptoRand) Intn(n int) int { 35 if n <= 0 { 36 return 0 37 } 38 var buffer [8]byte 39 size := 8 40 n64 := int64(n) 41 for i := 1; i < 8; i++ { 42 if n64 < int64(1)<<uint(i*8) { 43 size = i 44 break 45 } 46 } 47 if _, err := rand.Read(buffer[:size]); err != nil { 48 return mrnd.IntN(n) //nolint:gosec // Yes, it is ok to use a weak prng here 49 } 50 var v int 51 for i := size - 1; i >= 0; i-- { 52 v |= int(buffer[i]) << uint(i*8) 53 } 54 if v < 0 { 55 v = -v 56 } 57 return v % n 58 }