@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); }