CKKS EXPLAINED, PART 3: ENCRYPTION AND DECRYPTION

CKKS EXPLAINED, PART 3: ENCRYPTION AND DECRYPTION

Introduction

在之前的文章中,CKKS解释了第二部分:完整的编码和解码,我们看到了如何实现CKKS的编码器和解码器,这使我们能够将向量转换为多项式,反之亦然。这一步骤是必要的,因为我们将看到,与直接使用向量相比,使用多项式来构建同态加密方案要高效得多。

在本文中,我们将看到如何利用困难问题,如LWE或RLWE来构建一个近似同态加密方案。CKKS使用近似算术而不是精确算术,这意味着一旦我们完成计算,我们可能会得到一个略有不同于直接进行计算的结果。这意味着如果您加密了2和3,将它们的密文相加,然后解密,您可能会得到类似于4.99或5.01但不是5的结果。而其他方案,如BFV是精确的,这意味着它们将产生确切的5。

那么为什么要使用CKKS呢?CKKS更适用于实数上的算术运算,其中我们可以得到近似但接近的结果,而BFV更适用于整数上的算术运算。

在本文中,我们将看到如何利用LWE和RLWE实现近似算术同态加密方案的加密和解密过程。

Learning with Error

CKKS是一种公钥加密方案,其中生成了一个秘钥对,包括一个私钥和一个公钥。公钥用于加密并可以共享,而私钥用于解密并必须保密。

LWE(Learning With Error)是CKKS的基础,也是许多其他同态加密方案的基础之一。LWE问题最初由Regev在论文《On lattices, learning with errors, random linear codes, and cryptography》中引入。LWE问题是要区分形式为 ( a i , b i ) = ( a i , ⟨ a i , s ⟩ + e i ) (a_i, b_i) = (a_i, \langle a_i, s \rangle + e_i) (ai,bi)=(ai,ai,s+ei) 的带噪声对和 Z q n × Z q \mathbb{Z}_q^n\times\mathbb{Z}_q Zqn×Zq中真正随机的对。这里 a i , s ∈ Z q n a_i, s \in \mathbb{Z}_q^n ai,sZqn a i a_i ai 是均匀采样的, s s s 是我们的秘密, e i ∈ Z q e_i \in \mathbb{Z}_q eiZq 是小的噪声,通常是高斯分布的,用于增加问题的难度。如果不引入 e i e_i ei,解决这个线性系统将会变得容易得多,因为我们可以使用高斯消元法来解决线性系统。

Z q n × Z q \mathbb{Z}_q^n\times\mathbb{Z}_q Zqn×Zq 表示一个元素由两部分组成的集合,其中第一部分是长度为 n n n 的整数向量,每个分量都来自于模 q q q 的整数集合 Z q \mathbb{Z}_q Zq,第二部分是一个整数,同样来自于模 q q q 的整数集合 Z q \mathbb{Z}_q Zq

具体来说, Z q n × Z q \mathbb{Z}_q^n\times\mathbb{Z}_q Zqn×Zq 可以表示为:

Z q n × Z q = { ( x 1 , x 2 , … , x n , y ) ∣ x i ∈ Z q , y ∈ Z q } \mathbb{Z}_q^n\times\mathbb{Z}_q = \{(x_1, x_2, \ldots, x_n, y) \mid x_i \in \mathbb{Z}_q, y \in \mathbb{Z}_q\} Zqn×Zq={(x1,x2,,xn,y)xiZq,yZq}

其中 x 1 , x 2 , … , x n x_1, x_2, \ldots, x_n x1,x2,,xn 是整数向量的分量,每个分量都来自于模 q q q 的整数集合 Z q \mathbb{Z}_q Zq y y y 是一个整数,同样来自于模 q q q 的整数集合 Z q \mathbb{Z}_q Zq

LWE问题的目标是区分形式为 ( a i , b i ) = ( a i , ⟨ a i , s ⟩ + e i ) (a_i, b_i) = (a_i, \langle a_i, s \rangle + e_i) (ai,bi)=(ai,ai,s+ei) 的带噪声对和 Z q n × Z q \mathbb{Z}_q^n\times\mathbb{Z}_q Zqn×Zq中真正随机的对。

