Skip to content

Commit

Permalink
crypto: rework use of rng in swap claim proof
Browse files Browse the repository at this point in the history
  • Loading branch information
redshiftzero committed Jun 29, 2023
1 parent 7d66809 commit 0a4679f
Show file tree
Hide file tree
Showing 11 changed files with 389 additions and 267 deletions.
2 changes: 2 additions & 0 deletions crates/bin/pcli/src/command/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,8 @@ impl TxCmd {
position: swap_record.position,
output_data: swap_record.output_data,
epoch_duration: params.epoch_duration,
proof_blinding_r: Fq::rand(&mut OsRng),
proof_blinding_s: Fq::rand(&mut OsRng),
})
.plan(app.view(), account_group_id, AddressIndex::new(*source))
.await
Expand Down
6 changes: 5 additions & 1 deletion crates/bin/pcli/tests/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,12 @@ fn swap_claim_parameters_vs_current_swap_claim_circuit() {
let note_commitment_1 = output_1_note.commit();
let note_commitment_2 = output_2_note.commit();

let blinding_r = Fq::rand(&mut rng);
let blinding_s = Fq::rand(&mut rng);

let proof = SwapClaimProof::prove(
&mut rng,
blinding_r,
blinding_s,
pk,
swap_plaintext,
state_commitment_proof,
Expand Down
5 changes: 4 additions & 1 deletion crates/core/app/src/tests/swap_and_swap_claim.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use ark_ff::UniformRand;
use std::{ops::Deref, sync::Arc};

use crate::{app::App, MockClient, TempStorageExt};
Expand All @@ -6,7 +7,7 @@ use penumbra_chain::{
test_keys,
};
use penumbra_component::{ActionHandler, Component};
use penumbra_crypto::{asset, Address, Amount, Fee};
use penumbra_crypto::{asset, Address, Amount, Fee, Fq};
use penumbra_shielded_pool::component::ShieldedPool;
use penumbra_storage::{ArcStateDeltaExt, StateDelta, TempStorage};
use penumbra_transaction::Transaction;
Expand Down Expand Up @@ -105,6 +106,8 @@ async fn swap_and_swap_claim() -> anyhow::Result<()> {
position: swap_auth_path.position(),
output_data,
epoch_duration,
proof_blinding_r: Fq::rand(&mut rng),
proof_blinding_s: Fq::rand(&mut rng),
};
let claim = claim_plan.swap_claim(&test_keys::FULL_VIEWING_KEY, &swap_auth_path);

Expand Down
23 changes: 20 additions & 3 deletions crates/core/component/dex/src/swap_claim/plan.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use penumbra_crypto::{
keys::{IncomingViewingKey, NullifierKey},
FullViewingKey, Value,
FieldExt, Fq, FullViewingKey, Value,
};
use penumbra_proof_params::SWAPCLAIM_PROOF_PROVING_KEY;
use penumbra_proto::{core::dex::v1alpha1 as pb, DomainType, TypeUrl};
use penumbra_tct as tct;

use rand_core::OsRng;
use serde::{Deserialize, Serialize};
use tct::Position;

Expand All @@ -22,6 +21,10 @@ pub struct SwapClaimPlan {
pub position: Position,
pub output_data: BatchSwapOutputData,
pub epoch_duration: u64,
/// The first blinding factor used for generating the ZK proof.
pub proof_blinding_r: Fq,
/// The second blinding factor used for generating the ZK proof.
pub proof_blinding_s: Fq,
}

impl SwapClaimPlan {
Expand Down Expand Up @@ -59,7 +62,8 @@ impl SwapClaimPlan {

let nullifier = nk.derive_nullifier(self.position, &self.swap_plaintext.swap_commitment());
SwapClaimProof::prove(
&mut OsRng,
self.proof_blinding_r,
self.proof_blinding_s,
&SWAPCLAIM_PROOF_PROVING_KEY,
self.swap_plaintext.clone(),
state_commitment_proof.clone(),
Expand Down Expand Up @@ -129,13 +133,24 @@ impl From<SwapClaimPlan> for pb::SwapClaimPlan {
position: msg.position.into(),
output_data: Some(msg.output_data.into()),
epoch_duration: msg.epoch_duration,
proof_blinding_r: msg.proof_blinding_r.to_bytes().to_vec(),
proof_blinding_s: msg.proof_blinding_s.to_bytes().to_vec(),
}
}
}

impl TryFrom<pb::SwapClaimPlan> for SwapClaimPlan {
type Error = anyhow::Error;
fn try_from(msg: pb::SwapClaimPlan) -> Result<Self, Self::Error> {
let proof_blinding_r_bytes: [u8; 32] = msg
.proof_blinding_r
.try_into()
.map_err(|_| anyhow::anyhow!("malformed r in `SwapClaimPlan`"))?;
let proof_blinding_s_bytes: [u8; 32] = msg
.proof_blinding_s
.try_into()
.map_err(|_| anyhow::anyhow!("malformed s in `SwapClaimPlan`"))?;

Ok(Self {
swap_plaintext: msg
.swap_plaintext
Expand All @@ -147,6 +162,8 @@ impl TryFrom<pb::SwapClaimPlan> for SwapClaimPlan {
.ok_or_else(|| anyhow::anyhow!("missing output_data"))?
.try_into()?,
epoch_duration: msg.epoch_duration,
proof_blinding_r: Fq::from_bytes(proof_blinding_r_bytes)?,
proof_blinding_s: Fq::from_bytes(proof_blinding_s_bytes)?,
})
}
}
28 changes: 21 additions & 7 deletions crates/core/component/dex/src/swap_claim/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use ark_snark::SNARK;
use decaf377::{r1cs::FqVar, Bls12_377};
use penumbra_proto::{core::crypto::v1alpha1 as pb, DomainType, TypeUrl};
use penumbra_tct as tct;
use rand_core::{CryptoRngCore, OsRng};
use rand_core::OsRng;

use penumbra_crypto::{
asset::{self, AmountVar},
Expand Down Expand Up @@ -286,8 +286,11 @@ pub struct SwapClaimProof(pub [u8; GROTH16_PROOF_LENGTH_BYTES]);

impl SwapClaimProof {
#![allow(clippy::too_many_arguments)]
pub fn prove<R: CryptoRngCore>(
rng: &mut R,
/// Generate an [`SwapClaimProof`] given the proving key, public inputs,
/// witness data, and two random elements `blinding_r` and `blinding_s`.
pub fn prove(
blinding_r: Fq,
blinding_s: Fq,
pk: &ProvingKey<Bls12_377>,
swap_plaintext: SwapPlaintext,
state_commitment_proof: tct::Proof,
Expand Down Expand Up @@ -318,8 +321,10 @@ impl SwapClaimProof {
note_commitment_2,
};

let proof = Groth16::<Bls12_377, LibsnarkReduction>::prove(pk, circuit, rng)
.map_err(|err| anyhow::anyhow!(err))?;
let proof = Groth16::<Bls12_377, LibsnarkReduction>::create_proof_with_reduction(
circuit, pk, blinding_r, blinding_s,
)
.map_err(|err| anyhow::anyhow!(err))?;

let mut proof_bytes = [0u8; GROTH16_PROOF_LENGTH_BYTES];
Proof::serialize_compressed(&proof, &mut proof_bytes[..]).expect("can serialize Proof");
Expand Down Expand Up @@ -393,6 +398,7 @@ impl TryFrom<pb::ZkSwapClaimProof> for SwapClaimProof {
#[cfg(test)]
mod tests {
use super::*;
use ark_ff::UniformRand;
use penumbra_crypto::{
keys::{SeedPhrase, SpendKey},
Amount,
Expand Down Expand Up @@ -455,8 +461,12 @@ mod tests {
let note_commitment_1 = output_1_note.commit();
let note_commitment_2 = output_2_note.commit();

let blinding_r = Fq::rand(&mut rng);
let blinding_s = Fq::rand(&mut rng);

let proof = SwapClaimProof::prove(
&mut rng,
blinding_r,
blinding_s,
&pk,
swap_plaintext,
state_commitment_proof,
Expand Down Expand Up @@ -545,8 +555,12 @@ mod tests {
let note_commitment_1 = output_1_note.commit();
let note_commitment_2 = output_2_note.commit();

let blinding_r = Fq::rand(&mut rng);
let blinding_s = Fq::rand(&mut rng);

let proof = SwapClaimProof::prove(
&mut rng,
blinding_r,
blinding_s,
&pk,
swap_plaintext,
state_commitment_proof,
Expand Down
11 changes: 10 additions & 1 deletion crates/crypto/proof-params/benches/swap_claim.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use ark_ff::UniformRand;
use ark_relations::r1cs::{
ConstraintSynthesizer, ConstraintSystem, OptimizationGoal, SynthesisMode,
};
Expand All @@ -20,6 +21,8 @@ use rand_core::OsRng;

#[allow(clippy::too_many_arguments)]
fn prove(
r: Fq,
s: Fq,
swap_plaintext: SwapPlaintext,
state_commitment_proof: tct::Proof,
nk: NullifierKey,
Expand All @@ -34,7 +37,8 @@ fn prove(
output_data: BatchSwapOutputData,
) {
let _proof = SwapClaimProof::prove(
&mut OsRng,
r,
s,
&SWAPCLAIM_PROOF_PROVING_KEY,
swap_plaintext,
state_commitment_proof,
Expand Down Expand Up @@ -107,9 +111,14 @@ fn swap_claim_proving_time(c: &mut Criterion) {
let note_commitment_1 = output_1_note.commit();
let note_commitment_2 = output_2_note.commit();

let r = Fq::rand(&mut OsRng);
let s = Fq::rand(&mut OsRng);

c.bench_function("swap claim proving", |b| {
b.iter(|| {
prove(
r,
s,
swap_plaintext.clone(),
state_commitment_proof.clone(),
nk,
Expand Down
6 changes: 6 additions & 0 deletions crates/proto/src/gen/penumbra.core.dex.v1alpha1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,12 @@ pub struct SwapClaimPlan {
/// The epoch duration, used in proving.
#[prost(uint64, tag = "4")]
pub epoch_duration: u64,
/// The first blinding factor to use for the ZK swap claim proof.
#[prost(bytes = "vec", tag = "5")]
pub proof_blinding_r: ::prost::alloc::vec::Vec<u8>,
/// The second blinding factor to use for the ZK swap claim proof.
#[prost(bytes = "vec", tag = "6")]
pub proof_blinding_s: ::prost::alloc::vec::Vec<u8>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
Expand Down
40 changes: 40 additions & 0 deletions crates/proto/src/gen/penumbra.core.dex.v1alpha1.serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2413,6 +2413,12 @@ impl serde::Serialize for SwapClaimPlan {
if self.epoch_duration != 0 {
len += 1;
}
if !self.proof_blinding_r.is_empty() {
len += 1;
}
if !self.proof_blinding_s.is_empty() {
len += 1;
}
let mut struct_ser = serializer.serialize_struct("penumbra.core.dex.v1alpha1.SwapClaimPlan", len)?;
if let Some(v) = self.swap_plaintext.as_ref() {
struct_ser.serialize_field("swapPlaintext", v)?;
Expand All @@ -2426,6 +2432,12 @@ impl serde::Serialize for SwapClaimPlan {
if self.epoch_duration != 0 {
struct_ser.serialize_field("epochDuration", ToString::to_string(&self.epoch_duration).as_str())?;
}
if !self.proof_blinding_r.is_empty() {
struct_ser.serialize_field("proofBlindingR", pbjson::private::base64::encode(&self.proof_blinding_r).as_str())?;
}
if !self.proof_blinding_s.is_empty() {
struct_ser.serialize_field("proofBlindingS", pbjson::private::base64::encode(&self.proof_blinding_s).as_str())?;
}
struct_ser.end()
}
}
Expand All @@ -2443,6 +2455,10 @@ impl<'de> serde::Deserialize<'de> for SwapClaimPlan {
"outputData",
"epoch_duration",
"epochDuration",
"proof_blinding_r",
"proofBlindingR",
"proof_blinding_s",
"proofBlindingS",
];

#[allow(clippy::enum_variant_names)]
Expand All @@ -2451,6 +2467,8 @@ impl<'de> serde::Deserialize<'de> for SwapClaimPlan {
Position,
OutputData,
EpochDuration,
ProofBlindingR,
ProofBlindingS,
}
impl<'de> serde::Deserialize<'de> for GeneratedField {
fn deserialize<D>(deserializer: D) -> std::result::Result<GeneratedField, D::Error>
Expand All @@ -2476,6 +2494,8 @@ impl<'de> serde::Deserialize<'de> for SwapClaimPlan {
"position" => Ok(GeneratedField::Position),
"outputData" | "output_data" => Ok(GeneratedField::OutputData),
"epochDuration" | "epoch_duration" => Ok(GeneratedField::EpochDuration),
"proofBlindingR" | "proof_blinding_r" => Ok(GeneratedField::ProofBlindingR),
"proofBlindingS" | "proof_blinding_s" => Ok(GeneratedField::ProofBlindingS),
_ => Err(serde::de::Error::unknown_field(value, FIELDS)),
}
}
Expand All @@ -2499,6 +2519,8 @@ impl<'de> serde::Deserialize<'de> for SwapClaimPlan {
let mut position__ = None;
let mut output_data__ = None;
let mut epoch_duration__ = None;
let mut proof_blinding_r__ = None;
let mut proof_blinding_s__ = None;
while let Some(k) = map.next_key()? {
match k {
GeneratedField::SwapPlaintext => {
Expand Down Expand Up @@ -2529,13 +2551,31 @@ impl<'de> serde::Deserialize<'de> for SwapClaimPlan {
Some(map.next_value::<::pbjson::private::NumberDeserialize<_>>()?.0)
;
}
GeneratedField::ProofBlindingR => {
if proof_blinding_r__.is_some() {
return Err(serde::de::Error::duplicate_field("proofBlindingR"));
}
proof_blinding_r__ =
Some(map.next_value::<::pbjson::private::BytesDeserialize<_>>()?.0)
;
}
GeneratedField::ProofBlindingS => {
if proof_blinding_s__.is_some() {
return Err(serde::de::Error::duplicate_field("proofBlindingS"));
}
proof_blinding_s__ =
Some(map.next_value::<::pbjson::private::BytesDeserialize<_>>()?.0)
;
}
}
}
Ok(SwapClaimPlan {
swap_plaintext: swap_plaintext__,
position: position__.unwrap_or_default(),
output_data: output_data__,
epoch_duration: epoch_duration__.unwrap_or_default(),
proof_blinding_r: proof_blinding_r__.unwrap_or_default(),
proof_blinding_s: proof_blinding_s__.unwrap_or_default(),
})
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/proto/src/gen/proto_descriptor.bin
Git LFS file not shown
Loading

0 comments on commit 0a4679f

Please sign in to comment.