// 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 Ed25519.
/** 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]

See Ed25519ConstantsGenerator.

/** * 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); } } }