sCrypt 合约中的椭圆曲线算法:第二部分

news2024/11/25 18:58:14

我们在脚本中实现了椭圆曲线 (EC) 算法。在之前的实现中,我们进行链下计算并在脚本中验证结果。我们这里直接用脚本计算。

基于EC的应用非常多,特别是在密码学领域,如数字签名、加密、承诺方案等。作为具体示例,我们重新实现了 ECDSA 签名验证,允许使用任意消息验证签名。

模逆

在实现点加法和乘法之前,我们先介绍模逆,因为它是一个积木。

整数 a 的模乘逆是整数 x,使得 a*x ≡ 1 mod n。为了导出该值,我们使用扩展欧几里得算法 (eGCD)。因为在使用 EC 算法时模逆会占用大部分脚本大小,所以尽可能优化它是至关重要的。因此,我们使用内联汇编直接在原始脚本中对其进行编码。

扩展欧几里德算法

扩展欧几里德算法是对标准欧几里德算法的扩展。除了找到最大公约数 (GCD) 之外,它还计算 Bézout 恒等式的系数,它们是整数 xy,使得:

在这里插入图片描述

eGCD算法定义如下:

在这里插入图片描述

当余数 r(i+1)0 时停止执行。如果 ab 是互质的(在 EC 算法中它们总是应该互质,因为曲线参数 pn 是质数),x 也是 a mod b 的模逆。

下面是输入a=240b=46的eGCD算法的示例计算表:

在这里插入图片描述

资料来源: 维基百科

实现

以下是扩展欧几里德算法在 Script 中的高度优化实现。因为我们只对 t(i) 序列感兴趣,所以我们不需要跟踪 s(i) 序列,从而使脚本大小更小。

static function modInverseEGCD(int x, int n) : int {
    // The following script already does modular reduction at the start so there's no
    // need to normalize x before function call.
    asm {
        OP_2DUP OP_MOD OP_DUP OP_0 OP_LESSTHAN OP_IF OP_DUP OP_2 OP_PICK OP_ADD OP_ELSE OP_DUP OP_ENDIF OP_NIP OP_2 OP_ROLL OP_DROP
        OP_DUP OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK
        OP_1 OP_0 OP_1
        loop(UB) {
            OP_FROMALTSTACK OP_FROMALTSTACK OP_2DUP OP_DUP OP_IF OP_TUCK OP_MOD OP_TOALTSTACK OP_TOALTSTACK OP_DIV OP_MUL OP_SUB OP_TUCK OP_ELSE OP_TOALTSTACK OP_TOALTSTACK OP_DROP OP_DROP OP_ENDIF
        }
        OP_FROMALTSTACK OP_FROMALTSTACK OP_DROP OP_DROP OP_DROP OP_FROMALTSTACK OP_SWAP OP_NIP
    }
}
源代码

计算循环的上限

k 位模数 n 的迭代次数上限可以使用以下等式导出:

在这里插入图片描述

,其中 phi 是黄金比例:

在这里插入图片描述

对于 256 位的模数,如比特币曲线 secp256k1,我们得到 368 的上限。modInverseEGCD() 生成的脚本大小约为 7 KB。

点加法

在这里插入图片描述

椭圆曲线上的加点定义为​​通过点 PQ 的直线的曲线交点的负值。如果其中一个点是无限点 (0, 0),我们只返回另一个点。

static function addPoints(Point p, Point q) : Point {
    Point ret = {0, 0};

    if (p.x == 0 && p.y == 0) {
        // if P == inf -> P + Q = Q
        ret = q;
    } else if (q.x == 0 && q.y == 0) {
        // if Q == inf -> P + Q = P
        ret = p;
    } else {
        int lambda = 0;
        if (p.x == q.x && p.y == q.y) {
            lambda = (3 * p.x * p.x) * modInverseEGCD(2 * p.y, P);
        } else {
            lambda = (q.y - p.y) * modInverseEGCD(q.x - p.x, P);
        }

        int rx = modReduce(lambda * lambda - p.x - q.x, P);
        int ry = modReduce(lambda * (p.x - rx) - p.y, P);

        ret = {rx, ry};
    }

    return ret;
}
源代码

点加倍

在这里插入图片描述

如果 PQ 处于同一坐标,我们使用曲线在该坐标处的切线交点。

static function doublePoint(Point p) : Point {
    int lambda = (3 * p.x * p.x) * modInverseEGCD(2 * p.y, P);

    int rx = modReduce(lambda * lambda - 2 * p.x, P);
    int ry = modReduce(lambda * (p.x - rx) - p.y, P);
    
    Point res = {rx, ry};
    return res;
}
源代码

标量乘法

点与标量的乘法是我们定义的计算量最大的函数。为简单起见,我们使用了双倍-加法算法。还有其它更高效的方法。

