IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 区块链 -> libsecp256k1比特币密码算法开源库(十四) -> 正文阅读

[区块链]libsecp256k1比特币密码算法开源库(十四)

2021SC@SDUSC

DER签名(下)

在上一篇中介绍了DER签名的编码格式为:
0 x 30 [ t o t a l ? l e n g t h ] 0 x 02 [ R ? l e n g t h ] [ R ] 0 x 02 [ S ? l e n g t h ] [ S ] [ s i g h a s h ] 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash] 0x30[total?length]0x02[R?length][R]0x02[S?length][S][sighash]
其中还介绍了如果r或s的一个字节大于等于0x80,则在r或s前置0x00,这是因为如果最高位为1在DER编码看来这就应该是个负值,本来应该作为无符号数的r或s就会被当做有符号数,因此在前面需要加一个0x00。

在本篇代码分析中有部分涉及到“Low S values in signatures”规则,就是对上面的前置0x00的进一步讨论。现在规定,第一位设置0x00的r或s值称为高,第一位未设置0x00的r或s值称为低。

r 和s值是随机的。当两个值都为高时(都设置了第一个位),它们就都需要一个前置的 0x00字节。使用两个额外字节0x00,编码的r值和s值导致签名总长度为72个字节(不算[sighash])。在同一签名中两个值都很高的概率是 25%。直到 2014 年初,在区块链上可以观察到大约25%的72字节、50%的71字节和大约25%的70字节签名的分布。在71字节签名中,两个值之一为高,另一个为低。在70字节的签名中,两个值都必须是低。

2014年3月,Bitcoin Core v0.9.0版本开始减少高s值签名的份额。此版本包含对BitcoinCore钱包的更改,仅创建低s签名。随着2015年10月BitcoinCore v0.10.3和v0.11.1的发布,高s签名变得非标准,以完全消除延展性向量。这禁止具有高s值的交易被中继或用于挖矿。从 2015年12月开始,区块链上的几乎所有交易的签名中都只有低值。

既然现在比特币里面都开始用低s了,那么怎么把高s转换为低s呢?

方法很简单,用n值(有限域的秩n)减去s值就行了,n的值在libsecp256k1比特币密码算法开源库(五)里面给出过:
在这里插入图片描述
下面只需要
n ? s n-s n?s
就可以了,也就是:
0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141 - S

数字签名Signature

下面的Signature定义的函数中parse_overflowingparse_standardparse_standard_sliceparse_der在上一篇中已经介绍过了,本篇主要介绍后面的normalize_sserializeserialize_der

impl Signature {
    //允许签名溢出的反序列化
    pub fn parse_overflowing(p: &[u8; util::SIGNATURE_SIZE]) -> Signature {
        let mut r = Scalar::default();
        let mut s = Scalar::default();

        let _ = r.set_b32(array_ref!(p, 0, 32));
        let _ = s.set_b32(array_ref!(p, 32, 32));

        Signature { r, s }
    }

    //未溢出的签名的反序列化
    pub fn parse_standard(p: &[u8; util::SIGNATURE_SIZE]) -> Result<Signature, Error> {
        let mut r = Scalar::default();
        let mut s = Scalar::default();

        let overflowed_r = r.set_b32(array_ref!(p, 0, 32));
        let overflowed_s = s.set_b32(array_ref!(p, 32, 32));

        if bool::from(overflowed_r | overflowed_s) {
            return Err(Error::InvalidSignature);
        }

        Ok(Signature { r, s })
    }


    //复制未溢出的反序列化签名
    pub fn parse_standard_slice(p: &[u8]) -> Result<Signature, Error> {
        if p.len() != util::SIGNATURE_SIZE {
            return Err(Error::InvalidInputLength);
        }

        let mut a = [0; util::SIGNATURE_SIZE];
        a.copy_from_slice(p);
        Ok(Self::parse_standard(&a)?)
    }

