public void testSigningSameMessage(
      PublicKeySign signer,
      PublicKeyVerify verifier,
      boolean isDeterministic,
      byte[] message,
      int numberOfThreads,
      int numberOfSignatures)
      throws Exception {
    // TODO(b/148134669): Remove the following line.
    // There is a potential (but unlikely) race in java.security.Provider. In some cases, we only
    // initalize some of the java.security.Providers the first time we sign. If we do this
    // multithreaded, there is a potential for a race. To get around this, we first sign once, to
    // initialize everything.
    Object unused = signer.sign(message);

    ExceptionHandler exceptionHandler = new ExceptionHandler();
    Thread[] thread = new Thread[numberOfThreads];
    ArrayList<HashSet<String>> signatures = new ArrayList<HashSet<String>>();
    for (int i = 0; i < numberOfThreads; i++) {
      HashSet<String> sigs = new HashSet<String>();
      signatures.add(sigs);
      thread[i] = new SigningThread(signer, sigs, message, numberOfSignatures);
      thread[i].setUncaughtExceptionHandler(exceptionHandler);
    }
    for (int i = 0; i < numberOfThreads; i++) {
      thread[i].start();
    }
    for (int i = 0; i < numberOfThreads; i++) {
      thread[i].join();
    }
    exceptionHandler.check();

    if (isDeterministic) {
      String expectedSignature = Hex.encode(signer.sign(message));
      for (int i = 0; i < numberOfThreads; i++) {
        assertEquals(1, signatures.get(i).size());
        assertTrue(signatures.get(i).contains(expectedSignature));
      }
    } else {
      HashSet<String> allSignatures = new HashSet<String>();
      for (int i = 0; i < numberOfThreads; i++) {
        for (String sig : signatures.get(i)) {
          verifier.verify(Hex.decode(sig), message);
          assertFalse(allSignatures.contains(sig));
          allSignatures.add(sig);
        }
      }
      assertEquals(numberOfThreads * numberOfSignatures, allSignatures.size());
    }
  }
Sign the same message concurrently in multiple threads. The purpose of this test is to find
non-deterministic signatures schemes, that reuse nonces when signing concurrently.
java_src/src/test/java/com/google/crypto/tink/subtle/SignatureThreadSafetyTest.java