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

secp256k1的结构——ECDH密钥交换


在加密通信过程中可以使用Diffie Hellman密钥交换来进行密钥分发,经过密钥交换之后相当于通信双方都有了相同的密钥,可以使用对称加密的方式通信。在区块链比特币中同样有密钥交换,即Elliptic Curve Diffie Hellman,实现将比特币发送到接收方的地址。下文中将介绍相关背景知识以及对应代码实现。

ECDH地址

本部分内容摘自维基百科,略有改动。

ECDH 地址也称为隐形地址、可重复使用的支付代码、可重复使用的地址或paynyms。椭圆曲线 Diffie-Hellman (ECDH) 是一种密钥协商协议,它允许两方通过不安全的通道建立共享密钥。例如,Alice 和 Bob 可以在他们之间交流密码信息并就共享秘密达成一致,窃听者 Eve 可以看到所有他们的消息,但仍然无法计算共享密钥。(相应数学背景知识参见libsecp256k1比特币密码算法开源库(五)

通过让比特币的接收者发布一些发送者可以用来计算共享密钥的 ECDH 信息,可以在比特币context中使用该概念。这个共享的密钥成为发送者汇款到的比特币地址。接收方可以计算出相应的私钥以获取资金。

工作过程:

接收方本地生成地址私钥 q q q:
q = ECDH address privkey (generated by receiver)
接收方本地生成地址公钥 Q Q Q:
Q = q·G = ECDH address pubkey (published by receiver)

发送方本地生成nonce串 p p p:
p = nonce (generated by sender)
发送方根据nonce串 p p p生成公钥 P P P,发送给接收方:
P = p·G = nonce point (sent from sender to receiver)

发送方接收方生成共享密钥,且该共享密钥只有这双方知道:
p·Q = q.·P = p·q·G (ECDH shared secret point, known by sender and receiver but not eavesdroppers)
由于共享密钥是一个坐标点,因此经过哈希,将共享秘密点转换为标量c:
c = H(p·Q) = H(q·P) (tweak, shared secret point converted to number)

发送者使用接收者公钥和共享密钥生成的标量c计算比特币接收地址 Q ′ Q' Q,并把币送到该地址:
Q’ = Q + c·G (bitcoin pubkey, send coins here)

接收者计算自己的比特币接收地址 Q ′ Q' Q
Q’ = Q + c.G = (q + c)·G (bitcoin pubkey, watch for incoming coins)
相应的私钥 q ′ q' q用来接下来消费比特币:
q’ = q + c (bitcoin privkey, for spending incoming coins)

共享密钥ECDH

impl<D: Digest + Default> SharedSecret<D>中定义两个函数new_with_contextnew,其中函数new中也是直接调用函数new_with_context。在new_with_context中共享密钥的实现过程通过context.ecdh_raw::<D>(&pubkey.0, &seckey.0)来实现。

impl<D: Digest + Default> SharedSecret<D> {
    pub fn new_with_context(
        pubkey: &PublicKey,
        seckey: &SecretKey,
        context: &ECMultContext,
    ) -> Result<SharedSecret<D>, Error> {
        let inner = match context.ecdh_raw::<D>(&pubkey.0, &seckey.0) {
            Some(val) => val,
            None => return Err(Error::InvalidSecretKey),
        };

        Ok(SharedSecret(inner))
    }

    #[cfg(any(feature = "static-context", feature = "lazy-static-context"))]
    pub fn new(pubkey: &PublicKey, seckey: &SecretKey) -> Result<SharedSecret<D>, Error> {
        Self::new_with_context(pubkey, seckey, &ECMULT_CONTEXT)
    }
}

找到函数ecdh_raw,可以看出生成共享密钥的函数为ecmult_const(&mut res, &pt, &s)

impl ECMultContext {
    pub fn ecdh_raw<D: Digest + Default>(
        &self,
        point: &Affine,
        scalar: &Scalar,
    ) -> Option<GenericArray<u8, D::OutputSize>> {
        let mut digest: D = Default::default();

        let mut pt = *point;
        let s = *scalar;

        if s.is_zero() {
            return None;
        }

        let mut res = Jacobian::default();
        //生成共享密钥
        self.ecmult_const(&mut res, &pt, &s);
        pt.set_gej(&res);

        pt.x.normalize();
        pt.y.normalize();

        let x = pt.x.b32();
        let y = 0x02 | (if pt.y.is_odd() { 1 } else { 0 });

        digest.update(&[y]);
        digest.update(&x);
        Some(digest.finalize_reset())
    }
}

生成共享密钥的函数ecmult_const的代码如下。

pub fn ecmult_const(&self, r: &mut Jacobian, a: &Affine, scalar: &Scalar) {
        const WNAF_SIZE: usize = (WNAF_BITS + (WINDOW_A - 1) - 1) / (WINDOW_A - 1);

        let mut tmpa = Affine::default();
        let mut pre_a: [Affine; ECMULT_TABLE_SIZE_A] = Default::default();
        let mut z = Field::default();

        let mut wnaf_1 = [0i32; 1 + WNAF_SIZE];

        let sc = *scalar;
        let skew_1 = ecmult_wnaf_const(&mut wnaf_1, &sc, WINDOW_A - 1);

        /* Calculate odd multiples of a.  All multiples are brought to
         * the same Z 'denominator', which is stored in Z. Due to
         * secp256k1' isomorphism we can do all operations pretending
         * that the Z coordinate was 1, use affine addition formulae,
         * and correct the Z coordinate of the result once at the end.
         */
        r.set_ge(a);
        odd_multiples_table_globalz_windowa(&mut pre_a, &mut z, r);
        for i in 0..ECMULT_TABLE_SIZE_A {
            pre_a[i].y.normalize_weak();
        }

        /* first loop iteration (separated out so we can directly set
         * r, rather than having it start at infinity, get doubled
         * several times, then have its new value added to it) */
        let i = wnaf_1[WNAF_SIZE];
        debug_assert!(i != 0);
        table_get_ge_const(&mut tmpa, &pre_a, i, WINDOW_A);
        r.set_ge(&tmpa);

        /* remaining loop iterations */
        for i in (0..WNAF_SIZE).rev() {
            for _ in 0..(WINDOW_A - 1) {
                let r2 = *r;
                r.double_nonzero_in_place(&r2, None);
            }

            let n = wnaf_1[i];
            table_get_ge_const(&mut tmpa, &pre_a, n, WINDOW_A);
            debug_assert!(n != 0);
            *r = r.add_ge(&tmpa);
        }

        r.z *= &z;

        /* Correct for wNAF skew */
        let mut correction = *a;
        let mut correction_1_stor: AffineStorage;
        let a2_stor: AffineStorage;
        let mut tmpj = Jacobian::default();
        tmpj.set_ge(&correction);
        tmpj = tmpj.double_var(None);
        correction.set_gej(&tmpj);
        correction_1_stor = (*a).into();
        a2_stor = correction.into();

        /* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */
        correction_1_stor.cmov(&a2_stor, skew_1 == 2);

        /* Apply the correction */
        correction = correction_1_stor.into();
        correction = correction.neg();
        *r = r.add_ge(&correction)
    }

函数set_gej实现对给定的Jacobian坐标下的点坐标,找到其在仿射坐标中的对应点:

    pub fn set_gej(&mut self, a: &Jacobian) {
        self.infinity = a.infinity;
        let mut a = *a;
        a.z = a.z.inv();
        let z2 = a.z.sqr();
        let z3 = a.z * z2;
        a.x *= z2;
        a.y *= z3;
        a.z.set_int(1);
        self.x = a.x;
        self.y = a.y;
    }

impl<D: Digest> AsRef<[u8]> for SharedSecret<D>中定义函数as_ref

impl<D: Digest> AsRef<[u8]> for SharedSecret<D> {
    fn as_ref(&self) -> &[u8] {
        &self.0.as_ref()
    }
}

未完待续

  区块链 最新文章
盘点具备盈利潜力的几大加密板块,以及潜在
阅读笔记|让区块空间成为商品,打造Web3云
区块链1.0-比特币的数据结构
Team Finance被黑分析|黑客自建Token“瞒天
区块链≠绿色?波卡或成 Web3“生态环保”标
期货从入门到高深之手动交易系列D1课
以太坊基础---区块验证
进入以太坊合并的五个数字
经典同态加密算法Paillier解读 - 原理、实现
IPFS/Filecoin学习知识科普(四)
上一篇文章      下一篇文章      查看所有文章
加:2022-01-01 13:56:56  更:2022-01-01 13:58:30 
 
开发: 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年11日历 -2024/11/26 0:42:26-

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