Skip to content

Commit

Permalink
feat(app): add ECC calculator
Browse files Browse the repository at this point in the history
  • Loading branch information
Leon406 committed Apr 24, 2022
1 parent 763366b commit 1c456b5
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 5 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
group = "me.leon.tools"
version = "1.12.4.beta03"
version = "1.12.4.beta04"

plugins {
application
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/kotlin/me/leon/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package me.leon

import java.io.File

const val VERSION = "1.12.4.beta03"
const val BUILD_DATE = "2022-04-20"
const val VERSION = "1.12.4.beta04"
const val BUILD_DATE = "2022-04-24"
const val REPO_URL = "https://github.com/Leon406/ToolsFx"
const val REPO_ISSUE = "https://github.com/Leon406/ToolsFx/issues/new"
const val PJ52_URL = "https://www.52pojie.cn/thread-1501153-1-1.html"
Expand Down
46 changes: 46 additions & 0 deletions app/src/main/kotlin/me/leon/ext/crypto/ECCurves.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package me.leon.ext.crypto

import java.math.BigInteger
import me.leon.ext.toHex
import org.bouncycastle.asn1.sec.SECNamedCurves
import org.bouncycastle.crypto.ec.CustomNamedCurves
import org.bouncycastle.math.ec.ECCurve

val allCurves =
(CustomNamedCurves.getNames().toList().map { it.toString() } +
SECNamedCurves.getNames().toList().map { it.toString() })
.distinct()
.sorted()

val String.curve: ECCurve
get() = (CustomNamedCurves.getByName(this) ?: SECNamedCurves.getByName(this)).curve

fun String.curveMultiply(x: BigInteger, y: BigInteger, k: BigInteger): Pair<String, String> {
with(curve.createPoint(x, y).multiply(k).getEncoded(false).toHex()) {
return Pair(substring(2, 66), substring(66))
}
}

fun String.curveAdd(
x: BigInteger,
y: BigInteger,
x2: BigInteger,
y2: BigInteger
): Pair<String, String> {
with(curve) {
val hex = createPoint(x, y).add(createPoint(x2, y2)).getEncoded(false).toHex()
return Pair(hex.substring(2, 66), hex.substring(66))
}
}

fun String.curveSubtract(
x: BigInteger,
y: BigInteger,
x2: BigInteger,
y2: BigInteger
): Pair<String, String> {
with(curve) {
val hex = createPoint(x, y).subtract(createPoint(x2, y2)).getEncoded(false).toHex()
return Pair(hex.substring(2, 66), hex.substring(66))
}
}
1 change: 1 addition & 0 deletions app/src/main/kotlin/me/leon/view/BigIntFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class BigIntFragment : Fragment("BigInt") {
enableWhen(!isProcessing)
action { calculate() }
}
button("ECC Calculator") { action { find<ECCurveCalculator>().openWindow() } }
}
outputLayout(this)
}
Expand Down
102 changes: 102 additions & 0 deletions app/src/main/kotlin/me/leon/view/ECCurveCalculator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package me.leon.view

import javafx.beans.property.SimpleBooleanProperty
import javafx.beans.property.SimpleStringProperty
import javafx.geometry.Pos
import javafx.scene.control.RadioButton
import javafx.scene.control.TextField
import me.leon.ext.DEFAULT_SPACING
import me.leon.ext.cast
import me.leon.ext.crypto.*
import tornadofx.*

