├── .gitignore ├── AsynchronousRatchetingTree ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── facebook │ └── research │ └── asynchronousratchetingtree │ ├── GroupMessagingSetupPhase.java │ ├── GroupMessagingState.java │ ├── GroupMessagingTestImplementation.java │ ├── KeyServer.java │ ├── Main.java │ ├── MessageDistributer.java │ ├── Stopwatch.java │ ├── TestResult.java │ ├── Utils.java │ ├── art │ ├── ART.java │ ├── ARTSetupPhase.java │ ├── ARTState.java │ ├── ARTTestImplementation.java │ ├── message │ │ ├── ARTMessageDistributer.java │ │ ├── AuthenticatedMessage.java │ │ ├── CiphertextMessage.java │ │ ├── SetupMessage.java │ │ ├── UpdateMessage.java │ │ └── thrift │ │ │ ├── ART.thrift │ │ │ ├── AuthenticatedMessageStruct.java │ │ │ ├── CiphertextMessageStruct.java │ │ │ ├── NodeStruct.java │ │ │ ├── SetupMessageStruct.java │ │ │ └── UpdateMessageStruct.java │ └── tree │ │ ├── LeafNode.java │ │ ├── Node.java │ │ ├── ParentNode.java │ │ ├── PublicLeafNode.java │ │ ├── PublicParentNode.java │ │ ├── SecretLeafNode.java │ │ ├── SecretNode.java │ │ └── SecretParentNode.java │ ├── crypto │ ├── Crypto.java │ ├── DHKeyPair.java │ ├── DHPubKey.java │ └── SignedDHPubKey.java │ └── dhratchet │ ├── DHRatchet.java │ ├── DHRatchetSetupPhase.java │ ├── DHRatchetState.java │ └── message │ ├── DHRatchetMessage.java │ ├── DHRatchetMessageDistributer.java │ ├── DHRatchetSetupMessage.java │ └── thrift │ ├── DHRatchet.thrift │ ├── DHRatchetMessageStruct.java │ └── DHRatchetSetupMessageStruct.java ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── Makefile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | AsynchronousRatchetingTree/target 2 | .idea 3 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.facebook.research 5 | asynchronousratchetingtree 6 | jar 7 | 1.0-SNAPSHOT 8 | Asynchronous Ratcheting Tree 9 | https://eprint.iacr.org/2017/666 10 | 11 | 12 | 1.8 13 | 1.8 14 | UTF-8 15 | 16 | 17 | 18 | 19 | org.apache.thrift 20 | libthrift 21 | 0.10.0 22 | jar 23 | 24 | 25 | org.slf4j 26 | slf4j-simple 27 | 1.7.12 28 | 29 | 30 | org.zeromq 31 | curve25519-java 32 | 0.1.0 33 | 34 | 35 | 36 | 37 | 38 | 39 | org.apache.maven.plugins 40 | maven-shade-plugin 41 | 3.0.0 42 | 43 | 44 | package 45 | 46 | shade 47 | 48 | 49 | 50 | 51 | uber-${project.artifactId}-${project.version} 52 | 53 | 54 | com.facebook.research.asynchronousratchetingtree.Main 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | Attribution-NonCommercial 4.0 International 65 | https://creativecommons.org/licenses/by-nc/4.0/ 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/GroupMessagingSetupPhase.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.crypto.DHPubKey; 12 | 13 | public interface GroupMessagingSetupPhase { 14 | void generateNecessaryPreKeys(TState[] states); 15 | void setupInitiator(GroupMessagingTestImplementation implementation, TState[] states, DHPubKey[] identities, KeyServer keyServer); 16 | int getBytesSentByInitiator(); 17 | void setupAllOthers(GroupMessagingTestImplementation implementation, TState[] states, Integer[] active, DHPubKey[] identities, KeyServer keyServer); 18 | int getBytesSentByOthers(); 19 | int getBytesReceivedByOthers(); 20 | } 21 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/GroupMessagingState.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.crypto.DHKeyPair; 12 | import com.facebook.research.asynchronousratchetingtree.crypto.SignedDHPubKey; 13 | 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | 17 | abstract public class GroupMessagingState { 18 | private int peerNum; 19 | private int peerCount; 20 | private DHKeyPair identityKeyPair; 21 | private Map preKeys = new HashMap<>(); 22 | private Map signedPreKeys = new HashMap<>(); 23 | 24 | public GroupMessagingState(int peerNum, int peerCount) { 25 | this.peerNum = peerNum; 26 | this.peerCount = peerCount; 27 | identityKeyPair = DHKeyPair.generate(true); 28 | } 29 | 30 | final public int getPeerNum() { 31 | return peerNum; 32 | } 33 | 34 | final public int getPeerCount() { 35 | return peerCount; 36 | } 37 | 38 | final public DHKeyPair getIdentityKeyPair() { 39 | return identityKeyPair; 40 | } 41 | 42 | final public DHKeyPair getPreKeyFor(int peerNum) { 43 | if (!preKeys.containsKey(peerNum)) { 44 | preKeys.put(peerNum, DHKeyPair.generate(false)); 45 | } 46 | return preKeys.get(peerNum); 47 | } 48 | 49 | final public SignedDHPubKey getSignedDHPreKeyFor(int peerNum) { 50 | if (!signedPreKeys.containsKey(peerNum)) { 51 | byte[] pkBytes = getPreKeyFor(peerNum).getPubKeyBytes(); 52 | byte[] signature = getIdentityKeyPair().sign(pkBytes); 53 | signedPreKeys.put(peerNum, new SignedDHPubKey(pkBytes, signature)); 54 | } 55 | return signedPreKeys.get(peerNum); 56 | } 57 | 58 | abstract public byte[] getKeyWithPeer(int n); 59 | } 60 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/GroupMessagingTestImplementation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.crypto.DHPubKey; 12 | 13 | public interface GroupMessagingTestImplementation { 14 | byte[] setupMessageForPeer(TThreadState state, DHPubKey[] peers, KeyServer keyServer, int peer); 15 | void processSetupMessage(TThreadState state, byte[] serialisedMessage, int participantNum); 16 | MessageDistributer sendMessage(TThreadState state, byte[] plaintext); 17 | byte[] receiveMessage(TThreadState state, byte[] serialisedMessage); 18 | } 19 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/KeyServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.crypto.SignedDHPubKey; 12 | 13 | final public class KeyServer { 14 | GroupMessagingState[] states; 15 | 16 | public KeyServer(GroupMessagingState[] states) { 17 | this.states = states; 18 | } 19 | 20 | public SignedDHPubKey getSignedPreKey(GroupMessagingState state, int peerNum) { 21 | return states[peerNum].getSignedDHPreKeyFor(state.getPeerNum()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/Main.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.art.ARTTestImplementation; 12 | import com.facebook.research.asynchronousratchetingtree.art.ARTSetupPhase; 13 | import com.facebook.research.asynchronousratchetingtree.art.ARTState; 14 | import com.facebook.research.asynchronousratchetingtree.crypto.DHPubKey; 15 | import com.facebook.research.asynchronousratchetingtree.dhratchet.DHRatchet; 16 | import com.facebook.research.asynchronousratchetingtree.dhratchet.DHRatchetSetupPhase; 17 | import com.facebook.research.asynchronousratchetingtree.dhratchet.DHRatchetState; 18 | 19 | import java.security.NoSuchAlgorithmException; 20 | import java.security.SecureRandom; 21 | import java.util.*; 22 | import javax.crypto.Cipher; 23 | 24 | public class Main { 25 | private static boolean debug = true; 26 | 27 | public static void main(String[] args) { 28 | checkForUnlimitedStrengthCrypto(); 29 | 30 | // Run a test run first to warm up the JIT 31 | artTestRun(8, 8); 32 | dhTestRun(8, 8); 33 | 34 | List artResults = new LinkedList<>(); 35 | List dhResults = new LinkedList<>(); 36 | 37 | int test_size_limit = 1000; 38 | double multiplier = 1.5; 39 | 40 | // First run ART tests. Warm up the JIT with a few smallish values, and then start recording results. 41 | for (int i = 2; i < 20; i += 2) { 42 | artTestRun(i, i); 43 | } 44 | int lastNumber = 1; 45 | for (double i = 2.0; i <= test_size_limit; i *= multiplier) { 46 | int n = (int) i; 47 | if (n == lastNumber) { 48 | continue; 49 | } 50 | lastNumber = n; 51 | System.gc(); 52 | artResults.add(artTestRun(n, n)); 53 | } 54 | 55 | // Now run DH tests. Again, warm up the JIT with a few smallish values, and then start recording results. 56 | for (int i = 2; i < 20; i += 2) { 57 | dhTestRun(i, i); 58 | } 59 | lastNumber = 1; 60 | for (double i = 2.0; i <= test_size_limit; i *= multiplier) { 61 | int n = (int) i; 62 | if (n == lastNumber) { 63 | continue; 64 | } 65 | System.gc(); 66 | dhResults.add(dhTestRun(n, n)); 67 | } 68 | 69 | TestResult.outputHeaderLine(); 70 | Iterator artIterator = artResults.iterator(); 71 | while (artIterator.hasNext()) { 72 | TestResult r = artIterator.next(); 73 | r.output(); 74 | } 75 | 76 | Iterator dhIterator = dhResults.iterator(); 77 | while (dhIterator.hasNext()) { 78 | TestResult r = dhIterator.next(); 79 | r.output(); 80 | } 81 | } 82 | 83 | private static TestResult artTestRun(int n, int activePeers) { 84 | ARTState[] states = new ARTState[n]; 85 | 86 | for (int i = 0; i < n; i++) { 87 | states[i] = new ARTState(i, n); 88 | } 89 | 90 | return testRun( 91 | n, 92 | activePeers, 93 | states, 94 | new ARTSetupPhase(), 95 | new ARTTestImplementation() 96 | ); 97 | } 98 | 99 | private static void checkForUnlimitedStrengthCrypto() { 100 | boolean hasEnoughCrypto = true; 101 | try { 102 | if (Cipher.getMaxAllowedKeyLength("AES") < 256) { 103 | hasEnoughCrypto = false; 104 | } 105 | } catch (NoSuchAlgorithmException e) { 106 | hasEnoughCrypto = false; 107 | } 108 | if (!hasEnoughCrypto) { 109 | Utils.except("Your JRE does not support unlimited-strength " + 110 | "cryptography and thus cannot run ART. See README.md " + 111 | "for Java Cryptography Extension (JCE) Unlimited " + 112 | "Strength Jurisdiction Policy Files installation " + 113 | "instructions."); 114 | } 115 | } 116 | 117 | private static TestResult dhTestRun(int n, int activePeers) { 118 | DHRatchetState[] states = new DHRatchetState[n]; 119 | 120 | for (int i = 0; i < n; i++) { 121 | states[i] = new DHRatchetState(i, n); 122 | } 123 | 124 | return testRun( 125 | n, 126 | activePeers, 127 | states, 128 | new DHRatchetSetupPhase(), 129 | new DHRatchet() 130 | ); 131 | } 132 | 133 | private static TestResult testRun( 134 | int n, 135 | int activeCount, 136 | TState[] states, 137 | GroupMessagingSetupPhase setupPhase, 138 | GroupMessagingTestImplementation implementation 139 | ) { 140 | String testName = implementation.getClass().getSimpleName(); 141 | if (debug) Utils.print("\nStarting " + testName + " test run with " + n + " participants, of which " + activeCount + " active.\n"); 142 | TestResult result = new TestResult(testName, n, activeCount); 143 | 144 | if (debug) Utils.print("Creating random messages and senders."); 145 | SecureRandom random = new SecureRandom(); 146 | Set activeSet = new HashSet<>(); 147 | activeSet.add(0); // We always want the initiator in the set. 148 | while (activeSet.size() < activeCount) { 149 | activeSet.add(random.nextInt(n)); 150 | } 151 | Integer[] active = activeSet.toArray(new Integer[0]); 152 | 153 | int messagesToSend = 100; 154 | int messageLength = 32; // Message length 32 bytes, so we can compare as if we were just sending a symmetric key. 155 | int[] messageSenders = new int[messagesToSend]; 156 | byte[][] messages = new byte[messagesToSend][messageLength]; 157 | for (int i = 0; i < messagesToSend; i++) { 158 | // We're only interested in ratcheting events, so senders should always be 159 | // different from the previous sender. 160 | messageSenders[i] = active[random.nextInt(activeCount)]; 161 | while (i != 0 && messageSenders[i] == messageSenders[i-1]) { 162 | messageSenders[i] = active[random.nextInt(activeCount)]; 163 | } 164 | random.nextBytes(messages[i]); 165 | } 166 | 167 | 168 | // Create the necessary setup tooling in advance. 169 | DHPubKey[] identities = new DHPubKey[n]; 170 | for (int i = 0; i < n ; i++) { 171 | identities[i] = states[i].getIdentityKeyPair().getPubKey(); 172 | } 173 | KeyServer keyServer = new KeyServer(states); 174 | 175 | // Create and cache the necessary PreKeys in advance. 176 | setupPhase.generateNecessaryPreKeys(states); 177 | 178 | // We'll need two timers; as some interleaving events are counted. 179 | Stopwatch stopwatch1 = new Stopwatch(); 180 | Stopwatch stopwatch2 = new Stopwatch(); 181 | 182 | if (debug) Utils.print("Setting up session for initiator."); 183 | stopwatch1.startInterval(); 184 | setupPhase.setupInitiator(implementation, states, identities, keyServer); 185 | stopwatch1.endInterval(); 186 | if (debug) Utils.print("Took " + stopwatch1.getTotal() + " nanoseconds."); 187 | if (debug) Utils.print("Initiator sent " + setupPhase.getBytesSentByInitiator() + " bytes."); 188 | result.setInitiatorSetupTime(stopwatch1.getTotal()); 189 | result.setInitiatorSetupBytes(setupPhase.getBytesSentByInitiator()); 190 | stopwatch1.reset(); 191 | 192 | if (debug) Utils.print("Setting up session for " + activeCount + " peers."); 193 | stopwatch1.startInterval(); 194 | setupPhase.setupAllOthers(implementation, states, active, identities, keyServer); 195 | stopwatch1.endInterval(); 196 | if (debug) Utils.print("Took " + stopwatch1.getTotal() + " nanoseconds."); 197 | if (debug) Utils.print("Others received " + setupPhase.getBytesReceivedByOthers() + " bytes."); 198 | if (debug) Utils.print("Others sent " + setupPhase.getBytesSentByOthers() + " bytes."); 199 | result.setOthersSetupTime(stopwatch1.getTotal()); 200 | result.setOthersSetupBytesReceived(setupPhase.getBytesReceivedByOthers()); 201 | result.setOthersSetupBytesSent(setupPhase.getBytesSentByOthers()); 202 | stopwatch1.reset(); 203 | 204 | // Use stopwatch1 for sender, stopwatch2 for receiving. 205 | if (debug) Utils.print("Sending " + messagesToSend + " messages."); 206 | int totalSendSizes = 0; 207 | int totalReceiveSizes = 0; 208 | for (int i = 0; i < messagesToSend; i++) { 209 | int sender = messageSenders[i]; 210 | byte[] message = messages[i]; 211 | stopwatch1.startInterval(); 212 | MessageDistributer messageDistributer = implementation.sendMessage(states[sender], message); 213 | stopwatch1.endInterval(); 214 | 215 | totalSendSizes += messageDistributer.totalSize(); 216 | 217 | for (int j = 0; j < activeCount; j++) { 218 | int receiver = active[j]; 219 | if (receiver == sender) { 220 | continue; 221 | } 222 | byte[] received = messageDistributer.getUpdateMessageForParticipantNum(receiver); 223 | totalReceiveSizes += received.length; 224 | stopwatch2.startInterval(); 225 | byte[] decrypted = implementation.receiveMessage(states[receiver], received); 226 | stopwatch2.endInterval(); 227 | if (!Arrays.equals(message, decrypted)) { 228 | Utils.except("Message doesn't match."); 229 | } 230 | } 231 | } 232 | if (debug) Utils.print("Total sending time " + stopwatch1.getTotal() + " nanoseconds."); 233 | if (debug) Utils.print("Total receiving time " + stopwatch2.getTotal() + " nanoseconds."); 234 | if (debug) Utils.print("Total bytes sent: " + totalSendSizes + "."); 235 | if (debug) Utils.print("Total bytes received: " + totalReceiveSizes + "."); 236 | result.setSendingTime(stopwatch1.getTotal()); 237 | result.setReceivingTime(stopwatch2.getTotal()); 238 | result.setBytesSent(totalSendSizes); 239 | result.setBytesReceived(totalReceiveSizes); 240 | 241 | if (debug) Utils.print("Ended test run with " + n + " participants.\n---------------\n"); 242 | 243 | return result; 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/MessageDistributer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree; 10 | 11 | public interface MessageDistributer { 12 | public byte[] getUpdateMessageForParticipantNum(int participantNum); 13 | public int totalSize(); 14 | } 15 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/Stopwatch.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree; 10 | 11 | public class Stopwatch { 12 | private long nanos; 13 | private long intervalStart; 14 | 15 | public Stopwatch() { 16 | reset(); 17 | } 18 | 19 | public void startInterval() { 20 | intervalStart = System.nanoTime(); 21 | } 22 | 23 | public void endInterval() { 24 | long intervalEnd = System.nanoTime(); 25 | nanos += intervalEnd - intervalStart; 26 | } 27 | 28 | public long getTotal() { 29 | return nanos; 30 | } 31 | 32 | public void reset() { 33 | nanos = 0; 34 | intervalStart = -1; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/TestResult.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree; 10 | 11 | public class TestResult { 12 | private String type; 13 | private int groupSize; 14 | private int activeUsers; 15 | private long initiatorSetupTime; 16 | private int initiatorSetupBytes; 17 | private long othersSetupTime; 18 | private int othersSetupBytesSent; 19 | private int othersSetupBytesReceived; 20 | private long sendingTime; 21 | private long receivingTime; 22 | private int bytesSent; 23 | private int bytesReceived; 24 | 25 | public TestResult(String type, int groupSize, int activeUsers) { 26 | this.type = type; 27 | this.groupSize = groupSize; 28 | this.activeUsers = activeUsers; 29 | } 30 | 31 | public void setInitiatorSetupTime(long initiatorSetupTime) { 32 | this.initiatorSetupTime = initiatorSetupTime; 33 | } 34 | 35 | public void setInitiatorSetupBytes(int initiatorSetupBytes) { 36 | this.initiatorSetupBytes = initiatorSetupBytes; 37 | } 38 | 39 | public void setOthersSetupTime(long othersSetupTime) { 40 | this.othersSetupTime = othersSetupTime; 41 | } 42 | 43 | public void setOthersSetupBytesSent(int othersSetupBytesSent) { 44 | this.othersSetupBytesSent = othersSetupBytesSent; 45 | } 46 | 47 | public void setOthersSetupBytesReceived(int othersSetupBytesReceived) { 48 | this.othersSetupBytesReceived = othersSetupBytesReceived; 49 | } 50 | 51 | public void setSendingTime(long sendingTime) { 52 | this.sendingTime = sendingTime; 53 | } 54 | 55 | public void setReceivingTime(long receivingTime) { 56 | this.receivingTime = receivingTime; 57 | } 58 | 59 | public void setBytesSent(int bytesSent) { 60 | this.bytesSent = bytesSent; 61 | } 62 | 63 | public void setBytesReceived(int bytesReceived) { 64 | this.bytesReceived = bytesReceived; 65 | } 66 | 67 | public static void outputHeaderLine() { 68 | String[] columns = new String[] { 69 | "type", 70 | "participants", 71 | "active_participants", 72 | "init_setup_time", 73 | "init_setup_bytes", 74 | "others_setup_time", 75 | "others_setup_bytes_sent", 76 | "others_setup_bytes_received", 77 | "send_time", 78 | "receive_time", 79 | "bytes_sent", 80 | "bytes_received" 81 | }; 82 | System.out.println(String.join(",", columns)); 83 | } 84 | 85 | public void output() { 86 | String[] columns = new String[] { 87 | type, 88 | String.valueOf(groupSize), 89 | String.valueOf(activeUsers), 90 | String.valueOf(initiatorSetupTime), 91 | String.valueOf(initiatorSetupBytes), 92 | String.valueOf(othersSetupTime), 93 | String.valueOf(othersSetupBytesSent), 94 | String.valueOf(othersSetupBytesReceived), 95 | String.valueOf(sendingTime), 96 | String.valueOf(receivingTime), 97 | String.valueOf(bytesSent), 98 | String.valueOf(bytesReceived) 99 | }; 100 | System.out.println(String.join(",", columns)); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/Utils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.art.message.thrift.NodeStruct; 12 | import com.facebook.research.asynchronousratchetingtree.art.tree.Node; 13 | import org.apache.thrift.TBase; 14 | import org.apache.thrift.TDeserializer; 15 | import org.apache.thrift.TException; 16 | import org.apache.thrift.TSerializer; 17 | import org.apache.thrift.protocol.TCompactProtocol; 18 | import org.apache.thrift.protocol.TSimpleJSONProtocol; 19 | 20 | import javax.xml.bind.DatatypeConverter; 21 | import java.text.SimpleDateFormat; 22 | import java.util.Date; 23 | 24 | final public class Utils { 25 | public static void print(String a, Object... args) { 26 | SimpleDateFormat f = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss.SSS"); 27 | System.out.printf("[" + f.format(new Date()) + "] " + a + "\n", args); 28 | } 29 | 30 | public static void printHex(byte[] a) { 31 | print(DatatypeConverter.printHexBinary(a)); 32 | } 33 | 34 | public static void printTree(Node tree) { 35 | NodeStruct struct = Node.toThrift(tree); 36 | TSerializer serialiser = new TSerializer(new TSimpleJSONProtocol.Factory()); 37 | try { 38 | Utils.print(new String(serialiser.serialize(hexifyNodeStruct(struct)))); 39 | } catch (TException e) { 40 | Utils.except(e); 41 | } 42 | } 43 | 44 | public static NodeStruct hexifyNodeStruct(NodeStruct tree) { 45 | if (tree == null) { 46 | return null; 47 | } 48 | NodeStruct result = new NodeStruct(); 49 | result.setPublicKey(DatatypeConverter.printHexBinary(tree.getPublicKey()).getBytes()); 50 | result.setLeft(hexifyNodeStruct(tree.getLeft())); 51 | result.setRight(hexifyNodeStruct(tree.getRight())); 52 | return result; 53 | } 54 | 55 | /** 56 | * Throw a RuntimeException to simplify the example code by avoiding Java's explicit error handling. 57 | * Yet another reason that this could should absolutely never be used as-is. 58 | * The method throws, but also has the exception as its return type, so we can make the compiler happy by throwing 59 | * the output, or just call it raw. 60 | */ 61 | public static RuntimeException except(Exception e) { 62 | print(e.getClass().getSimpleName()); 63 | print(e.getMessage()); 64 | e.printStackTrace(); 65 | throw new RuntimeException(); 66 | } 67 | 68 | public static RuntimeException except(String s) { 69 | print(s); 70 | throw new RuntimeException(); 71 | } 72 | 73 | public static byte[] serialise(TBase thrift) { 74 | TSerializer serialiser = new TSerializer(new TCompactProtocol.Factory()); 75 | try { 76 | return serialiser.serialize(thrift); 77 | } catch (TException e) { 78 | throw Utils.except(e); 79 | } 80 | } 81 | 82 | public static void deserialise(TObject object, byte[] data) { 83 | TDeserializer deserialiser = new TDeserializer(new TCompactProtocol.Factory()); 84 | try { 85 | deserialiser.deserialize(object, data); 86 | } catch (TException e) { 87 | Utils.except(e); 88 | } 89 | } 90 | 91 | public static long startBenchmark() { 92 | return new Date().toInstant().toEpochMilli(); 93 | } 94 | 95 | public static long getBenchmarkDelta(long start) { 96 | return new Date().toInstant().toEpochMilli() - start; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/ART.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.art; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.Utils; 12 | import com.facebook.research.asynchronousratchetingtree.art.message.AuthenticatedMessage; 13 | import com.facebook.research.asynchronousratchetingtree.art.message.SetupMessage; 14 | import com.facebook.research.asynchronousratchetingtree.art.message.UpdateMessage; 15 | import com.facebook.research.asynchronousratchetingtree.art.tree.*; 16 | import com.facebook.research.asynchronousratchetingtree.crypto.Crypto; 17 | import com.facebook.research.asynchronousratchetingtree.crypto.DHKeyPair; 18 | import com.facebook.research.asynchronousratchetingtree.crypto.DHPubKey; 19 | 20 | import java.util.*; 21 | 22 | public class ART { 23 | public static AuthenticatedMessage setupGroup(ARTState state, DHPubKey[] peers, Map preKeys) { 24 | int numPeers = peers.length; 25 | 26 | DHKeyPair selfLeaf = DHKeyPair.generate(false); 27 | DHKeyPair keyExchangeKeyPair = DHKeyPair.generate(false); 28 | 29 | DHKeyPair[] leaves = new DHKeyPair[numPeers]; 30 | leaves[0] = selfLeaf; 31 | 32 | for (int i = 1; i < numPeers; i++) { // generate leaf keys for each agent 33 | leaves[i] = DHKeyPair.fromBytes( 34 | Crypto.keyExchangeInitiate( 35 | state.getIdentityKeyPair(), 36 | peers[i], 37 | keyExchangeKeyPair, 38 | preKeys.get(i) 39 | ), 40 | false 41 | ); 42 | } 43 | SecretNode tree = createTree(leaves); 44 | state.setIdentities(peers); 45 | state.setTree(tree); 46 | 47 | SetupMessage sm = new SetupMessage( 48 | peers, 49 | preKeys, 50 | keyExchangeKeyPair.getPubKey(), 51 | tree 52 | ); 53 | byte[] serialisedSetupMessage = sm.serialise(); 54 | byte[] signature = state.getIdentityKeyPair().sign(serialisedSetupMessage); 55 | deriveStageKey(state); 56 | 57 | return new AuthenticatedMessage(serialisedSetupMessage, signature); 58 | } 59 | 60 | public static void processSetupMessage(ARTState state, AuthenticatedMessage signedMessage, int leafNum) { 61 | SetupMessage message = new SetupMessage(signedMessage.getMessage()); 62 | boolean verified = message.getIdentities()[0].verify(signedMessage.getMessage(), signedMessage.getAuthenticator()); 63 | if (!verified) { 64 | Utils.except("Signature verification failed on the setup message."); 65 | } 66 | 67 | if (!Arrays.equals(state.getPreKeyFor(0).getPubKey().getPubKeyBytes(), message.getEphemeralKeys().get(leafNum).getPubKeyBytes())) { 68 | Utils.except("Used the wrong ephemeral key."); 69 | } 70 | SecretLeafNode leaf = new SecretLeafNode( 71 | DHKeyPair.fromBytes( 72 | Crypto.keyExchangeReceive(state.getIdentityKeyPair(), message.getIdentities()[0], state.getPreKeyFor(0), message.getKeyExchangeKey()), 73 | false 74 | ) 75 | ); 76 | state.setTree( 77 | updateTreeWithSecretLeaf( 78 | message.getTree(), 79 | state.getPeerNum(), 80 | leaf 81 | ) 82 | ); 83 | state.setIdentities( 84 | message.getIdentities() 85 | ); 86 | deriveStageKey(state); 87 | } 88 | 89 | public static AuthenticatedMessage updateKey(ARTState state) { 90 | SecretLeafNode newNode = new SecretLeafNode(DHKeyPair.generate(false)); 91 | SecretNode newTree = updateTreeWithSecretLeaf(state.getTree(), state.getPeerNum(), newNode); 92 | state.setTree(newTree); 93 | UpdateMessage m = new UpdateMessage( 94 | state.getPeerNum(), 95 | pathNodeKeys(state.getTree(), state.getPeerNum()) 96 | ); 97 | byte[] serialisedUpdateMessage = m.serialise(); 98 | byte[] mac = Crypto.hmacSha256(serialisedUpdateMessage, state.getStageKey()); 99 | deriveStageKey(state); 100 | return new AuthenticatedMessage(serialisedUpdateMessage, mac); 101 | } 102 | 103 | public static void processUpdateMessage(ARTState state, AuthenticatedMessage message) { 104 | byte[] mac = Crypto.hmacSha256(message.getMessage(), state.getStageKey()); 105 | if (!Arrays.equals(mac, message.getAuthenticator())) { 106 | Utils.except("MAC is incorrect for update message."); 107 | } 108 | UpdateMessage updateMessage = new UpdateMessage(message.getMessage()); 109 | Node tree = state.getTree(); 110 | tree = updateTreeWithPublicPath(tree, updateMessage.getLeafNum(), updateMessage.getPath(), 0); 111 | state.setTree((SecretNode) tree); 112 | deriveStageKey(state); 113 | } 114 | 115 | private static SecretNode createTree(DHKeyPair[] leaves) { 116 | int n = leaves.length; 117 | if (n == 0) { 118 | Utils.except("No leaves"); 119 | } 120 | if (n == 1) { 121 | return new SecretLeafNode(leaves[0]); 122 | } 123 | int l = leftTreeSize(n); 124 | SecretNode left = createTree(Arrays.copyOfRange(leaves, 0, l)); 125 | Node right = createTree(Arrays.copyOfRange(leaves, l, n)); 126 | return new SecretParentNode(left, right); 127 | } 128 | 129 | private static void deriveStageKey(ARTState state) { 130 | state.setStageKey( 131 | Crypto.artKDF( 132 | state.getStageKey(), 133 | ((SecretParentNode)state.getTree()).getRawSecretKey(), 134 | state.getIdentities(), 135 | state.getTree() 136 | ) 137 | ); 138 | } 139 | 140 | private static SecretNode updateTreeWithSecretLeaf(Node tree, int i, SecretLeafNode newLeaf) { 141 | int l = leftTreeSize(tree.numLeaves()); 142 | if (tree.numLeaves() == 1) { 143 | return newLeaf; 144 | } 145 | SecretParentNode result; 146 | ParentNode treeParent = (ParentNode)tree; 147 | 148 | if (i < l) { 149 | result = new SecretParentNode( 150 | updateTreeWithSecretLeaf(treeParent.getLeft(), i, newLeaf), 151 | treeParent.getRight() 152 | ); 153 | } else { 154 | result = new SecretParentNode( 155 | treeParent.getLeft(), 156 | updateTreeWithSecretLeaf(treeParent.getRight(), i - l, newLeaf) 157 | ); 158 | } 159 | return result; 160 | } 161 | 162 | private static Node updateTreeWithPublicPath(Node tree, int i, DHPubKey[] newPath, int pathIndex) { 163 | int l = leftTreeSize(tree.numLeaves()); 164 | if (newPath.length - 1 == pathIndex) { 165 | return new PublicLeafNode(newPath[pathIndex]); 166 | } 167 | 168 | ParentNode result; 169 | ParentNode treeAsParent = (ParentNode) tree; 170 | Node newLeft; 171 | Node newRight; 172 | 173 | if (i < l) { 174 | newLeft = updateTreeWithPublicPath(treeAsParent.getLeft(), i, newPath, pathIndex + 1); 175 | newRight = treeAsParent.getRight(); 176 | } else { 177 | newLeft = treeAsParent.getLeft(); 178 | newRight = updateTreeWithPublicPath(treeAsParent.getRight(), i - l, newPath, pathIndex + 1); 179 | } 180 | 181 | if (newLeft instanceof SecretNode) { 182 | result = new SecretParentNode((SecretNode)newLeft, newRight); 183 | } else if (newRight instanceof SecretNode) { 184 | result = new SecretParentNode(newLeft, (SecretNode)newRight); 185 | } else { 186 | result = new PublicParentNode( 187 | newPath[pathIndex], 188 | newLeft, 189 | newRight 190 | ); 191 | } 192 | 193 | if (!Arrays.equals(result.getPubKey().getPubKeyBytes(), newPath[pathIndex].getPubKeyBytes())) { 194 | Utils.printTree(result); 195 | Utils.except("Update operation inconsistent with provided path."); 196 | } 197 | 198 | return result; 199 | } 200 | 201 | protected static DHPubKey[] pathNodeKeys(Node tree, int i) { 202 | List keys = new ArrayList(); 203 | 204 | while (tree.numLeaves() > 1) { 205 | int l = leftTreeSize(tree.numLeaves()); 206 | ParentNode parentNode = (ParentNode) tree; 207 | keys.add(tree.getPubKey()); 208 | if (i < l) { 209 | tree = parentNode.getLeft(); 210 | } else { 211 | tree = parentNode.getRight(); 212 | i -= l; 213 | } 214 | } 215 | keys.add(tree.getPubKey()); 216 | return keys.toArray(new DHPubKey[] {}); 217 | } 218 | 219 | private static int leftTreeSize(int numLeaves) { 220 | return (int)Math.pow(2, Math.ceil(Math.log(numLeaves) / Math.log(2)) - 1); 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/ARTSetupPhase.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.art; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.GroupMessagingSetupPhase; 12 | import com.facebook.research.asynchronousratchetingtree.GroupMessagingTestImplementation; 13 | import com.facebook.research.asynchronousratchetingtree.KeyServer; 14 | import com.facebook.research.asynchronousratchetingtree.crypto.DHPubKey; 15 | 16 | public class ARTSetupPhase implements GroupMessagingSetupPhase { 17 | private byte[] setupMessage; 18 | private int bytesReceivedByOthers = 0; 19 | 20 | @Override 21 | public void generateNecessaryPreKeys(ARTState[] states) { 22 | // We only need PreKeys for the initiator. 23 | for (int i = 1; i < states.length; i++) { 24 | states[i].getSignedDHPreKeyFor(0); 25 | } 26 | } 27 | 28 | @Override 29 | public void setupInitiator(GroupMessagingTestImplementation implementation, ARTState[] states, DHPubKey[] identities, KeyServer keyServer) { 30 | int n = states.length; 31 | 32 | // Setup message is the same for all peers, so let's just do it once. 33 | setupMessage = implementation.setupMessageForPeer( 34 | states[0], 35 | identities, 36 | keyServer, 37 | 1 38 | ); 39 | } 40 | 41 | @Override 42 | public int getBytesSentByInitiator() { 43 | return setupMessage.length; 44 | } 45 | 46 | @Override 47 | public void setupAllOthers(GroupMessagingTestImplementation implementation, ARTState[] states, Integer[] active, DHPubKey[] identities, KeyServer keyServer) { 48 | for (int i = 0; i < active.length; i++) { 49 | int which = active[i]; 50 | if (which == 0) { // Don't import the setup message to the initiator itself. 51 | continue; 52 | } 53 | bytesReceivedByOthers += setupMessage.length; 54 | implementation.processSetupMessage(states[which], setupMessage, which); 55 | } 56 | } 57 | 58 | @Override 59 | public int getBytesSentByOthers() { 60 | return 0; 61 | } 62 | 63 | @Override 64 | public int getBytesReceivedByOthers() { 65 | return bytesReceivedByOthers; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/ARTState.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.art; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.GroupMessagingState; 12 | import com.facebook.research.asynchronousratchetingtree.Utils; 13 | import com.facebook.research.asynchronousratchetingtree.art.tree.SecretParentNode; 14 | import com.facebook.research.asynchronousratchetingtree.crypto.DHPubKey; 15 | import com.facebook.research.asynchronousratchetingtree.art.tree.SecretNode; 16 | 17 | public class ARTState extends GroupMessagingState { 18 | private SecretParentNode tree; 19 | private DHPubKey[] identities; 20 | private byte[] stageKey = new byte[0]; 21 | private byte[] setupMessage; 22 | 23 | public ARTState(int peerNum, int peerCount) { 24 | super(peerNum, peerCount); 25 | } 26 | 27 | public SecretNode getTree() { 28 | return tree; 29 | } 30 | 31 | public void setSetupMessage(byte[] setupMessage) { 32 | this.setupMessage = setupMessage; 33 | } 34 | 35 | public byte[] getSetupMessage() { 36 | return setupMessage; 37 | } 38 | 39 | public byte[] getKeyWithPeer(int n) { 40 | return getStageKey(); 41 | } 42 | 43 | public DHPubKey[] getIdentities() { 44 | return identities; 45 | } 46 | 47 | public void setIdentities(DHPubKey[] identities) { 48 | this.identities = identities; 49 | } 50 | 51 | public byte[] getStageKey() { 52 | return stageKey; 53 | } 54 | 55 | public void setStageKey(byte[] stageKey) { 56 | this.stageKey = stageKey; 57 | } 58 | 59 | public void setTree(SecretNode tree) { 60 | if (!(tree instanceof SecretParentNode)) { 61 | Utils.except("Tree cannot be a leaf."); 62 | } 63 | this.tree = (SecretParentNode) tree; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/ARTTestImplementation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.art; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.KeyServer; 12 | import com.facebook.research.asynchronousratchetingtree.Utils; 13 | import com.facebook.research.asynchronousratchetingtree.art.message.*; 14 | import com.facebook.research.asynchronousratchetingtree.GroupMessagingTestImplementation; 15 | import com.facebook.research.asynchronousratchetingtree.MessageDistributer; 16 | import com.facebook.research.asynchronousratchetingtree.art.message.CiphertextMessage; 17 | import com.facebook.research.asynchronousratchetingtree.crypto.Crypto; 18 | import com.facebook.research.asynchronousratchetingtree.crypto.DHPubKey; 19 | import com.facebook.research.asynchronousratchetingtree.crypto.SignedDHPubKey; 20 | import com.facebook.research.asynchronousratchetingtree.art.message.ARTMessageDistributer; 21 | import com.facebook.research.asynchronousratchetingtree.art.message.AuthenticatedMessage; 22 | 23 | import java.util.*; 24 | 25 | final public class ARTTestImplementation implements GroupMessagingTestImplementation { 26 | public byte[] setupMessageForPeer(ARTState state, DHPubKey[] peers, KeyServer keyServer, int peer) { 27 | byte[] setupMessageSerialised = state.getSetupMessage(); 28 | if (setupMessageSerialised == null) { 29 | Map preKeys = new HashMap<>(); 30 | for (int i = 1; i < peers.length; i++) { 31 | SignedDHPubKey signedPreKey = keyServer.getSignedPreKey(state, i); 32 | if (!peers[i].verify(signedPreKey.getPubKeyBytes(), signedPreKey.getSignature())) { 33 | Utils.except("PreKey signature check failed."); 34 | } 35 | preKeys.put(i, signedPreKey); 36 | } 37 | AuthenticatedMessage setupMessage = ART.setupGroup(state, peers, preKeys); 38 | setupMessageSerialised = setupMessage.serialise(); 39 | state.setSetupMessage(setupMessageSerialised); 40 | } 41 | return setupMessageSerialised; 42 | } 43 | 44 | public void processSetupMessage(ARTState state, byte[] serialisedMessage, int leafNum) { 45 | AuthenticatedMessage message = new AuthenticatedMessage(serialisedMessage); 46 | ART.processSetupMessage(state, message, leafNum); 47 | } 48 | 49 | public MessageDistributer sendMessage(ARTState state, byte[] plaintext) { 50 | AuthenticatedMessage updateMessage = ART.updateKey(state); 51 | 52 | // All peers have the same key, so the "withPeer(0)" aspect of this is a no-op. 53 | byte[] key = state.getKeyWithPeer(0); 54 | byte[] ciphertext = Crypto.encrypt(plaintext, key); 55 | 56 | CiphertextMessage message = new CiphertextMessage(updateMessage, ciphertext); 57 | return new ARTMessageDistributer(message); 58 | } 59 | 60 | public byte[] receiveMessage(ARTState state, byte[] serialisedMessage) { 61 | CiphertextMessage message = new CiphertextMessage(serialisedMessage); 62 | ART.processUpdateMessage(state, message.getAuthenticatedMessage()); 63 | 64 | // All peers have the same key, so the "withPeer(0)" aspect of this is a no-op. 65 | byte[] key = state.getKeyWithPeer(0); 66 | return Crypto.decrypt(message.getCiphertext(), key); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/message/ARTMessageDistributer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.art.message; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.MessageDistributer; 12 | 13 | public class ARTMessageDistributer implements MessageDistributer { 14 | private byte[] serialised; 15 | 16 | public ARTMessageDistributer(CiphertextMessage updateMessage) { 17 | serialised = updateMessage.serialise(); 18 | } 19 | 20 | @Override 21 | public byte[] getUpdateMessageForParticipantNum(int participantNum) { 22 | return serialised; 23 | } 24 | 25 | @Override 26 | public int totalSize() { 27 | return serialised.length; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/message/AuthenticatedMessage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.art.message; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.Utils; 12 | import com.facebook.research.asynchronousratchetingtree.art.message.thrift.AuthenticatedMessageStruct; 13 | 14 | public class AuthenticatedMessage { 15 | private byte[] message; 16 | private byte[] authenticator; 17 | 18 | public AuthenticatedMessage( 19 | byte[] message, 20 | byte[] authenticator 21 | ) { 22 | this.message = message; 23 | this.authenticator = authenticator; 24 | } 25 | 26 | public AuthenticatedMessage(byte[] thriftSerialised) { 27 | AuthenticatedMessageStruct struct = new AuthenticatedMessageStruct(); 28 | Utils.deserialise(struct, thriftSerialised); 29 | 30 | message = struct.getMessage(); 31 | authenticator = struct.getAuthenticator(); 32 | } 33 | 34 | public AuthenticatedMessage(AuthenticatedMessageStruct struct) { 35 | message = struct.getMessage(); 36 | authenticator = struct.getAuthenticator(); 37 | } 38 | 39 | public byte[] getMessage() { 40 | return message; 41 | } 42 | 43 | public byte[] getAuthenticator() { 44 | return authenticator; 45 | } 46 | 47 | public AuthenticatedMessageStruct getThriftStruct() { 48 | AuthenticatedMessageStruct struct = new AuthenticatedMessageStruct(); 49 | struct.setMessage(message); 50 | struct.setAuthenticator(authenticator); 51 | return struct; 52 | } 53 | 54 | public byte[] serialise() { 55 | return Utils.serialise(getThriftStruct()); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/message/CiphertextMessage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.art.message; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.Utils; 12 | import com.facebook.research.asynchronousratchetingtree.art.message.thrift.CiphertextMessageStruct; 13 | 14 | public class CiphertextMessage { 15 | private AuthenticatedMessage authenticatedMessage; 16 | private byte[] ciphertext; 17 | 18 | public CiphertextMessage(AuthenticatedMessage authenticatedMessage, byte[] ciphertext) { 19 | this.authenticatedMessage = authenticatedMessage; 20 | this.ciphertext = ciphertext; 21 | } 22 | 23 | public CiphertextMessage(byte[] thriftSerialised) { 24 | CiphertextMessageStruct struct = new CiphertextMessageStruct(); 25 | Utils.deserialise(struct, thriftSerialised); 26 | authenticatedMessage = new AuthenticatedMessage(struct.getAuthenticatedMessage()); 27 | ciphertext = struct.getCiphertext(); 28 | } 29 | 30 | public AuthenticatedMessage getAuthenticatedMessage() { 31 | return authenticatedMessage; 32 | } 33 | 34 | public byte[] getCiphertext() { 35 | return ciphertext; 36 | } 37 | 38 | public byte[] serialise() { 39 | CiphertextMessageStruct struct = new CiphertextMessageStruct(); 40 | struct.setAuthenticatedMessage(authenticatedMessage.getThriftStruct()); 41 | struct.setCiphertext(ciphertext); 42 | return Utils.serialise(struct); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/message/SetupMessage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.art.message; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.art.message.thrift.SetupMessageStruct; 12 | import com.facebook.research.asynchronousratchetingtree.art.tree.Node; 13 | import com.facebook.research.asynchronousratchetingtree.Utils; 14 | import com.facebook.research.asynchronousratchetingtree.crypto.DHPubKey; 15 | 16 | import java.util.*; 17 | 18 | public class SetupMessage { 19 | private DHPubKey[] identities; 20 | private Map ephemeralKeys; 21 | private DHPubKey keyExchangeKey; 22 | private Node tree; 23 | 24 | public SetupMessage(DHPubKey[] identities, Map ephemeralKeys, DHPubKey keyExchangeKey, Node tree) { 25 | this.identities = identities; 26 | this.ephemeralKeys = ephemeralKeys; 27 | this.keyExchangeKey = keyExchangeKey; 28 | this.tree = tree; 29 | } 30 | 31 | public SetupMessage(byte[] thriftSerialised) { 32 | SetupMessageStruct struct = new SetupMessageStruct(); 33 | Utils.deserialise(struct, thriftSerialised); 34 | 35 | identities = new DHPubKey[struct.getIdentitiesSize()]; 36 | for (int i = 0; i < identities.length; i++) { 37 | identities[i] = DHPubKey.pubKey( 38 | Base64.getDecoder().decode(struct.getIdentities().get(i)) 39 | ); 40 | } 41 | 42 | ephemeralKeys = new HashMap<>(); 43 | for (int i = 1; i < identities.length; i++) { 44 | ephemeralKeys.put( 45 | i, 46 | DHPubKey.pubKey( 47 | Base64.getDecoder().decode(struct.getEphemeralKeys().get(i)) 48 | ) 49 | ); 50 | } 51 | 52 | keyExchangeKey = DHPubKey.pubKey(struct.getKeyExchangeKey()); 53 | tree = Node.fromThrift(struct.getTree()); 54 | } 55 | 56 | public DHPubKey[] getIdentities() { 57 | return identities; 58 | } 59 | 60 | public Map getEphemeralKeys() { 61 | return ephemeralKeys; 62 | } 63 | 64 | public DHPubKey getKeyExchangeKey() { 65 | return keyExchangeKey; 66 | } 67 | 68 | public Node getTree() { 69 | return tree; 70 | } 71 | 72 | public byte[] serialise() { 73 | List identities = new ArrayList<>(); 74 | Map ephemeralKeys = new HashMap<>(); 75 | 76 | for (int i = 0; i < this.identities.length; i++) { 77 | identities.add(Base64.getEncoder().encodeToString(this.identities[i].getPubKeyBytes())); 78 | } 79 | 80 | for (int i = 1; i < this.identities.length; i++) { 81 | ephemeralKeys.put(i, Base64.getEncoder().encodeToString(this.ephemeralKeys.get(i).getPubKeyBytes())); 82 | } 83 | 84 | SetupMessageStruct struct = new SetupMessageStruct(); 85 | struct.setIdentities(identities); 86 | struct.setEphemeralKeys(ephemeralKeys); 87 | struct.setKeyExchangeKey(keyExchangeKey.getPubKeyBytes()); 88 | struct.setTree(Node.toThrift(tree)); 89 | 90 | return Utils.serialise(struct); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/message/UpdateMessage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.art.message; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.Utils; 12 | import com.facebook.research.asynchronousratchetingtree.art.message.thrift.UpdateMessageStruct; 13 | import com.facebook.research.asynchronousratchetingtree.crypto.DHPubKey; 14 | 15 | import java.util.ArrayList; 16 | import java.util.Base64; 17 | import java.util.List; 18 | 19 | public class UpdateMessage { 20 | int leafNum; 21 | DHPubKey[] path; 22 | 23 | public UpdateMessage(int leafNum, DHPubKey[] path) { 24 | this.leafNum = leafNum; 25 | this.path = path; 26 | } 27 | 28 | public UpdateMessage(byte[] thriftSerialised) { 29 | UpdateMessageStruct struct = new UpdateMessageStruct(); 30 | Utils.deserialise(struct, thriftSerialised); 31 | 32 | leafNum = struct.getLeafNum(); 33 | path = new DHPubKey[struct.getPathSize()]; 34 | for (int i = 0; i < path.length; i++) { 35 | path[i] = DHPubKey.pubKey( 36 | Base64.getDecoder().decode(struct.getPath().get(i)) 37 | ); 38 | } 39 | } 40 | 41 | public int getLeafNum() { 42 | return leafNum; 43 | } 44 | 45 | public DHPubKey[] getPath() { 46 | return path; 47 | } 48 | 49 | public byte[] serialise() { 50 | List path = new ArrayList<>(); 51 | for (int i = 0; i < this.path.length; i++) { 52 | path.add(Base64.getEncoder().encodeToString(this.path[i].getPubKeyBytes())); 53 | } 54 | UpdateMessageStruct struct = new UpdateMessageStruct(); 55 | struct.setLeafNum(leafNum); 56 | struct.setPath(path); 57 | return Utils.serialise(struct); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/message/thrift/ART.thrift: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017-present, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the license found in the 5 | # LICENSE file in the root directory of this source tree. 6 | # 7 | # Compile this file using the Thrift compiler, from the current directory, with the following command: 8 | # thrift -r --gen java -out ../../../../../../../ ART.thrift 9 | 10 | namespace java com.facebook.research.asynchronousratchetingtree.art.message.thrift 11 | 12 | struct SetupMessageStruct { 13 | 1: i32 leafNum, 14 | 2: list identities, 15 | 3: map ephemeralKeys, 16 | 4: binary keyExchangeKey, 17 | 5: NodeStruct tree, 18 | } 19 | 20 | struct NodeStruct { 21 | 1: binary publicKey, 22 | 2: optional NodeStruct left, 23 | 3: optional NodeStruct right, 24 | } 25 | 26 | struct UpdateMessageStruct { 27 | 1: i32 leafNum, 28 | 2: list path, 29 | } 30 | 31 | struct CiphertextMessageStruct { 32 | 1: AuthenticatedMessageStruct authenticatedMessage, 33 | 2: binary ciphertext, 34 | } 35 | 36 | struct AuthenticatedMessageStruct { 37 | 1: binary message, 38 | 2: binary authenticator, 39 | } 40 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/message/thrift/AuthenticatedMessageStruct.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Autogenerated by Thrift Compiler (0.10.0) 3 | * 4 | * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 5 | * @generated 6 | */ 7 | package com.facebook.research.asynchronousratchetingtree.art.message.thrift; 8 | 9 | @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) 10 | @javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2018-01-05") 11 | public class AuthenticatedMessageStruct implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { 12 | private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AuthenticatedMessageStruct"); 13 | 14 | private static final org.apache.thrift.protocol.TField MESSAGE_FIELD_DESC = new org.apache.thrift.protocol.TField("message", org.apache.thrift.protocol.TType.STRING, (short)1); 15 | private static final org.apache.thrift.protocol.TField AUTHENTICATOR_FIELD_DESC = new org.apache.thrift.protocol.TField("authenticator", org.apache.thrift.protocol.TType.STRING, (short)2); 16 | 17 | private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new AuthenticatedMessageStructStandardSchemeFactory(); 18 | private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new AuthenticatedMessageStructTupleSchemeFactory(); 19 | 20 | public java.nio.ByteBuffer message; // required 21 | public java.nio.ByteBuffer authenticator; // required 22 | 23 | /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ 24 | public enum _Fields implements org.apache.thrift.TFieldIdEnum { 25 | MESSAGE((short)1, "message"), 26 | AUTHENTICATOR((short)2, "authenticator"); 27 | 28 | private static final java.util.Map byName = new java.util.HashMap(); 29 | 30 | static { 31 | for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { 32 | byName.put(field.getFieldName(), field); 33 | } 34 | } 35 | 36 | /** 37 | * Find the _Fields constant that matches fieldId, or null if its not found. 38 | */ 39 | public static _Fields findByThriftId(int fieldId) { 40 | switch(fieldId) { 41 | case 1: // MESSAGE 42 | return MESSAGE; 43 | case 2: // AUTHENTICATOR 44 | return AUTHENTICATOR; 45 | default: 46 | return null; 47 | } 48 | } 49 | 50 | /** 51 | * Find the _Fields constant that matches fieldId, throwing an exception 52 | * if it is not found. 53 | */ 54 | public static _Fields findByThriftIdOrThrow(int fieldId) { 55 | _Fields fields = findByThriftId(fieldId); 56 | if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!"); 57 | return fields; 58 | } 59 | 60 | /** 61 | * Find the _Fields constant that matches name, or null if its not found. 62 | */ 63 | public static _Fields findByName(java.lang.String name) { 64 | return byName.get(name); 65 | } 66 | 67 | private final short _thriftId; 68 | private final java.lang.String _fieldName; 69 | 70 | _Fields(short thriftId, java.lang.String fieldName) { 71 | _thriftId = thriftId; 72 | _fieldName = fieldName; 73 | } 74 | 75 | public short getThriftFieldId() { 76 | return _thriftId; 77 | } 78 | 79 | public java.lang.String getFieldName() { 80 | return _fieldName; 81 | } 82 | } 83 | 84 | // isset id assignments 85 | public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; 86 | static { 87 | java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); 88 | tmpMap.put(_Fields.MESSAGE, new org.apache.thrift.meta_data.FieldMetaData("message", org.apache.thrift.TFieldRequirementType.DEFAULT, 89 | new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING , true))); 90 | tmpMap.put(_Fields.AUTHENTICATOR, new org.apache.thrift.meta_data.FieldMetaData("authenticator", org.apache.thrift.TFieldRequirementType.DEFAULT, 91 | new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING , true))); 92 | metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); 93 | org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(AuthenticatedMessageStruct.class, metaDataMap); 94 | } 95 | 96 | public AuthenticatedMessageStruct() { 97 | } 98 | 99 | public AuthenticatedMessageStruct( 100 | java.nio.ByteBuffer message, 101 | java.nio.ByteBuffer authenticator) 102 | { 103 | this(); 104 | this.message = org.apache.thrift.TBaseHelper.copyBinary(message); 105 | this.authenticator = org.apache.thrift.TBaseHelper.copyBinary(authenticator); 106 | } 107 | 108 | /** 109 | * Performs a deep copy on other. 110 | */ 111 | public AuthenticatedMessageStruct(AuthenticatedMessageStruct other) { 112 | if (other.isSetMessage()) { 113 | this.message = org.apache.thrift.TBaseHelper.copyBinary(other.message); 114 | } 115 | if (other.isSetAuthenticator()) { 116 | this.authenticator = org.apache.thrift.TBaseHelper.copyBinary(other.authenticator); 117 | } 118 | } 119 | 120 | public AuthenticatedMessageStruct deepCopy() { 121 | return new AuthenticatedMessageStruct(this); 122 | } 123 | 124 | @Override 125 | public void clear() { 126 | this.message = null; 127 | this.authenticator = null; 128 | } 129 | 130 | public byte[] getMessage() { 131 | setMessage(org.apache.thrift.TBaseHelper.rightSize(message)); 132 | return message == null ? null : message.array(); 133 | } 134 | 135 | public java.nio.ByteBuffer bufferForMessage() { 136 | return org.apache.thrift.TBaseHelper.copyBinary(message); 137 | } 138 | 139 | public AuthenticatedMessageStruct setMessage(byte[] message) { 140 | this.message = message == null ? (java.nio.ByteBuffer)null : java.nio.ByteBuffer.wrap(message.clone()); 141 | return this; 142 | } 143 | 144 | public AuthenticatedMessageStruct setMessage(java.nio.ByteBuffer message) { 145 | this.message = org.apache.thrift.TBaseHelper.copyBinary(message); 146 | return this; 147 | } 148 | 149 | public void unsetMessage() { 150 | this.message = null; 151 | } 152 | 153 | /** Returns true if field message is set (has been assigned a value) and false otherwise */ 154 | public boolean isSetMessage() { 155 | return this.message != null; 156 | } 157 | 158 | public void setMessageIsSet(boolean value) { 159 | if (!value) { 160 | this.message = null; 161 | } 162 | } 163 | 164 | public byte[] getAuthenticator() { 165 | setAuthenticator(org.apache.thrift.TBaseHelper.rightSize(authenticator)); 166 | return authenticator == null ? null : authenticator.array(); 167 | } 168 | 169 | public java.nio.ByteBuffer bufferForAuthenticator() { 170 | return org.apache.thrift.TBaseHelper.copyBinary(authenticator); 171 | } 172 | 173 | public AuthenticatedMessageStruct setAuthenticator(byte[] authenticator) { 174 | this.authenticator = authenticator == null ? (java.nio.ByteBuffer)null : java.nio.ByteBuffer.wrap(authenticator.clone()); 175 | return this; 176 | } 177 | 178 | public AuthenticatedMessageStruct setAuthenticator(java.nio.ByteBuffer authenticator) { 179 | this.authenticator = org.apache.thrift.TBaseHelper.copyBinary(authenticator); 180 | return this; 181 | } 182 | 183 | public void unsetAuthenticator() { 184 | this.authenticator = null; 185 | } 186 | 187 | /** Returns true if field authenticator is set (has been assigned a value) and false otherwise */ 188 | public boolean isSetAuthenticator() { 189 | return this.authenticator != null; 190 | } 191 | 192 | public void setAuthenticatorIsSet(boolean value) { 193 | if (!value) { 194 | this.authenticator = null; 195 | } 196 | } 197 | 198 | public void setFieldValue(_Fields field, java.lang.Object value) { 199 | switch (field) { 200 | case MESSAGE: 201 | if (value == null) { 202 | unsetMessage(); 203 | } else { 204 | if (value instanceof byte[]) { 205 | setMessage((byte[])value); 206 | } else { 207 | setMessage((java.nio.ByteBuffer)value); 208 | } 209 | } 210 | break; 211 | 212 | case AUTHENTICATOR: 213 | if (value == null) { 214 | unsetAuthenticator(); 215 | } else { 216 | if (value instanceof byte[]) { 217 | setAuthenticator((byte[])value); 218 | } else { 219 | setAuthenticator((java.nio.ByteBuffer)value); 220 | } 221 | } 222 | break; 223 | 224 | } 225 | } 226 | 227 | public java.lang.Object getFieldValue(_Fields field) { 228 | switch (field) { 229 | case MESSAGE: 230 | return getMessage(); 231 | 232 | case AUTHENTICATOR: 233 | return getAuthenticator(); 234 | 235 | } 236 | throw new java.lang.IllegalStateException(); 237 | } 238 | 239 | /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ 240 | public boolean isSet(_Fields field) { 241 | if (field == null) { 242 | throw new java.lang.IllegalArgumentException(); 243 | } 244 | 245 | switch (field) { 246 | case MESSAGE: 247 | return isSetMessage(); 248 | case AUTHENTICATOR: 249 | return isSetAuthenticator(); 250 | } 251 | throw new java.lang.IllegalStateException(); 252 | } 253 | 254 | @Override 255 | public boolean equals(java.lang.Object that) { 256 | if (that == null) 257 | return false; 258 | if (that instanceof AuthenticatedMessageStruct) 259 | return this.equals((AuthenticatedMessageStruct)that); 260 | return false; 261 | } 262 | 263 | public boolean equals(AuthenticatedMessageStruct that) { 264 | if (that == null) 265 | return false; 266 | if (this == that) 267 | return true; 268 | 269 | boolean this_present_message = true && this.isSetMessage(); 270 | boolean that_present_message = true && that.isSetMessage(); 271 | if (this_present_message || that_present_message) { 272 | if (!(this_present_message && that_present_message)) 273 | return false; 274 | if (!this.message.equals(that.message)) 275 | return false; 276 | } 277 | 278 | boolean this_present_authenticator = true && this.isSetAuthenticator(); 279 | boolean that_present_authenticator = true && that.isSetAuthenticator(); 280 | if (this_present_authenticator || that_present_authenticator) { 281 | if (!(this_present_authenticator && that_present_authenticator)) 282 | return false; 283 | if (!this.authenticator.equals(that.authenticator)) 284 | return false; 285 | } 286 | 287 | return true; 288 | } 289 | 290 | @Override 291 | public int hashCode() { 292 | int hashCode = 1; 293 | 294 | hashCode = hashCode * 8191 + ((isSetMessage()) ? 131071 : 524287); 295 | if (isSetMessage()) 296 | hashCode = hashCode * 8191 + message.hashCode(); 297 | 298 | hashCode = hashCode * 8191 + ((isSetAuthenticator()) ? 131071 : 524287); 299 | if (isSetAuthenticator()) 300 | hashCode = hashCode * 8191 + authenticator.hashCode(); 301 | 302 | return hashCode; 303 | } 304 | 305 | @Override 306 | public int compareTo(AuthenticatedMessageStruct other) { 307 | if (!getClass().equals(other.getClass())) { 308 | return getClass().getName().compareTo(other.getClass().getName()); 309 | } 310 | 311 | int lastComparison = 0; 312 | 313 | lastComparison = java.lang.Boolean.valueOf(isSetMessage()).compareTo(other.isSetMessage()); 314 | if (lastComparison != 0) { 315 | return lastComparison; 316 | } 317 | if (isSetMessage()) { 318 | lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.message, other.message); 319 | if (lastComparison != 0) { 320 | return lastComparison; 321 | } 322 | } 323 | lastComparison = java.lang.Boolean.valueOf(isSetAuthenticator()).compareTo(other.isSetAuthenticator()); 324 | if (lastComparison != 0) { 325 | return lastComparison; 326 | } 327 | if (isSetAuthenticator()) { 328 | lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.authenticator, other.authenticator); 329 | if (lastComparison != 0) { 330 | return lastComparison; 331 | } 332 | } 333 | return 0; 334 | } 335 | 336 | public _Fields fieldForId(int fieldId) { 337 | return _Fields.findByThriftId(fieldId); 338 | } 339 | 340 | public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { 341 | scheme(iprot).read(iprot, this); 342 | } 343 | 344 | public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { 345 | scheme(oprot).write(oprot, this); 346 | } 347 | 348 | @Override 349 | public java.lang.String toString() { 350 | java.lang.StringBuilder sb = new java.lang.StringBuilder("AuthenticatedMessageStruct("); 351 | boolean first = true; 352 | 353 | sb.append("message:"); 354 | if (this.message == null) { 355 | sb.append("null"); 356 | } else { 357 | org.apache.thrift.TBaseHelper.toString(this.message, sb); 358 | } 359 | first = false; 360 | if (!first) sb.append(", "); 361 | sb.append("authenticator:"); 362 | if (this.authenticator == null) { 363 | sb.append("null"); 364 | } else { 365 | org.apache.thrift.TBaseHelper.toString(this.authenticator, sb); 366 | } 367 | first = false; 368 | sb.append(")"); 369 | return sb.toString(); 370 | } 371 | 372 | public void validate() throws org.apache.thrift.TException { 373 | // check for required fields 374 | // check for sub-struct validity 375 | } 376 | 377 | private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { 378 | try { 379 | write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); 380 | } catch (org.apache.thrift.TException te) { 381 | throw new java.io.IOException(te); 382 | } 383 | } 384 | 385 | private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { 386 | try { 387 | read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); 388 | } catch (org.apache.thrift.TException te) { 389 | throw new java.io.IOException(te); 390 | } 391 | } 392 | 393 | private static class AuthenticatedMessageStructStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { 394 | public AuthenticatedMessageStructStandardScheme getScheme() { 395 | return new AuthenticatedMessageStructStandardScheme(); 396 | } 397 | } 398 | 399 | private static class AuthenticatedMessageStructStandardScheme extends org.apache.thrift.scheme.StandardScheme { 400 | 401 | public void read(org.apache.thrift.protocol.TProtocol iprot, AuthenticatedMessageStruct struct) throws org.apache.thrift.TException { 402 | org.apache.thrift.protocol.TField schemeField; 403 | iprot.readStructBegin(); 404 | while (true) 405 | { 406 | schemeField = iprot.readFieldBegin(); 407 | if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 408 | break; 409 | } 410 | switch (schemeField.id) { 411 | case 1: // MESSAGE 412 | if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { 413 | struct.message = iprot.readBinary(); 414 | struct.setMessageIsSet(true); 415 | } else { 416 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 417 | } 418 | break; 419 | case 2: // AUTHENTICATOR 420 | if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { 421 | struct.authenticator = iprot.readBinary(); 422 | struct.setAuthenticatorIsSet(true); 423 | } else { 424 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 425 | } 426 | break; 427 | default: 428 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 429 | } 430 | iprot.readFieldEnd(); 431 | } 432 | iprot.readStructEnd(); 433 | 434 | // check for required fields of primitive type, which can't be checked in the validate method 435 | struct.validate(); 436 | } 437 | 438 | public void write(org.apache.thrift.protocol.TProtocol oprot, AuthenticatedMessageStruct struct) throws org.apache.thrift.TException { 439 | struct.validate(); 440 | 441 | oprot.writeStructBegin(STRUCT_DESC); 442 | if (struct.message != null) { 443 | oprot.writeFieldBegin(MESSAGE_FIELD_DESC); 444 | oprot.writeBinary(struct.message); 445 | oprot.writeFieldEnd(); 446 | } 447 | if (struct.authenticator != null) { 448 | oprot.writeFieldBegin(AUTHENTICATOR_FIELD_DESC); 449 | oprot.writeBinary(struct.authenticator); 450 | oprot.writeFieldEnd(); 451 | } 452 | oprot.writeFieldStop(); 453 | oprot.writeStructEnd(); 454 | } 455 | 456 | } 457 | 458 | private static class AuthenticatedMessageStructTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { 459 | public AuthenticatedMessageStructTupleScheme getScheme() { 460 | return new AuthenticatedMessageStructTupleScheme(); 461 | } 462 | } 463 | 464 | private static class AuthenticatedMessageStructTupleScheme extends org.apache.thrift.scheme.TupleScheme { 465 | 466 | @Override 467 | public void write(org.apache.thrift.protocol.TProtocol prot, AuthenticatedMessageStruct struct) throws org.apache.thrift.TException { 468 | org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; 469 | java.util.BitSet optionals = new java.util.BitSet(); 470 | if (struct.isSetMessage()) { 471 | optionals.set(0); 472 | } 473 | if (struct.isSetAuthenticator()) { 474 | optionals.set(1); 475 | } 476 | oprot.writeBitSet(optionals, 2); 477 | if (struct.isSetMessage()) { 478 | oprot.writeBinary(struct.message); 479 | } 480 | if (struct.isSetAuthenticator()) { 481 | oprot.writeBinary(struct.authenticator); 482 | } 483 | } 484 | 485 | @Override 486 | public void read(org.apache.thrift.protocol.TProtocol prot, AuthenticatedMessageStruct struct) throws org.apache.thrift.TException { 487 | org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; 488 | java.util.BitSet incoming = iprot.readBitSet(2); 489 | if (incoming.get(0)) { 490 | struct.message = iprot.readBinary(); 491 | struct.setMessageIsSet(true); 492 | } 493 | if (incoming.get(1)) { 494 | struct.authenticator = iprot.readBinary(); 495 | struct.setAuthenticatorIsSet(true); 496 | } 497 | } 498 | } 499 | 500 | private static S scheme(org.apache.thrift.protocol.TProtocol proto) { 501 | return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); 502 | } 503 | } 504 | 505 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/message/thrift/CiphertextMessageStruct.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Autogenerated by Thrift Compiler (0.10.0) 3 | * 4 | * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 5 | * @generated 6 | */ 7 | package com.facebook.research.asynchronousratchetingtree.art.message.thrift; 8 | 9 | @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) 10 | @javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2018-01-05") 11 | public class CiphertextMessageStruct implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { 12 | private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("CiphertextMessageStruct"); 13 | 14 | private static final org.apache.thrift.protocol.TField AUTHENTICATED_MESSAGE_FIELD_DESC = new org.apache.thrift.protocol.TField("authenticatedMessage", org.apache.thrift.protocol.TType.STRUCT, (short)1); 15 | private static final org.apache.thrift.protocol.TField CIPHERTEXT_FIELD_DESC = new org.apache.thrift.protocol.TField("ciphertext", org.apache.thrift.protocol.TType.STRING, (short)2); 16 | 17 | private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new CiphertextMessageStructStandardSchemeFactory(); 18 | private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new CiphertextMessageStructTupleSchemeFactory(); 19 | 20 | public AuthenticatedMessageStruct authenticatedMessage; // required 21 | public java.nio.ByteBuffer ciphertext; // required 22 | 23 | /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ 24 | public enum _Fields implements org.apache.thrift.TFieldIdEnum { 25 | AUTHENTICATED_MESSAGE((short)1, "authenticatedMessage"), 26 | CIPHERTEXT((short)2, "ciphertext"); 27 | 28 | private static final java.util.Map byName = new java.util.HashMap(); 29 | 30 | static { 31 | for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { 32 | byName.put(field.getFieldName(), field); 33 | } 34 | } 35 | 36 | /** 37 | * Find the _Fields constant that matches fieldId, or null if its not found. 38 | */ 39 | public static _Fields findByThriftId(int fieldId) { 40 | switch(fieldId) { 41 | case 1: // AUTHENTICATED_MESSAGE 42 | return AUTHENTICATED_MESSAGE; 43 | case 2: // CIPHERTEXT 44 | return CIPHERTEXT; 45 | default: 46 | return null; 47 | } 48 | } 49 | 50 | /** 51 | * Find the _Fields constant that matches fieldId, throwing an exception 52 | * if it is not found. 53 | */ 54 | public static _Fields findByThriftIdOrThrow(int fieldId) { 55 | _Fields fields = findByThriftId(fieldId); 56 | if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!"); 57 | return fields; 58 | } 59 | 60 | /** 61 | * Find the _Fields constant that matches name, or null if its not found. 62 | */ 63 | public static _Fields findByName(java.lang.String name) { 64 | return byName.get(name); 65 | } 66 | 67 | private final short _thriftId; 68 | private final java.lang.String _fieldName; 69 | 70 | _Fields(short thriftId, java.lang.String fieldName) { 71 | _thriftId = thriftId; 72 | _fieldName = fieldName; 73 | } 74 | 75 | public short getThriftFieldId() { 76 | return _thriftId; 77 | } 78 | 79 | public java.lang.String getFieldName() { 80 | return _fieldName; 81 | } 82 | } 83 | 84 | // isset id assignments 85 | public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; 86 | static { 87 | java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); 88 | tmpMap.put(_Fields.AUTHENTICATED_MESSAGE, new org.apache.thrift.meta_data.FieldMetaData("authenticatedMessage", org.apache.thrift.TFieldRequirementType.DEFAULT, 89 | new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRUCT , "AuthenticatedMessageStruct"))); 90 | tmpMap.put(_Fields.CIPHERTEXT, new org.apache.thrift.meta_data.FieldMetaData("ciphertext", org.apache.thrift.TFieldRequirementType.DEFAULT, 91 | new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING , true))); 92 | metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); 93 | org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(CiphertextMessageStruct.class, metaDataMap); 94 | } 95 | 96 | public CiphertextMessageStruct() { 97 | } 98 | 99 | public CiphertextMessageStruct( 100 | AuthenticatedMessageStruct authenticatedMessage, 101 | java.nio.ByteBuffer ciphertext) 102 | { 103 | this(); 104 | this.authenticatedMessage = authenticatedMessage; 105 | this.ciphertext = org.apache.thrift.TBaseHelper.copyBinary(ciphertext); 106 | } 107 | 108 | /** 109 | * Performs a deep copy on other. 110 | */ 111 | public CiphertextMessageStruct(CiphertextMessageStruct other) { 112 | if (other.isSetAuthenticatedMessage()) { 113 | this.authenticatedMessage = new AuthenticatedMessageStruct(other.authenticatedMessage); 114 | } 115 | if (other.isSetCiphertext()) { 116 | this.ciphertext = org.apache.thrift.TBaseHelper.copyBinary(other.ciphertext); 117 | } 118 | } 119 | 120 | public CiphertextMessageStruct deepCopy() { 121 | return new CiphertextMessageStruct(this); 122 | } 123 | 124 | @Override 125 | public void clear() { 126 | this.authenticatedMessage = null; 127 | this.ciphertext = null; 128 | } 129 | 130 | public AuthenticatedMessageStruct getAuthenticatedMessage() { 131 | return this.authenticatedMessage; 132 | } 133 | 134 | public CiphertextMessageStruct setAuthenticatedMessage(AuthenticatedMessageStruct authenticatedMessage) { 135 | this.authenticatedMessage = authenticatedMessage; 136 | return this; 137 | } 138 | 139 | public void unsetAuthenticatedMessage() { 140 | this.authenticatedMessage = null; 141 | } 142 | 143 | /** Returns true if field authenticatedMessage is set (has been assigned a value) and false otherwise */ 144 | public boolean isSetAuthenticatedMessage() { 145 | return this.authenticatedMessage != null; 146 | } 147 | 148 | public void setAuthenticatedMessageIsSet(boolean value) { 149 | if (!value) { 150 | this.authenticatedMessage = null; 151 | } 152 | } 153 | 154 | public byte[] getCiphertext() { 155 | setCiphertext(org.apache.thrift.TBaseHelper.rightSize(ciphertext)); 156 | return ciphertext == null ? null : ciphertext.array(); 157 | } 158 | 159 | public java.nio.ByteBuffer bufferForCiphertext() { 160 | return org.apache.thrift.TBaseHelper.copyBinary(ciphertext); 161 | } 162 | 163 | public CiphertextMessageStruct setCiphertext(byte[] ciphertext) { 164 | this.ciphertext = ciphertext == null ? (java.nio.ByteBuffer)null : java.nio.ByteBuffer.wrap(ciphertext.clone()); 165 | return this; 166 | } 167 | 168 | public CiphertextMessageStruct setCiphertext(java.nio.ByteBuffer ciphertext) { 169 | this.ciphertext = org.apache.thrift.TBaseHelper.copyBinary(ciphertext); 170 | return this; 171 | } 172 | 173 | public void unsetCiphertext() { 174 | this.ciphertext = null; 175 | } 176 | 177 | /** Returns true if field ciphertext is set (has been assigned a value) and false otherwise */ 178 | public boolean isSetCiphertext() { 179 | return this.ciphertext != null; 180 | } 181 | 182 | public void setCiphertextIsSet(boolean value) { 183 | if (!value) { 184 | this.ciphertext = null; 185 | } 186 | } 187 | 188 | public void setFieldValue(_Fields field, java.lang.Object value) { 189 | switch (field) { 190 | case AUTHENTICATED_MESSAGE: 191 | if (value == null) { 192 | unsetAuthenticatedMessage(); 193 | } else { 194 | setAuthenticatedMessage((AuthenticatedMessageStruct)value); 195 | } 196 | break; 197 | 198 | case CIPHERTEXT: 199 | if (value == null) { 200 | unsetCiphertext(); 201 | } else { 202 | if (value instanceof byte[]) { 203 | setCiphertext((byte[])value); 204 | } else { 205 | setCiphertext((java.nio.ByteBuffer)value); 206 | } 207 | } 208 | break; 209 | 210 | } 211 | } 212 | 213 | public java.lang.Object getFieldValue(_Fields field) { 214 | switch (field) { 215 | case AUTHENTICATED_MESSAGE: 216 | return getAuthenticatedMessage(); 217 | 218 | case CIPHERTEXT: 219 | return getCiphertext(); 220 | 221 | } 222 | throw new java.lang.IllegalStateException(); 223 | } 224 | 225 | /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ 226 | public boolean isSet(_Fields field) { 227 | if (field == null) { 228 | throw new java.lang.IllegalArgumentException(); 229 | } 230 | 231 | switch (field) { 232 | case AUTHENTICATED_MESSAGE: 233 | return isSetAuthenticatedMessage(); 234 | case CIPHERTEXT: 235 | return isSetCiphertext(); 236 | } 237 | throw new java.lang.IllegalStateException(); 238 | } 239 | 240 | @Override 241 | public boolean equals(java.lang.Object that) { 242 | if (that == null) 243 | return false; 244 | if (that instanceof CiphertextMessageStruct) 245 | return this.equals((CiphertextMessageStruct)that); 246 | return false; 247 | } 248 | 249 | public boolean equals(CiphertextMessageStruct that) { 250 | if (that == null) 251 | return false; 252 | if (this == that) 253 | return true; 254 | 255 | boolean this_present_authenticatedMessage = true && this.isSetAuthenticatedMessage(); 256 | boolean that_present_authenticatedMessage = true && that.isSetAuthenticatedMessage(); 257 | if (this_present_authenticatedMessage || that_present_authenticatedMessage) { 258 | if (!(this_present_authenticatedMessage && that_present_authenticatedMessage)) 259 | return false; 260 | if (!this.authenticatedMessage.equals(that.authenticatedMessage)) 261 | return false; 262 | } 263 | 264 | boolean this_present_ciphertext = true && this.isSetCiphertext(); 265 | boolean that_present_ciphertext = true && that.isSetCiphertext(); 266 | if (this_present_ciphertext || that_present_ciphertext) { 267 | if (!(this_present_ciphertext && that_present_ciphertext)) 268 | return false; 269 | if (!this.ciphertext.equals(that.ciphertext)) 270 | return false; 271 | } 272 | 273 | return true; 274 | } 275 | 276 | @Override 277 | public int hashCode() { 278 | int hashCode = 1; 279 | 280 | hashCode = hashCode * 8191 + ((isSetAuthenticatedMessage()) ? 131071 : 524287); 281 | if (isSetAuthenticatedMessage()) 282 | hashCode = hashCode * 8191 + authenticatedMessage.hashCode(); 283 | 284 | hashCode = hashCode * 8191 + ((isSetCiphertext()) ? 131071 : 524287); 285 | if (isSetCiphertext()) 286 | hashCode = hashCode * 8191 + ciphertext.hashCode(); 287 | 288 | return hashCode; 289 | } 290 | 291 | @Override 292 | public int compareTo(CiphertextMessageStruct other) { 293 | if (!getClass().equals(other.getClass())) { 294 | return getClass().getName().compareTo(other.getClass().getName()); 295 | } 296 | 297 | int lastComparison = 0; 298 | 299 | lastComparison = java.lang.Boolean.valueOf(isSetAuthenticatedMessage()).compareTo(other.isSetAuthenticatedMessage()); 300 | if (lastComparison != 0) { 301 | return lastComparison; 302 | } 303 | if (isSetAuthenticatedMessage()) { 304 | lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.authenticatedMessage, other.authenticatedMessage); 305 | if (lastComparison != 0) { 306 | return lastComparison; 307 | } 308 | } 309 | lastComparison = java.lang.Boolean.valueOf(isSetCiphertext()).compareTo(other.isSetCiphertext()); 310 | if (lastComparison != 0) { 311 | return lastComparison; 312 | } 313 | if (isSetCiphertext()) { 314 | lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.ciphertext, other.ciphertext); 315 | if (lastComparison != 0) { 316 | return lastComparison; 317 | } 318 | } 319 | return 0; 320 | } 321 | 322 | public _Fields fieldForId(int fieldId) { 323 | return _Fields.findByThriftId(fieldId); 324 | } 325 | 326 | public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { 327 | scheme(iprot).read(iprot, this); 328 | } 329 | 330 | public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { 331 | scheme(oprot).write(oprot, this); 332 | } 333 | 334 | @Override 335 | public java.lang.String toString() { 336 | java.lang.StringBuilder sb = new java.lang.StringBuilder("CiphertextMessageStruct("); 337 | boolean first = true; 338 | 339 | sb.append("authenticatedMessage:"); 340 | if (this.authenticatedMessage == null) { 341 | sb.append("null"); 342 | } else { 343 | sb.append(this.authenticatedMessage); 344 | } 345 | first = false; 346 | if (!first) sb.append(", "); 347 | sb.append("ciphertext:"); 348 | if (this.ciphertext == null) { 349 | sb.append("null"); 350 | } else { 351 | org.apache.thrift.TBaseHelper.toString(this.ciphertext, sb); 352 | } 353 | first = false; 354 | sb.append(")"); 355 | return sb.toString(); 356 | } 357 | 358 | public void validate() throws org.apache.thrift.TException { 359 | // check for required fields 360 | // check for sub-struct validity 361 | } 362 | 363 | private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { 364 | try { 365 | write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); 366 | } catch (org.apache.thrift.TException te) { 367 | throw new java.io.IOException(te); 368 | } 369 | } 370 | 371 | private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { 372 | try { 373 | read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); 374 | } catch (org.apache.thrift.TException te) { 375 | throw new java.io.IOException(te); 376 | } 377 | } 378 | 379 | private static class CiphertextMessageStructStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { 380 | public CiphertextMessageStructStandardScheme getScheme() { 381 | return new CiphertextMessageStructStandardScheme(); 382 | } 383 | } 384 | 385 | private static class CiphertextMessageStructStandardScheme extends org.apache.thrift.scheme.StandardScheme { 386 | 387 | public void read(org.apache.thrift.protocol.TProtocol iprot, CiphertextMessageStruct struct) throws org.apache.thrift.TException { 388 | org.apache.thrift.protocol.TField schemeField; 389 | iprot.readStructBegin(); 390 | while (true) 391 | { 392 | schemeField = iprot.readFieldBegin(); 393 | if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 394 | break; 395 | } 396 | switch (schemeField.id) { 397 | case 1: // AUTHENTICATED_MESSAGE 398 | if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) { 399 | struct.authenticatedMessage = new AuthenticatedMessageStruct(); 400 | struct.authenticatedMessage.read(iprot); 401 | struct.setAuthenticatedMessageIsSet(true); 402 | } else { 403 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 404 | } 405 | break; 406 | case 2: // CIPHERTEXT 407 | if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { 408 | struct.ciphertext = iprot.readBinary(); 409 | struct.setCiphertextIsSet(true); 410 | } else { 411 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 412 | } 413 | break; 414 | default: 415 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 416 | } 417 | iprot.readFieldEnd(); 418 | } 419 | iprot.readStructEnd(); 420 | 421 | // check for required fields of primitive type, which can't be checked in the validate method 422 | struct.validate(); 423 | } 424 | 425 | public void write(org.apache.thrift.protocol.TProtocol oprot, CiphertextMessageStruct struct) throws org.apache.thrift.TException { 426 | struct.validate(); 427 | 428 | oprot.writeStructBegin(STRUCT_DESC); 429 | if (struct.authenticatedMessage != null) { 430 | oprot.writeFieldBegin(AUTHENTICATED_MESSAGE_FIELD_DESC); 431 | struct.authenticatedMessage.write(oprot); 432 | oprot.writeFieldEnd(); 433 | } 434 | if (struct.ciphertext != null) { 435 | oprot.writeFieldBegin(CIPHERTEXT_FIELD_DESC); 436 | oprot.writeBinary(struct.ciphertext); 437 | oprot.writeFieldEnd(); 438 | } 439 | oprot.writeFieldStop(); 440 | oprot.writeStructEnd(); 441 | } 442 | 443 | } 444 | 445 | private static class CiphertextMessageStructTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { 446 | public CiphertextMessageStructTupleScheme getScheme() { 447 | return new CiphertextMessageStructTupleScheme(); 448 | } 449 | } 450 | 451 | private static class CiphertextMessageStructTupleScheme extends org.apache.thrift.scheme.TupleScheme { 452 | 453 | @Override 454 | public void write(org.apache.thrift.protocol.TProtocol prot, CiphertextMessageStruct struct) throws org.apache.thrift.TException { 455 | org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; 456 | java.util.BitSet optionals = new java.util.BitSet(); 457 | if (struct.isSetAuthenticatedMessage()) { 458 | optionals.set(0); 459 | } 460 | if (struct.isSetCiphertext()) { 461 | optionals.set(1); 462 | } 463 | oprot.writeBitSet(optionals, 2); 464 | if (struct.isSetAuthenticatedMessage()) { 465 | struct.authenticatedMessage.write(oprot); 466 | } 467 | if (struct.isSetCiphertext()) { 468 | oprot.writeBinary(struct.ciphertext); 469 | } 470 | } 471 | 472 | @Override 473 | public void read(org.apache.thrift.protocol.TProtocol prot, CiphertextMessageStruct struct) throws org.apache.thrift.TException { 474 | org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; 475 | java.util.BitSet incoming = iprot.readBitSet(2); 476 | if (incoming.get(0)) { 477 | struct.authenticatedMessage = new AuthenticatedMessageStruct(); 478 | struct.authenticatedMessage.read(iprot); 479 | struct.setAuthenticatedMessageIsSet(true); 480 | } 481 | if (incoming.get(1)) { 482 | struct.ciphertext = iprot.readBinary(); 483 | struct.setCiphertextIsSet(true); 484 | } 485 | } 486 | } 487 | 488 | private static S scheme(org.apache.thrift.protocol.TProtocol proto) { 489 | return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); 490 | } 491 | } 492 | 493 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/message/thrift/NodeStruct.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Autogenerated by Thrift Compiler (0.10.0) 3 | * 4 | * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 5 | * @generated 6 | */ 7 | package com.facebook.research.asynchronousratchetingtree.art.message.thrift; 8 | 9 | @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) 10 | @javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2018-01-05") 11 | public class NodeStruct implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { 12 | private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("NodeStruct"); 13 | 14 | private static final org.apache.thrift.protocol.TField PUBLIC_KEY_FIELD_DESC = new org.apache.thrift.protocol.TField("publicKey", org.apache.thrift.protocol.TType.STRING, (short)1); 15 | private static final org.apache.thrift.protocol.TField LEFT_FIELD_DESC = new org.apache.thrift.protocol.TField("left", org.apache.thrift.protocol.TType.STRUCT, (short)2); 16 | private static final org.apache.thrift.protocol.TField RIGHT_FIELD_DESC = new org.apache.thrift.protocol.TField("right", org.apache.thrift.protocol.TType.STRUCT, (short)3); 17 | 18 | private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new NodeStructStandardSchemeFactory(); 19 | private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new NodeStructTupleSchemeFactory(); 20 | 21 | public java.nio.ByteBuffer publicKey; // required 22 | public NodeStruct left; // optional 23 | public NodeStruct right; // optional 24 | 25 | /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ 26 | public enum _Fields implements org.apache.thrift.TFieldIdEnum { 27 | PUBLIC_KEY((short)1, "publicKey"), 28 | LEFT((short)2, "left"), 29 | RIGHT((short)3, "right"); 30 | 31 | private static final java.util.Map byName = new java.util.HashMap(); 32 | 33 | static { 34 | for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { 35 | byName.put(field.getFieldName(), field); 36 | } 37 | } 38 | 39 | /** 40 | * Find the _Fields constant that matches fieldId, or null if its not found. 41 | */ 42 | public static _Fields findByThriftId(int fieldId) { 43 | switch(fieldId) { 44 | case 1: // PUBLIC_KEY 45 | return PUBLIC_KEY; 46 | case 2: // LEFT 47 | return LEFT; 48 | case 3: // RIGHT 49 | return RIGHT; 50 | default: 51 | return null; 52 | } 53 | } 54 | 55 | /** 56 | * Find the _Fields constant that matches fieldId, throwing an exception 57 | * if it is not found. 58 | */ 59 | public static _Fields findByThriftIdOrThrow(int fieldId) { 60 | _Fields fields = findByThriftId(fieldId); 61 | if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!"); 62 | return fields; 63 | } 64 | 65 | /** 66 | * Find the _Fields constant that matches name, or null if its not found. 67 | */ 68 | public static _Fields findByName(java.lang.String name) { 69 | return byName.get(name); 70 | } 71 | 72 | private final short _thriftId; 73 | private final java.lang.String _fieldName; 74 | 75 | _Fields(short thriftId, java.lang.String fieldName) { 76 | _thriftId = thriftId; 77 | _fieldName = fieldName; 78 | } 79 | 80 | public short getThriftFieldId() { 81 | return _thriftId; 82 | } 83 | 84 | public java.lang.String getFieldName() { 85 | return _fieldName; 86 | } 87 | } 88 | 89 | // isset id assignments 90 | private static final _Fields optionals[] = {_Fields.LEFT,_Fields.RIGHT}; 91 | public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; 92 | static { 93 | java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); 94 | tmpMap.put(_Fields.PUBLIC_KEY, new org.apache.thrift.meta_data.FieldMetaData("publicKey", org.apache.thrift.TFieldRequirementType.DEFAULT, 95 | new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING , true))); 96 | tmpMap.put(_Fields.LEFT, new org.apache.thrift.meta_data.FieldMetaData("left", org.apache.thrift.TFieldRequirementType.OPTIONAL, 97 | new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRUCT , "NodeStruct"))); 98 | tmpMap.put(_Fields.RIGHT, new org.apache.thrift.meta_data.FieldMetaData("right", org.apache.thrift.TFieldRequirementType.OPTIONAL, 99 | new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRUCT , "NodeStruct"))); 100 | metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); 101 | org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(NodeStruct.class, metaDataMap); 102 | } 103 | 104 | public NodeStruct() { 105 | } 106 | 107 | public NodeStruct( 108 | java.nio.ByteBuffer publicKey) 109 | { 110 | this(); 111 | this.publicKey = org.apache.thrift.TBaseHelper.copyBinary(publicKey); 112 | } 113 | 114 | /** 115 | * Performs a deep copy on other. 116 | */ 117 | public NodeStruct(NodeStruct other) { 118 | if (other.isSetPublicKey()) { 119 | this.publicKey = org.apache.thrift.TBaseHelper.copyBinary(other.publicKey); 120 | } 121 | if (other.isSetLeft()) { 122 | this.left = new NodeStruct(other.left); 123 | } 124 | if (other.isSetRight()) { 125 | this.right = new NodeStruct(other.right); 126 | } 127 | } 128 | 129 | public NodeStruct deepCopy() { 130 | return new NodeStruct(this); 131 | } 132 | 133 | @Override 134 | public void clear() { 135 | this.publicKey = null; 136 | this.left = null; 137 | this.right = null; 138 | } 139 | 140 | public byte[] getPublicKey() { 141 | setPublicKey(org.apache.thrift.TBaseHelper.rightSize(publicKey)); 142 | return publicKey == null ? null : publicKey.array(); 143 | } 144 | 145 | public java.nio.ByteBuffer bufferForPublicKey() { 146 | return org.apache.thrift.TBaseHelper.copyBinary(publicKey); 147 | } 148 | 149 | public NodeStruct setPublicKey(byte[] publicKey) { 150 | this.publicKey = publicKey == null ? (java.nio.ByteBuffer)null : java.nio.ByteBuffer.wrap(publicKey.clone()); 151 | return this; 152 | } 153 | 154 | public NodeStruct setPublicKey(java.nio.ByteBuffer publicKey) { 155 | this.publicKey = org.apache.thrift.TBaseHelper.copyBinary(publicKey); 156 | return this; 157 | } 158 | 159 | public void unsetPublicKey() { 160 | this.publicKey = null; 161 | } 162 | 163 | /** Returns true if field publicKey is set (has been assigned a value) and false otherwise */ 164 | public boolean isSetPublicKey() { 165 | return this.publicKey != null; 166 | } 167 | 168 | public void setPublicKeyIsSet(boolean value) { 169 | if (!value) { 170 | this.publicKey = null; 171 | } 172 | } 173 | 174 | public NodeStruct getLeft() { 175 | return this.left; 176 | } 177 | 178 | public NodeStruct setLeft(NodeStruct left) { 179 | this.left = left; 180 | return this; 181 | } 182 | 183 | public void unsetLeft() { 184 | this.left = null; 185 | } 186 | 187 | /** Returns true if field left is set (has been assigned a value) and false otherwise */ 188 | public boolean isSetLeft() { 189 | return this.left != null; 190 | } 191 | 192 | public void setLeftIsSet(boolean value) { 193 | if (!value) { 194 | this.left = null; 195 | } 196 | } 197 | 198 | public NodeStruct getRight() { 199 | return this.right; 200 | } 201 | 202 | public NodeStruct setRight(NodeStruct right) { 203 | this.right = right; 204 | return this; 205 | } 206 | 207 | public void unsetRight() { 208 | this.right = null; 209 | } 210 | 211 | /** Returns true if field right is set (has been assigned a value) and false otherwise */ 212 | public boolean isSetRight() { 213 | return this.right != null; 214 | } 215 | 216 | public void setRightIsSet(boolean value) { 217 | if (!value) { 218 | this.right = null; 219 | } 220 | } 221 | 222 | public void setFieldValue(_Fields field, java.lang.Object value) { 223 | switch (field) { 224 | case PUBLIC_KEY: 225 | if (value == null) { 226 | unsetPublicKey(); 227 | } else { 228 | if (value instanceof byte[]) { 229 | setPublicKey((byte[])value); 230 | } else { 231 | setPublicKey((java.nio.ByteBuffer)value); 232 | } 233 | } 234 | break; 235 | 236 | case LEFT: 237 | if (value == null) { 238 | unsetLeft(); 239 | } else { 240 | setLeft((NodeStruct)value); 241 | } 242 | break; 243 | 244 | case RIGHT: 245 | if (value == null) { 246 | unsetRight(); 247 | } else { 248 | setRight((NodeStruct)value); 249 | } 250 | break; 251 | 252 | } 253 | } 254 | 255 | public java.lang.Object getFieldValue(_Fields field) { 256 | switch (field) { 257 | case PUBLIC_KEY: 258 | return getPublicKey(); 259 | 260 | case LEFT: 261 | return getLeft(); 262 | 263 | case RIGHT: 264 | return getRight(); 265 | 266 | } 267 | throw new java.lang.IllegalStateException(); 268 | } 269 | 270 | /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ 271 | public boolean isSet(_Fields field) { 272 | if (field == null) { 273 | throw new java.lang.IllegalArgumentException(); 274 | } 275 | 276 | switch (field) { 277 | case PUBLIC_KEY: 278 | return isSetPublicKey(); 279 | case LEFT: 280 | return isSetLeft(); 281 | case RIGHT: 282 | return isSetRight(); 283 | } 284 | throw new java.lang.IllegalStateException(); 285 | } 286 | 287 | @Override 288 | public boolean equals(java.lang.Object that) { 289 | if (that == null) 290 | return false; 291 | if (that instanceof NodeStruct) 292 | return this.equals((NodeStruct)that); 293 | return false; 294 | } 295 | 296 | public boolean equals(NodeStruct that) { 297 | if (that == null) 298 | return false; 299 | if (this == that) 300 | return true; 301 | 302 | boolean this_present_publicKey = true && this.isSetPublicKey(); 303 | boolean that_present_publicKey = true && that.isSetPublicKey(); 304 | if (this_present_publicKey || that_present_publicKey) { 305 | if (!(this_present_publicKey && that_present_publicKey)) 306 | return false; 307 | if (!this.publicKey.equals(that.publicKey)) 308 | return false; 309 | } 310 | 311 | boolean this_present_left = true && this.isSetLeft(); 312 | boolean that_present_left = true && that.isSetLeft(); 313 | if (this_present_left || that_present_left) { 314 | if (!(this_present_left && that_present_left)) 315 | return false; 316 | if (!this.left.equals(that.left)) 317 | return false; 318 | } 319 | 320 | boolean this_present_right = true && this.isSetRight(); 321 | boolean that_present_right = true && that.isSetRight(); 322 | if (this_present_right || that_present_right) { 323 | if (!(this_present_right && that_present_right)) 324 | return false; 325 | if (!this.right.equals(that.right)) 326 | return false; 327 | } 328 | 329 | return true; 330 | } 331 | 332 | @Override 333 | public int hashCode() { 334 | int hashCode = 1; 335 | 336 | hashCode = hashCode * 8191 + ((isSetPublicKey()) ? 131071 : 524287); 337 | if (isSetPublicKey()) 338 | hashCode = hashCode * 8191 + publicKey.hashCode(); 339 | 340 | hashCode = hashCode * 8191 + ((isSetLeft()) ? 131071 : 524287); 341 | if (isSetLeft()) 342 | hashCode = hashCode * 8191 + left.hashCode(); 343 | 344 | hashCode = hashCode * 8191 + ((isSetRight()) ? 131071 : 524287); 345 | if (isSetRight()) 346 | hashCode = hashCode * 8191 + right.hashCode(); 347 | 348 | return hashCode; 349 | } 350 | 351 | @Override 352 | public int compareTo(NodeStruct other) { 353 | if (!getClass().equals(other.getClass())) { 354 | return getClass().getName().compareTo(other.getClass().getName()); 355 | } 356 | 357 | int lastComparison = 0; 358 | 359 | lastComparison = java.lang.Boolean.valueOf(isSetPublicKey()).compareTo(other.isSetPublicKey()); 360 | if (lastComparison != 0) { 361 | return lastComparison; 362 | } 363 | if (isSetPublicKey()) { 364 | lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.publicKey, other.publicKey); 365 | if (lastComparison != 0) { 366 | return lastComparison; 367 | } 368 | } 369 | lastComparison = java.lang.Boolean.valueOf(isSetLeft()).compareTo(other.isSetLeft()); 370 | if (lastComparison != 0) { 371 | return lastComparison; 372 | } 373 | if (isSetLeft()) { 374 | lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.left, other.left); 375 | if (lastComparison != 0) { 376 | return lastComparison; 377 | } 378 | } 379 | lastComparison = java.lang.Boolean.valueOf(isSetRight()).compareTo(other.isSetRight()); 380 | if (lastComparison != 0) { 381 | return lastComparison; 382 | } 383 | if (isSetRight()) { 384 | lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.right, other.right); 385 | if (lastComparison != 0) { 386 | return lastComparison; 387 | } 388 | } 389 | return 0; 390 | } 391 | 392 | public _Fields fieldForId(int fieldId) { 393 | return _Fields.findByThriftId(fieldId); 394 | } 395 | 396 | public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { 397 | scheme(iprot).read(iprot, this); 398 | } 399 | 400 | public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { 401 | scheme(oprot).write(oprot, this); 402 | } 403 | 404 | @Override 405 | public java.lang.String toString() { 406 | java.lang.StringBuilder sb = new java.lang.StringBuilder("NodeStruct("); 407 | boolean first = true; 408 | 409 | sb.append("publicKey:"); 410 | if (this.publicKey == null) { 411 | sb.append("null"); 412 | } else { 413 | org.apache.thrift.TBaseHelper.toString(this.publicKey, sb); 414 | } 415 | first = false; 416 | if (isSetLeft()) { 417 | if (!first) sb.append(", "); 418 | sb.append("left:"); 419 | if (this.left == null) { 420 | sb.append("null"); 421 | } else { 422 | sb.append(this.left); 423 | } 424 | first = false; 425 | } 426 | if (isSetRight()) { 427 | if (!first) sb.append(", "); 428 | sb.append("right:"); 429 | if (this.right == null) { 430 | sb.append("null"); 431 | } else { 432 | sb.append(this.right); 433 | } 434 | first = false; 435 | } 436 | sb.append(")"); 437 | return sb.toString(); 438 | } 439 | 440 | public void validate() throws org.apache.thrift.TException { 441 | // check for required fields 442 | // check for sub-struct validity 443 | } 444 | 445 | private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { 446 | try { 447 | write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); 448 | } catch (org.apache.thrift.TException te) { 449 | throw new java.io.IOException(te); 450 | } 451 | } 452 | 453 | private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { 454 | try { 455 | read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); 456 | } catch (org.apache.thrift.TException te) { 457 | throw new java.io.IOException(te); 458 | } 459 | } 460 | 461 | private static class NodeStructStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { 462 | public NodeStructStandardScheme getScheme() { 463 | return new NodeStructStandardScheme(); 464 | } 465 | } 466 | 467 | private static class NodeStructStandardScheme extends org.apache.thrift.scheme.StandardScheme { 468 | 469 | public void read(org.apache.thrift.protocol.TProtocol iprot, NodeStruct struct) throws org.apache.thrift.TException { 470 | org.apache.thrift.protocol.TField schemeField; 471 | iprot.readStructBegin(); 472 | while (true) 473 | { 474 | schemeField = iprot.readFieldBegin(); 475 | if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 476 | break; 477 | } 478 | switch (schemeField.id) { 479 | case 1: // PUBLIC_KEY 480 | if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { 481 | struct.publicKey = iprot.readBinary(); 482 | struct.setPublicKeyIsSet(true); 483 | } else { 484 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 485 | } 486 | break; 487 | case 2: // LEFT 488 | if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) { 489 | struct.left = new NodeStruct(); 490 | struct.left.read(iprot); 491 | struct.setLeftIsSet(true); 492 | } else { 493 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 494 | } 495 | break; 496 | case 3: // RIGHT 497 | if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) { 498 | struct.right = new NodeStruct(); 499 | struct.right.read(iprot); 500 | struct.setRightIsSet(true); 501 | } else { 502 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 503 | } 504 | break; 505 | default: 506 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 507 | } 508 | iprot.readFieldEnd(); 509 | } 510 | iprot.readStructEnd(); 511 | 512 | // check for required fields of primitive type, which can't be checked in the validate method 513 | struct.validate(); 514 | } 515 | 516 | public void write(org.apache.thrift.protocol.TProtocol oprot, NodeStruct struct) throws org.apache.thrift.TException { 517 | struct.validate(); 518 | 519 | oprot.writeStructBegin(STRUCT_DESC); 520 | if (struct.publicKey != null) { 521 | oprot.writeFieldBegin(PUBLIC_KEY_FIELD_DESC); 522 | oprot.writeBinary(struct.publicKey); 523 | oprot.writeFieldEnd(); 524 | } 525 | if (struct.left != null) { 526 | if (struct.isSetLeft()) { 527 | oprot.writeFieldBegin(LEFT_FIELD_DESC); 528 | struct.left.write(oprot); 529 | oprot.writeFieldEnd(); 530 | } 531 | } 532 | if (struct.right != null) { 533 | if (struct.isSetRight()) { 534 | oprot.writeFieldBegin(RIGHT_FIELD_DESC); 535 | struct.right.write(oprot); 536 | oprot.writeFieldEnd(); 537 | } 538 | } 539 | oprot.writeFieldStop(); 540 | oprot.writeStructEnd(); 541 | } 542 | 543 | } 544 | 545 | private static class NodeStructTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { 546 | public NodeStructTupleScheme getScheme() { 547 | return new NodeStructTupleScheme(); 548 | } 549 | } 550 | 551 | private static class NodeStructTupleScheme extends org.apache.thrift.scheme.TupleScheme { 552 | 553 | @Override 554 | public void write(org.apache.thrift.protocol.TProtocol prot, NodeStruct struct) throws org.apache.thrift.TException { 555 | org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; 556 | java.util.BitSet optionals = new java.util.BitSet(); 557 | if (struct.isSetPublicKey()) { 558 | optionals.set(0); 559 | } 560 | if (struct.isSetLeft()) { 561 | optionals.set(1); 562 | } 563 | if (struct.isSetRight()) { 564 | optionals.set(2); 565 | } 566 | oprot.writeBitSet(optionals, 3); 567 | if (struct.isSetPublicKey()) { 568 | oprot.writeBinary(struct.publicKey); 569 | } 570 | if (struct.isSetLeft()) { 571 | struct.left.write(oprot); 572 | } 573 | if (struct.isSetRight()) { 574 | struct.right.write(oprot); 575 | } 576 | } 577 | 578 | @Override 579 | public void read(org.apache.thrift.protocol.TProtocol prot, NodeStruct struct) throws org.apache.thrift.TException { 580 | org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; 581 | java.util.BitSet incoming = iprot.readBitSet(3); 582 | if (incoming.get(0)) { 583 | struct.publicKey = iprot.readBinary(); 584 | struct.setPublicKeyIsSet(true); 585 | } 586 | if (incoming.get(1)) { 587 | struct.left = new NodeStruct(); 588 | struct.left.read(iprot); 589 | struct.setLeftIsSet(true); 590 | } 591 | if (incoming.get(2)) { 592 | struct.right = new NodeStruct(); 593 | struct.right.read(iprot); 594 | struct.setRightIsSet(true); 595 | } 596 | } 597 | } 598 | 599 | private static S scheme(org.apache.thrift.protocol.TProtocol proto) { 600 | return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); 601 | } 602 | } 603 | 604 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/message/thrift/UpdateMessageStruct.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Autogenerated by Thrift Compiler (0.10.0) 3 | * 4 | * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 5 | * @generated 6 | */ 7 | package com.facebook.research.asynchronousratchetingtree.art.message.thrift; 8 | 9 | @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) 10 | @javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2018-01-05") 11 | public class UpdateMessageStruct implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { 12 | private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("UpdateMessageStruct"); 13 | 14 | private static final org.apache.thrift.protocol.TField LEAF_NUM_FIELD_DESC = new org.apache.thrift.protocol.TField("leafNum", org.apache.thrift.protocol.TType.I32, (short)1); 15 | private static final org.apache.thrift.protocol.TField PATH_FIELD_DESC = new org.apache.thrift.protocol.TField("path", org.apache.thrift.protocol.TType.LIST, (short)2); 16 | 17 | private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new UpdateMessageStructStandardSchemeFactory(); 18 | private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new UpdateMessageStructTupleSchemeFactory(); 19 | 20 | public int leafNum; // required 21 | public java.util.List path; // required 22 | 23 | /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ 24 | public enum _Fields implements org.apache.thrift.TFieldIdEnum { 25 | LEAF_NUM((short)1, "leafNum"), 26 | PATH((short)2, "path"); 27 | 28 | private static final java.util.Map byName = new java.util.HashMap(); 29 | 30 | static { 31 | for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { 32 | byName.put(field.getFieldName(), field); 33 | } 34 | } 35 | 36 | /** 37 | * Find the _Fields constant that matches fieldId, or null if its not found. 38 | */ 39 | public static _Fields findByThriftId(int fieldId) { 40 | switch(fieldId) { 41 | case 1: // LEAF_NUM 42 | return LEAF_NUM; 43 | case 2: // PATH 44 | return PATH; 45 | default: 46 | return null; 47 | } 48 | } 49 | 50 | /** 51 | * Find the _Fields constant that matches fieldId, throwing an exception 52 | * if it is not found. 53 | */ 54 | public static _Fields findByThriftIdOrThrow(int fieldId) { 55 | _Fields fields = findByThriftId(fieldId); 56 | if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!"); 57 | return fields; 58 | } 59 | 60 | /** 61 | * Find the _Fields constant that matches name, or null if its not found. 62 | */ 63 | public static _Fields findByName(java.lang.String name) { 64 | return byName.get(name); 65 | } 66 | 67 | private final short _thriftId; 68 | private final java.lang.String _fieldName; 69 | 70 | _Fields(short thriftId, java.lang.String fieldName) { 71 | _thriftId = thriftId; 72 | _fieldName = fieldName; 73 | } 74 | 75 | public short getThriftFieldId() { 76 | return _thriftId; 77 | } 78 | 79 | public java.lang.String getFieldName() { 80 | return _fieldName; 81 | } 82 | } 83 | 84 | // isset id assignments 85 | private static final int __LEAFNUM_ISSET_ID = 0; 86 | private byte __isset_bitfield = 0; 87 | public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; 88 | static { 89 | java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); 90 | tmpMap.put(_Fields.LEAF_NUM, new org.apache.thrift.meta_data.FieldMetaData("leafNum", org.apache.thrift.TFieldRequirementType.DEFAULT, 91 | new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32))); 92 | tmpMap.put(_Fields.PATH, new org.apache.thrift.meta_data.FieldMetaData("path", org.apache.thrift.TFieldRequirementType.DEFAULT, 93 | new org.apache.thrift.meta_data.ListMetaData(org.apache.thrift.protocol.TType.LIST, 94 | new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)))); 95 | metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); 96 | org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(UpdateMessageStruct.class, metaDataMap); 97 | } 98 | 99 | public UpdateMessageStruct() { 100 | } 101 | 102 | public UpdateMessageStruct( 103 | int leafNum, 104 | java.util.List path) 105 | { 106 | this(); 107 | this.leafNum = leafNum; 108 | setLeafNumIsSet(true); 109 | this.path = path; 110 | } 111 | 112 | /** 113 | * Performs a deep copy on other. 114 | */ 115 | public UpdateMessageStruct(UpdateMessageStruct other) { 116 | __isset_bitfield = other.__isset_bitfield; 117 | this.leafNum = other.leafNum; 118 | if (other.isSetPath()) { 119 | java.util.List __this__path = new java.util.ArrayList(other.path); 120 | this.path = __this__path; 121 | } 122 | } 123 | 124 | public UpdateMessageStruct deepCopy() { 125 | return new UpdateMessageStruct(this); 126 | } 127 | 128 | @Override 129 | public void clear() { 130 | setLeafNumIsSet(false); 131 | this.leafNum = 0; 132 | this.path = null; 133 | } 134 | 135 | public int getLeafNum() { 136 | return this.leafNum; 137 | } 138 | 139 | public UpdateMessageStruct setLeafNum(int leafNum) { 140 | this.leafNum = leafNum; 141 | setLeafNumIsSet(true); 142 | return this; 143 | } 144 | 145 | public void unsetLeafNum() { 146 | __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __LEAFNUM_ISSET_ID); 147 | } 148 | 149 | /** Returns true if field leafNum is set (has been assigned a value) and false otherwise */ 150 | public boolean isSetLeafNum() { 151 | return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __LEAFNUM_ISSET_ID); 152 | } 153 | 154 | public void setLeafNumIsSet(boolean value) { 155 | __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __LEAFNUM_ISSET_ID, value); 156 | } 157 | 158 | public int getPathSize() { 159 | return (this.path == null) ? 0 : this.path.size(); 160 | } 161 | 162 | public java.util.Iterator getPathIterator() { 163 | return (this.path == null) ? null : this.path.iterator(); 164 | } 165 | 166 | public void addToPath(java.lang.String elem) { 167 | if (this.path == null) { 168 | this.path = new java.util.ArrayList(); 169 | } 170 | this.path.add(elem); 171 | } 172 | 173 | public java.util.List getPath() { 174 | return this.path; 175 | } 176 | 177 | public UpdateMessageStruct setPath(java.util.List path) { 178 | this.path = path; 179 | return this; 180 | } 181 | 182 | public void unsetPath() { 183 | this.path = null; 184 | } 185 | 186 | /** Returns true if field path is set (has been assigned a value) and false otherwise */ 187 | public boolean isSetPath() { 188 | return this.path != null; 189 | } 190 | 191 | public void setPathIsSet(boolean value) { 192 | if (!value) { 193 | this.path = null; 194 | } 195 | } 196 | 197 | public void setFieldValue(_Fields field, java.lang.Object value) { 198 | switch (field) { 199 | case LEAF_NUM: 200 | if (value == null) { 201 | unsetLeafNum(); 202 | } else { 203 | setLeafNum((java.lang.Integer)value); 204 | } 205 | break; 206 | 207 | case PATH: 208 | if (value == null) { 209 | unsetPath(); 210 | } else { 211 | setPath((java.util.List)value); 212 | } 213 | break; 214 | 215 | } 216 | } 217 | 218 | public java.lang.Object getFieldValue(_Fields field) { 219 | switch (field) { 220 | case LEAF_NUM: 221 | return getLeafNum(); 222 | 223 | case PATH: 224 | return getPath(); 225 | 226 | } 227 | throw new java.lang.IllegalStateException(); 228 | } 229 | 230 | /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ 231 | public boolean isSet(_Fields field) { 232 | if (field == null) { 233 | throw new java.lang.IllegalArgumentException(); 234 | } 235 | 236 | switch (field) { 237 | case LEAF_NUM: 238 | return isSetLeafNum(); 239 | case PATH: 240 | return isSetPath(); 241 | } 242 | throw new java.lang.IllegalStateException(); 243 | } 244 | 245 | @Override 246 | public boolean equals(java.lang.Object that) { 247 | if (that == null) 248 | return false; 249 | if (that instanceof UpdateMessageStruct) 250 | return this.equals((UpdateMessageStruct)that); 251 | return false; 252 | } 253 | 254 | public boolean equals(UpdateMessageStruct that) { 255 | if (that == null) 256 | return false; 257 | if (this == that) 258 | return true; 259 | 260 | boolean this_present_leafNum = true; 261 | boolean that_present_leafNum = true; 262 | if (this_present_leafNum || that_present_leafNum) { 263 | if (!(this_present_leafNum && that_present_leafNum)) 264 | return false; 265 | if (this.leafNum != that.leafNum) 266 | return false; 267 | } 268 | 269 | boolean this_present_path = true && this.isSetPath(); 270 | boolean that_present_path = true && that.isSetPath(); 271 | if (this_present_path || that_present_path) { 272 | if (!(this_present_path && that_present_path)) 273 | return false; 274 | if (!this.path.equals(that.path)) 275 | return false; 276 | } 277 | 278 | return true; 279 | } 280 | 281 | @Override 282 | public int hashCode() { 283 | int hashCode = 1; 284 | 285 | hashCode = hashCode * 8191 + leafNum; 286 | 287 | hashCode = hashCode * 8191 + ((isSetPath()) ? 131071 : 524287); 288 | if (isSetPath()) 289 | hashCode = hashCode * 8191 + path.hashCode(); 290 | 291 | return hashCode; 292 | } 293 | 294 | @Override 295 | public int compareTo(UpdateMessageStruct other) { 296 | if (!getClass().equals(other.getClass())) { 297 | return getClass().getName().compareTo(other.getClass().getName()); 298 | } 299 | 300 | int lastComparison = 0; 301 | 302 | lastComparison = java.lang.Boolean.valueOf(isSetLeafNum()).compareTo(other.isSetLeafNum()); 303 | if (lastComparison != 0) { 304 | return lastComparison; 305 | } 306 | if (isSetLeafNum()) { 307 | lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.leafNum, other.leafNum); 308 | if (lastComparison != 0) { 309 | return lastComparison; 310 | } 311 | } 312 | lastComparison = java.lang.Boolean.valueOf(isSetPath()).compareTo(other.isSetPath()); 313 | if (lastComparison != 0) { 314 | return lastComparison; 315 | } 316 | if (isSetPath()) { 317 | lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.path, other.path); 318 | if (lastComparison != 0) { 319 | return lastComparison; 320 | } 321 | } 322 | return 0; 323 | } 324 | 325 | public _Fields fieldForId(int fieldId) { 326 | return _Fields.findByThriftId(fieldId); 327 | } 328 | 329 | public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { 330 | scheme(iprot).read(iprot, this); 331 | } 332 | 333 | public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { 334 | scheme(oprot).write(oprot, this); 335 | } 336 | 337 | @Override 338 | public java.lang.String toString() { 339 | java.lang.StringBuilder sb = new java.lang.StringBuilder("UpdateMessageStruct("); 340 | boolean first = true; 341 | 342 | sb.append("leafNum:"); 343 | sb.append(this.leafNum); 344 | first = false; 345 | if (!first) sb.append(", "); 346 | sb.append("path:"); 347 | if (this.path == null) { 348 | sb.append("null"); 349 | } else { 350 | sb.append(this.path); 351 | } 352 | first = false; 353 | sb.append(")"); 354 | return sb.toString(); 355 | } 356 | 357 | public void validate() throws org.apache.thrift.TException { 358 | // check for required fields 359 | // check for sub-struct validity 360 | } 361 | 362 | private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { 363 | try { 364 | write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); 365 | } catch (org.apache.thrift.TException te) { 366 | throw new java.io.IOException(te); 367 | } 368 | } 369 | 370 | private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { 371 | try { 372 | // it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor. 373 | __isset_bitfield = 0; 374 | read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); 375 | } catch (org.apache.thrift.TException te) { 376 | throw new java.io.IOException(te); 377 | } 378 | } 379 | 380 | private static class UpdateMessageStructStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { 381 | public UpdateMessageStructStandardScheme getScheme() { 382 | return new UpdateMessageStructStandardScheme(); 383 | } 384 | } 385 | 386 | private static class UpdateMessageStructStandardScheme extends org.apache.thrift.scheme.StandardScheme { 387 | 388 | public void read(org.apache.thrift.protocol.TProtocol iprot, UpdateMessageStruct struct) throws org.apache.thrift.TException { 389 | org.apache.thrift.protocol.TField schemeField; 390 | iprot.readStructBegin(); 391 | while (true) 392 | { 393 | schemeField = iprot.readFieldBegin(); 394 | if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 395 | break; 396 | } 397 | switch (schemeField.id) { 398 | case 1: // LEAF_NUM 399 | if (schemeField.type == org.apache.thrift.protocol.TType.I32) { 400 | struct.leafNum = iprot.readI32(); 401 | struct.setLeafNumIsSet(true); 402 | } else { 403 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 404 | } 405 | break; 406 | case 2: // PATH 407 | if (schemeField.type == org.apache.thrift.protocol.TType.LIST) { 408 | { 409 | org.apache.thrift.protocol.TList _list18 = iprot.readListBegin(); 410 | struct.path = new java.util.ArrayList(_list18.size); 411 | java.lang.String _elem19; 412 | for (int _i20 = 0; _i20 < _list18.size; ++_i20) 413 | { 414 | _elem19 = iprot.readString(); 415 | struct.path.add(_elem19); 416 | } 417 | iprot.readListEnd(); 418 | } 419 | struct.setPathIsSet(true); 420 | } else { 421 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 422 | } 423 | break; 424 | default: 425 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 426 | } 427 | iprot.readFieldEnd(); 428 | } 429 | iprot.readStructEnd(); 430 | 431 | // check for required fields of primitive type, which can't be checked in the validate method 432 | struct.validate(); 433 | } 434 | 435 | public void write(org.apache.thrift.protocol.TProtocol oprot, UpdateMessageStruct struct) throws org.apache.thrift.TException { 436 | struct.validate(); 437 | 438 | oprot.writeStructBegin(STRUCT_DESC); 439 | oprot.writeFieldBegin(LEAF_NUM_FIELD_DESC); 440 | oprot.writeI32(struct.leafNum); 441 | oprot.writeFieldEnd(); 442 | if (struct.path != null) { 443 | oprot.writeFieldBegin(PATH_FIELD_DESC); 444 | { 445 | oprot.writeListBegin(new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRING, struct.path.size())); 446 | for (java.lang.String _iter21 : struct.path) 447 | { 448 | oprot.writeString(_iter21); 449 | } 450 | oprot.writeListEnd(); 451 | } 452 | oprot.writeFieldEnd(); 453 | } 454 | oprot.writeFieldStop(); 455 | oprot.writeStructEnd(); 456 | } 457 | 458 | } 459 | 460 | private static class UpdateMessageStructTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { 461 | public UpdateMessageStructTupleScheme getScheme() { 462 | return new UpdateMessageStructTupleScheme(); 463 | } 464 | } 465 | 466 | private static class UpdateMessageStructTupleScheme extends org.apache.thrift.scheme.TupleScheme { 467 | 468 | @Override 469 | public void write(org.apache.thrift.protocol.TProtocol prot, UpdateMessageStruct struct) throws org.apache.thrift.TException { 470 | org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; 471 | java.util.BitSet optionals = new java.util.BitSet(); 472 | if (struct.isSetLeafNum()) { 473 | optionals.set(0); 474 | } 475 | if (struct.isSetPath()) { 476 | optionals.set(1); 477 | } 478 | oprot.writeBitSet(optionals, 2); 479 | if (struct.isSetLeafNum()) { 480 | oprot.writeI32(struct.leafNum); 481 | } 482 | if (struct.isSetPath()) { 483 | { 484 | oprot.writeI32(struct.path.size()); 485 | for (java.lang.String _iter22 : struct.path) 486 | { 487 | oprot.writeString(_iter22); 488 | } 489 | } 490 | } 491 | } 492 | 493 | @Override 494 | public void read(org.apache.thrift.protocol.TProtocol prot, UpdateMessageStruct struct) throws org.apache.thrift.TException { 495 | org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; 496 | java.util.BitSet incoming = iprot.readBitSet(2); 497 | if (incoming.get(0)) { 498 | struct.leafNum = iprot.readI32(); 499 | struct.setLeafNumIsSet(true); 500 | } 501 | if (incoming.get(1)) { 502 | { 503 | org.apache.thrift.protocol.TList _list23 = new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRING, iprot.readI32()); 504 | struct.path = new java.util.ArrayList(_list23.size); 505 | java.lang.String _elem24; 506 | for (int _i25 = 0; _i25 < _list23.size; ++_i25) 507 | { 508 | _elem24 = iprot.readString(); 509 | struct.path.add(_elem24); 510 | } 511 | } 512 | struct.setPathIsSet(true); 513 | } 514 | } 515 | } 516 | 517 | private static S scheme(org.apache.thrift.protocol.TProtocol proto) { 518 | return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); 519 | } 520 | } 521 | 522 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/tree/LeafNode.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.art.tree; 10 | 11 | abstract public class LeafNode implements Node { 12 | final public int numLeaves() { 13 | return 1; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/tree/Node.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.art.tree; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.art.message.thrift.NodeStruct; 12 | import com.facebook.research.asynchronousratchetingtree.crypto.DHPubKey; 13 | 14 | public interface Node { 15 | DHPubKey getPubKey(); 16 | int numLeaves(); 17 | 18 | static Node fromThrift(NodeStruct thrift) { 19 | if (thrift == null) { 20 | return null; 21 | } 22 | DHPubKey pubKey = DHPubKey.pubKey(thrift.getPublicKey()); 23 | NodeStruct left = thrift.getLeft(); 24 | NodeStruct right = thrift.getRight(); 25 | 26 | if (left == null && right == null) { 27 | return new PublicLeafNode(pubKey); 28 | } 29 | 30 | return new PublicParentNode( 31 | pubKey, 32 | fromThrift(left), 33 | fromThrift(right) 34 | ); 35 | } 36 | 37 | static NodeStruct toThrift(Node tree) { 38 | if (tree == null) { 39 | return null; 40 | } 41 | NodeStruct struct = new NodeStruct(); 42 | struct.setPublicKey(tree.getPubKey().getPubKeyBytes()); 43 | if (tree instanceof ParentNode) { 44 | struct.setLeft(Node.toThrift(((ParentNode) tree).getLeft())); 45 | struct.setRight(Node.toThrift(((ParentNode) tree).getRight())); 46 | } 47 | return struct; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/tree/ParentNode.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.art.tree; 10 | 11 | abstract public class ParentNode implements Node { 12 | protected Node left; 13 | protected Node right; 14 | 15 | public int numLeaves() { 16 | return left.numLeaves() + right.numLeaves(); 17 | } 18 | 19 | public Node getLeft() { 20 | return left; 21 | } 22 | 23 | public Node getRight() { 24 | return right; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/tree/PublicLeafNode.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.art.tree; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.crypto.DHPubKey; 12 | 13 | public class PublicLeafNode extends LeafNode { 14 | private DHPubKey pubKey; 15 | 16 | public PublicLeafNode(DHPubKey pubKey) { 17 | this.pubKey = pubKey; 18 | } 19 | 20 | public DHPubKey getPubKey() { 21 | return pubKey; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/tree/PublicParentNode.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.art.tree; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.crypto.DHPubKey; 12 | 13 | public class PublicParentNode extends ParentNode { 14 | private DHPubKey pubKey; 15 | 16 | public PublicParentNode(DHPubKey pubKey, Node left, Node right) { 17 | this.pubKey = pubKey; 18 | this.left = left; 19 | this.right = right; 20 | } 21 | 22 | public DHPubKey getPubKey() { 23 | return pubKey; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/tree/SecretLeafNode.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.art.tree; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.crypto.DHPubKey; 12 | import com.facebook.research.asynchronousratchetingtree.crypto.DHKeyPair; 13 | 14 | final public class SecretLeafNode extends LeafNode implements SecretNode { 15 | private DHKeyPair keyPair; 16 | 17 | public SecretLeafNode(DHKeyPair keyPair) { 18 | this.keyPair = keyPair; 19 | } 20 | 21 | public DHPubKey getPubKey() { 22 | return keyPair.getPubKey(); 23 | } 24 | 25 | public DHKeyPair getKeyPair() { 26 | return keyPair; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/tree/SecretNode.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.art.tree; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.crypto.DHKeyPair; 12 | 13 | public interface SecretNode extends Node { 14 | public DHKeyPair getKeyPair(); 15 | } 16 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/art/tree/SecretParentNode.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.art.tree; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.crypto.Crypto; 12 | import com.facebook.research.asynchronousratchetingtree.crypto.DHPubKey; 13 | import com.facebook.research.asynchronousratchetingtree.crypto.DHKeyPair; 14 | 15 | public class SecretParentNode extends ParentNode implements SecretNode { 16 | private DHKeyPair keyPair; 17 | 18 | public SecretParentNode(SecretNode left, Node right) { 19 | this.left = left; 20 | this.right = right; 21 | byte[] dhOutput = left.getKeyPair().exchange(right.getPubKey()); 22 | // Derive both a private ECDH key and an AES-128 encryption key. 23 | byte[] key = Crypto.hkdf(dhOutput, new byte[0], new byte[0], 32); 24 | 25 | keyPair = DHKeyPair.fromBytes(key, false); 26 | } 27 | 28 | public SecretParentNode(Node left, SecretNode right) { 29 | this.left = left; 30 | this.right = right; 31 | this.keyPair = DHKeyPair.fromBytes(right.getKeyPair().exchange(left.getPubKey()), false); 32 | byte[] dhOutput = right.getKeyPair().exchange(left.getPubKey()); 33 | // Derive both a private ECDH key and an AES-128 encryption key. 34 | byte[] key = Crypto.hkdf(dhOutput, new byte[0], new byte[0], 32); 35 | 36 | keyPair = DHKeyPair.fromBytes(key, false); 37 | } 38 | 39 | public DHPubKey getPubKey() { 40 | return keyPair.getPubKey(); 41 | } 42 | 43 | public DHKeyPair getKeyPair() { 44 | return keyPair; 45 | } 46 | 47 | public byte[] getRawSecretKey() { 48 | return keyPair.getPrivKeyBytes(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/crypto/Crypto.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.crypto; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.Utils; 12 | import com.facebook.research.asynchronousratchetingtree.art.tree.Node; 13 | import djb.Curve25519; 14 | 15 | import javax.crypto.Cipher; 16 | import javax.crypto.Mac; 17 | import javax.crypto.spec.GCMParameterSpec; 18 | import javax.crypto.spec.SecretKeySpec; 19 | import java.security.Key; 20 | import java.security.MessageDigest; 21 | import java.security.NoSuchAlgorithmException; 22 | import java.security.SecureRandom; 23 | import java.util.Arrays; 24 | 25 | /** 26 | * This crypto class is put together simply to make coding the rest of the example program easier. Please never actually 27 | * use it in production. 28 | */ 29 | public class Crypto { 30 | final public static int HASH_LENGTH = 32; 31 | 32 | public static MessageDigest startSHA256() { 33 | MessageDigest md; 34 | try { 35 | md = MessageDigest.getInstance("SHA-256"); 36 | } catch (NoSuchAlgorithmException e) { 37 | throw Utils.except(e); 38 | } 39 | return md; 40 | } 41 | 42 | public static byte[] hmacSha256(byte[] data, byte[] key) { 43 | Mac mac; 44 | try { 45 | mac = Mac.getInstance("HmacSHA256"); 46 | mac.init(new SecretKeySpec(key, "HmacSHA256")); 47 | } catch (Exception e) { 48 | throw Utils.except(e); 49 | } 50 | mac.update(data); 51 | return mac.doFinal(); 52 | } 53 | 54 | public static byte[] hkdf(byte[] input_keying_material, byte[] salt, byte[] info, int num_bytes) { 55 | // Extract step 56 | byte[] pseudo_random_key = hmacSha256(salt, input_keying_material); 57 | 58 | // Expand step 59 | byte[] output_bytes = new byte[num_bytes]; 60 | byte[] t = new byte[0]; 61 | for (byte i = 0; i < (num_bytes + 31) / 32; i++) { 62 | byte[] tInput = new byte[t.length + info.length + 1]; 63 | System.arraycopy(t, 0, tInput, 0, t.length); 64 | System.arraycopy(info, 0, tInput, t.length, info.length); 65 | tInput[tInput.length - 1] = i; 66 | 67 | t = hmacSha256(pseudo_random_key, tInput); 68 | int num_to_copy = num_bytes - (i * 32); 69 | if (num_to_copy > 32) { 70 | num_to_copy = 32; 71 | } 72 | 73 | System.arraycopy(t, 0, output_bytes, i * 32, num_to_copy); 74 | } 75 | return output_bytes; 76 | } 77 | 78 | public static byte[] artKDF( 79 | byte[] lastStageKey, 80 | byte[] treeKey, 81 | DHPubKey[] identities, 82 | Node tree 83 | ) { 84 | byte[] serialisedTree = Utils.serialise(Node.toThrift(tree)); 85 | byte[] ikm = new byte[lastStageKey.length + treeKey.length + serialisedTree.length]; 86 | System.arraycopy(lastStageKey, 0, ikm, 0, lastStageKey.length); 87 | System.arraycopy(treeKey, 0, ikm, lastStageKey.length, treeKey.length); 88 | System.arraycopy(serialisedTree, 0, ikm, lastStageKey.length + treeKey.length, serialisedTree.length); 89 | 90 | byte[] info = new byte[identities.length * Curve25519.KEY_SIZE]; 91 | for (int i = 0; i < identities.length; i++) { 92 | System.arraycopy(identities[i].getPubKeyBytes(), 0, info, i * Curve25519.KEY_SIZE, Curve25519.KEY_SIZE); 93 | } 94 | return hkdf(ikm, new byte[0], info, 16); 95 | } 96 | 97 | public static byte[] randomBytes(int n) { 98 | byte[] result = new byte[n]; 99 | SecureRandom rng = new SecureRandom(); 100 | rng.nextBytes(result); 101 | return result; 102 | } 103 | 104 | public static byte[] encrypt(byte[] message, byte[] keyBytes) { 105 | Cipher cipher; 106 | Key key; 107 | try { 108 | cipher = Cipher.getInstance("AES/GCM/NoPadding"); 109 | byte[] nonce = randomBytes(12); 110 | GCMParameterSpec paramSpec = new GCMParameterSpec(16 * 8, nonce); 111 | 112 | key = new SecretKeySpec(keyBytes, "AES"); 113 | cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec); 114 | 115 | int len = cipher.getOutputSize(message.length); 116 | byte[] result = new byte[len + 12]; 117 | System.arraycopy(nonce, 0, result, 0, 12); 118 | 119 | cipher.doFinal( 120 | message, 121 | 0, 122 | message.length, 123 | result, 124 | 12 125 | ); 126 | return result; 127 | } catch (Exception e) { 128 | throw Utils.except(e); 129 | } 130 | } 131 | 132 | public static byte[] decrypt(byte[] encrypted, byte[] keyBytes) { 133 | Cipher cipher; 134 | Key key; 135 | try { 136 | cipher = Cipher.getInstance("AES/GCM/NoPadding"); 137 | 138 | byte[] nonce = Arrays.copyOfRange(encrypted, 0, 12); 139 | byte[] ciphertext = Arrays.copyOfRange(encrypted, 12, encrypted.length); 140 | GCMParameterSpec paramSpec = new GCMParameterSpec(16 * 8, nonce); 141 | 142 | key = new SecretKeySpec(keyBytes, "AES"); 143 | cipher.init(Cipher.DECRYPT_MODE, key, paramSpec); 144 | 145 | return cipher.doFinal(ciphertext); 146 | } catch (Exception e) { 147 | throw Utils.except(e); 148 | } 149 | } 150 | 151 | public static byte[] keyExchangeInitiate( 152 | DHKeyPair selfIdentity, 153 | DHPubKey remoteIdentity, 154 | DHKeyPair keyExchangeKeyPair, 155 | DHPubKey remoteEphemeralKey 156 | ) { 157 | MessageDigest md = Crypto.startSHA256(); 158 | md.update(selfIdentity.exchange(remoteIdentity)); 159 | md.update(selfIdentity.exchange(remoteEphemeralKey)); 160 | md.update(keyExchangeKeyPair.exchange(remoteIdentity)); 161 | md.update(keyExchangeKeyPair.exchange(remoteEphemeralKey)); 162 | return md.digest(); 163 | } 164 | 165 | public static byte[] keyExchangeReceive( 166 | DHKeyPair selfIdentity, 167 | DHPubKey remoteIdentity, 168 | DHKeyPair ephemeralKey, 169 | DHPubKey keyExchangeKey 170 | ) { 171 | MessageDigest md = Crypto.startSHA256(); 172 | md.update(selfIdentity.exchange(remoteIdentity)); 173 | md.update(ephemeralKey.exchange(remoteIdentity)); 174 | md.update(selfIdentity.exchange(keyExchangeKey)); 175 | md.update(ephemeralKey.exchange(keyExchangeKey)); 176 | return md.digest(); 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/crypto/DHKeyPair.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.crypto; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.Utils; 12 | import djb.Curve25519; 13 | 14 | import java.security.MessageDigest; 15 | 16 | public class DHKeyPair extends DHPubKey { 17 | private byte[] priv; 18 | private byte[] privSign; 19 | 20 | protected DHKeyPair(byte[] pub, byte[] priv, byte[] privSign) { 21 | super(pub); 22 | this.priv = priv; 23 | this.privSign = privSign; 24 | } 25 | 26 | public static DHKeyPair generate(boolean allowSignatures) { 27 | return DHKeyPair.fromBytes(Crypto.randomBytes(Curve25519.KEY_SIZE), allowSignatures); 28 | } 29 | 30 | public static DHKeyPair fromBytes(byte[] priv, boolean allowSignatures) { 31 | byte[] pub = new byte[Curve25519.KEY_SIZE]; 32 | byte[] privSign; 33 | if (allowSignatures) { 34 | privSign = new byte[Curve25519.KEY_SIZE]; 35 | Curve25519.keygen(pub, privSign, priv); 36 | } else { 37 | privSign = null; 38 | Curve25519.keygen(pub, null, priv); 39 | } 40 | return new DHKeyPair(pub, priv, privSign); 41 | } 42 | 43 | public byte[] getPrivKeyBytes() { 44 | return priv; 45 | } 46 | 47 | public DHPubKey getPubKey() { 48 | return pubKey(getPubKeyBytes()); 49 | } 50 | 51 | public byte[] exchange(DHPubKey bob) { 52 | byte[] result = new byte[Curve25519.KEY_SIZE]; 53 | Curve25519.curve(result, getPrivKeyBytes(), bob.getPubKeyBytes()); 54 | return result; 55 | } 56 | 57 | /** 58 | * The Curve25519 library that we use implements KCDSA. The API provided accepts the first curve point 59 | * as an argument, and returns the second part of the signature. The first part is a hash of the public 60 | * curve point, so we append this ourselves. 61 | * In DHPubKey, we then verify signatures by hashing the input data similarly, and checking that the 62 | * output of the verification method equals the first part of the signature. 63 | * http://grouper.ieee.org/groups/1363/P1363a/contributions/kcdsa1363.pdf 64 | */ 65 | public byte[] sign(byte[] data) { 66 | if (privSign == null) { 67 | Utils.except("Non-signing key cannot be used for signing."); 68 | } 69 | boolean success = false; 70 | byte[] sig_second_part = new byte[0]; 71 | byte[] sig_first_part = new byte[0]; 72 | 73 | // Signature generation can fail, in which case we need to try a different Curve point. 74 | while (!success) { 75 | byte[] privCurvePoint = Crypto.randomBytes(Curve25519.KEY_SIZE); 76 | byte[] pubCurvePoint = new byte[Curve25519.KEY_SIZE]; 77 | Curve25519.keygen(pubCurvePoint, null, privCurvePoint); 78 | sig_first_part = Crypto.startSHA256().digest(pubCurvePoint); 79 | 80 | MessageDigest md = Crypto.startSHA256(); 81 | md.update(data); 82 | md.update(getPubKeyBytes()); 83 | byte[] digest = md.digest(); 84 | 85 | sig_second_part = new byte[Curve25519.KEY_SIZE]; 86 | success = Curve25519.sign( 87 | sig_second_part, 88 | digest, 89 | privCurvePoint, 90 | privSign 91 | ); 92 | } 93 | 94 | byte[] sig = new byte[Crypto.HASH_LENGTH + Curve25519.KEY_SIZE]; 95 | System.arraycopy(sig_first_part, 0, sig, 0, Crypto.HASH_LENGTH); 96 | System.arraycopy(sig_second_part, 0, sig, Crypto.HASH_LENGTH, Curve25519.KEY_SIZE); 97 | 98 | return sig; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/crypto/DHPubKey.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.crypto; 10 | 11 | import djb.Curve25519; 12 | 13 | import java.security.MessageDigest; 14 | import java.util.Arrays; 15 | 16 | public class DHPubKey { 17 | private byte[] pub; 18 | 19 | protected DHPubKey(byte[] pub) { 20 | this.pub = pub; 21 | } 22 | 23 | public static DHPubKey pubKey(byte[] pub) { 24 | if (pub == null || pub.length == 0) { 25 | return null; 26 | } 27 | return new DHPubKey(pub); 28 | } 29 | 30 | public byte[] getPubKeyBytes() { 31 | return pub; 32 | } 33 | 34 | public boolean verify(byte[] data, byte[] sig) { 35 | byte[] sig_first_part = Arrays.copyOfRange(sig, 0, Crypto.HASH_LENGTH); 36 | byte[] sig_second_part = Arrays.copyOfRange(sig, Crypto.HASH_LENGTH, sig.length); 37 | 38 | MessageDigest md = Crypto.startSHA256(); 39 | md.update(data); 40 | md.update(getPubKeyBytes()); 41 | byte[] digest = md.digest(); 42 | 43 | byte[] output = new byte[Curve25519.KEY_SIZE]; 44 | Curve25519.verify( 45 | output, 46 | sig_second_part, 47 | digest, 48 | getPubKeyBytes() 49 | ); 50 | 51 | return Arrays.equals( 52 | Crypto.startSHA256().digest(output), 53 | sig_first_part 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/crypto/SignedDHPubKey.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.crypto; 10 | 11 | public class SignedDHPubKey extends DHPubKey { 12 | private byte[] signature; 13 | 14 | public SignedDHPubKey(byte[] pubKey, byte[] signature) { 15 | super(pubKey); 16 | this.signature = signature; 17 | } 18 | 19 | public byte[] getSignature() { 20 | return signature; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/dhratchet/DHRatchet.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.dhratchet; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.KeyServer; 12 | import com.facebook.research.asynchronousratchetingtree.GroupMessagingTestImplementation; 13 | import com.facebook.research.asynchronousratchetingtree.MessageDistributer; 14 | import com.facebook.research.asynchronousratchetingtree.Utils; 15 | import com.facebook.research.asynchronousratchetingtree.crypto.Crypto; 16 | import com.facebook.research.asynchronousratchetingtree.crypto.DHKeyPair; 17 | import com.facebook.research.asynchronousratchetingtree.crypto.DHPubKey; 18 | import com.facebook.research.asynchronousratchetingtree.crypto.SignedDHPubKey; 19 | import com.facebook.research.asynchronousratchetingtree.dhratchet.message.DHRatchetMessageDistributer; 20 | import com.facebook.research.asynchronousratchetingtree.dhratchet.message.DHRatchetSetupMessage; 21 | import com.facebook.research.asynchronousratchetingtree.dhratchet.message.DHRatchetMessage; 22 | 23 | public class DHRatchet implements GroupMessagingTestImplementation { 24 | @Override 25 | public byte[] setupMessageForPeer(DHRatchetState state, DHPubKey[] peers, KeyServer keyServer, int i) { 26 | DHKeyPair identityKeyPair = state.getIdentityKeyPair(); 27 | 28 | SignedDHPubKey signedPreKey = keyServer.getSignedPreKey(state, i); 29 | if (!peers[i].verify(signedPreKey.getPubKeyBytes(), signedPreKey.getSignature())) { 30 | Utils.except("PreKey signature check failed."); 31 | } 32 | 33 | DHKeyPair ratchetKey = DHKeyPair.generate(false); 34 | state.setRootKey( 35 | i, 36 | Crypto.keyExchangeInitiate( 37 | identityKeyPair, 38 | peers[i], 39 | ratchetKey, 40 | keyServer.getSignedPreKey(state, i) 41 | ) 42 | ); 43 | state.setSelfRatchetKey(i, ratchetKey); 44 | state.setRatchetFlag(i, false); 45 | state.setIsSetup(i); 46 | 47 | DHRatchetSetupMessage setupMessage = new DHRatchetSetupMessage( 48 | state.getPeerNum(), 49 | identityKeyPair.getPubKey(), 50 | ratchetKey.getPubKey() 51 | ); 52 | return setupMessage.serialise(); 53 | } 54 | 55 | @Override 56 | public void processSetupMessage(DHRatchetState state, byte[] serialisedMessage, int participantNum) { 57 | DHRatchetSetupMessage message = new DHRatchetSetupMessage(serialisedMessage); 58 | int peerNum = message.getPeerNum(); 59 | state.setRootKey( 60 | peerNum, 61 | Crypto.keyExchangeReceive( 62 | state.getIdentityKeyPair(), 63 | message.getIdentity(), 64 | state.getPreKeyFor(peerNum), 65 | message.getEphemeralKey() 66 | ) 67 | ); 68 | state.setRemoteRatchetKey(peerNum, message.getEphemeralKey()); 69 | state.setRatchetFlag(peerNum, true); 70 | state.setIsSetup(peerNum); 71 | } 72 | 73 | @Override 74 | public MessageDistributer sendMessage(DHRatchetState state, byte[] plaintext) { 75 | byte[][] messages = new byte[state.getPeerCount()][]; 76 | for (int i = 0; i < state.getPeerCount(); i++) { 77 | if (i == state.getPeerNum()) { 78 | continue; 79 | } 80 | byte[] rootKey = state.getRootKey(i); 81 | if (state.getRatchetFlag(i)) { 82 | DHKeyPair selfRatchetKey = DHKeyPair.generate(false); 83 | state.setSelfRatchetKey(i, selfRatchetKey); 84 | rootKey = Crypto.hmacSha256( 85 | rootKey, 86 | selfRatchetKey.exchange(state.getRemoteRatchetKey(i)) 87 | ); 88 | state.setRootKey(i, rootKey); 89 | state.setRatchetFlag(i, false); 90 | } 91 | 92 | byte[] ciphertext = Crypto.encrypt(plaintext, rootKey); 93 | DHRatchetMessage message = new DHRatchetMessage( 94 | state.getPeerNum(), 95 | state.getSelfRatchetKey(i).getPubKey(), 96 | ciphertext 97 | ); 98 | messages[i] = message.serialise(); 99 | } 100 | return new DHRatchetMessageDistributer(messages); 101 | } 102 | 103 | @Override 104 | public byte[] receiveMessage(DHRatchetState state, byte[] serialisedMessage) { 105 | DHRatchetMessage message = new DHRatchetMessage(serialisedMessage); 106 | int i = message.getPeerNum(); 107 | byte[] rootKey = state.getRootKey(i); 108 | 109 | if (!state.getRatchetFlag(i)) { 110 | DHKeyPair selfRatchetKey = state.getSelfRatchetKey(i); 111 | DHPubKey remoteRatchetKey = message.getRatchetKey(); 112 | 113 | rootKey = Crypto.hmacSha256( 114 | rootKey, 115 | selfRatchetKey.exchange(remoteRatchetKey) 116 | ); 117 | state.setRootKey(i, rootKey); 118 | state.setRemoteRatchetKey( 119 | i, 120 | remoteRatchetKey 121 | ); 122 | state.setRatchetFlag(i, true); 123 | } 124 | 125 | return Crypto.decrypt(message.getCiphertext(), rootKey); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/dhratchet/DHRatchetSetupPhase.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.dhratchet; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.GroupMessagingSetupPhase; 12 | import com.facebook.research.asynchronousratchetingtree.GroupMessagingTestImplementation; 13 | import com.facebook.research.asynchronousratchetingtree.KeyServer; 14 | import com.facebook.research.asynchronousratchetingtree.crypto.DHPubKey; 15 | 16 | public class DHRatchetSetupPhase implements GroupMessagingSetupPhase { 17 | private byte[][] setupMessages; 18 | private int bytesReceivedByOthers = 0; 19 | private int bytesSentByOthers = 0; 20 | 21 | @Override 22 | public void generateNecessaryPreKeys(DHRatchetState[] states) { 23 | // We need PreKeys from each user to each user with a lower ID than them. 24 | for (int i = 0; i < states.length; i++) { 25 | for (int j = i + 1; j < states.length; j++) { 26 | states[j].getSignedDHPreKeyFor(i); 27 | } 28 | } 29 | } 30 | 31 | @Override 32 | public void setupInitiator(GroupMessagingTestImplementation implementation, DHRatchetState[] states, DHPubKey[] identities, KeyServer keyServer) { 33 | int n = states.length; 34 | setupMessages = new byte[n][]; 35 | for (int i = 1; i < n; i++) { 36 | setupMessages[i] = implementation.setupMessageForPeer(states[0], identities, keyServer, i); 37 | } 38 | } 39 | 40 | @Override 41 | public int getBytesSentByInitiator() { 42 | int total = 0; 43 | for (int i = 1; i < setupMessages.length; i++) { 44 | total += setupMessages[i].length; 45 | } 46 | return total; 47 | } 48 | 49 | /** 50 | * Here we aim to scale the total number of key exchanges performed proportionate to the number of active users. 51 | * This involves ensuring that every active user has done a key exchange for each of the others, and that they have 52 | * all done an unreciprocated key exchange with all other users. 53 | */ 54 | @Override 55 | public void setupAllOthers(GroupMessagingTestImplementation implementation, DHRatchetState[] states, Integer[] active, DHPubKey[] identities, KeyServer keyServer) { 56 | int n = states.length; 57 | 58 | // We need all active users to create and import each others' setup messages. 59 | for (int i = 0; i < active.length; i++) { 60 | int sender = active[i]; 61 | if (sender == 0) { 62 | continue; 63 | } 64 | // First let's import the initiator's state. 65 | bytesReceivedByOthers += setupMessages[sender].length; 66 | implementation.processSetupMessage(states[sender], setupMessages[sender], sender); 67 | 68 | for (int j = i + 1; j < active.length; j++) { 69 | int receiver = active[j]; 70 | if (receiver == 0) { 71 | continue; 72 | } 73 | byte[] setupMessage = implementation.setupMessageForPeer(states[sender], identities, keyServer, receiver); 74 | bytesSentByOthers += setupMessage.length; 75 | bytesReceivedByOthers += setupMessage.length; 76 | implementation.processSetupMessage(states[receiver], setupMessage, receiver); 77 | } 78 | } 79 | 80 | // Active users should still create state for inactive ones, it just shouldn't be imported. 81 | for (int i = 0; i < active.length; i++) { 82 | int sender = active[i]; 83 | for (int j = 0; j < n; j++) { 84 | if (states[sender].getIsSetup(j)) { 85 | continue; 86 | } 87 | byte[] setupMessage = implementation.setupMessageForPeer(states[sender], identities, keyServer, j); 88 | bytesSentByOthers += setupMessage.length; 89 | bytesReceivedByOthers += setupMessage.length; 90 | implementation.processSetupMessage(states[j], setupMessage, j); 91 | } 92 | } 93 | } 94 | 95 | @Override 96 | public int getBytesSentByOthers() { 97 | return bytesSentByOthers; 98 | } 99 | 100 | @Override 101 | public int getBytesReceivedByOthers() { 102 | return bytesReceivedByOthers; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/dhratchet/DHRatchetState.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.dhratchet; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.GroupMessagingState; 12 | import com.facebook.research.asynchronousratchetingtree.crypto.Crypto; 13 | import com.facebook.research.asynchronousratchetingtree.crypto.DHKeyPair; 14 | import com.facebook.research.asynchronousratchetingtree.crypto.DHPubKey; 15 | 16 | public class DHRatchetState extends GroupMessagingState { 17 | private byte[][] rootKeys; 18 | private DHKeyPair[] selfRatchetKeys; 19 | private DHPubKey[] remoteRatchetKeys; 20 | private boolean[] ratchetFlags; 21 | private boolean[] isSetup; 22 | 23 | public DHRatchetState(int peerNum, int peerCount) { 24 | super(peerNum, peerCount); 25 | rootKeys = new byte[peerCount][]; 26 | selfRatchetKeys = new DHKeyPair[peerCount]; 27 | remoteRatchetKeys = new DHPubKey[peerCount]; 28 | ratchetFlags = new boolean[peerCount]; 29 | isSetup = new boolean[peerCount]; 30 | } 31 | 32 | public void setRootKey(int i, byte[] rootKey) { 33 | rootKeys[i] = rootKey; 34 | } 35 | 36 | public byte[] getRootKey(int i) { 37 | return rootKeys[i]; 38 | } 39 | 40 | public void setSelfRatchetKey(int i, DHKeyPair ratchetKey) { 41 | selfRatchetKeys[i] = ratchetKey; 42 | } 43 | 44 | public DHKeyPair getSelfRatchetKey(int i) { 45 | return selfRatchetKeys[i]; 46 | } 47 | 48 | public void setRemoteRatchetKey(int i, DHPubKey ratchetKey) { 49 | remoteRatchetKeys[i] = ratchetKey; 50 | } 51 | 52 | public DHPubKey getRemoteRatchetKey(int i) { 53 | return remoteRatchetKeys[i]; 54 | } 55 | 56 | public void setRatchetFlag(int i, boolean flag) { 57 | ratchetFlags[i] = flag; 58 | } 59 | 60 | public boolean getRatchetFlag(int i) { 61 | return ratchetFlags[i]; 62 | } 63 | 64 | public byte[] getKeyWithPeer(int n) { 65 | return Crypto.hkdf(rootKeys[n], new byte[0], new byte[0], 16); 66 | } 67 | 68 | public void setIsSetup(int i) { 69 | isSetup[i] = true; 70 | } 71 | 72 | public boolean getIsSetup(int i) { 73 | return isSetup[i]; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/dhratchet/message/DHRatchetMessage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.dhratchet.message; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.Utils; 12 | import com.facebook.research.asynchronousratchetingtree.crypto.DHPubKey; 13 | import com.facebook.research.asynchronousratchetingtree.dhratchet.message.thrift.DHRatchetMessageStruct; 14 | 15 | public class DHRatchetMessage { 16 | private int peerNum; 17 | private DHPubKey ratchetKey; 18 | private byte[] ciphertext; 19 | 20 | public DHRatchetMessage( 21 | int peerNum, 22 | DHPubKey ratchetKey, 23 | byte[] ciphertext 24 | ) { 25 | this.peerNum = peerNum; 26 | this.ratchetKey = ratchetKey; 27 | this.ciphertext = ciphertext; 28 | } 29 | 30 | public DHRatchetMessage(byte[] thriftSerialised) { 31 | DHRatchetMessageStruct struct = new DHRatchetMessageStruct(); 32 | Utils.deserialise(struct, thriftSerialised); 33 | peerNum = struct.peerNum; 34 | ratchetKey = DHPubKey.pubKey(struct.getRatchetKey()); 35 | ciphertext = struct.getCiphertext(); 36 | } 37 | 38 | public int getPeerNum() { 39 | return peerNum; 40 | } 41 | 42 | public DHPubKey getRatchetKey() { 43 | return ratchetKey; 44 | } 45 | 46 | public byte[] getCiphertext() { 47 | return ciphertext; 48 | } 49 | 50 | public byte[] serialise() { 51 | DHRatchetMessageStruct struct = new DHRatchetMessageStruct(); 52 | struct.setPeerNum(peerNum); 53 | struct.setRatchetKey(ratchetKey.getPubKeyBytes()); 54 | struct.setCiphertext(ciphertext); 55 | return Utils.serialise(struct); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/dhratchet/message/DHRatchetMessageDistributer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.dhratchet.message; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.MessageDistributer; 12 | 13 | public class DHRatchetMessageDistributer implements MessageDistributer { 14 | private byte[][] updateMessages; 15 | 16 | public DHRatchetMessageDistributer(byte[][] updateMessages) { 17 | this.updateMessages = updateMessages; 18 | } 19 | 20 | @Override 21 | public byte[] getUpdateMessageForParticipantNum(int participantNum) { 22 | return updateMessages[participantNum]; 23 | } 24 | 25 | @Override 26 | public int totalSize() { 27 | int size = 0; 28 | for (int i = 0; i < updateMessages.length; i++) { 29 | if (updateMessages[i] == null) { 30 | continue; 31 | } 32 | size += updateMessages[i].length; 33 | } 34 | return size; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/dhratchet/message/DHRatchetSetupMessage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | package com.facebook.research.asynchronousratchetingtree.dhratchet.message; 10 | 11 | import com.facebook.research.asynchronousratchetingtree.Utils; 12 | import com.facebook.research.asynchronousratchetingtree.crypto.DHPubKey; 13 | import com.facebook.research.asynchronousratchetingtree.dhratchet.message.thrift.DHRatchetSetupMessageStruct; 14 | 15 | public class DHRatchetSetupMessage { 16 | private int peerNum; 17 | private DHPubKey identity; 18 | private DHPubKey ephemeralKey; 19 | 20 | public DHRatchetSetupMessage( 21 | int peerNum, 22 | DHPubKey identity, 23 | DHPubKey ephemeralKey 24 | ) { 25 | this.peerNum = peerNum; 26 | this.identity = identity; 27 | this.ephemeralKey = ephemeralKey; 28 | } 29 | 30 | public DHRatchetSetupMessage(byte[] thriftSerialised) { 31 | DHRatchetSetupMessageStruct struct = new DHRatchetSetupMessageStruct(); 32 | Utils.deserialise(struct, thriftSerialised); 33 | peerNum = struct.getPeerNum(); 34 | identity = DHPubKey.pubKey(struct.getIdentityKey()); 35 | ephemeralKey = DHPubKey.pubKey(struct.getEphemeralKey()); 36 | } 37 | 38 | public int getPeerNum() { 39 | return peerNum; 40 | } 41 | 42 | public DHPubKey getIdentity() { 43 | return identity; 44 | } 45 | 46 | public DHPubKey getEphemeralKey() { 47 | return ephemeralKey; 48 | } 49 | 50 | public byte[] serialise() { 51 | DHRatchetSetupMessageStruct struct = new DHRatchetSetupMessageStruct(); 52 | struct.setPeerNum(peerNum); 53 | struct.setIdentityKey(identity.getPubKeyBytes()); 54 | struct.setEphemeralKey(ephemeralKey.getPubKeyBytes()); 55 | return Utils.serialise(struct); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/dhratchet/message/thrift/DHRatchet.thrift: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017-present, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the license found in the 5 | # LICENSE file in the root directory of this source tree. 6 | # 7 | # Compile this file using the Thrift compiler, from the current directory, with the following command: 8 | # thrift -r --gen java -out ../../../../../../../ DHRatchet.thrift 9 | 10 | namespace java com.facebook.research.asynchronousratchetingtree.dhratchet.message.thrift 11 | 12 | struct DHRatchetSetupMessageStruct { 13 | 1: i32 peerNum, 14 | 2: binary identityKey, 15 | 3: binary ephemeralKey, 16 | } 17 | 18 | struct DHRatchetMessageStruct { 19 | 1: i32 peerNum, 20 | 2: binary ratchetKey, 21 | 3: binary ciphertext, 22 | } 23 | -------------------------------------------------------------------------------- /AsynchronousRatchetingTree/src/main/java/com/facebook/research/asynchronousratchetingtree/dhratchet/message/thrift/DHRatchetMessageStruct.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Autogenerated by Thrift Compiler (0.10.0) 3 | * 4 | * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 5 | * @generated 6 | */ 7 | package com.facebook.research.asynchronousratchetingtree.dhratchet.message.thrift; 8 | 9 | @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) 10 | @javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2018-01-05") 11 | public class DHRatchetMessageStruct implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { 12 | private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("DHRatchetMessageStruct"); 13 | 14 | private static final org.apache.thrift.protocol.TField PEER_NUM_FIELD_DESC = new org.apache.thrift.protocol.TField("peerNum", org.apache.thrift.protocol.TType.I32, (short)1); 15 | private static final org.apache.thrift.protocol.TField RATCHET_KEY_FIELD_DESC = new org.apache.thrift.protocol.TField("ratchetKey", org.apache.thrift.protocol.TType.STRING, (short)2); 16 | private static final org.apache.thrift.protocol.TField CIPHERTEXT_FIELD_DESC = new org.apache.thrift.protocol.TField("ciphertext", org.apache.thrift.protocol.TType.STRING, (short)3); 17 | 18 | private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new DHRatchetMessageStructStandardSchemeFactory(); 19 | private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new DHRatchetMessageStructTupleSchemeFactory(); 20 | 21 | public int peerNum; // required 22 | public java.nio.ByteBuffer ratchetKey; // required 23 | public java.nio.ByteBuffer ciphertext; // required 24 | 25 | /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ 26 | public enum _Fields implements org.apache.thrift.TFieldIdEnum { 27 | PEER_NUM((short)1, "peerNum"), 28 | RATCHET_KEY((short)2, "ratchetKey"), 29 | CIPHERTEXT((short)3, "ciphertext"); 30 | 31 | private static final java.util.Map byName = new java.util.HashMap(); 32 | 33 | static { 34 | for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { 35 | byName.put(field.getFieldName(), field); 36 | } 37 | } 38 | 39 | /** 40 | * Find the _Fields constant that matches fieldId, or null if its not found. 41 | */ 42 | public static _Fields findByThriftId(int fieldId) { 43 | switch(fieldId) { 44 | case 1: // PEER_NUM 45 | return PEER_NUM; 46 | case 2: // RATCHET_KEY 47 | return RATCHET_KEY; 48 | case 3: // CIPHERTEXT 49 | return CIPHERTEXT; 50 | default: 51 | return null; 52 | } 53 | } 54 | 55 | /** 56 | * Find the _Fields constant that matches fieldId, throwing an exception 57 | * if it is not found. 58 | */ 59 | public static _Fields findByThriftIdOrThrow(int fieldId) { 60 | _Fields fields = findByThriftId(fieldId); 61 | if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!"); 62 | return fields; 63 | } 64 | 65 | /** 66 | * Find the _Fields constant that matches name, or null if its not found. 67 | */ 68 | public static _Fields findByName(java.lang.String name) { 69 | return byName.get(name); 70 | } 71 | 72 | private final short _thriftId; 73 | private final java.lang.String _fieldName; 74 | 75 | _Fields(short thriftId, java.lang.String fieldName) { 76 | _thriftId = thriftId; 77 | _fieldName = fieldName; 78 | } 79 | 80 | public short getThriftFieldId() { 81 | return _thriftId; 82 | } 83 | 84 | public java.lang.String getFieldName() { 85 | return _fieldName; 86 | } 87 | } 88 | 89 | // isset id assignments 90 | private static final int __PEERNUM_ISSET_ID = 0; 91 | private byte __isset_bitfield = 0; 92 | public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; 93 | static { 94 | java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); 95 | tmpMap.put(_Fields.PEER_NUM, new org.apache.thrift.meta_data.FieldMetaData("peerNum", org.apache.thrift.TFieldRequirementType.DEFAULT, 96 | new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32))); 97 | tmpMap.put(_Fields.RATCHET_KEY, new org.apache.thrift.meta_data.FieldMetaData("ratchetKey", org.apache.thrift.TFieldRequirementType.DEFAULT, 98 | new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING , true))); 99 | tmpMap.put(_Fields.CIPHERTEXT, new org.apache.thrift.meta_data.FieldMetaData("ciphertext", org.apache.thrift.TFieldRequirementType.DEFAULT, 100 | new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING , true))); 101 | metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); 102 | org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(DHRatchetMessageStruct.class, metaDataMap); 103 | } 104 | 105 | public DHRatchetMessageStruct() { 106 | } 107 | 108 | public DHRatchetMessageStruct( 109 | int peerNum, 110 | java.nio.ByteBuffer ratchetKey, 111 | java.nio.ByteBuffer ciphertext) 112 | { 113 | this(); 114 | this.peerNum = peerNum; 115 | setPeerNumIsSet(true); 116 | this.ratchetKey = org.apache.thrift.TBaseHelper.copyBinary(ratchetKey); 117 | this.ciphertext = org.apache.thrift.TBaseHelper.copyBinary(ciphertext); 118 | } 119 | 120 | /** 121 | * Performs a deep copy on other. 122 | */ 123 | public DHRatchetMessageStruct(DHRatchetMessageStruct other) { 124 | __isset_bitfield = other.__isset_bitfield; 125 | this.peerNum = other.peerNum; 126 | if (other.isSetRatchetKey()) { 127 | this.ratchetKey = org.apache.thrift.TBaseHelper.copyBinary(other.ratchetKey); 128 | } 129 | if (other.isSetCiphertext()) { 130 | this.ciphertext = org.apache.thrift.TBaseHelper.copyBinary(other.ciphertext); 131 | } 132 | } 133 | 134 | public DHRatchetMessageStruct deepCopy() { 135 | return new DHRatchetMessageStruct(this); 136 | } 137 | 138 | @Override 139 | public void clear() { 140 | setPeerNumIsSet(false); 141 | this.peerNum = 0; 142 | this.ratchetKey = null; 143 | this.ciphertext = null; 144 | } 145 | 146 | public int getPeerNum() { 147 | return this.peerNum; 148 | } 149 | 150 | public DHRatchetMessageStruct setPeerNum(int peerNum) { 151 | this.peerNum = peerNum; 152 | setPeerNumIsSet(true); 153 | return this; 154 | } 155 | 156 | public void unsetPeerNum() { 157 | __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __PEERNUM_ISSET_ID); 158 | } 159 | 160 | /** Returns true if field peerNum is set (has been assigned a value) and false otherwise */ 161 | public boolean isSetPeerNum() { 162 | return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __PEERNUM_ISSET_ID); 163 | } 164 | 165 | public void setPeerNumIsSet(boolean value) { 166 | __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __PEERNUM_ISSET_ID, value); 167 | } 168 | 169 | public byte[] getRatchetKey() { 170 | setRatchetKey(org.apache.thrift.TBaseHelper.rightSize(ratchetKey)); 171 | return ratchetKey == null ? null : ratchetKey.array(); 172 | } 173 | 174 | public java.nio.ByteBuffer bufferForRatchetKey() { 175 | return org.apache.thrift.TBaseHelper.copyBinary(ratchetKey); 176 | } 177 | 178 | public DHRatchetMessageStruct setRatchetKey(byte[] ratchetKey) { 179 | this.ratchetKey = ratchetKey == null ? (java.nio.ByteBuffer)null : java.nio.ByteBuffer.wrap(ratchetKey.clone()); 180 | return this; 181 | } 182 | 183 | public DHRatchetMessageStruct setRatchetKey(java.nio.ByteBuffer ratchetKey) { 184 | this.ratchetKey = org.apache.thrift.TBaseHelper.copyBinary(ratchetKey); 185 | return this; 186 | } 187 | 188 | public void unsetRatchetKey() { 189 | this.ratchetKey = null; 190 | } 191 | 192 | /** Returns true if field ratchetKey is set (has been assigned a value) and false otherwise */ 193 | public boolean isSetRatchetKey() { 194 | return this.ratchetKey != null; 195 | } 196 | 197 | public void setRatchetKeyIsSet(boolean value) { 198 | if (!value) { 199 | this.ratchetKey = null; 200 | } 201 | } 202 | 203 | public byte[] getCiphertext() { 204 | setCiphertext(org.apache.thrift.TBaseHelper.rightSize(ciphertext)); 205 | return ciphertext == null ? null : ciphertext.array(); 206 | } 207 | 208 | public java.nio.ByteBuffer bufferForCiphertext() { 209 | return org.apache.thrift.TBaseHelper.copyBinary(ciphertext); 210 | } 211 | 212 | public DHRatchetMessageStruct setCiphertext(byte[] ciphertext) { 213 | this.ciphertext = ciphertext == null ? (java.nio.ByteBuffer)null : java.nio.ByteBuffer.wrap(ciphertext.clone()); 214 | return this; 215 | } 216 | 217 | public DHRatchetMessageStruct setCiphertext(java.nio.ByteBuffer ciphertext) { 218 | this.ciphertext = org.apache.thrift.TBaseHelper.copyBinary(ciphertext); 219 | return this; 220 | } 221 | 222 | public void unsetCiphertext() { 223 | this.ciphertext = null; 224 | } 225 | 226 | /** Returns true if field ciphertext is set (has been assigned a value) and false otherwise */ 227 | public boolean isSetCiphertext() { 228 | return this.ciphertext != null; 229 | } 230 | 231 | public void setCiphertextIsSet(boolean value) { 232 | if (!value) { 233 | this.ciphertext = null; 234 | } 235 | } 236 | 237 | public void setFieldValue(_Fields field, java.lang.Object value) { 238 | switch (field) { 239 | case PEER_NUM: 240 | if (value == null) { 241 | unsetPeerNum(); 242 | } else { 243 | setPeerNum((java.lang.Integer)value); 244 | } 245 | break; 246 | 247 | case RATCHET_KEY: 248 | if (value == null) { 249 | unsetRatchetKey(); 250 | } else { 251 | if (value instanceof byte[]) { 252 | setRatchetKey((byte[])value); 253 | } else { 254 | setRatchetKey((java.nio.ByteBuffer)value); 255 | } 256 | } 257 | break; 258 | 259 | case CIPHERTEXT: 260 | if (value == null) { 261 | unsetCiphertext(); 262 | } else { 263 | if (value instanceof byte[]) { 264 | setCiphertext((byte[])value); 265 | } else { 266 | setCiphertext((java.nio.ByteBuffer)value); 267 | } 268 | } 269 | break; 270 | 271 | } 272 | } 273 | 274 | public java.lang.Object getFieldValue(_Fields field) { 275 | switch (field) { 276 | case PEER_NUM: 277 | return getPeerNum(); 278 | 279 | case RATCHET_KEY: 280 | return getRatchetKey(); 281 | 282 | case CIPHERTEXT: 283 | return getCiphertext(); 284 | 285 | } 286 | throw new java.lang.IllegalStateException(); 287 | } 288 | 289 | /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ 290 | public boolean isSet(_Fields field) { 291 | if (field == null) { 292 | throw new java.lang.IllegalArgumentException(); 293 | } 294 | 295 | switch (field) { 296 | case PEER_NUM: 297 | return isSetPeerNum(); 298 | case RATCHET_KEY: 299 | return isSetRatchetKey(); 300 | case CIPHERTEXT: 301 | return isSetCiphertext(); 302 | } 303 | throw new java.lang.IllegalStateException(); 304 | } 305 | 306 | @Override 307 | public boolean equals(java.lang.Object that) { 308 | if (that == null) 309 | return false; 310 | if (that instanceof DHRatchetMessageStruct) 311 | return this.equals((DHRatchetMessageStruct)that); 312 | return false; 313 | } 314 | 315 | public boolean equals(DHRatchetMessageStruct that) { 316 | if (that == null) 317 | return false; 318 | if (this == that) 319 | return true; 320 | 321 | boolean this_present_peerNum = true; 322 | boolean that_present_peerNum = true; 323 | if (this_present_peerNum || that_present_peerNum) { 324 | if (!(this_present_peerNum && that_present_peerNum)) 325 | return false; 326 | if (this.peerNum != that.peerNum) 327 | return false; 328 | } 329 | 330 | boolean this_present_ratchetKey = true && this.isSetRatchetKey(); 331 | boolean that_present_ratchetKey = true && that.isSetRatchetKey(); 332 | if (this_present_ratchetKey || that_present_ratchetKey) { 333 | if (!(this_present_ratchetKey && that_present_ratchetKey)) 334 | return false; 335 | if (!this.ratchetKey.equals(that.ratchetKey)) 336 | return false; 337 | } 338 | 339 | boolean this_present_ciphertext = true && this.isSetCiphertext(); 340 | boolean that_present_ciphertext = true && that.isSetCiphertext(); 341 | if (this_present_ciphertext || that_present_ciphertext) { 342 | if (!(this_present_ciphertext && that_present_ciphertext)) 343 | return false; 344 | if (!this.ciphertext.equals(that.ciphertext)) 345 | return false; 346 | } 347 | 348 | return true; 349 | } 350 | 351 | @Override 352 | public int hashCode() { 353 | int hashCode = 1; 354 | 355 | hashCode = hashCode * 8191 + peerNum; 356 | 357 | hashCode = hashCode * 8191 + ((isSetRatchetKey()) ? 131071 : 524287); 358 | if (isSetRatchetKey()) 359 | hashCode = hashCode * 8191 + ratchetKey.hashCode(); 360 | 361 | hashCode = hashCode * 8191 + ((isSetCiphertext()) ? 131071 : 524287); 362 | if (isSetCiphertext()) 363 | hashCode = hashCode * 8191 + ciphertext.hashCode(); 364 | 365 | return hashCode; 366 | } 367 | 368 | @Override 369 | public int compareTo(DHRatchetMessageStruct other) { 370 | if (!getClass().equals(other.getClass())) { 371 | return getClass().getName().compareTo(other.getClass().getName()); 372 | } 373 | 374 | int lastComparison = 0; 375 | 376 | lastComparison = java.lang.Boolean.valueOf(isSetPeerNum()).compareTo(other.isSetPeerNum()); 377 | if (lastComparison != 0) { 378 | return lastComparison; 379 | } 380 | if (isSetPeerNum()) { 381 | lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.peerNum, other.peerNum); 382 | if (lastComparison != 0) { 383 | return lastComparison; 384 | } 385 | } 386 | lastComparison = java.lang.Boolean.valueOf(isSetRatchetKey()).compareTo(other.isSetRatchetKey()); 387 | if (lastComparison != 0) { 388 | return lastComparison; 389 | } 390 | if (isSetRatchetKey()) { 391 | lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.ratchetKey, other.ratchetKey); 392 | if (lastComparison != 0) { 393 | return lastComparison; 394 | } 395 | } 396 | lastComparison = java.lang.Boolean.valueOf(isSetCiphertext()).compareTo(other.isSetCiphertext()); 397 | if (lastComparison != 0) { 398 | return lastComparison; 399 | } 400 | if (isSetCiphertext()) { 401 | lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.ciphertext, other.ciphertext); 402 | if (lastComparison != 0) { 403 | return lastComparison; 404 | } 405 | } 406 | return 0; 407 | } 408 | 409 | public _Fields fieldForId(int fieldId) { 410 | return _Fields.findByThriftId(fieldId); 411 | } 412 | 413 | public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { 414 | scheme(iprot).read(iprot, this); 415 | } 416 | 417 | public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { 418 | scheme(oprot).write(oprot, this); 419 | } 420 | 421 | @Override 422 | public java.lang.String toString() { 423 | java.lang.StringBuilder sb = new java.lang.StringBuilder("DHRatchetMessageStruct("); 424 | boolean first = true; 425 | 426 | sb.append("peerNum:"); 427 | sb.append(this.peerNum); 428 | first = false; 429 | if (!first) sb.append(", "); 430 | sb.append("ratchetKey:"); 431 | if (this.ratchetKey == null) { 432 | sb.append("null"); 433 | } else { 434 | org.apache.thrift.TBaseHelper.toString(this.ratchetKey, sb); 435 | } 436 | first = false; 437 | if (!first) sb.append(", "); 438 | sb.append("ciphertext:"); 439 | if (this.ciphertext == null) { 440 | sb.append("null"); 441 | } else { 442 | org.apache.thrift.TBaseHelper.toString(this.ciphertext, sb); 443 | } 444 | first = false; 445 | sb.append(")"); 446 | return sb.toString(); 447 | } 448 | 449 | public void validate() throws org.apache.thrift.TException { 450 | // check for required fields 451 | // check for sub-struct validity 452 | } 453 | 454 | private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { 455 | try { 456 | write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); 457 | } catch (org.apache.thrift.TException te) { 458 | throw new java.io.IOException(te); 459 | } 460 | } 461 | 462 | private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { 463 | try { 464 | // it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor. 465 | __isset_bitfield = 0; 466 | read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); 467 | } catch (org.apache.thrift.TException te) { 468 | throw new java.io.IOException(te); 469 | } 470 | } 471 | 472 | private static class DHRatchetMessageStructStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { 473 | public DHRatchetMessageStructStandardScheme getScheme() { 474 | return new DHRatchetMessageStructStandardScheme(); 475 | } 476 | } 477 | 478 | private static class DHRatchetMessageStructStandardScheme extends org.apache.thrift.scheme.StandardScheme { 479 | 480 | public void read(org.apache.thrift.protocol.TProtocol iprot, DHRatchetMessageStruct struct) throws org.apache.thrift.TException { 481 | org.apache.thrift.protocol.TField schemeField; 482 | iprot.readStructBegin(); 483 | while (true) 484 | { 485 | schemeField = iprot.readFieldBegin(); 486 | if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 487 | break; 488 | } 489 | switch (schemeField.id) { 490 | case 1: // PEER_NUM 491 | if (schemeField.type == org.apache.thrift.protocol.TType.I32) { 492 | struct.peerNum = iprot.readI32(); 493 | struct.setPeerNumIsSet(true); 494 | } else { 495 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 496 | } 497 | break; 498 | case 2: // RATCHET_KEY 499 | if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { 500 | struct.ratchetKey = iprot.readBinary(); 501 | struct.setRatchetKeyIsSet(true); 502 | } else { 503 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 504 | } 505 | break; 506 | case 3: // CIPHERTEXT 507 | if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { 508 | struct.ciphertext = iprot.readBinary(); 509 | struct.setCiphertextIsSet(true); 510 | } else { 511 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 512 | } 513 | break; 514 | default: 515 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 516 | } 517 | iprot.readFieldEnd(); 518 | } 519 | iprot.readStructEnd(); 520 | 521 | // check for required fields of primitive type, which can't be checked in the validate method 522 | struct.validate(); 523 | } 524 | 525 | public void write(org.apache.thrift.protocol.TProtocol oprot, DHRatchetMessageStruct struct) throws org.apache.thrift.TException { 526 | struct.validate(); 527 | 528 | oprot.writeStructBegin(STRUCT_DESC); 529 | oprot.writeFieldBegin(PEER_NUM_FIELD_DESC); 530 | oprot.writeI32(struct.peerNum); 531 | oprot.writeFieldEnd(); 532 | if (struct.ratchetKey != null) { 533 | oprot.writeFieldBegin(RATCHET_KEY_FIELD_DESC); 534 | oprot.writeBinary(struct.ratchetKey); 535 | oprot.writeFieldEnd(); 536 | } 537 | if (struct.ciphertext != null) { 538 | oprot.writeFieldBegin(CIPHERTEXT_FIELD_DESC); 539 | oprot.writeBinary(struct.ciphertext); 540 | oprot.writeFieldEnd(); 541 | } 542 | oprot.writeFieldStop(); 543 | oprot.writeStructEnd(); 544 | } 545 | 546 | } 547 | 548 | private static class DHRatchetMessageStructTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { 549 | public DHRatchetMessageStructTupleScheme getScheme() { 550 | return new DHRatchetMessageStructTupleScheme(); 551 | } 552 | } 553 | 554 | private static class DHRatchetMessageStructTupleScheme extends org.apache.thrift.scheme.TupleScheme { 555 | 556 | @Override 557 | public void write(org.apache.thrift.protocol.TProtocol prot, DHRatchetMessageStruct struct) throws org.apache.thrift.TException { 558 | org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; 559 | java.util.BitSet optionals = new java.util.BitSet(); 560 | if (struct.isSetPeerNum()) { 561 | optionals.set(0); 562 | } 563 | if (struct.isSetRatchetKey()) { 564 | optionals.set(1); 565 | } 566 | if (struct.isSetCiphertext()) { 567 | optionals.set(2); 568 | } 569 | oprot.writeBitSet(optionals, 3); 570 | if (struct.isSetPeerNum()) { 571 | oprot.writeI32(struct.peerNum); 572 | } 573 | if (struct.isSetRatchetKey()) { 574 | oprot.writeBinary(struct.ratchetKey); 575 | } 576 | if (struct.isSetCiphertext()) { 577 | oprot.writeBinary(struct.ciphertext); 578 | } 579 | } 580 | 581 | @Override 582 | public void read(org.apache.thrift.protocol.TProtocol prot, DHRatchetMessageStruct struct) throws org.apache.thrift.TException { 583 | org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; 584 | java.util.BitSet incoming = iprot.readBitSet(3); 585 | if (incoming.get(0)) { 586 | struct.peerNum = iprot.readI32(); 587 | struct.setPeerNumIsSet(true); 588 | } 589 | if (incoming.get(1)) { 590 | struct.ratchetKey = iprot.readBinary(); 591 | struct.setRatchetKeyIsSet(true); 592 | } 593 | if (incoming.get(2)) { 594 | struct.ciphertext = iprot.readBinary(); 595 | struct.setCiphertextIsSet(true); 596 | } 597 | } 598 | } 599 | 600 | private static S scheme(org.apache.thrift.protocol.TProtocol proto) { 601 | return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); 602 | } 603 | } 604 | 605 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | Facebook has adopted a Code of Conduct that we expect project participants to 4 | adhere to. Please read the [full 5 | text](https://code.facebook.com/pages/876921332402685/open-source-code-of-conduct) 6 | so that you can understand what actions will and will not be tolerated. 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Asynchronous Ratcheting Tree 2 | We want to make contributing to this project as easy and transparent as 3 | possible. 4 | 5 | ## Our Development Process 6 | This repository contains example code, provided to ensure that the results of 7 | our paper "On Ends-to-Ends Encryption" are reproducible. As such, it is not 8 | under active development. We are interested in ensuring that the provided 9 | implementation is faithful to the algorithms described within the paper, so 10 | we will create or accept patches as and when bugs are discovered. 11 | 12 | ## Pull Requests 13 | We actively welcome your pull requests. 14 | 15 | 1. Fork the repo and create your branch from `master`. 16 | 2. Ensure that the benchmarks still run. 17 | 3. Make sure your code lints. 18 | 4. If you haven't already, complete the Contributor License Agreement ("CLA"). 19 | 20 | ## Contributor License Agreement ("CLA") 21 | In order to accept your pull request, we need you to submit a CLA. You only need 22 | to do this once to work on any of Facebook's open source projects. 23 | 24 | Complete your CLA here: 25 | 26 | ## Issues 27 | We use GitHub issues to track public bugs. Please ensure your description is 28 | clear and has sufficient instructions to be able to reproduce the issue. 29 | 30 | ## Coding Style 31 | * 2 spaces for indentation rather than tabs 32 | 33 | ## License 34 | By contributing to Asynchronous Ratcheting Tree, you agree that your 35 | contributions will be licensed under the LICENSE file in the root directory of 36 | this source tree. 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Attribution-NonCommercial 4.0 International 2 | 3 | ======================================================================= 4 | 5 | Creative Commons Corporation ("Creative Commons") is not a law firm and 6 | does not provide legal services or legal advice. Distribution of 7 | Creative Commons public licenses does not create a lawyer-client or 8 | other relationship. Creative Commons makes its licenses and related 9 | information available on an "as-is" basis. Creative Commons gives no 10 | warranties regarding its licenses, any material licensed under their 11 | terms and conditions, or any related information. Creative Commons 12 | disclaims all liability for damages resulting from their use to the 13 | fullest extent possible. 14 | 15 | Using Creative Commons Public Licenses 16 | 17 | Creative Commons public licenses provide a standard set of terms and 18 | conditions that creators and other rights holders may use to share 19 | original works of authorship and other material subject to copyright 20 | and certain other rights specified in the public license below. The 21 | following considerations are for informational purposes only, are not 22 | exhaustive, and do not form part of our licenses. 23 | 24 | Considerations for licensors: Our public licenses are 25 | intended for use by those authorized to give the public 26 | permission to use material in ways otherwise restricted by 27 | copyright and certain other rights. Our licenses are 28 | irrevocable. Licensors should read and understand the terms 29 | and conditions of the license they choose before applying it. 30 | Licensors should also secure all rights necessary before 31 | applying our licenses so that the public can reuse the 32 | material as expected. Licensors should clearly mark any 33 | material not subject to the license. This includes other CC- 34 | licensed material, or material used under an exception or 35 | limitation to copyright. More considerations for licensors: 36 | wiki.creativecommons.org/Considerations_for_licensors 37 | 38 | Considerations for the public: By using one of our public 39 | licenses, a licensor grants the public permission to use the 40 | licensed material under specified terms and conditions. If 41 | the licensor's permission is not necessary for any reason--for 42 | example, because of any applicable exception or limitation to 43 | copyright--then that use is not regulated by the license. Our 44 | licenses grant only permissions under copyright and certain 45 | other rights that a licensor has authority to grant. Use of 46 | the licensed material may still be restricted for other 47 | reasons, including because others have copyright or other 48 | rights in the material. A licensor may make special requests, 49 | such as asking that all changes be marked or described. 50 | Although not required by our licenses, you are encouraged to 51 | respect those requests where reasonable. More_considerations 52 | for the public: 53 | wiki.creativecommons.org/Considerations_for_licensees 54 | 55 | ======================================================================= 56 | 57 | Creative Commons Attribution-NonCommercial 4.0 International Public 58 | License 59 | 60 | By exercising the Licensed Rights (defined below), You accept and agree 61 | to be bound by the terms and conditions of this Creative Commons 62 | Attribution-NonCommercial 4.0 International Public License ("Public 63 | License"). To the extent this Public License may be interpreted as a 64 | contract, You are granted the Licensed Rights in consideration of Your 65 | acceptance of these terms and conditions, and the Licensor grants You 66 | such rights in consideration of benefits the Licensor receives from 67 | making the Licensed Material available under these terms and 68 | conditions. 69 | 70 | Section 1 -- Definitions. 71 | 72 | a. Adapted Material means material subject to Copyright and Similar 73 | Rights that is derived from or based upon the Licensed Material 74 | and in which the Licensed Material is translated, altered, 75 | arranged, transformed, or otherwise modified in a manner requiring 76 | permission under the Copyright and Similar Rights held by the 77 | Licensor. For purposes of this Public License, where the Licensed 78 | Material is a musical work, performance, or sound recording, 79 | Adapted Material is always produced where the Licensed Material is 80 | synched in timed relation with a moving image. 81 | 82 | b. Adapter's License means the license You apply to Your Copyright 83 | and Similar Rights in Your contributions to Adapted Material in 84 | accordance with the terms and conditions of this Public License. 85 | 86 | c. Copyright and Similar Rights means copyright and/or similar rights 87 | closely related to copyright including, without limitation, 88 | performance, broadcast, sound recording, and Sui Generis Database 89 | Rights, without regard to how the rights are labeled or 90 | categorized. For purposes of this Public License, the rights 91 | specified in Section 2(b)(1)-(2) are not Copyright and Similar 92 | Rights. 93 | d. Effective Technological Measures means those measures that, in the 94 | absence of proper authority, may not be circumvented under laws 95 | fulfilling obligations under Article 11 of the WIPO Copyright 96 | Treaty adopted on December 20, 1996, and/or similar international 97 | agreements. 98 | 99 | e. Exceptions and Limitations means fair use, fair dealing, and/or 100 | any other exception or limitation to Copyright and Similar Rights 101 | that applies to Your use of the Licensed Material. 102 | 103 | f. Licensed Material means the artistic or literary work, database, 104 | or other material to which the Licensor applied this Public 105 | License. 106 | 107 | g. Licensed Rights means the rights granted to You subject to the 108 | terms and conditions of this Public License, which are limited to 109 | all Copyright and Similar Rights that apply to Your use of the 110 | Licensed Material and that the Licensor has authority to license. 111 | 112 | h. Licensor means the individual(s) or entity(ies) granting rights 113 | under this Public License. 114 | 115 | i. NonCommercial means not primarily intended for or directed towards 116 | commercial advantage or monetary compensation. For purposes of 117 | this Public License, the exchange of the Licensed Material for 118 | other material subject to Copyright and Similar Rights by digital 119 | file-sharing or similar means is NonCommercial provided there is 120 | no payment of monetary compensation in connection with the 121 | exchange. 122 | 123 | j. Share means to provide material to the public by any means or 124 | process that requires permission under the Licensed Rights, such 125 | as reproduction, public display, public performance, distribution, 126 | dissemination, communication, or importation, and to make material 127 | available to the public including in ways that members of the 128 | public may access the material from a place and at a time 129 | individually chosen by them. 130 | 131 | k. Sui Generis Database Rights means rights other than copyright 132 | resulting from Directive 96/9/EC of the European Parliament and of 133 | the Council of 11 March 1996 on the legal protection of databases, 134 | as amended and/or succeeded, as well as other essentially 135 | equivalent rights anywhere in the world. 136 | 137 | l. You means the individual or entity exercising the Licensed Rights 138 | under this Public License. Your has a corresponding meaning. 139 | 140 | Section 2 -- Scope. 141 | 142 | a. License grant. 143 | 144 | 1. Subject to the terms and conditions of this Public License, 145 | the Licensor hereby grants You a worldwide, royalty-free, 146 | non-sublicensable, non-exclusive, irrevocable license to 147 | exercise the Licensed Rights in the Licensed Material to: 148 | 149 | a. reproduce and Share the Licensed Material, in whole or 150 | in part, for NonCommercial purposes only; and 151 | 152 | b. produce, reproduce, and Share Adapted Material for 153 | NonCommercial purposes only. 154 | 155 | 2. Exceptions and Limitations. For the avoidance of doubt, where 156 | Exceptions and Limitations apply to Your use, this Public 157 | License does not apply, and You do not need to comply with 158 | its terms and conditions. 159 | 160 | 3. Term. The term of this Public License is specified in Section 161 | 6(a). 162 | 163 | 4. Media and formats; technical modifications allowed. The 164 | Licensor authorizes You to exercise the Licensed Rights in 165 | all media and formats whether now known or hereafter created, 166 | and to make technical modifications necessary to do so. The 167 | Licensor waives and/or agrees not to assert any right or 168 | authority to forbid You from making technical modifications 169 | necessary to exercise the Licensed Rights, including 170 | technical modifications necessary to circumvent Effective 171 | Technological Measures. For purposes of this Public License, 172 | simply making modifications authorized by this Section 2(a) 173 | (4) never produces Adapted Material. 174 | 175 | 5. Downstream recipients. 176 | 177 | a. Offer from the Licensor -- Licensed Material. Every 178 | recipient of the Licensed Material automatically 179 | receives an offer from the Licensor to exercise the 180 | Licensed Rights under the terms and conditions of this 181 | Public License. 182 | 183 | b. No downstream restrictions. You may not offer or impose 184 | any additional or different terms or conditions on, or 185 | apply any Effective Technological Measures to, the 186 | Licensed Material if doing so restricts exercise of the 187 | Licensed Rights by any recipient of the Licensed 188 | Material. 189 | 190 | 6. No endorsement. Nothing in this Public License constitutes or 191 | may be construed as permission to assert or imply that You 192 | are, or that Your use of the Licensed Material is, connected 193 | with, or sponsored, endorsed, or granted official status by, 194 | the Licensor or others designated to receive attribution as 195 | provided in Section 3(a)(1)(A)(i). 196 | 197 | b. Other rights. 198 | 199 | 1. Moral rights, such as the right of integrity, are not 200 | licensed under this Public License, nor are publicity, 201 | privacy, and/or other similar personality rights; however, to 202 | the extent possible, the Licensor waives and/or agrees not to 203 | assert any such rights held by the Licensor to the limited 204 | extent necessary to allow You to exercise the Licensed 205 | Rights, but not otherwise. 206 | 207 | 2. Patent and trademark rights are not licensed under this 208 | Public License. 209 | 210 | 3. To the extent possible, the Licensor waives any right to 211 | collect royalties from You for the exercise of the Licensed 212 | Rights, whether directly or through a collecting society 213 | under any voluntary or waivable statutory or compulsory 214 | licensing scheme. In all other cases the Licensor expressly 215 | reserves any right to collect such royalties, including when 216 | the Licensed Material is used other than for NonCommercial 217 | purposes. 218 | 219 | Section 3 -- License Conditions. 220 | 221 | Your exercise of the Licensed Rights is expressly made subject to the 222 | following conditions. 223 | 224 | a. Attribution. 225 | 226 | 1. If You Share the Licensed Material (including in modified 227 | form), You must: 228 | 229 | a. retain the following if it is supplied by the Licensor 230 | with the Licensed Material: 231 | 232 | i. identification of the creator(s) of the Licensed 233 | Material and any others designated to receive 234 | attribution, in any reasonable manner requested by 235 | the Licensor (including by pseudonym if 236 | designated); 237 | 238 | ii. a copyright notice; 239 | 240 | iii. a notice that refers to this Public License; 241 | 242 | iv. a notice that refers to the disclaimer of 243 | warranties; 244 | 245 | v. a URI or hyperlink to the Licensed Material to the 246 | extent reasonably practicable; 247 | 248 | b. indicate if You modified the Licensed Material and 249 | retain an indication of any previous modifications; and 250 | 251 | c. indicate the Licensed Material is licensed under this 252 | Public License, and include the text of, or the URI or 253 | hyperlink to, this Public License. 254 | 255 | 2. You may satisfy the conditions in Section 3(a)(1) in any 256 | reasonable manner based on the medium, means, and context in 257 | which You Share the Licensed Material. For example, it may be 258 | reasonable to satisfy the conditions by providing a URI or 259 | hyperlink to a resource that includes the required 260 | information. 261 | 262 | 3. If requested by the Licensor, You must remove any of the 263 | information required by Section 3(a)(1)(A) to the extent 264 | reasonably practicable. 265 | 266 | 4. If You Share Adapted Material You produce, the Adapter's 267 | License You apply must not prevent recipients of the Adapted 268 | Material from complying with this Public License. 269 | 270 | Section 4 -- Sui Generis Database Rights. 271 | 272 | Where the Licensed Rights include Sui Generis Database Rights that 273 | apply to Your use of the Licensed Material: 274 | 275 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right 276 | to extract, reuse, reproduce, and Share all or a substantial 277 | portion of the contents of the database for NonCommercial purposes 278 | only; 279 | 280 | b. if You include all or a substantial portion of the database 281 | contents in a database in which You have Sui Generis Database 282 | Rights, then the database in which You have Sui Generis Database 283 | Rights (but not its individual contents) is Adapted Material; and 284 | 285 | c. You must comply with the conditions in Section 3(a) if You Share 286 | all or a substantial portion of the contents of the database. 287 | 288 | For the avoidance of doubt, this Section 4 supplements and does not 289 | replace Your obligations under this Public License where the Licensed 290 | Rights include other Copyright and Similar Rights. 291 | 292 | Section 5 -- Disclaimer of Warranties and Limitation of Liability. 293 | 294 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE 295 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS 296 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF 297 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, 298 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, 299 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR 300 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, 301 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT 302 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT 303 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. 304 | 305 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE 306 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, 307 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, 308 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, 309 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR 310 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN 311 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR 312 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR 313 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. 314 | 315 | c. The disclaimer of warranties and limitation of liability provided 316 | above shall be interpreted in a manner that, to the extent 317 | possible, most closely approximates an absolute disclaimer and 318 | waiver of all liability. 319 | 320 | Section 6 -- Term and Termination. 321 | 322 | a. This Public License applies for the term of the Copyright and 323 | Similar Rights licensed here. However, if You fail to comply with 324 | this Public License, then Your rights under this Public License 325 | terminate automatically. 326 | 327 | b. Where Your right to use the Licensed Material has terminated under 328 | Section 6(a), it reinstates: 329 | 330 | 1. automatically as of the date the violation is cured, provided 331 | it is cured within 30 days of Your discovery of the 332 | violation; or 333 | 334 | 2. upon express reinstatement by the Licensor. 335 | 336 | For the avoidance of doubt, this Section 6(b) does not affect any 337 | right the Licensor may have to seek remedies for Your violations 338 | of this Public License. 339 | 340 | c. For the avoidance of doubt, the Licensor may also offer the 341 | Licensed Material under separate terms or conditions or stop 342 | distributing the Licensed Material at any time; however, doing so 343 | will not terminate this Public License. 344 | 345 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public 346 | License. 347 | 348 | Section 7 -- Other Terms and Conditions. 349 | 350 | a. The Licensor shall not be bound by any additional or different 351 | terms or conditions communicated by You unless expressly agreed. 352 | 353 | b. Any arrangements, understandings, or agreements regarding the 354 | Licensed Material not stated herein are separate from and 355 | independent of the terms and conditions of this Public License. 356 | 357 | Section 8 -- Interpretation. 358 | 359 | a. For the avoidance of doubt, this Public License does not, and 360 | shall not be interpreted to, reduce, limit, restrict, or impose 361 | conditions on any use of the Licensed Material that could lawfully 362 | be made without permission under this Public License. 363 | 364 | b. To the extent possible, if any provision of this Public License is 365 | deemed unenforceable, it shall be automatically reformed to the 366 | minimum extent necessary to make it enforceable. If the provision 367 | cannot be reformed, it shall be severed from this Public License 368 | without affecting the enforceability of the remaining terms and 369 | conditions. 370 | 371 | c. No term or condition of this Public License will be waived and no 372 | failure to comply consented to unless expressly agreed to by the 373 | Licensor. 374 | 375 | d. Nothing in this Public License constitutes or may be interpreted 376 | as a limitation upon, or waiver of, any privileges and immunities 377 | that apply to the Licensor or You, including from the legal 378 | processes of any jurisdiction or authority. 379 | 380 | ======================================================================= 381 | 382 | Creative Commons is not a party to its public 383 | licenses. Notwithstanding, Creative Commons may elect to apply one of 384 | its public licenses to material it publishes and in those instances 385 | will be considered the “Licensor.” The text of the Creative Commons 386 | public licenses is dedicated to the public domain under the CC0 Public 387 | Domain Dedication. Except for the limited purpose of indicating that 388 | material is shared under a Creative Commons public license or as 389 | otherwise permitted by the Creative Commons policies published at 390 | creativecommons.org/policies, Creative Commons does not authorize the 391 | use of the trademark "Creative Commons" or any other trademark or logo 392 | of Creative Commons without its prior written consent including, 393 | without limitation, in connection with any unauthorized modifications 394 | to any of its public licenses or any other arrangements, 395 | understandings, or agreements concerning use of licensed material. For 396 | the avoidance of doubt, this paragraph does not form part of the 397 | public licenses. 398 | 399 | Creative Commons may be contacted at creativecommons.org. 400 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017-present, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the license found in the 5 | # LICENSE file in the root directory of this source tree. 6 | # 7 | 8 | help: 9 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "%-15s%s\n", $$1, $$2}' 10 | 11 | run: compile ## Run benchmarks from the paper, printing results to stdout 12 | @command -v java >/dev/null 2>&1 || { echo >&2 "I require java but it's not installed. Aborting."; exit 1; } 13 | java -Xms10g -Xmx10g -jar AsynchronousRatchetingTree/target/uber-AsynchronousRatchetingTree-1.0-SNAPSHOT.jar 14 | 15 | compile: ## Compile benchmarks 16 | @command -v mvn >/dev/null 2>&1 || { echo >&2 "I require maven but it's not installed. Aborting."; exit 1; } 17 | mvn --file AsynchronousRatchetingTree/pom.xml package 18 | 19 | clean: ## Remove Java artifacts 20 | @command -v mvn >/dev/null 2>&1 || { echo >&2 "I require maven but it's not installed. Aborting."; exit 1; } 21 | mvn --file AsynchronousRatchetingTree/pom.xml clean 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Asynchronous Ratcheting Tree 2 | 3 | Asynchronous Ratcheting Tree (ART) is a protocol for end-to-end encrypted group 4 | messaging. It aims to provide scalable group messaging while maintaining strong 5 | security guarantees. 6 | 7 | This repository contains the implementation used for the results in 8 | [our ART paper](https://eprint.iacr.org/2017/666). It contains implementations of 9 | ART and a pairwise Diffie-Hellman based ratcheting protocol which we used for 10 | comparison. 11 | 12 | The implementation in this repository is purely academic example code, and should 13 | not be used in any production or security-critical system. 14 | 15 | ## Requirements 16 | 17 | Asynchronous Ratcheting Trees requires or works with: 18 | * Java 1.8. 19 | * Apache Maven 1.8. 20 | * Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 21 | (http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html). 22 | * Apache Thrift 0.10.0 (just for rebuilding the Thrift definitions). 23 | 24 | ## Building and executing 25 | The Makefile in this directory will compile our source and then run the 26 | benchmarks; simply run 27 | 28 | make run 29 | 30 | ## The Team 31 | 32 | The team who worked on the Asynchronous Ratcheting Tree paper are as follows: 33 | 34 | From Facebook: 35 | * Jon Millican 36 | 37 | From Oxford University: 38 | * Katriel Cohn-Gordon 39 | * Cas Cremers 40 | * Luke Garratt 41 | * Kevin Milner 42 | 43 | We are grateful to our collaborators from Oxford University for the considerable 44 | time and expertise that they put in to this paper, and into the formal proofs of 45 | the ART protocol. 46 | 47 | ## Contributing 48 | 49 | See the CONTRIBUTING file for how to help out. 50 | 51 | ## License 52 | 53 | Asynchronous Ratcheting Tree is CC-BY-NC-licensed. 54 | --------------------------------------------------------------------------------