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

Relax Ownership Requirements for piprm. #446

Merged
merged 1 commit into from
Jul 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 4 additions & 2 deletions src/auxinfo/auxinfo_commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ impl CommitmentScheme {
rng.fill_bytes(rid.as_mut_slice());
rng.fill_bytes(u_i.as_mut_slice());

public_key.verify(&auxinfo_participant.retrieve_context())?;
public_key
.clone()
gatoWololo marked this conversation as resolved.
Show resolved Hide resolved
.verify(&auxinfo_participant.retrieve_context())?;
if auxinfo_participant.id() != public_key.participant() {
error!("Created auxinfo commitment scheme with different participant IDs in the sender and public_key fields");
return Err(InternalError::InternalInvariantFailed);
Expand All @@ -119,7 +121,7 @@ impl CommitmentScheme {
let scheme: CommitmentScheme = deserialize!(&message.unverified_bytes)?;

// Public parameters in this decommit must be consistent with each other
scheme.public_key.verify(context)?;
scheme.clone().public_key.verify(context)?;

// Owner must be consistent across message, public keys, and decommit
if scheme.public_key.participant() != scheme.pid {
Expand Down
4 changes: 2 additions & 2 deletions src/auxinfo/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ impl AuxInfoPublic {
pk: encryption_key,
params,
};
public.verify(context)?;
public.clone().verify(context)?;
Ok(public)
}

Expand All @@ -184,7 +184,7 @@ impl AuxInfoPublic {
/// Verifies that the public key's modulus matches the ZKSetupParameters
/// modulus N, and that the parameters have appropriate s and t values.
#[instrument(skip_all, err(Debug))]
pub(crate) fn verify(&self, context: &impl ProofContext) -> Result<()> {
pub(crate) fn verify(self, context: &impl ProofContext) -> Result<()> {
if self.pk.modulus() != self.params.scheme().modulus() {
error!("Mismatch between public key modulus and setup parameters modulus");
return Err(InternalError::Serialization);
Expand Down
2 changes: 1 addition & 1 deletion src/auxinfo/participant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -806,7 +806,7 @@ mod tests {
let public_key = output.find_public(pid);
assert!(public_key.is_some());
// Check that it's valid while we're here.
assert!(public_key.unwrap().verify(&context).is_ok());
assert!(public_key.unwrap().clone().verify(&context).is_ok());
publics_for_pid.push(public_key.unwrap());
}

Expand Down
12 changes: 7 additions & 5 deletions src/ring_pedersen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::{
utils::{modpow, random_plusminus_scaled, random_positive_bn},
zkp::{
piprm::{PiPrmProof, PiPrmSecret},
Proof, ProofContext,
Proof2, ProofContext,
},
};
use bytemuck::TransparentWrapper;
Expand Down Expand Up @@ -155,17 +155,19 @@ impl VerifiedRingPedersen {
rng: &mut (impl RngCore + CryptoRng),
) -> Result<Self> {
let (scheme, lambda, totient) = RingPedersen::extract(sk, rng)?;
let secrets = PiPrmSecret::new(lambda, totient);
let secrets = PiPrmSecret::new(&lambda, &totient);
let mut transcript = Transcript::new(b"PiPrmProof");
let proof = PiPrmProof::prove(&scheme, &secrets, context, &mut transcript, rng)?;
let proof = PiPrmProof::prove(&scheme, secrets, context, &mut transcript, rng)?;
Ok(Self { scheme, proof })
}

/// Verifies that the underlying [`RingPedersen`] commitment scheme was
/// constructed correctly according to the associated [`PiPrmProof`].
pub(crate) fn verify(&self, context: &impl ProofContext) -> Result<()> {
pub(crate) fn verify(self, context: &impl ProofContext) -> Result<()> {
let mut transcript = Transcript::new(b"PiPrmProof");
self.proof.verify(self.scheme(), context, &mut transcript)
// Note we directly borrow the `self.scheme` field instead of using the
// `.scheme()` method to avoid Rust lifetime issues.
self.proof.verify(&self.scheme, context, &mut transcript)
}

/// Returns the underlying [`RingPedersen`] commitment scheme associated
Expand Down
112 changes: 50 additions & 62 deletions src/zkp/piprm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,14 @@ use crate::{
errors::*,
ring_pedersen::RingPedersen,
utils::*,
zkp::{Proof, ProofContext},
zkp::{Proof2, ProofContext},
};
use libpaillier::unknown_order::BigNumber;
use merlin::Transcript;
use rand::{CryptoRng, RngCore};
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use tracing::error;
use zeroize::ZeroizeOnDrop;

// Soundness parameter.
const SOUNDNESS: usize = crate::parameters::SOUNDNESS_PARAMETER;
Expand All @@ -56,16 +55,15 @@ pub(crate) struct PiPrmProof {
/// This is comprised of two components:
/// 1. The secret exponent used when generating the [`RingPedersen`] parameters.
/// 2. Euler's totient of [`RingPedersen::modulus`].
#[derive(ZeroizeOnDrop)]
pub(crate) struct PiPrmSecret {
pub(crate) struct PiPrmSecret<'a> {
/// The secret exponent that correlates [`RingPedersen`] parameters
/// [`s`](RingPedersen::s) and [`t`](RingPedersen::t).
exponent: BigNumber,
exponent: &'a BigNumber,
/// Euler's totient of [`RingPedersen::modulus`].
totient: BigNumber,
totient: &'a BigNumber,
}

impl Debug for PiPrmSecret {
impl<'a> Debug for PiPrmSecret<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("piprm::PiPrmSecret")
.field("exponent", &"[redacted]")
Expand All @@ -74,9 +72,9 @@ impl Debug for PiPrmSecret {
}
}

impl PiPrmSecret {
impl<'a> PiPrmSecret<'a> {
/// Collect the secret knowledge for proving [`PiPrmProof`].
pub(crate) fn new(exponent: BigNumber, totient: BigNumber) -> Self {
pub(crate) fn new(exponent: &'a BigNumber, totient: &'a BigNumber) -> Self {
Self { exponent, totient }
}
}
Expand All @@ -98,20 +96,20 @@ fn generate_challenge_bytes(
Ok(challenges.into())
}

impl Proof for PiPrmProof {
type CommonInput = RingPedersen;
type ProverSecret = PiPrmSecret;
impl Proof2 for PiPrmProof {
type CommonInput<'a> = &'a RingPedersen;
gatoWololo marked this conversation as resolved.
Show resolved Hide resolved
gatoWololo marked this conversation as resolved.
Show resolved Hide resolved
type ProverSecret<'a> = PiPrmSecret<'a>;
#[cfg_attr(feature = "flame_it", flame("PiPrmProof"))]
fn prove<R: RngCore + CryptoRng>(
input: &Self::CommonInput,
secret: &Self::ProverSecret,
input: Self::CommonInput<'_>,
secret: Self::ProverSecret<'_>,
context: &impl ProofContext,
transcript: &mut Transcript,
rng: &mut R,
) -> Result<Self> {
// Sample secret exponents `a_i ← Z[ɸ(N)]`.
let secret_exponents: Vec<_> =
std::iter::repeat_with(|| random_positive_bn(rng, &secret.totient))
std::iter::repeat_with(|| random_positive_bn(rng, secret.totient))
.take(SOUNDNESS)
.collect();
// Compute commitments values `A_i = t^{a_i} mod N`.
Expand All @@ -126,7 +124,7 @@ impl Proof for PiPrmProof {
.zip(secret_exponents)
.map(|(e, a)| {
if e % 2 == 1 {
a.modadd(&secret.exponent, &secret.totient)
a.modadd(secret.exponent, secret.totient)
} else {
a
}
Expand All @@ -142,8 +140,8 @@ impl Proof for PiPrmProof {

#[cfg_attr(feature = "flame_it", flame("PiPrmProof"))]
fn verify(
&self,
input: &Self::CommonInput,
self,
input: Self::CommonInput<'_>,
context: &impl ProofContext,
transcript: &mut Transcript,
) -> Result<()> {
Expand Down Expand Up @@ -193,35 +191,36 @@ mod tests {
use crate::{paillier::DecryptionKey, utils::testing::init_testing, zkp::BadContext};
use rand::Rng;

/// Make a transcript for PiPrmProof.
fn transcript() -> Transcript {
Transcript::new(b"PiPrmProof")
}

fn random_ring_pedersen_proof<R: RngCore + CryptoRng>(
rng: &mut R,
) -> Result<(RingPedersen, PiPrmProof, BigNumber, BigNumber)> {
let (sk, _, _) = DecryptionKey::new(rng).unwrap();
let (scheme, lambda, totient) = RingPedersen::extract(&sk, rng)?;
let secrets = PiPrmSecret::new(lambda.clone(), totient.clone());
let mut transcript = Transcript::new(b"PiPrmProof");
let secrets = PiPrmSecret::new(&lambda, &totient);

let proof = PiPrmProof::prove(&scheme, &secrets, &(), &mut transcript, rng)?;
let proof = PiPrmProof::prove(&scheme, secrets, &(), &mut transcript(), rng)?;
Ok((scheme, proof, lambda, totient))
}

#[test]
fn piprm_proof_verifies() -> Result<()> {
let mut rng = init_testing();
let (input, proof, _, _) = random_ring_pedersen_proof(&mut rng)?;
let mut transcript = Transcript::new(b"PiPrmProof");

proof.verify(&input, &(), &mut transcript)
proof.verify(&input, &(), &mut transcript())
}

#[test]
fn piprm_proof_context_must_be_correct() -> Result<()> {
let context = BadContext {};
let mut rng = init_testing();
let (input, proof, _, _) = random_ring_pedersen_proof(&mut rng)?;
let mut transcript = Transcript::new(b"PiPrmProof");

let result = proof.verify(&input, &context, &mut transcript);
let result = proof.verify(&input, &context, &mut transcript());
assert!(result.is_err());
Ok(())
}
Expand All @@ -232,19 +231,16 @@ mod tests {
let serialized = bincode::serialize(&proof).unwrap();
let deserialized: PiPrmProof = bincode::deserialize(&serialized).unwrap();
assert_eq!(serialized, bincode::serialize(&deserialized).unwrap());
let mut transcript = Transcript::new(b"PiPrmProof");

deserialized.verify(&input, &(), &mut transcript)
deserialized.verify(&input, &(), &mut transcript())
}

#[test]
fn incorrect_lengths_fails() -> Result<()> {
let mut rng = init_testing();
let (input, proof, _, _) = random_ring_pedersen_proof(&mut rng)?;
// Validate that the proof is okay.
let mut transcript = Transcript::new(b"PiPrmProof");

assert!(proof.verify(&input, &(), &mut transcript).is_ok());
assert!(proof.clone().verify(&input, &(), &mut transcript()).is_ok());
// Test that too short vectors fail.
{
let mut bad_proof = proof.clone();
Expand All @@ -253,8 +249,7 @@ mod tests {
.into_iter()
.take(SOUNDNESS - 1)
.collect();
let mut transcript = Transcript::new(b"PiPrmProof");
assert!(bad_proof.verify(&input, &(), &mut transcript).is_err());
assert!(bad_proof.verify(&input, &(), &mut transcript()).is_err());
}
{
let mut bad_proof = proof.clone();
Expand All @@ -263,8 +258,7 @@ mod tests {
.into_iter()
.take(SOUNDNESS - 1)
.collect();
let mut transcript = Transcript::new(b"PiPrmProof");
assert!(bad_proof.verify(&input, &(), &mut transcript).is_err());
assert!(bad_proof.verify(&input, &(), &mut transcript()).is_err());
}
{
let mut bad_proof = proof.clone();
Expand All @@ -273,31 +267,27 @@ mod tests {
.into_iter()
.take(SOUNDNESS - 1)
.collect();
let mut transcript = Transcript::new(b"PiPrmProof");
assert!(bad_proof.verify(&input, &(), &mut transcript).is_err());
assert!(bad_proof.verify(&input, &(), &mut transcript()).is_err());
}
// Test that too long vectors fail.
{
let mut bad_proof = proof.clone();
bad_proof
.commitments
.push(random_positive_bn(&mut rng, input.modulus()));
let mut transcript = Transcript::new(b"PiPrmProof");
assert!(bad_proof.verify(&input, &(), &mut transcript).is_err());
assert!(bad_proof.verify(&input, &(), &mut transcript()).is_err());
}
{
let mut bad_proof = proof.clone();
bad_proof.challenge_bytes.push(rng.gen::<u8>());
let mut transcript = Transcript::new(b"PiPrmProof");
assert!(bad_proof.verify(&input, &(), &mut transcript).is_err());
assert!(bad_proof.verify(&input, &(), &mut transcript()).is_err());
}
{
let mut bad_proof = proof;
bad_proof
.responses
.push(random_positive_bn(&mut rng, input.modulus()));
let mut transcript = Transcript::new(b"PiPrmProof");
assert!(bad_proof.verify(&input, &(), &mut transcript).is_err());
assert!(bad_proof.verify(&input, &(), &mut transcript()).is_err());
}
Ok(())
}
Expand All @@ -307,15 +297,13 @@ mod tests {
let mut rng = init_testing();
let (input, proof, _, totient) = random_ring_pedersen_proof(&mut rng)?;
let bad_lambda = random_positive_bn(&mut rng, &totient);
let secrets = PiPrmSecret::new(bad_lambda, totient);
let mut transcript = Transcript::new(b"PiPrmProof");
let secrets = PiPrmSecret::new(&bad_lambda, &totient);

let bad_proof = PiPrmProof::prove(&input, secrets, &(), &mut transcript(), &mut rng)?;
assert!(bad_proof.verify(&input, &(), &mut transcript()).is_err());

let bad_proof = PiPrmProof::prove(&input, &secrets, &(), &mut transcript, &mut rng)?;
let mut transcript = Transcript::new(b"PiPrmProof");
assert!(bad_proof.verify(&input, &(), &mut transcript).is_err());
// Validate that the original proof is okay.
let mut transcript = Transcript::new(b"PiPrmProof");
assert!(proof.verify(&input, &(), &mut transcript).is_ok());
assert!(proof.verify(&input, &(), &mut transcript()).is_ok());

Ok(())
}
Expand All @@ -326,12 +314,14 @@ mod tests {

let (input, proof, _, _) = random_ring_pedersen_proof(&mut rng)?;
let (bad_input, _, _, _) = random_ring_pedersen_proof(&mut rng)?;
let mut transcript = Transcript::new(b"PiPrmProof");

assert!(proof.verify(&bad_input, &(), &mut transcript).is_err());
assert!(proof
.clone()
.verify(&bad_input, &(), &mut transcript())
.is_err());

// Validate that the original proof is okay.
let mut transcript = Transcript::new(b"PiPrmProof");
assert!(proof.verify(&input, &(), &mut transcript).is_ok());
assert!(proof.verify(&input, &(), &mut transcript()).is_ok());
Ok(())
}

Expand All @@ -344,27 +334,25 @@ mod tests {
for i in 0..SOUNDNESS {
let mut bad_proof = proof.clone();
bad_proof.commitments[i] = random_positive_bn(&mut rng, input.modulus());
let mut transcript = Transcript::new(b"PiPrmProof");
assert!(bad_proof.verify(&input, &(), &mut transcript).is_err());
assert!(bad_proof.verify(&input, &(), &mut transcript()).is_err());
}
for i in 0..SOUNDNESS {
let mut bad_proof = proof.clone();
let valid = bad_proof.challenge_bytes[i];
while bad_proof.challenge_bytes[i] == valid {
bad_proof.challenge_bytes[i] = rng.gen::<u8>();
}
let mut transcript = Transcript::new(b"PiPrmProof");
assert!(bad_proof.verify(&input, &(), &mut transcript).is_err());

assert!(bad_proof.verify(&input, &(), &mut transcript()).is_err());
}
for i in 0..SOUNDNESS {
let mut bad_proof = proof.clone();
bad_proof.responses[i] = random_positive_bn(&mut rng, input.modulus());
let mut transcript = Transcript::new(b"PiPrmProof");
assert!(bad_proof.verify(&input, &(), &mut transcript).is_err());

assert!(bad_proof.verify(&input, &(), &mut transcript()).is_err());
}
// Validate that the original proof is okay.
let mut transcript = Transcript::new(b"PiPrmProof");
assert!(proof.verify(&input, &(), &mut transcript).is_ok());
assert!(proof.verify(&input, &(), &mut transcript()).is_ok());

Ok(())
}
Expand Down