Skip to content

Commit

Permalink
Merge pull request #86 from klever-io/develop
Browse files Browse the repository at this point in the history
Promote new version
  • Loading branch information
gustavocbritto authored Jan 23, 2025
2 parents bbb97df + 2971206 commit 8d1f3a3
Show file tree
Hide file tree
Showing 11 changed files with 126 additions and 61 deletions.
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ homepage = "https://klever.org/"
license = "Apache-2.0"
repository = "https://github.com/kleverio/kos-rs"
rust-version = "1.69.0"
version = "0.2.0"
version = "0.2.2"

[workspace.dependencies]
bech32 = "0.9.1"
Expand Down Expand Up @@ -50,5 +50,5 @@ log = "0.4"
lazy_static = "1.4.0"
thiserror = "1.0"

kos = { version = "0.2.0", path = "./packages/kos", default-features = false }
kos = { version = "0.2.2", path = "./packages/kos", default-features = false }
kos-mobile = { version = "0.1.0", path = "./packages/kos-mobile", default-features = false }
63 changes: 54 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Klever Wallet Library for Rust (kos-rs)

kos-rs is an open-source library crafted to deliver fundamental low-level crypto-wallet capabilities for blockchain actions and transactions. Built with Rust, it ensures top-tier security and versatile platform adaptability, positioning it as a premier choice for constructing secure and high-performing blockchain solutions.
kos-rs is an open-source library crafted to deliver fundamental low-level crypto-wallet capabilities for blockchain
actions and transactions. Built with Rust, it ensures top-tier security and versatile platform adaptability, positioning
it as a premier choice for constructing secure and high-performing blockchain solutions.

#### KleverOS, which stands for Klever Wallet Ops Security, is a robust library meticulously crafted in Rust to guarantee the utmost security in private key generation while ensuring unparalleled auditability.

Expand All @@ -19,6 +21,50 @@ kos-rs is an open-source library crafted to deliver fundamental low-level crypto
- [x] Tron (TRX)
- [x] Klever (KLV)
- [x] Polygon (Matic)
- [x] Binance Smart Chain (BSC)
- [x] Huobi Token (HT)
- [x] Syscoin NEVM (SYS_NEVM)
- [x] Polkadot (DOT)
- [x] Kusama (KSM)
- [x] Reef (REEF)
- [x] Shiden (SDN)
- [x] Astar (ASTR)
- [x] Centrifuge (CFG)
- [x] KILT
- [x] Altair
- [x] Moonriver (MOVR)
- [x] Moonbeam (GLMR)
- [x] Sui (SUI)
- [x] Avail (AVAIL)
- [x] Rollux
- [x] Avalanche (AVAX)
- [x] Arbitrum (ARB)
- [x] Base
- [x] Near (NEAR)
- [x] Fantom (FTM)
- [x] Chiliz (CHZ)
- [x] Optimism (OP)
- [x] Polygon zkEVM
- [x] Stolz

#### Coming soon | Under development:

- Litecoin (LTC)
- Syscoin (SYS)
- Dogecoin (DOGE)
- Dash
- XRP
- Digibyte (DGB)
- Cosmos (ATOM)
- Celestia (TIA)
- Cudos
- Aura
- Internet Computer (ICP)
- Solana (SOL)
- BNB Chain
- Bitcoin Cash (BCH)
- Cardano (ADA)
- Aptos (APT)

## Getting Started with Javascript and Node.js

Expand All @@ -43,24 +89,23 @@ To add kos-rs to your Rust project, simply include it as a dependency in your `C
kos-rs = "0.1"
```


## Project Directory Structure

- `Makefile`: Main project build and automation configuration.
- `demo/`: JavaScript demo page with instructions on how to use the `kos-rs` library in web applications.

### Packages (Monorepo)

