Skip to content

Commit 92d9ae3

Browse files
committed
add some todos and a fix for commitment request concurrency
1 parent 8ef3ef7 commit 92d9ae3

File tree

6 files changed

+48
-43
lines changed

6 files changed

+48
-43
lines changed
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

src/main/java/org/torusresearch/torusutils/TorusUtils.java

+43-37
Original file line numberDiff line numberDiff line change
@@ -138,27 +138,28 @@ public static String getPostboxKey(TorusKey torusKey) {
138138

139139
public CompletableFuture<TorusKey> retrieveShares(String[] endpoints, BigInteger[] indexes, String verifier, HashMap<String, Object> verifierParams,
140140
String idToken, HashMap<String, Object> extraParams, String networkMigrated,
141-
@Nullable ImportedShare[] importedShares) {
141+
@Nullable ImportedShare[] importedShares) { // TODO: Rename to retrieveOrImportShare
142142
try {
143143

144-
if (endpoints.length != indexes.length) {
144+
if (endpoints.length != indexes.length) { // TODO: Fix params for this function, indexes are no longer needed here, other params are missing.
145145
throw new IllegalArgumentException("Length of endpoints must be the same as length of nodeIndexes");
146146
}
147147

148148
APIUtils.get(this.options.getAllowHost(), new Header[]{new Header("Origin", this.options.getOrigin()), new Header("verifier", verifier), new Header("verifierid", verifierParams.get("verifier_id").toString()), new Header("network", networkMigrated),
149-
new Header("clientid", this.options.getClientId()), new Header("enablegating", "true")}, true).get();
149+
new Header("clientid", this.options.getClientId()), new Header("enablegating", "true")}, true).get(); // TODO: Check these headers
150150
List<CompletableFuture<String>> promiseArr = new ArrayList<>();
151151
Set<SessionToken> sessionTokenData = new HashSet<>();
152152
Set<BigInteger> nodeIndexs = new HashSet<>();
153153
// generate temporary private and public key that is used to secure receive shares
154-
ECKeyPair sessionAuthKey = Keys.createEcKeyPair();
155-
String pubKey = Utils.padLeft(sessionAuthKey.getPublicKey().toString(16), '0', 128);
154+
ECKeyPair sessionAuthKey = Keys.createEcKeyPair(); // TODO: Change this to indicate it is a secp256k1 key
155+
String pubKey = Utils.padLeft(sessionAuthKey.getPublicKey().toString(16), '0', 128); // TODO: Refactor this to common class, avoid padding manually, this also helps with indicating where padding should not be used.
156156
String pubKeyX = pubKey.substring(0, pubKey.length() / 2);
157157
String pubKeyY = pubKey.substring(pubKey.length() / 2);
158158

159159
String tokenCommitment = Hash.sha3String(idToken);
160-
int t = endpoints.length / 4;
161-
int k = t * 2 + 1;
160+
161+
int minRequiredCommitmments = (endpoints.length * 3 / 4) + 1;
162+
int threshold = (endpoints.length * 2) + 1;
162163

163164
boolean isImportShareReq = false;
164165
if (importedShares != null && importedShares.length > 0) {
@@ -173,33 +174,37 @@ public CompletableFuture<TorusKey> retrieveShares(String[] endpoints, BigInteger
173174
CompletableFuture<String> p = APIUtils.post(endpoints[i], APIUtils.generateJsonRPCObject("CommitmentRequest", new CommitmentRequestParams("mug00", tokenCommitment.substring(2), pubKeyX, pubKeyY, String.valueOf(System.currentTimeMillis()), verifier)), false);
174175
promiseArr.add(i, p);
175176
}
176-
// send share request once k + t number of commitment requests have completed
177+
178+
// send share request once minRequiredCommitmments number of commitment requests have completed
177179
boolean finalIsImportShareReq = isImportShareReq;
178180
return new Some<>(promiseArr, (resultArr, commitmentsResolved) -> {
179181
List<String> completedRequests = new ArrayList<>();
180-
for (String result : resultArr) {
181-
if (result != null && !result.isEmpty()) {
182-
completedRequests.add(result);
182+
int received = 0;
183+
for (CompletableFuture<String> result : promiseArr) {
184+
try {
185+
if (result.get() != null && !result.get().isEmpty()) {
186+
received += 1;
187+
completedRequests.add(result.get());
188+
if (!finalIsImportShareReq) {
189+
if (received >= minRequiredCommitmments) {
190+
break;
191+
}
192+
}
193+
}
194+
} catch (Exception ex) {
195+
// ignore ex
183196
}
184197
}
198+
199+
// Return List<String> instead
185200
CompletableFuture<List<String>> completableFuture = new CompletableFuture<>();
186-
if (importedShares != null && importedShares.length > 0 && completedRequests.size() == endpoints.length) {
187-
completableFuture.complete(Arrays.asList(resultArr));
188-
} else if (importedShares != null && importedShares.length == 0 && completedRequests.size() >= k + t) {
189-
Gson gson = new Gson();
190-
// we don't consider commitment to succeed unless node 1 responds
191-
boolean requiredNodeResultFound = completedRequests.stream().anyMatch(x -> {
192-
if (x == null || x.isEmpty()) return false;
193-
JsonRPCResponse nodeSigResponse = gson.fromJson(x, JsonRPCResponse.class);
194-
if (nodeSigResponse == null || nodeSigResponse.getResult() == null) return false;
195-
NodeSignature nodeSignature = gson.fromJson(Utils.convertToJsonObject(nodeSigResponse.getResult()), NodeSignature.class);
196-
return nodeSignature != null && nodeSignature.getNodeindex().equals("1");
197-
});
198-
if (requiredNodeResultFound) completableFuture.complete(completedRequests);
199-
else completableFuture.completeExceptionally(new PredicateFailedException("commitment from node 1 not found"));
200-
} else {
201+
if (!finalIsImportShareReq && completedRequests.size() < minRequiredCommitmments) {
202+
completableFuture.completeExceptionally(new PredicateFailedException("insufficient responses for commitments"));
203+
} else if (finalIsImportShareReq && completedRequests.size() < Arrays.stream(endpoints).count()) {
201204
completableFuture.completeExceptionally(new PredicateFailedException("insufficient responses for commitments"));
202205
}
206+
207+
completableFuture.complete(Arrays.asList(resultArr));
203208
return completableFuture;
204209
}).getCompletableFuture().thenComposeAsync(responses -> {
205210
try {
@@ -318,7 +323,7 @@ public CompletableFuture<TorusKey> retrieveShares(String[] endpoints, BigInteger
318323
}
319324
}
320325

321-
String thresholdPublicKeyString = Utils.thresholdSame(completedResponsesPubKeys, k);
326+
String thresholdPublicKeyString = Utils.thresholdSame(completedResponsesPubKeys, threshold);
322327
PubKey thresholdPubKey = null;
323328

324329
if (thresholdPublicKeyString == null) {
@@ -464,15 +469,15 @@ public CompletableFuture<TorusKey> retrieveShares(String[] endpoints, BigInteger
464469
.filter(Objects::nonNull)
465470
.collect(Collectors.toList());
466471

467-
if (validSigs.size() < k) {
472+
if (validSigs.size() < threshold) {
468473
throw new RuntimeException("Insufficient number of signatures from nodes");
469474
}
470475

471476
List<String> validTokens = sessionTokens.stream()
472477
.filter(Objects::nonNull)
473478
.collect(Collectors.toList());
474479

475-
if (validTokens.size() < k) {
480+
if (validTokens.size() < threshold) {
476481
throw new RuntimeException("Insufficient number of tokens from nodes");
477482
}
478483

@@ -503,7 +508,7 @@ public CompletableFuture<TorusKey> retrieveShares(String[] endpoints, BigInteger
503508
elements.add(i);
504509
}
505510

506-
List<List<Integer>> allCombis = Utils.kCombinations(elements, k);
511+
List<List<Integer>> allCombis = Utils.kCombinations(elements, threshold);
507512

508513
for (List<Integer> currentCombi : allCombis) {
509514
Map<Integer, String> currentCombiShares = decryptedShares.entrySet().stream()
@@ -557,7 +562,7 @@ public CompletableFuture<TorusKey> retrieveShares(String[] endpoints, BigInteger
557562
}
558563
}
559564
}
560-
String thresholdPublicKeyString = Utils.thresholdSame(completedResponsesPubKeys, k);
565+
String thresholdPublicKeyString = Utils.thresholdSame(completedResponsesPubKeys, threshold);
561566
PubKey thresholdPubKey = null;
562567

563568
if (thresholdPublicKeyString == null) {
@@ -582,7 +587,7 @@ public CompletableFuture<TorusKey> retrieveShares(String[] endpoints, BigInteger
582587
} else {
583588
responsesSize = completedResponses.size();
584589
}
585-
if (responsesSize >= k && thresholdPubKey != null && (thresholdNonceData != null || verifierParams.get("extended_verifier_id") != null ||
590+
if (responsesSize >= threshold && thresholdPubKey != null && (thresholdNonceData != null || verifierParams.get("extended_verifier_id") != null ||
586591
LEGACY_NETWORKS_ROUTE_MAP.containsKey(networkMigrated))) {
587592
List<DecryptedShare> decryptedShares = new ArrayList<>();
588593
List<CompletableFuture<byte[]>> sharePromises = new ArrayList<>();
@@ -827,7 +832,7 @@ public CompletableFuture<TorusKey> retrieveShares(String[] endpoints, BigInteger
827832
}
828833
}
829834

830-
List<List<Integer>> allCombis = Utils.kCombinations(decryptedShares.size(), k);
835+
List<List<Integer>> allCombis = Utils.kCombinations(decryptedShares.size(), threshold);
831836
for (List<Integer> currentCombi : allCombis) {
832837
List<BigInteger> currentCombiSharesIndexes = new ArrayList<>();
833838
List<BigInteger> currentCombiSharesValues = new ArrayList<>();
@@ -983,11 +988,11 @@ public CompletableFuture<TorusKey> retrieveShares(String[] endpoints, BigInteger
983988
}
984989

985990
public CompletableFuture<TorusKey> retrieveShares(String[] endpoints, BigInteger[] indexes, String verifier, HashMap<String, Object> verifierParams, String idToken, @Nullable ImportedShare[] importedShares) {
986-
return this.retrieveShares(endpoints, indexes, verifier, verifierParams, idToken, null, getMigratedNetworkInfo(), importedShares);
991+
return this.retrieveShares(endpoints, indexes, verifier, verifierParams, idToken, null, getMigratedNetworkInfo(), importedShares); // TODO: extraParams should be passed here and not ignored
987992
}
988993

989994
public CompletableFuture<TorusKey> retrieveShares(String[] endpoints, BigInteger[] indexes, String verifier, HashMap<String, Object> verifierParams, String idToken) {
990-
return this.retrieveShares(endpoints, indexes, verifier, verifierParams, idToken, null, getMigratedNetworkInfo(), new ImportedShare[]{});
995+
return this.retrieveShares(endpoints, indexes, verifier, verifierParams, idToken, null, getMigratedNetworkInfo(), new ImportedShare[]{}); // TODO: extraParams should be passed here and not ignored
991996
}
992997

993998
public CompletableFuture<BigInteger> getMetadata(MetadataPubKey data) {
@@ -1267,10 +1272,11 @@ public CompletableFuture<TorusKey> importPrivateKey(
12671272
BigInteger[] nodeIndexes,
12681273
TorusNodePub[] nodePubKeys,
12691274
String verifier,
1270-
HashMap<String, Object> verifierParams,
1275+
HashMap<String, Object> verifierParams, // TODO: This must be strongly typed to VerifierParams
12711276
String idToken,
12721277
String newPrivateKey,
1273-
TorusUtilsExtraParams extraParams) throws Exception {
1278+
TorusUtilsExtraParams extraParams // TODO: This must have a default value
1279+
) throws Exception {
12741280

12751281
if (endpoints.length != nodeIndexes.length) {
12761282
CompletableFuture<TorusKey> future = new CompletableFuture<>();

src/main/java/org/torusresearch/torusutils/apis/Ecies.java

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public Ecies(String iv, String ephemPublicKey, String ciphertext, String mac) {
2121
this.ephemPublicKey = ephemPublicKey;
2222
this.mac = mac;
2323
this.ciphertext = ciphertext;
24+
this.mode = "AES256";
2425
}
2526

2627
public String getIv() {

src/main/java/org/torusresearch/torusutils/helpers/KeyUtils.java

-3
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,6 @@ public static List<ImportedShare> generateShares(KeyType keyType, BigInteger ser
242242
List<Ecies> encShares = new ArrayList<>();
243243
for (int i = 0; i < nodePubKeys.size(); i++) {
244244
String indexHex = String.format("%064x", nodeIndexes.get(i));
245-
//String indexHexPadded = Utils.addLeadingZerosForLength64(indexHex);
246-
//BigInt and converted to
247-
248245
Share shareInfo = shares.get(indexHex);
249246

250247
String iv = Utils.convertByteToHexadecimal(Utils.getRandomBytes(16));

src/main/java/org/torusresearch/torusutils/helpers/Predicate.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
import java.util.concurrent.CompletableFuture;
44

5+
import java.util.concurrent.ExecutionException;
56
import java.util.concurrent.atomic.AtomicBoolean;
67

78
public interface Predicate<T> {
8-
CompletableFuture<T> call(String[] resultArr, AtomicBoolean resolved) throws PredicateFailedException;
9+
CompletableFuture<T> call(String[] resultArr, AtomicBoolean resolved) throws PredicateFailedException, ExecutionException, InterruptedException;
910
}

src/test/java/org/torusresearch/torusutilstest/SapphireMainnetTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ public void shouldUpdateSessionTimeOfTokenSignatureData() throws Exception {
327327
byte[] decodedBytes = Base64.getDecoder().decode(sig.get("data"));
328328
String decodedString = new String(decodedBytes);
329329
HashMap parsedSigData = new Gson().fromJson(decodedString, HashMap.class);
330-
parsedSigsData.add(parsedSigData);
330+
// parsedSigsData.add(parsedSigData);
331331
}
332332

333333
long currentTimeSec = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());

0 commit comments

Comments
 (0)