Skip to content

Commit

Permalink
Optimized signature algorithm (#501)
Browse files Browse the repository at this point in the history
* add sign transfer tx test.

* optimize ecdsa sign method.

fix opt code.

update opcode

update opt ecdsa sign.

update

add ECDSASigner.java

add x,y,r,s log info

== to !=

add log info

update

* annotate the code for the test

* optimize sm2 sign method.

* add cache for SM2Signer object

* fix ci

* Add code comments
  • Loading branch information
ywy2090 authored Feb 11, 2020
1 parent 2b0bb69 commit 9d07564
Show file tree
Hide file tree
Showing 17 changed files with 1,074 additions and 26 deletions.
2 changes: 1 addition & 1 deletion .ci/ci_check_commit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
set -e

scan_code_script="cobra/cobra.py -f json -o /tmp/report.json -t "
ignore_files=(Constant.java PerformanceOkDSync.java SM2Algorithm.java SM2KeyGenerator.java test)
ignore_files=(ECDSASign.java Constant.java PerformanceOkDSync.java SM2Algorithm.java SM2KeyGenerator.java test)

LOG_ERROR() {
content=${1}
Expand Down
61 changes: 53 additions & 8 deletions src/main/java/org/fisco/bcos/web3j/crypto/ECDSASign.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,23 @@
import java.math.BigInteger;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.signers.ECDSASigner;
import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;
import org.fisco.bcos.web3j.utils.Numeric;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** Created by websterchen on 2018/4/25. */
public class ECDSASign implements SignInterface {

private static final Logger logger = LoggerFactory.getLogger(ECDSASign.class);

private static final BigInteger curveN =
new BigInteger(
1,
Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"));
private static final BigInteger halfCurveN = curveN.shiftRight(1);

@Override
public Sign.SignatureData signMessage(byte[] message, ECKeyPair keyPair) {
BigInteger privateKey = keyPair.getPrivateKey();
Expand All @@ -19,20 +30,54 @@ public Sign.SignatureData signMessage(byte[] message, ECKeyPair keyPair) {
byte[] messageHash = Hash.sha3(message);

ECDSASignature sig = sign(messageHash, privateKey);

// Now we have to work backwards to figure out the recId needed to recover the signature.
int recId = -1;

/** Optimize the algorithm for calculating the recId value */
ECPoint ecPoint = sig.p;
BigInteger affineXCoordValue = ecPoint.normalize().getAffineXCoord().toBigInteger();
BigInteger affineYCoordValue = ecPoint.normalize().getAffineYCoord().toBigInteger();

int recId = affineYCoordValue.and(BigInteger.ONE).intValue();
recId |= (affineXCoordValue.compareTo(sig.r) != 0 ? 2 : 0);
if (sig.s.compareTo(halfCurveN) > 0) {
sig.s = Sign.CURVE.getN().subtract(sig.s);
recId = recId ^ 1;
}

/**
* The algorithm that calculated the recId value before and can be used to test if recId
* value is correct
*/
/*
int recId0 = -1;
for (int i = 0; i < 4; i++) {
BigInteger k = Sign.recoverFromSignature(i, sig, messageHash);
if (k != null && k.equals(publicKey)) {
recId = i;
recId0 = i;
break;
}
}
if (recId == -1) {
if (recId0 == -1) {
throw new RuntimeException(
"Could not construct a recoverable key. This should never happen.");
}
if (recId != recId0) {
if (logger.isErrorEnabled()) {
logger.error(
" invalid recId value111, recId={}, recIdOld={}, s={}, r={}, x={}, y={} ",
recId,
recIdOld,
sig.s,
sig.r,
affineXCoordValue,
affineYCoordValue);
}
}
*/

int headerByte = recId + 27;

// 1 header + 32 bytes for R + 32 bytes for S
Expand All @@ -48,8 +93,8 @@ public static ECDSASignature sign(byte[] transactionHash, BigInteger privateKey)

ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(privateKey, CURVE);
signer.init(true, privKey);
BigInteger[] components = signer.generateSignature(transactionHash);

return new ECDSASignature(components[0], components[1]).toCanonicalised();
Object[] components = signer.generateSignature2(transactionHash);
return new ECDSASignature(
(BigInteger) components[0], (BigInteger) components[1], (ECPoint) components[2]);
}
}
19 changes: 15 additions & 4 deletions src/main/java/org/fisco/bcos/web3j/crypto/ECDSASignature.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
package org.fisco.bcos.web3j.crypto;

import java.math.BigInteger;
import org.bouncycastle.math.ec.ECPoint;

/** An ECDSA Signature. */
public class ECDSASignature {
public final BigInteger r;
public final BigInteger s;
public BigInteger r;
public BigInteger s;
/**
* The value of p is used to assist in calculating the value of recvID and it's value is
* generated during the signature process
*/
public ECPoint p;

public ECDSASignature(BigInteger r, BigInteger s) {
public ECDSASignature(BigInteger r, BigInteger s, ECPoint p) {
this.r = r;
this.s = s;
this.p = p;
}

public ECDSASignature(BigInteger r, BigInteger s) {
this(r, s, null);
}

/**
Expand Down Expand Up @@ -40,7 +51,7 @@ public ECDSASignature toCanonicalised() {
// N = 10
// s = 8, so (-8 % 10 == 2) thus both (r, 8) and (r, 2) are valid solutions.
// 10 - 8 == 2, giving us always the latter solution, which is canonical.
return new ECDSASignature(r, Sign.CURVE.getN().subtract(s));
return new ECDSASignature(r, Sign.CURVE.getN().subtract(s), p);
} else {
return this;
}
Expand Down
Loading

0 comments on commit 9d07564

Please sign in to comment.