在LWE问题中,我们有一组带噪声的对 ( a i , b i ) (a_i, b_i) (ai,bi),其中 a i a_i ai 是长度为 n n n 的向量, b i b_i bi 是一个整数。这些带噪声的对是通过选择秘密向量 s s s,生成矩阵 A = ( a 1 , … , a m ) A=(a_1,\ldots,a_m) A=(a1,,am),并添加噪声项 e i e_i ei 来构造的。

对于每个带噪声的对 ( a i , b i ) (a_i, b_i) (ai,bi),其中 a i a_i ai 是随机选择的向量, b i b_i bi 是通过将 a i a_i ai 与秘密向量 s s s 的内积加上噪声项 e i e_i ei 计算得到的。噪声项 e i e_i ei 是从特定分布中生成的随机数,通常是一个小的扰动项。

与此相对, Z q n × Z q \mathbb{Z}_q^n\times\mathbb{Z}_q Zqn×Zq 表示一个集合,其中元素是由长度为 n n n 的向量和一个整数组成的对。在这个集合中,向量和整数的取值是完全独立的,没有任何关联性。

LWE问题的目标是通过观察一组带噪声的对 ( a i , b i ) (a_i, b_i) (ai,bi) 来区分它们是否是由秘密向量 s s s 生成的。换句话说,我们需要确定给定的带噪声对是来自于LWE构造还是来自于纯随机的对。这种区分能力是LWE问题的核心,而解决LWE问题的算法将能够从带噪声的对中恢复出秘密向量 s s s 的近似。

example

假设我们有一个模数 q = 7 q = 7 q=7,向量维度 n = 3 n = 3 n=3,并且我们希望生成一个带噪声的对 ( a i , b i ) (a_i, b_i) (ai,bi),其中 a i a_i ai 是长度为 n n n 的向量, b i b_i bi 是一个整数。

首先,我们随机选择一个秘密向量 s = ( 2 , 4 , 1 ) s = (2, 4, 1) s=(2,4,1),其中每个分量都来自于模 q q q 的整数集合 Z q \mathbb{Z}_q Zq。然后,我们生成一个噪声项 e i e_i ei,该项满足特定的噪声分布。在这个例子中,我们假设 e i e_i ei 是从均值为0、方差为2的离散高斯分布中生成的。

现在,我们生成带噪声的对 ( a i , b i ) (a_i, b_i) (ai,bi)。对于每个 i i i,我们随机选择向量 a i a_i ai,其中每个分量 a i , j a_{i,j} ai,j 都是从模 q q q 的整数集合 Z q \mathbb{Z}_q Zq 中随机选择的。然后,我们计算 b i = ⟨ a i , s ⟩ + e i b_i = \langle a_i, s \rangle + e_i bi=ai,s+ei,其中 ⟨ ⋅ , ⋅ ⟩ \langle\cdot,\cdot\rangle , 表示向量的内积。

让我们通过一个具体的例子来说明:

假设我们生成的随机向量 a i a_i ai 如下:

  • a 1 = ( 3 , 6 , 4 ) a_1 = (3, 6, 4) a1=(3,6,4)
  • a 2 = ( 2 , 3 , 5 ) a_2 = (2, 3, 5) a2=(2,3,5)

对于这两个向量,我们计算相应的 b i b_i bi

  • b 1 = ⟨ a 1 , s ⟩ + e 1 = ( 3 ⋅ 2 + 6 ⋅ 4 + 4 ⋅ 1 ) + e 1 = 29 + e 1 b_1 = \langle a_1, s \rangle + e_1 = (3 \cdot 2 + 6 \cdot 4 + 4 \cdot 1) + e_1 = 29 + e_1 b1=a1,s+e1=(32+64+41)+e1=29+e1
  • b 2 = ⟨ a 2 , s ⟩ + e 2 = ( 2 ⋅ 2 + 3 ⋅ 4 + 5 ⋅ 1 ) + e 2 = 23 + e 2 b_2 = \langle a_2, s \rangle + e_2 = (2 \cdot 2 + 3 \cdot 4 + 5 \cdot 1) + e_2 = 23 + e_2 b2=a2,s+e2=(22+34+51)+e2=23+e2

