Skip to content
Open

vroom #1380

Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[submodule "vroom"]
path = vroom
url = https://github.com/SimonLangowski/VROOM.git
[submodule "blst-src"]
path = blst-src
url = https://github.com/supranational/blst.git
5 changes: 3 additions & 2 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -235,11 +235,12 @@ dependencies = [
[[package]]
name = "blst"
version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcdb4c7013139a150f9fc55d123186dbfaba0d912817466282c73ac49e71fb45"
dependencies = [
"cc",
"glob",
"rand 0.8.5",
"rand_chacha 0.3.1",
"serde",
"threadpool",
"zeroize",
]
Expand Down
8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ repository = "https://github.com/Chia-Network/chia_rs"
[workspace]
members = ["crates/*", "crates/*/fuzz", "wasm", "wheel"]

[patch.crates-io]
# Use local blst (with optional VROOM pairing) so only one native lib is linked
blst = { path = "./crates/blst" }

[workspace.package]
version = "0.38.1"

Expand Down Expand Up @@ -142,7 +146,9 @@ chia-protocol-fuzz = { path = "./crates/chia-protocol/fuzz", version = "0.38.1"
chia-puzzle-types-fuzz = { path = "./crates/chia-puzzle-types/fuzz", version = "0.38.1" }
clvm-traits-fuzz = { path = "./crates/clvm-traits/fuzz", version = "0.38.1" }
clvm-utils-fuzz = { path = "./crates/clvm-utils/fuzz", version = "0.38.1" }
blst = { version = "0.3.16", features = ["portable"] }
# BLS backend. When feature "vroom" is enabled (e.g. via chia-bls), pairing uses
# VROOM's implementation (vroom/ submodule). Otherwise standard blst from blst-src.
blst = { path = "./crates/blst", default-features = false, features = ["portable"] }
clvmr = "0.17.1"
clvm-fuzzing = "0.17.0"
syn = "2.0.101"
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@ A collection of Rust crates for working with the Chia blockchain. There are also
- [Python](https://www.python.org/downloads/) 3.9 or higher installed.
- The [Rust toolchain](https://rustup.rs/) must be installed.

After cloning, initialize submodules (required for the optional **vroom** BLS backend):

```bash
git submodule update --init --recursive
```

### Optional: VROOM backend for pairing

To use [VROOM](https://github.com/SimonLangowski/VROOM)’s pairing implementation (AVX512 RNS optimizations) where supported, build with the `vroom` feature. All other BLS operations (keygen, sign, verify, aggregation) use the standard blst implementation; only pairing uses VROOM when this feature is enabled.

```bash
cargo build --features vroom # or add vroom to default features in your crate
```

## Unit Tests

To run the unit tests for the whole workspace:
Expand Down
1 change: 1 addition & 0 deletions blst-src
Submodule blst-src added at dafa98
36 changes: 36 additions & 0 deletions crates/blst/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[package]
name = "blst"
version = "0.3.16"
authors = ["sean-sn <sean@supranational.net>"]
edition = "2018"
license = "Apache-2.0"
description = "Bindings for blst BLS12-381 library (with optional VROOM pairing)"
repository = "https://github.com/supranational/blst"
categories = ["cryptography"]
keywords = ["crypto", "bls", "signature", "asm", "wasm"]
links = "blst"

[features]
default = []
portable = []
force-adx = []
no-threads = []
serde-secret = ["serde"]
# Use VROOM's pairing implementation where supported (AVX512 RNS optimizations)
vroom = []

[build-dependencies]
cc = "1.0"
[target.'cfg(target_env = "msvc")'.build-dependencies]
glob = "0.3"

[dependencies]
zeroize = { version = "^1.1", features = ["zeroize_derive"] }
serde = { version = "1.0.152", optional = true }

[target.'cfg(not(any(target_arch="wasm32", target_os="none", target_os="unknown", target_os="uefi")))'.dependencies]
threadpool = "^1.8.1"

[dev-dependencies]
rand = "0.8"
rand_chacha = "0.3"
256 changes: 256 additions & 0 deletions crates/blst/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
#![allow(unused_imports)]

extern crate cc;

use std::env;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

fn copy_dir_all(src: &Path, dst: &Path) -> io::Result<()> {
fs::create_dir_all(dst)?;
for entry in fs::read_dir(src)? {
let entry = entry?;
let ty = entry.file_type()?;
let dst_path = dst.join(entry.file_name());
if ty.is_dir() {
copy_dir_all(&entry.path(), &dst_path)?;
} else {
fs::copy(entry.path(), dst_path)?;
}
}
Ok(())
}

fn assembly(
file_vec: &mut Vec<PathBuf>,
base_dir: &Path,
_arch: &str,
_is_msvc: bool,
) {
#[cfg(target_env = "msvc")]
if _is_msvc {
let sfx = match _arch {
"x86_64" => "x86_64",
"aarch64" => "armv8",
_ => "unknown",
};
let files =
glob::glob(&format!("{}/win64/*-{}.asm", base_dir.display(), sfx))
.expect("unable to collect assembly files");
for file in files {
file_vec.push(file.unwrap());
}
return;
}

file_vec.push(base_dir.join("assembly.S"));
}

fn main() {
if env::var("CARGO_FEATURE_SERDE_SECRET").is_ok() {
println!(
"cargo:warning=blst: non-production feature serde-secret enabled"
);
}

let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
let target_family = env::var("CARGO_CFG_TARGET_FAMILY").unwrap_or_default();

let target_no_std = target_os.eq("none")
|| (target_os.eq("unknown") && target_arch.eq("wasm32"))
|| target_os.eq("uefi")
|| env::var("BLST_TEST_NO_STD").is_ok();

if !target_no_std {
println!("cargo:rustc-cfg=feature=\"std\"");
if target_arch.eq("wasm32") || target_os.eq("unknown") {
println!("cargo:rustc-cfg=feature=\"no-threads\"");
}
}
println!("cargo:rerun-if-env-changed=BLST_TEST_NO_STD");

let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let workspace_root = manifest_dir.parent().and_then(|p| p.parent());

if Path::new("libblst.a").exists() {
println!("cargo:rustc-link-search=.");
println!("cargo:rustc-link-lib=blst");
println!("cargo:rerun-if-changed=libblst.a");
return;
}

let mut blst_base_dir = manifest_dir.join("blst");
if !blst_base_dir.exists() {
blst_base_dir = workspace_root
.map(|r| r.join("blst-src"))
.unwrap_or_else(|| {
manifest_dir
.parent()
.and_then(|dir| dir.parent())
.expect("can't access workspace root or blst repo")
.join("blst-src")
});
}

// When vroom feature is enabled, build from a staging copy that uses VROOM's pairing.c
let use_vroom = env::var("CARGO_FEATURE_VROOM").is_ok();
if use_vroom {
if let Some(ws) = workspace_root {
let vroom_pairing = ws.join("vroom").join("blst").join("pairing.c");
let blst_src = ws.join("blst-src");
if vroom_pairing.exists() && blst_src.exists() {
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let staging = out_dir.join("blst_vroom_build");
let staging_src = staging.join("src");
let staging_build = staging.join("build");

println!("cargo:warning=blst: building with VROOM pairing (vroom/blst/pairing.c)");
fs::create_dir_all(&staging_src).expect("create staging src");
fs::create_dir_all(&staging_build).expect("create staging build");

copy_dir_all(&blst_src.join("src"), &staging_src)
.expect("copy blst src to staging");
copy_dir_all(&blst_src.join("build"), &staging_build)
.expect("copy blst build to staging");
fs::copy(&vroom_pairing, staging_src.join("pairing.c"))
.expect("copy VROOM pairing.c");

println!("cargo:rerun-if-changed={}", vroom_pairing.display());
blst_base_dir = staging;
}
}
}
Comment thread
cursor[bot] marked this conversation as resolved.

if !blst_base_dir.exists() {
panic!(
"blst source not found at {} (set vroom feature and init submodules, or add blst-src)",
blst_base_dir.display()
);
}
println!("Using blst source directory {}", blst_base_dir.display());

if target_os.eq("uefi") && env::var("CC").is_err() {
match std::process::Command::new("clang").arg("--version").output() {
Ok(_) => env::set_var("CC", "clang"),
Err(_) => {}
}
}

if target_env.eq("sgx") && env::var("CC").is_err() {
if let Ok(out) = std::process::Command::new("clang").arg("--version").output() {
let version = String::from_utf8(out.stdout).unwrap_or_default();
if let Some(x) = version.find("clang version ") {
let x = x + 14;
let y = version[x..].find('.').unwrap_or(0);
if version[x..x + y].parse::<i32>().unwrap_or(0) >= 11 {
env::set_var("CC", "clang");
}
}
}
}

if target_env.eq("msvc")
&& env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap().eq("32")
&& env::var("CC").is_err()
{
if let Ok(out) =
std::process::Command::new("clang-cl").args(["-m32", "--version"]).output()
{
if String::from_utf8(out.stdout).unwrap_or_default()
.contains("Target: i386-pc-windows-msvc")
{
env::set_var("CC", "clang-cl");
}
}
}

let mut cc = cc::Build::new();

let c_src_dir = blst_base_dir.join("src");
println!("cargo:rerun-if-changed={}", c_src_dir.display());
let mut file_vec = vec![c_src_dir.join("server.c")];

if target_arch.eq("x86_64") || target_arch.eq("aarch64") {
let asm_dir = blst_base_dir.join("build");
println!("cargo:rerun-if-changed={}", asm_dir.display());
assembly(
&mut file_vec,
&asm_dir,
&target_arch,
cc.get_compiler().is_like_msvc(),
);
} else {
cc.define("__BLST_NO_ASM__", None);
}
match (cfg!(feature = "portable"), cfg!(feature = "force-adx")) {
(true, false) => {
if target_arch.eq("x86_64") && target_env.eq("sgx") {
panic!("'portable' is not supported on SGX target");
}
println!("cargo:warning=blst: compiling in portable mode");
cc.define("__BLST_PORTABLE__", None);
}
(false, true) => {
if target_arch.eq("x86_64") {
cc.define("__ADX__", None);
}
}
(false, false) => {
if target_arch.eq("x86_64") {
if target_env.eq("sgx") {
cc.define("__ADX__", None);
} else if env::var("CARGO_ENCODED_RUSTFLAGS")
.unwrap_or_default()
.contains("target-cpu=")
{
let feat_list = env::var("CARGO_CFG_TARGET_FEATURE").unwrap_or_default();
let features: Vec<_> = feat_list.split(',').collect();
if !features.contains(&"ssse3") {
cc.define("__BLST_PORTABLE__", None);
} else if features.contains(&"adx") {
cc.define("__ADX__", None);
}
} else {
#[cfg(target_arch = "x86_64")]
if std::is_x86_feature_detected!("adx") {
cc.define("__ADX__", None);
}
}
}
}
(true, true) => panic!("Cannot compile with both `portable` and `force-adx` features"),
}
if target_env.eq("msvc") && cc.get_compiler().is_like_msvc() {
cc.flag("-Zl");
}
cc.flag_if_supported("-mno-avx")
.flag_if_supported("-fno-builtin")
.flag_if_supported("-Wno-unused-function")
.flag_if_supported("-Wno-unused-command-line-argument");
if target_arch.eq("wasm32") || target_family.is_empty() {
cc.flag("-ffreestanding");
}
if target_arch.eq("wasm32") || target_no_std {
cc.define("SCRATCH_LIMIT", "(45 * 1024)");
}
if target_env.eq("sgx") {
cc.flag_if_supported("-mlvi-hardening");
cc.define("__SGX_LVI_HARDENING__", None);
cc.define("__BLST_NO_CPUID__", None);
cc.define("__ELF__", None);
cc.define("SCRATCH_LIMIT", "(45 * 1024)");
}
if !cfg!(debug_assertions) {
cc.opt_level(2);
}
cc.files(&file_vec).compile("blst");

let bindings = blst_base_dir.join("bindings");
if bindings.exists() {
println!("cargo:BINDINGS={}", bindings.to_string_lossy());
}
println!("cargo:C_SRC={}", c_src_dir.to_string_lossy());
}
1 change: 1 addition & 0 deletions crates/blst/rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
max_width = 80
Loading
Loading