Skip to content

Commit

Permalink
Chia proof of space re-implementation in Rust
Browse files Browse the repository at this point in the history
  • Loading branch information
nazar-pc committed May 11, 2023
1 parent e2c0429 commit 4d19fe6
Show file tree
Hide file tree
Showing 15 changed files with 2,449 additions and 8 deletions.
39 changes: 38 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ members = [
#
# This list is ordered alphabetically.
[profile.dev.package]
bitvec = { opt-level = 3 }
blake2 = { opt-level = 3 }
blake3 = { opt-level = 3 }
blake2b_simd = { opt-level = 3 }
blst = { opt-level = 3 }
blst_from_scratch = { opt-level = 3 }
chacha20 = { opt-level = 3 }
chacha20poly1305 = { opt-level = 3 }
cranelift-codegen = { opt-level = 3 }
cranelift-wasm = { opt-level = 3 }
Expand Down
30 changes: 30 additions & 0 deletions crates/subspace-proof-of-space/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,29 @@ include = [
bench = false

[dependencies]
bitvec = { version = "1.0.1", default-features = false, features = ["alloc", "atomic"], optional = true }
blake3 = { version = "1.3.3", default-features = false, optional = true }
chacha20 = { version = "0.9.1", default-features = false, optional = true }
subspace-chiapos = { git = "https://github.com/subspace/chiapos", rev = "3b1ab3ca24764d25da30e0c8243e0bf304b776a5", optional = true }
subspace-core-primitives = { version = "0.1.0", path = "../subspace-core-primitives", default-features = false }

# Ugly workaround for https://github.com/rust-lang/cargo/issues/1197
[target.'cfg(any(target_os = "linux", target_os = "macos", all(target_os = "windows", target_env = "gnu")))'.dependencies.sha2]
features = ["asm"]
version = "0.10.6"
optional = true

# Ugly workaround for https://github.com/rust-lang/cargo/issues/1197
# `asm` feature is not supported on Windows except with GNU toolchain
[target.'cfg(not(any(target_os = "linux", target_os = "macos", all(target_os = "windows", target_env = "gnu"))))'.dependencies.sha2]
default-features = false
version = "0.10.6"
optional = true

[dev-dependencies]
criterion = "0.4.0"
rand = "0.8.5"
subspace-chiapos = { git = "https://github.com/subspace/chiapos", rev = "3b1ab3ca24764d25da30e0c8243e0bf304b776a5" }

[[bench]]
name = "pos"
Expand All @@ -29,13 +47,25 @@ harness = false
[features]
default = ["std"]
std = [
"bitvec?/std",
"blake3?/std",
"chacha20?/std",
"subspace-core-primitives/std",
]
# Enable Chia proof of space support (legacy implementation uses C++ chiapos), only works in `std` environment for now
chia-legacy = [
"std",
"subspace-chiapos",
]
# Enable Chia proof of space support, using alternative implementation, works in no-std environment as well
chia = [
"bitvec",
"blake3",
"chacha20",
"sha2",
]
# Enable support for all possible K for chia: from smallest to insanely large as well as not popular in general
all-chia-k = []
# Enables shim proof of space that works much faster than original and can be used for testing purposes to reduce memory
# and CPU usage
shim = []
26 changes: 20 additions & 6 deletions crates/subspace-proof-of-space/benches/pos.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
#![feature(const_trait_impl)]

#[cfg(any(feature = "chia-legacy", feature = "shim"))]
#[cfg(any(feature = "chia-legacy", feature = "chia", feature = "shim"))]
use criterion::black_box;
use criterion::{criterion_group, criterion_main, Criterion};
#[cfg(any(feature = "chia-legacy", feature = "shim"))]
#[cfg(any(feature = "chia-legacy", feature = "chia", feature = "shim"))]
use subspace_core_primitives::PosSeed;
#[cfg(any(feature = "chia-legacy", feature = "shim"))]
#[cfg(any(feature = "chia-legacy", feature = "chia", feature = "shim"))]
use subspace_proof_of_space::{Quality, Table};

#[cfg(any(feature = "chia-legacy", feature = "shim"))]
#[cfg(any(feature = "chia-legacy", feature = "chia", feature = "shim"))]
const SEED: PosSeed = PosSeed::from([
35, 2, 52, 4, 51, 55, 23, 84, 91, 10, 111, 12, 13, 222, 151, 16, 228, 211, 254, 45, 92, 198,
204, 10, 9, 10, 11, 129, 139, 171, 15, 23,
]);

#[cfg(any(feature = "chia-legacy", feature = "shim"))]
#[cfg(any(feature = "chia-legacy", feature = "chia", feature = "shim"))]
fn pos_bench<PosTable>(
c: &mut Criterion,
name: &'static str,
Expand Down Expand Up @@ -70,7 +70,7 @@ fn pos_bench<PosTable>(
}

pub fn criterion_benchmark(c: &mut Criterion) {
#[cfg(not(any(feature = "chia-legacy", feature = "shim")))]
#[cfg(not(any(feature = "chia-legacy", feature = "chia", feature = "shim")))]
{
let _ = c;
panic!(r#"Enable "chia" and/or "shim" feature to run benches"#);
Expand All @@ -82,6 +82,20 @@ pub fn criterion_benchmark(c: &mut Criterion) {
// This challenge index with above seed is known to have a solution
let challenge_index_with_solution = 1;

pos_bench::<subspace_proof_of_space::chia_legacy::ChiaTable>(
c,
"chia-legacy",
challenge_index_without_solution,
challenge_index_with_solution,
)
}
#[cfg(feature = "chia")]
{
// This challenge index with above seed is known to not have a solution
let challenge_index_without_solution = 1232460437;
// This challenge index with above seed is known to have a solution
let challenge_index_with_solution = 124537303;

pos_bench::<subspace_proof_of_space::chia::ChiaTable>(
c,
"chia",
Expand Down
98 changes: 98 additions & 0 deletions crates/subspace-proof-of-space/src/chia.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//! Chia proof of space implementation
use crate::chiapos::Tables;
use crate::{PosTableType, Quality, Table};
use core::mem;
use subspace_core_primitives::{PosProof, PosQualityBytes, PosSeed};

const K: u8 = 17;

/// Abstraction that represents quality of the solution in the table.
///
/// Chia implementation.
#[derive(Debug)]
#[must_use]
pub struct ChiaQuality<'a> {
bytes: PosQualityBytes,
challenge: [u8; 32],
tables: &'a Tables<K>,
}

impl<'a> Quality for ChiaQuality<'a> {
fn to_bytes(&self) -> PosQualityBytes {
self.bytes
}

fn create_proof(&self) -> PosProof {
self.tables
.find_proof(&self.challenge)
.next()
.map(PosProof::from)
.expect("Proof always exists if quality exists; qed")
}
}

/// Subspace proof of space table
///
/// Chia implementation.
#[derive(Debug)]
pub struct ChiaTable {
tables: Tables<K>,
}

impl Table for ChiaTable {
const TABLE_TYPE: PosTableType = PosTableType::Chia;

type Quality<'a> = ChiaQuality<'a>;

fn generate(seed: &PosSeed) -> ChiaTable {
Self {
tables: Tables::<K>::create_simple((*seed).into()),
}
}

fn find_quality(&self, challenge_index: u32) -> Option<Self::Quality<'_>> {
let mut challenge = [0; 32];
challenge[..mem::size_of::<u32>()].copy_from_slice(&challenge_index.to_le_bytes());
let maybe_quality = self.tables.find_quality(&challenge).next();
maybe_quality.map(|quality| ChiaQuality {
bytes: PosQualityBytes::from(quality),
challenge,
tables: &self.tables,
})
}

fn is_proof_valid(
seed: &PosSeed,
challenge_index: u32,
proof: &PosProof,
) -> Option<PosQualityBytes> {
let mut challenge = [0; 32];
challenge[..mem::size_of::<u32>()].copy_from_slice(&challenge_index.to_le_bytes());
Tables::<K>::verify(**seed, &challenge, proof).map(PosQualityBytes::from)
}
}

#[cfg(test)]
mod tests {
use super::*;

const SEED: PosSeed = PosSeed::from([
35, 2, 52, 4, 51, 55, 23, 84, 91, 10, 111, 12, 13, 222, 151, 16, 228, 211, 254, 45, 92,
198, 204, 10, 9, 10, 11, 129, 139, 171, 15, 23,
]);

#[test]
fn basic() {
let table = ChiaTable::generate(&SEED);

assert!(table.find_quality(1232460437).is_none());

{
let challenge_index = 124537303;
let quality = table.find_quality(challenge_index).unwrap();
let proof = quality.create_proof();
let maybe_quality = ChiaTable::is_proof_valid(&SEED, challenge_index, &proof);
assert_eq!(maybe_quality, Some(quality.to_bytes()));
}
}
}
Loading

0 comments on commit 4d19fe6

Please sign in to comment.