Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/substrate #73

Closed
wants to merge 26 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4,061 changes: 0 additions & 4,061 deletions Cargo.lock

This file was deleted.

3 changes: 2 additions & 1 deletion packages/kos-crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ sha2 = { workspace = true }
sha3 = { workspace = true }
hmac = { workspace = true }
secp256k1 = { workspace = true, features = ["rand", "serde", "bitcoin_hashes"] }
ed25519-dalek = { workspace = true, features = ["serde"] }
ed25519-dalek = { workspace = true, features = ["serde"] }
aes-gcm = "0.10"
aes = { version = "0.8" }
cfb-mode = "0.8"
cbc = { version = "0.1", features = ["block-padding", "std"] }
pem = "3"
pbkdf2 = { version = "0.12", features = ["simple"] }
base64 = "0.21"
sp-core = "34.0.0"
24 changes: 23 additions & 1 deletion packages/kos-crypto/src/keypair.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::ed25519;
use crate::secp256k1;
use crate::sr25519;

use std::fmt;

use wasm_bindgen::prelude::wasm_bindgen;

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
Expand All @@ -11,6 +11,7 @@ enum KeyType {
Ed25519,
Secp256k1,
Secp256k1Compressed,
Sr25519,
}

#[derive(Clone, serde::Serialize, serde::Deserialize)]
Expand All @@ -19,6 +20,7 @@ pub struct KeyPair {
key_type: KeyType,
ed25519: Option<ed25519::Ed25519KeyPair>,
secp256k1: Option<secp256k1::Secp256k1KeyPair>,
sr25519: Option<sr25519::Sr25519KeyPair>,
}

#[wasm_bindgen]
Expand All @@ -28,6 +30,7 @@ impl KeyPair {
key_type: KeyType::Default,
ed25519: None,
secp256k1: None,
sr25519: None,
}
}

Expand All @@ -36,6 +39,7 @@ impl KeyPair {
key_type: KeyType::Ed25519,
ed25519: Some(kp),
secp256k1: None,
sr25519: None,
}
}

Expand All @@ -48,6 +52,16 @@ impl KeyPair {
},
ed25519: None,
secp256k1: Some(kp),
sr25519: None,
}
}

pub fn new_sr25519(kp: sr25519::Sr25519KeyPair) -> Self {
Self {
key_type: KeyType::Sr25519,
ed25519: None,
secp256k1: None,
sr25519: Some(kp),
}
}
}
Expand All @@ -59,6 +73,7 @@ impl KeyPair {
KeyType::Ed25519 => self.ed25519.as_ref().unwrap().sign_digest(digest),
KeyType::Secp256k1 => self.secp256k1.as_ref().unwrap().sign_digest(digest),
KeyType::Secp256k1Compressed => self.secp256k1.as_ref().unwrap().sign_digest(digest),
KeyType::Sr25519 => self.sr25519.as_ref().unwrap().sign_digest(digest),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle potential None values to prevent panics

In the methods sign_digest, verify_digest, public_key, and secret_key, using .as_ref().unwrap() on the sr25519 field can lead to a panic if the field is None. Even though the current design assumes that the field will be Some when key_type is Sr25519, it's safer to handle the None case explicitly to prevent unexpected panics and improve code robustness.

Apply this diff to handle potential None values:

-match self.key_type {
-    KeyType::Sr25519 => self.sr25519.as_ref().unwrap().sign_digest(digest),
+match self.key_type {
+    KeyType::Sr25519 => {
+        if let Some(sr25519_kp) = &self.sr25519 {
+            sr25519_kp.sign_digest(digest)
+        } else {
+            // Handle the error appropriately, e.g., return an error or default value
+            Vec::new() // or consider returning a Result type
+        }
+    },

Similarly, update the verify_digest, public_key, and secret_key methods to handle None values appropriately.

Also applies to: 98-102, 127-127, 143-143


🛠️ Refactor suggestion

Consider refactoring to reduce code duplication

The match statements in the methods sign_digest, verify_digest, public_key, and secret_key have repetitive patterns across different key types. Consider refactoring these methods to eliminate duplication, which will enhance maintainability and readability.

For example, you could introduce a trait that defines common behaviors for key pairs and implement it for each key type. Then, store the key pair in an enum or a trait object to simplify method implementations.

Also applies to: 98-102, 127-127, 143-143

}
}

Expand All @@ -80,6 +95,11 @@ impl KeyPair {
.as_ref()
.unwrap()
.verify_digest(digest, signature, public_key),
KeyType::Sr25519 => self
.sr25519
.as_ref()
.unwrap()
.verify_digest(digest, signature, public_key),
}
}
}
Expand All @@ -104,6 +124,7 @@ impl KeyPair {
KeyType::Secp256k1 | KeyType::Secp256k1Compressed => {
self.secp256k1.as_ref().unwrap().public_key()
}
KeyType::Sr25519 => self.sr25519.as_ref().unwrap().public_key(),
}
}

