将big.Int的最后8位放入uint8

I'm trying to write a password generator. It requires that characters be in ASCII representation, but I'm trying to use crypto/rand. This provides numbers in big.Int format, though, and I need to convert the relevant lower 8 bits to a form usable in a string. I've tried converting from big.Int to uint8 with no luck so far.

Is there a good and easy method to do this? I have seen answers involving using encoding/binary to convert from int64 to [8]uint8, but those seem needlessly complex for my purpose. Any guidance at all would be appreciated :).

If you want to get bytes out of crypto/rand, I'd skip the use of big.Int and rand.Int() entirely and use either rand.Read() or rand.Reader:

package main

import (
    "crypto/rand"
    "fmt"
    "io"
)

// If you want just a byte at a time ...
// (you could change 'byte' to int8 if you prefer)    
func secureRandomByte() byte {
    data := make([]byte, 1)
    if _, err := rand.Read(data); err != nil {
        // handle error
        panic(err)
    }
    return data[0]
}

// If you want to read multiple bytes at a time ...
func genPassword(len int) (string, error) {
    data := make([]byte, len)
    if _, err := io.ReadFull(rand.Reader, data); err != nil {
        // handle error
        return "", err
    }
    for i := range data {
        // XXX quick munge into something printable
        data[i] &= 0x3F
        data[i] += 0x20
    }
    return string(data), nil
}

func main() {
    b := secureRandomByte()
    fmt.Printf("%T = %v
", b, b)
    fmt.Println(genPassword(16))
}
package main

import (
        "fmt"
        "math/big"
)

func main() {
        mpInt := big.NewInt(0x123456789abcdef0)
        b := byte(mpInt.Int64())
        fmt.Printf("%02x", b)
}

f0

In action: http://play.golang.org/p/92PbLdiVsP


EDIT: Evan Shaw correctly points out in a comment bellow that the above code is actually incorrect for big Ints outside of int64 limits. Instead of pulling it from big.Bytes (which makes a copy of all of the bits representing a big.Int IIRC) it's probably more performant to use big.And:


package main

import (
        "fmt"
        "log"
        "math/big"
)

func lsB(n *big.Int) byte {
        var m big.Int
        return byte(m.And(m.SetInt64(255), n).Int64())
}

func main() {
        var mpInt big.Int
        if _, ok := mpInt.SetString("0x123456789abcdef012342", 0); !ok {
                log.Fatal()
        }

        fmt.Printf("%02x", lsB(&mpInt))
}

Playground: http://play.golang.org/p/pgkGEFgb8-