## 实现过程

public ECDSASignature sign(byte[] messageHash) {
ECDSASignature sig = doSign(messageHash);
// Now we have to work backwards to figure out the recId needed to recover the signature.
int recId = -1;
byte[] thisKey = this.pub.getEncoded(false);
// {1.1. Let x = r + jn  .........
int h = 4;
// h means how many possible point we can get. from 𝑟 (in the signature),,
for (int i = 0; i < h; i++) {
byte[] k = ECKey.recoverPubBytesFromSignature(i, sig, messageHash);
if (k != null && Arrays.equals(k, thisKey)) {
recId = i;
break;
}
}
if (recId == -1) {
throw new RuntimeException(
"Could not construct a recoverable key. This should never happen.");
}
** sig.v = (byte) (recId + ECDSASignature.vBase);**
return sig;
}

byte[] recoverPubBytesFromSignature(int recId, ECDSASignature sig, byte[] messageHash) {
// omit params validation
BigInteger n = CURVE.getN(); // Curve order.
BigInteger i = BigInteger.valueOf((long) recId / 2);
ECCurve.Fp curve = (ECCurve.Fp) CURVE.getCurve();
BigInteger prime = curve.getQ(); // Bouncy Castle is not consistent about the letter it uses for the prime.
if (x.compareTo(prime) >= 0) {
// Cannot have point co-ordinates larger than this as everything takes place
// modulo Q.
return null;
}
// Compressed keys require you to know an extra bit of data about the y-coord as
// there are two possibilities.
// So it's encoded in the recId.
ECPoint R = decompressKey(x, (recId & 1) == 1);
// 1.4. If nR != point at infinity, then do another iteration of Step 1 (callers
// responsibility).
if (!R.multiply(n).isInfinity())
return null;
// 1.5. Compute e from M using Steps 2 and 3 of ECDSA signature verification.
BigInteger e = new BigInteger(1, messageHash);
BigInteger eInv = BigInteger.ZERO.subtract(e).mod(n);
BigInteger rInv = sig.r.modInverse(n);
BigInteger srInv = rInv.multiply(sig.s).mod(n);
BigInteger eInvrInv = rInv.multiply(eInv).mod(n);
ECPoint.Fp q = (ECPoint.Fp) ECAlgorithms.sumOfTwoMultiplies(CURVE.getG(), eInvrInv, R, srInv);
return q.getEncoded(false);
}

## 小结

Cipolla算法是一般性求解二次剩余的方法，具体到secp256k1,我们利用其曲线和签名特性可以使用更针对性的高效方法来解决。到此，secp256k1公钥恢复主题相关内容从理论到实践描述完毕。

• 发表于 2020-08-10 17:52
• 阅读 ( 280 )
• 学分 ( 8 )
• 分类：入门/理论

blocksight

59 篇文章, 1392 学分