Implement `no_std` support via a default-enabled `std` feature flag.

Add thumbv7em-none-eabihf as a no-default-features build target.
This commit is contained in:
Kris Nuttycombe 2024-12-18 15:04:55 -07:00
parent 3c22357475
commit e8b04770f9
30 changed files with 261 additions and 135 deletions

View File

@ -41,12 +41,36 @@ jobs:
matrix:
target:
- wasm32-wasi
- thumbv7em-none-eabihf
steps:
- uses: actions/checkout@v4
with:
path: crate_root
# We use a synthetic crate to ensure no dev-dependencies are enabled, which can
# be incompatible with some of these targets.
- name: Create synthetic crate for testing
run: cargo init --lib ci-build
- name: Copy Rust version into synthetic crate
run: cp crate_root/rust-toolchain.toml ci-build/
- name: Copy patch directives into synthetic crate
run: |
echo "[patch.crates-io]" >> ./ci-build/Cargo.toml
cat ./crate_root/Cargo.toml | sed "0,/.\+\(patch.crates.\+\)/d" >> ./ci-build/Cargo.toml
- name: Add no_std pragma to lib.rs
run: |
echo "#![no_std]" > ./ci-build/src/lib.rs
- name: Add sapling-crypto as a dependency of the synthetic crate
working-directory: ./ci-build
run: cargo add --no-default-features --path ../crate_root
- name: Add lazy_static with the spin_no_std feature
working-directory: ./ci-build
run: cargo add lazy_static --features "spin_no_std"
- name: Add target
working-directory: ./ci-build
run: rustup target add ${{ matrix.target }}
- name: Build crate
run: cargo build --no-default-features --verbose --target ${{ matrix.target }}
- name: Build for target
working-directory: ./ci-build
run: cargo build --verbose --target ${{ matrix.target }}
bitrot:
name: Bitrot check

View File

@ -9,6 +9,13 @@ and this library adheres to Rust's notion of
### Added
- `sapling_crypto::pczt::Zip32Derivation::extract_account_index`
- `no_std` compatibility has been introduced by means of a default-enabled
`std` feature flag.
- A default-enabled `circuit` is now provided to enable downstream users to
avoid the need to depend upon the `bellman` crate.
### Changed
- MSRV is now 1.66
## [0.4.0] - 2024-12-16

38
Cargo.lock generated
View File

