Add ZSA functionality

The following modifications are required to support the ZSA circuit changes:
- Added a function CommitDomain::new_with_personalization to initialize the CommitDomain from two different personalizations. This is required to be able to use an identical R for ZEC and ZSA note commitments but a different Q.
- Added a function commit_from_hash_point to evaluate a Sinsemilla commit from a hash point.
- Added the ability to hash and blind independently.
This commit is contained in:
Constance Beguier 2025-03-20 09:36:56 +01:00 committed by GitHub
parent c61524dcce
commit 3542e897d4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 274 additions and 1 deletions

213
Cargo.lock generated Normal file
View File

@ -0,0 +1,213 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "arrayref"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
[[package]]
name = "arrayvec"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "blake2b_simd"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06e903a20b159e944f91ec8499fe1e55651480c541ea0a584f5d967c49ad9d99"
dependencies = [
"arrayref",
"arrayvec",
"constant_time_eq",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "constant_time_eq"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
[[package]]
name = "ff"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393"
dependencies = [
"rand_core",
"subtle",
]
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "group"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
dependencies = [
"ff",
"rand_core",
"subtle",
]
[[package]]
name = "libc"
version = "0.2.170"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828"
[[package]]
name = "pasta_curves"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095"
dependencies = [
"blake2b_simd",
"ff",
"group",
"rand",
"static_assertions",
"subtle",
]
[[package]]
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "sinsemilla"
version = "0.1.0"
dependencies = [
"ff",
"group",
"pasta_curves",
"rand",
"subtle",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "zerocopy"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

View File

@ -18,5 +18,9 @@ group = "0.13"
pasta_curves = { version = "0.5", default-features = false, features = ["alloc"] }
subtle = { version = "2.3", default-features = false }
[dev-dependencies]
ff = { version = "0.13", default-features = false }
rand = { version = "0.8" }
[features]
test-dependencies = []

View File

@ -212,6 +212,17 @@ impl CommitDomain {
}
}
/// Constructs a new `CommitDomain` from different values for `hash_domain` and `blind_domain`
pub fn new_with_personalization(hash_domain: &str, blind_domain: &str) -> Self {
let m_prefix = format!("{}-M", hash_domain);
let r_prefix = format!("{}-r", blind_domain);
let hasher_r = pallas::Point::hash_to_curve(&r_prefix);
CommitDomain {
M: HashDomain::new(&m_prefix),
R: hasher_r(&[]),
}
}
/// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit].
///
/// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit
@ -226,6 +237,26 @@ impl CommitDomain {
.map(|p| p + Wnaf::new().scalar(r).base(self.R))
}
/// $\mathsf{SinsemillaHashToPoint}$ from [§ 5.4.1.9][concretesinsemillahash].
///
/// [concretesinsemillahash]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillahash
pub fn hash_to_point(&self, msg: impl Iterator<Item = bool>) -> CtOption<pallas::Point> {
self.M.hash_to_point(msg)
}
/// Returns `SinsemillaCommit_r(personalization, msg) = hash_point + [r]R`
/// where `SinsemillaHash(personalization, msg) = hash_point`
/// and `R` is derived from the `personalization`.
#[allow(non_snake_case)]
pub fn commit_from_hash_point(
&self,
hash_point: CtOption<pallas::Point>,
r: &pallas::Scalar,
) -> CtOption<pallas::Point> {
// We use complete addition for the blinding factor.
hash_point.map(|p| p + Wnaf::new().scalar(r).base(self.R))
}
/// $\mathsf{SinsemillaShortCommit}$ from [§ 5.4.8.4][concretesinsemillacommit].
///
/// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit
@ -258,8 +289,10 @@ impl CommitDomain {
mod tests {
use alloc::vec::Vec;
use super::{Pad, K};
use super::{Pad, K, CommitDomain};
use pasta_curves::{arithmetic::CurveExt, pallas};
use ff::Field;
use rand::{rngs::OsRng, Rng};
#[test]
fn pad() {
@ -319,4 +352,27 @@ mod tests {
assert_eq!(computed, actual);
}
}
#[test]
fn commit_in_several_steps() {
let domain = CommitDomain::new("z.cash:ZSA-NoteCommit");
let mut os_rng = OsRng;
let msg: Vec<bool> = (0..36).map(|_| os_rng.gen::<bool>()).collect();
let rcm = pallas::Scalar::random(&mut os_rng);
// Evaluate the commitment with commit function
let commit1 = domain.commit(msg.clone().into_iter(), &rcm);
// Evaluate the commitment with the following steps
// 1. hash msg
// 2. evaluate the commitment from the hash point
let hash_point = domain.M.hash_to_point(msg.into_iter());
let commit2 = domain.commit_from_hash_point(hash_point, &rcm);
// Test equality
assert_eq!(commit1.unwrap(), commit2.unwrap());
}
}