Skip to content

Commit

Permalink
feat: make it #[no_std] compatible (#280)
Browse files Browse the repository at this point in the history
* make it #[no_std] comptabile

* chore: bump rust to 1.78, msrv to 1.73 and use cargo clippy

* fix: use std when its possible for floats

* fix: CI

* refactor: remove unnecessary qualification

* ci: set features correctly on opencl build

* chore: add Unicode 3.0 to allow licenses
  • Loading branch information
th7nder authored Dec 4, 2024
1 parent 8f180e1 commit adad955
Show file tree
Hide file tree
Showing 16 changed files with 100 additions and 43 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ jobs:
- run: nvcc --version
- name: CUDA tests
run: |
cargo nextest run --release --no-default-features --features cuda,pasta,bls,arity2,arity4,arity8,arity11,arity16,arity24,arity36
cargo nextest run --release --no-default-features --features std,cuda,pasta,bls,arity2,arity4,arity8,arity11,arity16,arity24,arity36
# Runs the test suite on a self-hosted GPU machine with CUDA and OpenCL enabled (that is using the OpenCL backend for NVIDIA GPUs)
test-opencl:
Expand Down Expand Up @@ -152,4 +152,4 @@ jobs:
- run: clinfo
- name: OpenCL tests
run: |
cargo nextest run --release --all-features
cargo nextest run --release --no-default-features --features std,strengthened,abomonation,opencl,pasta,bls,arity2,arity4,arity8,arity11,arity16,arity24,arity36
18 changes: 10 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
[package]
name = "neptune"
description = "Poseidon hashing over BLS12-381 for Filecoin."
version = "13.0.0"
version = "14.0.0"
authors = ["porcuquine <[email protected]>"]
edition = "2021"
license = "MIT OR Apache-2.0"
repository = "https://github.com/argumentcomputer/neptune"
rust-version = "1.71.0"
rust-version = "1.73.0"

[dependencies]
bellpepper = { workspace = true }
bellpepper-core = { workspace = true }
bellpepper = { workspace = true, optional = true }
bellpepper-core = { workspace = true, optional = true }
blake2s_simd = { workspace = true }
blstrs = { workspace = true, optional = true }
byteorder = { workspace = true }
ec-gpu = { workspace = true, optional = true }
ec-gpu-gen = { workspace = true, optional = true }
ff ={ workspace = true }
libm = { workspace = true }
ff = { workspace = true }
generic-array = { workspace = true }
pasta_curves = { workspace = true, features = ["serde"] }
serde = { version = "1.0", features = ["derive"] }
serde = { version = "1.0", features = ["derive"], optional = true }
trait-set = "0.3.0"
abomonation = { version = "0.7.3", optional = true }
abomonation_derive = { version = "0.1.0", package = "abomonation_derive_ng", optional = true }
Expand Down Expand Up @@ -57,7 +57,7 @@ incremental = false
codegen-units = 1

[features]
default = ["bls", "pasta"]
default = ["std", "bls", "pasta"]
cuda = ["ec-gpu-gen/cuda", "ec-gpu"]
opencl = ["ec-gpu-gen/opencl", "ec-gpu"]
# The supported arities for Poseidon running on the GPU are specified at compile-time.
Expand All @@ -74,6 +74,7 @@ strengthened = []
bls = ["blstrs/gpu"]
pasta = ["pasta_curves/gpu"]
portable = ["blstrs/portable"]
std = ["dep:serde", "dep:bellpepper", "dep:bellpepper-core"]
# Unsafe Abomonation-based serialization
abomonation = ["dep:abomonation", "dep:abomonation_derive"]

