lib.rs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. mod utils;
  2. use rand::{rngs::ThreadRng, thread_rng};
  3. use spiral_rs::{client::*, discrete_gaussian::*, params::*, util::*};
  4. use wasm_bindgen::prelude::*;
  5. const UUID_V4_LEN: usize = 36;
  6. // console_log! macro
  7. // #[wasm_bindgen]
  8. // extern "C" {
  9. // #[wasm_bindgen(js_namespace = console)]
  10. // fn log(s: &str);
  11. // }
  12. // macro_rules! console_log {
  13. // ($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
  14. // }
  15. // Container class for a static lifetime Client
  16. // Avoids a lifetime in the return signature of bound Rust functions
  17. #[wasm_bindgen]
  18. pub struct WrappedClient {
  19. client: Client<'static, ThreadRng>,
  20. }
  21. // Unsafe global with a static lifetime
  22. // Accessed unsafely only once, at load / setup
  23. static mut PARAMS: Params = get_empty_params();
  24. static mut RNG: Option<ThreadRng> = None;
  25. // Very simply test to ensure random generation is not obviously biased.
  26. fn dg_seems_okay() {
  27. let params = get_test_params();
  28. let mut rng = thread_rng();
  29. let mut dg = DiscreteGaussian::init(&params, &mut rng);
  30. let mut v = Vec::new();
  31. let trials = 10000;
  32. let mut sum = 0;
  33. for _ in 0..trials {
  34. let val = dg.sample();
  35. v.push(val);
  36. sum += val;
  37. }
  38. let mean = sum as f64 / trials as f64;
  39. let std_dev = params.noise_width / f64::sqrt(2f64 * std::f64::consts::PI);
  40. let std_dev_of_mean = std_dev / f64::sqrt(trials as f64);
  41. assert!(f64::abs(mean) < std_dev_of_mean * 5f64);
  42. }
  43. // Initializes a client; can optionally take in a set of parameters
  44. #[wasm_bindgen]
  45. pub fn initialize(json_params: Option<String>) -> WrappedClient {
  46. dg_seems_okay();
  47. // spiral_rs::ntt::test::ntt_correct();
  48. let cfg = r#"
  49. {'n': 2,
  50. 'nu_1': 10,
  51. 'nu_2': 6,
  52. 'p': 512,
  53. 'q_prime_bits': 21,
  54. 's_e': 85.83255142749422,
  55. 't_GSW': 10,
  56. 't_conv': 4,
  57. 't_exp': 16,
  58. 't_exp_right': 56,
  59. 'instances': 11,
  60. 'db_item_size': 100000 }
  61. "#;
  62. let mut cfg = cfg.replace("'", "\"");
  63. if json_params.is_some() {
  64. cfg = json_params.unwrap();
  65. }
  66. let client;
  67. // this minimal unsafe operation is need to initialize state
  68. unsafe {
  69. PARAMS = params_from_json(&cfg);
  70. RNG = Some(thread_rng());
  71. client = Client::init(&PARAMS, RNG.as_mut().unwrap());
  72. }
  73. WrappedClient { client }
  74. }
  75. #[wasm_bindgen]
  76. pub fn generate_public_parameters(c: &mut WrappedClient) -> Box<[u8]> {
  77. c.client.generate_keys().serialize().into_boxed_slice()
  78. }
  79. #[wasm_bindgen]
  80. pub fn generate_query(c: &mut WrappedClient, id: &str, idx_target: usize) -> Box<[u8]> {
  81. assert_eq!(id.len(), UUID_V4_LEN);
  82. let query = c.client.generate_query(idx_target);
  83. let mut query_buf = query.serialize();
  84. let mut full_query_buf = id.as_bytes().to_vec();
  85. full_query_buf.append(&mut query_buf);
  86. full_query_buf.into_boxed_slice()
  87. }
  88. #[wasm_bindgen]
  89. pub fn decode_response(c: &mut WrappedClient, data: Box<[u8]>) -> Box<[u8]> {
  90. c.client.decode_response(&*data).into_boxed_slice()
  91. }