数字签名每次都不同

时间:2019-06-10 04:37:44

标签: cryptography blockchain

数字签名取决于消息和密钥。假设接收者多次复制消息(我们使用唯一ID的原因),为什么签名会不同(由于消息和密钥相同)?

2 个答案:

答案 0 :(得分:0)

比特币使用ECDSA,并且同一消息和密钥的签名不同的原因是随机随机数,该随机数是在每次创建签名时生成的。

ECDSA签名是一对(r,s),其中r是kG的X坐标,而s =(m + r * x)/ k(其中k = nonce,m = message hash,x = private key ,G =曲线发生器)。

另请参阅https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Signature_generation_algorithm中的#3

答案 1 :(得分:0)

该答案只是对以上理论答案的实用补充。该摘录使用相同的私钥在for-loop内部对同一消息进行数字签名,并且每次都打印出不同的数字签名。这些签名中的每一个都是有效的,并且将使用签名者的公钥进行验证。

import java.security.Security;
import java.security.Signature;
import java.security.KeyFactory;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.KeyPairGenerator;
import java.security.KeyPair;

import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.interfaces.ECPublicKey;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

class liptic
{
    static String the_message = "how are you, little tiger?";

    public static void main(String args[]) throws Exception
    {
        Security.addProvider(new BouncyCastleProvider());
        SecureRandom random = new SecureRandom();
        ECParameterSpec ecSpec
            = 
ECNamedCurveTable.getParameterSpec("secp256k1");

        KeyPairGenerator g = 
KeyPairGenerator.getInstance("ECDH", "BC");
        g.initialize(ecSpec, random);
        KeyPair keyPair = g.generateKeyPair();

        byte[] bob_pubkey = Hex.decode( "040581E4AEEEB1CEA57094D1AD97B8C721509B6E5D3690C70BBB8EB2C5FE8040"
        +  "FB2C9B0A77EA2AD05C5E8DB499F647BC9A8BE829961950D6F5A45952C097CCB0BC");
    Signature signer = Signature.getInstance("SHA256withECDSA", "BC");

    ECPublicKeySpec pubkSpec = new ECPublicKeySpec(
        ecSpec.getCurve().decodePoint(bob_pubkey), ecSpec);

    ECPublicKey publicKey
        = (ECPublicKey)KeyFactory.getInstance("ECDSA", "BC")
              .generatePublic(pubkSpec);

    byte[] signature = null;
    byte[] input = the_message.getBytes();
    signer.initSign(keyPair.getPrivate());
    signer.update(input);
    for (int i = 0; i < 5; i++) {
        signature = signer.sign();
        System.out.println(o(signature));
    }
  }

    public static String o(byte[] bytes)
    {
      int n = 0;
      StringBuilder sb = new StringBuilder();
      for (byte b : bytes) {
        sb.append(String.format("%02X", b));
        n++;
        if (n % 128 == 0) {
            sb.append("\n");
        }
      }
      return sb.toString();
   }
}

以下是数字签名:

  • 3046022100889CC42C4BAA07FF33AB34CADD8BCB0A44E77031D4A5F5A9849840DF3AB63FDA0221009CA5C49FC0EBE9F839A0CFAB18CEC91C9169FF439C1E2DFD724D06E2DB9FE258li>
  • 30460221009D30465EFD3676982CBE12B998D41D012322C255594D5037F156143AEC7E7305022100A77FE7DEB580837A1A5A5D1B74334C56E9F26BA1834EE3AC93ECEB01349A6F1C
  • 3045022100DF4AF153D808A9199C18C97E689F1214E7F59C621D6ECBAADFE206B83707CA2802203E592D0152E79E14084183206F4B6DBC95D68FBA2D23F65884A3B68FA79A4E04
  • 304502202E9FA22709308D08106F76CBB6278B3F485A3C706EDA3FFAF5CE744D4B90E9510221009DD2370863D6C1CE36D828FF9B98347905F2D0856052C4A30B25DD00575B8921
  • 3045022100AA46FEA1A80498E481D46B17EFD7FBE6656641CD719AF1F5DC0C77ADD334729D0220471472117374E0284074EBC81172E6271CA9D86F54AFCE6E6CF6863814EBF824

这是使用椭圆曲线数字签名算法。