libsecp256k1比特币密码算法开源库(十四)

Posted yyDrifter

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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[totallength]0x02[Rlength][R]0x02[Slength][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 ns
就可以了,也就是:
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]以上是关于libsecp256k1比特币密码算法开源库(十四)的主要内容,如果未能解决你的问题,请参考以下文章

libsecp256k1比特币密码算法开源库

libsecp256k1比特币密码算法开源库

libsecp256k1比特币密码算法开源库

libsecp256k1比特币密码算法开源库

libsecp256k1比特币密码算法开源库

libsecp256k1比特币密码算法开源库