first commit
This commit is contained in:
commit
3f8e0ff6c9
72
.gitignore
vendored
Normal file
72
.gitignore
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
/target
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
.pytest_cache/
|
||||
*.py[cod]
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
.venv/
|
||||
env/
|
||||
bin/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
include/
|
||||
man/
|
||||
venv/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
pip-selfcheck.json
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
|
||||
# Mr Developer
|
||||
.mr.developer.cfg
|
||||
.project
|
||||
.pydevproject
|
||||
|
||||
# Rope
|
||||
.ropeproject
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
*.pot
|
||||
|
||||
.DS_Store
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyCharm
|
||||
.idea/
|
||||
|
||||
# VSCode
|
||||
.vscode/
|
||||
|
||||
# Pyenv
|
||||
.python-version
|
201
Cargo.lock
generated
Normal file
201
Cargo.lock
generated
Normal file
@ -0,0 +1,201 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "ecc_rs"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"pyo3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "indoc"
|
||||
version = "2.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.158"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyo3"
|
||||
version = "0.22.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "831e8e819a138c36e212f3af3fd9eeffed6bf1510a805af35b0edee5ffa59433"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"indoc",
|
||||
"libc",
|
||||
"memoffset",
|
||||
"once_cell",
|
||||
"portable-atomic",
|
||||
"pyo3-build-config",
|
||||
"pyo3-ffi",
|
||||
"pyo3-macros",
|
||||
"unindent",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-build-config"
|
||||
version = "0.22.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e8730e591b14492a8945cdff32f089250b05f5accecf74aeddf9e8272ce1fa8"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"target-lexicon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-ffi"
|
||||
version = "0.22.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e97e919d2df92eb88ca80a037969f44e5e70356559654962cbb3316d00300c6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pyo3-build-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-macros"
|
||||
version = "0.22.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb57983022ad41f9e683a599f2fd13c3664d7063a3ac5714cae4b7bee7d3f206"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"pyo3-macros-backend",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-macros-backend"
|
||||
version = "0.22.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec480c0c51ddec81019531705acac51bcdbeae563557c982aa8263bb96880372"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"pyo3-build-config",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.12.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "unindent"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"
|
14
Cargo.toml
Normal file
14
Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "ecc_rs"
|
||||
version = "0.1.1"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[lib]
|
||||
name = "ecc_rs"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
num-bigint = "0.4.6"
|
||||
num-traits = "0.2.19"
|
||||
pyo3 = "0.22.0"
|
15
pyproject.toml
Normal file
15
pyproject.toml
Normal file
@ -0,0 +1,15 @@
|
||||
[build-system]
|
||||
requires = ["maturin>=1.7,<2.0"]
|
||||
build-backend = "maturin"
|
||||
|
||||
[project]
|
||||
name = "ecc_rs"
|
||||
requires-python = ">=3.8"
|
||||
classifiers = [
|
||||
"Programming Language :: Rust",
|
||||
"Programming Language :: Python :: Implementation :: CPython",
|
||||
"Programming Language :: Python :: Implementation :: PyPy",
|
||||
]
|
||||
dynamic = ["version"]
|
||||
[tool.maturin]
|
||||
features = ["pyo3/extension-module"]
|
254
src/lib.rs
Normal file
254
src/lib.rs
Normal file
@ -0,0 +1,254 @@
|
||||
#![allow(dead_code)]
|
||||
use num_bigint::BigUint;
|
||||
use num_traits::{One, Zero};
|
||||
use pyo3::prelude::*;
|
||||
|
||||
/// Define curve
|
||||
#[derive(Debug, Clone)]
|
||||
struct CurveFp {
|
||||
name: &'static str,
|
||||
a: BigUint,
|
||||
b: BigUint,
|
||||
p: BigUint,
|
||||
n: BigUint,
|
||||
gx: BigUint,
|
||||
gy: BigUint,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Point {
|
||||
x: BigUint,
|
||||
y: BigUint,
|
||||
curve: CurveFp,
|
||||
}
|
||||
|
||||
// Initialize the SM2 Curve
|
||||
fn sm2p256v1() -> CurveFp {
|
||||
CurveFp {
|
||||
name: "sm2p256v1",
|
||||
a: BigUint::parse_bytes(
|
||||
b"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",
|
||||
16,
|
||||
)
|
||||
.unwrap(),
|
||||
b: BigUint::parse_bytes(
|
||||
b"28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",
|
||||
16,
|
||||
)
|
||||
.unwrap(),
|
||||
p: BigUint::parse_bytes(
|
||||
b"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",
|
||||
16,
|
||||
)
|
||||
.unwrap(),
|
||||
n: BigUint::parse_bytes(
|
||||
b"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",
|
||||
16,
|
||||
)
|
||||
.unwrap(),
|
||||
gx: BigUint::parse_bytes(
|
||||
b"32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",
|
||||
16,
|
||||
)
|
||||
.unwrap(),
|
||||
gy: BigUint::parse_bytes(
|
||||
b"BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0",
|
||||
16,
|
||||
)
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// 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;
|
||||
|
||||
if p1.x.is_zero() && p1.y.is_zero() {
|
||||
return p2.clone();
|
||||
}
|
||||
if p2.x.is_zero() && p2.y.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;
|
||||
|
||||
(num * mod_inverse(&denom, p)) % p
|
||||
};
|
||||
|
||||
println!("{lambda}");
|
||||
|
||||
let x3 = (lambda.clone() * &lambda - &p1.x - &p2.x) % p;
|
||||
let y3 = (lambda * (&p1.x + p - &x3) - &p1.y) % p;
|
||||
|
||||
Point {
|
||||
x: x3,
|
||||
y: y3,
|
||||
curve: curve.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn point_multiplication(p: &Point, n: &BigUint) -> Point {
|
||||
let mut result = Point {
|
||||
x: BigUint::zero(),
|
||||
y: BigUint::zero(),
|
||||
curve: p.curve.clone(),
|
||||
};
|
||||
|
||||
let mut addend = p.clone();
|
||||
let mut k = n.clone();
|
||||
|
||||
while !k.is_zero() {
|
||||
if &k % 2u32 == BigUint::one() {
|
||||
result = point_addition(&result, &addend);
|
||||
}
|
||||
addend = point_addition(&addend, &addend);
|
||||
k >>= 1;
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// SM2 addition
|
||||
#[pyfunction]
|
||||
fn add(p1: (String, String), p2: (String, String)) -> (String, String) {
|
||||
let curve = sm2p256v1();
|
||||
|
||||
let x1 = BigUint::parse_bytes(p1.0.as_bytes(), 10).unwrap();
|
||||
let y1 = BigUint::parse_bytes(p1.1.as_bytes(), 10).unwrap();
|
||||
let x2 = BigUint::parse_bytes(p2.0.as_bytes(), 10).unwrap();
|
||||
let y2 = BigUint::parse_bytes(p2.1.as_bytes(), 10).unwrap();
|
||||
|
||||
// 检查 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");
|
||||
}
|
||||
|
||||
let point1 = Point {
|
||||
x: x1,
|
||||
y: y1,
|
||||
curve: curve.clone(),
|
||||
};
|
||||
|
||||
let point2 = Point {
|
||||
x: x2,
|
||||
y: y2,
|
||||
curve: curve.clone(),
|
||||
};
|
||||
|
||||
let result = point_addition(&point1, &point2);
|
||||
|
||||
(result.x.to_str_radix(10), result.y.to_str_radix(10))
|
||||
}
|
||||
|
||||
/// SM2 multiply
|
||||
#[pyfunction]
|
||||
fn multiply(point: (String, String), n: String) -> (String, String) {
|
||||
let curve = sm2p256v1();
|
||||
let point = Point {
|
||||
x: BigUint::parse_bytes(point.0.as_bytes(), 10).unwrap(),
|
||||
y: BigUint::parse_bytes(point.1.as_bytes(), 10).unwrap(),
|
||||
curve: curve.clone(),
|
||||
};
|
||||
|
||||
let scalar_bn = BigUint::parse_bytes(n.as_bytes(), 10).unwrap();
|
||||
let result = point_multiplication(&point, &scalar_bn);
|
||||
|
||||
(result.x.to_str_radix(10), result.y.to_str_radix(10))
|
||||
}
|
||||
|
||||
/// A Python module implemented in Rust.
|
||||
#[pymodule]
|
||||
fn ecc_rs(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction_bound!(multiply, m)?)?;
|
||||
m.add_function(wrap_pyfunction_bound!(add, m)?)?;
|
||||
Ok(())
|
||||
}
|
24
test.py
Normal file
24
test.py
Normal file
@ -0,0 +1,24 @@
|
||||
import ecc_rs
|
||||
|
||||
# Example point coordinates for P1 and P2 as tuples (x1, y1) and (x2, y2)
|
||||
p1 = (
|
||||
"1234567890123456789012345678901234567890123456789012345678901234",
|
||||
"9876543210987654321098765432109876543210987654321098765432109876",
|
||||
)
|
||||
p2 = (
|
||||
"2234567890123456789012345678901234567890123456789012345678901234",
|
||||
"2876543210987654321098765432109876543210987654321098765432109876",
|
||||
)
|
||||
print(ecc_rs.__all__)
|
||||
|
||||
# Add the two points
|
||||
result_x, result_y = ecc_rs.add(p1, p2)
|
||||
print(f"Resulting Point: x = {result_x}, y = {result_y}")
|
||||
|
||||
# Convert the result to integers if needed
|
||||
result_x_int = int(result_x)
|
||||
result_y_int = int(result_y)
|
||||
print(f"Resulting Point as integers: x = {result_x_int}, y = {result_y_int}")
|
||||
|
||||
result = ecc_rs.multiply(p1, "2")
|
||||
print(f"Resulting Point: x = {result[0]}, y = {result[1]}")
|
Loading…
x
Reference in New Issue
Block a user