pub struct RingProof<G: Group> { /* private fields */ }
Expand description
Zero-knowledge proof that the one or more encrypted values is each in the a priori known set of admissible values. (Admissible values may differ among encrypted values.)
§Construction
In short, a proof is constructed almost identically to Borromean ring signatures by Maxwell and Poelstra, with the only major difference being that we work on ElGamal ciphertexts instead of group elements (= public keys).
A proof consists of one or more rings. Each ring proves than a certain
ElGamal ciphertext E = (R, B)
for public key K
in a group with generator G
encrypts one of distinct admissible values x_0
, x_1
, …, x_n
.
K
and G
are shared among rings, admissible values are generally not.
Different rings may have different number of admissible values.
§Single ring
A ring is a challenge e_0
and a set of responses s_0
, s_1
, …, s_n
, which
must satisfy the following verification procedure:
For each j
in 0..=n
, compute
R_G(j) = [s_j]G - [e_j]R;
R_K(j) = [s_j]K - [e_j](B - [x_j]G);
e_{j+1} = H(j, R_G(j), R_K(j));
Here, H
is a cryptographic hash function. The ring is valid if e_0 = e_{n+1}
.
This construction is almost identical to Abe–Ohkubo–Suzuki ring signatures,
with the only difference that two group elements are hashed on each iteration instead of one.
If admissible values consist of a single value, this protocol reduces to
LogEqualityProof
/ Chaum–Pedersen protocol.
As with “ordinary” ring signatures, constructing a ring is only feasible when knowing additional trapdoor information. Namely, the prover must know
r = dlog_G(R) = dlog_K(B - [x_j]G)
for a certain j
. (This discrete log r
is the random scalar used in ElGamal encryption.)
With this info, the prover constructs the ring as follows:
- Select random scalar
x
and computeR_G(j) = [x]G
,R_K(j) = [x]K
. - Compute
e_{j+1}
, …e_n
, …,e_j
(“wrapping” arounde_0 = e_{n+1}
) as per verification formulas.s_*
scalars are selected uniformly at random. - Compute
s_j
using the trapdoor information:s_j = x + e_j * r
.
§Multiple rings
Transformation to multiple rings is analogous to one in Borromean ring signatures.
Namely, challenge e_0
is shared among all rings and is computed by hashing
values of R_G
and R_K
with the maximum index for each of the rings.
§Applications
§Voting protocols
EncryptedChoice
uses RingProof
to prove that all encrypted
values are Boolean (0 or 1). Using a common challenge allows to reduce proof size by ~33%.
§Range proofs
See RangeProof
.
§Implementation details
- The proof is serialized as the common challenge
e_0
followed bys_i
scalars for all the rings. - Standalone proof generation and verification are not exposed in public crate APIs.
Rather, proofs are part of large protocols, such as
PublicKey::encrypt_bool()
/PublicKey::verify_bool()
. - The context of the proof is set using
Transcript
APIs, which provides hash functions in the protocol described above. Importantly, the proof itself commits to encrypted values and ring indexes, but not to the admissible values across the rings. This must be taken care of in a higher-level protocol, and this is the case for protocols exposed by the crate.
Implementations§
Source§impl<G: Group> RingProof<G>
impl<G: Group> RingProof<G>
Sourcepub fn to_bytes(&self) -> Vec<u8> ⓘ
pub fn to_bytes(&self) -> Vec<u8> ⓘ
Serializes this proof into bytes. As described above,
the proof is serialized as the common challenge e_0
followed by response scalars s_*
corresponding successively to each admissible value in each ring.
Sourcepub fn from_bytes(bytes: &[u8]) -> Option<Self>
pub fn from_bytes(bytes: &[u8]) -> Option<Self>
Attempts to deserialize a proof from bytes. Returns None
if bytes
do not represent
a well-formed proof.
Trait Implementations§
Source§impl<'de, G: Group> Deserialize<'de> for RingProof<G>
impl<'de, G: Group> Deserialize<'de> for RingProof<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>,
Auto Trait Implementations§
impl<G> Freeze for RingProof<G>
impl<G> RefUnwindSafe for RingProof<G>
impl<G> Send for RingProof<G>
impl<G> Sync for RingProof<G>
impl<G> Unpin for RingProof<G>
impl<G> UnwindSafe for RingProof<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
)