I've discovered for myself that java's BigInteger is very slow, so I'm trying to weakly optimize this java implementation of ed25519 which I will fork and post if successful by substituting BigInteger with jscience's LargeInteger.

I'm almost done converting all of the BigIntegers to LargeIntegers, but I still need an equivalent to BigInteger's and, and I need to know how long some byte[] variables should be and their offsets to use valueOf with byte[]s.

I could keep some of the existing code and merely convert BigIntegers to LargeIntegers, but I'd prefer to fully replace BigInteger.

"length - the maximum number of bytes to read." sounds like I should use .length of the byte[] to be converted. Is that correct? If not, what should be used?

"offset - the offset at which to start reading the bytes." sounds like I should use 0. Is that correct? If not, what should be used?

I'm 100% new to binary and cryptography.


1 Answer 1


Almost every Java .valueOf(byte[] s, int offset, int length) has the same meaning:

  • s is the array to read from.
  • offset is the location in the array to start reading from (inclusive).
  • length is the number of bytes to try and read - "try" because the array may not be long enough to have that many bytes from offset.

Remembering that Java arrays are zero-indexed, .valueOf(z, offset, length) will read from every byte from s[offset] to s[offset+length-1]. However, if offset+length > s.length, then every byte from s[offset] to s[s.length] will be read.

As an example, if we have byte[] s = new byte[] {10, 20, 30, 15, 4}, then:

  • LargeInteger.valueOf(s, 0, 5) will use all five bytes.
  • LargeInteger.valueOf(s, 1, 3) will use bytes {20, 30, 15}.
  • LargeInteger.valueOf(s, 3, 7) will use bytes {15, 4}.

In Ed25519, the length and offset you use will depend on what part of the byte[] you need to access. For example, initially you take a seed k and hash it to get h = H(k), which you then split into a LHS and RHS. You could convert the LHS and RHS independently into LargeIntegers with LargeInteger.valueOf(h, 0, b/8) for the LHS, and LargeInteger.valueOf(h, b/8, b/4-b/8) for the RHS.

So the end answer is, in most cases yes, you will use offset = 0 and length = s.length. And it looks like you can directly replace BigInteger.valueOf() with LargeInteger.valueOf().