



比特币诞生之初,开发人员只知道如何创建65字节的公钥。然而,后来的开发人员意识到,公钥还有一种只使用33字节的替代编码,并且与当时所有比特币全节点向后兼容,无须更改比特币协议。这些33字节的公钥被称为压缩公钥,而原始的65字节密钥被称为非压缩公钥。使用较小的公钥会让交易数据更小,从而允许在同一个区块中处理更多交易。
正如我们在4.1.3节中所见,一个公共密钥是椭圆曲线上的一个点( x , y )。因为这个曲线展现了一个数学函数,曲线上的一个点代表着方程的一个解,因此,如果我们知道了 x 坐标,我们可以通过求解方程 y 2 mod p =( x 3 +7)mod p 来计算出 y 坐标。这使得我们仅需存储公共密钥点的 x 坐标,省略掉 y 坐标,从而减少了256比特的密钥大小及其存储空间。在每一笔交易中减少近50%的数据,随着时间的推移可以节省大量的存储空间!
这是我们在4.1.3节中创建的私钥生成的公钥:
这是同一个公钥,520位的数字以130个十六进制数字形式展示,前缀为
,后面跟着x和y坐标,表示为:
:
虽然未压缩的公钥前缀为04,压缩公钥则以02或03开头。来看看为什么会有两种可能的前缀:因为方程式的左边是 y 2 ,求解 y 将得到一个平方根,它可能是正值或负值。从直观上讲,这意味着得到的 y 坐标可以位于 x 轴的上方或下方。正如你从图4-2中椭圆曲线的图形所看到的,曲线是对称的,也就是说它被 x 轴像镜子一样反射。因此,尽管我们可以省略 y 坐标,我们也必须存储 y 的符号(正或负)。换句话说,我们必须记住它是在 x 轴的上方还是下方,因为每个选项分别代表了一个不同的点和一个不同的公钥。当在有限域上对素数阶 p 进行二进制算术计算椭圆曲线时, y 坐标是偶数还是奇数,这与前面解释的正/负符号对应。因此,为了区分 y 的两个可能的值,当我们存储压缩的公钥时,如果 y 是偶数就加上前缀02,如果是奇数就加上前缀03。这样软件就能从 x 坐标正确推导出 y 坐标,并将公钥解压缩为点的完整坐标。公钥压缩如图4-8所示。
这是在4.1.3节中生成的同样的公钥,在此以压缩形式展示,占用264比特(66个十六进制字符),前缀03表明 y 坐标是奇数:
这个压缩公钥对应于同一个私钥,意味着它是由同一个私钥生成的。然而,它看起来与未压缩的公钥不同。更重要的是,如果我们使用HASH160函数(即RIPEMD160(SHA256(K)))将这个压缩公钥转换为承诺,那么它将产生一个与未压缩公钥不同的承诺,进而导致不同的比特币地址。这可能会让人感到困惑,因为这意味着单个私钥可以产生以两种不同格式(压缩和未压缩)表达的公钥,并生成两个不同的比特币地址。然而,这两个比特币地址的私钥是完全相同的。
在几乎所有的比特币软件中,压缩公钥现在已成为默认标准,并且在使用后期协议升级中添加的某些新特性时是必需的。
然而,一些软件仍然需要支持未压缩的公钥,比如导入旧钱包私钥的钱包应用程序。当新钱包扫描区块链以寻找旧的P2PKH输出和输入时,它需要知道是扫描65字节的公钥(以及承诺)还是扫描33字节的公钥(以及承诺)。若未正确扫描合适的类型,则可能导致用户无法使用其全部余额。为了解决这个问题,当从钱包导出私钥时,前缀WIF在新版比特币钱包中的实现略有不同,以表明这些私钥已被用于生成压缩公钥。
图4-8:公钥压缩