Expand All @@ -119,6 +140,7 @@ impl KeyPair {
KeyType::Secp256k1 | KeyType::Secp256k1Compressed => {
self.secp256k1.as_ref().unwrap().secret_key()
}
KeyType::Sr25519 => self.sr25519.as_ref().unwrap().secret_key(),
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/kos-crypto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ pub mod hash;
pub mod keypair;
pub mod mnemonic;
pub mod secp256k1;
pub mod sr25519;
100 changes: 100 additions & 0 deletions packages/kos-crypto/src/sr25519.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use coins_bip39::{English, Mnemonic};
use kos_types::{error::Error, Bytes32};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use sp_core::{sr25519, Pair};
use wasm_bindgen::prelude::wasm_bindgen;

#[wasm_bindgen]
pub struct Sr25519KeyPair {
keypair: sr25519::Pair,
}

impl Serialize for Sr25519KeyPair {
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
todo!()
}
}

impl<'de> Deserialize<'de> for Sr25519KeyPair {
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
todo!()
}
}

impl Clone for Sr25519KeyPair {
fn clone(&self) -> Sr25519KeyPair {
Sr25519KeyPair {
keypair: self.keypair.clone(),
}
}
}

impl Sr25519KeyPair {
pub fn random<R>(rng: &mut R) -> Self
where
R: rand::Rng + ?Sized,
{
let mut secret = Bytes32::zeroed();
rng.fill(secret.as_mut());

Sr25519KeyPair::new(secret.into())
}

pub fn new(secret: [u8; 32]) -> Self {
let keypair = sr25519::Pair::from_seed_slice(&secret).unwrap();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle potential errors instead of using unwrap() to prevent panics

Using unwrap() can cause the program to panic if an error occurs. Consider handling the error appropriately or propagating it using the ? operator.

Apply this diff to handle the potential error:

- let keypair = sr25519::Pair::from_seed_slice(&secret).unwrap();
+ let keypair = sr25519::Pair::from_seed_slice(&secret)?;

Also, update the function signature to return a Result<Self, Error>:

- pub fn new(secret: [u8; 32]) -> Self {
+ pub fn new(secret: [u8; 32]) -> Result<Self, Error> {

And adjust the return statement:

- Self { keypair }
+ Ok(Self { keypair })

Committable suggestion was skipped due to low confidence.

Self { keypair }
}

pub fn new_from_mnemonic_phrase_with_path(
phrase: &str,
path: &str,
password: Option<&str>,
) -> Result<Self, Error> {
let mnemonic = Mnemonic::<English>::new_from_phrase(phrase)?;
Self::new_from_mnemonic(path, mnemonic, password)
}

pub fn new_from_mnemonic(
path: &str,
m: Mnemonic<English>,
password: Option<&str>,
) -> Result<Self, Error> {
// Convert mnemonic to seed
let seed = format!("{}{}", m.to_phrase(), path);

// Derive keypair based on the provided path and seed
let keypair = Pair::from_string(&seed, password).unwrap();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle potential errors instead of using unwrap() to prevent panics

Using unwrap() can cause the program to panic if an error occurs. Consider handling the error appropriately or propagating it using the ? operator.

Apply this diff to handle the potential error:

- let keypair = Pair::from_string(&seed, password).unwrap();
+ let keypair = Pair::from_string(&seed, password)?;

Also, ensure that the function handles the Result properly and propagates the error if necessary.

Committable suggestion was skipped due to low confidence.


Ok(Self { keypair })
}
}

impl Sr25519KeyPair {
pub fn public_key(&self) -> Vec<u8> {
self.keypair.public().0.to_vec()
}

pub fn secret_key(&self) -> Vec<u8> {
self.keypair.to_raw_vec()
}
}

impl Sr25519KeyPair {
pub fn sign_digest(&self, message: &[u8]) -> Vec<u8> {
self.keypair.sign(message).0.to_vec()
}

pub fn verify_digest(&self, message: &[u8], signature: &[u8], public_key: &[u8]) -> bool {
let public = sr25519::Public::from_raw(<[u8; 32]>::try_from(public_key).unwrap());

let signature = sr25519::Signature::from_raw(<[u8; 64]>::try_from(signature).unwrap());
Comment on lines +94 to +96
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle potential errors instead of using unwrap() to prevent panics

Using unwrap() can cause panics if the conversion fails. Consider handling the errors appropriately to ensure the function behaves reliably.

Apply this diff to handle the potential errors:

- let public = sr25519::Public::from_raw(<[u8; 32]>::try_from(public_key).unwrap());
+ let public = sr25519::Public::from_raw(<[u8; 32]>::try_from(public_key)?);
- let signature = sr25519::Signature::from_raw(<[u8; 64]>::try_from(signature).unwrap());
+ let signature = sr25519::Signature::from_raw(<[u8; 64]>::try_from(signature)?);

Adjust the function signature to return a Result<bool, Error>:

- pub fn verify_digest(&self, message: &[u8], signature: &[u8], public_key: &[u8]) -> bool {
+ pub fn verify_digest(&self, message: &[u8], signature: &[u8], public_key: &[u8]) -> Result<bool, Error> {

Update the return statement accordingly:

- sr25519::Pair::verify(&signature, message, &public)
+ Ok(sr25519::Pair::verify(&signature, message, &public))

Committable suggestion was skipped due to low confidence.


sr25519::Pair::verify(&signature, message, &public)
}
}
15 changes: 13 additions & 2 deletions packages/kos-sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,19 @@ hex = { workspace = true }
rand = { workspace = true }
coins-bip39 = { workspace = true }
pem = "3"
web3 = { version = "0.19", default-features = false, features = ["http-tls", "wasm"] }
web3 = { version = "0.19", default-features = false, features = [
"http-tls",
"wasm",
] }
bitcoin = { version = "0.30" }
secp256k1 = { workspace = true, features = ["serde", "bitcoin_hashes"] }
rlp = "0.5"

reqwest = { workspace = true, default-features = false, features = ["rustls-tls", "blocking", "json"] }
reqwest = { workspace = true, default-features = false, features = [
"rustls-tls",
"blocking",
"json",
] }
wasm-bindgen-futures = "0.4"

lazy_static = { workspace = true }
Expand All @@ -49,8 +56,12 @@ kos-utils = { workspace = true }
pbjson = { workspace = true }
pbjson-types = { workspace = true }
prost = { workspace = true }
base64 = "0.22.1"
sp-core = "34.0.0"
parity-scale-codec = "3.6.12"

[dev-dependencies]
tokio = { version = "1", features = ["full"] }
tokio-test = "*"
dotenvy = "0.15.7"

Expand Down
2 changes: 1 addition & 1 deletion packages/kos-sdk/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ macro_rules! createChains {
}
}

createChains!(NONE, KLV, TRX, BTC, ETH, MATIC);
createChains!(NONE, KLV, TRX, BTC, ETH, MATIC, DOT, KSM, AVAIL);

// pub enum Chain {
// NONE, // 0
Expand Down
Loading
Loading