基于格密码的LWE问题

news2024/10/6 6:47:52

LWE

LWE问题, Learning With Errors,带有安全性证明的第一个版本是由Oded Regev 在2005年提出,Kawachi等给出了效率的改进,接着一些效率方面非常重要的改进由Peikert等提出。

格理论知识

格密码学(Lattice-based Crypto)是现在比较火的一个密码学分支,而且本身拥有抵抗量子计算(最近几年征集的抗量子计算的密码大致有基于HASH函数的密码、基于纠错码的密码、基于格的密码、多变量二次方程组密码、秘密钥密码)的特性。

整数格:设 v 1 , ⋯   , v n ∈ R m v_1,\cdots,v_n \in \mathbb{R}^m v1,,vnRm为一组线性无关的向量。由 v 1 , ⋯   , v n v_1,\cdots,v_n v1,,vn生成的格 L L L指的是向量 v 1 , ⋯   , v n v_1,\cdots,v_n v1,,vn的线性组合构成的向量集合,且其所使用的系数均在 Z \mathbb{Z} Z中,即 L = { a 1 v 1 + a 2 v 2 + ⋯ + a n v n : a 1 , a 2 , ⋯   , a n ∈ Z } L= \{a_1v_1+a_2v_2+\cdots+a_nv_n:a_1,a_2,\cdots,a_n\in\mathbb{Z}\} L={a1v1+a2v2++anvn:a1,a2,,anZ}

L L L 的维数等于格中向量的个数。

假定 v 1 , v 2 , ⋯   , v n v_1,v_2,\cdots,v_n v1,v2,,vn 是格 L L L 的基, w 1 , w 2 , ⋯   , w n ∈ L w_1,w_2,\cdots,w_n \in L w1,w2,,wnL,则必然存在整系数 a i j a_{ij} aij 使得:

