mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-09-30 18:12:32 +02:00
Caches shared key for performance.
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
package com.vitorpamplona.amethyst.benchmark
|
||||
|
||||
import androidx.benchmark.junit4.BenchmarkRule
|
||||
import androidx.benchmark.junit4.measureRepeated
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.vitorpamplona.quartz.crypto.CryptoUtils
|
||||
import com.vitorpamplona.quartz.crypto.KeyPair
|
||||
import com.vitorpamplona.quartz.encoders.Bech32
|
||||
import com.vitorpamplona.quartz.encoders.Hex
|
||||
import com.vitorpamplona.quartz.encoders.bechToBytes
|
||||
import com.vitorpamplona.quartz.encoders.toNpub
|
||||
import com.vitorpamplona.quartz.events.Event
|
||||
import junit.framework.TestCase.assertEquals
|
||||
import junit.framework.TestCase.assertNotNull
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class CryptoBenchmark {
|
||||
|
||||
@get:Rule
|
||||
val benchmarkRule = BenchmarkRule()
|
||||
|
||||
@Test
|
||||
fun getSharedKeyNip04() {
|
||||
val keyPair1 = KeyPair()
|
||||
val keyPair2 = KeyPair()
|
||||
|
||||
benchmarkRule.measureRepeated {
|
||||
assertNotNull(CryptoUtils.getSharedSecretNIP04(keyPair1.privKey!!, keyPair2.pubKey))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getSharedKeyNip44() {
|
||||
val keyPair1 = KeyPair()
|
||||
val keyPair2 = KeyPair()
|
||||
|
||||
benchmarkRule.measureRepeated {
|
||||
assertNotNull(CryptoUtils.getSharedSecretNIP24(keyPair1.privKey!!, keyPair2.pubKey))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun computeSharedKeyNip04() {
|
||||
val keyPair1 = KeyPair()
|
||||
val keyPair2 = KeyPair()
|
||||
|
||||
benchmarkRule.measureRepeated {
|
||||
assertNotNull(CryptoUtils.computeSharedSecretNIP04(keyPair1.privKey!!, keyPair2.pubKey))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun computeSharedKeyNip44() {
|
||||
val keyPair1 = KeyPair()
|
||||
val keyPair2 = KeyPair()
|
||||
|
||||
benchmarkRule.measureRepeated {
|
||||
assertNotNull(CryptoUtils.computeSharedSecretNIP24(keyPair1.privKey!!, keyPair2.pubKey))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun random() {
|
||||
benchmarkRule.measureRepeated {
|
||||
assertNotNull(CryptoUtils.random(1000))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun sha256() {
|
||||
val keyPair = KeyPair()
|
||||
|
||||
benchmarkRule.measureRepeated {
|
||||
assertNotNull(CryptoUtils.sha256(keyPair.pubKey))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun sign() {
|
||||
val keyPair = KeyPair()
|
||||
val msg = CryptoUtils.sha256(CryptoUtils.random(1000))
|
||||
|
||||
benchmarkRule.measureRepeated {
|
||||
assertNotNull(CryptoUtils.sign(msg, keyPair.privKey!!))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verify() {
|
||||
val keyPair = KeyPair()
|
||||
val msg = CryptoUtils.sha256(CryptoUtils.random(1000))
|
||||
val signature = CryptoUtils.sign(msg, keyPair.privKey!!)
|
||||
|
||||
benchmarkRule.measureRepeated {
|
||||
assertNotNull(CryptoUtils.verifySignature(signature, msg, keyPair.pubKey))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,10 +1,11 @@
|
||||
package com.vitorpamplona.quartz.crypto
|
||||
|
||||
import android.util.Log
|
||||
import android.util.LruCache
|
||||
import com.goterl.lazysodium.SodiumAndroid
|
||||
import com.goterl.lazysodium.utils.Key
|
||||
import com.vitorpamplona.quartz.events.Event
|
||||
import com.vitorpamplona.quartz.encoders.Hex
|
||||
import com.vitorpamplona.quartz.events.Event
|
||||
import fr.acinq.secp256k1.Secp256k1
|
||||
import java.security.MessageDigest
|
||||
import java.security.SecureRandom
|
||||
@@ -15,6 +16,9 @@ import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
|
||||
object CryptoUtils {
|
||||
private val sharedKeyCache04 = LruCache<Int, ByteArray>(200)
|
||||
private val sharedKeyCache24 = LruCache<Int, ByteArray>(200)
|
||||
|
||||
private val secp256k1 = Secp256k1.get()
|
||||
private val libSodium = SodiumAndroid()
|
||||
private val random = SecureRandom()
|
||||
@@ -27,8 +31,10 @@ object CryptoUtils {
|
||||
/**
|
||||
* Provides a 32B "private key" aka random number
|
||||
*/
|
||||
fun privkeyCreate(): ByteArray {
|
||||
val bytes = ByteArray(32)
|
||||
fun privkeyCreate() = random(32)
|
||||
|
||||
fun random(size: Int): ByteArray {
|
||||
val bytes = ByteArray(size)
|
||||
random.nextBytes(bytes)
|
||||
return bytes
|
||||
}
|
||||
@@ -52,12 +58,6 @@ object CryptoUtils {
|
||||
return MessageDigest.getInstance("SHA-256").digest(data)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 32B shared secret
|
||||
*/
|
||||
fun getSharedSecretNIP04(privateKey: ByteArray, pubKey: ByteArray): ByteArray =
|
||||
secp256k1.pubKeyTweakMul(h02 + pubKey, privateKey).copyOfRange(1, 33)
|
||||
|
||||
fun encryptNIP04(msg: String, privateKey: ByteArray, pubKey: ByteArray): String {
|
||||
val info = encryptNIP04(msg, getSharedSecretNIP04(privateKey, pubKey))
|
||||
val encryptionInfo = EncryptedInfoString(
|
||||
@@ -150,7 +150,39 @@ object CryptoUtils {
|
||||
/**
|
||||
* @return 32B shared secret
|
||||
*/
|
||||
fun getSharedSecretNIP24(privateKey: ByteArray, pubKey: ByteArray): ByteArray =
|
||||
fun getSharedSecretNIP04(privateKey: ByteArray, pubKey: ByteArray): ByteArray {
|
||||
val hash = combinedHashCode(privateKey, pubKey)
|
||||
val preComputed = sharedKeyCache04[hash]
|
||||
if (preComputed != null) return preComputed
|
||||
|
||||
val computed = computeSharedSecretNIP04(privateKey, pubKey)
|
||||
sharedKeyCache04.put(hash, computed)
|
||||
return computed
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 32B shared secret
|
||||
*/
|
||||
fun computeSharedSecretNIP04(privateKey: ByteArray, pubKey: ByteArray): ByteArray =
|
||||
secp256k1.pubKeyTweakMul(h02 + pubKey, privateKey).copyOfRange(1, 33)
|
||||
|
||||
/**
|
||||
* @return 32B shared secret
|
||||
*/
|
||||
fun getSharedSecretNIP24(privateKey: ByteArray, pubKey: ByteArray): ByteArray {
|
||||
val hash = combinedHashCode(privateKey, pubKey)
|
||||
val preComputed = sharedKeyCache24[hash]
|
||||
if (preComputed != null) return preComputed
|
||||
|
||||
val computed = computeSharedSecretNIP24(privateKey, pubKey)
|
||||
sharedKeyCache24.put(hash, computed)
|
||||
return computed
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 32B shared secret
|
||||
*/
|
||||
fun computeSharedSecretNIP24(privateKey: ByteArray, pubKey: ByteArray): ByteArray =
|
||||
sha256(secp256k1.pubKeyTweakMul(h02 + pubKey, privateKey).copyOfRange(1, 33))
|
||||
}
|
||||
|
||||
@@ -213,6 +245,13 @@ fun decodeJackson(json: String): EncryptedInfo {
|
||||
)
|
||||
}
|
||||
|
||||
fun combinedHashCode(a: ByteArray, b: ByteArray): Int {
|
||||
var result = 1
|
||||
for (element in a) result = 31 * result + element
|
||||
for (element in b) result = 31 * result + element
|
||||
return result
|
||||
}
|
||||
|
||||
/*
|
||||
OLD Versions used for the Benchmark
|
||||
|
||||
|
Reference in New Issue
Block a user