Expand All @@ -90,6 +91,7 @@ bellpepper = { version = "0.4.0", default-features = false }
blake2s_simd = "1.0.1"
blstrs = { version = "0.7.0" }
ff = "0.13.0"
libm = "0.2.8"
generic-array = "1.0"
pasta_curves = { version = "0.5" }
ec-gpu = { version = "0.2.0" }
Expand Down
1 change: 1 addition & 0 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ allow = [
"CC0-1.0",
"Apache-2.0",
"Unicode-DFS-2016",
"Unicode-3.0",
]
# List of explicitly disallowed licenses
# See https://spdx.org/licenses/ for list of possible licenses
Expand Down
2 changes: 1 addition & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[toolchain]
# The default profile includes rustc, rust-std, cargo, rust-docs, rustfmt and clippy.
profile = "default"
channel = "1.76"
channel = "1.78"
2 changes: 1 addition & 1 deletion src/column_tree_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ where
let end = start + column_count;

if end > self.leaf_count {
return Err(Error::Other("too many columns".to_string()));
return Err(Error::Other("too many columns"));
}

match self.column_batcher {
Expand Down
9 changes: 6 additions & 3 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{error, fmt};
use core::fmt;

#[derive(Debug, Clone)]
#[cfg(any(feature = "cuda", feature = "opencl"))]
Expand Down Expand Up @@ -47,10 +47,11 @@ pub enum Error {
FullBuffer,
/// Attempt to reference an index element that is out of bounds
IndexOutOfBounds,
#[cfg(any(feature = "cuda", feature = "opencl"))]
GpuError(String),
#[cfg(any(feature = "cuda", feature = "opencl"))]
ClError(ClError),
Other(String),
Other(&'static str),
}

#[cfg(any(feature = "cuda", feature = "opencl"))]
Expand All @@ -67,7 +68,8 @@ impl From<ec_gpu_gen::EcError> for Error {
}
}

impl error::Error for Error {}
#[cfg(feature = "std")]
impl std::error::Error for Error {}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
Expand All @@ -77,6 +79,7 @@ impl fmt::Display for Error {
"The size of the buffer cannot be greater than the hash arity."
),
Error::IndexOutOfBounds => write!(f, "The referenced index is outs of bounds."),
#[cfg(any(feature = "cuda", feature = "opencl"))]
Error::GpuError(s) => write!(f, "GPU Error: {s}"),
#[cfg(any(feature = "cuda", feature = "opencl"))]
Error::ClError(e) => write!(f, "OpenCL Error: {e}"),
Expand Down
14 changes: 10 additions & 4 deletions src/hash_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,16 @@ use abomonation::Abomonation;
#[cfg(feature = "abomonation")]
use abomonation_derive::Abomonation;
use ff::PrimeField;
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "std",
serde(bound(serialize = "F: Serialize", deserialize = "F: Deserialize<'de>"))
)]
#[cfg_attr(feature = "abomonation", derive(Abomonation))]
#[serde(bound(serialize = "F: Serialize", deserialize = "F: Deserialize<'de>"))]
#[cfg_attr(feature = "abomonation", abomonation_omit_bounds)]
pub enum HashType<F: PrimeField, A: Arity<F>> {
MerkleTree,
Expand Down Expand Up @@ -73,7 +78,8 @@ impl<F: PrimeField, A: Arity<F>> HashType<F, A> {
}
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "abomonation", derive(Abomonation))]
#[cfg_attr(feature = "abomonation", abomonation_omit_bounds)]
pub enum CType<F: PrimeField, A: Arity<F>> {
Expand All @@ -82,7 +88,7 @@ pub enum CType<F: PrimeField, A: Arity<F>> {
// This is a bit of a hack, but since `serde(skip)` tags the last variant arm,
// the generated code ends up being correct. But, in the future, do not
// carelessly add new variants to this enum.
#[serde(skip)]
#[cfg_attr(feature = "std", serde(skip))]
#[cfg_attr(feature = "abomonation", abomonation_skip)]
_Phantom((F, A)),
}
Expand Down
20 changes: 15 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![allow(dead_code)]
#![allow(unused_imports)]

extern crate alloc;
pub use alloc::vec::Vec;

pub use crate::poseidon::{Arity, Poseidon};
use crate::round_constants::generate_constants;
use crate::round_numbers::{round_numbers_base, round_numbers_strengthened};
Expand All @@ -11,8 +15,8 @@ use blstrs::Scalar as Fr;
pub use error::Error;
use ff::PrimeField;
use generic_array::GenericArray;
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};
use std::fmt;
use trait_set::trait_set;

