Circuit: optimize ZEC/ZSA hash computations in note commitment (#87)

We optimized note_commitment evaluation by sharing a portion of the hash evaluation between ZEC and ZSA.
1. message_common_prefix = a || b || c || d || e || f || g
2. message_suffix_zec = h_zec
3. message_suffix_zsa = h_zsa || i || j
4. Q = if (is_native_asset == 0) {Q_ZSA} else {Q_ZEC}
5. common_hash = hash(Q, message_common_prefix) // this part is shared
6. hash_point_zec = hash(common_hash, message_suffix_zec)
7. hash_point_zsa = hash(common_hash, message_suffix_zsa)
8. hash_point = if (is_native_asset == 0) {hash_point_zsa} else {hash_point_zec}
This commit is contained in:
Constance Beguier 2023-10-18 10:38:59 +02:00 committed by GitHub
parent 2810365f93
commit a680f410a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 3087 additions and 2030 deletions

View File

@ -15,7 +15,7 @@ use crate::{
use halo2_gadgets::{
ecc::{
chip::{EccChip, NonIdentityEccPoint},
Point, ScalarFixed,
NonIdentityPoint, Point, ScalarFixed,
},
sinsemilla::{
chip::{SinsemillaChip, SinsemillaConfig},
@ -1849,8 +1849,8 @@ pub(in crate::circuit) mod gadgets {
//
// https://p.z.cash/ZKS:action-cm-old-integrity?partial
// https://p.z.cash/ZKS:action-cmx-new-integrity?partial
let (cm, zs) = {
let message_zec = Message::from_pieces(
let (cm, zs_common, zs_zsa_suffix) = {
let message_common_prefix = Message::from_pieces(
chip.clone(),
vec![
a.clone(),
@ -1860,26 +1860,24 @@ pub(in crate::circuit) mod gadgets {
e.clone(),
f.clone(),
g.clone(),
h_zec.clone(),
],
);
let message_zsa = Message::from_pieces(
chip.clone(),
vec![
a.clone(),
b.clone(),
c.clone(),
d.clone(),
e.clone(),
f.clone(),
g.clone(),
h_zsa.clone(),
i.clone(),
j.clone(),
],
);
let message_suffix_zec = Message::from_pieces(chip.clone(), vec![h_zec.clone()]);
let message_suffix_zsa =
Message::from_pieces(chip.clone(), vec![h_zsa.clone(), i.clone(), j.clone()]);
// We will evaluate
// - `hash_point_zec = hash(Q_ZEC, message_common_prefix || message_suffix_zec)`, and
// - `hash_point_zsa = hash(Q_ZSA, message_common_prefix || message_suffix_zsa)`.
// by sharing a portion of the hash evaluation process between `hash_point_zec` and
// `hash_point_zsa`:
// 1. Q = if (is_native_asset == 0) {Q_ZSA} else {Q_ZEC}
// 2. common_hash = hash(Q, message_common_prefix) // this part is shared
// 3. hash_point_zec = hash(common_hash, message_suffix_zec)
// 4. hash_point_zsa = hash(common_hash, message_suffix_zsa)
// 5. hash_point = if (is_native_asset == 0) {hash_point_zsa} else {hash_point_zec}
let zec_domain = CommitDomain::new(
chip.clone(),
ecc_chip.clone(),
@ -1888,22 +1886,53 @@ pub(in crate::circuit) mod gadgets {
let zsa_domain =
CommitDomain::new(chip, ecc_chip.clone(), &OrchardCommitDomains::NoteZsaCommit);
// We evaluate `hash_point_zec=hash(Q_ZEC, message_zec)` and `hash_point_zsa(Q_ZSA, message_zsa)
// and then perform a MUX to select the desired hash_point
// TODO: We can optimize the evaluation of hash_point by mutualizing a portion of the
// hash evaluation process between hash_point_zec and hash_point_zsa.
// 1. common_bits = a || b || c || d || e || f || g
// 2. suffix_zec = h_zec
// 3. suffix_zsa = h_zsa || i || j
// 4. Q = if (is_native_asset == 0) {Q_ZSA} else {Q_ZEC}
// 5. hash_prefix = hash(Q, common_bits) // this part is mutualized
// 6. hash_zec = hash(hash_prefix, suffix_zec)
// 7. hash_zsa = hash(hash_prefix, suffix_zsa)
// 8. hash_point = if (is_native_asset == 0) {hash_zsa} else {hash_zec}
let (hash_point_zec, _zs_zec) =
zec_domain.hash(layouter.namespace(|| "hash ZEC note"), message_zec)?;
let (hash_point_zsa, zs_zsa) =
zsa_domain.hash(layouter.namespace(|| "hash ZSA note"), message_zsa)?;
// Perform a MUX to select the desired initial Q point
// q_init = q_init_zec if is_native_asset is true
// q_init = q_init_zsa if is_native_asset is false
let q_init = {
let q_init_zec = NonIdentityPoint::new(
ecc_chip.clone(),
layouter.namespace(|| "q_init_zec"),
Value::known(zec_domain.q_init()),
)?;
let q_init_zsa = NonIdentityPoint::new(
ecc_chip.clone(),
layouter.namespace(|| "q_init_zsa"),
Value::known(zsa_domain.q_init()),
)?;
mux_chip.mux_on_non_identity_points(
layouter.namespace(|| "mux on hash point"),
&is_native_asset,
q_init_zsa.inner(),
q_init_zec.inner(),
)?
};
// common_hash = hash(q_init, message_common_prefix)
//
// To evaluate the different hash, we could use either zec_domain or zsa_domain
// because we use a private initial point.
let (common_hash, zs_common) = zec_domain.hash_with_private_init(
layouter.namespace(|| "hash common prefix note"),
&q_init,
message_common_prefix,
)?;
// hash_point_zec = hash(common_hash, message_suffix_zec) = hash(q_init, message_zec)
let (hash_point_zec, _zs_zec) = zec_domain.hash_with_private_init(
layouter.namespace(|| "hash suffix ZEC note"),
common_hash.inner(),
message_suffix_zec,
)?;
// hash_point_zsa = hash(common_hash, message_suffix_zsa) = hash(q_init, message_zsa)
let (hash_point_zsa, zs_zsa) = zec_domain.hash_with_private_init(
layouter.namespace(|| "hash suffix ZSA note"),
common_hash.inner(),
message_suffix_zsa,
)?;
// Perform a MUX to select the desired hash point
// hash_point = hash_zec if is_native_asset is true
@ -1925,19 +1954,19 @@ pub(in crate::circuit) mod gadgets {
let commitment =
hash_point.add(layouter.namespace(|| "M + [r] R"), &blinding_factor)?;
(commitment, zs_zsa)
(commitment, zs_common, zs_zsa)
};
// `CommitDomain::hash` returns the running sum for each `MessagePiece`. Grab
// the outputs that we will need for canonicity checks.
let z13_a = zs[0][13].clone();
let z13_c = zs[2][13].clone();
let z1_d = zs[3][1].clone();
let z13_f = zs[5][13].clone();
let z1_g = zs[6][1].clone();
let z13_a = zs_common[0][13].clone();
let z13_c = zs_common[2][13].clone();
let z1_d = zs_common[3][1].clone();
let z13_f = zs_common[5][13].clone();
let z1_g = zs_common[6][1].clone();
let g_2 = z1_g.clone();
let z13_g = zs[6][13].clone();
let z13_i = zs[8][13].clone();
let z13_g = zs_common[6][13].clone();
let z13_i = zs_zsa_suffix[1][13].clone();
// Witness and constrain the bounds we need to ensure canonicity.
let (a_prime, z13_a_prime) = canon_bitshift_130(

File diff suppressed because it is too large Load Diff

Binary file not shown.