pub struct LogEqualityProof<G: Group> { /* private fields */ }
Expand description
Zero-knowledge proof of equality of two discrete logarithms in different bases, aka Chaum–Pedersen protocol.
§Construction
This proof is a result of the Fiat–Shamir transform applied to a standard ZKP of equality of the two discrete logs in different bases.
- Public parameters of the proof are the two bases
G
andK
in a prime-order group in which discrete log problem is believed to be hard. - Prover and verifier both know group elements
R
andB
, which presumably have the same discrete log in basesG
andK
respectively. - Prover additionally knows the discrete log in question:
r = dlog_G(R) = dlog_K(B)
.
The interactive proof is specified as a sigma protocol (see, e.g., this course) as follows:
- Commitment: The prover generates random scalar
x
. The prover sends to the verifierX_G = [x]G
andX_K = [x]K
. - Challenge: The verifier sends to the prover random scalar
c
. - Response: The prover computes scalar
s = x + cr
and sends it to the verifier.
Verification equations are:
[s]G ?= X_G + [c]R;
[s]K ?= X_K + [c]B.
In the non-interactive version of the proof, challenge c
is derived from hash(M)
,
where hash()
is a cryptographically secure hash function, and M
is an optional message
verified together with the proof (cf. public-key digital signatures). If M
is set, we
use a proof as a signature of knowledge. This allows to tie the proof to the context,
so it cannot be (re)used in other contexts.
To reduce the size of the proof, we use the trick underpinning ring signature constructions.
Namely, we represent the proof as (c, s)
; during verification, we restore X_G
, X_K
from the original verification equations above.
§Implementation details
- The proof is serialized as 2 scalars:
(c, s)
. - Proof generation is constant-time. Verification is not constant-time.
- Challenge
c
is derived usingTranscript
API.
§Examples
let mut rng = thread_rng();
let (log_base, _) =
Keypair::<Ristretto>::generate(&mut rng).into_tuple();
let (power_g, discrete_log) =
Keypair::<Ristretto>::generate(&mut rng).into_tuple();
let power_k = log_base.as_element() * discrete_log.expose_scalar();
let proof = LogEqualityProof::new(
&log_base,
&discrete_log,
(power_g.as_element(), power_k),
&mut Transcript::new(b"custom_proof"),
&mut rng,
);
proof.verify(
&log_base,
(power_g.as_element(), power_k),
&mut Transcript::new(b"custom_proof"),
)?;
Implementations§
Source§impl<G: Group> LogEqualityProof<G>
impl<G: Group> LogEqualityProof<G>
Sourcepub fn new<R: CryptoRng + RngCore>(
log_base: &PublicKey<G>,
secret: &SecretKey<G>,
powers: (G::Element, G::Element),
transcript: &mut Transcript,
rng: &mut R,
) -> Self
pub fn new<R: CryptoRng + RngCore>( log_base: &PublicKey<G>, secret: &SecretKey<G>, powers: (G::Element, G::Element), transcript: &mut Transcript, rng: &mut R, ) -> Self
Creates a new proof.
§Parameters
log_base
is the second discrete log base (K
in the notation above). The first log base is always theGroup
generator.secret
is the discrete log (r
in the notation above).powers
are[r]G
and[r]K
, respectively. It is not checked whetherr
is a discrete log of these powers; if this is not the case, the constructed proof will notverify
.
Sourcepub fn verify(
&self,
log_base: &PublicKey<G>,
powers: (G::Element, G::Element),
transcript: &mut Transcript,
) -> Result<(), VerificationError>
pub fn verify( &self, log_base: &PublicKey<G>, powers: (G::Element, G::Element), transcript: &mut Transcript, ) -> Result<(), VerificationError>
Verifies this proof.
§Parameters
log_base
is the second discrete log base (K
in the notation above). The first log base is always theGroup
generator.powers
are group elements presumably equal to[r]G
and[r]K
respectively, wherer
is a secret scalar.
§Errors
Returns an error if this proof does not verify.
Sourcepub fn to_bytes(self) -> Vec<u8> ⓘ
pub fn to_bytes(self) -> Vec<u8> ⓘ
Serializes this proof into bytes. As described above,
the is serialized as 2 scalars: (c, s)
, i.e., challenge and response.
Sourcepub fn from_bytes(bytes: &[u8]) -> Option<Self>
pub fn from_bytes(bytes: &[u8]) -> Option<Self>
Attempts to parse the proof from bytes
. Returns None
if bytes
do not represent
a well-formed proof.
Trait Implementations§
Source§impl<G: Clone + Group> Clone for LogEqualityProof<G>
impl<G: Clone + Group> Clone for LogEqualityProof<G>
Source§fn clone(&self) -> LogEqualityProof<G>
fn clone(&self) -> LogEqualityProof<G>
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moreSource§impl<'de, G: Group> Deserialize<'de> for LogEqualityProof<G>
impl<'de, G: Group> Deserialize<'de> for LogEqualityProof<G>
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl<G: Group> Serialize for LogEqualityProof<G>
impl<G: Group> Serialize for LogEqualityProof<G>
impl<G: Copy + Group> Copy for LogEqualityProof<G>
Auto Trait Implementations§
impl<G> Freeze for LogEqualityProof<G>
impl<G> RefUnwindSafe for LogEqualityProof<G>
impl<G> Send for LogEqualityProof<G>
impl<G> Sync for LogEqualityProof<G>
impl<G> Unpin for LogEqualityProof<G>
impl<G> UnwindSafe for LogEqualityProof<G>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§unsafe fn clone_to_uninit(&self, dst: *mut T)
unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit
)