Skip to content

Commit

Permalink
Merge pull request #125 from dusk-network/document
Browse files Browse the repository at this point in the history
  • Loading branch information
xevisalle authored Dec 11, 2024
2 parents 76ef6ec + 9dceb49 commit b17d0b8
Show file tree
Hide file tree
Showing 11 changed files with 123 additions and 58 deletions.
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
//!
//! **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

0 comments on commit b17d0b8

Please sign in to comment.