@@ -20,8 +20,6 @@ public class BftsmartConsensusClient implements ConsensusClient { | |||||
this.clientSettings = clientSettings; | this.clientSettings = clientSettings; | ||||
this.gatewayId = clientSettings.getClientId(); | this.gatewayId = clientSettings.getClientId(); | ||||
connect(); | |||||
} | } | ||||
@@ -45,7 +43,7 @@ public class BftsmartConsensusClient implements ConsensusClient { | |||||
} | } | ||||
@Override | @Override | ||||
public void connect() { | |||||
public synchronized void connect() { | |||||
//consensus client pool | //consensus client pool | ||||
BftsmartPeerProxyFactory peerProxyFactory = new BftsmartPeerProxyFactory((BftsmartClientSettings)clientSettings, gatewayId); | BftsmartPeerProxyFactory peerProxyFactory = new BftsmartPeerProxyFactory((BftsmartClientSettings)clientSettings, gatewayId); | ||||
@@ -27,16 +27,16 @@ public class BftsmartMessageService implements MessageService { | |||||
AsynchServiceProxy asynchServiceProxy = null; | AsynchServiceProxy asynchServiceProxy = null; | ||||
try { | try { | ||||
asynchServiceProxy = asyncPeerProxyPool.borrowObject(); | asynchServiceProxy = asyncPeerProxyPool.borrowObject(); | ||||
//0: Transaction msg, 1: Commitblock msg | |||||
byte[] msgType = BytesUtils.toBytes(0); | |||||
byte[] wrapMsg = new byte[message.length + 4]; | |||||
System.arraycopy(message, 0, wrapMsg, 4, message.length); | |||||
System.arraycopy(msgType, 0, wrapMsg, 0, 4); | |||||
System.out.printf("BftsmartMessageService invokeOrdered time = %s, id = %s threadId = %s \r\n", | |||||
System.currentTimeMillis(), asynchServiceProxy.getProcessId(), Thread.currentThread().getId()); | |||||
byte[] result = asynchServiceProxy.invokeOrdered(wrapMsg); | |||||
// //0: Transaction msg, 1: Commitblock msg | |||||
// byte[] msgType = BytesUtils.toBytes(0); | |||||
// byte[] wrapMsg = new byte[message.length + 4]; | |||||
// System.arraycopy(message, 0, wrapMsg, 4, message.length); | |||||
// System.arraycopy(msgType, 0, wrapMsg, 0, 4); | |||||
// | |||||
// System.out.printf("BftsmartMessageService invokeOrdered time = %s, id = %s threadId = %s \r\n", | |||||
// System.currentTimeMillis(), asynchServiceProxy.getProcessId(), Thread.currentThread().getId()); | |||||
byte[] result = asynchServiceProxy.invokeOrdered(message); | |||||
asyncFuture.complete(result); | asyncFuture.complete(result); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
@@ -13,10 +13,16 @@ import com.jd.blockchain.utils.serialize.binary.BinarySerializeUtils; | |||||
public class BftsmartConsensusManageService implements ConsensusManageService { | public class BftsmartConsensusManageService implements ConsensusManageService { | ||||
public static final int CLIENT_RANGE = 100 * 1000; | |||||
public static final int GATEWAY_SIZE = 100; | |||||
public static final int CLIENT_SIZE_PER_GATEWAY = 1000; | |||||
public static final int CLIENT_RANGE = GATEWAY_SIZE * CLIENT_SIZE_PER_GATEWAY; | |||||
private BftsmartNodeServer nodeServer; | private BftsmartNodeServer nodeServer; | ||||
private int clientId; | private int clientId; | ||||
private static final Lock authLock = new ReentrantLock(); | private static final Lock authLock = new ReentrantLock(); | ||||
public BftsmartConsensusManageService(BftsmartNodeServer nodeServer) { | public BftsmartConsensusManageService(BftsmartNodeServer nodeServer) { | ||||
@@ -41,6 +47,7 @@ public class BftsmartConsensusManageService implements ConsensusManageService { | |||||
try { | try { | ||||
authLock.lock(); | authLock.lock(); | ||||
((BftsmartClientIncomingConfig) clientIncomingSettings).setClientId(clientId++); | ((BftsmartClientIncomingConfig) clientIncomingSettings).setClientId(clientId++); | ||||
clientId += CLIENT_SIZE_PER_GATEWAY; | |||||
} finally { | } finally { | ||||
authLock.unlock(); | authLock.unlock(); | ||||
} | } | ||||
@@ -1,16 +1,13 @@ | |||||
package com.jd.blockchain.consensus.bftsmart.service; | package com.jd.blockchain.consensus.bftsmart.service; | ||||
import java.io.ByteArrayOutputStream; | import java.io.ByteArrayOutputStream; | ||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
import java.util.Properties; | |||||
import java.util.*; | |||||
import java.util.concurrent.CopyOnWriteArrayList; | import java.util.concurrent.CopyOnWriteArrayList; | ||||
import java.util.concurrent.ExecutorService; | import java.util.concurrent.ExecutorService; | ||||
import java.util.concurrent.Executors; | import java.util.concurrent.Executors; | ||||
import bftsmart.tom.*; | |||||
import org.slf4j.Logger; | import org.slf4j.Logger; | ||||
import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||
import com.jd.blockchain.consensus.ConsensusManageService; | import com.jd.blockchain.consensus.ConsensusManageService; | ||||
import com.jd.blockchain.consensus.NodeSettings; | import com.jd.blockchain.consensus.NodeSettings; | ||||
import com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider; | import com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider; | ||||
@@ -26,13 +23,8 @@ import com.jd.blockchain.ledger.TransactionState; | |||||
import com.jd.blockchain.utils.PropertiesUtils; | import com.jd.blockchain.utils.PropertiesUtils; | ||||
import com.jd.blockchain.utils.concurrent.AsyncFuture; | import com.jd.blockchain.utils.concurrent.AsyncFuture; | ||||
import com.jd.blockchain.utils.io.BytesUtils; | import com.jd.blockchain.utils.io.BytesUtils; | ||||
import bftsmart.reconfiguration.util.HostsConfig; | import bftsmart.reconfiguration.util.HostsConfig; | ||||
import bftsmart.reconfiguration.util.TOMConfiguration; | import bftsmart.reconfiguration.util.TOMConfiguration; | ||||
import bftsmart.tom.MessageContext; | |||||
import bftsmart.tom.ReplyContext; | |||||
import bftsmart.tom.ReplyContextMessage; | |||||
import bftsmart.tom.ServiceReplica; | |||||
import bftsmart.tom.core.messages.TOMMessage; | import bftsmart.tom.core.messages.TOMMessage; | ||||
import bftsmart.tom.server.defaultservices.DefaultRecoverable; | import bftsmart.tom.server.defaultservices.DefaultRecoverable; | ||||
@@ -42,15 +34,9 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer | |||||
private List<StateHandle> stateHandles = new CopyOnWriteArrayList<>(); | private List<StateHandle> stateHandles = new CopyOnWriteArrayList<>(); | ||||
// private List<BatchConsensusListener> batchConsensusListeners = new LinkedList<>(); | |||||
// private Map<ReplyContextMessage, AsyncFuture<byte[]>> replyContextMessages = new ConcurrentHashMap<>(); | |||||
// TODO 暂不处理队列溢出问题 | // TODO 暂不处理队列溢出问题 | ||||
private ExecutorService notifyReplyExecutors = Executors.newSingleThreadExecutor(); | private ExecutorService notifyReplyExecutors = Executors.newSingleThreadExecutor(); | ||||
// private ExecutorService sendCommitExecutors = Executors.newFixedThreadPool(2); | |||||
private volatile Status status = Status.STOPPED; | private volatile Status status = Status.STOPPED; | ||||
private final Object mutex = new Object(); | private final Object mutex = new Object(); | ||||
@@ -81,28 +67,6 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer | |||||
private int serverId; | private int serverId; | ||||
// private volatile String batchId = null; | |||||
// | |||||
//// private List<AsyncFuture<byte[]>> replyMessages ; | |||||
// | |||||
// private boolean leader_has_makedicision = false; | |||||
// | |||||
// private boolean commit_block_condition = false; | |||||
// | |||||
// private final AtomicLong txIndex = new AtomicLong(); | |||||
// | |||||
// private final AtomicLong blockIndex = new AtomicLong(); | |||||
// | |||||
// private static final AtomicInteger incrementNum = new AtomicInteger(); | |||||
// | |||||
//// private final BlockingQueue<ActionRequest> txRequestQueue = new LinkedBlockingQueue(); | |||||
// | |||||
// private final ExecutorService queueExecutor = Executors.newSingleThreadExecutor(); | |||||
// | |||||
// private final ScheduledExecutorService timerEexecutorService = new ScheduledThreadPoolExecutor(10); | |||||
// private ServiceProxy peerProxy; | |||||
public BftsmartNodeServer() { | public BftsmartNodeServer() { | ||||
} | } | ||||
@@ -113,28 +77,12 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer | |||||
//used later | //used later | ||||
this.stateMachineReplicate = stateMachineReplicate; | this.stateMachineReplicate = stateMachineReplicate; | ||||
this.messageHandle = messageHandler; | this.messageHandle = messageHandler; | ||||
this.manageService = new BftsmartConsensusManageService(this); | |||||
createConfig(); | createConfig(); | ||||
serverId = findServerId(); | serverId = findServerId(); | ||||
initConfig(serverId, systemConfig, hostsConfig); | initConfig(serverId, systemConfig, hostsConfig); | ||||
this.manageService = new BftsmartConsensusManageService(this); | |||||
} | } | ||||
//aim to send commit block message | |||||
// protected void createProxyClient() { | |||||
// BftsmartTopology topologyCopy = (BftsmartTopology) topology.copyOf(); | |||||
// | |||||
// MemoryBasedViewStorage viewStorage = new MemoryBasedViewStorage(topologyCopy.getView()); | |||||
// | |||||
// byte[] bytes = BinarySerializeUtils.serialize(tomConfig); | |||||
// | |||||
// TOMConfiguration decodeTomConfig = BinarySerializeUtils.deserialize(bytes); | |||||
// | |||||
// decodeTomConfig.setProcessId(0); | |||||
// | |||||
// peerProxy = new ServiceProxy(decodeTomConfig, viewStorage, null, null); | |||||
// | |||||
// } | |||||
protected int findServerId() { | protected int findServerId() { | ||||
int serverId = 0; | int serverId = 0; | ||||
@@ -242,214 +190,12 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer | |||||
return appExecuteBatch(commands, msgCtxs, fromConsensus, null); | return appExecuteBatch(commands, msgCtxs, fromConsensus, null); | ||||
} | } | ||||
// private boolean checkLeaderId(MessageContext[] msgCtxs) { | |||||
// boolean result = false; | |||||
// | |||||
// for (int i = 0; i < msgCtxs.length - 1; i++) { | |||||
// if (msgCtxs[i].getLeader() != msgCtxs[i+1].getLeader()) | |||||
// return result; | |||||
// } | |||||
// | |||||
// result = true; | |||||
// | |||||
// return result; | |||||
// } | |||||
// | |||||
// //普通消息处理 | |||||
// private void normalMsgProcess(ReplyContextMessage replyContextMsg, byte[] msg, String realmName, String batchId) { | |||||
// AsyncFuture<byte[]> replyMsg = messageHandle.processOrdered(replyContextMsg.getMessageContext().getOperationId(), msg, realmName, batchId); | |||||
// replyContextMessages.put(replyContextMsg, replyMsg); | |||||
// } | |||||
// | |||||
// //结块消息处理 | |||||
// private void commitMsgProcess(ReplyContextMessage replyContextMsg, String realmName, String batchId) { | |||||
// try{ | |||||
// //receive messages before commitblock message, then execute commit | |||||
// if (replyContextMessages.size() != 0) { | |||||
// messageHandle.completeBatch(realmName, batchId); | |||||
// messageHandle.commitBatch(realmName, batchId); | |||||
// } | |||||
// | |||||
// // commit block msg need response too | |||||
// CompletableAsyncFuture<byte[]> asyncFuture = new CompletableAsyncFuture<>(); | |||||
// TransactionResponse transactionRespHandle = new TransactionRespHandle(newBlockCommitRequest(), | |||||
// TransactionState.SUCCESS, TransactionState.SUCCESS); | |||||
// | |||||
// asyncFuture.complete(BinaryEncodingUtils.encode(transactionRespHandle, TransactionResponse.class)); | |||||
// replyContextMessages.put(replyContextMsg, asyncFuture); | |||||
// }catch (Exception e){ | |||||
// LOGGER.error("Error occurred on commit batch transactions, so the new block is canceled! --" + e.getMessage(), e); | |||||
// messageHandle.rollbackBatch(realmName, batchId, -1); | |||||
// }finally{ | |||||
// this.batchId = null; | |||||
// } | |||||
// } | |||||
// private void sendCommitMessage() { | |||||
// | |||||
// HashDigest ledgerHash = new HashDigest(Base58Utils.decode(realmName)); | |||||
// | |||||
// BlockchainKeyPair userKeyPeer = BlockchainKeyGenerator.getInstance().generate(); | |||||
// | |||||
// TxContentBlob txContentBlob = new TxContentBlob(ledgerHash); | |||||
// | |||||
// byte[] reqBytes = BinaryEncodingUtils.encode(txContentBlob, TransactionContent.class); | |||||
// | |||||
// HashDigest reqHash = CryptoUtils.hash(CryptoAlgorithm.SHA256).hash(reqBytes); | |||||
// | |||||
// txContentBlob.setHash(reqHash); | |||||
// | |||||
// TxRequestMessage transactionRequest = new TxRequestMessage(txContentBlob); | |||||
// | |||||
// byte[] msg = BinaryEncodingUtils.encode(transactionRequest, TransactionRequest.class); | |||||
// | |||||
// byte[] type = BytesUtils.toBytes(1); | |||||
// | |||||
// byte[] wrapMsg = new byte[msg.length + 4]; | |||||
// | |||||
// System.arraycopy(type, 0, wrapMsg, 0, 4); | |||||
// System.arraycopy(msg, 0, wrapMsg, 4, msg.length); | |||||
// | |||||
// peerProxy.invokeOrdered(wrapMsg); | |||||
// | |||||
// LOGGER.info("Send commit block msg success!"); | |||||
// } | |||||
// private TransactionRequest newBlockCommitRequest() { | |||||
// | |||||
// HashDigest ledgerHash = new HashDigest(Base58Utils.decode(realmName)); | |||||
// | |||||
// TxContentBlob txContentBlob = new TxContentBlob(ledgerHash); | |||||
// | |||||
// byte[] reqBytes = BinaryEncodingUtils.encode(txContentBlob, TransactionContent.class); | |||||
// | |||||
// HashDigest reqHash = CryptoUtils.hash(CryptoAlgorithm.SHA256).hash(reqBytes); | |||||
// | |||||
// txContentBlob.setHash(reqHash); | |||||
// | |||||
// TxRequestMessage transactionRequest = new TxRequestMessage(txContentBlob); | |||||
// | |||||
// return transactionRequest; | |||||
// } | |||||
// private void checkConsensusFinish() { | |||||
// BftsmartCommitBlockSettings commitBlockSettings = ((BftsmartServerSettings)serverSettings).getConsensusSettings().getCommitBlockSettings(); | |||||
// int txSize = commitBlockSettings.getTxSizePerBlock(); | |||||
// long maxDelay = commitBlockSettings.getMaxDelayMilliSecondsPerBlock(); | |||||
// | |||||
// long currIndex = txIndex.incrementAndGet(); | |||||
// if (currIndex == txSize) { | |||||
// txIndex.set(0); | |||||
// this.blockIndex.getAndIncrement(); | |||||
// sendCommitExecutors.execute(()-> { | |||||
// sendCommitMessage(); | |||||
// }); | |||||
// } else if (currIndex == 1) { | |||||
//// System.out.printf("checkConsensusFinish schedule blockIndex = %s \r\n", this.blockIndex.get()); | |||||
// timerEexecutorService.schedule(timeTask(this.blockIndex.get()), maxDelay, TimeUnit.MILLISECONDS); | |||||
// } | |||||
// | |||||
// return; | |||||
// } | |||||
// @Override | |||||
// public byte[][] appExecuteBatch(byte[][] commands, MessageContext[] msgCtxs, boolean fromConsensus, List<ReplyContextMessage> replyList) { | |||||
// | |||||
// if (!checkLeaderId(msgCtxs)) { | |||||
// throw new IllegalArgumentException(); | |||||
// } | |||||
// | |||||
// boolean isLeader = (msgCtxs[0].getLeader() == getId()); | |||||
// | |||||
// if (isLeader) { | |||||
// for (int i = 0; i < commands.length; i++) { | |||||
// byte[] wrapMsg = commands[i]; | |||||
// byte[] type = new byte[4]; | |||||
// byte[] msg= new byte[wrapMsg.length - 4]; | |||||
// | |||||
// System.arraycopy(wrapMsg, 0, type, 0, 4); | |||||
// System.arraycopy(wrapMsg, 4, msg, 0, wrapMsg.length - 4); | |||||
// | |||||
// MessageContext messageContext = msgCtxs[i]; | |||||
// ReplyContextMessage replyContextMessage = replyList.get(i); | |||||
// replyContextMessage.setMessageContext(messageContext); | |||||
// | |||||
// if (batchId == null) { | |||||
// batchId = messageHandle.beginBatch(realmName); | |||||
// } | |||||
// | |||||
// int msgType = BytesUtils.readInt(new ByteArrayInputStream(type)); | |||||
// | |||||
// if (msgType == 0) { | |||||
// | |||||
// //only leader do it | |||||
// checkConsensusFinish(); | |||||
// //normal message process | |||||
// normalMsgProcess(replyContextMessage, msg, realmName, batchId); | |||||
// } | |||||
// if (!leader_has_makedicision) { | |||||
// if (msgType == 1) { | |||||
// LOGGER.error("Error occurred on appExecuteBatch msg process, leader confilicting error!"); | |||||
// } | |||||
// | |||||
// if (commit_block_condition) { | |||||
// leader_has_makedicision = true; | |||||
// | |||||
//// sendCommitExecutors.execute(() -> { | |||||
// commit_block_condition = false; | |||||
// LOGGER.info("Txcount execute commit block!"); | |||||
// sendCommitMessage(); | |||||
//// }); | |||||
// | |||||
// } | |||||
// } else if (msgType == 1) { | |||||
// //commit block message | |||||
// commitMsgProcess(replyContextMessage, realmName, batchId); | |||||
// leader_has_makedicision = false; | |||||
// sendReplyMessage(); | |||||
// } | |||||
// } | |||||
// } else { | |||||
// for (int i = 0; i < commands.length; i++) { | |||||
// byte[] wrapMsg = commands[i]; | |||||
// byte[] type = new byte[4]; | |||||
// byte[] msg= new byte[wrapMsg.length - 4]; | |||||
// | |||||
// System.arraycopy(wrapMsg, 0, type, 0, 4); | |||||
// System.arraycopy(wrapMsg, 4, msg, 0, wrapMsg.length - 4); | |||||
// | |||||
// MessageContext messageContext = msgCtxs[i]; | |||||
// ReplyContextMessage replyContextMessage = replyList.get(i); | |||||
// replyContextMessage.setMessageContext(messageContext); | |||||
// | |||||
// if (batchId == null) { | |||||
// batchId = messageHandle.beginBatch(realmName); | |||||
// } | |||||
// | |||||
// int msgType = BytesUtils.readInt(new ByteArrayInputStream(type)); | |||||
// | |||||
// if (msgType == 0) { | |||||
// //normal message | |||||
// normalMsgProcess(replyContextMessage, msg, realmName, batchId); | |||||
// } else if (msgType == 1) { | |||||
// // commit block message | |||||
// commitMsgProcess(replyContextMessage, realmName, batchId); | |||||
// sendReplyMessage(); | |||||
// } | |||||
// } | |||||
// } | |||||
// | |||||
// return null; | |||||
// } | |||||
@Override | @Override | ||||
public byte[][] appExecuteBatch(byte[][] commands, MessageContext[] msgCtxs, boolean fromConsensus, List<ReplyContextMessage> replyList) { | public byte[][] appExecuteBatch(byte[][] commands, MessageContext[] msgCtxs, boolean fromConsensus, List<ReplyContextMessage> replyList) { | ||||
if (replyList == null || replyList.size() == 0) { | if (replyList == null || replyList.size() == 0) { | ||||
throw new IllegalArgumentException(); | throw new IllegalArgumentException(); | ||||
} | } | ||||
// todo 此部分需要重新改造 | // todo 此部分需要重新改造 | ||||
/** | /** | ||||
* 默认BFTSmart接口提供的commands是一个或多个共识结果的顺序集合 | * 默认BFTSmart接口提供的commands是一个或多个共识结果的顺序集合 | ||||
@@ -481,52 +227,6 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer | |||||
if (!manageConsensusCmds.isEmpty()) { | if (!manageConsensusCmds.isEmpty()) { | ||||
blockAndReply(manageConsensusCmds, manageReplyMsgs); | blockAndReply(manageConsensusCmds, manageReplyMsgs); | ||||
} | } | ||||
//// if (!checkLeaderId(msgCtxs)) { | |||||
//// throw new IllegalArgumentException(); | |||||
//// } | |||||
// | |||||
// if (replyList == null || replyList.size() == 0) { | |||||
// throw new IllegalArgumentException(); | |||||
// } | |||||
// | |||||
// for (int i = 0; i < commands.length; i++) { | |||||
// byte[] wrapMsg = commands[i]; | |||||
// byte[] type = new byte[4]; | |||||
// byte[] msg= new byte[wrapMsg.length - 4]; | |||||
// // batch messages, maybe in different consensus instance, leader also maybe different | |||||
// boolean isLeader = (msgCtxs[i].getLeader() == getId()); | |||||
// | |||||
// System.arraycopy(wrapMsg, 0, type, 0, 4); | |||||
// System.arraycopy(wrapMsg, 4, msg, 0, wrapMsg.length - 4); | |||||
// | |||||
// MessageContext messageContext = msgCtxs[i]; | |||||
// ReplyContextMessage replyContextMessage = replyList.get(i); | |||||
// replyContextMessage.setMessageContext(messageContext); | |||||
// | |||||
// if (batchId == null) { | |||||
// batchId = messageHandle.beginBatch(realmName); | |||||
// } | |||||
// | |||||
// int msgType = BytesUtils.readInt(new ByteArrayInputStream(type)); | |||||
// | |||||
// if (msgType == 0) { | |||||
// | |||||
// //only leader do it | |||||
// if (isLeader) { | |||||
// checkConsensusFinish(); | |||||
// } | |||||
// //normal message process | |||||
// normalMsgProcess(replyContextMessage, msg, realmName, batchId); | |||||
// } | |||||
// else if (msgType == 1) { | |||||
// //commit block message | |||||
// commitMsgProcess(replyContextMessage, realmName, batchId); | |||||
// sendReplyMessage(); | |||||
// } | |||||
// } | |||||
return null; | return null; | ||||
} | } | ||||
@@ -574,46 +274,6 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer | |||||
}); | }); | ||||
} | } | ||||
// private void sendReplyMessage() { | |||||
// for (ReplyContextMessage msg: replyContextMessages.keySet()) { | |||||
// byte[] reply = replyContextMessages.get(msg).get(); | |||||
// msg.setReply(reply); | |||||
// TOMMessage request = msg.getTomMessage(); | |||||
// ReplyContext replyContext = msg.getReplyContext(); | |||||
// request.reply = new TOMMessage(replyContext.getId(), request.getSession(), request.getSequence(), | |||||
// request.getOperationId(), msg.getReply(), replyContext.getCurrentViewId(), | |||||
// request.getReqType()); | |||||
// | |||||
// if (replyContext.getNumRepliers() > 0) { | |||||
// bftsmart.tom.util.Logger.println("(ServiceReplica.receiveMessages) sending reply to " | |||||
// + request.getSender() + " with sequence number " + request.getSequence() | |||||
// + " and operation ID " + request.getOperationId() + " via ReplyManager"); | |||||
// replyContext.getRepMan().send(request); | |||||
// } else { | |||||
// bftsmart.tom.util.Logger.println("(ServiceReplica.receiveMessages) sending reply to " | |||||
// + request.getSender() + " with sequence number " + request.getSequence() | |||||
// + " and operation ID " + request.getOperationId()); | |||||
// replyContext.getReplier().manageReply(request, msg.getMessageContext()); | |||||
// // cs.send(new int[]{request.getSender()}, request.reply); | |||||
// } | |||||
// } | |||||
// replyContextMessages.clear(); | |||||
// } | |||||
// private Runnable timeTask(final long currBlockIndex) { | |||||
// Runnable task = () -> { | |||||
// boolean isAdd = this.blockIndex.compareAndSet(currBlockIndex, currBlockIndex + 1); | |||||
// if (isAdd) { | |||||
// LOGGER.info("TimerTask execute commit block! "); | |||||
// this.txIndex.set(0); | |||||
// timerEexecutorService.execute(()-> { | |||||
// sendCommitMessage(); | |||||
// }); | |||||
// } | |||||
// }; | |||||
// return task; | |||||
// } | |||||
//notice | //notice | ||||
public byte[] getSnapshot() { | public byte[] getSnapshot() { | ||||
LOGGER.debug("------- GetSnapshot...[replica.id=" + this.getId() + "]"); | LOGGER.debug("------- GetSnapshot...[replica.id=" + this.getId() + "]"); | ||||
@@ -623,9 +283,6 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer | |||||
for (StateHandle stateHandle : stateHandles) { | for (StateHandle stateHandle : stateHandles) { | ||||
// TODO: 测试代码; | // TODO: 测试代码; | ||||
return stateHandle.takeSnapshot(); | return stateHandle.takeSnapshot(); | ||||
// byte[] state = stateHandle.takeSnapshot(); | |||||
// BytesEncoding.writeInNormal(state, out); | |||||
} | } | ||||
return out.toByteArray(); | return out.toByteArray(); | ||||
} | } | ||||
@@ -693,33 +350,6 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer | |||||
} | } | ||||
} | } | ||||
// private static class ActionRequestExtend { | |||||
// | |||||
// | |||||
// ReplyContextMessage replyContextMessage; | |||||
// | |||||
// private byte[] message; | |||||
// | |||||
// private ActionRequest actionRequest; | |||||
// | |||||
// public ActionRequestExtend(byte[] message) { | |||||
// this.message = message; | |||||
// actionRequest = BinaryEncodingUtils.decode(message); | |||||
// } | |||||
// | |||||
// public byte[] getMessage() { | |||||
// return message; | |||||
// } | |||||
// | |||||
// public ReplyContextMessage getReplyContextMessage() { | |||||
// return replyContextMessage; | |||||
// } | |||||
// | |||||
// public ActionRequest getActionRequest() { | |||||
// return actionRequest; | |||||
// } | |||||
// } | |||||
enum Status { | enum Status { | ||||
STARTING, | STARTING, | ||||
@@ -27,20 +27,6 @@ | |||||
<version>${project.version}</version> | <version>${project.version}</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>org.powermock</groupId> | |||||
<artifactId>powermock-module-junit4</artifactId> | |||||
<version>1.6.2</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.powermock</groupId> | |||||
<artifactId>powermock-api-mockito</artifactId> | |||||
<version>1.6.2</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | <dependency> | ||||
<groupId>net.i2p.crypto</groupId> | <groupId>net.i2p.crypto</groupId> | ||||
<artifactId>eddsa</artifactId> | <artifactId>eddsa</artifactId> | ||||
@@ -52,11 +38,6 @@ | |||||
<version>5.1.0</version> | <version>5.1.0</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>org.mockito</groupId> | |||||
<artifactId>mockito-core</artifactId> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | <dependency> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>crypto-framework</artifactId> | <artifactId>crypto-framework</artifactId> | ||||
@@ -2,85 +2,89 @@ package com.jd.blockchain.crypto.mpc; | |||||
import java.math.BigInteger; | import java.math.BigInteger; | ||||
import com.jd.blockchain.crypto.paillier.PaillierPublicKeyParameters; | |||||
import com.jd.blockchain.crypto.paillier.PaillierUtils; | |||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair; | import org.bouncycastle.crypto.AsymmetricCipherKeyPair; | ||||
import org.bouncycastle.crypto.CipherParameters; | |||||
import org.bouncycastle.crypto.agreement.ECDHBasicAgreement; | import org.bouncycastle.crypto.agreement.ECDHBasicAgreement; | ||||
import org.bouncycastle.crypto.params.ECDomainParameters; | import org.bouncycastle.crypto.params.ECDomainParameters; | ||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters; | import org.bouncycastle.crypto.params.ECPrivateKeyParameters; | ||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters; | import org.bouncycastle.crypto.params.ECPublicKeyParameters; | ||||
import org.bouncycastle.math.ec.ECCurve; | import org.bouncycastle.math.ec.ECCurve; | ||||
import org.bouncycastle.math.ec.ECPoint; | import org.bouncycastle.math.ec.ECPoint; | ||||
import org.bouncycastle.util.encoders.Hex; | |||||
import com.jd.blockchain.crypto.paillier.KeyPair; | |||||
import com.jd.blockchain.crypto.paillier.PaillierUtils; | |||||
import com.jd.blockchain.crypto.paillier.PublicKey; | |||||
import com.jd.blockchain.crypto.utils.sm.SM2Utils; | import com.jd.blockchain.crypto.utils.sm.SM2Utils; | ||||
import com.jd.blockchain.crypto.utils.sm.SM3Utils; | import com.jd.blockchain.crypto.utils.sm.SM3Utils; | ||||
import com.jd.blockchain.utils.io.BytesUtils; | import com.jd.blockchain.utils.io.BytesUtils; | ||||
public class MultiSum { | public class MultiSum { | ||||
private ECPrivateKeyParameters ePrivKey; | |||||
private ECPublicKeyParameters ePubKey; | |||||
private ECCurve curve; | |||||
private ECDomainParameters domainParams; | |||||
private static byte[] ePrivKey; | |||||
private static byte[] ePubKey; | |||||
private static ECCurve curve; | |||||
private static ECDomainParameters domainParams; | |||||
public void generateEphemeralKeyPair(){ | |||||
public static void generateEphemeralKeyPair(){ | |||||
AsymmetricCipherKeyPair eKeyPair = SM2Utils.generateKeyPair(); | AsymmetricCipherKeyPair eKeyPair = SM2Utils.generateKeyPair(); | ||||
this.ePrivKey = (ECPrivateKeyParameters) eKeyPair.getPrivate(); | |||||
this.ePubKey = (ECPublicKeyParameters) eKeyPair.getPublic(); | |||||
this.curve = SM2Utils.getCurve(); | |||||
this.domainParams = SM2Utils.getDomainParams(); | |||||
ECPrivateKeyParameters ecPrivKey = (ECPrivateKeyParameters) eKeyPair.getPrivate(); | |||||
ECPublicKeyParameters ecPubKey= (ECPublicKeyParameters) eKeyPair.getPublic(); | |||||
ePrivKey = bigIntegerToBytes(ecPrivKey.getD()); | |||||
ePubKey = ecPubKey.getQ().getEncoded(false); | |||||
curve = SM2Utils.getCurve(); | |||||
domainParams = SM2Utils.getDomainParams(); | |||||
} | } | ||||
public BigInteger calculateAgreement(CipherParameters otherEPubKey){ | |||||
public static byte[] calculateAgreement(byte[] otherEPubKey, byte[] ePrivKey){ | |||||
ECDHBasicAgreement basicAgreement = new ECDHBasicAgreement(); | ECDHBasicAgreement basicAgreement = new ECDHBasicAgreement(); | ||||
basicAgreement.init(ePrivKey); | |||||
return basicAgreement.calculateAgreement(otherEPubKey); | |||||
ECPoint ePubKeyPoint = resolvePubKeyBytes(otherEPubKey); | |||||
ECPublicKeyParameters pubKey = new ECPublicKeyParameters(ePubKeyPoint, domainParams); | |||||
ECPrivateKeyParameters privateKey = new ECPrivateKeyParameters(new BigInteger(1,ePrivKey), domainParams); | |||||
basicAgreement.init(privateKey); | |||||
BigInteger agreement = basicAgreement.calculateAgreement(pubKey); | |||||
return bigIntegerToBytes(agreement); | |||||
} | } | ||||
public static BigInteger deriveShares(byte[] frontID, byte[] rearID, BigInteger agreement){ | |||||
byte[] agreementBytes = agreement.toByteArray(); | |||||
public static byte[] deriveShares(byte[] frontID, byte[] rearID, byte[] agreementBytes){ | |||||
byte[] inputBytes = BytesUtils.concat(frontID,rearID,agreementBytes); | byte[] inputBytes = BytesUtils.concat(frontID,rearID,agreementBytes); | ||||
return new BigInteger(1,SM3Utils.hash(inputBytes)); | |||||
return SM3Utils.hash(inputBytes); | |||||
} | } | ||||
public static BigInteger encryptBlindedMsg(PublicKey encKey, BigInteger msg, BigInteger frontShare, BigInteger rearShare){ | |||||
return encKey.encrypt(msg.add(frontShare).subtract(rearShare).mod(encKey.getN())); | |||||
public static byte[] encryptBlindedMsg(byte[] paillierPubKey, int input, byte[] frontShare, byte[] rearShare){ | |||||
BigInteger integer = BigInteger.valueOf(input); | |||||
BigInteger frontInteger = new BigInteger(1,frontShare); | |||||
BigInteger rearInteger = new BigInteger(1,rearShare); | |||||
PaillierPublicKeyParameters encKey = PaillierUtils.bytes2PubKey(paillierPubKey); | |||||
BigInteger modulus = encKey.getModulus(); | |||||
BigInteger plaintext = integer.add(frontInteger).subtract(rearInteger).mod(modulus); | |||||
return PaillierUtils.encrypt(plaintext.toByteArray(),encKey); | |||||
} | } | ||||
public static BigInteger aggregateCiphertexts(PublicKey encKey, BigInteger... bigIntegersList){ | |||||
BigInteger aggregatedCiphertext = BigInteger.ONE; | |||||
for (BigInteger entry : bigIntegersList) { | |||||
aggregatedCiphertext = aggregatedCiphertext.multiply(entry).mod(encKey.getnSquared()); | |||||
} | |||||
return aggregatedCiphertext; | |||||
public static byte[] aggregateCiphertexts(byte[] paillierPubKey, byte[]... ciphertexts){ | |||||
return PaillierUtils.add(paillierPubKey,ciphertexts); | |||||
} | } | ||||
public static BigInteger decrypt(KeyPair keyPair, BigInteger ciphertext){ | |||||
return keyPair.decrypt(ciphertext); | |||||
public static byte[] decrypt(byte[] paillierPrivKey, byte[] ciphertext){ | |||||
return PaillierUtils.decrypt(ciphertext,paillierPrivKey); | |||||
} | } | ||||
public ECPublicKeyParameters getEPubKey(){return ePubKey;} | |||||
public ECPrivateKeyParameters getEPrivKey(){return ePrivKey;} | |||||
public static byte[] getEPubKey(){return ePubKey;} | |||||
public static byte[] getEPrivKey(){return ePrivKey;} | |||||
public byte[] getEPubKeyBytes(){ | |||||
byte[] ePubKeyBytes = new byte[65]; | |||||
byte[] ePubKeyBytesX = ePubKey.getQ().getAffineXCoord().getEncoded(); | |||||
byte[] ePubKeyBytesY = ePubKey.getQ().getAffineYCoord().getEncoded(); | |||||
System.arraycopy(Hex.decode("04"),0,ePubKeyBytes,0,1); | |||||
System.arraycopy(ePubKeyBytesX,0,ePubKeyBytes,1,32); | |||||
System.arraycopy(ePubKeyBytesY,0,ePubKeyBytes,1+32,32); | |||||
return ePubKeyBytes; | |||||
} | |||||
public byte[] getEPrivKeyBytes(){ | |||||
return PaillierUtils.BigIntegerToLBytes(ePrivKey.getD(),32); | |||||
} | |||||
// public byte[] getEPubKeyBytes(){ | |||||
// byte[] ePubKeyBytes = new byte[65]; | |||||
// byte[] ePubKeyBytesX = ePubKey.getQ().getAffineXCoord().getEncoded(); | |||||
// byte[] ePubKeyBytesY = ePubKey.getQ().getAffineYCoord().getEncoded(); | |||||
// System.arraycopy(Hex.decode("04"),0,ePubKeyBytes,0,1); | |||||
// System.arraycopy(ePubKeyBytesX,0,ePubKeyBytes,1,32); | |||||
// System.arraycopy(ePubKeyBytesY,0,ePubKeyBytes,1+32,32); | |||||
// return ePubKeyBytes; | |||||
// } | |||||
// | |||||
// public byte[] getEPrivKeyBytes(){ | |||||
// return bigIntegerToBytes(ePrivKey.getD()); | |||||
// } | |||||
public ECPublicKeyParameters resolveEPubKey(byte[] ePubKeyBytes){ | public ECPublicKeyParameters resolveEPubKey(byte[] ePubKeyBytes){ | ||||
byte[] ePubKeyX = new byte[32]; | byte[] ePubKeyX = new byte[32]; | ||||
@@ -95,4 +99,22 @@ public class MultiSum { | |||||
return new ECPrivateKeyParameters(new BigInteger(1,ePrivKeyBytes),domainParams); | return new ECPrivateKeyParameters(new BigInteger(1,ePrivKeyBytes),domainParams); | ||||
} | } | ||||
// To convert BigInteger to byte[] whose length is l | |||||
private static byte[] bigIntegerToBytes(BigInteger b){ | |||||
byte[] tmp = b.toByteArray(); | |||||
byte[] result = new byte[32]; | |||||
if (tmp.length > result.length) { | |||||
System.arraycopy(tmp, tmp.length - result.length, result, 0, result.length); | |||||
} | |||||
else { | |||||
System.arraycopy(tmp,0,result,result.length-tmp.length,tmp.length); | |||||
} | |||||
return result; | |||||
} | |||||
// To retrieve the public key point from publicKey in byte array mode | |||||
private static ECPoint resolvePubKeyBytes(byte[] publicKey){ | |||||
return curve.decodePoint(publicKey); | |||||
} | |||||
} | } |
@@ -1,98 +0,0 @@ | |||||
package com.jd.blockchain.crypto.paillier; | |||||
import java.math.BigInteger; | |||||
import java.util.List; | |||||
import com.jd.blockchain.utils.io.BytesUtils; | |||||
/** | |||||
* The MIT License (MIT) | |||||
* | |||||
* Copyright (c) 2014 Hendrik Kunert | |||||
* | |||||
* Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
* of this software and associated documentation files (the "Software"), to deal | |||||
* in the Software without restriction, including without limitation the rights | |||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
* copies of the Software, and to permit persons to whom the Software is | |||||
* furnished to do so, subject to the following conditions: | |||||
* | |||||
* The above copyright notice and this permission notice shall be included in | |||||
* all copies or substantial portions of the Software. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||||
* THE SOFTWARE. | |||||
*/ | |||||
/** | |||||
* A class that holds a pair of associated public and private keys. | |||||
*/ | |||||
public class KeyPair { | |||||
private final PrivateKey privateKey; | |||||
private final PublicKey publicKey; | |||||
private final BigInteger upperBound; | |||||
public KeyPair(PrivateKey privateKey, PublicKey publicKey, BigInteger upperBound) { | |||||
this.privateKey = privateKey; | |||||
this.publicKey = publicKey; | |||||
this.upperBound = upperBound; | |||||
} | |||||
public KeyPair(byte[] privKeyBytes,byte[] pubKeyBytes,byte[] upperBoundBytes){ | |||||
this.privateKey = new PrivateKey(privKeyBytes); | |||||
this.publicKey = new PublicKey(pubKeyBytes); | |||||
this.upperBound = new BigInteger(upperBoundBytes); | |||||
} | |||||
public KeyPair(byte[] keyPairBytes){ | |||||
List<byte[]> list = PaillierUtils.split(keyPairBytes, "##KeyPair##".getBytes()); | |||||
this.privateKey = new PrivateKey(list.get(0)); | |||||
this.publicKey = new PublicKey(list.get(1)); | |||||
this.upperBound = new BigInteger(list.get(2)); | |||||
} | |||||
public PrivateKey getPrivateKey() { | |||||
return privateKey; | |||||
} | |||||
public PublicKey getPublicKey() { | |||||
return publicKey; | |||||
} | |||||
public BigInteger getUpperBound() { return upperBound; } | |||||
/** | |||||
* Decrypts the given ciphertext. | |||||
* | |||||
* @param c The ciphertext that should be decrypted. | |||||
* @return The corresponding plaintext. If an upper bound was given to {@link KeyPairBuilder}, | |||||
* the result can also be negative. See {@link KeyPairBuilder#upperBound(BigInteger)} for details. | |||||
*/ | |||||
public final BigInteger decrypt(BigInteger c) { | |||||
BigInteger n = publicKey.getN(); | |||||
BigInteger nSquare = publicKey.getnSquared(); | |||||
BigInteger lambda = privateKey.getLambda(); | |||||
BigInteger u = privateKey.getPreCalculatedDenominator(); | |||||
BigInteger p = c.modPow(lambda, nSquare).subtract(BigInteger.ONE).divide(n).multiply(u).mod(n); | |||||
if (upperBound != null && p.compareTo(upperBound) > 0) { | |||||
p = p.subtract(n); | |||||
} | |||||
return p; | |||||
} | |||||
public byte[] getUpperBoundBytes(){ return upperBound.toByteArray(); } | |||||
public byte[] getKeyPairBytes(){ | |||||
return BytesUtils.concat(privateKey.getPrivKeyBytes(),"##KeyPair##".getBytes(),publicKey.getPubKeyBytes(),"##KeyPair##".getBytes(),upperBound.toByteArray()); | |||||
} | |||||
} |
@@ -1,165 +0,0 @@ | |||||
package com.jd.blockchain.crypto.paillier; | |||||
import java.math.BigInteger; | |||||
import java.security.SecureRandom; | |||||
import java.util.Random; | |||||
/** | |||||
* The MIT License (MIT) | |||||
* | |||||
* Copyright (c) 2014 Hendrik Kunert | |||||
* | |||||
* Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
* of this software and associated documentation files (the "Software"), to deal | |||||
* in the Software without restriction, including without limitation the rights | |||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
* copies of the Software, and to permit persons to whom the Software is | |||||
* furnished to do so, subject to the following conditions: | |||||
* | |||||
* The above copyright notice and this permission notice shall be included in | |||||
* all copies or substantial portions of the Software. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||||
* THE SOFTWARE. | |||||
*/ | |||||
/** | |||||
* A class that is used for generating a pair of associated public and private | |||||
* keys. | |||||
* | |||||
* @see KeyPair | |||||
*/ | |||||
public class KeyPairBuilder { | |||||
private int bits = 1024; | |||||
private int certainty = 0; | |||||
private Random rng; | |||||
private BigInteger upperBound; | |||||
/** | |||||
* Sets the size of the key to be created. | |||||
* <p> | |||||
* The default size is 1024 bits. | |||||
* | |||||
* @param bits The size of the key in bits. | |||||
* @return This instance of KeyPairBuilder for method chaining. | |||||
*/ | |||||
public KeyPairBuilder bits(int bits) { | |||||
this.bits = bits; | |||||
return this; | |||||
} | |||||
/** | |||||
* See {@link BigInteger#BigInteger(int, int, Random)} for more details. | |||||
* <p> | |||||
* The default value is 0. | |||||
* | |||||
* @return This instance of KeyPairBuilder for method chaining. | |||||
*/ | |||||
public KeyPairBuilder certainty(int certainty) { | |||||
this.certainty = certainty; | |||||
return this; | |||||
} | |||||
/** | |||||
* Sets the random number generator that is used for the generation of | |||||
* internally needed prime numbers. | |||||
* <p> | |||||
* The default is {@link SecureRandom}. | |||||
* <p> | |||||
* <b>Warning:</b> | |||||
* The change of this value affects the security of the whole cryptographic | |||||
* system. | |||||
* | |||||
* @param rng The random number generator that should be used instead of | |||||
* {@link SecureRandom}. | |||||
* @return This instance of KeyPairBuilder for method chaining. | |||||
*/ | |||||
public KeyPairBuilder randomNumberGenerator(Random rng) { | |||||
this.rng = rng; | |||||
return this; | |||||
} | |||||
/** | |||||
* Sets an upper bound that is used for decrypting ciphertexts representing a negative value. | |||||
* <p> | |||||
* In most cases the upper bound should be the same as of the underlying number system - | |||||
* for example {@link Integer#MAX_VALUE}. | |||||
* | |||||
* @param b The upper bound. | |||||
* @return This instance of KeyPairBuilder for method chaining. | |||||
*/ | |||||
public KeyPairBuilder upperBound(BigInteger b) { | |||||
this.upperBound = b; | |||||
return this; | |||||
} | |||||
/** | |||||
* Creates a pair of associated public and private keys. | |||||
* | |||||
* @return The pair of associated public and private keys. | |||||
*/ | |||||
public KeyPair generateKeyPair() { | |||||
if (rng == null) { | |||||
rng = new SecureRandom(); | |||||
} | |||||
BigInteger p, q; | |||||
int length = bits / 2; | |||||
if (certainty > 0) { | |||||
p = new BigInteger(length, certainty, rng); | |||||
q = new BigInteger(length, certainty, rng); | |||||
} else { | |||||
p = BigInteger.probablePrime(length, rng); | |||||
q = BigInteger.probablePrime(length, rng); | |||||
} | |||||
BigInteger n = p.multiply(q); | |||||
BigInteger nSquared = n.multiply(n); | |||||
BigInteger pMinusOne = p.subtract(BigInteger.ONE); | |||||
BigInteger qMinusOne = q.subtract(BigInteger.ONE); | |||||
BigInteger lambda = this.lcm(pMinusOne, qMinusOne); | |||||
BigInteger g; | |||||
BigInteger helper; | |||||
do { | |||||
g = new BigInteger(bits, rng); | |||||
helper = calculateL(g.modPow(lambda, nSquared), n); | |||||
} while (!helper.gcd(n).equals(BigInteger.ONE)); | |||||
PublicKey publicKey = new PublicKey(n, nSquared, g, bits); | |||||
PrivateKey privateKey = new PrivateKey(lambda, helper.modInverse(n)); | |||||
return new KeyPair(privateKey, publicKey, upperBound); | |||||
} | |||||
// TODO separate this somewhere | |||||
private BigInteger calculateL(BigInteger u, BigInteger n) { | |||||
BigInteger result = u.subtract(BigInteger.ONE); | |||||
result = result.divide(n); | |||||
return result; | |||||
} | |||||
// TODO add to own BigInteger extended class | |||||
private BigInteger lcm(BigInteger a, BigInteger b) { | |||||
BigInteger result; | |||||
BigInteger gcd = a.gcd(b); | |||||
result = a.abs().divide(gcd); | |||||
result = result.multiply(b.abs()); | |||||
return result; | |||||
} | |||||
} |
@@ -0,0 +1,51 @@ | |||||
package com.jd.blockchain.crypto.paillier; | |||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair; | |||||
import org.bouncycastle.math.Primes; | |||||
import org.bouncycastle.util.BigIntegers; | |||||
import java.math.BigInteger; | |||||
import java.security.SecureRandom; | |||||
/** | |||||
* @author zhanglin33 | |||||
* @title: PaillierKeyPairGenerator | |||||
* @description: generator of paillier key pair | |||||
* @date 2019-04-30, 14:48 | |||||
*/ | |||||
public class PaillierKeyPairGenerator { | |||||
private static final int STRENGTH = 2048; | |||||
public AsymmetricCipherKeyPair generateKeyPair() { | |||||
int pLength = (STRENGTH + 1) / 2; | |||||
int qLength = STRENGTH - pLength; | |||||
BigInteger p; | |||||
BigInteger q; | |||||
BigInteger n; | |||||
do { | |||||
do { | |||||
SecureRandom pRandom = new SecureRandom(); | |||||
p = BigIntegers.createRandomPrime(pLength, 1, pRandom); | |||||
} while (!isProbablePrime(p)); | |||||
do { | |||||
SecureRandom qRandom = new SecureRandom(); | |||||
q = BigIntegers.createRandomPrime(qLength, 1, qRandom); | |||||
} while (q.equals(p) || !isProbablePrime(p)); | |||||
n = q.multiply(p); | |||||
} while (n.bitLength() != STRENGTH); | |||||
return new AsymmetricCipherKeyPair(new PaillierPublicKeyParameters(n), new PaillierPrivateKeyParameters(p,q)); | |||||
} | |||||
// Primes class for FIPS 186-4 C.3 primality checking | |||||
private boolean isProbablePrime(BigInteger x) | |||||
{ | |||||
int iterations = 3; | |||||
SecureRandom random = new SecureRandom(); | |||||
return !Primes.hasAnySmallFactors(x) && Primes.isMRProbablePrime(x, random, iterations); | |||||
} | |||||
} |
@@ -0,0 +1,101 @@ | |||||
package com.jd.blockchain.crypto.paillier; | |||||
import org.bouncycastle.crypto.params.AsymmetricKeyParameter; | |||||
import java.math.BigInteger; | |||||
import static org.bouncycastle.util.BigIntegers.ONE; | |||||
/** | |||||
* @author zhanglin33 | |||||
* @title: PaillierPrivateKeyParameters | |||||
* @description: parameters about Paillier private key | |||||
* @date 2019-04-30, 14:39 | |||||
*/ | |||||
public class PaillierPrivateKeyParameters extends AsymmetricKeyParameter { | |||||
private BigInteger p; | |||||
private BigInteger q; | |||||
private BigInteger pSquared; | |||||
private BigInteger qSquared; | |||||
private BigInteger pInverse; | |||||
private BigInteger muP; | |||||
private BigInteger muQ; | |||||
public PaillierPrivateKeyParameters(BigInteger p, BigInteger q) { | |||||
super(true); | |||||
BigInteger generator = p.multiply(q).add(ONE); | |||||
this.p = p; | |||||
this.pSquared = p.multiply(p); | |||||
this.q = q; | |||||
this.qSquared = q.multiply(q); | |||||
this.pInverse = p.modInverse(q); | |||||
this.muP = hFunction(generator, p, pSquared); | |||||
this.muQ = hFunction(generator, q, qSquared); | |||||
} | |||||
public PaillierPrivateKeyParameters(BigInteger p, BigInteger pSquared, BigInteger q, BigInteger qSquared, | |||||
BigInteger pInverse, BigInteger muP, BigInteger muQ){ | |||||
super(true); | |||||
this.p = p; | |||||
this.pSquared = pSquared; | |||||
this.q = q; | |||||
this.qSquared = qSquared; | |||||
this.pInverse = pInverse; | |||||
this.muP = muP; | |||||
this.muQ = muQ; | |||||
} | |||||
// mu = h(x) = (L(g^(x-1) mod x^2))^(-1) mod n | |||||
private BigInteger hFunction(BigInteger generator, BigInteger x, BigInteger xSquared) { | |||||
BigInteger phiX = lFunction(generator.modPow(x.subtract(ONE),xSquared),x); | |||||
return phiX.modInverse(x); | |||||
} | |||||
// L(x) = (x-1) / n | |||||
public BigInteger lFunction(BigInteger x, BigInteger n) { | |||||
return x.subtract(ONE).divide(n); | |||||
} | |||||
public BigInteger getP() | |||||
{ | |||||
return p; | |||||
} | |||||
public BigInteger getPSquared() | |||||
{ | |||||
return pSquared; | |||||
} | |||||
public BigInteger getQ() | |||||
{ | |||||
return q; | |||||
} | |||||
public BigInteger getQSquared() | |||||
{ | |||||
return qSquared; | |||||
} | |||||
public BigInteger getPInverse() | |||||
{ | |||||
return pInverse; | |||||
} | |||||
public BigInteger getMuP() | |||||
{ | |||||
return muP; | |||||
} | |||||
public BigInteger getMuQ() | |||||
{ | |||||
return muQ; | |||||
} | |||||
} |
@@ -0,0 +1,59 @@ | |||||
package com.jd.blockchain.crypto.paillier; | |||||
import org.bouncycastle.crypto.params.AsymmetricKeyParameter; | |||||
import java.math.BigInteger; | |||||
import static org.bouncycastle.util.BigIntegers.ONE; | |||||
/** | |||||
* @author zhanglin33 | |||||
* @title: PaillierPublicKeyParameters | |||||
* @description: parameters about Paillier public key | |||||
* @date 2019-04-30, 14:41 | |||||
*/ | |||||
public class PaillierPublicKeyParameters extends AsymmetricKeyParameter { | |||||
private BigInteger modulus; | |||||
private BigInteger modulusSquared; | |||||
private BigInteger generator; | |||||
public PaillierPublicKeyParameters(BigInteger modulus) { | |||||
super(false); | |||||
this.modulus = validate(modulus); | |||||
this.modulusSquared = modulus.multiply(modulus); | |||||
this.generator = modulus.add(ONE); | |||||
} | |||||
public BigInteger getModulus() { | |||||
return modulus; | |||||
} | |||||
public BigInteger getModulusSquared() { | |||||
return modulusSquared; | |||||
} | |||||
public BigInteger getGenerator() { | |||||
return generator; | |||||
} | |||||
private BigInteger validate(BigInteger modulus) | |||||
{ | |||||
if ((modulus.intValue() & 1) == 0) | |||||
{ | |||||
throw new IllegalArgumentException("The modulus is even!"); | |||||
} | |||||
// the value is the product of the 132 smallest primes from 3 to 751 | |||||
if (!modulus.gcd(new BigInteger("145188775577763990151158743208307020242261438098488931355057091965" + | |||||
"931517706595657435907891265414916764399268423699130577757433083166" + | |||||
"651158914570105971074227669275788291575622090199821297575654322355" + | |||||
"049043101306108213104080801056529374892690144291505781966373045481" + | |||||
"8359472391642885328171302299245556663073719855")).equals(ONE)) | |||||
{ | |||||
throw new IllegalArgumentException("The modulus has a small prime factor!"); | |||||
} | |||||
return modulus; | |||||
} | |||||
} |
@@ -1,16 +1,200 @@ | |||||
package com.jd.blockchain.crypto.paillier; | package com.jd.blockchain.crypto.paillier; | ||||
import com.jd.blockchain.utils.io.BytesUtils; | |||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair; | |||||
import java.math.BigInteger; | import java.math.BigInteger; | ||||
import java.util.Arrays; | |||||
import java.util.LinkedList; | |||||
import java.util.List; | |||||
import java.security.SecureRandom; | |||||
import static org.bouncycastle.util.BigIntegers.ONE; | |||||
/** | |||||
* @author zhanglin33 | |||||
* @title: PaillierUtils | |||||
* @description: encryption, decryption, homomorphic addition and scalar multiplication in Paillier algorithm | |||||
* @date 2019-04-30, 14:49 | |||||
*/ | |||||
public class PaillierUtils { | public class PaillierUtils { | ||||
// To convert BigInteger to byte[] whose length is l | |||||
public static byte[] BigIntegerToLBytes(BigInteger b, int l){ | |||||
private static final int MODULUS_LENGTH = 256; | |||||
private static final int MODULUSSQUARED_LENGTH = 512; | |||||
private static final int P_LENGTH = 128; | |||||
private static final int PSQUARED_LENGTH = 256; | |||||
private static final int Q_LENGTH = 128; | |||||
private static final int QSQUARED_LENGTH = 256; | |||||
private static final int PINVERSE_LENGTH = 128; | |||||
private static final int MUP_LENGTH = 128; | |||||
private static final int MUQ_LENGTH = 128; | |||||
private static final int PRIVKEY_LENGTH = P_LENGTH + PSQUARED_LENGTH + Q_LENGTH + QSQUARED_LENGTH | |||||
+ PINVERSE_LENGTH + MUP_LENGTH + MUQ_LENGTH; | |||||
public static AsymmetricCipherKeyPair generateKeyPair(){ | |||||
PaillierKeyPairGenerator generator = new PaillierKeyPairGenerator(); | |||||
return generator.generateKeyPair(); | |||||
} | |||||
public static byte[] encrypt(byte[] plainBytes, byte[] publicKey) { | |||||
PaillierPublicKeyParameters pubKeyParams = bytes2PubKey(publicKey); | |||||
return encrypt(plainBytes, pubKeyParams); | |||||
} | |||||
public static byte[] encrypt(byte[] plainBytes, PaillierPublicKeyParameters pubKeyParams) { | |||||
SecureRandom random = new SecureRandom(); | |||||
return encrypt(plainBytes, pubKeyParams, random); | |||||
} | |||||
// c = g^m * r^n mod n^2 = (1+n)^m * r^n mod n^2 = (1 + n*m mod n^2) * r^n mod n^2 | |||||
public static byte[] encrypt(byte[] plainBytes, PaillierPublicKeyParameters pubKeyParams, SecureRandom random){ | |||||
BigInteger n = pubKeyParams.getModulus(); | |||||
BigInteger nSquared = pubKeyParams.getModulusSquared(); | |||||
BigInteger m = new BigInteger(1,plainBytes); | |||||
BigInteger r = new BigInteger(n.bitLength(), random); | |||||
BigInteger rawCiphertext = n.multiply(m).add(ONE).mod(nSquared); | |||||
BigInteger c = r.modPow(n, nSquared).multiply(rawCiphertext).mod(nSquared); | |||||
return bigIntegerToBytes(c, MODULUSSQUARED_LENGTH); | |||||
} | |||||
public static byte[] decrypt(byte[] cipherBytes, byte[] privateKey) { | |||||
PaillierPrivateKeyParameters privKeyParams = bytes2PrivKey(privateKey); | |||||
return decrypt(cipherBytes,privKeyParams); | |||||
} | |||||
// m mod p = L(c^(p-1) mod p^2) * muP mod p | |||||
// m mod q = L(c^(q-1) mod q^2) * muQ mod q | |||||
// m = (m mod p) * (1/q mod p) * q + (m mod q) * (1/p mod q) * p | |||||
// = ((m mod q)-(m mod p)) * (1/p mod q) mod q * p + (m mod p) | |||||
public static byte[] decrypt(byte[] cipherBytes, PaillierPrivateKeyParameters privKeyParams){ | |||||
BigInteger cihphertext = new BigInteger(1, cipherBytes); | |||||
BigInteger p = privKeyParams.getP(); | |||||
BigInteger pSquared = privKeyParams.getPSquared(); | |||||
BigInteger q = privKeyParams.getQ(); | |||||
BigInteger qSquared = privKeyParams.getQSquared(); | |||||
BigInteger pInverse = privKeyParams.getPInverse(); | |||||
BigInteger muP = privKeyParams.getMuP(); | |||||
BigInteger muQ = privKeyParams.getMuQ(); | |||||
BigInteger mModP = | |||||
privKeyParams.lFunction(cihphertext.modPow(p.subtract(ONE),pSquared),p).multiply(muP).mod(p); | |||||
BigInteger mModQ = | |||||
privKeyParams.lFunction(cihphertext.modPow(q.subtract(ONE),qSquared),q).multiply(muQ).mod(q); | |||||
BigInteger midValue = mModQ.subtract(mModP).multiply(pInverse).mod(q); | |||||
BigInteger m = midValue.multiply(p).add(mModP); | |||||
return m.toByteArray(); | |||||
} | |||||
public static byte[] pubKey2Bytes(PaillierPublicKeyParameters pubKeyParams) { | |||||
BigInteger n = pubKeyParams.getModulus(); | |||||
return bigIntegerToBytes(n, MODULUS_LENGTH); | |||||
} | |||||
public static PaillierPublicKeyParameters bytes2PubKey(byte[] publicKey) { | |||||
if (publicKey.length != MODULUS_LENGTH) { | |||||
throw new IllegalArgumentException("publicKey's length does not meet algorithm's requirement!"); | |||||
} | |||||
BigInteger n = new BigInteger(1, publicKey); | |||||
return new PaillierPublicKeyParameters(n); | |||||
} | |||||
public static byte[] privKey2Bytes(PaillierPrivateKeyParameters privKeyParams) { | |||||
BigInteger p = privKeyParams.getP(); | |||||
BigInteger pSquared = privKeyParams.getPSquared(); | |||||
BigInteger q = privKeyParams.getQ(); | |||||
BigInteger qSquared = privKeyParams.getQSquared(); | |||||
BigInteger pInverse = privKeyParams.getPInverse(); | |||||
BigInteger muP = privKeyParams.getMuP(); | |||||
BigInteger muQ = privKeyParams.getMuQ(); | |||||
byte[] pBytes = bigIntegerToBytes(p, P_LENGTH); | |||||
byte[] pSquaredBytes = bigIntegerToBytes(pSquared, PSQUARED_LENGTH); | |||||
byte[] qBytes = bigIntegerToBytes(q, Q_LENGTH); | |||||
byte[] qSquaredBytes = bigIntegerToBytes(qSquared, QSQUARED_LENGTH); | |||||
byte[] pInverseBytes = bigIntegerToBytes(pInverse, PINVERSE_LENGTH); | |||||
byte[] muPBytes = bigIntegerToBytes(muP, MUP_LENGTH); | |||||
byte[] muQBytes = bigIntegerToBytes(muQ, MUQ_LENGTH); | |||||
return BytesUtils.concat(pBytes,pSquaredBytes,qBytes,qSquaredBytes,pInverseBytes,muPBytes,muQBytes); | |||||
} | |||||
public static PaillierPrivateKeyParameters bytes2PrivKey(byte[] privateKey) { | |||||
if (privateKey.length != PRIVKEY_LENGTH) { | |||||
throw new IllegalArgumentException("privateKey's length does not meet algorithm's requirement!"); | |||||
} | |||||
byte[] pBytes = new byte[P_LENGTH]; | |||||
byte[] pSquaredBytes = new byte[PSQUARED_LENGTH]; | |||||
byte[] qBytes = new byte[Q_LENGTH]; | |||||
byte[] qSquaredBytes = new byte[QSQUARED_LENGTH]; | |||||
byte[] pInverseBytes = new byte[PINVERSE_LENGTH]; | |||||
byte[] muPBytes = new byte[MUP_LENGTH]; | |||||
byte[] muQBytes = new byte[MUQ_LENGTH]; | |||||
split(privateKey,pBytes,pSquaredBytes,qBytes,qSquaredBytes,pInverseBytes,muPBytes,muQBytes); | |||||
BigInteger p = new BigInteger(1, pBytes); | |||||
BigInteger pSquared = new BigInteger(1, pSquaredBytes); | |||||
BigInteger q = new BigInteger(1, qBytes); | |||||
BigInteger qSquared = new BigInteger(1, qSquaredBytes); | |||||
BigInteger pInverse = new BigInteger(1, pInverseBytes); | |||||
BigInteger muP = new BigInteger(1, muPBytes); | |||||
BigInteger muQ = new BigInteger(1, muQBytes); | |||||
return new PaillierPrivateKeyParameters(p,pSquared,q,qSquared,pInverse,muP,muQ); | |||||
} | |||||
public static byte[] add(byte[] publicKey, byte[]... ciphertexts) { | |||||
PaillierPublicKeyParameters pubKeyParams = bytes2PubKey(publicKey); | |||||
return add(pubKeyParams,ciphertexts); | |||||
} | |||||
public static byte[] add(PaillierPublicKeyParameters pubKeyParams, byte[]... ciphertexts) { | |||||
BigInteger result = ONE; | |||||
BigInteger multiplier; | |||||
BigInteger nSquared = pubKeyParams.getModulusSquared(); | |||||
for (byte[] each: ciphertexts) { | |||||
multiplier = new BigInteger(1, each); | |||||
result = result.multiply(multiplier).mod(nSquared); | |||||
} | |||||
return bigIntegerToBytes(result, MODULUSSQUARED_LENGTH); | |||||
} | |||||
public static byte[] scalarMultiply(byte[] publicKey, byte[] cipherBytes, long scalar) { | |||||
PaillierPublicKeyParameters pubKeyParams = bytes2PubKey(publicKey); | |||||
return scalarMultiply(pubKeyParams,cipherBytes,scalar); | |||||
} | |||||
public static byte[] scalarMultiply(PaillierPublicKeyParameters pubKeyParams, byte[] cipherBytes, long scalar) { | |||||
BigInteger nSquared = pubKeyParams.getModulusSquared(); | |||||
BigInteger cihertext = new BigInteger(1, cipherBytes); | |||||
BigInteger exponent = BigInteger.valueOf(scalar); | |||||
BigInteger result = cihertext.modPow(exponent,nSquared); | |||||
return bigIntegerToBytes(result, MODULUSSQUARED_LENGTH); | |||||
} | |||||
// To convert BigInteger to byte array in specified size | |||||
private static byte[] bigIntegerToBytes(BigInteger b, int bytesSize){ | |||||
byte[] tmp = b.toByteArray(); | byte[] tmp = b.toByteArray(); | ||||
byte[] result = new byte[l]; | |||||
byte[] result = new byte[bytesSize]; | |||||
if (tmp.length > result.length) { | if (tmp.length > result.length) { | ||||
System.arraycopy(tmp, tmp.length - result.length, result, 0, result.length); | System.arraycopy(tmp, tmp.length - result.length, result, 0, result.length); | ||||
} | } | ||||
@@ -20,42 +204,15 @@ public class PaillierUtils { | |||||
return result; | return result; | ||||
} | } | ||||
public static byte[] intToBytes(int i){ | |||||
byte[] result = new byte[4]; | |||||
result[0] = (byte) (i >> 24); | |||||
result[1] = (byte) (i >> 16); | |||||
result[2] = (byte) (i >> 8); | |||||
result[3] = (byte) (i); | |||||
return result; | |||||
} | |||||
public static int bytesToInt(byte[] array){ | |||||
int result = 0; | |||||
result |= ((array[0] & 0xFF) << 24); | |||||
result |= ((array[1] & 0xFF) << 16); | |||||
result |= ((array[2] & 0xFF) << 8); | |||||
result |= ((array[3] & 0xFF)); | |||||
return result; | |||||
} | |||||
private static void split(byte[] src, byte[]... bytesList) { | |||||
public static List<byte[]> split(byte[] array, byte[] delimiter) { | |||||
List<byte[]> byteArrays = new LinkedList<>(); | |||||
if (delimiter.length == 0) { | |||||
return byteArrays; | |||||
} | |||||
int begin = 0; | |||||
outer: | |||||
for (int i = 0; i < array.length - delimiter.length + 1; i++) { | |||||
for (int j = 0; j < delimiter.length; j++) { | |||||
if (array[i + j] != delimiter[j]) { | |||||
continue outer; | |||||
} | |||||
int srcPos = 0; | |||||
for (byte[] each: bytesList){ | |||||
System.arraycopy(src,srcPos,each,0,each.length); | |||||
srcPos += each.length; | |||||
if (srcPos >= src.length){ | |||||
break; | |||||
} | } | ||||
byteArrays.add(Arrays.copyOfRange(array, begin, i)); | |||||
begin = i + delimiter.length; | |||||
} | } | ||||
byteArrays.add(Arrays.copyOfRange(array, begin, array.length)); | |||||
return byteArrays; | |||||
} | } | ||||
} | } |
@@ -1,75 +0,0 @@ | |||||
package com.jd.blockchain.crypto.paillier; | |||||
import java.math.BigInteger; | |||||
import java.util.List; | |||||
/** | |||||
* The MIT License (MIT) | |||||
* | |||||
* Copyright (c) 2014 Hendrik Kunert | |||||
* | |||||
* Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
* of this software and associated documentation files (the "Software"), to deal | |||||
* in the Software without restriction, including without limitation the rights | |||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
* copies of the Software, and to permit persons to whom the Software is | |||||
* furnished to do so, subject to the following conditions: | |||||
* | |||||
* The above copyright notice and this permission notice shall be included in | |||||
* all copies or substantial portions of the Software. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||||
* THE SOFTWARE. | |||||
*/ | |||||
import com.jd.blockchain.utils.io.BytesUtils; | |||||
/** | |||||
* A class that represents the private part of the Paillier key pair. | |||||
*/ | |||||
public class PrivateKey { | |||||
private final BigInteger lambda; | |||||
private final BigInteger preCalculatedDenominator; | |||||
public PrivateKey(BigInteger lambda, BigInteger preCalculatedDenominator) { | |||||
this.lambda = lambda; | |||||
this.preCalculatedDenominator = preCalculatedDenominator; | |||||
} | |||||
public PrivateKey(byte[] lambdaBytes, byte[] preCalculatedDenominatorBytes){ | |||||
this.lambda = new BigInteger(lambdaBytes); | |||||
this.preCalculatedDenominator = new BigInteger(preCalculatedDenominatorBytes); | |||||
} | |||||
public PrivateKey(byte[] privKeyBytes){ | |||||
List<byte[]> list = PaillierUtils.split(privKeyBytes, "##PrivateKey##".getBytes()); | |||||
this.lambda = new BigInteger(list.get(0)); | |||||
this.preCalculatedDenominator = new BigInteger(list.get(1)); | |||||
} | |||||
public BigInteger getLambda() { | |||||
return lambda; | |||||
} | |||||
public BigInteger getPreCalculatedDenominator() { | |||||
return preCalculatedDenominator; | |||||
} | |||||
public byte[] getLambdaBytes(){ | |||||
return lambda.toByteArray(); | |||||
} | |||||
public byte[] getPreCalculatedDenominatorBytes(){ | |||||
return preCalculatedDenominator.toByteArray(); | |||||
} | |||||
public byte[] getPrivKeyBytes(){ | |||||
return BytesUtils.concat(getLambdaBytes(),"##PrivateKey##".getBytes(),getPreCalculatedDenominatorBytes()); | |||||
} | |||||
} |
@@ -1,129 +0,0 @@ | |||||
package com.jd.blockchain.crypto.paillier; | |||||
import java.math.BigInteger; | |||||
import java.util.LinkedList; | |||||
import java.util.List; | |||||
import java.util.Random; | |||||
/** | |||||
* The MIT License (MIT) | |||||
* | |||||
* Copyright (c) 2014 Hendrik Kunert | |||||
* | |||||
* Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
* of this software and associated documentation files (the "Software"), to deal | |||||
* in the Software without restriction, including without limitation the rights | |||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
* copies of the Software, and to permit persons to whom the Software is | |||||
* furnished to do so, subject to the following conditions: | |||||
* | |||||
* The above copyright notice and this permission notice shall be included in | |||||
* all copies or substantial portions of the Software. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||||
* THE SOFTWARE. | |||||
*/ | |||||
import com.jd.blockchain.utils.io.ByteArray; | |||||
import com.jd.blockchain.utils.io.BytesUtils; | |||||
/** | |||||
* A class that represents the public part of the Paillier key pair. | |||||
* <p> | |||||
* As in all asymmetric cryptographic systems it is responsible for the | |||||
* encryption. | |||||
* <p> | |||||
* Additional instructions for the decryption can be found on {@link KeyPair}. | |||||
* | |||||
* @see KeyPair | |||||
*/ | |||||
public class PublicKey { | |||||
private final int bits; | |||||
private final BigInteger n; | |||||
private final BigInteger nSquared; | |||||
private final BigInteger g; | |||||
public PublicKey(BigInteger n, BigInteger nSquared, BigInteger g, int bits) { | |||||
this.n = n; | |||||
this.nSquared = nSquared; | |||||
this.bits = bits; | |||||
this.g = g; | |||||
} | |||||
public PublicKey(byte[] nBytes, byte[] nSquaredBytes, byte[] gBytes, byte[] bitsBytes) { | |||||
this.n = new BigInteger(nBytes); | |||||
this.nSquared = new BigInteger(nSquaredBytes); | |||||
this.g = new BigInteger(gBytes); | |||||
this.bits = PaillierUtils.bytesToInt(bitsBytes); | |||||
} | |||||
public PublicKey(byte[] pubKeyBytes){ | |||||
List<byte[]> list = PaillierUtils.split(pubKeyBytes, "##PublicKey##".getBytes()); | |||||
this.n = new BigInteger(list.get(0)); | |||||
this.nSquared = new BigInteger(list.get(1)); | |||||
this.g = new BigInteger(list.get(2)); | |||||
this.bits = PaillierUtils.bytesToInt(list.get(3)); | |||||
} | |||||
public int getBits() { | |||||
return bits; | |||||
} | |||||
public BigInteger getN() { | |||||
return n; | |||||
} | |||||
public BigInteger getnSquared() { | |||||
return nSquared; | |||||
} | |||||
public BigInteger getG() { | |||||
return g; | |||||
} | |||||
/** | |||||
* Encrypts the given plaintext. | |||||
* | |||||
* @param m The plaintext that should be encrypted. | |||||
* @return The corresponding ciphertext. | |||||
*/ | |||||
public final BigInteger encrypt(BigInteger m) { | |||||
BigInteger r; | |||||
do { | |||||
r = new BigInteger(bits, new Random()); | |||||
} while (r.compareTo(n) >= 0); | |||||
BigInteger result = g.modPow(m, nSquared); | |||||
BigInteger x = r.modPow(n, nSquared); | |||||
result = result.multiply(x); | |||||
result = result.mod(nSquared); | |||||
return result; | |||||
} | |||||
public byte[] getBitsBytes(){ | |||||
return PaillierUtils.intToBytes(bits); | |||||
} | |||||
public byte[] getNBytes(){ return n.toByteArray(); } | |||||
public byte[] getNSquaredBytes(){ | |||||
return nSquared.toByteArray(); | |||||
} | |||||
public byte[] getGBytes(){ | |||||
return g.toByteArray(); | |||||
} | |||||
public byte[] getPubKeyBytes(){ | |||||
return BytesUtils.concat(getNBytes(),"##PublicKey##".getBytes(),getNSquaredBytes(),"##PublicKey##".getBytes(),getGBytes(),"##PublicKey##".getBytes(),getBitsBytes()); | |||||
} | |||||
} | |||||
@@ -39,35 +39,29 @@ public class EqualVerifyTest { | |||||
byte[] responderOutput; | byte[] responderOutput; | ||||
boolean isEqual; | boolean isEqual; | ||||
int i; | |||||
for (i = 0; i < 1000; i++) { | |||||
sponsorInput = 666; | |||||
responderInput = 666; | |||||
sponsorInput = 666; | |||||
responderInput = 666; | |||||
sponsorOutput = EqualVerify.sponsor(sponsorInput,sponsorEPubKeyBytes); | |||||
responderOutput = EqualVerify.responder(responderInput,sponsorOutput, | |||||
sponsorOutput = EqualVerify.sponsor(sponsorInput,sponsorEPubKeyBytes); | |||||
responderOutput = EqualVerify.responder(responderInput,sponsorOutput, | |||||
responderEPubKeyBytes,responderEPrivKeyBytes); | responderEPubKeyBytes,responderEPrivKeyBytes); | ||||
isEqual = EqualVerify.sponsorCheck(sponsorInput,responderOutput,sponsorEPrivKeyBytes); | |||||
isEqual = EqualVerify.sponsorCheck(sponsorInput,responderOutput,sponsorEPrivKeyBytes); | |||||
assertTrue(isEqual); | |||||
} | |||||
assertTrue(isEqual); | |||||
for (i = 0; i < 1000; i++){ | |||||
sponsorInput = 666; | |||||
responderInput = 667; | |||||
sponsorInput = 666; | |||||
responderInput = 667; | |||||
sponsorOutput = EqualVerify.sponsor(sponsorInput,sponsorEPubKeyBytes); | |||||
responderOutput = EqualVerify.responder(responderInput,sponsorOutput, | |||||
sponsorOutput = EqualVerify.sponsor(sponsorInput,sponsorEPubKeyBytes); | |||||
responderOutput = EqualVerify.responder(responderInput,sponsorOutput, | |||||
responderEPubKeyBytes,responderEPrivKeyBytes); | responderEPubKeyBytes,responderEPrivKeyBytes); | ||||
isEqual = EqualVerify.sponsorCheck(sponsorInput,responderOutput,sponsorEPrivKeyBytes); | |||||
isEqual = EqualVerify.sponsorCheck(sponsorInput,responderOutput,sponsorEPrivKeyBytes); | |||||
assertTrue(!isEqual); | |||||
} | |||||
} | |||||
assertTrue(!isEqual); | |||||
} | |||||
} | } |
@@ -25,26 +25,21 @@ public class IntCompareTest { | |||||
byte[][] cipherArray; | byte[][] cipherArray; | ||||
byte[][] aggregatedCipherArray; | byte[][] aggregatedCipherArray; | ||||
int output; | int output; | ||||
int i; | |||||
for (i = 0; i < 1000; i++) { | |||||
int sponsorInput = 10000; | |||||
int responderInput = 9999; | |||||
cipherArray = IntCompare.sponsor(sponsorInput, pubKeyBytes); | |||||
aggregatedCipherArray = IntCompare.responder(responderInput, cipherArray, pubKeyBytes); | |||||
output = IntCompare.sponsorOutput(aggregatedCipherArray, privKeyBytes); | |||||
assertEquals(1, output); | |||||
} | |||||
for (i = 0; i < 1000; i++) { | |||||
int sponsorInput = 10000; | |||||
int responderInput = 19999; | |||||
cipherArray = IntCompare.sponsor(sponsorInput, pubKeyBytes); | |||||
aggregatedCipherArray = IntCompare.responder(responderInput, cipherArray, pubKeyBytes); | |||||
output = IntCompare.sponsorOutput(aggregatedCipherArray, privKeyBytes); | |||||
assertEquals(0, output); | |||||
} | |||||
int sponsorInput = 10000; | |||||
int responderInput = 9999; | |||||
cipherArray = IntCompare.sponsor(sponsorInput, pubKeyBytes); | |||||
aggregatedCipherArray = IntCompare.responder(responderInput, cipherArray, pubKeyBytes); | |||||
output = IntCompare.sponsorOutput(aggregatedCipherArray, privKeyBytes); | |||||
assertEquals(1, output); | |||||
sponsorInput = 10000; | |||||
responderInput = 19999; | |||||
cipherArray = IntCompare.sponsor(sponsorInput, pubKeyBytes); | |||||
aggregatedCipherArray = IntCompare.responder(responderInput, cipherArray, pubKeyBytes); | |||||
output = IntCompare.sponsorOutput(aggregatedCipherArray, privKeyBytes); | |||||
assertEquals(0, output); | |||||
} | } | ||||
} | } |
@@ -1,105 +1,88 @@ | |||||
package test.com.jd.blockchain.crypto.mpc; | package test.com.jd.blockchain.crypto.mpc; | ||||
import com.jd.blockchain.crypto.mpc.MultiSum; | import com.jd.blockchain.crypto.mpc.MultiSum; | ||||
import com.jd.blockchain.crypto.paillier.KeyPair; | |||||
import com.jd.blockchain.crypto.paillier.KeyPairBuilder; | |||||
import com.jd.blockchain.crypto.paillier.PublicKey; | |||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters; | |||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters; | |||||
import org.bouncycastle.util.encoders.Hex; | |||||
import org.junit.Before; | |||||
import com.jd.blockchain.crypto.paillier.PaillierPrivateKeyParameters; | |||||
import com.jd.blockchain.crypto.paillier.PaillierPublicKeyParameters; | |||||
import com.jd.blockchain.crypto.paillier.PaillierUtils; | |||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair; | |||||
import org.junit.Test; | import org.junit.Test; | ||||
import java.math.BigInteger; | |||||
import static org.junit.Assert.*; | import static org.junit.Assert.*; | ||||
public class MultiSumTest { | public class MultiSumTest { | ||||
private KeyPair keyPair; | |||||
private PublicKey encKey; | |||||
@Before | |||||
public void init() { | |||||
KeyPairBuilder keygen = new KeyPairBuilder(); | |||||
keyPair = keygen.generateKeyPair(); | |||||
encKey = keyPair.getPublicKey(); | |||||
} | |||||
@Test | @Test | ||||
public void testMultiSum() { | public void testMultiSum() { | ||||
MultiSum instance1 = new MultiSum(); | |||||
MultiSum instance2 = new MultiSum(); | |||||
MultiSum instance3 = new MultiSum(); | |||||
AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair(); | |||||
PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic(); | |||||
PaillierPrivateKeyParameters privKeyParams = (PaillierPrivateKeyParameters) keyPair.getPrivate(); | |||||
BigInteger value1 = BigInteger.valueOf(6); | |||||
BigInteger value2 = BigInteger.valueOf(60); | |||||
BigInteger value3 = BigInteger.valueOf(600); | |||||
BigInteger expectedSum = BigInteger.valueOf(666); | |||||
byte[] encKey = PaillierUtils.pubKey2Bytes(pubKeyParams); | |||||
byte[] decKey = PaillierUtils.privKey2Bytes(privKeyParams); | |||||
int int1 = 6; | |||||
int int2 = 60; | |||||
int int3 = 600; | |||||
int sum = 666; | |||||
byte[] id1 = "1".getBytes(); | byte[] id1 = "1".getBytes(); | ||||
byte[] id2 = "2".getBytes(); | byte[] id2 = "2".getBytes(); | ||||
byte[] id3 = "3".getBytes(); | byte[] id3 = "3".getBytes(); | ||||
instance1.generateEphemeralKeyPair(); | |||||
instance2.generateEphemeralKeyPair(); | |||||
instance3.generateEphemeralKeyPair(); | |||||
MultiSum.generateEphemeralKeyPair(); | |||||
byte[] ePubKey1 = MultiSum.getEPubKey(); | |||||
byte[] ePrivKey1 = MultiSum.getEPrivKey(); | |||||
ECPublicKeyParameters ePubKey1 = instance1.getEPubKey(); | |||||
ECPublicKeyParameters ePubKey2 = instance2.getEPubKey(); | |||||
ECPublicKeyParameters ePubKey3 = instance3.getEPubKey(); | |||||
MultiSum.generateEphemeralKeyPair(); | |||||
byte[] ePubKey2 = MultiSum.getEPubKey(); | |||||
byte[] ePrivKey2 = MultiSum.getEPrivKey(); | |||||
BigInteger sk12 = instance1.calculateAgreement(ePubKey2); | |||||
BigInteger sk23 = instance2.calculateAgreement(ePubKey3); | |||||
BigInteger sk31 = instance1.calculateAgreement(ePubKey3); | |||||
MultiSum.generateEphemeralKeyPair(); | |||||
byte[] ePubKey3 = MultiSum.getEPubKey(); | |||||
byte[] ePrivKey3 = MultiSum.getEPrivKey(); | |||||
assertEquals(sk12,instance2.calculateAgreement(ePubKey1)); | |||||
assertEquals(sk23,instance3.calculateAgreement(ePubKey2)); | |||||
assertEquals(sk31,instance3.calculateAgreement(ePubKey1)); | |||||
BigInteger s12 = MultiSum.deriveShares(id1,id2,sk12); | |||||
BigInteger s23 = MultiSum.deriveShares(id2,id3,sk23); | |||||
BigInteger s31 = MultiSum.deriveShares(id3,id1,sk31); | |||||
byte[] sk12 = MultiSum.calculateAgreement(ePubKey2,ePrivKey1); | |||||
byte[] sk23 = MultiSum.calculateAgreement(ePubKey3,ePrivKey2); | |||||
byte[] sk31 = MultiSum.calculateAgreement(ePubKey1,ePrivKey3); | |||||
assertEquals(s12, MultiSum.deriveShares(id1,id2,sk12)); | |||||
assertEquals(s23, MultiSum.deriveShares(id2,id3,sk23)); | |||||
assertEquals(s31, MultiSum.deriveShares(id3,id1,sk31)); | |||||
assertArrayEquals(sk12,MultiSum.calculateAgreement(ePubKey1,ePrivKey2)); | |||||
assertArrayEquals(sk23,MultiSum.calculateAgreement(ePubKey2,ePrivKey3)); | |||||
assertArrayEquals(sk31,MultiSum.calculateAgreement(ePubKey3,ePrivKey1)); | |||||
BigInteger c1 = MultiSum.encryptBlindedMsg(encKey,value1,s12,s31); | |||||
BigInteger c2 = MultiSum.encryptBlindedMsg(encKey,value2,s23,s12); | |||||
BigInteger c3 = MultiSum.encryptBlindedMsg(encKey,value3,s31,s23); | |||||
byte[] s12 = MultiSum.deriveShares(id1,id2,sk12); | |||||
byte[] s23 = MultiSum.deriveShares(id2,id3,sk23); | |||||
byte[] s31 = MultiSum.deriveShares(id3,id1,sk31); | |||||
BigInteger aggregatedCiphertext = MultiSum.aggregateCiphertexts(encKey,c1,c2,c3); | |||||
assertArrayEquals(s12, MultiSum.deriveShares(id1,id2,sk12)); | |||||
assertArrayEquals(s23, MultiSum.deriveShares(id2,id3,sk23)); | |||||
assertArrayEquals(s31, MultiSum.deriveShares(id3,id1,sk31)); | |||||
BigInteger decryptedValue = MultiSum.decrypt(keyPair,aggregatedCiphertext); | |||||
byte[] c1 = MultiSum.encryptBlindedMsg(encKey,int1,s12,s31); | |||||
byte[] c2 = MultiSum.encryptBlindedMsg(encKey,int2,s23,s12); | |||||
byte[] c3 = MultiSum.encryptBlindedMsg(encKey,int3,s31,s23); | |||||
assertEquals(expectedSum,decryptedValue); | |||||
} | |||||
byte[] aggregatedCiphertext = MultiSum.aggregateCiphertexts(encKey,c1,c2,c3); | |||||
@Test | |||||
public void testResolveEPrivKey(){ | |||||
byte[] decryptedValue = MultiSum.decrypt(decKey,aggregatedCiphertext); | |||||
MultiSum instance = new MultiSum(); | |||||
instance.generateEphemeralKeyPair(); | |||||
ECPrivateKeyParameters expectedEPrivKey = instance.getEPrivKey(); | |||||
byte[] ePrivKeyBytes = instance.getEPrivKeyBytes(); | |||||
ECPrivateKeyParameters ePrivKey = instance.resolveEPrivKey(ePrivKeyBytes); | |||||
assertEquals(expectedEPrivKey.getD(),ePrivKey.getD()); | |||||
assertEquals(sum,byteArrayToInt(decryptedValue)); | |||||
} | } | ||||
@Test | |||||
public void testResolveEPubKey(){ | |||||
MultiSum instance = new MultiSum(); | |||||
instance.generateEphemeralKeyPair(); | |||||
ECPublicKeyParameters expectedEPubKey = instance.getEPubKey(); | |||||
byte[] ePubKeyBytes = instance.getEPubKeyBytes(); | |||||
ECPublicKeyParameters ePubKey = instance.resolveEPubKey(ePubKeyBytes); | |||||
assertEquals(Hex.toHexString(expectedEPubKey.getQ().getAffineXCoord().getEncoded()),Hex.toHexString(ePubKey.getQ().getAffineXCoord().getEncoded())); | |||||
assertEquals(Hex.toHexString(expectedEPubKey.getQ().getAffineYCoord().getEncoded()),Hex.toHexString(ePubKey.getQ().getAffineYCoord().getEncoded())); | |||||
private static int byteArrayToInt(byte[] input) { | |||||
int result; | |||||
int length = input.length; | |||||
byte[] buffer = new byte[4]; | |||||
if (length <= buffer.length){ | |||||
System.arraycopy(input,0,buffer,buffer.length - length,length); | |||||
} else { | |||||
System.arraycopy(input,length - buffer.length,buffer,0, buffer.length); | |||||
} | |||||
result = buffer[3] & 0xFF | | |||||
(buffer[2] & 0xFF) << 8 | | |||||
(buffer[1] & 0xFF) << 16 | | |||||
(buffer[0] & 0xFF) << 24; | |||||
return result; | |||||
} | } | ||||
} | } |
@@ -1,58 +0,0 @@ | |||||
package test.com.jd.blockchain.crypto.paillier; | |||||
import com.jd.blockchain.crypto.paillier.KeyPair; | |||||
import com.jd.blockchain.crypto.paillier.KeyPairBuilder; | |||||
import com.jd.blockchain.crypto.paillier.PublicKey; | |||||
import org.junit.Test; | |||||
import org.junit.runner.RunWith; | |||||
import org.junit.runners.Parameterized; | |||||
import java.math.BigInteger; | |||||
import java.util.Arrays; | |||||
import java.util.Collection; | |||||
import static org.junit.Assert.assertEquals; | |||||
/** | |||||
* Created by kunerd on 22.09.15. | |||||
*/ | |||||
@RunWith(value = Parameterized.class) | |||||
public class DecryptionTest { | |||||
@Parameterized.Parameters | |||||
public static Collection<Object[]> data() { | |||||
return Arrays.asList(createTestParameter(Long.MIN_VALUE), | |||||
createTestParameter(Integer.MIN_VALUE), | |||||
createTestParameter(Short.MIN_VALUE), | |||||
createTestParameter(0), | |||||
createTestParameter(Short.MAX_VALUE), | |||||
createTestParameter(Integer.MAX_VALUE), | |||||
createTestParameter(Long.MAX_VALUE)); | |||||
} | |||||
private BigInteger input; | |||||
private BigInteger expected; | |||||
public DecryptionTest(BigInteger input, BigInteger expected) { | |||||
this.input = input; | |||||
this.expected = expected; | |||||
} | |||||
@Test | |||||
public void test() { | |||||
KeyPair keyPair = new KeyPairBuilder().upperBound(BigInteger.valueOf(Long.MAX_VALUE)) | |||||
.generateKeyPair(); | |||||
PublicKey publicKey = keyPair.getPublicKey(); | |||||
BigInteger encryptedData = publicKey.encrypt(input); | |||||
assertEquals(expected, keyPair.decrypt(encryptedData)); | |||||
} | |||||
private static Object[] createTestParameter(long plaintext) { | |||||
BigInteger p = BigInteger.valueOf(plaintext); | |||||
return new Object[]{p, p}; | |||||
} | |||||
} | |||||
@@ -1,90 +0,0 @@ | |||||
package test.com.jd.blockchain.crypto.paillier; | |||||
import com.jd.blockchain.crypto.paillier.KeyPair; | |||||
import com.jd.blockchain.crypto.paillier.KeyPairBuilder; | |||||
import com.jd.blockchain.crypto.paillier.PublicKey; | |||||
import org.junit.Before; | |||||
import org.junit.Test; | |||||
import java.math.BigInteger; | |||||
import static org.junit.Assert.assertEquals; | |||||
public class HomomorphicPropertiesTest { | |||||
private KeyPair keypair; | |||||
private PublicKey publicKey; | |||||
@Before | |||||
public void init() { | |||||
KeyPairBuilder keygen = new KeyPairBuilder(); | |||||
this.keypair = keygen.generateKeyPair(); | |||||
this.publicKey = keypair.getPublicKey(); | |||||
} | |||||
@Test | |||||
public void testHomomorphicAddition() { | |||||
BigInteger plainA = BigInteger.valueOf(102); | |||||
BigInteger plainB = BigInteger.valueOf(203); | |||||
BigInteger encryptedA = publicKey.encrypt(plainA); | |||||
BigInteger encryptedB = publicKey.encrypt(plainB); | |||||
BigInteger decryptedProduct = keypair.decrypt(encryptedA.multiply( | |||||
encryptedB).mod(publicKey.getnSquared())); | |||||
BigInteger plainSum = plainA.add(plainB).mod(publicKey.getN()); | |||||
assertEquals(decryptedProduct, plainSum); | |||||
} | |||||
@Test | |||||
public void testHomomorphicConstantMultiplication() { | |||||
BigInteger plainA = BigInteger.valueOf(14); | |||||
BigInteger plainB = BigInteger.valueOf(203); | |||||
BigInteger encryptedA = publicKey.encrypt(plainA); | |||||
BigInteger decryptedPow = keypair.decrypt(encryptedA.modPow(plainB, | |||||
publicKey.getnSquared())); | |||||
BigInteger plainSum = plainA.multiply(plainB).mod(publicKey.getN()); | |||||
assertEquals(decryptedPow, plainSum); | |||||
} | |||||
@Test | |||||
public void testHomomorphicMultiplication() { | |||||
BigInteger plainA = BigInteger.valueOf(23); | |||||
BigInteger plainB = BigInteger.valueOf(234); | |||||
BigInteger encryptedA = publicKey.encrypt(plainA); | |||||
BigInteger decryptedPowA = keypair.decrypt(encryptedA.modPow( | |||||
plainB, publicKey.getnSquared())); | |||||
BigInteger plainSumA = plainA.multiply(plainB).mod(publicKey.getN()); | |||||
assertEquals(decryptedPowA, plainSumA); | |||||
BigInteger encryptedB = publicKey.encrypt(plainB); | |||||
BigInteger decryptedPowB = keypair.decrypt(encryptedB.modPow( | |||||
plainA, publicKey.getnSquared())); | |||||
BigInteger plainSumB = plainA.multiply(plainB).mod(publicKey.getN()); | |||||
assertEquals(decryptedPowB, plainSumB); | |||||
assertEquals(decryptedPowA, decryptedPowB); | |||||
} | |||||
@Test | |||||
public void testHomomorphicMultiplicationPowG() { | |||||
BigInteger plainA = BigInteger.valueOf(230); | |||||
BigInteger plainB = BigInteger.valueOf(100); | |||||
BigInteger g = publicKey.getG(); | |||||
BigInteger encryptedA = publicKey.encrypt(plainA); | |||||
BigInteger decryptedPow = keypair.decrypt(encryptedA.multiply(g.modPow( | |||||
plainB, publicKey.getnSquared()).mod(publicKey.getnSquared()))); | |||||
BigInteger plainSumA = plainA.add(plainB).mod(publicKey.getN()); | |||||
assertEquals(decryptedPow, plainSumA); | |||||
} | |||||
} |
@@ -1,43 +0,0 @@ | |||||
package test.com.jd.blockchain.crypto.paillier; | |||||
import com.jd.blockchain.crypto.paillier.KeyPair; | |||||
import com.jd.blockchain.crypto.paillier.KeyPairBuilder; | |||||
import com.jd.blockchain.crypto.paillier.PublicKey; | |||||
import org.junit.Before; | |||||
import org.junit.Test; | |||||
import java.math.BigInteger; | |||||
import static org.junit.Assert.assertEquals; | |||||
import static org.junit.Assert.assertNotEquals; | |||||
public class JPaillierTest { | |||||
private KeyPair keyPair; | |||||
private PublicKey publicKey; | |||||
@Before | |||||
public void init() { | |||||
KeyPairBuilder keygen = new KeyPairBuilder(); | |||||
keyPair = keygen.generateKeyPair(); | |||||
publicKey = keyPair.getPublicKey(); | |||||
} | |||||
@Test | |||||
public void testEncryption() { | |||||
BigInteger plainData = BigInteger.valueOf(10); | |||||
BigInteger encryptedData = publicKey.encrypt(plainData); | |||||
assertNotEquals(plainData, encryptedData); | |||||
} | |||||
@Test | |||||
public void testDecyption() { | |||||
BigInteger plainData = BigInteger.valueOf(10); | |||||
BigInteger encryptedData = publicKey.encrypt(plainData); | |||||
BigInteger decryptedData = keyPair.decrypt(encryptedData); | |||||
assertEquals(plainData, decryptedData); | |||||
} | |||||
} |
@@ -1,44 +0,0 @@ | |||||
package test.com.jd.blockchain.crypto.paillier; | |||||
import com.jd.blockchain.crypto.paillier.KeyPair; | |||||
import com.jd.blockchain.crypto.paillier.KeyPairBuilder; | |||||
import com.jd.blockchain.crypto.paillier.PrivateKey; | |||||
import com.jd.blockchain.crypto.paillier.PublicKey; | |||||
import org.junit.Before; | |||||
import org.junit.Test; | |||||
import java.math.BigInteger; | |||||
import static org.junit.Assert.assertEquals; | |||||
public class KeyPairBuilderPrivateKeyTest { | |||||
private KeyPairBuilder keygen; | |||||
private KeyPair keypair; | |||||
private PrivateKey privateKey; | |||||
@Before | |||||
public void init() { | |||||
this.keygen = new KeyPairBuilder(); | |||||
this.keypair = keygen.generateKeyPair(); | |||||
this.privateKey = keypair.getPrivateKey(); | |||||
} | |||||
@Test | |||||
public void testPreCalculatedDenominator() { | |||||
PublicKey publicKey = keypair.getPublicKey(); | |||||
BigInteger preCalculatedDenominator = privateKey.getPreCalculatedDenominator(); | |||||
BigInteger g = publicKey.getG(); | |||||
BigInteger n = publicKey.getN(); | |||||
BigInteger nSquared = publicKey.getnSquared(); | |||||
BigInteger lambda = privateKey.getLambda(); | |||||
BigInteger expected = g.modPow(lambda, nSquared); | |||||
expected = expected.subtract(BigInteger.ONE); | |||||
expected = expected.divide(n); | |||||
expected = expected.modInverse(n); | |||||
assertEquals(expected, preCalculatedDenominator); | |||||
} | |||||
} |
@@ -1,57 +0,0 @@ | |||||
package test.com.jd.blockchain.crypto.paillier; | |||||
import com.jd.blockchain.crypto.paillier.KeyPair; | |||||
import com.jd.blockchain.crypto.paillier.KeyPairBuilder; | |||||
import com.jd.blockchain.crypto.paillier.PrivateKey; | |||||
import com.jd.blockchain.crypto.paillier.PublicKey; | |||||
import org.junit.Before; | |||||
import org.junit.Test; | |||||
import java.math.BigInteger; | |||||
import static org.junit.Assert.assertEquals; | |||||
public class KeyPairBuilderPublicKeyTest { | |||||
private KeyPair keypair; | |||||
private PublicKey publicKey; | |||||
@Before | |||||
public void init() { | |||||
KeyPairBuilder keygen = new KeyPairBuilder(); | |||||
this.keypair = keygen.generateKeyPair(); | |||||
this.publicKey = keypair.getPublicKey(); | |||||
} | |||||
@Test | |||||
public void testBitsSetup() { | |||||
int BITS = 1024; | |||||
assertEquals(BITS, publicKey.getBits()); | |||||
} | |||||
@Test | |||||
public void testCalculationOfNSquared() { | |||||
BigInteger n = publicKey.getN(); | |||||
BigInteger nSquared = n.multiply(n); | |||||
assertEquals(nSquared, publicKey.getnSquared()); | |||||
} | |||||
@Test | |||||
public void testCalculationOfGOfG() { | |||||
PrivateKey privateKey = keypair.getPrivateKey(); | |||||
BigInteger n = publicKey.getN(); | |||||
BigInteger nSquared = publicKey.getnSquared(); | |||||
BigInteger g = publicKey.getG(); | |||||
BigInteger lambda = privateKey.getLambda(); | |||||
BigInteger l = g.modPow(lambda, nSquared); | |||||
l = l.subtract(BigInteger.ONE); | |||||
l = l.divide(n); | |||||
assertEquals(BigInteger.ONE, l.gcd(n)); | |||||
} | |||||
} |
@@ -1,113 +0,0 @@ | |||||
package test.com.jd.blockchain.crypto.paillier; | |||||
import static org.junit.Assert.assertEquals; | |||||
import java.math.BigInteger; | |||||
import java.security.SecureRandom; | |||||
import java.util.Random; | |||||
import org.junit.Before; | |||||
import org.junit.Test; | |||||
import org.junit.runner.RunWith; | |||||
import org.mockito.Mockito; | |||||
import org.powermock.api.mockito.PowerMockito; | |||||
import org.powermock.core.classloader.annotations.PrepareForTest; | |||||
import org.powermock.modules.junit4.PowerMockRunner; | |||||
import com.jd.blockchain.crypto.paillier.KeyPair; | |||||
import com.jd.blockchain.crypto.paillier.KeyPairBuilder; | |||||
import com.jd.blockchain.crypto.paillier.PrivateKey; | |||||
import com.jd.blockchain.crypto.paillier.PublicKey; | |||||
@RunWith(PowerMockRunner.class) | |||||
@PrepareForTest(KeyPairBuilder.class) | |||||
public class KeyPairBuilderTest { | |||||
private static final int BITS = 128; | |||||
private KeyPairBuilder keygen; | |||||
private PublicKey publicKey; | |||||
private PrivateKey privateKey; | |||||
private BigInteger p = BigInteger.valueOf(5); | |||||
private BigInteger q = BigInteger.valueOf(7); | |||||
private BigInteger g1 = BigInteger.valueOf(35); | |||||
private BigInteger g2 = BigInteger.valueOf(36); | |||||
private Random rng; | |||||
@Before | |||||
public void beforeEach() { | |||||
rng = PowerMockito.mock(SecureRandom.class); | |||||
keygen = new KeyPairBuilder() | |||||
.bits(BITS) | |||||
.randomNumberGenerator(rng); | |||||
PowerMockito.mockStatic(BigInteger.class); | |||||
} | |||||
private void prepareTest() throws Exception { | |||||
PowerMockito.when(BigInteger.probablePrime(BITS / 2, rng)).thenReturn(p, q); | |||||
PowerMockito.whenNew(BigInteger.class).withArguments(BITS, rng).thenReturn(g1, g2); | |||||
KeyPair keypair = keygen.generateKeyPair(); | |||||
publicKey = keypair.getPublicKey(); | |||||
privateKey = keypair.getPrivateKey(); | |||||
} | |||||
@Test | |||||
public void computationOfN() throws Exception { | |||||
prepareTest(); | |||||
BigInteger e = p.multiply(q); | |||||
BigInteger a = publicKey.getN(); | |||||
assertEquals(e, a); | |||||
} | |||||
@Test | |||||
public void computationOfLambda() throws Exception { | |||||
BigInteger e = new BigInteger("12"); | |||||
prepareTest(); | |||||
BigInteger a = privateKey.getLambda(); | |||||
assertEquals(e, a); | |||||
} | |||||
@Test | |||||
public void computationOfG() throws Exception { | |||||
prepareTest(); | |||||
PowerMockito.verifyNew(BigInteger.class, Mockito.times(2)).withArguments(Mockito.eq(128), Mockito.any(Random.class)); | |||||
} | |||||
@Test | |||||
public void withoutCertainty() throws Exception { | |||||
prepareTest(); | |||||
PowerMockito.verifyStatic(Mockito.times(2)); | |||||
BigInteger.probablePrime(BITS / 2, rng); | |||||
} | |||||
@Test | |||||
public void withCertainty() throws Exception { | |||||
int certainty = 6; | |||||
keygen.certainty(certainty); | |||||
PowerMockito.whenNew(BigInteger.class).withArguments(BITS / 2, certainty, rng).thenReturn(p, q); | |||||
prepareTest(); | |||||
PowerMockito.verifyNew(BigInteger.class, Mockito.times(2)).withArguments(BITS / 2, certainty, rng); | |||||
} | |||||
} |
@@ -0,0 +1,202 @@ | |||||
package test.com.jd.blockchain.crypto.paillier; | |||||
import com.jd.blockchain.crypto.paillier.PaillierPrivateKeyParameters; | |||||
import com.jd.blockchain.crypto.paillier.PaillierPublicKeyParameters; | |||||
import com.jd.blockchain.crypto.paillier.PaillierUtils; | |||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair; | |||||
import org.junit.Test; | |||||
import java.math.BigInteger; | |||||
import java.security.SecureRandom; | |||||
import static org.junit.Assert.assertEquals; | |||||
/** | |||||
* @author zhanglin33 | |||||
* @title: PaillierUtilsTest | |||||
* @description: Tests on PaillierUtils | |||||
* @date 2019-04-30, 14:54 | |||||
*/ | |||||
public class PaillierUtilsTest { | |||||
@Test | |||||
public void generateKeyPairTest() { | |||||
AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair(); | |||||
PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic(); | |||||
PaillierPrivateKeyParameters privKeyParams = (PaillierPrivateKeyParameters) keyPair.getPrivate(); | |||||
BigInteger n = pubKeyParams.getModulus(); | |||||
BigInteger nSquared = pubKeyParams.getModulusSquared(); | |||||
BigInteger g = pubKeyParams.getGenerator(); | |||||
BigInteger nConverted = new BigInteger(1, bigIntegerToBytes(n,256)); | |||||
BigInteger nSquaredConverted = new BigInteger(1, bigIntegerToBytes(nSquared,512)); | |||||
BigInteger gConverted = new BigInteger(1, bigIntegerToBytes(g,256)); | |||||
assertEquals(nConverted, n); | |||||
assertEquals(nSquaredConverted, nSquared); | |||||
assertEquals(gConverted, g); | |||||
BigInteger p = privKeyParams.getP(); | |||||
BigInteger pSquared = privKeyParams.getPSquared(); | |||||
BigInteger q = privKeyParams.getQ(); | |||||
BigInteger qSquared = privKeyParams.getQSquared(); | |||||
BigInteger pInverse = privKeyParams.getPInverse(); | |||||
BigInteger muP = privKeyParams.getMuP(); | |||||
BigInteger muQ = privKeyParams.getMuQ(); | |||||
BigInteger pConverted = new BigInteger(1, bigIntegerToBytes(p,128)); | |||||
BigInteger pSquaredConverted = new BigInteger(1, bigIntegerToBytes(pSquared,256)); | |||||
BigInteger qConverted = new BigInteger(1, bigIntegerToBytes(q,128)); | |||||
BigInteger qSquaredConverted = new BigInteger(1, bigIntegerToBytes(qSquared,256)); | |||||
BigInteger pInverseConverted = new BigInteger(1, bigIntegerToBytes(pInverse,128)); | |||||
BigInteger muPConverted = new BigInteger(1, bigIntegerToBytes(muP,128)); | |||||
BigInteger muQConverted = new BigInteger(1, bigIntegerToBytes(muQ,128)); | |||||
assertEquals(pConverted, p); | |||||
assertEquals(pSquaredConverted, pSquared); | |||||
assertEquals(qConverted, q); | |||||
assertEquals(qSquaredConverted, qSquared); | |||||
assertEquals(pInverseConverted, pInverse); | |||||
assertEquals(muPConverted, muP); | |||||
assertEquals(muQConverted, muQ); | |||||
} | |||||
@Test | |||||
public void encryptTest() { | |||||
AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair(); | |||||
PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic(); | |||||
byte[] pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams); | |||||
SecureRandom random = new SecureRandom(); | |||||
byte[] data = new byte[256]; | |||||
random.nextBytes(data); | |||||
byte[] ciphertextFromParams = PaillierUtils.encrypt(data,pubKeyParams); | |||||
byte[] ciphertextFromBytes = PaillierUtils.encrypt(data,pubKeyBytes); | |||||
assertEquals(512,ciphertextFromParams.length); | |||||
assertEquals(512,ciphertextFromBytes.length); | |||||
} | |||||
@Test | |||||
public void decryptTest(){ | |||||
AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair(); | |||||
PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic(); | |||||
PaillierPrivateKeyParameters privKeyParams = (PaillierPrivateKeyParameters) keyPair.getPrivate(); | |||||
byte[] pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams); | |||||
byte[] privKeyBytes = PaillierUtils.privKey2Bytes(privKeyParams); | |||||
int input = 666; | |||||
byte[] data = intToByteArray(input); | |||||
byte[] ciphertextFromParams = PaillierUtils.encrypt(data,pubKeyParams); | |||||
byte[] ciphertextFromBytes = PaillierUtils.encrypt(data,pubKeyBytes); | |||||
byte[] plaintextFromParams = PaillierUtils.decrypt(ciphertextFromBytes,privKeyParams); | |||||
byte[] plaintextFromBytes = PaillierUtils.decrypt(ciphertextFromParams,privKeyBytes); | |||||
int outputFromParams = byteArrayToInt(plaintextFromParams); | |||||
int outputFromBytes = byteArrayToInt(plaintextFromBytes); | |||||
assertEquals(input,outputFromParams); | |||||
assertEquals(input,outputFromBytes); | |||||
} | |||||
@Test | |||||
public void addTest() { | |||||
AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair(); | |||||
PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic(); | |||||
PaillierPrivateKeyParameters privKeyParams = (PaillierPrivateKeyParameters) keyPair.getPrivate(); | |||||
byte[] pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams); | |||||
int input1 = 600; | |||||
int input2 = 60; | |||||
int input3 = 6; | |||||
int sum = 666; | |||||
byte[] data1 = intToByteArray(input1); | |||||
byte[] data2 = intToByteArray(input2); | |||||
byte[] data3 = intToByteArray(input3); | |||||
byte[] ciphertext1 = PaillierUtils.encrypt(data1,pubKeyParams); | |||||
byte[] ciphertext2 = PaillierUtils.encrypt(data2,pubKeyParams); | |||||
byte[] ciphertext3 = PaillierUtils.encrypt(data3,pubKeyParams); | |||||
byte[] aggregatedCiphertext = PaillierUtils.add(pubKeyParams,ciphertext1,ciphertext2,ciphertext3); | |||||
byte[] plaintext = PaillierUtils.decrypt(aggregatedCiphertext,privKeyParams); | |||||
int output = byteArrayToInt(plaintext); | |||||
assertEquals(sum,output); | |||||
aggregatedCiphertext = PaillierUtils.add(pubKeyBytes,ciphertext1,ciphertext2,ciphertext3); | |||||
plaintext = PaillierUtils.decrypt(aggregatedCiphertext,privKeyParams); | |||||
output = byteArrayToInt(plaintext); | |||||
assertEquals(sum,output); | |||||
} | |||||
@Test | |||||
public void scalarMultiplyTest() { | |||||
AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair(); | |||||
PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic(); | |||||
PaillierPrivateKeyParameters privKeyParams = (PaillierPrivateKeyParameters) keyPair.getPrivate(); | |||||
byte[] pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams); | |||||
int input = 111; | |||||
int scalar = 6; | |||||
byte[] data = intToByteArray(input); | |||||
byte[] ciphertext = PaillierUtils.encrypt(data,pubKeyParams); | |||||
byte[] ciphertextPowered = PaillierUtils.scalarMultiply(pubKeyBytes,ciphertext,scalar); | |||||
byte[] plaintextMultiplied = PaillierUtils.decrypt(ciphertextPowered,privKeyParams); | |||||
int output = byteArrayToInt(plaintextMultiplied); | |||||
assertEquals(input * scalar, output); | |||||
} | |||||
private static byte[] intToByteArray(int input) { | |||||
byte[] result = new byte[4]; | |||||
result[0] = (byte) ((input >> 24) & 0xFF); | |||||
result[1] = (byte) ((input >> 16) & 0xFF); | |||||
result[2] = (byte) ((input >> 8 ) & 0xFF); | |||||
result[3] = (byte) ((input ) & 0xFF); | |||||
return result; | |||||
} | |||||
private static int byteArrayToInt(byte[] input) { | |||||
int result; | |||||
int length = input.length; | |||||
byte[] buffer = new byte[4]; | |||||
if (length <= buffer.length){ | |||||
System.arraycopy(input,0,buffer,buffer.length - length,length); | |||||
} else { | |||||
System.arraycopy(input,length - buffer.length,buffer,0, buffer.length); | |||||
} | |||||
result = buffer[3] & 0xFF | | |||||
(buffer[2] & 0xFF) << 8 | | |||||
(buffer[1] & 0xFF) << 16 | | |||||
(buffer[0] & 0xFF) << 24; | |||||
return result; | |||||
} | |||||
// To convert BigInteger to byte array in specified size | |||||
private static byte[] bigIntegerToBytes(BigInteger b, int bytesSize){ | |||||
byte[] tmp = b.toByteArray(); | |||||
byte[] result = new byte[bytesSize]; | |||||
if (tmp.length > result.length) { | |||||
System.arraycopy(tmp, tmp.length - result.length, result, 0, result.length); | |||||
} | |||||
else { | |||||
System.arraycopy(tmp,0,result,result.length-tmp.length,tmp.length); | |||||
} | |||||
return result; | |||||
} | |||||
} |
@@ -1,124 +0,0 @@ | |||||
package test.com.jd.blockchain.crypto.paillier; | |||||
import com.jd.blockchain.crypto.paillier.*; | |||||
import org.junit.Test; | |||||
import java.math.BigInteger; | |||||
import static org.junit.Assert.assertEquals; | |||||
public class ResolveTest { | |||||
@Test | |||||
public void testResolvePrivateKey() { | |||||
KeyPairBuilder keygen = new KeyPairBuilder(); | |||||
KeyPair keyPair = keygen.generateKeyPair(); | |||||
PrivateKey privKey = keyPair.getPrivateKey(); | |||||
BigInteger lambda = privKey.getLambda(); | |||||
BigInteger preCalculatedDenominator = privKey.getPreCalculatedDenominator(); | |||||
byte[] privKeyBytes = privKey.getPrivKeyBytes(); | |||||
byte[] lambdaBytes = privKey.getLambdaBytes(); | |||||
byte[] preCalculatedDenominatorBytes = privKey.getPreCalculatedDenominatorBytes(); | |||||
assertEquals(lambda,new BigInteger(lambdaBytes)); | |||||
assertEquals(preCalculatedDenominator,new BigInteger(preCalculatedDenominatorBytes)); | |||||
assertEquals(lambda,new PrivateKey(lambda,preCalculatedDenominator).getLambda()); | |||||
assertEquals(preCalculatedDenominator,(new PrivateKey(lambda,preCalculatedDenominator)).getPreCalculatedDenominator()); | |||||
assertEquals(lambda,(new PrivateKey(lambdaBytes,preCalculatedDenominatorBytes)).getLambda()); | |||||
assertEquals(preCalculatedDenominator,(new PrivateKey(lambdaBytes,preCalculatedDenominatorBytes)).getPreCalculatedDenominator()); | |||||
assertEquals(lambda,(new PrivateKey(privKeyBytes)).getLambda()); | |||||
assertEquals(preCalculatedDenominator,(new PrivateKey(privKeyBytes)).getPreCalculatedDenominator()); | |||||
} | |||||
@Test | |||||
public void testResolvePublicKey() { | |||||
KeyPairBuilder keygen = new KeyPairBuilder(); | |||||
KeyPair keyPair = keygen.generateKeyPair(); | |||||
PublicKey pubKey = keyPair.getPublicKey(); | |||||
int bits = pubKey.getBits(); | |||||
BigInteger n = pubKey.getN(); | |||||
BigInteger nSquared = pubKey.getnSquared(); | |||||
BigInteger g = pubKey.getG(); | |||||
byte[] pubKeyBytes = pubKey.getPubKeyBytes(); | |||||
byte[] bitsBytes = pubKey.getBitsBytes(); | |||||
byte[] nBytes = pubKey.getNBytes(); | |||||
byte[] nSquaredBytes = pubKey.getNSquaredBytes(); | |||||
byte[] gBytes = pubKey.getGBytes(); | |||||
assertEquals(bits,PaillierUtils.bytesToInt(bitsBytes)); | |||||
assertEquals(n,new BigInteger(nBytes)); | |||||
assertEquals(nSquared,new BigInteger(nSquaredBytes)); | |||||
assertEquals(g,new BigInteger(gBytes)); | |||||
assertEquals(bits,(new PublicKey(n,nSquared,g,bits)).getBits()); | |||||
assertEquals(n,(new PublicKey(n,nSquared,g,bits)).getN()); | |||||
assertEquals(nSquared,(new PublicKey(n,nSquared,g,bits)).getnSquared()); | |||||
assertEquals(g,(new PublicKey(n,nSquared,g,bits)).getG()); | |||||
assertEquals(bits,(new PublicKey(nBytes,nSquaredBytes,gBytes,bitsBytes)).getBits()); | |||||
assertEquals(n,(new PublicKey(nBytes,nSquaredBytes,gBytes,bitsBytes)).getN()); | |||||
assertEquals(nSquared,(new PublicKey(nBytes,nSquaredBytes,gBytes,bitsBytes)).getnSquared()); | |||||
assertEquals(g,(new PublicKey(nBytes,nSquaredBytes,gBytes,bitsBytes)).getG()); | |||||
assertEquals(bits,(new PublicKey(pubKeyBytes)).getBits()); | |||||
assertEquals(n,(new PublicKey(pubKeyBytes)).getN()); | |||||
assertEquals(nSquared,(new PublicKey(pubKeyBytes)).getnSquared()); | |||||
assertEquals(g,(new PublicKey(pubKeyBytes)).getG()); | |||||
} | |||||
@Test | |||||
public void testResolveKeyPair() { | |||||
KeyPairBuilder keygen = new KeyPairBuilder(); | |||||
keygen.upperBound(new BigInteger(PaillierUtils.intToBytes(Integer.MAX_VALUE))); | |||||
KeyPair keyPair = keygen.generateKeyPair(); | |||||
PrivateKey privKey = keyPair.getPrivateKey(); | |||||
PublicKey pubKey = keyPair.getPublicKey(); | |||||
BigInteger upperBound = keyPair.getUpperBound(); | |||||
byte[] keyPairBytes = keyPair.getKeyPairBytes(); | |||||
byte[] privKeyBytes = privKey.getPrivKeyBytes(); | |||||
byte[] pubKeyBytes = pubKey.getPubKeyBytes(); | |||||
byte[] upperBoundBytes = keyPair.getUpperBoundBytes(); | |||||
assertEquals(upperBound,keyPair.getUpperBound()); | |||||
assertEquals(privKey.getLambda(),keyPair.getPrivateKey().getLambda()); | |||||
assertEquals(privKey.getPreCalculatedDenominator(),keyPair.getPrivateKey().getPreCalculatedDenominator()); | |||||
assertEquals(pubKey.getBits(),keyPair.getPublicKey().getBits()); | |||||
assertEquals(pubKey.getN(),keyPair.getPublicKey().getN()); | |||||
assertEquals(pubKey.getnSquared(),keyPair.getPublicKey().getnSquared()); | |||||
assertEquals(pubKey.getG(),keyPair.getPublicKey().getG()); | |||||
assertEquals(upperBound,(new KeyPair(privKey,pubKey,upperBound).getUpperBound())); | |||||
assertEquals(privKey.getLambda(),(new KeyPair(privKey,pubKey,upperBound).getPrivateKey().getLambda())); | |||||
assertEquals(privKey.getPreCalculatedDenominator(),(new KeyPair(privKey,pubKey,upperBound).getPrivateKey().getPreCalculatedDenominator())); | |||||
assertEquals(pubKey.getBits(),(new KeyPair(privKey,pubKey,upperBound).getPublicKey().getBits())); | |||||
assertEquals(pubKey.getN(),(new KeyPair(privKey,pubKey,upperBound).getPublicKey().getN())); | |||||
assertEquals(pubKey.getnSquared(),(new KeyPair(privKey,pubKey,upperBound).getPublicKey().getnSquared())); | |||||
assertEquals(pubKey.getG(),(new KeyPair(privKey,pubKey,upperBound).getPublicKey().getG())); | |||||
assertEquals(upperBound,(new KeyPair(privKeyBytes,pubKeyBytes,upperBoundBytes).getUpperBound())); | |||||
assertEquals(privKey.getLambda(),(new KeyPair(privKeyBytes,pubKeyBytes,upperBoundBytes).getPrivateKey().getLambda())); | |||||
assertEquals(privKey.getPreCalculatedDenominator(),(new KeyPair(privKeyBytes,pubKeyBytes,upperBoundBytes).getPrivateKey().getPreCalculatedDenominator())); | |||||
assertEquals(pubKey.getBits(),(new KeyPair(privKeyBytes,pubKeyBytes,upperBoundBytes).getPublicKey().getBits())); | |||||
assertEquals(pubKey.getN(),(new KeyPair(privKeyBytes,pubKeyBytes,upperBoundBytes).getPublicKey().getN())); | |||||
assertEquals(pubKey.getnSquared(),(new KeyPair(privKeyBytes,pubKeyBytes,upperBoundBytes).getPublicKey().getnSquared())); | |||||
assertEquals(pubKey.getG(),(new KeyPair(privKeyBytes,pubKeyBytes,upperBoundBytes).getPublicKey().getG())); | |||||
assertEquals(upperBound,(new KeyPair(keyPairBytes).getUpperBound())); | |||||
assertEquals(privKey.getLambda(),(new KeyPair(keyPairBytes).getPrivateKey().getLambda())); | |||||
assertEquals(privKey.getPreCalculatedDenominator(),(new KeyPair(keyPairBytes).getPrivateKey().getPreCalculatedDenominator())); | |||||
assertEquals(pubKey.getBits(),(new KeyPair(keyPairBytes).getPublicKey().getBits())); | |||||
assertEquals(pubKey.getN(),(new KeyPair(keyPairBytes).getPublicKey().getN())); | |||||
assertEquals(pubKey.getnSquared(),(new KeyPair(keyPairBytes).getPublicKey().getnSquared())); | |||||
assertEquals(pubKey.getG(),(new KeyPair(keyPairBytes).getPublicKey().getG())); | |||||
} | |||||
} |
@@ -23,13 +23,14 @@ public class ClassicCryptoService implements CryptoService { | |||||
public static final JVMSecureRandomFunction JVM_SECURE_RANDOM = new JVMSecureRandomFunction(); | public static final JVMSecureRandomFunction JVM_SECURE_RANDOM = new JVMSecureRandomFunction(); | ||||
// public static final ECDSASignatureFunction ECDSA = new | |||||
// ECDSASignatureFunction(); | |||||
public static final ECDSASignatureFunction ECDSA = new ECDSASignatureFunction(); | |||||
public static final RSACryptoFunction RSA = new RSACryptoFunction(); | |||||
private static final Collection<CryptoFunction> FUNCTIONS; | private static final Collection<CryptoFunction> FUNCTIONS; | ||||
static { | static { | ||||
List<CryptoFunction> funcs = Arrays.asList(AES, ED25519, RIPEMD160, SHA256, JVM_SECURE_RANDOM); | |||||
List<CryptoFunction> funcs = Arrays.asList(AES, ED25519, ECDSA, RSA, RIPEMD160, SHA256, JVM_SECURE_RANDOM); | |||||
FUNCTIONS = Collections.unmodifiableList(funcs); | FUNCTIONS = Collections.unmodifiableList(funcs); | ||||
} | } | ||||
@@ -1,60 +1,129 @@ | |||||
package com.jd.blockchain.crypto.service.classic; | package com.jd.blockchain.crypto.service.classic; | ||||
import com.jd.blockchain.crypto.CryptoAlgorithm; | |||||
import com.jd.blockchain.crypto.AsymmetricKeypair; | |||||
import com.jd.blockchain.crypto.PrivKey; | |||||
import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.crypto.SignatureDigest; | |||||
import com.jd.blockchain.crypto.SignatureFunction; | |||||
import com.jd.blockchain.crypto.*; | |||||
import com.jd.blockchain.crypto.utils.classic.ECDSAUtils; | |||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair; | |||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters; | |||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters; | |||||
import java.math.BigInteger; | |||||
import static com.jd.blockchain.crypto.BaseCryptoKey.KEY_TYPE_BYTES; | |||||
import static com.jd.blockchain.crypto.CryptoBytes.ALGORYTHM_CODE_SIZE; | |||||
import static com.jd.blockchain.crypto.CryptoKeyType.PRIVATE; | |||||
import static com.jd.blockchain.crypto.CryptoKeyType.PUBLIC; | |||||
public class ECDSASignatureFunction implements SignatureFunction { | public class ECDSASignatureFunction implements SignatureFunction { | ||||
private static final CryptoAlgorithm ECDSA = ClassicAlgorithm.ECDSA; | |||||
private static final int PUBKEY_SIZE = 65; | |||||
private static final int PRIVKEY_SIZE = 32; | |||||
private static final int SIGNATUREDIGEST_SIZE = 64; | |||||
private static final int PUBKEY_LENGTH = ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + PUBKEY_SIZE; | |||||
private static final int PRIVKEY_LENGTH = ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + PRIVKEY_SIZE; | |||||
private static final int SIGNATUREDIGEST_LENGTH = ALGORYTHM_CODE_SIZE + SIGNATUREDIGEST_SIZE; | |||||
ECDSASignatureFunction() { | ECDSASignatureFunction() { | ||||
} | } | ||||
@Override | @Override | ||||
public SignatureDigest sign(PrivKey privKey, byte[] data) { | public SignatureDigest sign(PrivKey privKey, byte[] data) { | ||||
return null; | |||||
byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); | |||||
// 验证原始私钥长度为256比特,即32字节 | |||||
if (rawPrivKeyBytes.length != PRIVKEY_SIZE) { | |||||
throw new CryptoException("This key has wrong format!"); | |||||
} | |||||
// 验证密钥数据的算法标识对应ECDSA签名算法 | |||||
if (privKey.getAlgorithm() != ECDSA.code()) { | |||||
throw new CryptoException("This key is not ECDSA private key!"); | |||||
} | |||||
// 调用ECDSA签名算法计算签名结果 | |||||
return new SignatureDigest(ECDSA, ECDSAUtils.sign(data, rawPrivKeyBytes)); | |||||
} | } | ||||
@Override | @Override | ||||
public boolean verify(SignatureDigest digest, PubKey pubKey, byte[] data) { | public boolean verify(SignatureDigest digest, PubKey pubKey, byte[] data) { | ||||
return false; | |||||
byte[] rawPubKeyBytes = pubKey.getRawKeyBytes(); | |||||
byte[] rawDigestBytes = digest.getRawDigest(); | |||||
// 验证原始公钥长度为256比特,即32字节 | |||||
if (rawPubKeyBytes.length != PUBKEY_SIZE) { | |||||
throw new CryptoException("This key has wrong format!"); | |||||
} | |||||
// 验证密钥数据的算法标识对应ECDSA签名算法 | |||||
if (pubKey.getAlgorithm() != ECDSA.code()) { | |||||
throw new CryptoException("This key is not ECDSA public key!"); | |||||
} | |||||
// 验证签名数据的算法标识对应ECDSA签名算法,并且原始摘要长度为64字节 | |||||
if (digest.getAlgorithm() != ECDSA.code() || rawDigestBytes.length != SIGNATUREDIGEST_SIZE) { | |||||
throw new CryptoException("This is not ECDSA signature digest!"); | |||||
} | |||||
// 调用ECDSA验签算法验证签名结果 | |||||
return ECDSAUtils.verify(data, rawPubKeyBytes, rawDigestBytes); | |||||
} | } | ||||
@Override | @Override | ||||
public PubKey retrievePubKey(PrivKey privKey) { | public PubKey retrievePubKey(PrivKey privKey) { | ||||
return null; | |||||
byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); | |||||
byte[] rawPubKeyBytes = ECDSAUtils.retrievePublicKey(rawPrivKeyBytes); | |||||
return new PubKey(ECDSA, rawPubKeyBytes); | |||||
} | } | ||||
@Override | @Override | ||||
public boolean supportPrivKey(byte[] privKeyBytes) { | public boolean supportPrivKey(byte[] privKeyBytes) { | ||||
return false; | |||||
// 验证输入字节数组长度=算法标识长度+密钥类型长度+密钥长度,密钥数据的算法标识对应ECDSA签名算法,并且密钥类型是私钥 | |||||
return privKeyBytes.length == PRIVKEY_LENGTH && CryptoAlgorithm.match(ECDSA, privKeyBytes) | |||||
&& privKeyBytes[ALGORYTHM_CODE_SIZE] == PRIVATE.CODE; | |||||
} | } | ||||
@Override | @Override | ||||
public PrivKey resolvePrivKey(byte[] privKeyBytes) { | public PrivKey resolvePrivKey(byte[] privKeyBytes) { | ||||
return null; | |||||
if (supportPrivKey(privKeyBytes)) { | |||||
return new PrivKey(privKeyBytes); | |||||
} else { | |||||
throw new CryptoException("privKeyBytes are invalid!"); | |||||
} | |||||
} | } | ||||
@Override | @Override | ||||
public boolean supportPubKey(byte[] pubKeyBytes) { | public boolean supportPubKey(byte[] pubKeyBytes) { | ||||
return false; | |||||
// 验证输入字节数组长度=算法标识长度+密钥类型长度+密钥长度,密钥数据的算法标识对应ECDSA签名算法,并且密钥类型是公钥 | |||||
return pubKeyBytes.length == PUBKEY_LENGTH && CryptoAlgorithm.match(ECDSA, pubKeyBytes) | |||||
&& pubKeyBytes[ALGORYTHM_CODE_SIZE] == PUBLIC.CODE; | |||||
} | } | ||||
@Override | @Override | ||||
public PubKey resolvePubKey(byte[] pubKeyBytes) { | public PubKey resolvePubKey(byte[] pubKeyBytes) { | ||||
return null; | |||||
if (supportPubKey(pubKeyBytes)) { | |||||
return new PubKey(pubKeyBytes); | |||||
} else { | |||||
throw new CryptoException("pubKeyBytes are invalid!"); | |||||
} | |||||
} | } | ||||
@Override | @Override | ||||
public boolean supportDigest(byte[] digestBytes) { | public boolean supportDigest(byte[] digestBytes) { | ||||
return false; | |||||
// 验证输入字节数组长度=算法标识长度+摘要长度,字节数组的算法标识对应ECDSA算法 | |||||
return digestBytes.length == SIGNATUREDIGEST_LENGTH && CryptoAlgorithm.match(ECDSA, digestBytes); | |||||
} | } | ||||
@Override | @Override | ||||
public SignatureDigest resolveDigest(byte[] digestBytes) { | public SignatureDigest resolveDigest(byte[] digestBytes) { | ||||
return null; | |||||
if (supportDigest(digestBytes)) { | |||||
return new SignatureDigest(digestBytes); | |||||
} else { | |||||
throw new CryptoException("digestBytes are invalid!"); | |||||
} | |||||
} | } | ||||
@Override | @Override | ||||
@@ -64,6 +133,28 @@ public class ECDSASignatureFunction implements SignatureFunction { | |||||
@Override | @Override | ||||
public AsymmetricKeypair generateKeypair() { | public AsymmetricKeypair generateKeypair() { | ||||
return null; | |||||
// 调用ECDSA算法的密钥生成算法生成公私钥对priKey和pubKey,返回密钥对 | |||||
AsymmetricCipherKeyPair keyPair = ECDSAUtils.generateKeyPair(); | |||||
ECPrivateKeyParameters privKeyParams = (ECPrivateKeyParameters) keyPair.getPrivate(); | |||||
ECPublicKeyParameters pubKeyParams = (ECPublicKeyParameters) keyPair.getPublic(); | |||||
byte[] privKeyBytes = BigIntegerTo32Bytes(privKeyParams.getD()); | |||||
byte[] pubKeyBytes = pubKeyParams.getQ().getEncoded(false); | |||||
return new AsymmetricKeypair(new PubKey(ECDSA, pubKeyBytes), new PrivKey(ECDSA, privKeyBytes)); | |||||
} | |||||
// To convert BigInteger to byte[] whose length is 32 | |||||
private static byte[] BigIntegerTo32Bytes(BigInteger b){ | |||||
byte[] tmp = b.toByteArray(); | |||||
byte[] result = new byte[32]; | |||||
if (tmp.length > result.length) { | |||||
System.arraycopy(tmp, tmp.length - result.length, result, 0, result.length); | |||||
} | |||||
else { | |||||
System.arraycopy(tmp,0,result,result.length-tmp.length,tmp.length); | |||||
} | |||||
return result; | |||||
} | } | ||||
} | } |
@@ -49,9 +49,7 @@ public class ED25519SignatureFunction implements SignatureFunction { | |||||
} | } | ||||
// 调用ED25519签名算法计算签名结果 | // 调用ED25519签名算法计算签名结果 | ||||
// return new SignatureDigest(ED25519, Ed25519Utils.sign_512(data, rawPrivKeyBytes)); | |||||
return new SignatureDigest(ED25519, ED25519Utils.sign(data, rawPrivKeyBytes)); | return new SignatureDigest(ED25519, ED25519Utils.sign(data, rawPrivKeyBytes)); | ||||
} | } | ||||
@Override | @Override | ||||
@@ -70,13 +68,12 @@ public class ED25519SignatureFunction implements SignatureFunction { | |||||
throw new CryptoException("This key is not ED25519 public key!"); | throw new CryptoException("This key is not ED25519 public key!"); | ||||
} | } | ||||
// 验证密文数据的算法标识对应ED25519签名算法,并且原始摘要长度为64字节 | |||||
// 验证签名数据的算法标识对应ED25519签名算法,并且原始摘要长度为64字节 | |||||
if (digest.getAlgorithm() != ED25519.code() || rawDigestBytes.length != SIGNATUREDIGEST_SIZE) { | if (digest.getAlgorithm() != ED25519.code() || rawDigestBytes.length != SIGNATUREDIGEST_SIZE) { | ||||
throw new CryptoException("This is not ED25519 signature digest!"); | throw new CryptoException("This is not ED25519 signature digest!"); | ||||
} | } | ||||
// 调用ED25519验签算法验证签名结果 | // 调用ED25519验签算法验证签名结果 | ||||
// return Ed25519Utils.verify(data, rawPubKeyBytes, rawDigestBytes); | |||||
return ED25519Utils.verify(data, rawPubKeyBytes, rawDigestBytes); | return ED25519Utils.verify(data, rawPubKeyBytes, rawDigestBytes); | ||||
} | } | ||||
@@ -84,21 +81,8 @@ public class ED25519SignatureFunction implements SignatureFunction { | |||||
public PubKey retrievePubKey(PrivKey privKey) { | public PubKey retrievePubKey(PrivKey privKey) { | ||||
byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); | byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); | ||||
byte[] rawPubKeyBytes = ED25519Utils.retrievePublicKey(rawPrivKeyBytes); | byte[] rawPubKeyBytes = ED25519Utils.retrievePublicKey(rawPrivKeyBytes); | ||||
// EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512); | |||||
// EdDSAPrivateKeySpec privateKeySpec = new EdDSAPrivateKeySpec(rawPrivKeyBytes, spec); | |||||
// byte[] rawPubKeyBytes = privateKeySpec.getA().toByteArray(); | |||||
return new PubKey(ED25519, rawPubKeyBytes); | return new PubKey(ED25519, rawPubKeyBytes); | ||||
} | } | ||||
// | |||||
// @Override | |||||
// public byte[] retrievePubKey(byte[] privKeyBytes) { | |||||
// | |||||
// byte[] rawPrivKeyBytes = resolvePrivKey(privKeyBytes).getRawKeyBytes(); | |||||
// EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512); | |||||
// EdDSAPrivateKeySpec privateKeySpec = new EdDSAPrivateKeySpec(rawPrivKeyBytes, spec); | |||||
// byte[] rawPubKeyBytes = privateKeySpec.getA().toByteArray(); | |||||
// return new PubKey(ED25519, rawPubKeyBytes).toBytes(); | |||||
// } | |||||
@Override | @Override | ||||
public boolean supportPrivKey(byte[] privKeyBytes) { | public boolean supportPrivKey(byte[] privKeyBytes) { | ||||
@@ -112,7 +96,7 @@ public class ED25519SignatureFunction implements SignatureFunction { | |||||
if (supportPrivKey(privKeyBytes)) { | if (supportPrivKey(privKeyBytes)) { | ||||
return new PrivKey(privKeyBytes); | return new PrivKey(privKeyBytes); | ||||
} else { | } else { | ||||
throw new CryptoException("privKeyBytes is invalid!"); | |||||
throw new CryptoException("privKeyBytes are invalid!"); | |||||
} | } | ||||
} | } | ||||
@@ -121,7 +105,6 @@ public class ED25519SignatureFunction implements SignatureFunction { | |||||
// 验证输入字节数组长度=算法标识长度+密钥类型长度+密钥长度,密钥数据的算法标识对应ED25519签名算法,并且密钥类型是公钥 | // 验证输入字节数组长度=算法标识长度+密钥类型长度+密钥长度,密钥数据的算法标识对应ED25519签名算法,并且密钥类型是公钥 | ||||
return pubKeyBytes.length == PUBKEY_LENGTH && CryptoAlgorithm.match(ED25519, pubKeyBytes) | return pubKeyBytes.length == PUBKEY_LENGTH && CryptoAlgorithm.match(ED25519, pubKeyBytes) | ||||
&& pubKeyBytes[ALGORYTHM_CODE_SIZE] == PUBLIC.CODE; | && pubKeyBytes[ALGORYTHM_CODE_SIZE] == PUBLIC.CODE; | ||||
} | } | ||||
@Override | @Override | ||||
@@ -129,7 +112,7 @@ public class ED25519SignatureFunction implements SignatureFunction { | |||||
if (supportPubKey(pubKeyBytes)) { | if (supportPubKey(pubKeyBytes)) { | ||||
return new PubKey(pubKeyBytes); | return new PubKey(pubKeyBytes); | ||||
} else { | } else { | ||||
throw new CryptoException("pubKeyBytes is invalid!"); | |||||
throw new CryptoException("pubKeyBytes are invalid!"); | |||||
} | } | ||||
} | } | ||||
@@ -144,7 +127,7 @@ public class ED25519SignatureFunction implements SignatureFunction { | |||||
if (supportDigest(digestBytes)) { | if (supportDigest(digestBytes)) { | ||||
return new SignatureDigest(digestBytes); | return new SignatureDigest(digestBytes); | ||||
} else { | } else { | ||||
throw new CryptoException("digestBytes is invalid!"); | |||||
throw new CryptoException("digestBytes are invalid!"); | |||||
} | } | ||||
} | } | ||||
@@ -155,6 +138,7 @@ public class ED25519SignatureFunction implements SignatureFunction { | |||||
@Override | @Override | ||||
public AsymmetricKeypair generateKeypair() { | public AsymmetricKeypair generateKeypair() { | ||||
// 调用ED25519算法的密钥生成算法生成公私钥对priKey和pubKey,返回密钥对 | // 调用ED25519算法的密钥生成算法生成公私钥对priKey和pubKey,返回密钥对 | ||||
AsymmetricCipherKeyPair keyPair = ED25519Utils.generateKeyPair(); | AsymmetricCipherKeyPair keyPair = ED25519Utils.generateKeyPair(); | ||||
Ed25519PrivateKeyParameters privKeyParams = (Ed25519PrivateKeyParameters) keyPair.getPrivate(); | Ed25519PrivateKeyParameters privKeyParams = (Ed25519PrivateKeyParameters) keyPair.getPrivate(); | ||||
@@ -162,12 +146,6 @@ public class ED25519SignatureFunction implements SignatureFunction { | |||||
byte[] privKeyBytes = privKeyParams.getEncoded(); | byte[] privKeyBytes = privKeyParams.getEncoded(); | ||||
byte[] pubKeyBytes = pubKeyParams.getEncoded(); | byte[] pubKeyBytes = pubKeyParams.getEncoded(); | ||||
// KeyPairGenerator keyPairGenerator = new KeyPairGenerator(); | |||||
// KeyPair keyPair = keyPairGenerator.generateKeyPair(); | |||||
// EdDSAPrivateKey privKey = (EdDSAPrivateKey) keyPair.getPrivate(); | |||||
// EdDSAPublicKey pubKey = (EdDSAPublicKey) keyPair.getPublic(); | |||||
// return new CryptoKeyPair(new PubKey(ED25519, pubKey.getAbyte()), new PrivKey(ED25519, privKey.getSeed())); | |||||
return new AsymmetricKeypair(new PubKey(ED25519, pubKeyBytes), new PrivKey(ED25519, privKeyBytes)); | return new AsymmetricKeypair(new PubKey(ED25519, pubKeyBytes), new PrivKey(ED25519, privKeyBytes)); | ||||
} | } | ||||
} | } |
@@ -9,6 +9,7 @@ import com.jd.blockchain.crypto.CryptoBytes; | |||||
import com.jd.blockchain.crypto.CryptoException; | import com.jd.blockchain.crypto.CryptoException; | ||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.crypto.HashFunction; | import com.jd.blockchain.crypto.HashFunction; | ||||
import com.jd.blockchain.crypto.utils.classic.RIPEMD160Utils; | |||||
import com.jd.blockchain.utils.security.RipeMD160Utils; | import com.jd.blockchain.utils.security.RipeMD160Utils; | ||||
public class RIPEMD160HashFunction implements HashFunction { | public class RIPEMD160HashFunction implements HashFunction { | ||||
@@ -34,7 +35,7 @@ public class RIPEMD160HashFunction implements HashFunction { | |||||
throw new CryptoException("data is null!"); | throw new CryptoException("data is null!"); | ||||
} | } | ||||
byte[] digestBytes = RipeMD160Utils.hash(data); | |||||
byte[] digestBytes = RIPEMD160Utils.hash(data); | |||||
return new HashDigest(RIPEMD160, digestBytes); | return new HashDigest(RIPEMD160, digestBytes); | ||||
} | } | ||||
@@ -1,14 +1,15 @@ | |||||
package com.jd.blockchain.crypto.service.classic; | package com.jd.blockchain.crypto.service.classic; | ||||
import com.jd.blockchain.crypto.AsymmetricCiphertext; | |||||
import com.jd.blockchain.crypto.AsymmetricEncryptionFunction; | |||||
import com.jd.blockchain.crypto.Ciphertext; | |||||
import com.jd.blockchain.crypto.CryptoAlgorithm; | |||||
import com.jd.blockchain.crypto.AsymmetricKeypair; | |||||
import com.jd.blockchain.crypto.PrivKey; | |||||
import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.crypto.SignatureDigest; | |||||
import com.jd.blockchain.crypto.SignatureFunction; | |||||
import com.jd.blockchain.crypto.*; | |||||
import com.jd.blockchain.crypto.utils.classic.RSAUtils; | |||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair; | |||||
import org.bouncycastle.crypto.params.RSAKeyParameters; | |||||
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; | |||||
import static com.jd.blockchain.crypto.BaseCryptoKey.KEY_TYPE_BYTES; | |||||
import static com.jd.blockchain.crypto.CryptoBytes.ALGORYTHM_CODE_SIZE; | |||||
import static com.jd.blockchain.crypto.CryptoKeyType.PRIVATE; | |||||
import static com.jd.blockchain.crypto.CryptoKeyType.PUBLIC; | |||||
/** | /** | ||||
* @author zhanglin33 | * @author zhanglin33 | ||||
@@ -17,78 +18,195 @@ import com.jd.blockchain.crypto.SignatureFunction; | |||||
* @date 2019-03-25, 17:28 | * @date 2019-03-25, 17:28 | ||||
*/ | */ | ||||
public class RSACryptoFunction implements AsymmetricEncryptionFunction, SignatureFunction { | public class RSACryptoFunction implements AsymmetricEncryptionFunction, SignatureFunction { | ||||
private static final CryptoAlgorithm RSA = ClassicAlgorithm.RSA; | |||||
// modulus.length = 256, publicExponent.length = 1 | |||||
private static final int PUBKEY_SIZE = 257; | |||||
// modulus.length = 256, publicExponent.length = 1, privateExponent.length = 256, p.length = 128, q.length =128, | |||||
// dP.length = 128, dQ.length = 128, qInv.length = 128 | |||||
private static final int PRIVKEY_SIZE = 1153; | |||||
private static final int SIGNATUREDIGEST_SIZE = 256; | |||||
private static final int CIPHERTEXTBLOCK_SIZE = 256; | |||||
private static final int PUBKEY_LENGTH = ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + PUBKEY_SIZE; | |||||
private static final int PRIVKEY_LENGTH = ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + PRIVKEY_SIZE; | |||||
private static final int SIGNATUREDIGEST_LENGTH = ALGORYTHM_CODE_SIZE + SIGNATUREDIGEST_SIZE; | |||||
@Override | @Override | ||||
public Ciphertext encrypt(PubKey pubKey, byte[] data) { | public Ciphertext encrypt(PubKey pubKey, byte[] data) { | ||||
return null; | |||||
byte[] rawPubKeyBytes = pubKey.getRawKeyBytes(); | |||||
// 验证原始公钥长度为257字节 | |||||
if (rawPubKeyBytes.length != PUBKEY_SIZE) { | |||||
throw new CryptoException("This key has wrong format!"); | |||||
} | |||||
// 验证密钥数据的算法标识对应RSA算法 | |||||
if (pubKey.getAlgorithm() != RSA.code()) { | |||||
throw new CryptoException("The is not RSA public key!"); | |||||
} | |||||
// 调用RSA加密算法计算密文 | |||||
return new AsymmetricCiphertext(RSA, RSAUtils.encrypt(data, rawPubKeyBytes)); | |||||
} | } | ||||
@Override | @Override | ||||
public byte[] decrypt(PrivKey privKey, Ciphertext ciphertext) { | public byte[] decrypt(PrivKey privKey, Ciphertext ciphertext) { | ||||
return new byte[0]; | |||||
byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); | |||||
byte[] rawCiphertextBytes = ciphertext.getRawCiphertext(); | |||||
// 验证原始私钥长度为1153字节 | |||||
if (rawPrivKeyBytes.length != PRIVKEY_SIZE) { | |||||
throw new CryptoException("This key has wrong format!"); | |||||
} | |||||
// 验证密钥数据的算法标识对应RSA算法 | |||||
if (privKey.getAlgorithm() != RSA.code()) { | |||||
throw new CryptoException("This key is not RSA private key!"); | |||||
} | |||||
// 验证密文数据的算法标识对应RSA算法,并且密文是分组长度的整数倍 | |||||
if (ciphertext.getAlgorithm() != RSA.code() | |||||
|| rawCiphertextBytes.length % CIPHERTEXTBLOCK_SIZE != 0) { | |||||
throw new CryptoException("This is not RSA ciphertext!"); | |||||
} | |||||
// 调用RSA解密算法得到明文结果 | |||||
return RSAUtils.decrypt(rawCiphertextBytes, rawPrivKeyBytes); | |||||
} | } | ||||
@Override | @Override | ||||
public PubKey retrievePubKey(PrivKey privKey) { | public PubKey retrievePubKey(PrivKey privKey) { | ||||
return null; | |||||
byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); | |||||
byte[] rawPubKeyBytes = RSAUtils.retrievePublicKey(rawPrivKeyBytes); | |||||
return new PubKey(RSA, rawPubKeyBytes); | |||||
} | } | ||||
@Override | @Override | ||||
public SignatureDigest sign(PrivKey privKey, byte[] data) { | public SignatureDigest sign(PrivKey privKey, byte[] data) { | ||||
return null; | |||||
byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); | |||||
// 验证原始私钥长度为1153字节 | |||||
if (rawPrivKeyBytes.length != PRIVKEY_SIZE) { | |||||
throw new CryptoException("This key has wrong format!"); | |||||
} | |||||
// 验证密钥数据的算法标识对应RSA签名算法 | |||||
if (privKey.getAlgorithm() != RSA.code()) { | |||||
throw new CryptoException("This key is not RSA private key!"); | |||||
} | |||||
// 调用RSA签名算法计算签名结果 | |||||
return new SignatureDigest(RSA, RSAUtils.sign(data, rawPrivKeyBytes)); | |||||
} | } | ||||
@Override | @Override | ||||
public boolean verify(SignatureDigest digest, PubKey pubKey, byte[] data) { | public boolean verify(SignatureDigest digest, PubKey pubKey, byte[] data) { | ||||
return false; | |||||
byte[] rawPubKeyBytes = pubKey.getRawKeyBytes(); | |||||
byte[] rawDigestBytes = digest.getRawDigest(); | |||||
// 验证原始公钥长度为257字节 | |||||
if (rawPubKeyBytes.length != PUBKEY_SIZE) { | |||||
throw new CryptoException("This key has wrong format!"); | |||||
} | |||||
// 验证密钥数据的算法标识对应RSA签名算法 | |||||
if (pubKey.getAlgorithm() != RSA.code()) { | |||||
throw new CryptoException("This key is not RSA public key!"); | |||||
} | |||||
// 验证签名数据的算法标识对应RSA签名算法,并且原始签名长度为256字节 | |||||
if (digest.getAlgorithm() != RSA.code() || rawDigestBytes.length != SIGNATUREDIGEST_SIZE) { | |||||
throw new CryptoException("This is not RSA signature digest!"); | |||||
} | |||||
// 调用RSA验签算法验证签名结果 | |||||
return RSAUtils.verify(data, rawPubKeyBytes, rawDigestBytes); | |||||
} | } | ||||
@Override | @Override | ||||
public boolean supportPrivKey(byte[] privKeyBytes) { | public boolean supportPrivKey(byte[] privKeyBytes) { | ||||
return false; | |||||
// 验证输入字节数组长度=算法标识长度+密钥类型长度+密钥长度,密钥数据的算法标识对应RSA算法,并且密钥类型是私钥 | |||||
return privKeyBytes.length == PRIVKEY_LENGTH && CryptoAlgorithm.match(RSA, privKeyBytes) | |||||
&& privKeyBytes[ALGORYTHM_CODE_SIZE] == PRIVATE.CODE; | |||||
} | } | ||||
@Override | @Override | ||||
public PrivKey resolvePrivKey(byte[] privKeyBytes) { | public PrivKey resolvePrivKey(byte[] privKeyBytes) { | ||||
return null; | |||||
if (supportPrivKey(privKeyBytes)) { | |||||
return new PrivKey(privKeyBytes); | |||||
} else { | |||||
throw new CryptoException("privKeyBytes are invalid!"); | |||||
} | |||||
} | } | ||||
@Override | @Override | ||||
public boolean supportPubKey(byte[] pubKeyBytes) { | public boolean supportPubKey(byte[] pubKeyBytes) { | ||||
return false; | |||||
// 验证输入字节数组长度=算法标识长度+密钥类型长度+椭圆曲线点长度,密钥数据的算法标识对应RSA算法,并且密钥类型是公钥 | |||||
return pubKeyBytes.length == PUBKEY_LENGTH && CryptoAlgorithm.match(RSA, pubKeyBytes) | |||||
&& pubKeyBytes[ALGORYTHM_CODE_SIZE] == PUBLIC.CODE; | |||||
} | } | ||||
@Override | @Override | ||||
public PubKey resolvePubKey(byte[] pubKeyBytes) { | public PubKey resolvePubKey(byte[] pubKeyBytes) { | ||||
return null; | |||||
if (supportPubKey(pubKeyBytes)) { | |||||
return new PubKey(pubKeyBytes); | |||||
} else { | |||||
throw new CryptoException("pubKeyBytes are invalid!"); | |||||
} | |||||
} | } | ||||
@Override | @Override | ||||
public boolean supportDigest(byte[] digestBytes) { | public boolean supportDigest(byte[] digestBytes) { | ||||
return false; | |||||
// 验证输入字节数组长度=算法标识长度+签名长度,字节数组的算法标识对应RSA算法 | |||||
return digestBytes.length == SIGNATUREDIGEST_LENGTH && CryptoAlgorithm.match(RSA, digestBytes); | |||||
} | } | ||||
@Override | @Override | ||||
public SignatureDigest resolveDigest(byte[] digestBytes) { | public SignatureDigest resolveDigest(byte[] digestBytes) { | ||||
return null; | |||||
if (supportDigest(digestBytes)) { | |||||
return new SignatureDigest(digestBytes); | |||||
} else { | |||||
throw new CryptoException("digestBytes are invalid!"); | |||||
} | |||||
} | } | ||||
@Override | @Override | ||||
public boolean supportCiphertext(byte[] ciphertextBytes) { | public boolean supportCiphertext(byte[] ciphertextBytes) { | ||||
return false; | |||||
// 验证输入字节数组长度=密文分组的整数倍,字节数组的算法标识对应RSA算法 | |||||
return (ciphertextBytes.length % CIPHERTEXTBLOCK_SIZE == ALGORYTHM_CODE_SIZE) | |||||
&& CryptoAlgorithm.match(RSA, ciphertextBytes); | |||||
} | } | ||||
@Override | @Override | ||||
public AsymmetricCiphertext resolveCiphertext(byte[] ciphertextBytes) { | public AsymmetricCiphertext resolveCiphertext(byte[] ciphertextBytes) { | ||||
return null; | |||||
if (supportCiphertext(ciphertextBytes)) { | |||||
return new AsymmetricCiphertext(ciphertextBytes); | |||||
} else { | |||||
throw new CryptoException("ciphertextBytes are invalid!"); | |||||
} | |||||
} | } | ||||
@Override | @Override | ||||
public CryptoAlgorithm getAlgorithm() { | public CryptoAlgorithm getAlgorithm() { | ||||
return null; | |||||
return RSA; | |||||
} | } | ||||
@Override | @Override | ||||
public AsymmetricKeypair generateKeypair() { | public AsymmetricKeypair generateKeypair() { | ||||
return null; | |||||
AsymmetricCipherKeyPair keyPair = RSAUtils.generateKeyPair(); | |||||
RSAKeyParameters pubKey = (RSAKeyParameters) keyPair.getPublic(); | |||||
RSAPrivateCrtKeyParameters privKey = (RSAPrivateCrtKeyParameters) keyPair.getPrivate(); | |||||
byte[] pubKeyBytes = RSAUtils.pubKey2Bytes_RawKey(pubKey); | |||||
byte[] privKeyBytes = RSAUtils.privKey2Bytes_RawKey(privKey); | |||||
return new AsymmetricKeypair(new PubKey(RSA, pubKeyBytes), new PrivKey(RSA, privKeyBytes)); | |||||
} | } | ||||
} | } |
@@ -9,6 +9,7 @@ import com.jd.blockchain.crypto.CryptoBytes; | |||||
import com.jd.blockchain.crypto.CryptoException; | import com.jd.blockchain.crypto.CryptoException; | ||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.crypto.HashFunction; | import com.jd.blockchain.crypto.HashFunction; | ||||
import com.jd.blockchain.crypto.utils.classic.SHA256Utils; | |||||
import com.jd.blockchain.utils.security.ShaUtils; | import com.jd.blockchain.utils.security.ShaUtils; | ||||
public class SHA256HashFunction implements HashFunction { | public class SHA256HashFunction implements HashFunction { | ||||
@@ -34,7 +35,7 @@ public class SHA256HashFunction implements HashFunction { | |||||
throw new CryptoException("data is null!"); | throw new CryptoException("data is null!"); | ||||
} | } | ||||
byte[] digestBytes = ShaUtils.hash_256(data); | |||||
byte[] digestBytes = SHA256Utils.hash(data); | |||||
return new HashDigest(SHA256, digestBytes); | return new HashDigest(SHA256, digestBytes); | ||||
} | } | ||||
@@ -0,0 +1,170 @@ | |||||
package com.jd.blockchain.crypto.utils.classic; | |||||
import com.jd.blockchain.crypto.CryptoException; | |||||
import org.bouncycastle.crypto.CipherKeyGenerator; | |||||
import org.bouncycastle.crypto.KeyGenerationParameters; | |||||
import org.bouncycastle.crypto.engines.AESEngine; | |||||
import org.bouncycastle.crypto.modes.CBCBlockCipher; | |||||
import org.bouncycastle.crypto.paddings.PKCS7Padding; | |||||
import org.bouncycastle.crypto.params.KeyParameter; | |||||
import org.bouncycastle.crypto.params.ParametersWithIV; | |||||
import java.security.SecureRandom; | |||||
import java.util.Arrays; | |||||
/** | |||||
* @author zhanglin33 | |||||
* @title: AESUtils | |||||
* @description: AES128/CBC/PKCS7Padding symmetric encryption algorithm | |||||
* @date 2019-04-22, 09:37 | |||||
*/ | |||||
public class AESUtils { | |||||
// AES128 supports 128-bit(16 bytes) secret key | |||||
private static final int KEY_SIZE = 128 / 8; | |||||
// One block contains 16 bytes | |||||
private static final int BLOCK_SIZE = 16; | |||||
// Initial vector's size is 16 bytes | |||||
private static final int IV_SIZE = 16; | |||||
/** | |||||
* key generation | |||||
* | |||||
* @return secret key | |||||
*/ | |||||
public static byte[] generateKey(){ | |||||
CipherKeyGenerator keyGenerator = new CipherKeyGenerator(); | |||||
// To provide secure randomness and key length as input | |||||
// to prepare generate private key | |||||
keyGenerator.init(new KeyGenerationParameters(new SecureRandom(), KEY_SIZE * 8)); | |||||
// To generate key | |||||
return keyGenerator.generateKey(); | |||||
} | |||||
public static byte[] generateKey(byte[] seed){ | |||||
byte[] hash = SHA256Utils.hash(seed); | |||||
return Arrays.copyOf(hash, KEY_SIZE); | |||||
} | |||||
/** | |||||
* encryption | |||||
* | |||||
* @param plainBytes plaintext | |||||
* @param secretKey symmetric key | |||||
* @param iv initial vector | |||||
* @return ciphertext | |||||
*/ | |||||
public static byte[] encrypt(byte[] plainBytes, byte[] secretKey, byte[] iv){ | |||||
// To ensure that plaintext is not null | |||||
if (plainBytes == null) | |||||
{ | |||||
throw new CryptoException("plaintext is null!"); | |||||
} | |||||
if (secretKey.length != KEY_SIZE) | |||||
{ | |||||
throw new CryptoException("secretKey's length is wrong!"); | |||||
} | |||||
if (iv.length != IV_SIZE) | |||||
{ | |||||
throw new CryptoException("iv's length is wrong!"); | |||||
} | |||||
// To get the value padded into input | |||||
int padding = 16 - plainBytes.length % BLOCK_SIZE; | |||||
// The plaintext with padding value | |||||
byte[] plainBytesWithPadding = new byte[plainBytes.length + padding]; | |||||
System.arraycopy(plainBytes,0,plainBytesWithPadding,0,plainBytes.length); | |||||
// The padder adds PKCS7 padding to the input, which makes its length to | |||||
// become an integral multiple of 16 bytes | |||||
PKCS7Padding padder = new PKCS7Padding(); | |||||
// To add padding | |||||
padder.addPadding(plainBytesWithPadding, plainBytes.length); | |||||
CBCBlockCipher encryptor = new CBCBlockCipher(new AESEngine()); | |||||
// To provide key and initialisation vector as input | |||||
encryptor.init(true,new ParametersWithIV(new KeyParameter(secretKey),iv)); | |||||
byte[] output = new byte[plainBytesWithPadding.length + IV_SIZE]; | |||||
// To encrypt the input_p in CBC mode | |||||
for(int i = 0 ; i < plainBytesWithPadding.length/BLOCK_SIZE; i++) { | |||||
encryptor.processBlock(plainBytesWithPadding, i * BLOCK_SIZE, output, (i + 1) * BLOCK_SIZE); | |||||
} | |||||
// The IV locates on the first block of ciphertext | |||||
System.arraycopy(iv,0,output,0,BLOCK_SIZE); | |||||
return output; | |||||
} | |||||
public static byte[] encrypt(byte[] plainBytes, byte[] secretKey){ | |||||
byte[] iv = new byte[IV_SIZE]; | |||||
SecureRandom random = new SecureRandom(); | |||||
random.nextBytes(iv); | |||||
return encrypt(plainBytes,secretKey,iv); | |||||
} | |||||
/** | |||||
* decryption | |||||
* | |||||
* @param cipherBytes ciphertext | |||||
* @param secretKey symmetric key | |||||
* @return plaintext | |||||
*/ | |||||
public static byte[] decrypt(byte[] cipherBytes, byte[] secretKey){ | |||||
// To ensure that the ciphertext is not null | |||||
if (cipherBytes == null) | |||||
{ | |||||
throw new CryptoException("ciphertext is null!"); | |||||
} | |||||
// To ensure that the ciphertext's length is integral multiples of 16 bytes | |||||
if (cipherBytes.length % BLOCK_SIZE != 0) | |||||
{ | |||||
throw new CryptoException("ciphertext's length is wrong!"); | |||||
} | |||||
if (secretKey.length != KEY_SIZE) | |||||
{ | |||||
throw new CryptoException("secretKey's length is wrong!"); | |||||
} | |||||
byte[] iv = new byte[IV_SIZE]; | |||||
System.arraycopy(cipherBytes,0,iv,0,BLOCK_SIZE); | |||||
CBCBlockCipher decryptor = new CBCBlockCipher(new AESEngine()); | |||||
// To prepare the decryption | |||||
decryptor.init(false,new ParametersWithIV(new KeyParameter(secretKey),iv)); | |||||
byte[] outputWithPadding = new byte[cipherBytes.length-BLOCK_SIZE]; | |||||
// To decrypt the input in CBC mode | |||||
for(int i = 1 ; i < cipherBytes.length/BLOCK_SIZE ; i++) { | |||||
decryptor.processBlock(cipherBytes, i * BLOCK_SIZE, outputWithPadding, (i - 1) * BLOCK_SIZE); | |||||
} | |||||
int p = outputWithPadding[outputWithPadding.length-1]; | |||||
// To ensure that the padding of output_p is valid | |||||
if(p > BLOCK_SIZE || p < 0x01) | |||||
{ | |||||
throw new CryptoException("There no exists such padding!"); | |||||
} | |||||
for(int i = 0 ; i < p ; i++) | |||||
{ | |||||
if(outputWithPadding[outputWithPadding.length - i -1] != p) | |||||
{ | |||||
throw new CryptoException("Padding is invalid!"); | |||||
} | |||||
} | |||||
// To remove the padding from output and obtain plaintext | |||||
byte[] output = new byte[outputWithPadding.length - p]; | |||||
System.arraycopy(outputWithPadding, 0, output, 0, output.length); | |||||
return output; | |||||
} | |||||
} |
@@ -89,10 +89,10 @@ public class ECDSAUtils { | |||||
return sign(data,params); | return sign(data,params); | ||||
} | } | ||||
public static byte[] sign(byte[] data, byte[] privateKey, SecureRandom random, String ID){ | |||||
public static byte[] sign(byte[] data, byte[] privateKey, SecureRandom random){ | |||||
ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(new BigInteger(1,privateKey), DOMAIN_PARAMS); | ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(new BigInteger(1,privateKey), DOMAIN_PARAMS); | ||||
CipherParameters params = new ParametersWithID(new ParametersWithRandom(privKey,random),ID.getBytes()); | |||||
CipherParameters params = new ParametersWithRandom(privKey,random); | |||||
return sign(data,params); | return sign(data,params); | ||||
} | } | ||||
@@ -100,16 +100,14 @@ public class ECDSAUtils { | |||||
public static byte[] sign(byte[] data, CipherParameters params){ | public static byte[] sign(byte[] data, CipherParameters params){ | ||||
byte[] hashedMsg = SHA256Utils.hash(data); | byte[] hashedMsg = SHA256Utils.hash(data); | ||||
return sign(params,hashedMsg); | |||||
} | |||||
public static byte[] sign(CipherParameters params, byte[] hashedMsg){ | |||||
ECDSASigner signer = new ECDSASigner(); | ECDSASigner signer = new ECDSASigner(); | ||||
signer.init(true, params); | signer.init(true, params); | ||||
BigInteger[] signature = signer.generateSignature(hashedMsg); | BigInteger[] signature = signer.generateSignature(hashedMsg); | ||||
// // To decode the signature | |||||
// ASN1Sequence sig = ASN1Sequence.getInstance(encodedSignature); | |||||
// byte[] rBytes = BigIntegerTo32Bytes(ASN1Integer.getInstance(sig.getObjectAt(0)).getValue()); | |||||
// byte[] sBytes = BigIntegerTo32Bytes(ASN1Integer.getInstance(sig.getObjectAt(1)).getValue()); | |||||
byte[] rBytes = BigIntegerTo32Bytes(signature[0]); | byte[] rBytes = BigIntegerTo32Bytes(signature[0]); | ||||
byte[] sBytes = BigIntegerTo32Bytes(signature[1]); | byte[] sBytes = BigIntegerTo32Bytes(signature[1]); | ||||
@@ -120,6 +118,7 @@ public class ECDSAUtils { | |||||
return result; | return result; | ||||
} | } | ||||
/** | /** | ||||
* verification | * verification | ||||
* | * | ||||
@@ -139,6 +138,10 @@ public class ECDSAUtils { | |||||
public static boolean verify(byte[] data, CipherParameters params, byte[] signature){ | public static boolean verify(byte[] data, CipherParameters params, byte[] signature){ | ||||
byte[] hashedMsg = SHA256Utils.hash(data); | byte[] hashedMsg = SHA256Utils.hash(data); | ||||
return verify(params,signature,hashedMsg); | |||||
} | |||||
public static boolean verify(CipherParameters params, byte[] signature, byte[] hashedMsg){ | |||||
byte[] rBytes = new byte[R_SIZE]; | byte[] rBytes = new byte[R_SIZE]; | ||||
byte[] sBytes = new byte[S_SIZE]; | byte[] sBytes = new byte[S_SIZE]; | ||||
@@ -153,7 +156,6 @@ public class ECDSAUtils { | |||||
return verifier.verifySignature(hashedMsg,r,s); | return verifier.verifySignature(hashedMsg,r,s); | ||||
} | } | ||||
// To convert BigInteger to byte[] whose length is 32 | // To convert BigInteger to byte[] whose length is 32 | ||||
private static byte[] BigIntegerTo32Bytes(BigInteger b){ | private static byte[] BigIntegerTo32Bytes(BigInteger b){ | ||||
byte[] tmp = b.toByteArray(); | byte[] tmp = b.toByteArray(); | ||||
@@ -0,0 +1,25 @@ | |||||
package com.jd.blockchain.crypto.utils.classic; | |||||
import org.bouncycastle.crypto.digests.RIPEMD160Digest; | |||||
/** | |||||
* @author zhanglin33 | |||||
* @title: RIPEMD160Utils | |||||
* @description: RIPEMD160 hash algorithm | |||||
* @date 2019-04-10, 16:51 | |||||
*/ | |||||
public class RIPEMD160Utils { | |||||
// The length of RIPEMD160 output is 20 bytes | |||||
private static final int RIPEMD160DIGEST_LENGTH = 160 / 8; | |||||
public static byte[] hash(byte[] data){ | |||||
byte[] result = new byte[RIPEMD160DIGEST_LENGTH]; | |||||
RIPEMD160Digest ripemd160Digest = new RIPEMD160Digest(); | |||||
ripemd160Digest.update(data,0,data.length); | |||||
ripemd160Digest.doFinal(result,0); | |||||
return result; | |||||
} | |||||
} |
@@ -1,10 +1,521 @@ | |||||
package com.jd.blockchain.crypto.utils.classic; | package com.jd.blockchain.crypto.utils.classic; | ||||
import com.jd.blockchain.utils.io.BytesUtils; | |||||
import org.bouncycastle.asn1.*; | |||||
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; | |||||
import org.bouncycastle.asn1.pkcs.RSAPrivateKey; | |||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier; | |||||
import org.bouncycastle.crypto.*; | |||||
import org.bouncycastle.crypto.digests.SHA256Digest; | |||||
import org.bouncycastle.crypto.encodings.PKCS1Encoding; | |||||
import org.bouncycastle.crypto.engines.RSAEngine; | |||||
import org.bouncycastle.crypto.generators.RSAKeyPairGenerator; | |||||
import org.bouncycastle.crypto.params.ParametersWithRandom; | |||||
import org.bouncycastle.crypto.params.RSAKeyGenerationParameters; | |||||
import org.bouncycastle.crypto.params.RSAKeyParameters; | |||||
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; | |||||
import org.bouncycastle.crypto.signers.RSADigestSigner; | |||||
import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; | |||||
import sun.security.rsa.RSAPrivateCrtKeyImpl; | |||||
import java.io.IOException; | |||||
import java.math.BigInteger; | |||||
import java.security.KeyFactory; | |||||
import java.security.NoSuchAlgorithmException; | |||||
import java.security.SecureRandom; | |||||
import java.security.interfaces.RSAPublicKey; | |||||
import java.security.spec.InvalidKeySpecException; | |||||
import java.security.spec.PKCS8EncodedKeySpec; | |||||
import java.security.spec.X509EncodedKeySpec; | |||||
/** | /** | ||||
* @author zhanglin33 | * @author zhanglin33 | ||||
* @title: RSAUtils | * @title: RSAUtils | ||||
* @description: RSA encryption and signature algorithms | |||||
* @description: RSA2048 encryption(RSA/ECB/PKCS1Padding) and signature(SHA256withRSA) algorithms, | |||||
* and keys are output in raw, PKCS1v2 and PKCS8 formats | |||||
* @date 2019-03-25, 17:20 | * @date 2019-03-25, 17:20 | ||||
*/ | */ | ||||
public class RSAUtils { | |||||
public class RSAUtils { | |||||
private static final int KEYSIZEBITS = 2048; | |||||
private static final int CERTAINTY = 100; | |||||
private static final int MODULUS_LENGTH = 2048 / 8; | |||||
private static final int PRIVEXP_LENGTH = 2048 / 8; | |||||
private static final int P_LENGTH = 1024 / 8; | |||||
private static final int Q_LENGTH = 1024 / 8; | |||||
private static final int DP_LENGTH = 1024 / 8; | |||||
private static final int DQ_LENGTH = 1024 / 8; | |||||
private static final int QINV_LENGTH = 1024 / 8; | |||||
private static final BigInteger PUBEXP_0X03 = BigInteger.valueOf(0x03); | |||||
private static final BigInteger VERSION_2PRIMES = BigInteger.valueOf(0); | |||||
private static final AlgorithmIdentifier RSA_ALGORITHM_IDENTIFIER = | |||||
new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE); | |||||
private static final int PLAINTEXT_BLOCKSIZE = 256 - 11; | |||||
private static final int CIPHERTEXT_BLOCKSIZE = 256; | |||||
//-----------------Key Generation Algorithm----------------- | |||||
/** | |||||
* key pair generation | |||||
* | |||||
* @return key pair | |||||
*/ | |||||
public static AsymmetricCipherKeyPair generateKeyPair(){ | |||||
return generateKeyPair(new SecureRandom()); | |||||
} | |||||
public static AsymmetricCipherKeyPair generateKeyPair(SecureRandom random){ | |||||
AsymmetricCipherKeyPairGenerator kpGen = new RSAKeyPairGenerator(); | |||||
kpGen.init(new RSAKeyGenerationParameters(PUBEXP_0X03, random, KEYSIZEBITS, CERTAINTY)); | |||||
return kpGen.generateKeyPair(); | |||||
} | |||||
// Retrieve public key in raw keys form | |||||
public static byte[] retrievePublicKey(byte[] privateKey) { | |||||
RSAPrivateCrtKeyParameters privKey = bytes2PrivKey_RawKey(privateKey); | |||||
BigInteger modulus = privKey.getModulus(); | |||||
BigInteger exponent = privKey.getPublicExponent(); | |||||
RSAKeyParameters pubKey = new RSAKeyParameters(false, modulus, exponent); | |||||
return pubKey2Bytes_RawKey(pubKey); | |||||
} | |||||
//-----------------Digital Signature Algorithm----------------- | |||||
/** | |||||
* signature generation | |||||
* | |||||
* @param data data to be signed | |||||
* @param privateKey private key | |||||
* @return signature | |||||
*/ | |||||
public static byte[] sign(byte[] data, byte[] privateKey){ | |||||
RSAPrivateCrtKeyParameters privKey = bytes2PrivKey_RawKey(privateKey); | |||||
return sign(data,privKey); | |||||
} | |||||
public static byte[] sign(byte[] data, CipherParameters params){ | |||||
SHA256Digest digest = new SHA256Digest(); | |||||
RSADigestSigner signer = new RSADigestSigner(digest); | |||||
signer.init(true, params); | |||||
signer.update(data, 0, data.length); | |||||
try { | |||||
return signer.generateSignature(); | |||||
} catch (CryptoException e) { | |||||
throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e); | |||||
} | |||||
} | |||||
/** | |||||
* verification | |||||
* | |||||
* @param data data to be signed | |||||
* @param publicKey public key | |||||
* @param signature signature to be verified | |||||
* @return true or false | |||||
*/ | |||||
public static boolean verify(byte[] data, byte[] publicKey, byte[] signature){ | |||||
RSAKeyParameters pubKey = bytes2PubKey_RawKey(publicKey); | |||||
return verify(data,pubKey,signature); | |||||
} | |||||
public static boolean verify(byte[] data, CipherParameters params, byte[] signature){ | |||||
SHA256Digest digest = new SHA256Digest(); | |||||
RSADigestSigner signer = new RSADigestSigner(digest); | |||||
signer.init(false, params); | |||||
signer.update(data, 0, data.length); | |||||
return signer.verifySignature(signature); | |||||
} | |||||
//-----------------Public Key Encryption Algorithm----------------- | |||||
/** | |||||
* encryption | |||||
* | |||||
* @param plainBytes plaintext | |||||
* @param publicKey public key | |||||
* @return ciphertext | |||||
*/ | |||||
public static byte[] encrypt(byte[] plainBytes, byte[] publicKey){ | |||||
RSAKeyParameters pubKey = bytes2PubKey_RawKey(publicKey); | |||||
return encrypt(plainBytes,pubKey); | |||||
} | |||||
public static byte[] encrypt(byte[] plainBytes, byte[] publicKey, SecureRandom random){ | |||||
RSAKeyParameters pubKey = bytes2PubKey_RawKey(publicKey); | |||||
ParametersWithRandom params = new ParametersWithRandom(pubKey,random); | |||||
return encrypt(plainBytes,params); | |||||
} | |||||
public static byte[] encrypt(byte[] plainBytes, CipherParameters params){ | |||||
int blockNum = (plainBytes.length % PLAINTEXT_BLOCKSIZE == 0) ? (plainBytes.length / PLAINTEXT_BLOCKSIZE) | |||||
: (plainBytes.length / PLAINTEXT_BLOCKSIZE + 1); | |||||
int inputLength; | |||||
byte[] result = new byte[blockNum * CIPHERTEXT_BLOCKSIZE]; | |||||
byte[] buffer; | |||||
AsymmetricBlockCipher encryptor = new PKCS1Encoding(new RSAEngine()); | |||||
encryptor.init(true, params); | |||||
try { | |||||
for (int i= 0; i < blockNum; i++) { | |||||
inputLength = ((plainBytes.length - i * PLAINTEXT_BLOCKSIZE) > PLAINTEXT_BLOCKSIZE)? | |||||
PLAINTEXT_BLOCKSIZE : (plainBytes.length - i * PLAINTEXT_BLOCKSIZE); | |||||
buffer = encryptor.processBlock(plainBytes, i * PLAINTEXT_BLOCKSIZE, inputLength); | |||||
System.arraycopy(buffer,0, | |||||
result, i * CIPHERTEXT_BLOCKSIZE, CIPHERTEXT_BLOCKSIZE); | |||||
} | |||||
} catch (InvalidCipherTextException e) { | |||||
throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e); | |||||
} | |||||
return result; | |||||
} | |||||
/** | |||||
* decryption | |||||
* | |||||
* @param cipherBytes ciphertext | |||||
* @param privateKey private key | |||||
* @return plaintext | |||||
*/ | |||||
public static byte[] decrypt(byte[] cipherBytes, byte[] privateKey){ | |||||
RSAPrivateCrtKeyParameters privKey = bytes2PrivKey_RawKey(privateKey); | |||||
return decrypt(cipherBytes,privKey); | |||||
} | |||||
public static byte[] decrypt(byte[] cipherBytes, CipherParameters params){ | |||||
if (cipherBytes.length % CIPHERTEXT_BLOCKSIZE != 0) | |||||
{ | |||||
throw new com.jd.blockchain.crypto.CryptoException("ciphertext's length is wrong!"); | |||||
} | |||||
int blockNum = cipherBytes.length / CIPHERTEXT_BLOCKSIZE; | |||||
int count = 0; | |||||
byte[] buffer; | |||||
byte[] plaintextWithZeros = new byte[blockNum * PLAINTEXT_BLOCKSIZE]; | |||||
byte[] result; | |||||
AsymmetricBlockCipher decryptor = new PKCS1Encoding(new RSAEngine()); | |||||
decryptor.init(false,params); | |||||
try { | |||||
for (int i = 0; i < blockNum; i++){ | |||||
buffer = decryptor.processBlock(cipherBytes,i * CIPHERTEXT_BLOCKSIZE, CIPHERTEXT_BLOCKSIZE); | |||||
count += buffer.length; | |||||
System.arraycopy(buffer,0,plaintextWithZeros, i * PLAINTEXT_BLOCKSIZE, buffer.length); | |||||
} | |||||
} catch (InvalidCipherTextException e) { | |||||
throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e); | |||||
} | |||||
result = new byte[count]; | |||||
System.arraycopy(plaintextWithZeros,0,result,0,result.length); | |||||
return result; | |||||
} | |||||
/** | |||||
* This outputs the key in PKCS1v2 format. | |||||
* RSAPublicKey ::= SEQUENCE { | |||||
* modulus INTEGER, -- n | |||||
* publicExponent INTEGER, -- e | |||||
* } | |||||
*/ | |||||
public static byte[] pubKey2Bytes_PKCS1(RSAKeyParameters pubKey) | |||||
{ | |||||
ASN1EncodableVector v = new ASN1EncodableVector(); | |||||
v.add(new ASN1Integer(pubKey.getModulus())); | |||||
v.add(new ASN1Integer(pubKey.getExponent())); | |||||
DERSequence pubKeySequence = new DERSequence(v); | |||||
byte[] result; | |||||
try { | |||||
result = pubKeySequence.getEncoded(ASN1Encoding.DER); | |||||
} catch (IOException e) { | |||||
throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e); | |||||
} | |||||
return result; | |||||
} | |||||
public static byte[] pubKey2Bytes_PKCS8(RSAKeyParameters pubKey){ | |||||
BigInteger modulus = pubKey.getModulus(); | |||||
BigInteger exponent = pubKey.getExponent(); | |||||
return KeyUtil.getEncodedSubjectPublicKeyInfo(RSA_ALGORITHM_IDENTIFIER, | |||||
new org.bouncycastle.asn1.pkcs.RSAPublicKey(modulus, exponent)); | |||||
} | |||||
public static byte[] pubKey2Bytes_RawKey(RSAKeyParameters pubKey){ | |||||
BigInteger modulus = pubKey.getModulus(); | |||||
BigInteger exponent = pubKey.getExponent(); | |||||
byte[] exponentBytes = exponent.toByteArray(); | |||||
byte[] modulusBytes = bigInteger2Bytes(modulus,MODULUS_LENGTH); | |||||
return BytesUtils.concat(modulusBytes,exponentBytes); | |||||
} | |||||
public static RSAKeyParameters bytes2PubKey_PKCS1(byte[] pubKeyBytes) { | |||||
ASN1Sequence pubKeySequence = ASN1Sequence.getInstance(pubKeyBytes); | |||||
BigInteger modulus = ASN1Integer.getInstance(pubKeySequence.getObjectAt(0)).getValue(); | |||||
BigInteger exponent = ASN1Integer.getInstance(pubKeySequence.getObjectAt(1)).getValue(); | |||||
return new RSAKeyParameters(false, modulus, exponent); | |||||
} | |||||
public static RSAKeyParameters bytes2PubKey_PKCS8(byte[] pubKeyBytes) { | |||||
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pubKeyBytes); | |||||
KeyFactory keyFactory = null; | |||||
try { | |||||
keyFactory = KeyFactory.getInstance("RSA"); | |||||
} catch (NoSuchAlgorithmException e) { | |||||
throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e); | |||||
} | |||||
RSAPublicKey publicKey = null; | |||||
try { | |||||
publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec); | |||||
} catch (InvalidKeySpecException e) { | |||||
throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e); | |||||
} | |||||
assert publicKey != null; | |||||
BigInteger exponent = publicKey.getPublicExponent(); | |||||
BigInteger modulus = publicKey.getModulus(); | |||||
return new RSAKeyParameters(false,modulus,exponent); | |||||
} | |||||
public static RSAKeyParameters bytes2PubKey_RawKey(byte[] pubKeyBytes) { | |||||
byte[] modulusBytes = new byte[MODULUS_LENGTH]; | |||||
byte[] exponentBytes = new byte[pubKeyBytes.length - MODULUS_LENGTH]; | |||||
System.arraycopy(pubKeyBytes,0, modulusBytes,0, MODULUS_LENGTH); | |||||
System.arraycopy(pubKeyBytes,MODULUS_LENGTH, exponentBytes,0,exponentBytes.length); | |||||
BigInteger modulus = new BigInteger(1, modulusBytes); | |||||
BigInteger exponent = new BigInteger(1, exponentBytes); | |||||
return new RSAKeyParameters(false,modulus,exponent); | |||||
} | |||||
/** | |||||
* This outputs the key in PKCS1v2 format. | |||||
* RSAPrivateKey ::= SEQUENCE { | |||||
* VERSION_2PRIMES Version, | |||||
* modulus INTEGER, -- n | |||||
* publicExponent INTEGER, -- e | |||||
* privateExponent INTEGER, -- d | |||||
* prime1 INTEGER, -- p | |||||
* prime2 INTEGER, -- q | |||||
* exponent1 INTEGER, -- d mod (p-1) | |||||
* exponent2 INTEGER, -- d mod (q-1) | |||||
* coefficient INTEGER, -- (inverse of q) mod p | |||||
* otherPrimeInfos OtherPrimeInfos OPTIONAL | |||||
* } | |||||
* | |||||
* Version ::= INTEGER { two-prime(0), multi(1) } | |||||
* (CONSTRAINED BY {-- version must be multi if otherPrimeInfos present --}) | |||||
* | |||||
* This routine is written to output PKCS1 version 2.1, private keys. | |||||
*/ | |||||
public static byte[] privKey2Bytes_PKCS1(RSAPrivateCrtKeyParameters privKey) | |||||
{ | |||||
ASN1EncodableVector v = new ASN1EncodableVector(); | |||||
v.add(new ASN1Integer(VERSION_2PRIMES)); // version | |||||
v.add(new ASN1Integer(privKey.getModulus())); | |||||
v.add(new ASN1Integer(privKey.getPublicExponent())); | |||||
v.add(new ASN1Integer(privKey.getExponent())); | |||||
v.add(new ASN1Integer(privKey.getP())); | |||||
v.add(new ASN1Integer(privKey.getQ())); | |||||
v.add(new ASN1Integer(privKey.getDP())); | |||||
v.add(new ASN1Integer(privKey.getDQ())); | |||||
v.add(new ASN1Integer(privKey.getQInv())); | |||||
DERSequence privKeySequence = new DERSequence(v); | |||||
byte[] result; | |||||
try { | |||||
result = privKeySequence.getEncoded(ASN1Encoding.DER); | |||||
} catch (IOException e) { | |||||
throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e); | |||||
} | |||||
return result; | |||||
} | |||||
public static byte[] privKey2Bytes_PKCS8(RSAPrivateCrtKeyParameters privKey){ | |||||
BigInteger modulus = privKey.getModulus(); | |||||
BigInteger pubExp = privKey.getPublicExponent(); | |||||
BigInteger privExp = privKey.getExponent(); | |||||
BigInteger p = privKey.getP(); | |||||
BigInteger q = privKey.getQ(); | |||||
BigInteger dP = privKey.getDP(); | |||||
BigInteger dQ = privKey.getDQ(); | |||||
BigInteger qInv = privKey.getQInv(); | |||||
return KeyUtil.getEncodedPrivateKeyInfo(RSA_ALGORITHM_IDENTIFIER, | |||||
new RSAPrivateKey(modulus, pubExp, privExp, p, q, dP, dQ, qInv)); | |||||
} | |||||
public static byte[] privKey2Bytes_RawKey(RSAPrivateCrtKeyParameters privKey){ | |||||
BigInteger modulus = privKey.getModulus(); | |||||
BigInteger pubExp = privKey.getPublicExponent(); | |||||
BigInteger privExp = privKey.getExponent(); | |||||
BigInteger p = privKey.getP(); | |||||
BigInteger q = privKey.getQ(); | |||||
BigInteger dP = privKey.getDP(); | |||||
BigInteger dQ = privKey.getDQ(); | |||||
BigInteger qInv = privKey.getQInv(); | |||||
byte[] modulusBytes = bigInteger2Bytes(modulus,MODULUS_LENGTH); | |||||
byte[] pubExpBytes = pubExp.toByteArray(); | |||||
byte[] privExpBytes = bigInteger2Bytes(privExp,PRIVEXP_LENGTH); | |||||
byte[] pBytes = bigInteger2Bytes(p,P_LENGTH); | |||||
byte[] qBytes = bigInteger2Bytes(q,Q_LENGTH); | |||||
byte[] dPBytes = bigInteger2Bytes(dP,DP_LENGTH); | |||||
byte[] dQBytes = bigInteger2Bytes(dQ,DQ_LENGTH); | |||||
byte[] qInvBytes = bigInteger2Bytes(qInv,QINV_LENGTH); | |||||
return BytesUtils.concat(modulusBytes,pubExpBytes,privExpBytes,pBytes,qBytes,dPBytes,dQBytes,qInvBytes); | |||||
} | |||||
public static RSAPrivateCrtKeyParameters bytes2PrivKey_PKCS1(byte[] privKeyBytes){ | |||||
ASN1Sequence priKeySequence = ASN1Sequence.getInstance(privKeyBytes); | |||||
BigInteger modulus = ASN1Integer.getInstance(priKeySequence.getObjectAt(1)).getValue(); | |||||
BigInteger pubExp = ASN1Integer.getInstance(priKeySequence.getObjectAt(2)).getValue(); | |||||
BigInteger privExp = ASN1Integer.getInstance(priKeySequence.getObjectAt(3)).getValue(); | |||||
BigInteger p = ASN1Integer.getInstance(priKeySequence.getObjectAt(4)).getValue(); | |||||
BigInteger q = ASN1Integer.getInstance(priKeySequence.getObjectAt(5)).getValue(); | |||||
BigInteger dP = ASN1Integer.getInstance(priKeySequence.getObjectAt(6)).getValue(); | |||||
BigInteger dQ = ASN1Integer.getInstance(priKeySequence.getObjectAt(7)).getValue(); | |||||
BigInteger qInv = ASN1Integer.getInstance(priKeySequence.getObjectAt(8)).getValue(); | |||||
return new RSAPrivateCrtKeyParameters(modulus, pubExp, privExp, p, q, dP, dQ, qInv); | |||||
} | |||||
public static RSAPrivateCrtKeyParameters bytes2PrivKey_PKCS8(byte[] privKeyBytes){ | |||||
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKeyBytes); | |||||
KeyFactory keyFactory = null; | |||||
try { | |||||
keyFactory = KeyFactory.getInstance("RSA"); | |||||
} catch (NoSuchAlgorithmException e) { | |||||
throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e); | |||||
} | |||||
RSAPrivateCrtKeyImpl privateKey; | |||||
try { | |||||
privateKey = (RSAPrivateCrtKeyImpl) keyFactory.generatePrivate(keySpec); | |||||
} catch (InvalidKeySpecException e) { | |||||
throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e); | |||||
} | |||||
assert privateKey != null; | |||||
BigInteger modulus = privateKey.getModulus(); | |||||
BigInteger pubExp = privateKey.getPublicExponent(); | |||||
BigInteger privExp = privateKey.getPrivateExponent(); | |||||
BigInteger p = privateKey.getPrimeP(); | |||||
BigInteger q = privateKey.getPrimeQ(); | |||||
BigInteger dP = privateKey.getPrimeExponentP(); | |||||
BigInteger dQ = privateKey.getPrimeExponentQ(); | |||||
BigInteger qInv = privateKey.getCrtCoefficient(); | |||||
return new RSAPrivateCrtKeyParameters(modulus, pubExp, privExp, p, q, dP, dQ, qInv); | |||||
} | |||||
public static RSAPrivateCrtKeyParameters bytes2PrivKey_RawKey(byte[] privKeyBytes){ | |||||
byte[] modulusBytes = new byte[MODULUS_LENGTH]; | |||||
byte[] pubExpBytes = new byte[privKeyBytes.length - MODULUS_LENGTH - PRIVEXP_LENGTH - P_LENGTH - Q_LENGTH | |||||
- DP_LENGTH - DQ_LENGTH - QINV_LENGTH]; | |||||
byte[] privExpBytes = new byte[PRIVEXP_LENGTH]; | |||||
byte[] pBytes = new byte[P_LENGTH]; | |||||
byte[] qBytes = new byte[Q_LENGTH]; | |||||
byte[] dPBytes = new byte[DP_LENGTH]; | |||||
byte[] dQBytes = new byte[DQ_LENGTH]; | |||||
byte[] qInvBytes = new byte[QINV_LENGTH]; | |||||
System.arraycopy(privKeyBytes,0, modulusBytes,0, MODULUS_LENGTH); | |||||
System.arraycopy(privKeyBytes, MODULUS_LENGTH, pubExpBytes,0,pubExpBytes.length); | |||||
System.arraycopy(privKeyBytes,MODULUS_LENGTH + pubExpBytes.length, | |||||
privExpBytes,0,PRIVEXP_LENGTH); | |||||
System.arraycopy(privKeyBytes,MODULUS_LENGTH + pubExpBytes.length + PRIVEXP_LENGTH, | |||||
pBytes,0,P_LENGTH); | |||||
System.arraycopy(privKeyBytes,MODULUS_LENGTH + pubExpBytes.length + PRIVEXP_LENGTH + P_LENGTH, | |||||
qBytes,0,Q_LENGTH); | |||||
System.arraycopy(privKeyBytes,MODULUS_LENGTH + pubExpBytes.length + PRIVEXP_LENGTH + P_LENGTH + | |||||
Q_LENGTH, dPBytes,0,DP_LENGTH); | |||||
System.arraycopy(privKeyBytes,MODULUS_LENGTH + pubExpBytes.length + PRIVEXP_LENGTH + P_LENGTH + | |||||
Q_LENGTH + DP_LENGTH, dQBytes,0,DQ_LENGTH); | |||||
System.arraycopy(privKeyBytes,MODULUS_LENGTH + pubExpBytes.length + PRIVEXP_LENGTH + P_LENGTH + | |||||
Q_LENGTH + DP_LENGTH + DQ_LENGTH, qInvBytes,0,QINV_LENGTH); | |||||
BigInteger modulus = new BigInteger(1, modulusBytes); | |||||
BigInteger pubExp = new BigInteger(1, pubExpBytes); | |||||
BigInteger privExp = new BigInteger(1, privExpBytes); | |||||
BigInteger p = new BigInteger(1, pBytes); | |||||
BigInteger q = new BigInteger(1, qBytes); | |||||
BigInteger dP = new BigInteger(1, dPBytes); | |||||
BigInteger dQ = new BigInteger(1, dQBytes); | |||||
BigInteger qInv = new BigInteger(1, qInvBytes); | |||||
return new RSAPrivateCrtKeyParameters(modulus, pubExp, privExp, p, q, dP, dQ, qInv); | |||||
} | |||||
private static byte[] bigInteger2Bytes(BigInteger src, int length){ | |||||
byte[] result = new byte[length]; | |||||
byte[] srcBytes = src.toByteArray(); | |||||
int srcLength = srcBytes.length; | |||||
if (srcLength > length) { | |||||
System.arraycopy(srcBytes,srcLength - length, | |||||
result,0, length); | |||||
} else { | |||||
System.arraycopy(srcBytes,0, | |||||
result,length - srcLength, length); | |||||
} | |||||
return result; | |||||
} | |||||
} | } |
@@ -0,0 +1,352 @@ | |||||
package test.com.jd.blockchain.crypto.service.classic; | |||||
import com.jd.blockchain.crypto.*; | |||||
import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; | |||||
import com.jd.blockchain.utils.io.BytesUtils; | |||||
import org.junit.Test; | |||||
import java.util.Random; | |||||
import static com.jd.blockchain.crypto.CryptoAlgorithm.ASYMMETRIC_KEY; | |||||
import static com.jd.blockchain.crypto.CryptoAlgorithm.SIGNATURE_ALGORITHM; | |||||
import static com.jd.blockchain.crypto.CryptoKeyType.PRIVATE; | |||||
import static com.jd.blockchain.crypto.CryptoKeyType.PUBLIC; | |||||
import static org.junit.Assert.*; | |||||
/** | |||||
* @author zhanglin33 | |||||
* @title: ECDSASignatureFunctionTest | |||||
* @description: JunitTest for ECDSASignatureFunction in SPI mode | |||||
* @date 2019-04-23, 09:37 | |||||
*/ | |||||
public class ECDSASignatureFunctionTest { | |||||
@Test | |||||
public void getAlgorithmTest() { | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name()); | |||||
assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code()); | |||||
algorithm = Crypto.getAlgorithm("eCDsA"); | |||||
assertNotNull(algorithm); | |||||
assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name()); | |||||
assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code()); | |||||
algorithm = Crypto.getAlgorithm("eedsa"); | |||||
assertNull(algorithm); | |||||
} | |||||
@Test | |||||
public void generateKeyPairTest() { | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PubKey pubKey = keyPair.getPubKey(); | |||||
PrivKey privKey = keyPair.getPrivKey(); | |||||
assertEquals(PUBLIC.CODE, pubKey.getKeyType().CODE); | |||||
assertEquals(65, pubKey.getRawKeyBytes().length); | |||||
assertEquals(PRIVATE.CODE, privKey.getKeyType().CODE); | |||||
assertEquals(32, privKey.getRawKeyBytes().length); | |||||
assertEquals(algorithm.code(), pubKey.getAlgorithm()); | |||||
assertEquals(algorithm.code(), privKey.getAlgorithm()); | |||||
assertEquals(2 + 1 + 65, pubKey.toBytes().length); | |||||
assertEquals(2 + 1 + 32, privKey.toBytes().length); | |||||
byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); | |||||
byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE }; | |||||
byte[] privKeyTypeBytes = new byte[] { PRIVATE.CODE }; | |||||
byte[] rawPubKeyBytes = pubKey.getRawKeyBytes(); | |||||
byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); | |||||
assertArrayEquals(BytesUtils.concat(algoBytes, pubKeyTypeBytes, rawPubKeyBytes), pubKey.toBytes()); | |||||
assertArrayEquals(BytesUtils.concat(algoBytes, privKeyTypeBytes, rawPrivKeyBytes), privKey.toBytes()); | |||||
} | |||||
@Test | |||||
public void retrievePubKeyTest() { | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PubKey pubKey = keyPair.getPubKey(); | |||||
PrivKey privKey = keyPair.getPrivKey(); | |||||
PubKey retrievedPubKey = signatureFunction.retrievePubKey(privKey); | |||||
assertEquals(pubKey.getKeyType(), retrievedPubKey.getKeyType()); | |||||
assertEquals(pubKey.getRawKeyBytes().length, retrievedPubKey.getRawKeyBytes().length); | |||||
assertEquals(pubKey.getAlgorithm(), retrievedPubKey.getAlgorithm()); | |||||
assertArrayEquals(pubKey.toBytes(), retrievedPubKey.toBytes()); | |||||
} | |||||
@Test | |||||
public void signTest() { | |||||
byte[] data = new byte[1024]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PrivKey privKey = keyPair.getPrivKey(); | |||||
SignatureDigest signatureDigest = signatureFunction.sign(privKey, data); | |||||
byte[] signatureBytes = signatureDigest.toBytes(); | |||||
assertEquals(2 + 64, signatureBytes.length); | |||||
assertEquals(ClassicAlgorithm.ECDSA.code(), signatureDigest.getAlgorithm()); | |||||
assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 22 & 0x00FF)), | |||||
signatureDigest.getAlgorithm()); | |||||
byte[] algoBytes = BytesUtils.toBytes(signatureDigest.getAlgorithm()); | |||||
byte[] rawSinatureBytes = signatureDigest.getRawDigest(); | |||||
assertArrayEquals(BytesUtils.concat(algoBytes, rawSinatureBytes), signatureBytes); | |||||
} | |||||
@Test | |||||
public void verifyTest() { | |||||
byte[] data = new byte[1024]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PubKey pubKey = keyPair.getPubKey(); | |||||
PrivKey privKey = keyPair.getPrivKey(); | |||||
SignatureDigest signatureDigest = signatureFunction.sign(privKey, data); | |||||
assertTrue(signatureFunction.verify(signatureDigest, pubKey, data)); | |||||
} | |||||
@Test | |||||
public void supportPrivKeyTest() { | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PrivKey privKey = keyPair.getPrivKey(); | |||||
byte[] privKeyBytes = privKey.toBytes(); | |||||
assertTrue(signatureFunction.supportPrivKey(privKeyBytes)); | |||||
algorithm = Crypto.getAlgorithm("ripemd160"); | |||||
assertNotNull(algorithm); | |||||
byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); | |||||
byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE }; | |||||
byte[] rawKeyBytes = privKey.getRawKeyBytes(); | |||||
byte[] ripemd160PubKeyBytes = BytesUtils.concat(algoBytes, pubKeyTypeBytes, rawKeyBytes); | |||||
assertFalse(signatureFunction.supportPrivKey(ripemd160PubKeyBytes)); | |||||
} | |||||
@Test | |||||
public void resolvePrivKeyTest() { | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PrivKey privKey = keyPair.getPrivKey(); | |||||
byte[] privKeyBytes = privKey.toBytes(); | |||||
PrivKey resolvedPrivKey = signatureFunction.resolvePrivKey(privKeyBytes); | |||||
assertEquals(PRIVATE.CODE, resolvedPrivKey.getKeyType().CODE); | |||||
assertEquals(32, resolvedPrivKey.getRawKeyBytes().length); | |||||
assertEquals(ClassicAlgorithm.ECDSA.code(), resolvedPrivKey.getAlgorithm()); | |||||
assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 22 & 0x00FF)), | |||||
resolvedPrivKey.getAlgorithm()); | |||||
assertArrayEquals(privKeyBytes, resolvedPrivKey.toBytes()); | |||||
algorithm = Crypto.getAlgorithm("ripemd160"); | |||||
assertNotNull(algorithm); | |||||
byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); | |||||
byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE }; | |||||
byte[] rawKeyBytes = privKey.getRawKeyBytes(); | |||||
byte[] ripemd160PubKeyBytes = BytesUtils.concat(algoBytes, pubKeyTypeBytes, rawKeyBytes); | |||||
Class<?> expectedException = CryptoException.class; | |||||
Exception actualEx = null; | |||||
try { | |||||
signatureFunction.resolvePrivKey(ripemd160PubKeyBytes); | |||||
} catch (Exception e) { | |||||
actualEx = e; | |||||
} | |||||
assertNotNull(actualEx); | |||||
assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); | |||||
} | |||||
@Test | |||||
public void supportPubKeyTest() { | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PubKey pubKey = keyPair.getPubKey(); | |||||
byte[] pubKeyBytes = pubKey.toBytes(); | |||||
assertTrue(signatureFunction.supportPubKey(pubKeyBytes)); | |||||
algorithm = Crypto.getAlgorithm("ripemd160"); | |||||
assertNotNull(algorithm); | |||||
byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); | |||||
byte[] privKeyTypeBytes = new byte[] { PRIVATE.CODE }; | |||||
byte[] rawKeyBytes = pubKey.getRawKeyBytes(); | |||||
byte[] ripemd160PrivKeyBytes = BytesUtils.concat(algoBytes, privKeyTypeBytes, rawKeyBytes); | |||||
assertFalse(signatureFunction.supportPubKey(ripemd160PrivKeyBytes)); | |||||
} | |||||
@Test | |||||
public void resolvePubKeyTest() { | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PubKey pubKey = keyPair.getPubKey(); | |||||
byte[] pubKeyBytes = pubKey.toBytes(); | |||||
PubKey resolvedPubKey = signatureFunction.resolvePubKey(pubKeyBytes); | |||||
assertEquals(PUBLIC.CODE, resolvedPubKey.getKeyType().CODE); | |||||
assertEquals(65, resolvedPubKey.getRawKeyBytes().length); | |||||
assertEquals(ClassicAlgorithm.ECDSA.code(), resolvedPubKey.getAlgorithm()); | |||||
assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 22 & 0x00FF)), | |||||
resolvedPubKey.getAlgorithm()); | |||||
assertArrayEquals(pubKeyBytes, resolvedPubKey.toBytes()); | |||||
algorithm = Crypto.getAlgorithm("ripemd160"); | |||||
assertNotNull(algorithm); | |||||
byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); | |||||
byte[] privKeyTypeBytes = new byte[] { PRIVATE.CODE }; | |||||
byte[] rawKeyBytes = pubKey.getRawKeyBytes(); | |||||
byte[] ripemd160PrivKeyBytes = BytesUtils.concat(algoBytes, privKeyTypeBytes, rawKeyBytes); | |||||
Class<?> expectedException = CryptoException.class; | |||||
Exception actualEx = null; | |||||
try { | |||||
signatureFunction.resolvePrivKey(ripemd160PrivKeyBytes); | |||||
} catch (Exception e) { | |||||
actualEx = e; | |||||
} | |||||
assertNotNull(actualEx); | |||||
assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); | |||||
} | |||||
@Test | |||||
public void supportDigestTest() { | |||||
byte[] data = new byte[1024]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PrivKey privKey = keyPair.getPrivKey(); | |||||
SignatureDigest signatureDigest = signatureFunction.sign(privKey, data); | |||||
byte[] signatureDigestBytes = signatureDigest.toBytes(); | |||||
assertTrue(signatureFunction.supportDigest(signatureDigestBytes)); | |||||
algorithm = Crypto.getAlgorithm("ripemd160"); | |||||
assertNotNull(algorithm); | |||||
byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); | |||||
byte[] rawDigestBytes = signatureDigest.toBytes(); | |||||
byte[] ripemd160SignatureBytes = BytesUtils.concat(algoBytes, rawDigestBytes); | |||||
assertFalse(signatureFunction.supportDigest(ripemd160SignatureBytes)); | |||||
} | |||||
@Test | |||||
public void resolveDigestTest() { | |||||
byte[] data = new byte[1024]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PrivKey privKey = keyPair.getPrivKey(); | |||||
SignatureDigest signatureDigest = signatureFunction.sign(privKey, data); | |||||
byte[] signatureDigestBytes = signatureDigest.toBytes(); | |||||
SignatureDigest resolvedSignatureDigest = signatureFunction.resolveDigest(signatureDigestBytes); | |||||
assertEquals(64, resolvedSignatureDigest.getRawDigest().length); | |||||
assertEquals(ClassicAlgorithm.ECDSA.code(), resolvedSignatureDigest.getAlgorithm()); | |||||
assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 22 & 0x00FF)), | |||||
resolvedSignatureDigest.getAlgorithm()); | |||||
assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes()); | |||||
algorithm = Crypto.getAlgorithm("ripemd160"); | |||||
assertNotNull(algorithm); | |||||
byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); | |||||
byte[] rawDigestBytes = signatureDigest.getRawDigest(); | |||||
byte[] ripemd160SignatureDigestBytes = BytesUtils.concat(algoBytes, rawDigestBytes); | |||||
Class<?> expectedException = CryptoException.class; | |||||
Exception actualEx = null; | |||||
try { | |||||
signatureFunction.resolveDigest(ripemd160SignatureDigestBytes); | |||||
} catch (Exception e) { | |||||
actualEx = e; | |||||
} | |||||
assertNotNull(actualEx); | |||||
assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); | |||||
} | |||||
} |
@@ -0,0 +1,488 @@ | |||||
package test.com.jd.blockchain.crypto.service.classic; | |||||
import com.jd.blockchain.crypto.*; | |||||
import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; | |||||
import com.jd.blockchain.utils.io.BytesUtils; | |||||
import org.junit.Test; | |||||
import java.util.Random; | |||||
import static com.jd.blockchain.crypto.CryptoAlgorithm.*; | |||||
import static com.jd.blockchain.crypto.CryptoKeyType.PRIVATE; | |||||
import static com.jd.blockchain.crypto.CryptoKeyType.PUBLIC; | |||||
import static org.junit.Assert.*; | |||||
/** | |||||
* @author zhanglin33 | |||||
* @title: RSACryptoFunctionTest | |||||
* @description: JunitTest for RSACryptoFunction in SPI mode | |||||
* @date 2019-04-23, 15:30 | |||||
*/ | |||||
public class RSACryptoFunctionTest { | |||||
@Test | |||||
public void getAlgorithmTest() { | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name()); | |||||
assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code()); | |||||
algorithm = Crypto.getAlgorithm("Rsa"); | |||||
assertNotNull(algorithm); | |||||
assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name()); | |||||
assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code()); | |||||
algorithm = Crypto.getAlgorithm("rsa2"); | |||||
assertNull(algorithm); | |||||
} | |||||
@Test | |||||
public void generateKeyPairTest() { | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PubKey pubKey = keyPair.getPubKey(); | |||||
PrivKey privKey = keyPair.getPrivKey(); | |||||
assertEquals(PUBLIC.CODE, pubKey.getKeyType().CODE); | |||||
assertEquals(257, pubKey.getRawKeyBytes().length); | |||||
assertEquals(PRIVATE.CODE, privKey.getKeyType().CODE); | |||||
assertEquals(1153, privKey.getRawKeyBytes().length); | |||||
assertEquals(algorithm.code(), pubKey.getAlgorithm()); | |||||
assertEquals(algorithm.code(), privKey.getAlgorithm()); | |||||
assertEquals(2 + 1 + 257, pubKey.toBytes().length); | |||||
assertEquals(2 + 1 + 1153, privKey.toBytes().length); | |||||
byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); | |||||
byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE }; | |||||
byte[] privKeyTypeBytes = new byte[] { PRIVATE.CODE }; | |||||
byte[] rawPubKeyBytes = pubKey.getRawKeyBytes(); | |||||
byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); | |||||
assertArrayEquals(BytesUtils.concat(algoBytes, pubKeyTypeBytes, rawPubKeyBytes), pubKey.toBytes()); | |||||
assertArrayEquals(BytesUtils.concat(algoBytes, privKeyTypeBytes, rawPrivKeyBytes), privKey.toBytes()); | |||||
} | |||||
@Test | |||||
public void retrievePubKeyTest() { | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PubKey pubKey = keyPair.getPubKey(); | |||||
PrivKey privKey = keyPair.getPrivKey(); | |||||
PubKey retrievedPubKey = signatureFunction.retrievePubKey(privKey); | |||||
assertEquals(pubKey.getKeyType(), retrievedPubKey.getKeyType()); | |||||
assertEquals(pubKey.getRawKeyBytes().length, retrievedPubKey.getRawKeyBytes().length); | |||||
assertEquals(pubKey.getAlgorithm(), retrievedPubKey.getAlgorithm()); | |||||
assertArrayEquals(pubKey.toBytes(), retrievedPubKey.toBytes()); | |||||
} | |||||
@Test | |||||
public void signTest() { | |||||
byte[] data = new byte[1024]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PrivKey privKey = keyPair.getPrivKey(); | |||||
SignatureDigest signatureDigest = signatureFunction.sign(privKey, data); | |||||
byte[] signatureBytes = signatureDigest.toBytes(); | |||||
assertEquals(2 + 256, signatureBytes.length); | |||||
assertEquals(algorithm.code(), signatureDigest.getAlgorithm()); | |||||
assertEquals(ClassicAlgorithm.RSA.code(), signatureDigest.getAlgorithm()); | |||||
assertEquals((short) (SIGNATURE_ALGORITHM | ENCRYPTION_ALGORITHM | ASYMMETRIC_KEY | ((byte) 23 & 0x00FF)), | |||||
signatureDigest.getAlgorithm()); | |||||
byte[] algoBytes = BytesUtils.toBytes(signatureDigest.getAlgorithm()); | |||||
byte[] rawSinatureBytes = signatureDigest.getRawDigest(); | |||||
assertArrayEquals(BytesUtils.concat(algoBytes, rawSinatureBytes), signatureBytes); | |||||
} | |||||
@Test | |||||
public void verifyTest() { | |||||
byte[] data = new byte[1024]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PubKey pubKey = keyPair.getPubKey(); | |||||
PrivKey privKey = keyPair.getPrivKey(); | |||||
SignatureDigest signatureDigest = signatureFunction.sign(privKey, data); | |||||
assertTrue(signatureFunction.verify(signatureDigest, pubKey, data)); | |||||
} | |||||
@Test | |||||
public void encryptTest() { | |||||
byte[] data = new byte[128]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); | |||||
assertNotNull(algorithm); | |||||
AsymmetricEncryptionFunction asymmetricEncryptionFunction = Crypto | |||||
.getAsymmetricEncryptionFunction(algorithm); | |||||
AsymmetricKeypair keyPair = asymmetricEncryptionFunction.generateKeypair(); | |||||
PubKey pubKey = keyPair.getPubKey(); | |||||
Ciphertext ciphertext = asymmetricEncryptionFunction.encrypt(pubKey, data); | |||||
byte[] ciphertextBytes = ciphertext.toBytes(); | |||||
assertEquals(2 + 256, ciphertextBytes.length); | |||||
assertEquals(ClassicAlgorithm.RSA.code(), ciphertext.getAlgorithm()); | |||||
assertEquals((short) (SIGNATURE_ALGORITHM | ENCRYPTION_ALGORITHM | ASYMMETRIC_KEY | ((byte) 23 & 0x00FF)), | |||||
ciphertext.getAlgorithm()); | |||||
byte[] algoBytes = BytesUtils.toBytes(ciphertext.getAlgorithm()); | |||||
byte[] rawCiphertextBytes = ciphertext.getRawCiphertext(); | |||||
assertArrayEquals(BytesUtils.concat(algoBytes, rawCiphertextBytes), ciphertextBytes); | |||||
} | |||||
@Test | |||||
public void decryptTest() { | |||||
byte[] data = new byte[128]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); | |||||
assertNotNull(algorithm); | |||||
AsymmetricEncryptionFunction asymmetricEncryptionFunction = Crypto | |||||
.getAsymmetricEncryptionFunction(algorithm); | |||||
AsymmetricKeypair keyPair = asymmetricEncryptionFunction.generateKeypair(); | |||||
PubKey pubKey = keyPair.getPubKey(); | |||||
PrivKey privKey = keyPair.getPrivKey(); | |||||
Ciphertext ciphertext = asymmetricEncryptionFunction.encrypt(pubKey, data); | |||||
byte[] decryptedPlaintext = asymmetricEncryptionFunction.decrypt(privKey, ciphertext); | |||||
assertArrayEquals(data, decryptedPlaintext); | |||||
} | |||||
@Test | |||||
public void supportPrivKeyTest() { | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PrivKey privKey = keyPair.getPrivKey(); | |||||
byte[] privKeyBytes = privKey.toBytes(); | |||||
assertTrue(signatureFunction.supportPrivKey(privKeyBytes)); | |||||
algorithm = Crypto.getAlgorithm("ripemd160"); | |||||
assertNotNull(algorithm); | |||||
byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); | |||||
byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE }; | |||||
byte[] rawKeyBytes = privKey.getRawKeyBytes(); | |||||
byte[] ripemd160PubKeyBytes = BytesUtils.concat(algoBytes, pubKeyTypeBytes, rawKeyBytes); | |||||
assertFalse(signatureFunction.supportPrivKey(ripemd160PubKeyBytes)); | |||||
} | |||||
@Test | |||||
public void resolvePrivKeyTest() { | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PrivKey privKey = keyPair.getPrivKey(); | |||||
byte[] privKeyBytes = privKey.toBytes(); | |||||
PrivKey resolvedPrivKey = signatureFunction.resolvePrivKey(privKeyBytes); | |||||
assertEquals(PRIVATE.CODE, resolvedPrivKey.getKeyType().CODE); | |||||
assertEquals(1153, resolvedPrivKey.getRawKeyBytes().length); | |||||
assertEquals(ClassicAlgorithm.RSA.code(), resolvedPrivKey.getAlgorithm()); | |||||
assertEquals((short) (SIGNATURE_ALGORITHM | ENCRYPTION_ALGORITHM | ASYMMETRIC_KEY | ((byte) 23 & 0x00FF)), | |||||
resolvedPrivKey.getAlgorithm()); | |||||
assertArrayEquals(privKeyBytes, resolvedPrivKey.toBytes()); | |||||
algorithm = Crypto.getAlgorithm("ripemd160"); | |||||
assertNotNull(algorithm); | |||||
byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); | |||||
byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE }; | |||||
byte[] rawKeyBytes = privKey.getRawKeyBytes(); | |||||
byte[] ripemd160PubKeyBytes = BytesUtils.concat(algoBytes, pubKeyTypeBytes, rawKeyBytes); | |||||
Class<?> expectedException = CryptoException.class; | |||||
Exception actualEx = null; | |||||
try { | |||||
signatureFunction.resolvePrivKey(ripemd160PubKeyBytes); | |||||
} catch (Exception e) { | |||||
actualEx = e; | |||||
} | |||||
assertNotNull(actualEx); | |||||
assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); | |||||
} | |||||
@Test | |||||
public void supportPubKeyTest() { | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PubKey pubKey = keyPair.getPubKey(); | |||||
byte[] pubKeyBytes = pubKey.toBytes(); | |||||
assertTrue(signatureFunction.supportPubKey(pubKeyBytes)); | |||||
algorithm = Crypto.getAlgorithm("ripemd160"); | |||||
assertNotNull(algorithm); | |||||
byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); | |||||
byte[] privKeyTypeBytes = new byte[] { PRIVATE.CODE }; | |||||
byte[] rawKeyBytes = pubKey.getRawKeyBytes(); | |||||
byte[] ripemd160PrivKeyBytes = BytesUtils.concat(algoBytes, privKeyTypeBytes, rawKeyBytes); | |||||
assertFalse(signatureFunction.supportPubKey(ripemd160PrivKeyBytes)); | |||||
} | |||||
@Test | |||||
public void resolvePubKeyTest() { | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PubKey pubKey = keyPair.getPubKey(); | |||||
byte[] pubKeyBytes = pubKey.toBytes(); | |||||
PubKey resolvedPubKey = signatureFunction.resolvePubKey(pubKeyBytes); | |||||
assertEquals(PUBLIC.CODE, resolvedPubKey.getKeyType().CODE); | |||||
assertEquals(257, resolvedPubKey.getRawKeyBytes().length); | |||||
assertEquals(ClassicAlgorithm.RSA.code(), resolvedPubKey.getAlgorithm()); | |||||
assertEquals((short) (SIGNATURE_ALGORITHM | ENCRYPTION_ALGORITHM | ASYMMETRIC_KEY | ((byte) 23 & 0x00FF)), | |||||
resolvedPubKey.getAlgorithm()); | |||||
assertArrayEquals(pubKeyBytes, resolvedPubKey.toBytes()); | |||||
algorithm = Crypto.getAlgorithm("ripemd160"); | |||||
assertNotNull(algorithm); | |||||
byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); | |||||
byte[] privKeyTypeBytes = new byte[] { PRIVATE.CODE }; | |||||
byte[] rawKeyBytes = pubKey.getRawKeyBytes(); | |||||
byte[] ripemd160PrivKeyBytes = BytesUtils.concat(algoBytes, privKeyTypeBytes, rawKeyBytes); | |||||
Class<?> expectedException = CryptoException.class; | |||||
Exception actualEx = null; | |||||
try { | |||||
signatureFunction.resolvePrivKey(ripemd160PrivKeyBytes); | |||||
} catch (Exception e) { | |||||
actualEx = e; | |||||
} | |||||
assertNotNull(actualEx); | |||||
assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); | |||||
} | |||||
@Test | |||||
public void supportDigestTest() { | |||||
byte[] data = new byte[1024]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PrivKey privKey = keyPair.getPrivKey(); | |||||
SignatureDigest signatureDigest = signatureFunction.sign(privKey, data); | |||||
byte[] signatureDigestBytes = signatureDigest.toBytes(); | |||||
assertTrue(signatureFunction.supportDigest(signatureDigestBytes)); | |||||
algorithm = Crypto.getAlgorithm("ripemd160"); | |||||
assertNotNull(algorithm); | |||||
byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); | |||||
byte[] rawDigestBytes = signatureDigest.toBytes(); | |||||
byte[] ripemd160SignatureBytes = BytesUtils.concat(algoBytes, rawDigestBytes); | |||||
assertFalse(signatureFunction.supportDigest(ripemd160SignatureBytes)); | |||||
} | |||||
@Test | |||||
public void resolveDigestTest() { | |||||
byte[] data = new byte[1024]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||||
PrivKey privKey = keyPair.getPrivKey(); | |||||
SignatureDigest signatureDigest = signatureFunction.sign(privKey, data); | |||||
byte[] signatureDigestBytes = signatureDigest.toBytes(); | |||||
SignatureDigest resolvedSignatureDigest = signatureFunction.resolveDigest(signatureDigestBytes); | |||||
assertEquals(256, resolvedSignatureDigest.getRawDigest().length); | |||||
assertEquals(ClassicAlgorithm.RSA.code(), resolvedSignatureDigest.getAlgorithm()); | |||||
assertEquals((short) (SIGNATURE_ALGORITHM | ENCRYPTION_ALGORITHM | ASYMMETRIC_KEY | ((byte) 23 & 0x00FF)), | |||||
resolvedSignatureDigest.getAlgorithm()); | |||||
assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes()); | |||||
algorithm = Crypto.getAlgorithm("ripemd160"); | |||||
assertNotNull(algorithm); | |||||
byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); | |||||
byte[] rawDigestBytes = signatureDigest.getRawDigest(); | |||||
byte[] ripemd160SignatureDigestBytes = BytesUtils.concat(algoBytes, rawDigestBytes); | |||||
Class<?> expectedException = CryptoException.class; | |||||
Exception actualEx = null; | |||||
try { | |||||
signatureFunction.resolveDigest(ripemd160SignatureDigestBytes); | |||||
} catch (Exception e) { | |||||
actualEx = e; | |||||
} | |||||
assertNotNull(actualEx); | |||||
assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); | |||||
} | |||||
@Test | |||||
public void supportCiphertextTest() { | |||||
byte[] data = new byte[128]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); | |||||
assertNotNull(algorithm); | |||||
AsymmetricEncryptionFunction asymmetricEncryptionFunction = Crypto | |||||
.getAsymmetricEncryptionFunction(algorithm); | |||||
AsymmetricKeypair keyPair = asymmetricEncryptionFunction.generateKeypair(); | |||||
PubKey pubKey = keyPair.getPubKey(); | |||||
Ciphertext ciphertext = asymmetricEncryptionFunction.encrypt(pubKey, data); | |||||
byte[] ciphertextBytes = ciphertext.toBytes(); | |||||
assertTrue(asymmetricEncryptionFunction.supportCiphertext(ciphertextBytes)); | |||||
algorithm = Crypto.getAlgorithm("ripemd160"); | |||||
assertNotNull(algorithm); | |||||
byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); | |||||
byte[] rawCiphertextBytes = ciphertext.toBytes(); | |||||
byte[] ripemd160CiphertextBytes = BytesUtils.concat(algoBytes, rawCiphertextBytes); | |||||
assertFalse(asymmetricEncryptionFunction.supportCiphertext(ripemd160CiphertextBytes)); | |||||
} | |||||
@Test | |||||
public void resolveCiphertextTest() { | |||||
byte[] data = new byte[128]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); | |||||
assertNotNull(algorithm); | |||||
AsymmetricEncryptionFunction asymmetricEncryptionFunction = Crypto | |||||
.getAsymmetricEncryptionFunction(algorithm); | |||||
AsymmetricKeypair keyPair = asymmetricEncryptionFunction.generateKeypair(); | |||||
PubKey pubKey = keyPair.getPubKey(); | |||||
Ciphertext ciphertext = asymmetricEncryptionFunction.encrypt(pubKey, data); | |||||
byte[] ciphertextBytes = ciphertext.toBytes(); | |||||
Ciphertext resolvedCiphertext = asymmetricEncryptionFunction.resolveCiphertext(ciphertextBytes); | |||||
assertEquals(256, resolvedCiphertext.getRawCiphertext().length); | |||||
assertEquals(ClassicAlgorithm.RSA.code(), resolvedCiphertext.getAlgorithm()); | |||||
assertEquals((short) (SIGNATURE_ALGORITHM | ENCRYPTION_ALGORITHM | ASYMMETRIC_KEY | ((byte) 23 & 0x00FF)), | |||||
resolvedCiphertext.getAlgorithm()); | |||||
assertArrayEquals(ciphertextBytes, resolvedCiphertext.toBytes()); | |||||
algorithm = Crypto.getAlgorithm("ripemd160"); | |||||
assertNotNull(algorithm); | |||||
byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); | |||||
byte[] rawCiphertextBytes = ciphertext.getRawCiphertext(); | |||||
byte[] ripemd160CiphertextBytes = BytesUtils.concat(algoBytes, rawCiphertextBytes); | |||||
Class<?> expectedException = CryptoException.class; | |||||
Exception actualEx = null; | |||||
try { | |||||
asymmetricEncryptionFunction.resolveCiphertext(ripemd160CiphertextBytes); | |||||
} catch (Exception e) { | |||||
actualEx = e; | |||||
} | |||||
assertNotNull(actualEx); | |||||
assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); | |||||
} | |||||
} |
@@ -0,0 +1,100 @@ | |||||
package test.com.jd.blockchain.crypto.utils.classic; | |||||
import com.jd.blockchain.crypto.utils.classic.AESUtils; | |||||
import com.jd.blockchain.utils.io.BytesUtils; | |||||
import org.bouncycastle.util.encoders.Hex; | |||||
import org.junit.Test; | |||||
import java.util.Random; | |||||
import static org.junit.Assert.assertArrayEquals; | |||||
import static org.junit.Assert.assertEquals; | |||||
/** | |||||
* @author zhanglin33 | |||||
* @title: AESUtilsTest | |||||
* @description: Tests for methods in AESUtils | |||||
* @date 2019-04-22, 16:06 | |||||
*/ | |||||
public class AESUtilsTest { | |||||
@Test | |||||
public void generateKeyTest(){ | |||||
byte[] key = AESUtils.generateKey(); | |||||
assertEquals(16,key.length); | |||||
key = AESUtils.generateKey("abc".getBytes()); | |||||
assertArrayEquals( | |||||
Hex.decode("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad".substring(0,32)),key); | |||||
} | |||||
@Test | |||||
public void encryptTest(){ | |||||
String plaintext = "abc"; | |||||
String key = "1234567890123456"; | |||||
System.out.println(key.getBytes().length); | |||||
String iv = "1234567890123456"; | |||||
String expectedCiphertextIn2ndBlock = "f479efae2d41d23227f61e675fced95c"; | |||||
byte[] ciphertext = AESUtils.encrypt(plaintext.getBytes(),key.getBytes(),iv.getBytes()); | |||||
byte[] expectedCiphertext = BytesUtils.concat(iv.getBytes(),Hex.decode(expectedCiphertextIn2ndBlock)); | |||||
assertArrayEquals(expectedCiphertext,ciphertext); | |||||
} | |||||
@Test | |||||
public void decryptTest(){ | |||||
Random random = new Random(); | |||||
byte[] data = new byte[1024]; | |||||
random.nextBytes(data); | |||||
byte[] key = AESUtils.generateKey(); | |||||
byte[] ciphertext = AESUtils.encrypt(data,key); | |||||
byte[] plaintext = AESUtils.decrypt(ciphertext,key); | |||||
assertArrayEquals(data,plaintext); | |||||
} | |||||
// | |||||
// | |||||
// @Test | |||||
// public void encryptingPerformance() { | |||||
// | |||||
// byte[] data = new byte[1000]; | |||||
// Random random = new Random(); | |||||
// random.nextBytes(data); | |||||
// | |||||
// byte[] aesCiphertext = null; | |||||
// | |||||
// int count = 100000; | |||||
// | |||||
// | |||||
// byte[] aesKey = AESUtils.generateKey(); | |||||
// | |||||
// System.out.println("=================== do AES encrypt test ==================="); | |||||
// for (int r = 0; r < 5; r++) { | |||||
// System.out.println("------------- round[" + r + "] --------------"); | |||||
// long startTS = System.currentTimeMillis(); | |||||
// for (int i = 0; i < count; i++) { | |||||
// aesCiphertext = AESUtils.encrypt(data, aesKey); | |||||
// } | |||||
// long elapsedTS = System.currentTimeMillis() - startTS; | |||||
// System.out.println(String.format("AES Encrypting Count=%s; Elapsed Times=%s; KBPS=%.2f", count, elapsedTS, | |||||
// (count * 1000.00D) / elapsedTS)); | |||||
// } | |||||
// | |||||
// | |||||
// System.out.println("=================== do AES decrypt test ==================="); | |||||
// for (int r = 0; r < 5; r++) { | |||||
// System.out.println("------------- round[" + r + "] --------------"); | |||||
// long startTS = System.currentTimeMillis(); | |||||
// for (int i = 0; i < count; i++) { | |||||
// AESUtils.decrypt(aesCiphertext, aesKey); | |||||
// } | |||||
// long elapsedTS = System.currentTimeMillis() - startTS; | |||||
// System.out.println(String.format("AES Decrypting Count=%s; Elapsed Times=%s; KBPS=%.2f", count, elapsedTS, | |||||
// (count * 1000.00D) / elapsedTS)); | |||||
// } | |||||
// } | |||||
} |
@@ -2,16 +2,20 @@ package test.com.jd.blockchain.crypto.utils.classic; | |||||
import com.jd.blockchain.crypto.utils.classic.ECDSAUtils; | import com.jd.blockchain.crypto.utils.classic.ECDSAUtils; | ||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair; | import org.bouncycastle.crypto.AsymmetricCipherKeyPair; | ||||
import org.bouncycastle.crypto.CipherParameters; | |||||
import org.bouncycastle.crypto.params.ECDomainParameters; | import org.bouncycastle.crypto.params.ECDomainParameters; | ||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters; | import org.bouncycastle.crypto.params.ECPrivateKeyParameters; | ||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters; | import org.bouncycastle.crypto.params.ECPublicKeyParameters; | ||||
import org.bouncycastle.crypto.params.ParametersWithRandom; | |||||
import org.bouncycastle.math.ec.ECMultiplier; | import org.bouncycastle.math.ec.ECMultiplier; | ||||
import org.bouncycastle.math.ec.ECPoint; | import org.bouncycastle.math.ec.ECPoint; | ||||
import org.bouncycastle.math.ec.FixedPointCombMultiplier; | import org.bouncycastle.math.ec.FixedPointCombMultiplier; | ||||
import org.bouncycastle.util.encoders.Hex; | import org.bouncycastle.util.encoders.Hex; | ||||
import org.bouncycastle.util.test.FixedSecureRandom; | |||||
import org.junit.Test; | import org.junit.Test; | ||||
import java.math.BigInteger; | import java.math.BigInteger; | ||||
import java.security.SecureRandom; | |||||
import java.util.Random; | import java.util.Random; | ||||
import static org.junit.Assert.*; | import static org.junit.Assert.*; | ||||
@@ -110,6 +114,80 @@ public class ECDSAUtilsTest { | |||||
assertEquals("04" + xCoord + yCoord,Hex.toHexString(result).toUpperCase()); | assertEquals("04" + xCoord + yCoord,Hex.toHexString(result).toUpperCase()); | ||||
} | } | ||||
@Test | |||||
public void checkDeterministicValues(){ | |||||
// https://crypto.stackexchange.com/questions/41316/complete-set-of-test-vectors-for-ecdsa-secp256k1 | |||||
ECDomainParameters domainParams = ECDSAUtils.getDomainParams(); | |||||
ECPrivateKeyParameters privKey = new ECPrivateKeyParameters( | |||||
new BigInteger("ebb2c082fd7727890a28ac82f6bdf97bad8de9f5d7c9028692de1a255cad3e0f", 16), | |||||
domainParams); | |||||
ECPublicKeyParameters pubKey = new ECPublicKeyParameters( | |||||
domainParams.getCurve().decodePoint(Hex.decode("04" + | |||||
"779dd197a5df977ed2cf6cb31d82d43328b790dc6b3b7d4437a427bd5847dfcd" + | |||||
"e94b724a555b6d017bb7607c3e3281daf5b1699d6ef4124975c9237b917d426f")), | |||||
domainParams); | |||||
byte[] privKeyBytes = BigIntegerTo32Bytes(privKey.getD()); | |||||
byte[] pubKeyBytes = ECDSAUtils.retrievePublicKey(privKeyBytes); | |||||
assertArrayEquals(pubKeyBytes,pubKey.getQ().getEncoded(false)); | |||||
SecureRandom k = new FixedSecureRandom(Hex.decode("49a0d7b786ec9cde0d0721d72804befd06571c974b191efb42ecf322ba9ddd9a")); | |||||
CipherParameters params = new ParametersWithRandom(privKey,k); | |||||
byte[] hashedMsg = Hex.decode("4b688df40bcedbe641ddb16ff0a1842d9c67ea1c3bf63f3e0471baa664531d1a"); | |||||
byte[] signature = ECDSAUtils.sign(params,hashedMsg); | |||||
String r = "241097efbf8b63bf145c8961dbdf10c310efbb3b2676bbc0f8b08505c9e2f795"; | |||||
String s = "021006b7838609339e8b415a7f9acb1b661828131aef1ecbc7955dfb01f3ca0e"; | |||||
assertEquals(Hex.toHexString(signature),r + s); | |||||
assertTrue(ECDSAUtils.verify(pubKey,signature,hashedMsg)); | |||||
} | |||||
@Test | |||||
public void performanceTest(){ | |||||
int count = 10000; | |||||
byte[] data = new byte[1024]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
AsymmetricCipherKeyPair keyPair = ECDSAUtils.generateKeyPair(); | |||||
ECPrivateKeyParameters privKeyParams = (ECPrivateKeyParameters) keyPair.getPrivate(); | |||||
ECPublicKeyParameters pubKeyParams = (ECPublicKeyParameters) keyPair.getPublic(); | |||||
byte[] signatureDigest = ECDSAUtils.sign(data,privKeyParams); | |||||
assertTrue(ECDSAUtils.verify(data,pubKeyParams,signatureDigest)); | |||||
System.out.println("=================== do ECDSA sign test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
ECDSAUtils.sign(data,privKeyParams); | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("ECDSA Signing Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
System.out.println("=================== do ECDSA verify test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
ECDSAUtils.verify(data,pubKeyParams,signatureDigest); | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("ECDSA Verifying Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
} | |||||
// To convert BigInteger to byte[] whose length is 32 | // To convert BigInteger to byte[] whose length is 32 | ||||
private static byte[] BigIntegerTo32Bytes(BigInteger b){ | private static byte[] BigIntegerTo32Bytes(BigInteger b){ | ||||
byte[] tmp = b.toByteArray(); | byte[] tmp = b.toByteArray(); | ||||
@@ -122,6 +200,4 @@ public class ECDSAUtilsTest { | |||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
} | } |
@@ -108,4 +108,76 @@ public class ED25519UtilsTest { | |||||
assertTrue(Ed25519Utils.verify(data,pubKeyBytes,signatureDigest)); | assertTrue(Ed25519Utils.verify(data,pubKeyBytes,signatureDigest)); | ||||
} | } | ||||
@Test | |||||
public void performanceTest(){ | |||||
int count = 10000; | |||||
byte[] data = new byte[1024]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
AsymmetricCipherKeyPair keyPair = ED25519Utils.generateKeyPair(); | |||||
Ed25519PrivateKeyParameters privKeyParams = (Ed25519PrivateKeyParameters) keyPair.getPrivate(); | |||||
Ed25519PublicKeyParameters pubKeyParams = (Ed25519PublicKeyParameters) keyPair.getPublic(); | |||||
byte[] pubKeyBytes = pubKeyParams.getEncoded(); | |||||
byte[] privKeyBytes = privKeyParams.getEncoded(); | |||||
byte[] signatureDigest = ED25519Utils.sign(data,privKeyParams); | |||||
assertTrue(ED25519Utils.verify(data,pubKeyParams,signatureDigest)); | |||||
System.out.println("=================== do ED25519 sign test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
ED25519Utils.sign(data,privKeyParams); | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("ED25519 Signing Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
System.out.println("=================== do ED25519 verify test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
ED25519Utils.verify(data,pubKeyParams,signatureDigest); | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("ED25519 Verifying Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
System.out.println("=================== do ED25519 sign test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
Ed25519Utils.sign_512(data,privKeyBytes); | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("ED25519 Signing Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
System.out.println("=================== do ED25519 verify test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
Ed25519Utils.verify(data,pubKeyBytes,signatureDigest); | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("ED25519 Verifying Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
} | |||||
} | } |
@@ -0,0 +1,32 @@ | |||||
package test.com.jd.blockchain.crypto.utils.classic; | |||||
import com.jd.blockchain.crypto.utils.classic.RIPEMD160Utils; | |||||
import org.bouncycastle.util.encoders.Hex; | |||||
import org.junit.Test; | |||||
import static org.junit.Assert.assertEquals; | |||||
/** | |||||
* @author zhanglin33 | |||||
* @title: RIPEMD160UtilsTest | |||||
* @description: Tests for the hash method in RIPEMD160Utils | |||||
* @date 2019-04-10, 16:54 | |||||
*/ | |||||
public class RIPEMD160UtilsTest { | |||||
@Test | |||||
public void hashTest() { | |||||
byte[] data1 = "a".getBytes(); | |||||
byte[] data2 = "abc".getBytes(); | |||||
byte[] result1 = RIPEMD160Utils.hash(data1); | |||||
byte[] result2 = RIPEMD160Utils.hash(data2); | |||||
String respectedResult1 = "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"; | |||||
String respectedResult2 = "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"; | |||||
assertEquals(respectedResult1, Hex.toHexString(result1)); | |||||
assertEquals(respectedResult2, Hex.toHexString(result2)); | |||||
} | |||||
} |
@@ -0,0 +1,426 @@ | |||||
package test.com.jd.blockchain.crypto.utils.classic; | |||||
import com.jd.blockchain.crypto.utils.classic.RSAUtils; | |||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair; | |||||
import org.bouncycastle.crypto.params.AsymmetricKeyParameter; | |||||
import org.bouncycastle.crypto.params.RSAKeyParameters; | |||||
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; | |||||
import org.junit.Test; | |||||
import javax.crypto.BadPaddingException; | |||||
import javax.crypto.Cipher; | |||||
import javax.crypto.IllegalBlockSizeException; | |||||
import javax.crypto.NoSuchPaddingException; | |||||
import java.security.*; | |||||
import java.security.interfaces.RSAPrivateKey; | |||||
import java.security.interfaces.RSAPublicKey; | |||||
import java.util.Random; | |||||
import static org.junit.Assert.*; | |||||
/** | |||||
* @author zhanglin33 | |||||
* @title: RSAUtilsTest | |||||
* @description: Tests for methods in RSAUtils | |||||
* @date 2019-04-11, 17:10 | |||||
*/ | |||||
public class RSAUtilsTest { | |||||
@Test | |||||
public void generateKeyPairTest(){ | |||||
AsymmetricCipherKeyPair kp = RSAUtils.generateKeyPair(); | |||||
RSAKeyParameters pubKey = (RSAKeyParameters) kp.getPublic(); | |||||
RSAPrivateCrtKeyParameters privKey = (RSAPrivateCrtKeyParameters) kp.getPrivate(); | |||||
byte[] pubKeyBytes_RawKey = RSAUtils.pubKey2Bytes_RawKey(pubKey); | |||||
byte[] pubKeyBytesConverted_RawKey = | |||||
RSAUtils.pubKey2Bytes_RawKey(RSAUtils.bytes2PubKey_RawKey(pubKeyBytes_RawKey)); | |||||
assertArrayEquals(pubKeyBytes_RawKey,pubKeyBytesConverted_RawKey); | |||||
byte[] privKeyBytes_RawKey = RSAUtils.privKey2Bytes_RawKey(privKey); | |||||
byte[] privKeyBytesConverted_RawKey = | |||||
RSAUtils.privKey2Bytes_RawKey(RSAUtils.bytes2PrivKey_RawKey(privKeyBytes_RawKey)); | |||||
assertArrayEquals(privKeyBytes_RawKey,privKeyBytesConverted_RawKey); | |||||
System.out.println(pubKeyBytes_RawKey.length); | |||||
System.out.println(privKeyBytes_RawKey.length); | |||||
byte[] pubKeyBytes_PKCS1 = RSAUtils.pubKey2Bytes_PKCS1(pubKey); | |||||
byte[] pubKeyBytesConverted_PKCS1 = | |||||
RSAUtils.pubKey2Bytes_PKCS1(RSAUtils.bytes2PubKey_PKCS1(pubKeyBytes_PKCS1)); | |||||
assertArrayEquals(pubKeyBytes_PKCS1,pubKeyBytesConverted_PKCS1); | |||||
byte[] privKeyBytes_PKCS1 = RSAUtils.privKey2Bytes_PKCS1(privKey); | |||||
byte[] privKeyBytesConverted_PKCS1 = | |||||
RSAUtils.privKey2Bytes_PKCS1(RSAUtils.bytes2PrivKey_PKCS1(privKeyBytes_PKCS1)); | |||||
assertArrayEquals(privKeyBytes_PKCS1,privKeyBytesConverted_PKCS1); | |||||
byte[] pubKeyBytes_PKCS8 = RSAUtils.pubKey2Bytes_PKCS8(pubKey); | |||||
byte[] pubKeyBytesConverted_PKCS8 = | |||||
RSAUtils.pubKey2Bytes_PKCS8(RSAUtils.bytes2PubKey_PKCS8(pubKeyBytes_PKCS8)); | |||||
assertArrayEquals(pubKeyBytes_PKCS8,pubKeyBytesConverted_PKCS8); | |||||
byte[] privKeyBytes_PKCS8 = RSAUtils.privKey2Bytes_PKCS8(privKey); | |||||
byte[] privKeyBytesConverted_PKCS8 = | |||||
RSAUtils.privKey2Bytes_PKCS8(RSAUtils.bytes2PrivKey_PKCS8(privKeyBytes_PKCS8)); | |||||
assertArrayEquals(privKeyBytes_PKCS8,privKeyBytesConverted_PKCS8); | |||||
} | |||||
@Test | |||||
public void retrievePublicKeyTest(){ | |||||
AsymmetricCipherKeyPair kp = RSAUtils.generateKeyPair(); | |||||
RSAKeyParameters pubKey = (RSAKeyParameters) kp.getPublic(); | |||||
RSAPrivateCrtKeyParameters privKey = (RSAPrivateCrtKeyParameters) kp.getPrivate(); | |||||
byte[] privKeyBytes = RSAUtils.privKey2Bytes_RawKey(privKey); | |||||
byte[] pubKeyBytes = RSAUtils.pubKey2Bytes_RawKey(pubKey); | |||||
byte[] retrievedPubKeyBytes = RSAUtils.retrievePublicKey(privKeyBytes); | |||||
assertArrayEquals(pubKeyBytes,retrievedPubKeyBytes); | |||||
} | |||||
@Test | |||||
public void signTest(){ | |||||
byte[] data = new byte[1024]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
AsymmetricCipherKeyPair keyPair = RSAUtils.generateKeyPair(); | |||||
AsymmetricKeyParameter privKey = keyPair.getPrivate(); | |||||
byte[] privKeyBytes = RSAUtils.privKey2Bytes_RawKey((RSAPrivateCrtKeyParameters) privKey); | |||||
byte[] signatureFromPrivKey = RSAUtils.sign(data, privKey); | |||||
byte[] signatureFromPrivKeyBytes = RSAUtils.sign(data, privKeyBytes); | |||||
assertNotNull(signatureFromPrivKey); | |||||
assertEquals(2048 / 8, signatureFromPrivKey.length); | |||||
assertArrayEquals(signatureFromPrivKeyBytes,signatureFromPrivKey); | |||||
} | |||||
@Test | |||||
public void verifyTest(){ | |||||
byte[] data = new byte[1024]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
AsymmetricCipherKeyPair keyPair = RSAUtils.generateKeyPair(); | |||||
AsymmetricKeyParameter privKey = keyPair.getPrivate(); | |||||
AsymmetricKeyParameter pubKey = keyPair.getPublic(); | |||||
byte[] pubKeyBytes = RSAUtils.pubKey2Bytes_RawKey((RSAKeyParameters) pubKey); | |||||
byte[] signature = RSAUtils.sign(data,privKey); | |||||
boolean isValidFromPubKey = RSAUtils.verify(data, pubKey, signature); | |||||
boolean isValidFromPubKeyBytes = RSAUtils.verify(data, pubKeyBytes, signature); | |||||
assertTrue(isValidFromPubKey); | |||||
assertTrue(isValidFromPubKeyBytes); | |||||
} | |||||
@Test | |||||
public void encryptTest(){ | |||||
byte[] data = new byte[246]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
AsymmetricCipherKeyPair keyPair = RSAUtils.generateKeyPair(); | |||||
AsymmetricKeyParameter pubKey = keyPair.getPublic(); | |||||
byte[] pubKeyBytes = RSAUtils.pubKey2Bytes_RawKey((RSAKeyParameters) pubKey); | |||||
byte[] ciphertextFromPubKey = RSAUtils.encrypt(data,pubKey); | |||||
byte[] ciphertextFromPubKeyBytes = RSAUtils.encrypt(data,pubKeyBytes); | |||||
assertEquals(512,ciphertextFromPubKey.length); | |||||
assertEquals(512,ciphertextFromPubKeyBytes.length); | |||||
} | |||||
@Test | |||||
public void decryptTest(){ | |||||
AsymmetricCipherKeyPair keyPair = RSAUtils.generateKeyPair(); | |||||
AsymmetricKeyParameter pubKey = keyPair.getPublic(); | |||||
AsymmetricKeyParameter privKey = keyPair.getPrivate(); | |||||
byte[] privKeyBytes = RSAUtils.privKey2Bytes_RawKey((RSAPrivateCrtKeyParameters) privKey); | |||||
byte[] data; | |||||
for (int i = 1; i < 1024; i++) { | |||||
data = new byte[i]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
byte[] ciphertext = RSAUtils.encrypt(data, pubKey); | |||||
byte[] plaintextFromPrivKey = RSAUtils.decrypt(ciphertext, privKey); | |||||
byte[] plaintextFromPrivKeyBytes = RSAUtils.decrypt(ciphertext, privKeyBytes); | |||||
assertArrayEquals(data, plaintextFromPrivKey); | |||||
assertArrayEquals(data, plaintextFromPrivKeyBytes); | |||||
} | |||||
} | |||||
@Test | |||||
public void performanceTest(){ | |||||
int count = 10000; | |||||
byte[] data = new byte[128]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
AsymmetricCipherKeyPair keyPair = RSAUtils.generateKeyPair(); | |||||
AsymmetricKeyParameter privKey = keyPair.getPrivate(); | |||||
AsymmetricKeyParameter pubKey = keyPair.getPublic(); | |||||
byte[] signature = RSAUtils.sign(data,privKey); | |||||
byte[] ciphertext = RSAUtils.encrypt(data,pubKey); | |||||
System.out.println("=================== do RSA sign test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
RSAUtils.sign(data,privKey); | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("RSA Signing Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
System.out.println("=================== do RSA verify test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
RSAUtils.verify(data,pubKey,signature); | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("RSA Verifying Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
System.out.println("=================== do RSA encrypt test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
RSAUtils.encrypt(data,pubKey); | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("RSA Encrypting Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
System.out.println("=================== do RSA decrypt test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
RSAUtils.decrypt(ciphertext,privKey); | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("RSA Decrypting Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
} | |||||
@Test | |||||
public void encryptionConsistencyTest(){ | |||||
int count = 10000; | |||||
byte[] data = new byte[222]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
KeyPairGenerator keyPairGen = null; | |||||
try { | |||||
keyPairGen = KeyPairGenerator.getInstance("RSA"); | |||||
} catch (NoSuchAlgorithmException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
assert keyPairGen != null; | |||||
keyPairGen.initialize(2048, new SecureRandom()); | |||||
KeyPair keyPair = keyPairGen.generateKeyPair(); | |||||
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); | |||||
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); | |||||
byte[] publicKeyBytes = publicKey.getEncoded(); | |||||
byte[] privateKeyBytes = privateKey.getEncoded(); | |||||
RSAKeyParameters pubKey = RSAUtils.bytes2PubKey_PKCS8(publicKeyBytes); | |||||
RSAPrivateCrtKeyParameters privKey = RSAUtils.bytes2PrivKey_PKCS8(privateKeyBytes); | |||||
Cipher cipher; | |||||
byte[] ciphertext = null; | |||||
byte[] plaintext = null; | |||||
System.out.println("=================== do BouncyCastle-based RSA encrypt test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
ciphertext = RSAUtils.encrypt(data,pubKey); | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("BouncyCastle-based RSA Encrypting Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
assert ciphertext != null; | |||||
System.out.println("=================== do BouncyCastle-based RSA decrypt test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
plaintext = RSAUtils.decrypt(ciphertext,privKey); | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("BouncyCastle-based RSA Decrypting Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
System.out.println("=================== do JDK-based RSA encrypt test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
try { | |||||
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); | |||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey); | |||||
ciphertext = cipher.doFinal(data); | |||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | |||||
| IllegalBlockSizeException | BadPaddingException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("JDK-based RSA Encrypting Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
System.out.println("=================== do JDK-based RSA decrypt test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
try { | |||||
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); | |||||
cipher.init(Cipher.DECRYPT_MODE, privateKey); | |||||
plaintext = cipher.doFinal(ciphertext); | |||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | |||||
| IllegalBlockSizeException | BadPaddingException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("JDK-based RSA Decrypting Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
assertArrayEquals(data,plaintext); | |||||
assertArrayEquals(data,plaintext); | |||||
} | |||||
@Test | |||||
public void signatureConsistencyTest() { | |||||
int count = 10000; | |||||
byte[] data = new byte[222]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
KeyPairGenerator keyPairGen = null; | |||||
try { | |||||
keyPairGen = KeyPairGenerator.getInstance("RSA"); | |||||
} catch (NoSuchAlgorithmException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
assert keyPairGen != null; | |||||
keyPairGen.initialize(2048, new SecureRandom()); | |||||
KeyPair keyPair = keyPairGen.generateKeyPair(); | |||||
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); | |||||
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); | |||||
byte[] publicKeyBytes = publicKey.getEncoded(); | |||||
byte[] privateKeyBytes = privateKey.getEncoded(); | |||||
byte[] signature = null; | |||||
boolean isValid = false; | |||||
RSAKeyParameters pubKey = RSAUtils.bytes2PubKey_PKCS8(publicKeyBytes); | |||||
RSAPrivateCrtKeyParameters privKey = RSAUtils.bytes2PrivKey_PKCS8(privateKeyBytes); | |||||
System.out.println("=================== do BouncyCastle-based RSA sign test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
signature = RSAUtils.sign(data,privKey); | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("BouncyCastle-based RSA Signing Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
System.out.println("=================== do BouncyCastle-based RSA verify test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
isValid = RSAUtils.verify(data,pubKey,signature); | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("BouncyCastle-based RSA Verifying Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
System.out.println("=================== do JDK-based RSA sign test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
try { | |||||
Signature signer = Signature.getInstance("SHA256withRSA"); | |||||
signer.initSign(privateKey); | |||||
signer.update(data); | |||||
signature = signer.sign(); | |||||
} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("JDK-based RSA Signing Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
System.out.println("=================== do JDK-based RSA verify test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
try { | |||||
Signature verifier = Signature.getInstance("SHA256withRSA"); | |||||
verifier.initVerify(publicKey); | |||||
verifier.update(data); | |||||
isValid = verifier.verify(signature); | |||||
} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("JDK-based RSA Verifying Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
System.out.println(isValid); | |||||
} | |||||
} |
@@ -9,7 +9,7 @@ import static org.junit.Assert.assertEquals; | |||||
/** | /** | ||||
* @author zhanglin33 | * @author zhanglin33 | ||||
* @title: SHA256UtilsTest | * @title: SHA256UtilsTest | ||||
* @description: Tests for the hash method in ECDSAUtils | |||||
* @description: Tests for the hash method in SHA256Utils | |||||
* @date 2019-04-09, 16:18 | * @date 2019-04-09, 16:18 | ||||
*/ | */ | ||||
public class SHA256UtilsTest { | public class SHA256UtilsTest { | ||||
@@ -7,9 +7,9 @@ public abstract class BaseCryptoKey extends BaseCryptoBytes implements CryptoKey | |||||
public static final int KEY_TYPE_BYTES = 1; | public static final int KEY_TYPE_BYTES = 1; | ||||
private static final long serialVersionUID = 4543074827807908363L; | private static final long serialVersionUID = 4543074827807908363L; | ||||
// public BaseCryptoKey() { | |||||
// super(); | |||||
// } | |||||
public BaseCryptoKey() { | |||||
super(); | |||||
} | |||||
protected BaseCryptoKey(short algorithm, byte[] rawKeyBytes, CryptoKeyType keyType) { | protected BaseCryptoKey(short algorithm, byte[] rawKeyBytes, CryptoKeyType keyType) { | ||||
super(algorithm, CryptoBytesEncoding.encodeKeyBytes(rawKeyBytes, keyType)); | super(algorithm, CryptoBytesEncoding.encodeKeyBytes(rawKeyBytes, keyType)); | ||||
@@ -7,6 +7,7 @@ package com.jd.blockchain.crypto; | |||||
* | * | ||||
*/ | */ | ||||
public class PrivKey extends BaseCryptoKey { | public class PrivKey extends BaseCryptoKey { | ||||
private static final long serialVersionUID = 6265440395252295646L; | private static final long serialVersionUID = 6265440395252295646L; | ||||
public PrivKey(short algorithm, byte[] rawCryptoBytes) { | public PrivKey(short algorithm, byte[] rawCryptoBytes) { | ||||
@@ -9,7 +9,11 @@ package com.jd.blockchain.crypto; | |||||
public class PubKey extends BaseCryptoKey { | public class PubKey extends BaseCryptoKey { | ||||
private static final long serialVersionUID = -2055071197736385328L; | private static final long serialVersionUID = -2055071197736385328L; | ||||
public PubKey() { | |||||
super(); | |||||
} | |||||
public PubKey(short algorithm, byte[] rawCryptoBytes) { | public PubKey(short algorithm, byte[] rawCryptoBytes) { | ||||
super(algorithm, rawCryptoBytes, CryptoKeyType.PUBLIC); | super(algorithm, rawCryptoBytes, CryptoKeyType.PUBLIC); | ||||
} | } | ||||
@@ -1,78 +0,0 @@ | |||||
package com.jd.blockchain.crypto.serialize; | |||||
import com.alibaba.fastjson.parser.DefaultJSONParser; | |||||
import com.alibaba.fastjson.parser.JSONToken; | |||||
import com.alibaba.fastjson.parser.ParserConfig; | |||||
import com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.crypto.SignatureDigest; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
import com.jd.blockchain.utils.codec.Base58Utils; | |||||
import com.jd.blockchain.utils.io.BytesSlice; | |||||
import java.lang.reflect.InvocationTargetException; | |||||
import java.lang.reflect.Type; | |||||
import java.util.Map; | |||||
public class ByteArrayObjectDeserializer extends JavaBeanDeserializer { | |||||
private ByteArrayObjectDeserializer(Class<?> clazz) { | |||||
super(ParserConfig.global, clazz); | |||||
} | |||||
public static ByteArrayObjectDeserializer getInstance(Class<?> clazz) { | |||||
return new ByteArrayObjectDeserializer(clazz); | |||||
} | |||||
@SuppressWarnings("unchecked") | |||||
@Override | |||||
public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) { | |||||
if (type instanceof Class && clazz.isAssignableFrom((Class<?>) type)) { | |||||
String base58Str = parser.parseObject(String.class); | |||||
byte[] hashBytes = Base58Utils.decode(base58Str); | |||||
if (clazz == HashDigest.class) { | |||||
return (T) new HashDigest(hashBytes); | |||||
} else if (clazz == PubKey.class) { | |||||
return (T) new HashDigest(hashBytes); | |||||
} else if (clazz == SignatureDigest.class) { | |||||
return (T) new SignatureDigest(hashBytes); | |||||
} else if (clazz == Bytes.class) { | |||||
return (T) new Bytes(hashBytes); | |||||
} else if (clazz == BytesSlice.class) { | |||||
return (T) new BytesSlice(hashBytes); | |||||
} | |||||
} | |||||
return (T) parser.parse(fieldName); | |||||
} | |||||
@Override | |||||
public Object createInstance(Map<String, Object> map, ParserConfig config) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { | |||||
if (map == null || map.isEmpty()) { | |||||
return null; | |||||
} | |||||
for (Map.Entry<String, Object> entry : map.entrySet()) { | |||||
Object value = entry.getValue(); | |||||
if (value instanceof String) { | |||||
byte[] hashBytes = Base58Utils.decode((String)value); | |||||
if (clazz == HashDigest.class) { | |||||
return new HashDigest(hashBytes); | |||||
} else if (clazz == PubKey.class) { | |||||
return new PubKey(hashBytes); | |||||
} else if (clazz == SignatureDigest.class) { | |||||
return new SignatureDigest(hashBytes); | |||||
} else if (clazz == Bytes.class) { | |||||
return new Bytes(hashBytes); | |||||
} else if (clazz == BytesSlice.class) { | |||||
return new BytesSlice(hashBytes); | |||||
} | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
@Override | |||||
public int getFastMatchToken() { | |||||
return JSONToken.LBRACE; | |||||
} | |||||
} |
@@ -1,63 +0,0 @@ | |||||
package com.jd.blockchain.crypto.serialize; | |||||
import java.lang.reflect.Type; | |||||
import com.alibaba.fastjson.serializer.JSONSerializer; | |||||
import com.alibaba.fastjson.serializer.ObjectSerializer; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.crypto.SignatureDigest; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
import com.jd.blockchain.utils.io.BytesSlice; | |||||
public class ByteArrayObjectSerializer implements ObjectSerializer { | |||||
private Class<?> clazz; | |||||
private ByteArrayObjectSerializer(Class<?> clazz) { | |||||
this.clazz = clazz; | |||||
} | |||||
public static ByteArrayObjectSerializer getInstance(Class<?> clazz) { | |||||
return new ByteArrayObjectSerializer(clazz); | |||||
} | |||||
@Override | |||||
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) { | |||||
if (object.getClass() != clazz) { | |||||
serializer.writeNull(); | |||||
return; | |||||
} | |||||
if (object instanceof HashDigest) { | |||||
serializer.write(new HashDigestJson(((HashDigest) object).toBase58())); | |||||
} else if (object instanceof PubKey) { | |||||
serializer.write(new HashDigestJson(((PubKey) object).toBase58())); | |||||
} else if (object instanceof SignatureDigest) { | |||||
serializer.write(new HashDigestJson(((SignatureDigest) object).toBase58())); | |||||
} else if (object instanceof Bytes) { | |||||
serializer.write(new HashDigestJson(((Bytes) object).toBase58())); | |||||
} else if (object instanceof BytesSlice) { | |||||
byte[] bytes = ((BytesSlice) object).toBytes(); | |||||
serializer.write(new HashDigestJson(new String(bytes))); | |||||
} | |||||
} | |||||
private static class HashDigestJson { | |||||
String value; | |||||
public HashDigestJson(String value) { | |||||
this.value = value; | |||||
} | |||||
@SuppressWarnings("unused") | |||||
public String getValue() { | |||||
return value; | |||||
} | |||||
@SuppressWarnings("unused") | |||||
public void setValue(String value) { | |||||
this.value = value; | |||||
} | |||||
} | |||||
} |
@@ -72,7 +72,7 @@ public class SM2CryptoFunction implements AsymmetricEncryptionFunction, Signatur | |||||
throw new CryptoException("This key is not SM2 private key!"); | throw new CryptoException("This key is not SM2 private key!"); | ||||
} | } | ||||
// 验证密文数据的算法标识对应SM2签名算法,并且原始摘要长度为64字节 | |||||
// 验证密文数据的算法标识对应SM2算法,并且密文符合长度要求 | |||||
if (ciphertext.getAlgorithm() != SM2.code() | if (ciphertext.getAlgorithm() != SM2.code() | ||||
|| rawCiphertextBytes.length < ECPOINT_SIZE + HASHDIGEST_SIZE) { | || rawCiphertextBytes.length < ECPOINT_SIZE + HASHDIGEST_SIZE) { | ||||
throw new CryptoException("This is not SM2 ciphertext!"); | throw new CryptoException("This is not SM2 ciphertext!"); | ||||
@@ -89,14 +89,6 @@ public class SM2CryptoFunction implements AsymmetricEncryptionFunction, Signatur | |||||
return new PubKey(SM2, rawPubKeyBytes); | return new PubKey(SM2, rawPubKeyBytes); | ||||
} | } | ||||
// @Override | |||||
// public byte[] retrievePubKey(byte[] privKeyBytes) { | |||||
// | |||||
// byte[] rawPrivKeyBytes = resolvePrivKey(privKeyBytes).getRawKeyBytes(); | |||||
// byte[] rawPubKeyBytes = SM2Utils.retrievePublicKey(rawPrivKeyBytes); | |||||
// return new PubKey(SM2, rawPubKeyBytes).toBytes(); | |||||
// } | |||||
@Override | @Override | ||||
public boolean supportPrivKey(byte[] privKeyBytes) { | public boolean supportPrivKey(byte[] privKeyBytes) { | ||||
// 验证输入字节数组长度=算法标识长度+密钥类型长度+密钥长度,密钥数据的算法标识对应SM2算法,并且密钥类型是私钥 | // 验证输入字节数组长度=算法标识长度+密钥类型长度+密钥长度,密钥数据的算法标识对应SM2算法,并且密钥类型是私钥 | ||||
@@ -109,7 +101,7 @@ public class SM2CryptoFunction implements AsymmetricEncryptionFunction, Signatur | |||||
if (supportPrivKey(privKeyBytes)) { | if (supportPrivKey(privKeyBytes)) { | ||||
return new PrivKey(privKeyBytes); | return new PrivKey(privKeyBytes); | ||||
} else { | } else { | ||||
throw new CryptoException("privKeyBytes is invalid!"); | |||||
throw new CryptoException("privKeyBytes are invalid!"); | |||||
} | } | ||||
} | } | ||||
@@ -125,7 +117,7 @@ public class SM2CryptoFunction implements AsymmetricEncryptionFunction, Signatur | |||||
if (supportPubKey(pubKeyBytes)) { | if (supportPubKey(pubKeyBytes)) { | ||||
return new PubKey(pubKeyBytes); | return new PubKey(pubKeyBytes); | ||||
} else { | } else { | ||||
throw new CryptoException("pubKeyBytes is invalid!"); | |||||
throw new CryptoException("pubKeyBytes are invalid!"); | |||||
} | } | ||||
} | } | ||||
@@ -141,7 +133,7 @@ public class SM2CryptoFunction implements AsymmetricEncryptionFunction, Signatur | |||||
if (supportCiphertext(ciphertextBytes)) { | if (supportCiphertext(ciphertextBytes)) { | ||||
return new AsymmetricCiphertext(ciphertextBytes); | return new AsymmetricCiphertext(ciphertextBytes); | ||||
} else { | } else { | ||||
throw new CryptoException("ciphertextBytes is invalid!"); | |||||
throw new CryptoException("ciphertextBytes are invalid!"); | |||||
} | } | ||||
} | } | ||||
@@ -200,7 +192,7 @@ public class SM2CryptoFunction implements AsymmetricEncryptionFunction, Signatur | |||||
if (supportDigest(digestBytes)) { | if (supportDigest(digestBytes)) { | ||||
return new SignatureDigest(digestBytes); | return new SignatureDigest(digestBytes); | ||||
} else { | } else { | ||||
throw new CryptoException("digestBytes is invalid!"); | |||||
throw new CryptoException("digestBytes are invalid!"); | |||||
} | } | ||||
} | } | ||||
@@ -11,11 +11,12 @@ import org.bouncycastle.crypto.params.ParametersWithIV; | |||||
import java.security.SecureRandom; | import java.security.SecureRandom; | ||||
import java.util.Arrays; | |||||
public class SM4Utils { | public class SM4Utils { | ||||
// SM4 supports 128-bit secret key | |||||
private static final int KEY_LENGTH = 128; | |||||
// SM4 supports 128-bit(16 bytes) secret key | |||||
private static final int KEY_SIZE = 128 / 8; | |||||
// One block contains 16 bytes | // One block contains 16 bytes | ||||
private static final int BLOCK_SIZE = 16; | private static final int BLOCK_SIZE = 16; | ||||
// Initial vector's size is 16 bytes | // Initial vector's size is 16 bytes | ||||
@@ -33,12 +34,17 @@ public class SM4Utils { | |||||
// To provide secure randomness and key length as input | // To provide secure randomness and key length as input | ||||
// to prepare generate private key | // to prepare generate private key | ||||
keyGenerator.init(new KeyGenerationParameters(new SecureRandom(), KEY_LENGTH)); | |||||
keyGenerator.init(new KeyGenerationParameters(new SecureRandom(), KEY_SIZE * 8)); | |||||
// To generate key | // To generate key | ||||
return keyGenerator.generateKey(); | return keyGenerator.generateKey(); | ||||
} | } | ||||
public static byte[] generateKey(byte[] seed){ | |||||
byte[] hash = SM3Utils.hash(seed); | |||||
return Arrays.copyOf(hash, KEY_SIZE); | |||||
} | |||||
/** | /** | ||||
* encryption | * encryption | ||||
@@ -56,6 +62,16 @@ public class SM4Utils { | |||||
throw new CryptoException("plaintext is null!"); | throw new CryptoException("plaintext is null!"); | ||||
} | } | ||||
if (secretKey.length != KEY_SIZE) | |||||
{ | |||||
throw new CryptoException("secretKey's length is wrong!"); | |||||
} | |||||
if (iv.length != IV_SIZE) | |||||
{ | |||||
throw new CryptoException("iv's length is wrong!"); | |||||
} | |||||
// To get the value padded into input | // To get the value padded into input | ||||
int padding = 16 - plainBytes.length % BLOCK_SIZE; | int padding = 16 - plainBytes.length % BLOCK_SIZE; | ||||
// The plaintext with padding value | // The plaintext with padding value | ||||
@@ -105,11 +121,16 @@ public class SM4Utils { | |||||
} | } | ||||
// To ensure that the ciphertext's length is integral multiples of 16 bytes | // To ensure that the ciphertext's length is integral multiples of 16 bytes | ||||
if ( cipherBytes.length % BLOCK_SIZE != 0 ) | |||||
if (cipherBytes.length % BLOCK_SIZE != 0) | |||||
{ | { | ||||
throw new CryptoException("ciphertext's length is wrong!"); | throw new CryptoException("ciphertext's length is wrong!"); | ||||
} | } | ||||
if (secretKey.length != KEY_SIZE) | |||||
{ | |||||
throw new CryptoException("secretKey's length is wrong!"); | |||||
} | |||||
byte[] iv = new byte[IV_SIZE]; | byte[] iv = new byte[IV_SIZE]; | ||||
System.arraycopy(cipherBytes,0,iv,0,BLOCK_SIZE); | System.arraycopy(cipherBytes,0,iv,0,BLOCK_SIZE); | ||||
@@ -484,5 +484,4 @@ public class SM2CyptoFunctionTest { | |||||
assertNotNull(actualEx); | assertNotNull(actualEx); | ||||
assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); | assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); | ||||
} | } | ||||
} | } |
@@ -13,6 +13,8 @@ import org.junit.Test; | |||||
import com.jd.blockchain.crypto.utils.sm.SM2Utils; | import com.jd.blockchain.crypto.utils.sm.SM2Utils; | ||||
import java.util.Random; | |||||
public class SM2UtilsTest { | public class SM2UtilsTest { | ||||
@Test | @Test | ||||
@@ -160,74 +162,44 @@ public class SM2UtilsTest { | |||||
// } | // } | ||||
// | // | ||||
// | // | ||||
// @Test | |||||
// public void signingPerformace(){ | |||||
// | |||||
// byte[] data = new byte[1000]; | |||||
// Random random = new Random(); | |||||
// random.nextBytes(data); | |||||
// | |||||
// int count = 10000; | |||||
// | |||||
// byte[] sm2Digest = null; | |||||
// byte[] ed25519Digest = null; | |||||
// | |||||
// AsymmetricCipherKeyPair keyPair = SM2Utils.generateKeyPair(); | |||||
// ECPublicKeyParameters ecPub = (ECPublicKeyParameters) keyPair.getPublic(); | |||||
// ECPrivateKeyParameters ecPriv = (ECPrivateKeyParameters) keyPair.getPrivate(); | |||||
// | |||||
// System.out.println("=================== do SM2 sign test ==================="); | |||||
// | |||||
// for (int r = 0; r < 5; r++) { | |||||
// System.out.println("------------- round[" + r + "] --------------"); | |||||
// long startTS = System.currentTimeMillis(); | |||||
// for (int i = 0; i < count; i++) { | |||||
// sm2Digest = SM2Utils.sign(data,ecPriv); | |||||
// } | |||||
// long elapsedTS = System.currentTimeMillis() - startTS; | |||||
// System.out.println(String.format("SM2 Signing Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
// (count * 1000.00D) / elapsedTS)); | |||||
// } | |||||
// | |||||
// System.out.println("=================== do SM2 verify test ==================="); | |||||
// for (int r = 0; r < 5; r++) { | |||||
// System.out.println("------------- round[" + r + "] --------------"); | |||||
// long startTS = System.currentTimeMillis(); | |||||
// for (int i = 0; i < count; i++) { | |||||
// SM2Utils.verify(data,ecPub,sm2Digest); | |||||
// } | |||||
// long elapsedTS = System.currentTimeMillis() - startTS; | |||||
// System.out.println(String.format("SM2 Verifying Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
// (count * 1000.00D) / elapsedTS)); | |||||
// } | |||||
// | |||||
// KeyPairGenerator keyPairGenerator = new KeyPairGenerator(); | |||||
// KeyPair ed25519KeyPair = keyPairGenerator.generateKeyPair(); | |||||
// EdDSAPrivateKey privKey = (EdDSAPrivateKey) ed25519KeyPair.getPrivate(); | |||||
// EdDSAPublicKey pubKey = (EdDSAPublicKey) ed25519KeyPair.getPublic(); | |||||
// | |||||
// System.out.println("=================== do ED25519 sign test ==================="); | |||||
// for (int r = 0; r < 5; r++) { | |||||
// System.out.println("------------- round[" + r + "] --------------"); | |||||
// long startTS = System.currentTimeMillis(); | |||||
// for (int i = 0; i < count; i++) { | |||||
// ed25519Digest = Ed25519Utils.sign_512(data,privKey.getSeed()); | |||||
// } | |||||
// long elapsedTS = System.currentTimeMillis() - startTS; | |||||
// System.out.println(String.format("ED25519 Signing Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
// (count * 1000.00D) / elapsedTS)); | |||||
// } | |||||
// | |||||
// System.out.println("=================== do ED25519 verify test ==================="); | |||||
// for (int r = 0; r < 5; r++) { | |||||
// System.out.println("------------- round[" + r + "] --------------"); | |||||
// long startTS = System.currentTimeMillis(); | |||||
// for (int i = 0; i < count; i++) { | |||||
// Ed25519Utils.verify(data,pubKey.getAbyte(),ed25519Digest); | |||||
// } | |||||
// long elapsedTS = System.currentTimeMillis() - startTS; | |||||
// System.out.println(String.format("ED25519 Verifying Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
// (count * 1000.00D) / elapsedTS)); | |||||
// } | |||||
// } | |||||
@Test | |||||
public void signingPerformace(){ | |||||
byte[] data = new byte[1024]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
int count = 10000; | |||||
byte[] sm2Digest = null; | |||||
AsymmetricCipherKeyPair keyPair = SM2Utils.generateKeyPair(); | |||||
ECPublicKeyParameters ecPub = (ECPublicKeyParameters) keyPair.getPublic(); | |||||
ECPrivateKeyParameters ecPriv = (ECPrivateKeyParameters) keyPair.getPrivate(); | |||||
System.out.println("=================== do SM2 sign test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
sm2Digest = SM2Utils.sign(data,ecPriv); | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("SM2 Signing Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
System.out.println("=================== do SM2 verify test ==================="); | |||||
for (int r = 0; r < 5; r++) { | |||||
System.out.println("------------- round[" + r + "] --------------"); | |||||
long startTS = System.currentTimeMillis(); | |||||
for (int i = 0; i < count; i++) { | |||||
SM2Utils.verify(data,ecPub,sm2Digest); | |||||
} | |||||
long elapsedTS = System.currentTimeMillis() - startTS; | |||||
System.out.println(String.format("SM2 Verifying Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | |||||
(count * 1000.00D) / elapsedTS)); | |||||
} | |||||
} | |||||
} | } |
@@ -25,6 +25,28 @@ | |||||
<artifactId>runtime-modular-booter</artifactId> | <artifactId>runtime-modular-booter</artifactId> | ||||
<version>${project.version}</version> | <version>${project.version}</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>com.jd.blockchain</groupId> | |||||
<artifactId>storage-composite</artifactId> | |||||
<version>${project.version}</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.jd.blockchain</groupId> | |||||
<artifactId>storage-service</artifactId> | |||||
<version>${project.version}</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.jd.blockchain</groupId> | |||||
<artifactId>storage-redis</artifactId> | |||||
<version>${project.version}</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.jd.blockchain</groupId> | |||||
<artifactId>storage-rocksdb</artifactId> | |||||
<version>${project.version}</version> | |||||
</dependency> | |||||
<!-- <dependency> <groupId>com.jd.blockchain</groupId> <artifactId>gateway</artifactId> | <!-- <dependency> <groupId>com.jd.blockchain</groupId> <artifactId>gateway</artifactId> | ||||
<version>${project.version}</version> </dependency> --> | <version>${project.version}</version> </dependency> --> | ||||
@@ -62,15 +62,6 @@ | |||||
<useAllReactorProjects>true</useAllReactorProjects> | <useAllReactorProjects>true</useAllReactorProjects> | ||||
<includes> | <includes> | ||||
<include>com.jd.blockchain:tools-initializer-booter</include> | <include>com.jd.blockchain:tools-initializer-booter</include> | ||||
</includes> | |||||
<binaries> | |||||
<outputDirectory>libs</outputDirectory> | |||||
<unpack>false</unpack> | |||||
</binaries> | |||||
</moduleSet> | |||||
<moduleSet> | |||||
<useAllReactorProjects>true</useAllReactorProjects> | |||||
<includes> | |||||
<include>com.jd.blockchain:tools-keygen-booter</include> | <include>com.jd.blockchain:tools-keygen-booter</include> | ||||
</includes> | </includes> | ||||
<binaries> | <binaries> | ||||
@@ -1 +1,2 @@ | |||||
/target/ | /target/ | ||||
/.apt_generated_tests/ |
@@ -15,6 +15,17 @@ | |||||
<artifactId>consensus-framework</artifactId> | <artifactId>consensus-framework</artifactId> | ||||
<version>${project.version}</version> | <version>${project.version}</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>com.jd.blockchain</groupId> | |||||
<artifactId>consensus-bftsmart</artifactId> | |||||
<version>${project.version}</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.jd.blockchain</groupId> | |||||
<artifactId>consensus-mq</artifactId> | |||||
<version>${project.version}</version> | |||||
</dependency> | |||||
<dependency> | <dependency> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>ledger-rpc</artifactId> | <artifactId>ledger-rpc</artifactId> | ||||
@@ -43,11 +54,22 @@ | |||||
<version>${project.version}</version> | <version>${project.version}</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>com.jd.blockchain</groupId> | |||||
<artifactId>crypto-framework</artifactId> | |||||
<version>${project.version}</version> | |||||
</dependency> | |||||
<dependency> | <dependency> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>crypto-classic</artifactId> | <artifactId>crypto-classic</artifactId> | ||||
<version>${project.version}</version> | <version>${project.version}</version> | ||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.jd.blockchain</groupId> | |||||
<artifactId>crypto-sm</artifactId> | |||||
<version>${project.version}</version> | |||||
</dependency> | </dependency> | ||||
<dependency> | <dependency> | ||||
@@ -2,6 +2,7 @@ package com.jd.blockchain.gateway.service; | |||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.ParticipantNode; | import com.jd.blockchain.ledger.ParticipantNode; | ||||
import com.jd.blockchain.sdk.LedgerInitSettings; | |||||
/** | /** | ||||
* queryService only for gateway; | * queryService only for gateway; | ||||
@@ -24,4 +25,13 @@ public interface GatewayQueryService { | |||||
* @return | * @return | ||||
*/ | */ | ||||
ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash, int fromIndex, int count); | ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash, int fromIndex, int count); | ||||
/** | |||||
* 获取账本初始化配置信息 | |||||
* | |||||
* @param ledgerHash | |||||
* 账本Hash | |||||
* @return | |||||
*/ | |||||
LedgerInitSettings getLedgerInitSettings(HashDigest ledgerHash); | |||||
} | } |
@@ -0,0 +1,144 @@ | |||||
package com.jd.blockchain.gateway.service; | |||||
import com.jd.blockchain.consensus.ConsensusProvider; | |||||
import com.jd.blockchain.consensus.ConsensusProviders; | |||||
import com.jd.blockchain.consensus.ConsensusSettings; | |||||
import com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider; | |||||
import com.jd.blockchain.consensus.mq.MsgQueueConsensusProvider; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.gateway.PeerService; | |||||
import com.jd.blockchain.ledger.LedgerMetadata; | |||||
import com.jd.blockchain.ledger.ParticipantNode; | |||||
import com.jd.blockchain.sdk.LedgerInitSettings; | |||||
import com.jd.blockchain.utils.QueryUtil; | |||||
import com.jd.blockchain.utils.codec.HexUtils; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.stereotype.Component; | |||||
import java.util.Arrays; | |||||
/** | |||||
* @Author zhaogw | |||||
* @Date 2019/2/22 10:39 | |||||
*/ | |||||
@Component | |||||
public class GatewayQueryServiceHandler implements GatewayQueryService { | |||||
@Autowired | |||||
private PeerService peerService; | |||||
@Override | |||||
public HashDigest[] getLedgersHash(int fromIndex, int count) { | |||||
HashDigest ledgersHash[] = peerService.getQueryService().getLedgerHashs(); | |||||
int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex,count,ledgersHash.length); | |||||
HashDigest ledgersHashNew[] = Arrays.copyOfRange(ledgersHash,indexAndCount[0],indexAndCount[0]+indexAndCount[1]); | |||||
return ledgersHashNew; | |||||
} | |||||
@Override | |||||
public ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash, int fromIndex, int count) { | |||||
ParticipantNode participantNode[] = peerService.getQueryService().getConsensusParticipants(ledgerHash); | |||||
int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex,count,participantNode.length); | |||||
ParticipantNode participantNodesNew[] = Arrays.copyOfRange(participantNode,indexAndCount[0],indexAndCount[0]+indexAndCount[1]); | |||||
return participantNodesNew; | |||||
} | |||||
@Override | |||||
public LedgerInitSettings getLedgerInitSettings(HashDigest ledgerHash) { | |||||
ParticipantNode[] participantNodes = peerService.getQueryService().getConsensusParticipants(ledgerHash); | |||||
LedgerMetadata ledgerMetadata = peerService.getQueryService().getLedgerMetadata(ledgerHash); | |||||
return initLedgerInitSettings(participantNodes, ledgerMetadata); | |||||
} | |||||
/** | |||||
* 初始化账本配置 | |||||
* | |||||
* @param participantNodes | |||||
* 参与方列表 | |||||
* @param ledgerMetadata | |||||
* 账本元数据 | |||||
* @return | |||||
*/ | |||||
private LedgerInitSettings initLedgerInitSettings(ParticipantNode[] participantNodes, LedgerMetadata ledgerMetadata) { | |||||
LedgerInitSettings ledgerInitSettings = new LedgerInitSettings(); | |||||
// 设置参与方 | |||||
ledgerInitSettings.setParticipantNodes(participantNodes); | |||||
// 设置共识设置 | |||||
ledgerInitSettings.setConsensusSettings(initConsensusSettings(ledgerMetadata)); | |||||
// 设置参与方根Hash | |||||
ledgerInitSettings.setParticipantsHash(ledgerMetadata.getParticipantsHash()); | |||||
// 设置算法配置 | |||||
ledgerInitSettings.setCryptoSetting(ledgerMetadata.getSetting().getCryptoSetting()); | |||||
// 设置种子 | |||||
ledgerInitSettings.setSeed(initSeed(ledgerMetadata.getSeed())); | |||||
// 设置共识协议 | |||||
ledgerInitSettings.setConsensusProtocol(consensusProtocol(ledgerMetadata.getSetting().getConsensusProvider())); | |||||
return ledgerInitSettings; | |||||
} | |||||
/** | |||||
* 初始化账本种子信息 | |||||
* | |||||
* @param seedBytes | |||||
* 种子的字节数组显示 | |||||
* @return | |||||
* 种子以十六进制方式显示,为方便阅读,每隔八个字符中间以"-"分割 | |||||
*/ | |||||
private String initSeed(byte[] seedBytes) { | |||||
String seedString = HexUtils.encode(seedBytes); | |||||
// 每隔八个字符中加入一个一个横线 | |||||
StringBuffer seed = new StringBuffer(); | |||||
for( int i = 0; i < seedString.length(); i++) { | |||||
char c = seedString.charAt(i); | |||||
if (i != 0 && i % 8 == 0) { | |||||
seed.append("-"); | |||||
} | |||||
seed.append(c); | |||||
} | |||||
return seed.toString(); | |||||
} | |||||
/** | |||||
* 生成共识协议 | |||||
* | |||||
* @param consensusProvider | |||||
* 共识协议提提供者 | |||||
* @return | |||||
*/ | |||||
private int consensusProtocol(String consensusProvider) { | |||||
if (consensusProvider.equals(BftsmartConsensusProvider.NAME)) { | |||||
return LedgerInitSettings.CONSENSUS_PROTOCOL.BFTSMART.code(); | |||||
} else if (consensusProvider.equals(MsgQueueConsensusProvider.NAME)) { | |||||
return LedgerInitSettings.CONSENSUS_PROTOCOL.MSGQUEUE.code(); | |||||
} | |||||
return LedgerInitSettings.CONSENSUS_PROTOCOL.UNKNOWN.code(); | |||||
} | |||||
/** | |||||
* 初始化共识配置 | |||||
* | |||||
* @param ledgerMetadata | |||||
* 账本元数据 | |||||
* @return | |||||
*/ | |||||
private ConsensusSettings initConsensusSettings(LedgerMetadata ledgerMetadata) { | |||||
String consensusProvider = ledgerMetadata.getSetting().getConsensusProvider(); | |||||
ConsensusProvider provider = ConsensusProviders.getProvider(consensusProvider); | |||||
byte[] consensusSettingsBytes = ledgerMetadata.getSetting().getConsensusSetting().toBytes(); | |||||
return provider.getSettingsFactory().getConsensusSettingsEncoder().decode(consensusSettingsBytes); | |||||
} | |||||
} |
@@ -1,37 +1,37 @@ | |||||
package com.jd.blockchain.gateway.service; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.gateway.PeerService; | |||||
import com.jd.blockchain.ledger.ParticipantNode; | |||||
import com.jd.blockchain.utils.QueryUtil; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.stereotype.Component; | |||||
import java.util.Arrays; | |||||
import static com.jd.blockchain.utils.BaseConstant.QUERY_LIST_MAX; | |||||
/** | |||||
* @Author zhaogw | |||||
* @Date 2019/2/22 10:39 | |||||
*/ | |||||
@Component | |||||
public class GatewayQueryServiceImpl implements GatewayQueryService { | |||||
@Autowired | |||||
private PeerService peerService; | |||||
@Override | |||||
public HashDigest[] getLedgersHash(int fromIndex, int count) { | |||||
HashDigest ledgersHash[] = peerService.getQueryService().getLedgerHashs(); | |||||
int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex,count,ledgersHash.length); | |||||
HashDigest ledgersHashNew[] = Arrays.copyOfRange(ledgersHash,indexAndCount[0],indexAndCount[0]+indexAndCount[1]); | |||||
return ledgersHashNew; | |||||
} | |||||
@Override | |||||
public ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash, int fromIndex, int count) { | |||||
ParticipantNode participantNode[] = peerService.getQueryService().getConsensusParticipants(ledgerHash); | |||||
int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex,count,participantNode.length); | |||||
ParticipantNode participantNodesNew[] = Arrays.copyOfRange(participantNode,indexAndCount[0],indexAndCount[0]+indexAndCount[1]); | |||||
return participantNodesNew; | |||||
} | |||||
} | |||||
//package com.jd.blockchain.gateway.service; | |||||
// | |||||
//import com.jd.blockchain.crypto.HashDigest; | |||||
//import com.jd.blockchain.gateway.PeerService; | |||||
//import com.jd.blockchain.ledger.ParticipantNode; | |||||
//import com.jd.blockchain.utils.QueryUtil; | |||||
//import org.springframework.beans.factory.annotation.Autowired; | |||||
//import org.springframework.stereotype.Component; | |||||
//import java.util.Arrays; | |||||
// | |||||
//import static com.jd.blockchain.utils.BaseConstant.QUERY_LIST_MAX; | |||||
// | |||||
///** | |||||
// * @Author zhaogw | |||||
// * @Date 2019/2/22 10:39 | |||||
// */ | |||||
//@Component | |||||
//public class GatewayQueryServiceImpl implements GatewayQueryService { | |||||
// @Autowired | |||||
// private PeerService peerService; | |||||
// | |||||
// @Override | |||||
// public HashDigest[] getLedgersHash(int fromIndex, int count) { | |||||
// HashDigest ledgersHash[] = peerService.getQueryService().getLedgerHashs(); | |||||
// int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex,count,ledgersHash.length); | |||||
// HashDigest ledgersHashNew[] = Arrays.copyOfRange(ledgersHash,indexAndCount[0],indexAndCount[0]+indexAndCount[1]); | |||||
// return ledgersHashNew; | |||||
// } | |||||
// | |||||
// @Override | |||||
// public ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash, int fromIndex, int count) { | |||||
// ParticipantNode participantNode[] = peerService.getQueryService().getConsensusParticipants(ledgerHash); | |||||
// int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex,count,participantNode.length); | |||||
// ParticipantNode participantNodesNew[] = Arrays.copyOfRange(participantNode,indexAndCount[0],indexAndCount[0]+indexAndCount[1]); | |||||
// return participantNodesNew; | |||||
// } | |||||
//} |
@@ -8,6 +8,7 @@ import com.jd.blockchain.gateway.service.DataRetrievalService; | |||||
import com.jd.blockchain.gateway.service.GatewayQueryService; | import com.jd.blockchain.gateway.service.GatewayQueryService; | ||||
import com.jd.blockchain.ledger.*; | import com.jd.blockchain.ledger.*; | ||||
import com.jd.blockchain.sdk.BlockchainExtendQueryService; | import com.jd.blockchain.sdk.BlockchainExtendQueryService; | ||||
import com.jd.blockchain.sdk.LedgerInitSettings; | |||||
import com.jd.blockchain.tools.keygen.KeyGenCommand; | import com.jd.blockchain.tools.keygen.KeyGenCommand; | ||||
import com.jd.blockchain.utils.BaseConstant; | import com.jd.blockchain.utils.BaseConstant; | ||||
import com.jd.blockchain.utils.ConsoleUtils; | import com.jd.blockchain.utils.ConsoleUtils; | ||||
@@ -58,6 +59,17 @@ public class BlockBrowserController implements BlockchainExtendQueryService { | |||||
return peerService.getQueryService().getConsensusParticipants(ledgerHash); | return peerService.getQueryService().getConsensusParticipants(ledgerHash); | ||||
} | } | ||||
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/metadata") | |||||
@Override | |||||
public LedgerMetadata getLedgerMetadata(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { | |||||
return peerService.getQueryService().getLedgerMetadata(ledgerHash); | |||||
} | |||||
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/settings") | |||||
public LedgerInitSettings getLedgerInitSettings(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { | |||||
return gatewayQueryService.getLedgerInitSettings(ledgerHash); | |||||
} | |||||
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks") | @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks") | ||||
public LedgerBlock[] getBlocks(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { | public LedgerBlock[] getBlocks(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { | ||||
LedgerInfo ledgerInfo = peerService.getQueryService().getLedger(ledgerHash); | LedgerInfo ledgerInfo = peerService.getQueryService().getLedger(ledgerHash); | ||||
@@ -2,7 +2,7 @@ package com.jd.blockchain.gateway.web; | |||||
import java.util.List; | import java.util.List; | ||||
import com.jd.blockchain.utils.io.BytesSlice; | |||||
import com.jd.blockchain.web.serializes.ByteArrayObjectUtil; | |||||
import org.springframework.context.annotation.Configuration; | import org.springframework.context.annotation.Configuration; | ||||
import org.springframework.format.FormatterRegistry; | import org.springframework.format.FormatterRegistry; | ||||
import org.springframework.http.converter.HttpMessageConverter; | import org.springframework.http.converter.HttpMessageConverter; | ||||
@@ -11,12 +11,6 @@ import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry | |||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; | ||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | ||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.crypto.SignatureDigest; | |||||
import com.jd.blockchain.crypto.serialize.ByteArrayObjectDeserializer; | |||||
import com.jd.blockchain.crypto.serialize.ByteArrayObjectSerializer; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
import com.jd.blockchain.utils.io.ByteArray; | import com.jd.blockchain.utils.io.ByteArray; | ||||
import com.jd.blockchain.utils.serialize.json.JSONSerializeUtils; | import com.jd.blockchain.utils.serialize.json.JSONSerializeUtils; | ||||
import com.jd.blockchain.utils.web.model.JsonWebResponseMessageConverter; | import com.jd.blockchain.utils.web.model.JsonWebResponseMessageConverter; | ||||
@@ -30,13 +24,6 @@ import com.jd.blockchain.web.converters.HashDigestInputConverter; | |||||
@Configuration | @Configuration | ||||
public class GatewayWebServerConfigurer implements WebMvcConfigurer { | public class GatewayWebServerConfigurer implements WebMvcConfigurer { | ||||
private static final Class<?>[] BYTEARRAY_JSON_SERIALIZE_CLASS = new Class<?>[] { | |||||
HashDigest.class, | |||||
PubKey.class, | |||||
SignatureDigest.class, | |||||
Bytes.class, | |||||
BytesSlice.class}; | |||||
static { | static { | ||||
JSONSerializeUtils.disableCircularReferenceDetect(); | JSONSerializeUtils.disableCircularReferenceDetect(); | ||||
JSONSerializeUtils.configStringSerializer(ByteArray.class); | JSONSerializeUtils.configStringSerializer(ByteArray.class); | ||||
@@ -67,11 +54,11 @@ public class GatewayWebServerConfigurer implements WebMvcConfigurer { | |||||
registry.addConverter(new HashDigestInputConverter()); | registry.addConverter(new HashDigestInputConverter()); | ||||
} | } | ||||
@Override | |||||
public void addResourceHandlers(ResourceHandlerRegistry registry) { | |||||
@Override | |||||
public void addResourceHandlers(ResourceHandlerRegistry registry) { | |||||
registry.addResourceHandler("/webjars/**") | registry.addResourceHandler("/webjars/**") | ||||
.addResourceLocations("classpath:/META-INF/resources"); | .addResourceLocations("classpath:/META-INF/resources"); | ||||
} | |||||
} | |||||
@Override | @Override | ||||
public void addViewControllers(ViewControllerRegistry registry) { | public void addViewControllers(ViewControllerRegistry registry) { | ||||
@@ -79,10 +66,6 @@ public class GatewayWebServerConfigurer implements WebMvcConfigurer { | |||||
} | } | ||||
private void initByteArrayJsonSerialize() { | private void initByteArrayJsonSerialize() { | ||||
for (Class<?> byteArrayClass : BYTEARRAY_JSON_SERIALIZE_CLASS) { | |||||
JSONSerializeUtils.configSerialization(byteArrayClass, | |||||
ByteArrayObjectSerializer.getInstance(byteArrayClass), | |||||
ByteArrayObjectDeserializer.getInstance(byteArrayClass)); | |||||
} | |||||
ByteArrayObjectUtil.init(); | |||||
} | } | ||||
} | } |
@@ -1,28 +1,30 @@ | |||||
#网关的HTTP服务地址; | #网关的HTTP服务地址; | ||||
http.host=127.0.0.1 | |||||
http.host=0.0.0.0 | |||||
#网关的HTTP服务端口; | #网关的HTTP服务端口; | ||||
http.port=8081 | http.port=8081 | ||||
#网关的HTTP服务上下文路径,可选; | #网关的HTTP服务上下文路径,可选; | ||||
#http.context-path= | #http.context-path= | ||||
#共识节点的服务地址; | |||||
#共识节点的服务地址(与该网关节点连接的Peer节点的IP地址); | |||||
peer.host=127.0.0.1 | peer.host=127.0.0.1 | ||||
#共识节点的服务端口; | |||||
peer.port=7080 | |||||
#共识节点的服务端口(与该网关节点连接的Peer节点的端口); | |||||
peer.port=12000 | |||||
#共识节点的服务是否启用安全证书; | #共识节点的服务是否启用安全证书; | ||||
peer.secure=false | peer.secure=false | ||||
#共识节点的服务提供解析器 | #共识节点的服务提供解析器 | ||||
#BftSmart共识Provider:com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider | |||||
#简单消息共识Provider:com.jd.blockchain.consensus.mq.MsgQueueConsensusProvider | |||||
peer.providers=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider | peer.providers=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider | ||||
#数据检索服务对应URL | |||||
#数据检索服务对应URL,格式:http://{ip}:{port},例如:http://127.0.0.1:10001 | |||||
#若该值不配置或配置不正确,则浏览器模糊查询部分无法正常显示 | #若该值不配置或配置不正确,则浏览器模糊查询部分无法正常显示 | ||||
data.retrieval.url=http://192.168.1.1:10001 | |||||
data.retrieval.url=http://127.0.0.1:10001 | |||||
#默认公钥的内容(Base58编码数据); | #默认公钥的内容(Base58编码数据); | ||||
keys.default.pubkey=endPsK36g6bhgn5bj66uyX4uxqnkfGvdjpxWurAA5hbf8vVoVi8H | |||||
keys.default.pubkey=3snPdw7i7PapsDoW185c3kfK6p8s6SwiJAdEUzgnfeuUox12nxgzXu | |||||
#默认私钥的路径;在 pk-path 和 pk 之间必须设置其一; | #默认私钥的路径;在 pk-path 和 pk 之间必须设置其一; | ||||
keys.default.privkey-path= | keys.default.privkey-path= | ||||
#默认私钥的内容(加密的Base58编码数据);在 pk-path 和 pk 之间必须设置其一; | #默认私钥的内容(加密的Base58编码数据);在 pk-path 和 pk 之间必须设置其一; | ||||
keys.default.privkey=177gjwmuvDnccAvrvmJyCN1dgAqqGzfYpe3pZ8dWWNBneM5GgdsS96vgjvBP4fX61jWfohQ | |||||
keys.default.privkey=177gjyoEUhdD1NkQSxBVvfSyovMd1ha5H46zsb9kyErLNBuQkLRAf2ea6CNjStjCFJQN8S1 | |||||
#默认私钥的解码密码; | #默认私钥的解码密码; | ||||
keys.default.privkey-password=DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY | keys.default.privkey-password=DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY |
@@ -1,5 +1,7 @@ | |||||
package com.jd.blockchain.ledger.core; | package com.jd.blockchain.ledger.core; | ||||
import com.jd.blockchain.ledger.LedgerMetadata; | |||||
import com.jd.blockchain.ledger.LedgerSetting; | |||||
import org.slf4j.Logger; | import org.slf4j.Logger; | ||||
import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||
@@ -1,5 +1,6 @@ | |||||
package com.jd.blockchain.ledger.core; | package com.jd.blockchain.ledger.core; | ||||
import com.jd.blockchain.ledger.LedgerMetadata; | |||||
import com.jd.blockchain.ledger.ParticipantNode; | import com.jd.blockchain.ledger.ParticipantNode; | ||||
public interface LedgerAdministration { | public interface LedgerAdministration { | ||||
@@ -1,6 +1,7 @@ | |||||
package com.jd.blockchain.ledger.core; | package com.jd.blockchain.ledger.core; | ||||
import com.jd.blockchain.ledger.CryptoSetting; | import com.jd.blockchain.ledger.CryptoSetting; | ||||
import com.jd.blockchain.ledger.LedgerSetting; | |||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
public class LedgerConfiguration implements LedgerSetting { | public class LedgerConfiguration implements LedgerSetting { | ||||
@@ -1,36 +1,36 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.binaryproto.DataContract; | |||||
import com.jd.blockchain.binaryproto.DataField; | |||||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||||
import com.jd.blockchain.consts.DataCodes; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
@DataContract(code = DataCodes.METADATA) | |||||
public interface LedgerMetadata { | |||||
/** | |||||
* 账本的初始化种子; | |||||
* | |||||
* @return | |||||
*/ | |||||
@DataField(order = 1, primitiveType = PrimitiveType.BYTES) | |||||
byte[] getSeed(); | |||||
/** | |||||
* 共识参与方的默克尔树的根; | |||||
* | |||||
* @return | |||||
*/ | |||||
@DataField(order = 2, primitiveType = PrimitiveType.BYTES) | |||||
HashDigest getParticipantsHash(); | |||||
/** | |||||
* 账本配置; | |||||
* | |||||
* @return | |||||
*/ | |||||
@DataField(order = 3, refContract = true) | |||||
LedgerSetting getSetting(); | |||||
} | |||||
//package com.jd.blockchain.ledger.core; | |||||
// | |||||
//import com.jd.blockchain.binaryproto.DataContract; | |||||
//import com.jd.blockchain.binaryproto.DataField; | |||||
//import com.jd.blockchain.binaryproto.PrimitiveType; | |||||
//import com.jd.blockchain.consts.DataCodes; | |||||
//import com.jd.blockchain.crypto.HashDigest; | |||||
// | |||||
//@DataContract(code = DataCodes.METADATA) | |||||
//public interface LedgerMetadata { | |||||
// | |||||
// /** | |||||
// * 账本的初始化种子; | |||||
// * | |||||
// * @return | |||||
// */ | |||||
// @DataField(order = 1, primitiveType = PrimitiveType.BYTES) | |||||
// byte[] getSeed(); | |||||
// | |||||
// /** | |||||
// * 共识参与方的默克尔树的根; | |||||
// * | |||||
// * @return | |||||
// */ | |||||
// @DataField(order = 2, primitiveType = PrimitiveType.BYTES) | |||||
// HashDigest getParticipantsHash(); | |||||
// | |||||
// /** | |||||
// * 账本配置; | |||||
// * | |||||
// * @return | |||||
// */ | |||||
// @DataField(order = 3, refContract = true) | |||||
// LedgerSetting getSetting(); | |||||
// | |||||
//} |
@@ -1,24 +1,24 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.binaryproto.DataContract; | |||||
import com.jd.blockchain.binaryproto.DataField; | |||||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||||
import com.jd.blockchain.consts.DataCodes; | |||||
import com.jd.blockchain.ledger.CryptoSetting; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
@DataContract(code = DataCodes.METADATA_LEDGER_SETTING) | |||||
public interface LedgerSetting { | |||||
@DataField(order=0, primitiveType=PrimitiveType.TEXT) | |||||
String getConsensusProvider(); | |||||
@DataField(order=1, primitiveType=PrimitiveType.BYTES) | |||||
Bytes getConsensusSetting(); | |||||
@DataField(order=2, refContract=true) | |||||
CryptoSetting getCryptoSetting(); | |||||
// PrivilegeModelSetting getPrivilegesModelSetting(); | |||||
} | |||||
//package com.jd.blockchain.ledger.core; | |||||
// | |||||
//import com.jd.blockchain.binaryproto.DataContract; | |||||
//import com.jd.blockchain.binaryproto.DataField; | |||||
//import com.jd.blockchain.binaryproto.PrimitiveType; | |||||
//import com.jd.blockchain.consts.DataCodes; | |||||
//import com.jd.blockchain.ledger.CryptoSetting; | |||||
//import com.jd.blockchain.utils.Bytes; | |||||
// | |||||
//@DataContract(code = DataCodes.METADATA_LEDGER_SETTING) | |||||
//public interface LedgerSetting { | |||||
// | |||||
// @DataField(order=0, primitiveType=PrimitiveType.TEXT) | |||||
// String getConsensusProvider(); | |||||
// | |||||
// @DataField(order=1, primitiveType=PrimitiveType.BYTES) | |||||
// Bytes getConsensusSetting(); | |||||
// | |||||
// @DataField(order=2, refContract=true) | |||||
// CryptoSetting getCryptoSetting(); | |||||
// | |||||
//// PrivilegeModelSetting getPrivilegesModelSetting(); | |||||
// | |||||
//} |
@@ -3,16 +3,7 @@ package com.jd.blockchain.ledger.core.impl; | |||||
import com.jd.blockchain.binaryproto.BinaryProtocol; | import com.jd.blockchain.binaryproto.BinaryProtocol; | ||||
import com.jd.blockchain.binaryproto.PrimitiveType; | import com.jd.blockchain.binaryproto.PrimitiveType; | ||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.AccountHeader; | |||||
import com.jd.blockchain.ledger.BytesValue; | |||||
import com.jd.blockchain.ledger.KVDataEntry; | |||||
import com.jd.blockchain.ledger.KVDataObject; | |||||
import com.jd.blockchain.ledger.LedgerBlock; | |||||
import com.jd.blockchain.ledger.LedgerInfo; | |||||
import com.jd.blockchain.ledger.LedgerTransaction; | |||||
import com.jd.blockchain.ledger.ParticipantNode; | |||||
import com.jd.blockchain.ledger.TransactionState; | |||||
import com.jd.blockchain.ledger.UserInfo; | |||||
import com.jd.blockchain.ledger.*; | |||||
import com.jd.blockchain.ledger.core.ContractAccountSet; | import com.jd.blockchain.ledger.core.ContractAccountSet; | ||||
import com.jd.blockchain.ledger.core.DataAccount; | import com.jd.blockchain.ledger.core.DataAccount; | ||||
import com.jd.blockchain.ledger.core.DataAccountSet; | import com.jd.blockchain.ledger.core.DataAccountSet; | ||||
@@ -50,10 +41,12 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
@Override | @Override | ||||
public ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash) { | public ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash) { | ||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||||
LedgerBlock block = ledger.getLatestBlock(); | |||||
LedgerAdministration administration = ledger.getAdminAccount(block); | |||||
return administration.getParticipants(); | |||||
return ledgerAdministration(ledgerHash).getParticipants(); | |||||
} | |||||
@Override | |||||
public LedgerMetadata getLedgerMetadata(HashDigest ledgerHash) { | |||||
return ledgerAdministration(ledgerHash).getMetadata(); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -338,4 +331,11 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
int pages[] = QueryUtil.calFromIndexAndCount(fromIndex,count,(int)contractAccountSet.getTotalCount()); | int pages[] = QueryUtil.calFromIndexAndCount(fromIndex,count,(int)contractAccountSet.getTotalCount()); | ||||
return contractAccountSet.getAccounts(pages[0],pages[1]); | return contractAccountSet.getAccounts(pages[0],pages[1]); | ||||
} | } | ||||
private LedgerAdministration ledgerAdministration(HashDigest ledgerHash) { | |||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||||
LedgerBlock block = ledger.getLatestBlock(); | |||||
LedgerAdministration administration = ledger.getAdminAccount(block); | |||||
return administration; | |||||
} | |||||
} | } |
@@ -4,12 +4,7 @@ import com.jd.blockchain.binaryproto.BinaryProtocol; | |||||
import com.jd.blockchain.crypto.Crypto; | import com.jd.blockchain.crypto.Crypto; | ||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.crypto.HashFunction; | import com.jd.blockchain.crypto.HashFunction; | ||||
import com.jd.blockchain.ledger.BlockBody; | |||||
import com.jd.blockchain.ledger.CryptoSetting; | |||||
import com.jd.blockchain.ledger.LedgerBlock; | |||||
import com.jd.blockchain.ledger.LedgerDataSnapshot; | |||||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||||
import com.jd.blockchain.ledger.TransactionRequest; | |||||
import com.jd.blockchain.ledger.*; | |||||
import com.jd.blockchain.ledger.core.AccountAccessPolicy; | import com.jd.blockchain.ledger.core.AccountAccessPolicy; | ||||
import com.jd.blockchain.ledger.core.ContractAccountSet; | import com.jd.blockchain.ledger.core.ContractAccountSet; | ||||
import com.jd.blockchain.ledger.core.DataAccountSet; | import com.jd.blockchain.ledger.core.DataAccountSet; | ||||
@@ -20,7 +15,6 @@ import com.jd.blockchain.ledger.core.LedgerDataSet; | |||||
import com.jd.blockchain.ledger.core.LedgerEditor; | import com.jd.blockchain.ledger.core.LedgerEditor; | ||||
import com.jd.blockchain.ledger.core.LedgerException; | import com.jd.blockchain.ledger.core.LedgerException; | ||||
import com.jd.blockchain.ledger.core.LedgerRepository; | import com.jd.blockchain.ledger.core.LedgerRepository; | ||||
import com.jd.blockchain.ledger.core.LedgerSetting; | |||||
import com.jd.blockchain.ledger.core.LedgerTransactionContext; | import com.jd.blockchain.ledger.core.LedgerTransactionContext; | ||||
import com.jd.blockchain.ledger.core.TransactionSet; | import com.jd.blockchain.ledger.core.TransactionSet; | ||||
import com.jd.blockchain.ledger.core.UserAccountSet; | import com.jd.blockchain.ledger.core.UserAccountSet; | ||||
@@ -486,7 +480,7 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||||
} | } | ||||
static TransactionSet newTransactionSet(LedgerSetting ledgerSetting, String keyPrefix, | static TransactionSet newTransactionSet(LedgerSetting ledgerSetting, String keyPrefix, | ||||
ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) { | |||||
ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) { | |||||
// TransactionSet transactionSet = new | // TransactionSet transactionSet = new | ||||
// TransactionSet(ledgerSetting.getCryptoSetting(), | // TransactionSet(ledgerSetting.getCryptoSetting(), | ||||
// PrefixAppender.prefix(TRANSACTION_SET_PREFIX, ledgerExStorage), | // PrefixAppender.prefix(TRANSACTION_SET_PREFIX, ledgerExStorage), | ||||
@@ -5,17 +5,9 @@ import java.util.Stack; | |||||
import com.jd.blockchain.binaryproto.BinaryProtocol; | import com.jd.blockchain.binaryproto.BinaryProtocol; | ||||
import com.jd.blockchain.crypto.Crypto; | import com.jd.blockchain.crypto.Crypto; | ||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.BlockBody; | |||||
import com.jd.blockchain.ledger.CryptoSetting; | |||||
import com.jd.blockchain.ledger.LedgerBlock; | |||||
import com.jd.blockchain.ledger.LedgerDataSnapshot; | |||||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||||
import com.jd.blockchain.ledger.LedgerTransaction; | |||||
import com.jd.blockchain.ledger.TransactionRequest; | |||||
import com.jd.blockchain.ledger.TransactionState; | |||||
import com.jd.blockchain.ledger.*; | |||||
import com.jd.blockchain.ledger.core.LedgerDataSet; | import com.jd.blockchain.ledger.core.LedgerDataSet; | ||||
import com.jd.blockchain.ledger.core.LedgerEditor; | import com.jd.blockchain.ledger.core.LedgerEditor; | ||||
import com.jd.blockchain.ledger.core.LedgerSetting; | |||||
import com.jd.blockchain.ledger.core.LedgerTransactionContext; | import com.jd.blockchain.ledger.core.LedgerTransactionContext; | ||||
import com.jd.blockchain.ledger.core.TransactionSet; | import com.jd.blockchain.ledger.core.TransactionSet; | ||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | import com.jd.blockchain.storage.service.ExPolicyKVStorage; | ||||
@@ -67,7 +59,7 @@ public class LedgerTransactionalEditor implements LedgerEditor { | |||||
} | } | ||||
public static LedgerTransactionalEditor createEditor(LedgerSetting ledgerSetting, LedgerBlock previousBlock, | public static LedgerTransactionalEditor createEditor(LedgerSetting ledgerSetting, LedgerBlock previousBlock, | ||||
String ledgerKeyPrefix, ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) { | |||||
String ledgerKeyPrefix, ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) { | |||||
// new block; | // new block; | ||||
LedgerBlockData currBlock = new LedgerBlockData(previousBlock.getHeight() + 1, previousBlock.getLedgerHash(), | LedgerBlockData currBlock = new LedgerBlockData(previousBlock.getHeight() + 1, previousBlock.getLedgerHash(), | ||||
previousBlock.getHash()); | previousBlock.getHash()); | ||||
@@ -6,22 +6,7 @@ import java.util.List; | |||||
import com.alibaba.fastjson.JSON; | import com.alibaba.fastjson.JSON; | ||||
import com.jd.blockchain.contract.LedgerContext; | import com.jd.blockchain.contract.LedgerContext; | ||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.AccountHeader; | |||||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||||
import com.jd.blockchain.ledger.BytesValue; | |||||
import com.jd.blockchain.ledger.BytesValueEntry; | |||||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||||
import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||||
import com.jd.blockchain.ledger.BytesValueType; | |||||
import com.jd.blockchain.ledger.KVDataEntry; | |||||
import com.jd.blockchain.ledger.LedgerBlock; | |||||
import com.jd.blockchain.ledger.LedgerInfo; | |||||
import com.jd.blockchain.ledger.LedgerTransaction; | |||||
import com.jd.blockchain.ledger.Operation; | |||||
import com.jd.blockchain.ledger.ParticipantNode; | |||||
import com.jd.blockchain.ledger.TransactionState; | |||||
import com.jd.blockchain.ledger.UserInfo; | |||||
import com.jd.blockchain.ledger.UserRegisterOperation; | |||||
import com.jd.blockchain.ledger.*; | |||||
import com.jd.blockchain.ledger.core.impl.OperationHandleContext; | import com.jd.blockchain.ledger.core.impl.OperationHandleContext; | ||||
import com.jd.blockchain.transaction.BlockchainQueryService; | import com.jd.blockchain.transaction.BlockchainQueryService; | ||||
import com.jd.blockchain.transaction.DataAccountKVSetOperationBuilder; | import com.jd.blockchain.transaction.DataAccountKVSetOperationBuilder; | ||||
@@ -61,6 +46,11 @@ public class ContractLedgerContext implements LedgerContext { | |||||
return innerQueryService.getConsensusParticipants(ledgerHash); | return innerQueryService.getConsensusParticipants(ledgerHash); | ||||
} | } | ||||
@Override | |||||
public LedgerMetadata getLedgerMetadata(HashDigest ledgerHash) { | |||||
return innerQueryService.getLedgerMetadata(ledgerHash); | |||||
} | |||||
@Override | @Override | ||||
public LedgerBlock getBlock(HashDigest ledgerHash, long height) { | public LedgerBlock getBlock(HashDigest ledgerHash, long height) { | ||||
return innerQueryService.getBlock(ledgerHash, height); | return innerQueryService.getBlock(ledgerHash, height); | ||||
@@ -9,6 +9,7 @@ import static org.junit.Assert.assertTrue; | |||||
import java.util.Arrays; | import java.util.Arrays; | ||||
import java.util.Random; | import java.util.Random; | ||||
import com.jd.blockchain.ledger.LedgerMetadata; | |||||
import org.junit.Test; | import org.junit.Test; | ||||
import com.jd.blockchain.crypto.AddressEncoding; | import com.jd.blockchain.crypto.AddressEncoding; | ||||
@@ -20,7 +21,6 @@ import com.jd.blockchain.ledger.ParticipantNode; | |||||
import com.jd.blockchain.ledger.core.CryptoConfig; | import com.jd.blockchain.ledger.core.CryptoConfig; | ||||
import com.jd.blockchain.ledger.core.LedgerAdminAccount; | import com.jd.blockchain.ledger.core.LedgerAdminAccount; | ||||
import com.jd.blockchain.ledger.core.LedgerConfiguration; | import com.jd.blockchain.ledger.core.LedgerConfiguration; | ||||
import com.jd.blockchain.ledger.core.LedgerMetadata; | |||||
import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | ||||
import com.jd.blockchain.transaction.ConsensusParticipantData; | import com.jd.blockchain.transaction.ConsensusParticipantData; | ||||
import com.jd.blockchain.transaction.LedgerInitSettingData; | import com.jd.blockchain.transaction.LedgerInitSettingData; | ||||
@@ -7,6 +7,8 @@ import static org.junit.Assert.assertTrue; | |||||
import java.util.Random; | import java.util.Random; | ||||
import com.jd.blockchain.ledger.LedgerMetadata; | |||||
import com.jd.blockchain.ledger.LedgerSetting; | |||||
import org.junit.Before; | import org.junit.Before; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
@@ -21,8 +23,6 @@ import com.jd.blockchain.ledger.ParticipantNode; | |||||
import com.jd.blockchain.ledger.core.CryptoConfig; | import com.jd.blockchain.ledger.core.CryptoConfig; | ||||
import com.jd.blockchain.ledger.core.LedgerAdminAccount; | import com.jd.blockchain.ledger.core.LedgerAdminAccount; | ||||
import com.jd.blockchain.ledger.core.LedgerConfiguration; | import com.jd.blockchain.ledger.core.LedgerConfiguration; | ||||
import com.jd.blockchain.ledger.core.LedgerMetadata; | |||||
import com.jd.blockchain.ledger.core.LedgerSetting; | |||||
import com.jd.blockchain.ledger.core.ParticipantCertData; | import com.jd.blockchain.ledger.core.ParticipantCertData; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
@@ -0,0 +1,36 @@ | |||||
package com.jd.blockchain.ledger; | |||||
import com.jd.blockchain.binaryproto.DataContract; | |||||
import com.jd.blockchain.binaryproto.DataField; | |||||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||||
import com.jd.blockchain.consts.DataCodes; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
@DataContract(code = DataCodes.METADATA) | |||||
public interface LedgerMetadata { | |||||
/** | |||||
* 账本的初始化种子; | |||||
* | |||||
* @return | |||||
*/ | |||||
@DataField(order = 1, primitiveType = PrimitiveType.BYTES) | |||||
byte[] getSeed(); | |||||
/** | |||||
* 共识参与方的默克尔树的根; | |||||
* | |||||
* @return | |||||
*/ | |||||
@DataField(order = 2, primitiveType = PrimitiveType.BYTES) | |||||
HashDigest getParticipantsHash(); | |||||
/** | |||||
* 账本配置; | |||||
* | |||||
* @return | |||||
*/ | |||||
@DataField(order = 3, refContract = true) | |||||
LedgerSetting getSetting(); | |||||
} |
@@ -0,0 +1,24 @@ | |||||
package com.jd.blockchain.ledger; | |||||
import com.jd.blockchain.binaryproto.DataContract; | |||||
import com.jd.blockchain.binaryproto.DataField; | |||||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||||
import com.jd.blockchain.consts.DataCodes; | |||||
import com.jd.blockchain.ledger.CryptoSetting; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
@DataContract(code = DataCodes.METADATA_LEDGER_SETTING) | |||||
public interface LedgerSetting { | |||||
@DataField(order=0, primitiveType=PrimitiveType.TEXT) | |||||
String getConsensusProvider(); | |||||
@DataField(order=1, primitiveType=PrimitiveType.BYTES) | |||||
Bytes getConsensusSetting(); | |||||
@DataField(order=2, refContract=true) | |||||
CryptoSetting getCryptoSetting(); | |||||
// PrivilegeModelSetting getPrivilegesModelSetting(); | |||||
} |
@@ -36,6 +36,14 @@ public interface BlockchainQueryService { | |||||
*/ | */ | ||||
ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash); | ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash); | ||||
/** | |||||
* 返回当前账本的元数据 | |||||
* | |||||
* @param ledgerHash | |||||
* @return | |||||
*/ | |||||
LedgerMetadata getLedgerMetadata(HashDigest ledgerHash); | |||||
/** | /** | ||||
* 返回指定账本序号的区块; | * 返回指定账本序号的区块; | ||||
* | * | ||||
@@ -0,0 +1,101 @@ | |||||
package com.jd.blockchain.web.serializes; | |||||
import com.alibaba.fastjson.parser.DefaultJSONParser; | |||||
import com.alibaba.fastjson.parser.JSONToken; | |||||
import com.alibaba.fastjson.parser.ParserConfig; | |||||
import com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.crypto.SignatureDigest; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
import com.jd.blockchain.utils.codec.Base58Utils; | |||||
import com.jd.blockchain.utils.io.BytesSlice; | |||||
import java.lang.reflect.InvocationTargetException; | |||||
import java.lang.reflect.Type; | |||||
import java.util.Map; | |||||
public class ByteArrayObjectJsonDeserializer extends JavaBeanDeserializer { | |||||
private ByteArrayObjectJsonDeserializer(Class<?> clazz) { | |||||
super(ParserConfig.global, clazz); | |||||
} | |||||
public static ByteArrayObjectJsonDeserializer getInstance(Class<?> clazz) { | |||||
return new ByteArrayObjectJsonDeserializer(clazz); | |||||
} | |||||
@SuppressWarnings("unchecked") | |||||
@Override | |||||
public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) { | |||||
if (type instanceof Class && clazz.isAssignableFrom((Class<?>) type)) { | |||||
String parseText = parser.parseObject(String.class); | |||||
byte[] hashBytes = Base58Utils.decode(parseText); | |||||
if (clazz == HashDigest.class) { | |||||
return (T) new HashDigest(hashBytes); | |||||
} else if (clazz == PubKey.class) { | |||||
return (T) new HashDigest(hashBytes); | |||||
} else if (clazz == SignatureDigest.class) { | |||||
return (T) new SignatureDigest(hashBytes); | |||||
} else if (clazz == Bytes.class) { | |||||
return (T) new Bytes(hashBytes); | |||||
} else if (clazz == BytesSlice.class) { | |||||
return (T) new BytesSlice(hashBytes); | |||||
} | |||||
// else if (clazz == BytesValue.class) { | |||||
// ByteArrayObjectJsonSerializer.BytesValueJson valueJson = JSON.parseObject(parseText, ByteArrayObjectJsonSerializer.BytesValueJson.class); | |||||
// DataType dataType = valueJson.getType(); | |||||
// Object dataVal = valueJson.getValue(); | |||||
// byte[] bytes = null; | |||||
// switch (dataType) { | |||||
// case BYTES: | |||||
// bytes = ByteArray.fromHex((String) dataVal); | |||||
// break; | |||||
// case TEXT: | |||||
// bytes = ((String) dataVal).getBytes(); | |||||
// break; | |||||
// case INT64: | |||||
// bytes = BytesUtils.toBytes((Long) dataVal); | |||||
// break; | |||||
// case JSON: | |||||
// bytes = ((String) dataVal).getBytes(); | |||||
// break; | |||||
// } | |||||
// BytesValue bytesValue = new BytesValueImpl(dataType, bytes); | |||||
// return (T) bytesValue; | |||||
// } | |||||
} | |||||
return (T) parser.parse(fieldName); | |||||
} | |||||
@Override | |||||
public Object createInstance(Map<String, Object> map, ParserConfig config) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { | |||||
if (map == null || map.isEmpty()) { | |||||
return null; | |||||
} | |||||
for (Map.Entry<String, Object> entry : map.entrySet()) { | |||||
Object value = entry.getValue(); | |||||
if (value instanceof String) { | |||||
byte[] hashBytes = Base58Utils.decode((String) value); | |||||
if (clazz == HashDigest.class) { | |||||
return new HashDigest(hashBytes); | |||||
} else if (clazz == PubKey.class) { | |||||
return new PubKey(hashBytes); | |||||
} else if (clazz == SignatureDigest.class) { | |||||
return new SignatureDigest(hashBytes); | |||||
} else if (clazz == Bytes.class) { | |||||
return new Bytes(hashBytes); | |||||
} else if (clazz == BytesSlice.class) { | |||||
return new BytesSlice(hashBytes); | |||||
} | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
@Override | |||||
public int getFastMatchToken() { | |||||
return JSONToken.LBRACE; | |||||
} | |||||
} |
@@ -0,0 +1,120 @@ | |||||
package com.jd.blockchain.web.serializes; | |||||
import com.alibaba.fastjson.serializer.JSONSerializer; | |||||
import com.alibaba.fastjson.serializer.ObjectSerializer; | |||||
import com.jd.blockchain.binaryproto.DataType; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.crypto.SignatureDigest; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
import com.jd.blockchain.utils.codec.Base58Utils; | |||||
import com.jd.blockchain.utils.io.BytesSlice; | |||||
import java.lang.reflect.Type; | |||||
public class ByteArrayObjectJsonSerializer implements ObjectSerializer { | |||||
private Class<?> clazz; | |||||
private ByteArrayObjectJsonSerializer(Class<?> clazz) { | |||||
this.clazz = clazz; | |||||
} | |||||
public static ByteArrayObjectJsonSerializer getInstance(Class<?> clazz) { | |||||
return new ByteArrayObjectJsonSerializer(clazz); | |||||
} | |||||
@Override | |||||
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) { | |||||
if (object.getClass() != clazz) { | |||||
serializer.writeNull(); | |||||
return; | |||||
} | |||||
if (object instanceof HashDigest) { | |||||
serializer.write(new HashDigestJson(((HashDigest) object).toBase58())); | |||||
} else if (object instanceof PubKey) { | |||||
serializer.write(new HashDigestJson(((PubKey) object).toBase58())); | |||||
} else if (object instanceof SignatureDigest) { | |||||
serializer.write(new HashDigestJson(((SignatureDigest) object).toBase58())); | |||||
} else if (object instanceof Bytes) { | |||||
serializer.write(new HashDigestJson(((Bytes) object).toBase58())); | |||||
} else if (object instanceof BytesSlice) { | |||||
serializer.write(Base58Utils.encode(((BytesSlice) object).toBytes())); | |||||
} | |||||
// else if (object instanceof BytesValue) { | |||||
// DataType dataType = ((BytesValue) object).getType(); | |||||
// BytesSlice bytesValue = ((BytesValue) object).getValue(); | |||||
// Object realVal; | |||||
// switch (dataType) { | |||||
// case NIL: | |||||
// realVal = null; | |||||
// break; | |||||
// case TEXT: | |||||
// realVal = bytesValue.getString(); | |||||
// break; | |||||
// case BYTES: | |||||
// realVal = ByteArray.toHex(bytesValue.toBytes()); | |||||
// break; | |||||
// case INT32: | |||||
// realVal = bytesValue.getInt(); | |||||
// break; | |||||
// case INT64: | |||||
// realVal = bytesValue.getLong(); | |||||
// break; | |||||
// case JSON: | |||||
// realVal = bytesValue.getString(); | |||||
// break; | |||||
// default: | |||||
// realVal = ByteArray.toHex(bytesValue.toBytes()); | |||||
// break; | |||||
// } | |||||
// serializer.write(new BytesValueJson(dataType, realVal)); | |||||
// } | |||||
} | |||||
private static class HashDigestJson { | |||||
String value; | |||||
public HashDigestJson(String value) { | |||||
this.value = value; | |||||
} | |||||
public String getValue() { | |||||
return value; | |||||
} | |||||
public void setValue(String value) { | |||||
this.value = value; | |||||
} | |||||
} | |||||
public static class BytesValueJson { | |||||
public BytesValueJson(DataType type, Object value) { | |||||
this.type = type; | |||||
this.value = value; | |||||
} | |||||
DataType type; | |||||
Object value; | |||||
public DataType getType() { | |||||
return type; | |||||
} | |||||
public void setType(DataType type) { | |||||
this.type = type; | |||||
} | |||||
public Object getValue() { | |||||
return value; | |||||
} | |||||
public void setValue(Object value) { | |||||
this.value = value; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,41 @@ | |||||
/** | |||||
* Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||||
* FileName: com.jd.blockchain.web.serializes.ByteArrayObjectUtil | |||||
* Author: shaozhuguang | |||||
* Department: Y事业部 | |||||
* Date: 2019/3/27 上午11:23 | |||||
* Description: | |||||
*/ | |||||
package com.jd.blockchain.web.serializes; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.crypto.SignatureDigest; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
import com.jd.blockchain.utils.io.BytesSlice; | |||||
import com.jd.blockchain.utils.serialize.json.JSONSerializeUtils; | |||||
/** | |||||
* | |||||
* @author shaozhuguang | |||||
* @create 2019/3/27 | |||||
* @since 1.0.0 | |||||
*/ | |||||
public class ByteArrayObjectUtil { | |||||
public static final Class<?>[] BYTEARRAY_JSON_SERIALIZE_CLASS = new Class<?>[] { | |||||
HashDigest.class, | |||||
PubKey.class, | |||||
SignatureDigest.class, | |||||
Bytes.class, | |||||
BytesSlice.class}; | |||||
public static void init() { | |||||
for (Class<?> byteArrayClass : BYTEARRAY_JSON_SERIALIZE_CLASS) { | |||||
JSONSerializeUtils.configSerialization(byteArrayClass, | |||||
ByteArrayObjectJsonSerializer.getInstance(byteArrayClass), | |||||
ByteArrayObjectJsonDeserializer.getInstance(byteArrayClass)); | |||||
} | |||||
} | |||||
} |
@@ -1 +1,2 @@ | |||||
/target/ | /target/ | ||||
/.apt_generated_tests/ |
@@ -1,5 +1,7 @@ | |||||
package com.jd.blockchain.peer.web; | package com.jd.blockchain.peer.web; | ||||
import com.jd.blockchain.ledger.*; | |||||
import com.jd.blockchain.ledger.core.*; | |||||
import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
import org.springframework.web.bind.annotation.PathVariable; | import org.springframework.web.bind.annotation.PathVariable; | ||||
import org.springframework.web.bind.annotation.RequestMapping; | import org.springframework.web.bind.annotation.RequestMapping; | ||||
@@ -10,25 +12,6 @@ import org.springframework.web.bind.annotation.RestController; | |||||
import com.jd.blockchain.binaryproto.BinaryProtocol; | import com.jd.blockchain.binaryproto.BinaryProtocol; | ||||
import com.jd.blockchain.binaryproto.PrimitiveType; | import com.jd.blockchain.binaryproto.PrimitiveType; | ||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.AccountHeader; | |||||
import com.jd.blockchain.ledger.BytesValue; | |||||
import com.jd.blockchain.ledger.KVDataEntry; | |||||
import com.jd.blockchain.ledger.KVDataObject; | |||||
import com.jd.blockchain.ledger.LedgerBlock; | |||||
import com.jd.blockchain.ledger.LedgerInfo; | |||||
import com.jd.blockchain.ledger.LedgerTransaction; | |||||
import com.jd.blockchain.ledger.ParticipantNode; | |||||
import com.jd.blockchain.ledger.TransactionState; | |||||
import com.jd.blockchain.ledger.UserInfo; | |||||
import com.jd.blockchain.ledger.core.ContractAccountSet; | |||||
import com.jd.blockchain.ledger.core.DataAccount; | |||||
import com.jd.blockchain.ledger.core.DataAccountSet; | |||||
import com.jd.blockchain.ledger.core.LedgerAdministration; | |||||
import com.jd.blockchain.ledger.core.LedgerRepository; | |||||
import com.jd.blockchain.ledger.core.LedgerService; | |||||
import com.jd.blockchain.ledger.core.ParticipantCertData; | |||||
import com.jd.blockchain.ledger.core.TransactionSet; | |||||
import com.jd.blockchain.ledger.core.UserAccountSet; | |||||
import com.jd.blockchain.transaction.BlockchainQueryService; | import com.jd.blockchain.transaction.BlockchainQueryService; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.QueryUtil; | import com.jd.blockchain.utils.QueryUtil; | ||||
@@ -79,6 +62,15 @@ public class LedgerQueryController implements BlockchainQueryService { | |||||
return null; | return null; | ||||
} | } | ||||
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/metadata") | |||||
@Override | |||||
public LedgerMetadata getLedgerMetadata(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { | |||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||||
LedgerAdministration ledgerAdministration = ledger.getAdminInfo(); | |||||
LedgerMetadata ledgerMetadata = ledgerAdministration.getMetadata(); | |||||
return ledgerMetadata; | |||||
} | |||||
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/height/{blockHeight}") | @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/height/{blockHeight}") | ||||
@Override | @Override | ||||
public LedgerBlock getBlock(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | public LedgerBlock getBlock(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | ||||
@@ -2,22 +2,16 @@ package com.jd.blockchain.peer.web; | |||||
import java.util.List; | import java.util.List; | ||||
import com.jd.blockchain.utils.io.BytesSlice; | |||||
import com.jd.blockchain.web.converters.BinaryMessageConverter; | import com.jd.blockchain.web.converters.BinaryMessageConverter; | ||||
import com.jd.blockchain.web.converters.HashDigestInputConverter; | import com.jd.blockchain.web.converters.HashDigestInputConverter; | ||||
import com.jd.blockchain.web.serializes.ByteArrayObjectUtil; | |||||
import org.springframework.context.annotation.Configuration; | import org.springframework.context.annotation.Configuration; | ||||
import org.springframework.format.FormatterRegistry; | import org.springframework.format.FormatterRegistry; | ||||
import org.springframework.http.converter.HttpMessageConverter; | import org.springframework.http.converter.HttpMessageConverter; | ||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; | import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; | ||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | ||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.crypto.SignatureDigest; | |||||
import com.jd.blockchain.crypto.serialize.ByteArrayObjectDeserializer; | |||||
import com.jd.blockchain.crypto.serialize.ByteArrayObjectSerializer; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
import com.jd.blockchain.utils.io.ByteArray; | import com.jd.blockchain.utils.io.ByteArray; | ||||
import com.jd.blockchain.utils.serialize.json.JSONSerializeUtils; | import com.jd.blockchain.utils.serialize.json.JSONSerializeUtils; | ||||
import com.jd.blockchain.utils.web.model.JsonWebResponseMessageConverter; | import com.jd.blockchain.utils.web.model.JsonWebResponseMessageConverter; | ||||
@@ -25,13 +19,6 @@ import com.jd.blockchain.utils.web.model.JsonWebResponseMessageConverter; | |||||
@Configuration | @Configuration | ||||
public class PeerWebServerConfigurer implements WebMvcConfigurer { | public class PeerWebServerConfigurer implements WebMvcConfigurer { | ||||
private static final Class<?>[] BYTEARRAY_JSON_SERIALIZE_CLASS = new Class<?>[] { | |||||
HashDigest.class, | |||||
PubKey.class, | |||||
SignatureDigest.class, | |||||
Bytes.class, | |||||
BytesSlice.class}; | |||||
static { | static { | ||||
JSONSerializeUtils.disableCircularReferenceDetect(); | JSONSerializeUtils.disableCircularReferenceDetect(); | ||||
JSONSerializeUtils.configStringSerializer(ByteArray.class); | JSONSerializeUtils.configStringSerializer(ByteArray.class); | ||||
@@ -59,10 +46,6 @@ public class PeerWebServerConfigurer implements WebMvcConfigurer { | |||||
} | } | ||||
private void initByteArrayJsonSerialize() { | private void initByteArrayJsonSerialize() { | ||||
for (Class<?> byteArrayClass : BYTEARRAY_JSON_SERIALIZE_CLASS) { | |||||
JSONSerializeUtils.configSerialization(byteArrayClass, | |||||
ByteArrayObjectSerializer.getInstance(byteArrayClass), | |||||
ByteArrayObjectDeserializer.getInstance(byteArrayClass)); | |||||
} | |||||
ByteArrayObjectUtil.init(); | |||||
} | } | ||||
} | } |
@@ -297,6 +297,25 @@ | |||||
<artifactId>commons-collections4</artifactId> | <artifactId>commons-collections4</artifactId> | ||||
<version>4.1</version> | <version>4.1</version> | ||||
</dependency> | </dependency> | ||||
<!-- jar包扫描 --> | |||||
<dependency> | |||||
<groupId>org.reflections</groupId> | |||||
<artifactId>reflections</artifactId> | |||||
<version>0.9.10</version> | |||||
<exclusions> | |||||
<exclusion> | |||||
<groupId>com.google.guava</groupId> | |||||
<artifactId>guava</artifactId> | |||||
</exclusion> | |||||
</exclusions> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.google.guava</groupId> | |||||
<artifactId>guava</artifactId> | |||||
<version>19.0</version> | |||||
</dependency> | |||||
</dependencies> | </dependencies> | ||||
</dependencyManagement> | </dependencyManagement> | ||||
@@ -0,0 +1,113 @@ | |||||
package com.jd.blockchain.sdk; | |||||
import com.jd.blockchain.consensus.ConsensusSettings; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.ledger.CryptoSetting; | |||||
import com.jd.blockchain.ledger.ParticipantNode; | |||||
/** | |||||
* 账本初始化配置 | |||||
* | |||||
* @author shaozhuguang | |||||
* @date 2019-04-23 | |||||
* @since 1.0.0 | |||||
* | |||||
*/ | |||||
public class LedgerInitSettings { | |||||
/** | |||||
* 账本初始化种子 | |||||
*/ | |||||
private String seed; | |||||
/** | |||||
* 共识参与方的默克尔树的根; | |||||
*/ | |||||
private HashDigest participantsHash; | |||||
/** | |||||
* 算法配置 | |||||
*/ | |||||
private CryptoSetting cryptoSetting; | |||||
/** | |||||
* 共识协议 | |||||
*/ | |||||
private int consensusProtocol; | |||||
/** | |||||
* 共识配置 | |||||
*/ | |||||
private ConsensusSettings consensusSettings; | |||||
/** | |||||
* 共识参与方 | |||||
*/ | |||||
private ParticipantNode[] participantNodes; | |||||
public void setSeed(String seed) { | |||||
this.seed = seed; | |||||
} | |||||
public String getSeed() { | |||||
return seed; | |||||
} | |||||
public HashDigest getParticipantsHash() { | |||||
return participantsHash; | |||||
} | |||||
public void setParticipantsHash(HashDigest participantsHash) { | |||||
this.participantsHash = participantsHash; | |||||
} | |||||
public CryptoSetting getCryptoSetting() { | |||||
return cryptoSetting; | |||||
} | |||||
public void setCryptoSetting(CryptoSetting cryptoSetting) { | |||||
this.cryptoSetting = cryptoSetting; | |||||
} | |||||
public int getConsensusProtocol() { | |||||
return consensusProtocol; | |||||
} | |||||
public void setConsensusProtocol(int consensusProtocol) { | |||||
this.consensusProtocol = consensusProtocol; | |||||
} | |||||
public ConsensusSettings getConsensusSettings() { | |||||
return consensusSettings; | |||||
} | |||||
public void setConsensusSettings(ConsensusSettings consensusSettings) { | |||||
this.consensusSettings = consensusSettings; | |||||
} | |||||
public ParticipantNode[] getParticipantNodes() { | |||||
return participantNodes; | |||||
} | |||||
public void setParticipantNodes(ParticipantNode[] participantNodes) { | |||||
this.participantNodes = participantNodes; | |||||
} | |||||
public enum CONSENSUS_PROTOCOL { | |||||
UNKNOWN(0), | |||||
BFTSMART(1), | |||||
MSGQUEUE(2), | |||||
; | |||||
private int code; | |||||
CONSENSUS_PROTOCOL(int code) { | |||||
this.code = code; | |||||
} | |||||
public int code() { | |||||
return code; | |||||
} | |||||
} | |||||
} |
@@ -37,7 +37,12 @@ public abstract class BlockchainServiceProxy implements BlockchainService { | |||||
return getQueryService(ledgerHash).getConsensusParticipants(ledgerHash); | return getQueryService(ledgerHash).getConsensusParticipants(ledgerHash); | ||||
} | } | ||||
@Override | |||||
@Override | |||||
public LedgerMetadata getLedgerMetadata(HashDigest ledgerHash) { | |||||
return getQueryService(ledgerHash).getLedgerMetadata(ledgerHash); | |||||
} | |||||
@Override | |||||
public LedgerBlock getBlock(HashDigest ledgerHash, long height) { | public LedgerBlock getBlock(HashDigest ledgerHash, long height) { | ||||
return getQueryService(ledgerHash).getBlock(ledgerHash, height); | return getQueryService(ledgerHash).getBlock(ledgerHash, height); | ||||
} | } | ||||
@@ -204,6 +204,17 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService | |||||
@Override | @Override | ||||
ParticipantNode[] getConsensusParticipants(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash); | ParticipantNode[] getConsensusParticipants(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash); | ||||
/** | |||||
* 返回指定账本的元数据 | |||||
* | |||||
* @param ledgerHash | |||||
* @return | |||||
*/ | |||||
@HttpAction(method=HttpMethod.GET, path="ledgers/{ledgerHash}/metadata") | |||||
@Override | |||||
LedgerMetadata getLedgerMetadata(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash); | |||||
/** | /** | ||||
* 返回指定账本序号的区块; | * 返回指定账本序号的区块; | ||||
* | * | ||||
@@ -72,7 +72,7 @@ public class NodeSigningAppender implements TransactionService { | |||||
// 计算交易哈希; | // 计算交易哈希; | ||||
byte[] nodeRequestBytes = BinaryProtocol.encode(txMessage, TransactionRequest.class); | byte[] nodeRequestBytes = BinaryProtocol.encode(txMessage, TransactionRequest.class); | ||||
HashFunction hashFunc = Crypto.getHashFunction(signAlgorithm); | |||||
HashFunction hashFunc = Crypto.getHashFunction(this.hashAlgorithm); | |||||
HashDigest txHash = hashFunc.hash(nodeRequestBytes); | HashDigest txHash = hashFunc.hash(nodeRequestBytes); | ||||
txMessage.setHash(txHash); | txMessage.setHash(txHash); | ||||
@@ -14,5 +14,11 @@ | |||||
<artifactId>sdk-base</artifactId> | <artifactId>sdk-base</artifactId> | ||||
<version>${project.version}</version> | <version>${project.version}</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>com.jd.blockchain</groupId> | |||||
<artifactId>ledger-rpc</artifactId> | |||||
<version>${project.version}</version> | |||||
</dependency> | |||||
</dependencies> | </dependencies> | ||||
</project> | </project> |
@@ -3,15 +3,16 @@ package com.jd.blockchain.sdk.client; | |||||
import java.io.Closeable; | import java.io.Closeable; | ||||
import com.jd.blockchain.binaryproto.BinaryProtocol; | import com.jd.blockchain.binaryproto.BinaryProtocol; | ||||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||||
import com.jd.blockchain.consensus.ClientIdentification; | |||||
import com.jd.blockchain.consensus.ClientIdentifications; | |||||
import com.jd.blockchain.consensus.action.ActionRequest; | |||||
import com.jd.blockchain.consensus.action.ActionResponse; | |||||
import com.jd.blockchain.crypto.Crypto; | import com.jd.blockchain.crypto.Crypto; | ||||
import com.jd.blockchain.crypto.PrivKey; | import com.jd.blockchain.crypto.PrivKey; | ||||
import com.jd.blockchain.crypto.SignatureDigest; | import com.jd.blockchain.crypto.SignatureDigest; | ||||
import com.jd.blockchain.crypto.SignatureFunction; | import com.jd.blockchain.crypto.SignatureFunction; | ||||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||||
import com.jd.blockchain.ledger.DigitalSignature; | |||||
import com.jd.blockchain.ledger.TransactionContent; | |||||
import com.jd.blockchain.ledger.TransactionRequest; | |||||
import com.jd.blockchain.ledger.TransactionResponse; | |||||
import com.jd.blockchain.ledger.*; | |||||
import com.jd.blockchain.sdk.BlockchainService; | import com.jd.blockchain.sdk.BlockchainService; | ||||
import com.jd.blockchain.sdk.BlockchainServiceFactory; | import com.jd.blockchain.sdk.BlockchainServiceFactory; | ||||
import com.jd.blockchain.sdk.proxy.HttpBlockchainQueryService; | import com.jd.blockchain.sdk.proxy.HttpBlockchainQueryService; | ||||
@@ -24,6 +25,7 @@ import com.jd.blockchain.utils.http.agent.ServiceConnection; | |||||
import com.jd.blockchain.utils.http.agent.ServiceConnectionManager; | import com.jd.blockchain.utils.http.agent.ServiceConnectionManager; | ||||
import com.jd.blockchain.utils.http.agent.ServiceEndpoint; | import com.jd.blockchain.utils.http.agent.ServiceEndpoint; | ||||
import com.jd.blockchain.utils.net.NetworkAddress; | import com.jd.blockchain.utils.net.NetworkAddress; | ||||
import com.jd.blockchain.web.serializes.ByteArrayObjectUtil; | |||||
public class GatewayServiceFactory implements BlockchainServiceFactory, Closeable { | public class GatewayServiceFactory implements BlockchainServiceFactory, Closeable { | ||||
@@ -33,6 +35,31 @@ public class GatewayServiceFactory implements BlockchainServiceFactory, Closeabl | |||||
private BlockchainService blockchainService; | private BlockchainService blockchainService; | ||||
static { | |||||
DataContractRegistry.register(TransactionContent.class); | |||||
DataContractRegistry.register(TransactionContentBody.class); | |||||
DataContractRegistry.register(TransactionRequest.class); | |||||
DataContractRegistry.register(NodeRequest.class); | |||||
DataContractRegistry.register(EndpointRequest.class); | |||||
DataContractRegistry.register(TransactionResponse.class); | |||||
DataContractRegistry.register(DataAccountKVSetOperation.class); | |||||
DataContractRegistry.register(DataAccountKVSetOperation.KVWriteEntry.class); | |||||
DataContractRegistry.register(Operation.class); | |||||
DataContractRegistry.register(ContractCodeDeployOperation.class); | |||||
DataContractRegistry.register(ContractEventSendOperation.class); | |||||
DataContractRegistry.register(DataAccountRegisterOperation.class); | |||||
DataContractRegistry.register(UserRegisterOperation.class); | |||||
DataContractRegistry.register(ActionRequest.class); | |||||
DataContractRegistry.register(ActionResponse.class); | |||||
DataContractRegistry.register(ClientIdentifications.class); | |||||
DataContractRegistry.register(ClientIdentification.class); | |||||
ByteArrayObjectUtil.init(); | |||||
} | |||||
protected GatewayServiceFactory(ServiceEndpoint gatewayEndpoint, BlockchainKeypair userKey) { | protected GatewayServiceFactory(ServiceEndpoint gatewayEndpoint, BlockchainKeypair userKey) { | ||||
httpConnectionManager = new ServiceConnectionManager(); | httpConnectionManager = new ServiceConnectionManager(); | ||||
this.userKey = userKey; | this.userKey = userKey; | ||||
@@ -19,8 +19,6 @@ import com.jd.blockchain.crypto.HashFunction; | |||||
import com.jd.blockchain.crypto.PubKey; | import com.jd.blockchain.crypto.PubKey; | ||||
import com.jd.blockchain.crypto.SignatureDigest; | import com.jd.blockchain.crypto.SignatureDigest; | ||||
import com.jd.blockchain.crypto.SignatureFunction; | import com.jd.blockchain.crypto.SignatureFunction; | ||||
import com.jd.blockchain.crypto.serialize.ByteArrayObjectDeserializer; | |||||
import com.jd.blockchain.crypto.serialize.ByteArrayObjectSerializer; | |||||
import com.jd.blockchain.ledger.AccountHeader; | import com.jd.blockchain.ledger.AccountHeader; | ||||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | import com.jd.blockchain.ledger.BlockchainKeyGenerator; | ||||
import com.jd.blockchain.ledger.BlockchainKeypair; | import com.jd.blockchain.ledger.BlockchainKeypair; | ||||
@@ -53,17 +51,6 @@ import com.jd.blockchain.utils.serialize.json.JSONSerializeUtils; | |||||
public class SDK_GateWay_Query_Test_ { | public class SDK_GateWay_Query_Test_ { | ||||
private static Class<?>[] byteArrayClasss = new Class<?>[] { HashDigest.class, PubKey.class, | |||||
SignatureDigest.class }; | |||||
static { | |||||
for (Class<?> byteArrayClass : byteArrayClasss) { | |||||
JSONSerializeUtils.configSerialization(byteArrayClass, | |||||
ByteArrayObjectSerializer.getInstance(byteArrayClass), | |||||
ByteArrayObjectDeserializer.getInstance(byteArrayClass)); | |||||
} | |||||
} | |||||
private BlockchainKeypair CLIENT_CERT = null; | private BlockchainKeypair CLIENT_CERT = null; | ||||
private String GATEWAY_IPADDR = null; | private String GATEWAY_IPADDR = null; | ||||
@@ -14,7 +14,7 @@ | |||||
<artifactId>storage-service</artifactId> | <artifactId>storage-service</artifactId> | ||||
<version>${project.version}</version> | <version>${project.version}</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<!--<dependency> | |||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>storage-redis</artifactId> | <artifactId>storage-redis</artifactId> | ||||
<version>${project.version}</version> | <version>${project.version}</version> | ||||
@@ -24,6 +24,35 @@ | |||||
<artifactId>storage-rocksdb</artifactId> | <artifactId>storage-rocksdb</artifactId> | ||||
<version>${project.version}</version> | <version>${project.version}</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>com.jd.blockchain</groupId> | |||||
<artifactId>storage-tikv</artifactId> | |||||
<version>${project.version}</version> | |||||
</dependency>--> | |||||
<dependency> | |||||
<groupId>org.reflections</groupId> | |||||
<artifactId>reflections</artifactId> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.google.guava</groupId> | |||||
<artifactId>guava</artifactId> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.springframework.boot</groupId> | |||||
<artifactId>spring-boot</artifactId> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.springframework.boot</groupId> | |||||
<artifactId>spring-boot-autoconfigure</artifactId> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.springframework.boot</groupId> | |||||
<artifactId>spring-boot-configuration-processor</artifactId> | |||||
<optional>true</optional> | |||||
</dependency> | |||||
<!--<dependency> | <!--<dependency> | ||||
<groupId>org.rocksdb</groupId> | <groupId>org.rocksdb</groupId> | ||||
<artifactId>rocksdbjni</artifactId> | <artifactId>rocksdbjni</artifactId> | ||||
@@ -1,76 +1,100 @@ | |||||
package com.jd.blockchain.storage.service.impl.composite; | package com.jd.blockchain.storage.service.impl.composite; | ||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Set; | |||||
import java.util.concurrent.ConcurrentHashMap; | import java.util.concurrent.ConcurrentHashMap; | ||||
import com.jd.blockchain.storage.service.DbConnection; | import com.jd.blockchain.storage.service.DbConnection; | ||||
import com.jd.blockchain.storage.service.DbConnectionFactory; | import com.jd.blockchain.storage.service.DbConnectionFactory; | ||||
import com.jd.blockchain.storage.service.impl.redis.JedisConnection; | |||||
import com.jd.blockchain.storage.service.impl.redis.RedisConnectionFactory; | |||||
import com.jd.blockchain.storage.service.impl.rocksdb.RocksDBConnection; | |||||
import com.jd.blockchain.storage.service.impl.rocksdb.RocksDBConnectionFactory; | |||||
//import com.jd.blockchain.storage.service.utils.MemoryBasedDb; | |||||
import com.jd.blockchain.storage.service.utils.MemoryDBConn; | |||||
import com.jd.blockchain.storage.service.utils.MemoryDBConnFactory; | |||||
import org.reflections.Reflections; | |||||
import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | |||||
public class CompositeConnectionFactory implements DbConnectionFactory { | public class CompositeConnectionFactory implements DbConnectionFactory { | ||||
private static final RocksDBConnectionFactory rocksDBConnFactory = new RocksDBConnectionFactory(); | |||||
private static final RedisConnectionFactory redisConnFactory = new RedisConnectionFactory(); | |||||
private static final MemoryDBConnFactory memoryConnFactory = new MemoryDBConnFactory(); | |||||
private static final String CONN_PREFIX_REDIS = "redis://"; | |||||
private static final String CONN_PREFIX_ROCKSDB = "rocksdb://"; | |||||
private static final String CONN_PREFIX_MEMORY = "memory://"; | |||||
private final Map<String, DbConnection> connections = new ConcurrentHashMap<>(); | |||||
@Override | |||||
public DbConnection connect(String dbUri) { | |||||
return connect(dbUri, null); | |||||
} | |||||
@Override | |||||
public DbConnection connect(String dbConnectionString, String password) { | |||||
if (!dbConnectionString.startsWith(CONN_PREFIX_REDIS) && | |||||
!dbConnectionString.startsWith(CONN_PREFIX_ROCKSDB) && | |||||
!dbConnectionString.startsWith(CONN_PREFIX_MEMORY)){ | |||||
throw new IllegalArgumentException("Illegal format of composite db connection string!"); | |||||
} | |||||
if (dbConnectionString.startsWith(CONN_PREFIX_REDIS)) { | |||||
return redisConnFactory.connect(dbConnectionString, password); | |||||
} else if (dbConnectionString.startsWith(CONN_PREFIX_ROCKSDB)) { | |||||
return rocksDBConnFactory.connect(dbConnectionString, password); | |||||
} else if (dbConnectionString.startsWith(CONN_PREFIX_MEMORY)) { | |||||
return memoryConnFactory.connect(dbConnectionString, password); | |||||
} | |||||
return null; | |||||
} | |||||
@Override | |||||
public void close() { | |||||
for (DbConnection dbConnection : connections.values()) { | |||||
if (dbConnection.getClass().equals(JedisConnection.class)) { | |||||
((JedisConnection)dbConnection).close(); | |||||
} | |||||
else if (dbConnection.getClass().equals(RocksDBConnection.class)) { | |||||
((RocksDBConnection)dbConnection).dbClose(); | |||||
} | |||||
else if (dbConnection.getClass().equals(MemoryDBConn.class)) { | |||||
((MemoryDBConn)dbConnection).close(); | |||||
} | |||||
} | |||||
connections.clear(); | |||||
} | |||||
@Override | |||||
public boolean support(String scheme) { | |||||
return rocksDBConnFactory.support(scheme) || redisConnFactory.support(scheme) || memoryConnFactory.support(scheme); | |||||
} | |||||
// SPI的方式,需要初始化对应的Factory | |||||
private static final Map<String, DbConnectionFactory> connectionFactoryMap = new ConcurrentHashMap<>(); | |||||
private static Logger LOGGER = LoggerFactory.getLogger(CompositeConnectionFactory.class); | |||||
public CompositeConnectionFactory() { | |||||
init(); | |||||
} | |||||
private void init() { | |||||
// 初始化所有实现类 | |||||
Reflections reflections = new Reflections("com.jd.blockchain.storage.service"); | |||||
Set<Class<? extends DbConnectionFactory>> connectionSet = | |||||
reflections.getSubTypesOf(DbConnectionFactory.class); | |||||
for (Class<? extends DbConnectionFactory> clazz : connectionSet) { | |||||
if (clazz.equals(CompositeConnectionFactory.class)) { | |||||
continue; | |||||
} else { | |||||
try { | |||||
// 根据class生成对象 | |||||
DbConnectionFactory dbConnectionFactory = clazz.newInstance(); | |||||
String dbPrefix = dbConnectionFactory.dbPrefix(); | |||||
if (dbPrefix != null && dbPrefix.length() > 0 && | |||||
!connectionFactoryMap.containsKey(dbPrefix)) { | |||||
connectionFactoryMap.put(dbPrefix, dbConnectionFactory); | |||||
} | |||||
} catch (Exception e) { | |||||
LOGGER.error("class:{%s} init error {%s}", clazz.getName(), e.getMessage()); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
@Override | |||||
public DbConnection connect(String dbUri) { | |||||
return connect(dbUri, null); | |||||
} | |||||
@Override | |||||
public DbConnection connect(String dbConnectionString, String password) { | |||||
if (connectionFactoryMap.isEmpty()) { | |||||
throw new IllegalArgumentException("DB connections is empty, please init first!"); | |||||
} | |||||
for (Map.Entry<String, DbConnectionFactory> entry : connectionFactoryMap.entrySet()) { | |||||
String prefix = entry.getKey(); | |||||
if (dbConnectionString.startsWith(prefix)) { | |||||
return entry.getValue().connect(dbConnectionString, password); | |||||
} | |||||
} | |||||
throw new IllegalArgumentException("Illegal format of composite db connection string!"); | |||||
} | |||||
@Override | |||||
public void close() { | |||||
if (!connectionFactoryMap.isEmpty()) { | |||||
for (Map.Entry<String, DbConnectionFactory> entry : connectionFactoryMap.entrySet()) { | |||||
DbConnectionFactory dbConnectionFactory = entry.getValue(); | |||||
dbConnectionFactory.close(); | |||||
} | |||||
} | |||||
} | |||||
@Override | |||||
public String dbPrefix() { | |||||
return null; | |||||
} | |||||
@Override | |||||
public boolean support(String scheme) { | |||||
if (!connectionFactoryMap.isEmpty()) { | |||||
for (Map.Entry<String, DbConnectionFactory> entry : connectionFactoryMap.entrySet()) { | |||||
DbConnectionFactory dbConnectionFactory = entry.getValue(); | |||||
if (dbConnectionFactory.support(scheme)) { | |||||
return true; | |||||
} | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
} | } |
@@ -12,6 +12,7 @@ import org.springframework.context.annotation.Configuration; | |||||
@Configuration | @Configuration | ||||
@ComponentScan | @ComponentScan | ||||
public class CompositeStorageConfiguration { | public class CompositeStorageConfiguration { | ||||
@ConditionalOnMissingBean | @ConditionalOnMissingBean | ||||
@Bean | @Bean | ||||
public DbConnectionFactory compositeConnectionFactory() { | public DbConnectionFactory compositeConnectionFactory() { | ||||
@@ -1,112 +1,110 @@ | |||||
package test.com.jd.blockchain.storage.service.impl.composite; | |||||
import static org.junit.Assert.*; | |||||
import com.jd.blockchain.storage.service.DbConnection; | |||||
import com.jd.blockchain.storage.service.DbConnectionFactory; | |||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||||
import com.jd.blockchain.storage.service.impl.composite.CompositeConnectionFactory; | |||||
import com.jd.blockchain.storage.service.impl.rocksdb.RocksDBConnectionFactory; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
import com.jd.blockchain.utils.io.BytesUtils; | |||||
import com.jd.blockchain.utils.io.FileUtils; | |||||
import org.junit.Test; | |||||
import java.io.File; | |||||
import java.util.regex.Pattern; | |||||
public class CompositeConnectionFactoryTest { | |||||
public static final Pattern URI_PATTER_REDIS = Pattern | |||||
.compile("^\\w+\\://(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})\\:\\d+(/\\d*(/.*)*)?$"); | |||||
@Test | |||||
public void testRedisConnectionString() { | |||||
String connStr = "redis://192.168.86.130:6379/"; | |||||
boolean match = URI_PATTER_REDIS.matcher(connStr).matches(); | |||||
assertTrue(match); | |||||
connStr = "redis://192.168.86.131:6379/"; | |||||
match = URI_PATTER_REDIS.matcher(connStr).matches(); | |||||
assertTrue(match); | |||||
connStr = "redis://192.168.86.132:6379/"; | |||||
match = URI_PATTER_REDIS.matcher(connStr).matches(); | |||||
assertTrue(match); | |||||
connStr = "redis://192.168.86.133:6379/"; | |||||
match = URI_PATTER_REDIS.matcher(connStr).matches(); | |||||
assertTrue(match); | |||||
} | |||||
@Test | |||||
public void testRocksDbConnect() { | |||||
String dbUri = initEmptyDB("rocksdb_storage_test"); | |||||
long expectedVersion; | |||||
try (CompositeConnectionFactory dbConnFactory = new CompositeConnectionFactory()) { | |||||
// try (CompositeConnectionFactory dbConnFactory = CompositeConnectionFactory.getInstance()) { | |||||
DbConnection conn = dbConnFactory.connect(dbUri); | |||||
VersioningKVStorage verStorage = conn.getStorageService().getVersioningKVStorage(); | |||||
ExPolicyKVStorage exStorage = conn.getStorageService().getExPolicyKVStorage(); | |||||
expectedVersion = test(verStorage); | |||||
test(exStorage); | |||||
} | |||||
} | |||||
private String initEmptyDB(String name) { | |||||
String currDir = FileUtils.getCurrentDir(); | |||||
String dbDir = new File(currDir, name + ".db").getAbsolutePath(); | |||||
FileUtils.deleteFile(dbDir); | |||||
String dbURI = "rocksdb://" + dbDir; | |||||
return dbURI; | |||||
} | |||||
private long test(VersioningKVStorage verStorage) { | |||||
String key = "k1"; | |||||
long v = verStorage.getVersion(Bytes.fromString(key)); | |||||
assertEquals(-1, v); | |||||
byte[] data = verStorage.get(Bytes.fromString(key), -1); | |||||
assertNull(data); | |||||
data = verStorage.get(Bytes.fromString(key), 0); | |||||
assertNull(data); | |||||
data = verStorage.get(Bytes.fromString(key), 1); | |||||
assertNull(data); | |||||
data = BytesUtils.toBytes("data"); | |||||
v = verStorage.set(Bytes.fromString(key), data, -1); | |||||
assertEquals(0, v); | |||||
v = verStorage.set(Bytes.fromString(key), data, -1); | |||||
assertEquals(-1, v); | |||||
v = verStorage.set(Bytes.fromString(key), data, 0); | |||||
assertEquals(1, v); | |||||
return v; | |||||
} | |||||
private void test(ExPolicyKVStorage exStorage) { | |||||
String key = "kex"; | |||||
assertFalse(exStorage.exist(Bytes.fromString(key))); | |||||
byte[] data = exStorage.get(Bytes.fromString(key)); | |||||
assertNull(data); | |||||
data = BytesUtils.toBytes("data"); | |||||
assertFalse(exStorage.set(Bytes.fromString(key), data, ExPolicyKVStorage.ExPolicy.EXISTING)); | |||||
assertTrue(exStorage.set(Bytes.fromString(key), data, ExPolicyKVStorage.ExPolicy.NOT_EXISTING)); | |||||
assertTrue(exStorage.exist(Bytes.fromString(key))); | |||||
assertFalse(exStorage.set(Bytes.fromString(key), data, ExPolicyKVStorage.ExPolicy.NOT_EXISTING)); | |||||
assertTrue(exStorage.set(Bytes.fromString(key), data, ExPolicyKVStorage.ExPolicy.EXISTING)); | |||||
assertTrue(exStorage.set(Bytes.fromString(key), data, ExPolicyKVStorage.ExPolicy.EXISTING)); | |||||
assertFalse(exStorage.set(Bytes.fromString(key), data, ExPolicyKVStorage.ExPolicy.NOT_EXISTING)); | |||||
assertTrue(exStorage.exist(Bytes.fromString(key))); | |||||
byte[] reloadData = exStorage.get(Bytes.fromString(key)); | |||||
assertTrue(BytesUtils.equals(data, reloadData)); | |||||
} | |||||
} | |||||
//package test.com.jd.blockchain.storage.service.impl.composite; | |||||
//import static org.junit.Assert.*; | |||||
// | |||||
//import com.jd.blockchain.storage.service.DbConnection; | |||||
//import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||||
//import com.jd.blockchain.storage.service.VersioningKVStorage; | |||||
//import com.jd.blockchain.storage.service.impl.composite.CompositeConnectionFactory; | |||||
//import com.jd.blockchain.utils.Bytes; | |||||
//import com.jd.blockchain.utils.io.BytesUtils; | |||||
//import com.jd.blockchain.utils.io.FileUtils; | |||||
// | |||||
//import org.junit.Test; | |||||
// | |||||
//import java.io.File; | |||||
//import java.util.regex.Pattern; | |||||
// | |||||
//public class CompositeConnectionFactoryTest { | |||||
// | |||||
// public static final Pattern URI_PATTER_REDIS = Pattern | |||||
// .compile("^\\w+\\://(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})\\:\\d+(/\\d*(/.*)*)?$"); | |||||
// | |||||
// @Test | |||||
// public void testRedisConnectionString() { | |||||
// String connStr = "redis://192.168.86.130:6379/"; | |||||
// boolean match = URI_PATTER_REDIS.matcher(connStr).matches(); | |||||
// assertTrue(match); | |||||
// | |||||
// connStr = "redis://192.168.86.131:6379/"; | |||||
// match = URI_PATTER_REDIS.matcher(connStr).matches(); | |||||
// assertTrue(match); | |||||
// | |||||
// connStr = "redis://192.168.86.132:6379/"; | |||||
// match = URI_PATTER_REDIS.matcher(connStr).matches(); | |||||
// assertTrue(match); | |||||
// | |||||
// connStr = "redis://192.168.86.133:6379/"; | |||||
// match = URI_PATTER_REDIS.matcher(connStr).matches(); | |||||
// assertTrue(match); | |||||
// } | |||||
// | |||||
// @Test | |||||
// public void testRocksDbConnect() { | |||||
// String dbUri = initEmptyDB("rocksdb_storage_test"); | |||||
// long expectedVersion; | |||||
// try (CompositeConnectionFactory dbConnFactory = new CompositeConnectionFactory()) { | |||||
//// try (CompositeConnectionFactory dbConnFactory = CompositeConnectionFactory.getInstance()) { | |||||
// DbConnection conn = dbConnFactory.connect(dbUri); | |||||
// VersioningKVStorage verStorage = conn.getStorageService().getVersioningKVStorage(); | |||||
// ExPolicyKVStorage exStorage = conn.getStorageService().getExPolicyKVStorage(); | |||||
// | |||||
// expectedVersion = test(verStorage); | |||||
// | |||||
// test(exStorage); | |||||
// } | |||||
// } | |||||
// private String initEmptyDB(String name) { | |||||
// String currDir = FileUtils.getCurrentDir(); | |||||
// String dbDir = new File(currDir, name + ".db").getAbsolutePath(); | |||||
// FileUtils.deleteFile(dbDir); | |||||
// String dbURI = "rocksdb://" + dbDir; | |||||
// return dbURI; | |||||
// } | |||||
// private long test(VersioningKVStorage verStorage) { | |||||
// String key = "k1"; | |||||
// long v = verStorage.getVersion(Bytes.fromString(key)); | |||||
// assertEquals(-1, v); | |||||
// byte[] data = verStorage.get(Bytes.fromString(key), -1); | |||||
// assertNull(data); | |||||
// data = verStorage.get(Bytes.fromString(key), 0); | |||||
// assertNull(data); | |||||
// data = verStorage.get(Bytes.fromString(key), 1); | |||||
// assertNull(data); | |||||
// | |||||
// data = BytesUtils.toBytes("data"); | |||||
// v = verStorage.set(Bytes.fromString(key), data, -1); | |||||
// assertEquals(0, v); | |||||
// v = verStorage.set(Bytes.fromString(key), data, -1); | |||||
// assertEquals(-1, v); | |||||
// v = verStorage.set(Bytes.fromString(key), data, 0); | |||||
// assertEquals(1, v); | |||||
// return v; | |||||
// } | |||||
// | |||||
// private void test(ExPolicyKVStorage exStorage) { | |||||
// String key = "kex"; | |||||
// assertFalse(exStorage.exist(Bytes.fromString(key))); | |||||
// | |||||
// byte[] data = exStorage.get(Bytes.fromString(key)); | |||||
// assertNull(data); | |||||
// | |||||
// data = BytesUtils.toBytes("data"); | |||||
// assertFalse(exStorage.set(Bytes.fromString(key), data, ExPolicyKVStorage.ExPolicy.EXISTING)); | |||||
// | |||||
// assertTrue(exStorage.set(Bytes.fromString(key), data, ExPolicyKVStorage.ExPolicy.NOT_EXISTING)); | |||||
// assertTrue(exStorage.exist(Bytes.fromString(key))); | |||||
// | |||||
// assertFalse(exStorage.set(Bytes.fromString(key), data, ExPolicyKVStorage.ExPolicy.NOT_EXISTING)); | |||||
// | |||||
// assertTrue(exStorage.set(Bytes.fromString(key), data, ExPolicyKVStorage.ExPolicy.EXISTING)); | |||||
// assertTrue(exStorage.set(Bytes.fromString(key), data, ExPolicyKVStorage.ExPolicy.EXISTING)); | |||||
// assertFalse(exStorage.set(Bytes.fromString(key), data, ExPolicyKVStorage.ExPolicy.NOT_EXISTING)); | |||||
// | |||||
// assertTrue(exStorage.exist(Bytes.fromString(key))); | |||||
// | |||||
// byte[] reloadData = exStorage.get(Bytes.fromString(key)); | |||||
// assertTrue(BytesUtils.equals(data, reloadData)); | |||||
// } | |||||
// | |||||
// | |||||
//} |
@@ -0,0 +1 @@ | |||||
/.apt_generated_tests/ |
@@ -1,6 +1,9 @@ | |||||
package com.jd.blockchain.storage.service.impl.redis; | package com.jd.blockchain.storage.service.impl.redis; | ||||
import java.io.IOException; | |||||
import java.net.URI; | import java.net.URI; | ||||
import java.util.Map; | |||||
import java.util.concurrent.ConcurrentHashMap; | |||||
import java.util.regex.Pattern; | import java.util.regex.Pattern; | ||||
import com.jd.blockchain.storage.service.DbConnection; | import com.jd.blockchain.storage.service.DbConnection; | ||||
@@ -17,13 +20,20 @@ public class RedisConnectionFactory implements DbConnectionFactory { | |||||
// public static final Pattern URI_PATTER = Pattern | // public static final Pattern URI_PATTER = Pattern | ||||
// .compile("^\\w+\\://(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})\\:\\d+(/\\d+)?(/.*)*$"); | // .compile("^\\w+\\://(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})\\:\\d+(/\\d+)?(/.*)*$"); | ||||
private static final Map<String, DbConnection> connections = new ConcurrentHashMap<>(); | |||||
@Override | @Override | ||||
public DbConnection connect(String dbUri) { | public DbConnection connect(String dbUri) { | ||||
return connect(dbUri, null); | return connect(dbUri, null); | ||||
} | } | ||||
@Override | @Override | ||||
public DbConnection connect(String dbConnectionString, String password) { | |||||
public synchronized DbConnection connect(String dbConnectionString, String password) { | |||||
if (connections.containsKey(dbConnectionString)) { | |||||
// 暂不处理密码变化问题 | |||||
return connections.get(dbConnectionString); | |||||
} | |||||
URI dbUri = URI.create(dbConnectionString); | URI dbUri = URI.create(dbConnectionString); | ||||
if (!(dbUri.getScheme().equalsIgnoreCase("redis"))) { | if (!(dbUri.getScheme().equalsIgnoreCase("redis"))) { | ||||
@@ -42,7 +52,9 @@ public class RedisConnectionFactory implements DbConnectionFactory { | |||||
int port = dbUri.getPort(); | int port = dbUri.getPort(); | ||||
int dbId = retriveDbIdFromPath(dbUri.getPath()); | int dbId = retriveDbIdFromPath(dbUri.getPath()); | ||||
JedisPool pool = new JedisPool(config, host, port, Protocol.DEFAULT_TIMEOUT, password, dbId, false); | JedisPool pool = new JedisPool(config, host, port, Protocol.DEFAULT_TIMEOUT, password, dbId, false); | ||||
return new JedisConnection(pool); | |||||
JedisConnection jedisConnection = new JedisConnection(pool); | |||||
connections.put(dbConnectionString, jedisConnection); | |||||
return jedisConnection; | |||||
} | } | ||||
/** | /** | ||||
@@ -71,6 +83,11 @@ public class RedisConnectionFactory implements DbConnectionFactory { | |||||
return dbId; | return dbId; | ||||
} | } | ||||
@Override | |||||
public String dbPrefix() { | |||||
return "redis://"; | |||||
} | |||||
@Override | @Override | ||||
public boolean support(String scheme) { | public boolean support(String scheme) { | ||||
return RedisConsts.URI_SCHEME.equalsIgnoreCase(scheme); | return RedisConsts.URI_SCHEME.equalsIgnoreCase(scheme); | ||||
@@ -79,5 +96,14 @@ public class RedisConnectionFactory implements DbConnectionFactory { | |||||
@Override | @Override | ||||
public void close() { | public void close() { | ||||
// TODO: 未实现连接池的关闭; | // TODO: 未实现连接池的关闭; | ||||
if (!connections.isEmpty()) { | |||||
for (Map.Entry<String, DbConnection> entry : connections.entrySet()) { | |||||
try { | |||||
entry.getValue().close(); | |||||
} catch (IOException e) { | |||||
// 打印关闭异常日志 | |||||
} | |||||
} | |||||
} | |||||
} | } | ||||
} | } |
@@ -8,6 +8,7 @@ import org.rocksdb.RocksDBException; | |||||
import com.jd.blockchain.storage.service.DbConnection; | import com.jd.blockchain.storage.service.DbConnection; | ||||
import com.jd.blockchain.storage.service.KVStorageService; | import com.jd.blockchain.storage.service.KVStorageService; | ||||
import com.jd.blockchain.utils.io.FileUtils; | |||||
public class RocksDBConnection implements DbConnection { | public class RocksDBConnection implements DbConnection { | ||||
@@ -19,6 +20,10 @@ public class RocksDBConnection implements DbConnection { | |||||
public RocksDBConnection(String dbPath, Options options) { | public RocksDBConnection(String dbPath, Options options) { | ||||
try { | try { | ||||
String parentDir = FileUtils.getParent(dbPath); | |||||
if (!FileUtils.existDirectory(parentDir)) { | |||||
FileUtils.makeDirectory(parentDir); | |||||
} | |||||
this.db = RocksDB.open(options, dbPath); | this.db = RocksDB.open(options, dbPath); | ||||
} catch (RocksDBException e) { | } catch (RocksDBException e) { | ||||
throw new IllegalStateException(e.getMessage(), e); | throw new IllegalStateException(e.getMessage(), e); | ||||
@@ -43,7 +48,7 @@ public class RocksDBConnection implements DbConnection { | |||||
this.options = null; | this.options = null; | ||||
RocksDB db = this.db; | RocksDB db = this.db; | ||||
this.db = null; | this.db = null; | ||||
if (options != null) { | if (options != null) { | ||||
options.close(); | options.close(); | ||||
} | } | ||||
@@ -46,7 +46,7 @@ public class RocksDBConnectionFactory implements DbConnectionFactory { | |||||
String.format("Not supported db connection string with scheme \"%s\"!", dbUri.getScheme())); | String.format("Not supported db connection string with scheme \"%s\"!", dbUri.getScheme())); | ||||
} | } | ||||
String uriHead = URI_SCHEME + "://"; | |||||
String uriHead = dbPrefix(); | |||||
int beginIndex = dbConnectionString.indexOf(uriHead); | int beginIndex = dbConnectionString.indexOf(uriHead); | ||||
String dbPath = dbConnectionString.substring(beginIndex + uriHead.length()); | String dbPath = dbConnectionString.substring(beginIndex + uriHead.length()); | ||||
if (!dbPath.startsWith(File.separator)) { | if (!dbPath.startsWith(File.separator)) { | ||||
@@ -67,6 +67,11 @@ public class RocksDBConnectionFactory implements DbConnectionFactory { | |||||
} | } | ||||
@Override | |||||
public String dbPrefix() { | |||||
return URI_SCHEME + "://"; | |||||
} | |||||
@Override | @Override | ||||
public boolean support(String scheme) { | public boolean support(String scheme) { | ||||
return URI_SCHEME.equalsIgnoreCase(scheme); | return URI_SCHEME.equalsIgnoreCase(scheme); | ||||
@@ -3,7 +3,13 @@ package com.jd.blockchain.storage.service; | |||||
import java.io.Closeable; | import java.io.Closeable; | ||||
public interface DbConnectionFactory extends Closeable { | public interface DbConnectionFactory extends Closeable { | ||||
/** | |||||
* 数据库连接前缀 | |||||
* @return | |||||
*/ | |||||
String dbPrefix(); | |||||
/** | /** | ||||
* 是否支持指定 scheme 的连接字符串; | * 是否支持指定 scheme 的连接字符串; | ||||
* @param scheme | * @param scheme | ||||
@@ -25,6 +25,11 @@ public class MemoryDBConnFactory implements DbConnectionFactory { | |||||
private Map<String, DbConnection> memMap = new ConcurrentHashMap<>(); | private Map<String, DbConnection> memMap = new ConcurrentHashMap<>(); | ||||
@Override | |||||
public String dbPrefix() { | |||||
return "memory://"; | |||||
} | |||||
@Override | @Override | ||||
public boolean support(String scheme) { | public boolean support(String scheme) { | ||||
return true; | return true; | ||||