class ECCurveCalculator : View("ECCurveCalculator") {
private val selectedCurve = SimpleStringProperty(allCurves.last())
private val isShowY2 = SimpleBooleanProperty(false)
private var tfX1: TextField by singleAssign()
private var tfY1: TextField by singleAssign()
private var tfX2: TextField by singleAssign()
private var tfY2: TextField by singleAssign()
private var tfX: TextField by singleAssign()
private var tfY: TextField by singleAssign()
private var fPoint2: Field by singleAssign()
private var isMultiply = false
private var eccMethod = "multiply"
private var radix = 16

override val root = form {
fieldset {
field("x1:") { tfX1 = textfield() }
field("y1:") { tfY1 = textfield() }
}
fieldset {
fPoint2 = field("k:") { tfX2 = textfield() }
field("y2:") {
tfY2 = textfield()
visibleWhen(isShowY2)
}
}

hbox {
alignment = Pos.CENTER
spacing = DEFAULT_SPACING
togglegroup {
radiobutton("add")
radiobutton("subtract")
radiobutton("multiply") { isSelected = true }
selectedToggleProperty().addListener { _, _, newValue ->
isMultiply =
newValue.cast<RadioButton>().text.also { eccMethod = it } == "multiply"
fPoint2.text = if (isMultiply) "k:" else "y2:"
isShowY2.value = !isMultiply
}
}
combobox(selectedCurve, allCurves)
button(messages["run"]) { action { calculate() } }
}
fieldset {
field("x:") { tfX = textfield() }
field("y:") { tfY = textfield() }
}
}

private fun calculate() {
runAsync {
run {
when (eccMethod) {
"add" ->
selectedCurve
.get()
.curveAdd(
tfX1.text.also { println(it) }.toBigInteger(radix),
tfY1.text.toBigInteger(radix),
tfX2.text.toBigInteger(radix),
tfY2.text.toBigInteger(radix)
)
"subtract" ->
selectedCurve
.get()
.curveSubtract(
tfX1.text.toBigInteger(radix),
tfY1.text.toBigInteger(radix),
tfX2.text.toBigInteger(radix),
tfY2.text.toBigInteger(radix)
)
"multiply" ->
selectedCurve
.get()
.curveMultiply(
tfX1.text.toBigInteger(radix),
tfY1.text.toBigInteger(radix),
tfX2.text.toBigInteger(radix)
)
else -> throw IllegalArgumentException("Unknown method: $eccMethod")
}
}
} ui
{
tfX.text = it.first.uppercase()
tfY.text = it.second.uppercase()
}
}
}
24 changes: 22 additions & 2 deletions app/src/test/kotlin/me/leon/asymmetric/Sm2Test.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import cn.hutool.core.util.StrUtil
import cn.hutool.crypto.SecureUtil
import cn.hutool.crypto.SmUtil
import cn.hutool.crypto.asymmetric.KeyType
import java.security.*
import me.leon.encode.base.base64
import org.bouncycastle.crypto.params.*
import me.leon.ext.crypto.allCurves
import me.leon.ext.crypto.curveMultiply
import org.junit.Test
import kotlin.test.assertEquals

class Sm2Test {

// for check result
@Test
fun hutool() {
val text = "我是一段测试aaaa"
Expand All @@ -28,4 +30,22 @@ class Sm2Test {
val decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey))
println(decryptStr)
}

@Test
fun dotTimes() {
val dot1X =
"09F9DF311E5421A150DD7D161E4BC5C672179FAD1833FC076BB08FF356F35020".toBigInteger(16)
val dot1Y =
"CCEA490CE26775A52DC6EA718CC1AA600AED05FBF35E084A6632F6072DA9AD13".toBigInteger(16)
val k = "59276E27D506861A16680F3AD9C02DCCEF3CC1FA3CDBE4CE6D54B80DEAC1BC21".toBigInteger(16)

val expectedX = "335e18d751e51f040e27d468138b7ab1dc86ad7f981d7d416222fd6ab3ed230d"
val expectedY = "ab743ebcfb22d64f7b6ab791f70658f25b48fa93e54064fdbfbed3f0bd847ac9"
println(allCurves.joinToString("\n"))
"sm2p256v1".curveMultiply(dot1X, dot1Y, k).also {
println(it)
assertEquals(expectedX, it.first)
assertEquals(expectedY, it.second)
}
}
}

0 comments on commit 1c456b5

Please sign in to comment.