diff --git a/core/benches/license_circuit.rs b/core/benches/license_circuit.rs index d3c4bac..9b5fb32 100644 --- a/core/benches/license_circuit.rs +++ b/core/benches/license_circuit.rs @@ -4,14 +4,13 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. -use dusk_jubjub::{JubJubAffine, JubJubScalar, GENERATOR_EXTENDED}; +use dusk_jubjub::{JubJubAffine, JubJubScalar}; use dusk_plonk::prelude::*; use dusk_poseidon::{Domain, Hash}; -use ff::Field; use phoenix_core::{PublicKey, SecretKey}; use poseidon_merkle::{Item, Tree}; -use zk_citadel::{circuit, gadgets, License, Request, SessionCookie}; +use zk_citadel::{circuit, gadgets, License, LicenseCreator, SessionCookie}; use criterion::{criterion_group, criterion_main, Criterion}; use rand_core::OsRng; @@ -46,25 +45,23 @@ impl Circuit for LicenseCircuit { } fn license_circuit_benchmark(crit: &mut Criterion) { - // Compute gadget parameters let sk = SecretKey::random(&mut OsRng); let pk = PublicKey::from(&sk); let sk_lp = SecretKey::random(&mut OsRng); let pk_lp = PublicKey::from(&sk_lp); + let pp = PublicParameters::setup(1 << circuit::CAPACITY, &mut OsRng).unwrap(); let (prover, verifier) = Compiler::compile::(&pp, LABEL).expect("failed to compile circuit"); - let lsa = pk.gen_stealth_address(&JubJubScalar::random(&mut OsRng)); - let lsk = sk.gen_note_sk(&lsa); - let k_lic = JubJubAffine::from( - GENERATOR_EXTENDED * Hash::digest_truncated(Domain::Other, &[(*lsk.as_ref()).into()])[0], - ); - let req = Request::new(&pk_lp, &lsa, &k_lic, &mut OsRng).expect("Request correctly computed."); - let attr_data = JubJubScalar::from(ATTRIBUTE_DATA); - let lic = - License::new(&attr_data, &sk_lp, &req, &mut OsRng).expect("License correctly computed."); + let lic = License::new( + &attr_data, + &sk_lp, + &LicenseCreator::FromPublicKey(pk), + &mut OsRng, + ) + .expect("License correctly computed."); let mut tree = Tree::<(), { circuit::DEPTH }>::new(); let lpk = JubJubAffine::from(lic.lsa.note_pk().as_ref()); diff --git a/core/src/gadgets.rs b/core/src/gadgets.rs index d25faac..e2bdd4b 100644 --- a/core/src/gadgets.rs +++ b/core/src/gadgets.rs @@ -5,8 +5,7 @@ // Copyright (c) DUSK NETWORK. All rights reserved. use dusk_bytes::Serializable; -use dusk_jubjub::{GENERATOR, GENERATOR_NUMS}; -use dusk_jubjub::{GENERATOR_EXTENDED, GENERATOR_NUMS_EXTENDED}; +use dusk_jubjub::{dhke, GENERATOR, GENERATOR_EXTENDED, GENERATOR_NUMS, GENERATOR_NUMS_EXTENDED}; use dusk_plonk::prelude::*; use dusk_poseidon::Hash; use dusk_poseidon::{Domain, HashGadget}; @@ -168,12 +167,19 @@ impl GadgetParameters { merkle_proof: Opening<(), DEPTH>, ) -> Result<(Self, SessionCookie), phoenix_core::Error> { let lsk = sk.gen_note_sk(&lic.lsa); - let k_lic = JubJubAffine::from( - GENERATOR_EXTENDED - * Hash::digest_truncated(Domain::Other, &[(*lsk.as_ref()).into()])[0], - ); - - let dec: [u8; LIC_PLAINTEXT_SIZE] = decrypt(&k_lic, &lic.enc)?; + let k_lic = dhke(sk.a(), lic.lsa.R()); + + let dec: [u8; LIC_PLAINTEXT_SIZE] = match decrypt(&k_lic, &lic.enc) { + Ok(dec) => dec, + Err(_err) => { + let k_lic = JubJubAffine::from( + GENERATOR_EXTENDED + * Hash::digest_truncated(Domain::Other, &[(*lsk.as_ref()).into()])[0], + ); + + decrypt(&k_lic, &lic.enc)? + } + }; let mut sig_lic_bytes = [0u8; Signature::SIZE]; sig_lic_bytes.copy_from_slice(&dec[..Signature::SIZE]); @@ -185,8 +191,6 @@ impl GadgetParameters { JubJubScalar::from_bytes(&attr_data_bytes).expect("Deserialization was correct."); let lpk = JubJubAffine::from(*lic.lsa.note_pk().as_ref()); - - let lsk = sk.gen_note_sk(&lic.lsa); let lpk_p = JubJubAffine::from(GENERATOR_NUMS_EXTENDED * lsk.as_ref()); let s_0 = BlsScalar::random(&mut rng); diff --git a/core/src/lib.rs b/core/src/lib.rs index 63c19c2..5812ecc 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -12,6 +12,6 @@ mod session; pub mod circuit; pub mod gadgets; -pub use license::License; +pub use license::{License, LicenseCreator}; pub use request::Request; pub use session::{Session, SessionCookie}; diff --git a/core/src/license.rs b/core/src/license.rs index bbfc227..ae00ebd 100644 --- a/core/src/license.rs +++ b/core/src/license.rs @@ -7,10 +7,11 @@ use dusk_bytes::Serializable; use dusk_jubjub::dhke; use dusk_poseidon::{Domain, Hash}; +use ff::Field; use jubjub_schnorr::{SecretKey as NoteSecretKey, Signature}; use phoenix_core::{ aes::{decrypt, encrypt, ENCRYPTION_EXTRA_SIZE}, - Error, SecretKey, StealthAddress, + Error, PublicKey, SecretKey, StealthAddress, }; use rand_core::{CryptoRng, RngCore}; @@ -25,6 +26,11 @@ 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 { + FromRequest(Request), + FromPublicKey(PublicKey), +} + #[cfg_attr( feature = "rkyv-impl", derive(Archive, Serialize, Deserialize), @@ -40,19 +46,34 @@ impl License { pub fn new( attr_data: &JubJubScalar, sk_lp: &SecretKey, - req: &Request, + lc: &LicenseCreator, rng: &mut R, ) -> Result { - let k_dh = dhke(sk_lp.a(), req.rsa.R()); - let dec: [u8; REQ_PLAINTEXT_SIZE] = decrypt(&k_dh, &req.enc)?; + let (lsa, k_lic) = match lc { + LicenseCreator::FromRequest(req) => { + let k_dh = dhke(sk_lp.a(), req.rsa.R()); + let dec: [u8; REQ_PLAINTEXT_SIZE] = decrypt(&k_dh, &req.enc)?; + + let mut lsa_bytes = [0u8; StealthAddress::SIZE]; + lsa_bytes.copy_from_slice(&dec[..StealthAddress::SIZE]); + let lsa = + StealthAddress::from_bytes(&lsa_bytes).expect("Deserialization was correct."); + + let mut k_lic_bytes = [0u8; JubJubAffine::SIZE]; + k_lic_bytes.copy_from_slice(&dec[StealthAddress::SIZE..]); + let k_lic = + JubJubAffine::from_bytes(k_lic_bytes).expect("Deserialization was correct."); - let mut lsa_bytes = [0u8; StealthAddress::SIZE]; - lsa_bytes.copy_from_slice(&dec[..StealthAddress::SIZE]); - let lsa = StealthAddress::from_bytes(&lsa_bytes).expect("Deserialization was correct."); + (lsa, k_lic) + } + LicenseCreator::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()); - let mut k_lic_bytes = [0u8; JubJubAffine::SIZE]; - k_lic_bytes.copy_from_slice(&dec[StealthAddress::SIZE..]); - let k_lic = JubJubAffine::from_bytes(k_lic_bytes).expect("Deserialization was correct."); + (lsa, k_lic) + } + }; let lpk = JubJubAffine::from(lsa.note_pk().as_ref()); diff --git a/core/tests/citadel.rs b/core/tests/citadel.rs index af33c83..3bb04c0 100644 --- a/core/tests/citadel.rs +++ b/core/tests/citadel.rs @@ -12,7 +12,7 @@ use phoenix_core::{PublicKey, SecretKey}; use poseidon_merkle::{Item, Tree}; use rand_core::OsRng; -use zk_citadel::{circuit, gadgets, License, Request, Session, SessionCookie}; +use zk_citadel::{circuit, gadgets, License, LicenseCreator, Request, Session, SessionCookie}; static LABEL: &[u8; 12] = b"dusk-network"; @@ -45,8 +45,13 @@ fn test_full_citadel() { // Second, the LP computes these values and grants the License on-chain let attr_data = JubJubScalar::from(ATTRIBUTE_DATA); - let lic = - License::new(&attr_data, &sk_lp, &req, &mut OsRng).expect("License correctly computed."); + let lic = License::new( + &attr_data, + &sk_lp, + &LicenseCreator::FromRequest(req), + &mut OsRng, + ) + .expect("License correctly computed from request."); let mut tree = Tree::<(), { circuit::DEPTH }>::new(); let lpk = JubJubAffine::from(lic.lsa.note_pk().as_ref()); @@ -117,4 +122,51 @@ fn test_full_citadel() { // So, this should be an error assert!(session.verify(sc_false).is_err()); + + // A license issued from a public key should also work + let lic_from_pk = License::new( + &attr_data, + &sk_lp, + &LicenseCreator::FromPublicKey(pk), + &mut OsRng, + ) + .expect("License correctly computed from public key."); + + let lpk = JubJubAffine::from(lic_from_pk.lsa.note_pk().as_ref()); + + let item = Item { + hash: Hash::digest(Domain::Other, &[lpk.get_u(), lpk.get_v()])[0], + data: (), + }; + + tree.insert(pos + 1, item); + + let merkle_proof = tree.opening(pos + 1).expect("Tree was read successfully"); + + let (gp, sc) = gadgets::GadgetParameters::compute_parameters( + &sk, + &lic_from_pk, + &pk_lp, + &pk_sp, + &c, + &mut OsRng, + merkle_proof, + ) + .expect("Parameters computed correctly."); + + let (proof, public_inputs) = prover + .prove(&mut OsRng, &circuit::LicenseCircuit::new(&gp, &sc)) + .expect("failed to prove"); + verifier + .verify(&proof, &public_inputs) + .expect("failed to verify proof"); + + assert_eq!(JubJubAffine::from(pk_lp.A()), sc.pk_lp); + assert_eq!(JubJubAffine::from(pk_sp.A()), sc.pk_sp); + assert_eq!(c, sc.c); + assert_eq!(attr_data, sc.attr_data); + + let session = Session::from(&public_inputs); + assert_eq!(session.session_id, sc.session_id); + session.verify(sc).expect("Session verified correctly."); }