diff --git a/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/scalarmult/ScalarMultiplicationTest.kt b/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/scalarmult/ScalarMultiplicationTest.kt index 813fbd6..6b60495 100644 --- a/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/scalarmult/ScalarMultiplicationTest.kt +++ b/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/scalarmult/ScalarMultiplicationTest.kt @@ -1,5 +1,6 @@ package com.ionspin.kotlin.crypto.scalarmult +import com.ionspin.kotlin.crypto.LibsodiumInitializer import com.ionspin.kotlin.crypto.util.toHexString import kotlin.test.Test import kotlin.test.assertTrue @@ -29,22 +30,24 @@ class ScalarMultiplicationTest { @Test fun testScalarMultiplication() { - val alicePublicKey = ScalarMultiplication.scalarMultiplicationBase(aliceSecretKey) - assertTrue { - alicePublicKey.toHexString().equals(expectedAlicePublicKeyString) + LibsodiumInitializer.initializeWithCallback { + val alicePublicKey = ScalarMultiplication.scalarMultiplicationBase(aliceSecretKey) + assertTrue { + alicePublicKey.toHexString().equals(expectedAlicePublicKeyString) + } + val bobPublickKey = ScalarMultiplication.scalarMultiplicationBase(bobSecretKey) + assertTrue { + bobPublickKey.toHexString().equals(expectedBobPublickKeyString) + } + val aliceToBobSecret = ScalarMultiplication.scalarMultiplication(aliceSecretKey, bobPublickKey) + val bobToAliceSecret = ScalarMultiplication.scalarMultiplication(bobSecretKey, alicePublicKey) + assertTrue { + aliceToBobSecret.toHexString().equals(expectedSharedSecretString) + } + assertTrue { + bobToAliceSecret.toHexString().equals(expectedSharedSecretString) + } + println(aliceToBobSecret.toHexString()) } - val bobPublickKey = ScalarMultiplication.scalarMultiplicationBase(bobSecretKey) - assertTrue { - bobPublickKey.toHexString().equals(expectedBobPublickKeyString) - } - val aliceToBobSecret = ScalarMultiplication.scalarMultiplication(aliceSecretKey, bobPublickKey) - val bobToAliceSecret = ScalarMultiplication.scalarMultiplication(bobSecretKey, alicePublicKey) - assertTrue { - aliceToBobSecret.toHexString().equals(expectedSharedSecretString) - } - assertTrue { - bobToAliceSecret.toHexString().equals(expectedSharedSecretString) - } - println(aliceToBobSecret.toHexString()) } } diff --git a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt index 1bbdf21..a3aa2c5 100644 --- a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt +++ b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt @@ -232,8 +232,14 @@ interface JsSodiumInterface { fun crypto_stream_chacha20_xor(message : Uint8Array, nonce: Uint8Array, key: Uint8Array) : Uint8Array fun crypto_stream_chacha20_xor_ic(message : Uint8Array, nonce: Uint8Array, initialCounter: UInt, key: Uint8Array) : Uint8Array + // ---- Stream end ---- + // ---- Scalar multiplication ---- + fun crypto_scalarmult(privateKey: Uint8Array, publicKey: Uint8Array) : Uint8Array + fun crypto_scalarmult_base(privateKey: Uint8Array) : Uint8Array + + // ---- Scalar multiplication end ---- diff --git a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/scalarmult/ScalarMultiplication.kt b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/scalarmult/ScalarMultiplication.kt new file mode 100644 index 0000000..ce98b3b --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/scalarmult/ScalarMultiplication.kt @@ -0,0 +1,40 @@ +package com.ionspin.kotlin.crypto.scalarmult + +import com.ionspin.kotlin.crypto.getSodium +import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray +import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array + +actual object ScalarMultiplication { + /** + * This function can be used to compute a shared secret q given a user's secret key and another user's public key. + * n is crypto_scalarmult_SCALARBYTES bytes long, p and the output are crypto_scalarmult_BYTES bytes long. + * q represents the X coordinate of a point on the curve. As a result, the number of possible keys is limited to + * the group size (≈2^252), which is smaller than the key space. + * For this reason, and to mitigate subtle attacks due to the fact many (p, n) pairs produce the same result, + * using the output of the multiplication q directly as a shared key is not recommended. + * A better way to compute a shared key is h(q ‖ pk1 ‖ pk2), with pk1 and pk2 being the public keys. + * By doing so, each party can prove what exact public key they intended to perform a key exchange with + * (for a given public key, 11 other public keys producing the same shared secret can be trivially computed). + * This can be achieved with the following code snippet: + */ + actual fun scalarMultiplication(secretKeyN: UByteArray, publicKeyP: UByteArray): UByteArray { + val result = getSodium().crypto_scalarmult(secretKeyN.toUInt8Array(), publicKeyP.toUInt8Array()) + + return result.toUByteArray() + } + + /** + * Given a user's secret key n (crypto_scalarmult_SCALARBYTES bytes), the crypto_scalarmult_base() function + * computes the user's public key and puts it into q (crypto_scalarmult_BYTES bytes). + * crypto_scalarmult_BYTES and crypto_scalarmult_SCALARBYTES are provided for consistency, + * but it is safe to assume that crypto_scalarmult_BYTES == crypto_scalarmult_SCALARBYTES. + */ + actual fun scalarMultiplicationBase( + secretKeyN: UByteArray + ): UByteArray { + val result = getSodium().crypto_scalarmult_base( secretKeyN.toUInt8Array()) + + return result.toUByteArray() + } + +} diff --git a/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/scalarmult/ScalarMultiplication.kt b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/scalarmult/ScalarMultiplication.kt new file mode 100644 index 0000000..b936a28 --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/scalarmult/ScalarMultiplication.kt @@ -0,0 +1,43 @@ +package com.ionspin.kotlin.crypto.scalarmult + +import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium + +actual object ScalarMultiplication { + /** + * This function can be used to compute a shared secret q given a user's secret key and another user's public key. + * n is crypto_scalarmult_SCALARBYTES bytes long, p and the output are crypto_scalarmult_BYTES bytes long. + * q represents the X coordinate of a point on the curve. As a result, the number of possible keys is limited to + * the group size (≈2^252), which is smaller than the key space. + * For this reason, and to mitigate subtle attacks due to the fact many (p, n) pairs produce the same result, + * using the output of the multiplication q directly as a shared key is not recommended. + * A better way to compute a shared key is h(q ‖ pk1 ‖ pk2), with pk1 and pk2 being the public keys. + * By doing so, each party can prove what exact public key they intended to perform a key exchange with + * (for a given public key, 11 other public keys producing the same shared secret can be trivially computed). + * This can be achieved with the following code snippet: + */ + actual fun scalarMultiplication(secretKeyN: UByteArray, publicKeyP: UByteArray): UByteArray { + val result = UByteArray(crypto_scalarmult_BYTES) + + sodium.crypto_scalarmult(result.asByteArray(), secretKeyN.asByteArray(), publicKeyP.asByteArray()) + + + return result + } + + /** + * Given a user's secret key n (crypto_scalarmult_SCALARBYTES bytes), the crypto_scalarmult_base() function + * computes the user's public key and puts it into q (crypto_scalarmult_BYTES bytes). + * crypto_scalarmult_BYTES and crypto_scalarmult_SCALARBYTES are provided for consistency, + * but it is safe to assume that crypto_scalarmult_BYTES == crypto_scalarmult_SCALARBYTES. + */ + actual fun scalarMultiplicationBase( + secretKeyN: UByteArray + ): UByteArray { + val result = UByteArray(crypto_scalarmult_BYTES) + + sodium.crypto_scalarmult_base(result.asByteArray(), secretKeyN.asByteArray()) + + return result + } + +}