Closed m-finder closed 1 year ago
02, 03 开头的没有什么区别呢,y是偶数就是02,y是奇数就是03, 公钥的确是x,y 两部分,通过x可以算出y,
function decompressPublicKey($compressedKey) {
// 获取压缩标志和X坐标
$flag = substr($compressedKey, 0, 2);
$x = substr($compressedKey, 2);
// 将16进制字符串转换为大整数
$p = gmp_init('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF', 16);
$a = gmp_init('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC', 16);
$b = gmp_init('28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93', 16);
$gx = gmp_init('32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1711D7AFB1B8B4E16', 16);
$gy = gmp_init('BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0', 16);
$n = gmp_init('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123', 16);
// 计算Y坐标
$x = gmp_init($x, 16);
$alpha = gmp_powm($x, 3, $p);
$beta = gmp_add(gmp_mod(gmp_mul($a, $x), $p), $b);
$y2 = gmp_mod(gmp_add($alpha, $beta), $p);
$y = gmp_powm($y2, gmp_div_q(gmp_add($p, 1), 4), $p);
if ($flag == "02") {
// 如果压缩标志为“02”,则Y坐标为偶数
if (gmp_strval(gmp_mod($y, 2)) == "0") {
return "04" . gmp_strval($x, 16) . str_pad(gmp_strval($y, 16), 64, "0", STR_PAD_LEFT);
} else {
$y = gmp_sub($p, $y);
return "04" . gmp_strval($x, 16) . str_pad(gmp_strval($y, 16), 64, "0", STR_PAD_LEFT);
}
} elseif ($flag == "03") {
// 如果压缩标志为“03”,则Y坐标为奇数
if (gmp_strval(gmp_mod($y, 2)) == "1") {
return "04" . gmp_strval($x, 16) . str_pad(gmp_strval($y, 16), 64, "0", STR_PAD_LEFT);
} else {
$y = gmp_sub($p, $y);
return "04" . gmp_strval($x, 16) . str_pad(gmp_strval($y, 16), 64, "0", STR_PAD_LEFT);
}
} else {
return null;
}
}
完美,感谢大佬🙏
在跟银行做对接时,对方提供的 sm2 加密公钥长度为 66 位,03 开头。
查了下资料说是公钥分 x、y 两部分,x 为 02 开头,y 为 03 开头,04 表示完整公钥未压缩。
想问下大佬有方法将 x 或 y 还原成完整的公钥吗?或者是 sm2 支持下压缩密钥的加解密?