Skip to content

Commit ad86833

Browse files
Merge pull request #24 from cryspen/jonas/wasm-demo
WASM demo
2 parents f620b99 + df13ded commit ad86833

File tree

18 files changed

+1324
-80
lines changed

18 files changed

+1324
-80
lines changed

hacspec-scrambledb/oprf/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ p256.workspace = true
1111
hash-to-curve.workspace = true
1212
elgamal.workspace = true
1313
hacspec_lib.workspace = true
14+
sha256.workspace = true
1415

1516
[dev-dependencies]
1617
serde_json = { version = "1.0.102" }
1718
hex = { version = "0.4.3", features = ["serde"] }
1819
serde = { version = "1.0.180", features = ["derive"] }
1920
log = "0.4.19"
2021
pretty_env_logger = "0.5.0"
22+
rand = "0.8.5"

hacspec-scrambledb/oprf/src/coprf/coprf_online.rs

Lines changed: 192 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,7 @@ use elgamal::Ciphertext;
2020
use hacspec_lib::Randomness;
2121

2222
use super::coprf_setup::{BlindingPublicKey, CoPRFKey};
23-
use crate::{
24-
coprf::coprf_setup::{CoPRFReceiverContext, CoPRFRequesterContext},
25-
p256_sha256, Error,
26-
};
23+
use crate::{coprf::coprf_setup::CoPRFReceiverContext, p256_sha256, Error};
2724
use p256::{NatMod, P256Point};
2825

