libsecp256k1代码分析综述

2021SC@SDUSC


从本篇开始我将开始分析libsecp256k1中的代码。本开源库可以实现:
私钥经标量乘法生成公钥;
私钥签名(ECDSA);
公钥验证签名;
从签名消息中恢复公钥;
共享密钥(ECDH)
在这一篇中,我将对有限域和椭圆曲线的定义代码和椭圆曲线的几何加法和标量乘法运算进行分析。由于本人目前对这个项目整体认识不足,所以这一篇会随着我对后续代码细节理解的加深随时更改,后续的几篇会详细分析secp256k1开源库实现上述五个功能的代码段以及所用到的各种算法。
这个开源库使用rust语言编写,本人目前正在自学rust。目前阅读代码重点在于明白其中使用的各种算法和数据结构,理解这个开源库的各种功能,因此代码的分析不会强调语法的细枝末节。

有限域Galois Field

定义有限域的秩p以及模p运算

trait curve {
   fn p() ->BigInt ;
   //这里的p就是有限域的秩p
   }
   
struct Field<C: Curve >(BigInt);

impl<C: Curve> Field<C>{
   //将一个元素放入到有限域中,要进行mod p运算
   fn new( v: BigInt ) -> Self{
   Self( v.mod_floor (C::p()))
   }
}

椭圆曲线Elliptic Curves

定义椭圆曲线的三个参数:

//有限域椭圆曲线方程的三个参数a、b、p
use num_bigint::BigInt;
pub trait Curve {
   fn p() -> BigInt ;
   fn a() -> BigInt ;
   fn b() -> BigInt ;
}

具体到secp256k1椭圆曲线的三个参数值:

//定义secp256k1的三个参数a、b、p的值
struct P256K1Curve;

impl Curve for P256K1Curve {
      fn p() -> BigInt {
      BigInt::from_str_radix("FFFFFFFFFFFFFFFF
                              FFFFFFFFFFFFFFFF
                              FFFFFFFFFFFFFFFF
                              FFFFFFFEFFFFFC2F" ,16).unwrap()
      }//定义p取值为以上256位二进制数
      fn a() -> BigInt { BigInt::zero() }//定义a为0
      fn b() -> BigInt { BigInt::from(7u32) }//定义b为7,u32表示无符号int基本整数类型
}

定义椭圆曲线上的点,要么是一个无穷远点,要么就具有x值和y值:

pub enum PointValue {
  Infinity ,  //无穷远点
  Value {
  x: BigInt ,
  y: BigInt ,
  } //定义横纵坐标x和y
}

pub struct Point<C:Curve> {
  pub value: PointValue,
  _marker: PhantomData<C>,
  }

判断任意一个点是不是在椭圆曲线上:

impl<C:Curve> Point<C>{
   pub fn is_valid(&self) -> bool {
   match self.value {
    PointValue::Infinity => true, //如果是一个无穷远点,那么在椭圆曲线上
    PointValue::Value { ref x, ref y } => {
    (y * y - (x * x * x + &C::a() * x + &C::b()))
     .mod_floor(&C::p()) == BigInt::zero() },//如果不是无穷远点,就将该点的横纵坐标代入有限域下椭圆曲线方程检验
   } 
 }
}

椭圆曲线几何加法

进行椭圆曲线P和Q的几何加法主要分几种情况讨论:
P或Q中有一个是无穷远点;
P和Q是同一个点,横纵坐标一致;
P和Q是相反的点,即在图像上关于直线y=p/2对称;
P和Q是除上面三种情况外的一般点

如果其中一个P或者Q是无穷远点,将不是无穷远点的点的横纵坐标返回

impl<C: Curve> Add for Point<C> {
   fn add (self, other: Point<C>) -> Point <C> {
     let (ox, oy) = match other.value {
        PointValue::Infinity => return self ,
        PointValue::Value { ref x, ref y } => (x.clone(), y.clone()),};
     let (sx, sy) = match self.value {
        PointValue::Infinity => return other ,
        PointValue::Value { ref x, ref y } => (x.clone(), y.clone()),};
        ......
   }
}

P和Q横坐标一致时:
如果P和Q是相反的点,那么两点的纵坐标之和等于p,模p的结果为0,可以直接返回结果为无穷远点;
如果P和Q是相同的点,那么两点的纵坐标之和模p的结果一定不为0,就对自身(P或Q)取二倍。

impl<C: Curve> Add for Point <C> {
  fn add(self, other: Point<C>) -> Point <C> {
    ...
    if sx == ox {
       return if (sy + oy ).mod_floor(&C::p()) == BigInt::zero() {
         Point::infinity ()
         }else {
         self.double ()
         }
    }
    ...
  }
}

如果P和Q是一般点
先求斜率l,P点纵坐标减Q点纵坐标再乘以P点横坐标减Q点横坐标模p的乘法逆元,最后结果再对p取模。即 ( y P − y Q ) ( x P − x Q ) − 1   m o d   p ( y_P - y_Q) ( x_P - x_Q )^{-1}\, mod\,p (yPyQ)(xPxQ)1modp
再分别求出R的横纵坐标
x R = ( m 2 − x P − x Q )   m o d   p x_R = ( m^2 - x_P - x_Q )\, mod\,p xR=(m2xPxQ)modp
y R = [ m ( x P − x R ) − y P ]   m o d   p y_R = [m (x_P - x_R) - y_P ]\,mod\,p yR=[m(xPxR)yP]modp

impl<C: Curve > Add for Point<C> {
  type Output = Point <C>;
  fn add(self, other: Point <C>) -> Point<C> {
    ...
    let l = ((&oy - &sy) * utils::inverse_mod(&ox -&sx, C::p())).mod_floor (&C::p());
    let x3 = (&l * &l - &sx - &ox).mod_floor ( &C::p());
    let y3 = (&l *(&sx - &×3) - &sy ) .mod_floor ( &C::p());
    Self::from(PointValue::Value { x: x3, y: y3 })
    }
}

椭圆曲线标量乘法

对椭圆曲线上一点计算标量乘法,如果该点乘的系数n为0,那么返回结果直接就为无穷远点;否则让该点不断与自己做几何加法运算,直到n次结束。

impl<C: Curve> Mul<BigInt> for Point <C> {
  fn mul(self, n: BigInt) -> Point<C> {
    if n == 0 {
      Self::infinity ()
    }else {
     let mut ret = self.clone();
     for _ in 1 ... n {
        ret = ret + self.clone ();
        }
        ret
     }
  }
}

在secp256k1中被计算标量乘法的(也就是椭圆曲线群的生成元)基准点G的横纵坐标。

let g = Point::<P256K1Curve>::from(PointValue::Value {
  x: BigInt::from_str_radix(
  "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",16).unwrap(),
  y: BigInt::from_str_radix(
  "483ADA7726A3C4655DA4FBFCOE1108A8FD17B448A68554199C47D08FFB1004B8",16).unwrap()
});

基准点G进行标量乘法(系数n=3,即三次几何加法运算)得到新的点:

assert.eq!(
  g.clone() *BigInt::from(3u32),
  Point::<P256K1Curve>::from(PointValue::Value {
    x: BigInt::from_str_radix(
  "F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",16).unwrap(),
    y: BigInt::from_str_radix(
  "388F7B0F632DE8140FE337E62A37F3566500A99934C2231B6CB9FD7584B8E672",16).unwrap()
  })
);
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值