{ w 1 = a 11 v 1 + a 12 v 2 + ⋯ + a 1 n v n w 2 = a 21 v 1 + a 22 v 2 + ⋯ + a 2 n v n ⋮ w n = a n 1 v 1 + a n 2 v 2 + ⋯ + a n n v n \begin{cases} w_1=a_{11}v_1+a_{12}v_2+\cdots+a_{1n}v_n \\ w_2=a_{21}v_1+a_{22}v_2+\cdots+a_{2n}v_n \\ \vdots \\ w_n=a_{n1}v_1+a_{n2}v_2+\cdots+a_{nn}v_n \end{cases} w1=a11v1+a12v2++a1nvnw2=a21v1+a22v2++a2nvnwn=an1v1+an2v2++annvn

这样,格的问题就是矩阵运算了。

相关数学定义

定理3.1 L L L的任意两个基可以通过在左边乘上一个特定的矩阵来相互转化。这个矩阵是由整数构成的,并且它的行列式值为 ± 1 \pm1 ±1

定义3.2 所有向量的坐标都是整数的格称为整数格。等价地,当 m ≥ 1 m\ge1 m1时,整数格时 Z m \mathbb{Z}^m Zm的一个加法子群。

定义3.3 R m \mathbb{R}^m Rm的一个子集 L L L在加法和减法下是封闭的,则它是一个加法子群。如果再满足以下条件,那么它是一个离散加法子群:
存在一个常数 ε > 0 \varepsilon>0 ε>0,对任意 v ∈ L v \in L vL,有 L ⋂ { ω ∈ R m : ∣ ∣ ν − ω ∣ ∣ < ε } = { v } L\bigcap \{ \omega\in\mathbb{R}^m:||\nu-\omega||<\varepsilon\} = \{v\} L{ωRm:∣∣νω∣∣<ε}={v}
换句话说,如果在 L L L中任取一个向量 v v v,并以 v v v为圆心,以半径 ε \varepsilon ε画一个实心圆,那么 L L L中不会有别的点落在圆内。

定理3.2 R m \mathbb{R}^m Rm的一个子集是一个格,当且仅当它是一个离散加法子群。

定义3.4 L L L是一个维度为 n n n的格,且 v 1 , v 2 , … , v n v_1,v_2,…,v_n v1,v2,,vn L L L的基。对应于这个基的基础区域是如下向量的集合: F ( v 1 , v 2 , … , v n ) = { t 1 v 1 + t 2 v 2 + … + t n v n : 0 ≤ t i < 1 } F(v_1,v_2,…,v_n)=\{t_1v_1+t_2v_2+…+t_nv_n:0\le t_i <1\} F(v1,v2,,vn)={t1v1+t2v2++tnvn:0ti<1}

定理3.3 L ⊂ R n L\subset\mathbb{R}^n LRn是一个维度为n的格,且 F F F是它的基础区域。那么,对于任意向量 w ∈ R n w\in\mathbb{R}^n wRn,存在唯一的 t ∈ F t\in F tF和唯一的 v ∈ L v \in L vL,满足 w = t + v w=t+v w=t+v。也可写为 F + v = { t + v : t ∈ F } F+v = \{t+v:t\in F\} F+v={t+v:tF}

定义3.5 L L L是一个维度为n的格, F F F L L L的一个基础区域。 F F F的n维的体积称为 L L L的行列式(有时也成为协体积),记为 d e t L detL detL

难解问题

最短向量问题(SVP,The Shortest Vector Problem):

寻找一个格 L L L 中最短的非零向量。即,寻找一个 v ∈ L v \in L vL 满足其欧几里德范数 ∣ ∣ v ∣ ∣ \mid\mid v \mid\mid ∣∣v∣∣ 最小。

最接近向量问题(CVP,The Closest Vector Problem):

对于一个非格 L L L 中的向量 w w w,在格中寻找一个向量 v v v,使得 ∣ ∣ w − v ∣ ∣ \mid\mid w-v \mid\mid ∣∣wv∣∣ 最小。

CVP和SVP都是NP完备问题,因此求解起来十分困难,因此这两个问题都是可以作为密钥体制基础的。

LWE相关数学基础

LWE是一个CVP问题

在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述

LWE有搜索LWE(SLWE)和决策LWE(DLWE),SLWE最后的问题是需要我们找到s,而DLWE只需要让我们辨别看到的到底是LWE问题中的误差乘积还是一个随机生成的向量。

基于LWE的公钥密码体制

参数:n、m、l、t、r、q和一个实数 α \alpha α( α > 0 \alpha>0 α>0)

私钥:均匀随机的选取 S ∈ Z q n ∗ l S \in \mathbb{Z}^{n*l}_q SZqnl

公钥:均匀随机的选取 A ∈ Z q m ∗ n A \in \mathbb{Z}^{m*n}_q AZqmn E ∈ Z q m ∗ l E \in \mathbb{Z}^{m*l}_q EZqml。公钥是 ( A , P = A S + E ) ∈ Z q m ∗ n ∗ Z q m ∗ l (A,P=AS+E)\in \mathbb{Z}^{m*n}_q* \mathbb{Z}^{m*l}_q AP=AS+EZqmnZqml

加密:给定原文空间中一个元素 v ∈ Z t l v \in \mathbb{Z}^l_t vZtl,和一个公钥(A,P),均匀随机选取一个向量 a ∈ { − r , − r + 1 , … , r } m a \in \{-r,-r+1,…,r\}^m a{r,r+1,,r}m,然后输出一个密文( U = A T ∗ a , c = P T ∗ a + f ( v ) U = A^T*a,c = P^T*a+f(v) U=ATa,c=PTa+f(v) ∈ Z q n ∗ Z q l \in \mathbb{Z}^n_q* \mathbb{Z}^l_q ZqnZql

解密:给定一个密文 ( u , c ) ∈ Z q n ∗ Z q l (u,c)\in \mathbb{Z}^n_q* \mathbb{Z}^l_q (u,c)ZqnZql和一个私钥 S ∈ Z q n ∗ l S \in \mathbb{Z}^{n*l}_q SZqnl,输出 f − 1 ( c − s T u ) f^{-1}(c-s^Tu) f1(csTu)

这个密码体制中存在某个正的解密错误概率,这个概率可以通过选取适当的参数使得它变得很小。此外,在加密前如果一个纠错码被用来对一个信息进行编码,则错误概率可以被减少到不被发现的水平。(关于解密错误发生的概率评估详见《抗量子计算密码》)

ctf中出现的

随机选取一个矩阵 A ∈ Z q m ∗ n A \in \mathbb{Z}^{m*n}_q AZqmn,一个随机向量 s ∈ Z q n s \in \mathbb{Z}^n_q sZqn,和一个随机的噪音 e ∈ ε m e \in \varepsilon^m eεm

一个LWE系统的输出 g A ( s , e ) = A s + e m o d    q g_A(s,e) = As+e\mod q gA(s,e)=As+emodq

一个LWE问题是,给定一个矩阵A,和LWE系统的输出 g A ( s , e ) g_A(s,e) gA(s,e),还原s

(LWE的误差向量是一个满足正态分布的小向量)

因为加入了一些误差,如果使用高斯消元法的话,这些误差会聚集起来,使得解出来的东西跟实际值差很多。

求解

构造矩阵:
在这里插入图片描述

利用LLL算法Babai最近平面算法,可以在多项式时间内找到SVP近似解。

利用Embedding Technique构造一个Embedding Lattice,也可以解SVP。

LLL算法

高斯提出了如果在二维格中找到一组优质基的算法,这个算法的基本思想是从一个基向量中交替减去另一个基向量的倍数,直到没有更好的改进为止。(所谓没有更好的改进就是要满足算法中一个特定的条件要求):

高斯格基约减算法

输入:格L的一组基 v 1 v_1 v1 v 2 v_2 v2

输出:一组具有良好正交性的基向量

  1. 循环

  2. 如果 ∥ v 2 ∥ < ∥ v 1 ∥ \parallel v_2\parallel<\parallel v_1\parallel v2∥<∥v1,交换 v 1 和 v 2 v_1和v_2 v1v2

  3. 计算 m = ⌈ v 1 ∗ v 2 ∥ v 1 ∥ 2 ⌋ m = \left\lceil\frac{v_1*v_2}{\parallel v1\parallel^2}\right\rfloor m=v12v1v2(计算施密特正交化的系数)

  4. 如果m = 0,返回基向量 v 1 v_1 v1 v 2 v_2 v2

  5. v 2 − m v 1 v_2 - mv_1 v2mv1替换 v 2 v_2 v2

  6. 继续循环

更准确的说,当这个算法终止的时候,向量 v 1 v_1 v1就是格L中最短的非零向量,因此说这个算法可以很好的解决SVP问题

sagemath代码

def Gauss(x,y):
    # step 1
    v1 = x; v2 = y
    finished = False
    # step 2
    while not finished:
        # (a)
        m = round(( v2.dot_product(v1) / v1.dot_product(v1) ))
        # (b)
        v2 = v2 - m*v1
        # (c)
        if v1.norm() <= v2.norm():
            finished = True
        else:
            v1, v2 = v2, v1
    
   return v1, v2

LLL算法

1982年诞生的LLL算法可视为高斯算法在高维格中的推广

该算法可以解决某些维数较低的格中的SVP和CVP问题。但随着格的维数的增高,该算法的运行效果也随之减弱,以至于对于高维格来说,即使应用LLL算法,也无法很好的解决SVP和CVP问题。所以大多数基于格理论的密码系统的安全性,都依赖LLL算法以及其他格基约减算法能否高效解决apprSVP(近似最短向量问题)或apprCVP(近似最接近向量问题)问题的困难性。

用LLL约化基需要这组基满足两个条件:

1.size-reduce:对于所有的 1 ≤ j < i ≤ n 1 ≤ j < i ≤ n 1j<in,有 ∣ μ i , j ∣ ≤ 1 2 |\mu_{i,j}| \le \frac{1}{2} μi,j21 μ i , j = ∣ v i ∗ v j ∗ ∣ ∣ ∣ v j ∗ ∣ ∣ \mu_{i,j}=\frac{|v_i*v_j^*|}{||v_j^*||} μi,j=∣∣vj∣∣vivj为施密特正交化中的系数。

2.Lovász condition:对于所有的 1 < i ≤ n 1< i ≤ n 1<in ∣ ∣ v i ∗ ∣ ∣ 2 ≥ ( 3 4 − μ i , i − 1 2 ) ∣ ∣ v i − 1 ∗ ∣ ∣ 2 ||v_i^*||^2\ge(\frac{3}{4}-\mu^2_{i,i-1})||v_{i-1}^*||^2 ∣∣vi2(43μi,i12)∣∣vi12成立

img

sagemath代码简单实现:

def max(a, b):
    return a if a > b else b

def LLL_v0(M, delta=0.75):
    B = deepcopy(M)
    Q, mu = B.gram_schmidt()
    n, k = B.nrows(), 1
    
    while k < n:
        
        # size reduction step
        for j in reversed(range(k)):
            if abs( mu[k][j] ) > 0.5:
                B[k] = B[k] - round( mu[k][j] ) * B[j]
                Q, mu = B.gram_schmidt()
        
        # swap step 
        if Q[k].dot_product(Q[k]) >= (delta - mu[k][k-1]^2) * Q[k-1].dot_product(Q[k-1]):
            k = k + 1
        else:
            B[k], B[k-1] = B[k-1], B[k]
            Q, mu = B.gram_schmidt()
            k = max(k-1,1)
    
    return B 

常规实现

在进行一次交换步或约化步之后,实际上只需要修改 μ \mu μ(施密特正交化系数)和Q(正交向量组)的个别值。而简易实现中,每次都会重新计算整个施密特正交化,这样的实现是低效的。

def LLL_v1(M, delta=0.75):

    if delta < 0.25:
        print("delta should be greater than 0.25. Choose delta = 0.75 now.")
    alpha = delta if 0.25 < delta < 1 else 0.75
    
    x = M
    n = M.nrows()
    
    def reduce(k, l):
        do_reduce = False
                   
        if abs(mu[k,l]) > 0.5:
            do_reduce = True
            
            y[k] = y[k] - mu[k,l].round() * y[l]
            for j in range(l):
                mu[k,j] -=  mu[k,l].round() * mu[l,j]
            mu[k,l] = mu[k,l] - mu[k,l].round()       

        return
    
    def exchange(k):
        
        y[k-1], y[k] = y[k], y[k-1]
        NU = mu[k,k-1]
        delta = gamma[k] + NU ^ 2 * gamma[k-1]
        mu[k,k-1] = NU * gamma[k-1] / delta    # all above is right
        gamma[k] = gamma[k] * gamma[k-1] / delta
        gamma[k-1] = delta

        for j in range(k-1):
            mu[k-1,j], mu[k,j] = mu[k,j], mu[k-1,j]
        for i in range(k+1, n):
            xi = mu[i,k]
            mu[i,k] = mu[i,k-1] - NU * mu[i,k]
            mu[i,k-1] = mu[k,k-1] * mu[i,k] + xi      
            
        return
    
    # step (1) 
    y = deepcopy(x)
    # step (2) 
    y_star, mu = y.gram_schmidt()
    gamma = [y_star[i].norm() ^ 2 for i in range(n)]
    
    # step (3)
    k = 1
    
    # step (4)
    while k < n:      
        # step (4)(a)    
        reduce(k, k-1)

        # step (4)(b)
        if gamma[k] >= (alpha - mu[k,k-1]^2) * gamma[k-1]:
            # (i)
            for l in reversed(range(k-1)):
                reduce(k, l)
            # (ii)
            k = k + 1
        else:
            # (iii)
            exchange(k)
            # (iv)
            if k > 1:
                k = k-1

    return y

Babai最近平面算法

该算法主要由两步。第一步针对输入的格,输出LLL约化基;此时针对此约化基向量,形成整数线性组合,来保证与给定的向量t足够近。这个步骤跟LLL算法的内循环约化操作很类似

img

def BabaisClosestPlaneAlgorithm(L, w):
    '''
    Yet another method to solve apprCVP, using a given good basis.
    INPUT:
    * "L" -- a matrix representing the LLL-reduced basis (v1, ..., vn) of a lattice.
    * "w" -- a target vector to approach to.
    OUTPUT:
    * "v" -- a approximate closest vector.
    Quoted from "An Introduction to Mathematical Cryptography":
    In both theory and practice, Babai's closest plane algorithm
    seems to yield better results than Babai's closest vertex algorithm.
    '''
    G, _ = L.gram_schmidt()
    t = w
    i = L.nrows() - 1
    while i >= 0:
        w -= round( (w*G[i]) / G[i].norm()^2 ) * L[i]
        i -= 1
    return t - w

Embedding Technique

(不会用软件画图所有写纸上了,回头整理却找不到博客了,凑合看吧)

在这里插入图片描述
在这里插入图片描述

解题代码

例1:2020祥云杯 Easy Matrix

import numpy as np
from secret import *

def random_offset(size):
    x = np.random.normal(0, 4.7873, size)
    return np.rint(x)

secret = np.array(list(flag))

column = len(list(secret))
row = 128
prime = 2129

matrix = np.random.randint(512, size=(row, column))
product = matrix.dot(secret) % prime
offset = random_offset(size=row).astype(np.int64)
result = (product + offset) % prime

np.save("matrix.npy", matrix)
np.save("result.npy", result)

利用LLL算法和Babai最近平面算法

import numpy as np
from sage.modules.free_module_integer import IntegerLattice

def BabaisClosestPlaneAlgorithm(L, w):
    G, _ = L.gram_schmidt()
    t = w
    i = L.nrows() - 1
    while i >= 0:
        w -= round( (w*G[i]) / G[i].norm()^2 ) * L[i]
        i -= 1
    return t - w

row = 128
col = 42
p = 2129

M = Matrix(list(np.load('matrix.npy')))
R = vector(list(np.load('result.npy')))

A = [[0 for _ in range(row)] for _ in range(row)]
for i in range(128):
    for j in range(128):
        if i==j:
            A[i][j] = p
A = Matrix(A)
L = Matrix(A.stack(M.transpose()))
lattice = IntegerLattice(L, lll_reduce=True)
closest_vector = BabaisClosestPlaneAlgorithm(lattice.reduced_basis, R)

FLAG = Matrix(Zmod(p), M)
flag = FLAG.solve_right(closest_vector)
print(''.join( chr(i) for i in flag))

例2:利用Embedding Technique构造一个Embedding Lattice的代码

# Sage
DEBUG = False
m = 44
n = 55
p = 2^5
q = 2^10

def errorV():
  return vector(ZZ, [1 - randrange(3) for _ in range(n)])

def vecM():
  return vector(ZZ, [p//2 - randrange(p) for _ in range(m)])

def vecN():
  return vector(ZZ, [p//2 - randrange(p) for _ in range(n)])

def matrixMn():
  mt = matrix(ZZ, [[q//2 - randrange(q) for _ in range(n)] for _ in range(m)])
  return mt

A = matrixMn()
e = errorV()
x = vecM()
b = x*A+e

if DEBUG:
  print('A = \n%s' % A)
  print('x = %s' % x)
  print('b = %s' % b)
print('e = %s' % e)

z = matrix(ZZ, [0 for _ in range(m)]).transpose()
beta = matrix(ZZ, [1])
T = block_matrix([[A, z], [matrix(b), beta]])
if DEBUG:
  print('T = \n%s' % T)

print('-----')
L = T.LLL()
print(L[0])
print(L[0][:n] == e)

应用

GSW系统的构造就主要是基于格密码学中的LWE问题假设

其他格相关加密

GGH、NTRU

参考

https://lazzzaro.github.io/2020/11/07/crypto-%E6%A0%BC%E5%AF%86%E7%A0%81/

https://zhuanlan.zhihu.com/p/150920501

https://blog.csdn.net/qq_42667481/article/details/118332181

http://blog.k1rit0.eu.org/2021/03/31/The-learning-of-LWE/

《格理论与密码学》

《抗量子计算密码》

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

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

相关文章

PTA L1-093 猜帽子游戏 (15 分)

宝宝们在一起玩一个猜帽子游戏。每人头上被扣了一顶帽子&#xff0c;有的是黑色的&#xff0c;有的是黄色的。每个人可以看到别人头上的帽子&#xff0c;但是看不到自己的。游戏开始后&#xff0c;每个人可以猜自己头上的帽子是什么颜色&#xff0c;或者可以弃权不猜。如果没有…

机器学习算法 决策树

文章目录 一、决策树的原理二、决策树的构建2.1 ID3算法构建决策树2.2 C4.5 算法树的构建2.3 CART 树的创建 三、决策树的优缺点 一、决策树的原理 决策树&#xff08;Decision Tree&#xff09;是一种非参数的有监督学习方法&#xff0c;它能够从一系列有特征和标签的数据中总…

NDK OpenCV人脸定位

NDK系列之OpenCV人脸定位技术实战&#xff0c;本节主要是通过OpenCV C库&#xff0c;实现识别人脸定位&#xff0c;并对识别到的人脸画面增加红框显示。 实现效果&#xff1a; 实现逻辑&#xff1a; 1.初始化CameraX&#xff0c;绑定图片分析器ImageAnalysis&#xff0c;监听…

7.队列算法

算法&#xff1a;队列算法 队列是一种抽象的数据结构&#xff0c;有点类似于Stacks。与堆栈不同&#xff0c;队列的两端都是开放的。一端始终用于插入数据(入队)&#xff0c;另一端用于删除数据(出队)。队列遵循先进先出方法&#xff0c;即首先访问先存储的数据项。 一个真实的…

【C++初阶】类与对象(上)

一.什么是类&#xff0c;什么是对象 我们可以形象的把类比作是一个房子的设计图纸&#xff0c;而对象就是根据设计图纸设计出来的房子。 由设计图纸到房子的过程&#xff0c;我们称之为类的实例化。 C兼容C的&#xff0c;所以C中的结构体在C中也能用&#xff0c;但是C把结构体升…

rust教程 第一章 —— 初识rust

文章目录 前言一、Rust简介二、安装Rust编译器三、第一个Rust程序四、 IDE环境五、初识包管理六、总结 前言 本系列教程目录可查看这里&#xff1a;Rust教程目录 近些年来不断有新的语言崛起&#xff0c;比如当下非常火的go语言&#xff0c;不过相比于C&#xff0c;go语言确实…

C++类和对象 (3)

类和对象 1. 类的6个默认成员函数2. 构造函数2.1. 概念&#xff08;问题提出&#xff09;2.2. 特性 3.析构函数3.1. 概念3.2.特性 1. 类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在…

使用OpenFeign实现接口访问

1. 引言 在微服务横行的年代&#xff0c;后端根据业务的不一样分成了很多单独运行的服务&#xff0c;比如在物联网中&#xff0c;根据业务拆分为定时服务、设备控制等服务。当前端想控制设备时&#xff0c;其请求首先到其对应的后端服务&#xff0c;后端服务再调用设备控制服务…

Vue+Vant封装通用模态框单选框组件

前言 我们知道&#xff0c;在vant组件中提供的组件往往是比较基础的&#xff0c;能够满足基本需求。但是我们想实现ui设计的一些比较丰富效果的组件&#xff0c;需要自己去实现&#xff0c;且当项目中多次用到的时候&#xff0c;我们将以组件化的思想将其封装起来&#xff0c;…

Node.js -- 使用Express写接口

1.创建基本的服务器 //导入express const express require(express) //创建服务器实例 const app express() //调用app.listen方法&#xff0c;指定端口号并启动web服务器 app.listen(80,function(){console.log(Express server running at http://127.0.0.1) })2. 创建API路…

路由交换综合实验

拓扑结构&#xff1a; 要求 1、R6为网络运营商&#xff08;ISP&#xff09;&#xff0c;接口IP地址均为公有地址&#xff1b;该设备只能配置IP地址&#xff0c;之后不能在对其进行任何配置&#xff1b; 2、R1~R5为局域网&#xff0c;私有IP地址192.168.1.0/24&#xff0c;请合…

真题详解(UML图)-软件设计(五十五)

真题详解&#xff08;计算机知识&#xff09;-软件设计&#xff08;五十四)https://blog.csdn.net/ke1ying/article/details/130278265 组织域名&#xff1a; com商业组织 edu教育组织 gov政府组织 net主要网络支持中心 mil军事部门 Int国际组织 2、时间复杂度 O&#…

写一个自己的命令行解释器

写一个自己的命令行解释器 当我点开xshell运行服务器的时候bash就被加载到了内存中&#xff0c;此后我在bash上执行的所有程序都是作为bash的子进程。在bash这个进程内创建子进程&#xff0c;并让子进程去执行全新的代码&#xff0c;这不就是程序替换吗&#xff1f; 所以我们…

腾讯云4核8g服务器支持多少人在线使用?

腾讯云轻量4核8G12M轻量应用服务器支持多少人同时在线&#xff1f;通用型-4核8G-180G-2000G&#xff0c;2000GB月流量&#xff0c;系统盘为180GB SSD盘&#xff0c;12M公网带宽&#xff0c;下载速度峰值为1536KB/s&#xff0c;即1.5M/秒&#xff0c;假设网站内页平均大小为60KB…

【Unity入门】17.脚本访问父子结点

【Unity入门】脚本访问父子结点 大家好&#xff0c;我是Lampard~~ 欢迎来到Unity入门系列博客&#xff0c;所学知识来自B站阿发老师~感谢 &#xff08;一&#xff09;父级节点 &#xff08;1&#xff09;访问父级节点 父子关系我们并不陌生&#xff0c;在cocos中常用node:get…

单链表的实现

链表的概念与结构 链表与我们通讯录中的顺序表是不同的&#xff0c;顺序表的空间是连续的&#xff0c;像数组一样可以通过下标访问。而链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。即&#xff1a;链表…

数据结构笔记:二叉树的遍历与技巧

引言 本篇是最近有遇到过的一个题目&#xff0c;关于二叉树的遍历&#xff0c;正好有一些经验与技巧&#xff0c;所以开一篇帖子记录一下。 二叉树遍历介绍 遍历是数据结构中常见的操作&#xff0c;主要是将所有元素都访问一遍。对于线性结构来说&#xff0c;遍历分为两种&a…

RecyclerView 静态布局实现过程解析:如何构建高性能的列表

作者&#xff1a;maxcion Recyclerview在日常开发中所使用的控件中绝对是顶流一般的存在&#xff0c;想嚼它这个想法一次两次了。在网上也看了很多关于Recyclerview源码解析的文章&#xff0c;大佬们写的都很深刻&#xff0c;但是对于像我们这种储备知识不足的小白读者来说&…

前端实现端到端测试(代码版)

端到端测试框架选取 playwright 、 cypress 、 selenium 对比 cypress使用 下载 cypress npm install cypress --save-dev package.json npm run cypress:open {"scripts": {"cypress:open": "cypress open"} }使用流程 入门官方文档 npm ru…

一本通 3.4.5 最小生成树

1348&#xff1a;【例4-9】城市公交网建设问题 【题目描述】 有一张城市地图&#xff0c;图中的顶点为城市&#xff0c;无向边代表两个城市间的连通关系&#xff0c;边上的权为在这两个城市之间修建高速公路的造价&#xff0c;研究后发现&#xff0c;这个地图有一个特点&…