Latest webrev: http://cr.openjdk.java.net/~apetcher/8181594/webrev.02/
Comments inline below.
In addition, I also changed the name of IntegerModuloP_Base to
IntegerModuloP, and IntegerModuloP to ImmutableIntegerModuloP.
On 3/11/2018 12:04 PM, Xuelei Fan wrote:
On 2/26/2018 10:39 AM, Adam Petcher wrote:
On 2/23/2018 12:46 PM, Xuelei Fan wrote:
ArrayUtil.java:
===============
I'm not very sure how widely this utilities will be used in the
future. Looks like only BigIntegerModuloP uses this classes. I may
prefer to define private methods for byte array swap in
BigIntegerModuloP.
It is also used by XDHPublicKeyImpl (in the XDH code review). XDH
public keys are represented as BigInteger, and I use the array
reverse method to convert encoded keys to BigInteger.
If it is not widely used by other classes, please have these methods
in the class where is get called. The sun.security.util is exported
to other modules as well, we may not want to add stuff into this
package unless it is really necessary.
Okay. I put these methods in BigIntegerModuloP and removed the ArrayUtil
class. This array reverse code will be duplicated where it is used by
XDH public keys (in the other code review).
MutableIntegerModuloP.java
==========================
void conditionalSwapWith(MutableIntegerModuloP b, int swap);
As the 'swap' parameter can only be 0 or 1, could it be a boolean
parameter?
I couldn't come up with a way to implement this without branching
when the swap parameter is boolean. See
IntegerPolynomial.conditionalSwap to see how this is implemented in
arithmetic with an int swap argument. If you (or anyone) can think of
a way to do this with boolean, let me know.
I added a sentence to the comment above conditionalSwapWith that
describes why it is an int instead of a boolean.
I did not get the point about the need to avoid branching. Can you
have more details?
The goal is to avoid things like if(secret){...}, in order to prevent
the secrets from leaking into side channels (mostly timing and cache).
The way this method is used by XDH, the swap parameter is a single bit
of the private key. By storing this bit as an integer, and then doing
the swap using only integer arithmetic, we can avoid branching which may
leak the bits of the key.
Except the conditionalSwapWith() method, I did not get the points
why we need a mutable version. Would you please have more
description of this requirement?
The comment above the class definition has this sentence:
"This interface can be used to improve performance and avoid the
allocation of a large number of temporary objects."
Do you need more information than this in the comments? The
performance motivation is so that a.add(b).multiply(c)... can be done
without allocating a new buffer for each operation. For example,
without mutable field elements, an X25519 point multiplication would
allocate around 4,300 temporary arrays totaling 350,000 bytes. If I
remember correctly, switching the X25519 implementation to mutable
field elements reduced the point multiplication time by about half.
I see your point. The benefits is obviously.
OK, why you need the immutable version then? Sounds like the mutable
version interface is sufficient, including performance. If an
immutable version is really needed, we can have the implementation
making the decision. Accordingly, the conditionalSwapWith() can be
defined as optional method, if it is not required to be implemented in
immutable implementation.
It's confusing to me that the immutable and mutable and the base
versions/interfaces mixed together. It would be nice if we can
simplify the interface a little bit.
For internal APIs, sometimes we don't want the same quality level as
public APIs. I think this set of class will be widely used by new EC
curves, ChaCha20/Poly1305, or more in the future. It would be nice if
we could do it good at the beginning.
The mutable version adds the conditional swap as well as mutable
versions of many of the basic operations. The XDH implementation uses
both the mutable and immutable versions. The immutable version allows me
to simplify the client code because I don't have to worry about whether
some value has been modified. For example, the XDH code keeps a
representation of 0, 1, and the constant that defines the curve as
immutable values.
So I prefer to have both. It complicates this API a bit, but it allows
simpler and more robust code in the client of this API.
IntegerModuloP_Base.java
========================
default byte[] addModPowerTwo(IntegerModuloP_Base b, int len)
void addModPowerTwo(IntegerModuloP_Base b, byte[] result);
For the first sign of the method names, I thought it is to calculate
as "(this + b) ^ 2 mod m".
To be precise, it calculates "((this % p) + (b % p)) % 2^m" (where p
is the prime that defines the field, and m is the desired length, in
bits). Note that the addition here is normal integer addition (not
addition in GF(p)).
This operation is not used in XDH, but it is used in Poly1305 to add
the AES encryption of a nonce to a field element. So you can get more
information about this operation by reading the Poly1305 paper/RFC.
I was not meant to say the function of the method. I meant that the
method name is a little bit misleading, not very straightforward to me.
Besides, what's the benefits of the two methods? Could we just use:
this.add(b).asByteArray()
No, because that would calculate "((this + b) mod p) mod 2^m". The
value of (this + b) can be larger than p, so this would not produce
the desired result.
>>
I guess, but not very sure, it is for constant time calculation. If
the function is required, could it be renamed as:
// the result is inside of the size range
IntegerModuloP addModSize(IntegerModuloP_Base b, int size)
Or
// the result is wrapped if outside of the size range
IntegerModuloP addOnWrap(IntegerModuloP_Base b, int size)
and the use may look like:
this.addModSize(b, size).asByteArray()
Any attempt to perform the addition in IntegerModuloP and then pull
out the byte array will not work.
Does it mean if I perform a addition, and cannot get the byte array in
the following step?
that = this.add(b);
byte[] bs = that.asByteArray(); // does not work?
or
byte[] bs = that.asByteArray(length); // does not work?
or
byte[] bs = that.asByteArray(byteArray); // does not work?
This class can only represent field elements, so the sum would be in
the field, which is not what we want.
I did not get the point. If getting an add result, the add is done
(sum in the field). Did you have an example that pulling out the byte
array will not work?
Say we are in the field of integers modulo 269, and the final result of
some computation will be stored in a single byte. In this example, we
discard information when we truncate to the byte array. This may seem
strange, but it is exactly what Poly1305 does. Now say we want to add x
with itself, and x has the value 260.
// x.add(x) has value 251
byte[] result = new byte[1];
x.add(x).asByteArray(result); // result has value 251
x.addModPowerTwo(x, result) // result has value 8
The difference between the two statements above is that the first one
does a reduction mod 269 after the addition (and before converting to a
byte array), while the second one does not. I can't split addModPowerTwo
into two method calls without also adding another type for integers
modulo a possibly-non-prime, and I didn't think it was worth the effort.
I don't have a problem with renaming the method if you think this will
make it more clear. Let me know which name you prefer. The name
addModSize is probably okay, although technically we are reducing mod
2^size, so the name might be slightly misleading. Maybe something a
little less precise like addToSize?