Skip to content

Commit

Permalink
Add 'phoenix-core` to a workspace called phoenix
Browse files Browse the repository at this point in the history
Resolves #171

Co-authored-by: Xavier <xavier@dusk.network>
  • Loading branch information
moCello and xevisalle committed May 16, 2024
1 parent b6c51a1 commit 163fe82
Show file tree
Hide file tree
Showing 36 changed files with 236 additions and 179 deletions.
18 changes: 12 additions & 6 deletions .github/workflows/dusk_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,20 @@ jobs:
name: Dusk Analyzer
uses: dusk-network/.github/.github/workflows/dusk-analysis.yml@main

test_std:
name: tests std
test_core_std:
name: test core std
uses: dusk-network/.github/.github/workflows/run-tests.yml@main
with:
test_flags: --features alloc
test_flags: -p phoenix-core --features alloc

test_rkyv:
name: tests rkyv
test_core_rkyv:
name: test core rkyv
uses: dusk-network/.github/.github/workflows/run-tests.yml@main
with:
test_flags: --features rkyv-impl
test_flags: -p phoenix-core --features rkyv-impl

test_circuits:
name: test cirucits
uses: dusk-network/.github/.github/workflows/run-tests.yml@main
with:
test_flags: -p phoenix-circuits
4 changes: 1 addition & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
/target
**/*.rs.bk
/src/main.rs
**/target
Cargo.lock
55 changes: 5 additions & 50 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,51 +1,6 @@
[package]
name = "phoenix-core"
version = "0.27.0"
authors = ["zer0 <matteo@dusk.network>", "Victor Lopez <victor@dusk.network"]
edition = "2021"
repository = "https://github.com/dusk-network/phoenix-core"
description = "Anonymity-preserving zero-knowledge proof-powered transaction model"
license = "MPL-2.0"
exclude = [".github/workflows/dusk-ci.yml", ".gitignore"]

[dependencies]
rand_core = { version = "0.6", default-features = false }
dusk-bytes = "0.1"
dusk-plonk = { version = "0.19", default-features = false, optional = true }
dusk-bls12_381 = { version = "0.13", default-features = false }
bls12_381-bls = { version = "0.3", default-features = false }
dusk-jubjub = { version = "0.14", default-features = false, features = ["zeroize"] }
dusk-poseidon = { version = "0.33", default-features = false }
jubjub-schnorr = { version = "0.3", default-features = false }
subtle = { version = "^2.2.1", default-features = false }
ff = { version = "0.13", default-features = false }
aes-gcm = "0.10"
zeroize = { version = "1", default-features = false, features = ["derive"] }
rkyv = { version = "0.7", optional = true, default-features = false }
bytecheck = { version = "0.6", optional = true, default-features = false }

[dev-dependencies]
assert_matches = "1.3"
rand = "0.8"
rkyv = { version = "0.7", default-features = false, features = ["size_32"] }

