Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generalized orchardZSA #96

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
f9563f4
draft2
PaulLaux Jan 4, 2024
ba18c57
draft3
PaulLaux Jan 4, 2024
3d30876
draft4
PaulLaux Jan 4, 2024
52c28f1
draft5
PaulLaux Jan 4, 2024
f144fdb
draft6
PaulLaux Jan 4, 2024
b626ed9
Generalize orchard_zsa for backward bompatibility with non-ZSA functi…
dmidem Jan 17, 2024
65ae5f4
Minor changes in the doc comments
dmidem Jan 17, 2024
b628056
Add tests for note_encryption_v2
dmidem Jan 22, 2024
19bdfe1
Rename V2 name suffixes to Vanilla, and V3 - to ZSA
dmidem Jan 24, 2024
98ed01d
Make the Circuit struct generic to support different Orchard variants…
dmidem Jan 29, 2024
aeca03d
Continue Circuit generalization
dmidem Feb 6, 2024
7642927
Split circuit implementation into circuit_vanilla and circuit_zsa
dmidem Feb 12, 2024
b9f2878
Fix to support modified halo2
dmidem Feb 27, 2024
6958052
Add missed fields to fn print_action_circuit
dmidem Feb 27, 2024
886796e
Pin half crate to 1.8.2 (to resolve MSRV conflict)
dmidem Feb 27, 2024
6945948
Pin half crate to 1.8.2 for dev deps too (to resolve MSRV conflict)
dmidem Feb 27, 2024
4ac06bf
Pin half crate to 2.2.1
dmidem Feb 27, 2024
6ee3839
Fix cargo clippy errors
dmidem Feb 27, 2024
656ecd9
Convert arb_... testing functions to methods of dummy generict struct…
dmidem Mar 4, 2024
eb10eb7
Make hash_bundle_txid_data function backwards compatible
dmidem Mar 4, 2024
d4f3b2b
Refactor note_encryption.rs:
dmidem Mar 12, 2024
0a57dcc
Fix cargo clippy errors
dmidem Mar 12, 2024
f58a91c
Minor fix (make action module pub)
dmidem Mar 12, 2024
5887dc8
Make add_chip.rs a shared module between circuit_vanilla and circuit_…
dmidem Mar 15, 2024
d08fcd8
Introduce OrcharcCircuit trait to eliminate repetitive 'where crate::…
dmidem Mar 18, 2024
214a3e2
Introdice NoteByteReader and NoteByteWriter traiots to use with NoteB…
dmidem Mar 19, 2024
0e4f0e9
note_encryption: extract Domain impl, OrchardDoimain and NoteBytes de…
dmidem Mar 19, 2024
e987f39
Use vec with a proper length for the concrete OrchardDomain to genera…
dmidem Mar 25, 2024
add7e3f
Use try_fold instead of fold when cargo clippy suggests it
dmidem Mar 25, 2024
fb868fd
Rename domain_impl.rs in note_encryption to domain.rs
dmidem Mar 25, 2024
f39fa28
Intriduce orchard_flavor module with OrchardVanilla and OrchardZSA st…
dmidem Mar 25, 2024
a680158
Fix naming (OrchardDomainContex to OrchardDomainBase, Curcuit to Orch…
dmidem Mar 28, 2024
0f635d2
Fix 'half' dep duplication in Cargo.toml
dmidem Apr 9, 2024
617d37a
Remove rng from AssetBase::random call
dmidem Apr 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ Cargo.lock
.vscode
.idea
action-circuit-layout.png
*.[0-9]
*.[0-9][0-9]
9 changes: 5 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ rustdoc-args = ["--cfg", "docsrs", "--html-in-header", "katex-header.html"]
aes = "0.8"
bitvec = "1"
blake2b_simd = "=1.0.1" # Last version required rust 1.66
half = "=2.2.1" # Last version requires Rust 1.70
ff = "0.13"
fpe = "0.6"
group = { version = "0.13", features = ["wnaf-memuse"] }
halo2_gadgets = { git = "https://github.com/QED-it/halo2", branch = "zsa1" }
halo2_proofs = { git = "https://github.com/QED-it/halo2", branch = "zsa1", default-features = false, features = ["batch", "floor-planner-v1-legacy-pdqsort"] }
halo2_gadgets = { git = "https://github.com/QED-it/halo2", branch = "orchardzsa-backward-compatability" }
halo2_proofs = { git = "https://github.com/QED-it/halo2", branch = "orchardzsa-backward-compatability", default-features = false, features = ["batch", "floor-planner-v1-legacy-pdqsort"] }
hex = "0.4"
k256 = { version = "0.13.0", features = ["arithmetic", "schnorr"] }
lazy_static = "1"
Expand All @@ -54,8 +55,8 @@ plotters = { version = "0.3.0", optional = true }

[dev-dependencies]
bridgetree = "0.4"
criterion = "0.4" #Pinned: 0.5 depends on clap 4 which has MSRV 1.70
halo2_gadgets = { git = "https://github.com/QED-it/halo2", branch = "zsa1", features = ["test-dependencies"] }
criterion = "0.4" # 0.5 depends on clap 4 which has MSRV 1.70
halo2_gadgets = { git = "https://github.com/QED-it/halo2", branch = "orchardzsa-backward-compatability", features = ["test-dependencies"] }
hex = "0.4"
proptest = "1.0.0"
zcash_note_encryption_zsa = { package = "zcash_note_encryption", version = "0.4", git = "https://github.com/QED-it/zcash_note_encryption", branch = "zsa1", features = ["pre-zip-212"] }
Expand Down
8 changes: 5 additions & 3 deletions benches/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use orchard::{
bundle::Flags,
circuit::{ProvingKey, VerifyingKey},
keys::{FullViewingKey, Scope, SpendingKey},
orchard_flavor::OrchardZSA,
value::NoteValue,
Anchor, Bundle,
};
Expand All @@ -23,8 +24,9 @@ fn criterion_benchmark(c: &mut Criterion) {
let sk = SpendingKey::from_bytes([7; 32]).unwrap();
let recipient = FullViewingKey::from(&sk).address_at(0u32, Scope::External);

let vk = VerifyingKey::build();
let pk = ProvingKey::build();
// FIXME: consider adding test for OrchardVanilla as well
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, we need both

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets have this as a separate task

let vk = VerifyingKey::build::<OrchardZSA>();
let pk = ProvingKey::build::<OrchardZSA>();

let create_bundle = |num_recipients| {
let mut builder = Builder::new(
Expand All @@ -42,7 +44,7 @@ fn criterion_benchmark(c: &mut Criterion) {
)
.unwrap();
}
let bundle: Bundle<_, i64> = builder.build(rng).unwrap();
let bundle: Bundle<_, i64, OrchardZSA> = builder.build(rng).unwrap();

let instances: Vec<_> = bundle
.actions()
Expand Down
16 changes: 10 additions & 6 deletions benches/note_decryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use orchard::{
circuit::ProvingKey,
keys::{FullViewingKey, PreparedIncomingViewingKey, Scope, SpendingKey},
note::AssetBase,
note_encryption_v3::{CompactAction, OrchardDomainV3},
note_encryption::{action::CompactAction, OrchardDomainBase},
orchard_flavor::OrchardZSA,
value::NoteValue,
Anchor, Bundle,
};
Expand All @@ -15,9 +16,12 @@ use zcash_note_encryption_zsa::{batch, try_compact_note_decryption, try_note_dec
#[cfg(unix)]
use pprof::criterion::{Output, PProfProfiler};

type OrchardDomainZSA = OrchardDomainBase<OrchardZSA>;

fn bench_note_decryption(c: &mut Criterion) {
let rng = OsRng;
let pk = ProvingKey::build();
// FIXME: consider adding test for OrchardVanilla as well
let pk = ProvingKey::build::<OrchardZSA>();

let fvk = FullViewingKey::from(&SpendingKey::from_bytes([7; 32]).unwrap());
let valid_ivk = fvk.to_ivk(Scope::External);
Expand Down Expand Up @@ -70,7 +74,7 @@ fn bench_note_decryption(c: &mut Criterion) {
None,
)
.unwrap();
let bundle: Bundle<_, i64> = builder.build(rng).unwrap();
let bundle: Bundle<_, i64, OrchardZSA> = builder.build(rng).unwrap();
bundle
.create_proof(&pk, rng)
.unwrap()
Expand All @@ -79,7 +83,7 @@ fn bench_note_decryption(c: &mut Criterion) {
};
let action = bundle.actions().first();

let domain = OrchardDomainV3::for_action(action);
let domain = OrchardDomainZSA::for_action(action);

let compact = {
let mut group = c.benchmark_group("note-decryption");
Expand Down Expand Up @@ -120,12 +124,12 @@ fn bench_note_decryption(c: &mut Criterion) {
let ivks = 2;
let valid_ivks = vec![valid_ivk; ivks];
let actions: Vec<_> = (0..100)
.map(|_| (OrchardDomainV3::for_action(action), action.clone()))
.map(|_| (OrchardDomainZSA::for_action(action), action.clone()))
.collect();
let compact: Vec<_> = (0..100)
.map(|_| {
(
OrchardDomainV3::for_action(action),
OrchardDomainZSA::for_action(action),
CompactAction::from(action),
)
})
Expand Down
156 changes: 85 additions & 71 deletions src/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use memuse::DynamicUsage;

use crate::{
note::{ExtractedNoteCommitment, Nullifier, TransmittedNoteCiphertext},
note_encryption::OrchardDomain,
primitives::redpallas::{self, SpendAuth},
value::ValueCommitment,
};
Expand All @@ -15,30 +16,30 @@ use crate::{
/// Internally, this may both consume a note and create a note, or it may do only one of
/// the two. TODO: Determine which is more efficient (circuit size vs bundle size).
#[derive(Debug, Clone)]
pub struct Action<A> {
pub struct Action<A, D: OrchardDomain> {
/// The nullifier of the note being spent.
nf: Nullifier,
/// The randomized verification key for the note being spent.
rk: redpallas::VerificationKey<SpendAuth>,
/// A commitment to the new note being created.
cmx: ExtractedNoteCommitment,
/// The transmitted note ciphertext.
encrypted_note: TransmittedNoteCiphertext,
encrypted_note: TransmittedNoteCiphertext<D>,
/// A commitment to the net value created or consumed by this action.
cv_net: ValueCommitment,
/// The authorization for this action.
authorization: A,
}

impl<T> Action<T> {
impl<A, D: OrchardDomain> Action<A, D> {
/// Constructs an `Action` from its constituent parts.
pub fn from_parts(
nf: Nullifier,
rk: redpallas::VerificationKey<SpendAuth>,
cmx: ExtractedNoteCommitment,
encrypted_note: TransmittedNoteCiphertext,
encrypted_note: TransmittedNoteCiphertext<D>,
cv_net: ValueCommitment,
authorization: T,
authorization: A,
) -> Self {
Action {
nf,
Expand Down Expand Up @@ -66,7 +67,7 @@ impl<T> Action<T> {
}

/// Returns the encrypted note ciphertext.
pub fn encrypted_note(&self) -> &TransmittedNoteCiphertext {
pub fn encrypted_note(&self) -> &TransmittedNoteCiphertext<D> {
&self.encrypted_note
}

Expand All @@ -76,12 +77,12 @@ impl<T> Action<T> {
}

/// Returns the authorization for this action.
pub fn authorization(&self) -> &T {
pub fn authorization(&self) -> &A {
&self.authorization
}

/// Transitions this action from one authorization state to another.
pub fn map<U>(self, step: impl FnOnce(T) -> U) -> Action<U> {
pub fn map<U>(self, step: impl FnOnce(A) -> U) -> Action<U, D> {
Action {
nf: self.nf,
rk: self.rk,
Expand All @@ -93,7 +94,7 @@ impl<T> Action<T> {
}

/// Transitions this action from one authorization state to another.
pub fn try_map<U, E>(self, step: impl FnOnce(T) -> Result<U, E>) -> Result<Action<U>, E> {
pub fn try_map<U, E>(self, step: impl FnOnce(A) -> Result<U, E>) -> Result<Action<U, D>, E> {
Ok(Action {
nf: self.nf,
rk: self.rk,
Expand All @@ -105,7 +106,7 @@ impl<T> Action<T> {
}
}

impl DynamicUsage for Action<redpallas::Signature<SpendAuth>> {
impl<D: OrchardDomain> DynamicUsage for Action<redpallas::Signature<SpendAuth>, D> {
#[inline(always)]
fn dynamic_usage(&self) -> usize {
0
Expand All @@ -132,6 +133,7 @@ pub(crate) mod testing {
commitment::ExtractedNoteCommitment, nullifier::testing::arb_nullifier,
testing::arb_note, TransmittedNoteCiphertext,
},
note_encryption::OrchardDomain,
primitives::redpallas::{
self,
testing::{arb_spendauth_signing_key, arb_spendauth_verification_key},
Expand All @@ -141,70 +143,82 @@ pub(crate) mod testing {

use super::Action;

prop_compose! {
/// Generate an action without authorization data.
pub fn arb_unauthorized_action(spend_value: NoteValue, output_value: NoteValue)(
nf in arb_nullifier(),
rk in arb_spendauth_verification_key(),
note in arb_note(output_value),
asset in arb_asset_base()
) -> Action<()> {
let cmx = ExtractedNoteCommitment::from(note.commitment());
let cv_net = ValueCommitment::derive(
spend_value - output_value,
ValueCommitTrapdoor::zero(),
asset
);
// FIXME: make a real one from the note.
let encrypted_note = TransmittedNoteCiphertext {
epk_bytes: [0u8; 32],
enc_ciphertext: [0u8; 612],
out_ciphertext: [0u8; 80]
};
Action {
nf,
rk,
cmx,
encrypted_note,
cv_net,
authorization: ()
/// `ActionArb` serves as a utility structure in property-based testing, designed specifically to adapt
/// `arb_...` functions for compatibility with both variations of the Orchard protocol: Vanilla and ZSA.
/// This adaptation is necessary due to the proptest crate's limitation, which prevents the direct
/// transformation of `arb_...` functions into generic forms suitable for testing different protocol
/// flavors.
#[derive(Debug)]
pub struct ActionArb<D: OrchardDomain> {
phantom: std::marker::PhantomData<D>,
}

impl<D: OrchardDomain> ActionArb<D> {
prop_compose! {
/// Generate an action without authorization data.
pub fn arb_unauthorized_action(spend_value: NoteValue, output_value: NoteValue)(
nf in arb_nullifier(),
rk in arb_spendauth_verification_key(),
note in arb_note(output_value),
asset in arb_asset_base()
) -> Action<(), D> {
let cmx = ExtractedNoteCommitment::from(note.commitment());
let cv_net = ValueCommitment::derive(
spend_value - output_value,
ValueCommitTrapdoor::zero(),
asset
);
// FIXME: make a real one from the note.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do this

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

call arb_native_note() to create a note

let encrypted_note = TransmittedNoteCiphertext::<D> {
epk_bytes: [0u8; 32],
enc_ciphertext: D::NoteCiphertextBytes::from(&vec![0u8; D::ENC_CIPHERTEXT_SIZE]),
out_ciphertext: [0u8; 80]
};
Action {
nf,
rk,
cmx,
encrypted_note,
cv_net,
authorization: ()
}
}
}
}

prop_compose! {
/// Generate an action with invalid (random) authorization data.
pub fn arb_action(spend_value: NoteValue, output_value: NoteValue)(
nf in arb_nullifier(),
sk in arb_spendauth_signing_key(),
note in arb_note(output_value),
rng_seed in prop::array::uniform32(prop::num::u8::ANY),
fake_sighash in prop::array::uniform32(prop::num::u8::ANY),
asset in arb_asset_base()
) -> Action<redpallas::Signature<SpendAuth>> {
let cmx = ExtractedNoteCommitment::from(note.commitment());
let cv_net = ValueCommitment::derive(
spend_value - output_value,
ValueCommitTrapdoor::zero(),
asset
);

// FIXME: make a real one from the note.
let encrypted_note = TransmittedNoteCiphertext {
epk_bytes: [0u8; 32],
enc_ciphertext: [0u8; 612],
out_ciphertext: [0u8; 80]
};

let rng = StdRng::from_seed(rng_seed);

Action {
nf,
rk: redpallas::VerificationKey::from(&sk),
cmx,
encrypted_note,
cv_net,
authorization: sk.sign(rng, &fake_sighash),
prop_compose! {
/// Generate an action with invalid (random) authorization data.
pub fn arb_action(spend_value: NoteValue, output_value: NoteValue)(
nf in arb_nullifier(),
sk in arb_spendauth_signing_key(),
note in arb_note(output_value),
rng_seed in prop::array::uniform32(prop::num::u8::ANY),
fake_sighash in prop::array::uniform32(prop::num::u8::ANY),
asset in arb_asset_base()
) -> Action<redpallas::Signature<SpendAuth>, D> {
let cmx = ExtractedNoteCommitment::from(note.commitment());
let cv_net = ValueCommitment::derive(
spend_value - output_value,
ValueCommitTrapdoor::zero(),
asset
);

// FIXME: make a real one from the note.
let encrypted_note = TransmittedNoteCiphertext::<D> {
epk_bytes: [0u8; 32],
enc_ciphertext: D::NoteCiphertextBytes::from(&vec![0u8; D::ENC_CIPHERTEXT_SIZE]),
out_ciphertext: [0u8; 80]
};

let rng = StdRng::from_seed(rng_seed);

Action {
nf,
rk: redpallas::VerificationKey::from(&sk),
cmx,
encrypted_note,
cv_net,
authorization: sk.sign(rng, &fake_sighash),
}
}
}
}
Expand Down
Loading
Loading