区块链系统探索之路:基于椭圆曲线的私钥与公钥生成
前两节我们探讨了抽象代数的重要概念:有限域,然后研究了基于椭圆曲线上点的怪异”+“操作,两者表面看起来牛马不相及,实际上两者在逻辑上有着紧密的联系,简单来说如果我们在椭圆曲线上取一点G,然后让它跟自己做”+“操作,那么所得结果形成的集合就会构成有限域。
首先我们先给定一个有限域F(103)={0, 1, … 102}, 同时回忆一下我们前面讲过作用在有限域上的"+“和”*"两种操作其实对应在求余基础上普通的加法和乘法,由此我们判断有限域中某个点是否在给定椭圆曲线y ^ 2 = x ^ 3 + 7:上时,首先把该点的x,y坐标代入椭圆曲线方程,同时在求余的基础上判断左右两边是否相等,例如判断点(17, 64)(这里x,y坐标的值都从有限域F(103)中获取)是否在曲线上,我们做如下计算:
y ^ 2 = (64 ^ 2) % 103 = 79, x ^ 3 + 7 = (17 ^ 3 + 7 ) % 103 = 79
由于左右两边计算后取值相同,因此点(17, 64)在曲线上。
我们把有限域的"+“和” * " 两种运算跟上一节我们提到的椭圆曲线上点的"+"操作结合起来就能起到加密效果,这里要注意我们不要把两种操作混淆,因为他们对应的符号看起来一样,但实际对应的运算不一样。
首先我们把上面提到的有限域点在椭圆曲线上的判断逻辑用代码实现一下看看:
"""
将有限域的点输入到椭圆曲线,需要注意的是在椭圆曲线里执行+和*两种运算时,它会自动转换为
有限域定义的__add__ 和 __mul__运算,注意到即使运算操作的逻辑变了,但是判断点是否在椭圆曲线上
依然是判断椭圆曲线对应公式的两边是否相等
"""a = LimitFieldElement(0, 223)
b = LimitFieldElement(7, 223)
x = LimitFieldElement(192, 223)
y = LimitFieldElement(105, 223)
p1 = EllipticPoint(x, y, a, b)
print(f"Elliptc Point over F_223 is {p1}")
上面代码运行后所得结果为:
Elliptc Point over F_223 is EllipticPoint(x:LimitFieldElement_223(192),y:LimitFieldElement_223(105),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
这里需要注意,在执行EllipticPoint(x, y, a, b)这条语句时,它对应的__init__函数会被执行,里面会对输入参数执行如下运算:
if y ** 2 != x ** 3 + a * x + b:
这里相应操作例如 “**”, “*”, “+” , "!="对应到有限域对象中的_pow_, _mul_ , _add_, _ne_,这几个重载函数。
现在来点烧脑的,上一节我们推导了椭圆曲线上给定两点,如何得出他们执行"+"运算后所得的第3点,在算法中执行了一系列普通加减乘除运算,现在我们把这些运算全部转换为有限域上对应的运算,所得结果依然成立,例如给定两点P1(x1,y1), P2(x2, y2),要获得P3 = P1 + P2,我们在上一节执行了如下运算:
s = (y2 - y1)/(x2 - x1)
x3 = s ^ 2 - x1 - x3
y3 = s * (x1 - x3) - y1
上面的减法要对应到LimitFiniteField类的__sub__ ,”_truediv_“等逻辑实现。这里可以体会到,我们把普通的加减乘法运算换成带求余操作的运算后,原有结论依然成立,这就是抽象代数的强大作用。前面章节中我忘了实现LimitFinitField类中的__ sub __ , __ rmul __ 两个方法, 他们的实现如下:
def __sub__(self, other):if self.order != other.order:raise TypeError("不能对两个不同有限域的元素执行减法操作")num = (self.num - other.num) % self.orderreturn __class__(num, self.order)def __rmul__(self, scalar):#实现与常量相乘num = (self.num * scalar) % self.orderreturn __class__(num, self.order)
有了上面基础后,我们测试一下在有限域基础上椭圆曲线上点的”+“操作,代码如下:
```a = LimitFieldElement(0, 223)
b = LimitFieldElement(7, 223)
x = LimitFieldElement(192, 223)
y = LimitFieldElement(105, 223)
p1 = EllipticPoint(x, y, a, b)
#print(f"Elliptc Point over F_223 is {p1}")#基于有限域上椭圆曲线点对应的"+"操作
x2 = LimitFieldElement(17, 223)
y2 = LimitFieldElement(56, 223)
p2 = EllipticPoint(x2, y2, a, b)print(f"Elliptic point P1 + P2 is {p1 + p2}")
上面代码运行后所得结果如下:
Elliptic point P1 + P2 is EllipticPoint(x:LimitFieldElement_223(170),y:LimitFieldElement_223(142),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
下面我们要实现椭圆曲线点与常量的乘法,这个操作将对椭圆曲线加密产生重要作用,后面我们会选取椭圆曲线上一点G, 然后选取一个常量k, 计算 kG,其中k对应的就是私钥,而kG对应的就是公钥。这里基于一个原理是,即使让你知道点G, 同时给你k*G的结果,在数学上也没有办法能够逆向计算出k来,于是这点就成为了椭圆曲线加密的原理。
下面我们用代码实现一下椭圆曲线上给定一点G,然后计算k*G,, k = 1, 2, …所得结果,注意到常量乘法本质上是把G跟自己相加给定次数:
#计算点G(47, 71)的常量乘法
x = LimitFieldElement(47, 223)
y = LimitFieldElement(71, 223)
G = EllipticPoint(x, y, a, b)
result = G
for k in range(1, 22):if k != 1:result = result + Gprint(f"{k} * (47, 71) is {result}")
上面代码运行后所得结果如下:
1 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(47),y:LimitFieldElement_223(71),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
2 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(36),y:LimitFieldElement_223(111),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
3 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(15),y:LimitFieldElement_223(137),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
4 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(194),y:LimitFieldElement_223(51),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
5 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(126),y:LimitFieldElement_223(96),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
6 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(139),y:LimitFieldElement_223(137),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
7 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(92),y:LimitFieldElement_223(47),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
8 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(116),y:LimitFieldElement_223(55),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
9 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(69),y:LimitFieldElement_223(86),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
10 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(154),y:LimitFieldElement_223(150),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
11 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(154),y:LimitFieldElement_223(73),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
12 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(69),y:LimitFieldElement_223(137),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
13 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(116),y:LimitFieldElement_223(168),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
14 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(92),y:LimitFieldElement_223(176),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
15 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(139),y:LimitFieldElement_223(86),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
16 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(126),y:LimitFieldElement_223(127),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
17 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(194),y:LimitFieldElement_223(172),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
18 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(15),y:LimitFieldElement_223(86),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
19 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(36),y:LimitFieldElement_223(112),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
20 * (47, 71) is EllipticPoint(x:LimitFieldElement_223(47),y:LimitFieldElement_223(152),a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
21 * (47, 71) is EllipticPoint(x:None,y:None,a:LimitFieldElement_223(0), b:LimitFieldElement_223(7))
上面的运行结果有一个特点,那就是当k增加到21时,k*G 所得结果是椭圆曲线的0点,椭圆曲线上任取一点执行如上操作都会得到这样的结果,当k=1开始,一直到k=n使得k * G 为零点时,那么集合{0,G, 2*G, … ,(n-1)*G}所形成的集合在数学上称为”群“。
相比于前面我们提到的有限域,群中的元素只对应一种操作"+“(有限域有两种),下面我们看看群的一些性质:
1,单位0,也就是群中必然包含一个特殊元素"0”,任何元素跟他执行”+“操作,其结果都是该元素自己,也就是如果A是群中任何一个元素,那么A “+” 0 = A,
2,闭合性,如果A, B是群中两个元素,那么A “+” B 所得结果还是群中的元素。
3,可逆性,如果A是群中的一个元素,那么群中比如存在另一个元素B, 使得A “+” B = 0
4,交换性,如果A, B是群中两个元素,那么有 A “+” B = B “+” A
5,关联性,(A “+” B) “+” C = A “+” (B “+” C)
“群“是抽象代数中一个至关重要的概念,它也是密码学的支柱性概念。前面我们实现k * G时,代码是把G点执行k次”+"操作,现在我们给椭圆曲线的点添加常量乘法,在EllipitcPoint中增加代码实现如下:
def __rmul__(self, scalar):#如果常量是0,那么就返回椭圆曲线"0"点result = self.__class__(None, None, self.a, self.b)#自加给定次数for _ in range(scalar):result += selfreturn result
我们用如下代码测试一下上面的实现,可以发现输出结果跟原来一样,由此能确认实现的正确性:
#测试常量乘法:
for k in range(1, 22):print(f"{k} * (47, 71) is {k * G}")
接下来我们看比特币对应椭圆曲线的实现,对于比特币而言,它对应的椭圆曲线就是设置a = 0, b = 7, 因此它对应的曲线公式就是 y ^ 2 = x ^ 3 + 7,对比特币而言,它定义的有限域中元素个数为p = 2256 – 232 – 977, 同时G点的x分量为 G(x) = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
G(y) = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8,
当k = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141时,k * G = 0。
对于比特币使用的椭圆曲线,它有几个特点,首先是参数a, b非常简单,其次它对应有限域中元素个数及其多,接近2 ^ 256,所以椭圆曲线G点两个分量大小都接近256bit,也就是32字节,这个数值几乎接近了全宇宙的原子总数。
下面我们用代码看看G点是否在比特币曲线上:
#测试G点是否在曲线上
gx = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
p = 2 ** 256 - 2 ** 32 - 977
print(gy ** 2 % p == (gx ** 3 + 7) % p) #True
上面代码运行后返回True。下面我们尝试把G点的两个分量转换为有限域上的点,同时测试一下k * G 的结果是否为椭圆曲线上的0点,相应代码如下:
k = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
x = LimitFieldElement(gx, p)
y = LimitFieldElement(gy, p)
a = LimitFieldElement(0, p)
b = LimitFieldElement(7, p)
G = EllipticPoint(x, y, a, b)
print(f'result of n * G is {n * G}')
如果直接执行上面代码你会发现程序会卡死,原因在于k的值实在太大,我们在实现EllipticPoint类的常量乘法时(__ rmul __),使用的是循环k次加法,但由于k的值实在太大,因此循环无法在短时间内完成。
一种解决办法是使用二进制扩展来优化,我们看个具体例子,假设常量值k的值为36,它转换为二进制就是100100,于是k * G = (2 ^5 + 2 ^ 2) * G = 2 ^ 5 * G + 2 ^ 2 * G,这里可以看到我们把原来36次加法转换成2次乘法和1次加法,所需计算量不超过lg(k),注意到在计算(0b100100) * G时,我们从最右边的比特位开始遍历,如果比特位是0,那么我们只需要计算2 ^ k (k表示当前遍历的比特位在二进制中的位置),如果遍历到的比特位是1,那么就执行一次加法,于是我们把常量乘法进行如下优化:
def __rmul__(self, scalar):#二进制扩展coef = scalarcurrent = selfresult = self.__class__(None, None, self.a, self.b)while coef:if coef & 1: #如果当前比特位是1,那么执行加法result += currentcurrent += current #如果上次比特位的位置在k,那么下次比特位的位置变成k+1,2^(k+1)*G 等价于2^k*G + 2^k * Gcoef >>= 1return result
经过如上优化后再执行前面的代码,所得结果如下:
result of k * G is EllipticPoint(x:None,y:None,a:LimitFieldElement_115792089237316195423570985008687907853269984665640564039457584007908834671663(0), b:LimitFieldElement_115792089237316195423570985008687907853269984665640564039457584007908834671663(7))
可以看到 k * G的结果确实是椭圆曲线上的零点。由于比特币对应的椭圆曲线叫secp256k1,其中曲线的a,b参数等已经确定,同时有限域元素个数也确定,因此我们在LimitFinitField和EllipticPoint的基础上做对应子类,把相应参数给写死,代码如下:
P = 2**256 - 2**32 - 977class S256Field(LimitFieldElement):def __init__(self, num, order=None):# 参数写死即可super().__init__(num, P)def __repr__(self):return '{:x}'.format(self.num).zfill(64)N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141class S256Point(EllipticPoint):def __init__(self, x, y, a=None, b=None):a, b = S256Field(0), S256Field(7)if type(x) == int:super().__init__(S256Field(x), S256Field(y), a, b)else:# 如果x,y 是None,那么直接初始化椭圆曲线的0点super().__init__(x, y, a, b)def __repr__(self):if self.x is None:return 'S256Point(infinity)'return f'S256Point({self.x}, {self.y})'def __rmul__(self, k):k = k % Nreturn super().__rmul__(k)G = S256Point(0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8)print(N * G)
上面代码运行后输出结果为:
S256Point(infinity)
有了以上基础后,我们就可以通过椭圆曲线生成公钥和私钥,私钥很简单,我们只要在[1, N]这个范围内取一个值e即可,然后公钥就是P = e * G,有了公钥,我们就可以构建比特币钱包的地址。
更多内容请在B站搜索coding迪斯尼。本节代码下载地址为:
链接: https://pan.baidu.com/s/1SIVPmmVXYnA0pfKh4cfuEQ 提取码: b1fe
相关文章:
区块链系统探索之路:基于椭圆曲线的私钥与公钥生成
前两节我们探讨了抽象代数的重要概念:有限域,然后研究了基于椭圆曲线上点的怪异”“操作,两者表面看起来牛马不相及,实际上两者在逻辑上有着紧密的联系,简单来说如果我们在椭圆曲线上取一点G,然后让它跟自己做”“操作…...
Linux命令集(Linux常用命令--echo指令篇)
Linux命令集(Linux常用命令--echo指令篇) Linux常用命令集(echo指令篇)2.echo(echo)1. 输出自定义内容2. 禁止输出末尾换行符3. 转义功能4. 与特殊字符配合使用实现其余功能 Linux常用命令集(echo指令篇) 如…...
【电子学会】2023年03月图形化一级 -- 甲壳虫走迷宫
甲壳虫走迷宫 1. 准备工作 (1)绘制如图所示迷宫背景图,入口在左下角,出口在右上角,线段的颜色为黑色; (2)删除默认小猫角色,添加角色:Beetle; …...
老外从神话原型中提取的12个品牌个性
老外从神话原型中提取的12个品牌个性 也是西方视角,需要本土化 参照心理学大师荣格的理论:心理学潜意识派 趣讲大白话:品牌的调调是啥 【趣讲信息科技151期】 **************************** 12种原型又归属于4种人性动机。 1、稳定࿰…...
unity中的Quaternion.AngleAxis
介绍 unity中的Quaternion.AngleAxis 方法 Quaternion.AngleAxis() 函数是 Unity 引擎中的一个数学函数,用于创建一个绕着某个轴旋转一定角度的旋转四元数。在游戏开发中,经常会用到该函数来旋转物体或计算旋转后的方向向量。 该函数的函数原型为&…...
如何设置渗透测试实验室
导语:在本文中,我将介绍设置渗透实验室的最快方法。在开始下载和安装之前,必须确保你使用的计算机符合某些渗透测试的要求,这可以确保你可以一次运行多个虚拟机而不会出现任何问题。 在本文中,我将介绍设置渗透实验室的…...
Java时间类(八)-- Instant (时间戳类)(常用于Date与LocalDateTime的相互转化)
目录 1. Instant的概述: 2. Instant的常见方法: 3. Date --->Instant--->LocalDateTime 4. LocalDateTime --->Instant--->Date 1. Instant的概述...
C++模板
模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。模板的目的是为了提高复用性,将类型参数化,函数模板作用:建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚…...
【JavaEE】HTML基础知识
目录 1.HTML结构 2.HTML常见标签 3.表格标签 4.列表标签 5.表单标签 6.select 标签 7.textarea 标签 8.无语义标签: div & span 9.标签小练习 1.HTML结构 形如: <body idmyId>hello</body> HTML的书写格式 标签名 (body) 放到 <…...
mysql与redis区别
一、.redis和mysql的区别总结 (1)类型上 从类型上来说,mysql是关系型数据库,redis是缓存数据库 (2)作用上 mysql用于持久化的存储数据到硬盘,功能强大,但是速度较慢 redis用于存储使…...
Hive本地开发/学习环境配置
前提 hive依赖hadoop的相关组件,需要启动Hadoop的相关组件。 Hive 版本:3.1.3 Hadoop版本:3.3.4 hive-env.sh export HADOOP_HOME$HADOOP_HOME export HIVE_CONF_DIR/usr/local/Cellar/hive/3.1.3/libexec/conf export HIVE_AUX_JARS_PATH/…...
《基于EPNCC的脉搏信号特征识别与分类研究》阅读笔记
目录 一、论文摘要 二、论文十问 三、论文亮点与不足之处 四、与其他研究的比较 五、实际应用与影响 六、个人思考与启示 参考文献 一、论文摘要 为了快速获取脉搏信号的完整表征信息并验证脉搏信号在相关疾病临床诊断中的敏感性和有效性。在本文中,提出了一…...
Linux下解压和压缩命令大全(详解+案例)
linux常用的解压和压缩命令如下: .zip或.zipx 压缩文件.zip、.zipx:都可以使用zip命令。例如,要将目录/home/user1/mydata压缩成一个文件mydata.zip,可以使用以下命令: zip -r mydata.zip /home/user1/mydata/要解压…...
Linux的常用指令
重启 init 6或reboot 关机 init 0 或halt如果没有执行关机命令,强制断电或关闭本地虚拟机的窗口,会导致Linux操作系统文件的损坏,严重的可能导致系统无法正常启动。 清屏 clear 查看服务器的ip地址 ip addr 时间操作 普通用户可以查看时间&am…...
第 5 章 HBase 优化
5.1 RowKey 设计 一条数据的唯一标识就是 rowkey,那么这条数据存储于哪个分区,取决于 rowkey 处于 哪个一个预分区的区间内,设计 rowkey的主要目的 ,就是让数据均匀的分布于所有的 region 中,在一定程度上防止数据倾斜…...
台北房价预测
目录 1.数据理解1.1分析数据集的基本结构,查询并输出数据的前 10 行和 后 10 行1.2识别并输出所有变量 2.数据清洗2.1输出所有变量折线图2.2缺失值处理2.3异常值处理 3.数据分析3.1寻找相关性3.2划分数据集 4.数据整理4.1数据标准化 5.回归预测分析5.1线性回归&…...
9:00进去,9:05就出来了,这问的也太···
从外包出来,没想到死在另一家厂子了。 自从加入这家公司,每天都在加班,钱倒是给的不少,所以也就忍了。没想到8月一纸通知,所有人不许加班,薪资直降30%,顿时有吃不起饭的赶脚。 好在有个兄弟内推…...
debootstrap 构建 RISC-V 64 Ubuntu 根文件系统
debootstrap 构建 Ubuntu RISC-V Linux 根文件系统 flyfish 主机信息 命令 lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 20.04.6 LTS Release: 20.04 Codename: focal制作的根文件系统为 RISC-V 64 Ubuntu 22.04 LTS 1 主机…...
腾讯云轻量应用服务器(Lighthouse)怎么样?
轻量应用服务器是否好用,小白这么多年的经验来看,跑企业站或博客都没问题,因为小流量站是可以的。但是限制流量的服务器只适合小站。超流量后是要扣费的。简而言之,超过流量是按流量计费的。如果被攻击大概率会欠费。如果是企业用…...
学习 AI 常用的一些专业词汇
学习 AI 常用的一些专业词汇 AI 词汇集 AI 词汇集 神经网络(Neural Network): 由节点(模型参数)和连接(权重)组成的网络结构,用于机器学习与深度学习。 深度学习(Deep Learning): 使用包含多隐藏层神经网络进行表征学习的机器学习方法。 机器学习(Machine Learnin…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...