    //将DER格式的签名反序列化
    pub fn parse_der(p: &[u8]) -> Result<Signature, Error> {
        let mut decoder = Decoder::new(p);

        decoder.read_constructed_sequence()?;
        let rlen = decoder.read_len()?;

        if rlen != decoder.remaining_len() {
            return Err(Error::InvalidSignature);
        }

        let r = decoder.read_integer()?;
        let s = decoder.read_integer()?;

        if decoder.remaining_len() != 0 {
            return Err(Error::InvalidSignature);
        }

        Ok(Signature { r, s })
    }
   //将s规范化为低s
    pub fn normalize_s(&mut self) {
        if self.s.is_high() {
            self.s = -self.s;
        }
    }

    //将签名序列化为未溢出的格式,也就是上面的函数`parse_standard`的逆过程
    pub fn serialize(&self) -> [u8; util::SIGNATURE_SIZE] {
        let mut ret = [0u8; 64];
        self.r.fill_b32(array_mut_ref!(ret, 0, 32));
        self.s.fill_b32(array_mut_ref!(ret, 32, 32));
        ret
    }

    //将签名序列化为DER编码格式,也就是函数`parse_der`的逆过程
    pub fn serialize_der(&self) -> SignatureArray {
        fn fill_scalar_with_leading_zero(scalar: &Scalar) -> [u8; 33] {
            let mut ret = [0u8; 33];
            scalar.fill_b32(array_mut_ref!(ret, 1, 32));
            ret
        }

        let r_full = fill_scalar_with_leading_zero(&self.r);
        let s_full = fill_scalar_with_leading_zero(&self.s);

        fn integer_slice(full: &[u8; 33]) -> &[u8] {
            let mut len = 33;
            while len > 1 && full[full.len() - len] == 0 && full[full.len() - len + 1] < 0x80 {
                len -= 1;
            }
            &full[(full.len() - len)..]
        }

        let r = integer_slice(&r_full);
        let s = integer_slice(&s_full);

        let mut ret = SignatureArray::new(6 + r.len() + s.len());
        {
            let l = ret.as_mut();
            l[0] = 0x30;
            l[1] = 4 + r.len() as u8 + s.len() as u8;
            l[2] = 0x02;
            l[3] = r.len() as u8;
            l[4..(4 + r.len())].copy_from_slice(r);
            l[4 + r.len()] = 0x02;
            l[5 + r.len()] = s.len() as u8;
            l[(6 + r.len())..(6 + r.len() + s.len())].copy_from_slice(s);
        }

        ret
    }
}

数字签名s值的规范化

本函数实现将高s转换为低s,即将大于n的s转化为n-s:

pub fn normalize_s(&mut self) {
        if self.s.is_high() {
            self.s = -self.s;
        }
    }

判断s是否为高s通过调用is_high函数来实现:

/// Check whether a scalar is higher than the group order divided by 2.
    pub fn is_high(&self) -> bool {
        let mut yes: Choice = 0.into();
        let mut no: Choice = 0.into();
        no |= Choice::from((self.0[7] < SECP256K1_N_H_7) as u8);
        yes |= Choice::from((self.0[7] > SECP256K1_N_H_7) as u8) & !no;
        no |= Choice::from((self.0[6] < SECP256K1_N_H_6) as u8) & !yes; /* No need for a > check. */
        no |= Choice::from((self.0[5] < SECP256K1_N_H_5) as u8) & !yes; /* No need for a > check. */
        no |= Choice::from((self.0[4] < SECP256K1_N_H_4) as u8) & !yes; /* No need for a > check. */
        no |= Choice::from((self.0[3] < SECP256K1_N_H_3) as u8) & !yes;
        yes |= Choice::from((self.0[3] > SECP256K1_N_H_3) as u8) & !no;
        no |= Choice::from((self.0[2] < SECP256K1_N_H_2) as u8) & !yes;
        yes |= Choice::from((self.0[2] > SECP256K1_N_H_2) as u8) & !no;
        no |= Choice::from((self.0[1] < SECP256K1_N_H_1) as u8) & !yes;
        yes |= Choice::from((self.0[1] > SECP256K1_N_H_1) as u8) & !no;
        yes |= Choice::from((self.0[0] >= SECP256K1_N_H_0) as u8) & !no;
        yes.into()
    }

下面是上面函数使用的一些定义常量的取值:

