From 2a45d98b3749ac68dfc9e28b8a48b96c064f84ef Mon Sep 17 00:00:00 2001 From: Brandon Goodell Date: Thu, 8 Feb 2018 14:02:53 -0700 Subject: [PATCH] Directory reorg, batch verification, other optimizations --- .../BulletProofs/LinearBulletproof.java | 372 --------- source-code/BulletProofs/LogBulletproof.java | 532 ------------- .../BulletProofs/OptimizedLogBulletproof.java | 522 ------------- .../hodl/bulletproof/LinearBulletproof.java | 68 +- .../hodl/bulletproof/LogBulletproof.java | 103 ++- .../hodl/bulletproof/MultiBulletproof.java | 721 ++++++++++++++++++ .../bulletproof/OptimizedLogBulletproof.java | 103 ++- .../how/monero/hodl/bulletproof}/readme.md | 0 8 files changed, 905 insertions(+), 1516 deletions(-) delete mode 100644 source-code/BulletProofs/LinearBulletproof.java delete mode 100644 source-code/BulletProofs/LogBulletproof.java delete mode 100644 source-code/BulletProofs/OptimizedLogBulletproof.java create mode 100644 source-code/StringCT-java/src/how/monero/hodl/bulletproof/MultiBulletproof.java rename source-code/{BulletProofs => StringCT-java/src/how/monero/hodl/bulletproof}/readme.md (100%) 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/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.

(4) Your eyes only RTRS RingCT

huohuli@protonmail.chSurae Noether

Repo changes

Sarang Noether

(4) Re: Speaker Nominations...

Sarang NoetherKevin RabinovichChristopher Gragtmans

[bpase18attendees] BPASE 18 videos and slides online; thank you!

Allison Berke

(4) Chris <> Sarang and Surae

Christopher GragtmansSarang NoetherPaul Shapiro

(5) RTRS RingCT linkability and amortization

Surae NoetherRussell W. F. LaiTim Ruffing

[bpase18attendees] BPASE Day Three (1/26) Schedule

Allison Berke

[bpase18attendees] BPASE Day Two 1/25 schedule

Allison Berke

Verify Your Email Address

Verification

(2) DHL Consignment Notification Arrival:PKO-HAF10803271, Please Receive Your Packages!

DHL Online

[reddit] 1 new message from u/rugbrn

Reddit

(3) [reddit] 1 new message from u/snirpie

Reddit

(2) [reddit] 1 new message from u/Vespco

Reddit

[reddit] 2 new messages from u/snirpie

Reddit

[reddit] 1 new message from u/gr33d3r

Reddit

[bpase18attendees] BPASE '18 Registration confirmation and attendee details

Allison Berke

[reddit] 1 new message from u/0x263a

Reddit

(5) [reddit] 1 new message from u/pebx

Reddit

(2) Fw: Monero Research Lab

Surae Noethermrwhythat

(2) test

Brandon Goodell

⬆️ The Best of Reddit 2017 ⬆️

Reddit Newsletter

Multi BP update

Sarang Noether

(3) Updated BP code

Sarang Noether

[reddit] 1 new message from u/justaq1233

Reddit

(2) [reddit] 1 new message from u/endogenic

Reddit

[reddit] 1 new message from u/NASA_Welder

Reddit

[reddit] 1 new message from u/malabaribiriyani

Reddit

(14) zcash linkability draft

JQSurae Noether

[reddit] 1 new message from u/e-mess

Reddit

(2) [reddit] 1 new message from u/cryptobrant

Reddit

[reddit] 1 new message from u/Truseus

Reddit

[reddit] 1 new message from u/daveselbow

Reddit

[reddit] 1 new message from u/driedapricots

Reddit

[reddit] 1 new message from u/foyamoon

Reddit

[reddit] 1 new message from u/not_really_a_troll

Reddit

[reddit] 1 new message from u/TheCryptoDivision

Reddit

[reddit] 1 new message from u/AsianHouseShrew

Reddit

[reddit] 1 new message from u/xmr_eric

Reddit

[reddit] 1 new message from u/BBQ_RIBS

Reddit

[reddit] 3 new messages from u/captainintarrnet, u/john_alan

Reddit

[reddit] 1 new message from u/IeatBitcoins

Reddit

[reddit] 1 new message from u/fresheneesz

Reddit

[reddit] 2 new messages from u/drfloydch, u/CapnFartfaceMcGee

Reddit

[reddit] 1 new message from u/Wasabi567

Reddit

[reddit] 2 new messages from u/c-789, u/TinusMars

Reddit

Bulletproof code

Sarang Noether

[reddit] 1 new message from u/yoyoyodayoyo

Reddit

(28) SB linking

Surae NoetherSarang NoetherJQ

[reddit] 1 new message from u/captainintarrnet

Reddit

[reddit] 1 new message from u/Whooshless

Reddit
+

Repo changes

From: Sarang Noether <sarang.noether@protonmail.com>
To: Surae Noether
To
  • Surae Noether <surae.noether@protonmail.com>
  • Filter on:
This message contains remote content
This message contains embedded images
+ +
Type 1 or more characters for results.
    + \ 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