Updated to t-variant and new protocol

This commit is contained in:
Fritz Schmid 2023-03-06 19:10:03 +01:00
parent a11a92d3d7
commit 6fb0dcd867
10 changed files with 514 additions and 337 deletions

2
.cargo/config.toml Normal file
View File

@ -0,0 +1,2 @@
[build]
rustflags = ["-C", "target-cpu=native"]

2
.gitignore vendored
View File

@ -1,2 +1,4 @@
target
.code
req
req1

2
Cargo.lock generated
View File

@ -977,6 +977,7 @@ dependencies = [
"bit-vec",
"bitvec 0.22.0",
"bls12_381",
"futures",
"group",
"lazy_static",
"rand",
@ -1550,6 +1551,7 @@ version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff"
dependencies = [
"base64",
"serde",
"serde_with_macros",
]

View File

@ -23,7 +23,8 @@ time = "*"
rocket = "0.5.0-rc.1"
rayon = "*"
base64 = "*"
serde_with = "*"
serde_with = { version = "*", features = ["base64","default"] }
futures = "*"
reqwest ={ version = "*", features = ["json"]}
rocket_okapi = { version = "0.8.0-alpha-1", features = ["swagger", "rapidoc"] }

View File

@ -1,7 +1,7 @@
use bls12_381::*;
use crate::utils;
use crate::proofs;
use std::collections::HashMap;
use crate::shamir;
use std::time::Instant;
use rayon::prelude::*;
use serde::{Deserialize, Serialize};
@ -12,25 +12,22 @@ use crate::serializers;
use serde_with::serde_as;
#[serde_as]
#[derive(Deserialize, Serialize,JsonSchema)]
#[derive(Deserialize, Serialize,JsonSchema,Clone,Copy)]
pub struct PublicParameters{
#[serde_as(as = "Vec<serializers::SerializeScalar>")]
#[schemars(with = "Vec::<String>")]
pub space: Vec<Scalar>,
pub k: usize,
#[serde_as(as = "serializers::SerializeGt")]
#[schemars(with = "String")]
pub gt_gen: Gt,
#[serde_as(as = "Vec<serializers::SerializeGt>")]
#[schemars(with = "Vec::<String>")]
pub ratelimiter_public_keys: Vec<Gt>
#[serde_as(as = "serializers::SerializeGt")]
#[schemars(with = "String")]
pub ratelimiter_public_key: Gt
}
pub struct ServerState{
r: Scalar,
pub n: Scalar,
p: G2Projective
p: G2Projective,
pw: String,
}
impl ServerState {
@ -40,9 +37,9 @@ impl ServerState {
let username = username.to_owned();
let to_be_hashed = username + password;
let h2 = G2Affine::generator() * utils::hash_string_to_scalar(to_be_hashed);
let p = h2 * r;
ServerState{r,n,p}
let tempr = utils::hash_string_to_scalar(to_be_hashed);
let p = G2Affine::generator() * tempr * r;
ServerState{r,n,p,pw: password.to_owned()}
}
fn from_nonce(username: &String, password: &String, nonce: &Scalar) -> ServerState{
@ -50,14 +47,15 @@ impl ServerState {
let username = username.to_owned();
let to_be_hashed = username + password;
let h2 = G2Affine::generator() * utils::hash_string_to_scalar(to_be_hashed);
let p = h2 * r;
ServerState{r,n: nonce.clone(),p}
let tempr = utils::hash_string_to_scalar(to_be_hashed);
let p = G2Affine::generator() * tempr * r;
ServerState{r,n: nonce.clone(),p,pw: password.to_owned()}
}
}
#[serde_as]
#[derive(Serialize, Deserialize, JsonSchema)]
#[derive(Serialize, Deserialize, JsonSchema,Clone,Copy,Debug)]
pub struct RatelimiterRequest{
#[serde_as(as = "serializers::SerializeScalar")]
#[schemars(with = "String")]
@ -70,18 +68,36 @@ pub struct RatelimiterRequest{
#[serde_as]
#[derive(Serialize, Deserialize, JsonSchema)]
pub struct RatelimiterResponse{
elements: Vec<RatelimiterResponseElement>
proof: proofs::SameDLogProof,
#[serde_as(as = "serializers::SerializeGt")]
#[schemars(with = "String")]
u: Gt,
}
#[serde_as]
#[derive(Serialize, Deserialize, JsonSchema)]
pub struct EncryptedMessage{
#[serde_as(as = "serde_with::base64::Base64")]
#[schemars(with = "String")]
pub c1: [u8; 64],
#[serde_as(as = "serde_with::base64::Base64")]
#[schemars(with = "String")]
pub c2: [u8; 64],
#[serde_as(as = "serializers::SerializeScalar")]
#[schemars(with = "String")]
pub n: Scalar,
}
#[serde_as]
#[derive(Serialize, Deserialize, JsonSchema)]
pub struct RatelimiterResponseElement{
proof: proofs::SameDLogProof,
#[serde_as(as = "serializers::SerializeGt")]
pub struct SetKeyHelper{
#[serde_as(as = "serializers::SerializeScalar")]
#[schemars(with = "String")]
p: Gt
pub key: Scalar,
}
pub fn phe_init(username: &String, password: &String) -> (ServerState,RatelimiterRequest){
let ss = ServerState::new(username,password);
let rr = RatelimiterRequest{n:ss.n,p:ss.p};
@ -96,71 +112,184 @@ pub fn phe_init_decrypt(username: &String, password: &String,n: &Scalar) -> (Ser
return (ss,rr)
}
pub fn phe_ratelimiter(private_keys: &Vec<Scalar>, request: &RatelimiterRequest,pp: &PublicParameters) -> RatelimiterResponse {
let u = pairing(&G1Affine::from(G1Affine::generator() * request.n) , &G2Affine::from(request.p));
let results = private_keys.par_iter().zip(&pp.ratelimiter_public_keys).map(|(private_key,public_key)| {
let value = u*private_key;
let proof = proofs::SameDLogProofPublic{g:pp.gt_gen,h:u,y1:*public_key,y2:value}.proof(&private_key);
RatelimiterResponseElement{proof,p:value}
}).collect::<Vec<_>>();
RatelimiterResponse{elements:results}
pub fn phe_ratelimiter(private_key: &Scalar, request: &RatelimiterRequest,pp: &PublicParameters) -> RatelimiterResponse {
let n = request.n;
let u = pairing(&G1Affine::from(G1Affine::generator() * n) , &G2Affine::from(request.p));
let value = u*private_key;
let proof = proofs::SameDLogProofPublic{g:pp.gt_gen,h:u,y1:pp.ratelimiter_public_key,y2:value}.proof(&private_key);
RatelimiterResponse{proof,u:value}
}
pub fn phe_enc_finish(msg: &Vec<u8>,pp: &PublicParameters,response: &RatelimiterResponse,ss:&ServerState) -> Result<Vec<Gt>,String>{
let split_message = utils::split_message_into_space(msg,&pp.space,pp.k);
assert_eq!(split_message.len(),pp.ratelimiter_public_keys.len(),"key length {} and msglength {} do not match",pp.ratelimiter_public_keys.len(),split_message.len());
let u = pairing(&G1Affine::from(G1Affine::generator() * ss.n) , &G2Affine::from(ss.p));
pub fn phe_enc_finish_t(msg: &Vec<u8>,pp: &Vec<PublicParameters>,response: &Vec<RatelimiterResponse>,ss:&ServerState,n: i64) -> Result<EncryptedMessage,String>{
let h = pairing(&G1Affine::from(G1Affine::generator() * ss.n), &G2Affine::from(ss.p));
let r_inv = ss.r.invert().unwrap();
let values = pp.ratelimiter_public_keys.par_iter().zip(&response.elements).zip(&split_message).map(|((public_key,x),msg)|{
if !x.proof.verify(&proofs::SameDLogProofPublic{g:pp.gt_gen,h:u,y1:*public_key,y2:x.p}){
Err("Invalid Proof".to_string())
}else{
Ok(x.p * r_inv * msg)
}
}).collect::<Result<Vec<_>,String>>();
values
let proofok = response.par_iter().zip(pp).map(|(r,p)| r.proof.verify(&proofs::SameDLogProofPublic{g:p.gt_gen,h:h ,y1:p.ratelimiter_public_key,y2:r.u})).collect::<Vec<bool>>().iter().all(|x| *x);
if !proofok{
return Err("Proofs not ok".to_string());
}
let split_message = utils::vec_to_msg(msg);
let uvec = response.iter().map(|r| r.u).collect::<Vec<Gt>>();
let u = shamir::recover_shares(&uvec, n);
let ut = u * r_inv;
let c1 = utils::hash_data( // H3([u]t 1/r, pw, id, ns, nr) + M //id is username, ns is nonce
&[
&&"3".to_string(),
&&ut,
&&ss.pw,
&&ss.n,
//&response.iter().map(|r| &r.n).collect::<Vec<&Scalar>>(),
]);
let c2 =// H3([u]t 1/r, M, pw, id, ns, nr)
utils::hash_data(
&[
&&"3".to_string(),
&&ut,
&&split_message,
&&ss.pw,
&&ss.n,
//&response.iter().map(|r| &r.n).collect::<Vec<&Scalar>>(),
],
);
let c1 = utils::xor(&c1, &split_message);
Ok(EncryptedMessage{c1,c2,n:ss.n})
}
pub fn phe_dec_finish_simple(ciphertext: &Vec<Gt>,pp: &PublicParameters,response: &RatelimiterResponse,ss:&ServerState) -> Result<Vec<u8>,String>{
pub fn phe_dec_finish_t(ciphertext: &EncryptedMessage,pp: &Vec<PublicParameters>,response: &Vec<RatelimiterResponse>,ss:&ServerState,n: i64) -> Result<Vec<u8>,String>{
let h = pairing(&G1Affine::from(G1Affine::generator() * ss.n), &G2Affine::from(ss.p));
let r_inv = ss.r.invert().unwrap();
let proofok = response.par_iter().zip(pp).map(|(r,p)| r.proof.verify(&proofs::SameDLogProofPublic{g:p.gt_gen,h:h,y1:p.ratelimiter_public_key,y2:r.u})).collect::<Vec<bool>>().iter().all(|x| *x);
if !proofok{
return Err("Proofs not ok".to_string());
}
let uvec = response.iter().map(|r| r.u).collect::<Vec<Gt>>();
let u = shamir::recover_shares(&uvec, n);
let ut = u * r_inv;
let c1 = utils::hash_data( // H3([u]t 1/r, pw, id, ns, nr) + M //id is username, ns is nonce
&[
&&"3".to_string(),
&&ut,
&&ss.pw,
&&ss.n,
//&response.iter().map(|r| &r.n).collect::<Vec<&Scalar>>(),
]);
let c1 = utils::xor(&c1, &ciphertext.c1);
let c2 =// H3([u]t 1/r, M, pw, id, ns, nr)
utils::hash_data(
&[
&&"3".to_string(),
&&ut,
&&c1,
&&ss.pw,
&&ss.n,
//&response.iter().map(|r| &r.n).collect::<Vec<&Scalar>>(),
],
);
if c2 == ciphertext.c2{
Ok(c1.to_vec())
}else{
Err("Invalid ciphertext".to_string())
}
}
pub fn phe_enc_finish(msg: &Vec<u8>,pp: &PublicParameters,response: &RatelimiterResponse,ss:&ServerState) -> Result<EncryptedMessage,String>{
let split_message = utils::vec_to_msg(msg);
let u = pairing(&G1Affine::from(G1Affine::generator() * ss.n) , &G2Affine::from(ss.p));
let r_inv = ss.r.invert().unwrap();
let values = pp.ratelimiter_public_keys.par_iter().zip(&response.elements).map(|(public_key,x)|{
if !x.proof.verify(&proofs::SameDLogProofPublic{g:pp.gt_gen,h:u,y1:*public_key,y2:x.p}){
Err("Invalid Proof".to_string())
}else{
Ok(x.p * r_inv)
}
}).collect::<Result<Vec<_>,String>>()?;
return Ok(utils::solve_dlog(&values, ciphertext, &pp.space, pp.k)?);
if !response.proof.verify(&proofs::SameDLogProofPublic{g:pp.gt_gen,h:u,y1:pp.ratelimiter_public_key,y2:response.u}){
Err("Invalid Proof ENC".to_string())
}else{
let ut = response.u * r_inv;
let c1 = utils::hash_data( // H3([u]t 1/r, pw, id, ns, nr) + M //id is username, ns is nonce
&[
&&"3".to_string(),
&&ut,
&&ss.pw,
&&ss.n
]
);
let c1 = utils::xor(&c1,&split_message);
let c2 = // H3([u]t 1/r, M, pw, id, ns, nr)
utils::hash_data(
&[
&&"3".to_string(),
&&ut,
&&split_message,
&&ss.pw,
&&ss.n
]
);
Ok(EncryptedMessage{c1,c2,n:ss.n})
}
}
fn phe_dec_finish_preparedspace(pp: &PublicParameters,response: &RatelimiterResponse,ss:&ServerState,preparedspace: &Vec<HashMap<[u8;288],usize>>) -> Result<Vec<u8>,String>{
pub fn phe_dec_finish_simple(ciphertext: &EncryptedMessage,pp: &PublicParameters,response: &RatelimiterResponse,ss:&ServerState) -> Result<Vec<u8>,String>{
let u = pairing(&G1Affine::from(G1Affine::generator() * ss.n) , &G2Affine::from(ss.p));
let r_inv = ss.r.invert().unwrap();
if !response.proof.verify(&proofs::SameDLogProofPublic{g:pp.gt_gen,h:u,y1:pp.ratelimiter_public_key,y2:response.u}){
Err("Invalid Proof".to_string())
}else{
let values = pp.ratelimiter_public_keys.par_iter().zip(&response.elements).map(|(public_key,x)|{
if !x.proof.verify(&proofs::SameDLogProofPublic{g:pp.gt_gen,h:u,y1:*public_key,y2:x.p}){
Err("Invalid Proof".to_string())
let ut = response.u * r_inv;
let c1 = utils::hash_data( // H3([u]t 1/r, pw, id, ns, nr) + M //id is username, ns is nonce
&[
&&"3".to_string(),
&&ut,
&&ss.pw,
&&ss.n
]
);
let split_message = utils::xor(&ciphertext.c1,&c1);
let c2 = // H3([u]t 1/r, M, pw, id, ns, nr)
utils::hash_data(
&[
&&"3".to_string(),
&&ut,
&&split_message,
&&ss.pw,
&&ss.n
]
);
if ciphertext.c2 == c2 {
Ok(split_message.to_vec())
}else{
Ok(x.p * r_inv)
Err("Invalid C2".to_string())
}
}).collect::<Result<Vec<_>,String>>()?;
return Ok(utils::find_in_precomputed_space(&values, &pp.space,preparedspace, pp.k));
}
}
#[test]
fn test_core(){
rayon::ThreadPoolBuilder::new().num_threads(1).build_global().unwrap();
test_core_k(32,2);
//rayon::ThreadPoolBuilder::new().num_threads(8).build_global().unwrap();
test_core_k();
//test_core_k(32,4);
//test_core_k(32,8);
}
#[test]
fn t1est_core_test()
{
rayon::ThreadPoolBuilder::new().num_threads(1).build_global().unwrap();
test_core_t(10,10);
}
#[test]
fn test_speed_operations() {
let mut s1 = utils::random_scalar();
@ -238,42 +367,91 @@ fn test_speed_operations() {
println!(" {:.2?} gt exp ",start.elapsed()/1000);
}
fn test_core_t(n:i64,t:i64){
let msg = (0..64).map(|x|(x) as u8).collect::<Vec<_>>();
let generator = pairing(&G1Affine::generator(),&G2Affine::generator());
let realkey = utils::random_scalar();
let rlkeys = shamir::gen_shares_scalar(realkey,n,t);
let pps = rlkeys.iter().map(|x|PublicParameters{
gt_gen: generator,
ratelimiter_public_key: generator*x
}).collect::<Vec<_>>();
fn test_core_k(bytes:usize, k:usize) {
let pp_keys = pps.iter().map(|x|{x.ratelimiter_public_key}).collect::<Vec<_>>();
let keysize = bytes*8/k; //in bytes
let msg = (0..keysize/8*k).map(|x|(255*x/(keysize/8*k-1)) as u8).collect::<Vec<_>>();
let generator = utils::random_gt();
let keys = (0..keysize).map(|_|utils::random_scalar()).collect::<Vec<_>>();
let public_keys = keys.iter().map(|x|generator*x).collect::<Vec<_>>();
let space = utils::prepare_messages_to_space(k);
let pp = PublicParameters{space, ratelimiter_public_keys:public_keys,gt_gen:generator,k};
let pp_key = shamir::recover_shares(&pp_keys, n as i64);
assert_eq!(pp_key,generator*realkey,"Public keys do not match");
let start = Instant::now();
let (ss,request) = phe_init(&"test".to_string(),&"test".to_string());
println!("k: {} {:.2?} phe_init", k,start.elapsed());
println!("{:.2?} phe_init",start.elapsed());
let responses = (0..t as usize).into_par_iter().map(|i|{
let response = phe_ratelimiter(&rlkeys[i],&request,&pps[i]);
response
}).collect::<Vec<_>>();
let start = Instant::now();
let response = phe_ratelimiter(&keys,&request,&pp);
println!("k: {} {:.2?} phe_ratelimiter", k,start.elapsed());
let res = phe_enc_finish_t(&msg,&pps,&responses,&ss,n).unwrap();
println!("{:.2?} phe_enc_finish_t",start.elapsed());
let (ss,request) = phe_init_decrypt(&"test".to_string(),&"test".to_string(),&request.n);
let responses = (0..t as usize).into_par_iter().map(|i|{
let response = phe_ratelimiter(&rlkeys[i],&request,&pps[i]);
response
}).collect::<Vec<_>>();
let start = Instant::now();
let res = phe_dec_finish_t(&res,&pps,&responses,&ss,n);
println!("{:.2?} phe_dec_finish_t",start.elapsed());
assert_eq!(res.unwrap(),msg);
}
fn test_core_k() {
let msg = (0..64).map(|x|(x) as u8).collect::<Vec<_>>();
let generator = utils::random_gt();
let key = utils::random_scalar();
let public_key = generator*key;
let pp = PublicParameters{
gt_gen: generator,
ratelimiter_public_key: public_key
};
let start = Instant::now();
let (ss,request) = phe_init(&"test".to_string(),&"test".to_string());
println!("{:.2?} phe_init",start.elapsed());
let response = phe_ratelimiter(&key,&request,&pp);
let start = Instant::now();
for _i in 0..100{
let response = phe_ratelimiter(&key,&request,&pp);
}
println!("{:.2?} phe_ratelimiter",start.elapsed()/1000);
let ciphertext = phe_enc_finish(&msg,&pp,&response,&ss).unwrap();
println!("k: {} {:.2?} phe_enc_finish", k,start.elapsed());
let start = Instant::now();
for _i in 0..100{
let ciphertext = phe_enc_finish(&msg,&pp,&response,&ss).unwrap();
}
println!("{:.2?} phe_enc_finish",start.elapsed()/1000);
let (ss,request) = phe_init_decrypt(&"test".to_string(),&"test".to_string(),&ciphertext.n);
let response = phe_ratelimiter(&key,&request,&pp);
let expected = phe_dec_finish_simple(&ciphertext,&pp,&response,&ss).unwrap();
println!("k: {} {:.2?} phe_dec_finish_simple", k,start.elapsed());
assert_eq!(expected,msg);
let start = Instant::now();
let prepared_space = ciphertext.iter().map(|x|utils::prepare_messages_to_precomputed_space(&pp.space, x)).collect::<Vec<_>>();
println!("k: {} {:.2?} prepare_messages_to_precomputed_space", k,start.elapsed());
for _i in 0..100{
let expected = phe_dec_finish_simple(&ciphertext,&pp,&response,&ss).unwrap();
}
let start = Instant::now();
let expected = phe_dec_finish_preparedspace(&pp, &response, &ss, &prepared_space).unwrap();
println!("k: {} {:.2?} phe_dec_finish_preparedspace", k,start.elapsed());
println!("{:.2?} phe_dec_finish_simple", start.elapsed()/1000);
assert_eq!(expected,msg);
}

View File

@ -3,40 +3,50 @@
extern crate bls12_381;
extern crate rand;
use std::sync::RwLock;
use bls12_381::pairing;
use bls12_381::G2Affine;
use std::sync::Mutex;
use std::sync::Arc;
use rocket_okapi::settings::UrlObject;
use rocket_okapi::{openapi, openapi_get_routes, rapidoc::*, swagger_ui::*};
use rocket::serde::json::Json;
use rocket::Request;
use ophe::core::{RatelimiterRequest,RatelimiterResponse};
use ophe::core::{RatelimiterRequest,RatelimiterResponse,SetKeyHelper};
use ophe::core;
use ophe::utils;
use rocket::State;
use bls12_381::Scalar;
use bls12_381::G1Affine;
fn make_public_parameters() -> (Vec<Scalar>,core::PublicParameters){
let bytes = 32;
let k = 2;
let keysize = bytes*8/k;
let generator = utils::random_gt();
let keys = (0..keysize).map(|_|utils::random_scalar()).collect::<Vec<_>>();
let public_keys = keys.iter().map(|x|generator*x).collect::<Vec<_>>();
let space = utils::prepare_messages_to_space(k);
fn make_public_parameters(key: Scalar) -> CryptoserviceState{
let generator = pairing(&G1Affine::generator(), &G2Affine::generator());
let public_key = generator * key;
(keys,core::PublicParameters{space, ratelimiter_public_keys:public_keys,gt_gen:generator,k})
let pp = core::PublicParameters{ratelimiter_public_key:public_key,gt_gen:generator};
CryptoserviceState{key,pp}
}
struct CryptoserviceState {
key: Scalar,
pp: core::PublicParameters,
}
type CryptoserviceStatePointer = Arc<RwLock<CryptoserviceState>>;
#[rocket::main]
async fn main() {
let (keys,pp) = make_public_parameters();
let c = make_public_parameters(utils::random_scalar());
let c_p:CryptoserviceStatePointer = Arc::new(RwLock::new(c));
let launch_result = rocket::build()
.manage(pp)
.manage(keys)
.mount("/", openapi_get_routes![phe_help,get_public_parameters])
.manage(c_p)
.mount("/", openapi_get_routes![phe_help,get_public_parameters,set_key])
.mount(
"/swagger-ui/",
make_swagger_ui(&SwaggerUIConfig {
@ -69,16 +79,38 @@ async fn main() {
#[openapi()]
#[post("/phe_help",format = "json", data = "<request>")]
fn phe_help(request: Json<RatelimiterRequest>,pp: &State<core::PublicParameters>,keys: &State<Vec<Scalar>>) -> Json<RatelimiterResponse> {
Json(core::phe_ratelimiter(keys,&request,pp))
fn phe_help(request: Json<RatelimiterRequest>,c_state: &State<CryptoserviceStatePointer>) -> Json<RatelimiterResponse> {
let (key,pp) = {
let c_state = c_state.read().unwrap();
(c_state.key.clone(),c_state.pp.clone())
};
Json(core::phe_ratelimiter(&key,&request,&pp))
}
#[openapi()]
#[get("/get_public_parameters")]
fn get_public_parameters(pp: &State<core::PublicParameters>) -> Json<&core::PublicParameters>{
fn get_public_parameters(c_state: &State<CryptoserviceStatePointer>) -> Json<core::PublicParameters>{
let pp = c_state.read().unwrap().pp.clone();
Json(pp)
}
#[openapi()]
#[post("/set_key",format = "json", data = "<request>")]
fn set_key(request: Json<SetKeyHelper>,c_state: &State<CryptoserviceStatePointer>) -> Json<core::PublicParameters> {
let new_c = make_public_parameters(request.key);
let mut c_state = c_state.write().unwrap();
c_state.key = new_c.key;
c_state.pp = new_c.pp;
Json(new_c.pp)
}
#[catch(422)]
fn serialize_failed(_req: &Request) -> String {
format!("Malformed Request")

View File

@ -1,6 +1,6 @@
#![allow(dead_code)]
mod proofs;
pub mod utils;
mod shamir;
pub mod shamir;
pub mod core;
pub mod serializers;

View File

@ -3,40 +3,99 @@
extern crate bls12_381;
extern crate rand;
use bls12_381::G2Affine;
use bls12_381::pairing;
use bls12_381::G1Affine;
use std::time::Duration;
use crate::core::EncryptedMessage;
use rocket_okapi::settings::UrlObject;
use rocket_okapi::{openapi, openapi_get_routes, rapidoc::*, swagger_ui::*};
use rocket::serde::json::Json;
use rocket::Request;
use ophe::core::{RatelimiterResponse,PublicParameters};
use ophe::core::{PublicParameters,RatelimiterRequest,RatelimiterResponse};
use ophe::core;
use rocket::State;
use serde::{Deserialize, Serialize};
use rocket_okapi::okapi::schemars;
use rocket_okapi::okapi::schemars::JsonSchema;
use bls12_381::Scalar;
use bls12_381::Gt;
use ophe::serializers;
use serde_with::serde_as;
use futures::future::join_all;
use rocket::http::Status;
struct RlState {
pp: PublicParameters,
url: String,
client: reqwest::Client
}
struct OpheState {
pps: Vec<RlState>,
n: i64,
t: i64,
}
#[derive(Serialize,Deserialize,JsonSchema)]
struct EncryptRequest {
username: String,
password: String,
/// # data
/// data to be encrypted
data:String
}
#[serde_as]
#[derive(Serialize, Deserialize, JsonSchema)]
pub struct DecryptRequest{
username: String,
password: String,
ciphertext: EncryptedMessage
}
#[catch(422)]
fn serialize_failed(_req: &Request) -> String {
format!("Malformed Request")
}
#[rocket::main]
async fn main() {
let client = reqwest::Client::new();
let res = client.get("http://localhost:9999/get_public_parameters").send()
.await.map_err(|x|{format!("Cryptoservice not reachable: {}",x)}).unwrap().text().await.unwrap();
let cryptoservice_urls = vec!["http://localhost:9001","http://localhost:9002","http://localhost:9003"];
let n = cryptoservice_urls.len();
let t = n;
let rl_key = ophe::utils::random_scalar();
let rl_public_key = pairing(&G1Affine::generator(), &G2Affine::generator()) * rl_key;
println!("Generated public key: {:?}",rl_public_key);
let keys = ophe::shamir::gen_shares_scalar(rl_key, n as i64,t as i64);
let pps = keys.iter().zip(cryptoservice_urls).map( |(k,url)| async move{
let client = reqwest::ClientBuilder::new().tcp_keepalive(Some(Duration::from_secs(60))).build().unwrap();
let set_key_request = core::SetKeyHelper{key:k.clone()};
let res = client.post(&format!("{}/set_key",url)).json(&set_key_request).send()
.await.map_err(|x|{format!("Cryptoservice not reachable: {}",x)}).unwrap().text().await.unwrap();
let pp: PublicParameters = serde_json::from_str(&res).map_err(|x|{format!("Cryptoservice not reachable: {}",x)}).unwrap();
RlState{pp,url:url.to_string(),client}
}).collect::<Vec<_>>();
let pps = join_all(pps).await;
let pp_keys = pps.iter().map(|x|{x.pp.ratelimiter_public_key}).collect::<Vec<_>>();
let pp_key = ophe::shamir::recover_shares(&pp_keys, n as i64);
assert_eq!(pp_key,rl_public_key,"Public keys do not match");
let o_state = OpheState{pps,n: n as i64,t: t as i64};
let pp: PublicParameters = serde_json::from_str(&res).map_err(|x|{format!("Cryptoservice not reachable: {}",x)}).unwrap();
println!("Received public parameters from crytoservice");
let launch_result = rocket::build().mount("/", openapi_get_routes![make_request,decrypt])
.manage(pp)
let launch_result = rocket::build().mount("/", openapi_get_routes![encrypt,decrypt])
.manage(o_state)
.mount(
"/swagger-ui/",
make_swagger_ui(&SwaggerUIConfig {
@ -61,99 +120,60 @@ async fn main() {
.register("/",catchers![serialize_failed])
.launch()
.await;
match launch_result {
Ok(_) => println!("Rocket shut down gracefully."),
Err(err) => println!("Rocket had an error: {}", err),
};
}
#[derive(Serialize,Deserialize,JsonSchema)]
struct UsernamePw{
username: String,
password: String
}
#[catch(422)]
fn serialize_failed(_req: &Request) -> String {
format!("Malformed Request")
}
#[serde_as]
#[derive(Serialize, Deserialize, JsonSchema)]
pub struct EnrollResponse{
#[serde_as(as = "serializers::SerializeScalar")]
#[schemars(with = "String")]
n: Scalar,
#[serde_as(as = "Vec<serializers::SerializeGt>")]
#[schemars(with = "Vec<String>")]
ciphertext: Vec<Gt>
match launch_result {
Ok(_) => println!("Rocket shut down gracefully."),
Err(err) => println!("Rocket had an error: {}", err),
};
}
#[openapi()]
#[post("/make_request",format = "json", data = "<request>")]
async fn make_request(request: Json<UsernamePw>,pp: &State<core::PublicParameters>) -> Result<Json<EnrollResponse>,(Status, Json<String>)> {
#[post("/encrypt",format = "json", data = "<request>")]
async fn encrypt(request: Json<EncryptRequest>,o_state: &State<OpheState>) -> Result<Json<EncryptedMessage>,(Status, Json<String>)> {
let (ss,request1) = core::phe_init(&request.username,&request.password);
let client = reqwest::Client::new();
let mut msg = request.data.clone().into_bytes();
let res = client.post("http://localhost:9999/phe_help")
.json(&request1)
.send()
.await.map_err(|_x| {(Status::InternalServerError,Json("Cryptoserice unreachable.".to_string()))})?.text().await.map_err(|_x| {(Status::InternalServerError,Json("Cryptoserice unreachable.".to_string()))})?;
let response: RatelimiterResponse = serde_json::from_str(&res).map_err(|_x| {(Status::InternalServerError,Json("Invalid cryptoservice response.".to_string()))})?;
let mut msg = Vec::new();
for _x in 0..32{
msg.push(0u8);
if msg.len() > 64 {
return Err((Status::BadRequest,Json("Data too long.".to_string())))
}
let ciphertext = core::phe_enc_finish(&msg,&pp,&response,&ss).map_err(|x| {(Status::InternalServerError,Json("Decryption failed.".to_string()+&x))})?;
// pad to 64 bytes
msg.resize(64,0);
Ok(Json(EnrollResponse{n:ss.n,ciphertext}))
}
let pps = o_state.pps.iter().map(|x| x.pp).collect::<Vec<_>>();
let responses = get_ratelimiter_reponses(&request1,&o_state.pps).await.map_err(|x| {(Status::InternalServerError,Json("Decryption failed: ".to_string()+&x))})?;
#[serde_as]
#[derive(Serialize, Deserialize, JsonSchema)]
pub struct DecryptRequest{
#[serde_as(as = "serializers::SerializeScalar")]
#[schemars(with = "String")]
n: Scalar,
username: String,
password: String,
#[serde_as(as = "Vec<serializers::SerializeGt>")]
#[schemars(with = "Vec<String>")]
ciphertext: Vec<Gt>
let ciphertext = core::phe_enc_finish_t(&msg,&pps,&responses,&ss,o_state.n).map_err(|x| {(Status::InternalServerError,Json("Decryption failed.".to_string()+&x))})?;
Ok(Json(ciphertext))
}
#[openapi()]
#[post("/decrypt",format = "json", data = "<request>")]
async fn decrypt(request: Json<DecryptRequest>,pp: &State<core::PublicParameters>) -> Result<Json<bool>,(Status, Json<String>)>{
async fn decrypt(request: Json<DecryptRequest>,o_state: &State<OpheState>) -> Result<Json<String>,(Status, Json<String>)> {
let (ss,request1) = core::phe_init_decrypt(&request.username,&request.password,&request.ciphertext.n);
let res = decrypt_err(request,pp).await;
let responses = get_ratelimiter_reponses(&request1,&o_state.pps).await.map_err(|x| {(Status::InternalServerError,Json("Decryption failed: ".to_string()+&x))})?;
res
let pps = o_state.pps.iter().map(|x| x.pp).collect::<Vec<_>>();
let res = core::phe_dec_finish_t(&request.ciphertext,&pps,&responses,&ss,o_state.n).map_err(|x| {(Status::InternalServerError,Json("Decryption failed: ".to_string()+&x))})?;
Ok(Json(String::from_utf8(res).map_err(|_x| {(Status::InternalServerError,Json("Decryption failed. Utf8".to_string()))})?.trim_end_matches(char::from(0)).to_string()))
}
async fn get_ratelimiter_reponses(request: &RatelimiterRequest, urls: &Vec<RlState>) -> Result<Vec<RatelimiterResponse>,String> {
let responses = urls.iter().map(|x| async move {
let res = x.client.post(&format!("{}/phe_help",x.url))
.json(&request)
.send()
.await.map_err(|_x| {format!("Cryptoserice unreachable.")})?.text().await.map_err(|_x| {format!("Cryptoserice unreachable.")})?;
let rs = serde_json::from_str(&res).map_err(|_x| {format!("Invalid cryptoservice response.")})?;
Ok::<_,String>(rs)
});
async fn decrypt_err(request: Json<DecryptRequest>,pp: &State<core::PublicParameters>) -> Result<Json<bool>,(Status, Json<String>)> {
let (ss,request1) = core::phe_init_decrypt(&request.username,&request.password,&request.n);
let client = reqwest::Client::new();
let res = client.post("http://localhost:9999/phe_help")
.json(&request1)
.send()
.await.map_err(|_x| {(Status::InternalServerError,Json("Cryptoserice unreachable.".to_string()))})?.text().await.map_err(|_x| {(Status::InternalServerError,Json("Internal Error.".to_string()))})?;
let response: RatelimiterResponse = serde_json::from_str(&res).map_err(|_x| {(Status::InternalServerError,Json("Invalid cryptoservice response.".to_string()))})?;
let mut msg = Vec::new();
for _x in 0..32{
msg.push(0u8);
}
let expected = core::phe_dec_finish_simple(&request.ciphertext,&pp,&response,&ss).map_err(|x| {(Status::InternalServerError,Json("Decryption failed.".to_string()+&x))})?;
println!("{:?}",expected);
Ok(Json(true))
join_all(responses).await.into_iter().flatten().collect()
}

View File

@ -1,4 +1,5 @@
use bls12_381::*;
use rayon::prelude::*;
use crate::utils;
fn lambda(i: i64, shares: i64) -> (Scalar, bool) {
@ -19,17 +20,15 @@ fn lambda(i: i64, shares: i64) -> (Scalar, bool) {
}
}
fn recover_shares(shares: &Vec<Gt>, n: i64) -> Gt {
let mut target = Gt::identity();
for i in 0..shares.len() {
pub fn recover_shares(shares: &Vec<Gt>, n: i64) -> Gt {
shares.par_iter().enumerate().map(|(i, share)| {
let (l, b) = lambda((i + 1) as i64, n);
let mut temp = shares[i] * l;
let mut temp = share * l;
if b {
temp = -temp
}
target = target + temp;
}
return target;
temp
}).reduce(|| Gt::identity(), |a, b| a + b)
}
fn recover_shares_scalar(shares: &Vec<Scalar>, n: i64) -> Scalar {
@ -61,7 +60,7 @@ fn eval_at_scalar(poly: &Vec<Scalar>, x: i64) -> Scalar {
return y;
}
fn gen_shares(secret: Gt, n: i64, t: i64) -> Vec<Gt> {
pub fn gen_shares(secret: Gt, n: i64, t: i64) -> Vec<Gt> {
assert!(t > 0);
assert!(n >= t);
assert!(t <= n);
@ -77,7 +76,7 @@ fn gen_shares(secret: Gt, n: i64, t: i64) -> Vec<Gt> {
return shares;
}
fn gen_shares_scalar(secret: Scalar, n: i64, t: i64) -> Vec<Scalar> {
pub fn gen_shares_scalar(secret: Scalar, n: i64, t: i64) -> Vec<Scalar> {
assert!(t > 0);
assert!(n >= t);
assert!(t <= n);

View File

@ -4,11 +4,6 @@ use sha2::{Digest, Sha512};
use std::convert::TryInto;
use bls12_381::*;
use rand_core::{OsRng,RngCore};
use std::collections::HashMap;
use rayon::prelude::*;
#[cfg(test)]
use std::time::Instant;
pub fn random_scalar() -> Scalar {
let mut buf = [0u8; 64];
@ -20,6 +15,71 @@ pub fn random_gt() -> Gt{
Gt::random(OsRng)
}
pub trait HashData {
fn hash_data(&self) -> Vec<u8>;
}
impl HashData for &Gt {
fn hash_data(&self) -> Vec<u8> {
self.to_compressed().to_vec()
}
}
impl HashData for &G2Affine {
fn hash_data(&self) -> Vec<u8> {
self.to_compressed().to_vec()
}
}
impl HashData for &G1Affine {
fn hash_data(&self) -> Vec<u8> {
self.to_compressed().to_vec()
}
}
impl HashData for &Scalar {
fn hash_data(&self) -> Vec<u8> {
self.to_bytes().to_vec()
}
}
impl HashData for &String {
fn hash_data(&self) -> Vec<u8> {
self.as_bytes().to_vec()
}
}
impl HashData for &[u8; 64] {
fn hash_data(&self) -> Vec<u8> {
self.to_vec()
}
}
impl HashData for &Vec<&dyn HashData> {
fn hash_data(&self) -> Vec<u8> {
self.iter().map(|x| x.hash_data()).flatten().collect()
}
}
pub fn hash_data(elements: &[&dyn HashData]) -> [u8; 64] {
let buf:[u8; 64];
let mut hasher = Sha512::new();
for x in elements {
hasher.update(x.hash_data());
}
let result = hasher.finalize();
buf = result.as_slice().try_into().expect("Wrong length");
buf
}
pub fn hash_to_scalar(elements: &[&dyn HashData]) -> Scalar {
let buf = hash_data(elements);
Scalar::from_bytes_wide(&buf)
}
pub fn hash_string_to_scalar(element: String) -> Scalar {
let buf:[u8; 64];
let mut hasher = Sha512::new();
@ -44,144 +104,25 @@ pub fn hash_gt_to_scalar(elements: &[&Gt]) -> Scalar {
Scalar::from_bytes_wide(&buf)
}
pub fn prepare_messages_to_space(k: usize) -> Vec<Scalar>{
let mut m = Vec::new();
for _j in 0..1 << k {
//let current_m = Scalar::from_raw([(j + 1) as u64, 0, 0, 0]);
let current_m = random_scalar();
m.push(current_m);
pub fn convert_64_bytes_to_scalar(bytes: &[u8]) -> Result<Scalar, &'static str> {
if bytes.len() != 64 {
return Err("Wrong length");
}
m
let mut buf = [0u8; 64];
buf.copy_from_slice(bytes);
Ok(Scalar::from_bytes_wide(&buf))
}
pub fn prepare_messages_to_precomputed_space(space: &Vec<Scalar>,cipher: &Gt) -> HashMap<[u8;288],usize>{
let mapped = space.par_iter().map(|x|(cipher * x.invert().unwrap()).to_compressed()).collect::<Vec<_>>();
let mut m = HashMap::new();
(0..space.len()).for_each(|i| {
m.insert( mapped[i],i);
});
m
pub fn vec_to_msg(vec: &Vec<u8>) -> [u8; 64] {
let mut buf = [0u8; 64];
buf.copy_from_slice(vec);
buf
}
pub fn find_in_precomputed_space(ciphertext: &Vec<Gt>,_space: &Vec<Scalar>,maps: &Vec<HashMap<[u8;288],usize>>,k:usize) -> Vec<u8>{
let mut prep = Vec::new();
for i in 0..ciphertext.len() {
let index = maps[i][&ciphertext[i].to_compressed()];
for z in 0..k{
prep.push((index>>z)&1);
}
pub fn xor(a: &[u8], b: &[u8]) -> [u8; 64] {
let mut buf = [0u8; 64];
for i in 0..64 {
buf[i] = a[i] ^ b[i];
}
let mut result = Vec::new();
for i in 0..prep.len()/8{
let mut x = 0u8;
for j in 0..8{
x = x + (prep[i*8+j]<<j) as u8;
}
result.push(x as u8);
}
result
}
pub fn split_message_into_space(msg: &Vec<u8>,space: &Vec<Scalar>,k: usize) -> Vec<Scalar> {
let mut preparedmsg = Vec::new();
for i in 0..msg.len() {
for j in 0..8{
preparedmsg.push((msg[i]&(1<<j))>>j);
}
}
let msgsize = preparedmsg.len(); // size of msg in bits
assert!(msgsize%k==0,"Msg must be aligned to space"); //TODO extend msg with size and padding
let steps = msgsize / k;
let mut result = Vec::new();
for i in 0..steps{
let mut x = 0;
for j in 0..k{
x = x + ((preparedmsg[i*k+j] as usize)<<j);
}
result.push(space[x]);
}
result
}
pub fn solve_dlog(target: &Vec<Gt>,ciphertext: &Vec<Gt>,space:& Vec<Scalar>,k: usize) -> Result<Vec<u8>,String>{
let mut prep = Vec::new();
let spacesize = space.len();
let t = target.par_iter().map(|x|space.iter().map(|y|x*y).collect::<Vec<_>>()).collect::<Vec<_>>();
for i in 0..target.len() {
let mut found = false;
for j in 0..spacesize{
if t[i][j] == ciphertext[i]{
found = true;
for z in 0..k{
prep.push((j>>z)&1);
}
}
}
if !found {
return Err("Decryption failed.".to_string())
}
}
let mut result = Vec::new();
for i in 0..prep.len()/8{
let mut x = 0u8;
for j in 0..8{
x = x | (prep[i*8+j]<<j) as u8;
}
result.push(x as u8);
}
Ok(result)
}
#[cfg(test)]
fn test_msg_space_k(k: usize){
let start = Instant::now();
let space= prepare_messages_to_space(k);
println!("k: {} {:.2?} preparing message space", k,start.elapsed());
let msg =[1,2,3,4,255,128,127,151,16,15,127,200,0,13,15,16];
let start = Instant::now();
let split = split_message_into_space(&msg.to_vec(),&space,k);
println!("k: {} {:.2?} spliting into message space", k,start.elapsed());
let gt = random_gt();
let gts = (&split).into_iter().map(|_x|gt).collect::<Vec<Gt>>();
let test = (&split).into_iter().map(|x|gt*x).collect::<Vec<Gt>>();
let start = Instant::now();
let solved = solve_dlog(&gts, &test, &space, k).unwrap();
println!("k: {} {:.2?} solve dlog ", k,start.elapsed());
assert_eq!(msg.to_vec(),solved);
let start = Instant::now();
let prepared_space= (&test).into_iter().map(|x|prepare_messages_to_precomputed_space(&space, x)).collect::<Vec<HashMap<[u8;288],usize>>>();
println!("k: {} {:.2?} precomputing message space", k,start.elapsed());
let start = Instant::now();
let prepared_solved = find_in_precomputed_space(&gts,&space,&prepared_space, k);
println!("k: {} {:.2?} lookup in prepared message space", k,start.elapsed());
assert_eq!(msg.to_vec(),prepared_solved);
}
#[test]
fn test_msg_space() {
//rayon::ThreadPoolBuilder::new().num_threads(1).build_global().unwrap();
test_msg_space_k(2);
test_msg_space_k(4);
test_msg_space_k(8);
//test_msg_space_k(16);
buf
}