@Override
  public Signature makeSignatureCanonical(final Signature signature) {
    final Ed25519EncodedFieldElement s =
        new Ed25519EncodedFieldElement(Arrays.copyOf(signature.getBinaryS(), 64));
    final Ed25519EncodedFieldElement sModQ = s.modQ();

    return new Signature(signature.getBinaryR(), sModQ.getRaw());
  }
  @Override
  public boolean verify(final byte[] data, final Signature signature) {
    if (!this.isCanonicalSignature(signature)) {
      return false;
    }

    if (1
        == ArrayUtils.isEqualConstantTime(
            this.getKeyPair().getPublicKey().getRaw(), new byte[32])) {
      return false;
    }

    // h = H(encodedR, encodedA, data).
    final byte[] rawEncodedR = signature.getBinaryR();
    final byte[] rawEncodedA = this.getKeyPair().getPublicKey().getRaw();
    final Ed25519EncodedFieldElement h =
        new Ed25519EncodedFieldElement(Hashes.sha3_512(rawEncodedR, rawEncodedA, data));

    // hReduced = h mod group order
    final Ed25519EncodedFieldElement hModQ = h.modQ();

    Ed25519GroupElement A = this.getKeyPair().getPublicKey().getAsGroupElement();
    if (null == A) {
      // Must compute A.
      A = new Ed25519EncodedGroupElement(rawEncodedA).decode();
      A.precomputeForDoubleScalarMultiplication();
    }

    // R = encodedS * B - H(encodedR, encodedA, data) * A
    final Ed25519GroupElement calculatedR =
        Ed25519Group.BASE_POINT.doubleScalarMultiplyVariableTime(
            A, hModQ, new Ed25519EncodedFieldElement(signature.getBinaryS()));

    // Compare calculated R to given R.
    final byte[] encodedCalculatedR = calculatedR.encode().getRaw();
    final int result = ArrayUtils.isEqualConstantTime(encodedCalculatedR, rawEncodedR);
    return 1 == result;
  }
 @Override
 public boolean isCanonicalSignature(final Signature signature) {
   return -1 == signature.getS().compareTo(Ed25519Group.GROUP_ORDER)
       && 1 == signature.getS().compareTo(BigInteger.ZERO);
 }