基于web3j 5.0.0,如何在Java Spring Boot中压缩以太坊公钥?
以太坊未压缩公钥转压缩格式(web3j 5.0.0)
由于web3j 5.0.0没有内置的公钥压缩方法,你可以通过以下两种方式实现需求:
方法一:利用BouncyCastle库(web3j已依赖)
web3j底层依赖BouncyCastle,可直接用它的椭圆曲线工具类处理:
import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.asn1.x9.X9IntegerConverter; import org.bouncycastle.crypto.ec.CustomNamedCurves; import org.bouncycastle.math.ec.ECPoint; import org.web3j.utils.Hex; import java.math.BigInteger; import java.nio.ByteBuffer; import java.util.Arrays; // 生成密钥对并获取未压缩公钥 ECKeyPair ecKeyPair = Keys.createEcKeyPair(); BigInteger publicKey = ecKeyPair.getPublicKey(); // 以太坊使用secp256k1曲线 X9ECParameters curveParams = CustomNamedCurves.getByName("secp256k1"); // 将BigInteger公钥拆分为32字节的x、y坐标字节数组 BigInteger x = publicKey.shiftRight(256); BigInteger y = publicKey.and(new BigInteger("2").pow(256).subtract(BigInteger.ONE)); byte[] xBytes = convertTo32Bytes(x); byte[] yBytes = convertTo32Bytes(y); // 构造ECPoint并生成压缩格式编码 ECPoint point = curveParams.getCurve().createPoint(new BigInteger(1, xBytes), new BigInteger(1, yBytes)); byte[] compressedPubKeyBytes = point.getEncoded(true); // true表示压缩格式 // 转成十六进制字符串(用于目标场景) String compressedPublicKey = Hex.toHexString(compressedPubKeyBytes);
辅助方法:确保坐标是32字节长度
private static byte[] convertTo32Bytes(BigInteger value) { byte[] bytes = value.toByteArray(); if (bytes.length == 32) { return bytes; } else if (bytes.length > 32) { return Arrays.copyOfRange(bytes, bytes.length - 32, bytes.length); } else { byte[] padded = new byte[32]; System.arraycopy(bytes, 0, padded, 32 - bytes.length, bytes.length); return padded; } }
方法二:手动实现压缩逻辑
直接解析公钥的x、y坐标,根据y的奇偶性添加前缀:
import org.web3j.utils.Hex; import java.math.BigInteger; import java.nio.ByteBuffer; import java.util.Arrays; ECKeyPair ecKeyPair = Keys.createEcKeyPair(); BigInteger publicKey = ecKeyPair.getPublicKey(); // 拆分x和y坐标 BigInteger x = publicKey.shiftRight(256); BigInteger y = publicKey.and(new BigInteger("2").pow(256).subtract(BigInteger.ONE)); // 生成压缩公钥前缀:y为偶数用02,奇数用03 byte prefix = y.testBit(0) ? (byte) 0x03 : (byte) 0x02; // 将x转成32字节数组 byte[] xBytes = convertTo32Bytes(x); // 拼接前缀和x字节得到压缩公钥 byte[] compressedPubKeyBytes = ByteBuffer.allocate(33) .put(prefix) .put(xBytes) .array(); // 转十六进制字符串 String compressedPublicKey = Hex.toHexString(compressedPubKeyBytes);
两种方法生成的压缩公钥均以02或03开头,可直接用于你的目标场景。
内容的提问来源于stack exchange,提问作者Jijo
相关产品推荐
相关产品推荐

