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

Merge main into circuit #111

Merged
merged 9 commits into from
Jul 12, 2018
19 changes: 17 additions & 2 deletions src/circuit_proof/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,21 @@ impl CircuitProof {
.map(|(x_exp, mult)| x_exp * mult * r);
let T_points = vec![self.T_1, self.T_3, self.T_4, self.T_5, self.T_6];

// Decompress L and R points from inner product proof
let Ls = self
.ipp_proof
.L_vec
.iter()
.map(|p| p.decompress().ok_or("RangeProof's L point is invalid"))
.collect::<Result<Vec<_>, _>>()?;

let Rs = self
.ipp_proof
.R_vec
.iter()
.map(|p| p.decompress().ok_or("RangeProof's R point is invalid"))
.collect::<Result<Vec<_>, _>>()?;

let mega_check = RistrettoPoint::vartime_multiscalar_mul(
iter::once(x) // A_I
.chain(iter::once(xx)) // A_O
Expand All @@ -344,8 +359,8 @@ impl CircuitProof {
.chain(iter::once(&gen.pedersen_generators.B_blinding))
.chain(gen.G.iter())
.chain(gen.H.iter())
.chain(self.ipp_proof.L_vec.iter())
.chain(self.ipp_proof.R_vec.iter())
.chain(Ls.iter())
.chain(Rs.iter())
.chain(V.iter())
.chain(T_points.iter()),
);
Expand Down
112 changes: 98 additions & 14 deletions src/inner_product_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
use std::borrow::Borrow;
use std::iter;

use curve25519_dalek::ristretto::RistrettoPoint;
use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint};
use curve25519_dalek::scalar::Scalar;
use curve25519_dalek::traits::VartimeMultiscalarMul;

use proof_transcript::ProofTranscript;

#[derive(Serialize, Deserialize, Clone, Debug)]
#[derive(Clone, Debug)]
pub struct InnerProductProof {
pub(crate) L_vec: Vec<RistrettoPoint>,
pub(crate) R_vec: Vec<RistrettoPoint>,
pub(crate) L_vec: Vec<CompressedRistretto>,
pub(crate) R_vec: Vec<CompressedRistretto>,
pub(crate) a: Scalar,
pub(crate) b: Scalar,
}
Expand Down Expand Up @@ -96,8 +96,8 @@ impl InnerProductProof {
G_L.iter().chain(H_R.iter()).chain(iter::once(Q)),
);

L_vec.push(L);
R_vec.push(R);
L_vec.push(L.compress());
R_vec.push(R.compress());

verifier.commit(L.compress().as_bytes());
verifier.commit(R.compress().as_bytes());
Expand Down Expand Up @@ -139,10 +139,8 @@ impl InnerProductProof {

let mut challenges = Vec::with_capacity(lg_n);
for (L, R) in self.L_vec.iter().zip(self.R_vec.iter()) {
// XXX maybe avoid this compression when proof ser/de is sorted out
transcript.commit(L.compress().as_bytes());
transcript.commit(R.compress().as_bytes());

transcript.commit(L.as_bytes());
transcript.commit(R.as_bytes());
challenges.push(transcript.challenge_scalar());
}

Expand Down Expand Up @@ -190,7 +188,7 @@ impl InnerProductProof {
Q: &RistrettoPoint,
G: &[RistrettoPoint],
H: &[RistrettoPoint],
) -> Result<(), ()>
) -> Result<(), &'static str>
where
I: IntoIterator,
I::Item: Borrow<Scalar>,
Expand All @@ -210,6 +208,18 @@ impl InnerProductProof {
let neg_u_sq = u_sq.iter().map(|ui| -ui);
let neg_u_inv_sq = u_inv_sq.iter().map(|ui| -ui);

let Ls = self
.L_vec
.iter()
.map(|p| p.decompress().ok_or("InnerProductProof L point is invalid"))
.collect::<Result<Vec<_>, _>>()?;

let Rs = self
.R_vec
.iter()
.map(|p| p.decompress().ok_or("InnerProductProof R point is invalid"))
.collect::<Result<Vec<_>, _>>()?;

let expect_P = RistrettoPoint::vartime_multiscalar_mul(
iter::once(self.a * self.b)
.chain(a_times_s)
Expand All @@ -219,15 +229,81 @@ impl InnerProductProof {
iter::once(Q)
.chain(G.iter())
.chain(H.iter())
.chain(self.L_vec.iter())
.chain(self.R_vec.iter()),
.chain(Ls.iter())
.chain(Rs.iter()),
);

if expect_P == *P {
Ok(())
} else {
Err(())
Err("InnerProductProof is invalid")
}
}

/// Returns the size in bytes required to serialize the inner
/// product proof.
///
/// For vectors of length `n` the proof size is
/// \\(32 \cdot (2\lg n+2)\\) bytes.
pub fn serialized_size(&self) -> usize {
(self.L_vec.len() * 2 + 2) * 32
}

/// Serializes the proof into a byte array of \\(2n+2\\) 32-byte elements.
/// The layout of the inner product proof is:
/// * \\(n\\) pairs of compressed Ristretto points \\(L_0, R_0 \dots, L_{n-1}, R_{n-1}\\),
/// * two scalars \\(a, b\\).
pub fn to_bytes(&self) -> Vec<u8> {
let mut buf = Vec::with_capacity(self.serialized_size());
for (l, r) in self.L_vec.iter().zip(self.R_vec.iter()) {
buf.extend_from_slice(l.as_bytes());
buf.extend_from_slice(r.as_bytes());
}
buf.extend_from_slice(self.a.as_bytes());
buf.extend_from_slice(self.b.as_bytes());
buf
}

/// Deserializes the proof from a byte slice.
/// Returns an error in the following cases:
/// * the slice does not have \\(2n+2\\) 32-byte elements,
/// * \\(n\\) is larger or equal to 32 (proof is too big),
/// * any of \\(2n\\) points are not valid compressed Ristretto points,
/// * any of 2 scalars are not canonical scalars modulo Ristretto group order.
pub fn from_bytes(slice: &[u8]) -> Result<InnerProductProof, &'static str> {
let b = slice.len();
if b % 32 != 0 {
return Err("InnerProductProof size is not divisible by 32");
}
let num_elements = b / 32;
if num_elements < 2 {
return Err("InnerProductProof must contain at least two 32-byte elements");
}
if (num_elements - 2) % 2 != 0 {
return Err("InnerProductProof must contain even number of points");
}
let lg_n = (num_elements - 2) / 2;
if lg_n >= 32 {
return Err("InnerProductProof contains too many points");
}

use util::read32;

let mut L_vec: Vec<CompressedRistretto> = Vec::with_capacity(lg_n);
let mut R_vec: Vec<CompressedRistretto> = Vec::with_capacity(lg_n);
for i in 0..lg_n {
let pos = 2 * i * 32;
L_vec.push(CompressedRistretto(read32(&slice[pos..])));
R_vec.push(CompressedRistretto(read32(&slice[pos + 32..])));
}

let pos = 2 * lg_n * 32;
let a = Scalar::from_canonical_bytes(read32(&slice[pos..]))
.ok_or("InnerProductProof.a is not a canonical scalar")?;
let b = Scalar::from_canonical_bytes(read32(&slice[pos + 32..]))
.ok_or("InnerProductProof.b is not a canonical scalar")?;

Ok(InnerProductProof { L_vec, R_vec, a, b })
}
}

