简述
ECC(Elliptic Curves Cryptography,椭圆曲线密码编码学)是一种公开密钥算法。基于椭圆曲线数学的公开密钥加密算法,其本质是利用离散对数问题实现加密。
ECC的主要优势,是在使用更小的密钥的同时,提供更快的性能和更高等级的安全。
网上的理论大都讲的非常透彻,我也是看了很多,但是实际能力有限,对数论层面的只停留在浅薄的理解上,不敢乱讲。但是可以简单的说明其原理。
还有一点,加密算法包括RSA
和ECC
并不是不可以被破解,只是以当下现代计算机的计算性能算起来比较费劲,理论上破解ECC
需要最少250万年,其破解的代价很高,以此来达到不可破解目的。
用量子计算?不说现在有量子技术可不可么,假设量子计算可是可行的,那为什么不升级到量子加密?
ECC: 基于椭圆曲线和离散对数
其原理是数论理论中的单向运算函数,这种函数有一个特点:正方向计算容易,反方向计算却十分困难。
啥意思?就是计算:
1234 * 4567 = ?
计算这个简单,结果是:5635678。
那么,返过来计算:
5635678 = x * y
这样就不好计算了,而且结果有很多种有可能是:
5635678 = 1 * 5635678
5635678 = 2 * 2817839
5635678 = 3 * 1408919.5
都有可能。
应用
在编程领域最难的是0到1的过程,而复用前人的技术和经验上就比较轻松。
在对ECC的使用上,已经将这一算法简化到接口层面,通过调用接口来获提需要的安全性。
BouncyCastle 加密工具包
BouncyCastle(轻量级密码术包)是一种用于 Java 平台的开放源码的轻量级密码术包;Bouncycstle 包含了大量的密码算法,其支持椭圆曲线密码算法,并提供JCE 1.2.1的实现。它提供了Java标准库没有的一些算法,例如,RipeMD160哈希算法。
TRON 中也是使用的这个算法工具包。
官网:https://www.bouncycastle.org/
ECKey 类
ECC 类是对加密工具的一个抽象,从类的Copyright
上可以看到,这个类实际上是从ethereumJ
拿过来的。好的设计都是相通的。
ECC在TRON中,创建账号的时候的用法:
1.获取一个ECKey 对象
2.获得私钥
3.获得公钥
通过 TRON 中生成账户这个接口来,非常典型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| @Component @Slf4j(topic = "API") public class GenerateAddressServlet extends RateLimiterServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) { try { SignInterface sign = SignUtils.getGeneratedRandomSign(Utils.getRandom(), Args.getInstance().isECKeyCryptoEngine()); byte[] priKey = sign.getPrivateKey(); byte[] address = sign.getAddress(); String priKeyStr = Hex.encodeHexString(priKey); String base58check = StringUtil.encode58Check(address); String hexString = ByteArray.toHexString(address); JSONObject jsonAddress = new JSONObject(); jsonAddress.put("address", base58check); jsonAddress.put("hexAddress", hexString); jsonAddress.put("privateKey", priKeyStr); response.getWriter().println(jsonAddress.toJSONString()); } catch (Exception e) { Util.processError(e, response); } }
protected void doPost(HttpServletRequest request, HttpServletResponse response) { doGet(request, response); } }
|
调一下试试,反复多调几次可以生成不同的私钥
curl -X GET http://127.0.0.1:8090/wallet/generateaddress
结果关键是拿到私钥,然后通过私钥获得公钥、base58check:
address: TNV7s8K96ZgEiFDuecSXvzKKJgkXwtjkWi
hexAddress: 418949b347588b1901fdf3b6e6dc80dffcd385c4de
privateKey: f7252a484bc631e57910cf65481b12c32b2906fa05742c72f27669b9ddc5d871
使用就是这么简单,可以本地起一个FullNode
自行调用接口,产生新的私钥,并没有中心化节点的之间的通信,也可以调用官方节点的接口,都是一样的。可以反复生成私钥,用来测试。
看下SignUtils.getGeneratedRandomSign是怎么处理
1 2 3 4 5 6 7 8 9
| public static SignInterface getGeneratedRandomSign( SecureRandom secureRandom, boolean isECKeyCryptoEngine) { if (isECKeyCryptoEngine) { return new ECKey(secureRandom); } return new SM2(secureRandom); }
|
完整示例
使用一个完整的例子来看看怎么用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public static void test() { ECKey ecKey = new ECKey(Utils.getRandom()); String privateKey = ByteArray.toHexString(ecKey.getPrivKeyBytes()); String publicKey = Hex.toHexString(ecKey.getPubKey()); byte[] hexAddress = ecKey.getAddress(); String base58check1 = PublicMethed.getAddressString(privateKey); String base58check2 = StringUtil.encode58Check(hexAddress); String bash58check3 = Base58.encode58Check(hexAddress);
System.out.println("private key: " + privateKey); System.out.println("public key" + publicKey); System.out.println("hex address1: " + ByteArray.toHexString(hexAddress)); System.out.println("base58check1: " + base58check1); System.out.println("base58check2: " + base58check2); System.out.prntln("bash58check3: " + bash58check3); ByteString bytes = ByteString.copyFrom(Commons.decodeFromBase58Check(base58check1)); System.out.println("hex address2: " + ByteArray.toHexString(bytes.toByteArray())); }
|
base58check 地址
base58check是一种特殊的格式,我在之前的文章中讲过个格式。看看它是怎么实现的。
TRON 中有两处需要使用到base58check格式:
- 私钥address
- 账户address
基本上账户的address用的多,在转账交易中base58check地址用的是最多的。
base58check就是给人看的,实际数据存到数据库中就是byte[]。
看下 base58check 的工作原理:将输入数据进行两次hash后,截取部分数据进行base58编码。
1 2 3 4 5 6 7 8
| public static String encode58Check(byte[] input) { byte[] hash0 = Sha256Hash.hash(CommonParameter.getInstance().isECKeyCryptoEngine(), input); byte[] hash1 = Sha256Hash.hash(CommonParameter.getInstance().isECKeyCryptoEngine(), hash0); byte[] inputCheck = new byte[input.length + 4]; System.arraycopy(input, 0, inputCheck, 0, input.length); System.arraycopy(hash1, 0, inputCheck, input.length, 4); return Base58.encode(inputCheck); }
|
总结
分享了一下ECC的用法,使用场景上不同链的用法也都是大同小异,明白几个概念,在关键处不至于被卡住。
学习方法我不断强调先熟练使用,再谈理解。
总是会有朋友跟我谈如何学习、理解这个问题,总觉得自己不聪明、理解不了。排除每个各人的理解能力,只谈投入时间,如果没有达到称的上努力的程度,请先不要谈悟性,如果你做不到看一眼一分钟内就理解,那么每天最少一小时的时间成本投入都没有,那先不要谈悟性。
时间也是成本,不要吝啬在重要的事情上投入时间