Skip to content

Commit

Permalink
Adding an example for Financial Application! This application uses ck…
Browse files Browse the repository at this point in the history
…ks-engine crate and perform calculated on encrypted financial transactions
  • Loading branch information
santoshkumarpottumuthu committed Nov 26, 2024
1 parent c6f1ede commit 152b872
Show file tree
Hide file tree
Showing 2 changed files with 793 additions and 46 deletions.
138 changes: 92 additions & 46 deletions applications/FinancialExample.rs
Original file line number Diff line number Diff line change
@@ -1,68 +1,114 @@
use ckks_engine::utils::{encode, decode, mod_reduce};
use ckks_engine::utils::{encode, decode};
use ckks_engine::{CKKSEncryptor, CKKSDecryptor, CkksParameters, Polynomial};
use std::error::Error;
use csv::Reader;
use chrono::NaiveDate;
use chrono::Datelike;

fn main() {

fn main() -> Result<(), Box<dyn Error>> {
// Initialize CKKS parameters
let params = CkksParameters::new(4096, 1000000000000007);
let keygen = ckks_engine::KeyGenerator::new(); // No arguments required
let keygen = ckks_engine::KeyGenerator::new();
let (public_key, secret_key) = keygen.generate_keys();

let encryptor = CKKSEncryptor::new(public_key.clone(), params.clone());
let decryptor = CKKSDecryptor::new(secret_key.clone(), params.clone());

const SCALE: f64 = 1e7; // Scaling factor for encoding

// Step 1: Define transactions (plaintext)
let transactions = vec![500.69, -200.0, 300.0]; // Example transaction amounts
let labels = vec!["Deposit: +500", "Withdrawal: -200", "Deposit: +300"]; // Corresponding labels
println!("Current working directory: {:?}", std::env::current_dir()?);

// Step 2: Encrypt transaction amounts
let encrypted_transactions: Vec<Polynomial> = transactions
.iter()
.map(|&value| encode(&[value], SCALE))
.collect();
// File path to the dataset
let file_path = "transactions_2024.csv";


// Specify the year and month to analyze
let year = 2024;
let month = 7; // For July

// Step 1: Read and filter dataset
let (filtered_amounts, filtered_types) = read_and_filter_csv(file_path, year, month)?;

// Step 3: Encrypt transaction labels
let encrypted_labels: Vec<Polynomial> = labels
// Step 2: Encrypt amounts
let encrypted_transactions: Vec<Polynomial> = filtered_amounts
.iter()
.map(|label| {
// Encode the label string as bytes and then encode as a polynomial
let bytes = label.as_bytes();
let float_vals: Vec<f64> = bytes.iter().map(|&b| b as f64).collect();
encode(&float_vals, SCALE)
})
.map(|&amount| encryptor.encrypt_value(amount)) // Encrypt directly using `f64`
.collect();

// Step 4: Compute the total balance using homomorphic addition
let total_balance_encrypted = encrypted_transactions
.iter()
.cloned()
.reduce(|acc, value| encryptor.homomorphic_add(&acc, &value))
.unwrap();

// Step 5: Round the total balance for reporting
let rounded_balance_encrypted = encryptor.homomorphic_round(&total_balance_encrypted);
// Step 3: Calculate total Debit and Credit sums
let mut total_debit_encrypted = encode(&[0.0], SCALE);
let mut total_credit_encrypted = encode(&[0.0], SCALE);

// Step 6: Concatenate encrypted labels
let concatenated_labels_encrypted = encrypted_labels
.iter()
.cloned()
.reduce(|acc, label| encryptor.concatenate_encrypted_strings(&acc, &label))
.unwrap();
for (encrypted_amount, transaction_type) in encrypted_transactions.iter().zip(filtered_types.iter()) {
if transaction_type == "Debit" {
total_debit_encrypted = encryptor.homomorphic_add(&total_debit_encrypted, encrypted_amount);
} else if transaction_type == "Credit" {
total_credit_encrypted = encryptor.homomorphic_add(&total_credit_encrypted, encrypted_amount);
}
}

// Step 7: Decrypt and decode results
let total_balance = decode(&total_balance_encrypted, SCALE);
let rounded_balance = decode(&rounded_balance_encrypted, SCALE);
// Step 4: Decrypt results
let total_debit: Vec<f64> = decryptor.decrypt(&total_debit_encrypted); // Decrypt
let total_credit: Vec<f64> = decryptor.decrypt(&total_credit_encrypted); // Decrypt

// Decode concatenated labels back into plaintext
let concatenated_labels_plaintext: String = concatenated_labels_encrypted
.coeffs
.iter()
.map(|&c| (c as u8) as char)
.collect();
// Step 5: Count transactions
let debit_count = filtered_types.iter().filter(|&t| t == "Debit").count();
let credit_count = filtered_types.iter().filter(|&t| t == "Credit").count();

// Step 6: Print results
println!("Transaction Summary for {}/{}:", month, year);
println!("Total Debit Transactions: {}, Sum: {:?}", debit_count, total_debit);
println!("Total Credit Transactions: {}, Sum: {:?}", credit_count, total_credit);

Ok(())
}

// Function to read and filter CSV data for a given year and month
// fn read_and_filter_csv(file_path: &str, year: i32, month: u32) -> Result<(Vec<f64>, Vec<String>), Box<dyn Error>> {
// let mut reader = Reader::from_path(file_path)?;
// let mut filtered_amounts = Vec::new();
// let mut filtered_types = Vec::new();

// for result in reader.records() {
// let record = result?;
// let date = NaiveDate::parse_from_str(&record[0], "%d/%m/%Y")?;
// let transaction_type = record[1].to_string();
// let amount: f64 = record[2].parse()?;

// if date.year() == year && date.month() == month {
// filtered_amounts.push(amount);
// filtered_types.push(transaction_type);
// }
// }

// Ok((filtered_amounts, filtered_types))
// }


fn read_and_filter_csv(file_path: &str, year: i32, month: u32) -> Result<(Vec<f64>, Vec<String>), Box<dyn Error>> {
let mut reader = Reader::from_path(file_path)?;
let mut filtered_amounts = Vec::new();
let mut filtered_types = Vec::new();

for result in reader.records() {
let record = result?;
println!("Processing record: {:?}", record); // Debug statement

// Corrected date format
if let (Ok(date), Ok(amount)) = (
NaiveDate::parse_from_str(&record[0], "%Y-%m-%d"),
record[2].parse::<f64>(),
) {
if date.year() == year && date.month() == month {
filtered_amounts.push(amount);
filtered_types.push(record[1].to_string());
}
} else {
eprintln!("Skipping invalid row: {:?}", record); // Log invalid rows
}
}

// Print the results
println!("Total Balance: {:?}", total_balance);
println!("Rounded Balance: {:?}", rounded_balance);
println!("Transaction Labels: {:?}", concatenated_labels_plaintext);
Ok((filtered_amounts, filtered_types))
}
Loading

0 comments on commit 152b872

Please sign in to comment.