在这个例子中, e 1 e_1 e1 e 2 e_2 e2 是从离散高斯分布中生成的随机噪声项。

这样,我们就得到了两个带噪声的对 ( a 1 , b 1 ) (a_1, b_1) (a1,b1) ( a 2 , b 2 ) (a_2, b_2) (a2,b2),其中 a 1 , a 2 a_1, a_2 a1,a2 是长度为 3 的向量, b 1 , b 2 b_1, b_2 b1,b2 是整数。通过解决LWE问题,我们的目标是从这些带噪声的对中学习到秘密向量 s s s 的近似。

LWE问题被认为与最坏情况的格问题一样困难,目前对来自量子计算机的攻击是安全的。因此,我们可以利用从 ( a i , ⟨ a i , s ⟩ + e i ) (a_i,\langle a_i, s \rangle + e_i) (ai,ai,s+ei) 对中找到秘密 s s s 的难度,并基于此构建一个加密系统。

假设我们已生成了一个保密的秘钥 s ∈ Z q n s \in \mathbb{Z}_q^n sZqn,并发布了 n n n 对形式为 ( a i , ⟨ a i , s ⟩ + e i ) (a_i,\langle a_i, s \rangle + e_i) (ai,ai,s+ei) 的对,可以写成矩阵形式为 ( A , A ⋅ s + e ) (A,A \cdot s + e) (A,As+e),其中 A ∈ Z q n × n A\in\mathbb{Z}_q^{n\times n} AZqn×n e ∈ Z q n e \in \mathbb{Z}_q^n eZqn。正如LWE问题所述,从这个对中恢复秘密钥是困难的,因此我们可以利用它来创建一个公钥。

实际上,我们将使用 p = ( − A ⋅ s + e , A ) p=(-A \cdot s + e,A) p=(As+e,A) 作为我们的公钥,可以公开使用,因为很难从中提取出秘密钥。我们选择存储 − A ⋅ s -A \cdot s As 而不是 A ⋅ s A \cdot s As 是为了方便,但这并不改变问题。

然后,为了使用公钥和私钥加密和解密一个消息 μ ∈ Z q n \mu \in \mathbb{Z}_q^n μZqn,我们可以使用以下方案:

  • 使用公钥 p p p μ \mu μ进行加密:输出 c = ( μ , 0 ) + p = ( μ − A ⋅ s + e , A ) = ( c 0 , c 1 ) c = (\mu, 0) + p = (\mu - A \cdot s + e, A) = (c_0, c_1) c=(μ,0)+p=(μAs+e,A)=(c0,c1)
  • 使用私钥 s s s c c c进行解密:输出 μ ~ = c 0 + c 1 . s = μ − A . s + e + A . s = μ + e ≈ μ \tilde{\mu}=c_0+c_1.s=\mu-A.s+e+A.s=\mu+e\approx\mu μ~=c0+c1.s=μA.s+e+A.s=μ+eμ

因此,在加密阶段,我们使用公钥来对消息 μ \mu μ进行掩码。因此,消息被隐藏在密文的第一个坐标中,使用了掩码 − A ⋅ s -A \cdot s As。请记住, A A A是均匀采样的,因此它确实会有效地掩盖 μ \mu μ。要移除掩码,我们可以使用 c c c的第二个坐标,其中仅存储了 A A A,并将其与私钥 s s s结合以获得解密结果 μ + e \mu + e μ+e。注意,这里我们并没有得到原始消息 μ \mu μ,而是 μ \mu μ加上一些噪音 e e e,这就是为什么我们说我们有一个近似算术方案。如果 e e e足够小,那么解密结果将接近于原始的 μ \mu μ