- `packages/kos/`: Contains tools and utilities for exporting WebAssembly, designed for use in WebAssembly operations.
- `packages/kos-crypto/`: Cryptographic package with support for crypto curves for transaction signing, including asymmetric and symmetric cryptography.
- `packages/kos-proto/`: Library for building protocol messages.
- `packages/kos-sdk/`: Package for blockchain integration, wallet management, transaction construction, and signing implementations.
- `packages/kos-types/`: Package containing complex data types and helpful utilities.
- `packages/kos-utils/`: Package with utility libraries for various purposes.
- `packages/kos/`: Core package implementing all cryptocurrency wallet operations, including cryptographic functions,
curves, and basic offline wallet operations for each blockchain.
- `packages/kos-web/`: Package responsible for exporting kos functionality to JavaScript bindings, providing methods
for web-based implementations.
- `packages/kos-mobile/`: Package responsible for exporting kos functionality to mobile platforms, providing bindings
for both iOS (Swift) and Android (Kotlin).

---

## Apps powered by kos-rs

The kos-rs library powers several key applications within the Klever ecosystem:

- [Klever Wallet for iOS](https://apps.apple.com/uy/app/klever-wallet-bitcoin-crypto/id1615064243)
Expand Down
7 changes: 1 addition & 6 deletions packages/kos-mobile/android/lib/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,7 @@ android {
}

dependencies {
implementation(libs.java.jna) {
artifact {
extension ="aar"
type = "aar"
}
}
implementation(libs.java.jna)
testImplementation(libs.junit)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@ import org.junit.Assert.assertTrue
import org.junit.Test

class KOSTest {

@Test
fun testKOS() {

val dataToEncrypt = "Hello"
val password = "password"
val klvChainId = 38
val klvChainId: UInt = 38u
val mnemonic =
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
val klvPk0 = "8734062c1158f26a3ca8a4a0da87b527a7c168653f7f4c77045e5cf571497d9d"
Expand Down Expand Up @@ -51,7 +49,7 @@ class KOSTest {
val cfbDecryptedData = decrypt(cfbEncryptedData, password)
assertEquals(dataToEncrypt, cfbDecryptedData)

val walletFromMnemonic = generateWalletFromMnemonic(mnemonic, klvChainId, 0, false)
val walletFromMnemonic = generateWalletFromMnemonic(mnemonic, klvChainId, 0u, false)
assertEquals(klvChainId, walletFromMnemonic.chainId)
assertEquals(klvPk0, walletFromMnemonic.privateKey)
assertEquals(klvAddr0, walletFromMnemonic.address)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,19 @@ final class KOSMobileTests: XCTestCase {
let cfbDecryptedData = try! decrypt(data: cfbEncryptedData, password: password)
XCTAssertEqual(dataToEncrypt, cfbDecryptedData)

let walletFromMnemonic = try! generateWalletFromMnemonic(mnemonic: mnemonic, chainId: klvChainId, index: 0, useLegacyPath: false)
XCTAssertEqual(klvChainId, walletFromMnemonic.chainId)
let walletFromMnemonic = try! generateWalletFromMnemonic(mnemonic: mnemonic, chainId: UInt32(klvChainId), index: 0, useLegacyPath: false)
XCTAssertEqual(UInt32(klvChainId), walletFromMnemonic.chainId)
XCTAssertEqual(klvPk0, walletFromMnemonic.privateKey)
XCTAssertEqual(klvAddr0, walletFromMnemonic.address)
XCTAssertEqual(klvPath0, walletFromMnemonic.path)
XCTAssertEqual(klvKey0, walletFromMnemonic.publicKey)

let walletFromPk = try! generateWalletFromPrivateKey(chainId: klvChainId, privateKey: klvPk0)
XCTAssertEqual(klvChainId, walletFromPk.chainId)
let walletFromPk = try! generateWalletFromPrivateKey(chainId: UInt32(klvChainId), privateKey: klvPk0)
XCTAssertEqual(UInt32(klvChainId), walletFromPk.chainId)
XCTAssertEqual(klvPk0, walletFromPk.privateKey)
XCTAssertEqual(klvAddr0, walletFromPk.address)
XCTAssertEqual("", walletFromPk.path)
XCTAssertEqual(klvKey0, walletFromPk.publicKey)

}
}
}
44 changes: 25 additions & 19 deletions packages/kos-mobile/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ struct KOSTransaction {
enum TransactionChainOptions {
Evm {
chain_id: u32,
network_type: u32,
},
Btc {
prev_scripts: Vec<Vec<u8>>,
Expand All @@ -80,11 +79,8 @@ fn new_bitcoin_transaction_options(
}

#[uniffi::export]
fn new_evm_transaction_options(chain_id: u32, network_type: u32) -> TransactionChainOptions {
TransactionChainOptions::Evm {
chain_id,
network_type,
}
fn new_evm_transaction_options(chain_id: u32) -> TransactionChainOptions {
TransactionChainOptions::Evm { chain_id }
}

#[uniffi::export]
Expand Down Expand Up @@ -180,13 +176,7 @@ fn sign_transaction(
options: Option<TransactionChainOptions>,
) -> Result<KOSTransaction, KOSError> {
let options = match options {
Some(TransactionChainOptions::Evm {
chain_id,
network_type,
}) => Some(ChainOptions::EVM {
chain_id,
network_type,
}),
Some(TransactionChainOptions::Evm { chain_id }) => Some(ChainOptions::EVM { chain_id }),
Some(TransactionChainOptions::Btc {
prev_scripts,
input_amounts,
Expand All @@ -199,12 +189,8 @@ fn sign_transaction(

let mut chain = get_chain_by(account.chain_id)?;

if let Some(ChainOptions::EVM {
chain_id,
network_type,
}) = options
{
chain = create_custom_evm(chain_id, network_type).ok_or(KOSError::KOSDelegate(
if let Some(ChainOptions::EVM { chain_id }) = options {
chain = create_custom_evm(chain_id).ok_or(KOSError::KOSDelegate(
"Failed to create custom evm chain".to_string(),
))?;
}
Expand Down Expand Up @@ -465,6 +451,26 @@ mod tests {
);
}

#[test]
fn should_sign_transaction_with_options() {
let chain_id = 61;
let raw =
"b302f101819e84ae7937b285035f6cccc58252089498de4c83810b87f0e2cd92d80c9fac28c4ded4818568c696991f80c0808080";

let account = generate_wallet_from_mnemonic(
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about".to_string(),
chain_id,
0,
false,
)
.unwrap();

let options = new_evm_transaction_options(88888);
let transaction = sign_transaction(account, raw.to_string(), Some(options)).unwrap();

assert_eq!(transaction.raw, "02f87101819e84ae7937b285035f6cccc58252089498de4c83810b87f0e2cd92d80c9fac28c4ded4818568c696991f80c001a044c69f41bf47ad50dc98c74af68811384c9172055b01fcaa39e70f53df69b632a05e071cf1f9e12500b525f03a29f567520e1ea49a97e6a29d1fd432dc6303353e", "The raw doesn't match");
}

#[test]
fn should_sign_message() {
let chain_id = 38;
Expand Down
13 changes: 11 additions & 2 deletions packages/kos/src/chains/eth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,12 @@ impl Chain for ETH {
if let Ok(data) = std::str::from_utf8(&message) {
if let Ok(typed_data) = serde_json::from_str::<TypedData>(data) {
let digest = typed_data.eip712_signing_hash().unwrap();
return self.sign_raw(private_key, digest.to_vec());
let mut sig = self.sign_raw(private_key, digest.to_vec())?;

let last_index = sig.len() - 1;
sig[last_index] += 27;

return Ok(sig);
}
}
}
Expand All @@ -161,7 +166,11 @@ impl Chain for ETH {
]
.concat();
let hashed = keccak256_digest(&to_sign[..]);
let signature = self.sign_raw(private_key, hashed.to_vec())?;
let mut signature = self.sign_raw(private_key, hashed.to_vec())?;

let last_index = signature.len() - 1;
signature[last_index] += 27;

Ok(signature)
}

Expand Down
13 changes: 6 additions & 7 deletions packages/kos/src/chains/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,6 @@ pub struct Transaction {
pub enum ChainOptions {
EVM {
chain_id: u32,
network_type: u32,
},
BTC {
prev_scripts: Vec<Vec<u8>>,
Expand Down Expand Up @@ -384,7 +383,7 @@ impl ChainRegistry {
constants::LTC,
ChainInfo {
factory: || Box::new(btc::BTC::new_btc_based(5, "ltc", "LTC", "Litecoin")),
supported: true,
supported: false,
},
),
(
Expand Down Expand Up @@ -419,7 +418,7 @@ impl ChainRegistry {
constants::SYS,
ChainInfo {
factory: || Box::new(btc::BTC::new_btc_based(15, "sys", "SYS", "Syscoin")),
supported: true,
supported: false,
},
),
(
Expand Down Expand Up @@ -463,7 +462,7 @@ impl ChainRegistry {
constants::DGB,
ChainInfo {
factory: || Box::new(btc::BTC::new_btc_based(16, "dgb", "DGB", "Digibyte")),
supported: true,
supported: false,
},
),
(
Expand Down Expand Up @@ -704,7 +703,7 @@ impl ChainRegistry {
ids
}

fn create_custom_evm(&self, chain_id: u32, _network_type: u32) -> Option<Box<dyn Chain>> {
fn create_custom_evm(&self, chain_id: u32) -> Option<Box<dyn Chain>> {
Some(Box::new(eth::ETH::new_eth_based(
0,
chain_id,
Expand Down Expand Up @@ -755,6 +754,6 @@ pub fn get_supported_chains() -> Vec<u32> {
ChainRegistry::new().get_supported_chains()
}

pub fn create_custom_evm(chain_id: u32, network_type: u32) -> Option<Box<dyn Chain>> {
ChainRegistry::new().create_custom_evm(chain_id, network_type)
pub fn create_custom_evm(chain_id: u32) -> Option<Box<dyn Chain>> {
ChainRegistry::new().create_custom_evm(chain_id)
}
13 changes: 13 additions & 0 deletions packages/kos/src/chains/substrate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,19 @@ mod test {
let addr = dot.get_address(pbk).unwrap();
assert_eq!(addr, "13KVd4f2a4S5pLp4gTTFezyXdPWx27vQ9vS6xBXJ9yWVd7xo");
}
#[test]
fn test_get_addr1() {
let dot = super::Substrate::new(62, 42, "AVAIL", "Avail");

let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about".to_string();
let path = dot.get_path(1, false);

let seed = dot.mnemonic_to_seed(mnemonic, String::from("")).unwrap();
let pvk = dot.derive(seed, path).unwrap();
let pbk = dot.get_pbk(pvk).unwrap();
let addr = dot.get_address(pbk).unwrap();
assert_eq!(addr, "5DJ8y4CAHnmjt4rdoZpR1wgXnQDnKDksskx7JTphZhMxthiG");
}

#[test]
fn test_sign_raw() {
Expand Down
8 changes: 4 additions & 4 deletions packages/kos/src/crypto/bip32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,10 @@ pub fn derive_sr25519(input_key: &[u8], mut path: String) -> Result<[u8; 64], Bi
.strip_prefix("//")
.ok_or(Bip32Err::PathError)?
.to_string();
path = path
.strip_suffix("///")
.ok_or(Bip32Err::PathError)?
.to_string();

if let Some(stripped) = path.strip_suffix("///") {
path = stripped.to_string();
}

let chaincode_value = u8::from_str(path.as_str()).map_err(|_| Bip32Err::PathError)?;

Expand Down

0 comments on commit 8d1f3a3

Please sign in to comment.