Skip to content

Commit ca0a906

Browse files
authored
Merge pull request #4 from ooni/python-bindings
Python bindings
2 parents 074f044 + 8337fbd commit ca0a906

File tree

16 files changed

+903
-101
lines changed

16 files changed

+903
-101
lines changed

Cargo.lock

Lines changed: 383 additions & 81 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
[workspace]
2-
members = [
3-
"ooniauth-core"
4-
]
2+
members = ["ooniauth-core", "ooniauth-py"]
53
resolver = "2"
64

5+
[workspace.dependencies]
6+
rand = "0.8.5"
7+
bincode = "1"
8+
cmz = { version = "0.1.0-rc1" }
9+
serde = "1.0.219"
10+
thiserror = "2.0.12"
11+
712
[patch.crates-io]
813
cmz = { path = "include/cmz" }
914
sigma-compiler-core = { path = "include/sigma-compiler/sigma-compiler-core" }

ooniauth-core/Cargo.toml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@ cmz = "0.1.0-rc1"
88
curve25519-dalek = { version = "4", features = ["digest", "group", "rand_core", "serde"] }
99
ff = "0.13.1"
1010
group = "0.13.0"
11-
rand = "0.8.5"
12-
serde = "1.0.219"
11+
rand = {workspace = true}
12+
serde = {workspace = true}
1313
serde_with = "3.12.0"
14-
bincode = "1"
14+
bincode = {workspace = true}
1515
serde_bytes = "0.11.17"
1616
sha2 = "0.10.9"
1717
chrono = "0.4.41"
1818
time = "0.3.41"
1919
subtle = "2.6.1"
20-
thiserror = "2.0.12"
20+
thiserror = {workspace = true}
2121
syn = "2.0.103"
2222
hex = "0.4"
2323

@@ -28,7 +28,6 @@ criterion = { version = "0.5"}
2828
name = "basic_usage"
2929
test = true
3030

31-
3231
[[bench]]
3332
name = "bench_server"
3433
harness = false

ooniauth-core/examples/basic_usage.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
1111
// 1. Server initialization
1212
let now = Instant::now();
1313
println!("1. Initializing server...");
14-
let mut server = ServerState::new(&mut rng);
14+
let server = ServerState::new(&mut rng);
1515
let public_params = server.public_parameters();
1616
println!(" Key generation completed in {} ms", now.elapsed().as_millis());
1717

@@ -69,7 +69,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
6969
let probe_asn = "AS1234".to_string();
7070

7171
// Set valid age range (credential valid for 30 days)
72-
let today = server.today();
72+
let today = ServerState::today();
7373
let age_range = (today - 30)..(today + 1);
7474
let measurement_count_range = 0..100;
7575

ooniauth-core/src/lib.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ pub mod submit;
1818
#[derive(Debug, Serialize, Deserialize)]
1919
pub struct ServerState {
2020
/// The private key for the main User Auth credential
21-
sk: CMZPrivkey<G>,
22-
pp: CMZPubkey<G>,
21+
sk: SecretKey,
22+
pp: PublicParameters,
2323
}
2424

25+
pub type PublicParameters = CMZPubkey<G>;
26+
pub type SecretKey = CMZPrivkey<G>;
27+
2528
pub struct UserState {
2629
/// The public parameters for the client
27-
pub pp: CMZPubkey<G>,
30+
pub pp: PublicParameters,
2831
pub(crate) credential: Option<UserAuthCredential>,
2932
}
3033

@@ -38,13 +41,25 @@ impl ServerState {
3841
Self { sk, pp }
3942
}
4043