因此,我们已经看到如何利用 LWE 问题构建一个安全防御量子攻击的公共加密方案。上述实现的问题在于,虽然秘密密钥的大小为 O ( n ) \mathcal{O}(n) O(n),但由于矩阵 A A A的存在,公钥的大小为 O ( n 2 ) \mathcal{O}(n^2) O(n2),并且计算也需要 O ( n 2 ) \mathcal{O}(n^2) O(n2)次操作。因为 n n n将决定我们方案的安全性,如果我们使用 LWE 构建我们的方案,它在实践中将会太低效,因为密钥的 O ( n 2 ) \mathcal{O}(n^2) O(n2)大小和复杂度将使其太不实际。

Ring Learning with Error

因此,我们将考虑《On Ideal Lattices and Learning with Errors Over Rings》中介绍的Ring Learning With Error(RLWE)问题,它是LWE在环上的一种变体。我们不再使用 Z q n \mathbb{Z}_q^n Zqn中的向量,而是在 Z q [ X ] / ( X N + 1 ) \mathbb{Z}_q[X]/(X^N+1) Zq[X]/(XN+1)中使用多项式进行计算(这里假设 N N N是2的幂)。现在我们从 Z q [ X ] / ( X N + 1 ) \mathbb{Z}_q[X]/(X^N+1) Zq[X]/(XN+1)中随机选择多项式 a a a s s s e e e,其中 a a a仍然是均匀采样的, s s s是一个小的秘密多项式, e e e是一个小的噪声多项式。转向RLWE有两个主要优势:

  1. 密钥大小不再是二次的,而是线性的,因为我们现在输出公钥 p = ( − a ⋅ s + e , a ) p=(-a\cdot s+e,a) p=(as+e,a),其中 a ⋅ s a\cdot s as表示 a a a s s s的多项式乘积。由于所有操作都是在多项式之间进行的,私钥和公钥的大小都是 O ( n ) \mathcal{O}(n) O(n)
  2. 乘法是在多项式上进行的,因此可以使用离散傅立叶变换进行多项式乘法,复杂度为 O ( n log ⁡ ( n ) ) \mathcal{O}(n\log(n)) O(nlog(n)),而不是 O ( n 2 ) \mathcal{O}(n^2) O(n2),因为我们需要进行矩阵-向量乘法。

因此,通过使用RLWE而不是LWE,我们可以获得更小的密钥,并且操作速度更快,因此前面的方案变得更加实用。此外,RLWE仍然是一个困难问题,并提供强大的安全性保证,因此使用RLWE仍然提供了一个安全的方案。

现在我们明白了为什么使用多项式是重要的,因为它们为高效和安全的方案提供了基础。因此,现在你可以理解为什么我们要费力地将向量转换为 Z q [ X ] / ( X N + 1 ) \mathbb{Z}_q[X]/(X^N+1) Zq[X]/(XN+1)中的多项式,反之亦然,因为我们现在可以利用多项式环的代数结构。

