ot.rs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. // We really want points to be capital letters and scalars to be
  2. // lowercase letters
  3. #![allow(non_snake_case)]
  4. // Oblivious transfer
  5. use subtle::Choice;
  6. use subtle::ConditionallySelectable;
  7. use aes::Block;
  8. use rand::RngCore;
  9. use sha2::Digest;
  10. use sha2::Sha256;
  11. use sha2::Sha512;
  12. use curve25519_dalek::constants as dalek_constants;
  13. use curve25519_dalek::ristretto::CompressedRistretto;
  14. use curve25519_dalek::ristretto::RistrettoBasepointTable;
  15. use curve25519_dalek::ristretto::RistrettoPoint;
  16. use curve25519_dalek::scalar::Scalar;
  17. use lazy_static::lazy_static;
  18. // Generators of the Ristretto group (the standard B and another one C,
  19. // for which the DL relationship is unknown), and their precomputed
  20. // multiplication tables. Used for the Oblivious Transfer protocol
  21. lazy_static! {
  22. pub static ref OT_B: RistrettoPoint = dalek_constants::RISTRETTO_BASEPOINT_POINT;
  23. pub static ref OT_C: RistrettoPoint =
  24. RistrettoPoint::hash_from_bytes::<Sha512>(b"OT Generator C");
  25. pub static ref OT_B_TABLE: RistrettoBasepointTable = dalek_constants::RISTRETTO_BASEPOINT_TABLE;
  26. pub static ref OT_C_TABLE: RistrettoBasepointTable = RistrettoBasepointTable::create(&OT_C);
  27. }
  28. // 1-out-of-2 Oblivious Transfer (OT)
  29. fn ot12_request(sel: Choice) -> ((Choice, Scalar), [u8; 32]) {
  30. let Btable: &RistrettoBasepointTable = &OT_B_TABLE;
  31. let C: &RistrettoPoint = &OT_C;
  32. let mut rng = rand07::thread_rng();
  33. let x = Scalar::random(&mut rng);
  34. let xB = &x * Btable;
  35. let CmxB = C - xB;
  36. let P = RistrettoPoint::conditional_select(&xB, &CmxB, sel);
  37. ((sel, x), P.compress().to_bytes())
  38. }
  39. fn ot12_serve(query: &[u8; 32], m0: &[u8; 16], m1: &[u8; 16]) -> [u8; 64] {
  40. let Btable: &RistrettoBasepointTable = &OT_B_TABLE;
  41. let Ctable: &RistrettoBasepointTable = &OT_C_TABLE;
  42. let mut rng = rand07::thread_rng();
  43. let y = Scalar::random(&mut rng);
  44. let yB = &y * Btable;
  45. let yC = &y * Ctable;
  46. let P = CompressedRistretto::from_slice(query).decompress().unwrap();
  47. let yP0 = y * P;
  48. let yP1 = yC - yP0;
  49. let mut HyP0 = Sha256::digest(yP0.compress().as_bytes());
  50. for i in 0..16 {
  51. HyP0[i] ^= m0[i];
  52. }
  53. let mut HyP1 = Sha256::digest(yP1.compress().as_bytes());
  54. for i in 0..16 {
  55. HyP1[i] ^= m1[i];
  56. }
  57. let mut ret = [0u8; 64];
  58. ret[0..32].copy_from_slice(yB.compress().as_bytes());
  59. ret[32..48].copy_from_slice(&HyP0[0..16]);
  60. ret[48..64].copy_from_slice(&HyP1[0..16]);
  61. ret
  62. }
  63. fn ot12_receive(state: (Choice, Scalar), response: &[u8; 64]) -> [u8; 16] {
  64. let yB = CompressedRistretto::from_slice(&response[0..32])
  65. .decompress()
  66. .unwrap();
  67. let yP = state.1 * yB;
  68. let mut HyP = Sha256::digest(yP.compress().as_bytes());
  69. for i in 0..16 {
  70. HyP[i] ^= u8::conditional_select(&response[32 + i], &response[48 + i], state.0);
  71. }
  72. HyP[0..16].try_into().unwrap()
  73. }
  74. // Obliviously fetch the key for element q of the database (which has
  75. // 2^r elements total). Each bit of q is used in a 1-out-of-2 OT to get
  76. // one of the keys in each of the r pairs of keys on the server side.
  77. // The resulting r keys are XORed together.
  78. pub fn otkey_init() {
  79. // Resolve the lazy statics
  80. let _B: &RistrettoPoint = &OT_B;
  81. let _Btable: &RistrettoBasepointTable = &OT_B_TABLE;
  82. let _C: &RistrettoPoint = &OT_C;
  83. let _Ctable: &RistrettoBasepointTable = &OT_C_TABLE;
  84. }
  85. pub fn otkey_request(q: usize, r: usize) -> (Vec<(Choice, Scalar)>, Vec<[u8; 32]>) {
  86. let mut state: Vec<(Choice, Scalar)> = Vec::with_capacity(r);
  87. let mut query: Vec<[u8; 32]> = Vec::with_capacity(r);
  88. for i in 0..r {
  89. let bit = ((q >> i) & 1) as u8;
  90. let (si, qi) = ot12_request(bit.into());
  91. state.push(si);
  92. query.push(qi);
  93. }
  94. (state, query)
  95. }
  96. pub fn otkey_serve(query: Vec<[u8; 32]>, keys: &Vec<[u8; 16]>) -> Vec<[u8; 64]> {
  97. let r = query.len();
  98. assert!(keys.len() == 2 * r);
  99. let mut response: Vec<[u8; 64]> = Vec::with_capacity(r);
  100. for i in 0..r {
  101. response.push(ot12_serve(&query[i], &keys[2 * i], &keys[2 * i + 1]));
  102. }
  103. response
  104. }
  105. // XOR a 16-byte slice into a Block (which will be used as an AES key)
  106. pub fn xor16(outar: &mut Block, inar: &[u8; 16]) {
  107. for i in 0..16 {
  108. outar[i] ^= inar[i];
  109. }
  110. }
  111. pub fn otkey_receive(state: Vec<(Choice, Scalar)>, response: &Vec<[u8; 64]>) -> Block {
  112. let r = state.len();
  113. assert!(response.len() == r);
  114. let mut key = Block::from([0u8; 16]);
  115. for i in 0..r {
  116. xor16(&mut key, &ot12_receive(state[i], &response[i]));
  117. }
  118. key
  119. }
  120. // Generate the keys for encrypting the database
  121. pub fn gen_db_enc_keys(r: usize) -> Vec<[u8; 16]> {
  122. let mut keys: Vec<[u8; 16]> = Vec::new();
  123. let mut rng = rand::thread_rng();
  124. for _ in 0..2 * r {
  125. let mut k: [u8; 16] = [0; 16];
  126. rng.fill_bytes(&mut k);
  127. keys.push(k);
  128. }
  129. keys
  130. }