5 unstable releases
| 0.3.0 | Mar 9, 2026 |
|---|---|
| 0.2.2 | Mar 9, 2026 |
| 0.2.1 | Mar 8, 2026 |
| 0.2.0 | Mar 6, 2026 |
| 0.1.0 | Feb 27, 2026 |
#63 in #kms
580KB
12K
SLoC
Starknet Client
Starknet RPC client for interacting with TONGO contracts on Starknet.
✅ Implemented Features
Core Infrastructure
- ✅ Starknet RPC provider creation - JSON-RPC client setup
- ✅ Account address derivation - OpenZeppelin account address calculation
- ✅ ElGamal decryption - Decrypt cipher balances from chain
- ✅ Proof generation - Full parity with TypeScript for Fund, Transfer, Rollover, Withdraw
- ✅ Integration test skeleton - Complete flow documentation with TypeScript parity
Key Management
- ✅ BIP-44 key derivation - TONGO coin type 5454 and Starknet coin type 9004
- ✅ Public key derivation - Elliptic curve scalar multiplication
- ✅ Account address calculation - Pedersen hash + Starknet Keccak
Cryptographic Primitives
- ✅ Proof of Exponentiation (PoE) - Schnorr-like proofs for balances
- ✅ Proof of Exponentiation 2 (PoE2) - Okamoto's protocol for rollovers
- ✅ ElGamal encryption - Homomorphic encryption for transfers
- ✅ Fiat-Shamir challenges - Non-interactive proof generation
🚧 To Be Implemented
The following components require integration with the live Starknet network:
- RPC State Querying - Fetch encrypted balances from TONGO contract
- Transaction Signing - Sign and submit transactions using starknet-rust
- Calldata Serialization - Convert Rust proofs to Cairo calldata format
- ERC20 Approve Flow - Token approval before fund operations
- State Verification - Query and decrypt state after transactions
Account Derivation
The crate supports deriving Starknet account contract addresses using the standard contract address calculation formula:
use krusty_kms::{derive_keypair, derive_oz_account_address};
use starknet_types_core::felt::Felt;
// Derive a keypair from mnemonic
let keypair = derive_keypair(mnemonic, index, account_index, None)?;
// Get the public key x-coordinate
let affine = keypair.public_key.to_affine()?;
let public_key_x = affine.x();
// Calculate the account contract address
let class_hash = Felt::from_hex("0x05b4b537eaa2399e3aa99c4e2e0208ebd6c71bc1467938cd52c798c601e43564")?;
let account_address = derive_oz_account_address(&public_key_x, &class_hash, None)?;
Testing
Run the account derivation tests:
cargo test -p krusty-kms-client --test account_derivation
Next Steps
To complete the integration with Starknet:
1. Add TONGO Contract Interactions
Create a TongoClient struct that wraps the starknet provider and provides high-level methods:
pub struct TongoClient {
provider: JsonRpcClient<HttpTransport>,
contract_address: Felt,
}
impl TongoClient {
pub async fn fund(&self, account: &TongoAccount, amount: u128) -> Result<TransactionHash>;
pub async fn transfer(&self, account: &TongoAccount, to: &ProjectivePoint, amount: u128) -> Result<TransactionHash>;
pub async fn rollover(&self, account: &TongoAccount) -> Result<TransactionHash>;
pub async fn withdraw(&self, account: &TongoAccount, to: &Felt, amount: u128) -> Result<TransactionHash>;
pub async fn get_state(&self, public_key: &ProjectivePoint) -> Result<TongoState>;
}
2. Implement Account Signer
Add utilities for signing transactions using derived keys:
use starknet_rust::accounts::{Account, SingleOwnerAccount};
use starknet_rust::signers::{LocalWallet, SigningKey};
pub fn create_signer(
provider: JsonRpcClient<HttpTransport>,
private_key: &Felt,
address: &Felt,
chain_id: Felt,
) -> SingleOwnerAccount<JsonRpcClient<HttpTransport>, LocalWallet> {
let signer = LocalWallet::from(SigningKey::from_secret_scalar(private_key));
SingleOwnerAccount::new(provider, signer, *address, chain_id)
}
3. Add Integration Tests
Create tests that replicate the TypeScript tongo-sepolia.test.ts:
#[tokio::test]
#[ignore] // Requires Sepolia testnet access
async fn test_fund_operation() {
let provider = create_provider(SEPOLIA_RPC_URL);
let tongo_client = TongoClient::new(provider, TONGO_CONTRACT_ADDRESS);
// Derive TONGO keypair
let keypair = derive_keypair(MNEMONIC, 0, 0, None)?;
let account = TongoAccount::from_private_key(keypair.private_key, TONGO_CONTRACT_ADDRESS)?;
// Check initial balance
let state_before = tongo_client.get_state(&account.keypair.public_key).await?;
// Fund operation
let tx_hash = tongo_client.fund(&account, 1).await?;
provider.wait_for_transaction(tx_hash).await?;
// Verify balance increased
let state_after = tongo_client.get_state(&account.keypair.public_key).await?;
assert_eq!(state_after.balance, state_before.balance + 1);
}
OpenZeppelin Account Class Hash
The tests use the OpenZeppelin account class hash deployed on Sepolia:
0x05b4b537eaa2399e3aa99c4e2e0208ebd6c71bc1467938cd52c798c601e43564
This is the same class hash used in the TypeScript reference implementation.
TONGO Contract Address (Sepolia)
0x00b4cca30f0f641e01140c1c388f55641f1c3fe5515484e622b6cb91d8cee585
Related Crates
krusty-kms: Key derivation and account address calculationkrusty-kms-sdk: TONGO operation proof generationkrusty-kms-crypto: Cryptographic primitives (PoE, PoE2, ElGamal)
Dependencies
~21–36MB
~542K SLoC