Crate dalek_rangeproofs [−] [src]
A pure-Rust implementation of the Back-Maxwell rangeproof scheme defined in Confidential Assets (2017) by Poelstra, Back, Friedenbach, Maxwell, Wuille.
The scheme is instantiated using the Decaf group on Curve25519, as
implemented in
curve25519-dalek
.
Note that since the Decaf implementation in curve25519-dalek
is
currently UNFINISHED, UNREVIEWED, AND EXPERIMENTAL, so is this
library.
This implementation hardcodes the ring size m = 3
, as this is
the most efficient choice. The number of rings n
determines the
range [0,3^n]
, as well as the size and speed of the proof.
Examples
Suppose we want to prove that 134492616741
is within [0,3^40]
.
Since 340 ≅ 0.66 (264 ), this is just slightly narrower than the
range of a u64
.
To construct a proof that 134492616741
is within [0,3^40]
,
first choose orthogonal basepoints. Usually the basepoints would
be set or distributed as system-wide parameters. Here we choose
G
to be the Decaf coset containing the ed25519 basepoint and
generate the second basepoint as H = Hash(G)
. (Technically, G
is actually a DecafBasepointTable
, which implements
Mul<&Scalar>
using a precomputed table).
use sha2::Sha256; use curve25519_dalek::constants as dalek_constants; use curve25519_dalek::decaf::{DecafBasepointTable, DecafPoint}; use curve25519_dalek::scalar::Scalar; let G = &dalek_constants::DECAF_ED25519_BASEPOINT_TABLE; let H = DecafPoint::hash_from_bytes::<Sha256>(G.basepoint().compress().as_bytes());
You'll also need your value and a CSPRNG:
use rand::OsRng; let mut csprng = OsRng::new().unwrap(); let value = 134492616741;
We can now create the rangeproof, like so:
use dalek_rangeproofs::RangeProof; let (proof, commitment, blinding) = RangeProof::create(40, value, G, &H, &mut csprng).unwrap();
The output is the proof proof
, as well as commitment = blinding*G + value*H
.
We can serialize the proof using Serde. Here, we use CBOR.
extern crate serde_cbor; let proof_bytes: Vec<u8> = serde_cbor::ser::to_vec_packed(&proof).unwrap(); assert_eq!(proof_bytes.len(), 4125);
In this case, the serde_cbor
-encoded proof statement is
approximately 6.5% larger than the optimal 3872 = 32(1+3*40)
bytes. Another party can verify the proof statement from
proof_bytes
by doing:
extern crate serde_cbor; use dalek_rangeproofs::RangeProof; let proof: RangeProof = serde_cbor::from_slice(&proof_bytes).unwrap(); let C_option = proof.verify(40, G, &H); assert!(C_option.is_some()); let C = C_option.unwrap();
If the proof is well-formed, verify
returns the commitment to
the value. Since the commitment is the output of the
verification, the verifier is assured it opens to a value in the
range [0,3^n]
. However, without knowing both blinding
and the
actual value
, the verifier cannot open this commitment, because
Pedersen commitments are computationally binding and perfectly
hiding (in addition to being additively homomorphic, a feature
used within this scheme).
Later, to open this commitment, the prover could reveal the value
and the blinding, allowing others to check that commitment = blinding*G + value*H
.
let C_hat = &(G * &blinding) + &(&H * &Scalar::from_u64(value)); assert_eq!(C_hat, C);
Structs
RangeProof |
A Back-Maxwell rangeproof, which proves in zero knowledge that a
number is in a range |
Constants
RANGEPROOF_MAX_N |
The maximum allowed bound for the rangeproof. Currently this is
set to 41, because we only implement conversion to base 3 digits
for |