44+
pub fn secret_key_ref(&self) -> &SecretKey {
45+
&self.sk
46+
}
47+
48+
pub fn public_parameters_ref(&self) -> &PublicParameters {
49+
&self.pp
50+
}
51+
52+
pub fn from_creds(sk : SecretKey, pp : PublicParameters) -> Self {
53+
Self {sk, pp}
54+
}
55+
4156
/// Get the public parameters for credential operations
42-
pub fn public_parameters(&self) -> CMZPubkey<G> {
57+
pub fn public_parameters(&self) -> PublicParameters {
4358
self.pp.clone()
4459
}
4560

4661
/// Get today's (real or simulated) date as u32
47-
pub fn today(&self) -> u32 {
62+
pub fn today() -> u32 {
4863
// We will not encounter negative Julian dates (~6700 years ago)
4964
// or ones larger than 32 bits
5065
(time::OffsetDateTime::now_utc().date())

ooniauth-core/src/registration.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ impl UserState {
6464

6565
impl ServerState {
6666
pub fn open_registration(
67-
&mut self,
67+
&self,
6868
req: open_registration::Request,
6969
) -> Result<open_registration::Reply, CMZError> {
7070
let mut rng = rand::thread_rng();
@@ -78,7 +78,7 @@ impl ServerState {
7878
|UAC: &mut UserAuthCredential| {
7979
UAC.set_privkey(&self.sk);
8080
UAC.measurement_count = Some(Scalar::ZERO);
81-
UAC.age = Some(self.today().into());
81+
UAC.age = Some(ServerState::today().into());
8282
Ok(())
8383
},
8484
|_UAC: &UserAuthCredential| Ok(()),
@@ -97,7 +97,7 @@ mod tests {
9797
fn test_registration() {
9898
let rng = &mut rand::thread_rng();
9999
// Initialize group first for gen_keys
100-
let mut server_state = ServerState::new(rng);
100+
let server_state = ServerState::new(rng);
101101
// Note: request() will call cmz_group_init again, but that's okay
102102
let mut user_state = UserState::new(server_state.public_parameters());
103103

ooniauth-core/src/submit.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ impl UserState {
140140

141141
impl ServerState {
142142
pub fn handle_submit(
143-
&mut self,
143+
&self,
144144
rng: &mut (impl RngCore + CryptoRng),
145145
req: submit::Request,
146146
nym: &[u8; 32],
@@ -259,7 +259,7 @@ mod tests {
259259
// Test submit request with valid parameters
260260
let probe_cc = "US".to_string();
261261
let probe_asn = "AS1234".to_string();
262-
let today = server_state.today();
262+
let today = ServerState::today();
263263
let age_range = (today - 30)..(today + 1); // Credential valid for 30 days
264264
let measurement_count_range = 0..100;
265265

ooniauth-py/Cargo.toml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[package]
2+
name = "ooniauth_py"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
[lib]
8+
name = "ooniauth_py"
9+
crate-type = ["cdylib", "rlib"]
10+
11+
[dependencies]
12+
cmz = { workspace = true }
13+
ooniauth-core = {path = "../ooniauth-core"}
14+
pyo3 = "0.26.0"
15+
pyo3-stub-gen = "0.13.1"
16+
rand = {workspace = true}
17+
bincode = {workspace = true}
18+
serde = {workspace = true}
19+
thiserror = {workspace = true}

ooniauth-py/Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
all: stubs
2+
maturin build --release
3+
4+
dev: stubs
5+
maturin develop
6+
7+
dev-release: stubs
8+
maturin develop --release
9+
10+
stubs:
11+
cargo run --bin gen_stubs

ooniauth-py/ooniauth_py.pyi

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# This file is automatically generated by pyo3_stub_gen
2+
# ruff: noqa: E501, F401
3+
4+
import builtins
5+
import typing
6+
7+
class CredentialError(builtins.Exception):
8+
r"""
9+
An authentication error
10+
"""
11+
...
12+
13+
class DeserializationFailed(builtins.Exception):
14+
r"""
15+
An error trying to deserialize a binary buffer
16+
"""
17+
...
18+
19+
class ProtocolError(builtins.Exception):
20+
r"""
21+
An error performing the protocol
22+
"""
23+
...
24+
25+
class ServerState:
26+
def __new__(cls) -> ServerState: ...
27+
@staticmethod
28+
def from_creds(public_parameters:bytes, secret_key:bytes) -> ServerState:
29+
r"""
30+
Create a new server state from binary-serialized public and private keys
31+
This is meant to be used by the server, so it can store the keys somewhere and recreate the
32+
state when needed
33+
"""
34+
def get_secret_key(self) -> bytes: ...
35+
def get_public_parameters(self) -> bytes: ...
36+
def handle_registration_request(self, registration_request:bytes) -> bytes: ...
37+
@staticmethod
38+
def today() -> builtins.int: ...
39+
def handle_submit_request(self, nym:bytes, request:bytes, probe_cc:str, probe_asn:str, age_range:list, measurement_count_range:list) -> bytes: ...
40+
41+
class SubmitRequest:
42+
@property
43+
def nym(self) -> bytes: ...
44+
@property
45+
def request(self) -> bytes: ...
46+
47+
class UserState:
48+
def __new__(cls, public_params:bytes) -> UserState: ...
49+
def get_credential(self) -> typing.Optional[bytes]: ...
50+
def make_registration_request(self) -> bytes: ...
51+
def handle_registration_response(self, resp:bytes) -> None:
52+
r"""
53+
Handle a registration response sent by the server, updating your credentials
54+
55+
Note that this function will only work if you previously called
56+
`make_registration_request`
57+
"""
58+
def make_submit_request(self, probe_cc:str, probe_asn:str, emission_date:builtins.int) -> SubmitRequest: ...
59+
def handle_submit_response(self, response:bytes) -> None:
60+
r"""
61+
Handle a submit response sent by the server, updating your credentials
62+
63+
Note that this function will only work if you previously called
64+
`make_submit_request`
65+
"""
66+

0 commit comments

Comments
 (0)