diff --git a/Beacon.Sdk.Tests/Beacon.Sdk.Tests.csproj b/Beacon.Sdk.Tests/Beacon.Sdk.Tests.csproj index 21bcddf..ad1198d 100644 --- a/Beacon.Sdk.Tests/Beacon.Sdk.Tests.csproj +++ b/Beacon.Sdk.Tests/Beacon.Sdk.Tests.csproj @@ -7,14 +7,18 @@ - - - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + - + diff --git a/Beacon.Sdk.Tests/CryptoTests.cs b/Beacon.Sdk.Tests/CryptoTests.cs new file mode 100644 index 0000000..12b927f --- /dev/null +++ b/Beacon.Sdk.Tests/CryptoTests.cs @@ -0,0 +1,72 @@ +namespace Beacon.Sdk.Tests +{ + using Core.Infrastructure.Cryptography; + using Core.Infrastructure.Cryptography.NaCl; + using Core.Infrastructure.Cryptography.BouncyCastle; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Text; + + [TestClass] + public class CryptoTests + { + private byte[] randomPubKeyBytes { get; } = + { + 0x58, 0x96, 0xB4, 0xDE, 0x36, 0x93, 0x5F, 0x5, 0x79, 0x4E, 0xB8, 0x7, 0x3F, 0xB1, 0x7F, 0xE6, 0xAD, + 0x64, 0xFF, 0xE3, 0x48, 0x60, 0x81, 0x1C, 0x9D, 0xDF, 0xB9, 0xE4, 0xF3, 0x2F, 0xF7, 0x5B, + }; + + private byte[] convertedPubKeyBytes { get; } = + { + 0x50, 0x94, 0xD3, 0xF3, 0x88, 0xFD, 0x19, 0xF3, 0x3D, 0xBF, 0xA7, 0x3A, 0x6C, 0x9E, 0xCD, 0x80, 0x7C, + 0x1C, 0x92, 0x74, 0xE3, 0xA0, 0x71, 0x8F, 0xEC, 0xB8, 0xDD, 0x8D, 0x3E, 0x78, 0x66, 0x15 + }; + + [TestMethod] + public void TestSodiumConvertEd25519PublicKeyToCurve25519PublicKey() + { + var actual = PublicKeyAuth.ConvertEd25519PublicKeyToCurve25519PublicKey(randomPubKeyBytes); + CollectionAssert.AreEqual(convertedPubKeyBytes, actual); + } + + [TestMethod] + public void TestConvertEd25519PublicKeyToCurve25519PublicKey() + { + var actual = new byte[32]; + MontgomeryCurve25519.EdwardsToMontgomery(actual, randomPubKeyBytes); + CollectionAssert.AreEqual(convertedPubKeyBytes, actual); + } + + [TestMethod] + public void CanEncryptAndDecryptBySecretBox() + { + var key = SecureRandom.GetRandomBytes(32); + var nonce = SecureRandom.GetRandomBytes(24); + var message = Encoding.UTF8.GetBytes("Test message for secret box"); + + var cipher = SecretBox.Create(message, nonce, key); + + var decrypted = SecretBox.Open(cipher, nonce, key); + + CollectionAssert.AreEqual(message, decrypted); + } + + [TestMethod] + public void CanEncryptAndDecryptBySealedSecretBox() + { + var seed = SecureRandom.GetRandomBytes(32); + + var ed25519keyPair = PublicKeyAuth.GenerateKeyPair(seed); + + var curve25519sk = Ed25519Extensions.ConvertEd25519SecretKeyToCurve25519SecretKey(ed25519keyPair.PrivateKey); + var curve25519pk = Ed25519Extensions.ConvertEd25519PublicKeyToCurve25519PublicKey(ed25519keyPair.PublicKey); + + var message = Encoding.UTF8.GetBytes("Test message for secret box"); + + var cipher = SealedPublicKeyBox.Create(message, curve25519pk); + + var decrypted = SealedPublicKeyBox.Open(cipher, curve25519sk, curve25519pk); + + CollectionAssert.AreEqual(message, decrypted); + } + } +} \ No newline at end of file diff --git a/Beacon.Sdk/Beacon.Sdk.csproj b/Beacon.Sdk/Beacon.Sdk.csproj index 0410cff..5ee11f6 100644 --- a/Beacon.Sdk/Beacon.Sdk.csproj +++ b/Beacon.Sdk/Beacon.Sdk.csproj @@ -14,19 +14,19 @@ Mikhail Tatarenko Beacon.Sdk Beacon .NET SDK for Tezos wallet / dApps developers. - 1.0.16 + 1.0.18 Copyright © Baking Bad 2019-2022 enable - netstandard2.0 + netstandard2.1 + - diff --git a/Beacon.Sdk/Core/Domain/Entities/PeerFactory.cs b/Beacon.Sdk/Core/Domain/Entities/PeerFactory.cs index 3b58716..2a25494 100644 --- a/Beacon.Sdk/Core/Domain/Entities/PeerFactory.cs +++ b/Beacon.Sdk/Core/Domain/Entities/PeerFactory.cs @@ -1,7 +1,6 @@ namespace Beacon.Sdk.Core.Domain.Entities { - using System; - using Infrastructure.Cryptography.Libsodium; + using global::Beacon.Sdk.Core.Infrastructure.Cryptography; using Interfaces; using Netezos.Encoding; using Utils; @@ -17,10 +16,7 @@ public PeerFactory(ICryptographyService cryptographyService) public static byte[] Hash(byte[] message, int bufferLength) { - var buffer = new byte[bufferLength]; - Sodium.CryptoGenericHash(buffer, bufferLength, message, (ulong)message.Length, Array.Empty(), 0); - - return buffer; + return GenericHash.Hash(message, bufferLength); } public Peer Create(HexString hexPublicKey, string name, string version, string relayServer, bool isActive = false) diff --git a/Beacon.Sdk/Core/Domain/Interfaces/Data/ISessionKeyPairRepository.cs b/Beacon.Sdk/Core/Domain/Interfaces/Data/ISessionKeyPairRepository.cs index ff5f899..40931a1 100644 --- a/Beacon.Sdk/Core/Domain/Interfaces/Data/ISessionKeyPairRepository.cs +++ b/Beacon.Sdk/Core/Domain/Interfaces/Data/ISessionKeyPairRepository.cs @@ -2,7 +2,6 @@ namespace Beacon.Sdk.Core.Domain.Interfaces.Data { - using Infrastructure.Cryptography.Libsodium; using Utils; public interface ISessionKeyPairRepository diff --git a/Beacon.Sdk/Core/Domain/Interfaces/ICryptographyService.cs b/Beacon.Sdk/Core/Domain/Interfaces/ICryptographyService.cs index ea80f39..f9a1c60 100644 --- a/Beacon.Sdk/Core/Domain/Interfaces/ICryptographyService.cs +++ b/Beacon.Sdk/Core/Domain/Interfaces/ICryptographyService.cs @@ -2,7 +2,6 @@ namespace Beacon.Sdk.Core.Domain.Interfaces { - using Infrastructure.Cryptography.Libsodium; using Utils; public interface ICryptographyService diff --git a/Beacon.Sdk/Core/Domain/P2P/ChannelOpening/ChannelOpeningMessageBuilder.cs b/Beacon.Sdk/Core/Domain/P2P/ChannelOpening/ChannelOpeningMessageBuilder.cs index 5818edd..1a3f0ea 100644 --- a/Beacon.Sdk/Core/Domain/P2P/ChannelOpening/ChannelOpeningMessageBuilder.cs +++ b/Beacon.Sdk/Core/Domain/P2P/ChannelOpening/ChannelOpeningMessageBuilder.cs @@ -32,7 +32,7 @@ public ChannelOpeningMessageBuilder( public void BuildRecipientId(string relayServer, HexString hexPublicKey) { byte[] publicKeyByteArray = hexPublicKey.ToByteArray(); - byte[] hash = GenericHash.Hash(publicKeyByteArray, null, publicKeyByteArray.Length)!; + byte[] hash = GenericHash.Hash(publicKeyByteArray, publicKeyByteArray.Length)!; if (!HexString.TryParse(hash, out HexString hexHash)) throw new InvalidOperationException("Can not parse hash"); diff --git a/Beacon.Sdk/Core/Domain/Services/P2PMessageService.cs b/Beacon.Sdk/Core/Domain/Services/P2PMessageService.cs index 25b89ad..b6a700a 100644 --- a/Beacon.Sdk/Core/Domain/Services/P2PMessageService.cs +++ b/Beacon.Sdk/Core/Domain/Services/P2PMessageService.cs @@ -1,7 +1,7 @@ namespace Beacon.Sdk.Core.Domain.Services { using System.Text; - using Infrastructure.Cryptography.Libsodium; + using global::Beacon.Sdk.Core.Infrastructure.Cryptography; using Interfaces; using Interfaces.Data; using Netezos.Encoding; diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/BouncyCastle/Ed25519Extensions.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/BouncyCastle/Ed25519Extensions.cs new file mode 100644 index 0000000..332a49b --- /dev/null +++ b/Beacon.Sdk/Core/Infrastructure/Cryptography/BouncyCastle/Ed25519Extensions.cs @@ -0,0 +1,57 @@ +using Org.BouncyCastle.Crypto.Digests; +using System; + +namespace Beacon.Sdk.Core.Infrastructure.Cryptography.BouncyCastle +{ + using NaCl; + + public static class Ed25519Extensions + { + private const int PUBLIC_KEY_BYTES = 32; + private const int SCALAR_BYTES = 32; + private const int SECRET_KEY_BYTES = 32 + 32; + + /// Converts the ed25519 public key to curve25519 public key. + /// Ed25519 public key. + /// The curve25519 public key. + /// + public static byte[] ConvertEd25519PublicKeyToCurve25519PublicKey(byte[] ed25519PublicKey) + { + if (ed25519PublicKey == null || ed25519PublicKey.Length != PUBLIC_KEY_BYTES) + throw new ArgumentOutOfRangeException(nameof(ed25519PublicKey), ed25519PublicKey?.Length ?? 0, $"ed25519PublicKey must be {PUBLIC_KEY_BYTES} bytes in length."); + + var result = new byte[PUBLIC_KEY_BYTES]; + MontgomeryCurve25519.EdwardsToMontgomery(result, ed25519PublicKey); + return result; + } + + /// Converts the ed25519 secret key to curve25519 secret key. + /// Ed25519 secret key. + /// The curve25519 secret key. + /// + public static byte[] ConvertEd25519SecretKeyToCurve25519SecretKey(byte[] ed25519SecretKey) + { + // key can be appended with the public key or not (both are allowed) + if (ed25519SecretKey == null || (ed25519SecretKey.Length != PUBLIC_KEY_BYTES && ed25519SecretKey.Length != SECRET_KEY_BYTES)) + throw new ArgumentOutOfRangeException(nameof(ed25519SecretKey), ed25519SecretKey?.Length ?? 0, $"ed25519SecretKey must be either {PUBLIC_KEY_BYTES} or {SECRET_KEY_BYTES} bytes in length."); + + var sha512 = new Sha512Digest(); + + byte[] h = new byte[sha512.GetDigestSize()]; + + sha512.BlockUpdate(ed25519SecretKey, 0, SCALAR_BYTES); + sha512.DoFinal(h, 0); + + PruneScalar(h); + + return h.AsSpan(0, 32).ToArray(); + } + + private static void PruneScalar(byte[] n) + { + n[0] &= 0xF8; + n[SCALAR_BYTES - 1] &= 0x7F; + n[SCALAR_BYTES - 1] |= 0x40; + } + } +} \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/CryptographyService.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/CryptographyService.cs index 7680260..5a70d2b 100644 --- a/Beacon.Sdk/Core/Infrastructure/Cryptography/CryptographyService.cs +++ b/Beacon.Sdk/Core/Infrastructure/Cryptography/CryptographyService.cs @@ -4,14 +4,12 @@ namespace Beacon.Sdk.Core.Infrastructure.Cryptography using System.Linq; using System.Text; using Domain.Interfaces; - using Libsodium; using Utils; - using Sodium = Libsodium.Sodium; public class CryptographyService : ICryptographyService { - private static readonly int MacBytes = Sodium.CryptoBoxMacBytes(); - private static readonly int NonceBytes = Sodium.CryptoBoxNonceBytes(); + private static readonly int MacBytes = 16; + private static readonly int NonceBytes = 24; public SessionKeyPair CreateClientSessionKeyPair(byte[] clientPublicKey, byte[] serverPrivateKey) { @@ -20,7 +18,9 @@ public SessionKeyPair CreateClientSessionKeyPair(byte[] clientPublicKey, byte[] byte[] serverSecretKeyCurve = PublicKeyAuth.ConvertEd25519SecretKeyToCurve25519SecretKey(serverPrivateKey)!; byte[] clientPublicKeyCurve = PublicKeyAuth.ConvertEd25519PublicKeyToCurve25519PublicKey(clientPublicKey)!; - return KeyExchange.CreateClientSessionKeyPair(serverPublicKeyCurve, serverSecretKeyCurve, + return KeyExchange.CreateClientSessionKeyPair( + serverPublicKeyCurve, + serverSecretKeyCurve, clientPublicKeyCurve); } @@ -31,25 +31,19 @@ public SessionKeyPair CreateServerSessionKeyPair(byte[] clientPublicKey, byte[] byte[] serverSecretKeyCurve = PublicKeyAuth.ConvertEd25519SecretKeyToCurve25519SecretKey(serverPrivateKey)!; byte[] clientPublicKeyCurve = PublicKeyAuth.ConvertEd25519PublicKeyToCurve25519PublicKey(clientPublicKey)!; - return KeyExchange.CreateServerSessionKeyPair(serverPublicKeyCurve, serverSecretKeyCurve, + return KeyExchange.CreateServerSessionKeyPair( + serverPublicKeyCurve, + serverSecretKeyCurve, clientPublicKeyCurve); } - public byte[] Hash(byte[] input) => GenericHash.Hash(input, null, input.Length); + public byte[] Hash(byte[] input) => GenericHash.Hash(input, input.Length); - public byte[] Hash(byte[] message, int bufferLength) - { - var buffer = new byte[bufferLength]; - - Sodium.Initialize(); - Sodium.CryptoGenericHash(buffer, bufferLength, message, (ulong)message.Length, Array.Empty(), 0); - - return buffer; - } + public byte[] Hash(byte[] message, int resultLength) => GenericHash.Hash(message, resultLength); public KeyPair GenerateEd25519KeyPair(string seed) { - byte[] hash = GenericHash.Hash(seed, (byte[]?)null, 32); + byte[] hash = GenericHash.Hash(seed, 32); return PublicKeyAuth.GenerateKeyPair(hash); } @@ -67,14 +61,6 @@ public HexString Encrypt(string input, byte[] key) return hexPayload; } - // public static class ArrayExtensions - // { - // public byte this[Range input] - // { - // get; - // set; - // } - // } public string Decrypt(HexString hexInput, byte[] key) { byte[] bytes = hexInput.ToByteArray(); @@ -136,7 +122,7 @@ public byte[] GenerateLoginDigest() long now = DateTimeOffset.UtcNow.ToUnixTimeSeconds() * 1000; var message = $"login:{now / 1000 / (5 * 60)}"; - return GenericHash.Hash(message, (byte[]?)null, 32); + return GenericHash.Hash(message, 32); } public string GenerateHexSignature(byte[] loginDigest, byte[] secretKey) @@ -148,7 +134,7 @@ public string GenerateHexSignature(byte[] loginDigest, byte[] secretKey) public string GenerateHexId(byte[] publicKey) { - byte[] hash = GenericHash.Hash(publicKey, null, publicKey.Length); + byte[] hash = GenericHash.Hash(publicKey, publicKey.Length); return ToHexString(hash); } diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/GenericHash.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/GenericHash.cs new file mode 100644 index 0000000..7b8e779 --- /dev/null +++ b/Beacon.Sdk/Core/Infrastructure/Cryptography/GenericHash.cs @@ -0,0 +1,42 @@ +using System; +using System.Text; + +using Org.BouncyCastle.Crypto.Digests; + +namespace Beacon.Sdk.Core.Infrastructure.Cryptography +{ + public static partial class GenericHash + { + private const int BYTES_MIN = 0; + private const int BYTES_MAX = 64; + + /// Hashes a message, using the BLAKE2b primitive. + /// The message to be hashed. + /// The size (in bytes) of the desired result. + /// Returns a byte array. + /// + public static byte[] Hash(string message, int resultLength) + { + return Hash(Encoding.UTF8.GetBytes(message), resultLength); + } + + /// Hashes a message, using the BLAKE2b primitive. + /// The message to be hashed. + /// The size (in bytes) of the desired result. + /// Returns a byte array. + /// + public static byte[] Hash(byte[] message, int resultLength) + { + if (resultLength > BYTES_MAX || resultLength < BYTES_MIN) + throw new ArgumentOutOfRangeException(nameof(resultLength), resultLength, $"bytes must be between {BYTES_MIN} and {BYTES_MAX} bytes in length."); + + var array = new byte[resultLength]; + + var blake2bDigest = new Blake2bDigest(resultLength * 8); + blake2bDigest.BlockUpdate(message, 0, message.Length); + blake2bDigest.DoFinal(array, 0); + + return array; + } + } +} \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/KeyExchange.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/KeyExchange.cs new file mode 100644 index 0000000..c387e4a --- /dev/null +++ b/Beacon.Sdk/Core/Infrastructure/Cryptography/KeyExchange.cs @@ -0,0 +1,94 @@ +namespace Beacon.Sdk.Core.Infrastructure.Cryptography +{ + using System; + using Org.BouncyCastle.Crypto.Digests; + using Org.BouncyCastle.Math.EC.Rfc7748; + + public static class KeyExchange + { + // crypto_kx_PUBLICKEYBYTES + private const int PublicKeyBytes = 32; + + // crypto_kx_SECRETKEYBYTES + private const int SecretKeyBytes = 32; + + // crypto_kx_SESSIONKEYBYTES + private const int SessionKeyBytes = 32; + + private const int ScalarMultCurve25519Bytes = 32; + + public static SessionKeyPair CreateClientSessionKeyPair( + byte[] clientPublicKey, + byte[] clientSecretKey, + byte[] serverPublicKey) + { + var rx = new byte[SessionKeyBytes]; + var tx = new byte[SessionKeyBytes]; + + if (clientPublicKey is not { Length: PublicKeyBytes }) + throw new ArgumentException( + $"{nameof(clientPublicKey)} size must be {PublicKeyBytes} bytes in length."); + + if (clientSecretKey is not { Length: SecretKeyBytes }) + throw new ArgumentException( + $"{nameof(clientSecretKey)} size must be {SecretKeyBytes} bytes in length."); + + if (serverPublicKey is not { Length: PublicKeyBytes }) + throw new ArgumentException( + $"{nameof(serverPublicKey)} size must be {PublicKeyBytes} bytes in length."); + + var q = new byte[ScalarMultCurve25519Bytes]; + X25519.ScalarMult(clientSecretKey, 0, serverPublicKey, 0, q, 0); + + var h = new byte[2 * SessionKeyBytes]; + + var blake2bDigest = new Blake2bDigest(h.Length * 8); + blake2bDigest.BlockUpdate(q, 0, q.Length); + blake2bDigest.BlockUpdate(clientPublicKey, 0, PublicKeyBytes); + blake2bDigest.BlockUpdate(serverPublicKey, 0, PublicKeyBytes); + blake2bDigest.DoFinal(h, 0); + + Buffer.BlockCopy(h, 0, rx, 0, SessionKeyBytes); + Buffer.BlockCopy(h, SessionKeyBytes, tx, 0, SessionKeyBytes); + + return new SessionKeyPair(rx, tx); + } + + public static SessionKeyPair CreateServerSessionKeyPair( + byte[] serverPublicKey, + byte[] serverSecretKey, + byte[] clientPublicKey) + { + var rx = new byte[SessionKeyBytes]; + var tx = new byte[SessionKeyBytes]; + + if (serverPublicKey is not { Length: PublicKeyBytes }) + throw new ArgumentException( + $"{nameof(serverPublicKey)} size must be {PublicKeyBytes} bytes in length."); + + if (serverSecretKey is not { Length: SecretKeyBytes }) + throw new ArgumentException( + $"{nameof(serverSecretKey)} size must be {SecretKeyBytes} bytes in length."); + + if (clientPublicKey is not { Length: PublicKeyBytes }) + throw new ArgumentException( + $"{nameof(clientPublicKey)} size must be {PublicKeyBytes} bytes in length."); + + var q = new byte[ScalarMultCurve25519Bytes]; + X25519.ScalarMult(serverSecretKey, 0, clientPublicKey, 0, q, 0); + + var h = new byte[2 * SessionKeyBytes]; + + var blake2bDigest = new Blake2bDigest(h.Length * 8); + blake2bDigest.BlockUpdate(q, 0, q.Length); + blake2bDigest.BlockUpdate(clientPublicKey, 0, PublicKeyBytes); + blake2bDigest.BlockUpdate(serverPublicKey, 0, PublicKeyBytes); + blake2bDigest.DoFinal(h, 0); + + Buffer.BlockCopy(h, 0, tx, 0, SessionKeyBytes); + Buffer.BlockCopy(h, SessionKeyBytes, rx, 0, SessionKeyBytes); + + return new SessionKeyPair(rx, tx); + } + } +} \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/GenericHash.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/GenericHash.cs deleted file mode 100644 index 1fdeddc..0000000 --- a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/GenericHash.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Text; - -using Beacon.Sdk.Core.Infrastructure.Cryptography.Libsodium; - -namespace Beacon.Sdk.Core.Infrastructure.Cryptography -{ - public static partial class GenericHash - { - private const int BYTES_MIN = Sodium.crypto_generichash_blake2b_BYTES_MIN; - private const int BYTES_MAX = Sodium.crypto_generichash_blake2b_BYTES_MAX; - private const int KEY_BYTES_MIN = Sodium.crypto_generichash_blake2b_KEYBYTES_MIN; - private const int KEY_BYTES_MAX = Sodium.crypto_generichash_blake2b_KEYBYTES_MAX; - - /// Generates a random 64 byte key. - /// Returns a byte array with 64 random bytes - public static byte[] GenerateKey() - { - return SecureRandom.GetRandomBytes(KEY_BYTES_MAX); - } - - /// Hashes a message, with an optional key, using the BLAKE2b primitive. - /// The message to be hashed. - /// The key; may be null, otherwise between 16 and 64 bytes. - /// The size (in bytes) of the desired result. - /// Returns a byte array. - /// - /// - public static byte[] Hash(string message, byte[]? key, int bytes) - { - return Hash(Encoding.UTF8.GetBytes(message), key, bytes); - } - - /// Hashes a message, with an optional key, using the BLAKE2b primitive. - /// The message to be hashed. - /// The key; may be null, otherwise between 16 and 64 bytes. - /// The size (in bytes) of the desired result. - /// Returns a byte array. - /// - /// - public static byte[] Hash(byte[] message, byte[]? key, int bytes) - { - if (key == null) - key = Array.Empty(); - else if (key.Length > KEY_BYTES_MAX || key.Length < KEY_BYTES_MIN) - throw new ArgumentOutOfRangeException(nameof(key), key?.Length ?? 0, $"key must be between {KEY_BYTES_MIN} and {KEY_BYTES_MAX} bytes in length."); - if (bytes > BYTES_MAX || bytes < BYTES_MIN) - throw new ArgumentOutOfRangeException(nameof(bytes), bytes, $"bytes must be between {BYTES_MIN} and {BYTES_MAX} bytes in length."); - - var buffer = new byte[bytes]; - - Sodium.Initialize(); - Sodium.CryptoGenericHashBlake2b(buffer, buffer.Length, message, (ulong)message.Length, key, key.Length); - - return buffer; - } - } -} \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/ILibsodiumImpl.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/ILibsodiumImpl.cs deleted file mode 100644 index 663778f..0000000 --- a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/ILibsodiumImpl.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System; - -namespace Beacon.Sdk.Core.Infrastructure.Cryptography.Libsodium -{ - interface ILibsodiumImpl - { - int SodiumInit(); - int SodiumSetMisuseHandler(Action handler); - int SodiumLibraryVersionMajor(); - int SodiumLibraryVersionMinor(); - IntPtr SodiumVersionString(); - int CryptoSignEd25519( - byte[] sm, - ref ulong smlen_p, - byte[] m, - ulong mlen, - byte[] sk); - int CryptoSignEd25519Detached( - byte[] sig, - ref ulong siglen_p, - byte[] m, - ulong mlen, - byte[] sk); - int CryptoSignEd25519KeyPair( - byte[] pk, - byte[] sk); - int CryptoSignEd25519Open( - byte[] m, - ref ulong mlen_p, - byte[] sm, - ulong smlen, - byte[] pk); - int CryptoSignEd25519PkToCurve25519( - byte[] curve25519_pk, - byte[] ed25519_pk); - int CryptoSignEd25519SeedKeyPair( - byte[] pk, - byte[] sk, - byte[] seed); - int CryptoSignEd25519SkToCurve25519( - byte[] curve25519_sk, - byte[] ed25519_sk); - int CryptoSignEd25519SkToPk( - byte[] pk, - byte[] sk); - int CryptoSignEd25519SkToSeed( - byte[] seed, - byte[] sk); - int CryptoSignEd25519VerifyDetached( - byte[] sig, - byte[] m, - ulong mlen, - byte[] pk); - int CryptoGenericHashBlake2b( - byte[] @out, - int outlen, - byte[] @in, - ulong inlen, - byte[] key, - int keylen); - int CryptoSecretBoxEasy( - byte[] c, - byte[] m, - ulong mlen, - byte[] n, - byte[] k); - int CryptoSecretBoxOpenEasy( - byte[] m, - byte[] c, - ulong clen, - byte[] n, - byte[] k); - int CryptoBoxSeal( - byte[] c, - byte[] m, - ulong mlen, - byte[] pk); - int CryptoBoxSealOpen( - byte[] m, - byte[] c, - ulong clen, - byte[] pk, - byte[] sk); - int CryptoKxClientSessionKeys( - byte[] rx, - byte[] tx, - byte[] client_pk, - byte[] client_sk, - byte[] server_pk); - int CryptoKxServerSessionKeys( - byte[] rx, - byte[] tx, - byte[] server_pk, - byte[] server_sk, - byte[] client_pk); - int CryptoBoxMacBytes(); - int CryptoBoxNonceBytes(); - int CryptoGenericHash( - byte[] buffer, - int bufferLength, - byte[] message, - ulong messageLength, - byte[] key, - int keyLength); - } -} \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/InternalLibsodiumImpl.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/InternalLibsodiumImpl.cs deleted file mode 100644 index 035fbc9..0000000 --- a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/InternalLibsodiumImpl.cs +++ /dev/null @@ -1,209 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Beacon.Sdk.Core.Infrastructure.Cryptography.Libsodium -{ - internal class InternalLibsodiumImpl : ILibsodiumImpl - { - internal const string Library = "__Internal"; - - public int CryptoBoxMacBytes() => - crypto_box_macbytes(); - public int CryptoBoxNonceBytes() => - crypto_box_noncebytes(); - public int CryptoBoxSeal(byte[] c, byte[] m, ulong mlen, byte[] pk) => - crypto_box_seal(c, m, mlen, pk); - public int CryptoBoxSealOpen(byte[] m, byte[] c, ulong clen, byte[] pk, byte[] sk) => - crypto_box_seal_open(m, c, clen, pk, sk); - public int CryptoGenericHash(byte[] buffer, int bufferLength, byte[] message, ulong messageLength, byte[] key, int keyLength) => - crypto_generichash(buffer, bufferLength, message, messageLength, key, keyLength); - public int CryptoGenericHashBlake2b(byte[] @out, int outlen, byte[] @in, ulong inlen, byte[] key, int keylen) => - crypto_generichash_blake2b(@out, outlen, @in, inlen, key, keylen); - public int CryptoKxClientSessionKeys(byte[] rx, byte[] tx, byte[] client_pk, byte[] client_sk, byte[] server_pk) => - crypto_kx_client_session_keys(rx, tx, client_pk, client_sk, server_pk); - public int CryptoKxServerSessionKeys(byte[] rx, byte[] tx, byte[] server_pk, byte[] server_sk, byte[] client_pk) => - crypto_kx_server_session_keys(rx, tx, server_pk, server_sk, client_pk); - public int CryptoSecretBoxEasy(byte[] c, byte[] m, ulong mlen, byte[] n, byte[] k) => - crypto_secretbox_easy(c, m, mlen, n, k); - public int CryptoSecretBoxOpenEasy(byte[] m, byte[] c, ulong clen, byte[] n, byte[] k) => - crypto_secretbox_open_easy(m, c, clen, n, k); - public int CryptoSignEd25519(byte[] sm, ref ulong smlen_p, byte[] m, ulong mlen, byte[] sk) => - crypto_sign_ed25519(sm, ref smlen_p, m, mlen, sk); - public int CryptoSignEd25519Detached(byte[] sig, ref ulong siglen_p, byte[] m, ulong mlen, byte[] sk) => - crypto_sign_ed25519_detached(sig, ref siglen_p, m, mlen, sk); - public int CryptoSignEd25519KeyPair(byte[] pk, byte[] sk) => - crypto_sign_ed25519_keypair(pk, sk); - public int CryptoSignEd25519Open(byte[] m, ref ulong mlen_p, byte[] sm, ulong smlen, byte[] pk) => - crypto_sign_ed25519_open(m, ref mlen_p, sm, smlen, pk); - public int CryptoSignEd25519PkToCurve25519(byte[] curve25519_pk, byte[] ed25519_pk) => - crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk); - public int CryptoSignEd25519SeedKeyPair(byte[] pk, byte[] sk, byte[] seed) => - crypto_sign_ed25519_seed_keypair(pk, sk, seed); - public int CryptoSignEd25519SkToCurve25519(byte[] curve25519_sk, byte[] ed25519_sk) => - crypto_sign_ed25519_sk_to_curve25519(curve25519_sk, ed25519_sk); - public int CryptoSignEd25519SkToPk(byte[] pk, byte[] sk) => - crypto_sign_ed25519_sk_to_pk(pk, sk); - public int CryptoSignEd25519SkToSeed(byte[] seed, byte[] sk) => - crypto_sign_ed25519_sk_to_seed(seed, sk); - public int CryptoSignEd25519VerifyDetached(byte[] sig, byte[] m, ulong mlen, byte[] pk) => - crypto_sign_ed25519_verify_detached(sig, m, mlen, pk); - public int SodiumInit() => - sodium_init(); - public int SodiumLibraryVersionMajor() => - sodium_library_version_major(); - public int SodiumLibraryVersionMinor() => - sodium_library_version_minor(); - public int SodiumSetMisuseHandler(Action handler) => - sodium_set_misuse_handler(handler); - public IntPtr SodiumVersionString() => - sodium_version_string(); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int sodium_init(); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int sodium_set_misuse_handler(Action handler); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int sodium_library_version_major(); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int sodium_library_version_minor(); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr sodium_version_string(); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519( - byte[] sm, - ref ulong smlen_p, - byte[] m, - ulong mlen, - byte[] sk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519_detached( - byte[] sig, - ref ulong siglen_p, - byte[] m, - ulong mlen, - byte[] sk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519_keypair( - byte[] pk, - byte[] sk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519_open( - byte[] m, - ref ulong mlen_p, - byte[] sm, - ulong smlen, - byte[] pk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519_pk_to_curve25519( - byte[] curve25519_pk, - byte[] ed25519_pk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519_seed_keypair( - byte[] pk, - byte[] sk, - byte[] seed); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519_sk_to_curve25519( - byte[] curve25519_sk, - byte[] ed25519_sk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519_sk_to_pk( - byte[] pk, - byte[] sk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519_sk_to_seed( - byte[] seed, - byte[] sk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519_verify_detached( - byte[] sig, - byte[] m, - ulong mlen, - byte[] pk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_generichash_blake2b( - byte[] @out, - int outlen, - byte[] @in, - ulong inlen, - byte[] key, - int keylen); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_secretbox_easy( - byte[] c, - byte[] m, - ulong mlen, - byte[] n, - byte[] k); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_secretbox_open_easy( - byte[] m, - byte[] c, - ulong clen, - byte[] n, - byte[] k); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_box_seal( - byte[] c, - byte[] m, - ulong mlen, - byte[] pk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_box_seal_open( - byte[] m, - byte[] c, - ulong clen, - byte[] pk, - byte[] sk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_kx_client_session_keys( - byte[] rx, - byte[] tx, - byte[] client_pk, - byte[] client_sk, - byte[] server_pk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_kx_server_session_keys( - byte[] rx, - byte[] tx, - byte[] server_pk, - byte[] server_sk, - byte[] client_pk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_box_macbytes(); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_box_noncebytes(); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_generichash( - byte[] buffer, - int bufferLength, - byte[] message, - ulong messageLength, - byte[] key, - int keyLength); - } -} \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/KeyExchange.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/KeyExchange.cs deleted file mode 100644 index d000404..0000000 --- a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/KeyExchange.cs +++ /dev/null @@ -1,78 +0,0 @@ -namespace Beacon.Sdk.Core.Infrastructure.Cryptography.Libsodium -{ - using System; - - public static class KeyExchange - { - // crypto_kx_PUBLICKEYBYTES - private const int PublicKeyBytes = 32; - - // crypto_kx_SECRETKEYBYTES - private const int SecretKeyBytes = 32; - - // crypto_kx_SESSIONKEYBYTES - private const int SessionKeyBytes = 32; - - public static SessionKeyPair CreateClientSessionKeyPair(byte[] serverPublicKey, byte[] serverSecretKey, - byte[] clientPublicKey) - { - var rx = new byte[SessionKeyBytes]; - var tx = new byte[SessionKeyBytes]; - - if (serverPublicKey is not {Length: PublicKeyBytes}) - throw new ArgumentException( - $"{nameof(serverPublicKey)} size must be {PublicKeyBytes} bytes in length."); - - if (serverSecretKey is not {Length: SecretKeyBytes}) - throw new ArgumentException( - $"{nameof(serverSecretKey)} size must be {SecretKeyBytes} bytes in length."); - - if (clientPublicKey is not {Length: PublicKeyBytes}) - throw new ArgumentException( - $"{nameof(clientPublicKey)} size must be {PublicKeyBytes} bytes in length."); - - if (Sodium.CryptoKxClientSessionKeys( - rx, - tx, - serverPublicKey, - serverSecretKey, - clientPublicKey) != 0) - { - throw new Exception($"{nameof(Sodium)}: {nameof(KeyExchange)} error."); - } - - return new SessionKeyPair(rx, tx); - } - - public static SessionKeyPair CreateServerSessionKeyPair(byte[] serverPublicKey, byte[] serverSecretKey, - byte[] clientPublicKey) - { - var rx = new byte[SessionKeyBytes]; - var tx = new byte[SessionKeyBytes]; - - if (serverPublicKey is not {Length: PublicKeyBytes}) - throw new ArgumentException( - $"{nameof(serverPublicKey)} size must be {PublicKeyBytes} bytes in length."); - - if (serverSecretKey is not {Length: SecretKeyBytes}) - throw new ArgumentException( - $"{nameof(serverSecretKey)} size must be {SecretKeyBytes} bytes in length."); - - if (clientPublicKey is not {Length: PublicKeyBytes}) - throw new ArgumentException( - $"{nameof(clientPublicKey)} size must be {PublicKeyBytes} bytes in length."); - - if (Sodium.CryptoKxServerSessionKeys( - rx, - tx, - serverPublicKey, - serverSecretKey, - clientPublicKey) != 0) - { - throw new Exception($"{nameof(Sodium)}: {nameof(KeyExchange)} error."); - } - - return new SessionKeyPair(rx, tx); - } - } -} \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/LibsodiumImpl.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/LibsodiumImpl.cs deleted file mode 100644 index 7d19162..0000000 --- a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/LibsodiumImpl.cs +++ /dev/null @@ -1,209 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Beacon.Sdk.Core.Infrastructure.Cryptography.Libsodium -{ - internal class LibsodiumImpl : ILibsodiumImpl - { - internal const string Library = "libsodium"; - - public int CryptoBoxMacBytes() => - crypto_box_macbytes(); - public int CryptoBoxNonceBytes() => - crypto_box_noncebytes(); - public int CryptoBoxSeal(byte[] c, byte[] m, ulong mlen, byte[] pk) => - crypto_box_seal(c, m, mlen, pk); - public int CryptoBoxSealOpen(byte[] m, byte[] c, ulong clen, byte[] pk, byte[] sk) => - crypto_box_seal_open(m, c, clen, pk, sk); - public int CryptoGenericHash(byte[] buffer, int bufferLength, byte[] message, ulong messageLength, byte[] key, int keyLength) => - crypto_generichash(buffer, bufferLength, message, messageLength, key, keyLength); - public int CryptoGenericHashBlake2b(byte[] @out, int outlen, byte[] @in, ulong inlen, byte[] key, int keylen) => - crypto_generichash_blake2b(@out, outlen, @in, inlen, key, keylen); - public int CryptoKxClientSessionKeys(byte[] rx, byte[] tx, byte[] client_pk, byte[] client_sk, byte[] server_pk) => - crypto_kx_client_session_keys(rx, tx, client_pk, client_sk, server_pk); - public int CryptoKxServerSessionKeys(byte[] rx, byte[] tx, byte[] server_pk, byte[] server_sk, byte[] client_pk) => - crypto_kx_server_session_keys(rx, tx, server_pk, server_sk, client_pk); - public int CryptoSecretBoxEasy(byte[] c, byte[] m, ulong mlen, byte[] n, byte[] k) => - crypto_secretbox_easy(c, m, mlen, n, k); - public int CryptoSecretBoxOpenEasy(byte[] m, byte[] c, ulong clen, byte[] n, byte[] k) => - crypto_secretbox_open_easy(m, c, clen, n, k); - public int CryptoSignEd25519(byte[] sm, ref ulong smlen_p, byte[] m, ulong mlen, byte[] sk) => - crypto_sign_ed25519(sm, ref smlen_p, m, mlen, sk); - public int CryptoSignEd25519Detached(byte[] sig, ref ulong siglen_p, byte[] m, ulong mlen, byte[] sk) => - crypto_sign_ed25519_detached(sig, ref siglen_p, m, mlen, sk); - public int CryptoSignEd25519KeyPair(byte[] pk, byte[] sk) => - crypto_sign_ed25519_keypair(pk, sk); - public int CryptoSignEd25519Open(byte[] m, ref ulong mlen_p, byte[] sm, ulong smlen, byte[] pk) => - crypto_sign_ed25519_open(m, ref mlen_p, sm, smlen, pk); - public int CryptoSignEd25519PkToCurve25519(byte[] curve25519_pk, byte[] ed25519_pk) => - crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk); - public int CryptoSignEd25519SeedKeyPair(byte[] pk, byte[] sk, byte[] seed) => - crypto_sign_ed25519_seed_keypair(pk, sk, seed); - public int CryptoSignEd25519SkToCurve25519(byte[] curve25519_sk, byte[] ed25519_sk) => - crypto_sign_ed25519_sk_to_curve25519(curve25519_sk, ed25519_sk); - public int CryptoSignEd25519SkToPk(byte[] pk, byte[] sk) => - crypto_sign_ed25519_sk_to_pk(pk, sk); - public int CryptoSignEd25519SkToSeed(byte[] seed, byte[] sk) => - crypto_sign_ed25519_sk_to_seed(seed, sk); - public int CryptoSignEd25519VerifyDetached(byte[] sig, byte[] m, ulong mlen, byte[] pk) => - crypto_sign_ed25519_verify_detached(sig, m, mlen, pk); - public int SodiumInit() => - sodium_init(); - public int SodiumLibraryVersionMajor() => - sodium_library_version_major(); - public int SodiumLibraryVersionMinor() => - sodium_library_version_minor(); - public int SodiumSetMisuseHandler(Action handler) => - sodium_set_misuse_handler(handler); - public IntPtr SodiumVersionString() => - sodium_version_string(); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int sodium_init(); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int sodium_set_misuse_handler(Action handler); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int sodium_library_version_major(); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int sodium_library_version_minor(); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr sodium_version_string(); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519( - byte[] sm, - ref ulong smlen_p, - byte[] m, - ulong mlen, - byte[] sk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519_detached( - byte[] sig, - ref ulong siglen_p, - byte[] m, - ulong mlen, - byte[] sk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519_keypair( - byte[] pk, - byte[] sk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519_open( - byte[] m, - ref ulong mlen_p, - byte[] sm, - ulong smlen, - byte[] pk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519_pk_to_curve25519( - byte[] curve25519_pk, - byte[] ed25519_pk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519_seed_keypair( - byte[] pk, - byte[] sk, - byte[] seed); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519_sk_to_curve25519( - byte[] curve25519_sk, - byte[] ed25519_sk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519_sk_to_pk( - byte[] pk, - byte[] sk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519_sk_to_seed( - byte[] seed, - byte[] sk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_sign_ed25519_verify_detached( - byte[] sig, - byte[] m, - ulong mlen, - byte[] pk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_generichash_blake2b( - byte[] @out, - int outlen, - byte[] @in, - ulong inlen, - byte[] key, - int keylen); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_secretbox_easy( - byte[] c, - byte[] m, - ulong mlen, - byte[] n, - byte[] k); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_secretbox_open_easy( - byte[] m, - byte[] c, - ulong clen, - byte[] n, - byte[] k); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_box_seal( - byte[] c, - byte[] m, - ulong mlen, - byte[] pk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_box_seal_open( - byte[] m, - byte[] c, - ulong clen, - byte[] pk, - byte[] sk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_kx_client_session_keys( - byte[] rx, - byte[] tx, - byte[] client_pk, - byte[] client_sk, - byte[] server_pk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_kx_server_session_keys( - byte[] rx, - byte[] tx, - byte[] server_pk, - byte[] server_sk, - byte[] client_pk); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_box_macbytes(); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_box_noncebytes(); - - [DllImport(Library, CallingConvention = CallingConvention.Cdecl)] - internal static extern int crypto_generichash( - byte[] buffer, - int bufferLength, - byte[] message, - ulong messageLength, - byte[] key, - int keyLength); - } -} \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/PublicKeyAuth.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/PublicKeyAuth.cs deleted file mode 100644 index b23c2f1..0000000 --- a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/PublicKeyAuth.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System; - -using Beacon.Sdk.Core.Infrastructure.Cryptography.Libsodium; - -namespace Beacon.Sdk.Core.Infrastructure.Cryptography -{ - /// Public-key signatures - public static class PublicKeyAuth - { - private const int SECRET_KEY_BYTES = Sodium.crypto_sign_ed25519_SECRETKEYBYTES; - private const int PUBLIC_KEY_BYTES = Sodium.crypto_sign_ed25519_PUBLICKEYBYTES; - private const int BYTES = Sodium.crypto_sign_ed25519_BYTES; - private const int SEED_BYTES = Sodium.crypto_sign_ed25519_SEEDBYTES; - - public static int SecretKeyBytes { get; } = SECRET_KEY_BYTES; - public static int PublicKeyBytes { get; } = PUBLIC_KEY_BYTES; - public static int SignatureBytes { get; } = BYTES; - public static int SeedBytes { get; } = SEED_BYTES; - - /// Creates a new key pair based on the provided seed. - /// The seed. - /// A KeyPair. - /// - public static KeyPair GenerateKeyPair(byte[] seed) - { - if (seed == null || seed.Length != SEED_BYTES) - throw new ArgumentOutOfRangeException(nameof(seed), seed?.Length ?? 0, $"seed must be {SEED_BYTES} bytes in length."); - - var publicKey = new byte[PUBLIC_KEY_BYTES]; - var privateKey = new byte[SECRET_KEY_BYTES]; - - Sodium.Initialize(); - Sodium.CryptoSignEd25519SeedKeyPair(publicKey, privateKey, seed); - - return new KeyPair(publicKey, privateKey); - } - - /// Signs a message with Ed25519. - /// The message. - /// The 64 byte private key. - /// Signed message. - /// - public static byte[] Sign(byte[] message, byte[] key) - { - if (key == null || key.Length != SECRET_KEY_BYTES) - throw new ArgumentOutOfRangeException(nameof(key), key?.Length ?? 0, $"key must be {SECRET_KEY_BYTES} bytes in length."); - - var buffer = new byte[message.Length + BYTES]; - ulong bufferLength = 0; - - Sodium.Initialize(); - Sodium.CryptoSignEd25519(buffer, ref bufferLength, message, (ulong)message.Length, key); - - Array.Resize(ref buffer, (int)bufferLength); - return buffer; - } - - /// Signs a message with Ed25519. - /// The message. - /// The 64 byte private key. - /// The signature. - /// - public static byte[] SignDetached(byte[] message, byte[] key) - { - if (key == null || key.Length != SECRET_KEY_BYTES) - throw new ArgumentOutOfRangeException(nameof(key), key?.Length ?? 0, $"key must be {SECRET_KEY_BYTES} bytes in length."); - - var signature = new byte[BYTES]; - ulong signatureLength = 0; - - Sodium.Initialize(); - Sodium.CryptoSignEd25519Detached(signature, ref signatureLength, message, (ulong)message.Length, key); - - return signature; - } - - /// Converts the ed25519 public key to curve25519 public key. - /// Ed25519 public key. - /// The curve25519 public key. - /// - /// - public static byte[] ConvertEd25519PublicKeyToCurve25519PublicKey(byte[] ed25519PublicKey) - { - if (ed25519PublicKey == null || ed25519PublicKey.Length != PUBLIC_KEY_BYTES) - throw new ArgumentOutOfRangeException(nameof(ed25519PublicKey), ed25519PublicKey?.Length ?? 0, $"ed25519PublicKey must be {PUBLIC_KEY_BYTES} bytes in length."); - - var buffer = new byte[Sodium.crypto_scalarmult_curve25519_BYTES]; - - Sodium.Initialize(); - var ret = Sodium.CryptoSignEd25519PkToCurve25519(buffer, ed25519PublicKey); - - if (ret != 0) - throw new Exception("Failed to convert public key."); - - return buffer; - } - - /// Converts the ed25519 secret key to curve25519 secret key. - /// Ed25519 secret key. - /// The curve25519 secret key. - /// - /// - public static byte[] ConvertEd25519SecretKeyToCurve25519SecretKey(byte[] ed25519SecretKey) - { - // key can be appended with the public key or not (both are allowed) - if (ed25519SecretKey == null || (ed25519SecretKey.Length != PUBLIC_KEY_BYTES && ed25519SecretKey.Length != SECRET_KEY_BYTES)) - throw new ArgumentOutOfRangeException(nameof(ed25519SecretKey), ed25519SecretKey?.Length ?? 0, $"ed25519SecretKey must be either {PUBLIC_KEY_BYTES} or {SECRET_KEY_BYTES} bytes in length."); - - var buffer = new byte[Sodium.crypto_scalarmult_curve25519_SCALARBYTES]; - - Sodium.Initialize(); - var ret = Sodium.CryptoSignEd25519SkToCurve25519(buffer, ed25519SecretKey); - - if (ret != 0) - throw new Exception("Failed to convert secret key."); - - return buffer; - } - } -} diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/Sodium.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/Sodium.cs deleted file mode 100644 index bc90dbc..0000000 --- a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/Sodium.cs +++ /dev/null @@ -1,247 +0,0 @@ -// ReSharper disable InconsistentNaming - -namespace Beacon.Sdk.Core.Infrastructure.Cryptography.Libsodium -{ - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - using System.Threading; - - public enum SodiumLibraryType - { - /// - /// Default dynamic libraries - /// - /// - /// Library name: libsodium.dll for Windows, libsodium.so for Linux/Android, libsodium.dylib for macOS - /// - Dynamic, - /// - /// Static library (default for iOS) - /// - /// - /// Library name: libsodium.a, actual used name: "__Internal" - /// - StaticInternal - } - - public static class Sodium - { - internal const int SODIUM_LIBRARY_VERSION_MAJOR = 10; - internal const int SODIUM_LIBRARY_VERSION_MINOR = 3; - internal const string SODIUM_VERSION_STRING = "1.0.18"; - internal const int crypto_sign_ed25519_BYTES = 64; - internal const int crypto_sign_ed25519_PUBLICKEYBYTES = 32; - internal const int crypto_sign_ed25519_SECRETKEYBYTES = 32 + 32; - internal const int crypto_sign_ed25519_SEEDBYTES = 32; - internal const int crypto_scalarmult_curve25519_BYTES = 32; - internal const int crypto_scalarmult_curve25519_SCALARBYTES = 32; - internal const int crypto_generichash_blake2b_BYTES_MAX = 64; - internal const int crypto_generichash_blake2b_BYTES_MIN = 16; - internal const int crypto_generichash_blake2b_KEYBYTES_MAX = 64; - internal const int crypto_generichash_blake2b_KEYBYTES_MIN = 16; - internal const int crypto_secretbox_xsalsa20poly1305_KEYBYTES = 32; - internal const int crypto_secretbox_xsalsa20poly1305_MACBYTES = 16; - internal const int crypto_secretbox_xsalsa20poly1305_NONCEBYTES = 24; - internal const int crypto_box_curve25519xsalsa20poly1305_MACBYTES = 16; - internal const int crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES = 32; - internal const int crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES = 32; - - static ILibsodiumImpl _impl = new LibsodiumImpl(); - - public static void SetLibraryType(SodiumLibraryType type) - { - _impl = type switch - { - SodiumLibraryType.Dynamic => new LibsodiumImpl(), - SodiumLibraryType.StaticInternal => new InternalLibsodiumImpl(), - _ => new LibsodiumImpl(), - }; - } - - private static readonly Action s_misuseHandler = new(InternalError); - - private static int s_initialized; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void Initialize() - { - if (s_initialized == 0) - { - InitializeCore(); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void InitializeCore() - { - try - { - if (SodiumLibraryVersionMajor() != SODIUM_LIBRARY_VERSION_MAJOR || - SodiumLibraryVersionMinor() != SODIUM_LIBRARY_VERSION_MINOR) - { - string? version = Marshal.PtrToStringAnsi(SodiumVersionString()); - throw (version != null && version != SODIUM_VERSION_STRING) - ? new NotSupportedException($"An error occurred while initializing cryptographic primitives. (Expected libsodium {SODIUM_VERSION_STRING} but found {version}.)") - : new NotSupportedException("An error occurred while initializing cryptographic primitives."); - } - - if (SodiumSetMisuseHandler(s_misuseHandler) != 0) - { - throw new NotSupportedException("An error occurred while initializing cryptographic primitives."); - } - - // sodium_init() returns 0 on success, -1 on failure, and 1 if the library had already been initialized. - if (SodiumInit() < 0) - { - throw new NotSupportedException("An error occurred while initializing cryptographic primitives."); - } - } - catch (DllNotFoundException e) - { - throw new PlatformNotSupportedException("Could not initialize platform-specific components. libsodium-core may not be supported on this platform. See https://github.com/ektrah/libsodium-core/blob/master/INSTALL.md for more information.", e); - } - catch (BadImageFormatException e) - { - throw new PlatformNotSupportedException("Could not initialize platform-specific components. libsodium-core may not be supported on this platform. See https://github.com/ektrah/libsodium-core/blob/master/INSTALL.md for more information.", e); - } - - Interlocked.Exchange(ref s_initialized, 1); - } - - private static void InternalError() - { - throw new NotSupportedException("An internal error occurred."); - } - - internal static int SodiumInit() => - _impl.SodiumInit(); - - internal static int SodiumSetMisuseHandler(Action handler) => - _impl.SodiumSetMisuseHandler(handler); - - internal static int SodiumLibraryVersionMajor() => - _impl.SodiumLibraryVersionMajor(); - - internal static int SodiumLibraryVersionMinor() => - _impl.SodiumLibraryVersionMinor(); - - internal static IntPtr SodiumVersionString() => - _impl.SodiumVersionString(); - - internal static int CryptoSignEd25519( - byte[] sm, - ref ulong smlen_p, - byte[] m, - ulong mlen, - byte[] sk) => _impl.CryptoSignEd25519(sm, ref smlen_p, m, mlen, sk); - - internal static int CryptoSignEd25519Detached( - byte[] sig, - ref ulong siglen_p, - byte[] m, - ulong mlen, - byte[] sk) => _impl.CryptoSignEd25519Detached(sig, ref siglen_p, m, mlen, sk); - - internal static int CryptoSignEd25519KeyPair( - byte[] pk, - byte[] sk) => _impl.CryptoSignEd25519KeyPair(pk, sk); - - internal static int CryptoSignEd25519Open( - byte[] m, - ref ulong mlen_p, - byte[] sm, - ulong smlen, - byte[] pk) => _impl.CryptoSignEd25519Open(m, ref mlen_p, sm, smlen, pk); - - internal static int CryptoSignEd25519PkToCurve25519( - byte[] curve25519_pk, - byte[] ed25519_pk) => _impl.CryptoSignEd25519PkToCurve25519(curve25519_pk, ed25519_pk); - - internal static int CryptoSignEd25519SeedKeyPair( - byte[] pk, - byte[] sk, - byte[] seed) => _impl.CryptoSignEd25519SeedKeyPair(pk, sk, seed); - - internal static int CryptoSignEd25519SkToCurve25519( - byte[] curve25519_sk, - byte[] ed25519_sk) => _impl.CryptoSignEd25519SkToCurve25519(curve25519_sk, ed25519_sk); - - internal static int CryptoSignEd25519SkToPk( - byte[] pk, - byte[] sk) => _impl.CryptoSignEd25519SkToPk(pk, sk); - - internal static int CryptoSignEd25519SkToSeed( - byte[] seed, - byte[] sk) => _impl.CryptoSignEd25519SkToSeed(seed, sk); - - internal static int CryptoSignEd25519VerifyDetached( - byte[] sig, - byte[] m, - ulong mlen, - byte[] pk) => _impl.CryptoSignEd25519VerifyDetached(sig, m, mlen, pk); - - internal static int CryptoGenericHashBlake2b( - byte[] @out, - int outlen, - byte[] @in, - ulong inlen, - byte[] key, - int keylen) => _impl.CryptoGenericHashBlake2b(@out, outlen, @in, inlen, key, keylen); - - internal static int CryptoSecretBoxEasy( - byte[] c, - byte[] m, - ulong mlen, - byte[] n, - byte[] k) => _impl.CryptoSecretBoxEasy(c, m, mlen, n, k); - - internal static int CryptoSecretBoxOpenEasy( - byte[] m, - byte[] c, - ulong clen, - byte[] n, - byte[] k) => _impl.CryptoSecretBoxOpenEasy(m, c, clen, n, k); - - internal static int CryptoBoxSeal( - byte[] c, - byte[] m, - ulong mlen, - byte[] pk) => _impl.CryptoBoxSeal(c, m, mlen, pk); - - internal static int CryptoBoxSealOpen( - byte[] m, - byte[] c, - ulong clen, - byte[] pk, - byte[] sk) => _impl.CryptoBoxSealOpen(m, c, clen, pk, sk); - - internal static int CryptoKxClientSessionKeys( - byte[] rx, - byte[] tx, - byte[] client_pk, - byte[] client_sk, - byte[] server_pk) => _impl.CryptoKxClientSessionKeys(rx, tx, client_pk, client_sk, server_pk); - - internal static int CryptoKxServerSessionKeys( - byte[] rx, - byte[] tx, - byte[] server_pk, - byte[] server_sk, - byte[] client_pk) => _impl.CryptoKxServerSessionKeys(rx, tx, server_pk, server_sk, client_pk); - - internal static int CryptoBoxMacBytes() => - _impl.CryptoBoxMacBytes(); - - internal static int CryptoBoxNonceBytes() => - _impl.CryptoBoxNonceBytes(); - - internal static int CryptoGenericHash( - byte[] buffer, - int bufferLength, - byte[] message, - ulong messageLength, - byte[] key, - int keyLength) => _impl.CryptoGenericHash(buffer, bufferLength, message, messageLength, key, keyLength); - } -} \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/FieldElement.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/FieldElement.cs new file mode 100644 index 0000000..6004cdc --- /dev/null +++ b/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/FieldElement.cs @@ -0,0 +1,38 @@ +namespace Beacon.Sdk.Core.Infrastructure.Cryptography.NaCl.Internal.Ed25519Ref10 +{ + using System; + + internal struct FieldElement + { + internal int x0; + internal int x1; + internal int x2; + internal int x3; + internal int x4; + internal int x5; + internal int x6; + internal int x7; + internal int x8; + internal int x9; + + //public static readonly FieldElement Zero = new FieldElement(); + //public static readonly FieldElement One = new FieldElement() { x0 = 1 }; + + internal FieldElement(params int[] elements) + { + if (elements.Length != 10) + throw new InvalidOperationException("An assertion in Chaos.Crypto failed: elements.Length != 10"); + + x0 = elements[0]; + x1 = elements[1]; + x2 = elements[2]; + x3 = elements[3]; + x4 = elements[4]; + x5 = elements[5]; + x6 = elements[6]; + x7 = elements[7]; + x8 = elements[8]; + x9 = elements[9]; + } + } +} \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_1.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_1.cs new file mode 100644 index 0000000..0c5818e --- /dev/null +++ b/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_1.cs @@ -0,0 +1,11 @@ +namespace Beacon.Sdk.Core.Infrastructure.Cryptography.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + public static void fe_1(out FieldElement h) + { + h = default(FieldElement); + h.x0 = 1; + } + } +} \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_add.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_add.cs new file mode 100644 index 0000000..2a57229 --- /dev/null +++ b/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_add.cs @@ -0,0 +1,63 @@ +using System; + +namespace Beacon.Sdk.Core.Infrastructure.Cryptography.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* + h = f + g + Can overlap h with f or g. + + Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + + Postconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + */ + //void fe_add(fe h,const fe f,const fe g) + internal static void fe_add(out FieldElement h, ref FieldElement f, ref FieldElement g) + { + Int32 f0 = f.x0; + Int32 f1 = f.x1; + Int32 f2 = f.x2; + Int32 f3 = f.x3; + Int32 f4 = f.x4; + Int32 f5 = f.x5; + Int32 f6 = f.x6; + Int32 f7 = f.x7; + Int32 f8 = f.x8; + Int32 f9 = f.x9; + Int32 g0 = g.x0; + Int32 g1 = g.x1; + Int32 g2 = g.x2; + Int32 g3 = g.x3; + Int32 g4 = g.x4; + Int32 g5 = g.x5; + Int32 g6 = g.x6; + Int32 g7 = g.x7; + Int32 g8 = g.x8; + Int32 g9 = g.x9; + Int32 h0 = f0 + g0; + Int32 h1 = f1 + g1; + Int32 h2 = f2 + g2; + Int32 h3 = f3 + g3; + Int32 h4 = f4 + g4; + Int32 h5 = f5 + g5; + Int32 h6 = f6 + g6; + Int32 h7 = f7 + g7; + Int32 h8 = f8 + g8; + Int32 h9 = f9 + g9; + h.x0 = h0; + h.x1 = h1; + h.x2 = h2; + h.x3 = h3; + h.x4 = h4; + h.x5 = h5; + h.x6 = h6; + h.x7 = h7; + h.x8 = h8; + h.x9 = h9; + } + } +} \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_frombytes.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_frombytes.cs new file mode 100644 index 0000000..51f55d7 --- /dev/null +++ b/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_frombytes.cs @@ -0,0 +1,162 @@ +using System; + +namespace Beacon.Sdk.Core.Infrastructure.Cryptography.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + private static Int64 load_3(byte[] data, int offset) + { + uint result; + result = (uint)data[offset + 0]; + result |= (uint)data[offset + 1] << 8; + result |= (uint)data[offset + 2] << 16; + return (Int64)(UInt64)result; + } + + private static Int64 load_4(byte[] data, int offset) + { + uint result; + result = (uint)data[offset + 0]; + result |= (uint)data[offset + 1] << 8; + result |= (uint)data[offset + 2] << 16; + result |= (uint)data[offset + 3] << 24; + return (Int64)(UInt64)result; + } + + // Ignores top bit of h. + internal static void fe_frombytes(out FieldElement h, byte[] data, int offset) + { + Int64 h0 = load_4(data, offset); + Int64 h1 = load_3(data, offset + 4) << 6; + Int64 h2 = load_3(data, offset + 7) << 5; + Int64 h3 = load_3(data, offset + 10) << 3; + Int64 h4 = load_3(data, offset + 13) << 2; + Int64 h5 = load_4(data, offset + 16); + Int64 h6 = load_3(data, offset + 20) << 7; + Int64 h7 = load_3(data, offset + 23) << 5; + Int64 h8 = load_3(data, offset + 26) << 4; + Int64 h9 = (load_3(data, offset + 29) & 8388607) << 2; + Int64 carry0; + Int64 carry1; + Int64 carry2; + Int64 carry3; + Int64 carry4; + Int64 carry5; + Int64 carry6; + Int64 carry7; + Int64 carry8; + Int64 carry9; + + carry9 = (h9 + (Int64)(1 << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 << 25; + carry1 = (h1 + (Int64)(1 << 24)) >> 25; + h2 += carry1; + h1 -= carry1 << 25; + carry3 = (h3 + (Int64)(1 << 24)) >> 25; + h4 += carry3; + h3 -= carry3 << 25; + carry5 = (h5 + (Int64)(1 << 24)) >> 25; + h6 += carry5; + h5 -= carry5 << 25; + carry7 = (h7 + (Int64)(1 << 24)) >> 25; + h8 += carry7; + h7 -= carry7 << 25; + + carry0 = (h0 + (Int64)(1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 << 26; + carry2 = (h2 + (Int64)(1 << 25)) >> 26; + h3 += carry2; + h2 -= carry2 << 26; + carry4 = (h4 + (Int64)(1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 << 26; + carry6 = (h6 + (Int64)(1 << 25)) >> 26; + h7 += carry6; + h6 -= carry6 << 26; + carry8 = (h8 + (Int64)(1 << 25)) >> 26; + h9 += carry8; + h8 -= carry8 << 26; + + h.x0 = (int)h0; + h.x1 = (int)h1; + h.x2 = (int)h2; + h.x3 = (int)h3; + h.x4 = (int)h4; + h.x5 = (int)h5; + h.x6 = (int)h6; + h.x7 = (int)h7; + h.x8 = (int)h8; + h.x9 = (int)h9; + } + + // does NOT ignore top bit + internal static void fe_frombytes2(out FieldElement h, byte[] data, int offset) + { + Int64 h0 = load_4(data, offset); + Int64 h1 = load_3(data, offset + 4) << 6; + Int64 h2 = load_3(data, offset + 7) << 5; + Int64 h3 = load_3(data, offset + 10) << 3; + Int64 h4 = load_3(data, offset + 13) << 2; + Int64 h5 = load_4(data, offset + 16); + Int64 h6 = load_3(data, offset + 20) << 7; + Int64 h7 = load_3(data, offset + 23) << 5; + Int64 h8 = load_3(data, offset + 26) << 4; + Int64 h9 = load_3(data, offset + 29) << 2; + Int64 carry0; + Int64 carry1; + Int64 carry2; + Int64 carry3; + Int64 carry4; + Int64 carry5; + Int64 carry6; + Int64 carry7; + Int64 carry8; + Int64 carry9; + + carry9 = (h9 + (Int64)(1 << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 << 25; + carry1 = (h1 + (Int64)(1 << 24)) >> 25; + h2 += carry1; + h1 -= carry1 << 25; + carry3 = (h3 + (Int64)(1 << 24)) >> 25; + h4 += carry3; + h3 -= carry3 << 25; + carry5 = (h5 + (Int64)(1 << 24)) >> 25; + h6 += carry5; + h5 -= carry5 << 25; + carry7 = (h7 + (Int64)(1 << 24)) >> 25; + h8 += carry7; + h7 -= carry7 << 25; + + carry0 = (h0 + (Int64)(1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 << 26; + carry2 = (h2 + (Int64)(1 << 25)) >> 26; + h3 += carry2; + h2 -= carry2 << 26; + carry4 = (h4 + (Int64)(1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 << 26; + carry6 = (h6 + (Int64)(1 << 25)) >> 26; + h7 += carry6; + h6 -= carry6 << 26; + carry8 = (h8 + (Int64)(1 << 25)) >> 26; + h9 += carry8; + h8 -= carry8 << 26; + + h.x0 = (int)h0; + h.x1 = (int)h1; + h.x2 = (int)h2; + h.x3 = (int)h3; + h.x4 = (int)h4; + h.x5 = (int)h5; + h.x6 = (int)h6; + h.x7 = (int)h7; + h.x8 = (int)h8; + h.x9 = (int)h9; + } + } +} \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_invert.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_invert.cs new file mode 100644 index 0000000..ff37e17 --- /dev/null +++ b/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_invert.cs @@ -0,0 +1,179 @@ +using System; + +namespace Beacon.Sdk.Core.Infrastructure.Cryptography.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + internal static void fe_invert(out FieldElement result, ref FieldElement z) + { + FieldElement t0; + FieldElement t1; + FieldElement t2; + FieldElement t3; + int i; + + /* qhasm: fe z1 */ + + /* qhasm: fe z2 */ + + /* qhasm: fe z8 */ + + /* qhasm: fe z9 */ + + /* qhasm: fe z11 */ + + /* qhasm: fe z22 */ + + /* qhasm: fe z_5_0 */ + + /* qhasm: fe z_10_5 */ + + /* qhasm: fe z_10_0 */ + + /* qhasm: fe z_20_10 */ + + /* qhasm: fe z_20_0 */ + + /* qhasm: fe z_40_20 */ + + /* qhasm: fe z_40_0 */ + + /* qhasm: fe z_50_10 */ + + /* qhasm: fe z_50_0 */ + + /* qhasm: fe z_100_50 */ + + /* qhasm: fe z_100_0 */ + + /* qhasm: fe z_200_100 */ + + /* qhasm: fe z_200_0 */ + + /* qhasm: fe z_250_50 */ + + /* qhasm: fe z_250_0 */ + + /* qhasm: fe z_255_5 */ + + /* qhasm: fe z_255_21 */ + + /* qhasm: enter pow225521 */ + + /* qhasm: z2 = z1^2^1 */ + /* asm 1: fe_sq(>z2=fe#1,z2=fe#1,>z2=fe#1); */ + /* asm 2: fe_sq(>z2=t0,z2=t0,>z2=t0); */ + fe_sq(out t0, ref z); //for (i = 1; i < 1; ++i) fe_sq(out t0, ref t0); + + /* qhasm: z8 = z2^2^2 */ + /* asm 1: fe_sq(>z8=fe#2,z8=fe#2,>z8=fe#2); */ + /* asm 2: fe_sq(>z8=t1,z8=t1,>z8=t1); */ + fe_sq(out t1, ref t0); for (i = 1; i < 2; ++i) fe_sq(out t1, ref t1); + + /* qhasm: z9 = z1*z8 */ + /* asm 1: fe_mul(>z9=fe#2,z9=t1,z11=fe#1,z11=t0,z22=fe#3,z22=fe#3,>z22=fe#3); */ + /* asm 2: fe_sq(>z22=t2,z22=t2,>z22=t2); */ + fe_sq(out t2, ref t0); //for (i = 1; i < 1; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_5_0 = z9*z22 */ + /* asm 1: fe_mul(>z_5_0=fe#2,z_5_0=t1,z_10_5=fe#3,z_10_5=fe#3,>z_10_5=fe#3); */ + /* asm 2: fe_sq(>z_10_5=t2,z_10_5=t2,>z_10_5=t2); */ + fe_sq(out t2, ref t1); for (i = 1; i < 5; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_10_0 = z_10_5*z_5_0 */ + /* asm 1: fe_mul(>z_10_0=fe#2,z_10_0=t1,z_20_10=fe#3,z_20_10=fe#3,>z_20_10=fe#3); */ + /* asm 2: fe_sq(>z_20_10=t2,z_20_10=t2,>z_20_10=t2); */ + fe_sq(out t2, ref t1); for (i = 1; i < 10; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_20_0 = z_20_10*z_10_0 */ + /* asm 1: fe_mul(>z_20_0=fe#3,z_20_0=t2,z_40_20=fe#4,z_40_20=fe#4,>z_40_20=fe#4); */ + /* asm 2: fe_sq(>z_40_20=t3,z_40_20=t3,>z_40_20=t3); */ + fe_sq(out t3, ref t2); for (i = 1; i < 20; ++i) fe_sq(out t3, ref t3); + + /* qhasm: z_40_0 = z_40_20*z_20_0 */ + /* asm 1: fe_mul(>z_40_0=fe#3,z_40_0=t2,z_50_10=fe#3,z_50_10=fe#3,>z_50_10=fe#3); */ + /* asm 2: fe_sq(>z_50_10=t2,z_50_10=t2,>z_50_10=t2); */ + fe_sq(out t2, ref t2); for (i = 1; i < 10; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_50_0 = z_50_10*z_10_0 */ + /* asm 1: fe_mul(>z_50_0=fe#2,z_50_0=t1,z_100_50=fe#3,z_100_50=fe#3,>z_100_50=fe#3); */ + /* asm 2: fe_sq(>z_100_50=t2,z_100_50=t2,>z_100_50=t2); */ + fe_sq(out t2, ref t1); for (i = 1; i < 50; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_100_0 = z_100_50*z_50_0 */ + /* asm 1: fe_mul(>z_100_0=fe#3,z_100_0=t2,z_200_100=fe#4,z_200_100=fe#4,>z_200_100=fe#4); */ + /* asm 2: fe_sq(>z_200_100=t3,z_200_100=t3,>z_200_100=t3); */ + fe_sq(out t3, ref t2); for (i = 1; i < 100; ++i) fe_sq(out t3, ref t3); + + /* qhasm: z_200_0 = z_200_100*z_100_0 */ + /* asm 1: fe_mul(>z_200_0=fe#3,z_200_0=t2,z_250_50=fe#3,z_250_50=fe#3,>z_250_50=fe#3); */ + /* asm 2: fe_sq(>z_250_50=t2,z_250_50=t2,>z_250_50=t2); */ + fe_sq(out t2, ref t2); for (i = 1; i < 50; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_250_0 = z_250_50*z_50_0 */ + /* asm 1: fe_mul(>z_250_0=fe#2,z_250_0=t1,z_255_5=fe#2,z_255_5=fe#2,>z_255_5=fe#2); */ + /* asm 2: fe_sq(>z_255_5=t1,z_255_5=t1,>z_255_5=t1); */ + fe_sq(out t1, ref t1); for (i = 1; i < 5; ++i) fe_sq(out t1, ref t1); + + /* qhasm: z_255_21 = z_255_5*z11 */ + /* asm 1: fe_mul(>z_255_21=fe#12,z_255_21=out,> 26; h1 += carry0; h0 -= carry0 << 26; + carry4 = (h4 + (Int64)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + /* |h0| <= 2^25 */ + /* |h4| <= 2^25 */ + /* |h1| <= 1.71*2^59 */ + /* |h5| <= 1.71*2^59 */ + + carry1 = (h1 + (Int64)(1 << 24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry5 = (h5 + (Int64)(1 << 24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + /* |h1| <= 2^24; from now on fits into int32 */ + /* |h5| <= 2^24; from now on fits into int32 */ + /* |h2| <= 1.41*2^60 */ + /* |h6| <= 1.41*2^60 */ + + carry2 = (h2 + (Int64)(1 << 25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry6 = (h6 + (Int64)(1 << 25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + /* |h2| <= 2^25; from now on fits into int32 unchanged */ + /* |h6| <= 2^25; from now on fits into int32 unchanged */ + /* |h3| <= 1.71*2^59 */ + /* |h7| <= 1.71*2^59 */ + + carry3 = (h3 + (Int64)(1 << 24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry7 = (h7 + (Int64)(1 << 24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + /* |h3| <= 2^24; from now on fits into int32 unchanged */ + /* |h7| <= 2^24; from now on fits into int32 unchanged */ + /* |h4| <= 1.72*2^34 */ + /* |h8| <= 1.41*2^60 */ + + carry4 = (h4 + (Int64)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry8 = (h8 + (Int64)(1 << 25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + /* |h4| <= 2^25; from now on fits into int32 unchanged */ + /* |h8| <= 2^25; from now on fits into int32 unchanged */ + /* |h5| <= 1.01*2^24 */ + /* |h9| <= 1.71*2^59 */ + + carry9 = (h9 + (Int64)(1 << 24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + /* |h9| <= 2^24; from now on fits into int32 unchanged */ + /* |h0| <= 1.1*2^39 */ + + carry0 = (h0 + (Int64)(1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + /* |h0| <= 2^25; from now on fits into int32 unchanged */ + /* |h1| <= 1.01*2^24 */ + + h.x0 = (Int32)h0; + h.x1 = (Int32)h1; + h.x2 = (Int32)h2; + h.x3 = (Int32)h3; + h.x4 = (Int32)h4; + h.x5 = (Int32)h5; + h.x6 = (Int32)h6; + h.x7 = (Int32)h7; + h.x8 = (Int32)h8; + h.x9 = (Int32)h9; + } + } +} \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_sq.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_sq.cs new file mode 100644 index 0000000..6557b73 --- /dev/null +++ b/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_sq.cs @@ -0,0 +1,153 @@ +using System; + +namespace Beacon.Sdk.Core.Infrastructure.Cryptography.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* + h = f * f + Can overlap h with f. + + Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + + Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. + */ + + /* + See fe_mul.c for discussion of implementation strategy. + */ + internal static void fe_sq(out FieldElement h, ref FieldElement f) + { + Int32 f0 = f.x0; + Int32 f1 = f.x1; + Int32 f2 = f.x2; + Int32 f3 = f.x3; + Int32 f4 = f.x4; + Int32 f5 = f.x5; + Int32 f6 = f.x6; + Int32 f7 = f.x7; + Int32 f8 = f.x8; + Int32 f9 = f.x9; + Int32 f0_2 = 2 * f0; + Int32 f1_2 = 2 * f1; + Int32 f2_2 = 2 * f2; + Int32 f3_2 = 2 * f3; + Int32 f4_2 = 2 * f4; + Int32 f5_2 = 2 * f5; + Int32 f6_2 = 2 * f6; + Int32 f7_2 = 2 * f7; + Int32 f5_38 = 38 * f5; /* 1.959375*2^30 */ + Int32 f6_19 = 19 * f6; /* 1.959375*2^30 */ + Int32 f7_38 = 38 * f7; /* 1.959375*2^30 */ + Int32 f8_19 = 19 * f8; /* 1.959375*2^30 */ + Int32 f9_38 = 38 * f9; /* 1.959375*2^30 */ + Int64 f0f0 = f0 * (Int64)f0; + Int64 f0f1_2 = f0_2 * (Int64)f1; + Int64 f0f2_2 = f0_2 * (Int64)f2; + Int64 f0f3_2 = f0_2 * (Int64)f3; + Int64 f0f4_2 = f0_2 * (Int64)f4; + Int64 f0f5_2 = f0_2 * (Int64)f5; + Int64 f0f6_2 = f0_2 * (Int64)f6; + Int64 f0f7_2 = f0_2 * (Int64)f7; + Int64 f0f8_2 = f0_2 * (Int64)f8; + Int64 f0f9_2 = f0_2 * (Int64)f9; + Int64 f1f1_2 = f1_2 * (Int64)f1; + Int64 f1f2_2 = f1_2 * (Int64)f2; + Int64 f1f3_4 = f1_2 * (Int64)f3_2; + Int64 f1f4_2 = f1_2 * (Int64)f4; + Int64 f1f5_4 = f1_2 * (Int64)f5_2; + Int64 f1f6_2 = f1_2 * (Int64)f6; + Int64 f1f7_4 = f1_2 * (Int64)f7_2; + Int64 f1f8_2 = f1_2 * (Int64)f8; + Int64 f1f9_76 = f1_2 * (Int64)f9_38; + Int64 f2f2 = f2 * (Int64)f2; + Int64 f2f3_2 = f2_2 * (Int64)f3; + Int64 f2f4_2 = f2_2 * (Int64)f4; + Int64 f2f5_2 = f2_2 * (Int64)f5; + Int64 f2f6_2 = f2_2 * (Int64)f6; + Int64 f2f7_2 = f2_2 * (Int64)f7; + Int64 f2f8_38 = f2_2 * (Int64)f8_19; + Int64 f2f9_38 = f2 * (Int64)f9_38; + Int64 f3f3_2 = f3_2 * (Int64)f3; + Int64 f3f4_2 = f3_2 * (Int64)f4; + Int64 f3f5_4 = f3_2 * (Int64)f5_2; + Int64 f3f6_2 = f3_2 * (Int64)f6; + Int64 f3f7_76 = f3_2 * (Int64)f7_38; + Int64 f3f8_38 = f3_2 * (Int64)f8_19; + Int64 f3f9_76 = f3_2 * (Int64)f9_38; + Int64 f4f4 = f4 * (Int64)f4; + Int64 f4f5_2 = f4_2 * (Int64)f5; + Int64 f4f6_38 = f4_2 * (Int64)f6_19; + Int64 f4f7_38 = f4 * (Int64)f7_38; + Int64 f4f8_38 = f4_2 * (Int64)f8_19; + Int64 f4f9_38 = f4 * (Int64)f9_38; + Int64 f5f5_38 = f5 * (Int64)f5_38; + Int64 f5f6_38 = f5_2 * (Int64)f6_19; + Int64 f5f7_76 = f5_2 * (Int64)f7_38; + Int64 f5f8_38 = f5_2 * (Int64)f8_19; + Int64 f5f9_76 = f5_2 * (Int64)f9_38; + Int64 f6f6_19 = f6 * (Int64)f6_19; + Int64 f6f7_38 = f6 * (Int64)f7_38; + Int64 f6f8_38 = f6_2 * (Int64)f8_19; + Int64 f6f9_38 = f6 * (Int64)f9_38; + Int64 f7f7_38 = f7 * (Int64)f7_38; + Int64 f7f8_38 = f7_2 * (Int64)f8_19; + Int64 f7f9_76 = f7_2 * (Int64)f9_38; + Int64 f8f8_19 = f8 * (Int64)f8_19; + Int64 f8f9_38 = f8 * (Int64)f9_38; + Int64 f9f9_38 = f9 * (Int64)f9_38; + Int64 h0 = f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38; + Int64 h1 = f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38; + Int64 h2 = f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19; + Int64 h3 = f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38; + Int64 h4 = f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38; + Int64 h5 = f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38; + Int64 h6 = f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19; + Int64 h7 = f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38; + Int64 h8 = f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38; + Int64 h9 = f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2; + Int64 carry0; + Int64 carry1; + Int64 carry2; + Int64 carry3; + Int64 carry4; + Int64 carry5; + Int64 carry6; + Int64 carry7; + Int64 carry8; + Int64 carry9; + + carry0 = (h0 + (Int64)(1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry4 = (h4 + (Int64)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + + carry1 = (h1 + (Int64)(1 << 24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry5 = (h5 + (Int64)(1 << 24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + + carry2 = (h2 + (Int64)(1 << 25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry6 = (h6 + (Int64)(1 << 25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + + carry3 = (h3 + (Int64)(1 << 24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry7 = (h7 + (Int64)(1 << 24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry4 = (h4 + (Int64)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry8 = (h8 + (Int64)(1 << 25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + carry9 = (h9 + (Int64)(1 << 24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + + carry0 = (h0 + (Int64)(1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + + h.x0 = (Int32)h0; + h.x1 = (Int32)h1; + h.x2 = (Int32)h2; + h.x3 = (Int32)h3; + h.x4 = (Int32)h4; + h.x5 = (Int32)h5; + h.x6 = (Int32)h6; + h.x7 = (Int32)h7; + h.x8 = (Int32)h8; + h.x9 = (Int32)h9; + } + } +} \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_sub.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_sub.cs new file mode 100644 index 0000000..9a5b374 --- /dev/null +++ b/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_sub.cs @@ -0,0 +1,63 @@ +using System; + +namespace Beacon.Sdk.Core.Infrastructure.Cryptography.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* + h = f - g + Can overlap h with f or g. + + Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + + Postconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + */ + + internal static void fe_sub(out FieldElement h, ref FieldElement f, ref FieldElement g) + { + Int32 f0 = f.x0; + Int32 f1 = f.x1; + Int32 f2 = f.x2; + Int32 f3 = f.x3; + Int32 f4 = f.x4; + Int32 f5 = f.x5; + Int32 f6 = f.x6; + Int32 f7 = f.x7; + Int32 f8 = f.x8; + Int32 f9 = f.x9; + Int32 g0 = g.x0; + Int32 g1 = g.x1; + Int32 g2 = g.x2; + Int32 g3 = g.x3; + Int32 g4 = g.x4; + Int32 g5 = g.x5; + Int32 g6 = g.x6; + Int32 g7 = g.x7; + Int32 g8 = g.x8; + Int32 g9 = g.x9; + Int32 h0 = f0 - g0; + Int32 h1 = f1 - g1; + Int32 h2 = f2 - g2; + Int32 h3 = f3 - g3; + Int32 h4 = f4 - g4; + Int32 h5 = f5 - g5; + Int32 h6 = f6 - g6; + Int32 h7 = f7 - g7; + Int32 h8 = f8 - g8; + Int32 h9 = f9 - g9; + h.x0 = h0; + h.x1 = h1; + h.x2 = h2; + h.x3 = h3; + h.x4 = h4; + h.x5 = h5; + h.x6 = h6; + h.x7 = h7; + h.x8 = h8; + h.x9 = h9; + } + } +} \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_tobytes.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_tobytes.cs new file mode 100644 index 0000000..40f7b53 --- /dev/null +++ b/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/Internal/Ed25519Ref10/fe_tobytes.cs @@ -0,0 +1,173 @@ +using System; + +namespace Beacon.Sdk.Core.Infrastructure.Cryptography.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* + Preconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + + Write p=2^255-19; q=floor(h/p). + Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). + + Proof: + Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. + Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4. + + Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). + Then 0> 0); + s[offset + 1] = (byte)(h0 >> 8); + s[offset + 2] = (byte)(h0 >> 16); + s[offset + 3] = (byte)((h0 >> 24) | (h1 << 2)); + s[offset + 4] = (byte)(h1 >> 6); + s[offset + 5] = (byte)(h1 >> 14); + s[offset + 6] = (byte)((h1 >> 22) | (h2 << 3)); + s[offset + 7] = (byte)(h2 >> 5); + s[offset + 8] = (byte)(h2 >> 13); + s[offset + 9] = (byte)((h2 >> 21) | (h3 << 5)); + s[offset + 10] = (byte)(h3 >> 3); + s[offset + 11] = (byte)(h3 >> 11); + s[offset + 12] = (byte)((h3 >> 19) | (h4 << 6)); + s[offset + 13] = (byte)(h4 >> 2); + s[offset + 14] = (byte)(h4 >> 10); + s[offset + 15] = (byte)(h4 >> 18); + s[offset + 16] = (byte)(h5 >> 0); + s[offset + 17] = (byte)(h5 >> 8); + s[offset + 18] = (byte)(h5 >> 16); + s[offset + 19] = (byte)((h5 >> 24) | (h6 << 1)); + s[offset + 20] = (byte)(h6 >> 7); + s[offset + 21] = (byte)(h6 >> 15); + s[offset + 22] = (byte)((h6 >> 23) | (h7 << 3)); + s[offset + 23] = (byte)(h7 >> 5); + s[offset + 24] = (byte)(h7 >> 13); + s[offset + 25] = (byte)((h7 >> 21) | (h8 << 4)); + s[offset + 26] = (byte)(h8 >> 4); + s[offset + 27] = (byte)(h8 >> 12); + s[offset + 28] = (byte)((h8 >> 20) | (h9 << 6)); + s[offset + 29] = (byte)(h9 >> 2); + s[offset + 30] = (byte)(h9 >> 10); + s[offset + 31] = (byte)(h9 >> 18); + } + } + + internal static void fe_reduce(out FieldElement hr, ref FieldElement h) + { + Int32 h0 = h.x0; + Int32 h1 = h.x1; + Int32 h2 = h.x2; + Int32 h3 = h.x3; + Int32 h4 = h.x4; + Int32 h5 = h.x5; + Int32 h6 = h.x6; + Int32 h7 = h.x7; + Int32 h8 = h.x8; + Int32 h9 = h.x9; + Int32 q; + Int32 carry0; + Int32 carry1; + Int32 carry2; + Int32 carry3; + Int32 carry4; + Int32 carry5; + Int32 carry6; + Int32 carry7; + Int32 carry8; + Int32 carry9; + + q = (19 * h9 + (((Int32)1) << 24)) >> 25; + q = (h0 + q) >> 26; + q = (h1 + q) >> 25; + q = (h2 + q) >> 26; + q = (h3 + q) >> 25; + q = (h4 + q) >> 26; + q = (h5 + q) >> 25; + q = (h6 + q) >> 26; + q = (h7 + q) >> 25; + q = (h8 + q) >> 26; + q = (h9 + q) >> 25; + + /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */ + h0 += 19 * q; + /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */ + + carry0 = h0 >> 26; + h1 += carry0; + h0 -= carry0 << 26; + carry1 = h1 >> 25; + h2 += carry1; + h1 -= carry1 << 25; + carry2 = h2 >> 26; + h3 += carry2; + h2 -= carry2 << 26; + carry3 = h3 >> 25; + h4 += carry3; + h3 -= carry3 << 25; + carry4 = h4 >> 26; + h5 += carry4; + h4 -= carry4 << 26; + carry5 = h5 >> 25; + h6 += carry5; + h5 -= carry5 << 25; + carry6 = h6 >> 26; + h7 += carry6; + h6 -= carry6 << 26; + carry7 = h7 >> 25; + h8 += carry7; + h7 -= carry7 << 25; + carry8 = h8 >> 26; + h9 += carry8; + h8 -= carry8 << 26; + carry9 = h9 >> 25; + h9 -= carry9 << 25; + /* h10 = carry9 */ + + hr.x0 = h0; + hr.x1 = h1; + hr.x2 = h2; + hr.x3 = h3; + hr.x4 = h4; + hr.x5 = h5; + hr.x6 = h6; + hr.x7 = h7; + hr.x8 = h8; + hr.x9 = h9; + } + } +} \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/MontgomeryCurve25519.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/MontgomeryCurve25519.cs new file mode 100644 index 0000000..51e453f --- /dev/null +++ b/Beacon.Sdk/Core/Infrastructure/Cryptography/NaCl/MontgomeryCurve25519.cs @@ -0,0 +1,31 @@ +using System; + + +namespace Beacon.Sdk.Core.Infrastructure.Cryptography.NaCl +{ + using Internal.Ed25519Ref10; + + public static class MontgomeryCurve25519 + { + public static void EdwardsToMontgomery(ArraySegment montgomery, ArraySegment edwards) + { + FieldElement edwardsY, edwardsZ, montgomeryX; + FieldOperations.fe_frombytes(out edwardsY, edwards.Array, edwards.Offset); + FieldOperations.fe_1(out edwardsZ); + EdwardsToMontgomeryX(out montgomeryX, ref edwardsY, ref edwardsZ); + FieldOperations.fe_tobytes(montgomery.Array, montgomery.Offset, ref montgomeryX); + montgomery.Array[montgomery.Offset + 31] |= (byte)(edwards.Array[edwards.Offset + 31] & 0x80); // copy sign + } + + private static void EdwardsToMontgomeryX(out FieldElement montgomeryX, ref FieldElement edwardsY, + ref FieldElement edwardsZ) + { + // montgomeryX = (edwardsZ + edwardsY) / (edwardsZ - edwardsY) + FieldElement tempX, tempZ; + FieldOperations.fe_add(out tempX, ref edwardsZ, ref edwardsY); + FieldOperations.fe_sub(out tempZ, ref edwardsZ, ref edwardsY); + FieldOperations.fe_invert(out tempZ, ref tempZ); + FieldOperations.fe_mul(out montgomeryX, ref tempX, ref tempZ); + } + } +} \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/PublicKeyAuth.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/PublicKeyAuth.cs new file mode 100644 index 0000000..99a3895 --- /dev/null +++ b/Beacon.Sdk/Core/Infrastructure/Cryptography/PublicKeyAuth.cs @@ -0,0 +1,76 @@ +using System; + +using Beacon.Sdk.Core.Infrastructure.Cryptography.BouncyCastle; +using Org.BouncyCastle.Math.EC.Rfc8032; + +namespace Beacon.Sdk.Core.Infrastructure.Cryptography +{ + /// Public-key signatures + public static class PublicKeyAuth + { + private const int SECRET_KEY_BYTES = 32 + 32; + private const int PUBLIC_KEY_BYTES = 32; + private const int BYTES = 64; + private const int SEED_BYTES = 32; + + public static int SecretKeyBytes { get; } = SECRET_KEY_BYTES; + public static int PublicKeyBytes { get; } = PUBLIC_KEY_BYTES; + public static int SignatureBytes { get; } = BYTES; + public static int SeedBytes { get; } = SEED_BYTES; + + /// Creates a new key pair based on the provided seed. + /// The seed. + /// A KeyPair. + /// + public static KeyPair GenerateKeyPair(byte[] seed) + { + if (seed == null || seed.Length != SEED_BYTES) + throw new ArgumentOutOfRangeException(nameof(seed), seed?.Length ?? 0, $"seed must be {SEED_BYTES} bytes in length."); + + var publicKey = new byte[PUBLIC_KEY_BYTES]; + var privateKey = new byte[SECRET_KEY_BYTES]; + + Ed25519.GeneratePublicKey(seed, 0, publicKey, 0); + + Buffer.BlockCopy(seed, 0, privateKey, 0, SEED_BYTES); + Buffer.BlockCopy(publicKey, 0, privateKey, SEED_BYTES, PUBLIC_KEY_BYTES); + + return new KeyPair(publicKey, privateKey); + } + + /// Signs a message with Ed25519. + /// The message. + /// The 64 byte private key. + /// The signature. + /// + public static byte[] SignDetached(byte[] message, byte[] key) + { + if (key == null || key.Length != SECRET_KEY_BYTES) + throw new ArgumentOutOfRangeException(nameof(key), key?.Length ?? 0, $"key must be {SECRET_KEY_BYTES} bytes in length."); + + var signature = new byte[BYTES]; + + Ed25519.Sign(key, 0, message, 0, message.Length, signature, 0); + + return signature; + } + + /// Converts the ed25519 public key to curve25519 public key. + /// Ed25519 public key. + /// The curve25519 public key. + /// + public static byte[] ConvertEd25519PublicKeyToCurve25519PublicKey(byte[] ed25519PublicKey) + { + return Ed25519Extensions.ConvertEd25519PublicKeyToCurve25519PublicKey(ed25519PublicKey); + } + + /// Converts the ed25519 secret key to curve25519 secret key. + /// Ed25519 secret key. + /// The curve25519 secret key. + /// + public static byte[] ConvertEd25519SecretKeyToCurve25519SecretKey(byte[] ed25519SecretKey) + { + return Ed25519Extensions.ConvertEd25519SecretKeyToCurve25519SecretKey(ed25519SecretKey); + } + } +} \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/SealedPublicKeyBox.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/SealedPublicKeyBox.cs similarity index 53% rename from Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/SealedPublicKeyBox.cs rename to Beacon.Sdk/Core/Infrastructure/Cryptography/SealedPublicKeyBox.cs index 758a27c..657c6c3 100644 --- a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/SealedPublicKeyBox.cs +++ b/Beacon.Sdk/Core/Infrastructure/Cryptography/SealedPublicKeyBox.cs @@ -1,16 +1,19 @@ using System; using System.Text; -using Beacon.Sdk.Core.Infrastructure.Cryptography.Libsodium; +using NaCl; +using Org.BouncyCastle.Crypto.Digests; namespace Beacon.Sdk.Core.Infrastructure.Cryptography { /// Create and Open SealedPublicKeyBoxes. public static class SealedPublicKeyBox { - public const int RecipientPublicKeyBytes = Sodium.crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES; - public const int RecipientSecretKeyBytes = Sodium.crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES; - private const int CryptoBoxSealbytes = Sodium.crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES + Sodium.crypto_box_curve25519xsalsa20poly1305_MACBYTES; + public const int RecipientPublicKeyBytes = 32; + public const int RecipientSecretKeyBytes = 32; + private const int PublicKeyBytes = 32; + private const int MacBytes = 16; + private const int NonceBytes = 24; /// Creates a SealedPublicKeyBox /// The message. @@ -34,17 +37,29 @@ public static byte[] Create(byte[] message, byte[] recipientPublicKey) if (recipientPublicKey == null || recipientPublicKey.Length != RecipientPublicKeyBytes) throw new ArgumentOutOfRangeException(nameof(recipientPublicKey), recipientPublicKey?.Length ?? 0, $"recipientPublicKey must be {RecipientPublicKeyBytes} bytes in length."); - var buffer = new byte[message.Length + CryptoBoxSealbytes]; + var buffer = new byte[message.Length + PublicKeyBytes + MacBytes]; - Sodium.Initialize(); - var ret = Sodium.CryptoBoxSeal( - buffer, - message, - (ulong)message.Length, - recipientPublicKey); + Curve25519XSalsa20Poly1305.KeyPair(out var esk, out var epk); - if (ret != 0) - throw new Exception("Failed to create SealedBox"); + var secretBoxSeal = new Curve25519XSalsa20Poly1305(esk, recipientPublicKey); + + var nonce = GetSealNonce(epk, recipientPublicKey); + + secretBoxSeal.Encrypt( + cipher: new Span(buffer)[PublicKeyBytes..], // skip first 32 bytes for public key + message: message, + nonce: nonce); + + Buffer.BlockCopy(epk, 0, buffer, 0, PublicKeyBytes); + + //var ret = Sodium.CryptoBoxSeal( + // buffer, + // message, + // (ulong)message.Length, + // recipientPublicKey); + + //if (ret != 0) + // throw new Exception("Failed to create SealedBox"); return buffer; } @@ -54,8 +69,7 @@ public static byte[] Create(byte[] message, byte[] recipientPublicKey) /// The recipient's secret key. /// The recipient's public key. /// The decrypted message. - /// - /// + /// public static byte[] Open(byte[] cipherText, byte[] recipientSecretKey, byte[] recipientPublicKey) { if (recipientSecretKey == null || recipientSecretKey.Length != RecipientSecretKeyBytes) @@ -63,23 +77,46 @@ public static byte[] Open(byte[] cipherText, byte[] recipientSecretKey, byte[] r if (recipientPublicKey == null || recipientPublicKey.Length != RecipientPublicKeyBytes) throw new ArgumentOutOfRangeException(nameof(recipientPublicKey), recipientPublicKey?.Length ?? 0, $"recipientPublicKey must be {RecipientPublicKeyBytes} bytes in length."); - if (cipherText.Length < CryptoBoxSealbytes) + if (cipherText.Length < PublicKeyBytes + MacBytes) throw new Exception("Failed to open SealedBox"); - var buffer = new byte[cipherText.Length - CryptoBoxSealbytes]; + var buffer = new byte[cipherText.Length - (PublicKeyBytes + MacBytes)]; + + var nonce = GetSealNonce(cipherText, recipientPublicKey); - Sodium.Initialize(); - var ret = Sodium.CryptoBoxSealOpen( - buffer, - cipherText, - (ulong)cipherText.Length, - recipientPublicKey, - recipientSecretKey); + var secretBoxSeal = new Curve25519XSalsa20Poly1305(recipientSecretKey, new ReadOnlySpan(cipherText)[..PublicKeyBytes]); - if (ret != 0) + if (!secretBoxSeal.TryDecrypt( + message: buffer, + cipher: new ReadOnlySpan(cipherText)[PublicKeyBytes..], + nonce: nonce)) + { throw new Exception("Failed to open SealedBox"); + } + + //var ret = Sodium.CryptoBoxSealOpen( + // buffer, + // cipherText, + // (ulong)cipherText.Length, + // recipientPublicKey, + // recipientSecretKey); + + //if (ret != 0) + // throw new Exception("Failed to open SealedBox"); return buffer; } + + private static byte[] GetSealNonce(byte[] pk1, byte[] pk2) + { + var nonce = new byte[NonceBytes]; + + var blake2bDigest = new Blake2bDigest(NonceBytes * 8); + blake2bDigest.BlockUpdate(pk1, 0, PublicKeyBytes); + blake2bDigest.BlockUpdate(pk2, 0, PublicKeyBytes); + blake2bDigest.DoFinal(nonce, 0); + + return nonce; + } } } \ No newline at end of file diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/SecretBox.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/SecretBox.cs similarity index 76% rename from Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/SecretBox.cs rename to Beacon.Sdk/Core/Infrastructure/Cryptography/SecretBox.cs index 4e8ad7a..6c246a2 100644 --- a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/SecretBox.cs +++ b/Beacon.Sdk/Core/Infrastructure/Cryptography/SecretBox.cs @@ -1,16 +1,16 @@ using System; using System.Text; -using Beacon.Sdk.Core.Infrastructure.Cryptography.Libsodium; +using NaCl; namespace Beacon.Sdk.Core.Infrastructure.Cryptography { /// Create and Open Secret Boxes. public static class SecretBox { - private const int KEY_BYTES = Sodium.crypto_secretbox_xsalsa20poly1305_KEYBYTES; - private const int NONCE_BYTES = Sodium.crypto_secretbox_xsalsa20poly1305_NONCEBYTES; - private const int MAC_BYTES = Sodium.crypto_secretbox_xsalsa20poly1305_MACBYTES; + private const int KEY_BYTES = 32; + private const int NONCE_BYTES = 24; + private const int MAC_BYTES = 16; /// Creates a Secret Box /// Hex-encoded string to be encrypted. @@ -30,9 +30,7 @@ public static byte[] Create(string message, byte[] nonce, byte[] key) /// The 24 byte nonce. /// The 32 byte key. /// The encrypted message. - /// - /// - /// + /// public static byte[] Create(byte[] message, byte[] nonce, byte[] key) { if (key == null || key.Length != KEY_BYTES) @@ -42,11 +40,20 @@ public static byte[] Create(byte[] message, byte[] nonce, byte[] key) var buffer = new byte[message.Length + MAC_BYTES]; - Sodium.Initialize(); - var ret = Sodium.CryptoSecretBoxEasy(buffer, message, (ulong)message.Length, nonce, key); + // todo: change to BouncyCastle? + var secretBox = new XSalsa20Poly1305(key); - if (ret != 0) - throw new Exception("Failed to create SecretBox"); + secretBox.Encrypt( + cipher: buffer, + message: message, + nonce: nonce); + + //var ret = Sodium.CryptoSecretBoxEasy( + // buffer, + // message, + // (ulong)message.Length, + // nonce, + // key); return buffer; } @@ -56,9 +63,7 @@ public static byte[] Create(byte[] message, byte[] nonce, byte[] key) /// The 24 byte nonce. /// The 32 byte nonce. /// The decrypted text. - /// - /// - /// + /// public static byte[] Open(byte[] cipherText, byte[] nonce, byte[] key) { if (key == null || key.Length != KEY_BYTES) @@ -96,11 +101,22 @@ public static byte[] Open(byte[] cipherText, byte[] nonce, byte[] key) var buffer = new byte[cipherText.Length - MAC_BYTES]; - Sodium.Initialize(); - var ret = Sodium.CryptoSecretBoxOpenEasy(buffer, cipherText, (ulong)cipherText.Length, nonce, key); + var secretBox = new XSalsa20Poly1305(key); - if (ret != 0) + if (!secretBox.TryDecrypt( + message: buffer, + cipher: cipherText, + nonce: nonce)) + { throw new Exception("Failed to open SecretBox"); + } + + //var ret = Sodium.CryptoSecretBoxOpenEasy( + // buffer, + // cipherText, + // (ulong)cipherText.Length, + // nonce, + // key); return buffer; } diff --git a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/SessionKeyPair.cs b/Beacon.Sdk/Core/Infrastructure/Cryptography/SessionKeyPair.cs similarity index 78% rename from Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/SessionKeyPair.cs rename to Beacon.Sdk/Core/Infrastructure/Cryptography/SessionKeyPair.cs index 6977b40..ef8cbdf 100644 --- a/Beacon.Sdk/Core/Infrastructure/Cryptography/Libsodium/SessionKeyPair.cs +++ b/Beacon.Sdk/Core/Infrastructure/Cryptography/SessionKeyPair.cs @@ -1,4 +1,4 @@ -namespace Beacon.Sdk.Core.Infrastructure.Cryptography.Libsodium +namespace Beacon.Sdk.Core.Infrastructure.Cryptography { public struct SessionKeyPair { diff --git a/Beacon.Sdk/Core/Infrastructure/Repositories/InMemorySessionKeyPairRepository.cs b/Beacon.Sdk/Core/Infrastructure/Repositories/InMemorySessionKeyPairRepository.cs index 57eb4fe..e6ff4df 100644 --- a/Beacon.Sdk/Core/Infrastructure/Repositories/InMemorySessionKeyPairRepository.cs +++ b/Beacon.Sdk/Core/Infrastructure/Repositories/InMemorySessionKeyPairRepository.cs @@ -3,7 +3,6 @@ namespace Beacon.Sdk.Core.Infrastructure.Repositories { using System.Collections.Concurrent; - using Cryptography.Libsodium; using Domain.Interfaces; using Domain.Interfaces.Data; using Utils; diff --git a/README.md b/README.md index 2a18c45..3f41433 100644 --- a/README.md +++ b/README.md @@ -18,53 +18,6 @@ Beacon .NET SDK is [available on NuGet](https://www.nuget.org/packages/Beacon.Sd dotnet add package Beacon.Sdk ``` -### Libsodium library runtime dependencies - -Beacon.Sdk uses the [libsodium](https://doc.libsodium.org/) cryptographic library. Some platforms may require additional runtime or static binaries: - -#### Windows/Linux/MacOS - -All runtime binaries already included. Nothing to do... - -#### Android - -`libsodium.so` library files for different architectures must be included in project resources: -``` -Project -└── Resources - └── lib - └── arm64-v8a - └── libsodium.so - └── armeabi-v7a - └── libsodium.so - └── x86_64 - └── libsodium.so -``` - -#### iOS static linking - -`libsodium.a` static library files must be compiled for all required architectures (arm64, armv7, i386 e.t.c). - -Binaries for all architectures must be concatenated to universal (fat) binary file: -``` -lipo -create -output libsodium.a libsodium-i386.a libsodium-arm64.a libsodium-armv7.a -``` - -The resulting `libsodium.a` file must be added to iOS project with the `Build Action` property set to `None`. - -The next step is to specify iOS extra build arguments: - -``` --gcc_flags "-L${ProjectDir} -lsodium -force_load ${ProjectDir}/libsodium.a" -``` - -And the last step is to specify how the library will be used by your application at startup: -```Csharp -using Beacon.Sdk.Core.Infrastructure.Cryptography.Libsodium; - -Sodium.SetLibraryType(SodiumLibraryType.StaticInternal); -``` - ## Usage For a complete example, refer