假设我们有一个RLWE方案,其中我们在环 Z q [ X ] / ( X 4 + 1 ) \mathbb{Z}_q[X]/(X^4 + 1) Zq[X]/(X4+1)上进行计算, q q q是我们的模量。我们希望生成一个公钥和一个私钥来加密和解密消息。

  1. 密钥生成:

    • 我们首先随机选择一个小的秘密多项式 s = 3 X 2 + 2 X + 1 s = 3X^2 + 2X + 1 s=3X2+2X+1 和一个小的噪声多项式 e = X 3 + X 2 + 2 X + 1 e = X^3 + X^2 + 2X + 1 e=X3+X2+2X+1

    • 然后我们随机选择一个多项式 a = X 3 + 2 X 2 + X + 1 a = X^3 + 2X^2 + X + 1 a=X3+2X2+X+1,这个多项式仍然是均匀采样的。

    • 我们计算公钥 p = ( − a ⋅ s + e , a ) p = (-a \cdot s + e, a) p=(as+e,a)。首先,计算 − a ⋅ s = − ( X 3 + 2 X 2 + X + 1 ) ⋅ ( 3 X 2 + 2 X + 1 ) -a \cdot s = -(X^3 + 2X^2 + X + 1) \cdot (3X^2 + 2X + 1) as=(X3+2X2+X+1)(3X2+2X+1),得到 − a ⋅ s = − 3 X 5 − 5 X 4 − 3 X 3 − X 2 − 2 X − 1 -a \cdot s = -3X^5 - 5X^4 - 3X^3 - X^2 - 2X - 1 as=3X55X43X3X22X1,然后加上噪声多项式 e e e,得到 − a ⋅ s + e = − 3 X 5 − 5 X 4 − 3 X 3 − 2 X 2 − X -a \cdot s + e = -3X^5 - 5X^4 - 3X^3 - 2X^2 - X as+e=3X55X43X32X2X。公钥 p p p 就是这个结果和 a a a 的组合,即 p = ( − 3 X 5 − 5 X 4 − 3 X 3 − 2 X 2 − X , X 3 + 2 X 2 + X + 1 ) p = (-3X^5 - 5X^4 - 3X^3 - 2X^2 - X, X^3 + 2X^2 + X + 1) p=(3X55X43X32X2X,X3+2X2+X+1)

  2. 加密:

    假设我们有一个消息 μ = 2 X 2 + X + 1 \mu = 2X^2 + X + 1 μ=2X2+X+1,我们希望将其加密。我们随机选择一个小的噪声多项式 e ′ = X 2 + 1 e' = X^2 + 1 e=X2+1

    我们计算密文 c = ( μ − a ⋅ s + e ′ , a ) c = (\mu - a \cdot s + e', a) c=(μas+e,a)。首先,计算 μ − a ⋅ s = ( 2 X 2 + X + 1 ) − ( X 3 + 2 X 2 + X + 1 ) ⋅ ( 3 X 2 + 2 X + 1 ) \mu - a \cdot s = (2X^2 + X + 1) - (X^3 + 2X^2 + X + 1) \cdot (3X^2 + 2X + 1) μas=(2X2+X+1)(X3+2X2+X+1)(3X2+2X+1),得到 μ − a ⋅ s = − 3 X 6 − 3 X 5 − 2 X 4 − 2 X 3 − X 2 \mu - a \cdot s = -3X^6 - 3X^5 - 2X^4 - 2X^3 - X^2 μas=3X63X52X42X3X2,然后加上噪声多项式 e ′ e' e,得到 μ − a ⋅ s + e ′ = − 3 X 6 − 3 X 5 − 2 X 4 − X 3 − X 2 + 1 \mu - a \cdot s + e' = -3X^6 - 3X^5 - 2X^4 - X^3 - X^2 + 1 μas+e=3X63X52X4X3X2+1。密文 c c c 就是这个结果和 a a a 的组合,即 c = ( − 3 X 6 − 3 X 5 − 2 X 4 − X 3 − X 2 + 1 , X 3 + 2 X 2 + X + 1 ) c = (-3X^6 - 3X^5 - 2X^4 - X^3 - X^2 + 1, X^3 + 2X^2 + X + 1) c=(3X63X52X4X3X2+1,X3+2X2+X+1)

  3. 解密:

    使用私钥 s s s 对密文 c c c 进行解密。解密过程为 μ ′ = c 0 + c 1 ⋅ s \mu' = c_0 + c_1 \cdot s μ=c0+c1s。将 c 0 c_0 c0 替换为 − 3 X 6 − 3 X 5 − 2 X 4 − X 3 − X 2 + 1 -3X^6 - 3X^5 - 2X^4 - X^3 - X^2 + 1 3X63X52X4X3X2+1 c 1 c_1 c1 替换为 X 3 + 2 X 2 + X + 1 X^3 + 2X^2 + X + 1 X3+2X2+X+1 s s s 替换为 3 X 2 + 2 X + 1 3X^2 + 2X + 1 3X2+2X+1。进行多项式乘法和加法后,得到解密结果 μ ′ = 2 X 2 + X + 1 \mu' = 2X^2 + X + 1 μ=2X2+X+1,与原始消息 μ \mu μ 相同。

这是一个简化的RLWE示例,演示了如何生成密钥、加密消息和解密密文。 RLWE的优势在于密钥的大小更小,并且可以使用更高效的乘法操作进行计算。

Homomorphic operations

现在我们已经了解了为什么要在 Z q [ X ] / ( X N + 1 ) \mathbb{Z}_q[X]/(X^N+1) Zq[X]/(XN+1)的多项式上工作,以及如何基于此构建加密方案,让我们看看如何定义密文上的加法和乘法,以实现同态加密方案。

我们说过我们有一个秘密 s s s和一个公钥 p = ( b , a ) = ( − a ⋅ s + e , a ) p=(b,a)=(-a\cdot s+e,a) p=(b,a)=(as+e,a)。要加密一个消息 μ \mu μ,我们简单地输出 c = ( μ + b , a ) c=(\mu+b,a) c=(μ+b,a),而要使用 s s s解密它,我们评估 c 0 + c 1 ⋅ s c_0+c_1\cdot s c0+c1s,这将近似地给出原始消息。

Addition

假设我们有两个消息 μ \mu μ μ ′ \mu' μ,并将它们加密为 c = ( c 0 , c 1 ) c=(c_0,c_1) c=(c0,c1) c ′ = ( c 0 ′ , c 1 ′ ) c'=(c'_0,c'_1) c=(c0,c1)。那么 c add = c + c ′ = ( c 0 + c 0 ′ , c 1 + c 1 ′ ) c_{\text{add}}=c+c'=(c_0+c'_0,c_1+c'_1) cadd=c+c=(c0+c0,c1+c1) 就是 μ + μ ′ \mu+\mu' μ+μ 的正确加密结果。也就是说,当我们使用秘密 s s s 进行解密时,我们会得到(近似地) μ + μ ′ \mu+\mu' μ+μ

确切地说,对 c add c_{\text{add}} cadd 的解密过程为 c add , 0 + c add , 1 ⋅ s = c 0 + c 0 ′ + ( c 1 + c 1 ′ ) ⋅ s = c 0 + c 1 ⋅ s + c 0 ′ + c 1 ′ ⋅ s = μ + μ ′ + 2 e ≈ μ + μ ′ c_{\text{add},0}+c_{\text{add},1}\cdot s=c_0+c'_0+(c_1+c'_1)\cdot s=c_0+c_1\cdot s+c'_0+c'_1\cdot s= \mu+\mu'+2e\approx\mu+\mu' cadd,0+cadd,1s=c0+c0+(c1+c1)s=c0+c1s+c0+c1s=μ+μ+2eμ+μ。这里我们假设 e e e 是可以忽略的。

