blob: 99bea9ef7fbb2cb72e3588904b0f2b766702a202 [file] [log] [blame]
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package com.google.crypto.tink.subtle;
import java.math.BigInteger;
/** Constants used in {@link Ed25519}. */
final class Ed25519Constants {
// d = -121665 / 121666 mod 2^255-19
static final long[] D;
// 2d
static final long[] D2;
// 2^((p-1)/4) mod p where p = 2^255-19
static final long[] SQRTM1;
/**
* Base point for the Edwards twisted curve = (x, 4/5) and its exponentiations. B_TABLE[i][j] =
* (j+1)*256^i*B for i in [0, 32) and j in [0, 8). Base point B = B_TABLE[0][0]
*
* <p>See {@link Ed25519ConstantsGenerator}.
*/
static final Ed25519.CachedXYT[][] B_TABLE;
static final Ed25519.CachedXYT[] B2;
private static final BigInteger P_BI =
BigInteger.valueOf(2).pow(255).subtract(BigInteger.valueOf(19));
private static final BigInteger D_BI =
BigInteger.valueOf(-121665).multiply(BigInteger.valueOf(121666).modInverse(P_BI)).mod(P_BI);
private static final BigInteger D2_BI = BigInteger.valueOf(2).multiply(D_BI).mod(P_BI);
private static final BigInteger SQRTM1_BI =
BigInteger.valueOf(2).modPow(P_BI.subtract(BigInteger.ONE).divide(BigInteger.valueOf(4)), P_BI);
private static class Point {
private BigInteger x;
private BigInteger y;
}
private static BigInteger recoverX(BigInteger y) {
// x^2 = (y^2 - 1) / (d * y^2 + 1) mod 2^255-19
BigInteger xx =
y.pow(2)
.subtract(BigInteger.ONE)
.multiply(D_BI.multiply(y.pow(2)).add(BigInteger.ONE).modInverse(P_BI));
BigInteger x = xx.modPow(P_BI.add(BigInteger.valueOf(3)).divide(BigInteger.valueOf(8)), P_BI);
if (!x.pow(2).subtract(xx).mod(P_BI).equals(BigInteger.ZERO)) {
x = x.multiply(SQRTM1_BI).mod(P_BI);
}
if (x.testBit(0)) {
x = P_BI.subtract(x);
}
return x;
}
private static Point edwards(Point a, Point b) {
Point o = new Point();
BigInteger xxyy = D_BI.multiply(a.x.multiply(b.x).multiply(a.y).multiply(b.y)).mod(P_BI);
o.x =
(a.x.multiply(b.y).add(b.x.multiply(a.y)))
.multiply(BigInteger.ONE.add(xxyy).modInverse(P_BI))
.mod(P_BI);
o.y =
(a.y.multiply(b.y).add(a.x.multiply(b.x)))
.multiply(BigInteger.ONE.subtract(xxyy).modInverse(P_BI))
.mod(P_BI);
return o;
}
private static byte[] toLittleEndian(BigInteger n) {
byte[] b = new byte[32];
byte[] nBytes = n.toByteArray();
System.arraycopy(nBytes, 0, b, 32 - nBytes.length, nBytes.length);
for (int i = 0; i < b.length / 2; i++) {
byte t = b[i];
b[i] = b[b.length - i - 1];
b[b.length - i - 1] = t;
}
return b;
}
private static Ed25519.CachedXYT getCachedXYT(Point p) {
return new Ed25519.CachedXYT(
Field25519.expand(toLittleEndian(p.y.add(p.x).mod(P_BI))),
Field25519.expand(toLittleEndian(p.y.subtract(p.x).mod(P_BI))),
Field25519.expand(toLittleEndian(D2_BI.multiply(p.x).multiply(p.y).mod(P_BI))));
}
static {
Point b = new Point();
b.y = BigInteger.valueOf(4).multiply(BigInteger.valueOf(5).modInverse(P_BI)).mod(P_BI);
b.x = recoverX(b.y);
D = Field25519.expand(toLittleEndian(D_BI));
D2 = Field25519.expand(toLittleEndian(D2_BI));
SQRTM1 = Field25519.expand(toLittleEndian(SQRTM1_BI));
Point bi = b;
B_TABLE = new Ed25519.CachedXYT[32][8];
for (int i = 0; i < 32; i++) {
Point bij = bi;
for (int j = 0; j < 8; j++) {
B_TABLE[i][j] = getCachedXYT(bij);
bij = edwards(bij, bi);
}
for (int j = 0; j < 8; j++) {
bi = edwards(bi, bi);
}
}
bi = b;
Point b2 = edwards(b, b);
B2 = new Ed25519.CachedXYT[8];
for (int i = 0; i < 8; i++) {
B2[i] = getCachedXYT(bi);
bi = edwards(bi, b2);
}
}
}