mirror of
https://github.com/monero-project/research-lab.git
synced 2024-11-16 15:57:37 +00:00
converted to use x25519 bouncycastle impl
This commit is contained in:
parent
46d95551ff
commit
63dfd2bcae
15 changed files with 304 additions and 233 deletions
BIN
source-code/RuffCT-java/lib/bcprov-jdk15on-156.jar
Normal file
BIN
source-code/RuffCT-java/lib/bcprov-jdk15on-156.jar
Normal file
Binary file not shown.
|
@ -6,7 +6,6 @@ import org.apache.commons.pool2.BasePooledObjectFactory;
|
|||
import org.apache.commons.pool2.PooledObject;
|
||||
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
import org.nem.core.crypto.ed25519.arithmetic.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.SecureRandom;
|
||||
|
@ -14,7 +13,6 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import static how.monero.hodl.crypto.HashToPoint.hashToPoint;
|
||||
import static how.monero.hodl.util.ByteUtil.*;
|
||||
|
||||
public class CryptoUtil {
|
||||
|
@ -32,12 +30,6 @@ public class CryptoUtil {
|
|||
}
|
||||
});
|
||||
|
||||
public static final Ed25519GroupElement G = Ed25519Group.BASE_POINT;
|
||||
public static final Ed25519GroupElement H = new Ed25519EncodedGroupElement(hexToBytes("8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94")).decode();
|
||||
static {
|
||||
H.precomputeForScalarMultiplication();
|
||||
}
|
||||
|
||||
public static Scalar hashToScalar(byte[] a) {
|
||||
return new Scalar(scReduce32(fastHash(a)));
|
||||
}
|
||||
|
@ -89,21 +81,15 @@ public class CryptoUtil {
|
|||
}
|
||||
|
||||
public static final Random random = new SecureRandom();
|
||||
public static byte[] randomPointAsBytes() {
|
||||
return randomPoint().encode().getRaw();
|
||||
}
|
||||
public static Ed25519GroupElement randomPoint() {
|
||||
return Ed25519Group.BASE_POINT.scalarMultiply(Scalar.randomScalar());
|
||||
}
|
||||
public static byte[] randomMessage(int len) {
|
||||
byte[] m = new byte[len];
|
||||
random.nextBytes(m);
|
||||
return m;
|
||||
}
|
||||
|
||||
public static byte[] toBytes(Ed25519GroupElement[] a) {
|
||||
public static byte[] toBytes(Curve25519Point[] a) {
|
||||
byte[] r = new byte[0];
|
||||
for(Ed25519GroupElement ai : a) r = concat(r, ai.encode().getRaw());
|
||||
for(Curve25519Point ai : a) r = concat(r, ai.toBytes());
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -115,40 +101,39 @@ public class CryptoUtil {
|
|||
|
||||
|
||||
|
||||
public static PointPair COMeg(Scalar xAmount, Scalar rMask) {
|
||||
return new PointPair(G.scalarMultiply(xAmount).add(getHpnGLookup(1).scalarMultiply(rMask).toCached()), G.scalarMultiply(rMask));
|
||||
public static Curve25519PointPair COMeg(Scalar xAmount, Scalar rMask) {
|
||||
return new Curve25519PointPair(Curve25519Point.G.scalarMultiply(xAmount).add(getHpnGLookup(1).scalarMultiply(rMask)), Curve25519Point.G.scalarMultiply(rMask));
|
||||
}
|
||||
|
||||
public static Ed25519GroupElement COMp(Scalar xAmount, Scalar rMask) {
|
||||
return G.scalarMultiply(xAmount).add(getHpnGLookup(1).scalarMultiply(rMask).toCached());
|
||||
public static Curve25519Point COMp(Scalar xAmount, Scalar rMask) {
|
||||
return Curve25519Point.G.scalarMultiply(xAmount).add(getHpnGLookup(1).scalarMultiply(rMask));
|
||||
}
|
||||
|
||||
public static Ed25519GroupElement COMb(Scalar[][] x, Scalar r) {
|
||||
public static Curve25519Point COMb(Scalar[][] x, Scalar r) {
|
||||
int m = x.length;
|
||||
int n = x[0].length;
|
||||
Ed25519GroupElement A = G.scalarMultiply(r);
|
||||
Curve25519Point A = Curve25519Point.G.scalarMultiply(r);
|
||||
for(int j=0; j<m; j++) {
|
||||
for(int i=0; i<n; i++) {
|
||||
A = A.toP3().add(getHpnGLookup(j * n + i + 1).scalarMultiply(x[j][i]).toCached());
|
||||
A = A.add(getHpnGLookup(j * n + i + 1).scalarMultiply(x[j][i]));
|
||||
}
|
||||
}
|
||||
return A;
|
||||
}
|
||||
|
||||
|
||||
public static Map<Integer, Ed25519GroupElement> HpnGLookup = new HashMap<>();
|
||||
public static Map<Integer, Curve25519Point> HpnGLookup = new HashMap<>();
|
||||
|
||||
public static Ed25519GroupElement getHpnGLookup(int n) {
|
||||
public static Curve25519Point getHpnGLookup(int n) {
|
||||
if(!HpnGLookup.containsKey(n)) {
|
||||
Ed25519GroupElement HpnG = hashToPoint(G.scalarMultiply(Scalar.intToScalar(n)));
|
||||
//HpnG.precomputeForScalarMultiplication(); // try precomputed vs non-precomputed to check best performance
|
||||
Curve25519Point HpnG = Curve25519Point.hashToPoint(Curve25519Point.G.scalarMultiply(Scalar.intToScalar(n)));
|
||||
HpnGLookup.put(n, HpnG);
|
||||
}
|
||||
return HpnGLookup.get(n);
|
||||
}
|
||||
|
||||
public static PointPair ENCeg(Ed25519GroupElement X, Scalar r) {
|
||||
return new PointPair(getHpnGLookup(1).scalarMultiply(r).toP3().add(X.toCached()), G.scalarMultiply(r));
|
||||
public static Curve25519PointPair ENCeg(Curve25519Point X, Scalar r) {
|
||||
return new Curve25519PointPair(getHpnGLookup(1).scalarMultiply(r).add(X), Curve25519Point.G.scalarMultiply(r));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
package how.monero.hodl.crypto;
|
||||
|
||||
import org.bouncycastle.jce.ECNamedCurveTable;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
|
||||
import java.security.Security;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import static how.monero.hodl.crypto.CryptoUtil.hashToScalar;
|
||||
import static how.monero.hodl.util.ByteUtil.bytesToHex;
|
||||
|
||||
public class Curve25519Point {
|
||||
|
||||
public static ECParameterSpec ecsp;
|
||||
|
||||
static {
|
||||
try {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
ecsp = ECNamedCurveTable.getParameterSpec("curve25519");
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ECPoint point;
|
||||
public Curve25519Point(ECPoint point) {
|
||||
this.point = point;
|
||||
}
|
||||
public Curve25519Point(byte[] a) {
|
||||
this.point = ecsp.getCurve().decodePoint(a);
|
||||
}
|
||||
|
||||
public static Curve25519Point randomPoint() {
|
||||
return BASE_POINT.scalarMultiply(Scalar.randomScalar());
|
||||
}
|
||||
public Curve25519Point scalarMultiply(Scalar a) {
|
||||
scalarMults++;
|
||||
if(this==BASE_POINT) scalarBaseMults++;
|
||||
|
||||
if(enableLineRecording) {
|
||||
Optional<StackTraceElement> optionalCaller = Arrays.stream(new Exception().getStackTrace()).filter(e -> e.getFileName().equals(lineRecordingSourceFile)).findFirst();
|
||||
if (optionalCaller.isPresent()) {
|
||||
StackTraceElement caller = optionalCaller.get();
|
||||
lineNumberCallFrequencyMap.putIfAbsent(caller.getLineNumber(), 0);
|
||||
lineNumberCallFrequencyMap.computeIfPresent(caller.getLineNumber(), (key, oldValue) -> oldValue + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return new Curve25519Point(point.multiply(a.toBigInteger()));
|
||||
}
|
||||
public Curve25519Point add(Curve25519Point a) {
|
||||
return new Curve25519Point(point.add(a.point));
|
||||
}
|
||||
public Curve25519Point subtract(Curve25519Point a) {
|
||||
return new Curve25519Point(point.subtract(a.point));
|
||||
}
|
||||
public byte[] toBytes() {
|
||||
return point.getEncoded(true);
|
||||
}
|
||||
public boolean satisfiesCurveEquation() {
|
||||
return true;
|
||||
}
|
||||
public static Curve25519Point hashToPoint(byte[] a) {
|
||||
return BASE_POINT.scalarMultiply(hashToScalar(a));
|
||||
}
|
||||
public static Curve25519Point hashToPoint(Curve25519Point a) {
|
||||
return hashToPoint(a.toBytes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return bytesToHex(toBytes());
|
||||
}
|
||||
|
||||
public static Curve25519Point ZERO = new Curve25519Point(ecsp.getCurve().getInfinity());
|
||||
public static Curve25519Point BASE_POINT = new Curve25519Point(ecsp.getG());
|
||||
public static Curve25519Point G = BASE_POINT;
|
||||
|
||||
public static int scalarMults = 0;
|
||||
public static int scalarBaseMults = 0;
|
||||
|
||||
public static String lineRecordingSourceFile = null;
|
||||
public static boolean enableLineRecording = false;
|
||||
public static Map<Integer, Integer> lineNumberCallFrequencyMap = new TreeMap<>((a, b)->a.compareTo(b));
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return point.equals(((Curve25519Point) obj).point);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package how.monero.hodl.crypto;
|
||||
|
||||
import static how.monero.hodl.util.ByteUtil.*;
|
||||
|
||||
public class Curve25519PointPair {
|
||||
public Curve25519Point P1;
|
||||
public Curve25519Point P2;
|
||||
public Curve25519PointPair(Curve25519Point P1, Curve25519Point P2) {
|
||||
this.P1 = P1;
|
||||
this.P2 = P2;
|
||||
}
|
||||
public byte[] toBytes() {
|
||||
return concat(P1.toBytes(), P2.toBytes());
|
||||
}
|
||||
public Curve25519PointPair add(Curve25519PointPair a) {
|
||||
return new Curve25519PointPair(P1.add(a.P1), P2.add(a.P2));
|
||||
}
|
||||
public Curve25519PointPair subtract(Curve25519PointPair a) {
|
||||
return new Curve25519PointPair(P1.subtract(a.P1), P2.subtract(a.P2));
|
||||
}
|
||||
public Curve25519PointPair multiply(Scalar n) {
|
||||
return new Curve25519PointPair(P1.scalarMultiply(n), P2.scalarMultiply(n));
|
||||
}
|
||||
|
||||
public boolean equals(Curve25519PointPair obj) {
|
||||
return P1.equals(obj.P1) && P2.equals(obj.P2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(P1: " + bytesToHex(P1.toBytes()) + ", P2: " + P2 + ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
package how.monero.hodl.crypto;
|
||||
|
||||
import org.nem.core.crypto.ed25519.arithmetic.Ed25519GroupElement;
|
||||
|
||||
import static how.monero.hodl.util.ByteUtil.*;
|
||||
|
||||
public class PointPair {
|
||||
public Ed25519GroupElement P1;
|
||||
public Ed25519GroupElement P2;
|
||||
public PointPair(Ed25519GroupElement P1, Ed25519GroupElement P2) {
|
||||
this.P1 = P1;
|
||||
this.P2 = P2;
|
||||
}
|
||||
public byte[] toBytes() {
|
||||
return concat(P1.encode().getRaw(), P2.encode().getRaw());
|
||||
}
|
||||
public PointPair add(PointPair a) {
|
||||
return new PointPair(P1.toP3().add(a.P1.toP3().toCached()), P2.toP3().add(a.P2.toP3().toCached()));
|
||||
}
|
||||
public PointPair subtract(PointPair a) {
|
||||
return new PointPair(P1.toP3().subtract(a.P1.toCached()), P2.toP3().subtract(a.P2.toCached()));
|
||||
}
|
||||
public PointPair multiply(Scalar n) {
|
||||
return new PointPair(P1.toP3().scalarMultiply(n), P2.toP3().scalarMultiply(n));
|
||||
}
|
||||
|
||||
public boolean equals(PointPair obj) {
|
||||
return P1.toP3().equals(obj.P1.toP3()) && P2.toP3().equals(obj.P2.toP3());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(P1: " + bytesToHex(P1.encode().getRaw()) + ", P2: " + P2 + ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,11 +1,8 @@
|
|||
package how.monero.hodl.cursor;
|
||||
|
||||
import how.monero.hodl.crypto.PointPair;
|
||||
import how.monero.hodl.crypto.Curve25519Point;
|
||||
import how.monero.hodl.crypto.Curve25519PointPair;
|
||||
import how.monero.hodl.crypto.Scalar;
|
||||
import org.nem.core.crypto.ed25519.arithmetic.Ed25519EncodedFieldElement;
|
||||
import org.nem.core.crypto.ed25519.arithmetic.Ed25519EncodedGroupElement;
|
||||
import org.nem.core.crypto.ed25519.arithmetic.Ed25519FieldElement;
|
||||
import org.nem.core.crypto.ed25519.arithmetic.Ed25519GroupElement;
|
||||
|
||||
public class BootleRuffingCursor extends Cursor {
|
||||
public byte[] data;
|
||||
|
@ -14,15 +11,12 @@ public class BootleRuffingCursor extends Cursor {
|
|||
super(data);
|
||||
}
|
||||
|
||||
public Ed25519GroupElement readGroupElement() {
|
||||
return new Ed25519EncodedGroupElement(readBytes(32)).decode();
|
||||
public Curve25519Point readGroupElement() {
|
||||
return new Curve25519Point(readBytes(32));
|
||||
}
|
||||
public Ed25519FieldElement readFieldElement() {
|
||||
return new Ed25519EncodedFieldElement(readBytes(32)).decode();
|
||||
}
|
||||
public PointPair[] readPointPairArray(int len) {
|
||||
PointPair[] result = new PointPair[len];
|
||||
for(int i=0; i<len; i++) result[i] = new PointPair(readGroupElement(), readGroupElement());
|
||||
public Curve25519PointPair[] readPointPairArray(int len) {
|
||||
Curve25519PointPair[] result = new Curve25519PointPair[len];
|
||||
for(int i=0; i<len; i++) result[i] = new Curve25519PointPair(readGroupElement(), readGroupElement());
|
||||
return result;
|
||||
}
|
||||
public Scalar[][] readScalar2DArray(int m, int n) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package how.monero.hodl.ringSignature;
|
||||
|
||||
import how.monero.hodl.crypto.Curve25519Point;
|
||||
import how.monero.hodl.crypto.Scalar;
|
||||
import org.nem.core.crypto.ed25519.arithmetic.Ed25519GroupElement;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
@ -12,10 +12,10 @@ import static how.monero.hodl.crypto.CryptoUtil.*;
|
|||
|
||||
public class Multisignature {
|
||||
|
||||
public static Ed25519GroupElement[] lexicographicalSort(Ed25519GroupElement[] X) {
|
||||
SortedMap<String, Ed25519GroupElement> hexToPoint = new TreeMap<>();
|
||||
for(Ed25519GroupElement Xi : X) hexToPoint.put(bytesToHex(Xi.encode().getRaw()), Xi);
|
||||
return hexToPoint.values().stream().toArray(Ed25519GroupElement[]::new);
|
||||
public static Curve25519Point[] lexicographicalSort(Curve25519Point[] X) {
|
||||
SortedMap<String, Curve25519Point> hexToPoint = new TreeMap<>();
|
||||
for(Curve25519Point Xi : X) hexToPoint.put(bytesToHex(Xi.toBytes()), Xi);
|
||||
return hexToPoint.values().stream().toArray(Curve25519Point[]::new);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -25,18 +25,18 @@ public class Multisignature {
|
|||
2) For each i=1,2,...,n, compute c[i] = Hs(X[i], R, L*, M)
|
||||
3) Accept if and only if sG = R + c[1]*X[1] + ... + c[n]*X[n]
|
||||
*/
|
||||
public static boolean verify(byte[] M, Ed25519GroupElement[] X, Signature signature) {
|
||||
public static boolean verify(byte[] M, Curve25519Point[] X, Signature signature) {
|
||||
int n = X.length;
|
||||
|
||||
Scalar XAsterisk = hashToScalar(toBytes(lexicographicalSort(X)));
|
||||
|
||||
Scalar[] c = new Scalar[n];
|
||||
for(int i=0; i<n; i++) {
|
||||
c[i] = hashToScalar(concat(X[i].encode().getRaw(), signature.R.encode().getRaw(), XAsterisk.bytes, M));
|
||||
c[i] = hashToScalar(concat(X[i].toBytes(), signature.R.toBytes(), XAsterisk.bytes, M));
|
||||
}
|
||||
Ed25519GroupElement sG = G.scalarMultiply(signature.s);
|
||||
Ed25519GroupElement sG1 = signature.R;
|
||||
for(int i=0; i<n; i++) sG1 = sG1.toP3().add(X[i].scalarMultiply(c[i]).toCached());
|
||||
Curve25519Point sG = Curve25519Point.G.scalarMultiply(signature.s);
|
||||
Curve25519Point sG1 = signature.R;
|
||||
for(int i=0; i<n; i++) sG1 = sG1.add(X[i].scalarMultiply(c[i]));
|
||||
return sG.equals(sG1);
|
||||
}
|
||||
|
||||
|
@ -53,12 +53,12 @@ public class Multisignature {
|
|||
5) Compute s = s[1] + ... + s[n].
|
||||
6) Output the signature sigma = (R, s)
|
||||
*/
|
||||
public static Signature sign(byte[] M, Scalar[] x, Ed25519GroupElement[] X) {
|
||||
public static Signature sign(byte[] M, Scalar[] x, Curve25519Point[] X) {
|
||||
int n = x.length;
|
||||
if(X==null) {
|
||||
X = new Ed25519GroupElement[n];
|
||||
X = new Curve25519Point[n];
|
||||
for(int i=0; i<n; i++) {
|
||||
X[i] = G.scalarMultiply(x[i]);
|
||||
X[i] = Curve25519Point.G.scalarMultiply(x[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -68,11 +68,11 @@ public class Multisignature {
|
|||
for(int i=0; i<n; i++) rArray[i] = randomScalar();
|
||||
Scalar r = sumArray(rArray);
|
||||
|
||||
Ed25519GroupElement R = G.scalarMultiply(r);
|
||||
Curve25519Point R = Curve25519Point.G.scalarMultiply(r);
|
||||
Scalar[] c = new Scalar[n];
|
||||
Scalar[] sArray = new Scalar[n];
|
||||
for(int i=0; i<n; i++) {
|
||||
c[i] = hashToScalar(concat(X[i].encode().getRaw(), R.encode().getRaw(), XAsterisk.bytes, M));
|
||||
c[i] = hashToScalar(concat(X[i].toBytes(), R.toBytes(), XAsterisk.bytes, M));
|
||||
sArray[i] = rArray[i].add(x[i].mul(c[i]));
|
||||
}
|
||||
Scalar s = sumArray(sArray);
|
||||
|
@ -80,13 +80,13 @@ public class Multisignature {
|
|||
}
|
||||
|
||||
public static class Signature {
|
||||
Ed25519GroupElement R;
|
||||
Curve25519Point R;
|
||||
Scalar s;
|
||||
public Signature(Ed25519GroupElement R, Scalar s) {
|
||||
public Signature(Curve25519Point R, Scalar s) {
|
||||
this.R = R; this.s = s;
|
||||
}
|
||||
public byte[] toBytes() {
|
||||
return concat(R.encode().getRaw(), s.bytes);
|
||||
return concat(R.toBytes(), s.bytes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,13 +96,13 @@ public class Multisignature {
|
|||
*/
|
||||
public static KeyPair keygen() {
|
||||
Scalar x = randomScalar();
|
||||
Ed25519GroupElement X = G.scalarMultiply(x);
|
||||
Curve25519Point X = Curve25519Point.G.scalarMultiply(x);
|
||||
return new KeyPair(x, X);
|
||||
}
|
||||
public static class KeyPair {
|
||||
public Scalar x;
|
||||
public Ed25519GroupElement X;
|
||||
public KeyPair(Scalar x, Ed25519GroupElement X) {
|
||||
public Curve25519Point X;
|
||||
public KeyPair(Scalar x, Curve25519Point X) {
|
||||
this.x = x; this.X = X;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
package how.monero.hodl.ringSignature;
|
||||
|
||||
import how.monero.hodl.crypto.PointPair;
|
||||
import how.monero.hodl.crypto.Curve25519Point;
|
||||
import how.monero.hodl.crypto.Curve25519PointPair;
|
||||
import how.monero.hodl.crypto.Scalar;
|
||||
import org.nem.core.crypto.ed25519.arithmetic.Ed25519GroupElement;
|
||||
|
||||
public class SpendParams {
|
||||
|
||||
public int iAsterisk;
|
||||
public PointPair[][] pk;
|
||||
public BootleRuffing.SK[] sk;
|
||||
public Ed25519GroupElement[] ki;
|
||||
public Ed25519GroupElement[] co;
|
||||
public Curve25519PointPair[][] pk;
|
||||
public StringCT.SK[] sk;
|
||||
public Curve25519Point[] ki;
|
||||
public Curve25519Point[] co;
|
||||
public byte[] M;
|
||||
public Scalar s;
|
||||
public int decompositionBase;
|
||||
|
|
|
@ -1,23 +1,20 @@
|
|||
package how.monero.hodl.ringSignature;
|
||||
|
||||
import how.monero.hodl.crypto.PointPair;
|
||||
import how.monero.hodl.crypto.Curve25519Point;
|
||||
import how.monero.hodl.crypto.Curve25519PointPair;
|
||||
import how.monero.hodl.crypto.Scalar;
|
||||
import how.monero.hodl.cursor.BootleRuffingCursor;
|
||||
import how.monero.hodl.util.VarInt;
|
||||
import org.nem.core.crypto.ed25519.arithmetic.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static how.monero.hodl.crypto.CryptoUtil.*;
|
||||
import static how.monero.hodl.crypto.HashToPoint.hashToPoint;
|
||||
import static how.monero.hodl.crypto.Scalar.bigIntegerArrayToScalarArray;
|
||||
import static how.monero.hodl.crypto.Scalar.randomScalar;
|
||||
import static how.monero.hodl.util.ByteUtil.*;
|
||||
|
||||
|
||||
public class BootleRuffing {
|
||||
public class StringCT {
|
||||
|
||||
public static class SK {
|
||||
public Scalar r;
|
||||
|
@ -34,39 +31,39 @@ public class BootleRuffing {
|
|||
|
||||
public static KeyGenResult KEYGEN() {
|
||||
SK sk = new SK(randomScalar(), randomScalar());
|
||||
Ed25519GroupElement ki = G.scalarMultiply(sk.r1);
|
||||
PointPair pk = ENCeg(ki, sk.r);
|
||||
Curve25519Point ki = Curve25519Point.G.scalarMultiply(sk.r1);
|
||||
Curve25519PointPair pk = ENCeg(ki, sk.r);
|
||||
return new KeyGenResult(sk, ki, pk);
|
||||
}
|
||||
public static class KeyGenResult {
|
||||
public SK sk;
|
||||
public Ed25519GroupElement ki;
|
||||
public PointPair pk = null;
|
||||
public KeyGenResult(SK sk, Ed25519GroupElement ki, PointPair pk) {
|
||||
public Curve25519Point ki;
|
||||
public Curve25519PointPair pk = null;
|
||||
public KeyGenResult(SK sk, Curve25519Point ki, Curve25519PointPair pk) {
|
||||
this.sk = sk; this.ki = ki; this.pk = pk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "sk: " + sk.toString() + ", ki: " + bytesToHex(ki.encode().getRaw()) + ", pk: " + (pk==null ? "(no pk)" : "pk: " + pk);
|
||||
return "sk: " + sk.toString() + ", ki: " + bytesToHex(ki.toBytes()) + ", pk: " + (pk==null ? "(no pk)" : "pk: " + pk);
|
||||
}
|
||||
}
|
||||
|
||||
public static class F {
|
||||
public Ed25519GroupElement[] ki;
|
||||
public PointPair[][] pk;
|
||||
public Ed25519GroupElement[] co;
|
||||
public Ed25519GroupElement co1;
|
||||
public Curve25519Point[] ki;
|
||||
public Curve25519PointPair[][] pk;
|
||||
public Curve25519Point[] co;
|
||||
public Curve25519Point co1;
|
||||
byte[] M;
|
||||
public F(Ed25519GroupElement[] ki, PointPair[][] pk, Ed25519GroupElement[] co, Ed25519GroupElement co1, byte[] M) {
|
||||
public F(Curve25519Point[] ki, Curve25519PointPair[][] pk, Curve25519Point[] co, Curve25519Point co1, byte[] M) {
|
||||
this.ki = ki; this.pk = pk; this.co = co; this.co1 = co1; this.M = M;
|
||||
}
|
||||
byte[] toBytes() {
|
||||
byte[] r = new byte[0];
|
||||
for(int i=0; i<ki.length; i++) r = concat(r, ki[i].encode().getRaw());
|
||||
for(int i=0; i<ki.length; i++) r = concat(r, ki[i].toBytes());
|
||||
for(int i=0; i<pk.length; i++) for(int j=0; j<pk[i].length; j++) r = concat(r, pk[i][j].toBytes());
|
||||
for(int i=0; i<co.length; i++) r = concat(r, co[i].encode().getRaw());
|
||||
r = concat(r, co1.encode().getRaw());
|
||||
for(int i=0; i<co.length; i++) r = concat(r, co[i].toBytes());
|
||||
r = concat(r, co1.toBytes());
|
||||
r = concat(r, M);
|
||||
return r;
|
||||
}
|
||||
|
@ -75,16 +72,16 @@ public class BootleRuffing {
|
|||
public static SpendSignature SPEND(SpendParams sp) {
|
||||
|
||||
int iAsterisk = sp.iAsterisk;
|
||||
PointPair[][] pk = sp.pk;
|
||||
Curve25519PointPair[][] pk = sp.pk;
|
||||
SK[] sk = sp.sk;
|
||||
Ed25519GroupElement[] ki = sp.ki;
|
||||
Ed25519GroupElement[] co = sp.co;
|
||||
Curve25519Point[] ki = sp.ki;
|
||||
Curve25519Point[] co = sp.co;
|
||||
byte[] M = sp.M;
|
||||
Scalar s = sp.s;
|
||||
int decompositionBase = sp.decompositionBase;
|
||||
int decompositionExponent = sp.decompositionExponent;
|
||||
|
||||
Ed25519GroupElement co1 = G.scalarMultiply(s);
|
||||
Curve25519Point co1 = Curve25519Point.G.scalarMultiply(s);
|
||||
F f = new F(ki, pk, co, co1, M);
|
||||
SubResult cf1 = SUB(f);
|
||||
Scalar s1 = s;
|
||||
|
@ -101,16 +98,16 @@ public class BootleRuffing {
|
|||
public static class SpendSignature {
|
||||
public int decompositionBase;
|
||||
public int decompositionExponent;
|
||||
public Ed25519GroupElement co1;
|
||||
public Curve25519Point co1;
|
||||
public Proof2 sigma1;
|
||||
Multisignature.Signature sigma2;
|
||||
public SpendSignature(int decompositionBase, int decompositionExponent, Ed25519GroupElement co1, Proof2 sigma1, Multisignature.Signature sigma2) {
|
||||
public SpendSignature(int decompositionBase, int decompositionExponent, Curve25519Point co1, Proof2 sigma1, Multisignature.Signature sigma2) {
|
||||
this.decompositionBase = decompositionBase; this.decompositionExponent = decompositionExponent; this.co1 = co1; this.sigma1 = sigma1; this.sigma2 = sigma2;
|
||||
}
|
||||
public byte[] toBytes() {
|
||||
byte[] result;
|
||||
result = concat(VarInt.writeVarInt(decompositionBase), VarInt.writeVarInt(decompositionExponent));
|
||||
result = concat(result, co1.encode().getRaw(), sigma1.toBytes(decompositionBase, decompositionExponent), sigma2.toBytes());
|
||||
result = concat(result, co1.toBytes(), sigma1.toBytes(decompositionBase, decompositionExponent), sigma2.toBytes());
|
||||
return result;
|
||||
}
|
||||
public static SpendSignature fromBytes(byte[] a) {
|
||||
|
@ -131,15 +128,15 @@ public class BootleRuffing {
|
|||
public static SubResult SUB(F fin) {
|
||||
int L = fin.pk.length; // inputs
|
||||
int N = fin.pk[0].length; // ring size
|
||||
PointPair[] pkz = new PointPair[L];
|
||||
Curve25519PointPair[] pkz = new Curve25519PointPair[L];
|
||||
Scalar[] f = new Scalar[L];
|
||||
for(int j=0; j<L; j++) {
|
||||
pkz[j] = new PointPair(fin.ki[j], Ed25519Group.ZERO_P3);
|
||||
f[j] = hashToScalar(concat(fin.ki[j].encode().getRaw(), fin.toBytes(), longToLittleEndianUint32ByteArray(j)));
|
||||
pkz[j] = new Curve25519PointPair(fin.ki[j], Curve25519Point.ZERO);
|
||||
f[j] = hashToScalar(concat(fin.ki[j].toBytes(), fin.toBytes(), longToLittleEndianUint32ByteArray(j)));
|
||||
}
|
||||
PointPair[] c = new PointPair[N];
|
||||
Curve25519PointPair[] c = new Curve25519PointPair[N];
|
||||
for(int i=0; i<N; i++) {
|
||||
c[i] = new PointPair(fin.co[i], fin.co1);
|
||||
c[i] = new Curve25519PointPair(fin.co[i], fin.co1);
|
||||
for(int j=0; j<L; j++) {
|
||||
c[i] = c[i].add( (fin.pk[j][i].subtract(pkz[j])).multiply(f[j]) );
|
||||
}
|
||||
|
@ -147,9 +144,9 @@ public class BootleRuffing {
|
|||
return new SubResult(c, f);
|
||||
}
|
||||
public static class SubResult {
|
||||
public PointPair[] c;
|
||||
public Curve25519PointPair[] c;
|
||||
public Scalar[] f;
|
||||
public SubResult(PointPair[] c, Scalar[] f) {
|
||||
public SubResult(Curve25519PointPair[] c, Scalar[] f) {
|
||||
this.c = c; this.f = f;
|
||||
}
|
||||
}
|
||||
|
@ -177,7 +174,7 @@ public class BootleRuffing {
|
|||
}
|
||||
}
|
||||
|
||||
Ed25519GroupElement A = COMb(a, rA);
|
||||
Curve25519Point A = COMb(a, rA);
|
||||
|
||||
Scalar[][] c = new Scalar[m][n];
|
||||
Scalar[][] d = new Scalar[m][n];
|
||||
|
@ -188,10 +185,10 @@ public class BootleRuffing {
|
|||
}
|
||||
}
|
||||
|
||||
Ed25519GroupElement C = COMb(c, rC);
|
||||
Ed25519GroupElement D = COMb(d, rD);
|
||||
Curve25519Point C = COMb(c, rC);
|
||||
Curve25519Point D = COMb(d, rD);
|
||||
|
||||
Scalar x = hashToScalar(concat(A.encode().getRaw(), C.encode().getRaw(), D.encode().getRaw()));
|
||||
Scalar x = hashToScalar(concat(A.toBytes(), C.toBytes(), D.toBytes()));
|
||||
|
||||
Scalar[][] f = new Scalar[m][n];
|
||||
for(int j=0; j<m; j++) {
|
||||
|
@ -214,20 +211,20 @@ public class BootleRuffing {
|
|||
}
|
||||
|
||||
public static class Proof1 {
|
||||
public Ed25519GroupElement A;
|
||||
public Ed25519GroupElement C;
|
||||
public Ed25519GroupElement D;
|
||||
public Curve25519Point A;
|
||||
public Curve25519Point C;
|
||||
public Curve25519Point D;
|
||||
private Scalar[][] fTrimmed;
|
||||
private Scalar zA;
|
||||
private Scalar zC;
|
||||
public transient Scalar[][] a;
|
||||
|
||||
private Proof1(Ed25519GroupElement A, Ed25519GroupElement C, Ed25519GroupElement D, Scalar[][] fTrimmed,
|
||||
private Proof1(Curve25519Point A, Curve25519Point C, Curve25519Point D, Scalar[][] fTrimmed,
|
||||
Scalar zA, Scalar zC, Scalar[][] a) {
|
||||
this.A = A; this.C = C; this.D = D; this.fTrimmed = fTrimmed; this.zA = zA; this.zC = zC; this.a = a;
|
||||
}
|
||||
private byte[] toBytes(int decompositionBase, int decompositionExponent) {
|
||||
byte[] result = concat(A.encode().getRaw(), C.encode().getRaw(), D.encode().getRaw());
|
||||
byte[] result = concat(A.toBytes(), C.toBytes(), D.toBytes());
|
||||
for(int j=0; j<decompositionExponent; j++) {
|
||||
for(int i=0; i<decompositionBase-1; i++) {
|
||||
result = concat(result, fTrimmed[j][i].bytes);
|
||||
|
@ -238,7 +235,7 @@ public class BootleRuffing {
|
|||
}
|
||||
}
|
||||
|
||||
public static Proof2 PROVE2(PointPair[] co, int iAsterisk, Scalar r, int inputs, int decompositionBase, int decompositionExponent) {
|
||||
public static Proof2 PROVE2(Curve25519PointPair[] co, int iAsterisk, Scalar r, int inputs, int decompositionBase, int decompositionExponent) {
|
||||
|
||||
int ringSize = (int) Math.pow(decompositionBase, decompositionExponent);
|
||||
|
||||
|
@ -256,22 +253,22 @@ public class BootleRuffing {
|
|||
}
|
||||
}
|
||||
|
||||
Ed25519GroupElement B = COMb(d, rB);
|
||||
Curve25519Point B = COMb(d, rB);
|
||||
|
||||
Proof1 P = PROVE1(d, rB);
|
||||
|
||||
Scalar[][] coefs = COEFS(P.a, iAsterisk);
|
||||
|
||||
PointPair[] G = new PointPair[decompositionExponent];
|
||||
Curve25519PointPair[] G = new Curve25519PointPair[decompositionExponent];
|
||||
|
||||
for(int k=0; k<decompositionExponent; k++) {
|
||||
G[k] = ENCeg(Ed25519Group.ZERO_P3, u[k]);
|
||||
G[k] = ENCeg(Curve25519Point.ZERO, u[k]);
|
||||
for (int i = 0; i < ringSize; i++) {
|
||||
G[k] = G[k].add(co[i].multiply(coefs[i][k]));
|
||||
}
|
||||
}
|
||||
|
||||
byte[] bytes = concat(P.A.encode().getRaw(), P.C.encode().getRaw(), P.D.encode().getRaw());
|
||||
byte[] bytes = concat(P.A.toBytes(), P.C.toBytes(), P.D.toBytes());
|
||||
Scalar x1 = hashToScalar(bytes);
|
||||
|
||||
Scalar z = r.mul(x1.pow(decompositionExponent));
|
||||
|
@ -284,11 +281,11 @@ public class BootleRuffing {
|
|||
|
||||
public static class Proof2 {
|
||||
Proof1 P;
|
||||
public Ed25519GroupElement B;
|
||||
public PointPair[] G;
|
||||
public Curve25519Point B;
|
||||
public Curve25519PointPair[] G;
|
||||
public Scalar z;
|
||||
|
||||
private Proof2(Proof1 P, Ed25519GroupElement B, PointPair[] G, Scalar z) {
|
||||
private Proof2(Proof1 P, Curve25519Point B, Curve25519PointPair[] G, Scalar z) {
|
||||
this.P = P;
|
||||
this.B = B;
|
||||
this.G = G;
|
||||
|
@ -297,8 +294,8 @@ public class BootleRuffing {
|
|||
|
||||
private byte[] toBytes(int decompositionBase, int decompositionExponent) {
|
||||
byte[] bytes;
|
||||
bytes = concat(P.toBytes(decompositionBase, decompositionExponent), B.encode().getRaw());
|
||||
for(PointPair g : G) bytes = concat(bytes, g.toBytes());
|
||||
bytes = concat(P.toBytes(decompositionBase, decompositionExponent), B.toBytes());
|
||||
for(Curve25519PointPair g : G) bytes = concat(bytes, g.toBytes());
|
||||
bytes = concat(bytes, z.bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
@ -321,7 +318,7 @@ public class BootleRuffing {
|
|||
return r;
|
||||
}
|
||||
|
||||
public static boolean VALID1(Ed25519GroupElement B, Proof1 P) {
|
||||
public static boolean VALID1(Curve25519Point B, Proof1 P) {
|
||||
boolean abcdOnCurve =
|
||||
P.A.satisfiesCurveEquation()
|
||||
&& B.satisfiesCurveEquation()
|
||||
|
@ -342,7 +339,7 @@ public class BootleRuffing {
|
|||
}
|
||||
}
|
||||
|
||||
Scalar x = hashToScalar(concat(P.A.encode().getRaw(), P.C.encode().getRaw(), P.D.encode().getRaw()));
|
||||
Scalar x = hashToScalar(concat(P.A.toBytes(), P.C.toBytes(), P.D.toBytes()));
|
||||
|
||||
for(int j=0; j<m; j++) {
|
||||
f[j][0] = x;
|
||||
|
@ -369,11 +366,11 @@ public class BootleRuffing {
|
|||
}
|
||||
}
|
||||
|
||||
if(!B.toP3().scalarMultiply(x).toP3().add(P.A.toP3().toCached()).equals(COMb(f, P.zA))) {
|
||||
if(!B.scalarMultiply(x).add(P.A).equals(COMb(f, P.zA))) {
|
||||
System.out.println("VALID1: FAILED xB + A == COMp(f[0][0], ..., f[m-1][n-1]; z[A])");
|
||||
return false;
|
||||
}
|
||||
if(!P.C.toP3().scalarMultiply(x).toP3().add(P.D.toP3().toCached()).equals(COMb(f1, P.zC))) {
|
||||
if(!P.C.scalarMultiply(x).add(P.D).equals(COMb(f1, P.zC))) {
|
||||
System.out.println("VALID1: FAILED xC + D == COMp(f'[0][0], ..., f'[m-1][n-1]; z[C])");
|
||||
return false;
|
||||
}
|
||||
|
@ -382,7 +379,7 @@ public class BootleRuffing {
|
|||
|
||||
}
|
||||
|
||||
public static boolean VALID2(int decompositionBase, Proof2 P1, PointPair[] co) {
|
||||
public static boolean VALID2(int decompositionBase, Proof2 P1, Curve25519PointPair[] co) {
|
||||
|
||||
boolean abcdOnCurve =
|
||||
P1.P.A.satisfiesCurveEquation()
|
||||
|
@ -399,7 +396,7 @@ public class BootleRuffing {
|
|||
return false;
|
||||
}
|
||||
|
||||
Scalar x1 = hashToScalar(concat(P1.P.A.encode().getRaw(), P1.P.C.encode().getRaw(), P1.P.D.encode().getRaw()));
|
||||
Scalar x1 = hashToScalar(concat(P1.P.A.toBytes(), P1.P.C.toBytes(), P1.P.D.toBytes()));
|
||||
|
||||
int decompositionExponent = P1.P.fTrimmed.length;
|
||||
Scalar[][] f = new Scalar[decompositionExponent][decompositionBase];
|
||||
|
@ -411,9 +408,9 @@ public class BootleRuffing {
|
|||
|
||||
int ringSize = (int) Math.pow(decompositionBase, decompositionExponent);
|
||||
|
||||
PointPair c = ENCeg(Ed25519Group.ZERO_P3, P1.z);
|
||||
Curve25519PointPair c = ENCeg(Curve25519Point.ZERO, P1.z);
|
||||
|
||||
Scalar x = hashToScalar(concat(P1.P.A.encode().getRaw(), P1.P.C.encode().getRaw(), P1.P.D.encode().getRaw()));
|
||||
Scalar x = hashToScalar(concat(P1.P.A.toBytes(), P1.P.C.toBytes(), P1.P.D.toBytes()));
|
||||
for(int j=0; j<decompositionExponent; j++) {
|
||||
f[j][0] = x;
|
||||
for(int i=1; i<decompositionBase; i++) {
|
||||
|
@ -427,7 +424,7 @@ public class BootleRuffing {
|
|||
g[0] = g[0].mul(f[j][0]);
|
||||
}
|
||||
|
||||
PointPair c1 = co[0].multiply(g[0]);
|
||||
Curve25519PointPair c1 = co[0].multiply(g[0]);
|
||||
for(int i=1; i<ringSize; i++) {
|
||||
int[] iSequence = nAryDecompose(decompositionBase, i, decompositionExponent);
|
||||
g[i] = f[0][iSequence[0]];
|
||||
|
@ -445,14 +442,14 @@ public class BootleRuffing {
|
|||
boolean result = c1.equals(c);
|
||||
if(!result) {
|
||||
System.out.println("VALID2: FAILED: c' != c");
|
||||
System.out.println("c: (" + bytesToHex(c.P1.encode().getRaw()) + ", " + bytesToHex(c.P2.encode().getRaw()));
|
||||
System.out.println("c': (" + bytesToHex(c1.P1.encode().getRaw()) + ", " + bytesToHex(c1.P2.encode().getRaw()));
|
||||
System.out.println("c: (" + bytesToHex(c.P1.toBytes()) + ", " + bytesToHex(c.P2.toBytes()));
|
||||
System.out.println("c': (" + bytesToHex(c1.P1.toBytes()) + ", " + bytesToHex(c1.P2.toBytes()));
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
public static boolean VER(Ed25519GroupElement[] ki, PointPair[][] pk, Ed25519GroupElement[] co, Ed25519GroupElement co1, byte[] M, SpendSignature spendSignature) {
|
||||
public static boolean VER(Curve25519Point[] ki, Curve25519PointPair[][] pk, Curve25519Point[] co, Curve25519Point co1, byte[] M, SpendSignature spendSignature) {
|
||||
|
||||
F f = new F(ki, pk, co, co1, M);
|
||||
|
||||
|
@ -473,11 +470,11 @@ public class BootleRuffing {
|
|||
|
||||
public static class Output {
|
||||
public SK sk;
|
||||
public Ed25519GroupElement ki;
|
||||
public PointPair pk;
|
||||
public Curve25519Point ki;
|
||||
public Curve25519PointPair pk;
|
||||
|
||||
public Scalar mask;
|
||||
public Ed25519GroupElement co;
|
||||
public Curve25519Point co;
|
||||
public BigInteger amount;
|
||||
public static Output genRandomOutput(BigInteger amount) {
|
||||
Output o = new Output();
|
|
@ -1,7 +1,7 @@
|
|||
package test.how.monero.hodl;
|
||||
|
||||
import how.monero.hodl.crypto.Curve25519Point;
|
||||
import how.monero.hodl.ringSignature.SpendParams;
|
||||
import org.nem.core.crypto.ed25519.arithmetic.Ed25519GroupElement;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -10,7 +10,7 @@ import java.util.ArrayList;
|
|||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static how.monero.hodl.ringSignature.BootleRuffing.*;
|
||||
import static how.monero.hodl.ringSignature.StringCT.*;
|
||||
import static test.how.monero.hodl.BootleRuffingSpendTest.createTestSpendParams;
|
||||
|
||||
public class BootleRuffingBenchmarks {
|
||||
|
@ -54,12 +54,12 @@ public class BootleRuffingBenchmarks {
|
|||
// create a transaction to spend the outputs, resulting in a signature that proves the authority to send them
|
||||
SpendSignature[] spendSignature = new SpendSignature[testIterations];
|
||||
for (int i=0; i<testIterations; i++) {
|
||||
Ed25519GroupElement.scalarMults = 0;
|
||||
Ed25519GroupElement.scalarBaseMults = 0;
|
||||
Curve25519Point.scalarMults = 0;
|
||||
Curve25519Point.scalarBaseMults = 0;
|
||||
spendSignature[i] = SPEND(sp[i]);
|
||||
}
|
||||
int spendScalarMults = Ed25519GroupElement.scalarMults;
|
||||
int spendScalarBaseMults = Ed25519GroupElement.scalarBaseMults;
|
||||
int spendScalarMults = Curve25519Point.scalarMults;
|
||||
int spendScalarBaseMults = Curve25519Point.scalarBaseMults;
|
||||
|
||||
long spendSignatureGenerationDuration = (new Date().getTime()-startMs);
|
||||
System.out.println("Spend signature generation duration: " + spendSignatureGenerationDuration + " ms");
|
||||
|
@ -72,13 +72,13 @@ public class BootleRuffingBenchmarks {
|
|||
|
||||
// verify the spend transaction
|
||||
for (int i=0; i<testIterations; i++) {
|
||||
Ed25519GroupElement.scalarMults = 0;
|
||||
Ed25519GroupElement.scalarBaseMults = 0;
|
||||
Curve25519Point.scalarMults = 0;
|
||||
Curve25519Point.scalarBaseMults = 0;
|
||||
boolean verified = VER(sp[i].ki, sp[i].pk, sp[i].co, spendSignature[i].co1, sp[i].M, spendSignature[i]);
|
||||
System.out.println("verified: " + verified);
|
||||
}
|
||||
int verifyScalarMults = Ed25519GroupElement.scalarMults;
|
||||
int verifyScalarBaseMults = Ed25519GroupElement.scalarBaseMults;
|
||||
int verifyScalarMults = Curve25519Point.scalarMults;
|
||||
int verifyScalarBaseMults = Curve25519Point.scalarBaseMults;
|
||||
|
||||
|
||||
long spendSignatureVerificationDuration = (new Date().getTime()-startMs);
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
package test.how.monero.hodl;
|
||||
|
||||
import how.monero.hodl.crypto.PointPair;
|
||||
import how.monero.hodl.crypto.Curve25519Point;
|
||||
import how.monero.hodl.crypto.Curve25519PointPair;
|
||||
import how.monero.hodl.crypto.Scalar;
|
||||
import how.monero.hodl.ringSignature.SpendParams;
|
||||
import org.nem.core.crypto.ed25519.arithmetic.Ed25519GroupElement;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static how.monero.hodl.crypto.CryptoUtil.*;
|
||||
import static how.monero.hodl.ringSignature.BootleRuffing.*;
|
||||
import static how.monero.hodl.ringSignature.StringCT.*;
|
||||
|
||||
public class BootleRuffingSpendTest {
|
||||
|
||||
|
@ -39,35 +38,35 @@ public class BootleRuffingSpendTest {
|
|||
|
||||
// input commitments
|
||||
// commitments to the amounts of all inputs referenced in the transaction (real inputs and decoys)
|
||||
Ed25519GroupElement[][] inputCommitments = new Ed25519GroupElement[inputs][ringSize];
|
||||
Curve25519Point[][] inputCommitments = new Curve25519Point[inputs][ringSize];
|
||||
for(int j=0; j<inputs; j++) {
|
||||
for(int i=0; i<ringSize; i++) {
|
||||
if(i==sp.iAsterisk) inputCommitments[j][i] = realInputs[j].co;
|
||||
else inputCommitments[j][i] = randomPoint();
|
||||
else inputCommitments[j][i] = Curve25519Point.randomPoint();
|
||||
}
|
||||
}
|
||||
|
||||
// there is a co commitment for each ring
|
||||
// each member of co is sum(COMp(input amt i)) - sum(COMp(output amt i))
|
||||
sp.co = new Ed25519GroupElement[ringSize];
|
||||
sp.co = new Curve25519Point[ringSize];
|
||||
for(int i=0; i<ringSize; i++) {
|
||||
sp.co[i] = inputCommitments[0][i];
|
||||
for(int j=1; j<inputs; j++) {
|
||||
sp.co[i] = sp.co[i].toP3().add(inputCommitments[j][i].toP3().toCached());
|
||||
sp.co[i] = sp.co[i].add(inputCommitments[j][i]);
|
||||
}
|
||||
for(int k=0; k<outputs.length; k++) {
|
||||
sp.co[i] = sp.co[i].toP3().subtract(outputs[k].co.toP3().toCached());
|
||||
sp.co[i] = sp.co[i].subtract(outputs[k].co);
|
||||
}
|
||||
}
|
||||
|
||||
// the public keys for every input referenced (including real inputs and decoys)
|
||||
sp.pk = new PointPair[inputs][ringSize];
|
||||
sp.pk = new Curve25519PointPair[inputs][ringSize];
|
||||
|
||||
// the secret key for every real input referenced
|
||||
sp.sk = new SK[inputs];
|
||||
|
||||
// the key image for every real input referenced
|
||||
sp.ki = new Ed25519GroupElement[inputs];
|
||||
sp.ki = new Curve25519Point[inputs];
|
||||
|
||||
for(int j=0; j<inputs; j++) {
|
||||
for(int i=0; i<ringSize; i++) {
|
||||
|
@ -84,14 +83,14 @@ public class BootleRuffingSpendTest {
|
|||
for(int i=0; i<realInputs.length; i++) sp.s = sp.s.add(realInputs[i].mask);
|
||||
for(int i=0; i<outputs.length; i++) sp.s = sp.s.sub(outputs[i].mask);
|
||||
|
||||
Ed25519GroupElement S = realInputs[0].co;
|
||||
for(int i=1; i<realInputs.length; i++) S = S.toP3().add(realInputs[i].co.toP3().toCached());
|
||||
S = S.toP3().subtract(G.scalarMultiply(new Scalar(fee)).toP3().toCached());
|
||||
for(int i=0; i<outputs.length; i++) S = S.toP3().subtract(outputs[i].co.toP3().toCached());
|
||||
Curve25519Point S = realInputs[0].co;
|
||||
for(int i=1; i<realInputs.length; i++) S = S.add(realInputs[i].co);
|
||||
S = S.subtract(Curve25519Point.G.scalarMultiply(new Scalar(fee)));
|
||||
for(int i=0; i<outputs.length; i++) S = S.subtract(outputs[i].co);
|
||||
|
||||
Ed25519GroupElement S1 = getHpnGLookup(1).scalarMultiply(sp.s);
|
||||
Curve25519Point S1 = getHpnGLookup(1).scalarMultiply(sp.s);
|
||||
|
||||
if(!S.toP3().equals(S1)) throw new RuntimeException("S != S'");
|
||||
if(!S.equals(S1)) throw new RuntimeException("S != S'");
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
@ -114,8 +113,8 @@ public class BootleRuffingSpendTest {
|
|||
|
||||
if(pauseAtEachStage) { System.out.println("Press enter to continue"); try { System.in.read(); } catch (Exception e) {}; System.out.println("Continuing..."); }
|
||||
|
||||
Ed25519GroupElement.scalarMults = 0;
|
||||
Ed25519GroupElement.scalarBaseMults = 0;
|
||||
Curve25519Point.scalarMults = 0;
|
||||
Curve25519Point.scalarBaseMults = 0;
|
||||
|
||||
startMs = new Date().getTime();
|
||||
// create a transaction to spend the outputs, resulting in a signature that proves the authority to send them
|
||||
|
@ -133,29 +132,29 @@ public class BootleRuffingSpendTest {
|
|||
if(pauseAtEachStage) { System.out.println("Press enter to continue"); try { System.in.read(); } catch (Exception e) {}; System.out.println("Continuing..."); }
|
||||
startMs = new Date().getTime();
|
||||
|
||||
System.out.println("Spend ScalarMults: " + Ed25519GroupElement.scalarMults);
|
||||
System.out.println("Spend BaseScalarMults: " + Ed25519GroupElement.scalarBaseMults);
|
||||
Ed25519GroupElement.scalarMults = 0;
|
||||
Ed25519GroupElement.scalarBaseMults = 0;
|
||||
System.out.println("Spend ScalarMults: " + Curve25519Point.scalarMults);
|
||||
System.out.println("Spend BaseScalarMults: " + Curve25519Point.scalarBaseMults);
|
||||
Curve25519Point.scalarMults = 0;
|
||||
Curve25519Point.scalarBaseMults = 0;
|
||||
|
||||
//Ed25519GroupElement.enableLineRecording = true;
|
||||
Ed25519GroupElement.lineRecordingSourceFile = "BootleRuffing.java";
|
||||
Curve25519Point.lineRecordingSourceFile = "BootleRuffing.java";
|
||||
|
||||
// verify the spend transaction
|
||||
for (int i=0; i<testIterations; i++) {
|
||||
|
||||
spendSignature[i] = SpendSignature.fromBytes(spendSignatureBytes[i]);
|
||||
//spendSignature[i] = SpendSignature.fromBytes(spendSignatureBytes[i]);
|
||||
|
||||
boolean verified = VER(sp[i].ki, sp[i].pk, sp[i].co, spendSignature[i].co1, sp[i].M, spendSignature[i]);
|
||||
System.out.println("verified: " + verified);
|
||||
}
|
||||
|
||||
System.out.println("Verify ScalarMults: " + Ed25519GroupElement.scalarMults);
|
||||
System.out.println("Verify BaseScalarMults: " + Ed25519GroupElement.scalarBaseMults);
|
||||
System.out.println("Verify ScalarMults: " + Curve25519Point.scalarMults);
|
||||
System.out.println("Verify BaseScalarMults: " + Curve25519Point.scalarBaseMults);
|
||||
|
||||
System.out.println("Signature verification duration: " + (new Date().getTime()-startMs) + " ms");
|
||||
|
||||
if(Ed25519GroupElement.enableLineRecording) Ed25519GroupElement.lineNumberCallFrequencyMap.entrySet().stream().forEach(e->{System.out.println("line: " + e.getKey() + ", calls: " + e.getValue());});
|
||||
if(Curve25519Point.enableLineRecording) Curve25519Point.lineNumberCallFrequencyMap.entrySet().stream().forEach(e->{System.out.println("line: " + e.getKey() + ", calls: " + e.getValue());});
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package test.how.monero.hodl;
|
||||
|
||||
import how.monero.hodl.crypto.Curve25519Point;
|
||||
import how.monero.hodl.crypto.Scalar;
|
||||
import org.nem.core.crypto.ed25519.arithmetic.Ed25519GroupElement;
|
||||
|
||||
import static how.monero.hodl.crypto.CryptoUtil.COMb;
|
||||
import static how.monero.hodl.ringSignature.BootleRuffing.*;
|
||||
import static how.monero.hodl.ringSignature.StringCT.*;
|
||||
|
||||
public class Prove1Valid1Test1 {
|
||||
|
||||
|
@ -19,7 +19,7 @@ public class Prove1Valid1Test1 {
|
|||
|
||||
Proof1 P = PROVE1(b, r);
|
||||
|
||||
Ed25519GroupElement B = COMb(b, r);
|
||||
Curve25519Point B = COMb(b, r);
|
||||
|
||||
System.out.println("VALID1 returns " + VALID1(B, P));
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package test.how.monero.hodl;
|
||||
|
||||
import how.monero.hodl.crypto.PointPair;
|
||||
import how.monero.hodl.crypto.Curve25519PointPair;
|
||||
import how.monero.hodl.crypto.Scalar;
|
||||
|
||||
import static how.monero.hodl.crypto.CryptoUtil.COMeg;
|
||||
import static how.monero.hodl.ringSignature.BootleRuffing.*;
|
||||
import static how.monero.hodl.ringSignature.StringCT.*;
|
||||
|
||||
public class Prove2Valid2Test1 {
|
||||
|
||||
|
@ -16,7 +16,7 @@ public class Prove2Valid2Test1 {
|
|||
Scalar r = Scalar.ONE;
|
||||
Scalar s = Scalar.ONE;
|
||||
|
||||
PointPair[] co = new PointPair[]{
|
||||
Curve25519PointPair[] co = new Curve25519PointPair[]{
|
||||
COMeg(Scalar.ZERO, r),
|
||||
COMeg(Scalar.ONE, s)
|
||||
};
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package test.how.monero.hodl;
|
||||
|
||||
import how.monero.hodl.crypto.PointPair;
|
||||
import how.monero.hodl.crypto.Curve25519PointPair;
|
||||
import how.monero.hodl.crypto.Scalar;
|
||||
|
||||
import static how.monero.hodl.crypto.CryptoUtil.COMeg;
|
||||
import static how.monero.hodl.ringSignature.BootleRuffing.*;
|
||||
import static how.monero.hodl.ringSignature.StringCT.*;
|
||||
|
||||
public class Prove2Valid2Test1a {
|
||||
|
||||
|
@ -14,7 +14,7 @@ public class Prove2Valid2Test1a {
|
|||
|
||||
Scalar r = Scalar.ONE;
|
||||
|
||||
PointPair[] co = new PointPair[]{
|
||||
Curve25519PointPair[] co = new Curve25519PointPair[]{
|
||||
COMeg(Scalar.ONE,Scalar.ONE),
|
||||
COMeg(Scalar.ONE,Scalar.ONE),
|
||||
COMeg(Scalar.ONE,Scalar.ONE),
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package test.how.monero.hodl;
|
||||
|
||||
import how.monero.hodl.crypto.PointPair;
|
||||
import how.monero.hodl.crypto.Curve25519Point;
|
||||
import how.monero.hodl.crypto.Curve25519PointPair;
|
||||
import how.monero.hodl.crypto.Scalar;
|
||||
import org.nem.core.crypto.ed25519.arithmetic.Ed25519GroupElement;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import static how.monero.hodl.crypto.CryptoUtil.COMeg;
|
||||
import static how.monero.hodl.ringSignature.BootleRuffing.*;
|
||||
import static how.monero.hodl.ringSignature.StringCT.*;
|
||||
|
||||
public class Prove2Valid2Test1b {
|
||||
|
||||
|
@ -21,7 +21,7 @@ public class Prove2Valid2Test1b {
|
|||
|
||||
System.out.println("---------------------------------------------------------------------------");
|
||||
int len = (int) Math.pow(2, k);
|
||||
PointPair[] co = new PointPair[len];
|
||||
Curve25519PointPair[] co = new Curve25519PointPair[len];
|
||||
for (int i = 0; i < len; i++) co[i] = COMeg(Scalar.intToScalar(i), Scalar.ONE);
|
||||
|
||||
int iAsterisk = 0;
|
||||
|
@ -34,23 +34,23 @@ public class Prove2Valid2Test1b {
|
|||
System.out.println("decompositionBase: " + decompositionBase);
|
||||
System.out.println("decompositionExponent: " + decompositionExponent);
|
||||
|
||||
Ed25519GroupElement.scalarMults = 0;
|
||||
Ed25519GroupElement.scalarBaseMults = 0;
|
||||
Curve25519Point.scalarMults = 0;
|
||||
Curve25519Point.scalarBaseMults = 0;
|
||||
long startMs = new Date().getTime();
|
||||
|
||||
Proof2 P2 = PROVE2(co, iAsterisk, r, inputs, decompositionBase, decompositionExponent);
|
||||
|
||||
System.out.println("PROVE2 duration: " + (new Date().getTime() - startMs) + " ms");
|
||||
System.out.println("PROVE2 ScalarMults: " + Ed25519GroupElement.scalarMults);
|
||||
System.out.println("PROVE2 BaseScalarMults: " + Ed25519GroupElement.scalarBaseMults);
|
||||
Ed25519GroupElement.scalarMults = 0;
|
||||
Ed25519GroupElement.scalarBaseMults = 0;
|
||||
System.out.println("PROVE2 ScalarMults: " + Curve25519Point.scalarMults);
|
||||
System.out.println("PROVE2 BaseScalarMults: " + Curve25519Point.scalarBaseMults);
|
||||
Curve25519Point.scalarMults = 0;
|
||||
Curve25519Point.scalarBaseMults = 0;
|
||||
startMs = new Date().getTime();
|
||||
|
||||
System.out.println("VALID2 result: " + VALID2(decompositionBase, P2, co));
|
||||
|
||||
System.out.println("VALID2 ScalarMults: " + Ed25519GroupElement.scalarMults);
|
||||
System.out.println("VALID2 BaseScalarMults: " + Ed25519GroupElement.scalarBaseMults);
|
||||
System.out.println("VALID2 ScalarMults: " + Curve25519Point.scalarMults);
|
||||
System.out.println("VALID2 BaseScalarMults: " + Curve25519Point.scalarBaseMults);
|
||||
|
||||
System.out.println("VALID2 duration: " + (new Date().getTime() - startMs) + " ms");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue