Compare commits
9 Commits
31d5d63897
...
main
Author | SHA1 | Date | |
---|---|---|---|
ba45c2cd1d | |||
dd1cc20be6 | |||
5ffc3f4c1e | |||
ec5bab3697 | |||
880c34ce03 | |||
0b9ae82c17 | |||
a8e3dd7f1e | |||
9c1b3996f3 | |||
41038ebdf4 |
116
Cargo.lock
generated
116
Cargo.lock
generated
@@ -1,12 +1,12 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.3.0"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@@ -15,14 +15,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "ecc_rs"
|
||||
version = "0.1.1"
|
||||
name = "crypto-bigint"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96272c2ff28b807e09250b180ad1fb7889a3258f7455759b5c3c58b719467130"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"rand_core",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ecc_rs"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"crypto-bigint",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"pyo3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
@@ -31,15 +54,15 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "indoc"
|
||||
version = "2.0.5"
|
||||
version = "2.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
|
||||
checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.158"
|
||||
version = "0.2.171"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
@@ -80,30 +103,30 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.7.0"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265"
|
||||
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyo3"
|
||||
version = "0.22.2"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "831e8e819a138c36e212f3af3fd9eeffed6bf1510a805af35b0edee5ffa59433"
|
||||
checksum = "17da310086b068fbdcefbba30aeb3721d5bb9af8db4987d6735b2183ca567229"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"indoc",
|
||||
@@ -120,9 +143,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-build-config"
|
||||
version = "0.22.2"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e8730e591b14492a8945cdff32f089250b05f5accecf74aeddf9e8272ce1fa8"
|
||||
checksum = "e27165889bd793000a098bb966adc4300c312497ea25cf7a690a9f0ac5aa5fc1"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"target-lexicon",
|
||||
@@ -130,9 +153,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-ffi"
|
||||
version = "0.22.2"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e97e919d2df92eb88ca80a037969f44e5e70356559654962cbb3316d00300c6"
|
||||
checksum = "05280526e1dbf6b420062f3ef228b78c0c54ba94e157f5cb724a609d0f2faabc"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pyo3-build-config",
|
||||
@@ -140,9 +163,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-macros"
|
||||
version = "0.22.2"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb57983022ad41f9e683a599f2fd13c3664d7063a3ac5714cae4b7bee7d3f206"
|
||||
checksum = "5c3ce5686aa4d3f63359a5100c62a127c9f15e8398e5fdeb5deef1fed5cd5f44"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"pyo3-macros-backend",
|
||||
@@ -152,9 +175,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-macros-backend"
|
||||
version = "0.22.2"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec480c0c51ddec81019531705acac51bcdbeae563557c982aa8263bb96880372"
|
||||
checksum = "f4cf6faa0cbfb0ed08e89beb8103ae9724eb4750e3a78084ba4017cbe94f3855"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
@@ -165,18 +188,33 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.37"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.77"
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -185,18 +223,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.12.16"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
||||
checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
||||
[[package]]
|
||||
name = "unindent"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"
|
||||
checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
15
Cargo.toml
15
Cargo.toml
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "ecc_rs"
|
||||
version = "0.1.1"
|
||||
edition = "2021"
|
||||
version = "0.1.2"
|
||||
edition = "2024"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[lib]
|
||||
@@ -9,6 +9,11 @@ name = "ecc_rs"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
num-bigint = "0.4.6"
|
||||
num-traits = "0.2.19"
|
||||
pyo3 = { version = "0.22.2", features = ["extension-module", "num-bigint"] }
|
||||
crypto-bigint = "0.6.1"
|
||||
num-bigint = "0.*"
|
||||
num-traits = "0.*"
|
||||
pyo3 = { version = "0.*", features = [
|
||||
"extension-module",
|
||||
"num-bigint",
|
||||
"abi3-py312",
|
||||
] }
|
||||
|
103
benchmark.py
Normal file
103
benchmark.py
Normal file
@@ -0,0 +1,103 @@
|
||||
import ecc_rs
|
||||
import time
|
||||
import ecc_py
|
||||
import random
|
||||
|
||||
point = tuple[int, int]
|
||||
# Example point coordinates for P1 and P2 as tuples (x1, y1) and (x2, y2)
|
||||
p1 = (
|
||||
1234567890123456789012345678901234567890123456789012345678901234,
|
||||
9876543210987654321098765432109876543210987654321098765432109876,
|
||||
)
|
||||
p2 = (
|
||||
2234567890123456789012345678901234567890123456789012345678901234,
|
||||
2876543210987654321098765432109876543210987654321098765432109876,
|
||||
)
|
||||
|
||||
# Add the two points
|
||||
result_x, result_y = ecc_rs.add(p1, p2)
|
||||
print(f"Resulting Point: x = {result_x}, y = {result_y}")
|
||||
|
||||
|
||||
result = ecc_rs.multiply(p1, 2)
|
||||
print(f"Resulting Point: x = {result[0]}, y = {result[1]}")
|
||||
|
||||
|
||||
# 生成密钥对模块
|
||||
class CurveFp:
|
||||
def __init__(self, A, B, P, N, Gx, Gy, name):
|
||||
self.A = A
|
||||
self.B = B
|
||||
self.P = P
|
||||
self.N = N
|
||||
self.Gx = Gx
|
||||
self.Gy = Gy
|
||||
self.name = name
|
||||
|
||||
|
||||
sm2p256v1 = CurveFp(
|
||||
name="sm2p256v1",
|
||||
A=0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC,
|
||||
B=0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93,
|
||||
P=0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF,
|
||||
N=0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123,
|
||||
Gx=0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7,
|
||||
Gy=0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0,
|
||||
)
|
||||
|
||||
# 生成元
|
||||
g = (sm2p256v1.Gx, sm2p256v1.Gy)
|
||||
|
||||
|
||||
def multiply(a: point, n: int) -> point:
|
||||
|
||||
result = ecc_rs.multiply(a, n)
|
||||
return result
|
||||
|
||||
|
||||
def add(a: point, b: point) -> point:
|
||||
result = ecc_rs.add(a, b)
|
||||
return result
|
||||
|
||||
|
||||
random_mul_times = random.randint(0, sm2p256v1.N)
|
||||
|
||||
start_time = time.time() # 获取开始时间
|
||||
for i in range(10):
|
||||
result = multiply(g, random_mul_times) # 执行函数
|
||||
end_time = time.time() # 获取结束时间
|
||||
rs_mul_elapsed_time = end_time - start_time # 计算执行时间
|
||||
print(f"rust multiply 执行时间: {rs_mul_elapsed_time:.6f} 秒")
|
||||
# rust multiply 执行时间: 0.000849 秒
|
||||
|
||||
start_time = time.time() # 获取开始时间
|
||||
for i in range(10):
|
||||
result = ecc_py.multiply(g, random_mul_times) # 执行函数
|
||||
end_time = time.time() # 获取结束时间
|
||||
py_mul_elapsed_time = end_time - start_time # 计算执行时间
|
||||
print(f"ecc_py multiply 执行时间: {py_mul_elapsed_time:.6f} 秒")
|
||||
# ecc_py multiply 执行时间: 0.001374 秒
|
||||
|
||||
mul_improve = (py_mul_elapsed_time - rs_mul_elapsed_time) / py_mul_elapsed_time * 100
|
||||
|
||||
print(f"rust 实现 mul 提速 {mul_improve:.3f}%")
|
||||
|
||||
start_time = time.time() # 获取开始时间
|
||||
for i in range(10):
|
||||
result = add(g, g) # 执行函数
|
||||
end_time = time.time() # 获取结束时间
|
||||
rs_add_elapsed_time = end_time - start_time # 计算执行时间
|
||||
print(f"rust add 执行时间: {rs_add_elapsed_time:.6f} 秒")
|
||||
# rust add 执行时间: 0.000378 秒
|
||||
|
||||
start_time = time.time() # 获取开始时间
|
||||
for i in range(10):
|
||||
result = ecc_py.add(g, g) # 执行函数
|
||||
end_time = time.time() # 获取结束时间
|
||||
py_add_elapsed_time = end_time - start_time # 计算执行时间
|
||||
print(f"ecc_py add 执行时间: {py_add_elapsed_time:.6f} 秒")
|
||||
# ecc_py add 执行时间: 0.000510 秒
|
||||
|
||||
add_improve = (py_add_elapsed_time - rs_add_elapsed_time) / py_add_elapsed_time * 100
|
||||
|
||||
print(f"rust 实现 add 提速 {add_improve:.3f}%")
|
132
ecc_py.py
Normal file
132
ecc_py.py
Normal file
@@ -0,0 +1,132 @@
|
||||
from typing import Tuple
|
||||
|
||||
point = Tuple[int, int]
|
||||
|
||||
|
||||
# 生成密钥对模块
|
||||
class CurveFp:
|
||||
def __init__(self, A, B, P, N, Gx, Gy, name):
|
||||
self.A = A
|
||||
self.B = B
|
||||
self.P = P
|
||||
self.N = N
|
||||
self.Gx = Gx
|
||||
self.Gy = Gy
|
||||
self.name = name
|
||||
|
||||
|
||||
sm2p256v1 = CurveFp(
|
||||
name="sm2p256v1",
|
||||
A=0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC,
|
||||
B=0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93,
|
||||
P=0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF,
|
||||
N=0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123,
|
||||
Gx=0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7,
|
||||
Gy=0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0,
|
||||
)
|
||||
|
||||
|
||||
def multiply(a: point, n: int) -> point:
|
||||
|
||||
N = sm2p256v1.N
|
||||
A = sm2p256v1.A
|
||||
P = sm2p256v1.P
|
||||
return fromJacobian(jacobianMultiply(toJacobian(a), n, N, A, P), P)
|
||||
|
||||
|
||||
def add(
|
||||
a: point,
|
||||
b: point,
|
||||
) -> point:
|
||||
A = sm2p256v1.A
|
||||
P = sm2p256v1.P
|
||||
return fromJacobian(jacobianAdd(toJacobian(a), toJacobian(b), A, P), P)
|
||||
|
||||
|
||||
def inv(a: int, n: int) -> int:
|
||||
if a == 0:
|
||||
return 0
|
||||
lm, hm = 1, 0
|
||||
low, high = a % n, n
|
||||
while low > 1:
|
||||
r = high // low
|
||||
nm, new = hm - lm * r, high - low * r
|
||||
lm, low, hm, high = nm, new, lm, low
|
||||
return lm % n
|
||||
|
||||
|
||||
def toJacobian(Xp_Yp: point) -> Tuple[int, int, int]:
|
||||
Xp, Yp = Xp_Yp
|
||||
return (Xp, Yp, 1)
|
||||
|
||||
|
||||
def fromJacobian(Xp_Yp_Zp: Tuple[int, int, int], P: int) -> point:
|
||||
Xp, Yp, Zp = Xp_Yp_Zp
|
||||
z = inv(Zp, P)
|
||||
return ((Xp * z**2) % P, (Yp * z**3) % P)
|
||||
|
||||
|
||||
def jacobianDouble(
|
||||
Xp_Yp_Zp: Tuple[int, int, int], A: int, P: int
|
||||
) -> Tuple[int, int, int]:
|
||||
Xp, Yp, Zp = Xp_Yp_Zp
|
||||
if not Yp:
|
||||
return (0, 0, 0)
|
||||
ysq = (Yp**2) % P
|
||||
S = (4 * Xp * ysq) % P
|
||||
M = (3 * Xp**2 + A * Zp**4) % P
|
||||
nx = (M**2 - 2 * S) % P
|
||||
ny = (M * (S - nx) - 8 * ysq**2) % P
|
||||
nz = (2 * Yp * Zp) % P
|
||||
return (nx, ny, nz)
|
||||
|
||||
|
||||
def jacobianAdd(
|
||||
Xp_Yp_Zp: Tuple[int, int, int], Xq_Yq_Zq: Tuple[int, int, int], A: int, P: int
|
||||
) -> Tuple[int, int, int]:
|
||||
Xp, Yp, Zp = Xp_Yp_Zp
|
||||
Xq, Yq, Zq = Xq_Yq_Zq
|
||||
if not Yp:
|
||||
return (Xq, Yq, Zq)
|
||||
if not Yq:
|
||||
return (Xp, Yp, Zp)
|
||||
U1 = (Xp * Zq**2) % P
|
||||
U2 = (Xq * Zp**2) % P
|
||||
S1 = (Yp * Zq**3) % P
|
||||
S2 = (Yq * Zp**3) % P
|
||||
if U1 == U2:
|
||||
if S1 != S2:
|
||||
return (0, 0, 1)
|
||||
return jacobianDouble((Xp, Yp, Zp), A, P)
|
||||
H = U2 - U1
|
||||
R = S2 - S1
|
||||
H2 = (H * H) % P
|
||||
H3 = (H * H2) % P
|
||||
U1H2 = (U1 * H2) % P
|
||||
nx = (R**2 - H3 - 2 * U1H2) % P
|
||||
ny = (R * (U1H2 - nx) - S1 * H3) % P
|
||||
nz = (H * Zp * Zq) % P
|
||||
return (nx, ny, nz)
|
||||
|
||||
|
||||
def jacobianMultiply(
|
||||
Xp_Yp_Zp: Tuple[int, int, int], n: int, N: int, A: int, P: int
|
||||
) -> Tuple[int, int, int]:
|
||||
Xp, Yp, Zp = Xp_Yp_Zp
|
||||
if Yp == 0 or n == 0:
|
||||
return (0, 0, 1)
|
||||
if n == 1:
|
||||
return (Xp, Yp, Zp)
|
||||
if n < 0 or n >= N:
|
||||
return jacobianMultiply((Xp, Yp, Zp), n % N, N, A, P)
|
||||
if (n % 2) == 0:
|
||||
return jacobianDouble(jacobianMultiply((Xp, Yp, Zp), n // 2, N, A, P), A, P)
|
||||
if (n % 2) == 1:
|
||||
return jacobianAdd(
|
||||
jacobianDouble(jacobianMultiply((Xp, Yp, Zp), n // 2, N, A, P), A, P),
|
||||
(Xp, Yp, Zp),
|
||||
A,
|
||||
P,
|
||||
)
|
||||
|
||||
raise ValueError("jacobian Multiply error")
|
51
ecc_rs.pyi
51
ecc_rs.pyi
@@ -1,4 +1,51 @@
|
||||
# ecc_rs.pyi
|
||||
|
||||
def add(p1: tuple[int, int], p2: tuple[int, int]) -> tuple[int, int]: ...
|
||||
def multiply(point: tuple[int, int], n: int) -> tuple[int, int]: ...
|
||||
point = tuple[int, int]
|
||||
|
||||
def add(p1: point, p2: point) -> point:
|
||||
"""
|
||||
Adds two points on the SM2 elliptic curve.
|
||||
|
||||
Performs point addition on the SM2 curve defined by `sm2p256v1()`.
|
||||
|
||||
Args:
|
||||
p1 (point): A tuple representing the x and y coordinates of the first point.
|
||||
p2 (point): A tuple representing the x and y coordinates of the second point.
|
||||
|
||||
Raises:
|
||||
Panic: If the x or y coordinates of either point are not valid on the curve.
|
||||
|
||||
Returns:
|
||||
point: A tuple representing the x and y coordinates of the resulting point after addition.
|
||||
|
||||
Example:
|
||||
>>> p1 = (x1, y1)
|
||||
>>> p2 = (x2, y2)
|
||||
>>> result = add(p1, p2)
|
||||
"""
|
||||
...
|
||||
|
||||
def multiply(point: point, n: int) -> point:
|
||||
"""
|
||||
multiply(point, n)
|
||||
|
||||
Performs scalar multiplication of a point on the SM2 curve.
|
||||
|
||||
performs the multiplication operation on the SM2 curve defined by `sm2p256v1()`.
|
||||
|
||||
Args:
|
||||
point (point): representing the x and y coordinates of the point.
|
||||
n (int): representing the scalar to multiply the point by.
|
||||
|
||||
Raises:
|
||||
Panic: If the x or y coordinates of the point are not less than the curve parameter `p`.
|
||||
|
||||
Returns:
|
||||
point: representing the x and y coordinates of the result point.
|
||||
|
||||
Example:
|
||||
>>> point = (g, g)
|
||||
>>> n = 10
|
||||
>>> result = multiply(point, n)
|
||||
"""
|
||||
...
|
||||
|
@@ -10,6 +10,12 @@ classifiers = [
|
||||
"Programming Language :: Python :: Implementation :: CPython",
|
||||
]
|
||||
dynamic = ["version"]
|
||||
authors = [{ name = "Liang Junyong", email = "2251250136@qq.com" }]
|
||||
readme = "readme.md"
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://git.mamahaha.work/sangge/ecc_rs"
|
||||
|
||||
[tool.maturin]
|
||||
features = ["pyo3/extension-module"]
|
||||
bindings = "pyo3"
|
||||
|
@@ -1,5 +1,14 @@
|
||||
# ecc_rs
|
||||
|
||||
a simple rust implementation of SM2 binding for python.
|
||||
powered by pyo3.
|
||||
|
||||
useage
|
||||
|
||||
```python
|
||||
import ecc_rs
|
||||
|
||||
point = tuple[int, int]
|
||||
# Example point coordinates for P1 and P2 as tuples (x1, y1) and (x2, y2)
|
||||
p1 = (
|
||||
1234567890123456789012345678901234567890123456789012345678901234,
|
||||
@@ -17,3 +26,5 @@ print(f"Resulting Point: x = {result_x}, y = {result_y}")
|
||||
|
||||
result = ecc_rs.multiply(p1, 2)
|
||||
print(f"Resulting Point: x = {result[0]}, y = {result[1]}")
|
||||
|
||||
```
|
302
src/lib.rs
302
src/lib.rs
@@ -16,10 +16,19 @@ struct CurveFp {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Point {
|
||||
struct Point<'a> {
|
||||
x: BigUint,
|
||||
y: BigUint,
|
||||
curve: CurveFp,
|
||||
curve: &'a CurveFp,
|
||||
}
|
||||
|
||||
/// 椭圆曲线上的点(雅可比坐标)
|
||||
#[derive(Clone)]
|
||||
struct JacobianPoint<'a> {
|
||||
x: BigUint, // X 坐标
|
||||
y: BigUint, // Y 坐标
|
||||
z: BigUint, // Z 坐标
|
||||
curve: &'a CurveFp, // 椭圆曲线的参数
|
||||
}
|
||||
|
||||
// Initialize the SM2 Curve
|
||||
@@ -59,137 +68,180 @@ fn sm2p256v1() -> CurveFp {
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the greatest common divisor (GCD) of two `BigUint` numbers.
|
||||
///
|
||||
/// The function uses the Euclidean algorithm to compute the GCD. The algorithm is based on
|
||||
/// the principle that the greatest common divisor of two numbers does not change if the larger
|
||||
/// number is replaced by its difference with the smaller number.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `a` - The first `BigUint` number.
|
||||
/// * `b` - The second `BigUint` number.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `BigUint` - The greatest common divisor of `a` and `b`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// let a = BigUint::from(60u32);
|
||||
/// let b = BigUint::from(48u32);
|
||||
/// let result = gcd(a, b);
|
||||
/// assert_eq!(result, BigUint::from(12u32));
|
||||
/// ```
|
||||
fn gcd(a: &BigUint, b: &BigUint) -> BigUint {
|
||||
let mut c = a.clone();
|
||||
let mut d = b.clone();
|
||||
while !a.is_zero() {
|
||||
let temp = c.clone();
|
||||
c = d % c;
|
||||
d = temp;
|
||||
}
|
||||
d
|
||||
}
|
||||
|
||||
/// Computes the modular inverse of `a` under modulo `m`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `a` - A reference to a BigUint representing the number to find the modular inverse of.
|
||||
/// * `p` - A reference to a BigUint representing the modulus.
|
||||
///
|
||||
/// # Return1
|
||||
///
|
||||
/// * A BigUint representing the modular inverse of `a` modulo `p`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if the modular inverse does not exist (i.e., if `a` and `p` are not coprime).
|
||||
fn mod_inverse(a: &BigUint, m: &BigUint) -> BigUint {
|
||||
let (mut t, mut new_t) = (BigUint::zero(), BigUint::one());
|
||||
let (mut r, mut new_r) = (m.clone(), a.clone());
|
||||
|
||||
while !new_r.is_zero() {
|
||||
let quotient = &r / &new_r;
|
||||
|
||||
let temp_t = new_t.clone();
|
||||
new_t = if t < (quotient.clone() * &temp_t) {
|
||||
// BigUint can't be negative,
|
||||
// so we use mod to handle the case where t < quotient * temp_t
|
||||
(&t + m - &(quotient.clone() * &temp_t) % m) % m
|
||||
} else {
|
||||
&t - &(quotient.clone() * &temp_t)
|
||||
};
|
||||
|
||||
let temp_r = new_r.clone();
|
||||
new_r = &r - &(quotient.clone() * &temp_r);
|
||||
r = temp_r;
|
||||
t = temp_t;
|
||||
}
|
||||
|
||||
if r > BigUint::one() {
|
||||
panic!("Modular inverse does not exist");
|
||||
}
|
||||
|
||||
if t < BigUint::zero() {
|
||||
t += m;
|
||||
}
|
||||
|
||||
t
|
||||
}
|
||||
fn point_addition(p1: &Point, p2: &Point) -> Point {
|
||||
let curve = &p1.curve;
|
||||
let p = &curve.p;
|
||||
|
||||
fn point_addition<'a>(p1: &'a Point<'a>, p2: &'a Point<'a>) -> Point<'a> {
|
||||
// 如果 p1 是零点,返回一个新构造的 p2 点,而不是克隆
|
||||
if p1.x.is_zero() && p1.y.is_zero() {
|
||||
return Point {
|
||||
x: p2.x.clone(),
|
||||
y: p2.y.clone(),
|
||||
curve: p2.curve, // 如果 curve 是引用,保持引用即可
|
||||
};
|
||||
}
|
||||
|
||||
// 如果 p2 是零点,返回一个新构造的 p1 点,而不是克隆
|
||||
if p2.x.is_zero() && p2.y.is_zero() {
|
||||
return Point {
|
||||
x: p1.x.clone(),
|
||||
y: p1.y.clone(),
|
||||
curve: p1.curve, // 如果 curve 是引用,保持引用即可
|
||||
};
|
||||
}
|
||||
|
||||
from_jacobian(jacobian_add(to_jacobian(p1), to_jacobian(p2)))
|
||||
}
|
||||
|
||||
/// 将仿射坐标转换为雅可比坐标 (X, Y, Z)
|
||||
fn to_jacobian<'a>(p: &'a Point) -> JacobianPoint<'a> {
|
||||
JacobianPoint {
|
||||
x: p.x.clone(),
|
||||
y: p.y.clone(),
|
||||
z: BigUint::one(), // Z = 1 表示仿射坐标
|
||||
curve: p.curve,
|
||||
}
|
||||
}
|
||||
|
||||
/// 将雅可比坐标转换为仿射坐标
|
||||
fn from_jacobian(p: JacobianPoint) -> Point {
|
||||
if p.z.is_zero() {
|
||||
return Point {
|
||||
x: BigUint::zero(),
|
||||
y: BigUint::zero(),
|
||||
curve: p.curve,
|
||||
};
|
||||
}
|
||||
let p_mod = &p.curve.p;
|
||||
|
||||
// 计算 Z 的模反
|
||||
let z_inv = p.z.modinv(p_mod).expect("modinv failed");
|
||||
let z_inv2 = (&z_inv * &z_inv) % p_mod; // Z_inv^2
|
||||
let z_inv3 = (&z_inv2 * &z_inv) % p_mod; // Z_inv^3
|
||||
|
||||
// 计算 x = X * Z_inv^2, y = Y * Z_inv^3
|
||||
let x_affine = (&p.x * &z_inv2) % p_mod;
|
||||
let y_affine = (&p.y * &z_inv3) % p_mod;
|
||||
|
||||
Point {
|
||||
x: x_affine,
|
||||
y: y_affine,
|
||||
curve: p.curve,
|
||||
}
|
||||
}
|
||||
|
||||
/// 雅可比坐标下的点加法
|
||||
fn jacobian_add<'a>(p1: JacobianPoint<'a>, p2: JacobianPoint<'a>) -> JacobianPoint<'a> {
|
||||
if p1.z.is_zero() {
|
||||
return p2.clone();
|
||||
}
|
||||
if p2.x.is_zero() && p2.y.is_zero() {
|
||||
if p2.z.is_zero() {
|
||||
return p1.clone();
|
||||
}
|
||||
|
||||
let lambda = if p1.x == p2.x && p1.y == p2.y {
|
||||
let num = (BigUint::from(3u32) * &p1.x * &p1.x + &curve.a) % p;
|
||||
let denom = (BigUint::from(2u32) * &p1.y) % p;
|
||||
(num * mod_inverse(&denom, p)) % p
|
||||
} else {
|
||||
let num = ((&p2.y + p) - &p1.y) % p;
|
||||
let denom = ((&p2.x + p) - &p1.x) % p;
|
||||
let p_mod = &p1.curve.p;
|
||||
|
||||
(num * mod_inverse(&denom, p)) % p
|
||||
};
|
||||
// U1 = X1 * Z2^2, U2 = X2 * Z1^2
|
||||
let z1z1 = (&p1.z * &p1.z) % p_mod;
|
||||
let z2z2 = (&p2.z * &p2.z) % p_mod;
|
||||
let u1 = (&p1.x * &z2z2) % p_mod;
|
||||
let u2 = (&p2.x * &z1z1) % p_mod;
|
||||
|
||||
let x3 = (lambda.clone() * &lambda - &p1.x - &p2.x) % p;
|
||||
let y3 = (lambda * (&p1.x + p - &x3) - &p1.y) % p;
|
||||
// S1 = Y1 * Z2^3, S2 = Y2 * Z1^3
|
||||
let z1z1z1 = (&z1z1 * &p1.z) % p_mod;
|
||||
let z2z2z2 = (&z2z2 * &p2.z) % p_mod;
|
||||
let s1 = (&p1.y * &z2z2z2) % p_mod;
|
||||
let s2 = (&p2.y * &z1z1z1) % p_mod;
|
||||
|
||||
Point {
|
||||
if u1 == u2 && s1 == s2 {
|
||||
// 点倍运算 (p1 == p2)
|
||||
return jacobian_double(p1);
|
||||
}
|
||||
|
||||
// H = U2 - U1, R = S2 - S1
|
||||
let h = (u2 + p_mod - &u1) % p_mod;
|
||||
let r = (s2 + p_mod - &s1) % p_mod;
|
||||
|
||||
// X3 = R^2 - H^3 - 2 * U1 * H^2
|
||||
let h2 = (&h * &h) % p_mod;
|
||||
let h3 = (&h2 * &h) % p_mod;
|
||||
let x3 = (&r * &r + p_mod - &h3 - (&BigUint::from(2u32) * &u1 * &h2) % p_mod) % p_mod;
|
||||
|
||||
// Y3 = R * (U1 * H^2 - X3) - S1 * H^3
|
||||
let y3 =
|
||||
(&r * ((&u1 * &h2 + p_mod - (&x3 % p_mod)) % p_mod) + p_mod - (&s1 * &h3) % p_mod) % p_mod;
|
||||
|
||||
// Z3 = Z1 * Z2 * H
|
||||
let z3 = (&p1.z * &p2.z * &h) % p_mod;
|
||||
|
||||
JacobianPoint {
|
||||
x: x3,
|
||||
y: y3,
|
||||
curve: curve.clone(),
|
||||
z: z3,
|
||||
curve: p1.curve,
|
||||
}
|
||||
}
|
||||
|
||||
fn point_multiplication(p: &Point, n: &BigUint) -> Point {
|
||||
let mut result = Point {
|
||||
/// 雅可比坐标下的点倍运算
|
||||
fn jacobian_double(p: JacobianPoint) -> JacobianPoint {
|
||||
let p_mod = &p.curve.p;
|
||||
|
||||
if p.y.is_zero() {
|
||||
return JacobianPoint {
|
||||
x: BigUint::zero(),
|
||||
y: BigUint::zero(),
|
||||
z: BigUint::zero(),
|
||||
curve: p.curve,
|
||||
};
|
||||
}
|
||||
|
||||
// S = 4 * X * Y^2
|
||||
let y2 = (&p.y * &p.y) % p_mod;
|
||||
let s = (&p.x * &y2 * BigUint::from(4u32)) % p_mod;
|
||||
|
||||
// M = 3 * X^2 + a * Z^4
|
||||
let z2 = (&p.z * &p.z) % p_mod;
|
||||
let z4 = (&z2 * &z2) % p_mod;
|
||||
let m = ((&p.x * &p.x * BigUint::from(3u32)) + &p.curve.a * &z4) % p_mod;
|
||||
|
||||
// X3 = M^2 - 2 * S
|
||||
let x3 = (&m * &m + p_mod - &s * BigUint::from(2u32)) % p_mod;
|
||||
|
||||
// Y3 = M * (S - X3) - 8 * Y^4
|
||||
let y4 = (&y2 * &y2) % p_mod;
|
||||
let y3 = (&m * (&s + p_mod - &x3) + p_mod - BigUint::from(8u32) * &y4) % p_mod;
|
||||
|
||||
// Z3 = 2 * Y * Z
|
||||
let z3 = (&p.y * &p.z * BigUint::from(2u32)) % p_mod;
|
||||
|
||||
JacobianPoint {
|
||||
x: x3,
|
||||
y: y3,
|
||||
z: z3,
|
||||
curve: p.curve,
|
||||
}
|
||||
}
|
||||
|
||||
fn point_multiplication<'a>(p: &'a Point<'a>, n: &BigUint) -> Point<'a> {
|
||||
let mut result = JacobianPoint {
|
||||
x: BigUint::zero(),
|
||||
y: BigUint::zero(),
|
||||
curve: p.curve.clone(),
|
||||
y: BigUint::one(), // 无穷远点的雅可比坐标表示
|
||||
z: BigUint::zero(),
|
||||
curve: p.curve,
|
||||
};
|
||||
|
||||
let mut addend = p.clone();
|
||||
// 将输入点从仿射坐标转换为雅可比坐标
|
||||
let mut addend = to_jacobian(p);
|
||||
let mut k = n.clone();
|
||||
|
||||
// 使用二进制展开法进行点乘运算
|
||||
while !k.is_zero() {
|
||||
if &k % 2u32 == BigUint::one() {
|
||||
result = point_addition(&result, &addend);
|
||||
result = jacobian_add(result, addend.clone());
|
||||
}
|
||||
addend = point_addition(&addend, &addend);
|
||||
addend = jacobian_double(addend); // 倍点运算
|
||||
k >>= 1;
|
||||
}
|
||||
|
||||
result
|
||||
// 将结果从雅可比坐标转换为仿射坐标
|
||||
from_jacobian(result)
|
||||
}
|
||||
|
||||
/// SM2 addition
|
||||
@@ -202,24 +254,24 @@ fn add(p1: (BigUint, BigUint), p2: (BigUint, BigUint)) -> (BigUint, BigUint) {
|
||||
let x2 = p2.0;
|
||||
let y2 = p2.1;
|
||||
|
||||
// 检查 x 和 y 是否小于曲线参数 p
|
||||
if x1 >= curve.p || y1 >= curve.p {
|
||||
panic!("Point p1 coordinates are out of range");
|
||||
}
|
||||
if x2 >= curve.p || y2 >= curve.p {
|
||||
panic!("Point p2 coordinates are out of range");
|
||||
// Check if x and y are less than the curve parameter p
|
||||
match (x1 >= curve.p, y1 >= curve.p, x2 >= curve.p, y2 >= curve.p) {
|
||||
(true, _, _, _) | (_, true, _, _) | (_, _, true, _) | (_, _, _, true) => {
|
||||
panic!("Point coordinates are out of range");
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let point1 = Point {
|
||||
x: x1,
|
||||
y: y1,
|
||||
curve: curve.clone(),
|
||||
curve: &curve,
|
||||
};
|
||||
|
||||
let point2 = Point {
|
||||
x: x2,
|
||||
y: y2,
|
||||
curve: curve.clone(),
|
||||
curve: &curve,
|
||||
};
|
||||
|
||||
let result = point_addition(&point1, &point2);
|
||||
@@ -228,13 +280,23 @@ fn add(p1: (BigUint, BigUint), p2: (BigUint, BigUint)) -> (BigUint, BigUint) {
|
||||
|
||||
/// SM2 multiply
|
||||
#[pyfunction]
|
||||
fn multiply(point: (BigUint, BigUint), n: BigUint) -> (BigUint, BigUint) {
|
||||
fn multiply(point: (BigUint, BigUint), mut n: BigUint) -> (BigUint, BigUint) {
|
||||
let curve = sm2p256v1();
|
||||
|
||||
if n >= curve.n {
|
||||
n %= &curve.n;
|
||||
}
|
||||
|
||||
match (point.0 < curve.p, point.1 < curve.p) {
|
||||
(false, _) | (_, false) => panic!("Point coordinates are out of range"),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Construct the point with BigUint values
|
||||
let point = Point {
|
||||
x: point.0.clone(),
|
||||
y: point.1.clone(),
|
||||
curve: curve.clone(),
|
||||
x: point.0,
|
||||
y: point.1,
|
||||
curve: &curve,
|
||||
};
|
||||
// Perform point multiplication
|
||||
let result = point_multiplication(&point, &n);
|
||||
|
Reference in New Issue
Block a user