Skip to content

Commit 116eaff

Browse files
authored
feat: no_std support. (#79)
1 parent 13d4cd2 commit 116eaff

File tree

19 files changed

+141
-28
lines changed

19 files changed

+141
-28
lines changed

.github/workflows/rust.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,30 @@ jobs:
2626
- name: Run tests
2727
run: cargo test --verbose
2828

29+
no-std-check:
30+
runs-on: ubuntu-latest
31+
32+
steps:
33+
- uses: actions/checkout@v3
34+
- name: Install Rust toolchain
35+
uses: actions-rs/toolchain@v1
36+
with:
37+
toolchain: stable
38+
profile: minimal
39+
override: true
40+
- name: Check no_std compilation
41+
run: |
42+
echo "Checking no_std compilation..."
43+
cargo check --no-default-features --verbose
44+
- name: Check std compilation
45+
run: |
46+
echo "Checking std compilation..."
47+
cargo check --verbose
48+
- name: Check all features
49+
run: |
50+
echo "Checking with all features..."
51+
cargo check --all-features --verbose
52+
2953
3054
full-setup:
3155

@@ -46,5 +70,7 @@ jobs:
4670

4771
- name: Build (nightly)
4872
run: cargo +${{ matrix.toolchain }} build --all-features --verbose
73+
- name: Build no_std (nightly)
74+
run: cargo +${{ matrix.toolchain }} build --no-default-features --verbose
4975
- name: Run tests (nightly)
5076
run: cargo +${{ matrix.toolchain }} test --all-features --verbose

Cargo.toml

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,25 @@ exclude = [
1919
".gitignore"
2020
]
2121

22+
[features]
23+
default = ["std"]
24+
std = ["thiserror", "rand", "num-bigint/std", "num-traits/std", "sha3/std", "rand_core/std"]
25+
2226
[dependencies]
2327
ff = { version = "0.13", features = ["derive"] }
2428
group = "0.13.0"
25-
num-bigint = "0.4.6"
26-
num-traits = "0.2.19"
27-
rand = "0.8.5"
28-
sha3 = "0.10.8"
29-
subtle = "2.6.1"
30-
thiserror = "1"
31-
keccak = "0.1.5"
32-
zerocopy = "0.8"
33-
zeroize = "1.8.1"
29+
num-bigint = { version = "0.4.6", default-features = false }
30+
num-traits = { version = "0.2.19", default-features = false, features = ["libm"] }
31+
rand = { version = "0.8.5", optional = true }
32+
rand_core = { version = "0.6", default-features = false }
33+
sha3 = { version = "0.10.8", default-features = false }
34+
subtle = { version = "2.6.1", default-features = false }
35+
thiserror = { version = "1", optional = true }
36+
keccak = { version = "0.1.5", default-features = false }
37+
zerocopy = { version = "0.8", default-features = false }
38+
zeroize = { version = "1.8.1", default-features = false, features = ["alloc"] }
39+
hashbrown = { version = "0.15", default-features = false }
40+
ahash = { version = "0.8", default-features = false }
3441

3542
[dev-dependencies]
3643
bls12_381 = "0.8.0"

src/codec.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use crate::duplex_sponge::DuplexSpongeInterface;
44
pub use crate::duplex_sponge::{keccak::KeccakDuplexSponge, shake::ShakeDuplexSponge};
5+
use alloc::vec;
56
use ff::PrimeField;
67
use group::prime::PrimeGroup;
78
use num_bigint::BigUint;

src/composition.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,13 @@
1818
//! )
1919
//! ```
2020
21+
use alloc::vec::Vec;
2122
use ff::{Field, PrimeField};
2223
use group::prime::PrimeGroup;
24+
#[cfg(feature = "std")]
25+
use rand::{CryptoRng, Rng};
26+
#[cfg(not(feature = "std"))]
27+
use rand_core::{CryptoRng, RngCore as Rng};
2328
use sha3::{Digest, Sha3_256};
2429
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
2530

@@ -162,7 +167,7 @@ impl<G: PrimeGroup + ConstantTimeEq> ComposedRelation<G> {
162167
fn prover_commit_simple(
163168
protocol: &CanonicalLinearRelation<G>,
164169
witness: &<CanonicalLinearRelation<G> as SigmaProtocol>::Witness,
165-
rng: &mut (impl rand::Rng + rand::CryptoRng),
170+
rng: &mut (impl Rng + CryptoRng),
166171
) -> Result<(ComposedCommitment<G>, ComposedProverState<G>), Error> {
167172
protocol.prover_commit(witness, rng).map(|(c, s)| {
168173
(
@@ -185,7 +190,7 @@ impl<G: PrimeGroup + ConstantTimeEq> ComposedRelation<G> {
185190
fn prover_commit_and(
186191
protocols: &[ComposedRelation<G>],
187192
witnesses: &[ComposedWitness<G>],
188-
rng: &mut (impl rand::Rng + rand::CryptoRng),
193+
rng: &mut (impl Rng + CryptoRng),
189194
) -> Result<(ComposedCommitment<G>, ComposedProverState<G>), Error> {
190195
if protocols.len() != witnesses.len() {
191196
return Err(Error::InvalidInstanceWitnessPair);
@@ -227,7 +232,7 @@ impl<G: PrimeGroup + ConstantTimeEq> ComposedRelation<G> {
227232
fn prover_commit_or(
228233
instances: &[ComposedRelation<G>],
229234
witnesses: &[ComposedWitness<G>],
230-
rng: &mut (impl rand::Rng + rand::CryptoRng),
235+
rng: &mut (impl Rng + CryptoRng),
231236
) -> Result<(ComposedCommitment<G>, ComposedProverState<G>), Error> {
232237
if instances.len() != witnesses.len() {
233238
return Err(Error::InvalidInstanceWitnessPair);
@@ -360,7 +365,7 @@ impl<G: PrimeGroup + ConstantTimeEq> SigmaProtocol for ComposedRelation<G> {
360365
fn prover_commit(
361366
&self,
362367
witness: &Self::Witness,
363-
rng: &mut (impl rand::Rng + rand::CryptoRng),
368+
rng: &mut (impl Rng + CryptoRng),
364369
) -> Result<(Self::Commitment, Self::ProverState), Error> {
365370
match (self, witness) {
366371
(ComposedRelation::Simple(p), ComposedWitness::Simple(w)) => {
@@ -634,7 +639,7 @@ impl<G: PrimeGroup + ConstantTimeEq> SigmaProtocolSimulator for ComposedRelation
634639
}
635640
}
636641

637-
fn simulate_response<R: rand::Rng + rand::CryptoRng>(&self, rng: &mut R) -> Self::Response {
642+
fn simulate_response<R: Rng + CryptoRng>(&self, rng: &mut R) -> Self::Response {
638643
match self {
639644
ComposedRelation::Simple(p) => ComposedResponse::Simple(p.simulate_response(rng)),
640645
ComposedRelation::And(ps) => {
@@ -654,7 +659,7 @@ impl<G: PrimeGroup + ConstantTimeEq> SigmaProtocolSimulator for ComposedRelation
654659
}
655660
}
656661

657-
fn simulate_transcript<R: rand::Rng + rand::CryptoRng>(
662+
fn simulate_transcript<R: Rng + CryptoRng>(
658663
&self,
659664
rng: &mut R,
660665
) -> Result<(Self::Commitment, Self::Challenge, Self::Response), Error> {

src/duplex_sponge/keccak.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//! It is designed to match test vectors from the original Sage implementation.
55
66
use crate::duplex_sponge::DuplexSpongeInterface;
7+
use alloc::vec::Vec;
78
use zerocopy::IntoBytes;
89

910
const RATE: usize = 136;

src/duplex_sponge/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
//! a generic interface for cryptographic sponge functions that support
55
//! duplex operations: alternating absorb and squeeze phases.
66
7+
use alloc::vec::Vec;
8+
79
pub mod keccak;
810
pub mod shake;
911

src/duplex_sponge/shake.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
//! This module implements a duplex sponge construction using SHAKE128.
44
55
use crate::duplex_sponge::DuplexSpongeInterface;
6+
use alloc::vec;
7+
use alloc::vec::Vec;
68
use sha3::digest::{ExtendableOutput, Update};
79
use sha3::Shake128;
810

src/errors.rs

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,14 @@
88
//! - Mismatched parameter lengths (e.g., during batch verification),
99
//! - Access to unassigned group variables in constraint systems.
1010
11+
use alloc::string::String;
12+
#[cfg(not(feature = "std"))]
13+
use core::fmt;
14+
1115
/// Represents an invalid instance error.
12-
#[derive(Debug, thiserror::Error)]
13-
#[error("Invalid instance: {message}")]
16+
#[derive(Debug)]
17+
#[cfg_attr(feature = "std", derive(thiserror::Error))]
18+
#[cfg_attr(feature = "std", error("Invalid instance: {message}"))]
1419
pub struct InvalidInstance {
1520
/// The error message describing what's invalid about the instance.
1621
pub message: String,
@@ -35,22 +40,47 @@ impl From<InvalidInstance> for Error {
3540
///
3641
/// This may occur during proof generation, response computation, or verification.
3742
#[non_exhaustive]
38-
#[derive(Debug, thiserror::Error)]
43+
#[derive(Debug)]
44+
#[cfg_attr(feature = "std", derive(thiserror::Error))]
3945
pub enum Error {
4046
/// The proof is invalid: verification failed.
41-
#[error("Verification failed.")]
47+
#[cfg_attr(feature = "std", error("Verification failed."))]
4248
VerificationFailure,
4349
/// Indicates an invalid statement/witness pair
44-
#[error("Invalid instance/witness pair.")]
50+
#[cfg_attr(feature = "std", error("Invalid instance/witness pair."))]
4551
InvalidInstanceWitnessPair,
4652
/// Uninitialized group element variable.
47-
#[error("Uninitialized group element variable: {var_debug}")]
53+
#[cfg_attr(
54+
feature = "std",
55+
error("Uninitialized group element variable: {var_debug}")
56+
)]
4857
UnassignedGroupVar {
4958
/// Debug representation of the unassigned variable.
5059
var_debug: String,
5160
},
5261
}
5362

63+
// Manual Display implementation for no_std compatibility
64+
#[cfg(not(feature = "std"))]
65+
impl fmt::Display for InvalidInstance {
66+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67+
write!(f, "Invalid instance: {}", self.message)
68+
}
69+
}
70+
71+
#[cfg(not(feature = "std"))]
72+
impl fmt::Display for Error {
73+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74+
match self {
75+
Error::VerificationFailure => write!(f, "Verification failed."),
76+
Error::InvalidInstanceWitnessPair => write!(f, "Invalid instance/witness pair."),
77+
Error::UnassignedGroupVar { var_debug } => {
78+
write!(f, "Uninitialized group element variable: {}", var_debug)
79+
}
80+
}
81+
}
82+
}
83+
5484
pub type Result<T> = core::result::Result<T, Error>;
5585

5686
/// Construct an `Ok` value of type `Result<T, sigma_rs::errors::Error>`.

src/fiat_shamir.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,12 @@
1515
use crate::errors::Error;
1616
use crate::traits::SigmaProtocol;
1717
use crate::{codec::Codec, traits::SigmaProtocolSimulator};
18+
use alloc::vec::Vec;
1819

20+
#[cfg(feature = "std")]
1921
use rand::{CryptoRng, RngCore};
22+
#[cfg(not(feature = "std"))]
23+
use rand_core::{CryptoRng, RngCore};
2024

2125
type Transcript<P> = (
2226
<P as SigmaProtocol>::Commitment,

src/group/msm.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use alloc::vec;
2+
use alloc::vec::Vec;
13
use ff::PrimeField;
24
use group::prime::PrimeGroup;
35

@@ -82,7 +84,7 @@ fn msm_internal<G: PrimeGroup>(bases: &[G], scalars: &[G::Scalar]) -> G {
8284
window_buckets.push((window, vec![G::identity(); buckets_num]));
8385
}
8486

85-
for (scalar, base) in scalars.into_iter().zip(bases) {
87+
for (scalar, base) in scalars.iter().zip(bases) {
8688
for (w, bucket) in window_buckets.iter_mut() {
8789
let scalar_repr = scalar.to_repr();
8890
let scalar_bytes = scalar_repr.as_ref();

0 commit comments

Comments
 (0)