Patient health risk
Some of our most sensitive data is arguably our health-related data.
With FHE, we can protect such ultra sensitive data while still enabling machine learning models to be trained over this data or receiving predictions/analysis of our risks of developing certain diseases.
In this section, we’ll look at a toy application assessing an individual’s chance of developing heart disease based on factors such as their age, weight, alcohol consumption, and existing health conditions.
How will our algorithm work?
Our algorithm aims to assess an individual’s risk of developing cardiac disease by evaluating several health and lifestyle factors. It does this by collecting parameters such as age, weight, alcohol consumption, and existing health conditions and then increments the risk score based on the interplay between these specific parameters. For example, a smoker will have a higher risk of cardiac complications, as will an individual who has a sendentary lifestyle. This score is then returned to the individual in encrypted form, which they can decrypt and use with well known risk charts to make informed decisions about their health.
Normal program (aka no privacy)
Here is the plaintext version of the program (providing no privacy) so that the whoever is performing the risk analysis can view the individual’s age, weight, height, etc.
Let’s start defining our program to assess cardiac risk. First, we define a function to get a bit from a byte array. We will need this function to extract the individual risk factors from a packed representation of the risked factors.
inline bool get_bit(uint8_t flags, unsigned int n) {
return ((flags >> n) & 0x1);
}
Inside our function, we extract the individual risk factors using the get_bit
function defined earlier. In this code we access arguments through pointers; for FHE programs, all inputs are required to be passed in by reference and hence our plaintext functions follow this convention.
With all the characteristics extracted, we can now proceed to calculate the risk score by using the following conditions and sum up the results:
uint8_t cardio(
uint8_t packed_risk_factors,
uint8_t age,
uint8_t hdl,
uint8_t weight,
uint8_t height,
uint8_t physical_activity,
uint8_t glasses_alcohol
) {
bool man = get_bit(packed_risk_factors, 0);
bool smoking = get_bit(packed_risk_factors, 1);
bool diabetic = get_bit(packed_risk_factors, 2);
bool high_bp = get_bit(packed_risk_factors, 3);
uint8_t cond1 = man && (age > 50);
uint8_t cond2 = !man && (age > 60);
uint8_t cond3 = smoking;
uint8_t cond4 = diabetic;
uint8_t cond5 = high_bp;
uint8_t cond6 = hdl < 40;
uint8_t cond7 = weight > ((uint8_t) (height - 90));
uint8_t cond8 = physical_activity < 30;
uint8_t cond9 = man && (glasses_alcohol > 3);
uint8_t cond10 = !man && (glasses_alcohol > 2);
return cond1 + cond2 + cond3 + cond4 + cond5 + cond6 + cond7 + cond8 + cond9 + cond10;
}
Private program walkthrough
To create a private program, we update the function’s signature with [[clang::fhe_program]]
and the inputs/outputs with [[clang::encrypted]]
. And that’s it, we’re done! The program now hides all the individual’s sensitive health data from whoever is performing the risk analysis! Only the patient can view the final result.
[[clang::fhe_program]] uint8_t cardio(
[[clang::encrypted]] uint8_t packed_risk_factors,
[[clang::encrypted]] uint8_t age,
[[clang::encrypted]] uint8_t hdl,
[[clang::encrypted]] uint8_t weight,
[[clang::encrypted]] uint8_t height,
[[clang::encrypted]] uint8_t physical_activity,
[[clang::encrypted]] uint8_t glasses_alcohol
) {
bool man = get_bit(packed_risk_factors, 0);
bool smoking = get_bit(packed_risk_factors, 1);
bool diabetic = get_bit(packed_risk_factors, 2);
bool high_bp = get_bit(packed_risk_factors, 3);
uint8_t cond1 = man && (age > 50);
uint8_t cond2 = !man && (age > 60);
uint8_t cond3 = smoking;
uint8_t cond4 = diabetic;
uint8_t cond5 = high_bp;
uint8_t cond6 = hdl < 40;
uint8_t cond7 = weight > ((uint8_t) (height - 90));
uint8_t cond8 = physical_activity < 30;
uint8_t cond9 = man && (glasses_alcohol > 3);
uint8_t cond10 = !man && (glasses_alcohol > 2);
return cond1 + cond2 + cond3 + cond4 + cond5 + cond6 + cond7 + cond8 + cond9 + cond10;
}
Running the program
If you’d like to run the program, feel free to look at the corresponding code here.
Performance
Running the program takes 0.40 seconds on an AWS c7a.16xlarge machine (64 cores) and 1.41 seconds on an 14 inch M2 Macbook Pro with 10 cores (6 performance, 4 efficiency).
What’s missing?
In a real world application, the data related to risk factors would need to be stored encrypted in an Electronic Health Record (EHR) system to enable more complicated analyses.