use of io.nem.symbol.core.crypto.Signature in project nem2-sdk-java by nemtech.
the class Ed25519DsaSigner method sign.
@Override
@SuppressWarnings("squid:S00117")
public Signature sign(final byte[] data) {
if (!this.getKeyPair().hasPrivateKey()) {
throw new CryptoException("cannot sign without private key");
}
Hasher hasher32 = Hashes::sha512;
Hasher hasher64 = Hashes::sha512;
// Hash the private key to improve randomness.
final byte[] hash = hasher32.hash(this.getKeyPair().getPrivateKey().getBytes());
// r = H(hash_b,...,hash_2b-1, data) where b=256.
final Ed25519EncodedFieldElement r = new Ed25519EncodedFieldElement(hasher64.hash(// only
Arrays.copyOfRange(hash, 32, 64), // key hash
data));
// Reduce size of r since we are calculating mod group order anyway
final Ed25519EncodedFieldElement rModQ = r.modQ();
// R = rModQ * base point.
final Ed25519GroupElement R = Ed25519Group.BASE_POINT.scalarMultiply(rModQ);
final Ed25519EncodedGroupElement encodedR = R.encode();
// S = (r + H(encodedR, encodedA, data) * a) mod group order where
// encodedR and encodedA are the little endian encodings of the group element R
// and the
// public
// key A and
// a is the lower 32 bytes of hash after clamping.
final Ed25519EncodedFieldElement h = new Ed25519EncodedFieldElement(hasher64.hash(encodedR.getRaw(), this.getKeyPair().getPublicKey().getBytes(), data));
final Ed25519EncodedFieldElement hModQ = h.modQ();
final Ed25519EncodedFieldElement encodedS = hModQ.multiplyAndAddModQ(Ed25519Utils.prepareForScalarMultiply(this.getKeyPair().getPrivateKey()), rModQ);
// Signature is (encodedR, encodedS)
final Signature signature = new Signature(encodedR.getRaw(), encodedS.getRaw());
if (!this.isCanonicalSignature(signature)) {
throw new CryptoException("Generated signature is not canonical");
}
return signature;
}
use of io.nem.symbol.core.crypto.Signature in project nem2-sdk-java by nemtech.
the class Ed25519DsaSignerTest method signReturnsExpectedSignature.
@Test
public void signReturnsExpectedSignature() {
// Arrange:
final CryptoEngine engine = this.getCryptoEngine();
final KeyPair keyPair = KeyPair.random(engine);
for (int i = 0; i < 20; i++) {
final DsaSigner dsaSigner = this.getDsaSigner(keyPair);
final byte[] input = RandomUtils.generateRandomBytes();
// Act:
final Signature signature1 = dsaSigner.sign(input);
final Signature signature2 = MathUtils.sign(keyPair, input);
// Assert:
Assertions.assertEquals(signature1, signature2);
}
}
use of io.nem.symbol.core.crypto.Signature in project nem2-sdk-java by nemtech.
the class Ed25519DsaSignerTest method makeCanonicalMakesNonCanonicalSignatureCanonical.
@Test
public void makeCanonicalMakesNonCanonicalSignatureCanonical() {
// Arrange:
final CryptoEngine engine = this.getCryptoEngine();
final KeyPair kp = KeyPair.random(engine);
final DsaSigner dsaSigner = this.getDsaSigner(kp);
final byte[] input = RandomUtils.generateRandomBytes();
// Act:
final Signature signature = dsaSigner.sign(input);
final BigInteger nonCanonicalS = engine.getCurve().getGroupOrder().add(signature.getS());
final Signature nonCanonicalSignature = new Signature(signature.getR(), nonCanonicalS);
Assertions.assertFalse(dsaSigner.isCanonicalSignature(nonCanonicalSignature));
final Signature canonicalSignature = dsaSigner.makeSignatureCanonical(nonCanonicalSignature);
// Assert:
Assertions.assertTrue(dsaSigner.isCanonicalSignature(canonicalSignature));
}
use of io.nem.symbol.core.crypto.Signature in project nem2-sdk-java by nemtech.
the class Ed25519DsaSignerTest method replacingRWithGroupOrderPlusRInSignatureRuinsSignature.
@Test
public void replacingRWithGroupOrderPlusRInSignatureRuinsSignature() {
// Arrange:
final CryptoEngine engine = this.getCryptoEngine();
final BigInteger groupOrder = engine.getCurve().getGroupOrder();
final KeyPair kp = KeyPair.random(engine);
final DsaSigner dsaSigner = this.getDsaSigner(kp);
Signature signature;
byte[] input;
while (true) {
input = RandomUtils.generateRandomBytes();
signature = dsaSigner.sign(input);
if (signature.getR().add(groupOrder).compareTo(BigInteger.ONE.shiftLeft(256)) < 0) {
break;
}
}
// Act:
final Signature signature2 = new Signature(groupOrder.add(signature.getR()), signature.getS());
// Assert:
Assertions.assertFalse(dsaSigner.verify(input, signature2));
}
use of io.nem.symbol.core.crypto.Signature in project nem2-sdk-java by nemtech.
the class Ed25519DsaSignerTest method verifyReturnsFalseIfPublicKeyIsZeroArray.
@Test
public void verifyReturnsFalseIfPublicKeyIsZeroArray() {
// Arrange:
final CryptoEngine engine = this.getCryptoEngine();
final KeyPair kp = KeyPair.random(engine);
final DsaSigner dsaSigner = this.getDsaSigner(kp);
final byte[] input = RandomUtils.generateRandomBytes();
final Signature signature = dsaSigner.sign(input);
final Ed25519DsaSigner dsaSignerWithZeroArrayPublicKey = Mockito.mock(Ed25519DsaSigner.class);
final KeyPair keyPairWithZeroArrayPublicKey = Mockito.mock(KeyPair.class);
Mockito.when(dsaSignerWithZeroArrayPublicKey.getKeyPair()).thenReturn(keyPairWithZeroArrayPublicKey);
Mockito.when(keyPairWithZeroArrayPublicKey.getPublicKey()).thenReturn(new PublicKey(new byte[32]));
Mockito.when(dsaSignerWithZeroArrayPublicKey.verify(input, signature)).thenCallRealMethod();
Mockito.when(dsaSignerWithZeroArrayPublicKey.isCanonicalSignature(signature)).thenReturn(true);
// Act:
final boolean result = dsaSignerWithZeroArrayPublicKey.verify(input, signature);
// Assert (getKeyPair() would be called more than once if it got beyond the
// second check):
Assertions.assertFalse(result);
Mockito.verify(dsaSignerWithZeroArrayPublicKey, Mockito.times(1)).isCanonicalSignature(signature);
Mockito.verify(dsaSignerWithZeroArrayPublicKey, Mockito.times(1)).getKeyPair();
}
Aggregations