这意味着,如果你对密文进行加法操作,并将其解密,你将得到明文的加法结果!这意味着通过这个简单的方案,你可以允许某人在加密的数据上进行加法操作,而用户仍然可以解密它并得到正确的结果。这是我们朝着同态加密方案迈出的第一步。

Multiplication

然而,我们仍然需要定义密文上的乘法,这更加复杂。事实上,我们的目标是找到一个密文 c mult c_{\text{mult}} cmult,当我们用秘密密钥 s s s 进行解密时,我们得到明文的乘积。

由于两个密文的乘法更加复杂,我们现在将重点放在将密文与明文相乘上,并在以后的文章中看看如何在密文之间进行乘法运算。

假设我们有一个明文 μ \mu μ,加密为密文 c = ( c 0 , c 1 ) c=(c_0,c_1) c=(c0,c1),以及另一个明文 μ ′ \mu' μ。那么要获得乘法的密文,我们只需要输出 c mult = ( μ ′ ⋅ c 0 , μ ′ ⋅ c 1 ) c_{\text{mult}}=(\mu'\cdot c_0,\mu'\cdot c_1) cmult=(μc0,μc1)

确实,当解密 c mult c_{\text{mult}} cmult 时,我们得到 μ ′ ⋅ c 0 + μ ′ ⋅ c 1 ⋅ s = μ ′ ⋅ ( c 0 + c 1 ⋅ s ) = μ ′ ⋅ ( μ + e ) = μ ′ ⋅ μ + μ ′ ⋅ e ≈ μ ′ ⋅ μ \mu'\cdot c_0+\mu'\cdot c_1\cdot s=\mu'\cdot (c_0+c_1\cdot s)=\mu'\cdot (\mu+e)=\mu'\cdot \mu+\mu'\cdot e\approx\mu'\cdot \mu μc0+μc1s=μ(c0+c1s)=μ(μ+e)=μμ+μeμμ