static function multByScalar(Point p, int m) : Point {
    // Double and add method.
    // Lowest bit to highest.
    Point n = p;
    Point q = {0, 0};

    bytes mb =   reverseBytes(num2bin(m, S), S);
    bytes mask = reverseBytes(num2bin(1, S), S);
    bytes zero = reverseBytes(num2bin(0, S), S);

    loop (256) : i {
        if ((mb & (mask << i)) != zero) {
            q = addPoints(q, n);
        }

        n = doublePoint(n);
    }

    return q;
}
源代码

ECDSA 签名验证

现在我们已经实现了所有需要的 EC 原语,我们可以定义一个函数来检查任意消息签名的有效性,而无需任何新的操作码,例如 BTC 上的 OP_CHECKSIGFROMSTACK 或 BCH 上的 OP_DATASIGVERIFY(又名 OP_CHECKDATASIG)。

static function verifySig(bytes m, Signature sig, Point pubKey) : bool {
    Sha256 hash = hash256(m);
    int hashInt = unpack(reverseBytes(hash, 32));

    require(sig.r >= 1 && sig.r < n && sig.s >= 1 && sig.s < n);

    int sInv = modInverseEGCD(sig.s, n);
    int u1 = modReduce(hashInt * sInv, n);
    int u2 = modReduce(sig.r * sInv, n);

    Point U1 = multByScalar(G, u1);
    Point U2 = multByScalar(pubKey, u2);
    Point X = addPoints(U1, U2);

    return sig.r == X.x;
}

正如我们所见,该函数调用了两次标量乘法。单次调用 multByScalar() 会花费我们大约 5 MB 的脚本大小。因此,单个签名验证大约需要 10 MB 的脚本,可以进一步优化。我们甚至可以使用自定义曲线而不是标准的 secp256k1 并使用更大的密钥大小来显着提高安全性。

致谢

这是 nChain 白皮书 1611 的实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/42866.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

11.28作业

实现对点灯所涉及函数的封装 1.头文件 #ifndef __GPIO_H__ #define __GPIO_H__ //结构体封装 typedef struct{volatile unsigned int MODER;volatile unsigned int OTYPER;volatile unsigned int OSPEEDR;volatile unsigned int PUPDR;volatile unsigned int IDR;volatile un…

Kotlin进阶指南 - 单元测试

为了减少一些功能繁琐的测试流程&#xff0c;单元测试是提升开发效率的有效方式之一 在早些年的时候我有记录过一篇 Android 使用单元测试&#xff0c;只不过当时更多的针对 Java 方面的单元测试&#xff1b;在使用 Kotlin 后&#xff0c;我发现单元测试有点不同&#xff0c;好…

Nacos注册中心和服务消费方式

目录 一&#xff0c;服务治理介绍 什么是服务治理&#xff1f; 常见的注册中心 二&#xff0c;nacos简介 三&#xff0c;搭建nacos环境 四&#xff0c;代码演示 五&#xff0c;基于Feign实现服务调用 什么是Feign Feign的使用 Feign参数传递 一&#xff0c;服务治理介…

全国心力衰竭日:重症心衰的黑科技——永久型人工心脏

今天是第8个“全国心力衰竭日”。近几年&#xff0c;中国逐渐老龄化&#xff0c;心衰则是老龄化面临的严峻问题。我国心衰患病率估计已达1.3%&#xff0c;至少有1000万心力衰竭患者。中国已成为世界上拥有最大心衰患者群的国家之一。心力衰竭作为大多数心血管疾病的终末阶段&am…

如何在 docker 容器使用 nginx 实现反向代理统一站点入口

在微服务架构下&#xff0c;我们会部署很多微服务来实现我们的系统。每个微服务会有不同的端口。而用户在访问我们的站点时希望通过统一的端口来访问所有的服务&#xff0c;因为在很多情况下用户只能通过 80 或者 443 端口访问外界服务。 这个时候我们就可以使用反向代理来实现…

云上“两地三中心”,中小企业都用得起的多保险灾备方案

在云时代&#xff0c;大部分中小型企业都奔跑在云上或是服务器托管公司。任何规模的数据中心服务中断都会让你的企业踩雷。据统计&#xff0c;80%的数据中心服务中断都是由服务器硬件造成的。 据万博智云不完全统计&#xff1a; 2021年3月&#xff0c;一场大火完全摧毁了OVH在…

[附源码]计算机毕业设计SpringBoot蛋糕购物商城

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

如何将pdf转word?这几个软件可以做到文档格式转换

我们在日常办公中使用较为频繁的就是pdf和word两种文件格式&#xff0c;pdf的兼容性较好&#xff0c;就算跨设备传输也不会出现乱码的情况&#xff1b;word文档可以直接进行编辑修改&#xff0c;各有各的好处。如果我们想对pdf的内容进行修改的话&#xff0c;就需要把pdf文件转…

优维低代码:Redirect 路由重定向If 条件渲染

