Skip to content

Commit

Permalink
Add PoL (#718)
Browse files Browse the repository at this point in the history
* Add PoL crate

* promote cl crate to nomos-node repo

* add github action for risc0 proof

* fix actions scrupt

* add metal feature

* fix risc0 install

* remove check test
  • Loading branch information
zeegomo authored Sep 3, 2024
1 parent c4c5eba commit 6f6bb61
Show file tree
Hide file tree
Showing 25 changed files with 1,592 additions and 2 deletions.
21 changes: 21 additions & 0 deletions .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,27 @@ jobs:
with:
name: integration-test-artifacts
path: tests/.tmp*

risc0:
name: Risc0 tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: true
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- name: Install risc0
run: cargo install cargo-risczero && cargo risczero install
- name: Cargo test
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path proof_of_leadership/risc0/prover/Cargo.toml


lints:
name: Rust lints
Expand Down
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ members = [
"consensus/carnot-engine",
"consensus/cryptarchia-engine",
"ledger/cryptarchia-ledger",
"tests"
"cl/cl",
"tests",
]
resolver = "2"
exclude = ["proof_of_leadership/risc0/risc0_proofs"]
resolver = "2"
13 changes: 13 additions & 0 deletions cl/cl/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "cl"
version = "0.1.0"
edition = "2021"

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

[dependencies]
serde = {version="1.0", features = ["derive"]}
rand = "0.8.5"
rand_core = "0.6.0"
hex = "0.4.3"
sha2 = "0.10"
149 changes: 149 additions & 0 deletions cl/cl/src/balance.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
use rand_core::CryptoRngCore;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};

use crate::PartialTxWitness;

pub type Value = u64;
pub type Unit = [u8; 32];

#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
pub struct Balance([u8; 32]);

impl Balance {
pub fn to_bytes(&self) -> [u8; 32] {
self.0
}
}

#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct UnitBalance {
pub unit: Unit,
pub pos: u64,
pub neg: u64,
}

impl UnitBalance {
pub fn is_zero(&self) -> bool {
self.pos == self.neg
}
}

#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct BalanceWitness {
pub balances: Vec<UnitBalance>,
pub blinding: [u8; 16],
}

impl BalanceWitness {
pub fn random_blinding(mut rng: impl CryptoRngCore) -> [u8; 16] {
let mut blinding = [0u8; 16];
rng.fill_bytes(&mut blinding);

blinding
}

pub fn zero(blinding: [u8; 16]) -> Self {
Self {
balances: Default::default(),
blinding,
}
}

pub fn from_ptx(ptx: &PartialTxWitness, blinding: [u8; 16]) -> Self {
let mut balance = Self::zero(blinding);

for input in ptx.inputs.iter() {
balance.insert_negative(input.note.unit, input.note.value);
}

for output in ptx.outputs.iter() {
balance.insert_positive(output.note.unit, output.note.value);
}

balance.clear_zeros();

balance
}

pub fn insert_positive(&mut self, unit: Unit, value: Value) {
for unit_bal in self.balances.iter_mut() {
if unit_bal.unit == unit {
unit_bal.pos += value;
return;
}
}

// Unit was not found, so we must create one.
self.balances.push(UnitBalance {
unit,
pos: value,
neg: 0,
});
}

pub fn insert_negative(&mut self, unit: Unit, value: Value) {
for unit_bal in self.balances.iter_mut() {
if unit_bal.unit == unit {
unit_bal.neg += value;
return;
}
}

self.balances.push(UnitBalance {
unit,
pos: 0,
neg: value,
});
}

pub fn clear_zeros(&mut self) {
let mut i = 0usize;
while i < self.balances.len() {
if self.balances[i].is_zero() {
self.balances.swap_remove(i);
// don't increment `i` since the last element has been swapped into the
// `i`'th place
} else {
i += 1;
}
}
}

pub fn combine(balances: impl IntoIterator<Item = Self>, blinding: [u8; 16]) -> Self {
let mut combined = BalanceWitness::zero(blinding);

for balance in balances {
for unit_bal in balance.balances.iter() {
if unit_bal.pos > unit_bal.neg {
combined.insert_positive(unit_bal.unit, unit_bal.pos - unit_bal.neg);
} else {
combined.insert_negative(unit_bal.unit, unit_bal.neg - unit_bal.pos);
}
}
}

combined.clear_zeros();

combined
}

pub fn is_zero(&self) -> bool {
self.balances.is_empty()
}

pub fn commit(&self) -> Balance {
let mut hasher = Sha256::new();
hasher.update(b"NOMOS_CL_BAL_COMMIT");

for unit_balance in self.balances.iter() {
hasher.update(unit_balance.unit);
hasher.update(unit_balance.pos.to_le_bytes());
hasher.update(unit_balance.neg.to_le_bytes());
}
hasher.update(self.blinding);

let commit_bytes: [u8; 32] = hasher.finalize().into();
Balance(commit_bytes)
}
}
117 changes: 117 additions & 0 deletions cl/cl/src/bundle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
use serde::{Deserialize, Serialize};

