public void EncryptDecryptNBlocksTest() { // Arrange var rnd = new Random(); var key = new byte[Snuffle.KEY_SIZE_IN_BYTES]; for (var i = 0; i < 64; i++) { rnd.NextBytes(key); var cipher = new ChaCha20(key, 0); for (var j = 0; j < 64; j++) { var expectedInput = new byte[rnd.Next(300)]; rnd.NextBytes(expectedInput); // Act var output = cipher.Encrypt(expectedInput); var actualInput = cipher.Decrypt(output); // Assert //Assert.AreEqual(expectedInput, actualInput); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(expectedInput, actualInput)); } } }
public void ConstantTimeEqualsSegmentsMustHaveSameLength() { var x = new byte[5]; var y = new byte[5]; Assert.Throws <ArgumentException>(() => CryptoBytes.ConstantTimeEquals(new ArraySegment <byte>(x, 0, 4), new ArraySegment <byte>(y, 0, 5))); }
public void ConstantTimeEqualsSegmentsSuccess() { var x = new byte[] { 1, 2, 3 }; var y = new byte[] { 1, 2, 3 }; Assert.IsTrue(CryptoBytes.ConstantTimeEquals(x.Pad(), y.Pad())); }
public void EncryptDecryptLongMessagesWithNonceTest() { var rnd = new Random(); var dataSize = 16; while (dataSize <= (1 << 24)) { var plaintext = new byte[dataSize]; rnd.NextBytes(plaintext); var key = new byte[Snuffle.KEY_SIZE_IN_BYTES]; rnd.NextBytes(key); var cipher = new XChaCha20(key, 0); var nonce = new byte[cipher.NonceSizeInBytes()]; rnd.NextBytes(nonce); var ciphertext = cipher.Encrypt(plaintext, nonce); var decrypted = cipher.Decrypt(ciphertext, nonce); //Assert.AreEqual(plaintext, decrypted); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(plaintext, decrypted)); dataSize += 5 * dataSize / 11; } }
public void EncryptDecryptLongMessagesWithNonceTest() { var rnd = new Random(); var dataSize = 16; while (dataSize <= (1 << 24)) { var plaintext = new byte[dataSize]; rnd.NextBytes(plaintext); var aad = new byte[dataSize / 3]; rnd.NextBytes(aad); var nonce = new byte[12]; rnd.NextBytes(nonce); var key = new byte[Snuffle.KEY_SIZE_IN_BYTES]; rnd.NextBytes(key); var aead = new ChaCha20Poly1305(key); var ciphertext = aead.Encrypt(plaintext, aad, nonce); var decrypted = aead.Decrypt(ciphertext, aad, nonce); //Assert.AreEqual(plaintext, decrypted); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(plaintext, decrypted)); dataSize += 5 * dataSize / 11; } }
public void ConstantTimeEqualsSuccess() { var x = new byte[] { 1, 2, 3 }; var y = new byte[] { 1, 2, 3 }; Assert.IsTrue(CryptoBytes.ConstantTimeEquals(x, y)); }
public static bool crypto_sign_verify(ReadOnlySpan <byte> sig, ReadOnlySpan <byte> m, ReadOnlySpan <byte> pk) { if ((sig[63] & 224) != 0) { return(false); } if (GroupOperations.ge_frombytes_negate_vartime(out var A, pk) != 0) { return(false); } var hasher = new Sha512(); hasher.Update(sig.Slice(0, 32)); hasher.Update(pk.Slice(0, 32)); hasher.Update(m); Span <byte> h = stackalloc byte[64]; hasher.Finish(h); ScalarOperations.sc_reduce(h); GroupOperations.ge_double_scalarmult_vartime(out var R, h, in A, sig.Slice(32, 32)); Span <byte> checkr = stackalloc byte[32]; GroupOperations.ge_tobytes(checkr, in R); var result = CryptoBytes.ConstantTimeEquals(checkr, sig, 32); CryptoBytes.Wipe(h); CryptoBytes.Wipe(checkr); return(result); }
public void ConstantTimeEqualsSegmentsMustHaveSameLength() { var x = new byte[5]; var y = new byte[5]; CryptoBytes.ConstantTimeEquals(new ArraySegment <byte>(x, 0, 4), new ArraySegment <byte>(y, 0, 5)); }
public void EncryptDecryptWithNonceTest() { var rnd = new Random(); var key = new byte[Snuffle.KEY_SIZE_IN_BYTES]; rnd.NextBytes(key); var aead = new ChaCha20Poly1305(key); for (var i = 0; i < 100; i++) { var message = new byte[100]; rnd.NextBytes(message); var aad = new byte[16]; rnd.NextBytes(aad); var nonce = new byte[12]; rnd.NextBytes(nonce); var ciphertext = aead.Encrypt(message, aad, nonce); var decrypted = aead.Decrypt(ciphertext, aad, nonce); //Assert.AreEqual(message, decrypted); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(message, decrypted)); } }
public void ConstantTimeEqualsSegmentsSuccess() { var x = new byte[] { 1, 2, 3 }; var y = new byte[] { 1, 2, 3 }; CryptoBytes.ConstantTimeEquals(x.Pad(), y.Pad()).Should().BeTrue(); }
public void ConstantTimeEqualsRangeSuccess() { var x = new byte[] { 1, 2, 3 }; var y = new byte[] { 1, 2, 3 }; var paddedX = x.Pad(); var paddedY = y.Pad(); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(paddedX.Array, paddedX.Offset, paddedY.Array, paddedY.Offset, paddedX.Count)); }
public void ConstantTimeEqualsSegmentsFail() { var x = new byte[] { 1, 2, 3 }; foreach (var y in x.WithChangedBit()) { Assert.IsFalse(CryptoBytes.ConstantTimeEquals(x.Pad(), y.Pad())); } }
public void ConstantTimeEqualsSegmentsMustHaveSameLength() { var x = new byte[5]; var y = new byte[5]; Action act = () => CryptoBytes.ConstantTimeEquals(new ArraySegment <byte>(x, 0, 4), new ArraySegment <byte>(y, 0, 5)); act.Should().Throw <ArgumentException>(); }
public void ConstantTimeEqualsFail() { var x = new byte[] { 1, 2, 3 }; foreach (var y in x.WithChangedBit()) { CryptoBytes.ConstantTimeEquals(x, y).Should().BeFalse(); } }
public void ChaCha20TestVectorTC8() { // TC8: key: 'All your base are belong to us!, IV: 'IETF2013' // Test vector TC8 from RFC draft by J. Strombergson // https://tools.ietf.org/html/draft-strombergson-chacha-test-vectors-01 // Arrange var key = new byte[32] { 0xC4, 0x6E, 0xC1, 0xB1, 0x8C, 0xE8, 0xA8, 0x78, 0x72, 0x5A, 0x37, 0xE7, 0x80, 0xDF, 0xB7, 0x35, 0x1F, 0x68, 0xED, 0x2E, 0x19, 0x4C, 0x79, 0xFB, 0xC6, 0xAE, 0xBE, 0xE1, 0xA6, 0x67, 0x97, 0x5D }; // The first 4 bytes are set to zero and a large counter // is used; this makes the RFC 8439 version of ChaCha20 // compatible with the original specification by D. J. Bernstein. var nonce = new byte[12] { 0x00, 0x00, 0x00, 0x00, 0x1A, 0xDA, 0x31, 0xD5, 0xCF, 0x68, 0x82, 0x21 }; // Act var cipher = new ChaCha20(key, 0); var block0 = new byte[Snuffle.BLOCK_SIZE_IN_BYTES]; var block1 = new byte[Snuffle.BLOCK_SIZE_IN_BYTES]; cipher.ProcessKeyStreamBlock(nonce, 0, block0); cipher.ProcessKeyStreamBlock(nonce, 1, block1); // Assert var expected = new byte[128] { 0xF6, 0x3A, 0x89, 0xB7, 0x5C, 0x22, 0x71, 0xF9, 0x36, 0x88, 0x16, 0x54, 0x2B, 0xA5, 0x2F, 0x06, 0xED, 0x49, 0x24, 0x17, 0x92, 0x30, 0x2B, 0x00, 0xB5, 0xE8, 0xF8, 0x0A, 0xE9, 0xA4, 0x73, 0xAF, 0xC2, 0x5B, 0x21, 0x8F, 0x51, 0x9A, 0xF0, 0xFD, 0xD4, 0x06, 0x36, 0x2E, 0x8D, 0x69, 0xDE, 0x7F, 0x54, 0xC6, 0x04, 0xA6, 0xE0, 0x0F, 0x35, 0x3F, 0x11, 0x0F, 0x77, 0x1B, 0xDC, 0xA8, 0xAB, 0x92, 0xE5, 0xFB, 0xC3, 0x4E, 0x60, 0xA1, 0xD9, 0xA9, 0xDB, 0x17, 0x34, 0x5B, 0x0A, 0x40, 0x27, 0x36, 0x85, 0x3B, 0xF9, 0x10, 0xB0, 0x60, 0xBD, 0xF1, 0xF8, 0x97, 0xB6, 0x29, 0x0F, 0x01, 0xD1, 0x38, 0xAE, 0x2C, 0x4C, 0x90, 0x22, 0x5B, 0xA9, 0xEA, 0x14, 0xD5, 0x18, 0xF5, 0x59, 0x29, 0xDE, 0xA0, 0x98, 0xCA, 0x7A, 0x6C, 0xCF, 0xE6, 0x12, 0x27, 0x05, 0x3C, 0x84, 0xE4, 0x9A, 0x4A, 0x33, 0x32 }; //Assert.AreEqual(expected, Combine(block0, block1)); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(expected, CryptoBytes.Combine(block0, block1))); }
public void ConstantTimeEqualsRangeFail() { var x = new byte[] { 1, 2, 3 }; foreach (var y in x.WithChangedBit()) { var paddedX = x.Pad(); var paddedY = y.Pad(); Assert.IsFalse(CryptoBytes.ConstantTimeEquals(paddedX.Array, paddedX.Offset, paddedY.Array, paddedY.Offset, paddedX.Count)); } }
/// <summary> /// Verifies the authentication <paramref name="mac"> using the specified <paramref name="key"> and <paramref name="data">. /// </summary> /// <param name="key">The secret key.</param> /// <param name="data">The data.</param> /// <param name="mac">The authentication tag.</param> /// <exception cref="CryptographicException"></exception> public static void VerifyMac(ReadOnlySpan <byte> key, ReadOnlySpan <byte> data, ReadOnlySpan <byte> mac) { Span <byte> tag = stackalloc byte[MAC_TAG_SIZE_IN_BYTES]; ComputeMac(key, data, tag); if (!CryptoBytes.ConstantTimeEquals(tag, mac)) { throw new CryptographicException(MAC_EXCEPTION_INVALID); } }
// Original crypto_sign_open, for reference only /*public static int crypto_sign_open( * byte[] m, out int mlen, * byte[] sm, int smlen, * byte[] pk) * { * byte[] h = new byte[64]; * byte[] checkr = new byte[32]; * GroupElementP3 A; * GroupElementP2 R; * int i; * * mlen = -1; * if (smlen < 64) return -1; * if ((sm[63] & 224) != 0) return -1; * if (GroupOperations.ge_frombytes_negate_vartime(out A, pk, 0) != 0) return -1; * * for (i = 0; i < smlen; ++i) m[i] = sm[i]; * for (i = 0; i < 32; ++i) m[32 + i] = pk[i]; * Sha512BclWrapper.crypto_hash_sha512(h, m, 0, smlen); * ScalarOperations.sc_reduce(h); * * var sm32 = new byte[32]; * Array.Copy(sm, 32, sm32, 0, 32); * GroupOperations.ge_double_scalarmult_vartime(out R, h, ref A, sm32); * GroupOperations.ge_tobytes(checkr, 0, ref R); * if (Helpers.crypto_verify_32(checkr, sm) != 0) * { * for (i = 0; i < smlen; ++i) * m[i] = 0; * return -1; * } * * for (i = 0; i < smlen - 64; ++i) * m[i] = sm[64 + i]; * for (i = smlen - 64; i < smlen; ++i) * m[i] = 0; * mlen = smlen - 64; * return 0; * }*/ public static bool crypto_sign_verify( byte[] sig, int sigoffset, byte[] m, int moffset, int mlen, byte[] pk, int pkoffset) { byte[] h; byte[] checkr = new byte[32]; GroupElementP3 A; GroupElementP2 R; if ((sig[sigoffset + 63] & 224) != 0) { return(false); } if (GroupOperations.ge_frombytes_negate_vartime(out A, pk, pkoffset) != 0) { return(false); } var blake2bConfig = new Blake2BConfig { OutputSizeInBytes = 64 }; var hasher = Blake2B.Create(blake2bConfig); hasher.Update(sig, sigoffset, 32); hasher.Update(pk, pkoffset, 32); hasher.Update(m, moffset, mlen); h = hasher.Finish(); /* * var hasher = new Sha512(); * hasher.Update(sig, sigoffset, 32); * hasher.Update(pk, pkoffset, 32); * hasher.Update(m, moffset, mlen); * h = hasher.Finish(); */ ScalarOperations.sc_reduce(h); var sm32 = new byte[32];//todo: remove allocation Array.Copy(sig, sigoffset + 32, sm32, 0, 32); GroupOperations.ge_double_scalarmult_vartime(out R, h, ref A, sm32); GroupOperations.ge_tobytes(checkr, 0, ref R); var result = CryptoBytes.ConstantTimeEquals(checkr, 0, sig, sigoffset, 32); CryptoBytes.Wipe(h); CryptoBytes.Wipe(checkr); return(result); }
public void HChaCha20TestVectors() { // Arrange foreach (var test in HChaCha20TestVector.HChaCha20TestVectors) { var cipher = new XChaCha20(test.Key, 0); // Act var output = cipher.HChaCha20(test.Input); // Assert //Assert.That(output, Is.EqualTo(test.Output)); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(test.Output, output)); } }
/// <summary> /// Verifies the authentication <paramref name="mac"/> using the specified <paramref name="key"/> and <paramref name="data"/>. /// </summary> /// <param name="key">The secret key.</param> /// <param name="data">The data.</param> /// <param name="tag">The authentication tag.</param> /// <exception cref="CryptographicException"></exception> public static void VerifyMac(ReadOnlySpan <byte> key, ReadOnlySpan <byte> data, ReadOnlySpan <byte> tag) { if (tag.Length != MAC_TAG_SIZE_IN_BYTES) { throw new CryptographicException($"The tag length in bytes must be {MAC_TAG_SIZE_IN_BYTES}."); } Span <byte> mac = stackalloc byte[MAC_TAG_SIZE_IN_BYTES]; ComputeMac(key, data, mac); if (!CryptoBytes.ConstantTimeEquals(mac, tag)) { throw new CryptographicException(MAC_EXCEPTION_INVALID); } }
public void ChaCha20TestVector() { // https://tools.ietf.org/html/rfc8439#section-2.4.2 // Arrange foreach (var test in Rfc8439TestVector.Rfc8439TestVectors) { // Act var cipher = new ChaCha20(test.Key, test.InitialCounter); var output = cipher.Decrypt(CryptoBytes.Combine(test.Nonce, test.CipherText)); // Assert //Assert.That(output, Is.EqualTo(test.PlainText)); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(test.PlainText, output)); } }
public void XChaCha20TestVectors() { // From libsodium's test/default/xchacha20.c (tv_stream_xchacha20) and https://tools.ietf.org/html/draft-arciszewski-xchacha-00. // Arrange foreach (var test in XChaCha20TestVector.XChaCha20TestVectors) { // Act var cipher = new XChaCha20(test.Key, 0); var output = cipher.Decrypt(CryptoBytes.Combine(test.Nonce, test.CipherText)); // Assert //Assert.That(output, Is.EqualTo(test.Output)); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(test.PlainText, output)); } }
public void XChaCha20Poly1305TestVectors() { // From libsodium's test/default/aead_xchacha20poly1305.c and https://tools.ietf.org/html/draft-arciszewski-xchacha-01. // Arrange foreach (var test in XChaCha20Poly1305TestVector.TestVectors) { // Act var aead = new XChaCha20Poly1305(test.Key); //var message = aead.Decrypt(CryptoBytes.Combine(test.CipherText, test.Tag), test.Aad, test.Nonce); // same as below... var output = aead.Decrypt(CryptoBytes.Combine(test.Nonce, test.CipherText, test.Tag), test.Aad); // Assert //Assert.That(output, Is.EqualTo(test.PlainText)); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(test.PlainText, output)); } }
public void ChaCha20Poly1305TestVector2() { // https://tools.ietf.org/html/rfc8439 // Arrange foreach (var test in Rfc8439TestVector.Rfc7634AeadTestVectors) { // Act var aead = new ChaCha20Poly1305(test.Key); var ct = aead.Encrypt(test.PlainText, test.Aad, test.Nonce); Assert.That(ct, Is.EqualTo(CryptoBytes.Combine(test.CipherText, test.Tag))); var output = aead.Decrypt(ct, test.Aad, test.Nonce); // Assert //Assert.That(output, Is.EqualTo(test.PlainText)); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(test.PlainText, output)); } }
public void EncryptDecrypt1BlockTest() { // Arrange var rnd = new Random(); var key = new byte[Snuffle.KEY_SIZE_IN_BYTES]; rnd.NextBytes(key); var expectedInput = Encoding.UTF8.GetBytes("Hello World!!"); var cipher = new ChaCha20(key, 0); // Act var output = cipher.Encrypt(expectedInput); var actualInput = cipher.Decrypt(output); // Assert //Assert.AreEqual(expectedInput, actualInput); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(expectedInput, actualInput)); }
public void ModifiedAssociatedDataFails() { var rnd = new Random(); var key = new byte[Snuffle.KEY_SIZE_IN_BYTES]; rnd.NextBytes(key); var aead = new ChaCha20Poly1305(key); var aad = new byte[0]; for (var msgSize = 0; msgSize < 75; msgSize++) { var message = new byte[msgSize]; rnd.NextBytes(message); // encrypting with aad as a 0-length array var ciphertext = aead.Encrypt(message, aad); var decrypted = aead.Decrypt(ciphertext, aad); //Assert.AreEqual(message, decrypted); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(message, decrypted)); var decrypted2 = aead.Decrypt(ciphertext, null); //Assert.AreEqual(message, decrypted2); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(message, decrypted2)); var badAad = new byte[] { 1, 2, 3 }; Assert.Throws <CryptographicException>(() => aead.Decrypt(ciphertext, badAad), SnufflePoly1305.AEAD_EXCEPTION_INVALID_TAG); // encrypting with aad equal to null ciphertext = aead.Encrypt(message, null); decrypted = aead.Decrypt(ciphertext, aad); //Assert.AreEqual(message, decrypted); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(message, decrypted)); decrypted2 = aead.Decrypt(ciphertext, null); //Assert.AreEqual(message, decrypted2); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(message, decrypted2)); Assert.Throws <CryptographicException>(() => aead.Decrypt(ciphertext, badAad), SnufflePoly1305.AEAD_EXCEPTION_INVALID_TAG); } }
// Original crypto_sign_open, for reference only /*public static int crypto_sign_open( * byte[] m, out int mlen, * byte[] sm, int smlen, * byte[] pk) * { * byte[] h = new byte[64]; * byte[] checkr = new byte[32]; * GroupElementP3 A; * GroupElementP2 R; * int i; * * mlen = -1; * if (smlen < 64) return -1; * if ((sm[63] & 224) != 0) return -1; * if (GroupOperations.ge_frombytes_negate_vartime(out A, pk, 0) != 0) return -1; * * for (i = 0; i < smlen; ++i) m[i] = sm[i]; * for (i = 0; i < 32; ++i) m[32 + i] = pk[i]; * Sha512BclWrapper.crypto_hash_sha512(h, m, 0, smlen); * ScalarOperations.sc_reduce(h); * * var sm32 = new byte[32]; * Array.Copy(sm, 32, sm32, 0, 32); * GroupOperations.ge_double_scalarmult_vartime(out R, h, ref A, sm32); * GroupOperations.ge_tobytes(checkr, 0, ref R); * if (Helpers.crypto_verify_32(checkr, sm) != 0) * { * for (i = 0; i < smlen; ++i) * m[i] = 0; * return -1; * } * * for (i = 0; i < smlen - 64; ++i) * m[i] = sm[64 + i]; * for (i = smlen - 64; i < smlen; ++i) * m[i] = 0; * mlen = smlen - 64; * return 0; * }*/ public static bool crypto_sign_verify( byte[] sig, int sigoffset, byte[] m, int moffset, int mlen, byte[] pk, int pkoffset) { byte[] checkr = new byte[32]; GroupElementP3 A; GroupElementP2 R; if ((sig[sigoffset + 63] & 224) != 0) { return(false); } if (GroupOperations.ge_frombytes_negate_vartime(out A, pk, pkoffset) != 0) { return(false); } var hash = new KeccakDigest(512); hash.BlockUpdate(sig, sigoffset, 32); hash.BlockUpdate(pk, pkoffset, 32); hash.BlockUpdate(m, moffset, mlen); var b = new byte[64]; hash.DoFinal(b, 0); ScalarOperations.sc_reduce(b); var sm32 = new byte[32];//todo: remove allocation Array.Copy(sig, sigoffset + 32, sm32, 0, 32); GroupOperations.ge_double_scalarmult_vartime(out R, b, ref A, sm32); GroupOperations.ge_tobytes(checkr, 0, ref R); var result = CryptoBytes.ConstantTimeEquals(checkr, 0, sig, sigoffset, 32); CryptoBytes.Wipe(b); CryptoBytes.Wipe(checkr); return(result); }
public static bool crypto_sign_verify( byte[] signature, int signatureOffset, byte[] message, int messageOffset, int messageLength, byte[] publicKey, int publicKeyOffset) { byte[] h; byte[] checkr = new byte[32]; GroupElementP3 A; GroupElementP2 R; if ((signature[signatureOffset + 63] & 224) != 0) { return(false); } if (GroupOperations.ge_frombytes_negate_vartime(out A, publicKey, publicKeyOffset) != 0) { return(false); } var hasher = new Sha512(); hasher.Update(signature, signatureOffset, 32); hasher.Update(publicKey, publicKeyOffset, 32); hasher.Update(message, messageOffset, messageLength); h = hasher.FinalizeHash(); ScalarOperations.sc_reduce(h); var sm32 = new byte[32];//todo: remove allocation Array.Copy(signature, signatureOffset + 32, sm32, 0, 32); GroupOperations.ge_double_scalarmult_vartime(out R, h, ref A, sm32); GroupOperations.ge_tobytes(checkr, 0, ref R); var result = CryptoBytes.ConstantTimeEquals(checkr, 0, signature, signatureOffset, 32); CryptoBytes.Wipe(h); CryptoBytes.Wipe(checkr); return(result); }
public static bool CryptoSignVerify( byte[] sig, int sigoffset, byte[] m, int moffset, int mlen, byte[] pk, int pkoffset) { var checker = new byte[32]; GroupElementP3 A; GroupElementP2 R; if ((sig[sigoffset + 63] & 224) != 0) { return(false); } if (GroupOperations.FromBytes(out A, pk, pkoffset) != 0) { return(false); } var hasher = new Sha512(); hasher.Update(sig, sigoffset, 32); hasher.Update(pk, pkoffset, 32); hasher.Update(m, moffset, mlen); var h = hasher.Finalize(); ScalarOperations.Reduce(h); var sm32 = new byte[32]; Array.Copy(sig, sigoffset + 32, sm32, 0, 32); GroupOperations.DoubleScalarMult(out R, h, ref A, sm32); GroupOperations.ToBytes(checker, 0, ref R); var result = CryptoBytes.ConstantTimeEquals(checker, 0, sig, sigoffset, 32); CryptoBytes.Wipe(h); CryptoBytes.Wipe(checker); return(result); }
// Original crypto_sign_open, for reference only /*public static int crypto_sign_open( * byte[] m, out int mlen, * byte[] sm, int smlen, * byte[] pk) * { * byte[] h = new byte[64]; * byte[] checkr = new byte[32]; * GroupElementP3 A; * GroupElementP2 R; * int i; * * mlen = -1; * if (smlen < 64) return -1; * if ((sm[63] & 224) != 0) return -1; * if (GroupOperations.ge_frombytes_negate_vartime(out A, pk, 0) != 0) return -1; * * for (i = 0; i < smlen; ++i) m[i] = sm[i]; * for (i = 0; i < 32; ++i) m[32 + i] = pk[i]; * Sha512BclWrapper.crypto_hash_sha512(h, m, 0, smlen); * ScalarOperations.sc_reduce(h); * * var sm32 = new byte[32]; * Array.Copy(sm, 32, sm32, 0, 32); * GroupOperations.ge_double_scalarmult_vartime(out R, h, ref A, sm32); * GroupOperations.ge_tobytes(checkr, 0, ref R); * if (Helpers.crypto_verify_32(checkr, sm) != 0) * { * for (i = 0; i < smlen; ++i) * m[i] = 0; * return -1; * } * * for (i = 0; i < smlen - 64; ++i) * m[i] = sm[64 + i]; * for (i = smlen - 64; i < smlen; ++i) * m[i] = 0; * mlen = smlen - 64; * return 0; * }*/ public static bool CryptoSignVerify( byte[] sig, int sigoffset, byte[] m, int moffset, int mlen, byte[] pk, int pkoffset) { var checkr = new byte[32]; GroupElementP3 A; GroupElementP2 R; if ((sig[sigoffset + 63] & 224) != 0) { return(false); } if (stellar_dotnet_sdk.chaos.nacl.Internal.Ed25519Ref10.GroupOperations.ge_frombytes_negate_vartime(out A, pk, pkoffset) != 0) { return(false); } var hasher = new Sha512(); hasher.Update(sig, sigoffset, 32); hasher.Update(pk, pkoffset, 32); hasher.Update(m, moffset, mlen); var h = hasher.Finish(); ScalarOperations.ScReduce(h); var sm32 = new byte[32]; //todo: remove allocation Array.Copy(sig, sigoffset + 32, sm32, 0, 32); stellar_dotnet_sdk.chaos.nacl.Internal.Ed25519Ref10.GroupOperations.ge_double_scalarmult_vartime(out R, h, ref A, sm32); stellar_dotnet_sdk.chaos.nacl.Internal.Ed25519Ref10.GroupOperations.GeToBytes(checkr, 0, ref R); var result = CryptoBytes.ConstantTimeEquals(checkr, 0, sig, sigoffset, 32); CryptoBytes.Wipe(h); CryptoBytes.Wipe(checkr); return(result); }