优维低代码技术专栏&#xff0c;是一个全新的、技术为主的专栏&#xff0c;由优维技术委员会成员执笔&#xff0c;基于优维7年低代码技术研发及运维成果&#xff0c;主要介绍低代码相关的技术原理及架构逻辑&#xff0c;目的是给广大运维人提供一个技术交流与学习的平台。 连载…

Centos7扩容root分区

Background 安装centos7系统时&#xff0c;如果没有自定义分区&#xff0c;系统默认给root分配的空间只有50G&#xff0c;其他空间都分配给了你创建的普通用户/home目录。这里我们把home的空间匀出一部分给root。 1、首先要注意数据安全 备份home目录的数据 tar zcf /tmp/hom…

vue学习1~18

1. vue基础知识和原理 1.1 初识Vue 想让Vue工作&#xff0c;就必须创建一个Vue实例&#xff0c;且要传入一个配置对象demo容器里的代码依然符合html规范&#xff0c;只不过混入了一些特殊的Vue语法demo容器里的代码被称为【Vue模板】Vue实例和容器是一一对应的真实开发中只有…

城市三维地理信息可视化 技术解析

一、三维地理信息系统分析空间数据的科学工具 三维地理信息系统&#xff0c;即三维GIS&#xff0c;是对包括大气层在内的地球表层&#xff0c;与地理有关的数据进行采集、储存、管理、运算、分析、显示和描述的技术系统。 基于三维GIS将现实世界中三维对象的相关属性与空间位…

什么是CRM系统?CRM的价值体现在哪里?

图为简道云看板对企业来说&#xff0c;完整的工作流程可以概括为售前、售中和售后三个阶段。每一个阶段都需要不同的管理。而CRM客户关系管理系统&#xff0c;能够帮助企业在这三个阶段进行业务管理及客户管理&#xff0c;帮助企业更好地运营&#xff0c;提高企业的竞争力。 简…

软件设计与体系结构简答题汇总

假设系统中有三个类&#xff0c;分别为类 A 、类 B 和类 C 。在现有的设计中&#xff0c;让类 A 直接依赖类 B &#xff0c;如果要将类 A 改为依赖类 C &#xff0c;必须通过修改类 A 的代码来达成&#xff0c;请问这样的设计符合开闭原则吗&#xff08; 2 分&#xff09;&…

跟着官方帮助文档学ICEM网格划分(附视频教程)

作者 | 如鹰展翅上腾 导读&#xff1a;划分结构化网格是ICEM软件的一大特色&#xff0c;自学的话会比较耗时&#xff0c;如有人带的话&#xff0c;入门进阶都是比较快的&#xff0c;就像一层窗户纸一捅就破。软件是使我们研究的问题得以求解的工具&#xff0c;重点侧向于操作…

毕业设计 基于大数据的服务器数据分析与可视化系统 -python 可视化 大数据

文章目录0 前言1 课题背景2 实现效果3 数据收集分析过程**总体框架图****kafka 创建日志主题****flume 收集日志写到 kafka****python 读取 kafka 实时处理****数据分析可视化**4 Flask框架5 最后0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&…

企业数据流转5个大坑,你最烦哪个?

对于公司来说&#xff0c;注重数据安全已然是一个必须项&#xff0c;如何保护数据安全也是让公司管理者头痛的问题。 云宝贝罗列了公司5个常见的数据安全场景&#xff0c;并给出了应对方法&#xff0c;看看你公司有没有踩雷。 01、文件云端流转&#xff0c;不落地 “员工在公…

【初阶数据结构】——限定性线性表:栈 和 队列详解(C描述)

文章目录前言1. 栈1.1 栈的概念及结构1.2栈的实现1.2.1 动态or静态1.2.2 结构介绍1.2.3 初始化栈1.2.4 销毁栈1.2.5 压栈1.2.6 出栈1.2.7 判空1.2.8 取栈顶元素1.2.9 获取有效元素个数1.3 测试1.4 源码展示1.4.1 stack.h1.4.2 stack.c1.4.3 test.c2. 队列2.1 队列的概念及结构2…

2022年最新全国各省五级行政区划代码及名称数据(省-市-区县-乡镇-村)

1、数据来源&#xff1a;国家统计局 2、官方更新时间&#xff1a;2021年10月31日 3、数据样例&#xff1a; 包括字段&#xff1a;省份名称、城市代码、城市名称、区县代码、区县名称、乡镇街道代码、乡镇街道名称、居委会村代码、城乡分类代码、居委会村名称、完整五级地址 …

Java的JFrame窗体的创建(两种方法)

第一种直接创建 package com.jwz.h综合项目;import javax.swing.*;public class Test {public static void main(String[] args) {//创建宽高jFrame.setSize(488, 580);//创建窗口对象JFrame jFrame new JFrame();jFrame.setTitle("拼图游戏");//设置标题jFrame.se…