use crate::{partial_tx::PartialTx, BalanceWitness, PartialTxWitness};

/// The transaction bundle is a collection of partial transactions.
/// The goal in bundling transactions is to produce a set of partial transactions
/// that balance each other.

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Bundle {
pub partials: Vec<PartialTx>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BundleWitness {
pub partials: Vec<PartialTxWitness>,
}

impl BundleWitness {
pub fn balance(&self) -> BalanceWitness {
BalanceWitness::combine(self.partials.iter().map(|ptx| ptx.balance()), [0u8; 16])
}

pub fn commit(&self) -> Bundle {
Bundle {
partials: Vec::from_iter(self.partials.iter().map(|ptx| ptx.commit())),
}
}
}

#[cfg(test)]
mod test {
use crate::{
balance::UnitBalance,
input::InputWitness,
note::{derive_unit, NoteWitness},
nullifier::NullifierSecret,
output::OutputWitness,
partial_tx::PartialTxWitness,
};

use super::*;

#[test]
fn test_bundle_balance() {
let mut rng = rand::thread_rng();
let (nmo, eth, crv) = (derive_unit("NMO"), derive_unit("ETH"), derive_unit("CRV"));

let nf_a = NullifierSecret::random(&mut rng);
let nf_b = NullifierSecret::random(&mut rng);
let nf_c = NullifierSecret::random(&mut rng);

let nmo_10_utxo = OutputWitness::new(NoteWitness::basic(10, nmo, &mut rng), nf_a.commit());
let nmo_10_in = InputWitness::from_output(nmo_10_utxo, nf_a);

let eth_23_utxo = OutputWitness::new(NoteWitness::basic(23, eth, &mut rng), nf_b.commit());
let eth_23_in = InputWitness::from_output(eth_23_utxo, nf_b);

let crv_4840_out =
OutputWitness::new(NoteWitness::basic(4840, crv, &mut rng), nf_c.commit());

let ptx_unbalanced = PartialTxWitness {
inputs: vec![nmo_10_in, eth_23_in],
outputs: vec![crv_4840_out],
balance_blinding: BalanceWitness::random_blinding(&mut rng),
};

let bundle_witness = BundleWitness {
partials: vec![ptx_unbalanced.clone()],
};

assert!(!bundle_witness.balance().is_zero());
assert_eq!(
bundle_witness.balance().balances,
vec![
UnitBalance {
unit: nmo,
pos: 0,
neg: 10
},
UnitBalance {
unit: eth,
pos: 0,
neg: 23
},
UnitBalance {
unit: crv,
pos: 4840,
neg: 0
},
]
);

let crv_4840_in = InputWitness::from_output(crv_4840_out, nf_c);
let nmo_10_out = OutputWitness::new(
NoteWitness::basic(10, nmo, &mut rng),
NullifierSecret::random(&mut rng).commit(), // transferring to a random owner
);
let eth_23_out = OutputWitness::new(
NoteWitness::basic(23, eth, &mut rng),
NullifierSecret::random(&mut rng).commit(), // transferring to a random owner
);

let ptx_solved = PartialTxWitness {
inputs: vec![crv_4840_in],
outputs: vec![nmo_10_out, eth_23_out],
balance_blinding: BalanceWitness::random_blinding(&mut rng),
};

let witness = BundleWitness {
partials: vec![ptx_unbalanced, ptx_solved],
};

assert!(witness.balance().is_zero());
assert_eq!(witness.balance().balances, vec![]);
}
}
4 changes: 4 additions & 0 deletions cl/cl/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#[derive(Debug)]
pub enum Error {
ProofFailed,
}
Loading

0 comments on commit 6f6bb61

Please sign in to comment.