[features]
default = [] # "alloc" is suggested as default feature but would be breaking change
alloc = []
rkyv-impl = [
"dusk-poseidon/rkyv-impl",
"dusk-jubjub/rkyv-impl",
"jubjub-schnorr/rkyv-impl",
"dusk-bls12_381/rkyv-impl",
"bls12_381-bls/rkyv-impl",
"rkyv",
"bytecheck"
[workspace]
members = [
"core",
"circuits",
]
zk = [
"dusk-plonk",
]

[[test]]
name = "gadgets"
path = "tests/gadgets.rs"
required-features = ["zk"]
resolver = "2"
32 changes: 7 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,11 @@
# Phoenix Core
# Phoenix

Phoenix is an anonymity-preserving zero-knowledge proof-powered transaction model formalized and developed by Dusk Network.
Phoenix is the transaction model used by Dusk, an open-source public blockchain with a UTXO-based architecture that allows for the execution of obfuscated transactions and confidential smart contracts.

# General
In privacy-preserving blockchains, there are no accounts or wallets at the protocol layer. Instead, coins are stored as a list of UTXOs with a quantity and some criteria for spending it. In this approach, transactions are created by consuming existing UTXOs and producing new ones in their place. Dusk follows this system, and UTXOs are called notes.

Although somewhat based on the UTXO model utilized in the [Zcash protocol](https://github.com/zcash/zips/blob/master/protocol/protocol.pdf), Phoenix is uniquely capable to enable privacy-preserving smart contract by allowing confidential spending of public output (gas and coinbase transactions).
Unlike transparent transaction models, where it is easy to monitor which notes were spent, this task is much harder in a privacy-preserving network, since the details of the notes must be kept hidden. In this case, the network must keep track of all notes ever created by storing their hashes in the leaves of a Merkle tree (called Merkle tree of notes). That is, when a transaction is validated, the network includes the hashes of the new notes to the leaves of this tree.
To prevent double spending, transactions include a list of deterministic values called nullifiers, one for each note being spent, which invalidates these notes.
The idea here is that the nullifier is computed in such a way that an external observer cannot link it to any specific note. This way, when a transaction is accepted, the network knows that some notes are nullified and can no longer be spent, but does not know which ones.

Unlike Zcash, in which transactions can be potentially linked [\[1\]](https://arxiv.org/pdf/1712.01210)[\[2\]](https://orbilu.uni.lu/bitstream/10993/39996/1/Zcash_Miner_Linking%20%282%29.pdf), Phoenix guarantees transaction unlinkability through combining the so-called "obfuscated notes" (i.e. outputs containing encrypted values) with "transparent notes" (i.e. outputs containing plain values) into a single Merkle Tree.

All the transactions utilize one-time keys. It is totally up to the user how he wants to manage his secret key: he could have one or many secret keys for many unspent outputs. The inner Diffie-Hellman key exchange randomness mechanism guarantees the note public key will not repeat for the same spender public key, which causes the identification of the spender to be unfeasible.

For further details, check out the technical paper to be published soon.

# Concepts

## Zero-knowledge

Phoenix uses zero-knowledge proofs to guarantee:

- Transaction balance consistency
- Prevent double-spending attacks
- Prove the ownership of unspent outputs

The set of unspent outputs is a union of obfuscated and transparent note sets. Both notes share a similar structure aside from the obfuscated containing encrypted values and transparent notes containing plain values.

The owner of a note can share his/her `View Key`, allowing a third-party (e.g. a wallet provider) to detect the outputs belonging to the owner as well as the value of the encrypted in the note, in case of an obfuscated note.

The spending of a note can be done only via a `Secret Key`, known only to the owner of the note.
Please refer to the [docs](https://github.com/dusk-network/phoenix/blob/master/docs/protocol-description.pdf) for more detail.
19 changes: 19 additions & 0 deletions circuits/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- Add `phoenix-circuits` as a workspace member of `phoenix` [#171]
- Add elgamal encryption and decryption gadgets [#171]

<!-- ISSUES -->
[#171]: https://github.com/dusk-network/phoenix/issues/171

<!-- VERSIONS -->
[Unreleased]: https://github.com/dusk-network/phoenix/compare/v0.27.0...HEAD
19 changes: 19 additions & 0 deletions circuits/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "phoenix-circuits"
version = "0.1.0"
edition = "2021"
repository = "https://github.com/dusk-network/phoenix/circuits"
description = "Circuit definitions for Phoenix, an privacy-preserving ZKP-based transaction model"
license = "MPL-2.0"
exclude = [".github/workflows/dusk-ci.yml", ".gitignore"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
phoenix-core = { path = "../core" }
dusk-plonk = { version = "0.19", default-features = false }
dusk-jubjub = { version = "0.14", default-features = false }

[dev-dependencies]
ff = { version = "0.13", default-features = false }
rand_core = { version = "0.6", default-features = false }
11 changes: 11 additions & 0 deletions circuits/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Phoenix Circuits

Phoenix is the transaction model used by Dusk, an open-source public blockchain with a UTXO-based architecture that allows for the execution of obfuscated transactions and confidential smart contracts.

This library contains the implementation of the Phoenix-circuits, to prove, in zero-knowledge, that the following conditions hold true:

1. Membership: every note that is about to be spent is included in the Merkle tree of notes.
2. Ownership: the sender holds the note secret key for every note that is about to be spent.
3. Nullification: the nullifier is calculated correctly.
4. Minting: the value commitment for the newly minted notes are computed correctly.
5. Balance integrity: the sum of the value of all spent notes is equal to the value of the sum of all minted notes + the gas fee + a crossover, where a crossover refers to funds being transfered to a contract.
14 changes: 6 additions & 8 deletions src/encryption/elgamal.rs → circuits/src/encryption/elgamal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
//! Reference: https://link.springer.com/chapter/10.1007/3-540-39568-7_2

use dusk_jubjub::{JubJubExtended, JubJubScalar, GENERATOR};

#[cfg(feature = "zk")]
use dusk_plonk::prelude::*;

/// Encrypts a JubJubExtended plaintext given a public key and a fresh random
Expand All @@ -27,8 +25,10 @@ pub fn encrypt(
(ciphertext_1, ciphertext_2)
}

/// Decrypts a ciphertext given a secret key,
/// returning a JubJubExtended plaintext
/// Decrypts a ciphertext given a secret key.
///
/// ## Return
/// Returns a JubJubExtended plaintext.
pub fn decrypt(
secret_key: &JubJubScalar,
ciphertext_1: &JubJubExtended,
Expand All @@ -38,9 +38,8 @@ pub fn decrypt(
ciphertext_2 - ciphertext_1 * secret_key
}

/// Encrypt in-circuit a plaintext WitnessPoint, returning
/// a ciphertext (WitnessPoint, WitnessPoint)
#[cfg(feature = "zk")]
/// Encrypt in-circuit a plaintext WitnessPoint, returning a ciphertext
/// (WitnessPoint, WitnessPoint)
pub fn encrypt_gadget(
composer: &mut Composer,
public_key: WitnessPoint,
Expand All @@ -56,7 +55,6 @@ pub fn encrypt_gadget(

/// Decrypt in-circuit a ciphertext (WitnessPoint, WitnessPoint),
/// returning a plaintext WitnessPoint
#[cfg(feature = "zk")]
pub fn decrypt_gadget(
composer: &mut Composer,
secret_key: Witness,
Expand Down
3 changes: 0 additions & 3 deletions src/encryption/mod.rs → circuits/src/encryption/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,5 @@
//
// Copyright (c) DUSK NETWORK. All rights reserved.

/// AES symmetric cipher
pub mod aes;

/// ElGamal asymmetric cipher
pub mod elgamal;
17 changes: 17 additions & 0 deletions circuits/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) DUSK NETWORK. All rights reserved.

//! Phoenix's circuits and gadgets.

#![allow(non_snake_case)]
#![deny(missing_docs)]
#![no_std]

/// Encryption algorithm
mod encryption;

/// ElGamal asymmetric cipher
pub use encryption::elgamal;
23 changes: 21 additions & 2 deletions tests/gadgets.rs → circuits/tests/elgamal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,31 @@
// Copyright (c) DUSK NETWORK. All rights reserved.

use dusk_jubjub::{JubJubAffine, JubJubScalar, GENERATOR_EXTENDED};
use dusk_plonk::prelude::*;
use ff::Field;
use phoenix_circuits::elgamal;
use phoenix_core::{PublicKey, SecretKey};
use rand_core::OsRng;

use phoenix_core::{elgamal, PublicKey, SecretKey};
#[test]
fn test_elgamal_encrypt_and_decrypt() {
let sk = SecretKey::random(&mut OsRng);
let pk = PublicKey::from(&sk);

use dusk_plonk::prelude::*;
let message = GENERATOR_EXTENDED * JubJubScalar::from(1234u64);

// Encrypt using a fresh random value 'r'
let r = JubJubScalar::random(&mut OsRng);
let (c1, c2) = elgamal::encrypt(pk.A(), &message, &r);

// Assert decryption
let dec_message = elgamal::decrypt(sk.a(), &c1, &c2);
assert_eq!(message, dec_message);

// Assert decryption using an incorrect key
let dec_message_wrong = elgamal::decrypt(sk.b(), &c1, &c2);
assert_ne!(message, dec_message_wrong);
}

static LABEL: &[u8; 12] = b"dusk-network";
const CAPACITY: usize = 13; // capacity required for the setup
Expand Down
Loading

0 comments on commit 163fe82

Please sign in to comment.