summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-05-10 16:14:17 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2024-05-10 16:14:17 +0000
commit80bd5c441a57372e451f4e661a42b0c8c4716767 (patch)
tree8c736dde0f6155d7625056b1a639dd12ea72e60d
parent95c2700dc12b3b7c8128de3a0472e51297dca74b (diff)
parent7669d1ff48ad30ebabf9555ddf40663180b9cdd9 (diff)
downloadbouncycastle-busytown-mac-infra-release.tar.gz
Merge "Snap for 11819167 from 716439e2b6aae37d9a5285e80764580916a9737f to busytown-mac-infra-release" into busytown-mac-infra-releasebusytown-mac-infra-release
-rw-r--r--Android.bp70
-rw-r--r--README.android11
-rw-r--r--TEST_MAPPING12
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java48
-rw-r--r--bcprov/src/test/java/org/bouncycastle/math/ec/custom/sec/test/SecP256R1FieldTest.java175
-rw-r--r--bcprov/src/test/java/org/bouncycastle/math/ec/custom/sec/test/SecP384R1FieldTest.java140
-rw-r--r--bcprov/src/test/java/org/bouncycastle/math/ec/test/AllTests.java65
-rw-r--r--bcprov/src/test/java/org/bouncycastle/math/ec/test/ECAlgorithmsTest.java239
-rw-r--r--bcprov/src/test/java/org/bouncycastle/math/ec/test/ECPointPerformanceTest.java202
-rw-r--r--bcprov/src/test/java/org/bouncycastle/math/ec/test/ECPointTest.java740
-rw-r--r--bcprov/src/test/java/org/bouncycastle/math/ec/test/F2mProofer.java204
-rw-r--r--bcprov/src/test/java/org/bouncycastle/math/ec/test/FixedPointTest.java90
-rw-r--r--bcprov/src/test/java/org/bouncycastle/math/raw/test/AllTests.java46
-rw-r--r--bcprov/src/test/java/org/bouncycastle/math/raw/test/InterleaveTest.java86
-rw-r--r--bcprov/src/test/java/org/bouncycastle/math/test/AllTests.java46
-rw-r--r--bcprov/src/test/java/org/bouncycastle/math/test/PrimesTest.java183
-rw-r--r--bcprov/src/test/java/org/bouncycastle/test/PrintTestResult.java36
-rw-r--r--bcprov/src/test/java/org/bouncycastle/util/Times.java9
-rw-r--r--mts/Android.bp44
-rw-r--r--mts/AndroidManifest.xml31
-rw-r--r--mts/MtsLibcoreBouncyCastleTestCases.xml61
-rw-r--r--proguard.flags185
-rw-r--r--repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java48
-rw-r--r--repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/custom/sec/test/SecP256R1FieldTest.java179
-rw-r--r--repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/custom/sec/test/SecP384R1FieldTest.java144
-rw-r--r--repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/AllTests.java69
-rw-r--r--repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/ECAlgorithmsTest.java243
-rw-r--r--repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/ECPointPerformanceTest.java204
-rw-r--r--repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/ECPointTest.java744
-rw-r--r--repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/F2mProofer.java208
-rw-r--r--repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/FixedPointTest.java94
-rw-r--r--repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/raw/test/AllTests.java50
-rw-r--r--repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/raw/test/InterleaveTest.java90
-rw-r--r--repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/test/AllTests.java50
-rw-r--r--repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/test/PrimesTest.java187
-rw-r--r--repackaged/bcprov/src/test/java/com/android/org/bouncycastle/test/PrintTestResult.java40
-rw-r--r--repackaged/bcprov/src/test/java/com/android/org/bouncycastle/util/Times.java13
-rw-r--r--repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java48
-rwxr-xr-xsrcgen/generate_android_src.sh1
39 files changed, 4996 insertions, 139 deletions
diff --git a/Android.bp b/Android.bp
index fadb1f70..f56f10e1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -51,38 +51,23 @@ java_defaults {
errorprone: {
javacflags: [
"-Xep:MissingOverride:OFF", // Ignore missing @Override.
+ "-Xep:BoxedPrimitiveEquality:WARN",
+ "-Xep:DoubleBraceInitialization:WARN",
+ "-Xep:HashtableContains:WARN",
],
},
}
-// These cannot build in the PDK, because the PDK requires all libraries
-// compile against SDK versions.
java_defaults {
name: "bouncycastle-defaults",
defaults: [
"bouncycastle-errorprone-defaults",
],
hostdex: true,
- target: {
- android: {
- product_variables: {
- pdk: {
- enabled: false,
- },
- },
- },
- },
lint: {
warning_checks: ["SuspiciousIndentation"],
},
- errorprone: {
- javacflags: [
- "-Xep:BoxedPrimitiveEquality:WARN",
- "-Xep:DoubleBraceInitialization:WARN",
- "-Xep:HashtableContains:WARN",
- ],
- },
}
// The src files for bouncycastle, used to generate core platform / intra-core
@@ -104,7 +89,6 @@ java_library {
visibility: [
"//art/build/apex",
"//art/build/sdk",
- "//external/wycheproof",
"//libcore:__subpackages__",
"//packages/modules/ArtPrebuilt",
],
@@ -120,6 +104,34 @@ java_library {
libs: ["unsupportedappusage"],
+ optimize: {
+ enabled: true,
+ shrink: true,
+ optimize: true,
+ obfuscate: false,
+ proguard_compatibility: false,
+ ignore_warnings: false,
+ proguard_flags_files: ["proguard.flags"],
+ },
+
+ sdk_version: "none",
+ system_modules: "art-module-intra-core-api-stubs-system-modules",
+}
+
+java_library_static {
+ name: "bouncycastle-test-lib",
+ visibility: [
+ "//packages/modules/ArtPrebuilt",
+ "//external/bouncycastle/mts",
+ ],
+ srcs: [
+ "repackaged/bcprov/src/test/java/**/*.java",
+ ],
+ libs: ["bouncycastle"],
+ static_libs: [
+ "junit",
+ "platform-test-annotations",
+ ],
sdk_version: "none",
system_modules: "art-module-intra-core-api-stubs-system-modules",
}
@@ -174,11 +186,13 @@ unbundled_visibility = [
"//packages/apps/RemoteProvisioner/tests/unittests",
"//packages/modules/Connectivity/tests/cts/net",
"//packages/modules/RemoteKeyProvisioning/app/tests/unit",
+ "//packages/modules/Virtualization/service_vm/test_apk",
"//packages/modules/Wifi/service",
"//packages/modules/Wifi/service/tests/wifitests",
"//libcore",
"//system/extras/verity",
"//system/security/identity/util",
+ "//tools/apksig",
"//tools/security/remote_provisioning/attestation_testing",
"//vendor:__subpackages__",
]
@@ -199,6 +213,7 @@ java_library {
sdk_version: "core_current",
min_sdk_version: "30",
java_version: "1.7",
+ apex_available: ["com.android.wifi"],
}
// Bouncycastle PKIX classes in the original org.bouncycastle package for use
@@ -247,6 +262,22 @@ java_library_host {
static_libs: ["bouncycastle-unbundled"],
}
+java_test_host {
+ name: "bouncycastle-host-tests",
+ srcs: [
+ "bcprov/src/test/java/**/*.java",
+ ],
+ static_libs: [
+ "bouncycastle-unbundled",
+ "junit",
+ "platform-test-annotations",
+ ],
+ test_options: {
+ unit_test: true,
+ },
+ test_suites: ["general-tests"],
+}
+
// Bouncycastle subset for use by frameworks/opt/net/ike project.
//
// Avoids including the whole of bouncycastle_unbundled in ike.
@@ -307,6 +338,7 @@ java_library {
//Excludes directories not needed.
java_library {
name: "bouncycastle-uwb",
+ defaults: ["bouncycastle-errorprone-defaults"],
visibility: [
"//packages/modules/Uwb/service",
],
diff --git a/README.android b/README.android
index 2b6c07f2..da805c03 100644
--- a/README.android
+++ b/README.android
@@ -64,11 +64,16 @@ The following steps are recommended for porting new Bouncy Castle versions.
* If upstream added a file to a directory we deleted, we probably don't
need it
- d) Confirm all changes
+ d) Update the list of exported APIs in proguard.flags, if necessary.
+
+ Check this in particular if new algorithms are getting registered with
+ ConfigurableProvider.addAlgorithm or ConfigurableProvider.addPrivateAlgorithm.
+
+ e) Confirm all changes
git diff aosp/master
- e) Run the tests, commonly at least
+ f) Run the tests, commonly at least
cts -m CtsLibcoreTestCases
cts -m CtsLibcoreFileIOTestCases
@@ -77,6 +82,6 @@ The following steps are recommended for porting new Bouncy Castle versions.
cts -m CtsLibcoreOkHttpTestCases
cts -m CtsLibcoreWycheproofBCTestCases
- e) Get the change reviewed
+ g) Get the change reviewed
repo upload .
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 00000000..5a9d38a3
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "MtsLibcoreBouncyCastleTestCases",
+ "options": [
+ {
+ "instrumentation-arg": "core-test-mode:=presubmit"
+ }
+ ]
+ }
+ ]
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
index 8c678059..7dadfa7f 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
@@ -957,56 +957,26 @@ public class BaseBlockCipher
{
byte[] iv = new byte[ivLength];
- // BEGIN Android-changed: For PBE keys with no IV, log and use IV of 0
+ // BEGIN Android-changed: Reject PBE keys with no IV
// These keys were accepted in BC 1.52 (and treated as having an IV of 0) but
- // rejected outright in BC 1.54 (even if an IV was passed in params). We
- // want the eventual state to be that an IV can be passed in params, but the key
- // is rejected otherwise. For now, log that these will be rejected in a future
- // release. See b/27995180 for historical details.
- // ivRandom.nextBytes(iv);
+ // rejected outright in BC 1.54 (even if an IV was passed in params).
+ // See b/27995180 for historical details.
if (!isBCPBEKeyWithoutIV(key)) {
ivRandom.nextBytes(iv);
} else {
- // TODO(b/70275132): Change to rejecting these keys
- System.err.println(" ******** DEPRECATED FUNCTIONALITY ********");
- System.err.println(" * You have initialized a cipher with a PBE key with no IV and");
- System.err.println(" * have not provided an IV in the AlgorithmParameterSpec. This");
- System.err.println(" * configuration is deprecated. The cipher will be initialized");
- System.err.println(" * with an all-zero IV, but in a future release this call will");
- System.err.println(" * throw an exception.");
- new InvalidAlgorithmParameterException("No IV set when using PBE key")
- .printStackTrace(System.err);
+ throw new InvalidAlgorithmParameterException("No IV set when using PBE key");
}
- // END Android-changed: For PBE keys with no IV, log and use IV of 0
+ // END Android-changed: Reject PBE keys with no IV
param = new ParametersWithIV(param, iv);
ivParam = (ParametersWithIV)param;
}
else if (cipher.getUnderlyingCipher().getAlgorithmName().indexOf("PGPCFB") < 0)
{
- // BEGIN Android-changed: For PBE keys with no IV, log and use IV of 0
+ // BEGIN Android-changed: Reject PBE keys with no IV
// These keys were accepted in BC 1.52 (and treated as having an IV of 0) but
- // rejected outright in BC 1.54 (even if an IV was passed in params). We
- // want the eventual state to be that an IV can be passed in params, but the key
- // is rejected otherwise. For now, log that these will be rejected in a future
- // release. See b/27995180 for historical details.
- // throw new InvalidAlgorithmParameterException("no IV set when one expected");
- if (!isBCPBEKeyWithoutIV(key)) {
- throw new InvalidAlgorithmParameterException("no IV set when one expected");
- } else {
- // TODO(b/70275132): Change to rejecting these keys
- System.err.println(" ******** DEPRECATED FUNCTIONALITY ********");
- System.err.println(" * You have initialized a cipher with a PBE key with no IV and");
- System.err.println(" * have not provided an IV in the AlgorithmParameterSpec. This");
- System.err.println(" * configuration is deprecated. The cipher will be initialized");
- System.err.println(" * with an all-zero IV, but in a future release this call will");
- System.err.println(" * throw an exception.");
- new InvalidAlgorithmParameterException("No IV set when using PBE key")
- .printStackTrace(System.err);
- // Mimic behaviour in 1.52 by using an IV of 0's
- param = new ParametersWithIV(param, new byte[ivLength]);
- ivParam = (ParametersWithIV)param;
- }
- // END Android-changed: For PBE keys with no IV, log and use IV of 0
+ // rejected outright in BC 1.54 (even if an IV was passed in params).
+ throw new InvalidAlgorithmParameterException("No IV set when using PBE key");
+ // END Android-changed: Reject PBE keys with no IV
}
}
diff --git a/bcprov/src/test/java/org/bouncycastle/math/ec/custom/sec/test/SecP256R1FieldTest.java b/bcprov/src/test/java/org/bouncycastle/math/ec/custom/sec/test/SecP256R1FieldTest.java
new file mode 100644
index 00000000..b59f1924
--- /dev/null
+++ b/bcprov/src/test/java/org/bouncycastle/math/ec/custom/sec/test/SecP256R1FieldTest.java
@@ -0,0 +1,175 @@
+package org.bouncycastle.math.ec.custom.sec.test;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.ec.CustomNamedCurves;
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.raw.Nat256;
+
+import junit.framework.TestCase;
+
+public class SecP256R1FieldTest extends TestCase
+{
+ private static final SecureRandom RANDOM = new SecureRandom();
+
+ private static final X9ECParameters DP = CustomNamedCurves
+ .getByOID(SECObjectIdentifiers.secp256r1);
+ private static final BigInteger Q = DP.getCurve().getField().getCharacteristic();
+
+ public void testMultiply1()
+ {
+ int COUNT = 1000;
+
+ for (int i = 0; i < COUNT; ++i)
+ {
+ ECFieldElement x = generateMultiplyInput_Random();
+ ECFieldElement y = generateMultiplyInput_Random();
+
+ BigInteger X = x.toBigInteger(), Y = y.toBigInteger();
+ BigInteger R = X.multiply(Y).mod(Q);
+
+ ECFieldElement z = x.multiply(y);
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+ }
+
+ public void testMultiply2()
+ {
+ int COUNT = 100;
+ ECFieldElement[] inputs = new ECFieldElement[COUNT];
+ BigInteger[] INPUTS = new BigInteger[COUNT];
+
+ for (int i = 0; i < inputs.length; ++i)
+ {
+ inputs[i] = generateMultiplyInput_Random();
+ INPUTS[i] = inputs[i].toBigInteger();
+ }
+
+ for (int j = 0; j < inputs.length; ++j)
+ {
+ for (int k = 0; k < inputs.length; ++k)
+ {
+ BigInteger R = INPUTS[j].multiply(INPUTS[k]).mod(Q);
+
+ ECFieldElement z = inputs[j].multiply(inputs[k]);
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+ }
+ }
+
+ public void testSquare()
+ {
+ int COUNT = 1000;
+
+ for (int i = 0; i < COUNT; ++i)
+ {
+ ECFieldElement x = generateMultiplyInput_Random();
+
+ BigInteger X = x.toBigInteger();
+ BigInteger R = X.multiply(X).mod(Q);
+
+ ECFieldElement z = x.square();
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+ }
+
+ /**
+ * Test multiplication with specifically selected values that triggered a bug in the modular
+ * reduction in OpenSSL (last affected version 0.9.8g).
+ *
+ * See "Practical realisation and elimination of an ECC-related software bug attack", B. B.
+ * Brumley, M. Barbarosa, D. Page, F. Vercauteren.
+ */
+ public void testMultiply_OpenSSLBug()
+ {
+ int COUNT = 100;
+
+ for (int i = 0; i < COUNT; ++i)
+ {
+ ECFieldElement x = generateMultiplyInputA_OpenSSLBug();
+ ECFieldElement y = generateMultiplyInputB_OpenSSLBug();
+
+ BigInteger X = x.toBigInteger(), Y = y.toBigInteger();
+ BigInteger R = X.multiply(Y).mod(Q);
+
+ ECFieldElement z = x.multiply(y);
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+ }
+
+ /**
+ * Test squaring with specifically selected values that triggered a bug in the modular reduction
+ * in OpenSSL (last affected version 0.9.8g).
+ *
+ * See "Practical realisation and elimination of an ECC-related software bug attack", B. B.
+ * Brumley, M. Barbarosa, D. Page, F. Vercauteren.
+ */
+ public void testSquare_OpenSSLBug()
+ {
+ int COUNT = 100;
+
+ for (int i = 0; i < COUNT; ++i)
+ {
+ ECFieldElement x = generateSquareInput_OpenSSLBug();
+
+ BigInteger X = x.toBigInteger();
+ BigInteger R = X.multiply(X).mod(Q);
+
+ ECFieldElement z = x.square();
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+ }
+
+ private ECFieldElement fe(BigInteger x)
+ {
+ return DP.getCurve().fromBigInteger(x);
+ }
+
+ private ECFieldElement generateMultiplyInput_Random()
+ {
+ return fe(new BigInteger(DP.getCurve().getFieldSize() + 32, RANDOM).mod(Q));
+ }
+
+ private ECFieldElement generateMultiplyInputA_OpenSSLBug()
+ {
+ int[] x = Nat256.create();
+ x[0] = RANDOM.nextInt() >>> 1;
+ x[4] = 3;
+ x[7] = -1;
+
+ return fe(Nat256.toBigInteger(x));
+ }
+
+ private ECFieldElement generateMultiplyInputB_OpenSSLBug()
+ {
+ int[] x = Nat256.create();
+ x[0] = RANDOM.nextInt() >>> 1;
+ x[3] = 1;
+ x[7] = -1;
+
+ return fe(Nat256.toBigInteger(x));
+ }
+
+ private ECFieldElement generateSquareInput_OpenSSLBug()
+ {
+ int[] x = Nat256.create();
+ x[0] = RANDOM.nextInt() >>> 1;
+ x[4] = 2;
+ x[7] = -1;
+
+ return fe(Nat256.toBigInteger(x));
+ }
+}
diff --git a/bcprov/src/test/java/org/bouncycastle/math/ec/custom/sec/test/SecP384R1FieldTest.java b/bcprov/src/test/java/org/bouncycastle/math/ec/custom/sec/test/SecP384R1FieldTest.java
new file mode 100644
index 00000000..be6f5d19
--- /dev/null
+++ b/bcprov/src/test/java/org/bouncycastle/math/ec/custom/sec/test/SecP384R1FieldTest.java
@@ -0,0 +1,140 @@
+package org.bouncycastle.math.ec.custom.sec.test;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.ec.CustomNamedCurves;
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.raw.Nat;
+
+import junit.framework.TestCase;
+
+public class SecP384R1FieldTest extends TestCase
+{
+ private static final SecureRandom RANDOM = new SecureRandom();
+
+ private static final X9ECParameters DP = CustomNamedCurves
+ .getByOID(SECObjectIdentifiers.secp384r1);
+ private static final BigInteger Q = DP.getCurve().getField().getCharacteristic();
+
+ public void testMultiply1()
+ {
+ int COUNT = 1000;
+
+ for (int i = 0; i < COUNT; ++i)
+ {
+ ECFieldElement x = generateMultiplyInput_Random();
+ ECFieldElement y = generateMultiplyInput_Random();
+
+ BigInteger X = x.toBigInteger(), Y = y.toBigInteger();
+ BigInteger R = X.multiply(Y).mod(Q);
+
+ ECFieldElement z = x.multiply(y);
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+ }
+
+ public void testMultiply2()
+ {
+ int COUNT = 100;
+ ECFieldElement[] inputs = new ECFieldElement[COUNT];
+ BigInteger[] INPUTS = new BigInteger[COUNT];
+
+ for (int i = 0; i < inputs.length; ++i)
+ {
+ inputs[i] = generateMultiplyInput_Random();
+ INPUTS[i] = inputs[i].toBigInteger();
+ }
+
+ for (int j = 0; j < inputs.length; ++j)
+ {
+ for (int k = 0; k < inputs.length; ++k)
+ {
+ BigInteger R = INPUTS[j].multiply(INPUTS[k]).mod(Q);
+
+ ECFieldElement z = inputs[j].multiply(inputs[k]);
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+ }
+ }
+
+ public void testSquare()
+ {
+ int COUNT = 1000;
+
+ for (int i = 0; i < COUNT; ++i)
+ {
+ ECFieldElement x = generateMultiplyInput_Random();
+
+ BigInteger X = x.toBigInteger();
+ BigInteger R = X.multiply(X).mod(Q);
+
+ ECFieldElement z = x.square();
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+ }
+
+ public void testSquare_CarryBug()
+ {
+ int COUNT = 100;
+
+ for (int i = 0; i < COUNT; ++i)
+ {
+ ECFieldElement x = generateSquareInput_CarryBug();
+
+ BigInteger X = x.toBigInteger();
+ BigInteger R = X.multiply(X).mod(Q);
+
+ ECFieldElement z = x.square();
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+ }
+
+ /*
+ * Based on another example input demonstrating the carry propagation bug in Nat192.square, as
+ * reported by Joseph Friel on dev-crypto.
+ */
+ public void testSquare_CarryBug_Reported()
+ {
+ ECFieldElement x = fe(new BigInteger("2fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", 16));
+
+ BigInteger X = x.toBigInteger();
+ BigInteger R = X.multiply(X).mod(Q);
+
+ ECFieldElement z = x.square();
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+
+ private ECFieldElement fe(BigInteger x)
+ {
+ return DP.getCurve().fromBigInteger(x);
+ }
+
+ private ECFieldElement generateMultiplyInput_Random()
+ {
+ return fe(new BigInteger(DP.getCurve().getFieldSize() + 32, RANDOM).mod(Q));
+ }
+
+ private ECFieldElement generateSquareInput_CarryBug()
+ {
+ int[] x = Nat.create(12);
+ x[0] = RANDOM.nextInt() >>> 1;
+ x[6] = 2;
+ x[10] = -1 << 16;
+ x[11] = -1;
+
+ return fe(Nat.toBigInteger(12, x));
+ }
+}
diff --git a/bcprov/src/test/java/org/bouncycastle/math/ec/test/AllTests.java b/bcprov/src/test/java/org/bouncycastle/math/ec/test/AllTests.java
new file mode 100644
index 00000000..7d5751c7
--- /dev/null
+++ b/bcprov/src/test/java/org/bouncycastle/math/ec/test/AllTests.java
@@ -0,0 +1,65 @@
+package org.bouncycastle.math.ec.test;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.bouncycastle.test.PrintTestResult;
+
+public class AllTests
+ extends TestCase
+{
+ public static void main (String[] args)
+ throws Exception
+ {
+ PrintTestResult.printResult( junit.textui.TestRunner.run(suite()));
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ TestSuite suite = new TestSuite("EC Math tests");
+
+ // Android-changed: parameterized the test.
+ // suite.addTestSuite(ECAlgorithmsTest.class);
+ suite.addTestSuite(ECPointTest.class);
+ suite.addTestSuite(FixedPointTest.class);
+
+ return new BCTestSetup(suite);
+ }
+
+ static List enumToList(Enumeration en)
+ {
+ List rv = new ArrayList();
+
+ while (en.hasMoreElements())
+ {
+ rv.add(en.nextElement());
+ }
+
+ return rv;
+ }
+
+ static class BCTestSetup
+ extends TestSetup
+ {
+ public BCTestSetup(Test test)
+ {
+ super(test);
+ }
+
+ protected void setUp()
+ {
+
+ }
+
+ protected void tearDown()
+ {
+
+ }
+ }
+}
diff --git a/bcprov/src/test/java/org/bouncycastle/math/ec/test/ECAlgorithmsTest.java b/bcprov/src/test/java/org/bouncycastle/math/ec/test/ECAlgorithmsTest.java
new file mode 100644
index 00000000..0c43b5a1
--- /dev/null
+++ b/bcprov/src/test/java/org/bouncycastle/math/ec/test/ECAlgorithmsTest.java
@@ -0,0 +1,239 @@
+package org.bouncycastle.math.ec.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.asn1.x9.X9ECPoint;
+import org.bouncycastle.crypto.ec.CustomNamedCurves;
+import org.bouncycastle.math.ec.ECAlgorithms;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+// Android-changed: parameterized the test.
+@RunWith(Parameterized.class)
+public class ECAlgorithmsTest
+{
+ private static final int SCALE = 4;
+ private static final SecureRandom RND = new SecureRandom();
+
+
+ // BEGIN Android-added: parameterized the test.
+ @Parameterized.Parameters(name = "{0}")
+ public static String[] getAllX9ECParameters() {
+ Set<String> names = new HashSet<>(AllTests.enumToList(ECNamedCurveTable.getNames()));
+ names.addAll(AllTests.enumToList(CustomNamedCurves.getNames()));
+ return names.toArray(new String[0]);
+ }
+
+ @Parameterized.Parameter(0)
+ public String name;
+
+ private ArrayList getX9s(String name) {
+ ArrayList<X9ECParameters> x9s = new ArrayList<>();
+
+ X9ECParameters x9 = ECNamedCurveTable.getByName(name);
+ if (x9 != null)
+ {
+ addTestCurves(x9s, x9);
+ }
+
+ x9 = CustomNamedCurves.getByName(name);
+ if (x9 != null)
+ {
+ addTestCurves(x9s, x9);
+ }
+ return x9s;
+ }
+ // END Android-added: parameterized the test.
+
+ @Ignore("secp256r1 is covered by testSumOfMultipliesComplete")
+ public void testSumOfMultiplies()
+ {
+ X9ECParameters x9 = CustomNamedCurves.getByName("secp256r1");
+ assertNotNull(x9);
+ doTestSumOfMultiplies(x9);
+ }
+
+ // TODO Ideally, mark this test not to run by default
+ @Test
+ public void testSumOfMultipliesComplete()
+ {
+ // Android-changed: parameterized the test.
+ // ArrayList x9s = getTestCurves();
+ ArrayList<X9ECParameters> x9s = getX9s(name);
+ Iterator it = x9s.iterator();
+ while (it.hasNext())
+ {
+ X9ECParameters x9 = (X9ECParameters)it.next();
+ doTestSumOfMultiplies(x9);
+ }
+ }
+
+ @Ignore("secp256r1 is covered by testSumOfTwoMultipliesComplete")
+ public void testSumOfTwoMultiplies()
+ {
+ X9ECParameters x9 = CustomNamedCurves.getByName("secp256r1");
+ assertNotNull(x9);
+ doTestSumOfTwoMultiplies(x9);
+ }
+
+ // TODO Ideally, mark this test not to run by default
+ @Test
+ public void testSumOfTwoMultipliesComplete()
+ {
+ // Android-changed: parameterized the test.
+ // ArrayList x9s = getTestCurves();
+ ArrayList<X9ECParameters> x9s = getX9s(name);
+ Iterator it = x9s.iterator();
+ while (it.hasNext())
+ {
+ X9ECParameters x9 = (X9ECParameters)it.next();
+ doTestSumOfTwoMultiplies(x9);
+ }
+ }
+
+ private void doTestSumOfMultiplies(X9ECParameters x9)
+ {
+ ECPoint[] points = new ECPoint[SCALE];
+ BigInteger[] scalars = new BigInteger[SCALE];
+ for (int i = 0; i < SCALE; ++i)
+ {
+ points[i] = getRandomPoint(x9);
+ scalars[i] = getRandomScalar(x9);
+ }
+
+ ECPoint u = x9.getCurve().getInfinity();
+ for (int i = 0; i < SCALE; ++i)
+ {
+ u = u.add(points[i].multiply(scalars[i]));
+
+ ECPoint v = ECAlgorithms.sumOfMultiplies(copyPoints(points, i + 1), copyScalars(scalars, i + 1));
+
+ ECPoint[] results = new ECPoint[]{ u, v };
+ x9.getCurve().normalizeAll(results);
+
+ assertPointsEqual("ECAlgorithms.sumOfMultiplies is incorrect", results[0], results[1]);
+ }
+ }
+
+ private void doTestSumOfTwoMultiplies(X9ECParameters x9)
+ {
+ ECPoint p = getRandomPoint(x9);
+ BigInteger a = getRandomScalar(x9);
+
+ for (int i = 0; i < SCALE; ++i)
+ {
+ ECPoint q = getRandomPoint(x9);
+ BigInteger b = getRandomScalar(x9);
+
+ ECPoint u = p.multiply(a).add(q.multiply(b));
+ ECPoint v = ECAlgorithms.shamirsTrick(p, a, q, b);
+ ECPoint w = ECAlgorithms.sumOfTwoMultiplies(p, a, q, b);
+
+ ECPoint[] results = new ECPoint[]{ u, v, w };
+ x9.getCurve().normalizeAll(results);
+
+ assertPointsEqual("ECAlgorithms.shamirsTrick is incorrect", results[0], results[1]);
+ assertPointsEqual("ECAlgorithms.sumOfTwoMultiplies is incorrect", results[0], results[2]);
+
+ p = q;
+ a = b;
+ }
+ }
+
+ private void assertPointsEqual(String message, ECPoint a, ECPoint b)
+ {
+ assertEquals(message, a, b);
+ }
+
+ private ECPoint[] copyPoints(ECPoint[] ps, int len)
+ {
+ ECPoint[] result = new ECPoint[len];
+ System.arraycopy(ps, 0, result, 0, len);
+ return result;
+ }
+
+ private BigInteger[] copyScalars(BigInteger[] ks, int len)
+ {
+ BigInteger[] result = new BigInteger[len];
+ System.arraycopy(ks, 0, result, 0, len);
+ return result;
+ }
+
+ private ECPoint getRandomPoint(X9ECParameters x9)
+ {
+ return x9.getG().multiply(getRandomScalar(x9));
+ }
+
+ private BigInteger getRandomScalar(X9ECParameters x9)
+ {
+ return new BigInteger(x9.getN().bitLength(), RND);
+ }
+
+ private ArrayList getTestCurves()
+ {
+ ArrayList x9s = new ArrayList();
+ Set names = new HashSet(AllTests.enumToList(ECNamedCurveTable.getNames()));
+ names.addAll(AllTests.enumToList(CustomNamedCurves.getNames()));
+
+ Iterator it = names.iterator();
+ while (it.hasNext())
+ {
+ String name = (String)it.next();
+
+ X9ECParameters x9 = ECNamedCurveTable.getByName(name);
+ if (x9 != null)
+ {
+ addTestCurves(x9s, x9);
+ }
+
+ x9 = CustomNamedCurves.getByName(name);
+ if (x9 != null)
+ {
+ addTestCurves(x9s, x9);
+ }
+ }
+ return x9s;
+ }
+
+ private void addTestCurves(ArrayList x9s, X9ECParameters x9)
+ {
+ ECCurve curve = x9.getCurve();
+
+ int[] coords = ECCurve.getAllCoordinateSystems();
+ for (int i = 0; i < coords.length; ++i)
+ {
+ int coord = coords[i];
+ if (curve.getCoordinateSystem() == coord)
+ {
+ x9s.add(x9);
+ }
+ else if (curve.supportsCoordinateSystem(coord))
+ {
+ ECCurve c = curve.configure().setCoordinateSystem(coord).create();
+ x9s.add(new X9ECParameters(c, new X9ECPoint(c.importPoint(x9.getG()), false), x9.getN(), x9.getH()));
+ }
+ }
+ }
+
+ // Android-changed: Use JUnit4.
+ /*
+ public static Test suite()
+ {
+ return new TestSuite(ECAlgorithmsTest.class);
+ }
+ */
+}
diff --git a/bcprov/src/test/java/org/bouncycastle/math/ec/test/ECPointPerformanceTest.java b/bcprov/src/test/java/org/bouncycastle/math/ec/test/ECPointPerformanceTest.java
new file mode 100644
index 00000000..65cf8faa
--- /dev/null
+++ b/bcprov/src/test/java/org/bouncycastle/math/ec/test/ECPointPerformanceTest.java
@@ -0,0 +1,202 @@
+package org.bouncycastle.math.ec.test;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import junit.framework.TestCase;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.ec.CustomNamedCurves;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.Times;
+
+/**
+ * Compares the performance of the the window NAF point multiplication against conventional point
+ * multiplication.
+ */
+public class ECPointPerformanceTest extends TestCase
+{
+ static final int MILLIS_PER_ROUND = 200;
+ static final int MILLIS_WARMUP = 1000;
+
+ static final int MULTS_PER_CHECK = 16;
+ static final int NUM_ROUNDS = 10;
+
+ private static String[] COORD_NAMES = new String[]{ "AFFINE", "HOMOGENEOUS", "JACOBIAN", "JACOBIAN-CHUDNOVSKY",
+ "JACOBIAN-MODIFIED", "LAMBDA-AFFINE", "LAMBDA-PROJECTIVE", "SKEWED" };
+
+ private void randMult(String curveName) throws Exception
+ {
+ X9ECParameters spec = ECNamedCurveTable.getByName(curveName);
+ if (spec != null)
+ {
+ randMult(curveName, spec);
+ }
+
+ spec = CustomNamedCurves.getByName(curveName);
+ if (spec != null)
+ {
+ randMult(curveName + " (custom)", spec);
+ }
+ }
+
+ private void randMult(String label, X9ECParameters spec) throws Exception
+ {
+ ECCurve C = spec.getCurve();
+ ECPoint G = (ECPoint)spec.getG();
+ BigInteger n = spec.getN();
+
+ SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
+ random.setSeed(System.currentTimeMillis());
+
+ System.out.println(label);
+
+ int[] coords = ECCurve.getAllCoordinateSystems();
+ for (int i = 0; i < coords.length; ++i)
+ {
+ int coord = coords[i];
+ if (C.supportsCoordinateSystem(coord))
+ {
+ ECCurve c = C;
+ ECPoint g = G;
+
+ boolean defaultCoord = (c.getCoordinateSystem() == coord);
+ if (!defaultCoord)
+ {
+ c = C.configure().setCoordinateSystem(coord).create();
+ g = c.importPoint(G);
+ }
+
+ double avgRate = randMult(random, g, n);
+ String coordName = COORD_NAMES[coord];
+ StringBuffer sb = new StringBuffer();
+ sb.append(" ");
+ sb.append(defaultCoord ? '*' : ' ');
+ sb.append(coordName);
+ for (int j = sb.length(); j < 30; ++j)
+ {
+ sb.append(' ');
+ }
+ sb.append(": ");
+ sb.append(avgRate);
+ sb.append(" mults/sec");
+ for (int j = sb.length(); j < 64; ++j)
+ {
+ sb.append(' ');
+ }
+ sb.append('(');
+ sb.append(1000.0 / avgRate);
+ sb.append(" millis/mult)");
+ System.out.println(sb.toString());
+ }
+ }
+ }
+
+ private double randMult(SecureRandom random, ECPoint g, BigInteger n) throws Exception
+ {
+ BigInteger[] ks = new BigInteger[128];
+ for (int i = 0; i < ks.length; ++i)
+ {
+ ks[i] = new BigInteger(n.bitLength() - 1, random);
+ }
+
+ int ki = 0;
+ ECPoint p = g;
+
+ {
+ long startTime = Times.nanoTime();
+ long goalTime = startTime + 1000000L * MILLIS_WARMUP;
+
+ do
+ {
+ BigInteger k = ks[ki];
+ p = g.multiply(k);
+ if ((ki & 1) != 0)
+ {
+ g = p;
+ }
+ if (++ki == ks.length)
+ {
+ ki = 0;
+ }
+ }
+ while (Times.nanoTime() < goalTime);
+ }
+
+ double minRate = Double.MAX_VALUE, maxRate = Double.MIN_VALUE, totalRate = 0.0;
+
+ for (int i = 1; i <= NUM_ROUNDS; i++)
+ {
+ long startTime = Times.nanoTime();
+ long goalTime = startTime + 1000000L * MILLIS_PER_ROUND;
+ long count = 0, endTime;
+
+ do
+ {
+ ++count;
+
+ for (int j = 0; j < MULTS_PER_CHECK; ++j)
+ {
+ BigInteger k = ks[ki];
+ p = g.multiply(k);
+ if ((ki & 1) != 0)
+ {
+ g = p;
+ }
+ if (++ki == ks.length)
+ {
+ ki = 0;
+ }
+ }
+
+ endTime = Times.nanoTime();
+ }
+ while (endTime < goalTime);
+
+ double roundElapsed = (double)(endTime - startTime);
+ double roundRate = count * MULTS_PER_CHECK * 1000000000L / roundElapsed;
+
+ minRate = Math.min(minRate, roundRate);
+ maxRate = Math.max(maxRate, roundRate);
+ totalRate += roundRate;
+ }
+
+ return (totalRate - minRate - maxRate) / (NUM_ROUNDS - 2);
+ }
+
+ public void testMultiply() throws Exception
+ {
+ // Android-changed: Skip this test as this perf test is timed out.
+ if (true) {
+ return;
+ }
+ SortedSet names = new TreeSet(AllTests.enumToList(ECNamedCurveTable.getNames()));
+ names.addAll(AllTests.enumToList(CustomNamedCurves.getNames()));
+
+ Set oids = new HashSet();
+
+ Iterator it = names.iterator();
+ while (it.hasNext())
+ {
+ String name = (String)it.next();
+ ASN1ObjectIdentifier oid = ECNamedCurveTable.getOID(name);
+ if (oid == null)
+ {
+ oid = CustomNamedCurves.getOID(name);
+ }
+ if (oid != null && !oids.add(oid))
+ {
+ continue;
+ }
+
+ randMult(name);
+ }
+ }
+}
diff --git a/bcprov/src/test/java/org/bouncycastle/math/ec/test/ECPointTest.java b/bcprov/src/test/java/org/bouncycastle/math/ec/test/ECPointTest.java
new file mode 100644
index 00000000..aaf2f5b6
--- /dev/null
+++ b/bcprov/src/test/java/org/bouncycastle/math/ec/test/ECPointTest.java
@@ -0,0 +1,740 @@
+package org.bouncycastle.math.ec.test;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.asn1.x9.X9ECPoint;
+import org.bouncycastle.crypto.ec.CustomNamedCurves;
+import org.bouncycastle.math.ec.ECAlgorithms;
+import org.bouncycastle.math.ec.ECConstants;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.WNafUtil;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.BigIntegers;
+import org.bouncycastle.util.Integers;
+import org.bouncycastle.util.encoders.Hex;
+
+import android.platform.test.annotations.LargeTest;
+
+/**
+ * Test class for {@link org.bouncycastle.math.ec.ECPoint ECPoint}. All
+ * literature values are taken from "Guide to elliptic curve cryptography",
+ * Darrel Hankerson, Alfred J. Menezes, Scott Vanstone, 2004, Springer-Verlag
+ * New York, Inc.
+ */
+public class ECPointTest extends TestCase
+{
+ /**
+ * Random source used to generate random points
+ */
+ private SecureRandom secRand = new SecureRandom();
+
+ private ECPointTest.Fp fp = null;
+
+ private ECPointTest.F2m f2m = null;
+
+ /**
+ * Nested class containing sample literature values for <code>Fp</code>.
+ */
+ public static class Fp
+ {
+ private final BigInteger q = new BigInteger("1063");
+
+ private final BigInteger a = new BigInteger("4");
+
+ private final BigInteger b = new BigInteger("20");
+
+ private final BigInteger n = new BigInteger("38");
+
+ private final BigInteger h = new BigInteger("1");
+
+ private final ECCurve curve = new ECCurve.Fp(q, a, b, n, h);
+
+ private final ECPoint infinity = curve.getInfinity();
+
+ private final int[] pointSource = { 1, 5, 4, 10, 234, 1024, 817, 912 };
+
+ private ECPoint[] p = new ECPoint[pointSource.length / 2];
+
+ /**
+ * Creates the points on the curve with literature values.
+ */
+ private void createPoints()
+ {
+ for (int i = 0; i < pointSource.length / 2; i++)
+ {
+ p[i] = curve.createPoint(
+ new BigInteger(Integer.toString(pointSource[2 * i])),
+ new BigInteger(Integer.toString(pointSource[2 * i + 1])));
+ }
+ }
+ }
+
+ /**
+ * Nested class containing sample literature values for <code>F2m</code>.
+ */
+ public static class F2m
+ {
+ // Irreducible polynomial for TPB z^4 + z + 1
+ private final int m = 4;
+
+ private final int k1 = 1;
+
+ // a = z^3
+ private final BigInteger aTpb = new BigInteger("1000", 2);
+
+ // b = z^3 + 1
+ private final BigInteger bTpb = new BigInteger("1001", 2);
+
+ private final BigInteger n = new BigInteger("23");
+
+ private final BigInteger h = new BigInteger("1");
+
+ private final ECCurve.F2m curve = new ECCurve.F2m(m, k1, aTpb, bTpb, n, h);
+
+ private final ECPoint.F2m infinity = (ECPoint.F2m) curve.getInfinity();
+
+ private final String[] pointSource = { "0010", "1111", "1100", "1100",
+ "0001", "0001", "1011", "0010" };
+
+ private ECPoint[] p = new ECPoint[pointSource.length / 2];
+
+ /**
+ * Creates the points on the curve with literature values.
+ */
+ private void createPoints()
+ {
+ for (int i = 0; i < pointSource.length / 2; i++)
+ {
+ p[i] = curve.createPoint(
+ new BigInteger(pointSource[2 * i], 2),
+ new BigInteger(pointSource[2 * i + 1], 2));
+ }
+ }
+ }
+
+ public void setUp()
+ {
+ fp = new ECPointTest.Fp();
+ fp.createPoints();
+
+ f2m = new ECPointTest.F2m();
+ f2m.createPoints();
+ }
+
+ /**
+ * Tests, if inconsistent points can be created, i.e. points with exactly
+ * one null coordinate (not permitted).
+ */
+ public void testPointCreationConsistency()
+ {
+ try
+ {
+ ECPoint bad = fp.curve.createPoint(new BigInteger("12"), null);
+ fail();
+ }
+ catch (IllegalArgumentException expected)
+ {
+ }
+
+ try
+ {
+ ECPoint bad = fp.curve.createPoint(null, new BigInteger("12"));
+ fail();
+ }
+ catch (IllegalArgumentException expected)
+ {
+ }
+
+ try
+ {
+ ECPoint bad = f2m.curve.createPoint(new BigInteger("1011"), null);
+ fail();
+ }
+ catch (IllegalArgumentException expected)
+ {
+ }
+
+ try
+ {
+ ECPoint bad = f2m.curve.createPoint(null, new BigInteger("1011"));
+ fail();
+ }
+ catch (IllegalArgumentException expected)
+ {
+ }
+ }
+
+ /**
+ * Tests <code>ECPoint.add()</code> against literature values.
+ *
+ * @param p
+ * The array of literature values.
+ * @param infinity
+ * The point at infinity on the respective curve.
+ */
+ private void implTestAdd(ECPoint[] p, ECPoint infinity)
+ {
+ assertPointsEqual("p0 plus p1 does not equal p2", p[2], p[0].add(p[1]));
+ assertPointsEqual("p1 plus p0 does not equal p2", p[2], p[1].add(p[0]));
+ for (int i = 0; i < p.length; i++)
+ {
+ assertPointsEqual("Adding infinity failed", p[i], p[i].add(infinity));
+ assertPointsEqual("Adding to infinity failed", p[i], infinity.add(p[i]));
+ }
+ }
+
+ /**
+ * Calls <code>implTestAdd()</code> for <code>Fp</code> and
+ * <code>F2m</code>.
+ */
+ public void testAdd()
+ {
+ implTestAdd(fp.p, fp.infinity);
+ implTestAdd(f2m.p, f2m.infinity);
+ }
+
+ /**
+ * Tests <code>ECPoint.twice()</code> against literature values.
+ *
+ * @param p
+ * The array of literature values.
+ */
+ private void implTestTwice(ECPoint[] p)
+ {
+ assertPointsEqual("Twice incorrect", p[3], p[0].twice());
+ assertPointsEqual("Add same point incorrect", p[3], p[0].add(p[0]));
+ }
+
+ /**
+ * Calls <code>implTestTwice()</code> for <code>Fp</code> and
+ * <code>F2m</code>.
+ */
+ public void testTwice()
+ {
+ implTestTwice(fp.p);
+ implTestTwice(f2m.p);
+ }
+
+ private void implTestThreeTimes(ECPoint[] p)
+ {
+ ECPoint P = p[0];
+ ECPoint _3P = P.add(P).add(P);
+ assertPointsEqual("ThreeTimes incorrect", _3P, P.threeTimes());
+ assertPointsEqual("TwicePlus incorrect", _3P, P.twicePlus(P));
+ }
+
+ /**
+ * Calls <code>implTestThreeTimes()</code> for <code>Fp</code> and
+ * <code>F2m</code>.
+ */
+ public void testThreeTimes()
+ {
+ implTestThreeTimes(fp.p);
+ implTestThreeTimes(f2m.p);
+ }
+
+ /**
+ * Goes through all points on an elliptic curve and checks, if adding a
+ * point <code>k</code>-times is the same as multiplying the point by
+ * <code>k</code>, for all <code>k</code>. Should be called for points
+ * on very small elliptic curves only.
+ *
+ * @param p
+ * The base point on the elliptic curve.
+ * @param infinity
+ * The point at infinity on the elliptic curve.
+ */
+ private void implTestAllPoints(ECPoint p, ECPoint infinity)
+ {
+ ECPoint adder = infinity;
+ ECPoint multiplier = infinity;
+
+ BigInteger i = BigInteger.valueOf(1);
+ do
+ {
+ adder = adder.add(p);
+ multiplier = p.multiply(i);
+ assertPointsEqual("Results of add() and multiply() are inconsistent "
+ + i, adder, multiplier);
+ i = i.add(BigInteger.ONE);
+ }
+ while (!(adder.equals(infinity)));
+ }
+
+ /**
+ * Calls <code>implTestAllPoints()</code> for the small literature curves,
+ * both for <code>Fp</code> and <code>F2m</code>.
+ */
+ public void testAllPoints()
+ {
+ for (int i = 0; i < fp.p.length; i++)
+ {
+ implTestAllPoints(fp.p[i], fp.infinity);
+ }
+
+ for (int i = 0; i < f2m.p.length; i++)
+ {
+ implTestAllPoints(f2m.p[i], f2m.infinity);
+ }
+ }
+
+ /**
+ * Checks, if the point multiplication algorithm of the given point yields
+ * the same result as point multiplication done by the reference
+ * implementation given in <code>multiply()</code>. This method chooses a
+ * random number by which the given point <code>p</code> is multiplied.
+ *
+ * @param p
+ * The point to be multiplied.
+ * @param numBits
+ * The bitlength of the random number by which <code>p</code>
+ * is multiplied.
+ */
+ private void implTestMultiply(ECPoint p, int numBits)
+ {
+ BigInteger k = new BigInteger(numBits, secRand);
+ ECPoint ref = ECAlgorithms.referenceMultiply(p, k);
+ ECPoint q = p.multiply(k);
+ assertPointsEqual("ECPoint.multiply is incorrect", ref, q);
+ }
+
+ /**
+ * Checks, if the point multiplication algorithm of the given point yields
+ * the same result as point multiplication done by the reference
+ * implementation given in <code>multiply()</code>. This method tests
+ * multiplication of <code>p</code> by every number of bitlength
+ * <code>numBits</code> or less.
+ *
+ * @param p
+ * The point to be multiplied.
+ * @param numBits
+ * Try every multiplier up to this bitlength
+ */
+ private void implTestMultiplyAll(ECPoint p, int numBits)
+ {
+ BigInteger bound = BigInteger.ONE.shiftLeft(numBits);
+ BigInteger k = BigInteger.ZERO;
+
+ do
+ {
+ ECPoint ref = ECAlgorithms.referenceMultiply(p, k);
+ ECPoint q = p.multiply(k);
+ assertPointsEqual("ECPoint.multiply is incorrect", ref, q);
+ k = k.add(BigInteger.ONE);
+ }
+ while (k.compareTo(bound) < 0);
+ }
+
+ /**
+ * Tests <code>ECPoint.add()</code> and <code>ECPoint.subtract()</code>
+ * for the given point and the given point at infinity.
+ *
+ * @param p
+ * The point on which the tests are performed.
+ * @param infinity
+ * The point at infinity on the same curve as <code>p</code>.
+ */
+ private void implTestAddSubtract(ECPoint p, ECPoint infinity)
+ {
+ assertPointsEqual("Twice and Add inconsistent", p.twice(), p.add(p));
+ assertPointsEqual("Twice p - p is not p", p, p.twice().subtract(p));
+ assertPointsEqual("TwicePlus(p, -p) is not p", p, p.twicePlus(p.negate()));
+ assertPointsEqual("p - p is not infinity", infinity, p.subtract(p));
+ assertPointsEqual("p plus infinity is not p", p, p.add(infinity));
+ assertPointsEqual("infinity plus p is not p", p, infinity.add(p));
+ assertPointsEqual("infinity plus infinity is not infinity ", infinity, infinity.add(infinity));
+ assertPointsEqual("Twice infinity is not infinity ", infinity, infinity.twice());
+ }
+
+ /**
+ * Calls <code>implTestAddSubtract()</code> for literature values, both
+ * for <code>Fp</code> and <code>F2m</code>.
+ */
+ public void testAddSubtractMultiplySimple()
+ {
+ int fpBits = fp.curve.getOrder().bitLength();
+ for (int iFp = 0; iFp < fp.pointSource.length / 2; iFp++)
+ {
+ implTestAddSubtract(fp.p[iFp], fp.infinity);
+
+ implTestMultiplyAll(fp.p[iFp], fpBits);
+ implTestMultiplyAll(fp.infinity, fpBits);
+ }
+
+ int f2mBits = f2m.curve.getOrder().bitLength();
+ for (int iF2m = 0; iF2m < f2m.pointSource.length / 2; iF2m++)
+ {
+ implTestAddSubtract(f2m.p[iF2m], f2m.infinity);
+
+ implTestMultiplyAll(f2m.p[iF2m], f2mBits);
+ implTestMultiplyAll(f2m.infinity, f2mBits);
+ }
+ }
+
+ /**
+ * Test encoding with and without point compression.
+ *
+ * @param p
+ * The point to be encoded and decoded.
+ */
+ private void implTestEncoding(ECPoint p)
+ {
+ // Not Point Compression
+ byte[] unCompBarr = p.getEncoded(false);
+ ECPoint decUnComp = p.getCurve().decodePoint(unCompBarr);
+ assertPointsEqual("Error decoding uncompressed point", p, decUnComp);
+
+ // Point compression
+ byte[] compBarr = p.getEncoded(true);
+ ECPoint decComp = p.getCurve().decodePoint(compBarr);
+ assertPointsEqual("Error decoding compressed point", p, decComp);
+ }
+
+ private void implAddSubtractMultiplyTwiceEncodingTest(ECCurve curve, ECPoint q, BigInteger n)
+ {
+ // Get point at infinity on the curve
+ ECPoint infinity = curve.getInfinity();
+
+ implTestAddSubtract(q, infinity);
+ implTestMultiply(q, n.bitLength());
+ implTestMultiply(infinity, n.bitLength());
+
+ int logSize = 32 - Integers.numberOfLeadingZeros(curve.getFieldSize() - 1);
+ int rounds = Math.max(2, Math.min(10, 32 - 3 * logSize));
+
+ ECPoint p = q;
+ for (int i = 0; i < rounds; ++i)
+ {
+ implTestEncoding(p);
+ p = p.twice();
+ }
+ }
+
+ private void implSqrtTest(ECCurve c)
+ {
+ if (ECAlgorithms.isFpCurve(c))
+ {
+ BigInteger p = c.getField().getCharacteristic();
+ BigInteger pMinusOne = p.subtract(ECConstants.ONE);
+ BigInteger legendreExponent = p.shiftRight(1);
+
+ ECFieldElement zero = c.fromBigInteger(BigInteger.ZERO);
+ assertEquals(zero, zero.sqrt());
+
+ ECFieldElement one = c.fromBigInteger(BigInteger.ONE);
+ assertEquals(one, one.sqrt());
+
+ for (int i = 0; i < 20; ++i)
+ {
+ BigInteger x = BigIntegers.createRandomInRange(ECConstants.TWO, pMinusOne, secRand);
+ ECFieldElement fe = c.fromBigInteger(x);
+ ECFieldElement root = fe.sqrt();
+
+ if (root == null)
+ {
+ assertEquals(pMinusOne, x.modPow(legendreExponent, p));
+ }
+ else
+ {
+ assertEquals(fe, root.square());
+ }
+ }
+ }
+ else if (ECAlgorithms.isF2mCurve(c))
+ {
+ int m = c.getFieldSize();
+ BigInteger x = new BigInteger(m, secRand);
+ ECFieldElement fe = c.fromBigInteger(x);
+ for (int i = 0; i < 100; ++i)
+ {
+ ECFieldElement sq = fe.square();
+ ECFieldElement check = sq.sqrt();
+ assertEquals(fe, check);
+ fe = sq;
+ }
+ }
+ }
+
+ private void implValidityTest(ECCurve c, ECPoint g)
+ {
+ assertTrue(g.isValid());
+
+ if (ECAlgorithms.isF2mCurve(c))
+ {
+ BigInteger h = c.getCofactor();
+ if (null != h)
+ {
+ if (!h.testBit(0))
+ {
+ ECFieldElement sqrtB = c.getB().sqrt();
+ ECPoint order2 = c.createPoint(ECConstants.ZERO, sqrtB.toBigInteger());
+ assertTrue(order2.twice().isInfinity());
+ assertFalse(order2.isValid());
+ ECPoint bad2 = g.add(order2);
+ assertFalse(bad2.isValid());
+ ECPoint good2 = bad2.add(order2);
+ assertTrue(good2.isValid());
+
+ if (!h.testBit(1))
+ {
+ ECFieldElement L = solveQuadraticEquation(c, c.getA());
+ assertNotNull(L);
+ ECFieldElement T = sqrtB;
+ ECFieldElement x = T.sqrt();
+ ECFieldElement y = T.add(x.multiply(L));
+ ECPoint order4 = c.createPoint(x.toBigInteger(), y.toBigInteger());
+ assertTrue(order4.twice().equals(order2));
+ assertFalse(order4.isValid());
+ ECPoint bad4_1 = g.add(order4);
+ assertFalse(bad4_1.isValid());
+ ECPoint bad4_2 = bad4_1.add(order4);
+ assertFalse(bad4_2.isValid());
+ ECPoint bad4_3 = bad4_2.add(order4);
+ assertFalse(bad4_3.isValid());
+ ECPoint good4 = bad4_3.add(order4);
+ assertTrue(good4.isValid());
+ }
+ }
+ }
+ }
+ }
+
+ private void implAddSubtractMultiplyTwiceEncodingTestAllCoords(X9ECParameters x9ECParameters)
+ {
+ BigInteger n = x9ECParameters.getN();
+ ECPoint G = x9ECParameters.getG();
+ ECCurve C = x9ECParameters.getCurve();
+
+ int[] coords = ECCurve.getAllCoordinateSystems();
+ for (int i = 0; i < coords.length; ++i)
+ {
+ int coord = coords[i];
+ if (C.supportsCoordinateSystem(coord))
+ {
+ ECCurve c = C;
+ ECPoint g = G;
+
+ if (c.getCoordinateSystem() != coord)
+ {
+ c = C.configure().setCoordinateSystem(coord).create();
+ g = c.importPoint(G);
+ }
+
+ // The generator is multiplied by random b to get random q
+ BigInteger b = new BigInteger(n.bitLength(), secRand);
+ ECPoint q = g.multiply(b).normalize();
+
+ implAddSubtractMultiplyTwiceEncodingTest(c, q, n);
+
+ implSqrtTest(c);
+
+ implValidityTest(c, g);
+ }
+ }
+ }
+
+ /**
+ * Calls <code>implTestAddSubtract()</code>,
+ * <code>implTestMultiply</code> and <code>implTestEncoding</code> for
+ * the standard elliptic curves as given in <code>SECNamedCurves</code>.
+ */
+ @LargeTest
+ public void testAddSubtractMultiplyTwiceEncoding()
+ {
+ Set names = new HashSet(enumToList(ECNamedCurveTable.getNames()));
+ names.addAll(enumToList(CustomNamedCurves.getNames()));
+
+ Iterator it = names.iterator();
+ while (it.hasNext())
+ {
+ String name = (String)it.next();
+
+ X9ECParameters x9A = ECNamedCurveTable.getByName(name);
+ X9ECParameters x9B = CustomNamedCurves.getByName(name);
+
+ if (x9A != null && x9B != null)
+ {
+ assertEquals(x9A.getCurve().getField(), x9B.getCurve().getField());
+ assertEquals(x9A.getCurve().getA().toBigInteger(), x9B.getCurve().getA().toBigInteger());
+ assertEquals(x9A.getCurve().getB().toBigInteger(), x9B.getCurve().getB().toBigInteger());
+ assertOptionalValuesAgree(x9A.getCurve().getCofactor(), x9B.getCurve().getCofactor());
+ assertOptionalValuesAgree(x9A.getCurve().getOrder(), x9B.getCurve().getOrder());
+
+ assertPointsEqual("Custom curve base-point inconsistency", x9A.getG(), x9B.getG());
+
+ assertEquals(x9A.getH(), x9B.getH());
+ assertEquals(x9A.getN(), x9B.getN());
+ assertOptionalValuesAgree(x9A.getSeed(), x9B.getSeed());
+
+ BigInteger k = new BigInteger(x9A.getN().bitLength(), secRand);
+ ECPoint pA = x9A.getG().multiply(k);
+ ECPoint pB = x9B.getG().multiply(k);
+ assertPointsEqual("Custom curve multiplication inconsistency", pA, pB);
+ }
+
+ if (x9A != null)
+ {
+ implAddSubtractMultiplyTwiceEncodingTestAllCoords(x9A);
+ }
+
+ if (x9B != null)
+ {
+ implAddSubtractMultiplyTwiceEncodingTestAllCoords(x9B);
+ }
+ }
+ }
+
+ public void testExampleFpB0() throws Exception
+ {
+ /*
+ * The supersingular curve y^2 = x^3 - 3.x (i.e. with 'B' == 0) from RFC 6508 2.1, with
+ * curve parameters from RFC 6509 Appendix A.
+ */
+ BigInteger p = fromHex(
+ "997ABB1F0A563FDA65C61198DAD0657A"
+ + "416C0CE19CB48261BE9AE358B3E01A2E"
+ + "F40AAB27E2FC0F1B228730D531A59CB0"
+ + "E791B39FF7C88A19356D27F4A666A6D0"
+ + "E26C6487326B4CD4512AC5CD65681CE1"
+ + "B6AFF4A831852A82A7CF3C521C3C09AA"
+ + "9F94D6AF56971F1FFCE3E82389857DB0"
+ + "80C5DF10AC7ACE87666D807AFEA85FEB");
+ BigInteger a = p.subtract(BigInteger.valueOf(3));
+ BigInteger b = BigInteger.valueOf(0);
+ byte[] S = null;
+ BigInteger n = p.add(BigInteger.valueOf(1)).shiftRight(2);
+ BigInteger h = BigInteger.valueOf(4);
+
+ ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h));
+
+ X9ECPoint G = configureBasepoint(curve, "04"
+ // Px
+ + "53FC09EE332C29AD0A7990053ED9B52A"
+ + "2B1A2FD60AEC69C698B2F204B6FF7CBF"
+ + "B5EDB6C0F6CE2308AB10DB9030B09E10"
+ + "43D5F22CDB9DFA55718BD9E7406CE890"
+ + "9760AF765DD5BCCB337C86548B72F2E1"
+ + "A702C3397A60DE74A7C1514DBA66910D"
+ + "D5CFB4CC80728D87EE9163A5B63F73EC"
+ + "80EC46C4967E0979880DC8ABEAE63895"
+ // Py
+ + "0A8249063F6009F1F9F1F0533634A135"
+ + "D3E82016029906963D778D821E141178"
+ + "F5EA69F4654EC2B9E7F7F5E5F0DE55F6"
+ + "6B598CCF9A140B2E416CFF0CA9E032B9"
+ + "70DAE117AD547C6CCAD696B5B7652FE0"
+ + "AC6F1E80164AA989492D979FC5A4D5F2"
+ + "13515AD7E9CB99A980BDAD5AD5BB4636"
+ + "ADB9B5706A67DCDE75573FD71BEF16D7");
+
+ X9ECParameters x9 = new X9ECParameters(curve, G, n, h, S);
+
+ implAddSubtractMultiplyTwiceEncodingTestAllCoords(x9);
+ }
+
+ private void assertPointsEqual(String message, ECPoint a, ECPoint b)
+ {
+ // NOTE: We intentionally test points for equality in both directions
+ assertEquals(message, a, b);
+ assertEquals(message, b, a);
+ }
+
+ private void assertOptionalValuesAgree(Object a, Object b)
+ {
+ if (a != null && b != null)
+ {
+ assertEquals(a, b);
+ }
+ }
+
+ private void assertOptionalValuesAgree(byte[] a, byte[] b)
+ {
+ if (a != null && b != null)
+ {
+ assertTrue(Arrays.areEqual(a, b));
+ }
+ }
+
+ private static X9ECPoint configureBasepoint(ECCurve curve, String encoding)
+ {
+ X9ECPoint G = new X9ECPoint(curve, Hex.decode(encoding));
+ WNafUtil.configureBasepoint(G.getPoint());
+ return G;
+ }
+
+ private static ECCurve configureCurve(ECCurve curve)
+ {
+ return curve;
+ }
+
+ private List enumToList(Enumeration en)
+ {
+ List rv = new ArrayList();
+
+ while (en.hasMoreElements())
+ {
+ rv.add(en.nextElement());
+ }
+
+ return rv;
+ }
+
+ private static BigInteger fromHex(
+ String hex)
+ {
+ return new BigInteger(1, Hex.decode(hex));
+ }
+
+ private static ECFieldElement solveQuadraticEquation(ECCurve c, ECFieldElement rhs)
+ {
+ if (rhs.isZero())
+ {
+ return rhs;
+ }
+
+ ECFieldElement gamma, z, zeroElement = c.fromBigInteger(ECConstants.ZERO);
+
+ int m = c.getFieldSize();
+ Random rand = new Random();
+ do
+ {
+ ECFieldElement t = c.fromBigInteger(new BigInteger(m, rand));
+ z = zeroElement;
+ ECFieldElement w = rhs;
+ for (int i = 1; i < m; i++)
+ {
+ ECFieldElement w2 = w.square();
+ z = z.square().add(w2.multiply(t));
+ w = w2.add(rhs);
+ }
+ if (!w.isZero())
+ {
+ return null;
+ }
+ gamma = z.square().add(z);
+ }
+ while (gamma.isZero());
+
+ return z;
+ }
+
+ public static Test suite()
+ {
+ return new TestSuite(ECPointTest.class);
+ }
+}
diff --git a/bcprov/src/test/java/org/bouncycastle/math/ec/test/F2mProofer.java b/bcprov/src/test/java/org/bouncycastle/math/ec/test/F2mProofer.java
new file mode 100644
index 00000000..b6875203
--- /dev/null
+++ b/bcprov/src/test/java/org/bouncycastle/math/ec/test/F2mProofer.java
@@ -0,0 +1,204 @@
+package org.bouncycastle.math.ec.test;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Set;
+
+import org.bouncycastle.asn1.sec.SECNamedCurves;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.BigIntegers;
+
+public class F2mProofer
+{
+ private static final int NUM_SAMPLES = 1000;
+
+ private static final String PATH = "crypto/test/src/org/bouncycastle/math/ec/test/samples/";
+
+ private static final String INPUT_FILE_NAME_PREFIX = "Input_";
+
+ private static final String RESULT_FILE_NAME_PREFIX = "Output_";
+
+ /**
+ * The standard curves on which the tests are done
+ */
+ public static final String[] CURVES = { "sect163r2", "sect233r1",
+ "sect283r1", "sect409r1", "sect571r1" };
+
+ private String pointToString(ECPoint.F2m p)
+ {
+ ECFieldElement.F2m x = (ECFieldElement.F2m) p.getAffineXCoord();
+ ECFieldElement.F2m y = (ECFieldElement.F2m) p.getAffineYCoord();
+
+ int m = x.getM();
+ int len = m / 2 + 5;
+
+ StringBuffer sb = new StringBuffer(len);
+ sb.append('(');
+ sb.append(x.toBigInteger().toString(16));
+ sb.append(", ");
+ sb.append(y.toBigInteger().toString(16));
+ sb.append(')');
+
+ return sb.toString();
+ }
+
+ private void generateRandomInput(X9ECParameters x9ECParameters)
+ throws NoSuchAlgorithmException, IOException
+ {
+ ECPoint.F2m g = (ECPoint.F2m) x9ECParameters.getG();
+ int m = ((ECFieldElement.F2m) (g.getAffineXCoord())).getM();
+
+ SecureRandom secRand = SecureRandom.getInstance("SHA1PRNG");
+ Properties inputProps = new Properties();
+ for (int i = 0; i < NUM_SAMPLES; i++)
+ {
+ BigInteger rand = BigIntegers.createRandomBigInteger(m, secRand);
+ inputProps.put(Integer.toString(i), rand.toString(16));
+ }
+ String bits = Integer.toString(m);
+ FileOutputStream fos = new FileOutputStream(PATH
+ + INPUT_FILE_NAME_PREFIX + bits + ".properties");
+ inputProps.store(fos, "Input Samples of length" + bits);
+ }
+
+ private void multiplyPoints(X9ECParameters x9ECParameters,
+ String classPrefix) throws IOException
+ {
+ ECPoint.F2m g = (ECPoint.F2m) x9ECParameters.getG();
+ int m = ((ECFieldElement.F2m) (g.getAffineXCoord())).getM();
+
+ String inputFileName = PATH + INPUT_FILE_NAME_PREFIX + m
+ + ".properties";
+ Properties inputProps = new Properties();
+ inputProps.load(new FileInputStream(inputFileName));
+
+ Properties outputProps = new Properties();
+
+ for (int i = 0; i < NUM_SAMPLES; i++)
+ {
+ BigInteger rand = new BigInteger(inputProps.getProperty(Integer
+ .toString(i)), 16);
+ ECPoint.F2m result = (ECPoint.F2m) g.multiply(rand).normalize();
+ String resultStr = pointToString(result);
+ outputProps.setProperty(Integer.toString(i), resultStr);
+ }
+
+ String outputFileName = PATH + RESULT_FILE_NAME_PREFIX + classPrefix
+ + "_" + m + ".properties";
+ FileOutputStream fos = new FileOutputStream(outputFileName);
+ outputProps.store(fos, "Output Samples of length" + m);
+ }
+
+ private Properties loadResults(String classPrefix, int m)
+ throws IOException
+ {
+ FileInputStream fis = new FileInputStream(PATH
+ + RESULT_FILE_NAME_PREFIX + classPrefix + "_" + m + ".properties");
+ Properties res = new Properties();
+ res.load(fis);
+ return res;
+
+ }
+
+ private void compareResult(X9ECParameters x9ECParameters,
+ String classPrefix1, String classPrefix2) throws IOException
+ {
+ ECPoint.F2m g = (ECPoint.F2m) x9ECParameters.getG();
+ int m = ((ECFieldElement.F2m) (g.getAffineXCoord())).getM();
+
+ Properties res1 = loadResults(classPrefix1, m);
+ Properties res2 = loadResults(classPrefix2, m);
+
+ Set keys = res1.keySet();
+ Iterator iter = keys.iterator();
+ while (iter.hasNext())
+ {
+ String key = (String) iter.next();
+ String result1 = res1.getProperty(key);
+ String result2 = res2.getProperty(key);
+ if (!(result1.equals(result2)))
+ {
+ System.err.println("Difference found: m = " + m + ", "
+ + result1 + " does not equal " + result2);
+ }
+ }
+
+ }
+
+ private static void usage()
+ {
+ System.err.println("Usage: F2mProofer [-init | -multiply <className> "
+ + "| -compare <className1> <className2>]");
+ }
+
+ public static void main(String[] args) throws Exception
+ {
+ if (args.length == 0)
+ {
+ usage();
+ return;
+ }
+ F2mProofer proofer = new F2mProofer();
+ if (args[0].equals("-init"))
+ {
+ System.out.println("Generating random input...");
+ for (int i = 0; i < CURVES.length; i++)
+ {
+ X9ECParameters x9ECParameters = SECNamedCurves
+ .getByName(CURVES[i]);
+ proofer.generateRandomInput(x9ECParameters);
+ }
+ System.out
+ .println("Successfully generated random input in " + PATH);
+ }
+ else if (args[0].equals("-compare"))
+ {
+ if (args.length < 3)
+ {
+ usage();
+ return;
+ }
+ String classPrefix1 = args[1];
+ String classPrefix2 = args[2];
+ System.out.println("Comparing results...");
+ for (int i = 0; i < CURVES.length; i++)
+ {
+ X9ECParameters x9ECParameters = SECNamedCurves
+ .getByName(CURVES[i]);
+ proofer.compareResult(x9ECParameters, classPrefix1,
+ classPrefix2);
+ }
+ System.out.println("Successfully compared results in " + PATH);
+ }
+ else if (args[0].equals("-multiply"))
+ {
+ if (args.length < 2)
+ {
+ usage();
+ return;
+ }
+ String classPrefix = args[1];
+ System.out.println("Multiplying points...");
+ for (int i = 0; i < CURVES.length; i++)
+ {
+ X9ECParameters x9ECParameters = SECNamedCurves
+ .getByName(CURVES[i]);
+ proofer.multiplyPoints(x9ECParameters, classPrefix);
+ }
+ System.out.println("Successfully generated multiplied points in "
+ + PATH);
+ }
+ else
+ {
+ usage();
+ }
+ }
+}
diff --git a/bcprov/src/test/java/org/bouncycastle/math/ec/test/FixedPointTest.java b/bcprov/src/test/java/org/bouncycastle/math/ec/test/FixedPointTest.java
new file mode 100644
index 00000000..08d4c087
--- /dev/null
+++ b/bcprov/src/test/java/org/bouncycastle/math/ec/test/FixedPointTest.java
@@ -0,0 +1,90 @@
+package org.bouncycastle.math.ec.test;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.ec.CustomNamedCurves;
+import org.bouncycastle.math.ec.ECAlgorithms;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.FixedPointCombMultiplier;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+public class FixedPointTest
+ extends TestCase
+{
+ private static final SecureRandom RANDOM = new SecureRandom();
+
+ private static final int TESTS_PER_CURVE = 5;
+
+ public void testFixedPointMultiplier()
+ {
+ final FixedPointCombMultiplier M = new FixedPointCombMultiplier();
+
+ Set names = new HashSet(enumToList(ECNamedCurveTable.getNames()));
+ names.addAll(enumToList(CustomNamedCurves.getNames()));
+
+ Iterator it = names.iterator();
+ while (it.hasNext())
+ {
+ String name = (String)it.next();
+
+ X9ECParameters x9A = ECNamedCurveTable.getByName(name);
+ X9ECParameters x9B = CustomNamedCurves.getByName(name);
+
+ X9ECParameters x9 = x9B != null ? x9B : x9A;
+
+ for (int i = 0; i < TESTS_PER_CURVE; ++i)
+ {
+ BigInteger k = new BigInteger(x9.getN().bitLength(), RANDOM);
+ ECPoint pRef = ECAlgorithms.referenceMultiply(x9.getG(), k);
+
+ if (x9A != null)
+ {
+ ECPoint pA = M.multiply(x9A.getG(), k);
+ assertPointsEqual("Standard curve fixed-point failure", pRef, pA);
+ }
+
+ if (x9B != null)
+ {
+ ECPoint pB = M.multiply(x9B.getG(), k);
+ assertPointsEqual("Custom curve fixed-point failure", pRef, pB);
+ }
+ }
+ }
+ }
+
+ private List enumToList(Enumeration en)
+ {
+ List rv = new ArrayList();
+
+ while (en.hasMoreElements())
+ {
+ rv.add(en.nextElement());
+ }
+
+ return rv;
+ }
+
+ private void assertPointsEqual(String message, ECPoint a, ECPoint b)
+ {
+ // NOTE: We intentionally test points for equality in both directions
+ assertEquals(message, a, b);
+ assertEquals(message, b, a);
+ }
+
+ public static Test suite()
+ {
+ return new TestSuite(FixedPointTest.class);
+ }
+}
diff --git a/bcprov/src/test/java/org/bouncycastle/math/raw/test/AllTests.java b/bcprov/src/test/java/org/bouncycastle/math/raw/test/AllTests.java
new file mode 100644
index 00000000..c15cb94d
--- /dev/null
+++ b/bcprov/src/test/java/org/bouncycastle/math/raw/test/AllTests.java
@@ -0,0 +1,46 @@
+package org.bouncycastle.math.raw.test;
+
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.bouncycastle.test.PrintTestResult;
+
+public class AllTests
+ extends TestCase
+{
+ public static void main (String[] args)
+ throws Exception
+ {
+ PrintTestResult.printResult( junit.textui.TestRunner.run(suite()));
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ TestSuite suite = new TestSuite("Raw math tests");
+
+ suite.addTest(InterleaveTest.suite());
+
+ return new BCTestSetup(suite);
+ }
+
+ static class BCTestSetup
+ extends TestSetup
+ {
+ public BCTestSetup(Test test)
+ {
+ super(test);
+ }
+
+ protected void setUp()
+ {
+
+ }
+
+ protected void tearDown()
+ {
+
+ }
+ }
+}
diff --git a/bcprov/src/test/java/org/bouncycastle/math/raw/test/InterleaveTest.java b/bcprov/src/test/java/org/bouncycastle/math/raw/test/InterleaveTest.java
new file mode 100644
index 00000000..d701030b
--- /dev/null
+++ b/bcprov/src/test/java/org/bouncycastle/math/raw/test/InterleaveTest.java
@@ -0,0 +1,86 @@
+package org.bouncycastle.math.raw.test;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.math.raw.Interleave;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+public class InterleaveTest extends TestCase
+{
+ private static final int ITERATIONS = 1000;
+
+ private static final SecureRandom R = new SecureRandom();
+
+ public void testExpand8To16()
+ {
+ // NOTE: Just test all inputs here
+ for (int iteration = 0; iteration < 256; ++iteration)
+ {
+ // NOTE: Implementation is expected to mask input
+ int x = iteration | (R.nextInt() << 8);
+ int expected = (int)referenceShuffle(x & 0xFFL);
+ int actual = Interleave.expand8to16(x);
+ assertEquals(expected, actual);
+ }
+ }
+
+ public void testExpand16To32()
+ {
+ for (int iteration = 0; iteration < ITERATIONS; ++iteration)
+ {
+ // NOTE: Implementation is expected to mask input
+ int x = R.nextInt();
+ int expected = (int)referenceShuffle(x & 0xFFFFL);
+ int actual = Interleave.expand16to32(x);
+ assertEquals(expected, actual);
+ }
+ }
+
+ public void testExpand32To64()
+ {
+ for (int iteration = 0; iteration < ITERATIONS; ++iteration)
+ {
+ int x = R.nextInt();
+ long expected = referenceShuffle(x & 0xFFFFFFFFL);
+ long actual = Interleave.expand32to64(x);
+ assertEquals(expected, actual);
+ }
+ }
+
+ public void testExpand64To128()
+ {
+ for (int iteration = 0; iteration < ITERATIONS; ++iteration)
+ {
+ long x = R.nextLong();
+ long expected = referenceShuffle(x);
+ long[] actual = new long[9];
+ int offset = iteration % 8;
+ // NOTE: Implementation must overwrite existing values
+ actual[offset ] = R.nextLong();
+ actual[offset + 1] = R.nextLong();
+ Interleave.expand64To128(x, actual, offset);
+ assertEquals((expected ) & 0x5555555555555555L, actual[offset ]);
+ assertEquals((expected >>> 1) & 0x5555555555555555L, actual[offset + 1]);
+ }
+ }
+
+ public static Test suite()
+ {
+ return new TestSuite(InterleaveTest.class);
+ }
+
+ private static long referenceShuffle(long x)
+ {
+ long result = 0, y = x >>> 32;
+ for (int bit = 0; bit < 32; ++bit)
+ {
+ long selector = 1L << bit;
+ result |= ((x & selector) << (bit ));
+ result |= ((y & selector) << (bit + 1));
+ }
+ return result;
+ }
+}
diff --git a/bcprov/src/test/java/org/bouncycastle/math/test/AllTests.java b/bcprov/src/test/java/org/bouncycastle/math/test/AllTests.java
new file mode 100644
index 00000000..f849b508
--- /dev/null
+++ b/bcprov/src/test/java/org/bouncycastle/math/test/AllTests.java
@@ -0,0 +1,46 @@
+package org.bouncycastle.math.test;
+
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.bouncycastle.test.PrintTestResult;
+
+public class AllTests
+ extends TestCase
+{
+ public static void main (String[] args)
+ throws Exception
+ {
+ PrintTestResult.printResult( junit.textui.TestRunner.run(suite()));
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ TestSuite suite = new TestSuite("Math tests");
+
+ suite.addTestSuite(PrimesTest.class);
+
+ return new BCTestSetup(suite);
+ }
+
+ static class BCTestSetup
+ extends TestSetup
+ {
+ public BCTestSetup(Test test)
+ {
+ super(test);
+ }
+
+ protected void setUp()
+ {
+
+ }
+
+ protected void tearDown()
+ {
+
+ }
+ }
+}
diff --git a/bcprov/src/test/java/org/bouncycastle/math/test/PrimesTest.java b/bcprov/src/test/java/org/bouncycastle/math/test/PrimesTest.java
new file mode 100644
index 00000000..13af4cac
--- /dev/null
+++ b/bcprov/src/test/java/org/bouncycastle/math/test/PrimesTest.java
@@ -0,0 +1,183 @@
+package org.bouncycastle.math.test;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.math.Primes;
+import org.bouncycastle.math.Primes.MROutput;
+import org.bouncycastle.math.Primes.STOutput;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.BigIntegers;
+
+public class PrimesTest extends TestCase
+{
+ private static final int ITERATIONS = 10;
+ private static final int PRIME_BITS = 256;
+ private static final int PRIME_CERTAINTY = 100;
+
+ private static final BigInteger TWO = BigInteger.valueOf(2);
+
+ private static final SecureRandom R = new SecureRandom();
+
+ public void testHasAnySmallFactors()
+ {
+ for (int iterations = 0; iterations < ITERATIONS; ++iterations)
+ {
+ BigInteger prime = randomPrime();
+ assertFalse(Primes.hasAnySmallFactors(prime));
+
+ // NOTE: Loop through ALL small values to be sure no small primes are missing
+ for (int smallFactor = 2; smallFactor <= Primes.SMALL_FACTOR_LIMIT; ++smallFactor)
+ {
+ BigInteger nonPrimeWithSmallFactor = BigInteger.valueOf(smallFactor).multiply(prime);
+ assertTrue(Primes.hasAnySmallFactors(nonPrimeWithSmallFactor));
+ }
+ }
+ }
+
+ public void testEnhancedMRProbablePrime()
+ {
+ int mrIterations = (PRIME_CERTAINTY + 1) / 2;
+ for (int iterations = 0; iterations < ITERATIONS; ++iterations)
+ {
+ BigInteger prime = randomPrime();
+ MROutput mr = Primes.enhancedMRProbablePrimeTest(prime, R, mrIterations);
+ assertFalse(mr.isProvablyComposite());
+ assertFalse(mr.isNotPrimePower());
+ assertNull(mr.getFactor());
+
+ BigInteger primePower = prime;
+ for (int i = 0; i <= (iterations % 8); ++i)
+ {
+ primePower = primePower.multiply(prime);
+ }
+
+ MROutput mr2 = Primes.enhancedMRProbablePrimeTest(primePower, R, mrIterations);
+ assertTrue(mr2.isProvablyComposite());
+ assertFalse(mr2.isNotPrimePower());
+ assertEquals(mr2.getFactor(), prime);
+
+ BigInteger nonPrimePower = randomPrime().multiply(prime);
+ MROutput mr3 = Primes.enhancedMRProbablePrimeTest(nonPrimePower, R, mrIterations);
+ assertTrue(mr3.isProvablyComposite());
+ assertTrue(mr3.isNotPrimePower());
+ assertNull(mr.getFactor());
+ }
+ }
+
+ public void testMRProbablePrime()
+ {
+ int mrIterations = (PRIME_CERTAINTY + 1) / 2;
+ for (int iterations = 0; iterations < ITERATIONS; ++iterations)
+ {
+ BigInteger prime = randomPrime();
+ assertTrue(Primes.isMRProbablePrime(prime, R, mrIterations));
+
+ BigInteger nonPrime = randomPrime().multiply(prime);
+ assertFalse(Primes.isMRProbablePrime(nonPrime, R, mrIterations));
+ }
+ }
+
+ public void testMRProbablePrimeToBase()
+ {
+ int mrIterations = (PRIME_CERTAINTY + 1) / 2;
+ for (int iterations = 0; iterations < ITERATIONS; ++iterations)
+ {
+ BigInteger prime = randomPrime();
+ assertTrue(referenceIsMRProbablePrime(prime, mrIterations));
+
+ BigInteger nonPrime = randomPrime().multiply(prime);
+ assertFalse(referenceIsMRProbablePrime(nonPrime, mrIterations));
+ }
+ }
+
+ public void testSTRandomPrime()
+ {
+ Digest[] digests = new Digest[]{ new SHA1Digest(), new SHA256Digest() };
+ for (int digestIndex = 0; digestIndex < digests.length; ++digestIndex)
+ {
+ int coincidenceCount = 0;
+
+ Digest digest = digests[digestIndex];
+ for (int iterations = 0; iterations < ITERATIONS; ++iterations)
+ {
+ try
+ {
+ byte[] inputSeed = new byte[16];
+ R.nextBytes(inputSeed);
+
+ STOutput st = Primes.generateSTRandomPrime(digest, PRIME_BITS, inputSeed);
+ assertTrue(isPrime(st.getPrime()));
+
+ STOutput st2 = Primes.generateSTRandomPrime(digest, PRIME_BITS, inputSeed);
+ assertEquals(st.getPrime(), st2.getPrime());
+ assertEquals(st.getPrimeGenCounter(), st2.getPrimeGenCounter());
+ assertTrue(Arrays.areEqual(st.getPrimeSeed(), st2.getPrimeSeed()));
+
+ for (int i = 0; i < inputSeed.length; ++i)
+ {
+ inputSeed[i] ^= 0xFF;
+ }
+
+ STOutput st3 = Primes.generateSTRandomPrime(digest, PRIME_BITS, inputSeed);
+ assertTrue(!st.getPrime().equals(st3.getPrime()));
+ assertFalse(Arrays.areEqual(st.getPrimeSeed(), st3.getPrimeSeed()));
+
+ if (st.getPrimeGenCounter() == st3.getPrimeGenCounter())
+ {
+ ++coincidenceCount;
+ }
+ }
+ catch (IllegalStateException e)
+ {
+ if (e.getMessage().startsWith("Too many iterations"))
+ {
+ --iterations;
+ continue;
+ }
+
+ throw e;
+ }
+ }
+
+ assertTrue(coincidenceCount * coincidenceCount < ITERATIONS);
+ }
+ }
+
+ public static Test suite()
+ {
+ return new TestSuite(PrimesTest.class);
+ }
+
+ private static boolean referenceIsMRProbablePrime(BigInteger x, int numBases)
+ {
+ BigInteger xSubTwo = x.subtract(TWO);
+
+ for (int i = 0; i < numBases; ++i)
+ {
+ BigInteger b = BigIntegers.createRandomInRange(TWO, xSubTwo, R);
+ if (!Primes.isMRProbablePrimeToBase(x, b))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static boolean isPrime(BigInteger x)
+ {
+ return x.isProbablePrime(PRIME_CERTAINTY);
+ }
+
+ private static BigInteger randomPrime()
+ {
+ return BigIntegers.createRandomPrime(PRIME_BITS, PRIME_CERTAINTY, R);
+ }
+}
diff --git a/bcprov/src/test/java/org/bouncycastle/test/PrintTestResult.java b/bcprov/src/test/java/org/bouncycastle/test/PrintTestResult.java
new file mode 100644
index 00000000..2cca70b2
--- /dev/null
+++ b/bcprov/src/test/java/org/bouncycastle/test/PrintTestResult.java
@@ -0,0 +1,36 @@
+package org.bouncycastle.test;
+
+
+import java.util.Enumeration;
+
+import junit.framework.TestResult;
+
+public class PrintTestResult
+{
+ public static void printResult(TestResult result)
+ {
+ Enumeration e = result.failures();
+ if (e != null)
+ {
+ while (e.hasMoreElements())
+ {
+ System.out.println(e.nextElement());
+ }
+ }
+
+ e = result.errors();
+ if (e != null)
+ {
+ while (e.hasMoreElements())
+ {
+ System.out.println(e.nextElement());
+ }
+ }
+
+ if (!result.wasSuccessful())
+ {
+ System.exit(1);
+ }
+ }
+}
+
diff --git a/bcprov/src/test/java/org/bouncycastle/util/Times.java b/bcprov/src/test/java/org/bouncycastle/util/Times.java
new file mode 100644
index 00000000..617d00bd
--- /dev/null
+++ b/bcprov/src/test/java/org/bouncycastle/util/Times.java
@@ -0,0 +1,9 @@
+package org.bouncycastle.util;
+
+public final class Times
+{
+ public static long nanoTime()
+ {
+ return System.nanoTime();
+ }
+}
diff --git a/mts/Android.bp b/mts/Android.bp
new file mode 100644
index 00000000..be0378fd
--- /dev/null
+++ b/mts/Android.bp
@@ -0,0 +1,44 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// 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 {
+ default_visibility: ["//visibility:private"],
+ default_applicable_licenses: ["external_bouncycastle_license"],
+}
+
+// Tests used in ART MTS.
+android_test {
+ name: "MtsLibcoreBouncyCastleTestCases",
+ platform_apis: true,
+ min_sdk_version: "31",
+ manifest: "AndroidManifest.xml",
+ static_libs: [
+ "bouncycastle-test-lib",
+ "cts-core-test-runner-axt",
+ ],
+ dex_preopt: {
+ enabled: false,
+ },
+ optimize: {
+ enabled: false,
+ },
+ test_suites: [
+ "general-tests",
+ "mts-art",
+ ],
+ host_required: ["cts-dalvik-host-test-runner"],
+ test_config: "MtsLibcoreBouncyCastleTestCases.xml",
+}
diff --git a/mts/AndroidManifest.xml b/mts/AndroidManifest.xml
new file mode 100644
index 00000000..135a8611
--- /dev/null
+++ b/mts/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.libcore.mts.bouncycastle">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-sdk android:minSdkVersion="31" />
+ <application android:usesCleartextTraffic="true"></application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.libcore.mts.bouncycastle"
+ android:label="Bouncy Castle test cases">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsLibcoreTestRunListener" />
+ </instrumentation>
+
+</manifest>
diff --git a/mts/MtsLibcoreBouncyCastleTestCases.xml b/mts/MtsLibcoreBouncyCastleTestCases.xml
new file mode 100644
index 00000000..541731c3
--- /dev/null
+++ b/mts/MtsLibcoreBouncyCastleTestCases.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ 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.
+-->
+<configuration description="Config for MTS Libcore Bouncy Castle test cases">
+ <option name="config-descriptor:metadata" key="component" value="libcore" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <!-- Test is eligible to run on Android Multiuser users other than SYSTEM.
+ See source.android.com/devices/tech/admin/multi-user#user_types -->
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.art.apex" />
+ <option name="config-descriptor:metadata" key="mainline-param" value="com.android.art.apex" />
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <!-- This MTS test module requires wifi, ensure wifi is on -->
+ <option name="run-command" value="settings put global wifi_on 1" />
+ <option name="run-command" value="svc wifi enable" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <!-- this has just the instrumentation which acts as the tests we want to run -->
+ <option name="test-file-name" value="MtsLibcoreBouncyCastleTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.compatibility.testtype.LibcoreTest" >
+ <option name="package" value="android.libcore.mts.bouncycastle" />
+ <option name="instrumentation-arg" key="filter"
+ value="com.android.cts.core.runner.ExpectationBasedFilter" />
+ <option name="core-expectation" value="/knownfailures.txt" />
+ <option name="runtime-hint" value="15m"/>
+ <!-- 20x default timeout of 600sec -->
+ <option name="shell-timeout" value="12000000"/>
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.TestFailureModuleController">
+ <option name="screenshot-on-failure" value="false" />
+ </object>
+
+ <!-- When this test is run in a Mainline context (e.g. with `mts-tradefed`), only enable it if
+ one of the Mainline modules below is present on the device used for testing. -->
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <!-- ART Mainline Module (internal version). -->
+ <option name="mainline-module-package-name" value="com.google.android.art" />
+ <!-- ART Mainline Module (external (AOSP) version). -->
+ <option name="mainline-module-package-name" value="com.android.art" />
+ </object>
+
+ <!-- Only run tests if the device under test is SDK version 31 (Android 12) or above. -->
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" />
+</configuration>
diff --git a/proguard.flags b/proguard.flags
new file mode 100644
index 00000000..4a4ff37a
--- /dev/null
+++ b/proguard.flags
@@ -0,0 +1,185 @@
+-keep class com.android.org.bouncycastle.jce.provider.BouncyCastleProvider { public *; }
+
+# Keep classes for Android supported algorithms, and internal ones loaded
+# through reflection (cf. calls to ConfigurableProvider.addAlgorithm and
+# ConfigurableProvider.addPrivateAlgorithm). The *$Mappings classes are used
+# internally through reflection to configure the algorithms.
+
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$PBEWithHmacSHA1AndAES_128 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$PBEWithHmacSHA1AndAES_256 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$PBEWithHmacSHA224AndAES_128 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$PBEWithHmacSHA224AndAES_256 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$PBEWithHmacSHA256AndAES_128 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$PBEWithHmacSHA256AndAES_256 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$PBEWithHmacSHA384AndAES_128 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$PBEWithHmacSHA384AndAES_256 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$PBEWithHmacSHA512AndAES_128 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$PBEWithHmacSHA512AndAES_256 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$PBKDF2WithHmacSHA18BIT { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$PBKDF2WithHmacSHA1UTF8 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$PBKDF2WithHmacSHA224UTF8 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$PBKDF2WithHmacSHA256UTF8 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$PBKDF2WithHmacSHA384UTF8 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$PBKDF2WithHmacSHA512UTF8 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$PBKDF2withUTF8 { public *; }
+
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPKCS12$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPKCS12$AlgParams { public *; }
+
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBES2AlgorithmParameters$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBES2AlgorithmParameters$PBEWithHmacSHA1AES128AlgorithmParameters { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBES2AlgorithmParameters$PBEWithHmacSHA1AES256AlgorithmParameters { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBES2AlgorithmParameters$PBEWithHmacSHA224AES128AlgorithmParameters { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBES2AlgorithmParameters$PBEWithHmacSHA224AES256AlgorithmParameters { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBES2AlgorithmParameters$PBEWithHmacSHA256AES128AlgorithmParameters { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBES2AlgorithmParameters$PBEWithHmacSHA256AES256AlgorithmParameters { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBES2AlgorithmParameters$PBEWithHmacSHA384AES128AlgorithmParameters { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBES2AlgorithmParameters$PBEWithHmacSHA384AES256AlgorithmParameters { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBES2AlgorithmParameters$PBEWithHmacSHA512AES128AlgorithmParameters { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.PBES2AlgorithmParameters$PBEWithHmacSHA512AES256AlgorithmParameters { public *; }
+
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$CBC { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$ECB { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$PBEWithAESCBC { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$PBEWithAESCBC { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$PBEWithAESCBC { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$PBEWithMD5And128BitAESCBCOpenSSL { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$PBEWithMD5And192BitAESCBCOpenSSL { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$PBEWithMD5And256BitAESCBCOpenSSL { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$PBEWithSHA1AESCBC128 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$PBEWithSHA1AESCBC192 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$PBEWithSHA1AESCBC256 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$PBEWithSHA256AESCBC128 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$PBEWithSHA256AESCBC192 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$PBEWithSHA256AESCBC256 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$PBEWithSHA256And128BitAESBC { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$PBEWithSHA256And192BitAESBC { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$PBEWithSHA256And256BitAESBC { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$PBEWithSHAAnd128BitAESBC { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$PBEWithSHAAnd192BitAESBC { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$PBEWithSHAAnd256BitAESBC { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.AES$Wrap { public *; }
+
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.ARC4$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.ARC4$KeyGen { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.ARC4$PBEWithSHAAnd128Bit { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.ARC4$PBEWithSHAAnd128BitKeyFactory { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.ARC4$PBEWithSHAAnd40Bit { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.ARC4$PBEWithSHAAnd40BitKeyFactory { public *; }
+
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.Blowfish$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.Blowfish$AlgParams { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.Blowfish$ECB { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.Blowfish$KeyGen { public *; }
+
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.DES$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.DES$ECB { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.DES$KeyFactory { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.DES$KeyGenerator { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.DES$PBEWithMD5 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.DES$PBEWithMD5KeyFactory { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.DES$PBEWithSHA1 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.DES$PBEWithSHA1KeyFactory { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters { public *; }
+
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.DESede$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.DESede$ECB { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.DESede$PBEWithSHAAndDES2Key { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.DESede$PBEWithSHAAndDES2KeyFactory { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.DESede$PBEWithSHAAndDES3Key { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.DESede$PBEWithSHAAndDES3KeyFactory { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.DESede$Wrap { public *; }
+
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.RC2$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.RC2$PBEWithMD5AndRC2 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.RC2$PBEWithMD5KeyFactory { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.RC2$PBEWithSHA1AndRC2 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.RC2$PBEWithSHA1KeyFactory { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.RC2$PBEWithSHAAnd128BitKeyFactory { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.RC2$PBEWithSHAAnd128BitRC2 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.RC2$PBEWithSHAAnd40BitKeyFactory { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.RC2$PBEWithSHAAnd40BitRC2 { public *; }
+
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.Twofish$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.Twofish$PBEWithSHA { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.symmetric.Twofish$PBEWithSHAKeyFactory { public *; }
+
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.DSA$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.dsa.AlgorithmParameterGeneratorSpi { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.dsa.AlgorithmParametersSpi { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.dsa.DSASigner$dsa224 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.dsa.DSASigner$dsa256 { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.dsa.DSASigner$noneDSA { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.dsa.DSASigner$stdDSA { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.dsa.KeyFactorySpi { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.dsa.KeyPairGeneratorSpi { public *; }
+
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.DH$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.dh.AlgorithmParameterGeneratorSpi { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.dh.AlgorithmParametersSpi { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.dh.KeyAgreementSpi { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.dh.KeyFactorySpi { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.dh.KeyPairGeneratorSpi { public *; }
+
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.RSA$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.rsa.AlgorithmParametersSpi$PSS { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.rsa.CipherSpi$NoPadding { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyPairGeneratorSpi { public *; }
+
+-keep class com.android.org.bouncycastle.jcajce.provider.digest.SHA1$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.digest.SHA1$PBEWithMacKeyFactory { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.digest.SHA1$SHA1Mac { public *; }
+
+-keep class com.android.org.bouncycastle.jcajce.provider.digest.SHA224$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.digest.SHA224$HashMac { public *; }
+
+-keep class com.android.org.bouncycastle.jcajce.provider.digest.SHA256$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.digest.SHA256$HashMac { public *; }
+
+-keep class com.android.org.bouncycastle.jcajce.provider.digest.SHA384$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.digest.SHA384$HashMac { public *; }
+
+-keep class com.android.org.bouncycastle.jcajce.provider.digest.SHA512$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.digest.SHA512$HashMac { public *; }
+
+-keep class com.android.org.bouncycastle.jcajce.provider.keystore.BC$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.keystore.bc.BcKeyStoreSpi$BouncyCastleStore { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.keystore.bc.BcKeyStoreSpi$Std { public *; }
+
+-keep class com.android.org.bouncycastle.jcajce.provider.keystore.PKCS12$Mappings { public *; }
+-keep class com.android.org.bouncycastle.jcajce.provider.keystore.pkcs12.PKCS12KeyStoreSpi$BCPKCS12KeyStore { public *; }
+
+-keep class com.android.org.bouncycastle.jce.provider.CertStoreCollectionSpi { public *; }
+-keep class com.android.org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi { public *; }
+-keep class com.android.org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi { public *; }
+
+# Classes only accessed from tests in MtsLibcoreBouncyCastleTestCases
+-keep class com.android.org.bouncycastle.asn1.x9.ECNamedCurveTable { public *; }
+-keep class com.android.org.bouncycastle.asn1.x9.X962NamedCurves { public *; }
+-keep class com.android.org.bouncycastle.asn1.x9.X9ECParameters { public *; }
+-keep class com.android.org.bouncycastle.asn1.x9.X9ECPoint { public *; }
+-keep class com.android.org.bouncycastle.crypto.ec.CustomNamedCurves { public *; }
+-keep class com.android.org.bouncycastle.math.Primes { public *; }
+-keep class com.android.org.bouncycastle.math.Primes$* { public *; }
+-keep class com.android.org.bouncycastle.math.ec.ECAlgorithms { public *; }
+-keep class com.android.org.bouncycastle.math.ec.ECCurve { public *; }
+-keep class com.android.org.bouncycastle.math.ec.ECCurve$Config { public *; }
+-keep class com.android.org.bouncycastle.math.ec.ECPoint { public *; }
+-keep class com.android.org.bouncycastle.math.ec.FixedPointCombMultiplier { public *; }
+-keep class com.android.org.bouncycastle.math.raw.Interleave { public *; }
+-keep class com.android.org.bouncycastle.math.raw.Nat { public *; }
+-keep class com.android.org.bouncycastle.math.raw.Nat256 { public *; }
+-keep class com.android.org.bouncycastle.util.Arrays { public *; }
+-keep class com.android.org.bouncycastle.util.Integers { public *; }
+-keep class com.android.org.bouncycastle.util.encoders.Hex { public *; }
+
+# Classes only accessed from tests in CtsLibcoreTestCases
+# tests.com.android.org.bouncycastle.jce.provider.CertBlocklistTest
+-keep class com.android.org.bouncycastle.jce.provider.CertBlocklist { public *; }
+-keep class com.android.org.bouncycastle.util.encoders.Base64 { public *; }
+# tests.com.android.org.bouncycastle.crypto.digests
+-keep class com.android.org.bouncycastle.crypto.digests.*Digest { public *; }
+-keep class com.android.org.bouncycastle.crypto.digests.OpenSSLDigest$* { public *; }
diff --git a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
index 1eeb6e96..51310cb5 100644
--- a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
+++ b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
@@ -961,56 +961,26 @@ public class BaseBlockCipher
{
byte[] iv = new byte[ivLength];
- // BEGIN Android-changed: For PBE keys with no IV, log and use IV of 0
+ // BEGIN Android-changed: Reject PBE keys with no IV
// These keys were accepted in BC 1.52 (and treated as having an IV of 0) but
- // rejected outright in BC 1.54 (even if an IV was passed in params). We
- // want the eventual state to be that an IV can be passed in params, but the key
- // is rejected otherwise. For now, log that these will be rejected in a future
- // release. See b/27995180 for historical details.
- // ivRandom.nextBytes(iv);
+ // rejected outright in BC 1.54 (even if an IV was passed in params).
+ // See b/27995180 for historical details.
if (!isBCPBEKeyWithoutIV(key)) {
ivRandom.nextBytes(iv);
} else {
- // TODO(b/70275132): Change to rejecting these keys
- System.err.println(" ******** DEPRECATED FUNCTIONALITY ********");
- System.err.println(" * You have initialized a cipher with a PBE key with no IV and");
- System.err.println(" * have not provided an IV in the AlgorithmParameterSpec. This");
- System.err.println(" * configuration is deprecated. The cipher will be initialized");
- System.err.println(" * with an all-zero IV, but in a future release this call will");
- System.err.println(" * throw an exception.");
- new InvalidAlgorithmParameterException("No IV set when using PBE key")
- .printStackTrace(System.err);
+ throw new InvalidAlgorithmParameterException("No IV set when using PBE key");
}
- // END Android-changed: For PBE keys with no IV, log and use IV of 0
+ // END Android-changed: Reject PBE keys with no IV
param = new ParametersWithIV(param, iv);
ivParam = (ParametersWithIV)param;
}
else if (cipher.getUnderlyingCipher().getAlgorithmName().indexOf("PGPCFB") < 0)
{
- // BEGIN Android-changed: For PBE keys with no IV, log and use IV of 0
+ // BEGIN Android-changed: Reject PBE keys with no IV
// These keys were accepted in BC 1.52 (and treated as having an IV of 0) but
- // rejected outright in BC 1.54 (even if an IV was passed in params). We
- // want the eventual state to be that an IV can be passed in params, but the key
- // is rejected otherwise. For now, log that these will be rejected in a future
- // release. See b/27995180 for historical details.
- // throw new InvalidAlgorithmParameterException("no IV set when one expected");
- if (!isBCPBEKeyWithoutIV(key)) {
- throw new InvalidAlgorithmParameterException("no IV set when one expected");
- } else {
- // TODO(b/70275132): Change to rejecting these keys
- System.err.println(" ******** DEPRECATED FUNCTIONALITY ********");
- System.err.println(" * You have initialized a cipher with a PBE key with no IV and");
- System.err.println(" * have not provided an IV in the AlgorithmParameterSpec. This");
- System.err.println(" * configuration is deprecated. The cipher will be initialized");
- System.err.println(" * with an all-zero IV, but in a future release this call will");
- System.err.println(" * throw an exception.");
- new InvalidAlgorithmParameterException("No IV set when using PBE key")
- .printStackTrace(System.err);
- // Mimic behaviour in 1.52 by using an IV of 0's
- param = new ParametersWithIV(param, new byte[ivLength]);
- ivParam = (ParametersWithIV)param;
- }
- // END Android-changed: For PBE keys with no IV, log and use IV of 0
+ // rejected outright in BC 1.54 (even if an IV was passed in params).
+ throw new InvalidAlgorithmParameterException("No IV set when using PBE key");
+ // END Android-changed: Reject PBE keys with no IV
}
}
diff --git a/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/custom/sec/test/SecP256R1FieldTest.java b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/custom/sec/test/SecP256R1FieldTest.java
new file mode 100644
index 00000000..39c9fea4
--- /dev/null
+++ b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/custom/sec/test/SecP256R1FieldTest.java
@@ -0,0 +1,179 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.bouncycastle.math.ec.custom.sec.test;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import com.android.org.bouncycastle.asn1.sec.SECObjectIdentifiers;
+import com.android.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.org.bouncycastle.crypto.ec.CustomNamedCurves;
+import com.android.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.org.bouncycastle.math.raw.Nat256;
+
+import junit.framework.TestCase;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP256R1FieldTest extends TestCase
+{
+ private static final SecureRandom RANDOM = new SecureRandom();
+
+ private static final X9ECParameters DP = CustomNamedCurves
+ .getByOID(SECObjectIdentifiers.secp256r1);
+ private static final BigInteger Q = DP.getCurve().getField().getCharacteristic();
+
+ public void testMultiply1()
+ {
+ int COUNT = 1000;
+
+ for (int i = 0; i < COUNT; ++i)
+ {
+ ECFieldElement x = generateMultiplyInput_Random();
+ ECFieldElement y = generateMultiplyInput_Random();
+
+ BigInteger X = x.toBigInteger(), Y = y.toBigInteger();
+ BigInteger R = X.multiply(Y).mod(Q);
+
+ ECFieldElement z = x.multiply(y);
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+ }
+
+ public void testMultiply2()
+ {
+ int COUNT = 100;
+ ECFieldElement[] inputs = new ECFieldElement[COUNT];
+ BigInteger[] INPUTS = new BigInteger[COUNT];
+
+ for (int i = 0; i < inputs.length; ++i)
+ {
+ inputs[i] = generateMultiplyInput_Random();
+ INPUTS[i] = inputs[i].toBigInteger();
+ }
+
+ for (int j = 0; j < inputs.length; ++j)
+ {
+ for (int k = 0; k < inputs.length; ++k)
+ {
+ BigInteger R = INPUTS[j].multiply(INPUTS[k]).mod(Q);
+
+ ECFieldElement z = inputs[j].multiply(inputs[k]);
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+ }
+ }
+
+ public void testSquare()
+ {
+ int COUNT = 1000;
+
+ for (int i = 0; i < COUNT; ++i)
+ {
+ ECFieldElement x = generateMultiplyInput_Random();
+
+ BigInteger X = x.toBigInteger();
+ BigInteger R = X.multiply(X).mod(Q);
+
+ ECFieldElement z = x.square();
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+ }
+
+ /**
+ * Test multiplication with specifically selected values that triggered a bug in the modular
+ * reduction in OpenSSL (last affected version 0.9.8g).
+ *
+ * See "Practical realisation and elimination of an ECC-related software bug attack", B. B.
+ * Brumley, M. Barbarosa, D. Page, F. Vercauteren.
+ */
+ public void testMultiply_OpenSSLBug()
+ {
+ int COUNT = 100;
+
+ for (int i = 0; i < COUNT; ++i)
+ {
+ ECFieldElement x = generateMultiplyInputA_OpenSSLBug();
+ ECFieldElement y = generateMultiplyInputB_OpenSSLBug();
+
+ BigInteger X = x.toBigInteger(), Y = y.toBigInteger();
+ BigInteger R = X.multiply(Y).mod(Q);
+
+ ECFieldElement z = x.multiply(y);
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+ }
+
+ /**
+ * Test squaring with specifically selected values that triggered a bug in the modular reduction
+ * in OpenSSL (last affected version 0.9.8g).
+ *
+ * See "Practical realisation and elimination of an ECC-related software bug attack", B. B.
+ * Brumley, M. Barbarosa, D. Page, F. Vercauteren.
+ */
+ public void testSquare_OpenSSLBug()
+ {
+ int COUNT = 100;
+
+ for (int i = 0; i < COUNT; ++i)
+ {
+ ECFieldElement x = generateSquareInput_OpenSSLBug();
+
+ BigInteger X = x.toBigInteger();
+ BigInteger R = X.multiply(X).mod(Q);
+
+ ECFieldElement z = x.square();
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+ }
+
+ private ECFieldElement fe(BigInteger x)
+ {
+ return DP.getCurve().fromBigInteger(x);
+ }
+
+ private ECFieldElement generateMultiplyInput_Random()
+ {
+ return fe(new BigInteger(DP.getCurve().getFieldSize() + 32, RANDOM).mod(Q));
+ }
+
+ private ECFieldElement generateMultiplyInputA_OpenSSLBug()
+ {
+ int[] x = Nat256.create();
+ x[0] = RANDOM.nextInt() >>> 1;
+ x[4] = 3;
+ x[7] = -1;
+
+ return fe(Nat256.toBigInteger(x));
+ }
+
+ private ECFieldElement generateMultiplyInputB_OpenSSLBug()
+ {
+ int[] x = Nat256.create();
+ x[0] = RANDOM.nextInt() >>> 1;
+ x[3] = 1;
+ x[7] = -1;
+
+ return fe(Nat256.toBigInteger(x));
+ }
+
+ private ECFieldElement generateSquareInput_OpenSSLBug()
+ {
+ int[] x = Nat256.create();
+ x[0] = RANDOM.nextInt() >>> 1;
+ x[4] = 2;
+ x[7] = -1;
+
+ return fe(Nat256.toBigInteger(x));
+ }
+}
diff --git a/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/custom/sec/test/SecP384R1FieldTest.java b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/custom/sec/test/SecP384R1FieldTest.java
new file mode 100644
index 00000000..d43d57a7
--- /dev/null
+++ b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/custom/sec/test/SecP384R1FieldTest.java
@@ -0,0 +1,144 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.bouncycastle.math.ec.custom.sec.test;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import com.android.org.bouncycastle.asn1.sec.SECObjectIdentifiers;
+import com.android.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.org.bouncycastle.crypto.ec.CustomNamedCurves;
+import com.android.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.org.bouncycastle.math.raw.Nat;
+
+import junit.framework.TestCase;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP384R1FieldTest extends TestCase
+{
+ private static final SecureRandom RANDOM = new SecureRandom();
+
+ private static final X9ECParameters DP = CustomNamedCurves
+ .getByOID(SECObjectIdentifiers.secp384r1);
+ private static final BigInteger Q = DP.getCurve().getField().getCharacteristic();
+
+ public void testMultiply1()
+ {
+ int COUNT = 1000;
+
+ for (int i = 0; i < COUNT; ++i)
+ {
+ ECFieldElement x = generateMultiplyInput_Random();
+ ECFieldElement y = generateMultiplyInput_Random();
+
+ BigInteger X = x.toBigInteger(), Y = y.toBigInteger();
+ BigInteger R = X.multiply(Y).mod(Q);
+
+ ECFieldElement z = x.multiply(y);
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+ }
+
+ public void testMultiply2()
+ {
+ int COUNT = 100;
+ ECFieldElement[] inputs = new ECFieldElement[COUNT];
+ BigInteger[] INPUTS = new BigInteger[COUNT];
+
+ for (int i = 0; i < inputs.length; ++i)
+ {
+ inputs[i] = generateMultiplyInput_Random();
+ INPUTS[i] = inputs[i].toBigInteger();
+ }
+
+ for (int j = 0; j < inputs.length; ++j)
+ {
+ for (int k = 0; k < inputs.length; ++k)
+ {
+ BigInteger R = INPUTS[j].multiply(INPUTS[k]).mod(Q);
+
+ ECFieldElement z = inputs[j].multiply(inputs[k]);
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+ }
+ }
+
+ public void testSquare()
+ {
+ int COUNT = 1000;
+
+ for (int i = 0; i < COUNT; ++i)
+ {
+ ECFieldElement x = generateMultiplyInput_Random();
+
+ BigInteger X = x.toBigInteger();
+ BigInteger R = X.multiply(X).mod(Q);
+
+ ECFieldElement z = x.square();
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+ }
+
+ public void testSquare_CarryBug()
+ {
+ int COUNT = 100;
+
+ for (int i = 0; i < COUNT; ++i)
+ {
+ ECFieldElement x = generateSquareInput_CarryBug();
+
+ BigInteger X = x.toBigInteger();
+ BigInteger R = X.multiply(X).mod(Q);
+
+ ECFieldElement z = x.square();
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+ }
+
+ /*
+ * Based on another example input demonstrating the carry propagation bug in Nat192.square, as
+ * reported by Joseph Friel on dev-crypto.
+ */
+ public void testSquare_CarryBug_Reported()
+ {
+ ECFieldElement x = fe(new BigInteger("2fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", 16));
+
+ BigInteger X = x.toBigInteger();
+ BigInteger R = X.multiply(X).mod(Q);
+
+ ECFieldElement z = x.square();
+ BigInteger Z = z.toBigInteger();
+
+ assertEquals(R, Z);
+ }
+
+ private ECFieldElement fe(BigInteger x)
+ {
+ return DP.getCurve().fromBigInteger(x);
+ }
+
+ private ECFieldElement generateMultiplyInput_Random()
+ {
+ return fe(new BigInteger(DP.getCurve().getFieldSize() + 32, RANDOM).mod(Q));
+ }
+
+ private ECFieldElement generateSquareInput_CarryBug()
+ {
+ int[] x = Nat.create(12);
+ x[0] = RANDOM.nextInt() >>> 1;
+ x[6] = 2;
+ x[10] = -1 << 16;
+ x[11] = -1;
+
+ return fe(Nat.toBigInteger(12, x));
+ }
+}
diff --git a/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/AllTests.java b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/AllTests.java
new file mode 100644
index 00000000..95dfdc82
--- /dev/null
+++ b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/AllTests.java
@@ -0,0 +1,69 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.bouncycastle.math.ec.test;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import com.android.org.bouncycastle.test.PrintTestResult;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AllTests
+ extends TestCase
+{
+ public static void main (String[] args)
+ throws Exception
+ {
+ PrintTestResult.printResult( junit.textui.TestRunner.run(suite()));
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ TestSuite suite = new TestSuite("EC Math tests");
+
+ // Android-changed: parameterized the test.
+ // suite.addTestSuite(ECAlgorithmsTest.class);
+ suite.addTestSuite(ECPointTest.class);
+ suite.addTestSuite(FixedPointTest.class);
+
+ return new BCTestSetup(suite);
+ }
+
+ static List enumToList(Enumeration en)
+ {
+ List rv = new ArrayList();
+
+ while (en.hasMoreElements())
+ {
+ rv.add(en.nextElement());
+ }
+
+ return rv;
+ }
+
+ static class BCTestSetup
+ extends TestSetup
+ {
+ public BCTestSetup(Test test)
+ {
+ super(test);
+ }
+
+ protected void setUp()
+ {
+
+ }
+
+ protected void tearDown()
+ {
+
+ }
+ }
+}
diff --git a/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/ECAlgorithmsTest.java b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/ECAlgorithmsTest.java
new file mode 100644
index 00000000..63f9221c
--- /dev/null
+++ b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/ECAlgorithmsTest.java
@@ -0,0 +1,243 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.bouncycastle.math.ec.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.android.org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import com.android.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.org.bouncycastle.asn1.x9.X9ECPoint;
+import com.android.org.bouncycastle.crypto.ec.CustomNamedCurves;
+import com.android.org.bouncycastle.math.ec.ECAlgorithms;
+import com.android.org.bouncycastle.math.ec.ECCurve;
+import com.android.org.bouncycastle.math.ec.ECPoint;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+// Android-changed: parameterized the test.
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(Parameterized.class)
+public class ECAlgorithmsTest
+{
+ private static final int SCALE = 4;
+ private static final SecureRandom RND = new SecureRandom();
+
+
+ // BEGIN Android-added: parameterized the test.
+ @Parameterized.Parameters(name = "{0}")
+ public static String[] getAllX9ECParameters() {
+ Set<String> names = new HashSet<>(AllTests.enumToList(ECNamedCurveTable.getNames()));
+ names.addAll(AllTests.enumToList(CustomNamedCurves.getNames()));
+ return names.toArray(new String[0]);
+ }
+
+ @Parameterized.Parameter(0)
+ public String name;
+
+ private ArrayList getX9s(String name) {
+ ArrayList<X9ECParameters> x9s = new ArrayList<>();
+
+ X9ECParameters x9 = ECNamedCurveTable.getByName(name);
+ if (x9 != null)
+ {
+ addTestCurves(x9s, x9);
+ }
+
+ x9 = CustomNamedCurves.getByName(name);
+ if (x9 != null)
+ {
+ addTestCurves(x9s, x9);
+ }
+ return x9s;
+ }
+ // END Android-added: parameterized the test.
+
+ @Ignore("secp256r1 is covered by testSumOfMultipliesComplete")
+ public void testSumOfMultiplies()
+ {
+ X9ECParameters x9 = CustomNamedCurves.getByName("secp256r1");
+ assertNotNull(x9);
+ doTestSumOfMultiplies(x9);
+ }
+
+ // TODO Ideally, mark this test not to run by default
+ @Test
+ public void testSumOfMultipliesComplete()
+ {
+ // Android-changed: parameterized the test.
+ // ArrayList x9s = getTestCurves();
+ ArrayList<X9ECParameters> x9s = getX9s(name);
+ Iterator it = x9s.iterator();
+ while (it.hasNext())
+ {
+ X9ECParameters x9 = (X9ECParameters)it.next();
+ doTestSumOfMultiplies(x9);
+ }
+ }
+
+ @Ignore("secp256r1 is covered by testSumOfTwoMultipliesComplete")
+ public void testSumOfTwoMultiplies()
+ {
+ X9ECParameters x9 = CustomNamedCurves.getByName("secp256r1");
+ assertNotNull(x9);
+ doTestSumOfTwoMultiplies(x9);
+ }
+
+ // TODO Ideally, mark this test not to run by default
+ @Test
+ public void testSumOfTwoMultipliesComplete()
+ {
+ // Android-changed: parameterized the test.
+ // ArrayList x9s = getTestCurves();
+ ArrayList<X9ECParameters> x9s = getX9s(name);
+ Iterator it = x9s.iterator();
+ while (it.hasNext())
+ {
+ X9ECParameters x9 = (X9ECParameters)it.next();
+ doTestSumOfTwoMultiplies(x9);
+ }
+ }
+
+ private void doTestSumOfMultiplies(X9ECParameters x9)
+ {
+ ECPoint[] points = new ECPoint[SCALE];
+ BigInteger[] scalars = new BigInteger[SCALE];
+ for (int i = 0; i < SCALE; ++i)
+ {
+ points[i] = getRandomPoint(x9);
+ scalars[i] = getRandomScalar(x9);
+ }
+
+ ECPoint u = x9.getCurve().getInfinity();
+ for (int i = 0; i < SCALE; ++i)
+ {
+ u = u.add(points[i].multiply(scalars[i]));
+
+ ECPoint v = ECAlgorithms.sumOfMultiplies(copyPoints(points, i + 1), copyScalars(scalars, i + 1));
+
+ ECPoint[] results = new ECPoint[]{ u, v };
+ x9.getCurve().normalizeAll(results);
+
+ assertPointsEqual("ECAlgorithms.sumOfMultiplies is incorrect", results[0], results[1]);
+ }
+ }
+
+ private void doTestSumOfTwoMultiplies(X9ECParameters x9)
+ {
+ ECPoint p = getRandomPoint(x9);
+ BigInteger a = getRandomScalar(x9);
+
+ for (int i = 0; i < SCALE; ++i)
+ {
+ ECPoint q = getRandomPoint(x9);
+ BigInteger b = getRandomScalar(x9);
+
+ ECPoint u = p.multiply(a).add(q.multiply(b));
+ ECPoint v = ECAlgorithms.shamirsTrick(p, a, q, b);
+ ECPoint w = ECAlgorithms.sumOfTwoMultiplies(p, a, q, b);
+
+ ECPoint[] results = new ECPoint[]{ u, v, w };
+ x9.getCurve().normalizeAll(results);
+
+ assertPointsEqual("ECAlgorithms.shamirsTrick is incorrect", results[0], results[1]);
+ assertPointsEqual("ECAlgorithms.sumOfTwoMultiplies is incorrect", results[0], results[2]);
+
+ p = q;
+ a = b;
+ }
+ }
+
+ private void assertPointsEqual(String message, ECPoint a, ECPoint b)
+ {
+ assertEquals(message, a, b);
+ }
+
+ private ECPoint[] copyPoints(ECPoint[] ps, int len)
+ {
+ ECPoint[] result = new ECPoint[len];
+ System.arraycopy(ps, 0, result, 0, len);
+ return result;
+ }
+
+ private BigInteger[] copyScalars(BigInteger[] ks, int len)
+ {
+ BigInteger[] result = new BigInteger[len];
+ System.arraycopy(ks, 0, result, 0, len);
+ return result;
+ }
+
+ private ECPoint getRandomPoint(X9ECParameters x9)
+ {
+ return x9.getG().multiply(getRandomScalar(x9));
+ }
+
+ private BigInteger getRandomScalar(X9ECParameters x9)
+ {
+ return new BigInteger(x9.getN().bitLength(), RND);
+ }
+
+ private ArrayList getTestCurves()
+ {
+ ArrayList x9s = new ArrayList();
+ Set names = new HashSet(AllTests.enumToList(ECNamedCurveTable.getNames()));
+ names.addAll(AllTests.enumToList(CustomNamedCurves.getNames()));
+
+ Iterator it = names.iterator();
+ while (it.hasNext())
+ {
+ String name = (String)it.next();
+
+ X9ECParameters x9 = ECNamedCurveTable.getByName(name);
+ if (x9 != null)
+ {
+ addTestCurves(x9s, x9);
+ }
+
+ x9 = CustomNamedCurves.getByName(name);
+ if (x9 != null)
+ {
+ addTestCurves(x9s, x9);
+ }
+ }
+ return x9s;
+ }
+
+ private void addTestCurves(ArrayList x9s, X9ECParameters x9)
+ {
+ ECCurve curve = x9.getCurve();
+
+ int[] coords = ECCurve.getAllCoordinateSystems();
+ for (int i = 0; i < coords.length; ++i)
+ {
+ int coord = coords[i];
+ if (curve.getCoordinateSystem() == coord)
+ {
+ x9s.add(x9);
+ }
+ else if (curve.supportsCoordinateSystem(coord))
+ {
+ ECCurve c = curve.configure().setCoordinateSystem(coord).create();
+ x9s.add(new X9ECParameters(c, new X9ECPoint(c.importPoint(x9.getG()), false), x9.getN(), x9.getH()));
+ }
+ }
+ }
+
+ // Android-changed: Use JUnit4.
+ /*
+ public static Test suite()
+ {
+ return new TestSuite(ECAlgorithmsTest.class);
+ }
+ */
+}
diff --git a/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/ECPointPerformanceTest.java b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/ECPointPerformanceTest.java
new file mode 100644
index 00000000..104b65fb
--- /dev/null
+++ b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/ECPointPerformanceTest.java
@@ -0,0 +1,204 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.bouncycastle.math.ec.test;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import junit.framework.TestCase;
+import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import com.android.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.org.bouncycastle.crypto.ec.CustomNamedCurves;
+import com.android.org.bouncycastle.math.ec.ECCurve;
+import com.android.org.bouncycastle.math.ec.ECPoint;
+import com.android.org.bouncycastle.util.Times;
+
+/**
+ * Compares the performance of the the window NAF point multiplication against conventional point
+ * multiplication.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECPointPerformanceTest extends TestCase
+{
+ static final int MILLIS_PER_ROUND = 200;
+ static final int MILLIS_WARMUP = 1000;
+
+ static final int MULTS_PER_CHECK = 16;
+ static final int NUM_ROUNDS = 10;
+
+ private static String[] COORD_NAMES = new String[]{ "AFFINE", "HOMOGENEOUS", "JACOBIAN", "JACOBIAN-CHUDNOVSKY",
+ "JACOBIAN-MODIFIED", "LAMBDA-AFFINE", "LAMBDA-PROJECTIVE", "SKEWED" };
+
+ private void randMult(String curveName) throws Exception
+ {
+ X9ECParameters spec = ECNamedCurveTable.getByName(curveName);
+ if (spec != null)
+ {
+ randMult(curveName, spec);
+ }
+
+ spec = CustomNamedCurves.getByName(curveName);
+ if (spec != null)
+ {
+ randMult(curveName + " (custom)", spec);
+ }
+ }
+
+ private void randMult(String label, X9ECParameters spec) throws Exception
+ {
+ ECCurve C = spec.getCurve();
+ ECPoint G = (ECPoint)spec.getG();
+ BigInteger n = spec.getN();
+
+ SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
+ random.setSeed(System.currentTimeMillis());
+
+ System.out.println(label);
+
+ int[] coords = ECCurve.getAllCoordinateSystems();
+ for (int i = 0; i < coords.length; ++i)
+ {
+ int coord = coords[i];
+ if (C.supportsCoordinateSystem(coord))
+ {
+ ECCurve c = C;
+ ECPoint g = G;
+
+ boolean defaultCoord = (c.getCoordinateSystem() == coord);
+ if (!defaultCoord)
+ {
+ c = C.configure().setCoordinateSystem(coord).create();
+ g = c.importPoint(G);
+ }
+
+ double avgRate = randMult(random, g, n);
+ String coordName = COORD_NAMES[coord];
+ StringBuffer sb = new StringBuffer();
+ sb.append(" ");
+ sb.append(defaultCoord ? '*' : ' ');
+ sb.append(coordName);
+ for (int j = sb.length(); j < 30; ++j)
+ {
+ sb.append(' ');
+ }
+ sb.append(": ");
+ sb.append(avgRate);
+ sb.append(" mults/sec");
+ for (int j = sb.length(); j < 64; ++j)
+ {
+ sb.append(' ');
+ }
+ sb.append('(');
+ sb.append(1000.0 / avgRate);
+ sb.append(" millis/mult)");
+ System.out.println(sb.toString());
+ }
+ }
+ }
+
+ private double randMult(SecureRandom random, ECPoint g, BigInteger n) throws Exception
+ {
+ BigInteger[] ks = new BigInteger[128];
+ for (int i = 0; i < ks.length; ++i)
+ {
+ ks[i] = new BigInteger(n.bitLength() - 1, random);
+ }
+
+ int ki = 0;
+ ECPoint p = g;
+
+ {
+ long startTime = Times.nanoTime();
+ long goalTime = startTime + 1000000L * MILLIS_WARMUP;
+
+ do
+ {
+ BigInteger k = ks[ki];
+ p = g.multiply(k);
+ if ((ki & 1) != 0)
+ {
+ g = p;
+ }
+ if (++ki == ks.length)
+ {
+ ki = 0;
+ }
+ }
+ while (Times.nanoTime() < goalTime);
+ }
+
+ double minRate = Double.MAX_VALUE, maxRate = Double.MIN_VALUE, totalRate = 0.0;
+
+ for (int i = 1; i <= NUM_ROUNDS; i++)
+ {
+ long startTime = Times.nanoTime();
+ long goalTime = startTime + 1000000L * MILLIS_PER_ROUND;
+ long count = 0, endTime;
+
+ do
+ {
+ ++count;
+
+ for (int j = 0; j < MULTS_PER_CHECK; ++j)
+ {
+ BigInteger k = ks[ki];
+ p = g.multiply(k);
+ if ((ki & 1) != 0)
+ {
+ g = p;
+ }
+ if (++ki == ks.length)
+ {
+ ki = 0;
+ }
+ }
+
+ endTime = Times.nanoTime();
+ }
+ while (endTime < goalTime);
+
+ double roundElapsed = (double)(endTime - startTime);
+ double roundRate = count * MULTS_PER_CHECK * 1000000000L / roundElapsed;
+
+ minRate = Math.min(minRate, roundRate);
+ maxRate = Math.max(maxRate, roundRate);
+ totalRate += roundRate;
+ }
+
+ return (totalRate - minRate - maxRate) / (NUM_ROUNDS - 2);
+ }
+
+ public void testMultiply() throws Exception
+ {
+ // Android-changed: Skip this test as this perf test is timed out.
+ if (true) {
+ return;
+ }
+ SortedSet names = new TreeSet(AllTests.enumToList(ECNamedCurveTable.getNames()));
+ names.addAll(AllTests.enumToList(CustomNamedCurves.getNames()));
+
+ Set oids = new HashSet();
+
+ Iterator it = names.iterator();
+ while (it.hasNext())
+ {
+ String name = (String)it.next();
+ ASN1ObjectIdentifier oid = ECNamedCurveTable.getOID(name);
+ if (oid == null)
+ {
+ oid = CustomNamedCurves.getOID(name);
+ }
+ if (oid != null && !oids.add(oid))
+ {
+ continue;
+ }
+
+ randMult(name);
+ }
+ }
+}
diff --git a/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/ECPointTest.java b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/ECPointTest.java
new file mode 100644
index 00000000..0978d2ef
--- /dev/null
+++ b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/ECPointTest.java
@@ -0,0 +1,744 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.bouncycastle.math.ec.test;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import com.android.org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import com.android.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.org.bouncycastle.asn1.x9.X9ECPoint;
+import com.android.org.bouncycastle.crypto.ec.CustomNamedCurves;
+import com.android.org.bouncycastle.math.ec.ECAlgorithms;
+import com.android.org.bouncycastle.math.ec.ECConstants;
+import com.android.org.bouncycastle.math.ec.ECCurve;
+import com.android.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.org.bouncycastle.math.ec.ECPoint;
+import com.android.org.bouncycastle.math.ec.WNafUtil;
+import com.android.org.bouncycastle.util.Arrays;
+import com.android.org.bouncycastle.util.BigIntegers;
+import com.android.org.bouncycastle.util.Integers;
+import com.android.org.bouncycastle.util.encoders.Hex;
+
+import android.platform.test.annotations.LargeTest;
+
+/**
+ * Test class for {@link com.android.org.bouncycastle.math.ec.ECPoint ECPoint}. All
+ * literature values are taken from "Guide to elliptic curve cryptography",
+ * Darrel Hankerson, Alfred J. Menezes, Scott Vanstone, 2004, Springer-Verlag
+ * New York, Inc.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECPointTest extends TestCase
+{
+ /**
+ * Random source used to generate random points
+ */
+ private SecureRandom secRand = new SecureRandom();
+
+ private ECPointTest.Fp fp = null;
+
+ private ECPointTest.F2m f2m = null;
+
+ /**
+ * Nested class containing sample literature values for <code>Fp</code>.
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class Fp
+ {
+ private final BigInteger q = new BigInteger("1063");
+
+ private final BigInteger a = new BigInteger("4");
+
+ private final BigInteger b = new BigInteger("20");
+
+ private final BigInteger n = new BigInteger("38");
+
+ private final BigInteger h = new BigInteger("1");
+
+ private final ECCurve curve = new ECCurve.Fp(q, a, b, n, h);
+
+ private final ECPoint infinity = curve.getInfinity();
+
+ private final int[] pointSource = { 1, 5, 4, 10, 234, 1024, 817, 912 };
+
+ private ECPoint[] p = new ECPoint[pointSource.length / 2];
+
+ /**
+ * Creates the points on the curve with literature values.
+ */
+ private void createPoints()
+ {
+ for (int i = 0; i < pointSource.length / 2; i++)
+ {
+ p[i] = curve.createPoint(
+ new BigInteger(Integer.toString(pointSource[2 * i])),
+ new BigInteger(Integer.toString(pointSource[2 * i + 1])));
+ }
+ }
+ }
+
+ /**
+ * Nested class containing sample literature values for <code>F2m</code>.
+ * @hide This class is not part of the Android public SDK API
+ */
+ public static class F2m
+ {
+ // Irreducible polynomial for TPB z^4 + z + 1
+ private final int m = 4;
+
+ private final int k1 = 1;
+
+ // a = z^3
+ private final BigInteger aTpb = new BigInteger("1000", 2);
+
+ // b = z^3 + 1
+ private final BigInteger bTpb = new BigInteger("1001", 2);
+
+ private final BigInteger n = new BigInteger("23");
+
+ private final BigInteger h = new BigInteger("1");
+
+ private final ECCurve.F2m curve = new ECCurve.F2m(m, k1, aTpb, bTpb, n, h);
+
+ private final ECPoint.F2m infinity = (ECPoint.F2m) curve.getInfinity();
+
+ private final String[] pointSource = { "0010", "1111", "1100", "1100",
+ "0001", "0001", "1011", "0010" };
+
+ private ECPoint[] p = new ECPoint[pointSource.length / 2];
+
+ /**
+ * Creates the points on the curve with literature values.
+ */
+ private void createPoints()
+ {
+ for (int i = 0; i < pointSource.length / 2; i++)
+ {
+ p[i] = curve.createPoint(
+ new BigInteger(pointSource[2 * i], 2),
+ new BigInteger(pointSource[2 * i + 1], 2));
+ }
+ }
+ }
+
+ public void setUp()
+ {
+ fp = new ECPointTest.Fp();
+ fp.createPoints();
+
+ f2m = new ECPointTest.F2m();
+ f2m.createPoints();
+ }
+
+ /**
+ * Tests, if inconsistent points can be created, i.e. points with exactly
+ * one null coordinate (not permitted).
+ */
+ public void testPointCreationConsistency()
+ {
+ try
+ {
+ ECPoint bad = fp.curve.createPoint(new BigInteger("12"), null);
+ fail();
+ }
+ catch (IllegalArgumentException expected)
+ {
+ }
+
+ try
+ {
+ ECPoint bad = fp.curve.createPoint(null, new BigInteger("12"));
+ fail();
+ }
+ catch (IllegalArgumentException expected)
+ {
+ }
+
+ try
+ {
+ ECPoint bad = f2m.curve.createPoint(new BigInteger("1011"), null);
+ fail();
+ }
+ catch (IllegalArgumentException expected)
+ {
+ }
+
+ try
+ {
+ ECPoint bad = f2m.curve.createPoint(null, new BigInteger("1011"));
+ fail();
+ }
+ catch (IllegalArgumentException expected)
+ {
+ }
+ }
+
+ /**
+ * Tests <code>ECPoint.add()</code> against literature values.
+ *
+ * @param p
+ * The array of literature values.
+ * @param infinity
+ * The point at infinity on the respective curve.
+ */
+ private void implTestAdd(ECPoint[] p, ECPoint infinity)
+ {
+ assertPointsEqual("p0 plus p1 does not equal p2", p[2], p[0].add(p[1]));
+ assertPointsEqual("p1 plus p0 does not equal p2", p[2], p[1].add(p[0]));
+ for (int i = 0; i < p.length; i++)
+ {
+ assertPointsEqual("Adding infinity failed", p[i], p[i].add(infinity));
+ assertPointsEqual("Adding to infinity failed", p[i], infinity.add(p[i]));
+ }
+ }
+
+ /**
+ * Calls <code>implTestAdd()</code> for <code>Fp</code> and
+ * <code>F2m</code>.
+ */
+ public void testAdd()
+ {
+ implTestAdd(fp.p, fp.infinity);
+ implTestAdd(f2m.p, f2m.infinity);
+ }
+
+ /**
+ * Tests <code>ECPoint.twice()</code> against literature values.
+ *
+ * @param p
+ * The array of literature values.
+ */
+ private void implTestTwice(ECPoint[] p)
+ {
+ assertPointsEqual("Twice incorrect", p[3], p[0].twice());
+ assertPointsEqual("Add same point incorrect", p[3], p[0].add(p[0]));
+ }
+
+ /**
+ * Calls <code>implTestTwice()</code> for <code>Fp</code> and
+ * <code>F2m</code>.
+ */
+ public void testTwice()
+ {
+ implTestTwice(fp.p);
+ implTestTwice(f2m.p);
+ }
+
+ private void implTestThreeTimes(ECPoint[] p)
+ {
+ ECPoint P = p[0];
+ ECPoint _3P = P.add(P).add(P);
+ assertPointsEqual("ThreeTimes incorrect", _3P, P.threeTimes());
+ assertPointsEqual("TwicePlus incorrect", _3P, P.twicePlus(P));
+ }
+
+ /**
+ * Calls <code>implTestThreeTimes()</code> for <code>Fp</code> and
+ * <code>F2m</code>.
+ */
+ public void testThreeTimes()
+ {
+ implTestThreeTimes(fp.p);
+ implTestThreeTimes(f2m.p);
+ }
+
+ /**
+ * Goes through all points on an elliptic curve and checks, if adding a
+ * point <code>k</code>-times is the same as multiplying the point by
+ * <code>k</code>, for all <code>k</code>. Should be called for points
+ * on very small elliptic curves only.
+ *
+ * @param p
+ * The base point on the elliptic curve.
+ * @param infinity
+ * The point at infinity on the elliptic curve.
+ */
+ private void implTestAllPoints(ECPoint p, ECPoint infinity)
+ {
+ ECPoint adder = infinity;
+ ECPoint multiplier = infinity;
+
+ BigInteger i = BigInteger.valueOf(1);
+ do
+ {
+ adder = adder.add(p);
+ multiplier = p.multiply(i);
+ assertPointsEqual("Results of add() and multiply() are inconsistent "
+ + i, adder, multiplier);
+ i = i.add(BigInteger.ONE);
+ }
+ while (!(adder.equals(infinity)));
+ }
+
+ /**
+ * Calls <code>implTestAllPoints()</code> for the small literature curves,
+ * both for <code>Fp</code> and <code>F2m</code>.
+ */
+ public void testAllPoints()
+ {
+ for (int i = 0; i < fp.p.length; i++)
+ {
+ implTestAllPoints(fp.p[i], fp.infinity);
+ }
+
+ for (int i = 0; i < f2m.p.length; i++)
+ {
+ implTestAllPoints(f2m.p[i], f2m.infinity);
+ }
+ }
+
+ /**
+ * Checks, if the point multiplication algorithm of the given point yields
+ * the same result as point multiplication done by the reference
+ * implementation given in <code>multiply()</code>. This method chooses a
+ * random number by which the given point <code>p</code> is multiplied.
+ *
+ * @param p
+ * The point to be multiplied.
+ * @param numBits
+ * The bitlength of the random number by which <code>p</code>
+ * is multiplied.
+ */
+ private void implTestMultiply(ECPoint p, int numBits)
+ {
+ BigInteger k = new BigInteger(numBits, secRand);
+ ECPoint ref = ECAlgorithms.referenceMultiply(p, k);
+ ECPoint q = p.multiply(k);
+ assertPointsEqual("ECPoint.multiply is incorrect", ref, q);
+ }
+
+ /**
+ * Checks, if the point multiplication algorithm of the given point yields
+ * the same result as point multiplication done by the reference
+ * implementation given in <code>multiply()</code>. This method tests
+ * multiplication of <code>p</code> by every number of bitlength
+ * <code>numBits</code> or less.
+ *
+ * @param p
+ * The point to be multiplied.
+ * @param numBits
+ * Try every multiplier up to this bitlength
+ */
+ private void implTestMultiplyAll(ECPoint p, int numBits)
+ {
+ BigInteger bound = BigInteger.ONE.shiftLeft(numBits);
+ BigInteger k = BigInteger.ZERO;
+
+ do
+ {
+ ECPoint ref = ECAlgorithms.referenceMultiply(p, k);
+ ECPoint q = p.multiply(k);
+ assertPointsEqual("ECPoint.multiply is incorrect", ref, q);
+ k = k.add(BigInteger.ONE);
+ }
+ while (k.compareTo(bound) < 0);
+ }
+
+ /**
+ * Tests <code>ECPoint.add()</code> and <code>ECPoint.subtract()</code>
+ * for the given point and the given point at infinity.
+ *
+ * @param p
+ * The point on which the tests are performed.
+ * @param infinity
+ * The point at infinity on the same curve as <code>p</code>.
+ */
+ private void implTestAddSubtract(ECPoint p, ECPoint infinity)
+ {
+ assertPointsEqual("Twice and Add inconsistent", p.twice(), p.add(p));
+ assertPointsEqual("Twice p - p is not p", p, p.twice().subtract(p));
+ assertPointsEqual("TwicePlus(p, -p) is not p", p, p.twicePlus(p.negate()));
+ assertPointsEqual("p - p is not infinity", infinity, p.subtract(p));
+ assertPointsEqual("p plus infinity is not p", p, p.add(infinity));
+ assertPointsEqual("infinity plus p is not p", p, infinity.add(p));
+ assertPointsEqual("infinity plus infinity is not infinity ", infinity, infinity.add(infinity));
+ assertPointsEqual("Twice infinity is not infinity ", infinity, infinity.twice());
+ }
+
+ /**
+ * Calls <code>implTestAddSubtract()</code> for literature values, both
+ * for <code>Fp</code> and <code>F2m</code>.
+ */
+ public void testAddSubtractMultiplySimple()
+ {
+ int fpBits = fp.curve.getOrder().bitLength();
+ for (int iFp = 0; iFp < fp.pointSource.length / 2; iFp++)
+ {
+ implTestAddSubtract(fp.p[iFp], fp.infinity);
+
+ implTestMultiplyAll(fp.p[iFp], fpBits);
+ implTestMultiplyAll(fp.infinity, fpBits);
+ }
+
+ int f2mBits = f2m.curve.getOrder().bitLength();
+ for (int iF2m = 0; iF2m < f2m.pointSource.length / 2; iF2m++)
+ {
+ implTestAddSubtract(f2m.p[iF2m], f2m.infinity);
+
+ implTestMultiplyAll(f2m.p[iF2m], f2mBits);
+ implTestMultiplyAll(f2m.infinity, f2mBits);
+ }
+ }
+
+ /**
+ * Test encoding with and without point compression.
+ *
+ * @param p
+ * The point to be encoded and decoded.
+ */
+ private void implTestEncoding(ECPoint p)
+ {
+ // Not Point Compression
+ byte[] unCompBarr = p.getEncoded(false);
+ ECPoint decUnComp = p.getCurve().decodePoint(unCompBarr);
+ assertPointsEqual("Error decoding uncompressed point", p, decUnComp);
+
+ // Point compression
+ byte[] compBarr = p.getEncoded(true);
+ ECPoint decComp = p.getCurve().decodePoint(compBarr);
+ assertPointsEqual("Error decoding compressed point", p, decComp);
+ }
+
+ private void implAddSubtractMultiplyTwiceEncodingTest(ECCurve curve, ECPoint q, BigInteger n)
+ {
+ // Get point at infinity on the curve
+ ECPoint infinity = curve.getInfinity();
+
+ implTestAddSubtract(q, infinity);
+ implTestMultiply(q, n.bitLength());
+ implTestMultiply(infinity, n.bitLength());
+
+ int logSize = 32 - Integers.numberOfLeadingZeros(curve.getFieldSize() - 1);
+ int rounds = Math.max(2, Math.min(10, 32 - 3 * logSize));
+
+ ECPoint p = q;
+ for (int i = 0; i < rounds; ++i)
+ {
+ implTestEncoding(p);
+ p = p.twice();
+ }
+ }
+
+ private void implSqrtTest(ECCurve c)
+ {
+ if (ECAlgorithms.isFpCurve(c))
+ {
+ BigInteger p = c.getField().getCharacteristic();
+ BigInteger pMinusOne = p.subtract(ECConstants.ONE);
+ BigInteger legendreExponent = p.shiftRight(1);
+
+ ECFieldElement zero = c.fromBigInteger(BigInteger.ZERO);
+ assertEquals(zero, zero.sqrt());
+
+ ECFieldElement one = c.fromBigInteger(BigInteger.ONE);
+ assertEquals(one, one.sqrt());
+
+ for (int i = 0; i < 20; ++i)
+ {
+ BigInteger x = BigIntegers.createRandomInRange(ECConstants.TWO, pMinusOne, secRand);
+ ECFieldElement fe = c.fromBigInteger(x);
+ ECFieldElement root = fe.sqrt();
+
+ if (root == null)
+ {
+ assertEquals(pMinusOne, x.modPow(legendreExponent, p));
+ }
+ else
+ {
+ assertEquals(fe, root.square());
+ }
+ }
+ }
+ else if (ECAlgorithms.isF2mCurve(c))
+ {
+ int m = c.getFieldSize();
+ BigInteger x = new BigInteger(m, secRand);
+ ECFieldElement fe = c.fromBigInteger(x);
+ for (int i = 0; i < 100; ++i)
+ {
+ ECFieldElement sq = fe.square();
+ ECFieldElement check = sq.sqrt();
+ assertEquals(fe, check);
+ fe = sq;
+ }
+ }
+ }
+
+ private void implValidityTest(ECCurve c, ECPoint g)
+ {
+ assertTrue(g.isValid());
+
+ if (ECAlgorithms.isF2mCurve(c))
+ {
+ BigInteger h = c.getCofactor();
+ if (null != h)
+ {
+ if (!h.testBit(0))
+ {
+ ECFieldElement sqrtB = c.getB().sqrt();
+ ECPoint order2 = c.createPoint(ECConstants.ZERO, sqrtB.toBigInteger());
+ assertTrue(order2.twice().isInfinity());
+ assertFalse(order2.isValid());
+ ECPoint bad2 = g.add(order2);
+ assertFalse(bad2.isValid());
+ ECPoint good2 = bad2.add(order2);
+ assertTrue(good2.isValid());
+
+ if (!h.testBit(1))
+ {
+ ECFieldElement L = solveQuadraticEquation(c, c.getA());
+ assertNotNull(L);
+ ECFieldElement T = sqrtB;
+ ECFieldElement x = T.sqrt();
+ ECFieldElement y = T.add(x.multiply(L));
+ ECPoint order4 = c.createPoint(x.toBigInteger(), y.toBigInteger());
+ assertTrue(order4.twice().equals(order2));
+ assertFalse(order4.isValid());
+ ECPoint bad4_1 = g.add(order4);
+ assertFalse(bad4_1.isValid());
+ ECPoint bad4_2 = bad4_1.add(order4);
+ assertFalse(bad4_2.isValid());
+ ECPoint bad4_3 = bad4_2.add(order4);
+ assertFalse(bad4_3.isValid());
+ ECPoint good4 = bad4_3.add(order4);
+ assertTrue(good4.isValid());
+ }
+ }
+ }
+ }
+ }
+
+ private void implAddSubtractMultiplyTwiceEncodingTestAllCoords(X9ECParameters x9ECParameters)
+ {
+ BigInteger n = x9ECParameters.getN();
+ ECPoint G = x9ECParameters.getG();
+ ECCurve C = x9ECParameters.getCurve();
+
+ int[] coords = ECCurve.getAllCoordinateSystems();
+ for (int i = 0; i < coords.length; ++i)
+ {
+ int coord = coords[i];
+ if (C.supportsCoordinateSystem(coord))
+ {
+ ECCurve c = C;
+ ECPoint g = G;
+
+ if (c.getCoordinateSystem() != coord)
+ {
+ c = C.configure().setCoordinateSystem(coord).create();
+ g = c.importPoint(G);
+ }
+
+ // The generator is multiplied by random b to get random q
+ BigInteger b = new BigInteger(n.bitLength(), secRand);
+ ECPoint q = g.multiply(b).normalize();
+
+ implAddSubtractMultiplyTwiceEncodingTest(c, q, n);
+
+ implSqrtTest(c);
+
+ implValidityTest(c, g);
+ }
+ }
+ }
+
+ /**
+ * Calls <code>implTestAddSubtract()</code>,
+ * <code>implTestMultiply</code> and <code>implTestEncoding</code> for
+ * the standard elliptic curves as given in <code>SECNamedCurves</code>.
+ */
+ @LargeTest
+ public void testAddSubtractMultiplyTwiceEncoding()
+ {
+ Set names = new HashSet(enumToList(ECNamedCurveTable.getNames()));
+ names.addAll(enumToList(CustomNamedCurves.getNames()));
+
+ Iterator it = names.iterator();
+ while (it.hasNext())
+ {
+ String name = (String)it.next();
+
+ X9ECParameters x9A = ECNamedCurveTable.getByName(name);
+ X9ECParameters x9B = CustomNamedCurves.getByName(name);
+
+ if (x9A != null && x9B != null)
+ {
+ assertEquals(x9A.getCurve().getField(), x9B.getCurve().getField());
+ assertEquals(x9A.getCurve().getA().toBigInteger(), x9B.getCurve().getA().toBigInteger());
+ assertEquals(x9A.getCurve().getB().toBigInteger(), x9B.getCurve().getB().toBigInteger());
+ assertOptionalValuesAgree(x9A.getCurve().getCofactor(), x9B.getCurve().getCofactor());
+ assertOptionalValuesAgree(x9A.getCurve().getOrder(), x9B.getCurve().getOrder());
+
+ assertPointsEqual("Custom curve base-point inconsistency", x9A.getG(), x9B.getG());
+
+ assertEquals(x9A.getH(), x9B.getH());
+ assertEquals(x9A.getN(), x9B.getN());
+ assertOptionalValuesAgree(x9A.getSeed(), x9B.getSeed());
+
+ BigInteger k = new BigInteger(x9A.getN().bitLength(), secRand);
+ ECPoint pA = x9A.getG().multiply(k);
+ ECPoint pB = x9B.getG().multiply(k);
+ assertPointsEqual("Custom curve multiplication inconsistency", pA, pB);
+ }
+
+ if (x9A != null)
+ {
+ implAddSubtractMultiplyTwiceEncodingTestAllCoords(x9A);
+ }
+
+ if (x9B != null)
+ {
+ implAddSubtractMultiplyTwiceEncodingTestAllCoords(x9B);
+ }
+ }
+ }
+
+ public void testExampleFpB0() throws Exception
+ {
+ /*
+ * The supersingular curve y^2 = x^3 - 3.x (i.e. with 'B' == 0) from RFC 6508 2.1, with
+ * curve parameters from RFC 6509 Appendix A.
+ */
+ BigInteger p = fromHex(
+ "997ABB1F0A563FDA65C61198DAD0657A"
+ + "416C0CE19CB48261BE9AE358B3E01A2E"
+ + "F40AAB27E2FC0F1B228730D531A59CB0"
+ + "E791B39FF7C88A19356D27F4A666A6D0"
+ + "E26C6487326B4CD4512AC5CD65681CE1"
+ + "B6AFF4A831852A82A7CF3C521C3C09AA"
+ + "9F94D6AF56971F1FFCE3E82389857DB0"
+ + "80C5DF10AC7ACE87666D807AFEA85FEB");
+ BigInteger a = p.subtract(BigInteger.valueOf(3));
+ BigInteger b = BigInteger.valueOf(0);
+ byte[] S = null;
+ BigInteger n = p.add(BigInteger.valueOf(1)).shiftRight(2);
+ BigInteger h = BigInteger.valueOf(4);
+
+ ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h));
+
+ X9ECPoint G = configureBasepoint(curve, "04"
+ // Px
+ + "53FC09EE332C29AD0A7990053ED9B52A"
+ + "2B1A2FD60AEC69C698B2F204B6FF7CBF"
+ + "B5EDB6C0F6CE2308AB10DB9030B09E10"
+ + "43D5F22CDB9DFA55718BD9E7406CE890"
+ + "9760AF765DD5BCCB337C86548B72F2E1"
+ + "A702C3397A60DE74A7C1514DBA66910D"
+ + "D5CFB4CC80728D87EE9163A5B63F73EC"
+ + "80EC46C4967E0979880DC8ABEAE63895"
+ // Py
+ + "0A8249063F6009F1F9F1F0533634A135"
+ + "D3E82016029906963D778D821E141178"
+ + "F5EA69F4654EC2B9E7F7F5E5F0DE55F6"
+ + "6B598CCF9A140B2E416CFF0CA9E032B9"
+ + "70DAE117AD547C6CCAD696B5B7652FE0"
+ + "AC6F1E80164AA989492D979FC5A4D5F2"
+ + "13515AD7E9CB99A980BDAD5AD5BB4636"
+ + "ADB9B5706A67DCDE75573FD71BEF16D7");
+
+ X9ECParameters x9 = new X9ECParameters(curve, G, n, h, S);
+
+ implAddSubtractMultiplyTwiceEncodingTestAllCoords(x9);
+ }
+
+ private void assertPointsEqual(String message, ECPoint a, ECPoint b)
+ {
+ // NOTE: We intentionally test points for equality in both directions
+ assertEquals(message, a, b);
+ assertEquals(message, b, a);
+ }
+
+ private void assertOptionalValuesAgree(Object a, Object b)
+ {
+ if (a != null && b != null)
+ {
+ assertEquals(a, b);
+ }
+ }
+
+ private void assertOptionalValuesAgree(byte[] a, byte[] b)
+ {
+ if (a != null && b != null)
+ {
+ assertTrue(Arrays.areEqual(a, b));
+ }
+ }
+
+ private static X9ECPoint configureBasepoint(ECCurve curve, String encoding)
+ {
+ X9ECPoint G = new X9ECPoint(curve, Hex.decode(encoding));
+ WNafUtil.configureBasepoint(G.getPoint());
+ return G;
+ }
+
+ private static ECCurve configureCurve(ECCurve curve)
+ {
+ return curve;
+ }
+
+ private List enumToList(Enumeration en)
+ {
+ List rv = new ArrayList();
+
+ while (en.hasMoreElements())
+ {
+ rv.add(en.nextElement());
+ }
+
+ return rv;
+ }
+
+ private static BigInteger fromHex(
+ String hex)
+ {
+ return new BigInteger(1, Hex.decode(hex));
+ }
+
+ private static ECFieldElement solveQuadraticEquation(ECCurve c, ECFieldElement rhs)
+ {
+ if (rhs.isZero())
+ {
+ return rhs;
+ }
+
+ ECFieldElement gamma, z, zeroElement = c.fromBigInteger(ECConstants.ZERO);
+
+ int m = c.getFieldSize();
+ Random rand = new Random();
+ do
+ {
+ ECFieldElement t = c.fromBigInteger(new BigInteger(m, rand));
+ z = zeroElement;
+ ECFieldElement w = rhs;
+ for (int i = 1; i < m; i++)
+ {
+ ECFieldElement w2 = w.square();
+ z = z.square().add(w2.multiply(t));
+ w = w2.add(rhs);
+ }
+ if (!w.isZero())
+ {
+ return null;
+ }
+ gamma = z.square().add(z);
+ }
+ while (gamma.isZero());
+
+ return z;
+ }
+
+ public static Test suite()
+ {
+ return new TestSuite(ECPointTest.class);
+ }
+}
diff --git a/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/F2mProofer.java b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/F2mProofer.java
new file mode 100644
index 00000000..062d2091
--- /dev/null
+++ b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/F2mProofer.java
@@ -0,0 +1,208 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.bouncycastle.math.ec.test;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Set;
+
+import com.android.org.bouncycastle.asn1.sec.SECNamedCurves;
+import com.android.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.org.bouncycastle.math.ec.ECPoint;
+import com.android.org.bouncycastle.util.BigIntegers;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class F2mProofer
+{
+ private static final int NUM_SAMPLES = 1000;
+
+ private static final String PATH = "crypto/test/src/com/android/org/bouncycastle/math/ec/test/samples/";
+
+ private static final String INPUT_FILE_NAME_PREFIX = "Input_";
+
+ private static final String RESULT_FILE_NAME_PREFIX = "Output_";
+
+ /**
+ * The standard curves on which the tests are done
+ */
+ public static final String[] CURVES = { "sect163r2", "sect233r1",
+ "sect283r1", "sect409r1", "sect571r1" };
+
+ private String pointToString(ECPoint.F2m p)
+ {
+ ECFieldElement.F2m x = (ECFieldElement.F2m) p.getAffineXCoord();
+ ECFieldElement.F2m y = (ECFieldElement.F2m) p.getAffineYCoord();
+
+ int m = x.getM();
+ int len = m / 2 + 5;
+
+ StringBuffer sb = new StringBuffer(len);
+ sb.append('(');
+ sb.append(x.toBigInteger().toString(16));
+ sb.append(", ");
+ sb.append(y.toBigInteger().toString(16));
+ sb.append(')');
+
+ return sb.toString();
+ }
+
+ private void generateRandomInput(X9ECParameters x9ECParameters)
+ throws NoSuchAlgorithmException, IOException
+ {
+ ECPoint.F2m g = (ECPoint.F2m) x9ECParameters.getG();
+ int m = ((ECFieldElement.F2m) (g.getAffineXCoord())).getM();
+
+ SecureRandom secRand = SecureRandom.getInstance("SHA1PRNG");
+ Properties inputProps = new Properties();
+ for (int i = 0; i < NUM_SAMPLES; i++)
+ {
+ BigInteger rand = BigIntegers.createRandomBigInteger(m, secRand);
+ inputProps.put(Integer.toString(i), rand.toString(16));
+ }
+ String bits = Integer.toString(m);
+ FileOutputStream fos = new FileOutputStream(PATH
+ + INPUT_FILE_NAME_PREFIX + bits + ".properties");
+ inputProps.store(fos, "Input Samples of length" + bits);
+ }
+
+ private void multiplyPoints(X9ECParameters x9ECParameters,
+ String classPrefix) throws IOException
+ {
+ ECPoint.F2m g = (ECPoint.F2m) x9ECParameters.getG();
+ int m = ((ECFieldElement.F2m) (g.getAffineXCoord())).getM();
+
+ String inputFileName = PATH + INPUT_FILE_NAME_PREFIX + m
+ + ".properties";
+ Properties inputProps = new Properties();
+ inputProps.load(new FileInputStream(inputFileName));
+
+ Properties outputProps = new Properties();
+
+ for (int i = 0; i < NUM_SAMPLES; i++)
+ {
+ BigInteger rand = new BigInteger(inputProps.getProperty(Integer
+ .toString(i)), 16);
+ ECPoint.F2m result = (ECPoint.F2m) g.multiply(rand).normalize();
+ String resultStr = pointToString(result);
+ outputProps.setProperty(Integer.toString(i), resultStr);
+ }
+
+ String outputFileName = PATH + RESULT_FILE_NAME_PREFIX + classPrefix
+ + "_" + m + ".properties";
+ FileOutputStream fos = new FileOutputStream(outputFileName);
+ outputProps.store(fos, "Output Samples of length" + m);
+ }
+
+ private Properties loadResults(String classPrefix, int m)
+ throws IOException
+ {
+ FileInputStream fis = new FileInputStream(PATH
+ + RESULT_FILE_NAME_PREFIX + classPrefix + "_" + m + ".properties");
+ Properties res = new Properties();
+ res.load(fis);
+ return res;
+
+ }
+
+ private void compareResult(X9ECParameters x9ECParameters,
+ String classPrefix1, String classPrefix2) throws IOException
+ {
+ ECPoint.F2m g = (ECPoint.F2m) x9ECParameters.getG();
+ int m = ((ECFieldElement.F2m) (g.getAffineXCoord())).getM();
+
+ Properties res1 = loadResults(classPrefix1, m);
+ Properties res2 = loadResults(classPrefix2, m);
+
+ Set keys = res1.keySet();
+ Iterator iter = keys.iterator();
+ while (iter.hasNext())
+ {
+ String key = (String) iter.next();
+ String result1 = res1.getProperty(key);
+ String result2 = res2.getProperty(key);
+ if (!(result1.equals(result2)))
+ {
+ System.err.println("Difference found: m = " + m + ", "
+ + result1 + " does not equal " + result2);
+ }
+ }
+
+ }
+
+ private static void usage()
+ {
+ System.err.println("Usage: F2mProofer [-init | -multiply <className> "
+ + "| -compare <className1> <className2>]");
+ }
+
+ public static void main(String[] args) throws Exception
+ {
+ if (args.length == 0)
+ {
+ usage();
+ return;
+ }
+ F2mProofer proofer = new F2mProofer();
+ if (args[0].equals("-init"))
+ {
+ System.out.println("Generating random input...");
+ for (int i = 0; i < CURVES.length; i++)
+ {
+ X9ECParameters x9ECParameters = SECNamedCurves
+ .getByName(CURVES[i]);
+ proofer.generateRandomInput(x9ECParameters);
+ }
+ System.out
+ .println("Successfully generated random input in " + PATH);
+ }
+ else if (args[0].equals("-compare"))
+ {
+ if (args.length < 3)
+ {
+ usage();
+ return;
+ }
+ String classPrefix1 = args[1];
+ String classPrefix2 = args[2];
+ System.out.println("Comparing results...");
+ for (int i = 0; i < CURVES.length; i++)
+ {
+ X9ECParameters x9ECParameters = SECNamedCurves
+ .getByName(CURVES[i]);
+ proofer.compareResult(x9ECParameters, classPrefix1,
+ classPrefix2);
+ }
+ System.out.println("Successfully compared results in " + PATH);
+ }
+ else if (args[0].equals("-multiply"))
+ {
+ if (args.length < 2)
+ {
+ usage();
+ return;
+ }
+ String classPrefix = args[1];
+ System.out.println("Multiplying points...");
+ for (int i = 0; i < CURVES.length; i++)
+ {
+ X9ECParameters x9ECParameters = SECNamedCurves
+ .getByName(CURVES[i]);
+ proofer.multiplyPoints(x9ECParameters, classPrefix);
+ }
+ System.out.println("Successfully generated multiplied points in "
+ + PATH);
+ }
+ else
+ {
+ usage();
+ }
+ }
+}
diff --git a/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/FixedPointTest.java b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/FixedPointTest.java
new file mode 100644
index 00000000..e72ca170
--- /dev/null
+++ b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/ec/test/FixedPointTest.java
@@ -0,0 +1,94 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.bouncycastle.math.ec.test;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import com.android.org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import com.android.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.org.bouncycastle.crypto.ec.CustomNamedCurves;
+import com.android.org.bouncycastle.math.ec.ECAlgorithms;
+import com.android.org.bouncycastle.math.ec.ECPoint;
+import com.android.org.bouncycastle.math.ec.FixedPointCombMultiplier;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class FixedPointTest
+ extends TestCase
+{
+ private static final SecureRandom RANDOM = new SecureRandom();
+
+ private static final int TESTS_PER_CURVE = 5;
+
+ public void testFixedPointMultiplier()
+ {
+ final FixedPointCombMultiplier M = new FixedPointCombMultiplier();
+
+ Set names = new HashSet(enumToList(ECNamedCurveTable.getNames()));
+ names.addAll(enumToList(CustomNamedCurves.getNames()));
+
+ Iterator it = names.iterator();
+ while (it.hasNext())
+ {
+ String name = (String)it.next();
+
+ X9ECParameters x9A = ECNamedCurveTable.getByName(name);
+ X9ECParameters x9B = CustomNamedCurves.getByName(name);
+
+ X9ECParameters x9 = x9B != null ? x9B : x9A;
+
+ for (int i = 0; i < TESTS_PER_CURVE; ++i)
+ {
+ BigInteger k = new BigInteger(x9.getN().bitLength(), RANDOM);
+ ECPoint pRef = ECAlgorithms.referenceMultiply(x9.getG(), k);
+
+ if (x9A != null)
+ {
+ ECPoint pA = M.multiply(x9A.getG(), k);
+ assertPointsEqual("Standard curve fixed-point failure", pRef, pA);
+ }
+
+ if (x9B != null)
+ {
+ ECPoint pB = M.multiply(x9B.getG(), k);
+ assertPointsEqual("Custom curve fixed-point failure", pRef, pB);
+ }
+ }
+ }
+ }
+
+ private List enumToList(Enumeration en)
+ {
+ List rv = new ArrayList();
+
+ while (en.hasMoreElements())
+ {
+ rv.add(en.nextElement());
+ }
+
+ return rv;
+ }
+
+ private void assertPointsEqual(String message, ECPoint a, ECPoint b)
+ {
+ // NOTE: We intentionally test points for equality in both directions
+ assertEquals(message, a, b);
+ assertEquals(message, b, a);
+ }
+
+ public static Test suite()
+ {
+ return new TestSuite(FixedPointTest.class);
+ }
+}
diff --git a/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/raw/test/AllTests.java b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/raw/test/AllTests.java
new file mode 100644
index 00000000..560dd7d1
--- /dev/null
+++ b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/raw/test/AllTests.java
@@ -0,0 +1,50 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.bouncycastle.math.raw.test;
+
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import com.android.org.bouncycastle.test.PrintTestResult;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AllTests
+ extends TestCase
+{
+ public static void main (String[] args)
+ throws Exception
+ {
+ PrintTestResult.printResult( junit.textui.TestRunner.run(suite()));
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ TestSuite suite = new TestSuite("Raw math tests");
+
+ suite.addTest(InterleaveTest.suite());
+
+ return new BCTestSetup(suite);
+ }
+
+ static class BCTestSetup
+ extends TestSetup
+ {
+ public BCTestSetup(Test test)
+ {
+ super(test);
+ }
+
+ protected void setUp()
+ {
+
+ }
+
+ protected void tearDown()
+ {
+
+ }
+ }
+}
diff --git a/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/raw/test/InterleaveTest.java b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/raw/test/InterleaveTest.java
new file mode 100644
index 00000000..355e139a
--- /dev/null
+++ b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/raw/test/InterleaveTest.java
@@ -0,0 +1,90 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.bouncycastle.math.raw.test;
+
+import java.security.SecureRandom;
+
+import com.android.org.bouncycastle.math.raw.Interleave;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class InterleaveTest extends TestCase
+{
+ private static final int ITERATIONS = 1000;
+
+ private static final SecureRandom R = new SecureRandom();
+
+ public void testExpand8To16()
+ {
+ // NOTE: Just test all inputs here
+ for (int iteration = 0; iteration < 256; ++iteration)
+ {
+ // NOTE: Implementation is expected to mask input
+ int x = iteration | (R.nextInt() << 8);
+ int expected = (int)referenceShuffle(x & 0xFFL);
+ int actual = Interleave.expand8to16(x);
+ assertEquals(expected, actual);
+ }
+ }
+
+ public void testExpand16To32()
+ {
+ for (int iteration = 0; iteration < ITERATIONS; ++iteration)
+ {
+ // NOTE: Implementation is expected to mask input
+ int x = R.nextInt();
+ int expected = (int)referenceShuffle(x & 0xFFFFL);
+ int actual = Interleave.expand16to32(x);
+ assertEquals(expected, actual);
+ }
+ }
+
+ public void testExpand32To64()
+ {
+ for (int iteration = 0; iteration < ITERATIONS; ++iteration)
+ {
+ int x = R.nextInt();
+ long expected = referenceShuffle(x & 0xFFFFFFFFL);
+ long actual = Interleave.expand32to64(x);
+ assertEquals(expected, actual);
+ }
+ }
+
+ public void testExpand64To128()
+ {
+ for (int iteration = 0; iteration < ITERATIONS; ++iteration)
+ {
+ long x = R.nextLong();
+ long expected = referenceShuffle(x);
+ long[] actual = new long[9];
+ int offset = iteration % 8;
+ // NOTE: Implementation must overwrite existing values
+ actual[offset ] = R.nextLong();
+ actual[offset + 1] = R.nextLong();
+ Interleave.expand64To128(x, actual, offset);
+ assertEquals((expected ) & 0x5555555555555555L, actual[offset ]);
+ assertEquals((expected >>> 1) & 0x5555555555555555L, actual[offset + 1]);
+ }
+ }
+
+ public static Test suite()
+ {
+ return new TestSuite(InterleaveTest.class);
+ }
+
+ private static long referenceShuffle(long x)
+ {
+ long result = 0, y = x >>> 32;
+ for (int bit = 0; bit < 32; ++bit)
+ {
+ long selector = 1L << bit;
+ result |= ((x & selector) << (bit ));
+ result |= ((y & selector) << (bit + 1));
+ }
+ return result;
+ }
+}
diff --git a/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/test/AllTests.java b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/test/AllTests.java
new file mode 100644
index 00000000..34377f2d
--- /dev/null
+++ b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/test/AllTests.java
@@ -0,0 +1,50 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.bouncycastle.math.test;
+
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import com.android.org.bouncycastle.test.PrintTestResult;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AllTests
+ extends TestCase
+{
+ public static void main (String[] args)
+ throws Exception
+ {
+ PrintTestResult.printResult( junit.textui.TestRunner.run(suite()));
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ TestSuite suite = new TestSuite("Math tests");
+
+ suite.addTestSuite(PrimesTest.class);
+
+ return new BCTestSetup(suite);
+ }
+
+ static class BCTestSetup
+ extends TestSetup
+ {
+ public BCTestSetup(Test test)
+ {
+ super(test);
+ }
+
+ protected void setUp()
+ {
+
+ }
+
+ protected void tearDown()
+ {
+
+ }
+ }
+}
diff --git a/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/test/PrimesTest.java b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/test/PrimesTest.java
new file mode 100644
index 00000000..f690484f
--- /dev/null
+++ b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/math/test/PrimesTest.java
@@ -0,0 +1,187 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.bouncycastle.math.test;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import com.android.org.bouncycastle.crypto.Digest;
+import com.android.org.bouncycastle.crypto.digests.SHA1Digest;
+import com.android.org.bouncycastle.crypto.digests.SHA256Digest;
+import com.android.org.bouncycastle.math.Primes;
+import com.android.org.bouncycastle.math.Primes.MROutput;
+import com.android.org.bouncycastle.math.Primes.STOutput;
+import com.android.org.bouncycastle.util.Arrays;
+import com.android.org.bouncycastle.util.BigIntegers;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PrimesTest extends TestCase
+{
+ private static final int ITERATIONS = 10;
+ private static final int PRIME_BITS = 256;
+ private static final int PRIME_CERTAINTY = 100;
+
+ private static final BigInteger TWO = BigInteger.valueOf(2);
+
+ private static final SecureRandom R = new SecureRandom();
+
+ public void testHasAnySmallFactors()
+ {
+ for (int iterations = 0; iterations < ITERATIONS; ++iterations)
+ {
+ BigInteger prime = randomPrime();
+ assertFalse(Primes.hasAnySmallFactors(prime));
+
+ // NOTE: Loop through ALL small values to be sure no small primes are missing
+ for (int smallFactor = 2; smallFactor <= Primes.SMALL_FACTOR_LIMIT; ++smallFactor)
+ {
+ BigInteger nonPrimeWithSmallFactor = BigInteger.valueOf(smallFactor).multiply(prime);
+ assertTrue(Primes.hasAnySmallFactors(nonPrimeWithSmallFactor));
+ }
+ }
+ }
+
+ public void testEnhancedMRProbablePrime()
+ {
+ int mrIterations = (PRIME_CERTAINTY + 1) / 2;
+ for (int iterations = 0; iterations < ITERATIONS; ++iterations)
+ {
+ BigInteger prime = randomPrime();
+ MROutput mr = Primes.enhancedMRProbablePrimeTest(prime, R, mrIterations);
+ assertFalse(mr.isProvablyComposite());
+ assertFalse(mr.isNotPrimePower());
+ assertNull(mr.getFactor());
+
+ BigInteger primePower = prime;
+ for (int i = 0; i <= (iterations % 8); ++i)
+ {
+ primePower = primePower.multiply(prime);
+ }
+
+ MROutput mr2 = Primes.enhancedMRProbablePrimeTest(primePower, R, mrIterations);
+ assertTrue(mr2.isProvablyComposite());
+ assertFalse(mr2.isNotPrimePower());
+ assertEquals(mr2.getFactor(), prime);
+
+ BigInteger nonPrimePower = randomPrime().multiply(prime);
+ MROutput mr3 = Primes.enhancedMRProbablePrimeTest(nonPrimePower, R, mrIterations);
+ assertTrue(mr3.isProvablyComposite());
+ assertTrue(mr3.isNotPrimePower());
+ assertNull(mr.getFactor());
+ }
+ }
+
+ public void testMRProbablePrime()
+ {
+ int mrIterations = (PRIME_CERTAINTY + 1) / 2;
+ for (int iterations = 0; iterations < ITERATIONS; ++iterations)
+ {
+ BigInteger prime = randomPrime();
+ assertTrue(Primes.isMRProbablePrime(prime, R, mrIterations));
+
+ BigInteger nonPrime = randomPrime().multiply(prime);
+ assertFalse(Primes.isMRProbablePrime(nonPrime, R, mrIterations));
+ }
+ }
+
+ public void testMRProbablePrimeToBase()
+ {
+ int mrIterations = (PRIME_CERTAINTY + 1) / 2;
+ for (int iterations = 0; iterations < ITERATIONS; ++iterations)
+ {
+ BigInteger prime = randomPrime();
+ assertTrue(referenceIsMRProbablePrime(prime, mrIterations));
+
+ BigInteger nonPrime = randomPrime().multiply(prime);
+ assertFalse(referenceIsMRProbablePrime(nonPrime, mrIterations));
+ }
+ }
+
+ public void testSTRandomPrime()
+ {
+ Digest[] digests = new Digest[]{ new SHA1Digest(), new SHA256Digest() };
+ for (int digestIndex = 0; digestIndex < digests.length; ++digestIndex)
+ {
+ int coincidenceCount = 0;
+
+ Digest digest = digests[digestIndex];
+ for (int iterations = 0; iterations < ITERATIONS; ++iterations)
+ {
+ try
+ {
+ byte[] inputSeed = new byte[16];
+ R.nextBytes(inputSeed);
+
+ STOutput st = Primes.generateSTRandomPrime(digest, PRIME_BITS, inputSeed);
+ assertTrue(isPrime(st.getPrime()));
+
+ STOutput st2 = Primes.generateSTRandomPrime(digest, PRIME_BITS, inputSeed);
+ assertEquals(st.getPrime(), st2.getPrime());
+ assertEquals(st.getPrimeGenCounter(), st2.getPrimeGenCounter());
+ assertTrue(Arrays.areEqual(st.getPrimeSeed(), st2.getPrimeSeed()));
+
+ for (int i = 0; i < inputSeed.length; ++i)
+ {
+ inputSeed[i] ^= 0xFF;
+ }
+
+ STOutput st3 = Primes.generateSTRandomPrime(digest, PRIME_BITS, inputSeed);
+ assertTrue(!st.getPrime().equals(st3.getPrime()));
+ assertFalse(Arrays.areEqual(st.getPrimeSeed(), st3.getPrimeSeed()));
+
+ if (st.getPrimeGenCounter() == st3.getPrimeGenCounter())
+ {
+ ++coincidenceCount;
+ }
+ }
+ catch (IllegalStateException e)
+ {
+ if (e.getMessage().startsWith("Too many iterations"))
+ {
+ --iterations;
+ continue;
+ }
+
+ throw e;
+ }
+ }
+
+ assertTrue(coincidenceCount * coincidenceCount < ITERATIONS);
+ }
+ }
+
+ public static Test suite()
+ {
+ return new TestSuite(PrimesTest.class);
+ }
+
+ private static boolean referenceIsMRProbablePrime(BigInteger x, int numBases)
+ {
+ BigInteger xSubTwo = x.subtract(TWO);
+
+ for (int i = 0; i < numBases; ++i)
+ {
+ BigInteger b = BigIntegers.createRandomInRange(TWO, xSubTwo, R);
+ if (!Primes.isMRProbablePrimeToBase(x, b))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static boolean isPrime(BigInteger x)
+ {
+ return x.isProbablePrime(PRIME_CERTAINTY);
+ }
+
+ private static BigInteger randomPrime()
+ {
+ return BigIntegers.createRandomPrime(PRIME_BITS, PRIME_CERTAINTY, R);
+ }
+}
diff --git a/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/test/PrintTestResult.java b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/test/PrintTestResult.java
new file mode 100644
index 00000000..83f266f6
--- /dev/null
+++ b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/test/PrintTestResult.java
@@ -0,0 +1,40 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.bouncycastle.test;
+
+
+import java.util.Enumeration;
+
+import junit.framework.TestResult;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PrintTestResult
+{
+ public static void printResult(TestResult result)
+ {
+ Enumeration e = result.failures();
+ if (e != null)
+ {
+ while (e.hasMoreElements())
+ {
+ System.out.println(e.nextElement());
+ }
+ }
+
+ e = result.errors();
+ if (e != null)
+ {
+ while (e.hasMoreElements())
+ {
+ System.out.println(e.nextElement());
+ }
+ }
+
+ if (!result.wasSuccessful())
+ {
+ System.exit(1);
+ }
+ }
+}
+
diff --git a/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/util/Times.java b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/util/Times.java
new file mode 100644
index 00000000..05ca4b1b
--- /dev/null
+++ b/repackaged/bcprov/src/test/java/com/android/org/bouncycastle/util/Times.java
@@ -0,0 +1,13 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.bouncycastle.util;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class Times
+{
+ public static long nanoTime()
+ {
+ return System.nanoTime();
+ }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
index 7eaf8ac8..50417c7a 100644
--- a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
@@ -961,56 +961,26 @@ public class BaseBlockCipher
{
byte[] iv = new byte[ivLength];
- // BEGIN Android-changed: For PBE keys with no IV, log and use IV of 0
+ // BEGIN Android-changed: Reject PBE keys with no IV
// These keys were accepted in BC 1.52 (and treated as having an IV of 0) but
- // rejected outright in BC 1.54 (even if an IV was passed in params). We
- // want the eventual state to be that an IV can be passed in params, but the key
- // is rejected otherwise. For now, log that these will be rejected in a future
- // release. See b/27995180 for historical details.
- // ivRandom.nextBytes(iv);
+ // rejected outright in BC 1.54 (even if an IV was passed in params).
+ // See b/27995180 for historical details.
if (!isBCPBEKeyWithoutIV(key)) {
ivRandom.nextBytes(iv);
} else {
- // TODO(b/70275132): Change to rejecting these keys
- System.err.println(" ******** DEPRECATED FUNCTIONALITY ********");
- System.err.println(" * You have initialized a cipher with a PBE key with no IV and");
- System.err.println(" * have not provided an IV in the AlgorithmParameterSpec. This");
- System.err.println(" * configuration is deprecated. The cipher will be initialized");
- System.err.println(" * with an all-zero IV, but in a future release this call will");
- System.err.println(" * throw an exception.");
- new InvalidAlgorithmParameterException("No IV set when using PBE key")
- .printStackTrace(System.err);
+ throw new InvalidAlgorithmParameterException("No IV set when using PBE key");
}
- // END Android-changed: For PBE keys with no IV, log and use IV of 0
+ // END Android-changed: Reject PBE keys with no IV
param = new ParametersWithIV(param, iv);
ivParam = (ParametersWithIV)param;
}
else if (cipher.getUnderlyingCipher().getAlgorithmName().indexOf("PGPCFB") < 0)
{
- // BEGIN Android-changed: For PBE keys with no IV, log and use IV of 0
+ // BEGIN Android-changed: Reject PBE keys with no IV
// These keys were accepted in BC 1.52 (and treated as having an IV of 0) but
- // rejected outright in BC 1.54 (even if an IV was passed in params). We
- // want the eventual state to be that an IV can be passed in params, but the key
- // is rejected otherwise. For now, log that these will be rejected in a future
- // release. See b/27995180 for historical details.
- // throw new InvalidAlgorithmParameterException("no IV set when one expected");
- if (!isBCPBEKeyWithoutIV(key)) {
- throw new InvalidAlgorithmParameterException("no IV set when one expected");
- } else {
- // TODO(b/70275132): Change to rejecting these keys
- System.err.println(" ******** DEPRECATED FUNCTIONALITY ********");
- System.err.println(" * You have initialized a cipher with a PBE key with no IV and");
- System.err.println(" * have not provided an IV in the AlgorithmParameterSpec. This");
- System.err.println(" * configuration is deprecated. The cipher will be initialized");
- System.err.println(" * with an all-zero IV, but in a future release this call will");
- System.err.println(" * throw an exception.");
- new InvalidAlgorithmParameterException("No IV set when using PBE key")
- .printStackTrace(System.err);
- // Mimic behaviour in 1.52 by using an IV of 0's
- param = new ParametersWithIV(param, new byte[ivLength]);
- ivParam = (ParametersWithIV)param;
- }
- // END Android-changed: For PBE keys with no IV, log and use IV of 0
+ // rejected outright in BC 1.54 (even if an IV was passed in params).
+ throw new InvalidAlgorithmParameterException("No IV set when using PBE key");
+ // END Android-changed: Reject PBE keys with no IV
}
}
diff --git a/srcgen/generate_android_src.sh b/srcgen/generate_android_src.sh
index 6498bc79..6bd894b3 100755
--- a/srcgen/generate_android_src.sh
+++ b/srcgen/generate_android_src.sh
@@ -31,6 +31,7 @@ DEFAULT_CONSTRUCTORS_FILE=${BOUNCY_CASTLE_DIR}/srcgen/default-constructors.txt
SOURCE_DIRS="\
src/main/java \
+ src/test/java \
"
# Repackage the project's source.