// See https://www.lurklurk.org/effective-rust/re-export.html
Expand Down Expand Up @@ -45,8 +49,11 @@ compile_error!("The `strengthened` feature needs the `cuda` and/or `opencl` feat
compile_error!("The `cuda` and `opencl` features need the `bls` and/or `pasta` feature to be set");

/// Poseidon circuit
#[cfg(feature = "std")]
pub mod circuit;
#[cfg(feature = "std")]
pub mod circuit2;
#[cfg(feature = "std")]
pub mod circuit2_witness;
pub mod error;
mod matrix;
Expand All @@ -60,6 +67,7 @@ mod round_constants;
mod round_numbers;

/// Sponge
#[cfg(any(test, feature = "std"))]
pub mod sponge;

/// Hash types and domain separation tags.
Expand Down Expand Up @@ -97,21 +105,23 @@ trait_set! {
pub trait NeptuneField = PrimeField + ec_gpu::GpuName;
}

#[cfg(feature = "std")]
mod serde_impl;

pub(crate) const TEST_SEED: [u8; 16] = [
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5,
];

#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "abomonation", derive(Abomonation))]
pub enum Strength {
Standard,
Strengthened,
}

impl fmt::Display for Strength {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
impl core::fmt::Display for Strength {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Standard => write!(f, "standard"),
Self::Strengthened => write!(f, "strengthened"),
Expand Down Expand Up @@ -183,7 +193,7 @@ fn round_constants<F: PrimeField>(arity: usize, strength: &Strength) -> Vec<F> {

let fr_num_bits = F::NUM_BITS;
let field_size = {
assert!(fr_num_bits <= u32::from(std::u16::MAX));
assert!(fr_num_bits <= u32::from(core::u16::MAX));
// It's safe to convert to u16 for compatibility with other types.
fr_num_bits as u16
};
Expand Down
7 changes: 4 additions & 3 deletions src/matrix.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Allow `&Matrix` in function signatures.
#![allow(clippy::ptr_arg)]

use crate::Vec;
use ff::PrimeField;

/// Matrix functions here are, at least for now, quick and dirty — intended only to support precomputation of poseidon optimization.
Expand Down Expand Up @@ -116,7 +117,7 @@ pub(crate) fn left_apply_matrix<F: PrimeField>(m: &Matrix<F>, v: &[F]) -> Vec<F>
"Matrix can only be applied to vector of same size."
);

let mut result = vec![F::ZERO; v.len()];
let mut result = alloc::vec![F::ZERO; v.len()];

for (result, row) in result.iter_mut().zip(m.iter()) {
for (mat_val, vec_val) in row.iter().zip(v) {
Expand All @@ -137,7 +138,7 @@ pub(crate) fn apply_matrix<F: PrimeField>(m: &Matrix<F>, v: &[F]) -> Vec<F> {
"Matrix can only be applied to vector of same size."
);

let mut result = vec![F::ZERO; v.len()];
let mut result = alloc::vec![F::ZERO; v.len()];
for (j, val) in result.iter_mut().enumerate() {
for (i, row) in m.iter().enumerate() {
let mut tmp = row[j];
Expand Down Expand Up @@ -165,7 +166,7 @@ pub(crate) fn transpose<F: PrimeField>(matrix: &Matrix<F>) -> Matrix<F> {

#[allow(clippy::needless_range_loop)]
pub(crate) fn make_identity<F: PrimeField>(size: usize) -> Matrix<F> {
let mut result = vec![vec![F::ZERO; size]; size];
let mut result = alloc::vec![alloc::vec![F::ZERO; size]; size];
for i in 0..size {
result[i][i] = F::ONE;
}
Expand Down
14 changes: 9 additions & 5 deletions src/mds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@ use abomonation::Abomonation;
#[cfg(feature = "abomonation")]
use abomonation_derive::Abomonation;
use ff::PrimeField;
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};

use crate::matrix;
use crate::matrix::{
apply_matrix, invert, is_identity, is_invertible, is_square, left_apply_matrix, mat_mul, minor,
transpose, Matrix,
};
use crate::Vec;

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "abomonation", derive(Abomonation))]
#[cfg_attr(feature = "abomonation", abomonation_bounds(where F::Repr: Abomonation))]
pub struct MdsMatrices<F: PrimeField> {
Expand Down Expand Up @@ -58,7 +61,8 @@ pub(crate) fn derive_mds_matrices<F: PrimeField>(m: Matrix<F>) -> MdsMatrices<F>
/// This means its first row and column are each dense, and the interior matrix
/// (minor to the element in both the row and column) is the identity.
/// We will pluralize this compact structure `sparse_matrixes` to distinguish from `sparse_matrices` from which they are created.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "abomonation", derive(Abomonation))]
#[cfg_attr(feature = "abomonation", abomonation_bounds(where F::Repr: Abomonation))]
pub struct SparseMatrix<F: PrimeField> {
Expand Down Expand Up @@ -174,12 +178,12 @@ fn make_prime<F: PrimeField>(m: &Matrix<F>) -> Matrix<F> {
.enumerate()
.map(|(i, row)| match i {
0 => {
let mut new_row = vec![F::ZERO; row.len()];
let mut new_row = alloc::vec![F::ZERO; row.len()];
new_row[0] = F::ONE;
new_row
}
_ => {
let mut new_row = vec![F::ZERO; row.len()];
let mut new_row = alloc::vec![F::ZERO; row.len()];
new_row[1..].copy_from_slice(&row[1..]);
new_row
}
Expand All @@ -201,7 +205,7 @@ fn make_double_prime<F: PrimeField>(m: &Matrix<F>, m_hat_inv: &Matrix<F>) -> Mat
new_row
}
_ => {
let mut new_row = vec![F::ZERO; row.len()];
let mut new_row = alloc::vec![F::ZERO; row.len()];
new_row[0] = w_hat[i - 1];
new_row[i] = F::ONE;
new_row
Expand Down
11 changes: 7 additions & 4 deletions src/poseidon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@ use crate::mds::{
};
use crate::poseidon_alt::{hash_correct, hash_optimized_dynamic};
use crate::preprocessing::compress_round_constants;
use crate::Vec;
use crate::{matrix, quintic_s_box, BatchHasher, Strength, DEFAULT_STRENGTH};
use crate::{round_constants, round_numbers, Error};
#[cfg(feature = "abomonation")]
use abomonation::Abomonation;
#[cfg(feature = "abomonation")]
use abomonation_derive::Abomonation;
use core::marker::PhantomData;
use ff::PrimeField;
use generic_array::{sequence::GenericSequence, typenum, ArrayLength, GenericArray};
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};
use std::marker::PhantomData;
use typenum::marker_traits::Unsigned;
use typenum::*;

Expand Down Expand Up @@ -868,12 +870,12 @@ where
}
}

let _ = std::mem::replace(&mut self.elements, result);
let _ = core::mem::replace(&mut self.elements, result);
}

pub(crate) fn product_mds_with_matrix_left(&mut self, matrix: &Matrix<F>) {
let result = left_apply_matrix(matrix, &self.elements);
let _ = std::mem::replace(
let _ = core::mem::replace(
&mut self.elements,
GenericArray::<F, A::ConstantsSize>::generate(|i| result[i]),
);
Expand All @@ -900,9 +902,10 @@ where
val.add_assign(&tmp);
}

let _ = std::mem::replace(&mut self.elements, result);
let _ = core::mem::replace(&mut self.elements, result);
}

#[cfg(feature = "std")]
pub(crate) fn debug(&self, msg: &str) {
dbg!(msg, &self.constants_offset, &self.elements);
}
Expand Down
1 change: 1 addition & 0 deletions src/poseidon_alt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//! These are tested (in `poseidon::test`) to be equivalent to the 'static optimized' version
//! used for actual hashing by the neptune library.
use crate::poseidon::{Arity, Poseidon};
use crate::Vec;
use crate::{matrix, quintic_s_box};
use ff::PrimeField;

Expand Down
Loading

0 comments on commit adad955

Please sign in to comment.