diff --git a/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/ed25519/Ed25519.kt b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/ed25519/Ed25519.kt new file mode 100644 index 0000000..d734b04 --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/ed25519/Ed25519.kt @@ -0,0 +1,196 @@ +package com.ionspin.kotlin.crypto.ed25519 + +import com.ionspin.kotlin.crypto.util.LibsodiumUtil + +/** + * Created by Johannes Leupold + * johannes.leupold@kobil.com + * on 12-Aug-2024 + */ + +const val crypto_core_ed25519_BYTES = 32 +const val crypto_core_ed25519_UNIFORMBYTES = 32 +const val crypto_core_ed25519_HASHBYTES = 64 +const val crypto_core_ed25519_SCALARBYTES = 32 +const val crypto_core_ed25519_NONREDUCEDSCALARBYTES = 64 + +const val crypto_scalarmult_ed25519_BYTES = 32U +const val crypto_scalarmult_ed25519_SCALARBYTES = 32U + +expect abstract class Ed25519LowLevel() { + fun isValidPoint(encoded: UByteArray): Boolean + fun addPoints(p: UByteArray, q: UByteArray): UByteArray + fun subtractPoints(p: UByteArray, q: UByteArray): UByteArray + fun encodedPointFromHash(hash: UByteArray): UByteArray + fun encodedPointFromUniform(uniform: UByteArray): UByteArray + fun randomEncodedPoint(): UByteArray + fun randomEncodedScalar(): UByteArray + fun invertScalar(scalar: UByteArray): UByteArray + fun negateScalar(scalar: UByteArray): UByteArray + fun complementScalar(scalar: UByteArray): UByteArray + fun addScalars(x: UByteArray, y: UByteArray): UByteArray + fun subtractScalars(x: UByteArray, y: UByteArray): UByteArray + fun multiplyScalars(x: UByteArray, y: UByteArray): UByteArray + fun reduceScalar(scalar: UByteArray): UByteArray + fun scalarMultiplication(n: UByteArray, p: UByteArray): UByteArray + fun scalarMultiplicationNoClamp(n: UByteArray, p: UByteArray): UByteArray + fun scalarMultiplicationBase(n: UByteArray): UByteArray + fun scalarMultiplicationBaseNoClamp(n: UByteArray): UByteArray +} + +object Ed25519 : Ed25519LowLevel() { + fun add(p: Point, q: Point): Point = + Point(addPoints(p.encoded, q.encoded)) + + fun subtract(p: Point, q: Point): Point = + Point(subtractPoints(p.encoded, q.encoded)) + + fun pointFromHash(hash: UByteArray): Point = Point(encodedPointFromHash(hash)) + + fun pointFromUniform(uniform: UByteArray): Point = Point(encodedPointFromUniform(uniform)) + + fun randomPoint(): Point = Point(randomEncodedPoint()) + + fun randomScalar(): Scalar = Scalar(randomEncodedScalar()) + + fun invert(scalar: Scalar): Scalar = + Scalar(invertScalar(scalar.encoded)) + + fun negate(scalar: Scalar): Scalar = + Scalar(negateScalar(scalar.encoded)) + + fun complement(scalar: Scalar): Scalar = + Scalar(complementScalar(scalar.encoded)) + + fun add(x: Scalar, y: Scalar): Scalar = + Scalar(addScalars(x.encoded, y.encoded)) + + fun subtract(x: Scalar, y: Scalar): Scalar = + Scalar(subtractScalars(x.encoded, y.encoded)) + + fun multiply(x: Scalar, y: Scalar): Scalar = + Scalar(multiplyScalars(x.encoded, y.encoded)) + + fun reduce(scalar: Scalar): Scalar = + Scalar(reduceScalar(scalar.encoded)) + + fun scalarMultiplication(p: Point, n: Scalar): Point = + Point(scalarMultiplication(n.encoded, p.encoded)) + + fun scalarMultiplicationNoClamp(p: Point, n: Scalar): Point = + Point(scalarMultiplicationNoClamp(n.encoded, p.encoded)) + + fun scalarMultiplicationBase(n: Scalar): Point = + Point(scalarMultiplicationBase(n.encoded)) + + fun scalarMultiplicationBaseNoClamp(n: Scalar): Point = + Point(scalarMultiplicationBaseNoClamp(n.encoded)) + + data class Point(val encoded: UByteArray) { + operator fun plus(q: Point): Point = add(this, q) + operator fun minus(q: Point): Point = subtract(this, q) + + operator fun times(n: Scalar): Point = scalarMultiplication(this, n) + fun times(n: Scalar, clamp: Boolean): Point = + if (clamp) scalarMultiplication(this, n) else scalarMultiplicationNoClamp(this, n) + + fun toHex(): String = LibsodiumUtil.toHex(encoded) + + override fun equals(other: Any?): Boolean = (other as? Point)?.encoded?.contentEquals(encoded) == true + override fun hashCode(): Int = encoded.contentHashCode() + + companion object { + val IDENTITY: Point = Point(UByteArray(crypto_core_ed25519_BYTES)) + val BASE: Point = scalarMultiplicationBase(Scalar.ONE) + + fun fromHash(hash: UByteArray): Point = pointFromHash(hash) + + fun fromUniform(uniform: UByteArray): Point = pointFromUniform(uniform) + + fun random(): Point = randomPoint() + + fun multiplyBase(n: Scalar): Point = scalarMultiplicationBase(n) + + fun multiplyBaseNoClamp(n: Scalar): Point = scalarMultiplicationBaseNoClamp(n) + + fun fromHex(hex: String): Point = Point(LibsodiumUtil.fromHex(hex)) + } + } + + data class Scalar(val encoded: UByteArray) { + operator fun plus(y: Scalar): Scalar = add(this, y) + operator fun plus(y: UInt): Scalar = this + fromUInt(y) + operator fun plus(y: ULong): Scalar = this + fromULong(y) + + operator fun minus(y: Scalar): Scalar = subtract(this, y) + operator fun minus(y: UInt): Scalar = this - fromUInt(y) + operator fun minus(y: ULong): Scalar = this - fromULong(y) + + operator fun times(y: Scalar): Scalar = multiply(this, y) + operator fun times(y: UInt): Scalar = this * fromUInt(y) + operator fun times(y: ULong): Scalar = this * fromULong(y) + + operator fun div(y: Scalar): Scalar = multiply(this, invert(y)) + operator fun div(y: UInt): Scalar = this / fromUInt(y) + operator fun div(y: ULong): Scalar = this / fromULong(y) + + operator fun unaryMinus(): Scalar = negate(this) + + operator fun times(p: Point): Point = scalarMultiplication(p, this) + fun times(p: Point, clamp: Boolean): Point = + if (clamp) scalarMultiplication(p, this) else scalarMultiplicationNoClamp(p, this) + + fun reduce(): Scalar = reduce(this) + fun invert(): Scalar = invert(this) + fun complement(): Scalar = complement(this) + + fun multiplyWithBase(): Point = scalarMultiplicationBase(this) + + fun multiplyWithBaseNoClamp(): Point = scalarMultiplicationBaseNoClamp(this) + + fun toHex(): String = LibsodiumUtil.toHex(encoded) + + override fun equals(other: Any?): Boolean = (other as? Scalar)?.encoded?.contentEquals(encoded) == true + override fun hashCode(): Int = encoded.contentHashCode() + + companion object { + val ZERO = fromUInt(0U) + val ONE = fromUInt(1U) + val TWO = fromUInt(2U) + + fun random(): Scalar = randomScalar() + + fun fromUInt(i: UInt): Scalar = fromULong(i.toULong()) + + fun fromULong(l: ULong): Scalar { + val encoded = UByteArray(crypto_core_ed25519_SCALARBYTES) + var rem = l + + for (i in 0..7) { + encoded[i] = (rem and 0xffU).toUByte() + rem = rem shr 8 + } + + return Scalar(encoded) + } + + fun fromHex(hex: String): Scalar { + require(hex.length <= 2 * crypto_core_ed25519_NONREDUCEDSCALARBYTES) { + "Scalars must be at most $crypto_core_ed25519_NONREDUCEDSCALARBYTES bytes long" + } + + if (hex.length > 2 * crypto_core_ed25519_SCALARBYTES) { + val encoded = LibsodiumUtil.fromHex(hex.padEnd(2 * crypto_core_ed25519_NONREDUCEDSCALARBYTES, '0')) + // Scalars are encoded in little-endian order, so the end can be padded with zeroes up to the size of a + // non-reduced scalar. After decoding, it is reduced, to obtain a scalar in the canonical range + return Scalar(reduceScalar(encoded)) + } else { + val encoded = LibsodiumUtil.fromHex(hex.padEnd(2 * crypto_core_ed25519_SCALARBYTES, '0')) + // Scalars are encoded in little-endian order, so the end can be padded with zeroes up to the size of a + // scalar. + return Scalar(encoded) + } + } + } + } +} \ No newline at end of file diff --git a/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/ristretto255/Ristretto255.kt b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/ristretto255/Ristretto255.kt index 5f73a9d..d34793a 100644 --- a/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/ristretto255/Ristretto255.kt +++ b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/ristretto255/Ristretto255.kt @@ -24,13 +24,13 @@ expect abstract class Ristretto255LowLevel() { fun encodedPointFromHash(hash: UByteArray): UByteArray fun randomEncodedPoint(): UByteArray fun randomEncodedScalar(): UByteArray - fun invert(scalar: UByteArray): UByteArray - fun negate(scalar: UByteArray): UByteArray - fun complement(scalar: UByteArray): UByteArray + fun invertScalar(scalar: UByteArray): UByteArray + fun negateScalar(scalar: UByteArray): UByteArray + fun complementScalar(scalar: UByteArray): UByteArray fun addScalars(x: UByteArray, y: UByteArray): UByteArray fun subtractScalars(x: UByteArray, y: UByteArray): UByteArray fun multiplyScalars(x: UByteArray, y: UByteArray): UByteArray - fun reduce(scalar: UByteArray): UByteArray + fun reduceScalar(scalar: UByteArray): UByteArray fun scalarMultiplication(n: UByteArray, p: UByteArray): UByteArray fun scalarMultiplicationBase(n: UByteArray): UByteArray } @@ -49,13 +49,13 @@ object Ristretto255 : Ristretto255LowLevel() { fun randomScalar(): Scalar = Scalar(randomEncodedScalar()) fun invert(scalar: Scalar): Scalar = - Scalar(invert(scalar.encoded)) + Scalar(invertScalar(scalar.encoded)) fun negate(scalar: Scalar): Scalar = - Scalar(negate(scalar.encoded)) + Scalar(negateScalar(scalar.encoded)) fun complement(scalar: Scalar): Scalar = - Scalar(complement(scalar.encoded)) + Scalar(complementScalar(scalar.encoded)) fun add(x: Scalar, y: Scalar): Scalar = Scalar(addScalars(x.encoded, y.encoded)) @@ -67,7 +67,7 @@ object Ristretto255 : Ristretto255LowLevel() { Scalar(multiplyScalars(x.encoded, y.encoded)) fun reduce(scalar: Scalar): Scalar = - Scalar(reduce(scalar.encoded)) + Scalar(reduceScalar(scalar.encoded)) fun scalarMultiplication(p: Point, n: Scalar): Point = Point(scalarMultiplication(n.encoded, p.encoded)) @@ -162,7 +162,7 @@ object Ristretto255 : Ristretto255LowLevel() { val encoded = LibsodiumUtil.fromHex(hex.padEnd(2 * crypto_core_ristretto255_NONREDUCEDSCALARBYTES, '0')) // Scalars are encoded in little-endian order, so the end can be padded with zeroes up to the size of a // non-reduced scalar. After decoding, it is reduced, to obtain a scalar in the canonical range - return Scalar(reduce(encoded)) + return Scalar(reduceScalar(encoded)) } else { val encoded = LibsodiumUtil.fromHex(hex.padEnd(2 * crypto_core_ristretto255_SCALARBYTES, '0')) // Scalars are encoded in little-endian order, so the end can be padded with zeroes up to the size of a 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 dc2a338..9efe8e2 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 @@ -413,4 +413,65 @@ external object JsSodiumInterface { // // ---- Ristretto255 end ---- + + + // + // ---- Ed25519 ---- + + @JsName("crypto_core_ed25519_is_valid_point") + fun crypto_core_ed25519_is_valid_point(p: Uint8Array): Boolean + + @JsName("crypto_core_ed25519_random") + fun crypto_core_ed25519_random(): Uint8Array + + @JsName("crypto_core_ed25519_from_hash") + fun crypto_core_ed25519_from_hash(r: Uint8Array): Uint8Array + + @JsName("crypto_core_ed25519_from_uniform") + fun crypto_core_ed25519_from_uniform(r: Uint8Array): Uint8Array + + @JsName("crypto_core_ed25519_add") + fun crypto_core_ed25519_add(p: Uint8Array, q: Uint8Array): Uint8Array + + @JsName("crypto_core_ed25519_sub") + fun crypto_core_ed25519_sub(p: Uint8Array, q: Uint8Array): Uint8Array + + @JsName("crypto_core_ed25519_scalar_random") + fun crypto_core_ed25519_scalar_random(): Uint8Array + + @JsName("crypto_core_ed25519_scalar_reduce") + fun crypto_core_ed25519_scalar_reduce(s: Uint8Array): Uint8Array + + @JsName("crypto_core_ed25519_scalar_invert") + fun crypto_core_ed25519_scalar_invert(s: Uint8Array): Uint8Array + + @JsName("crypto_core_ed25519_scalar_negate") + fun crypto_core_ed25519_scalar_negate(s: Uint8Array): Uint8Array + + @JsName("crypto_core_ed25519_scalar_complement") + fun crypto_core_ed25519_scalar_complement(s: Uint8Array): Uint8Array + + @JsName("crypto_core_ed25519_scalar_add") + fun crypto_core_ed25519_scalar_add(x: Uint8Array, y: Uint8Array): Uint8Array + + @JsName("crypto_core_ed25519_scalar_sub") + fun crypto_core_ed25519_scalar_sub(x: Uint8Array, y: Uint8Array): Uint8Array + + @JsName("crypto_core_ed25519_scalar_mul") + fun crypto_core_ed25519_scalar_mul(x: Uint8Array, y: Uint8Array): Uint8Array + + @JsName("crypto_scalarmult_ed25519") + fun crypto_scalarmult_ed25519(n: Uint8Array, p: Uint8Array): Uint8Array + + @JsName("crypto_scalarmult_ed25519_noclamp") + fun crypto_scalarmult_ed25519_noclamp(n: Uint8Array, p: Uint8Array): Uint8Array + + @JsName("crypto_scalarmult_ed25519_base") + fun crypto_scalarmult_ed25519_base(n: Uint8Array): Uint8Array + + @JsName("crypto_scalarmult_ed25519_base_noclamp") + fun crypto_scalarmult_ed25519_base_noclamp(n: Uint8Array): Uint8Array + + // + // ---- Ed25519 end ---- } diff --git a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/ed25519/Ed25519LowLevel.kt b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/ed25519/Ed25519LowLevel.kt new file mode 100644 index 0000000..a9d863d --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/ed25519/Ed25519LowLevel.kt @@ -0,0 +1,112 @@ +package com.ionspin.kotlin.crypto.ed25519 + +import com.ionspin.kotlin.crypto.getSodium +import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray +import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array + +actual abstract class Ed25519LowLevel actual constructor() { + actual fun isValidPoint(encoded: UByteArray): Boolean = + getSodium().crypto_core_ed25519_is_valid_point(encoded.toUint8Array()) + + actual fun addPoints(p: UByteArray, q: UByteArray): UByteArray { + val result = getSodium().crypto_core_ed25519_add(p.toUint8Array(), q.toUint8Array()) + + return result.toUByteArray() + } + + actual fun subtractPoints(p: UByteArray, q: UByteArray): UByteArray { + val result = getSodium().crypto_core_ed25519_sub(p.toUint8Array(), q.toUint8Array()) + + return result + } + + actual fun encodedPointFromHash(hash: UByteArray): UByteArray { + val result = getSodium().crypto_core_ed25519_from_hash(hash.toUint8Array()) + + return result.toUByteArray() + } + + actual fun encodedPointFromUniform(uniform: UByteArray): UByteArray { + val result = getSodium().crypto_core_ed25519_from_uniform(hash.toUint8Array()) + + return result.toUByteArray() + } + + actual fun randomEncodedPoint(): UByteArray { + val result = getSodium().crypto_core_ed25519_random() + + return result.toUByteArray() + } + + actual fun randomEncodedScalar(): UByteArray { + val result = getSodium().crypto_core_ed25519_scalar_random() + + return result.toUByteArray() + } + + actual fun invertScalar(scalar: UByteArray): UByteArray { + val result = getSodium().crypto_core_ed25519_scalar_invert(scalar.toUint8Array()) + + return result.toUByteArray() + } + + actual fun negateScalar(scalar: UByteArray): UByteArray { + val result = getSodium().crypto_core_ed25519_scalar_negate(scalar.toUint8Array()) + + return result.toUByteArray() + } + + actual fun complementScalar(scalar: UByteArray): UByteArray { + val result = getSodium().crypto_core_ed25519_scalar_complement(scalar.toUint8Array()) + + return result.toUByteArray() + } + + actual fun addScalars(x: UByteArray, y: UByteArray): UByteArray { + val result = getSodium().crypto_core_ed25519_scalar_add(x.toUint8Array(), y.toUint8Array()) + + return result.toUByteArray() + } + + actual fun subtractScalars(x: UByteArray, y: UByteArray): UByteArray { + val result = getSodium().crypto_core_ed25519_scalar_sub(x.toUint8Array(), y.toUint8Array()) + + return result.toUByteArray() + } + + actual fun multiplyScalars(x: UByteArray, y: UByteArray): UByteArray { + val result = getSodium().crypto_core_ed25519_scalar_mul(x.toUint8Array(), y.toUint8Array()) + + return result.toUByteArray() + } + + actual fun reduceScalar(scalar: UByteArray): UByteArray { + val result = getSodium().crypto_core_ed25519_scalar_reduce(scalar.toUint8Array()) + + return result.toUByteArray() + } + + actual fun scalarMultiplication(n: UByteArray, p: UByteArray): UByteArray { + val result = getSodium().crypto_scalarmult_ed25519(n.toUint8Array(), p.toUint8Array()) + + return result.toUByteArray() + } + + actual fun scalarMultiplicationNoClamp(n: UByteArray, p: UByteArray): UByteArray { + val result = getSodium().crypto_scalarmult_ed25519_noclamp(n.toUint8Array(), p.toUint8Array()) + + return result.toUByteArray() + } + + actual fun scalarMultiplicationBase(n: UByteArray): UByteArray { + val result = getSodium().crypto_scalarmult_ed25519_base(n.toUint8Array()) + + return result.toUByteArray() + } + + actual fun scalarMultiplicationBaseNoClamp(n: UByteArray): UByteArray { + val result = getSodium().crypto_scalarmult_ed25519_base_noclamp(n.toUint8Array()) + + return result.toUByteArray() + } +} \ No newline at end of file diff --git a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/ristretto255/Ristretto255LowLevel.kt b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/ristretto255/Ristretto255LowLevel.kt index b96c1ed..60a84d4 100644 --- a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/ristretto255/Ristretto255LowLevel.kt +++ b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/ristretto255/Ristretto255LowLevel.kt @@ -38,19 +38,19 @@ actual abstract class Ristretto255LowLevel actual constructor() { return result.toUByteArray() } - actual fun invert(scalar: UByteArray): UByteArray { + actual fun invertScalar(scalar: UByteArray): UByteArray { val result = getSodium().crypto_core_ristretto255_scalar_invert(scalar.toUint8Array()) return result.toUByteArray() } - actual fun negate(scalar: UByteArray): UByteArray { + actual fun negateScalar(scalar: UByteArray): UByteArray { val result = getSodium().crypto_core_ristretto255_scalar_negate(scalar.toUint8Array()) return result.toUByteArray() } - actual fun complement(scalar: UByteArray): UByteArray { + actual fun complementScalar(scalar: UByteArray): UByteArray { val result = getSodium().crypto_core_ristretto255_scalar_complement(scalar.toUint8Array()) return result.toUByteArray() @@ -74,7 +74,7 @@ actual abstract class Ristretto255LowLevel actual constructor() { return result.toUByteArray() } - actual fun reduce(scalar: UByteArray): UByteArray { + actual fun reduceScalar(scalar: UByteArray): UByteArray { val result = getSodium().crypto_core_ristretto255_scalar_reduce(scalar.toUint8Array()) return result.toUByteArray() diff --git a/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/JnaLibsodiumInterface.kt b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/JnaLibsodiumInterface.kt index cefdc88..0962c7f 100644 --- a/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/JnaLibsodiumInterface.kt +++ b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/JnaLibsodiumInterface.kt @@ -1329,4 +1329,46 @@ interface JnaLibsodiumInterface : Library { // // // ---- Ristretto255 end ---- + +// +// // ---- Ed25519 ---- + + fun crypto_core_ed25519_is_valid_point(p: ByteArray): Int + + fun crypto_core_ed25519_random(p: ByteArray) + + fun crypto_core_ed25519_from_hash(p: ByteArray, r: ByteArray): Int + + fun crypto_core_ed25519_from_uniform(p: ByteArray, r: ByteArray): Int + + fun crypto_core_ed25519_add(r: ByteArray, p: ByteArray, q: ByteArray): Int + + fun crypto_core_ed25519_sub(r: ByteArray, p: ByteArray, q: ByteArray): Int + + fun crypto_core_ed25519_scalar_random(r: ByteArray) + + fun crypto_core_ed25519_scalar_reduce(r: ByteArray, s: ByteArray) + + fun crypto_core_ed25519_scalar_invert(recip: ByteArray, s: ByteArray): Int + + fun crypto_core_ed25519_scalar_negate(neg: ByteArray, s: ByteArray) + + fun crypto_core_ed25519_scalar_complement(comp: ByteArray, s: ByteArray) + + fun crypto_core_ed25519_scalar_add(z: ByteArray, x: ByteArray, y: ByteArray) + + fun crypto_core_ed25519_scalar_sub(z: ByteArray, x: ByteArray, y: ByteArray) + + fun crypto_core_ed25519_scalar_mul(z: ByteArray, x: ByteArray, y: ByteArray) + + fun crypto_scalarmult_ed25519(q: ByteArray, n: ByteArray, p: ByteArray): Int + + fun crypto_scalarmult_ed25519_noclamp(q: ByteArray, n: ByteArray, p: ByteArray): Int + + fun crypto_scalarmult_ed25519_base(q: ByteArray, n: ByteArray): Int + + fun crypto_scalarmult_ed25519_base_noclamp(q: ByteArray, n: ByteArray): Int + +// +// // ---- Ed25519 end ---- } diff --git a/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/ed25519/Ed25519LowLevel.kt b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/ed25519/Ed25519LowLevel.kt new file mode 100644 index 0000000..6d69532 --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/ed25519/Ed25519LowLevel.kt @@ -0,0 +1,145 @@ +package com.ionspin.kotlin.crypto.ed25519 + +import com.ionspin.kotlin.crypto.GeneralLibsodiumException.Companion.ensureLibsodiumSuccess +import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodiumJna +import kotlin.UByteArray + +actual abstract class Ed25519LowLevel actual constructor() { + actual fun isValidPoint(encoded: UByteArray): Boolean = + sodiumJna.crypto_core_ed25519_is_valid_point(encoded.asByteArray()) == 1 + + actual fun addPoints(p: UByteArray, q: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_BYTES) + + sodiumJna.crypto_core_ed25519_add(result.asByteArray(), p.asByteArray(), q.asByteArray()) + .ensureLibsodiumSuccess() + + return result + } + + actual fun subtractPoints(p: UByteArray, q: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_BYTES) + + sodiumJna.crypto_core_ed25519_sub(result.asByteArray(), p.asByteArray(), q.asByteArray()) + .ensureLibsodiumSuccess() + + return result + } + + actual fun encodedPointFromHash(hash: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_BYTES) + + sodiumJna.crypto_core_ed25519_from_hash(result.asByteArray(), hash.asByteArray()) + + return result + } + + actual fun encodedPointFromUniform(uniform: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_BYTES) + + sodiumJna.crypto_core_ed25519_from_uniform(result.asByteArray(), uniform.asByteArray()) + .ensureLibsodiumSuccess() + + return result + } + + actual fun randomEncodedPoint(): UByteArray = UByteArray(crypto_core_ed25519_BYTES).also { + sodiumJna.crypto_core_ed25519_random(it.asByteArray()) + } + + actual fun randomEncodedScalar(): UByteArray = UByteArray(crypto_core_ed25519_SCALARBYTES).also { + sodiumJna.crypto_core_ed25519_scalar_random(it.asByteArray()) + } + + actual fun invertScalar(scalar: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_SCALARBYTES) + + sodiumJna.crypto_core_ed25519_scalar_invert(result.asByteArray(), scalar.asByteArray()).ensureLibsodiumSuccess() + + return result + } + + actual fun negateScalar(scalar: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_SCALARBYTES) + + sodiumJna.crypto_core_ed25519_scalar_negate(result.asByteArray(), scalar.asByteArray()) + + return result + } + + actual fun complementScalar(scalar: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_SCALARBYTES) + + sodiumJna.crypto_core_ed25519_scalar_complement(result.asByteArray(), scalar.asByteArray()) + + return result + } + + actual fun addScalars(x: UByteArray, y: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_SCALARBYTES) + + sodiumJna.crypto_core_ed25519_scalar_add(result.asByteArray(), x.asByteArray(), y.asByteArray()) + + return result + } + + actual fun subtractScalars(x: UByteArray, y: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_SCALARBYTES) + + sodiumJna.crypto_core_ed25519_scalar_sub(result.asByteArray(), x.asByteArray(), y.asByteArray()) + + return result + } + + actual fun multiplyScalars(x: UByteArray, y: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_SCALARBYTES) + + sodiumJna.crypto_core_ed25519_scalar_mul(result.asByteArray(), x.asByteArray(), y.asByteArray()) + + return result + } + + actual fun reduceScalar(scalar: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_SCALARBYTES) + + sodiumJna.crypto_core_ed25519_scalar_reduce(result.asByteArray(), scalar.asByteArray()) + + return result + } + + actual fun scalarMultiplication(n: UByteArray, p: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_BYTES) + + sodiumJna.crypto_scalarmult_ed25519(result.asByteArray(), n.asByteArray(), p.asByteArray()) + .ensureLibsodiumSuccess() + + return result + } + + actual fun scalarMultiplicationNoClamp(n: UByteArray, p: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_BYTES) + + sodiumJna.crypto_scalarmult_ed25519_noclamp(result.asByteArray(), n.asByteArray(), p.asByteArray()) + .ensureLibsodiumSuccess() + + return result + } + + actual fun scalarMultiplicationBase(n: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_BYTES) + + sodiumJna.crypto_scalarmult_ed25519_base(result.asByteArray(), n.asByteArray()) + .ensureLibsodiumSuccess() + + return result + } + + actual fun scalarMultiplicationBaseNoClamp(n: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_BYTES) + + sodiumJna.crypto_scalarmult_ed25519_base_noclamp(result.asByteArray(), n.asByteArray()) + .ensureLibsodiumSuccess() + + return result + } +} \ No newline at end of file diff --git a/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/ristretto255/Ristretto255LowLevel.kt b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/ristretto255/Ristretto255LowLevel.kt index 5d7c76c..931c756 100644 --- a/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/ristretto255/Ristretto255LowLevel.kt +++ b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/ristretto255/Ristretto255LowLevel.kt @@ -42,7 +42,7 @@ actual abstract class Ristretto255LowLevel actual constructor() { sodiumJna.crypto_core_ristretto255_scalar_random(it.asByteArray()) } - actual fun invert(scalar: UByteArray): UByteArray { + actual fun invertScalar(scalar: UByteArray): UByteArray { val result = UByteArray(crypto_core_ristretto255_SCALARBYTES) sodiumJna.crypto_core_ristretto255_scalar_invert(result.asByteArray(), scalar.asByteArray()).ensureLibsodiumSuccess() @@ -50,7 +50,7 @@ actual abstract class Ristretto255LowLevel actual constructor() { return result } - actual fun negate(scalar: UByteArray): UByteArray { + actual fun negateScalar(scalar: UByteArray): UByteArray { val result = UByteArray(crypto_core_ristretto255_SCALARBYTES) sodiumJna.crypto_core_ristretto255_scalar_negate(result.asByteArray(), scalar.asByteArray()) @@ -58,7 +58,7 @@ actual abstract class Ristretto255LowLevel actual constructor() { return result } - actual fun complement(scalar: UByteArray): UByteArray { + actual fun complementScalar(scalar: UByteArray): UByteArray { val result = UByteArray(crypto_core_ristretto255_SCALARBYTES) sodiumJna.crypto_core_ristretto255_scalar_complement(result.asByteArray(), scalar.asByteArray()) @@ -90,7 +90,7 @@ actual abstract class Ristretto255LowLevel actual constructor() { return result } - actual fun reduce(scalar: UByteArray): UByteArray { + actual fun reduceScalar(scalar: UByteArray): UByteArray { val result = UByteArray(crypto_core_ristretto255_SCALARBYTES) sodiumJna.crypto_core_ristretto255_scalar_reduce(result.asByteArray(), scalar.asByteArray()) @@ -102,6 +102,7 @@ actual abstract class Ristretto255LowLevel actual constructor() { val result = UByteArray(crypto_core_ristretto255_BYTES) sodiumJna.crypto_scalarmult_ristretto255(result.asByteArray(), n.asByteArray(), p.asByteArray()) + .ensureLibsodiumSuccess() return result } @@ -110,6 +111,7 @@ actual abstract class Ristretto255LowLevel actual constructor() { val result = UByteArray(crypto_core_ristretto255_BYTES) sodiumJna.crypto_scalarmult_ristretto255_base(result.asByteArray(), n.asByteArray()) + .ensureLibsodiumSuccess() return result } diff --git a/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/ed25519/Ed25519LowLevel.kt b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/ed25519/Ed25519LowLevel.kt new file mode 100644 index 0000000..2d40cb3 --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/ed25519/Ed25519LowLevel.kt @@ -0,0 +1,243 @@ +package com.ionspin.kotlin.crypto.ed25519 + +import com.ionspin.kotlin.crypto.GeneralLibsodiumException.Companion.ensureLibsodiumSuccess +import com.ionspin.kotlin.crypto.util.toPtr +import kotlinx.cinterop.usePinned +import libsodium.crypto_core_ed25519_add +import libsodium.crypto_core_ed25519_from_hash +import libsodium.crypto_core_ed25519_from_uniform +import libsodium.crypto_core_ed25519_is_valid_point +import libsodium.crypto_core_ed25519_random +import libsodium.crypto_core_ed25519_scalar_add +import libsodium.crypto_core_ed25519_scalar_complement +import libsodium.crypto_core_ed25519_scalar_invert +import libsodium.crypto_core_ed25519_scalar_mul +import libsodium.crypto_core_ed25519_scalar_negate +import libsodium.crypto_core_ed25519_scalar_random +import libsodium.crypto_core_ed25519_scalar_reduce +import libsodium.crypto_core_ed25519_scalar_sub +import libsodium.crypto_core_ed25519_sub +import libsodium.crypto_scalarmult_ed25519 +import libsodium.crypto_scalarmult_ed25519_base +import libsodium.crypto_scalarmult_ed25519_base_noclamp +import libsodium.crypto_scalarmult_ed25519_noclamp + + +actual abstract class Ed25519LowLevel actual constructor() { + actual fun isValidPoint(encoded: UByteArray): Boolean { + return encoded.usePinned { crypto_core_ed25519_is_valid_point(it.toPtr()) == 1 } + } + + actual fun addPoints(p: UByteArray, q: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_BYTES) + + result.usePinned { resultPinned -> + p.usePinned { pPinned -> + q.usePinned { qPinned -> + crypto_core_ed25519_add(resultPinned.toPtr(), pPinned.toPtr(), qPinned.toPtr()) + .ensureLibsodiumSuccess() + } + } + } + + return result + } + + actual fun subtractPoints(p: UByteArray, q: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_BYTES) + + result.usePinned { resultPinned -> + p.usePinned { pPinned -> + q.usePinned { qPinned -> + crypto_core_ed25519_sub(resultPinned.toPtr(), pPinned.toPtr(), qPinned.toPtr()) + .ensureLibsodiumSuccess() + } + } + } + + return result + } + + actual fun encodedPointFromHash(hash: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_BYTES) + + result.usePinned { resultPinned -> + hash.usePinned { hashPinned -> + crypto_core_ed25519_from_hash(resultPinned.toPtr(), hashPinned.toPtr()) + } + } + + return result + } + + actual fun encodedPointFromUniform(uniform: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_BYTES) + + result.usePinned { resultPinned -> + uniform.usePinned { uniformPinned -> + crypto_core_ed25519_from_uniform(resultPinned.toPtr(), uniformPinned.toPtr()) + .ensureLibsodiumSuccess() + } + } + + return result + } + + actual fun randomEncodedPoint(): UByteArray = UByteArray(crypto_core_ed25519_BYTES).apply { + usePinned { crypto_core_ed25519_random(it.toPtr()) } + } + + actual fun randomEncodedScalar(): UByteArray = UByteArray(crypto_core_ed25519_SCALARBYTES).apply { + usePinned { crypto_core_ed25519_scalar_random(it.toPtr()) } + } + + actual fun invertScalar(scalar: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_SCALARBYTES) + + result.usePinned { resultPinned -> + scalar.usePinned { scalarPinned -> + crypto_core_ed25519_scalar_invert(resultPinned.toPtr(), scalarPinned.toPtr()).ensureLibsodiumSuccess() + } + } + + + return result + } + + actual fun negateScalar(scalar: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_SCALARBYTES) + + result.usePinned { resultPinned -> + scalar.usePinned { scalarPinned -> + crypto_core_ed25519_scalar_negate(resultPinned.toPtr(), scalarPinned.toPtr()) + } + } + + + return result + } + + actual fun complementScalar(scalar: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_SCALARBYTES) + + result.usePinned { resultPinned -> + scalar.usePinned { scalarPinned -> + crypto_core_ed25519_scalar_complement(resultPinned.toPtr(), scalarPinned.toPtr()) + } + } + + return result + } + + actual fun addScalars(x: UByteArray, y: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_SCALARBYTES) + + result.usePinned { resultPinned -> + x.usePinned { xPinned -> + y.usePinned { yPinned -> + crypto_core_ed25519_scalar_add(resultPinned.toPtr(), xPinned.toPtr(), yPinned.toPtr()) + } + } + } + + return result + } + + actual fun subtractScalars(x: UByteArray, y: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_SCALARBYTES) + + result.usePinned { resultPinned -> + x.usePinned { xPinned -> + y.usePinned { yPinned -> + crypto_core_ed25519_scalar_sub(resultPinned.toPtr(), xPinned.toPtr(), yPinned.toPtr()) + } + } + } + + return result + } + + actual fun multiplyScalars(x: UByteArray, y: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_SCALARBYTES) + + result.usePinned { resultPinned -> + x.usePinned { xPinned -> + y.usePinned { yPinned -> + crypto_core_ed25519_scalar_mul(resultPinned.toPtr(), xPinned.toPtr(), yPinned.toPtr()) + } + } + } + + return result + } + + actual fun reduceScalar(scalar: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_SCALARBYTES) + + result.usePinned { resultPinned -> + scalar.usePinned { scalarPinned -> + crypto_core_ed25519_scalar_reduce(resultPinned.toPtr(), scalarPinned.toPtr()) + } + } + + return result + } + + actual fun scalarMultiplication(n: UByteArray, p: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_BYTES) + + result.usePinned { resultPinned -> + n.usePinned { nPinned -> + p.usePinned { pPinned -> + crypto_scalarmult_ed25519(resultPinned.toPtr(), nPinned.toPtr(), pPinned.toPtr()) + .ensureLibsodiumSuccess() + } + } + } + + + return result + } + + actual fun scalarMultiplicationNoClamp(n: UByteArray, p: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_BYTES) + + result.usePinned { resultPinned -> + n.usePinned { nPinned -> + p.usePinned { pPinned -> + crypto_scalarmult_ed25519_noclamp(resultPinned.toPtr(), nPinned.toPtr(), pPinned.toPtr()) + .ensureLibsodiumSuccess() + } + } + } + + + return result + } + + actual fun scalarMultiplicationBase(n: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_BYTES) + + result.usePinned { resultPinned -> + n.usePinned { nPinned -> + crypto_scalarmult_ed25519_base(resultPinned.toPtr(), nPinned.toPtr()) + .ensureLibsodiumSuccess() + } + } + + return result + } + + actual fun scalarMultiplicationBaseNoClamp(n: UByteArray): UByteArray { + val result = UByteArray(crypto_core_ed25519_BYTES) + + result.usePinned { resultPinned -> + n.usePinned { nPinned -> + crypto_scalarmult_ed25519_base_noclamp(resultPinned.toPtr(), nPinned.toPtr()) + .ensureLibsodiumSuccess() + } + } + + return result + } +} \ No newline at end of file diff --git a/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/ristretto255/Ristretto255LowLevel.kt b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/ristretto255/Ristretto255LowLevel.kt index f381710..5bb6bd1 100644 --- a/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/ristretto255/Ristretto255LowLevel.kt +++ b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/ristretto255/Ristretto255LowLevel.kt @@ -1,5 +1,6 @@ package com.ionspin.kotlin.crypto.ristretto255 +import com.ionspin.kotlin.crypto.GeneralLibsodiumException.Companion.ensureLibsodiumSuccess import com.ionspin.kotlin.crypto.util.toPtr import kotlinx.cinterop.usePinned import libsodium.crypto_core_ristretto255_add @@ -74,7 +75,7 @@ actual abstract class Ristretto255LowLevel actual constructor() { usePinned { crypto_core_ristretto255_scalar_random(it.toPtr()) } } - actual fun invert(scalar: UByteArray): UByteArray { + actual fun invertScalar(scalar: UByteArray): UByteArray { val result = UByteArray(crypto_core_ristretto255_SCALARBYTES) result.usePinned { resultPinned -> @@ -87,7 +88,7 @@ actual abstract class Ristretto255LowLevel actual constructor() { return result } - actual fun negate(scalar: UByteArray): UByteArray { + actual fun negateScalar(scalar: UByteArray): UByteArray { val result = UByteArray(crypto_core_ristretto255_SCALARBYTES) result.usePinned { resultPinned -> @@ -100,7 +101,7 @@ actual abstract class Ristretto255LowLevel actual constructor() { return result } - actual fun complement(scalar: UByteArray): UByteArray { + actual fun complementScalar(scalar: UByteArray): UByteArray { val result = UByteArray(crypto_core_ristretto255_SCALARBYTES) result.usePinned { resultPinned -> @@ -154,7 +155,7 @@ actual abstract class Ristretto255LowLevel actual constructor() { return result } - actual fun reduce(scalar: UByteArray): UByteArray { + actual fun reduceScalar(scalar: UByteArray): UByteArray { val result = UByteArray(crypto_core_ristretto255_SCALARBYTES) result.usePinned { resultPinned -> @@ -173,6 +174,7 @@ actual abstract class Ristretto255LowLevel actual constructor() { n.usePinned { nPinned -> p.usePinned { pPinned -> crypto_scalarmult_ristretto255(resultPinned.toPtr(), nPinned.toPtr(), pPinned.toPtr()) + .ensureLibsodiumSuccess() } } } @@ -187,6 +189,7 @@ actual abstract class Ristretto255LowLevel actual constructor() { result.usePinned { resultPinned -> n.usePinned { nPinned -> crypto_scalarmult_ristretto255_base(resultPinned.toPtr(), nPinned.toPtr()) + .ensureLibsodiumSuccess() } }