1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#![allow(dead_code)]

use sinkhole_core::errors::QueryError;

use curve25519_dalek::constants::RISTRETTO_BASEPOINT_TABLE;
use curve25519_dalek::scalar::Scalar;
use elgamal_ristretto::ciphertext::Ciphertext;
use elgamal_ristretto::private::SecretKey;
use elgamal_ristretto::public::PublicKey;

#[derive(Debug, Clone)]
pub struct Query {
    pub encrypted: Vec<Ciphertext>,
    private_key: SecretKey,
    size: usize,
}

impl Query {
    pub fn new(sk: SecretKey, size: usize, index: usize) -> Result<Self, QueryError> {
        if index > size - 1 {
            return Err(QueryError {
                error: "Index of query should not be larger than the size of the query".to_owned(),
            });
        }

        let pk = PublicKey::from(&sk);
        let mut decrypted_query = vec![Scalar::zero(); size - 1];
        decrypted_query.insert(index, Scalar::one());

        let encrypted_query: Vec<Ciphertext> = decrypted_query
            .into_iter()
            .map(|x| pk.encrypt(&(&x * &RISTRETTO_BASEPOINT_TABLE)))
            .collect();

        Ok(Query {
            private_key: sk,
            size,
            encrypted: encrypted_query,
        })
    }
}

impl sinkhole_core::traits::core::Query for Query {
    fn extract_result(&self, result: Ciphertext, k: u32) -> Result<Scalar, QueryError> {
        let point_result = self.private_key.decrypt(&result);
        recover_scalar(point_result, k)
    }
}

fn recover_scalar(
    point: curve25519_dalek::ristretto::RistrettoPoint,
    k: u32,
) -> Result<Scalar, QueryError> {
    for i in 0..2u64.pow(k) {
        if &Scalar::from(i as u64) * &RISTRETTO_BASEPOINT_TABLE == point {
            return Ok(Scalar::from(i as u64));
        }
    }
    Err(QueryError {
        error: format!["Scalar is not in [0..2^{}] range", k],
    })
}