因此,通过这种加法和乘法的实现,我们已经看到可以加密一些数据,对其进行操作,然后解密后得到与对明文数据进行计算相同的结果。

由于我们还有一些其他概念要解决,例如密文-密文乘法、重线性化和重新缩放,我们暂时不会涵盖代码实现。一旦我们掌握了所有的基本组件,我们将把一切都组合在一起,构建一个端到端的近似同态加密方案,类似于CKKS!

所以我希望你理解了如何使用RLWE构建同态加密方案,并且下一步是密文-密文乘法!

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

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

相关文章

笨办法学 Python3 第五版(预览)(三)

原文:Learn Python the Hard Way, 5th Edition (Early Release) 译者:飞龙 协议:CC BY-NC-SA 4.0 练习 30:假如 这是你将要输入的下一个 Python 脚本,它向你介绍了if语句。输入这个代码,确保它能够完美运行…

怎么快速编辑视频

背景:怎么简单快速编辑视频 利用FFmpeg功能,简单快速编辑视频,如按9:16提前剪切视频、替换背景音乐。 下载FFmpeg:https://ffmpeg.org/download.html 将FFmpeg的路径添加到环境变量中: Windows:在系统的环…

Home-credit海外贷款信贷产品源码/线上贷款产品大全/贷款平台软件源码/海外借贷平台

测试环境:Linux系统CentOS7.6、宝塔、PHP7.3、MySQL5.6,根目录public,伪静态laravel5,开启ssl证书 语言:中文简体、英文 laravel框架的程序有点多,这个团队估计主要就是搞laravel开发的,基本上…

前端架构: 脚手架通用框架封装之脚手架注册和命令注册开发(教程二)

脚手架注册和命令注册 1 )脚手架的注册 接上文,仍旧在 abc-cli 项目中参考:https://blog.csdn.net/Tyro_java/article/details/136381086之前初始化的时候,使用的是 yargs, 现在我们想要使用 commander在cli包中安装 commander $…

2024 最新版 Compose material3 下拉刷新

2024 最新版 Compose material3 下拉刷新,版本 > 1.2.0 的 compose material3 已经更新了下拉刷新组件的 Api 见 https://developer.android.com/jetpack/androidx/releases/compose-material3?hlzh-cn#1.2.0 使用方法:https://developer.android.…

YOLOv9独家原创改进|增加SPD-Conv无卷积步长或池化:用于低分辨率图像和小物体的新 CNN 模块

专栏介绍:YOLOv9改进系列 | 包含深度学习最新创新,主力高效涨点!!! 一、文章摘要 卷积神经网络(CNNs)在计算即使觉任务中如图像分类和目标检测等取得了显著的成功。然而,当图像分辨率较低或物体较小时&…

可以用来测试的接口

实际开发过程中,我们可以通过postman工具来测试接口 get请求 https://api.github.com/events?id1&nameuser post请求 http://httpbin.org/post 参数1:key1value1 参数2:key2value2

(C语言)回调函数

回调函数是什么? 回调函数就是⼀个通过函数指针调⽤的函数。 如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被⽤来调⽤其所指向的函数 时,被调⽤的函数就是回调函数。回调函数不是由该函数的实现⽅…

技术阅读周刊第十四期:常用的 Git 配置

技术阅读周刊,每周更新。 历史更新 20231122:第十一期20231129:第十二期20240105:第十三期:一些提高生产力的终端命令20240112:第十四期:Golang 作者 Rob Pike 在 GopherConAU 上的分享 How I w…

探索Manticore Search:开源全文搜索引擎的强大功能

