diff --git a/source-code/BulletProofs/LinearBulletproof.java b/source-code/BulletProofs/LinearBulletproof.java
deleted file mode 100644
index f33913e..0000000
--- a/source-code/BulletProofs/LinearBulletproof.java
+++ /dev/null
@@ -1,372 +0,0 @@
-// NOTE: this interchanges the roles of G and H to match other code's behavior
-
-package how.monero.hodl.bulletproof;
-
-import how.monero.hodl.crypto.Curve25519Point;
-import how.monero.hodl.crypto.Scalar;
-import how.monero.hodl.crypto.CryptoUtil;
-import how.monero.hodl.util.ByteUtil;
-import java.math.BigInteger;
-import how.monero.hodl.util.VarInt;
-import java.util.Random;
-
-import static how.monero.hodl.crypto.Scalar.randomScalar;
-import static how.monero.hodl.crypto.CryptoUtil.*;
-import static how.monero.hodl.util.ByteUtil.*;
-
-public class LinearBulletproof
-{
- private static int N;
- private static Curve25519Point G;
- private static Curve25519Point H;
- private static Curve25519Point[] Gi;
- private static Curve25519Point[] Hi;
-
- public static class ProofTuple
- {
- private Curve25519Point V;
- private Curve25519Point A;
- private Curve25519Point S;
- private Curve25519Point T1;
- private Curve25519Point T2;
- private Scalar taux;
- private Scalar mu;
- private Scalar[] l;
- private Scalar[] r;
-
- public ProofTuple(Curve25519Point V, Curve25519Point A, Curve25519Point S, Curve25519Point T1, Curve25519Point T2, Scalar taux, Scalar mu, Scalar[] l, Scalar[] r)
- {
- this.V = V;
- this.A = A;
- this.S = S;
- this.T1 = T1;
- this.T2 = T2;
- this.taux = taux;
- this.mu = mu;
- this.l = l;
- this.r = r;
- }
- }
-
- /* Given two scalar arrays, construct a vector commitment */
- public static Curve25519Point VectorExponent(Scalar[] a, Scalar[] b)
- {
- Curve25519Point Result = Curve25519Point.ZERO;
- for (int i = 0; i < N; i++)
- {
- Result = Result.add(Gi[i].scalarMultiply(a[i]));
- Result = Result.add(Hi[i].scalarMultiply(b[i]));
- }
- return Result;
- }
-
- /* Given a scalar, construct a vector of powers */
- public static Scalar[] VectorPowers(Scalar x)
- {
- Scalar[] result = new Scalar[N];
- for (int i = 0; i < N; i++)
- {
- result[i] = x.pow(i);
- }
- return result;
- }
-
- /* Given two scalar arrays, construct the inner product */
- public static Scalar InnerProduct(Scalar[] a, Scalar[] b)
- {
- Scalar result = Scalar.ZERO;
- for (int i = 0; i < N; i++)
- {
- result = result.add(a[i].mul(b[i]));
- }
- return result;
- }
-
- /* Given two scalar arrays, construct the Hadamard product */
- public static Scalar[] Hadamard(Scalar[] a, Scalar[] b)
- {
- Scalar[] result = new Scalar[N];
- for (int i = 0; i < N; i++)
- {
- result[i] = a[i].mul(b[i]);
- }
- return result;
- }
-
- /* Add two vectors */
- public static Scalar[] VectorAdd(Scalar[] a, Scalar[] b)
- {
- Scalar[] result = new Scalar[N];
- for (int i = 0; i < N; i++)
- {
- result[i] = a[i].add(b[i]);
- }
- return result;
- }
-
- /* Subtract two vectors */
- public static Scalar[] VectorSubtract(Scalar[] a, Scalar[] b)
- {
- Scalar[] result = new Scalar[N];
- for (int i = 0; i < N; i++)
- {
- result[i] = a[i].sub(b[i]);
- }
- return result;
- }
-
- /* Multiply a scalar and a vector */
- public static Scalar[] VectorScalar(Scalar[] a, Scalar x)
- {
- Scalar[] result = new Scalar[N];
- for (int i = 0; i < N; i++)
- {
- result[i] = a[i].mul(x);
- }
- return result;
- }
-
- /* Compute the inverse of a scalar, the stupid way */
- public static Scalar Invert(Scalar x)
- {
- Scalar inverse = new Scalar(x.toBigInteger().modInverse(CryptoUtil.l));
- assert x.mul(inverse).equals(Scalar.ONE);
-
- return inverse;
- }
-
- /* Compute the value of k(y,z) */
- public static Scalar ComputeK(Scalar y, Scalar z)
- {
- Scalar result = Scalar.ZERO;
- result = result.sub(z.sq().mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y))));
- result = result.sub(z.pow(3).mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(Scalar.TWO))));
-
- return result;
- }
-
- /* Given a value v (0..2^N-1) and a mask gamma, construct a range proof */
- public static ProofTuple PROVE(Scalar v, Scalar gamma)
- {
- Curve25519Point V = H.scalarMultiply(v).add(G.scalarMultiply(gamma));
-
- // This hash is updated for Fiat-Shamir throughout the proof
- Scalar hashCache = hashToScalar(V.toBytes());
-
- // PAPER LINES 36-37
- Scalar[] aL = new Scalar[N];
- Scalar[] aR = new Scalar[N];
-
- BigInteger tempV = v.toBigInteger();
- for (int i = N-1; i >= 0; i--)
- {
- BigInteger basePow = BigInteger.valueOf(2).pow(i);
- if (tempV.divide(basePow).equals(BigInteger.ZERO))
- {
- aL[i] = Scalar.ZERO;
- }
- else
- {
- aL[i] = Scalar.ONE;
- tempV = tempV.subtract(basePow);
- }
-
- aR[i] = aL[i].sub(Scalar.ONE);
- }
-
- // DEBUG: Test to ensure this recovers the value
- BigInteger test_aL = BigInteger.ZERO;
- BigInteger test_aR = BigInteger.ZERO;
- for (int i = 0; i < N; i++)
- {
- if (aL[i].equals(Scalar.ONE))
- test_aL = test_aL.add(BigInteger.valueOf(2).pow(i));
- if (aR[i].equals(Scalar.ZERO))
- test_aR = test_aR.add(BigInteger.valueOf(2).pow(i));
- }
- assert test_aL.equals(v.toBigInteger());
- assert test_aR.equals(v.toBigInteger());
-
- // PAPER LINES 38-39
- Scalar alpha = randomScalar();
- Curve25519Point A = VectorExponent(aL,aR).add(G.scalarMultiply(alpha));
-
- // PAPER LINES 40-42
- Scalar[] sL = new Scalar[N];
- Scalar[] sR = new Scalar[N];
- for (int i = 0; i < N; i++)
- {
- sL[i] = randomScalar();
- sR[i] = randomScalar();
- }
- Scalar rho = randomScalar();
- Curve25519Point S = VectorExponent(sL,sR).add(G.scalarMultiply(rho));
-
- // PAPER LINES 43-45
- hashCache = hashToScalar(concat(hashCache.bytes,A.toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,S.toBytes()));
- Scalar y = hashCache;
- hashCache = hashToScalar(hashCache.bytes);
- Scalar z = hashCache;
-
- Scalar t0 = Scalar.ZERO;
- Scalar t1 = Scalar.ZERO;
- Scalar t2 = Scalar.ZERO;
-
- t0 = t0.add(z.mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y))));
- t0 = t0.add(z.sq().mul(v));
- Scalar k = ComputeK(y,z);
- t0 = t0.add(k);
-
- // DEBUG: Test the value of t0 has the correct form
- Scalar test_t0 = Scalar.ZERO;
- test_t0 = test_t0.add(InnerProduct(aL,Hadamard(aR,VectorPowers(y))));
- test_t0 = test_t0.add(z.mul(InnerProduct(VectorSubtract(aL,aR),VectorPowers(y))));
- test_t0 = test_t0.add(z.sq().mul(InnerProduct(VectorPowers(Scalar.TWO),aL)));
- test_t0 = test_t0.add(k);
- assert test_t0.equals(t0);
-
- t1 = t1.add(InnerProduct(VectorSubtract(aL,VectorScalar(VectorPowers(Scalar.ONE),z)),Hadamard(VectorPowers(y),sR)));
- t1 = t1.add(InnerProduct(sL,VectorAdd(Hadamard(VectorPowers(y),VectorAdd(aR,VectorScalar(VectorPowers(Scalar.ONE),z))),VectorScalar(VectorPowers(Scalar.TWO),z.sq()))));
- t2 = t2.add(InnerProduct(sL,Hadamard(VectorPowers(y),sR)));
-
- // PAPER LINES 47-48
- Scalar tau1 = randomScalar();
- Scalar tau2 = randomScalar();
- Curve25519Point T1 = H.scalarMultiply(t1).add(G.scalarMultiply(tau1));
- Curve25519Point T2 = H.scalarMultiply(t2).add(G.scalarMultiply(tau2));
-
- // PAPER LINES 49-51
- hashCache = hashToScalar(concat(hashCache.bytes,z.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,T1.toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,T2.toBytes()));
- Scalar x = hashCache;
-
- // PAPER LINES 52-53
- Scalar taux = Scalar.ZERO;
- taux = tau1.mul(x);
- taux = taux.add(tau2.mul(x.sq()));
- taux = taux.add(gamma.mul(z.sq()));
- Scalar mu = x.mul(rho).add(alpha);
-
- // PAPER LINES 54-57
- Scalar[] l = new Scalar[N];
- Scalar[] r = new Scalar[N];
-
- l = VectorAdd(VectorSubtract(aL,VectorScalar(VectorPowers(Scalar.ONE),z)),VectorScalar(sL,x));
- r = VectorAdd(Hadamard(VectorPowers(y),VectorAdd(aR,VectorAdd(VectorScalar(VectorPowers(Scalar.ONE),z),VectorScalar(sR,x)))),VectorScalar(VectorPowers(Scalar.TWO),z.sq()));
-
- // DEBUG: Test if the l and r vectors match the polynomial forms
- Scalar test_t = Scalar.ZERO;
- test_t = test_t.add(t0).add(t1.mul(x));
- test_t = test_t.add(t2.mul(x.sq()));
- assert test_t.equals(InnerProduct(l,r));
-
- // PAPER LINE 58
- return new ProofTuple(V,A,S,T1,T2,taux,mu,l,r);
- }
-
- /* Given a range proof, determine if it is valid */
- public static boolean VERIFY(ProofTuple proof)
- {
- // Reconstruct the challenges
- Scalar hashCache = hashToScalar(proof.V.toBytes());
- hashCache = hashToScalar(concat(hashCache.bytes,proof.A.toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.S.toBytes()));
- Scalar y = hashCache;
- hashCache = hashToScalar(hashCache.bytes);
- Scalar z = hashCache;
- hashCache = hashToScalar(concat(hashCache.bytes,z.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.T1.toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.T2.toBytes()));
- Scalar x = hashCache;
-
- // PAPER LINE 60
- Scalar t = InnerProduct(proof.l,proof.r);
-
- // PAPER LINE 61
- Curve25519Point L61Left = G.scalarMultiply(proof.taux).add(H.scalarMultiply(t));
-
- Scalar k = ComputeK(y,z);
-
- Curve25519Point L61Right = H.scalarMultiply(k.add(z.mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y)))));
- L61Right = L61Right.add(proof.V.scalarMultiply(z.sq()));
- L61Right = L61Right.add(proof.T1.scalarMultiply(x));
- L61Right = L61Right.add(proof.T2.scalarMultiply(x.sq()));
-
- if (!L61Right.equals(L61Left))
- {
- return false;
- }
-
- // PAPER LINE 62
- Curve25519Point P = Curve25519Point.ZERO;
- P = P.add(proof.A);
- P = P.add(proof.S.scalarMultiply(x));
-
- Scalar[] Gexp = new Scalar[N];
- for (int i = 0; i < N; i++)
- Gexp[i] = Scalar.ZERO.sub(z);
-
- Scalar[] Hexp = new Scalar[N];
- for (int i = 0; i < N; i++)
- {
- Hexp[i] = Scalar.ZERO;
- Hexp[i] = Hexp[i].add(z.mul(y.pow(i)));
- Hexp[i] = Hexp[i].add(z.sq().mul(Scalar.TWO.pow(i)));
- Hexp[i] = Hexp[i].mul(Invert(y).pow(i));
- }
- P = P.add(VectorExponent(Gexp,Hexp));
-
- // PAPER LINE 63
- for (int i = 0; i < N; i++)
- {
- Hexp[i] = Scalar.ZERO;
- Hexp[i] = Hexp[i].add(proof.r[i]);
- Hexp[i] = Hexp[i].mul(Invert(y).pow(i));
- }
- Curve25519Point L63Right = VectorExponent(proof.l,Hexp).add(G.scalarMultiply(proof.mu));
-
- if (!L63Right.equals(P))
- {
- return false;
- }
-
- return true;
- }
-
- public static void main(String[] args)
- {
- // Number of bits in the range
- N = 64;
-
- // Set the curve base points
- G = Curve25519Point.G;
- H = Curve25519Point.hashToPoint(G);
- Gi = new Curve25519Point[N];
- Hi = new Curve25519Point[N];
- for (int i = 0; i < N; i++)
- {
- Gi[i] = getHpnGLookup(2*i);
- Hi[i] = getHpnGLookup(2*i+1);
- }
-
- // Run a bunch of randomized trials
- Random rando = new Random();
- int TRIALS = 250;
- int count = 0;
-
- while (count < TRIALS)
- {
- long amount = rando.nextLong();
- if (amount > Math.pow(2,N)-1 || amount < 0)
- continue;
-
- ProofTuple proof = PROVE(new Scalar(BigInteger.valueOf(amount)),randomScalar());
- if (!VERIFY(proof))
- System.out.println("Test failed");
-
- count += 1;
- }
- }
-}
diff --git a/source-code/BulletProofs/LogBulletproof.java b/source-code/BulletProofs/LogBulletproof.java
deleted file mode 100644
index 7061cd9..0000000
--- a/source-code/BulletProofs/LogBulletproof.java
+++ /dev/null
@@ -1,532 +0,0 @@
-// NOTE: this interchanges the roles of G and H to match other code's behavior
-
-package how.monero.hodl.bulletproof;
-
-import how.monero.hodl.crypto.Curve25519Point;
-import how.monero.hodl.crypto.Scalar;
-import how.monero.hodl.crypto.CryptoUtil;
-import java.math.BigInteger;
-import java.util.Random;
-
-import static how.monero.hodl.crypto.Scalar.randomScalar;
-import static how.monero.hodl.crypto.CryptoUtil.*;
-import static how.monero.hodl.util.ByteUtil.*;
-
-public class LogBulletproof
-{
- private static int N;
- private static int logN;
- private static Curve25519Point G;
- private static Curve25519Point H;
- private static Curve25519Point[] Gi;
- private static Curve25519Point[] Hi;
-
- public static class ProofTuple
- {
- private Curve25519Point V;
- private Curve25519Point A;
- private Curve25519Point S;
- private Curve25519Point T1;
- private Curve25519Point T2;
- private Scalar taux;
- private Scalar mu;
- private Curve25519Point[] L;
- private Curve25519Point[] R;
- private Scalar a;
- private Scalar b;
- private Scalar t;
-
- public ProofTuple(Curve25519Point V, Curve25519Point A, Curve25519Point S, Curve25519Point T1, Curve25519Point T2, Scalar taux, Scalar mu, Curve25519Point[] L, Curve25519Point[] R, Scalar a, Scalar b, Scalar t)
- {
- this.V = V;
- this.A = A;
- this.S = S;
- this.T1 = T1;
- this.T2 = T2;
- this.taux = taux;
- this.mu = mu;
- this.L = L;
- this.R = R;
- this.a = a;
- this.b = b;
- this.t = t;
- }
- }
-
- /* Given two scalar arrays, construct a vector commitment */
- public static Curve25519Point VectorExponent(Scalar[] a, Scalar[] b)
- {
- assert a.length == N && b.length == N;
-
- Curve25519Point Result = Curve25519Point.ZERO;
- for (int i = 0; i < N; i++)
- {
- Result = Result.add(Gi[i].scalarMultiply(a[i]));
- Result = Result.add(Hi[i].scalarMultiply(b[i]));
- }
- return Result;
- }
-
- /* Compute a custom vector-scalar commitment */
- public static Curve25519Point VectorExponentCustom(Curve25519Point[] A, Curve25519Point[] B, Scalar[] a, Scalar[] b)
- {
- assert a.length == A.length && b.length == B.length && a.length == b.length;
-
- Curve25519Point Result = Curve25519Point.ZERO;
- for (int i = 0; i < a.length; i++)
- {
- Result = Result.add(A[i].scalarMultiply(a[i]));
- Result = Result.add(B[i].scalarMultiply(b[i]));
- }
- return Result;
- }
-
- /* Given a scalar, construct a vector of powers */
- public static Scalar[] VectorPowers(Scalar x)
- {
- Scalar[] result = new Scalar[N];
- for (int i = 0; i < N; i++)
- {
- result[i] = x.pow(i);
- }
- return result;
- }
-
- /* Given two scalar arrays, construct the inner product */
- public static Scalar InnerProduct(Scalar[] a, Scalar[] b)
- {
- assert a.length == b.length;
-
- Scalar result = Scalar.ZERO;
- for (int i = 0; i < a.length; i++)
- {
- result = result.add(a[i].mul(b[i]));
- }
- return result;
- }
-
- /* Given two scalar arrays, construct the Hadamard product */
- public static Scalar[] Hadamard(Scalar[] a, Scalar[] b)
- {
- assert a.length == b.length;
-
- Scalar[] result = new Scalar[a.length];
- for (int i = 0; i < a.length; i++)
- {
- result[i] = a[i].mul(b[i]);
- }
- return result;
- }
-
- /* Given two curvepoint arrays, construct the Hadamard product */
- public static Curve25519Point[] Hadamard2(Curve25519Point[] A, Curve25519Point[] B)
- {
- assert A.length == B.length;
-
- Curve25519Point[] Result = new Curve25519Point[A.length];
- for (int i = 0; i < A.length; i++)
- {
- Result[i] = A[i].add(B[i]);
- }
- return Result;
- }
-
- /* Add two vectors */
- public static Scalar[] VectorAdd(Scalar[] a, Scalar[] b)
- {
- assert a.length == b.length;
-
- Scalar[] result = new Scalar[a.length];
- for (int i = 0; i < a.length; i++)
- {
- result[i] = a[i].add(b[i]);
- }
- return result;
- }
-
- /* Subtract two vectors */
- public static Scalar[] VectorSubtract(Scalar[] a, Scalar[] b)
- {
- assert a.length == b.length;
-
- Scalar[] result = new Scalar[a.length];
- for (int i = 0; i < a.length; i++)
- {
- result[i] = a[i].sub(b[i]);
- }
- return result;
- }
-
- /* Multiply a scalar and a vector */
- public static Scalar[] VectorScalar(Scalar[] a, Scalar x)
- {
- Scalar[] result = new Scalar[a.length];
- for (int i = 0; i < a.length; i++)
- {
- result[i] = a[i].mul(x);
- }
- return result;
- }
-
- /* Exponentiate a curve vector by a scalar */
- public static Curve25519Point[] VectorScalar2(Curve25519Point[] A, Scalar x)
- {
- Curve25519Point[] Result = new Curve25519Point[A.length];
- for (int i = 0; i < A.length; i++)
- {
- Result[i] = A[i].scalarMultiply(x);
- }
- return Result;
- }
-
- /* Compute the inverse of a scalar, the stupid way */
- public static Scalar Invert(Scalar x)
- {
- Scalar inverse = new Scalar(x.toBigInteger().modInverse(CryptoUtil.l));
-
- assert x.mul(inverse).equals(Scalar.ONE);
- return inverse;
- }
-
- /* Compute the slice of a curvepoint vector */
- public static Curve25519Point[] CurveSlice(Curve25519Point[] a, int start, int stop)
- {
- Curve25519Point[] Result = new Curve25519Point[stop-start];
- for (int i = start; i < stop; i++)
- {
- Result[i-start] = a[i];
- }
- return Result;
- }
-
- /* Compute the slice of a scalar vector */
- public static Scalar[] ScalarSlice(Scalar[] a, int start, int stop)
- {
- Scalar[] result = new Scalar[stop-start];
- for (int i = start; i < stop; i++)
- {
- result[i-start] = a[i];
- }
- return result;
- }
-
- /* Compute the value of k(y,z) */
- public static Scalar ComputeK(Scalar y, Scalar z)
- {
- Scalar result = Scalar.ZERO;
- result = result.sub(z.sq().mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y))));
- result = result.sub(z.pow(3).mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(Scalar.TWO))));
-
- return result;
- }
-
- /* Given a value v (0..2^N-1) and a mask gamma, construct a range proof */
- public static ProofTuple PROVE(Scalar v, Scalar gamma)
- {
- Curve25519Point V = H.scalarMultiply(v).add(G.scalarMultiply(gamma));
-
- // This hash is updated for Fiat-Shamir throughout the proof
- Scalar hashCache = hashToScalar(V.toBytes());
-
- // PAPER LINES 36-37
- Scalar[] aL = new Scalar[N];
- Scalar[] aR = new Scalar[N];
-
- BigInteger tempV = v.toBigInteger();
- for (int i = N-1; i >= 0; i--)
- {
- BigInteger basePow = BigInteger.valueOf(2).pow(i);
- if (tempV.divide(basePow).equals(BigInteger.ZERO))
- {
- aL[i] = Scalar.ZERO;
- }
- else
- {
- aL[i] = Scalar.ONE;
- tempV = tempV.subtract(basePow);
- }
-
- aR[i] = aL[i].sub(Scalar.ONE);
- }
-
- // PAPER LINES 38-39
- Scalar alpha = randomScalar();
- Curve25519Point A = VectorExponent(aL,aR).add(G.scalarMultiply(alpha));
-
- // PAPER LINES 40-42
- Scalar[] sL = new Scalar[N];
- Scalar[] sR = new Scalar[N];
- for (int i = 0; i < N; i++)
- {
- sL[i] = randomScalar();
- sR[i] = randomScalar();
- }
- Scalar rho = randomScalar();
- Curve25519Point S = VectorExponent(sL,sR).add(G.scalarMultiply(rho));
-
- // PAPER LINES 43-45
- hashCache = hashToScalar(concat(hashCache.bytes,A.toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,S.toBytes()));
- Scalar y = hashCache;
- hashCache = hashToScalar(hashCache.bytes);
- Scalar z = hashCache;
-
- // Polynomial construction before PAPER LINE 46
- Scalar t0 = Scalar.ZERO;
- Scalar t1 = Scalar.ZERO;
- Scalar t2 = Scalar.ZERO;
-
- t0 = t0.add(z.mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y))));
- t0 = t0.add(z.sq().mul(v));
- Scalar k = ComputeK(y,z);
- t0 = t0.add(k);
-
- t1 = t1.add(InnerProduct(VectorSubtract(aL,VectorScalar(VectorPowers(Scalar.ONE),z)),Hadamard(VectorPowers(y),sR)));
- t1 = t1.add(InnerProduct(sL,VectorAdd(Hadamard(VectorPowers(y),VectorAdd(aR,VectorScalar(VectorPowers(Scalar.ONE),z))),VectorScalar(VectorPowers(Scalar.TWO),z.sq()))));
-
- t2 = t2.add(InnerProduct(sL,Hadamard(VectorPowers(y),sR)));
-
- // PAPER LINES 47-48
- Scalar tau1 = randomScalar();
- Scalar tau2 = randomScalar();
- Curve25519Point T1 = H.scalarMultiply(t1).add(G.scalarMultiply(tau1));
- Curve25519Point T2 = H.scalarMultiply(t2).add(G.scalarMultiply(tau2));
-
- // PAPER LINES 49-51
- hashCache = hashToScalar(concat(hashCache.bytes,z.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,T1.toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,T2.toBytes()));
- Scalar x = hashCache;
-
- // PAPER LINES 52-53
- Scalar taux = Scalar.ZERO;
- taux = tau1.mul(x);
- taux = taux.add(tau2.mul(x.sq()));
- taux = taux.add(gamma.mul(z.sq()));
- Scalar mu = x.mul(rho).add(alpha);
-
- // PAPER LINES 54-57
- Scalar[] l = new Scalar[N];
- Scalar[] r = new Scalar[N];
-
- l = VectorAdd(VectorSubtract(aL,VectorScalar(VectorPowers(Scalar.ONE),z)),VectorScalar(sL,x));
- r = VectorAdd(Hadamard(VectorPowers(y),VectorAdd(aR,VectorAdd(VectorScalar(VectorPowers(Scalar.ONE),z),VectorScalar(sR,x)))),VectorScalar(VectorPowers(Scalar.TWO),z.sq()));
-
- Scalar t = InnerProduct(l,r);
-
- // PAPER LINES 32-33
- hashCache = hashToScalar(concat(hashCache.bytes,x.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,taux.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,mu.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,t.bytes));
- Scalar x_ip = hashCache;
-
- // These are used in the inner product rounds
- int nprime = N;
- Curve25519Point[] Gprime = new Curve25519Point[N];
- Curve25519Point[] Hprime = new Curve25519Point[N];
- Scalar[] aprime = new Scalar[N];
- Scalar[] bprime = new Scalar[N];
- for (int i = 0; i < N; i++)
- {
- Gprime[i] = Gi[i];
- Hprime[i] = Hi[i].scalarMultiply(Invert(y).pow(i));
- aprime[i] = l[i];
- bprime[i] = r[i];
- }
- Curve25519Point[] L = new Curve25519Point[logN];
- Curve25519Point[] R = new Curve25519Point[logN];
- int round = 0; // track the index based on number of rounds
- Scalar[] w = new Scalar[logN]; // this is the challenge x in the inner product protocol
-
- // PAPER LINE 13
- while (nprime > 1)
- {
- // PAPER LINE 15
- nprime /= 2;
-
- // PAPER LINES 16-17
- Scalar cL = InnerProduct(ScalarSlice(aprime,0,nprime),ScalarSlice(bprime,nprime,bprime.length));
- Scalar cR = InnerProduct(ScalarSlice(aprime,nprime,aprime.length),ScalarSlice(bprime,0,nprime));
-
- // PAPER LINES 18-19
- L[round] = VectorExponentCustom(CurveSlice(Gprime,nprime,Gprime.length),CurveSlice(Hprime,0,nprime),ScalarSlice(aprime,0,nprime),ScalarSlice(bprime,nprime,bprime.length)).add(H.scalarMultiply(cL.mul(x_ip)));
- R[round] = VectorExponentCustom(CurveSlice(Gprime,0,nprime),CurveSlice(Hprime,nprime,Hprime.length),ScalarSlice(aprime,nprime,aprime.length),ScalarSlice(bprime,0,nprime)).add(H.scalarMultiply(cR.mul(x_ip)));
-
- // PAPER LINES 21-22
- hashCache = hashToScalar(concat(hashCache.bytes,L[round].toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,R[round].toBytes()));
- w[round] = hashCache;
-
- // PAPER LINES 24-25
- Gprime = Hadamard2(VectorScalar2(CurveSlice(Gprime,0,nprime),Invert(w[round])),VectorScalar2(CurveSlice(Gprime,nprime,Gprime.length),w[round]));
- Hprime = Hadamard2(VectorScalar2(CurveSlice(Hprime,0,nprime),w[round]),VectorScalar2(CurveSlice(Hprime,nprime,Hprime.length),Invert(w[round])));
-
- // PAPER LINES 28-29
- aprime = VectorAdd(VectorScalar(ScalarSlice(aprime,0,nprime),w[round]),VectorScalar(ScalarSlice(aprime,nprime,aprime.length),Invert(w[round])));
- bprime = VectorAdd(VectorScalar(ScalarSlice(bprime,0,nprime),Invert(w[round])),VectorScalar(ScalarSlice(bprime,nprime,bprime.length),w[round]));
-
- round += 1;
- }
-
- // PAPER LINE 58 (with inclusions from PAPER LINE 8 and PAPER LINE 20)
- return new ProofTuple(V,A,S,T1,T2,taux,mu,L,R,aprime[0],bprime[0],t);
- }
-
- /* Given a range proof, determine if it is valid */
- public static boolean VERIFY(ProofTuple proof)
- {
- // Reconstruct the challenges
- Scalar hashCache = hashToScalar(proof.V.toBytes());
- hashCache = hashToScalar(concat(hashCache.bytes,proof.A.toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.S.toBytes()));
- Scalar y = hashCache;
- hashCache = hashToScalar(hashCache.bytes);
- Scalar z = hashCache;
- hashCache = hashToScalar(concat(hashCache.bytes,z.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.T1.toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.T2.toBytes()));
- Scalar x = hashCache;
- hashCache = hashToScalar(concat(hashCache.bytes,x.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.taux.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.mu.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.t.bytes));
- Scalar x_ip = hashCache;
-
- // PAPER LINE 61
- Curve25519Point L61Left = G.scalarMultiply(proof.taux).add(H.scalarMultiply(proof.t));
-
- Scalar k = ComputeK(y,z);
-
- Curve25519Point L61Right = H.scalarMultiply(k.add(z.mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y)))));
- L61Right = L61Right.add(proof.V.scalarMultiply(z.sq()));
- L61Right = L61Right.add(proof.T1.scalarMultiply(x));
- L61Right = L61Right.add(proof.T2.scalarMultiply(x.sq()));
-
- if (!L61Right.equals(L61Left))
- return false;
-
- // PAPER LINE 62
- Curve25519Point P = Curve25519Point.ZERO;
- P = P.add(proof.A);
- P = P.add(proof.S.scalarMultiply(x));
-
- Scalar[] Gexp = new Scalar[N];
- for (int i = 0; i < N; i++)
- Gexp[i] = Scalar.ZERO.sub(z);
-
- Scalar[] Hexp = new Scalar[N];
- for (int i = 0; i < N; i++)
- {
- Hexp[i] = Scalar.ZERO;
- Hexp[i] = Hexp[i].add(z.mul(y.pow(i)));
- Hexp[i] = Hexp[i].add(z.sq().mul(Scalar.TWO.pow(i)));
- Hexp[i] = Hexp[i].mul(Invert(y).pow(i));
- }
- P = P.add(VectorExponent(Gexp,Hexp));
-
- // Compute the number of rounds for the inner product
- int rounds = proof.L.length;
-
- // PAPER LINES 21-22
- // The inner product challenges are computed per round
- Scalar[] w = new Scalar[rounds];
- hashCache = hashToScalar(concat(hashCache.bytes,proof.L[0].toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.R[0].toBytes()));
- w[0] = hashCache;
- if (rounds > 1)
- {
- for (int i = 1; i < rounds; i++)
- {
- hashCache = hashToScalar(concat(hashCache.bytes,proof.L[i].toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.R[i].toBytes()));
- w[i] = hashCache;
- }
- }
-
- // Basically PAPER LINES 24-25
- // Compute the curvepoints from G[i] and H[i]
- Curve25519Point InnerProdG = Curve25519Point.ZERO;
- Curve25519Point InnerProdH = Curve25519Point.ZERO;
- for (int i = 0; i < N; i++)
- {
- // Convert the index to binary IN REVERSE and construct the scalar exponent
- int index = i;
- Scalar gScalar = Scalar.ONE;
- Scalar hScalar = Invert(y).pow(i);
-
- for (int j = rounds-1; j >= 0; j--)
- {
- int J = w.length - j - 1; // because this is done in reverse bit order
- int basePow = (int) Math.pow(2,j); // assumes we don't get too big
- if (index / basePow == 0) // bit is zero
- {
- gScalar = gScalar.mul(Invert(w[J]));
- hScalar = hScalar.mul(w[J]);
- }
- else // bit is one
- {
- gScalar = gScalar.mul(w[J]);
- hScalar = hScalar.mul(Invert(w[J]));
- index -= basePow;
- }
- }
-
- // Now compute the basepoint's scalar multiplication
- // Each of these could be written as a multiexp operation instead
- InnerProdG = InnerProdG.add(Gi[i].scalarMultiply(gScalar));
- InnerProdH = InnerProdH.add(Hi[i].scalarMultiply(hScalar));
- }
-
- // PAPER LINE 26
- Curve25519Point Pprime = P.add(G.scalarMultiply(Scalar.ZERO.sub(proof.mu)));
-
- for (int i = 0; i < rounds; i++)
- {
- Pprime = Pprime.add(proof.L[i].scalarMultiply(w[i].sq()));
- Pprime = Pprime.add(proof.R[i].scalarMultiply(Invert(w[i]).sq()));
- }
- Pprime = Pprime.add(H.scalarMultiply(proof.t.mul(x_ip)));
-
- if (!Pprime.equals(InnerProdG.scalarMultiply(proof.a).add(InnerProdH.scalarMultiply(proof.b)).add(H.scalarMultiply(proof.a.mul(proof.b).mul(x_ip)))))
- return false;
-
- return true;
- }
-
- public static void main(String[] args)
- {
- // Number of bits in the range
- N = 64;
- logN = 6; // its log, manually
-
- // Set the curve base points
- G = Curve25519Point.G;
- H = Curve25519Point.hashToPoint(G);
- Gi = new Curve25519Point[N];
- Hi = new Curve25519Point[N];
- for (int i = 0; i < N; i++)
- {
- Gi[i] = getHpnGLookup(2*i);
- Hi[i] = getHpnGLookup(2*i+1);
- }
-
- // Run a bunch of randomized trials
- Random rando = new Random();
- int TRIALS = 250;
- int count = 0;
-
- while (count < TRIALS)
- {
- long amount = rando.nextLong();
- if (amount > Math.pow(2,N)-1 || amount < 0)
- continue;
-
- ProofTuple proof = PROVE(new Scalar(BigInteger.valueOf(amount)),randomScalar());
- if (!VERIFY(proof))
- System.out.println("Test failed");
-
- count += 1;
- }
- }
-}
diff --git a/source-code/BulletProofs/MultiBulletproof.java b/source-code/BulletProofs/MultiBulletproof.java
deleted file mode 100644
index 48277ef..0000000
--- a/source-code/BulletProofs/MultiBulletproof.java
+++ /dev/null
@@ -1,554 +0,0 @@
-// NOTE: this interchanges the roles of G and H to match other code's behavior
-
-package how.monero.hodl.bulletproof;
-
-import how.monero.hodl.crypto.Curve25519Point;
-import how.monero.hodl.crypto.Scalar;
-import how.monero.hodl.crypto.CryptoUtil;
-import java.math.BigInteger;
-import java.util.Random;
-
-import static how.monero.hodl.crypto.Scalar.randomScalar;
-import static how.monero.hodl.crypto.CryptoUtil.*;
-import static how.monero.hodl.util.ByteUtil.*;
-
-public class MultiBulletproof
-{
- private static int N;
- private static int logMN;
- private static int M;
- private static Curve25519Point G;
- private static Curve25519Point H;
- private static Curve25519Point[] Gi;
- private static Curve25519Point[] Hi;
-
- public static class ProofTuple
- {
- private Curve25519Point V[];
- private Curve25519Point A;
- private Curve25519Point S;
- private Curve25519Point T1;
- private Curve25519Point T2;
- private Scalar taux;
- private Scalar mu;
- private Curve25519Point[] L;
- private Curve25519Point[] R;
- private Scalar a;
- private Scalar b;
- private Scalar t;
-
- public ProofTuple(Curve25519Point V[], Curve25519Point A, Curve25519Point S, Curve25519Point T1, Curve25519Point T2, Scalar taux, Scalar mu, Curve25519Point[] L, Curve25519Point[] R, Scalar a, Scalar b, Scalar t)
- {
- this.V = V;
- this.A = A;
- this.S = S;
- this.T1 = T1;
- this.T2 = T2;
- this.taux = taux;
- this.mu = mu;
- this.L = L;
- this.R = R;
- this.a = a;
- this.b = b;
- this.t = t;
- }
- }
-
- /* Given two scalar arrays, construct a vector commitment */
- public static Curve25519Point VectorExponent(Scalar[] a, Scalar[] b)
- {
- assert a.length == M*N && b.length == M*N;
-
- Curve25519Point Result = Curve25519Point.ZERO;
- for (int i = 0; i < M*N; i++)
- {
- Result = Result.add(Gi[i].scalarMultiply(a[i]));
- Result = Result.add(Hi[i].scalarMultiply(b[i]));
- }
- return Result;
- }
-
- /* Compute a custom vector-scalar commitment */
- public static Curve25519Point VectorExponentCustom(Curve25519Point[] A, Curve25519Point[] B, Scalar[] a, Scalar[] b)
- {
- assert a.length == A.length && b.length == B.length && a.length == b.length;
-
- Curve25519Point Result = Curve25519Point.ZERO;
- for (int i = 0; i < a.length; i++)
- {
- Result = Result.add(A[i].scalarMultiply(a[i]));
- Result = Result.add(B[i].scalarMultiply(b[i]));
- }
- return Result;
- }
-
- /* Given a scalar, construct a vector of powers */
- public static Scalar[] VectorPowers(Scalar x, int size)
- {
- Scalar[] result = new Scalar[size];
- for (int i = 0; i < size; i++)
- {
- result[i] = x.pow(i);
- }
- return result;
- }
-
- /* Given two scalar arrays, construct the inner product */
- public static Scalar InnerProduct(Scalar[] a, Scalar[] b)
- {
- assert a.length == b.length;
-
- Scalar result = Scalar.ZERO;
- for (int i = 0; i < a.length; i++)
- {
- result = result.add(a[i].mul(b[i]));
- }
- return result;
- }
-
- /* Given two scalar arrays, construct the Hadamard product */
- public static Scalar[] Hadamard(Scalar[] a, Scalar[] b)
- {
- assert a.length == b.length;
-
- Scalar[] result = new Scalar[a.length];
- for (int i = 0; i < a.length; i++)
- {
- result[i] = a[i].mul(b[i]);
- }
- return result;
- }
-
- /* Given two curvepoint arrays, construct the Hadamard product */
- public static Curve25519Point[] Hadamard2(Curve25519Point[] A, Curve25519Point[] B)
- {
- assert A.length == B.length;
-
- Curve25519Point[] Result = new Curve25519Point[A.length];
- for (int i = 0; i < A.length; i++)
- {
- Result[i] = A[i].add(B[i]);
- }
- return Result;
- }
-
- /* Add two vectors */
- public static Scalar[] VectorAdd(Scalar[] a, Scalar[] b)
- {
- assert a.length == b.length;
-
- Scalar[] result = new Scalar[a.length];
- for (int i = 0; i < a.length; i++)
- {
- result[i] = a[i].add(b[i]);
- }
- return result;
- }
-
- /* Subtract two vectors */
- public static Scalar[] VectorSubtract(Scalar[] a, Scalar[] b)
- {
- assert a.length == b.length;
-
- Scalar[] result = new Scalar[a.length];
- for (int i = 0; i < a.length; i++)
- {
- result[i] = a[i].sub(b[i]);
- }
- return result;
- }
-
- /* Multiply a scalar and a vector */
- public static Scalar[] VectorScalar(Scalar[] a, Scalar x)
- {
- Scalar[] result = new Scalar[a.length];
- for (int i = 0; i < a.length; i++)
- {
- result[i] = a[i].mul(x);
- }
- return result;
- }
-
- /* Exponentiate a curve vector by a scalar */
- public static Curve25519Point[] VectorScalar2(Curve25519Point[] A, Scalar x)
- {
- Curve25519Point[] Result = new Curve25519Point[A.length];
- for (int i = 0; i < A.length; i++)
- {
- Result[i] = A[i].scalarMultiply(x);
- }
- return Result;
- }
-
- /* Compute the inverse of a scalar, the stupid way */
- public static Scalar Invert(Scalar x)
- {
- Scalar inverse = new Scalar(x.toBigInteger().modInverse(CryptoUtil.l));
-
- assert x.mul(inverse).equals(Scalar.ONE);
- return inverse;
- }
-
- /* Compute the slice of a curvepoint vector */
- public static Curve25519Point[] CurveSlice(Curve25519Point[] a, int start, int stop)
- {
- Curve25519Point[] Result = new Curve25519Point[stop-start];
- for (int i = start; i < stop; i++)
- {
- Result[i-start] = a[i];
- }
- return Result;
- }
-
- /* Compute the slice of a scalar vector */
- public static Scalar[] ScalarSlice(Scalar[] a, int start, int stop)
- {
- Scalar[] result = new Scalar[stop-start];
- for (int i = start; i < stop; i++)
- {
- result[i-start] = a[i];
- }
- return result;
- }
-
- /* Construct an aggregate range proof */
- public static ProofTuple PROVE(Scalar[] v, Scalar[] gamma)
- {
- Curve25519Point[] V = new Curve25519Point[M];
-
- V[0] = H.scalarMultiply(v[0]).add(G.scalarMultiply(gamma[0]));
- // This hash is updated for Fiat-Shamir throughout the proof
- Scalar hashCache = hashToScalar(V[0].toBytes());
- for (int j = 1; j < M; j++)
- {
- V[j] = H.scalarMultiply(v[j]).add(G.scalarMultiply(gamma[j]));
- hashCache = hashToScalar(concat(hashCache.bytes,V[j].toBytes()));
- }
-
- // PAPER LINES 36-37
- Scalar[] aL = new Scalar[M*N];
- Scalar[] aR = new Scalar[M*N];
-
- for (int j = 0; j < M; j++)
- {
- BigInteger tempV = v[j].toBigInteger();
- for (int i = N-1; i >= 0; i--)
- {
- BigInteger basePow = BigInteger.valueOf(2).pow(i);
- if (tempV.divide(basePow).equals(BigInteger.ZERO))
- {
- aL[j*N+i] = Scalar.ZERO;
- }
- else
- {
- aL[j*N+i] = Scalar.ONE;
- tempV = tempV.subtract(basePow);
- }
-
- aR[j*N+i] = aL[j*N+i].sub(Scalar.ONE);
- }
- }
-
- // PAPER LINES 38-39
- Scalar alpha = randomScalar();
- Curve25519Point A = VectorExponent(aL,aR).add(G.scalarMultiply(alpha));
-
- // PAPER LINES 40-42
- Scalar[] sL = new Scalar[M*N];
- Scalar[] sR = new Scalar[M*N];
- for (int i = 0; i < M*N; i++)
- {
- sL[i] = randomScalar();
- sR[i] = randomScalar();
- }
- Scalar rho = randomScalar();
- Curve25519Point S = VectorExponent(sL,sR).add(G.scalarMultiply(rho));
-
- // PAPER LINES 43-45
- hashCache = hashToScalar(concat(hashCache.bytes,A.toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,S.toBytes()));
- Scalar y = hashCache;
- hashCache = hashToScalar(hashCache.bytes);
- Scalar z = hashCache;
-
- // Polynomial construction by coefficients
- Scalar[] l0;
- Scalar[] l1;
- Scalar[] r0;
- Scalar[] r1;
-
- l0 = VectorSubtract(aL,VectorScalar(VectorPowers(Scalar.ONE,M*N),z));
- l1 = sL;
-
- // This computes the ugly sum/concatenation from PAPER LINE 65
- Scalar[] zerosTwos = new Scalar[M*N];
- for (int i = 0; i < M*N; i++)
- {
- zerosTwos[i] = Scalar.ZERO;
- for (int j = 1; j <= M; j++) // note this starts from 1
- {
- Scalar temp = Scalar.ZERO;
- if (i >= (j-1)*N && i < j*N)
- temp = Scalar.TWO.pow(i-(j-1)*N); // exponent ranges from 0..N-1
- zerosTwos[i] = zerosTwos[i].add(z.pow(1+j).mul(temp));
- }
- }
-
- r0 = VectorAdd(aR,VectorScalar(VectorPowers(Scalar.ONE,M*N),z));
- r0 = Hadamard(r0,VectorPowers(y,M*N));
- r0 = VectorAdd(r0,zerosTwos);
- r1 = Hadamard(VectorPowers(y,M*N),sR);
-
- // Polynomial construction before PAPER LINE 46
- Scalar t0 = InnerProduct(l0,r0);
- Scalar t1 = InnerProduct(l0,r1).add(InnerProduct(l1,r0));
- Scalar t2 = InnerProduct(l1,r1);
-
- // PAPER LINES 47-48
- Scalar tau1 = randomScalar();
- Scalar tau2 = randomScalar();
- Curve25519Point T1 = H.scalarMultiply(t1).add(G.scalarMultiply(tau1));
- Curve25519Point T2 = H.scalarMultiply(t2).add(G.scalarMultiply(tau2));
-
- // PAPER LINES 49-51
- hashCache = hashToScalar(concat(hashCache.bytes,z.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,T1.toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,T2.toBytes()));
- Scalar x = hashCache;
-
- // PAPER LINES 52-53
- Scalar taux = tau1.mul(x);
- taux = taux.add(tau2.mul(x.sq()));
- for (int j = 1; j <= M; j++) // note this starts from 1
- {
- taux = taux.add(z.pow(1+j).mul(gamma[j-1]));
- }
- Scalar mu = x.mul(rho).add(alpha);
-
- // PAPER LINES 54-57
- Scalar[] l = l0;
- l = VectorAdd(l,VectorScalar(l1,x));
- Scalar[] r = r0;
- r = VectorAdd(r,VectorScalar(r1,x));
-
- Scalar t = InnerProduct(l,r);
-
- // PAPER LINES 32-33
- hashCache = hashToScalar(concat(hashCache.bytes,x.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,taux.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,mu.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,t.bytes));
- Scalar x_ip = hashCache;
-
- // These are used in the inner product rounds
- int nprime = M*N;
- Curve25519Point[] Gprime = new Curve25519Point[M*N];
- Curve25519Point[] Hprime = new Curve25519Point[M*N];
- Scalar[] aprime = new Scalar[M*N];
- Scalar[] bprime = new Scalar[M*N];
- for (int i = 0; i < M*N; i++)
- {
- Gprime[i] = Gi[i];
- Hprime[i] = Hi[i].scalarMultiply(Invert(y).pow(i));
- aprime[i] = l[i];
- bprime[i] = r[i];
- }
- Curve25519Point[] L = new Curve25519Point[logMN];
- Curve25519Point[] R = new Curve25519Point[logMN];
- int round = 0; // track the index based on number of rounds
- Scalar[] w = new Scalar[logMN]; // this is the challenge x in the inner product protocol
-
- // PAPER LINE 13
- while (nprime > 1)
- {
- // PAPER LINE 15
- nprime /= 2;
-
- // PAPER LINES 16-17
- Scalar cL = InnerProduct(ScalarSlice(aprime,0,nprime),ScalarSlice(bprime,nprime,bprime.length));
- Scalar cR = InnerProduct(ScalarSlice(aprime,nprime,aprime.length),ScalarSlice(bprime,0,nprime));
-
- // PAPER LINES 18-19
- L[round] = VectorExponentCustom(CurveSlice(Gprime,nprime,Gprime.length),CurveSlice(Hprime,0,nprime),ScalarSlice(aprime,0,nprime),ScalarSlice(bprime,nprime,bprime.length)).add(H.scalarMultiply(cL.mul(x_ip)));
- R[round] = VectorExponentCustom(CurveSlice(Gprime,0,nprime),CurveSlice(Hprime,nprime,Hprime.length),ScalarSlice(aprime,nprime,aprime.length),ScalarSlice(bprime,0,nprime)).add(H.scalarMultiply(cR.mul(x_ip)));
-
- // PAPER LINES 21-22
- hashCache = hashToScalar(concat(hashCache.bytes,L[round].toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,R[round].toBytes()));
- w[round] = hashCache;
-
- // PAPER LINES 24-25
- Gprime = Hadamard2(VectorScalar2(CurveSlice(Gprime,0,nprime),Invert(w[round])),VectorScalar2(CurveSlice(Gprime,nprime,Gprime.length),w[round]));
- Hprime = Hadamard2(VectorScalar2(CurveSlice(Hprime,0,nprime),w[round]),VectorScalar2(CurveSlice(Hprime,nprime,Hprime.length),Invert(w[round])));
-
- // PAPER LINES 28-29
- aprime = VectorAdd(VectorScalar(ScalarSlice(aprime,0,nprime),w[round]),VectorScalar(ScalarSlice(aprime,nprime,aprime.length),Invert(w[round])));
- bprime = VectorAdd(VectorScalar(ScalarSlice(bprime,0,nprime),Invert(w[round])),VectorScalar(ScalarSlice(bprime,nprime,bprime.length),w[round]));
-
- round += 1;
- }
-
- // PAPER LINE 58 (with inclusions from PAPER LINE 8 and PAPER LINE 20)
- return new ProofTuple(V,A,S,T1,T2,taux,mu,L,R,aprime[0],bprime[0],t);
- }
-
- /* Given a range proof, determine if it is valid */
- public static boolean VERIFY(ProofTuple proof)
- {
- // Reconstruct the challenges
- Scalar hashCache = hashToScalar(proof.V[0].toBytes());
- for (int j = 1; j < M; j++)
- hashCache = hashToScalar(concat(hashCache.bytes,proof.V[j].toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.A.toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.S.toBytes()));
- Scalar y = hashCache;
- hashCache = hashToScalar(hashCache.bytes);
- Scalar z = hashCache;
- hashCache = hashToScalar(concat(hashCache.bytes,z.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.T1.toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.T2.toBytes()));
- Scalar x = hashCache;
- hashCache = hashToScalar(concat(hashCache.bytes,x.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.taux.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.mu.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.t.bytes));
- Scalar x_ip = hashCache;
-
- // PAPER LINE 61
- Curve25519Point L61Left = G.scalarMultiply(proof.taux).add(H.scalarMultiply(proof.t));
-
- Scalar k = Scalar.ZERO.sub(z.sq().mul(InnerProduct(VectorPowers(Scalar.ONE,M*N),VectorPowers(y,M*N))));
- for (int j = 1; j <= M; j++) // note this starts from 1
- {
- k = k.sub(z.pow(j+2).mul(InnerProduct(VectorPowers(Scalar.ONE,N),VectorPowers(Scalar.TWO,N))));
- }
-
- Curve25519Point L61Right = H.scalarMultiply(k.add(z.mul(InnerProduct(VectorPowers(Scalar.ONE,M*N),VectorPowers(y,M*N)))));
- for (int j = 0; j < M; j++)
- {
- L61Right = L61Right.add(proof.V[j].scalarMultiply(z.pow(j+2)));
- }
- L61Right = L61Right.add(proof.T1.scalarMultiply(x));
- L61Right = L61Right.add(proof.T2.scalarMultiply(x.sq()));
-
- if (!L61Right.equals(L61Left))
- return false;
-
- // PAPER LINE 62
- Curve25519Point P = Curve25519Point.ZERO;
- P = P.add(proof.A);
- P = P.add(proof.S.scalarMultiply(x));
-
- // PAPER LINES 21-22
- // The inner product challenges are computed per round
- Scalar[] w = new Scalar[logMN];
- hashCache = hashToScalar(concat(hashCache.bytes,proof.L[0].toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.R[0].toBytes()));
- w[0] = hashCache;
- if (logMN > 1)
- {
- for (int i = 1; i < logMN; i++)
- {
- hashCache = hashToScalar(concat(hashCache.bytes,proof.L[i].toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.R[i].toBytes()));
- w[i] = hashCache;
- }
- }
-
- // Basically PAPER LINES 24-25
- // Compute the curvepoints from G[i] and H[i]
- Curve25519Point InnerProdG = Curve25519Point.ZERO;
- Curve25519Point InnerProdH = Curve25519Point.ZERO;
- for (int i = 0; i < M*N; i++)
- {
- // Convert the index to binary IN REVERSE and construct the scalar exponent
- int index = i;
- Scalar gScalar = proof.a;
- Scalar hScalar = proof.b.mul(Invert(y).pow(i));
-
- for (int j = logMN-1; j >= 0; j--)
- {
- int J = w.length - j - 1; // because this is done in reverse bit order
- int basePow = (int) Math.pow(2,j); // assumes we don't get too big
- if (index / basePow == 0) // bit is zero
- {
- gScalar = gScalar.mul(Invert(w[J]));
- hScalar = hScalar.mul(w[J]);
- }
- else // bit is one
- {
- gScalar = gScalar.mul(w[J]);
- hScalar = hScalar.mul(Invert(w[J]));
- index -= basePow;
- }
- }
-
- gScalar = gScalar.add(z);
- hScalar = hScalar.sub(z.mul(y.pow(i)).add(z.pow(2+i/N).mul(Scalar.TWO.pow(i%N))).mul(Invert(y).pow(i)));
-
- // Now compute the basepoint's scalar multiplication
- // Each of these could be written as a multiexp operation instead
- InnerProdG = InnerProdG.add(Gi[i].scalarMultiply(gScalar));
- InnerProdH = InnerProdH.add(Hi[i].scalarMultiply(hScalar));
- }
-
- // PAPER LINE 26
- Curve25519Point Pprime = P.add(G.scalarMultiply(Scalar.ZERO.sub(proof.mu)));
-
- for (int i = 0; i < logMN; i++)
- {
- Pprime = Pprime.add(proof.L[i].scalarMultiply(w[i].sq()));
- Pprime = Pprime.add(proof.R[i].scalarMultiply(Invert(w[i]).sq()));
- }
- Pprime = Pprime.add(H.scalarMultiply(proof.t.mul(x_ip)));
-
- if (!Pprime.equals(InnerProdG.add(InnerProdH).add(H.scalarMultiply(proof.a.mul(proof.b).mul(x_ip)))))
- return false;
-
- return true;
- }
-
- public static void main(String[] args)
- {
- // Test parameters
- N = 64; // number of bits in amount range (so amounts are 0..2^(N-1))
- M = 4; // number of outputs (must be a power of 2)
- logMN = 8; // must be manually set to log_2(MN)
- int TRIALS = 25; // number of randomized trials to run
-
- // Set the curve base points
- G = Curve25519Point.G;
- H = Curve25519Point.hashToPoint(G);
- Gi = new Curve25519Point[M*N];
- Hi = new Curve25519Point[M*N];
- for (int i = 0; i < M*N; i++)
- {
- Gi[i] = getHpnGLookup(2*i);
- Hi[i] = getHpnGLookup(2*i+1);
- }
-
- // Run a bunch of randomized trials
- Random rando = new Random();
- int count = 0;
-
- Scalar[] amounts = new Scalar[M];
- Scalar[] masks = new Scalar[M];
- while (count < TRIALS)
- {
- for (int j = 0; j < M; j++)
- {
- long amount = -1L;
- while (amount > Math.pow(2,N)-1 || amount < 0L)
- amount = rando.nextLong();
- amounts[j] = new Scalar(BigInteger.valueOf(amount));
- masks[j] = randomScalar();
- }
-
- ProofTuple proof = PROVE(amounts,masks);
- if (!VERIFY(proof))
- System.out.println("Test failed");
-
- count += 1;
- }
- }
-}
diff --git a/source-code/BulletProofs/OptimizedLogBulletproof.java b/source-code/BulletProofs/OptimizedLogBulletproof.java
deleted file mode 100644
index 6752fc7..0000000
--- a/source-code/BulletProofs/OptimizedLogBulletproof.java
+++ /dev/null
@@ -1,522 +0,0 @@
-// NOTE: this interchanges the roles of G and H to match other code's behavior
-
-package how.monero.hodl.bulletproof;
-
-import how.monero.hodl.crypto.Curve25519Point;
-import how.monero.hodl.crypto.Scalar;
-import how.monero.hodl.crypto.CryptoUtil;
-import java.math.BigInteger;
-import java.util.Random;
-
-import static how.monero.hodl.crypto.Scalar.randomScalar;
-import static how.monero.hodl.crypto.CryptoUtil.*;
-import static how.monero.hodl.util.ByteUtil.*;
-
-public class OptimizedLogBulletproof
-{
- private static int N;
- private static int logN;
- private static Curve25519Point G;
- private static Curve25519Point H;
- private static Curve25519Point[] Gi;
- private static Curve25519Point[] Hi;
-
- public static class ProofTuple
- {
- private Curve25519Point V;
- private Curve25519Point A;
- private Curve25519Point S;
- private Curve25519Point T1;
- private Curve25519Point T2;
- private Scalar taux;
- private Scalar mu;
- private Curve25519Point[] L;
- private Curve25519Point[] R;
- private Scalar a;
- private Scalar b;
- private Scalar t;
-
- public ProofTuple(Curve25519Point V, Curve25519Point A, Curve25519Point S, Curve25519Point T1, Curve25519Point T2, Scalar taux, Scalar mu, Curve25519Point[] L, Curve25519Point[] R, Scalar a, Scalar b, Scalar t)
- {
- this.V = V;
- this.A = A;
- this.S = S;
- this.T1 = T1;
- this.T2 = T2;
- this.taux = taux;
- this.mu = mu;
- this.L = L;
- this.R = R;
- this.a = a;
- this.b = b;
- this.t = t;
- }
- }
-
- /* Given two scalar arrays, construct a vector commitment */
- public static Curve25519Point VectorExponent(Scalar[] a, Scalar[] b)
- {
- assert a.length == N && b.length == N;
-
- Curve25519Point Result = Curve25519Point.ZERO;
- for (int i = 0; i < N; i++)
- {
- Result = Result.add(Gi[i].scalarMultiply(a[i]));
- Result = Result.add(Hi[i].scalarMultiply(b[i]));
- }
- return Result;
- }
-
- /* Compute a custom vector-scalar commitment */
- public static Curve25519Point VectorExponentCustom(Curve25519Point[] A, Curve25519Point[] B, Scalar[] a, Scalar[] b)
- {
- assert a.length == A.length && b.length == B.length && a.length == b.length;
-
- Curve25519Point Result = Curve25519Point.ZERO;
- for (int i = 0; i < a.length; i++)
- {
- Result = Result.add(A[i].scalarMultiply(a[i]));
- Result = Result.add(B[i].scalarMultiply(b[i]));
- }
- return Result;
- }
-
- /* Given a scalar, construct a vector of powers */
- public static Scalar[] VectorPowers(Scalar x)
- {
- Scalar[] result = new Scalar[N];
- for (int i = 0; i < N; i++)
- {
- result[i] = x.pow(i);
- }
- return result;
- }
-
- /* Given two scalar arrays, construct the inner product */
- public static Scalar InnerProduct(Scalar[] a, Scalar[] b)
- {
- assert a.length == b.length;
-
- Scalar result = Scalar.ZERO;
- for (int i = 0; i < a.length; i++)
- {
- result = result.add(a[i].mul(b[i]));
- }
- return result;
- }
-
- /* Given two scalar arrays, construct the Hadamard product */
- public static Scalar[] Hadamard(Scalar[] a, Scalar[] b)
- {
- assert a.length == b.length;
-
- Scalar[] result = new Scalar[a.length];
- for (int i = 0; i < a.length; i++)
- {
- result[i] = a[i].mul(b[i]);
- }
- return result;
- }
-
- /* Given two curvepoint arrays, construct the Hadamard product */
- public static Curve25519Point[] Hadamard2(Curve25519Point[] A, Curve25519Point[] B)
- {
- assert A.length == B.length;
-
- Curve25519Point[] Result = new Curve25519Point[A.length];
- for (int i = 0; i < A.length; i++)
- {
- Result[i] = A[i].add(B[i]);
- }
- return Result;
- }
-
- /* Add two vectors */
- public static Scalar[] VectorAdd(Scalar[] a, Scalar[] b)
- {
- assert a.length == b.length;
-
- Scalar[] result = new Scalar[a.length];
- for (int i = 0; i < a.length; i++)
- {
- result[i] = a[i].add(b[i]);
- }
- return result;
- }
-
- /* Subtract two vectors */
- public static Scalar[] VectorSubtract(Scalar[] a, Scalar[] b)
- {
- assert a.length == b.length;
-
- Scalar[] result = new Scalar[a.length];
- for (int i = 0; i < a.length; i++)
- {
- result[i] = a[i].sub(b[i]);
- }
- return result;
- }
-
- /* Multiply a scalar and a vector */
- public static Scalar[] VectorScalar(Scalar[] a, Scalar x)
- {
- Scalar[] result = new Scalar[a.length];
- for (int i = 0; i < a.length; i++)
- {
- result[i] = a[i].mul(x);
- }
- return result;
- }
-
- /* Exponentiate a curve vector by a scalar */
- public static Curve25519Point[] VectorScalar2(Curve25519Point[] A, Scalar x)
- {
- Curve25519Point[] Result = new Curve25519Point[A.length];
- for (int i = 0; i < A.length; i++)
- {
- Result[i] = A[i].scalarMultiply(x);
- }
- return Result;
- }
-
- /* Compute the inverse of a scalar, the stupid way */
- public static Scalar Invert(Scalar x)
- {
- Scalar inverse = new Scalar(x.toBigInteger().modInverse(CryptoUtil.l));
-
- assert x.mul(inverse).equals(Scalar.ONE);
- return inverse;
- }
-
- /* Compute the slice of a curvepoint vector */
- public static Curve25519Point[] CurveSlice(Curve25519Point[] a, int start, int stop)
- {
- Curve25519Point[] Result = new Curve25519Point[stop-start];
- for (int i = start; i < stop; i++)
- {
- Result[i-start] = a[i];
- }
- return Result;
- }
-
- /* Compute the slice of a scalar vector */
- public static Scalar[] ScalarSlice(Scalar[] a, int start, int stop)
- {
- Scalar[] result = new Scalar[stop-start];
- for (int i = start; i < stop; i++)
- {
- result[i-start] = a[i];
- }
- return result;
- }
-
- /* Compute the value of k(y,z) */
- public static Scalar ComputeK(Scalar y, Scalar z)
- {
- Scalar result = Scalar.ZERO;
- result = result.sub(z.sq().mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y))));
- result = result.sub(z.pow(3).mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(Scalar.TWO))));
-
- return result;
- }
-
- /* Given a value v (0..2^N-1) and a mask gamma, construct a range proof */
- public static ProofTuple PROVE(Scalar v, Scalar gamma)
- {
- Curve25519Point V = H.scalarMultiply(v).add(G.scalarMultiply(gamma));
-
- // This hash is updated for Fiat-Shamir throughout the proof
- Scalar hashCache = hashToScalar(V.toBytes());
-
- // PAPER LINES 36-37
- Scalar[] aL = new Scalar[N];
- Scalar[] aR = new Scalar[N];
-
- BigInteger tempV = v.toBigInteger();
- for (int i = N-1; i >= 0; i--)
- {
- BigInteger basePow = BigInteger.valueOf(2).pow(i);
- if (tempV.divide(basePow).equals(BigInteger.ZERO))
- {
- aL[i] = Scalar.ZERO;
- }
- else
- {
- aL[i] = Scalar.ONE;
- tempV = tempV.subtract(basePow);
- }
-
- aR[i] = aL[i].sub(Scalar.ONE);
- }
-
- // PAPER LINES 38-39
- Scalar alpha = randomScalar();
- Curve25519Point A = VectorExponent(aL,aR).add(G.scalarMultiply(alpha));
-
- // PAPER LINES 40-42
- Scalar[] sL = new Scalar[N];
- Scalar[] sR = new Scalar[N];
- for (int i = 0; i < N; i++)
- {
- sL[i] = randomScalar();
- sR[i] = randomScalar();
- }
- Scalar rho = randomScalar();
- Curve25519Point S = VectorExponent(sL,sR).add(G.scalarMultiply(rho));
-
- // PAPER LINES 43-45
- hashCache = hashToScalar(concat(hashCache.bytes,A.toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,S.toBytes()));
- Scalar y = hashCache;
- hashCache = hashToScalar(hashCache.bytes);
- Scalar z = hashCache;
-
- // Polynomial construction before PAPER LINE 46
- Scalar t0 = Scalar.ZERO;
- Scalar t1 = Scalar.ZERO;
- Scalar t2 = Scalar.ZERO;
-
- t0 = t0.add(z.mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y))));
- t0 = t0.add(z.sq().mul(v));
- Scalar k = ComputeK(y,z);
- t0 = t0.add(k);
-
- t1 = t1.add(InnerProduct(VectorSubtract(aL,VectorScalar(VectorPowers(Scalar.ONE),z)),Hadamard(VectorPowers(y),sR)));
- t1 = t1.add(InnerProduct(sL,VectorAdd(Hadamard(VectorPowers(y),VectorAdd(aR,VectorScalar(VectorPowers(Scalar.ONE),z))),VectorScalar(VectorPowers(Scalar.TWO),z.sq()))));
-
- t2 = t2.add(InnerProduct(sL,Hadamard(VectorPowers(y),sR)));
-
- // PAPER LINES 47-48
- Scalar tau1 = randomScalar();
- Scalar tau2 = randomScalar();
- Curve25519Point T1 = H.scalarMultiply(t1).add(G.scalarMultiply(tau1));
- Curve25519Point T2 = H.scalarMultiply(t2).add(G.scalarMultiply(tau2));
-
- // PAPER LINES 49-51
- hashCache = hashToScalar(concat(hashCache.bytes,z.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,T1.toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,T2.toBytes()));
- Scalar x = hashCache;
-
- // PAPER LINES 52-53
- Scalar taux = Scalar.ZERO;
- taux = tau1.mul(x);
- taux = taux.add(tau2.mul(x.sq()));
- taux = taux.add(gamma.mul(z.sq()));
- Scalar mu = x.mul(rho).add(alpha);
-
- // PAPER LINES 54-57
- Scalar[] l = new Scalar[N];
- Scalar[] r = new Scalar[N];
-
- l = VectorAdd(VectorSubtract(aL,VectorScalar(VectorPowers(Scalar.ONE),z)),VectorScalar(sL,x));
- r = VectorAdd(Hadamard(VectorPowers(y),VectorAdd(aR,VectorAdd(VectorScalar(VectorPowers(Scalar.ONE),z),VectorScalar(sR,x)))),VectorScalar(VectorPowers(Scalar.TWO),z.sq()));
-
- Scalar t = InnerProduct(l,r);
-
- // PAPER LINES 32-33
- hashCache = hashToScalar(concat(hashCache.bytes,x.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,taux.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,mu.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,t.bytes));
- Scalar x_ip = hashCache;
-
- // These are used in the inner product rounds
- int nprime = N;
- Curve25519Point[] Gprime = new Curve25519Point[N];
- Curve25519Point[] Hprime = new Curve25519Point[N];
- Scalar[] aprime = new Scalar[N];
- Scalar[] bprime = new Scalar[N];
- for (int i = 0; i < N; i++)
- {
- Gprime[i] = Gi[i];
- Hprime[i] = Hi[i].scalarMultiply(Invert(y).pow(i));
- aprime[i] = l[i];
- bprime[i] = r[i];
- }
- Curve25519Point[] L = new Curve25519Point[logN];
- Curve25519Point[] R = new Curve25519Point[logN];
- int round = 0; // track the index based on number of rounds
- Scalar[] w = new Scalar[logN]; // this is the challenge x in the inner product protocol
-
- // PAPER LINE 13
- while (nprime > 1)
- {
- // PAPER LINE 15
- nprime /= 2;
-
- // PAPER LINES 16-17
- Scalar cL = InnerProduct(ScalarSlice(aprime,0,nprime),ScalarSlice(bprime,nprime,bprime.length));
- Scalar cR = InnerProduct(ScalarSlice(aprime,nprime,aprime.length),ScalarSlice(bprime,0,nprime));
-
- // PAPER LINES 18-19
- L[round] = VectorExponentCustom(CurveSlice(Gprime,nprime,Gprime.length),CurveSlice(Hprime,0,nprime),ScalarSlice(aprime,0,nprime),ScalarSlice(bprime,nprime,bprime.length)).add(H.scalarMultiply(cL.mul(x_ip)));
- R[round] = VectorExponentCustom(CurveSlice(Gprime,0,nprime),CurveSlice(Hprime,nprime,Hprime.length),ScalarSlice(aprime,nprime,aprime.length),ScalarSlice(bprime,0,nprime)).add(H.scalarMultiply(cR.mul(x_ip)));
-
- // PAPER LINES 21-22
- hashCache = hashToScalar(concat(hashCache.bytes,L[round].toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,R[round].toBytes()));
- w[round] = hashCache;
-
- // PAPER LINES 24-25
- Gprime = Hadamard2(VectorScalar2(CurveSlice(Gprime,0,nprime),Invert(w[round])),VectorScalar2(CurveSlice(Gprime,nprime,Gprime.length),w[round]));
- Hprime = Hadamard2(VectorScalar2(CurveSlice(Hprime,0,nprime),w[round]),VectorScalar2(CurveSlice(Hprime,nprime,Hprime.length),Invert(w[round])));
-
- // PAPER LINES 28-29
- aprime = VectorAdd(VectorScalar(ScalarSlice(aprime,0,nprime),w[round]),VectorScalar(ScalarSlice(aprime,nprime,aprime.length),Invert(w[round])));
- bprime = VectorAdd(VectorScalar(ScalarSlice(bprime,0,nprime),Invert(w[round])),VectorScalar(ScalarSlice(bprime,nprime,bprime.length),w[round]));
-
- round += 1;
- }
-
- // PAPER LINE 58 (with inclusions from PAPER LINE 8 and PAPER LINE 20)
- return new ProofTuple(V,A,S,T1,T2,taux,mu,L,R,aprime[0],bprime[0],t);
- }
-
- /* Given a range proof, determine if it is valid */
- public static boolean VERIFY(ProofTuple proof)
- {
- // Reconstruct the challenges
- Scalar hashCache = hashToScalar(proof.V.toBytes());
- hashCache = hashToScalar(concat(hashCache.bytes,proof.A.toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.S.toBytes()));
- Scalar y = hashCache;
- hashCache = hashToScalar(hashCache.bytes);
- Scalar z = hashCache;
- hashCache = hashToScalar(concat(hashCache.bytes,z.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.T1.toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.T2.toBytes()));
- Scalar x = hashCache;
- hashCache = hashToScalar(concat(hashCache.bytes,x.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.taux.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.mu.bytes));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.t.bytes));
- Scalar x_ip = hashCache;
-
- // PAPER LINE 61
- Curve25519Point L61Left = G.scalarMultiply(proof.taux).add(H.scalarMultiply(proof.t));
-
- Scalar k = ComputeK(y,z);
-
- Curve25519Point L61Right = H.scalarMultiply(k.add(z.mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y)))));
- L61Right = L61Right.add(proof.V.scalarMultiply(z.sq()));
- L61Right = L61Right.add(proof.T1.scalarMultiply(x));
- L61Right = L61Right.add(proof.T2.scalarMultiply(x.sq()));
-
- if (!L61Right.equals(L61Left))
- return false;
-
- // PAPER LINE 62
- Curve25519Point P = Curve25519Point.ZERO;
- P = P.add(proof.A);
- P = P.add(proof.S.scalarMultiply(x));
-
- // Compute the number of rounds for the inner product
- int rounds = proof.L.length;
-
- // PAPER LINES 21-22
- // The inner product challenges are computed per round
- Scalar[] w = new Scalar[rounds];
- hashCache = hashToScalar(concat(hashCache.bytes,proof.L[0].toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.R[0].toBytes()));
- w[0] = hashCache;
- if (rounds > 1)
- {
- for (int i = 1; i < rounds; i++)
- {
- hashCache = hashToScalar(concat(hashCache.bytes,proof.L[i].toBytes()));
- hashCache = hashToScalar(concat(hashCache.bytes,proof.R[i].toBytes()));
- w[i] = hashCache;
- }
- }
-
- // Basically PAPER LINES 24-25
- // Compute the curvepoints from G[i] and H[i]
- Curve25519Point InnerProdG = Curve25519Point.ZERO;
- Curve25519Point InnerProdH = Curve25519Point.ZERO;
- for (int i = 0; i < N; i++)
- {
- // Convert the index to binary IN REVERSE and construct the scalar exponent
- int index = i;
- Scalar gScalar = proof.a;
- Scalar hScalar = proof.b.mul(Invert(y).pow(i));
-
- for (int j = rounds-1; j >= 0; j--)
- {
- int J = w.length - j - 1; // because this is done in reverse bit order
- int basePow = (int) Math.pow(2,j); // assumes we don't get too big
- if (index / basePow == 0) // bit is zero
- {
- gScalar = gScalar.mul(Invert(w[J]));
- hScalar = hScalar.mul(w[J]);
- }
- else // bit is one
- {
- gScalar = gScalar.mul(w[J]);
- hScalar = hScalar.mul(Invert(w[J]));
- index -= basePow;
- }
- }
-
- // Adjust the scalars using the exponents from PAPER LINE 62
- gScalar = gScalar.add(z);
- hScalar = hScalar.sub(z.mul(y.pow(i)).add(z.sq().mul(Scalar.TWO.pow(i))).mul(Invert(y).pow(i)));
-
- // Now compute the basepoint's scalar multiplication
- // Each of these could be written as a multiexp operation instead
- InnerProdG = InnerProdG.add(Gi[i].scalarMultiply(gScalar));
- InnerProdH = InnerProdH.add(Hi[i].scalarMultiply(hScalar));
- }
-
- // PAPER LINE 26
- Curve25519Point Pprime = P.add(G.scalarMultiply(Scalar.ZERO.sub(proof.mu)));
-
- for (int i = 0; i < rounds; i++)
- {
- Pprime = Pprime.add(proof.L[i].scalarMultiply(w[i].sq()));
- Pprime = Pprime.add(proof.R[i].scalarMultiply(Invert(w[i]).sq()));
- }
- Pprime = Pprime.add(H.scalarMultiply(proof.t.mul(x_ip)));
-
- if (!Pprime.equals(InnerProdG.add(InnerProdH).add(H.scalarMultiply(proof.a.mul(proof.b).mul(x_ip)))))
- return false;
-
- return true;
- }
-
- public static void main(String[] args)
- {
- // Number of bits in the range
- N = 64;
- logN = 6; // its log, manually
-
- // Set the curve base points
- G = Curve25519Point.G;
- H = Curve25519Point.hashToPoint(G);
- Gi = new Curve25519Point[N];
- Hi = new Curve25519Point[N];
- for (int i = 0; i < N; i++)
- {
- Gi[i] = getHpnGLookup(2*i);
- Hi[i] = getHpnGLookup(2*i+1);
- }
-
- // Run a bunch of randomized trials
- Random rando = new Random();
- int TRIALS = 250;
- int count = 0;
-
- while (count < TRIALS)
- {
- long amount = rando.nextLong();
- if (amount > Math.pow(2,N)-1 || amount < 0)
- continue;
-
- ProofTuple proof = PROVE(new Scalar(BigInteger.valueOf(amount)),randomScalar());
- if (!VERIFY(proof))
- System.out.println("Test failed");
-
- count += 1;
- }
- }
-}
diff --git a/source-code/StringCT-java/src/how/monero/hodl/bulletproof/LinearBulletproof.java b/source-code/StringCT-java/src/how/monero/hodl/bulletproof/LinearBulletproof.java
index 42c1d8a..f33913e 100644
--- a/source-code/StringCT-java/src/how/monero/hodl/bulletproof/LinearBulletproof.java
+++ b/source-code/StringCT-java/src/how/monero/hodl/bulletproof/LinearBulletproof.java
@@ -1,3 +1,5 @@
+// NOTE: this interchanges the roles of G and H to match other code's behavior
+
package how.monero.hodl.bulletproof;
import how.monero.hodl.crypto.Curve25519Point;
@@ -133,10 +135,23 @@ public class LinearBulletproof
return inverse;
}
+ /* Compute the value of k(y,z) */
+ public static Scalar ComputeK(Scalar y, Scalar z)
+ {
+ Scalar result = Scalar.ZERO;
+ result = result.sub(z.sq().mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y))));
+ result = result.sub(z.pow(3).mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(Scalar.TWO))));
+
+ return result;
+ }
+
/* Given a value v (0..2^N-1) and a mask gamma, construct a range proof */
public static ProofTuple PROVE(Scalar v, Scalar gamma)
{
- Curve25519Point V = G.scalarMultiply(v).add(H.scalarMultiply(gamma));
+ Curve25519Point V = H.scalarMultiply(v).add(G.scalarMultiply(gamma));
+
+ // This hash is updated for Fiat-Shamir throughout the proof
+ Scalar hashCache = hashToScalar(V.toBytes());
// PAPER LINES 36-37
Scalar[] aL = new Scalar[N];
@@ -174,7 +189,7 @@ public class LinearBulletproof
// PAPER LINES 38-39
Scalar alpha = randomScalar();
- Curve25519Point A = VectorExponent(aL,aR).add(H.scalarMultiply(alpha));
+ Curve25519Point A = VectorExponent(aL,aR).add(G.scalarMultiply(alpha));
// PAPER LINES 40-42
Scalar[] sL = new Scalar[N];
@@ -185,11 +200,14 @@ public class LinearBulletproof
sR[i] = randomScalar();
}
Scalar rho = randomScalar();
- Curve25519Point S = VectorExponent(sL,sR).add(H.scalarMultiply(rho));
+ Curve25519Point S = VectorExponent(sL,sR).add(G.scalarMultiply(rho));
// PAPER LINES 43-45
- Scalar y = hashToScalar(concat(A.toBytes(),S.toBytes()));
- Scalar z = hashToScalar(y.bytes);
+ hashCache = hashToScalar(concat(hashCache.bytes,A.toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,S.toBytes()));
+ Scalar y = hashCache;
+ hashCache = hashToScalar(hashCache.bytes);
+ Scalar z = hashCache;
Scalar t0 = Scalar.ZERO;
Scalar t1 = Scalar.ZERO;
@@ -197,9 +215,7 @@ public class LinearBulletproof
t0 = t0.add(z.mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y))));
t0 = t0.add(z.sq().mul(v));
- Scalar k = Scalar.ZERO;
- k = k.sub(z.sq().mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y))));
- k = k.sub(z.pow(3).mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(Scalar.TWO))));
+ Scalar k = ComputeK(y,z);
t0 = t0.add(k);
// DEBUG: Test the value of t0 has the correct form
@@ -217,11 +233,14 @@ public class LinearBulletproof
// PAPER LINES 47-48
Scalar tau1 = randomScalar();
Scalar tau2 = randomScalar();
- Curve25519Point T1 = G.scalarMultiply(t1).add(H.scalarMultiply(tau1));
- Curve25519Point T2 = G.scalarMultiply(t2).add(H.scalarMultiply(tau2));
+ Curve25519Point T1 = H.scalarMultiply(t1).add(G.scalarMultiply(tau1));
+ Curve25519Point T2 = H.scalarMultiply(t2).add(G.scalarMultiply(tau2));
// PAPER LINES 49-51
- Scalar x = hashToScalar(concat(z.bytes,T1.toBytes(),T2.toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,z.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,T1.toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,T2.toBytes()));
+ Scalar x = hashCache;
// PAPER LINES 52-53
Scalar taux = Scalar.ZERO;
@@ -251,21 +270,26 @@ public class LinearBulletproof
public static boolean VERIFY(ProofTuple proof)
{
// Reconstruct the challenges
- Scalar y = hashToScalar(concat(proof.A.toBytes(),proof.S.toBytes()));
- Scalar z = hashToScalar(y.bytes);
- Scalar x = hashToScalar(concat(z.bytes,proof.T1.toBytes(),proof.T2.toBytes()));
+ Scalar hashCache = hashToScalar(proof.V.toBytes());
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.A.toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.S.toBytes()));
+ Scalar y = hashCache;
+ hashCache = hashToScalar(hashCache.bytes);
+ Scalar z = hashCache;
+ hashCache = hashToScalar(concat(hashCache.bytes,z.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.T1.toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.T2.toBytes()));
+ Scalar x = hashCache;
// PAPER LINE 60
Scalar t = InnerProduct(proof.l,proof.r);
// PAPER LINE 61
- Curve25519Point L61Left = H.scalarMultiply(proof.taux).add(G.scalarMultiply(t));
+ Curve25519Point L61Left = G.scalarMultiply(proof.taux).add(H.scalarMultiply(t));
- Scalar k = Scalar.ZERO;
- k = k.sub(z.sq().mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y))));
- k = k.sub(z.pow(3).mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(Scalar.TWO))));
+ Scalar k = ComputeK(y,z);
- Curve25519Point L61Right = G.scalarMultiply(k.add(z.mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y)))));
+ Curve25519Point L61Right = H.scalarMultiply(k.add(z.mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y)))));
L61Right = L61Right.add(proof.V.scalarMultiply(z.sq()));
L61Right = L61Right.add(proof.T1.scalarMultiply(x));
L61Right = L61Right.add(proof.T2.scalarMultiply(x.sq()));
@@ -301,7 +325,7 @@ public class LinearBulletproof
Hexp[i] = Hexp[i].add(proof.r[i]);
Hexp[i] = Hexp[i].mul(Invert(y).pow(i));
}
- Curve25519Point L63Right = VectorExponent(proof.l,Hexp).add(H.scalarMultiply(proof.mu));
+ Curve25519Point L63Right = VectorExponent(proof.l,Hexp).add(G.scalarMultiply(proof.mu));
if (!L63Right.equals(P))
{
@@ -323,8 +347,8 @@ public class LinearBulletproof
Hi = new Curve25519Point[N];
for (int i = 0; i < N; i++)
{
- Gi[i] = getHpnGLookup(i);
- Hi[i] = getHpnGLookup(N+i);
+ Gi[i] = getHpnGLookup(2*i);
+ Hi[i] = getHpnGLookup(2*i+1);
}
// Run a bunch of randomized trials
diff --git a/source-code/StringCT-java/src/how/monero/hodl/bulletproof/LogBulletproof.java b/source-code/StringCT-java/src/how/monero/hodl/bulletproof/LogBulletproof.java
index cf1cda7..7061cd9 100644
--- a/source-code/StringCT-java/src/how/monero/hodl/bulletproof/LogBulletproof.java
+++ b/source-code/StringCT-java/src/how/monero/hodl/bulletproof/LogBulletproof.java
@@ -1,3 +1,5 @@
+// NOTE: this interchanges the roles of G and H to match other code's behavior
+
package how.monero.hodl.bulletproof;
import how.monero.hodl.crypto.Curve25519Point;
@@ -208,10 +210,23 @@ public class LogBulletproof
return result;
}
+ /* Compute the value of k(y,z) */
+ public static Scalar ComputeK(Scalar y, Scalar z)
+ {
+ Scalar result = Scalar.ZERO;
+ result = result.sub(z.sq().mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y))));
+ result = result.sub(z.pow(3).mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(Scalar.TWO))));
+
+ return result;
+ }
+
/* Given a value v (0..2^N-1) and a mask gamma, construct a range proof */
public static ProofTuple PROVE(Scalar v, Scalar gamma)
{
- Curve25519Point V = G.scalarMultiply(v).add(H.scalarMultiply(gamma));
+ Curve25519Point V = H.scalarMultiply(v).add(G.scalarMultiply(gamma));
+
+ // This hash is updated for Fiat-Shamir throughout the proof
+ Scalar hashCache = hashToScalar(V.toBytes());
// PAPER LINES 36-37
Scalar[] aL = new Scalar[N];
@@ -236,7 +251,7 @@ public class LogBulletproof
// PAPER LINES 38-39
Scalar alpha = randomScalar();
- Curve25519Point A = VectorExponent(aL,aR).add(H.scalarMultiply(alpha));
+ Curve25519Point A = VectorExponent(aL,aR).add(G.scalarMultiply(alpha));
// PAPER LINES 40-42
Scalar[] sL = new Scalar[N];
@@ -247,11 +262,14 @@ public class LogBulletproof
sR[i] = randomScalar();
}
Scalar rho = randomScalar();
- Curve25519Point S = VectorExponent(sL,sR).add(H.scalarMultiply(rho));
+ Curve25519Point S = VectorExponent(sL,sR).add(G.scalarMultiply(rho));
// PAPER LINES 43-45
- Scalar y = hashToScalar(concat(A.toBytes(),S.toBytes()));
- Scalar z = hashToScalar(y.bytes);
+ hashCache = hashToScalar(concat(hashCache.bytes,A.toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,S.toBytes()));
+ Scalar y = hashCache;
+ hashCache = hashToScalar(hashCache.bytes);
+ Scalar z = hashCache;
// Polynomial construction before PAPER LINE 46
Scalar t0 = Scalar.ZERO;
@@ -260,9 +278,7 @@ public class LogBulletproof
t0 = t0.add(z.mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y))));
t0 = t0.add(z.sq().mul(v));
- Scalar k = Scalar.ZERO;
- k = k.sub(z.sq().mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y))));
- k = k.sub(z.pow(3).mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(Scalar.TWO))));
+ Scalar k = ComputeK(y,z);
t0 = t0.add(k);
t1 = t1.add(InnerProduct(VectorSubtract(aL,VectorScalar(VectorPowers(Scalar.ONE),z)),Hadamard(VectorPowers(y),sR)));
@@ -273,11 +289,14 @@ public class LogBulletproof
// PAPER LINES 47-48
Scalar tau1 = randomScalar();
Scalar tau2 = randomScalar();
- Curve25519Point T1 = G.scalarMultiply(t1).add(H.scalarMultiply(tau1));
- Curve25519Point T2 = G.scalarMultiply(t2).add(H.scalarMultiply(tau2));
+ Curve25519Point T1 = H.scalarMultiply(t1).add(G.scalarMultiply(tau1));
+ Curve25519Point T2 = H.scalarMultiply(t2).add(G.scalarMultiply(tau2));
// PAPER LINES 49-51
- Scalar x = hashToScalar(concat(z.bytes,T1.toBytes(),T2.toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,z.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,T1.toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,T2.toBytes()));
+ Scalar x = hashCache;
// PAPER LINES 52-53
Scalar taux = Scalar.ZERO;
@@ -296,7 +315,11 @@ public class LogBulletproof
Scalar t = InnerProduct(l,r);
// PAPER LINES 32-33
- Scalar x_ip = hashToScalar(concat(x.bytes,taux.bytes,mu.bytes,t.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,x.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,taux.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,mu.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,t.bytes));
+ Scalar x_ip = hashCache;
// These are used in the inner product rounds
int nprime = N;
@@ -327,14 +350,13 @@ public class LogBulletproof
Scalar cR = InnerProduct(ScalarSlice(aprime,nprime,aprime.length),ScalarSlice(bprime,0,nprime));
// PAPER LINES 18-19
- L[round] = VectorExponentCustom(CurveSlice(Gprime,nprime,Gprime.length),CurveSlice(Hprime,0,nprime),ScalarSlice(aprime,0,nprime),ScalarSlice(bprime,nprime,bprime.length)).add(G.scalarMultiply(cL.mul(x_ip)));
- R[round] = VectorExponentCustom(CurveSlice(Gprime,0,nprime),CurveSlice(Hprime,nprime,Hprime.length),ScalarSlice(aprime,nprime,aprime.length),ScalarSlice(bprime,0,nprime)).add(G.scalarMultiply(cR.mul(x_ip)));
+ L[round] = VectorExponentCustom(CurveSlice(Gprime,nprime,Gprime.length),CurveSlice(Hprime,0,nprime),ScalarSlice(aprime,0,nprime),ScalarSlice(bprime,nprime,bprime.length)).add(H.scalarMultiply(cL.mul(x_ip)));
+ R[round] = VectorExponentCustom(CurveSlice(Gprime,0,nprime),CurveSlice(Hprime,nprime,Hprime.length),ScalarSlice(aprime,nprime,aprime.length),ScalarSlice(bprime,0,nprime)).add(H.scalarMultiply(cR.mul(x_ip)));
// PAPER LINES 21-22
- if (round == 0)
- w[0] = hashToScalar(concat(L[0].toBytes(),R[0].toBytes()));
- else
- w[round] = hashToScalar(concat(w[round-1].bytes,L[round].toBytes(),R[round].toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,L[round].toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,R[round].toBytes()));
+ w[round] = hashCache;
// PAPER LINES 24-25
Gprime = Hadamard2(VectorScalar2(CurveSlice(Gprime,0,nprime),Invert(w[round])),VectorScalar2(CurveSlice(Gprime,nprime,Gprime.length),w[round]));
@@ -355,19 +377,28 @@ public class LogBulletproof
public static boolean VERIFY(ProofTuple proof)
{
// Reconstruct the challenges
- Scalar y = hashToScalar(concat(proof.A.toBytes(),proof.S.toBytes()));
- Scalar z = hashToScalar(y.bytes);
- Scalar x = hashToScalar(concat(z.bytes,proof.T1.toBytes(),proof.T2.toBytes()));
- Scalar x_ip = hashToScalar(concat(x.bytes,proof.taux.bytes,proof.mu.bytes,proof.t.bytes));
+ Scalar hashCache = hashToScalar(proof.V.toBytes());
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.A.toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.S.toBytes()));
+ Scalar y = hashCache;
+ hashCache = hashToScalar(hashCache.bytes);
+ Scalar z = hashCache;
+ hashCache = hashToScalar(concat(hashCache.bytes,z.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.T1.toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.T2.toBytes()));
+ Scalar x = hashCache;
+ hashCache = hashToScalar(concat(hashCache.bytes,x.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.taux.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.mu.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.t.bytes));
+ Scalar x_ip = hashCache;
// PAPER LINE 61
- Curve25519Point L61Left = H.scalarMultiply(proof.taux).add(G.scalarMultiply(proof.t));
+ Curve25519Point L61Left = G.scalarMultiply(proof.taux).add(H.scalarMultiply(proof.t));
- Scalar k = Scalar.ZERO;
- k = k.sub(z.sq().mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y))));
- k = k.sub(z.pow(3).mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(Scalar.TWO))));
+ Scalar k = ComputeK(y,z);
- Curve25519Point L61Right = G.scalarMultiply(k.add(z.mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y)))));
+ Curve25519Point L61Right = H.scalarMultiply(k.add(z.mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y)))));
L61Right = L61Right.add(proof.V.scalarMultiply(z.sq()));
L61Right = L61Right.add(proof.T1.scalarMultiply(x));
L61Right = L61Right.add(proof.T2.scalarMultiply(x.sq()));
@@ -400,12 +431,16 @@ public class LogBulletproof
// PAPER LINES 21-22
// The inner product challenges are computed per round
Scalar[] w = new Scalar[rounds];
- w[0] = hashToScalar(concat(proof.L[0].toBytes(),proof.R[0].toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.L[0].toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.R[0].toBytes()));
+ w[0] = hashCache;
if (rounds > 1)
{
for (int i = 1; i < rounds; i++)
{
- w[i] = hashToScalar(concat(w[i-1].bytes,proof.L[i].toBytes(),proof.R[i].toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.L[i].toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.R[i].toBytes()));
+ w[i] = hashCache;
}
}
@@ -444,16 +479,16 @@ public class LogBulletproof
}
// PAPER LINE 26
- Curve25519Point Pprime = P.add(H.scalarMultiply(Scalar.ZERO.sub(proof.mu)));
+ Curve25519Point Pprime = P.add(G.scalarMultiply(Scalar.ZERO.sub(proof.mu)));
for (int i = 0; i < rounds; i++)
{
Pprime = Pprime.add(proof.L[i].scalarMultiply(w[i].sq()));
Pprime = Pprime.add(proof.R[i].scalarMultiply(Invert(w[i]).sq()));
}
- Pprime = Pprime.add(G.scalarMultiply(proof.t.mul(x_ip)));
+ Pprime = Pprime.add(H.scalarMultiply(proof.t.mul(x_ip)));
- if (!Pprime.equals(InnerProdG.scalarMultiply(proof.a).add(InnerProdH.scalarMultiply(proof.b)).add(G.scalarMultiply(proof.a.mul(proof.b).mul(x_ip)))))
+ if (!Pprime.equals(InnerProdG.scalarMultiply(proof.a).add(InnerProdH.scalarMultiply(proof.b)).add(H.scalarMultiply(proof.a.mul(proof.b).mul(x_ip)))))
return false;
return true;
@@ -472,8 +507,8 @@ public class LogBulletproof
Hi = new Curve25519Point[N];
for (int i = 0; i < N; i++)
{
- Gi[i] = getHpnGLookup(i);
- Hi[i] = getHpnGLookup(N+i);
+ Gi[i] = getHpnGLookup(2*i);
+ Hi[i] = getHpnGLookup(2*i+1);
}
// Run a bunch of randomized trials
diff --git a/source-code/StringCT-java/src/how/monero/hodl/bulletproof/MultiBulletproof.java b/source-code/StringCT-java/src/how/monero/hodl/bulletproof/MultiBulletproof.java
new file mode 100644
index 0000000..8e9e381
--- /dev/null
+++ b/source-code/StringCT-java/src/how/monero/hodl/bulletproof/MultiBulletproof.java
@@ -0,0 +1,721 @@
+
+
+
(2) Inbox | surae.noether@protonmail.com | ProtonMail
Request timed out, please try again. Try again
+ From : Sarang Noether <sarang.noether@protonmail.com>
February 7, 2018 12:53 PM 02/07/2018 (a day ago)
To : Surae Noether
Move to inbox Move to trash Mark as unread Mark as spam View source code View rendered HTML View headers Print
Show details Hide details Please make the following change to the repo.
- In the (.../hodl/bulletproof) directory that now contains the moved files, replace MultiBulletproof.java with the new attached version. The commit message for these three steps should state something like "batch verification, optimizations, and directory reorganization".
- Add the new MRL-XXXX technical note files to wherever those live.
- Party on.
SN
70.20 KB 2 files attached
+
+
ProtonMail requires Javascript. Enable Javascript and reload this page to continue.
+
\ No newline at end of file
diff --git a/source-code/StringCT-java/src/how/monero/hodl/bulletproof/OptimizedLogBulletproof.java b/source-code/StringCT-java/src/how/monero/hodl/bulletproof/OptimizedLogBulletproof.java
index 6b2acde..6752fc7 100644
--- a/source-code/StringCT-java/src/how/monero/hodl/bulletproof/OptimizedLogBulletproof.java
+++ b/source-code/StringCT-java/src/how/monero/hodl/bulletproof/OptimizedLogBulletproof.java
@@ -1,3 +1,5 @@
+// NOTE: this interchanges the roles of G and H to match other code's behavior
+
package how.monero.hodl.bulletproof;
import how.monero.hodl.crypto.Curve25519Point;
@@ -208,10 +210,23 @@ public class OptimizedLogBulletproof
return result;
}
+ /* Compute the value of k(y,z) */
+ public static Scalar ComputeK(Scalar y, Scalar z)
+ {
+ Scalar result = Scalar.ZERO;
+ result = result.sub(z.sq().mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y))));
+ result = result.sub(z.pow(3).mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(Scalar.TWO))));
+
+ return result;
+ }
+
/* Given a value v (0..2^N-1) and a mask gamma, construct a range proof */
public static ProofTuple PROVE(Scalar v, Scalar gamma)
{
- Curve25519Point V = G.scalarMultiply(v).add(H.scalarMultiply(gamma));
+ Curve25519Point V = H.scalarMultiply(v).add(G.scalarMultiply(gamma));
+
+ // This hash is updated for Fiat-Shamir throughout the proof
+ Scalar hashCache = hashToScalar(V.toBytes());
// PAPER LINES 36-37
Scalar[] aL = new Scalar[N];
@@ -236,7 +251,7 @@ public class OptimizedLogBulletproof
// PAPER LINES 38-39
Scalar alpha = randomScalar();
- Curve25519Point A = VectorExponent(aL,aR).add(H.scalarMultiply(alpha));
+ Curve25519Point A = VectorExponent(aL,aR).add(G.scalarMultiply(alpha));
// PAPER LINES 40-42
Scalar[] sL = new Scalar[N];
@@ -247,11 +262,14 @@ public class OptimizedLogBulletproof
sR[i] = randomScalar();
}
Scalar rho = randomScalar();
- Curve25519Point S = VectorExponent(sL,sR).add(H.scalarMultiply(rho));
+ Curve25519Point S = VectorExponent(sL,sR).add(G.scalarMultiply(rho));
// PAPER LINES 43-45
- Scalar y = hashToScalar(concat(A.toBytes(),S.toBytes()));
- Scalar z = hashToScalar(y.bytes);
+ hashCache = hashToScalar(concat(hashCache.bytes,A.toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,S.toBytes()));
+ Scalar y = hashCache;
+ hashCache = hashToScalar(hashCache.bytes);
+ Scalar z = hashCache;
// Polynomial construction before PAPER LINE 46
Scalar t0 = Scalar.ZERO;
@@ -260,9 +278,7 @@ public class OptimizedLogBulletproof
t0 = t0.add(z.mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y))));
t0 = t0.add(z.sq().mul(v));
- Scalar k = Scalar.ZERO;
- k = k.sub(z.sq().mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y))));
- k = k.sub(z.pow(3).mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(Scalar.TWO))));
+ Scalar k = ComputeK(y,z);
t0 = t0.add(k);
t1 = t1.add(InnerProduct(VectorSubtract(aL,VectorScalar(VectorPowers(Scalar.ONE),z)),Hadamard(VectorPowers(y),sR)));
@@ -273,11 +289,14 @@ public class OptimizedLogBulletproof
// PAPER LINES 47-48
Scalar tau1 = randomScalar();
Scalar tau2 = randomScalar();
- Curve25519Point T1 = G.scalarMultiply(t1).add(H.scalarMultiply(tau1));
- Curve25519Point T2 = G.scalarMultiply(t2).add(H.scalarMultiply(tau2));
+ Curve25519Point T1 = H.scalarMultiply(t1).add(G.scalarMultiply(tau1));
+ Curve25519Point T2 = H.scalarMultiply(t2).add(G.scalarMultiply(tau2));
// PAPER LINES 49-51
- Scalar x = hashToScalar(concat(z.bytes,T1.toBytes(),T2.toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,z.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,T1.toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,T2.toBytes()));
+ Scalar x = hashCache;
// PAPER LINES 52-53
Scalar taux = Scalar.ZERO;
@@ -296,7 +315,11 @@ public class OptimizedLogBulletproof
Scalar t = InnerProduct(l,r);
// PAPER LINES 32-33
- Scalar x_ip = hashToScalar(concat(x.bytes,taux.bytes,mu.bytes,t.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,x.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,taux.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,mu.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,t.bytes));
+ Scalar x_ip = hashCache;
// These are used in the inner product rounds
int nprime = N;
@@ -327,14 +350,13 @@ public class OptimizedLogBulletproof
Scalar cR = InnerProduct(ScalarSlice(aprime,nprime,aprime.length),ScalarSlice(bprime,0,nprime));
// PAPER LINES 18-19
- L[round] = VectorExponentCustom(CurveSlice(Gprime,nprime,Gprime.length),CurveSlice(Hprime,0,nprime),ScalarSlice(aprime,0,nprime),ScalarSlice(bprime,nprime,bprime.length)).add(G.scalarMultiply(cL.mul(x_ip)));
- R[round] = VectorExponentCustom(CurveSlice(Gprime,0,nprime),CurveSlice(Hprime,nprime,Hprime.length),ScalarSlice(aprime,nprime,aprime.length),ScalarSlice(bprime,0,nprime)).add(G.scalarMultiply(cR.mul(x_ip)));
+ L[round] = VectorExponentCustom(CurveSlice(Gprime,nprime,Gprime.length),CurveSlice(Hprime,0,nprime),ScalarSlice(aprime,0,nprime),ScalarSlice(bprime,nprime,bprime.length)).add(H.scalarMultiply(cL.mul(x_ip)));
+ R[round] = VectorExponentCustom(CurveSlice(Gprime,0,nprime),CurveSlice(Hprime,nprime,Hprime.length),ScalarSlice(aprime,nprime,aprime.length),ScalarSlice(bprime,0,nprime)).add(H.scalarMultiply(cR.mul(x_ip)));
// PAPER LINES 21-22
- if (round == 0)
- w[0] = hashToScalar(concat(L[0].toBytes(),R[0].toBytes()));
- else
- w[round] = hashToScalar(concat(w[round-1].bytes,L[round].toBytes(),R[round].toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,L[round].toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,R[round].toBytes()));
+ w[round] = hashCache;
// PAPER LINES 24-25
Gprime = Hadamard2(VectorScalar2(CurveSlice(Gprime,0,nprime),Invert(w[round])),VectorScalar2(CurveSlice(Gprime,nprime,Gprime.length),w[round]));
@@ -355,19 +377,28 @@ public class OptimizedLogBulletproof
public static boolean VERIFY(ProofTuple proof)
{
// Reconstruct the challenges
- Scalar y = hashToScalar(concat(proof.A.toBytes(),proof.S.toBytes()));
- Scalar z = hashToScalar(y.bytes);
- Scalar x = hashToScalar(concat(z.bytes,proof.T1.toBytes(),proof.T2.toBytes()));
- Scalar x_ip = hashToScalar(concat(x.bytes,proof.taux.bytes,proof.mu.bytes,proof.t.bytes));
+ Scalar hashCache = hashToScalar(proof.V.toBytes());
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.A.toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.S.toBytes()));
+ Scalar y = hashCache;
+ hashCache = hashToScalar(hashCache.bytes);
+ Scalar z = hashCache;
+ hashCache = hashToScalar(concat(hashCache.bytes,z.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.T1.toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.T2.toBytes()));
+ Scalar x = hashCache;
+ hashCache = hashToScalar(concat(hashCache.bytes,x.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.taux.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.mu.bytes));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.t.bytes));
+ Scalar x_ip = hashCache;
// PAPER LINE 61
- Curve25519Point L61Left = H.scalarMultiply(proof.taux).add(G.scalarMultiply(proof.t));
+ Curve25519Point L61Left = G.scalarMultiply(proof.taux).add(H.scalarMultiply(proof.t));
- Scalar k = Scalar.ZERO;
- k = k.sub(z.sq().mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y))));
- k = k.sub(z.pow(3).mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(Scalar.TWO))));
+ Scalar k = ComputeK(y,z);
- Curve25519Point L61Right = G.scalarMultiply(k.add(z.mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y)))));
+ Curve25519Point L61Right = H.scalarMultiply(k.add(z.mul(InnerProduct(VectorPowers(Scalar.ONE),VectorPowers(y)))));
L61Right = L61Right.add(proof.V.scalarMultiply(z.sq()));
L61Right = L61Right.add(proof.T1.scalarMultiply(x));
L61Right = L61Right.add(proof.T2.scalarMultiply(x.sq()));
@@ -386,12 +417,16 @@ public class OptimizedLogBulletproof
// PAPER LINES 21-22
// The inner product challenges are computed per round
Scalar[] w = new Scalar[rounds];
- w[0] = hashToScalar(concat(proof.L[0].toBytes(),proof.R[0].toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.L[0].toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.R[0].toBytes()));
+ w[0] = hashCache;
if (rounds > 1)
{
for (int i = 1; i < rounds; i++)
{
- w[i] = hashToScalar(concat(w[i-1].bytes,proof.L[i].toBytes(),proof.R[i].toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.L[i].toBytes()));
+ hashCache = hashToScalar(concat(hashCache.bytes,proof.R[i].toBytes()));
+ w[i] = hashCache;
}
}
@@ -434,16 +469,16 @@ public class OptimizedLogBulletproof
}
// PAPER LINE 26
- Curve25519Point Pprime = P.add(H.scalarMultiply(Scalar.ZERO.sub(proof.mu)));
+ Curve25519Point Pprime = P.add(G.scalarMultiply(Scalar.ZERO.sub(proof.mu)));
for (int i = 0; i < rounds; i++)
{
Pprime = Pprime.add(proof.L[i].scalarMultiply(w[i].sq()));
Pprime = Pprime.add(proof.R[i].scalarMultiply(Invert(w[i]).sq()));
}
- Pprime = Pprime.add(G.scalarMultiply(proof.t.mul(x_ip)));
+ Pprime = Pprime.add(H.scalarMultiply(proof.t.mul(x_ip)));
- if (!Pprime.equals(InnerProdG.add(InnerProdH).add(G.scalarMultiply(proof.a.mul(proof.b).mul(x_ip)))))
+ if (!Pprime.equals(InnerProdG.add(InnerProdH).add(H.scalarMultiply(proof.a.mul(proof.b).mul(x_ip)))))
return false;
return true;
@@ -462,8 +497,8 @@ public class OptimizedLogBulletproof
Hi = new Curve25519Point[N];
for (int i = 0; i < N; i++)
{
- Gi[i] = getHpnGLookup(i);
- Hi[i] = getHpnGLookup(N+i);
+ Gi[i] = getHpnGLookup(2*i);
+ Hi[i] = getHpnGLookup(2*i+1);
}
// Run a bunch of randomized trials
diff --git a/source-code/BulletProofs/readme.md b/source-code/StringCT-java/src/how/monero/hodl/bulletproof/readme.md
similarity index 100%
rename from source-code/BulletProofs/readme.md
rename to source-code/StringCT-java/src/how/monero/hodl/bulletproof/readme.md