const SECP256K1_N: [u32; 8] = [
    0xD0364141, 0xBFD25E8C, 0xAF48A03B, 0xBAAEDCE6, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
];

const SECP256K1_N_H_0: u32 = 0x681B20A0;
const SECP256K1_N_H_1: u32 = 0xDFE92F46;
const SECP256K1_N_H_2: u32 = 0x57A4501D;
const SECP256K1_N_H_3: u32 = 0x5D576E73;
const SECP256K1_N_H_4: u32 = 0xFFFFFFFF;
const SECP256K1_N_H_5: u32 = 0xFFFFFFFF;
const SECP256K1_N_H_6: u32 = 0xFFFFFFFF;
const SECP256K1_N_H_7: u32 = 0x7FFFFFFF;

数字签名的序列化

本函数实现将数字签名的r部分和s部分分别序列化。首先创建一个64字节的ret数组(64个数组元素,每个数组元素一字节),并初始化数组元素全为0。然后调用fill_b32函数实现将反序列化的r和s转化为序列化的r和s。

pub fn serialize(&self) -> [u8; util::SIGNATURE_SIZE] {
        let mut ret = [0u8; 64];
        self.r.fill_b32(array_mut_ref!(ret, 0, 32));
        self.s.fill_b32(array_mut_ref!(ret, 32, 32));
        ret
    }

函数fill_b32实现过程如下所示。r和s在序列化前共32字节,为Scalar类型,用8个数组元素,数组元素为u32类型;现在转化为32个数组元素,数组元素为u8类型。

    pub fn fill_b32(&self, bin: &mut [u8; 32]) {
        bin[0] = (self.0[7] >> 24) as u8;
        bin[1] = (self.0[7] >> 16) as u8;
        bin[2] = (self.0[7] >> 8) as u8;
        bin[3] = (self.0[7]) as u8;
        bin[4] = (self.0[6] >> 24) as u8;
        bin[5] = (self.0[6] >> 16) as u8;
        bin[6] = (self.0[6] >> 8) as u8;
        bin[7] = (self.0[6]) as u8;
        bin[8] = (self.0[5] >> 24) as u8;
        bin[9] = (self.0[5] >> 16) as u8;
        bin[10] = (self.0[5] >> 8) as u8;
        bin[11] = (self.0[5]) as u8;
        bin[12] = (self.0[4] >> 24) as u8;
        bin[13] = (self.0[4] >> 16) as u8;
        bin[14] = (self.0[4] >> 8) as u8;
        bin[15] = (self.0[4]) as u8;
        bin[16] = (self.0[3] >> 24) as u8;
        bin[17] = (self.0[3] >> 16) as u8;
        bin[18] = (self.0[3] >> 8) as u8;
        bin[19] = (self.0[3]) as u8;
        bin[20] = (self.0[2] >> 24) as u8;
        bin[21] = (self.0[2] >> 16) as u8;
        bin[22] = (self.0[2] >> 8) as u8;
        bin[23] = (self.0[2]) as u8;
        bin[24] = (self.0[1] >> 24) as u8;
        bin[25] = (self.0[1] >> 16) as u8;
        bin[26] = (self.0[1] >> 8) as u8;
        bin[27] = (self.0[1]) as u8;
        bin[28] = (self.0[0] >> 24) as u8;
        bin[29] = (self.0[0] >> 16) as u8;
        bin[30] = (self.0[0] >> 8) as u8;
        bin[31] = (self.0[0]) as u8;
    }

序列化数字签名转化为DER格式

首先在这里摆上DER序列化的格式:
0 x 30 [ t o t a l ? l e n g t h ] 0 x 02 [ R ? l e n g t h ] [ R ] 0 x 02 [ S ? l e n g t h ] [ S ] 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] 0x30[total?length]0x02[R?length][R]0x02[S?length][S]
本函数实现将已经序列化的数字签名的r和s转化为DER序列化格式。