2926
/// CoPRF Inputs can be arbitrary byte strings.
@@ -100,23 +97,25 @@ pub fn prepare_blind_convert(
10097
/// collusion-resistance.
10198
pub fn blind_convert(
10299
bpk: BlindingPublicKey,
103-
key_i: CoPRFKey,
104-
key_j: CoPRFKey,
100+
key_from: CoPRFKey,
101+
key_to: CoPRFKey,
105102
blind_input: BlindInput,
106103
randomness: &mut Randomness,
107104
) -> Result<BlindOutput, Error> {
108-
let delta = key_j * key_i.inv();
105+
let delta = key_to * key_from.inv();
109106
let ctx_rerandomized = elgamal::rerandomize(bpk, blind_input, randomness)?;
110107
elgamal::scalar_mul_ciphertext(delta, ctx_rerandomized).map_err(|e| e.into())
111108
}
112109

113110
#[cfg(test)]
114111
mod tests {
112+
use crate::coprf::coprf_setup::{derive_key, CoPRFEvaluatorContext};
113+
115114
use super::*;
116115

117116
// =========== Unblinded Operations ===========
118117

119-
/// The clear evaluation of the PRF based on the PRF by Naor, Pinkas, and Reingold:
118+
/// The cleartext evaluation of the PRF based on the PRF by Naor, Pinkas, and Reingold:
120119
///
121120
/// ```text
122121
/// PRF: K x X -> G
@@ -154,13 +153,195 @@ mod tests {
154153
/// is performed by first computing a `delta` scalar from both evaluation
155154
/// keys, which when mulitplied with the output to convert will cancel out
156155
/// the original evaluation key and multiply by the target evaluation key.
157-
pub fn convert(key_i: CoPRFKey, key_j: CoPRFKey, y: Output) -> Result<Output, Error> {
158-
let delta = key_j * key_i.inv();
156+
pub fn convert(
157+
key_origin: CoPRFKey,
158+
key_destination: CoPRFKey,
159+
y: Output,
160+
) -> Result<Output, Error> {
161+
let delta = key_destination * key_origin.inv();
159162
let result = p256::p256_point_mul(delta, y)?;
160163

161164
Ok(result)
162165
}
163166

167+
fn generate_randomness() -> Randomness {
168+
use rand::prelude::*;
169+
170+
let mut rng = rand::thread_rng();
171+
let mut randomness = [0u8; 1000000];
172+
rng.fill_bytes(&mut randomness);
173+
let randomness = Randomness::new(randomness.to_vec());
174+
175+
randomness
176+
}
177+
178+
#[test]
179+
fn self_test_eval_convert() {
180+
let mut randomness = generate_randomness();
181+
182+
let test_context = b"Test";
183+
let test_input = b"TestInput";
184+
let evaluator_context = CoPRFEvaluatorContext::new(&mut randomness).unwrap();
185+
186+
let key_origin1 = derive_key(&evaluator_context, b"1").unwrap();
187+
let key_origin2 = derive_key(&evaluator_context, b"2").unwrap();
188+
let key_destination = derive_key(&evaluator_context, b"3").unwrap();
189+
190+
let y_under_origin1 = evaluate(test_context, key_origin1, test_input).unwrap();
191+
let y_under_origin2 = evaluate(test_context, key_origin2, test_input).unwrap();
192+
193+
let y_under_destination = evaluate(test_context, key_destination, test_input).unwrap();
194+
let converted_y_from_1 = convert(key_origin1, key_destination, y_under_origin1).unwrap();
195+
let converted_y_from_2 = convert(key_origin2, key_destination, y_under_origin2).unwrap();
196+
197+
assert_eq!(converted_y_from_1, converted_y_from_2);
198+
assert_eq!(converted_y_from_1, y_under_destination);
199+
}
200+
201+
#[test]
202+
fn test_blind_evaluate() {
203+
let mut randomness = generate_randomness();
204+
205+
let test_context = b"Test";
206+
let test_input = b"TestInput";
207+
let evaluator_context = CoPRFEvaluatorContext::new(&mut randomness).unwrap();
208+
let receiver_context = CoPRFReceiverContext::new(&mut randomness);
209+
210+
let blind_input = blind(
211+
receiver_context.get_bpk(),
212+
test_input,
213+
test_context.to_vec(),
214+
&mut randomness,
215+
)
216+
.unwrap();
217+
218+
let evaluation_key = derive_key(&evaluator_context, b"TestKey").unwrap();
219+
let blind_result = blind_evaluate(
220+
evaluation_key,
221+
receiver_context.get_bpk(),
222+
blind_input,
223+
&mut randomness,
224+
)
225+
.unwrap();
226+
227+
let unblinded_result = finalize(&receiver_context, blind_result).unwrap();
228+
229+
let expected_result = evaluate(test_context, evaluation_key, test_input).unwrap();
230+
231+
assert_eq!(unblinded_result, expected_result);
232+
}
233+
164234
#[test]
165-
fn test_name() {}
235+
fn blind_convergence() {
236+
let mut randomness = generate_randomness();
237+
238+
let test_context = b"Test";
239+
let test_input = b"TestInput";
240+
let evaluator_context = CoPRFEvaluatorContext::new(&mut randomness).unwrap();
241+
let receiver_context = CoPRFReceiverContext::new(&mut randomness);
242+
243+
let key_origin1 = derive_key(&evaluator_context, b"1").unwrap();
244+
let key_origin2 = derive_key(&evaluator_context, b"2").unwrap();
245+
let key_destination = derive_key(&evaluator_context, b"3").unwrap();
246+
247+
let y_under_destination = evaluate(test_context, key_destination, test_input).unwrap();
248+
let y1 = evaluate(test_context, key_origin1, test_input).unwrap();
249+
let y2 = evaluate(test_context, key_origin2, test_input).unwrap();
250+
251+
let blind1 =
252+
prepare_blind_convert(receiver_context.get_bpk(), y1, &mut randomness).unwrap();
253+
let blind2 =
254+
prepare_blind_convert(receiver_context.get_bpk(), y2, &mut randomness).unwrap();
255+
256+
let blind_result_1 = blind_convert(
257+
receiver_context.get_bpk(),
258+
key_origin1,
259+
key_destination,
260+
blind1,
261+
&mut randomness,
262+
)
263+
.unwrap();
264+
265+
let blind_result_2 = blind_convert(
266+
receiver_context.get_bpk(),
267+
key_origin2,
268+
key_destination,
269+
blind2,
270+
&mut randomness,
271+
)
272+
.unwrap();
273+
274+
let res1 = finalize(&receiver_context, blind_result_1).unwrap();
275+
let res2 = finalize(&receiver_context, blind_result_2).unwrap();
276+
277+
assert_eq!(res1, res2);
278+
assert_eq!(res1, y_under_destination);
279+
}
280+
#[test]
281+
fn test_blind_conversion() {
282+
let mut randomness = generate_randomness();
283+
284+
let test_context = b"Test";
285+
let test_input = b"TestInput";
286+
let evaluator_context = CoPRFEvaluatorContext::new(&mut randomness).unwrap();
287+
let receiver_context = CoPRFReceiverContext::new(&mut randomness);
288+
289+
let blind_input = blind(
290+
receiver_context.get_bpk(),
291+
test_input,
292+
test_context.to_vec(),
293+
&mut randomness,
294+
)
295+
.unwrap();
296+
297+
let key_eval = derive_key(&evaluator_context, b"TestKey").unwrap();
298+
let key_destination = derive_key(&evaluator_context, b"DestinationKey").unwrap();
299+
300+
let blind_result = blind_evaluate(
301+
key_eval,
302+
receiver_context.get_bpk(),
303+
blind_input,
304+
&mut randomness,
305+
)
306+
.unwrap();
307+
308+
let expected_result = evaluate(test_context, key_destination, test_input).unwrap();
309+
310+
// converting the blinded result directly
311+
let blind_converted_result = blind_convert(
312+
receiver_context.get_bpk(),
313+
key_eval,
314+
key_destination,
315+
blind_result,
316+
&mut randomness,
317+
)
318+
.unwrap();
319+
320+
let unblinded_converted_result =
321+
finalize(&receiver_context, blind_converted_result).unwrap();
322+
assert_eq!(expected_result, unblinded_converted_result);
323+
324+
// converting after unblinding and re-blinding
325+
let unblinded_intermediate_result = finalize(&receiver_context, blind_result).unwrap();
326+
327+
let prepped_input = prepare_blind_convert(
328+
receiver_context.get_bpk(),
329+
unblinded_intermediate_result,
330+
&mut randomness,
331+
)
332+
.unwrap();
333+
334+
let blind_converted_result = blind_convert(
335+
receiver_context.get_bpk(),
336+
key_eval,
337+
key_destination,
338+
prepped_input,
339+
&mut randomness,
340+
)
341+
.unwrap();
342+
343+
let unblinded_converted_result =
344+
finalize(&receiver_context, blind_converted_result).unwrap();
345+
assert_eq!(expected_result, unblinded_converted_result);
346+
}
166347
}

hacspec-scrambledb/oprf/src/coprf/coprf_setup.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ pub type BlindingPrivateKey = elgamal::DecryptionKey;
2626
/// `Nsk` bytes of entropy is provided to the key derivation
2727
/// algorithm, where `Nsk` is the number of bytes to represent a valid
2828
/// private key, i.e. a P256 scalar in our case.
29-
pub type CoPRFMasterSecret = [u8; 32];
29+
pub type CoPRFMasterSecret = Vec<u8>;
30+
const COPRF_MSK_BYTES: usize = 32;
3031

3132
/// A coPRF evaluation key is identified by a bytestring of arbitrary
3233
/// length.
@@ -78,8 +79,9 @@ impl CoPRFEvaluatorContext {
7879
/// ### E.1.2. Evaluator Setup
7980
/// The coPRF evaluator holds the master secret as well as any PRF
8081
/// evaluation keys derived from it.
81-
pub fn new(msk: CoPRFMasterSecret) -> Self {
82-
CoPRFEvaluatorContext { msk }
82+
pub fn new(randomness: &mut Randomness) -> Result<Self, Error> {
83+
let msk = randomness.bytes(COPRF_MSK_BYTES)?.to_vec();
84+
Ok(CoPRFEvaluatorContext { msk })
8385
}
8486
}
8587

@@ -120,5 +122,7 @@ pub fn derive_key(context: &CoPRFEvaluatorContext, key_id: &[u8]) -> Result<CoPR
120122
let mut key_material = context.msk.to_vec();
121123
key_material.extend_from_slice(key_id);
122124

123-
p256::random_scalar(&mut Randomness::new(key_material)).map_err(|e| e.into())
125+
let random_bytes = sha256::hash(&key_material);
126+
127+
p256::random_scalar(&mut Randomness::new(random_bytes.to_vec())).map_err(|e| e.into())
124128
}

hacspec-scrambledb/oprf/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub enum Error {
77
CurveError,
88
HashToCurveError,
99
ElgamalError,
10+
RandomnessError,
1011
}
1112

1213
impl From<p256::Error> for Error {
@@ -27,6 +28,12 @@ impl From<elgamal::Error> for Error {
2728
}
2829
}
2930

31+
impl From<hacspec_lib::Error> for Error {
32+
fn from(_value: hacspec_lib::Error) -> Self {
33+
Self::RandomnessError
34+
}
35+
}
36+
3037
// 3. Protocol
3138
pub mod protocol;
3239

hacspec-scrambledb/prp/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ edition = "2021"
77

88
[dependencies]
99
hacspec_lib.workspace = true
10+
11+
[dev-dependencies]
12+
rand = "0.8.5"

hacspec-scrambledb/prp/src/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,19 @@ pub fn prp(input: Block, key: &ChaChaKey) -> Block {
127127
let state = chacha20_init(key, b"scrambledbiv", 1);
128128
chacha20_encrypt_block(state, 2, &input)
129129
}
130+
131+
#[cfg(test)]
132+
mod tests {
133+
use super::*;
134+
use rand::prelude::*;
135+
136+
#[test]
137+
fn test_inversion() {
138+
let mut key = [0u8; 32];
139+
rand::thread_rng().fill_bytes(&mut key);
140+
141+
let block = [1u8; 64];
142+
assert_ne!(block, prp(block, &key));
143+
assert_eq!(block, prp(prp(block, &key), &key));
144+
}
145+
}

hacspec-scrambledb/scrambledb/Cargo.toml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,42 @@ edition = "2021"
55

66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

8+
[lib]
9+
crate-type = ["rlib", "cdylib"]
10+
811
[dependencies]
912
oprf.workspace = true
1013
elgamal.workspace = true
1114
prp.workspace = true
1215
p256.workspace = true
1316
hacspec_lib.workspace = true
17+
hash-to-curve.workspace = true
18+
19+
wasm-bindgen = { version = "0.2.87", optional = true }
20+
rand = { version = "0.8.5", optional = true }
21+
getrandom = { version = "0.2.10", features = ["js"], optional = true }
22+
hex = { version = "0.4.3", optional = true }
23+
24+
25+
gloo-utils = { version = "0.1", features = ["serde"] }
26+
serde_json = "1.0.106"
27+
28+
[dependencies.web-sys]
29+
version = "0.3.4"
30+
optional = true
31+
features = [
32+
'Document',
33+
'Element',
34+
'HtmlElement',
35+
'Node',
36+
'Window',
37+
'console',
38+
'HtmlTableElement',
39+
'HtmlTableRowElement',
40+
]
41+
42+
[features]
43+
wasm = ["wasm-bindgen", "getrandom", "web-sys", "rand", "hex"]
44+
45+
[dev-dependencies]
46+
scrambledb = { path = ".", features = ["rand"] }

hacspec-scrambledb/scrambledb/src/error.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ impl From<oprf::Error> for Error {
1212
oprf::Error::CurveError => Self::CorruptedData,
1313
oprf::Error::HashToCurveError => Self::CorruptedData,
1414
oprf::Error::ElgamalError => Self::RandomnessError,
15+
oprf::Error::RandomnessError => Self::RandomnessError,
1516
}
1617
}
1718
}

0 commit comments

Comments
 (0)