Loading... ## AR关键文档 HTTP : [https://docs.arweave.org/developers/server/http-api](https://docs.arweave.org/developers/server/http-api) **查询交易上链情况:**[https://arweave.net/unconfirmed_tx/](https://arweave.net/unconfirmed_tx/){id} ## maven关键信息导入 ``` <dependency> <groupId>com.nimbusds</groupId> <artifactId>nimbus-jose-jwt</artifactId> <version>9.19</version> </dependency> <!-- hutool与fastjson可根据需要引入 --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-core</artifactId> <version>${hutool-version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>${fastjson.version}</version> </dependency> ``` ## 签名 ``` /** * Ar 交易bean * * @author Ganhua * @date 2022/2/22 */ @Getter @Setter @NoArgsConstructor public class ArTransaction { private static Random rand; static { try { rand = SecureRandom.getInstanceStrong(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } } private Integer format = 2; /** * 交易签名的sha256 hash */ private String id; /** * 账户上一笔交易hash 防止重复交易 */ @JSONField(name = "last_tx") @Alias("last_tx") private String lastTx; /** * 发送方 JWK的 n模值 完整的base64str */ private String owner; /** * 交易费用 */ private String reward; private String data = ""; /** * 发送方标识符 相当于备注 但需要设置为json格式 */ private List<Tag> tags; /** * 目标地址的 SHA-256 hash 可以使用空字符串 */ private String target; /** * 金额 没有可使用空字符串 */ private String quantity; @JSONField(name = "data_size") @Alias("data_size") private String dataSize = "0"; /** * 交易签名 */ private String signature; @JSONField(name = "data_root") @Alias("data_root") public String dataRoot = ""; public ArTransaction(String toAddress, BigDecimal quantity,List<Tag> tags) { this.tags = Tag.tagsEncode(tags); this.target = toAddress; // 12位 this.quantity = quantity.multiply(CurrencyType.ARWEAVE.getPrecision()).stripTrailingZeros().toPlainString(); } public String updateReward(BigDecimal price, long speedFactor){ BigDecimal base = BigDecimal.valueOf(100); BigDecimal speed = new BigDecimal(speedFactor); return (price.multiply((base.add(speed)))).divide(base,0, RoundingMode.DOWN).toString(); } public RSAPrivateCrtKeyParameters getPrivateKey(String privateKeyJson){ JSONObject json = JSON.parseObject(privateKeyJson); BigInteger e = CryptoUtils.base64Dec(json.getString("e")); BigInteger n = CryptoUtils.base64Dec(json.getString("n")); BigInteger d = CryptoUtils.base64Dec(json.getString("d")); BigInteger p = CryptoUtils.base64Dec(json.getString("p")); BigInteger q = CryptoUtils.base64Dec(json.getString("q")); BigInteger dp = CryptoUtils.base64Dec(json.getString("dp")); BigInteger dq = CryptoUtils.base64Dec(json.getString("dq")); BigInteger qi = CryptoUtils.base64Dec(json.getString("qi")); return new RSAPrivateCrtKeyParameters(n,e,d,p,q,dp,dq,qi); } @SneakyThrows public void signature(String privateKeyJson){ JSONObject json = JSON.parseObject(privateKeyJson); this.lastTx = ArWalletApi.syncGetTransactionAnchor(); this.owner = new Base64URL(json.getString("n")).toString(); this.reward = updateReward(ArWalletApi.getTransactionPrice(null,this.target),0); ArrayList<Object> dataList = new ArrayList<>(); String formatStr = CryptoUtils.encode("" + this.format); dataList.add(formatStr); dataList.add(this.owner); dataList.add(this.target); String quantityStr = CryptoUtils.base64(this.quantity.getBytes()); dataList.add(quantityStr); String rewardStr = CryptoUtils.base64(this.reward.getBytes()); dataList.add(rewardStr); dataList.add(this.lastTx); dataList.add(Tag.tagValue(this.tags)); String dataSizeStr = CryptoUtils.base64(this.dataSize.getBytes()); dataList.add(dataSizeStr); if (this.dataRoot!=null){ dataList.add(this.dataRoot); } byte[] signData = CryptoUtils.deepHash(dataList); byte[] signatureStr = sign(privateKeyJson, signData); this.id = CryptoUtils.base64(CryptoUtils.sha256(signatureStr)); this.signature = CryptoUtils.base64(signatureStr); } @SneakyThrows public byte[] sign(String privateKeyJson,byte[] hash){ JSONObject json = JSON.parseObject(privateKeyJson); RSAPrivateCrtKeyParameters privateKey = getPrivateKey(privateKeyJson); PSSSigner pssSigner = new PSSSigner(new RSAEngine(), new SHA256Digest(), 32); pssSigner.init(true, new ParametersWithRandom(privateKey)); pssSigner.update(hash, 0, hash.length); byte[] result; try { result = pssSigner.generateSignature(); RSAKeyParameters pub = new RSAKeyParameters(false, CryptoUtils.base64Dec(json.getString("n")), CryptoUtils.base64Dec(json.getString("e"))); pssSigner.init(false, pub); pssSigner.update(hash, 0, hash.length); if(!pssSigner.verifySignature(result)){ throw new DangerException("签名失败"); } } catch (Exception ex) { throw new DangerException("无法生成pss签名 " + ex.getMessage(), ex); } return result; } } ``` ``` /** * Ar加解密函数 工具 * @author Ganhua * @date 2022/2/17 */ public class CryptoUtils { public static byte[] toBigEndianBytes(BigInteger n){ byte[] bytes = n.toByteArray(); if (bytes.length > 1 && bytes[0] == (byte)0){ return PrimitiveArrayUtil.remove(bytes,0); } return new byte[0]; } public static String toJson(ArWallet wallet){ Dict json = Dict.create().set("kty", "RSA") .set("e", encode(wallet.getPublicKey().getPublicExponent())) .set("n", encode(wallet.getPublicKey().getModulus())) .set("d", encode(wallet.getPrivateKey().getPrivateExponent())) .set("p", encode(wallet.getPrivateKey().getPrimeP())) .set("q", encode(wallet.getPrivateKey().getPrimeQ())) .set("dp", encode(wallet.getPrivateKey().getPrimeExponentP())) .set("dq", encode(wallet.getPrivateKey().getPrimeExponentQ())) .set("qi", encode(wallet.getPrivateKey().getCrtCoefficient())); return JSON.toJSONString(json); } public static byte[] decode(String originalInput) { return Base64.getUrlDecoder().decode(originalInput); } public static String base64(byte[] bytes){ return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); } public static String encode(String byteStr){ return Base64.getUrlEncoder().withoutPadding().encodeToString(byteStr.getBytes()); } public static String encode(BigInteger bigInt){ return Base64URL.encode(bigInt).toString(); } public static BigInteger base64Dec(String base64){ return new Base64URL(base64).decodeToBigInteger(); } @SneakyThrows public static byte[] sha256(byte[] bytes){ MessageDigest instance = MessageDigest.getInstance("SHA-256"); instance.update(bytes); return instance.digest(); } public static byte[] getSha384StrJava(byte[] data){ MessageDigest messageDigest; byte[] encodeStr = null; try { messageDigest = MessageDigest.getInstance("SHA-384"); messageDigest.update(data); encodeStr = messageDigest.digest(); } catch (Exception e) { e.printStackTrace(); } return encodeStr; } public static byte[] deepHashStr(String str) throws Exception { byte[] result; byte[] data = decode(str); String length = "" + data.length; String blob = "blob"; ByteArrayOutputStream os = new ByteArrayOutputStream(); os.write(blob.getBytes()); os.write(length.getBytes()); byte[] tag = os.toByteArray(); byte[] tagHash = getSha384StrJava(tag); byte[] dataHash = getSha384StrJava(data); os = new ByteArrayOutputStream(); os.write(tagHash); os.write(dataHash); byte[] finalContent = os.toByteArray(); result = getSha384StrJava(finalContent); return result; } public static byte[] deepHashChunk(List<Object> data, byte[] acc) throws Exception{ if (data.isEmpty()) { return acc; } byte[] result; byte[] dHash; if (data.get(0) instanceof String){ String str = (String) data.get(0); dHash = deepHashStr(str); } else{ Object[] value = (Object[]) data.get(0); ArrayList<Object> dData = new ArrayList<>(Arrays.asList(value)); dHash = deepHash(dData); } ByteArrayOutputStream os = new ByteArrayOutputStream(); os.write(acc); os.write(dHash); result = os.toByteArray(); result = getSha384StrJava(result); List<Object> subData = data.subList(1,data.size()); result = deepHashChunk(subData,result); return result; } public static byte[] deepHash(List<Object> data) throws Exception{ ByteArrayOutputStream os = new ByteArrayOutputStream(); String listSizeInString = "" + data.size(); String key = "list"; os.write(key.getBytes()); os.write(listSizeInString.getBytes()); byte[] tag = os.toByteArray(); byte[] tagHash = getSha384StrJava(tag); return deepHashChunk(data,tagHash); } ``` ## 生成地址相关类 ``` @SneakyThrows public WalletResult createWalletAddress() { SecureRandom sr = new SecureRandom(); int keySize = 4096; KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(new RSAKeyGenParameterSpec(keySize, ArWallet.PUBLIC_EXPONENT_USED_BY_ARWEAVE),sr); KeyPair kp = kpg.generateKeyPair(); ArWallet arWallet = new ArWallet((RSAPublicKey) kp.getPublic(), (RSAPrivateCrtKey) kp.getPrivate()); String privateKey = CryptoUtils.toJson(arWallet); return WalletResult.builder().address(arWallet.getAddress().toString()).privateKey(privateKey).build(); } @Getter @Setter public class ArWallet { public static final BigInteger PUBLIC_EXPONENT_USED_BY_ARWEAVE = new BigInteger("65537"); private Owner owner; private Address address; private byte[] asPKCS8; private RSAPublicKey publicKey; private RSAPrivateCrtKey privateKey; public ArWallet(RSAPublicKey pub, RSAPrivateCrtKey priv) { this.publicKey = pub; this.privateKey = priv; this.owner = new Owner(pub.getModulus()); this.address = Address.ofKey(pub); this.asPKCS8 = priv.getEncoded(); } } @Getter @Setter @NoArgsConstructor public class Address { private final int length = 32; private byte[] bytes; public Address(byte[] bytes){ this.bytes = bytes; } @SneakyThrows public static Address ofModulus(BigInteger n){ return new Address(CryptoUtils.sha256(Base64URL.encode(n).decode())); } public static Address ofKey(RSAKey k){ return ofModulus(k.getModulus()); } @Override public String toString() { return Base64Encoder.encodeUrlSafe(this.bytes); } } @Getter @Setter @NoArgsConstructor public class Owner { private byte[] bytes; private RSAPublicKey publicKey; /** * 初始化结构 */ @SneakyThrows public Owner(BigInteger n){ this.bytes = CryptoUtils.toBigEndianBytes(n); this.publicKey = (RSAPublicKey)KeyFactory.getInstance("RSA").generatePublic( new RSAPublicKeySpec(n,ArWallet.PUBLIC_EXPONENT_USED_BY_ARWEAVE) ); } @Override public String toString() { return Base64.encodeUrlSafe(this.bytes); } } ``` 最后修改:2022 年 03 月 11 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 2 社会很单纯~复杂滴是人呐~谁能在乎我呀
2 条评论
能问下CurrencyType.ARWEAVE是什么吗,
就是类型、ar币的类型