- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试学习一些加密编码,并生成了一个当前保存在字节数组 (byte[] privatekey) 中的 32 字节私钥。我知道公钥是使用 secp256k1 命名的椭圆曲线参数和一个公式生成的,其中 publickey = G * privatekey
,其中 G 是椭圆曲线上的某个点(ECPoint?),但我无法将该命名参数规范和公式转换为实际编码的公钥。我知道从 java 7 开始,java.security.*
和 java.security.spec.*
包中包含了一些类可以在短代码中执行此操作,但是我找不到一个很好的示例来说明如何在不使用第三方库的情况下执行此操作。
This bitcoin stackexchange link has all the theoretical answer and great python and C# code, but nothing in Java 。
编辑/更新:我尝试使用以下代码获得所需内容:
String secp256k1_G_uncompressed_string = "0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8";
byte[] secp256k1_G_uncompressed_bytes = DatatypeConverter.parseHexBinary(secp256k1_G_uncompressed_string);
String privatekeystring = "1184CD2CDD640CA42CFC3A091C51D549B2F016D454B2774019C2B2D2E08529FD";
byte[] privatekeybytes = DatatypeConverter.parseHexBinary(privatekeystring);
BigInteger secp256k1_G_num = new BigInteger(1, secp256k1_G_uncompressed_bytes);
BigInteger privatekey_num = new BigInteger(1, privatekeybytes);
BigInteger curvepoint = secp256k1_G_num.multiply(privatekey_num);
byte[] publickeybytes = curvepoint.toByteArray();
System.out.println(DatatypeConverter.printHexBinary(privatekeybytes));
System.out.println(DatatypeConverter.printHexBinary(publickeybytes));
04d0988bfa799f7d7ef9ab3de97ef481cd0f75d2367ad456607647edde665d6f6 fbdd594388756a7beaf73b4822bc22d36e9bda7db82df2b8b623673eefc0b7495
4E6801418BB6EF9F462F69830F82EB51BB9224219B9D89C8C34FB746297F59779D8B986194181BD7AB99DC7E3086914EA13C4B37E05716CADCA0AE391CE81C4B85E0F09E8628F0F81692B5D08D0D8B9E20615A5D23DE0F591D02C650554BB1D8
最佳答案
椭圆曲线点不是整数。将点 (G) 的编码表示放入 BigInteger
并试图将其用作整数是不正确的。椭圆曲线点乘法不是整数乘法,远没有BigInteger.multiply
那么简单.它是用左边的标量写的,例如kG 不是 Gk。
将比特币 Q 中给出的标准(或至少是传统的)算法转换为 Java 对任何 Java 程序员来说确实应该是一个相当简单的练习。
Scalar Multiplication of Point over elliptic Curve包含(在答案中)P192 aka secp192r1 的正确实现;可以通过将 p 和 a 替换为规范中的值(来自 https://www.secg.org 的 SEC2 或 X9.62,如果有)或任何现有实现(包括 Java(见下文))并丢弃 P192,将其转换为 secp256k1 - 特定的测试数据。实际上你主要需要改变 p; Koblitz 曲线被选择为具有 a=0。 Elliptic Curve Multiplication Function包含一个不太正确的实现,据说是针对 secp256k1 的,但实际上并不包含任何曲线的常量。
since java 7, there are classes included in the java.security.* and java.security.spec.* packages to do this in short code
java.security
中看到的类。和
javax.crypto
来自实现代码,该代码属于完全不同的类(大部分(仍然)在
sun.*
和
com.sun.*
下)在一个或多个“提供者”中,这些“提供者”是单独的 jar 并且在技术上是可选的;可以在不更改代码中的调用的情况下删除、添加或更改提供程序,尽管大多数人不这样做。自 Java 5(称为 1.5)以来,就存在用于 EC 加密的 JCA 'facade' 类,但标准构建中未包含实现 EC 算法的提供程序;要使用它们,您必须添加第三方提供程序。从 java 7 开始,包含一个标准的 SunEC 提供程序。但是,JCA(不仅适用于 EC 的所有算法)在生成后将私钥和公钥严格分开,特别是它无法访问 EC 内部存在的私有(private)到公共(public)的派生逻辑。
KeyPairGenerator kg = KeyPairGenerator.getInstance ("EC");
kg.initialize (new ECGenParameterSpec ("secp256k1"));
ECParameterSpec p = ((ECPublicKey) kg.generateKeyPair().getPublic()).getParams();
System.out.println ("p=(dec)" + ((ECFieldFp) p.getCurve().getField()).getP() );
ECPoint G = p.getGenerator();
System.out.format ("Gx=(hex)%032x%n", G.getAffineX());
System.out.format ("Gy=(hex)%032x%n", G.getAffineY());
//
byte[] privatekey_enc = DatatypeConverter.parseHexBinary(
"303E020100301006072A8648CE3D020106052B8104000A042730250201010420"+
"1184CD2CDD640CA42CFC3A091C51D549B2F016D454B2774019C2B2D2E08529FD");
// note fixed prefix for PKCS8-EC-secp256k1 plus your private value
KeyFactory kf = KeyFactory.getInstance("EC");
PrivateKey k1 = kf.generatePrivate(new PKCS8EncodedKeySpec(privatekey_enc));
ECParameterSpec p2 = ((ECPrivateKey) k1).getParams();
System.out.println ("again p=(dec)" + ((ECFieldFp) p2.getCurve().getField()).getP() );
p=(dec)115792089237316195423570985008687907853269984665640564039457584007908834671663
Gx=(hex)79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
Gy=(hex)483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
again p=(dec)115792089237316195423570985008687907853269984665640564039457584007908834671663
ECParameterSpec
包含 EC 曲线参数的对象(基础字段、曲线系数、基点又名生成器、顺序和辅因子;以及内部“名称”,尽管 API 未公开它)。我打印的标有“p”的值是调用
getP
的结果它从曲线参数中返回一项,即基础素数场的模数,以及您需要在链接帖子中显示的计算中使用的值
mod(p)
和
modInverse(p)
和
modPow(,p)
.由于此 p(或 P)是曲线的参数,因此该曲线上的所有键都相同;请注意,我打印的两个值是相同的,即使它们来自不同的键。实际上有两种用于密码学标准化的椭圆曲线:在素数域上的曲线,用 Fp 表示,以及在特征 2 的扩展域上的曲线,用 F2m 表示。 secp256k1 是第一种,这就是为什么要转换为
ECFieldFp
调用前
getP()
.
ECParameterSpec
结合使用。成
ECPublicKeySpec
并转换并使用它——或者你可以将点编码附加到一个相似但不同的固定前缀以获得
X509EncodedKeySpec
这是 Java 用于公钥的编码,并在不需要
ECParameterSpec
的情况下进行转换。提前 - 但据我所知,你的整个问题是你还没有公共(public)点并想要推导出它,这需要链接帖子中显示的点乘计算。
关于java - 在 native java (7+) 中从字节数组私钥生成 EC 公钥,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48832170/
我是一名优秀的程序员,十分优秀!