区块链系统探索之路:基于椭圆曲线的私钥与公钥生成
前两节我们探讨了抽象代数的重要概念:有限域,然后研究了基于椭圆曲线上点的怪异”+“操作,两者表面看起来牛马不相及,实际上两者在逻辑上有着紧密的联系,简单来说如果我们在椭圆曲线上取一点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…...
IP协议基础
文章目录 基本概念IP和TCP分别解决什么问题 以下过程都是在网络层完成的网段划分路由路由转发过程路由表 基本概念 主机: 配有IP地址, 但是不进行路由控制的设备。 路由器: 即配有IP地址, 又能进行路由控制。 节点: 主机和路由器的统称。 IP和TCP分别解决什么问题 TCP解决…...
Redis主从复制、哨兵实战
环境:linux centos7.x ,虚拟机3台 版本:redis-6.2.6 1.下载安转redis 下载地址 wget https://download.redis.io/releases/redis-6.2.6.tar.gz解压 tar -zxvf redis-6.2.6.tar.gz移动目录 mv redis-6.2.6 /usr/local/redis编译 cd /usr/…...
README.md编写
一、摘要 项目一般会有个描述文件,对于项目的代码来讲,这个描述就是README.md文件,可以描述各模块功能、目录结构等。该文件可以方便让人快速了解项目的代码结构和功能。当然,若要深层次的了解项目,就得看项目总体的需…...
软件设计证书倒计时28天
从一个月前的果断报考软件设计证书,我没有后悔过。 软件设计证书一个月备考情况: 现在做选择题的正确率可以达到65%。是重复做过两遍历年真题。 接下来是继续做模拟题。 大题的题型基本是都知道, 第一题数据流图,第二题er图&…...
程序员基础的硬件知识(cpu、主板、显卡、内存条等)
一、综合简介 cpu:负责运算数据,就等于你的大脑运算速度。 显卡:本来没有显卡,后来因为大家对图片要求越来越高,视频要求越来越高,啥都让cpu算太累了,于是分出来一个,专门用来计算…...
优化Google Cloud Storage大文件上传和内存溢出
背景 我们的项目每天都会并行上传好几万份文件到下游的GCP Cloud Storage,当文件比较大时,会采用GCP的可续上传方案,通过把文件切分成多个数据块,分多次HTTP请求上传到GCP Bucket,具体可参考https://cloud.google.com…...
chatGPT的prompt技巧
Prompt 公式是 Prompt 的特定格式,通常由三个主要元素组成: 任务:明确而简洁地陈述 Prompt 要求模型生成的内容。指令:模型在生成文本时应遵循的指令。角色:模型在生成文本时应扮演的角色。 指令 Prompt 技术 指令 …...
【华为OD机试 2023最新 】统一限载货物数最小值(C语言题解 100%)
文章目录 题目描述输入描述输出描述备注用例题目解析代码思路C语言题目描述 火车站附近的货物中转站负责将到站货物运往仓库,小明在中转站负责调度2K辆中转车(K辆干货中转车,K辆湿货中转车)。 货物由不同供货商从各地发来,各地的货物是依次进站,然后小明按照卸货顺序依…...
ios 在windows chrome 联调
必要条件 1、iOS设备、数据线 2、Node.js 环境 3、Chrome 浏览器 4、电脑登录iTunes 5、手机 Safari 浏览器环境准备 1、安装Node环境参考Node安装的教程,确保终端输入node时可正常使用 2、安装 scoope 以及相关配置为了安装后续需要用的工具 remotedebug-ios-web…...
干翻Mybatis源码系列之第六篇:Mybatis可选缓存概述
前言 一:后续Mybatis我们会研究那些内容? Mybatis核心运行源码分析(前面系列文章已经探讨过) Mybatis中缓存的使用 Mybatis与Spring集成 Mybatis 插件。 Mybatis的插件可以对Mybatis内核功能或者是业务功能进行拓展,…...
WordPress.com 托管/百度优化seo
A:一般来说,电脑音响多是有源音箱,其内部一定会存在放大器,所以噪音不可避免,有源音箱的噪音按来源大致可分为电磁干扰、机械噪声和热噪声等。电磁干扰主要可以分为电源变压器干扰和杂散电磁波干扰。一般来说ÿ…...
aspcms做双语网站修改配置/东莞网站制作公司联系方式
1. 1.js事项编程式跳转 2.在onload生命周期函数中接受参数 3. 调试接口请求必须是https协议,调试阶段可以设置不校验就可以用:...
dephi 网站开发/免费com域名注册网站
转载于:https://www.cnblogs.com/arci/p/11030173.html...
做速卖通代码的网站/黑帽seo排名
2019独角兽企业重金招聘Python工程师标准>>> 一、Aggregate简介 db.collection.aggregate()是基于数据处理的聚合管道,每个文档通过一个由多个阶段(stage)组成的管道,可以对每个阶段的管道进行分组、过滤等功能&#…...
中铁建设集团有限公司官方网站/百度指数的基本功能
因为虽然匿名内部类在方法的内部,但实际编译的时候,内部类编译成Outer.Inner,这说明内部类所处的位置和外部类中的方法处在同一个等级上,外部类中的方法中的变量或参数只是方法的局部变量,这些变量或参数的作用域只在这个方法内部…...
做网站怎样用链接赚钱/一键优化表格
作者:Autodesk中国公司 朱小羽 在2005年全球GIS市场总体增长仅为4%的情况下,Autodesk在这一领域中仍然实现了24%的增长率,远高于所有的主要竞争对手。更具有革命性意义的是,与竞争对手不同,Autodesk地理空间产品线从…...