@ -342,6 +342,15 @@ version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6"
[[package]]
name = "core2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "239fa3ae9b63c2dc74bd3fa852d4792b8b305ae64eeede946265b6af62f1fff3"
dependencies = [
"memchr",
]
[[package]]
name = "cpp_demangle"
version = "0.4.3"
@ -815,9 +824,9 @@ dependencies = [
[[package]]
name = "memuse"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2145869435ace5ea6ea3d35f59be559317ec9a0d04e1812d5f185a87b6d36f1a"
checksum = "3d97bbf43eb4f088f8ca469930cde17fa036207c9a5e02ccc5107c4e8b17c964"
[[package]]
name = "miniz_oxide"
@ -1202,12 +1211,10 @@ dependencies = [
[[package]]
name = "redjubjub"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a60db2c3bc9c6fd1e8631fee75abc008841d27144be744951d6b9b75f9b569c"
source = "git+https://github.com/nuttycom/redjubjub?rev=e413019904400f4caa3550df7c4040befadfbb14#e413019904400f4caa3550df7c4040befadfbb14"
dependencies = [
"rand_core",
"reddsa",
"serde",
"thiserror",
"zeroize",
]
@ -1315,8 +1322,8 @@ dependencies = [
"blake2b_simd",
"blake2s_simd",
"bls12_381",
"byteorder",
"chacha20poly1305",
"core2",
"criterion",
"document-features",
"ff",
@ -1504,29 +1511,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
dependencies = [
"once_cell",
]
[[package]]
name = "typenum"
@ -1893,9 +1885,9 @@ dependencies = [
[[package]]
name = "zip32"
version = "0.1.0"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d724a63be4dfb50b7f3617e542984e22e4b4a5b8ca5de91f55613152885e6b22"
checksum = "4226d0aee9c9407c27064dfeec9d7b281c917de3374e1e5a2e2cfad9e09de19e"
dependencies = [
"blake2b_simd",
"memuse",

View File

@ -7,7 +7,7 @@ authors = [
"Kris Nuttycombe <kris@electriccoin.co>",
]
edition = "2021"
rust-version = "1.65"
rust-version = "1.66"
description = "Cryptographic library for Zcash Sapling"
homepage = "https://github.com/zcash/sapling-crypto"
repository = "https://github.com/zcash/sapling-crypto"
@ -18,48 +18,50 @@ features = ["test-dependencies"]
rustdoc-args = ["--cfg", "docsrs"]
[dependencies]
ff = "0.13"
group = { version = "0.13", features = ["wnaf-memuse"] }
ff = { version = "0.13", default-features = false }
group = "0.13"
bls12_381 = "0.8"
jubjub = "0.10"
redjubjub = "0.7"
bls12_381 = { version = "0.8", default-features = false, features = ["alloc"] }
jubjub = { version = "0.10", default-features = false, features = ["alloc"] }
redjubjub = { version = "0.7", default-features = false }
zcash_spec = "0.1"
# Boilerplate
getset = "0.1"
# No-std support
core2 = { version = "0.3", default-features = false, features = ["alloc"] }
# Circuits
bellman = { version = "0.14", default-features = false, features = ["groth16"] }
bellman = { version = "0.14", features = ["groth16"], optional = true }
# CSPRNG
rand = "0.8"
rand_core = "0.6"
rand = { version = "0.8", default-features = false }
rand_core = { version = "0.6", default-features = false }
# Digests
blake2b_simd = "1"
blake2s_simd = "1"
blake2b_simd = { version = "1", default-features = false }
blake2s_simd = { version = "1", default-features = false }
# Documentation
document-features = "0.2"
document-features = { version = "0.2", optional = true }
# Encodings
byteorder = "1"
hex = "0.4"
hex = { version = "0.4", default-features = false, features = ["alloc"] }
# Logging and metrics
memuse = "0.2.1"
tracing = "0.1"
memuse = { version = "0.2.2", default-features = false }
tracing = { version = "0.1", default-features = false }
# Note Commitment Trees
bitvec = "1"
incrementalmerkletree = { version = "0.7", features = ["legacy-api"] }
bitvec = { version = "1", default-features = false }
incrementalmerkletree = { version = "0.7", default-features = false, features = ["legacy-api"] }
# Note encryption
zcash_note_encryption = { version = "0.4", features = ["pre-zip-212"] }
# Secret management
subtle = "2.2.3"
subtle = { version = "2.2.3", default-features = false }
# Static constants
lazy_static = "1"
@ -69,8 +71,9 @@ proptest = { version = "1", optional = true }
# ZIP 32
aes = "0.8"
fpe = "0.6"
zip32 = "0.1"
fpe = { version = "0.6", default-features = false, features = ["alloc"] }
zip32 = { version = "0.1.1", default-features = false }
[dev-dependencies]
chacha20poly1305 = "0.10"
@ -83,10 +86,26 @@ rand_xorshift = "0.3"
pprof = { version = "0.11", features = ["criterion", "flamegraph"] } # MSRV 1.56
[features]
default = ["multicore"]
default = ["multicore", "std"]
std = [
"core2/std",
"document-features",
"group/wnaf-memuse",
"redjubjub/std",
"circuit",
]
## Enables creation of Sapling proofs
circuit = [
"bellman",
"bls12_381/bits",
"bls12_381/groups",
"bls12_381/pairings",
"jubjub/bits",
]
## Enables multithreading support for creating proofs.
multicore = ["bellman/multicore"]
multicore = ["circuit", "bellman/multicore"]
### A temporary feature flag that exposes granular APIs needed by `zcashd`. These APIs
### should not be relied upon and will be removed in a future release.
@ -105,3 +124,6 @@ harness = false
[[bench]]
name = "pedersen_hash"
harness = false
[patch.crates-io]
redjubjub = { git = "https://github.com/nuttycom/redjubjub", rev = "e413019904400f4caa3550df7c4040befadfbb14" }

View File

@ -1,6 +1,13 @@
# sapling-crypto
This repository contains a (work-in-progress) implementation of Zcash's "Sapling" cryptography.
This repository contains an implementation of Zcash's "Sapling" cryptography.
## `no_std` compatibility
Downstream users of this crate must enable the `spin_no_std` feature of the
`lazy_static` crate in order to take advantage of `no_std` builds; this is due
to the fact that `--no-default-features` builds of `lazy_static` still rely on
`std`.
## License

View File

@ -1,3 +1,3 @@
[toolchain]
channel = "1.65.0"
channel = "1.66.0"
components = ["clippy", "rustfmt"]

View File

@ -1,7 +1,8 @@
//! Types and functions for building Sapling transaction components.
use core::fmt;
use std::{collections::BTreeMap, iter, marker::PhantomData};
use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use core::{fmt, iter, marker::PhantomData};
use group::ff::Field;
use incrementalmerkletree::Position;
@ -11,24 +12,27 @@ use redjubjub::{Binding, SpendAuth};
use zcash_note_encryption::EphemeralKeyBytes;
use crate::{
bundle::{
Authorization, Authorized, Bundle, GrothProofBytes, OutputDescription, SpendDescription,
},
circuit,
bundle::{Authorization, Authorized, Bundle, GrothProofBytes},
keys::{
EphemeralSecretKey, ExpandedSpendingKey, FullViewingKey, OutgoingViewingKey,
SpendAuthorizingKey, SpendValidatingKey,
},
note::ExtractedNoteCommitment,
note_encryption::{sapling_note_encryption, Zip212Enforcement},
prover::{OutputProver, SpendProver},
util::generate_random_rseed_internal,
value::{
CommitmentSum, NoteValue, TrapdoorSum, ValueCommitTrapdoor, ValueCommitment, ValueSum,
},
value::{NoteValue, ValueCommitTrapdoor, ValueCommitment, ValueSum},
Anchor, Diversifier, MerklePath, Node, Note, Nullifier, PaymentAddress, SaplingIvk,
NOTE_COMMITMENT_TREE_DEPTH,
};
#[cfg(feature = "circuit")]
use crate::{
bundle::{OutputDescription, SpendDescription},
circuit,
prover::{OutputProver, SpendProver},
value::{CommitmentSum, TrapdoorSum},
zip32::ExtendedSpendingKey,
Anchor, Diversifier, MerklePath, Node, Note, Nullifier, PaymentAddress, ProofGenerationKey,
SaplingIvk, NOTE_COMMITMENT_TREE_DEPTH,
ProofGenerationKey,
};
/// If there are any shielded inputs, always have at least two shielded outputs, padding
@ -268,6 +272,7 @@ impl PreparedSpendInfo {
(cv, nullifier, rk, alpha)
}
#[cfg(feature = "circuit")]
fn build<Pr: SpendProver, R: RngCore>(
self,
proof_generation_key: Option<ProofGenerationKey>,
@ -464,6 +469,7 @@ impl PreparedOutputInfo {
)
}
#[cfg(feature = "circuit")]
fn build<Pr: OutputProver, R: RngCore>(
self,
rng: &mut R,
@ -664,6 +670,7 @@ impl Builder {
}
/// Constructs the Sapling bundle from the builder's accumulated state.
#[cfg(feature = "circuit")]
pub fn build<SP: SpendProver, OP: OutputProver, R: RngCore, V: TryFrom<i64>>(
self,
extsks: &[ExtendedSpendingKey],
@ -726,6 +733,7 @@ impl Builder {
/// Constructs a new Sapling transaction bundle of the given type from the specified set of spends
/// and outputs.
#[cfg(feature = "circuit")]
pub fn bundle<SP: SpendProver, OP: OutputProver, R: RngCore, V: TryFrom<i64>>(
rng: R,
bundle_type: BundleType,
@ -917,6 +925,7 @@ fn build_bundle<B, SP, OP, R: RngCore>(
/// Type alias for an in-progress bundle that has no proofs or signatures.
///
/// This is returned by [`Builder::build`].
#[cfg(feature = "circuit")]
pub type UnauthorizedBundle<V> = Bundle<InProgress<Unproven, Unsigned>, V>;
/// Marker trait representing bundle proofs in the process of being created.
@ -951,9 +960,11 @@ impl<P: InProgressProofs, S: InProgressSignatures> Authorization for InProgress<
///
/// The [`SpendDescription`]s and [`OutputDescription`]s within the bundle contain the
/// private data needed to create proofs.
#[cfg(feature = "circuit")]
#[derive(Clone, Copy, Debug)]
pub struct Unproven;
#[cfg(feature = "circuit")]
impl InProgressProofs for Unproven {
type SpendProof = circuit::Spend;
type OutputProof = circuit::Output;
@ -969,16 +980,19 @@ impl InProgressProofs for Proven {
}
/// Reports on the progress made towards creating proofs for a bundle.
#[cfg(feature = "circuit")]
pub trait ProverProgress {
/// Updates the progress instance with the number of steps completed and the total
/// number of steps.
fn update(&mut self, cur: u32, end: u32);
}
#[cfg(feature = "circuit")]
impl ProverProgress for () {
fn update(&mut self, _: u32, _: u32) {}
}
#[cfg(feature = "circuit")]
impl<U: From<(u32, u32)>> ProverProgress for std::sync::mpsc::Sender<U> {
fn update(&mut self, cur: u32, end: u32) {
// If the send fails, we should ignore the error, not crash.
@ -986,12 +1000,14 @@ impl<U: From<(u32, u32)>> ProverProgress for std::sync::mpsc::Sender<U> {
}
}
#[cfg(feature = "circuit")]
impl<U: ProverProgress> ProverProgress for &mut U {
fn update(&mut self, cur: u32, end: u32) {
(*self).update(cur, end);
}
}
#[cfg(feature = "circuit")]
struct CreateProofs<'a, SP: SpendProver, OP: OutputProver, R: RngCore, U: ProverProgress> {
spend_prover: &'a SP,
output_prover: &'a OP,
@ -1001,6 +1017,7 @@ struct CreateProofs<'a, SP: SpendProver, OP: OutputProver, R: RngCore, U: Prover
progress: u32,
}
#[cfg(feature = "circuit")]
impl<'a, SP: SpendProver, OP: OutputProver, R: RngCore, U: ProverProgress>
CreateProofs<'a, SP, OP, R, U>
{
@ -1041,6 +1058,7 @@ impl<'a, SP: SpendProver, OP: OutputProver, R: RngCore, U: ProverProgress>
OP::encode_proof(proof)
}
#[cfg(feature = "circuit")]
fn map_authorization<S: InProgressSignatures>(
&mut self,
a: InProgress<Unproven, S>,
@ -1052,6 +1070,7 @@ impl<'a, SP: SpendProver, OP: OutputProver, R: RngCore, U: ProverProgress>
}
}
#[cfg(feature = "circuit")]
impl<S: InProgressSignatures, V> Bundle<InProgress<Unproven, S>, V> {
/// Creates the proofs for this bundle.
pub fn create_proofs<SP: SpendProver, OP: OutputProver>(

View File

@ -1,3 +1,4 @@
use alloc::vec::Vec;
use core::fmt::Debug;
use memuse::DynamicUsage;
@ -9,7 +10,7 @@ use zcash_note_encryption::{
};
use crate::{
circuit::GROTH_PROOF_SIZE,
constants::GROTH_PROOF_SIZE,
note::ExtractedNoteCommitment,
note_encryption::{CompactOutputDescription, SaplingDomain},
value::ValueCommitment,
@ -220,8 +221,8 @@ pub struct SpendDescription<A: Authorization> {
spend_auth_sig: A::AuthSig,
}
impl<A: Authorization> std::fmt::Debug for SpendDescription<A> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
impl<A: Authorization> core::fmt::Debug for SpendDescription<A> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
write!(
f,
"SpendDescription(cv = {:?}, anchor = {:?}, nullifier = {:?}, rk = {:?}, spend_auth_sig = {:?})",
@ -431,8 +432,8 @@ impl<A> ShieldedOutput<SaplingDomain, ENC_CIPHERTEXT_SIZE> for OutputDescription
}
}
impl<A> std::fmt::Debug for OutputDescription<A> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
impl<A> core::fmt::Debug for OutputDescription<A> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
write!(
f,
"OutputDescription(cv = {:?}, cmu = {:?}, ephemeral_key = {:?})",
@ -498,7 +499,7 @@ impl<A> From<OutputDescription<A>> for CompactOutputDescription {
#[cfg(any(test, feature = "test-dependencies"))]
#[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))]
pub mod testing {
use std::fmt;
use core::fmt;
use ff::Field;
use group::{Group, GroupEncoding};
@ -507,7 +508,7 @@ pub mod testing {
use rand::{rngs::StdRng, SeedableRng};
use crate::{
circuit::GROTH_PROOF_SIZE,
constants::GROTH_PROOF_SIZE,
note::testing::arb_cmu,
value::{
testing::{arb_note_value_bounded, arb_trapdoor},

View File

@ -1,15 +1,14 @@
//! The Sapling circuits.
use alloc::vec::Vec;
use core::fmt;
use std::io;
use core2::io;
use group::{ff::PrimeField, Curve};
use bellman::{groth16, Circuit, ConstraintSystem, SynthesisError};
use bls12_381::Bls12;
use super::{value::NoteValue, PaymentAddress, ProofGenerationKey};
use bellman::gadgets::blake2s;
use bellman::gadgets::boolean;
use bellman::gadgets::multipack;
@ -21,6 +20,7 @@ use self::constants::{
PROOF_GENERATION_KEY_GENERATOR, SPENDING_KEY_GENERATOR, VALUE_COMMITMENT_RANDOMNESS_GENERATOR,
VALUE_COMMITMENT_VALUE_GENERATOR,
};
use crate::{value::NoteValue, PaymentAddress, ProofGenerationKey};
#[cfg(test)]
use group::ff::PrimeFieldBits;
@ -29,9 +29,6 @@ mod constants;
mod ecc;
mod pedersen_hash;
// π_A + π_B + π_C
pub(crate) const GROTH_PROOF_SIZE: usize = 48 + 96 + 48;
/// The opening (value and randomness) of a Sapling value commitment.
#[derive(Clone)]
pub struct ValueCommitmentOpening {
@ -703,7 +700,7 @@ fn test_input_circuit_with_bls12_381() {
let mut rhs = uncle;
if b {
::std::mem::swap(&mut lhs, &mut rhs);
::core::mem::swap(&mut lhs, &mut rhs);
}
let lhs = lhs.to_le_bits();
@ -886,7 +883,7 @@ fn test_input_circuit_with_bls12_381_external_test_vectors() {
let mut rhs = uncle;
if b {
::std::mem::swap(&mut lhs, &mut rhs);
::core::mem::swap(&mut lhs, &mut rhs);
}
let lhs = lhs.to_le_bits();

View File

@ -2,6 +2,7 @@
use crate::constants::{PEDERSEN_HASH_CHUNKS_PER_GENERATOR, PEDERSEN_HASH_GENERATORS};
use alloc::vec::Vec;
use bls12_381::Scalar;
use group::{ff::Field, Curve, Group};
use jubjub::ExtendedPoint;

View File

@ -1,6 +1,7 @@
//! Gadgets implementing Jubjub elliptic curve operations.
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use alloc::vec::Vec;
use core::ops::{AddAssign, MulAssign, Neg, SubAssign};
use bellman::{ConstraintSystem, SynthesisError};
@ -620,6 +621,7 @@ impl MontgomeryPoint {
#[cfg(test)]
mod test {
use alloc::vec::Vec;
use bellman::ConstraintSystem;
use group::{
ff::{Field, PrimeField, PrimeFieldBits},

View File

@ -3,6 +3,7 @@
use super::ecc::{EdwardsPoint, MontgomeryPoint};
pub use crate::pedersen_hash::Personalization;
use alloc::vec::Vec;
use bellman::gadgets::boolean::Boolean;
use bellman::gadgets::lookup::*;
use bellman::{ConstraintSystem, SynthesisError};

View File

@ -1,5 +1,6 @@
//! Various constants used by the Sapling protocol.
use alloc::vec::Vec;
use ff::PrimeField;
use group::Group;
use jubjub::SubgroupPoint;
@ -38,6 +39,9 @@ pub const VALUE_COMMITMENT_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_cv";
/// BLAKE2s Personalization for the nullifier position generator (for computing rho)
pub const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_J_";
// π_A + π_B + π_C
pub(crate) const GROTH_PROOF_SIZE: usize = 48 + 96 + 48;
/// The prover will demonstrate knowledge of discrete log with respect to this base when
/// they are constructing a proof, in order to authorize proof construction.
pub const PROOF_GENERATION_KEY_GENERATOR: SubgroupPoint = SubgroupPoint::from_raw_unchecked(

View File

@ -4,8 +4,9 @@
//!
//! [section 4.2.2]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents
use std::fmt;
use std::io::{self, Read, Write};
use alloc::vec::Vec;
use core::fmt;
use core2::io::{self, Read, Write};
use super::{
address::PaymentAddress,
@ -444,6 +445,7 @@ impl SaplingIvk {
#[derive(Clone, Debug)]
pub struct PreparedIncomingViewingKey(PreparedScalar);
#[cfg(feature = "std")]
impl memuse::DynamicUsage for PreparedIncomingViewingKey {
fn dynamic_usage(&self) -> usize {
self.0.dynamic_usage()
@ -690,6 +692,7 @@ pub mod testing {
#[cfg(test)]
mod tests {
use alloc::string::ToString;
use group::{Group, GroupEncoding};
use super::{FullViewingKey, SpendAuthorizingKey, SpendValidatingKey};

View File

@ -8,17 +8,26 @@
//! opposed to e.g. an Orchard payment address, which is also shielded).
//!
//! ## Feature flags
#![doc = document_features::document_features!()]
#![cfg_attr(feature = "std", doc = document_features::document_features!())]
//!
#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
// Catch documentation errors caused by code changes.
#![deny(rustdoc::broken_intra_doc_links)]
#![deny(unsafe_code)]
#[macro_use]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
mod address;
pub mod builder;
pub mod bundle;
#[cfg(feature = "circuit")]
pub mod circuit;
pub mod constants;
pub mod group_hash;
@ -27,11 +36,13 @@ pub mod note;
pub mod note_encryption;
pub mod pczt;
pub mod pedersen_hash;
#[cfg(feature = "circuit")]
pub mod prover;
mod spec;
mod tree;
pub mod util;
pub mod value;
#[cfg(feature = "circuit")]
mod verifier;
pub mod zip32;
@ -43,6 +54,8 @@ pub use tree::{
merkle_hash, Anchor, CommitmentTree, IncrementalWitness, MerklePath, Node,
NOTE_COMMITMENT_TREE_DEPTH,
};
#[cfg(feature = "circuit")]
pub use verifier::{BatchValidator, SaplingVerificationContext};
#[cfg(any(test, feature = "test-dependencies"))]

View File

@ -1,5 +1,6 @@
use std::array::TryFromSliceError;
use std::fmt;
use alloc::fmt;
use alloc::vec::Vec;
use core::array::TryFromSliceError;
use subtle::{Choice, ConstantTimeEq};

View File

@ -2,8 +2,8 @@
//!
//! NB: the example code is only covering the post-Canopy case.
use alloc::vec::Vec;
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
use byteorder::{LittleEndian, WriteBytesExt};
use ff::PrimeField;
use memuse::DynamicUsage;
use rand_core::RngCore;
@ -193,9 +193,7 @@ impl Domain for SaplingDomain {
Rseed::AfterZip212(_) => 2,
};
input[1..12].copy_from_slice(&note.recipient().diversifier().0);
(&mut input[12..20])
.write_u64::<LittleEndian>(note.value().inner())
.unwrap();
input[12..20].copy_from_slice(&note.value().inner().to_le_bytes());
match note.rseed() {
Rseed::BeforeZip212(rcm) => {
@ -462,6 +460,7 @@ pub fn try_sapling_output_recovery(
#[cfg(test)]
mod tests {
use alloc::vec::Vec;
use chacha20poly1305::{
aead::{AeadInPlace, KeyInit},
ChaCha20Poly1305,
@ -486,7 +485,7 @@ mod tests {
use crate::{
bundle::{GrothProofBytes, OutputDescription},
circuit::GROTH_PROOF_SIZE,
constants::GROTH_PROOF_SIZE,
keys::{DiversifiedTransmissionKey, EphemeralSecretKey, OutgoingViewingKey},
note::ExtractedNoteCommitment,
note_encryption::PreparedIncomingViewingKey,

View File

@ -1,7 +1,9 @@
//! PCZT support for Sapling.
use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt;
use std::collections::BTreeMap;
use getset::Getters;
use redjubjub::{Binding, SpendAuth};
@ -30,7 +32,9 @@ pub use io_finalizer::IoFinalizerError;
mod updater;
pub use updater::{OutputUpdater, SpendUpdater, Updater, UpdaterError};
#[cfg(feature = "circuit")]
mod prover;
#[cfg(feature = "circuit")]
pub use prover::ProverError;
mod signer;
@ -277,7 +281,7 @@ pub struct Output {
}
impl fmt::Debug for Output {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Output")
.field("cv", &self.cv)
.field("cmu", &self.cmu)

View File

@ -1,3 +1,4 @@
use alloc::vec::Vec;
use rand::{CryptoRng, RngCore};
use crate::value::{CommitmentSum, TrapdoorSum};

View File

@ -1,4 +1,6 @@
use std::collections::BTreeMap;
use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::vec::Vec;
use ff::PrimeField;
use zcash_note_encryption::{EphemeralKeyBytes, OutgoingCipherKey};

View File

@ -1,3 +1,6 @@
use alloc::string::String;
use alloc::vec::Vec;
use crate::ProofGenerationKey;
use super::{Bundle, Output, Spend, Zip32Derivation};

View File

@ -3,14 +3,12 @@
#[cfg(test)]
pub(crate) mod test_vectors;
use byteorder::{ByteOrder, LittleEndian};
use alloc::vec::Vec;
use core::ops::{AddAssign, Neg};
use ff::PrimeField;
use group::Group;
use std::ops::{AddAssign, Neg};
use super::constants::{
PEDERSEN_HASH_CHUNKS_PER_GENERATOR, PEDERSEN_HASH_EXP_TABLE, PEDERSEN_HASH_EXP_WINDOW_SIZE,
};
use super::constants::{PEDERSEN_HASH_CHUNKS_PER_GENERATOR, PEDERSEN_HASH_EXP_WINDOW_SIZE};
#[derive(Copy, Clone)]
pub enum Personalization {
@ -41,7 +39,7 @@ where
.chain(bits.into_iter());
let mut result = jubjub::SubgroupPoint::identity();
let mut generators = PEDERSEN_HASH_EXP_TABLE.iter();
let mut generators = crate::constants::PEDERSEN_HASH_EXP_TABLE.iter();
loop {
let mut acc = jubjub::Fr::zero();
@ -94,7 +92,11 @@ where
let acc = acc.to_repr();
let num_limbs: usize = acc.as_ref().len() / 8;
let mut limbs = vec![0u64; num_limbs + 1];
LittleEndian::read_u64_into(acc.as_ref(), &mut limbs[..num_limbs]);
for (src, dst) in acc.chunks_exact(8).zip(limbs[..num_limbs].iter_mut()) {
let mut limb_bytes = [0u8; 8];
limb_bytes.copy_from_slice(src);
*dst = u64::from_le_bytes(limb_bytes);
}
let mut tmp = jubjub::SubgroupPoint::identity();
@ -124,6 +126,7 @@ where
#[cfg(test)]
pub mod test {
use alloc::string::ToString;
use group::Curve;
use super::*;

View File

@ -1,6 +1,7 @@
//! Test vectors from https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_pedersen.py
use super::{test::TestVector, Personalization};
use alloc::vec::Vec;
pub fn get_vectors<'a>() -> Vec<TestVector<'a>> {
vec![

View File

@ -6,7 +6,8 @@ use rand_core::RngCore;
use crate::{
bundle::GrothProofBytes,
circuit::{self, GROTH_PROOF_SIZE},
circuit,
constants::GROTH_PROOF_SIZE,
keys::EphemeralSecretKey,
value::{NoteValue, ValueCommitTrapdoor},
MerklePath,
@ -179,7 +180,8 @@ pub mod mock {
use super::{OutputProver, SpendProver};
use crate::{
bundle::GrothProofBytes,
circuit::{self, ValueCommitmentOpening, GROTH_PROOF_SIZE},
circuit::{self, ValueCommitmentOpening},
constants::GROTH_PROOF_SIZE,
keys::EphemeralSecretKey,
value::{NoteValue, ValueCommitTrapdoor},
Diversifier, MerklePath, PaymentAddress, ProofGenerationKey, Rseed,

View File

@ -1,3 +1,5 @@
use alloc::vec::Vec;
pub(crate) struct TestVector {
pub ovk: [u8; 32],
pub ivk: [u8; 32],

View File

@ -1,3 +1,5 @@
use alloc::vec::Vec;
pub(crate) struct TestVector {
pub(crate) sk: [u8; 32],
pub(crate) vk: [u8; 32],

View File

@ -4,7 +4,8 @@ use incrementalmerkletree::{Hashable, Level};
use lazy_static::lazy_static;
use subtle::CtOption;
use std::fmt;
use alloc::vec::Vec;
use core::fmt;
use super::{
note::ExtractedNoteCommitment,
@ -20,14 +21,16 @@ pub type MerklePath = incrementalmerkletree::MerklePath<Node, NOTE_COMMITMENT_TR
lazy_static! {
static ref UNCOMMITTED_SAPLING: bls12_381::Scalar = bls12_381::Scalar::one();
static ref EMPTY_ROOTS: Vec<Node> = {
let mut v = vec![Node::empty_leaf()];
for d in 0..NOTE_COMMITMENT_TREE_DEPTH {
let next = Node::combine(d.into(), &v[usize::from(d)], &v[usize::from(d)]);
v.push(next);
}
v
};
static ref EMPTY_ROOTS: Vec<Node> = empty_roots();
}
fn empty_roots() -> Vec<Node> {
let mut v = vec![Node::empty_leaf()];
for d in 0..NOTE_COMMITMENT_TREE_DEPTH {
let next = Node::combine(d.into(), &v[usize::from(d)], &v[usize::from(d)]);
v.push(next);
}
v
}
/// Compute a parent node in the Sapling commitment tree given its two children.
@ -144,6 +147,7 @@ impl Node {
}
/// Returns the wrapped value
#[cfg(feature = "circuit")]
pub(crate) fn inner(&self) -> &jubjub::Base {
&self.0
}

View File

@ -18,6 +18,7 @@ impl fmt::Display for OverflowError {
}
}
#[cfg(feature = "std")]
impl std::error::Error for OverflowError {}
/// A sum of Sapling note values.

View File

@ -140,7 +140,10 @@ impl BatchValidator {
}
if let Err(e) = self.signatures.verify(&mut rng) {
#[cfg(feature = "std")]
tracing::debug!("Signature batch validation failed: {}", e);
#[cfg(not(feature = "std"))]
tracing::debug!("Signature batch validation failed: {:?}", e);
return false;
}

View File

@ -6,14 +6,13 @@
use aes::Aes256;
use blake2b_simd::Params as Blake2bParams;
use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt};
use fpe::ff1::{BinaryNumeralString, FF1};
use subtle::CtOption;
use zcash_spec::PrfExpand;
use zip32::{ChainCode, ChildIndex, DiversifierIndex, Scope};
use std::io::{self, Read, Write};
use std::ops::AddAssign;
use core::ops::AddAssign;
use core2::io::{self, Read, Write};
use super::{Diversifier, NullifierDerivingKey, PaymentAddress, ViewingKey};
use crate::note_encryption::PreparedIncomingViewingKey;
@ -269,7 +268,7 @@ pub struct ExtendedSpendingKey {
dk: DiversifierKey,
}
impl std::cmp::PartialEq for ExtendedSpendingKey {
impl core::cmp::PartialEq for ExtendedSpendingKey {
fn eq(&self, rhs: &ExtendedSpendingKey) -> bool {
self.depth == rhs.depth
&& self.parent_fvk_tag == rhs.parent_fvk_tag
@ -282,8 +281,8 @@ impl std::cmp::PartialEq for ExtendedSpendingKey {
}
}
impl std::fmt::Debug for ExtendedSpendingKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
impl core::fmt::Debug for ExtendedSpendingKey {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
write!(
f,
"ExtendedSpendingKey(d = {}, tag_p = {:?}, i = {:?})",
@ -354,17 +353,20 @@ impl ExtendedSpendingKey {
/// Reads and decodes the encoded form of the extended spending key as defined in
/// [ZIP 32](https://zips.z.cash/zip-0032) from the provided reader.
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
let depth = reader.read_u8()?;
let mut depth = [0; 1];
reader.read_exact(&mut depth)?;
let depth = depth[0];
let mut tag = [0; 4];
reader.read_exact(&mut tag)?;
let child_index = reader.read_u32::<LittleEndian>().and_then(|i| {
KeyIndex::new(depth, i).ok_or_else(|| {
io::Error::new(
io::ErrorKind::Unsupported,
let mut child_index_bytes = [0; 4];
reader.read_exact(&mut child_index_bytes)?;
let child_index =
KeyIndex::new(depth, u32::from_le_bytes(child_index_bytes)).ok_or_else(|| {
core2::io::Error::new(
core2::io::ErrorKind::InvalidData,
"Unsupported child index in encoding",
)
})
})?;
})?;
let mut c = [0; 32];
reader.read_exact(&mut c)?;
let expsk = ExpandedSpendingKey::read(&mut reader)?;
@ -420,7 +422,7 @@ impl ExtendedSpendingKey {
let fvk = FullViewingKey::from_expanded_spending_key(&self.expsk);
let tmp = {
let mut le_i = [0; 4];
LittleEndian::write_u32(&mut le_i, i.index());
le_i.copy_from_slice(&i.index().to_le_bytes());
PrfExpand::SAPLING_ZIP32_CHILD_HARDENED.with(
self.chain_code.as_bytes(),
&self.expsk.to_bytes(),
@ -529,7 +531,7 @@ pub struct ExtendedFullViewingKey {
pub(crate) dk: DiversifierKey,
}
impl std::cmp::PartialEq for ExtendedFullViewingKey {
impl core::cmp::PartialEq for ExtendedFullViewingKey {
fn eq(&self, rhs: &ExtendedFullViewingKey) -> bool {
self.depth == rhs.depth
&& self.parent_fvk_tag == rhs.parent_fvk_tag
@ -542,8 +544,8 @@ impl std::cmp::PartialEq for ExtendedFullViewingKey {
}
}
impl std::fmt::Debug for ExtendedFullViewingKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
impl core::fmt::Debug for ExtendedFullViewingKey {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
write!(
f,
"ExtendedFullViewingKey(d = {}, tag_p = {:?}, i = {:?})",
@ -554,17 +556,20 @@ impl std::fmt::Debug for ExtendedFullViewingKey {
impl ExtendedFullViewingKey {
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
let depth = reader.read_u8()?;
let mut depth = [0; 1];
reader.read_exact(&mut depth)?;
let depth = depth[0];
let mut tag = [0; 4];
reader.read_exact(&mut tag)?;
let child_index = reader.read_u32::<LittleEndian>().and_then(|i| {
KeyIndex::new(depth, i).ok_or_else(|| {
io::Error::new(
io::ErrorKind::Unsupported,
let mut child_index_bytes = [0; 4];
reader.read_exact(&mut child_index_bytes)?;
let child_index =
KeyIndex::new(depth, u32::from_le_bytes(child_index_bytes)).ok_or_else(|| {
core2::io::Error::new(
core2::io::ErrorKind::InvalidData,
"Unsupported child index in encoding",
)
})
})?;
})?;
let mut c = [0; 32];
reader.read_exact(&mut c)?;
let fvk = FullViewingKey::read(&mut reader)?;
@ -582,9 +587,9 @@ impl ExtendedFullViewingKey {
}
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
writer.write_u8(self.depth)?;
writer.write_all(&[self.depth])?;
writer.write_all(&self.parent_fvk_tag.0)?;
writer.write_u32::<LittleEndian>(self.child_index.index())?;
writer.write_all(&self.child_index.index().to_le_bytes())?;
writer.write_all(self.chain_code.as_bytes())?;
writer.write_all(&self.fvk.to_bytes())?;
writer.write_all(&self.dk.0)?;