Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Import the non-FFI Rust sources of zkgroup #392

Merged
merged 5 commits into from
Oct 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ members = [
"rust/hsm-enclave",
"rust/poksho",
"rust/protocol",
"rust/zkgroup",
"rust/bridge/ffi",
"rust/bridge/jni",
"rust/bridge/node",
Expand All @@ -14,6 +15,7 @@ default-members = [
"rust/device-transfer",
"rust/poksho",
"rust/protocol",
"rust/zkgroup",
]
resolver = "2" # so that our dev-dependency features don't leak into products

Expand Down
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ Swift, or TypeScript library. The underlying implementations are written in Rust

- libsignal-protocol: Implements the Signal protocol, including the [Double Ratchet algorithm][]. A
replacement for [libsignal-protocol-java][] and [libsignal-metadata-java][].
- signal-crypto: Cryptographic primitives such as AES-GCM-SIV. We use [RustCrypto][]'s where we can
- signal-crypto: Cryptographic primitives such as AES-GCM. We use [RustCrypto][]'s where we can
but sometimes have differing needs.
- device-transfer: Support logic for Signal's device-to-device transfer feature.
- poksho: Utilities for implementing zero-knowledge proofs; stands for "proof-of-knowledge, stateful-hash-object". See [zkgroup][].
- hsm-enclave: A wrapper around the [Noise protocol][] used to securely communicate with server-side [HSMs][].
- zkgroup: Functionality for [zero-knowledge groups][] and related features available in Signal.
- poksho: Utilities for implementing zero-knowledge proofs (such as those used by zkgroup); stands for "proof-of-knowledge, stateful-hash-object".

This repository is used by the Signal client apps ([Android][], [iOS][], and [Desktop][]). Use
outside of Signal is unsupported. In particular, the products of this repository are the Java,
Expand All @@ -20,7 +22,9 @@ layers.
[libsignal-protocol-java]: https://github.com/signalapp/libsignal-protocol-java
[libsignal-metadata-java]: https://github.com/signalapp/libsignal-metadata-java
[RustCrypto]: https://github.com/RustCrypto
[zkgroup]: https://github.com/signalapp/zkgroup
[Noise protocol]: http://noiseprotocol.org/
[HSMs]: https://en.wikipedia.org/wiki/Hardware_security_module
[zero-knowledge groups]: https://signal.org/blog/signal-private-group-system/
[Android]: https://github.com/signalapp/Signal-Android
[iOS]: https://github.com/signalapp/Signal-iOS
[Desktop]: https://github.com/signalapp/Signal-Desktop
Expand Down
37 changes: 37 additions & 0 deletions rust/zkgroup/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#
# Copyright 2020-2021 Signal Messenger, LLC.
# SPDX-License-Identifier: AGPL-3.0-only
#

[package]
name = "zkgroup"
version = "0.9.0"
authors = ["Trevor Perrin <trevp@signal.org>"]
edition = "2018"
description = "A zero-knowledge group library"
license = "AGPL-3.0-only"

[dependencies]
poksho = { path = "../poksho" }

bincode = "1.2.1"
serde = { version = "1.0.106", features = ["derive"] }
sha2 = "0.9.0"
hex = "0.4.0"
aead = "0.4.0"
aes-gcm-siv = "0.10.0"

[dependencies.curve25519-dalek]
features = ["serde"]
version = "3.0.0"
git = "https://github.com/signalapp/curve25519-dalek.git"
branch = "3.0.0-lizard2"

# Below is for benchmarking:

[dev-dependencies]
criterion = "0.3.1"

[[bench]]
name = "zkgroup_benchmarks"
harness = false
224 changes: 224 additions & 0 deletions rust/zkgroup/benches/zkgroup_benchmarks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
//
// Copyright 2020 Signal Messenger, LLC.
// SPDX-License-Identifier: AGPL-3.0-only
//

use criterion::{criterion_group, criterion_main, Criterion};

extern crate zkgroup;

fn benchmark_integration_auth(c: &mut Criterion) {
let server_secret_params = zkgroup::ServerSecretParams::generate(zkgroup::TEST_ARRAY_32);
let server_public_params = server_secret_params.get_public_params();

let master_key = zkgroup::groups::GroupMasterKey::new(zkgroup::TEST_ARRAY_32_1);
let group_secret_params =
zkgroup::groups::GroupSecretParams::derive_from_master_key(master_key);
let group_public_params = group_secret_params.get_public_params();

// Random UID and issueTime
let uid = zkgroup::TEST_ARRAY_16;
let redemption_time = 123456u32;

// SERVER
// Issue credential
let randomness = zkgroup::TEST_ARRAY_32_2;
let auth_credential_response =
server_secret_params.issue_auth_credential(randomness, uid, redemption_time);

c.bench_function("issue_auth_credential", |b| {
b.iter(|| server_secret_params.issue_auth_credential(randomness, uid, redemption_time))
});

// CLIENT
let auth_credential = server_public_params
.receive_auth_credential(uid, redemption_time, &auth_credential_response)
.unwrap();

c.bench_function("receive_auth_credential", |b| {
b.iter(|| {
server_public_params
.receive_auth_credential(uid, redemption_time, &auth_credential_response)
.unwrap()
})
});

// Create and decrypt user entry
let uuid_ciphertext = group_secret_params.encrypt_uuid(uid);
let plaintext = group_secret_params.decrypt_uuid(uuid_ciphertext).unwrap();
assert!(plaintext == uid);

// Create and receive presentation
let randomness = zkgroup::TEST_ARRAY_32_5;

let presentation = server_public_params.create_auth_credential_presentation(
randomness,
group_secret_params,
auth_credential,
);

c.bench_function("create_auth_credential_presentation", |b| {
b.iter(|| {
server_public_params.create_auth_credential_presentation(
randomness,
group_secret_params,
auth_credential,
)
})
});

let _presentation_bytes = &bincode::serialize(&presentation).unwrap();

//for b in presentation_bytes.iter() {
// print!("0x{:02x}, ", b);
//}
//assert!(AUTH_CREDENTIAL_PRESENTATION_RESULT[..] == presentation_bytes[..]);

c.bench_function("verify_auth_credential_presentation", |b| {
b.iter(|| {
server_secret_params
.verify_auth_credential_presentation(group_public_params, &presentation)
.unwrap();
})
});
}

// Copied and modified from tests/integration_tests.rs
pub fn benchmark_integration_profile(c: &mut Criterion) {
// Random UID and issueTime
let _uid = zkgroup::TEST_ARRAY_16;

// SERVER
let server_secret_params = zkgroup::ServerSecretParams::generate(zkgroup::TEST_ARRAY_32);
let server_public_params = server_secret_params.get_public_params();

// CLIENT
let master_key = zkgroup::groups::GroupMasterKey::new(zkgroup::TEST_ARRAY_32_1);
let group_secret_params =
zkgroup::groups::GroupSecretParams::derive_from_master_key(master_key);
let group_public_params = group_secret_params.get_public_params();

let uid = zkgroup::TEST_ARRAY_16;
let profile_key =
zkgroup::profiles::ProfileKey::create(zkgroup::common::constants::TEST_ARRAY_32_1);
let profile_key_commitment = profile_key.get_commitment(uid);

// Create context and request
let randomness = zkgroup::TEST_ARRAY_32_3;

let context = server_public_params.create_profile_key_credential_request_context(
randomness,
uid,
profile_key,
);

c.bench_function("create_profile_key_credential_request_context", |b| {
b.iter(|| {
server_public_params.create_profile_key_credential_request_context(
randomness,
uid,
profile_key,
)
})
});

let request = context.get_request();

// SERVER

let randomness = zkgroup::TEST_ARRAY_32_4;
let response = server_secret_params
.issue_profile_key_credential(randomness, &request, uid, profile_key_commitment)
.unwrap();

c.bench_function("issue_profile_key_credential", |b| {
b.iter(|| {
server_secret_params
.issue_profile_key_credential(randomness, &request, uid, profile_key_commitment)
.unwrap()
})
});

// CLIENT
// Gets stored profile credential
let profile_key_credential = server_public_params
.receive_profile_key_credential(&context, &response)
.unwrap();

c.bench_function("receive_profile_key_credential", |b| {
b.iter(|| {
server_public_params
.receive_profile_key_credential(&context, &response)
.unwrap()
})
});

// Create encrypted UID and profile key
let uuid_ciphertext = group_secret_params.encrypt_uuid(uid);

c.bench_function("encrypt_uuid", |b| {
b.iter(|| group_secret_params.encrypt_uuid(uid))
});

let plaintext = group_secret_params.decrypt_uuid(uuid_ciphertext).unwrap();

c.bench_function("decrypt_uuid", |b| {
b.iter(|| group_secret_params.decrypt_uuid(uuid_ciphertext))
});

assert!(plaintext == uid);

let profile_key_ciphertext = group_secret_params.encrypt_profile_key(profile_key, uid);

c.bench_function("encrypt_profile_key", |b| {
b.iter(|| group_secret_params.encrypt_profile_key(profile_key, uid))
});

let decrypted_profile_key = group_secret_params
.decrypt_profile_key(profile_key_ciphertext, uid)
.unwrap();

c.bench_function("decrypt_profile_key", |b| {
b.iter(|| group_secret_params.decrypt_profile_key(profile_key_ciphertext, uid))
});

assert!(decrypted_profile_key.get_bytes() == profile_key.get_bytes());

// Create presentation
let randomness = zkgroup::TEST_ARRAY_32_5;

let presentation = server_public_params.create_profile_key_credential_presentation(
randomness,
group_secret_params,
profile_key_credential,
);

c.bench_function("create_profile_key_credential_presentation", |b| {
b.iter(|| {
server_public_params.create_profile_key_credential_presentation(
randomness,
group_secret_params,
profile_key_credential,
)
})
});

// SERVER
server_secret_params
.verify_profile_key_credential_presentation(group_public_params, &presentation)
.unwrap();

c.bench_function("verify_profile_key_credential_presentation", |b| {
b.iter(|| {
server_secret_params
.verify_profile_key_credential_presentation(group_public_params, &presentation)
})
});
}

criterion_group!(
benches,
benchmark_integration_profile,
benchmark_integration_auth
);
criterion_main!(benches);
14 changes: 14 additions & 0 deletions rust/zkgroup/src/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// Copyright 2020 Signal Messenger, LLC.
// SPDX-License-Identifier: AGPL-3.0-only
//

pub mod auth;
pub mod groups;
pub mod profiles;
pub mod receipts;

pub mod server_params;

pub use server_params::ServerPublicParams;
pub use server_params::ServerSecretParams;
12 changes: 12 additions & 0 deletions rust/zkgroup/src/api/auth.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// Copyright 2020 Signal Messenger, LLC.
// SPDX-License-Identifier: AGPL-3.0-only
//

pub mod auth_credential;
pub mod auth_credential_presentation;
pub mod auth_credential_response;

pub use auth_credential::AuthCredential;
pub use auth_credential_presentation::AuthCredentialPresentation;
pub use auth_credential_response::AuthCredentialResponse;
17 changes: 17 additions & 0 deletions rust/zkgroup/src/api/auth/auth_credential.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// Copyright 2020 Signal Messenger, LLC.
// SPDX-License-Identifier: AGPL-3.0-only
//

use serde::{Deserialize, Serialize};

use crate::common::simple_types::*;
use crate::crypto;

#[derive(Copy, Clone, Serialize, Deserialize)]
pub struct AuthCredential {
pub(crate) reserved: ReservedBytes,
pub(crate) credential: crypto::credentials::AuthCredential,
pub(crate) uid: crypto::uid_struct::UidStruct,
pub(crate) redemption_time: RedemptionTime,
}
Loading