在下面的代码中,首先变量r_fulls_full调用了函数fill_scalar_with_leading_zero,生成了一个包含33个u8类型的0的数组元素,也就是
r f u l l = [ 0 ] ? ? ? [ 0 ] ? 33 个 s f u l l = [ 0 ] ? ? ? [ 0 ] ? 33 个 r _{full}= \overbrace{ [0]\cdot\cdot\cdot[0] }^{33\text{个}}\\s _{full}= \overbrace{ [0]\cdot\cdot\cdot[0] }^{33\text{个}} rfull?=[0]???[0] ?33?sfull?=[0]???[0] ?33?
之所以是33个,是因为r和s本来32位,但考虑可能出现高r高s需要再加一个0x00,需要再添一个字节。

然后变量rs调用了函数integer_slice,实现将序列化的r和s最小化,也就是将高位的0字节抹去,如果抹去了该0字节使得最高位字节大于0x80,则不抹去,这个函数会使得r和s最小。

然后在 let mut ret = SignatureArray::new(6 + r.len() + s.len());中实现DER的生成。
l[0] = 0x30;表示DER格式的第一个字段;
l[1] = 4 + r.len() as u8 + s.len() as u8;表示计算[total-length];
l[2] = 0x02;表示DER格式的0x02字段,也就是r的开始字段;
l[3] = r.len() as u8;表示计算[R-length],调用len函数实现;
l[4..(4 + r.len())].copy_from_slice(r);将integer_slice生成的r直接复制到[R]中
l[4 + r.len()] = 0x02;表示DER格式的0x02字段,也就是s的开始字段;
l[5 + r.len()] = s.len() as u8;表示计算[S-length],调用len函数实现;
l[(6 + r.len())..(6 + r.len() + s.len())].copy_from_slice(s);将integer_slice生成的s直接复制到[S]中。
DER生成结束。

 pub fn serialize_der(&self) -> SignatureArray {
 //r和s初始化
        fn fill_scalar_with_leading_zero(scalar: &Scalar) -> [u8; 33] {
            let mut ret = [0u8; 33];
            scalar.fill_b32(array_mut_ref!(ret, 1, 32));
            ret
        }

        let r_full = fill_scalar_with_leading_zero(&self.r);
        let s_full = fill_scalar_with_leading_zero(&self.s);
//r和s最小化
        fn integer_slice(full: &[u8; 33]) -> &[u8] {
            let mut len = 33;
            while len > 1 && full[full.len() - len] == 0 && 
            full[full.len() - len + 1] < 0x80 {
                len -= 1;
            }
            &full[(full.len() - len)..]
        }

        let r = integer_slice(&r_full);
        let s = integer_slice(&s_full);
//生成DER
        let mut ret = SignatureArray::new(6 + r.len() + s.len());
        {
            let l = ret.as_mut();
            l[0] = 0x30;
            l[1] = 4 + r.len() as u8 + s.len() as u8;
            l[2] = 0x02;
            l[3] = r.len() as u8;
            l[4..(4 + r.len())].copy_from_slice(r);
            l[4 + r.len()] = 0x02;
            l[5 + r.len()] = s.len() as u8;
            l[(6 + r.len())..(6 + r.len() + s.len())].copy_from_slice(s);
        }

        ret
    }
}

上面函数中使用了SignatureArray结构体:

pub struct SignatureArray([u8; 6 + 33 + 33], usize);

SignatureArray结构体定义了如下函数,包括初始化一个DER序列、计算长度和判断长度是否为0。

impl SignatureArray {
    pub fn new(size: usize) -> Self {
        SignatureArray([0u8; 6 + 33 + 33], size)
    }

    pub fn len(&self) -> usize {
        self.1
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
}
  区块链 最新文章
盘点具备盈利潜力的几大加密板块,以及潜在
阅读笔记|让区块空间成为商品,打造Web3云
区块链1.0-比特币的数据结构
Team Finance被黑分析|黑客自建Token“瞒天
区块链≠绿色?波卡或成 Web3“生态环保”标
期货从入门到高深之手动交易系列D1课
以太坊基础---区块验证
进入以太坊合并的五个数字
经典同态加密算法Paillier解读 - 原理、实现
IPFS/Filecoin学习知识科普(四)
上一篇文章      下一篇文章      查看所有文章
加:2021-12-14 15:59:44  更:2021-12-14 16:00:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/29 8:41:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计