在当今信息爆炸的时代,数据的快速检索变得至关重要。无论是在电子商务网站、新闻门户还是企业内部文档,高效的搜索引擎都是确保用户满意度和工作效率的关键因素之一。而在搜索引擎领域,Manticore Search 作为一款开源的全文搜索引擎&#xff…

大模型(LLM)的量化技术Quantization原理学习

在自然语言处理领域,大型语言模型(LLM)在自然语言处理领域的应用越来越广泛。然而,随着模型规模的增大,计算和存储资源的需求也急剧增加。为了降低计算和存储开销,同时保持模型的性能,LLM大模型…

2024最新算法:鹦鹉优化算法(Parrot optimizer,PO)求解23个基准函数(提供MATLAB代码)

一、鹦鹉优化算法 鹦鹉优化算法(Parrot optimizer,PO)由Junbo Lian等人于2024年提出的一种高效的元启发式算法,该算法从驯养的鹦鹉中观察到的觅食、停留、交流和对陌生人行为的恐惧中汲取灵感。这些行为被封装在四个不同的公式中…

c语言--qsort函数(详解)

目录 一、定义二、用qsort函数排序整型数据三、用qsort排序结构数据四、qsort函数的模拟实现 一、定义 二、用qsort函数排序整型数据 #include<stdio.h> scanf_S(int *arr,int sz) {for (int i 0; i < sz; i){scanf("%d", &arr[i]);} } int int_cmp(c…

消息队列kafka

消息队列解决的问题 1. 解耦&#xff0c;通过消息队列实现应用之间解耦&#xff0c;模块儿之间解耦 2. 跨线程/进程通信&#xff0c;通过消息队列传递数据&#xff0c;实现不同线程/进程间通信 3. 提升系统稳定性&#xff0c;在高并发场景通过消息队列缓冲&#xff0c;可以实…

哈啰Java 春招 24届

时长 1h 3. 为什么使用分布式ID&#xff0c;解决了什么问题 4. Leaf算法了解吗&#xff1f;讲一下原理和工作流程以及优缺点 5. 有没有可能导致id重复&#xff1f;该如何解决&#xff1f; 6. 项目中redis是如何运用的&#xff1f; 7. 项目中分布式锁是如何实现的&#xff1f; 8…

解决在 Mac 上安装 Adobe 软件弹出提示:安装包已经被损坏并且不能被打开。

问题&#xff1a; “INSTALLER” is damaged and can’t be opened. You should eject the disk image. 解决方法和步骤&#xff1a; 打开安装包&#xff1b;将安装包 “INSTALLER” 拖动复制到某个文件夹&#xff0c;复制后的文件路径例如像这样&#xff1a;/Users/michael…

LLC谐振变换器变频移相混合控制MATLAB仿真

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 基本控制原理 为了实现变换器较小的电压增益&#xff0c;同时又有较 高的效率&#xff0c;文中在变频控制的基础上加入移相控制&#xff0c; 在这种控制策略下&#xff0c;变换器通过调节一次侧开关管 的开关…

leetcode 热题 100_盛最多水的容器

题解一&#xff1a; 双指针遍历&#xff1a;容量计算公式为min(左高度&#xff0c;右高度)*底部距离&#xff0c;我们可以令底部距离逐步递减&#xff08;左右两边的指针向中部移动&#xff09;。此时对于min(左高度&#xff0c;右高度)&#xff0c;假设较高的线向中部移动&…

带你玩转数据结构-单链表(适合初学者的文章,讲解的很仔细哦)

前言: &#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&#x1f32f; C语言进阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f349;本篇简介:>:讲解数据结构中链表的知识,;链表的分类,c语言实现单链…

重学Springboot3-@import注解的作用

重学Springboot3-import注解的作用 1. 引言2. Import 注解的基本用法3. 导入多个配置类4. 使用 Import 导入组件5. 使用 ImportSelector 和 ImportBeanDefinitionRegistrar6. 总结 1. 引言 在 Spring Framework 中&#xff0c;Import 注解是一个重要的元注解&#xff0c;它允许…