Expand Down Expand Up @@ -305,6 +381,14 @@ mod tests {
.verify(&mut verifier, util::exp_iter(y_inv), &P, &Q, &G, &H)
.is_ok()
);

let proof = InnerProductProof::from_bytes(proof.to_bytes().as_slice()).unwrap();
let mut verifier = ProofTranscript::new(b"innerproducttest");
assert!(
proof
.verify(&mut verifier, util::exp_iter(y_inv), &P, &Q, &G, &H)
.is_ok()
);
}

#[test]
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
//! [RFC 1990 stabilizes](https://github.com/rust-lang/rust/issues/44732).

extern crate byteorder;
extern crate core;
extern crate curve25519_dalek;
extern crate rand;
extern crate sha2;
Expand All @@ -17,6 +18,7 @@ extern crate tiny_keccak;

#[macro_use]
extern crate serde_derive;
extern crate serde;

#[cfg(test)]
extern crate test;
Expand Down
8 changes: 4 additions & 4 deletions src/range_proof/dealer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,10 +232,10 @@ impl<'a, 'b> DealerAwaitingProofShares<'a, 'b> {
);

Ok(RangeProof {
A: self.A,
S: self.S,
T_1: self.T_1,
T_2: self.T_2,
A: self.A.compress(),
S: self.S.compress(),
T_1: self.T_1.compress(),
T_2: self.T_2.compress(),
t_x,
t_x_blinding,
e_blinding,
Expand Down
Loading