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

Add crate documentation #125

Merged
merged 3 commits into from
Dec 11, 2024
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
6 changes: 3 additions & 3 deletions contract/tests/license_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use execution_core::plonk::{Prover, Verifier};
use rand::rngs::StdRng;
use rand::{CryptoRng, RngCore, SeedableRng};
use rkyv::{check_archived_root, Deserialize, Infallible};
use zk_citadel::{circuit, gadgets, License, LicenseCreator, Request, SessionCookie};
use zk_citadel::{circuit, gadgets, License, LicenseOrigin, Request, SessionCookie};

const PROVER_BYTES: &[u8] = include_bytes!("../../target/prover");

Expand Down Expand Up @@ -56,7 +56,7 @@ fn create_test_license<R: RngCore + CryptoRng>(
rng: &mut R,
) -> License {
let request = Request::new(sk_user, pk_user, pk_lp, rng).unwrap();
License::new(attr, sk_lp, &LicenseCreator::FromRequest(request), rng).unwrap()
License::new(attr, sk_lp, &LicenseOrigin::FromRequest(request), rng).unwrap()
}

fn initialize() -> Session {
Expand Down Expand Up @@ -301,7 +301,7 @@ fn use_license_get_session() {
let request =
Request::new(&sk_user, &pk_user, &pk_lp, rng).expect("Request correctly created.");
let attr = JubJubScalar::from(USER_ATTRIBUTES);
let license = License::new(&attr, &sk_lp, &LicenseCreator::FromRequest(request), rng).unwrap();
let license = License::new(&attr, &sk_lp, &LicenseOrigin::FromRequest(request), rng).unwrap();

let license_blob = rkyv::to_bytes::<_, 4096>(&license)
.expect("Request should serialize correctly")
Expand Down
3 changes: 2 additions & 1 deletion core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Add `circuit` module
- Add `LicenseCreator`
- Add `LicenseOrigin`
- Add crate documentation

### Changed

Expand Down
4 changes: 2 additions & 2 deletions core/benches/license_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use dusk_poseidon::{Domain, Hash};
use phoenix_core::{PublicKey, SecretKey};
use poseidon_merkle::{Item, Tree};

use zk_citadel::{circuit, gadgets, License, LicenseCreator, SessionCookie};
use zk_citadel::{circuit, gadgets, License, LicenseOrigin, SessionCookie};

use criterion::{criterion_group, criterion_main, Criterion};
use rand_core::OsRng;
Expand Down Expand Up @@ -58,7 +58,7 @@ fn license_circuit_benchmark(crit: &mut Criterion) {
let lic = License::new(
&attr_data,
&sk_lp,
&LicenseCreator::FromPublicKey(pk),
&LicenseOrigin::FromPublicKey(pk),
&mut OsRng,
)
.expect("License correctly computed.");
Expand Down
11 changes: 9 additions & 2 deletions core/src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,23 @@ use crate::{gadgets, SessionCookie};
use dusk_plonk::prelude::*;

#[allow(dead_code)]
pub const CAPACITY: usize = 15; // capacity required for the setup
pub const DEPTH: usize = 16; // depth of the n-ary Merkle tree

/// The capacity required for the setup
pub const CAPACITY: usize = 15;
/// The depth of the n-ary Merkle tree
pub const DEPTH: usize = 16;

/// A standard license circuit that simply uses the [`use_license`]
/// gadget with no additional operations
#[derive(Default, Debug)]
pub struct LicenseCircuit {
gp: gadgets::GadgetParameters<DEPTH>,
sc: SessionCookie,
}

impl LicenseCircuit {
/// A method to create a new [`LicenseCircuit`] from some [`GadgetParameters`]
/// and a [`SessionCookie`]
pub fn new(gp: &gadgets::GadgetParameters<DEPTH>, sc: &SessionCookie) -> Self {
Self { gp: *gp, sc: *sc }
}
Expand Down
1 change: 0 additions & 1 deletion core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use core::fmt;

/// All possible errors for Citadel
#[allow(missing_docs)]
#[allow(clippy::enum_variant_names)]
#[derive(Debug, Clone)]
pub enum Error {
Expand Down
44 changes: 23 additions & 21 deletions core/src/gadgets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,18 @@ use crate::{license::LIC_PLAINTEXT_SIZE, License, SessionCookie};

use poseidon_merkle::zk::opening_gadget;

// out of this circuit, the generated public inputs vector collects
// these values in that particular order:
//
// public_inputs[0]: session_id
// public_inputs[1]: session_hash
// public_inputs[2]: com_0
// public_inputs[3]: com_1.x
// public_inputs[4]: com_1.y
// public_inputs[5]: com_2.x
// public_inputs[6]: com_2.y
// public_inputs[7]: root

/// The [`use_license`] gadget for the [`LicenseCircuit`]. It is meant
/// to use Citadel licenses on-chain. Out of this circuit, the generated
/// public inputs vector collects these values in that particular order:
///
/// session_id
/// session_hash
/// com_0
/// com_1.x
/// com_1.y
/// com_2.x
/// com_2.y
/// root
pub fn use_license<const DEPTH: usize>(
composer: &mut Composer,
gp: &GadgetParameters<DEPTH>,
Expand Down Expand Up @@ -110,24 +110,25 @@ pub fn use_license<const DEPTH: usize>(
Ok(())
}

/// The parameters required by the [`use_license`] gadget
#[cfg_attr(
feature = "rkyv-impl",
derive(Archive, Serialize, Deserialize),
archive_attr(derive(bytecheck::CheckBytes))
)]
#[derive(Debug, Clone, Copy)]
pub struct GadgetParameters<const DEPTH: usize> {
pub lpk: JubJubAffine, // license public key
pub lpk_p: JubJubAffine, // license public key prime
pub sig_lic: Signature, // signature of the license
lpk: JubJubAffine, // license public key
lpk_p: JubJubAffine, // license public key prime
sig_lic: Signature, // signature of the license

pub com_0: BlsScalar, // Hash commitment 0
pub com_1: JubJubExtended, // Pedersen Commitment 1
pub com_2: JubJubExtended, // Pedersen Commitment 2
com_0: BlsScalar, // Hash commitment 0
com_1: JubJubExtended, // Pedersen Commitment 1
com_2: JubJubExtended, // Pedersen Commitment 2

pub session_hash: BlsScalar, // hash of the session
pub sig_session_hash: SignatureDouble, // signature of the session_hash
pub merkle_proof: Opening<(), DEPTH>, // Merkle proof for the Proof of Validity
session_hash: BlsScalar, // hash of the session
sig_session_hash: SignatureDouble, // signature of the session_hash
merkle_proof: Opening<(), DEPTH>, // Merkle proof for the Proof of Validity
}

impl<const DEPTH: usize> Default for GadgetParameters<DEPTH> {
Expand Down Expand Up @@ -156,6 +157,7 @@ impl<const DEPTH: usize> Default for GadgetParameters<DEPTH> {
}

impl<const DEPTH: usize> GadgetParameters<DEPTH> {
/// Method to generate the [`GadgetParameters`] struct
#[allow(clippy::too_many_arguments)]
pub fn compute_parameters<R: RngCore + CryptoRng>(
sk: &SecretKey,
Expand Down
19 changes: 18 additions & 1 deletion core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,31 @@
//
// Copyright (c) DUSK NETWORK. All rights reserved.

//! This package contains the core implementation of Citadel, a self-sovereign identity protocol for
//! decentralized networks, allowing users to receive licenses issued by license providers (LP), and
//! to use them to prove sensitive information in zero-knowledge to service providers (SP).
//!
//! Reference: https://arxiv.org/pdf/2301.09378
//!
xevisalle marked this conversation as resolved.
Show resolved Hide resolved
//! **DISCLAIMER**: this package **has not gone through an exhaustive security analysis**,
//! so it is not intended to be used in a production environment, only for academic purposes.

#![deny(missing_docs)]

mod error;
mod license;
mod request;
mod session;

/// The arithmetic circuit module to use licenses
pub mod circuit;

/// The gadget module required by the license circuit and / or
/// in third party circuits, to use licenses
pub mod gadgets;

pub use license::{License, LicenseCreator};
pub use license::{License, LicenseOrigin};
pub use request::Request;
pub use session::{Session, SessionCookie};

pub use error::Error;
26 changes: 17 additions & 9 deletions core/src/license.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use dusk_bytes::Serializable;
use dusk_jubjub::dhke;
use dusk_poseidon::{Domain, Hash};
use ff::Field;
use jubjub_schnorr::{SecretKey as NoteSecretKey, Signature};
use jubjub_schnorr::{SecretKey as LicenseSecretKey, Signature};
use phoenix_core::{
aes::{decrypt, encrypt, ENCRYPTION_EXTRA_SIZE},
Error, PublicKey, SecretKey, StealthAddress,
Expand All @@ -26,31 +26,39 @@ use crate::request::{Request, REQ_PLAINTEXT_SIZE};
pub(crate) const LIC_PLAINTEXT_SIZE: usize = Signature::SIZE + JubJubScalar::SIZE;
const LIC_ENCRYPTION_SIZE: usize = LIC_PLAINTEXT_SIZE + ENCRYPTION_EXTRA_SIZE;

pub enum LicenseCreator {
/// Enumeration used to create new licenses
pub enum LicenseOrigin {
/// From a [`Request`] sent on-chain
FromRequest(Request),
/// From a [`PublicKey`] of a given user
FromPublicKey(PublicKey),
}

/// The struct defining a Citadel license, an asset that represents
/// the right of a user to use a specific service
#[cfg_attr(
feature = "rkyv-impl",
derive(Archive, Serialize, Deserialize),
archive_attr(derive(bytecheck::CheckBytes))
)]
#[derive(Debug, Clone)]
pub struct License {
pub lsa: StealthAddress, // license stealth address
pub enc: [u8; LIC_ENCRYPTION_SIZE], // encryption of the license signature and attribute data
/// The stealth address of the license
pub lsa: StealthAddress,
/// The encryption of the license signature and the attribute data
pub enc: [u8; LIC_ENCRYPTION_SIZE],
}

impl License {
/// Method to generate a new [`License`]
pub fn new<R: RngCore + CryptoRng>(
attr_data: &JubJubScalar,
sk_lp: &SecretKey,
lc: &LicenseCreator,
lo: &LicenseOrigin,
rng: &mut R,
) -> Result<Self, Error> {
let (lsa, k_lic) = match lc {
LicenseCreator::FromRequest(req) => {
let (lsa, k_lic) = match lo {
LicenseOrigin::FromRequest(req) => {
let k_dh = dhke(sk_lp.a(), req.rsa.R());
let dec: [u8; REQ_PLAINTEXT_SIZE] = decrypt(&k_dh, &req.enc)?;

Expand All @@ -66,7 +74,7 @@ impl License {

(lsa, k_lic)
}
LicenseCreator::FromPublicKey(pk_user) => {
LicenseOrigin::FromPublicKey(pk_user) => {
let r_dh = JubJubScalar::random(&mut *rng);
let lsa = pk_user.gen_stealth_address(&r_dh);
let k_lic = dhke(&r_dh, pk_user.A());
Expand All @@ -81,7 +89,7 @@ impl License {
Domain::Other,
&[lpk.get_u(), lpk.get_v(), BlsScalar::from(*attr_data)],
)[0];
let sig_lic = NoteSecretKey::from(sk_lp.a()).sign(rng, message);
let sig_lic = LicenseSecretKey::from(sk_lp.a()).sign(rng, message);

let mut plaintext = sig_lic.to_bytes().to_vec();
plaintext.append(&mut attr_data.to_bytes().to_vec());
Expand Down
10 changes: 8 additions & 2 deletions core/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,24 @@ use dusk_plonk::prelude::*;
pub(crate) const REQ_PLAINTEXT_SIZE: usize = StealthAddress::SIZE + JubJubAffine::SIZE;
const REQ_ENCRYPTION_SIZE: usize = REQ_PLAINTEXT_SIZE + ENCRYPTION_EXTRA_SIZE;

/// The struct defining a Citadel request, a set of information that
/// a user sends to the network to inform a LP that the user is
/// requesting a license from them
#[cfg_attr(
feature = "rkyv-impl",
derive(Archive, Serialize, Deserialize),
archive_attr(derive(bytecheck::CheckBytes))
)]
#[derive(Debug)]
pub struct Request {
pub rsa: StealthAddress, // request stealth address
pub enc: [u8; REQ_ENCRYPTION_SIZE], // encryption of the license stealth address and k_lic
/// The stealth address for the request
pub rsa: StealthAddress,
/// The encryption of the license stealth address and the k_lic symmetric key
pub enc: [u8; REQ_ENCRYPTION_SIZE],
}

impl Request {
/// Method to create a new [`Request`] given ther user keys and the public key of LP
pub fn new<R: RngCore + CryptoRng>(
sk_user: &SecretKey,
pk_user: &PublicKey,
Expand Down
51 changes: 38 additions & 13 deletions core/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,33 @@ use rkyv::{Archive, Deserialize, Serialize};

use dusk_plonk::prelude::*;

/// The struct defining a Citadel session, a set of public values shared
/// on-chain that represent the use of a service by an unknown user
#[cfg_attr(
feature = "rkyv-impl",
derive(Archive, Serialize, Deserialize),
archive_attr(derive(bytecheck::CheckBytes))
)]
#[derive(Debug)]
pub struct Session {
/// The hash of the public key of the SP and a nonce
pub session_hash: BlsScalar,
/// The ID of the [`Session`], computed as the hash of
/// the lpk' and the challenge
pub session_id: BlsScalar,

pub com_0: BlsScalar, // Hash commitment 0
pub com_1: JubJubExtended, // Pedersen Commitment 1
pub com_2: JubJubExtended, // Pedersen Commitment 2
/// The hash commitment 0 from the license circuit,
/// that commits to the public key of the LP
pub com_0: BlsScalar,
/// The Pedersen commitment 1 from the license circuit,
/// that commits to the attribute data
pub com_1: JubJubExtended,
/// The Pedersen commitment 2 from the license circuit,
/// that commits to the challenge
pub com_2: JubJubExtended,
}

impl Session {
/// Method that generates a [`Session`] from a public inputs vector
pub fn from(public_inputs: &[BlsScalar]) -> Self {
let session_id = public_inputs[0];
let session_hash = public_inputs[1];
Expand All @@ -54,6 +65,8 @@ impl Session {
}
}

/// Method that verifies a [`SessionCookie`], by checking if all the
/// openings match the commitments of the given [`Session`]
pub fn verify(&self, sc: SessionCookie) -> Result<(), Error> {
let session_hash =
Hash::digest(Domain::Other, &[sc.pk_sp.get_u(), sc.pk_sp.get_v(), sc.r])[0];
Expand All @@ -80,22 +93,34 @@ impl Session {
}
}

/// The struct defining a session cookie, a secret value
/// known only by the user and the SP, used to verify that
/// a given session is correct
#[cfg_attr(
feature = "rkyv-impl",
derive(Archive, Serialize, Deserialize),
archive_attr(derive(bytecheck::CheckBytes))
)]
#[derive(Default, Debug, Clone, Copy)]
pub struct SessionCookie {
pub pk_sp: JubJubAffine, // public key of the SP
pub r: BlsScalar, // randomness for session_hash
/// Public key of the SP
pub pk_sp: JubJubAffine,
/// Randomness for session_hash
pub r: BlsScalar,
/// The ID of the session
pub session_id: BlsScalar,

pub pk_lp: JubJubAffine, // public key of the LP
pub attr_data: JubJubScalar, // attribute data of the license
pub c: JubJubScalar, // challenge value

pub s_0: BlsScalar, // randomness for com_0
pub s_1: JubJubScalar, // randomness for com_1
pub s_2: JubJubScalar, // randomness for com_2
/// Public key of the LP
pub pk_lp: JubJubAffine,
/// Attribute data of the license
pub attr_data: JubJubScalar,
/// Challenge value
pub c: JubJubScalar,

/// Randomness for com_0
pub s_0: BlsScalar,
/// Randomness for com_1
pub s_1: JubJubScalar,
/// Randomness for com_2
pub s_2: JubJubScalar,
}
Loading
Loading