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

Add a transcript protocol function that checks for identity points. #248

Merged
merged 6 commits into from
May 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ keywords = ["cryptography", "ristretto", "zero-knowledge", "bulletproofs"]
description = "A pure-Rust implementation of Bulletproofs using Ristretto"

[dependencies]
curve25519-dalek = { version = "1", features = ["serde"] }
curve25519-dalek = { version = "1.0.3", features = ["serde"] }
subtle = "2"
sha3 = "0.8"
digest = "0.8"
Expand All @@ -21,7 +21,7 @@ byteorder = "1"
serde = "1"
serde_derive = "1"
failure = "0.1"
merlin = "1"
merlin = "1.1"
clear_on_drop = "0.2"

[dev-dependencies]
Expand Down
12 changes: 6 additions & 6 deletions src/inner_product_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ impl InnerProductProof {
L_vec.push(L);
R_vec.push(R);

transcript.commit_point(b"L", &L);
transcript.commit_point(b"R", &R);
transcript.append_point(b"L", &L);
transcript.append_point(b"R", &R);

let u = transcript.challenge_scalar(b"u");
let u_inv = u.invert();
Expand Down Expand Up @@ -154,8 +154,8 @@ impl InnerProductProof {
L_vec.push(L);
R_vec.push(R);

transcript.commit_point(b"L", &L);
transcript.commit_point(b"R", &R);
transcript.append_point(b"L", &L);
transcript.append_point(b"R", &R);

let u = transcript.challenge_scalar(b"u");
let u_inv = u.invert();
Expand Down Expand Up @@ -205,8 +205,8 @@ impl InnerProductProof {

let mut challenges = Vec::with_capacity(lg_n);
for (L, R) in self.L_vec.iter().zip(self.R_vec.iter()) {
transcript.commit_point(b"L", L);
transcript.commit_point(b"R", R);
transcript.validate_and_append_point(b"L", L)?;
transcript.validate_and_append_point(b"R", R)?;
challenges.push(transcript.challenge_scalar(b"u"));
}

Expand Down
28 changes: 14 additions & 14 deletions src/r1cs/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ impl<'a, 'b> Prover<'a, 'b> {

// Add the commitment to the transcript.
let V = self.cs.pc_gens.commit(v, v_blinding).compress();
self.cs.transcript.commit_point(b"V", &V);
self.cs.transcript.append_point(b"V", &V);

(V, Variable::Committed(i))
}
Expand All @@ -216,7 +216,7 @@ impl<'a, 'b> Prover<'a, 'b> {
// We cannot do this in advance because user can commit variables one-by-one,
// but this suffix provides safe disambiguation because each variable
// is prefixed with a separate label.
self.cs.transcript.commit_u64(b"m", self.m);
self.cs.transcript.append_u64(b"m", self.m);
self.cs
}
}
Expand Down Expand Up @@ -325,7 +325,7 @@ impl<'a, 'b> ProverCS<'a, 'b> {

// Commit the blinding factors for the input wires
for v_b in &self.v_blinding {
builder = builder.commit_witness_bytes(b"v_blinding", v_b.as_bytes());
builder = builder.rekey_with_witness_bytes(b"v_blinding", v_b.as_bytes());
}

use rand::thread_rng;
Expand Down Expand Up @@ -368,9 +368,9 @@ impl<'a, 'b> ProverCS<'a, 'b> {
)
.compress();

self.transcript.commit_point(b"A_I", &A_I);
self.transcript.commit_point(b"A_O", &A_O);
self.transcript.commit_point(b"S", &S);
self.transcript.append_point(b"A_I", &A_I);
self.transcript.append_point(b"A_O", &A_O);
self.transcript.append_point(b"S", &S);

// 4. Compute blinded vector polynomials l(x) and r(x)

Expand Down Expand Up @@ -419,11 +419,11 @@ impl<'a, 'b> ProverCS<'a, 'b> {
let T_5 = self.pc_gens.commit(t_poly.t5, t_5_blinding).compress();
let T_6 = self.pc_gens.commit(t_poly.t6, t_6_blinding).compress();

self.transcript.commit_point(b"T_1", &T_1);
self.transcript.commit_point(b"T_3", &T_3);
self.transcript.commit_point(b"T_4", &T_4);
self.transcript.commit_point(b"T_5", &T_5);
self.transcript.commit_point(b"T_6", &T_6);
self.transcript.append_point(b"T_1", &T_1);
self.transcript.append_point(b"T_3", &T_3);
self.transcript.append_point(b"T_4", &T_4);
self.transcript.append_point(b"T_5", &T_5);
self.transcript.append_point(b"T_6", &T_6);

let x = self.transcript.challenge_scalar(b"x");

Expand Down Expand Up @@ -460,10 +460,10 @@ impl<'a, 'b> ProverCS<'a, 'b> {

let e_blinding = x * (i_blinding + x * (o_blinding + x * s_blinding));

self.transcript.commit_scalar(b"t_x", &t_x);
self.transcript.append_scalar(b"t_x", &t_x);
self.transcript
.commit_scalar(b"t_x_blinding", &t_x_blinding);
self.transcript.commit_scalar(b"e_blinding", &e_blinding);
.append_scalar(b"t_x_blinding", &t_x_blinding);
self.transcript.append_scalar(b"e_blinding", &e_blinding);

// Get a challenge value to combine statements for the IPP
let w = self.transcript.challenge_scalar(b"w");
Expand Down
26 changes: 13 additions & 13 deletions src/r1cs/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ impl<'a, 'b> Verifier<'a, 'b> {
self.cs.V.push(commitment);

// Add the commitment to the transcript.
self.cs.transcript.commit_point(b"V", &commitment);
self.cs.transcript.append_point(b"V", &commitment);

Variable::Committed(i)
}
Expand All @@ -183,7 +183,7 @@ impl<'a, 'b> Verifier<'a, 'b> {
// We cannot do this in advance because user can commit variables one-by-one,
// but this suffix provides safe disambiguation because each variable
// is prefixed with a separate label.
self.cs.transcript.commit_u64(b"m", self.m);
self.cs.transcript.append_u64(b"m", self.m);
self.cs
}
}
Expand Down Expand Up @@ -261,26 +261,26 @@ impl<'a, 'b> VerifierCS<'a, 'b> {
// We are performing a single-party circuit proof, so party index is 0.
let gens = self.bp_gens.share(0);

self.transcript.commit_point(b"A_I", &proof.A_I);
self.transcript.commit_point(b"A_O", &proof.A_O);
self.transcript.commit_point(b"S", &proof.S);
self.transcript.append_point(b"A_I", &proof.A_I);
self.transcript.append_point(b"A_O", &proof.A_O);
self.transcript.append_point(b"S", &proof.S);

let y = self.transcript.challenge_scalar(b"y");
let z = self.transcript.challenge_scalar(b"z");

self.transcript.commit_point(b"T_1", &proof.T_1);
self.transcript.commit_point(b"T_3", &proof.T_3);
self.transcript.commit_point(b"T_4", &proof.T_4);
self.transcript.commit_point(b"T_5", &proof.T_5);
self.transcript.commit_point(b"T_6", &proof.T_6);
self.transcript.append_point(b"T_1", &proof.T_1);
self.transcript.append_point(b"T_3", &proof.T_3);
self.transcript.append_point(b"T_4", &proof.T_4);
self.transcript.append_point(b"T_5", &proof.T_5);
self.transcript.append_point(b"T_6", &proof.T_6);

let x = self.transcript.challenge_scalar(b"x");

self.transcript.commit_scalar(b"t_x", &proof.t_x);
self.transcript.append_scalar(b"t_x", &proof.t_x);
self.transcript
.commit_scalar(b"t_x_blinding", &proof.t_x_blinding);
.append_scalar(b"t_x_blinding", &proof.t_x_blinding);
self.transcript
.commit_scalar(b"e_blinding", &proof.e_blinding);
.append_scalar(b"e_blinding", &proof.e_blinding);

let w = self.transcript.challenge_scalar(b"w");

Expand Down
16 changes: 8 additions & 8 deletions src/range_proof/dealer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,15 @@ impl<'a, 'b> DealerAwaitingBitCommitments<'a, 'b> {

// Commit each V_j individually
for vc in bit_commitments.iter() {
self.transcript.commit_point(b"V", &vc.V_j);
self.transcript.append_point(b"V", &vc.V_j);
}

// Commit aggregated A_j, S_j
let A: RistrettoPoint = bit_commitments.iter().map(|vc| vc.A_j).sum();
self.transcript.commit_point(b"A", &A.compress());
self.transcript.append_point(b"A", &A.compress());

let S: RistrettoPoint = bit_commitments.iter().map(|vc| vc.S_j).sum();
self.transcript.commit_point(b"S", &S.compress());
self.transcript.append_point(b"S", &S.compress());

let y = self.transcript.challenge_scalar(b"y");
let z = self.transcript.challenge_scalar(b"z");
Expand Down Expand Up @@ -158,8 +158,8 @@ impl<'a, 'b> DealerAwaitingPolyCommitments<'a, 'b> {
let T_1: RistrettoPoint = poly_commitments.iter().map(|pc| pc.T_1_j).sum();
let T_2: RistrettoPoint = poly_commitments.iter().map(|pc| pc.T_2_j).sum();

self.transcript.commit_point(b"T_1", &T_1.compress());
self.transcript.commit_point(b"T_2", &T_2.compress());
self.transcript.append_point(b"T_1", &T_1.compress());
self.transcript.append_point(b"T_2", &T_2.compress());

let x = self.transcript.challenge_scalar(b"x");
let poly_challenge = PolyChallenge { x };
Expand Down Expand Up @@ -221,10 +221,10 @@ impl<'a, 'b> DealerAwaitingProofShares<'a, 'b> {
let t_x_blinding: Scalar = proof_shares.iter().map(|ps| ps.t_x_blinding).sum();
let e_blinding: Scalar = proof_shares.iter().map(|ps| ps.e_blinding).sum();

self.transcript.commit_scalar(b"t_x", &t_x);
self.transcript.append_scalar(b"t_x", &t_x);
self.transcript
.commit_scalar(b"t_x_blinding", &t_x_blinding);
self.transcript.commit_scalar(b"e_blinding", &e_blinding);
.append_scalar(b"t_x_blinding", &t_x_blinding);
self.transcript.append_scalar(b"e_blinding", &e_blinding);

// Get a challenge value to combine statements for the IPP
let w = self.transcript.challenge_scalar(b"w");
Expand Down
19 changes: 11 additions & 8 deletions src/range_proof/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,24 +287,27 @@ impl RangeProof {
transcript.rangeproof_domain_sep(n as u64, m as u64);

for V in value_commitments.iter() {
transcript.commit_point(b"V", V);
// Allow the commitments to be zero (0 value, 0 blinding)
// See https://github.com/dalek-cryptography/bulletproofs/pull/248#discussion_r255167177
transcript.append_point(b"V", V);
}
transcript.commit_point(b"A", &self.A);
transcript.commit_point(b"S", &self.S);

transcript.validate_and_append_point(b"A", &self.A)?;
transcript.validate_and_append_point(b"S", &self.S)?;

let y = transcript.challenge_scalar(b"y");
let z = transcript.challenge_scalar(b"z");
let zz = z * z;
let minus_z = -z;

transcript.commit_point(b"T_1", &self.T_1);
transcript.commit_point(b"T_2", &self.T_2);
transcript.validate_and_append_point(b"T_1", &self.T_1)?;
transcript.validate_and_append_point(b"T_2", &self.T_2)?;

let x = transcript.challenge_scalar(b"x");

transcript.commit_scalar(b"t_x", &self.t_x);
transcript.commit_scalar(b"t_x_blinding", &self.t_x_blinding);
transcript.commit_scalar(b"e_blinding", &self.e_blinding);
transcript.append_scalar(b"t_x", &self.t_x);
transcript.append_scalar(b"t_x_blinding", &self.t_x_blinding);
transcript.append_scalar(b"e_blinding", &self.e_blinding);

let w = transcript.challenge_scalar(b"w");

Expand Down
72 changes: 44 additions & 28 deletions src/transcript.rs
Original file line number Diff line number Diff line change
@@ -1,59 +1,75 @@
//! Defines a `TranscriptProtocol` trait for using a Merlin transcript.

use byteorder::{ByteOrder, LittleEndian};
use curve25519_dalek::ristretto::CompressedRistretto;
use curve25519_dalek::scalar::Scalar;
use merlin::Transcript;

use errors::ProofError;

pub trait TranscriptProtocol {
/// Commit a domain separator for an `n`-bit, `m`-party range proof.
/// Append a domain separator for an `n`-bit, `m`-party range proof.
fn rangeproof_domain_sep(&mut self, n: u64, m: u64);
/// Commit a domain separator for a length-`n` inner product proof.

/// Append a domain separator for a length-`n` inner product proof.
fn innerproduct_domain_sep(&mut self, n: u64);
/// Commit a domain separator for a constraint system.

/// Append a domain separator for a constraint system.
fn r1cs_domain_sep(&mut self);
/// Commit a 64-bit integer.
fn commit_u64(&mut self, label: &'static [u8], n: u64);
/// Commit a `scalar` with the given `label`.
fn commit_scalar(&mut self, label: &'static [u8], scalar: &Scalar);
/// Commit a `point` with the given `label`.
fn commit_point(&mut self, label: &'static [u8], point: &CompressedRistretto);

/// Append a `scalar` with the given `label`.
fn append_scalar(&mut self, label: &'static [u8], scalar: &Scalar);

/// Append a `point` with the given `label`.
fn append_point(&mut self, label: &'static [u8], point: &CompressedRistretto);

/// Check that a point is not the identity, then append it to the
/// transcript. Otherwise, return an error.
fn validate_and_append_point(
&mut self,
label: &'static [u8],
point: &CompressedRistretto,
) -> Result<(), ProofError>;

/// Compute a `label`ed challenge variable.
fn challenge_scalar(&mut self, label: &'static [u8]) -> Scalar;
}

fn le_u64(value: u64) -> [u8; 8] {
let mut value_bytes = [0u8; 8];
LittleEndian::write_u64(&mut value_bytes, value);
value_bytes
}

impl TranscriptProtocol for Transcript {
fn rangeproof_domain_sep(&mut self, n: u64, m: u64) {
self.commit_bytes(b"dom-sep", b"rangeproof v1");
self.commit_bytes(b"n", &le_u64(n));
self.commit_bytes(b"m", &le_u64(m));
self.append_message(b"dom-sep", b"rangeproof v1");
self.append_u64(b"n", n);
self.append_u64(b"m", m);
}

fn innerproduct_domain_sep(&mut self, n: u64) {
self.commit_bytes(b"dom-sep", b"ipp v1");
self.commit_bytes(b"n", &le_u64(n));
self.append_message(b"dom-sep", b"ipp v1");
self.append_u64(b"n", n);
}

fn r1cs_domain_sep(&mut self) {
self.commit_bytes(b"dom-sep", b"r1cs v1");
self.append_message(b"dom-sep", b"r1cs v1");
}

fn commit_u64(&mut self, label: &'static [u8], n: u64) {
self.commit_bytes(label, &le_u64(n));
fn append_scalar(&mut self, label: &'static [u8], scalar: &Scalar) {
self.append_message(label, scalar.as_bytes());
}

fn commit_scalar(&mut self, label: &'static [u8], scalar: &Scalar) {
self.commit_bytes(label, scalar.as_bytes());
fn append_point(&mut self, label: &'static [u8], point: &CompressedRistretto) {
self.append_message(label, point.as_bytes());
}

fn commit_point(&mut self, label: &'static [u8], point: &CompressedRistretto) {
self.commit_bytes(label, point.as_bytes());
fn validate_and_append_point(
&mut self,
label: &'static [u8],
point: &CompressedRistretto,
) -> Result<(), ProofError> {
use curve25519_dalek::traits::IsIdentity;

if point.is_identity() {
Err(ProofError::VerificationError)
} else {
Ok(self.append_message(label, point.as_bytes()))
}
}

fn challenge_scalar(&mut self, label: &'static [u8]) -> Scalar {
Expand Down
10 changes: 6 additions & 4 deletions tests/r1cs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,10 @@ impl ShuffleProof {
R1CSError,
> {
// Apply a domain separator with the shuffle parameters to the transcript
// XXX should this be part of the gadget?
let k = input.len();
transcript.commit_bytes(b"dom-sep", b"ShuffleProof");
transcript.commit_bytes(b"k", Scalar::from(k as u64).as_bytes());
transcript.append_message(b"dom-sep", b"ShuffleProof");
transcript.append_u64(b"k", k as u64);

let mut prover = Prover::new(&bp_gens, &pc_gens, transcript);

Expand Down Expand Up @@ -111,9 +112,10 @@ impl ShuffleProof {
output_commitments: &Vec<CompressedRistretto>,
) -> Result<(), R1CSError> {
// Apply a domain separator with the shuffle parameters to the transcript
// XXX should this be part of the gadget?
let k = input_commitments.len();
transcript.commit_bytes(b"dom-sep", b"ShuffleProof");
transcript.commit_bytes(b"k", Scalar::from(k as u64).as_bytes());
transcript.append_message(b"dom-sep", b"ShuffleProof");
transcript.append_u64(b"k", k as u64);

let mut verifier = Verifier::new(&bp_gens, &pc_gens, transcript);

Expand Down