{"action":"created","comment":{"url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/pulls/comments/201486133","pull_request_review_id":135969170,"id":201486133,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIwMTQ4NjEzMw==","diff_hunk":"@@ -0,0 +1,781 @@\n+#![allow(non_snake_case)]\n+\n+use rand::{CryptoRng, Rng};\n+use std::iter;\n+\n+use curve25519_dalek::ristretto::RistrettoPoint;\n+use curve25519_dalek::scalar::Scalar;\n+use curve25519_dalek::traits::{IsIdentity, MultiscalarMul, VartimeMultiscalarMul};\n+\n+use generators::Generators;\n+use inner_product_proof::{inner_product, InnerProductProof};\n+use proof_transcript::ProofTranscript;\n+use util;\n+\n+#[derive(Clone, Debug)]\n+pub struct Circuit {\n+    n: usize,\n+    m: usize,\n+    q: usize,\n+    c: Vec<Scalar>,        // vector of constants, length q\n+    W_L: Vec<Vec<Scalar>>, // q vectors, of length n each\n+    W_R: Vec<Vec<Scalar>>,\n+    W_O: Vec<Vec<Scalar>>,\n+    W_V: Vec<Vec<Scalar>>, // q vectors, of length m each\n+}\n+\n+impl Circuit {\n+    pub fn check_parameters(&self) -> Result<(), &'static str> {\n+        if self.W_L.len() != self.q\n+            || self.W_R.len() != self.q\n+            || self.W_O.len() != self.q\n+            || self.W_V.len() != self.q\n+        {\n+            return Err(\"Circuit matrix size doesn't match specified parameters.\");\n+        }\n+        if self.c.len() != self.q {\n+            return Err(\"Circuit constants vector size doesn't match specified parameters.\");\n+        }\n+        Ok(())\n+    }\n+}\n+\n+#[derive(Clone, Debug)]\n+pub struct CircuitProof {\n+    pub A_I: RistrettoPoint,\n+    pub A_O: RistrettoPoint,\n+    pub S: RistrettoPoint,\n+    pub T_1: RistrettoPoint,\n+    pub T_3: RistrettoPoint,\n+    pub T_4: RistrettoPoint,\n+    pub T_5: RistrettoPoint,\n+    pub T_6: RistrettoPoint,\n+    pub t_x: Scalar,\n+    pub t_x_blinding: Scalar,\n+    pub e_blinding: Scalar,\n+    pub ipp_proof: InnerProductProof,\n+}\n+\n+impl CircuitProof {\n+    pub fn prove<R: Rng + CryptoRng>(\n+        gen: &Generators,\n+        transcript: &mut ProofTranscript,\n+        rng: &mut R,\n+        circuit: Circuit,\n+        a_L: Vec<Scalar>,\n+        a_R: Vec<Scalar>,\n+        a_O: Vec<Scalar>,\n+        v_blinding: Vec<Scalar>,\n+    ) -> Result<CircuitProof, &'static str> {\n+        circuit.check_parameters()?;\n+        if a_L.len() != circuit.n\n+            || a_R.len() != circuit.n\n+            || a_O.len() != circuit.n\n+            || v_blinding.len() != circuit.m\n+        {\n+            return Err(\"Input vector size doesn't match specified parameters.\");\n+        }\n+        if gen.n != circuit.n {\n+            return Err(\"Generator length doesn't match specified parameters.\");\n+        }\n+\n+        transcript.commit_u64(circuit.n as u64);\n+        transcript.commit_u64(circuit.m as u64);\n+        transcript.commit_u64(circuit.q as u64);\n+\n+        let i_blinding = Scalar::random(rng);\n+        let o_blinding = Scalar::random(rng);\n+        let s_blinding = Scalar::random(rng);\n+        let s_L: Vec<Scalar> = (0..circuit.n).map(|_| Scalar::random(rng)).collect();\n+        let s_R: Vec<Scalar> = (0..circuit.n).map(|_| Scalar::random(rng)).collect();\n+\n+        // A_I = <a_L, G> + <a_R, H> + i_blinding * B_blinding\n+        let A_I = RistrettoPoint::multiscalar_mul(\n+            iter::once(&i_blinding).chain(a_L.iter()).chain(a_R.iter()),\n+            iter::once(&gen.pedersen_generators.B_blinding)\n+                .chain(gen.G.iter())\n+                .chain(gen.H.iter()),\n+        );\n+\n+        // A_O = <a_O, G> + o_blinding * B_blinding\n+        let A_O = RistrettoPoint::multiscalar_mul(\n+            iter::once(&o_blinding).chain(a_O.iter()),\n+            iter::once(&gen.pedersen_generators.B_blinding).chain(gen.G.iter()),\n+        );\n+\n+        // S = <s_L, G> + <s_R, H> + s_blinding * B_blinding\n+        let S = RistrettoPoint::multiscalar_mul(\n+            iter::once(&s_blinding).chain(s_L.iter()).chain(s_R.iter()),\n+            iter::once(&gen.pedersen_generators.B_blinding)\n+                .chain(gen.G.iter())\n+                .chain(gen.H.iter()),\n+        );\n+\n+        transcript.commit(A_I.compress().as_bytes());\n+        transcript.commit(A_O.compress().as_bytes());\n+        transcript.commit(S.compress().as_bytes());\n+        let y = transcript.challenge_scalar();\n+        let z = transcript.challenge_scalar();\n+\n+        let mut l_poly = util::VecPoly3::zero(circuit.n);\n+        let mut r_poly = util::VecPoly3::zero(circuit.n);\n+\n+        let z_zQ_WL: Vec<Scalar> = matrix_flatten(circuit.W_L, z, circuit.n)?;\n+        let z_zQ_WR: Vec<Scalar> = matrix_flatten(circuit.W_R, z, circuit.n)?;\n+        let z_zQ_WO: Vec<Scalar> = matrix_flatten(circuit.W_O, z, circuit.n)?;\n+\n+        let mut exp_y = Scalar::one(); // y^n starting at n=0\n+        let mut exp_y_inv = Scalar::one(); // y^-n starting at n=0\n+        let y_inv = y.invert();\n+\n+        for i in 0..circuit.n {\n+            // l_poly.0 = 0\n+            // l_poly.1 = a_L + y^-n * (z * z^Q * W_R)\n+            l_poly.1[i] = a_L[i] + exp_y_inv * z_zQ_WR[i];\n+            // l_poly.2 = a_O\n+            l_poly.2[i] = a_O[i];\n+            // l_poly.3 = s_L\n+            l_poly.3[i] = s_L[i];\n+            // r_poly.0 = (z * z^Q * W_O) - y^n\n+            r_poly.0[i] = z_zQ_WO[i] - exp_y;\n+            // r_poly.1 = y^n * a_R + (z * z^Q * W_L)\n+            r_poly.1[i] = exp_y * a_R[i] + z_zQ_WL[i];\n+            // r_poly.2 = 0\n+            // r_poly.3 = y^n * s_R\n+            r_poly.3[i] = exp_y * s_R[i];\n+\n+            exp_y = exp_y * y; // y^i -> y^(i+1)\n+            exp_y_inv = exp_y_inv * y_inv; // y^-i -> y^-(i+1)\n+        }\n+\n+        let t_poly = l_poly.inner_product(&r_poly);\n+\n+        let t_1_blinding = Scalar::random(rng);\n+        let t_3_blinding = Scalar::random(rng);\n+        let t_4_blinding = Scalar::random(rng);\n+        let t_5_blinding = Scalar::random(rng);\n+        let t_6_blinding = Scalar::random(rng);\n+\n+        let T_1 = gen.pedersen_generators.commit(t_poly.t1, t_1_blinding);\n+        let T_3 = gen.pedersen_generators.commit(t_poly.t3, t_3_blinding);\n+        let T_4 = gen.pedersen_generators.commit(t_poly.t4, t_4_blinding);\n+        let T_5 = gen.pedersen_generators.commit(t_poly.t5, t_5_blinding);\n+        let T_6 = gen.pedersen_generators.commit(t_poly.t6, t_6_blinding);\n+\n+        transcript.commit(T_1.compress().as_bytes());\n+        transcript.commit(T_3.compress().as_bytes());\n+        transcript.commit(T_4.compress().as_bytes());\n+        transcript.commit(T_5.compress().as_bytes());\n+        transcript.commit(T_6.compress().as_bytes());\n+        let x = transcript.challenge_scalar();\n+\n+        // t_2_blinding = <z*z^Q, W_V * v_blinding>\n+        // in the t_x_blinding calculations, line 76.\n+        let t_2_blinding = circuit\n+            .W_V\n+            .iter()\n+            .zip(util::exp_iter(z))\n+            .map(|(W_V_i, exp_z)| z * exp_z * inner_product(&W_V_i, &v_blinding))\n+            .sum();\n+\n+        let t_blinding_poly = util::Poly6 {\n+            t1: t_1_blinding,\n+            t2: t_2_blinding,\n+            t3: t_3_blinding,\n+            t4: t_4_blinding,\n+            t5: t_5_blinding,\n+            t6: t_6_blinding,\n+        };\n+\n+        let t_x = t_poly.eval(x);\n+        let t_x_blinding = t_blinding_poly.eval(x);\n+        let l_vec = l_poly.eval(x);\n+        let r_vec = r_poly.eval(x);\n+        let e_blinding = x * (i_blinding + x * (o_blinding + x * s_blinding));\n+\n+        transcript.commit(t_x.as_bytes());\n+        transcript.commit(t_x_blinding.as_bytes());\n+        transcript.commit(e_blinding.as_bytes());\n+\n+        // Get a challenge value to combine statements for the IPP\n+        let w = transcript.challenge_scalar();\n+        let Q = w * gen.pedersen_generators.B;\n+\n+        let ipp_proof = InnerProductProof::create(\n+            transcript,\n+            &Q,\n+            util::exp_iter(y.invert()),\n+            gen.G.to_vec(),\n+            gen.H.to_vec(),\n+            l_vec.clone(),\n+            r_vec.clone(),\n+        );\n+\n+        Ok(CircuitProof {\n+            A_I,\n+            A_O,\n+            S,\n+            T_1,\n+            T_3,\n+            T_4,\n+            T_5,\n+            T_6,\n+            t_x,\n+            t_x_blinding,\n+            e_blinding,\n+            ipp_proof,\n+        })\n+    }\n+\n+    pub fn verify<R: Rng + CryptoRng>(\n+        &self,\n+        gen: &Generators,\n+        transcript: &mut ProofTranscript,\n+        rng: &mut R,\n+        circuit: Circuit,\n+        V: Vec<RistrettoPoint>, // Vector of commitments, length m\n+    ) -> Result<(), &'static str> {\n+        circuit.check_parameters()?;\n+        if V.len() != circuit.m {\n+            return Err(\"Commitments vector size doesn't match specified parameters.\");\n+        }\n+        if gen.n != circuit.n {\n+            return Err(\"Generator length doesn't match specified parameters.\");\n+        }\n+\n+        transcript.commit_u64(circuit.n as u64);\n+        transcript.commit_u64(circuit.m as u64);\n+        transcript.commit_u64(circuit.q as u64);\n+        transcript.commit(self.A_I.compress().as_bytes());\n+        transcript.commit(self.A_O.compress().as_bytes());\n+        transcript.commit(self.S.compress().as_bytes());\n+        let y = transcript.challenge_scalar();\n+        let z = transcript.challenge_scalar();\n+\n+        transcript.commit(self.T_1.compress().as_bytes());\n+        transcript.commit(self.T_3.compress().as_bytes());\n+        transcript.commit(self.T_4.compress().as_bytes());\n+        transcript.commit(self.T_5.compress().as_bytes());\n+        transcript.commit(self.T_6.compress().as_bytes());\n+        let x = transcript.challenge_scalar();\n+\n+        transcript.commit(self.t_x.as_bytes());\n+        transcript.commit(self.t_x_blinding.as_bytes());\n+        transcript.commit(self.e_blinding.as_bytes());\n+        let w = transcript.challenge_scalar();\n+\n+        let r = Scalar::random(rng);\n+\n+        // Calculate points that represent the matrices\n+        let H_prime: Vec<RistrettoPoint> = gen\n+            .H\n+            .iter()\n+            .zip(util::exp_iter(y.invert()))\n+            .map(|(H_i, exp_y_inv)| H_i * exp_y_inv)\n+            .collect();\n+        // W_L_point = <h * y^-n , z * z^Q * W_L>, line 81\n+        let W_L_flatten: Vec<Scalar> = matrix_flatten(circuit.W_L, z, circuit.n)?;\n+        let W_L_point =\n+            RistrettoPoint::vartime_multiscalar_mul(W_L_flatten.clone(), H_prime.iter());\n+        // W_R_point = <g , y^-n * z * z^Q * W_R>, line 82\n+        let W_R_flatten: Vec<Scalar> = matrix_flatten(circuit.W_R, z, circuit.n)?;\n+        let W_R_flatten_yinv: Vec<Scalar> = W_R_flatten\n+            .iter()\n+            .zip(util::exp_iter(y.invert()))\n+            .map(|(W_R_right_i, exp_y_inv)| W_R_right_i * exp_y_inv)\n+            .collect();\n+        let W_R_point =\n+            RistrettoPoint::vartime_multiscalar_mul(W_R_flatten_yinv.clone(), gen.G.iter());\n+        // W_O_point = <h * y^-n , z * z^Q * W_O>, line 83\n+        let W_O_flatten: Vec<Scalar> = matrix_flatten(circuit.W_O, z, circuit.n)?;\n+        let W_O_point = RistrettoPoint::vartime_multiscalar_mul(W_O_flatten, H_prime.iter());\n+\n+        // Get IPP variables\n+        let (x_sq, x_inv_sq, s) = self.ipp_proof.verification_scalars(transcript);\n+        let s_inv = s.iter().rev().take(circuit.n);\n+        let a = self.ipp_proof.a;\n+        let b = self.ipp_proof.b;\n+\n+        // define parameters for P check\n+        let g = s.iter().take(circuit.n).map(|s_i| -a * s_i);\n+        let h = s_inv\n+            .zip(util::exp_iter(y.invert()))\n+            .map(|(s_i_inv, exp_y_inv)| -exp_y_inv * b * s_i_inv - Scalar::one());\n+\n+        // define parameters for t check\n+        let delta = inner_product(&W_R_flatten_yinv, &W_L_flatten);\n+        let powers_of_z: Vec<Scalar> = util::exp_iter(z).take(circuit.q).collect();\n+        let z_c = z * inner_product(&powers_of_z, &circuit.c);\n+        let W_V_flatten: Vec<Scalar> = matrix_flatten(circuit.W_V, z, circuit.m)?;\n+        let V_multiplier = W_V_flatten.iter().map(|W_V_i| r * x * x * W_V_i);\n+\n+        let mega_check = RistrettoPoint::vartime_multiscalar_mul(\n+            iter::once(x) // A_I\n+                .chain(iter::once(x * x)) // A_O\n+                .chain(iter::once(x)) // W_L_point\n+                .chain(iter::once(x)) // W_R_point\n+                .chain(iter::once(Scalar::one())) // W_O_point\n+                .chain(iter::once(x * x * x)) // S\n+                .chain(iter::once(w * (self.t_x - a * b) + r * (x * x * (delta + z_c) - self.t_x))) // B\n+                .chain(iter::once(-self.e_blinding - r * self.t_x_blinding)) // B_blinding\n+                .chain(g) // G\n+                .chain(h) // H\n+                .chain(x_sq.iter().cloned()) // ipp_proof.L_vec\n+                .chain(x_inv_sq.iter().cloned()) // ipp_proof.R_vec\n+                .chain(V_multiplier) // V\n+                .chain(iter::once(r * x)) // T_1\n+                .chain(iter::once(r * x * x * x)) // T_3\n+                .chain(iter::once(r * x * x * x * x)) // T_4\n+                .chain(iter::once(r * x * x * x * x * x)) // T_5\n+                .chain(iter::once(r * x * x * x * x * x * x)), // T_6\n+            iter::once(&self.A_I)\n+                .chain(iter::once(&self.A_O))\n+                .chain(iter::once(&W_L_point))\n+                .chain(iter::once(&W_R_point))\n+                .chain(iter::once(&W_O_point))\n+                .chain(iter::once(&self.S))\n+                .chain(iter::once(&gen.pedersen_generators.B))\n+                .chain(iter::once(&gen.pedersen_generators.B_blinding))\n+                .chain(gen.G.iter())\n+                .chain(gen.H.iter())\n+                .chain(self.ipp_proof.L_vec.iter())\n+                .chain(self.ipp_proof.R_vec.iter())\n+                .chain(V.iter())\n+                .chain(iter::once(&self.T_1))\n+                .chain(iter::once(&self.T_3))\n+                .chain(iter::once(&self.T_4))\n+                .chain(iter::once(&self.T_5))\n+                .chain(iter::once(&self.T_6)),\n+        );\n+\n+        if !mega_check.is_identity() {\n+            return Err(\"Circuit did not verify correctly.\");\n+        }\n+\n+        Ok(())\n+    }\n+}\n+\n+// Computes z * z^Q * W, where W is a qxn matrix and z is a scalar.\n+// Input: Qxn matrix of scalars and scalar z\n+// Output: length n vector of Scalars\n+pub fn matrix_flatten(\n+    W: Vec<Vec<Scalar>>,\n+    z: Scalar,\n+    output_dim: usize,","path":"src/circuit_proof/mod.rs","position":365,"original_position":365,"commit_id":"61cf9a4c3bacd895f26329903a5fc8659828c4a9","original_commit_id":"61cf9a4c3bacd895f26329903a5fc8659828c4a9","user":{"login":"cathieyun","id":3314874,"node_id":"MDQ6VXNlcjMzMTQ4NzQ=","avatar_url":"https://avatars3.githubusercontent.com/u/3314874?v=4","gravatar_id":"","url":"https://api.github.com/users/cathieyun","html_url":"https://github.com/cathieyun","followers_url":"https://api.github.com/users/cathieyun/followers","following_url":"https://api.github.com/users/cathieyun/following{/other_user}","gists_url":"https://api.github.com/users/cathieyun/gists{/gist_id}","starred_url":"https://api.github.com/users/cathieyun/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cathieyun/subscriptions","organizations_url":"https://api.github.com/users/cathieyun/orgs","repos_url":"https://api.github.com/users/cathieyun/repos","events_url":"https://api.github.com/users/cathieyun/events{/privacy}","received_events_url":"https://api.github.com/users/cathieyun/received_events","type":"User","site_admin":false},"body":"The reason we need the `output_dim` parameter is if the matrix is size `qxn` where `q=0` and `n>0` (such as in the `mul_circuit_2` test case). In this case, you could not figure out what the output vector's size should be (since you can't figure out `n` by looking at the matrix), but the output of the `matrix_flatten` function should still be a length `n` vector. \r\n\r\nIt's possible to do a check higher up for if `n=0`, before calling `matrix_flatten`, but I thought it would be cleaner to pass in `n` as `output_dim` and have the `matrix_flatten` function take care of those checks internally.","created_at":"2018-07-10T20:37:52Z","updated_at":"2018-07-10T20:38:32Z","html_url":"https://github.com/dalek-cryptography/bulletproofs/pull/102#discussion_r201486133","pull_request_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/pulls/102","author_association":"COLLABORATOR","_links":{"self":{"href":"https://api.github.com/repos/dalek-cryptography/bulletproofs/pulls/comments/201486133"},"html":{"href":"https://github.com/dalek-cryptography/bulletproofs/pull/102#discussion_r201486133"},"pull_request":{"href":"https://api.github.com/repos/dalek-cryptography/bulletproofs/pulls/102"}},"in_reply_to_id":201455963},"pull_request":{"url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/pulls/102","id":194442285,"node_id":"MDExOlB1bGxSZXF1ZXN0MTk0NDQyMjg1","html_url":"https://github.com/dalek-cryptography/bulletproofs/pull/102","diff_url":"https://github.com/dalek-cryptography/bulletproofs/pull/102.diff","patch_url":"https://github.com/dalek-cryptography/bulletproofs/pull/102.patch","issue_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/issues/102","number":102,"state":"open","locked":false,"title":"Arithmetic circuit proof code","user":{"login":"cathieyun","id":3314874,"node_id":"MDQ6VXNlcjMzMTQ4NzQ=","avatar_url":"https://avatars3.githubusercontent.com/u/3314874?v=4","gravatar_id":"","url":"https://api.github.com/users/cathieyun","html_url":"https://github.com/cathieyun","followers_url":"https://api.github.com/users/cathieyun/followers","following_url":"https://api.github.com/users/cathieyun/following{/other_user}","gists_url":"https://api.github.com/users/cathieyun/gists{/gist_id}","starred_url":"https://api.github.com/users/cathieyun/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cathieyun/subscriptions","organizations_url":"https://api.github.com/users/cathieyun/orgs","repos_url":"https://api.github.com/users/cathieyun/repos","events_url":"https://api.github.com/users/cathieyun/events{/privacy}","received_events_url":"https://api.github.com/users/cathieyun/received_events","type":"User","site_admin":false},"body":"Corresponds with: https://github.com/chain/ristretto-bulletproofs/issues/97\r\n\r\nCircuit proof code:\r\n- generates a circuit proof using IPP optimization\r\n- verifies a circuit proof \r\n- contains tests for basic multiplication, addition, and shuffle circuits\r\n\r\nNext steps:\r\n- figure out how to bypass matrix representation of circuits (R1CS directly to bulletproofs)\r\n- figure out how to do higher-level circuit representations (bellman?)\r\n- benchmarking for more complex circuits\r\n\r\nPTAL!","created_at":"2018-06-13T00:28:23Z","updated_at":"2018-07-10T20:38:32Z","closed_at":null,"merged_at":null,"merge_commit_sha":"37c5ec8ae764635ff50828f7f5eb49f8581c3e8f","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/pulls/102/commits","review_comments_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/pulls/102/comments","review_comment_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/issues/102/comments","statuses_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/statuses/61cf9a4c3bacd895f26329903a5fc8659828c4a9","head":{"label":"dalek-cryptography:circuit-code","ref":"circuit-code","sha":"61cf9a4c3bacd895f26329903a5fc8659828c4a9","user":{"login":"dalek-cryptography","id":35540388,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM1NTQwMzg4","avatar_url":"https://avatars3.githubusercontent.com/u/35540388?v=4","gravatar_id":"","url":"https://api.github.com/users/dalek-cryptography","html_url":"https://github.com/dalek-cryptography","followers_url":"https://api.github.com/users/dalek-cryptography/followers","following_url":"https://api.github.com/users/dalek-cryptography/following{/other_user}","gists_url":"https://api.github.com/users/dalek-cryptography/gists{/gist_id}","starred_url":"https://api.github.com/users/dalek-cryptography/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dalek-cryptography/subscriptions","organizations_url":"https://api.github.com/users/dalek-cryptography/orgs","repos_url":"https://api.github.com/users/dalek-cryptography/repos","events_url":"https://api.github.com/users/dalek-cryptography/events{/privacy}","received_events_url":"https://api.github.com/users/dalek-cryptography/received_events","type":"Organization","site_admin":false},"repo":{"id":119915731,"node_id":"MDEwOlJlcG9zaXRvcnkxMTk5MTU3MzE=","name":"bulletproofs","full_name":"dalek-cryptography/bulletproofs","owner":{"login":"dalek-cryptography","id":35540388,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM1NTQwMzg4","avatar_url":"https://avatars3.githubusercontent.com/u/35540388?v=4","gravatar_id":"","url":"https://api.github.com/users/dalek-cryptography","html_url":"https://github.com/dalek-cryptography","followers_url":"https://api.github.com/users/dalek-cryptography/followers","following_url":"https://api.github.com/users/dalek-cryptography/following{/other_user}","gists_url":"https://api.github.com/users/dalek-cryptography/gists{/gist_id}","starred_url":"https://api.github.com/users/dalek-cryptography/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dalek-cryptography/subscriptions","organizations_url":"https://api.github.com/users/dalek-cryptography/orgs","repos_url":"https://api.github.com/users/dalek-cryptography/repos","events_url":"https://api.github.com/users/dalek-cryptography/events{/privacy}","received_events_url":"https://api.github.com/users/dalek-cryptography/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dalek-cryptography/bulletproofs","description":" A pure-Rust implementation of Bulletproofs using Ristretto.","fork":false,"url":"https://api.github.com/repos/dalek-cryptography/bulletproofs","forks_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/forks","keys_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/teams","hooks_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/hooks","issue_events_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/issues/events{/number}","events_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/events","assignees_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/assignees{/user}","branches_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/branches{/branch}","tags_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/tags","blobs_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/git/refs{/sha}","trees_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/statuses/{sha}","languages_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/languages","stargazers_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/stargazers","contributors_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/contributors","subscribers_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/subscribers","subscription_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/subscription","commits_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/commits{/sha}","git_commits_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/git/commits{/sha}","comments_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/comments{/number}","issue_comment_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/issues/comments{/number}","contents_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/contents/{+path}","compare_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/merges","archive_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/downloads","issues_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/issues{/number}","pulls_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/pulls{/number}","milestones_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/milestones{/number}","notifications_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/labels{/name}","releases_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/releases{/id}","deployments_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/deployments","created_at":"2018-02-02T01:35:49Z","updated_at":"2018-07-10T18:18:58Z","pushed_at":"2018-07-10T19:00:49Z","git_url":"git://github.com/dalek-cryptography/bulletproofs.git","ssh_url":"git@github.com:dalek-cryptography/bulletproofs.git","clone_url":"https://github.com/dalek-cryptography/bulletproofs.git","svn_url":"https://github.com/dalek-cryptography/bulletproofs","homepage":"","size":1766,"stargazers_count":115,"watchers_count":115,"language":"Rust","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":9,"mirror_url":null,"archived":false,"open_issues_count":24,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":9,"open_issues":24,"watchers":115,"default_branch":"main"}},"base":{"label":"dalek-cryptography:circuit","ref":"circuit","sha":"011deb1cfc02a980d06d56ed0a36542a77ec2f17","user":{"login":"dalek-cryptography","id":35540388,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM1NTQwMzg4","avatar_url":"https://avatars3.githubusercontent.com/u/35540388?v=4","gravatar_id":"","url":"https://api.github.com/users/dalek-cryptography","html_url":"https://github.com/dalek-cryptography","followers_url":"https://api.github.com/users/dalek-cryptography/followers","following_url":"https://api.github.com/users/dalek-cryptography/following{/other_user}","gists_url":"https://api.github.com/users/dalek-cryptography/gists{/gist_id}","starred_url":"https://api.github.com/users/dalek-cryptography/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dalek-cryptography/subscriptions","organizations_url":"https://api.github.com/users/dalek-cryptography/orgs","repos_url":"https://api.github.com/users/dalek-cryptography/repos","events_url":"https://api.github.com/users/dalek-cryptography/events{/privacy}","received_events_url":"https://api.github.com/users/dalek-cryptography/received_events","type":"Organization","site_admin":false},"repo":{"id":119915731,"node_id":"MDEwOlJlcG9zaXRvcnkxMTk5MTU3MzE=","name":"bulletproofs","full_name":"dalek-cryptography/bulletproofs","owner":{"login":"dalek-cryptography","id":35540388,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM1NTQwMzg4","avatar_url":"https://avatars3.githubusercontent.com/u/35540388?v=4","gravatar_id":"","url":"https://api.github.com/users/dalek-cryptography","html_url":"https://github.com/dalek-cryptography","followers_url":"https://api.github.com/users/dalek-cryptography/followers","following_url":"https://api.github.com/users/dalek-cryptography/following{/other_user}","gists_url":"https://api.github.com/users/dalek-cryptography/gists{/gist_id}","starred_url":"https://api.github.com/users/dalek-cryptography/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dalek-cryptography/subscriptions","organizations_url":"https://api.github.com/users/dalek-cryptography/orgs","repos_url":"https://api.github.com/users/dalek-cryptography/repos","events_url":"https://api.github.com/users/dalek-cryptography/events{/privacy}","received_events_url":"https://api.github.com/users/dalek-cryptography/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dalek-cryptography/bulletproofs","description":" A pure-Rust implementation of Bulletproofs using Ristretto.","fork":false,"url":"https://api.github.com/repos/dalek-cryptography/bulletproofs","forks_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/forks","keys_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/teams","hooks_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/hooks","issue_events_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/issues/events{/number}","events_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/events","assignees_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/assignees{/user}","branches_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/branches{/branch}","tags_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/tags","blobs_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/git/refs{/sha}","trees_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/statuses/{sha}","languages_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/languages","stargazers_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/stargazers","contributors_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/contributors","subscribers_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/subscribers","subscription_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/subscription","commits_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/commits{/sha}","git_commits_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/git/commits{/sha}","comments_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/comments{/number}","issue_comment_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/issues/comments{/number}","contents_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/contents/{+path}","compare_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/merges","archive_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/downloads","issues_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/issues{/number}","pulls_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/pulls{/number}","milestones_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/milestones{/number}","notifications_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/labels{/name}","releases_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/releases{/id}","deployments_url":"https://api.github.com/repos/dalek-cryptography/bulletproofs/deployments","created_at":"2018-02-02T01:35:49Z","updated_at":"2018-07-10T18:18:58Z","pushed_at":"2018-07-10T19:00:49Z","git_url":"git://github.com/dalek-cryptography/bulletproofs.git","ssh_url":"git@github.com:dalek-cryptography/bulletproofs.git","clone_url":"https://github.com/dalek-cryptography/bulletproofs.git","svn_url":"https://github.com/dalek-cryptography/bulletproofs","homepage":"","size":1766,"stargazers_count":115,"watchers_count":115,"language":"Rust","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":9,"mirror_url":null,"archived":false,"open_issues_count":24,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":9,"open_issues":24,"watchers":115,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/dalek-cryptography/bulletproofs/pulls/102"},"html":{"href":"https://github.com/dalek-cryptography/bulletproofs/pull/102"},"issue":{"href":"https://api.github.com/repos/dalek-cryptography/bulletproofs/issues/102"},"comments":{"href":"https://api.github.com/repos/dalek-cryptography/bulletproofs/issues/102/comments"},"review_comments":{"href":"https://api.github.com/repos/dalek-cryptography/bulletproofs/pulls/102/comments"},"review_comment":{"href":"https://api.github.com/repos/dalek-cryptography/bulletproofs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dalek-cryptography/bulletproofs/pulls/102/commits"},"statuses":{"href":"https://api.github.com/repos/dalek-cryptography/bulletproofs/statuses/61cf9a4c3bacd895f26329903a5fc8659828c4a9"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"cathieyun"}}