pub struct RangeProof<G: Group> { /* private fields */ }Expand description
Zero-knowledge proof that an ElGamal ciphertext encrypts a value into a certain range 0..n.
§Construction
To make the proof more compact – O(log n) in terms of size and proving / verification
complexity – we use the same trick as for Pedersen commitments (used, e.g., for confidential
transaction amounts in Elements):
- Represent the encrypted value
xasx = x_0 + k_0 * x_1 + k_0 * k_1 * x_2 + …, where0 <= x_i < t_iis the decomposition ofxas per theRangeDecomposition,0..t_0 + k_0 * (0..t_1 + …). As an example, ifnis a power of 2, one can choose a decomposition as the base-2 presentation ofx, i.e.,t_i = k_i = 2for alli. For brevity, denote a multiplier ofx_iinxdecomposition asK_i,K_i = k_0 * … * k_{i-1};K_0 = 1by extension. - Split the ciphertext:
E = E_0 + E_1 + …, whereE_iencryptsK_i * x_i. - Produce a
RingProofthat for allithe encrypted scalar forE_iis among 0,K_i, …,K_i * (t_i - 1). The range proof consists of allE_iciphertexts and thisRingProof.
As with range proofs for Pedersen commitments, this construction is not optimal in terms of space or proving / verification complexity for large ranges; it is linear w.r.t. the bit length of the range. (Constructions like Bulletproofs are logarithmic w.r.t. the bit length.) Still, it can be useful for small ranges.
§Examples
// Generate the ciphertext receiver.
let mut rng = thread_rng();
let receiver = Keypair::<Ristretto>::generate(&mut rng);
// Find the optimal range decomposition for our range
// and specialize it for the Ristretto group.
let range = RangeDecomposition::optimal(100).into();
let (ciphertext, proof) = RangeProof::new(
receiver.public(),
&range,
55,
&mut Transcript::new(b"test_proof"),
&mut rng,
);
let ciphertext = Ciphertext::from(ciphertext);
// Check that the ciphertext is valid
let lookup = DiscreteLogTable::new(0..100);
assert_eq!(receiver.secret().decrypt(ciphertext, &lookup), Some(55));
// ...and that the proof verifies.
proof.verify(
receiver.public(),
&range,
ciphertext,
&mut Transcript::new(b"test_proof"),
)?;Implementations§
Source§impl<G: Group> RangeProof<G>
impl<G: Group> RangeProof<G>
Sourcepub fn new<R: RngCore + CryptoRng>(
receiver: &PublicKey<G>,
range: &PreparedRange<G>,
value: u64,
transcript: &mut Transcript,
rng: &mut R,
) -> (CiphertextWithValue<G, u64>, Self)
pub fn new<R: RngCore + CryptoRng>( receiver: &PublicKey<G>, range: &PreparedRange<G>, value: u64, transcript: &mut Transcript, rng: &mut R, ) -> (CiphertextWithValue<G, u64>, Self)
Encrypts value for receiver and creates a zero-knowledge proof that the encrypted value
is in range.
This is a lower-level operation; see PublicKey::encrypt_range() for a higher-level
alternative.
§Panics
Panics if value is outside the range specified by range.
Sourcepub fn from_ciphertext<R: RngCore + CryptoRng>(
receiver: &PublicKey<G>,
range: &PreparedRange<G>,
ciphertext: &CiphertextWithValue<G, u64>,
transcript: &mut Transcript,
rng: &mut R,
) -> Self
pub fn from_ciphertext<R: RngCore + CryptoRng>( receiver: &PublicKey<G>, range: &PreparedRange<G>, ciphertext: &CiphertextWithValue<G, u64>, transcript: &mut Transcript, rng: &mut R, ) -> Self
Creates a proof that a value in ciphertext is in the range.
The caller is responsible for providing a ciphertext encrypted for the receiver;
if the ciphertext is encrypted for another public key, the resulting proof will not verify.
§Panics
Panics if value is outside the range specified by range.
Sourcepub fn verify(
&self,
receiver: &PublicKey<G>,
range: &PreparedRange<G>,
ciphertext: Ciphertext<G>,
transcript: &mut Transcript,
) -> Result<(), VerificationError>
pub fn verify( &self, receiver: &PublicKey<G>, range: &PreparedRange<G>, ciphertext: Ciphertext<G>, transcript: &mut Transcript, ) -> Result<(), VerificationError>
Verifies this proof against ciphertext for receiver and the specified range.
This is a lower-level operation; see PublicKey::verify_range() for a higher-level
alternative.
For a proof to verify, all parameters must be identical to ones provided when creating
the proof. In particular, range must have the same decomposition.
§Errors
Returns an error if this proof does not verify.
Trait Implementations§
Source§impl<G: Clone + Group> Clone for RangeProof<G>
impl<G: Clone + Group> Clone for RangeProof<G>
Source§fn clone(&self) -> RangeProof<G>
fn clone(&self) -> RangeProof<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 RangeProof<G>
impl<'de, G: Group> Deserialize<'de> for RangeProof<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 RangeProof<G>
impl<G> RefUnwindSafe for RangeProof<G>
impl<G> Send for RangeProof<G>
impl<G> Sync for RangeProof<G>
impl<G> Unpin for RangeProof<G>
impl<G> UnwindSafe for RangeProof<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)