Skip to content

Commit

Permalink
Merge pull request #107 from zcash/full-refactor
Browse files Browse the repository at this point in the history
Bring in refactor of the crate
  • Loading branch information
str4d authored Dec 11, 2023
2 parents 49017b4 + df6681c commit a1194fe
Show file tree
Hide file tree
Showing 55 changed files with 13,522 additions and 11,072 deletions.
81 changes: 61 additions & 20 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,31 +1,72 @@
[package]
authors = ["Sean Bowe <[email protected]>"]
description = "Cryptographic library for Zcash Sapling"
documentation = "https://github.com/zcash-hackworks/sapling"
homepage = "https://github.com/zcash-hackworks/sapling"
license = "MIT/Apache-2.0"
name = "sapling-crypto"
repository = "https://github.com/zcash-hackworks/sapling"
version = "0.0.1"

[dependencies.pairing]
version = "0.14.2"
features = ["expose-arith"]
authors = [
"Sean Bowe <[email protected]>",
"Jack Grigg <[email protected]>",
"Kris Nuttycombe <[email protected]>",
]
edition = "2021"
rust-version = "1.65"
description = "Cryptographic library for Zcash Sapling"
homepage = "https://github.com/zcash/sapling-crypto"
repository = "https://github.com/zcash/sapling-crypto"
license = "MIT OR Apache-2.0"

[dependencies]
rand = "0.4"
digest = "0.7"
bellman = "0.1"
ff = "0.13"
group = "0.13"

bls12_381 = "0.8"
jubjub = "0.10"
redjubjub = "0.7"
zcash_spec = "0.1"

# Circuits
bellman = { version = "0.14", default-features = false, features = ["groth16"] }

# CSPRNG
rand = "0.8"
rand_core = "0.6"

# Digests
blake2b_simd = "1"
blake2s_simd = "1"

# Encodings
byteorder = "1"
hex = "0.4"

# Logging and metrics
memuse = "0.2.1"
tracing = "0.1"

# Note Commitment Trees
bitvec = "1"
incrementalmerkletree = "0.5"

# Note encryption
zcash_note_encryption = "0.4"

# Secret management
subtle = "2.2.3"

# Static constants
lazy_static = "1"

# Test dependencies
proptest = { version = "1", optional = true }

[dependencies.blake2-rfc]
git = "https://github.com/gtank/blake2-rfc"
rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"
# ZIP 32
aes = "0.8"
fpe = "0.6"
zip32 = "0.1"

[dev-dependencies]
hex-literal = "0.1"
rust-crypto = "0.2"
chacha20poly1305 = "0.10"
proptest = "1"
rand_xorshift = "0.3"

[features]
default = ["u128-support"]
u128-support = ["pairing/u128-support"]
multicore = ["bellman/multicore"]
test-dependencies = ["proptest"]
118 changes: 118 additions & 0 deletions src/address.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
use super::{
keys::{DiversifiedTransmissionKey, Diversifier},
note::{Note, Rseed},
value::NoteValue,
};

/// A Sapling payment address.
///
/// # Invariants
///
/// - `diversifier` is guaranteed to be valid for Sapling (only 50% of diversifiers are).
/// - `pk_d` is guaranteed to be prime-order (i.e. in the prime-order subgroup of Jubjub,
/// and not the identity).
#[derive(Clone, Copy, Debug)]
pub struct PaymentAddress {
pk_d: DiversifiedTransmissionKey,
diversifier: Diversifier,
}

impl PartialEq for PaymentAddress {
fn eq(&self, other: &Self) -> bool {
self.pk_d == other.pk_d && self.diversifier == other.diversifier
}
}

impl Eq for PaymentAddress {}

impl PaymentAddress {
/// Constructs a PaymentAddress from a diversifier and a Jubjub point.
///
/// Returns None if `diversifier` is not valid for Sapling, or `pk_d` is the identity.
/// Note that we cannot verify in this constructor that `pk_d` is derived from
/// `diversifier`, so addresses for which these values have no known relationship
/// (and therefore no-one can receive funds at them) can still be constructed.
pub fn from_parts(diversifier: Diversifier, pk_d: DiversifiedTransmissionKey) -> Option<Self> {
// Check that the diversifier is valid
diversifier.g_d()?;

Self::from_parts_unchecked(diversifier, pk_d)
}

/// Constructs a PaymentAddress from a diversifier and a Jubjub point.
///
/// Returns None if `pk_d` is the identity. The caller must check that `diversifier`
/// is valid for Sapling.
pub(crate) fn from_parts_unchecked(
diversifier: Diversifier,
pk_d: DiversifiedTransmissionKey,
) -> Option<Self> {
if pk_d.is_identity() {
None
} else {
Some(PaymentAddress { pk_d, diversifier })
}
}

/// Parses a PaymentAddress from bytes.
pub fn from_bytes(bytes: &[u8; 43]) -> Option<Self> {
let diversifier = {
let mut tmp = [0; 11];
tmp.copy_from_slice(&bytes[0..11]);
Diversifier(tmp)
};

let pk_d = DiversifiedTransmissionKey::from_bytes(bytes[11..43].try_into().unwrap());
if pk_d.is_some().into() {
// The remaining invariants are checked here.
PaymentAddress::from_parts(diversifier, pk_d.unwrap())
} else {
None
}
}

/// Returns the byte encoding of this `PaymentAddress`.
pub fn to_bytes(&self) -> [u8; 43] {
let mut bytes = [0; 43];
bytes[0..11].copy_from_slice(&self.diversifier.0);
bytes[11..].copy_from_slice(&self.pk_d.to_bytes());
bytes
}

/// Returns the [`Diversifier`] for this `PaymentAddress`.
pub fn diversifier(&self) -> &Diversifier {
&self.diversifier
}

/// Returns `pk_d` for this `PaymentAddress`.
pub fn pk_d(&self) -> &DiversifiedTransmissionKey {
&self.pk_d
}

pub(crate) fn g_d(&self) -> jubjub::SubgroupPoint {
self.diversifier.g_d().expect("checked at construction")
}

pub fn create_note(&self, value: NoteValue, rseed: Rseed) -> Note {
Note::from_parts(*self, value, rseed)
}
}

#[cfg(any(test, feature = "test-dependencies"))]
pub(super) mod testing {
use proptest::prelude::*;

use super::{
super::keys::{testing::arb_incoming_viewing_key, Diversifier, SaplingIvk},
PaymentAddress,
};

pub fn arb_payment_address() -> impl Strategy<Value = PaymentAddress> {
arb_incoming_viewing_key().prop_flat_map(|ivk: SaplingIvk| {
any::<[u8; 11]>().prop_filter_map(
"Sampled diversifier must generate a valid Sapling payment address.",
move |d| ivk.to_payment_address(Diversifier(d)),
)
})
}
}
Loading

0 comments on commit a1194fe

Please sign in to comment.