Skip to content

math/big: add Int.FillBytes #35833

@FiloSottile

Description

@FiloSottile

When implementing cryptography, what we need is almost always a fixed size buffer representing a value in big endian. What math/big.Int.Bytes provides is a variable size buffer, so all over the place there are snippets of code that do make, Bytes and copy with a len dependent index. I just implemented one the other day for https://golang.org/cl/208484, and just saw one in x/crypto/acme.

I'd be willing to bet that every Bytes invocation in a crypto package is doing something similar. I also learned that random bugs that occur approximately every 256 executions are probably due to missing this step, and I have found such a bug in the wild at least twice.

I propose we solve this at the math/big API level, and add (*math/big.Int).BytesWithSize.

// BytesWithSize returns the absolute value of x as a big-endian
// byte slice of length size. If x doesn't fit in such a buffer,
// BytesWithSize will panic.
func (x *Int) BytesWithSize(size int) []byte {
	b := x.Bytes()
	switch {
	case len(b) > size:
		panic("math/big: value won't fit requested size")
	case len(b) == size:
		return b
	default:
		buf := make([]byte, size)
		copy(buf[size-len(b):], b)
		return buf
	}
}

I don't have a strong opinion on the len(b) > size behavior. Where we use it in crypto packages we always know an upper bound, and if we cross it we might as well panic because something went catastrophically wrong. (And the current code would either panic or silently truncate, which is worse.)

/cc @griesemer @katiehockman

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions