基于NTRU的签名算法学习1

本文基于Modular Lattice Signatures, revisited学习了NTRUSign的基本思想,以及其改进。本文主要对该文章进行了转译,并利用python实现了底层的加解密、同态、签名等运算。

☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

基于ntru的签名算法学习1 - 创想鸟

1.  介绍

  由于量子计算机的威胁,组织和研究小组正在寻找候选算法来替代RSA和ECC基于方案。在所有候选方案中,基于点阵的解决方案似乎是最有前途的解决方案。对于加密方案,NTRUEncrypt是已知的最快的基于格的加密算法之一。在签名方案方面,目前有几种基于格点的签名方案依赖于NTRU格点的安全性,如BLISS、DLP和pqNTRUSign 。

  本文重述了模格签名方案。给定具有陷门函数T的格LL,它是行向量的短基;和向量m形式的信息摘要,其系数为[0,p)模签名方案的签名是格向量v,使

  1.v≡mmod  pv≡mmodp

  2.v∈Lv∈L

  可以通过以下步骤获得此向量:

  1.从LL采样一个向量v0v0;

  2.用TT对v0v0进行微调,使v:=v0+aTv:=v0+aT满足某aa的同余条件;

  3.使用拒收抽样从vv中隐藏TT

  在本文中,我们将从以下角度重新审视上述方案。

  安全证明。在原模格签名方案中,公钥安全问题与唯一最短非零向量问题(uSVP)有关。从L(一个坏的基础)中恢复T;而不可伪造性是基于一个晶格与一个晶格平移的交点上的近似最接近向量问题(approx-CVP),即L∩(pZn+mp)L∩(pZn+mp)。虽然第二个问题对于这个特殊的晶格来说是困难的,但是第一个问题和第二个问题之间的联系是缺失的。因此,该方案需要两个(看似独立的)硬度假设。例如,当方案通过一个NTRU晶格实例化时,他们需要对NTRU晶格进行uSVP假设,对两个晶格的交集进行上述approx- cvp假设。

  在本文中,我们去掉了第二个假设。从本质上说,攻击者是给定一个晶格(任何晶格,不一定NTRU晶格),他被要求找到一个等晶格向量,这个向量相等的已知值mod p。换句话说,攻击者需要找到一个向量与预先确定的在这篇文章中,我们删除第二个假设。从本质上说,攻击者是给定一个晶格(任何晶格,不一定NTRU晶格),他被要求找到一个等晶格向量,这个向量相等的已知值mod p。换句话说,攻击者需要找到一个向量与预先设定的最低有效位。我们命名这个问题与截断(LWT)学习问题,可以被视为学习的逆着(LWR)问题,给出了在这种情况下,一个矩阵A和b = ⌊sAmod  q⌋p⌊sAmodq⌋p,并要求找到s。也就是说,找到一个向量与晶格预先确定的最重要的部分.

  这允许我们将伪造攻击与approx-SVP连接起来。因此,我们只需要一个简单的假设。特别地,当方案通过一个短整数解决方案(SIS)问题实例化时,在我们的方案中伪造签名与解决随机格的approx-svp一样困难。另一方面,当方案通过一个NTRU格实例化时,我们要求NTRU格的approx- svp是困难的,这等价于unique- svp假设(直到一个多项式因子),即, NTRU算法。

  抽样方法。早期基于点阵的签名方案,如GGHSign和NTRUSign,在消息/签名对的转录本中泄漏私钥信息。攻击者可以使用学习平行六面体的方法从足够长的文本中生成签名密钥”。

  其中,Lyubashevsky提出了一种拒绝采样的方法来阻止转录泄漏攻击。使用他的技术,签名是根据一个固定的公共分布产生的(通常是一个高斯分布,如均匀分布)。记录只显示这种公开分发,不包含关于用于生成签名的特定签名密钥的信息。因此,采样方法成为设计签名方案的核心问题。例如,用双模高斯采样器代替高斯采样器可以显著提高算法的性能.

  原先方案中的签名是格向量。由于验证者已经知道用于验证目的的格的一个(坏的)基,只要验证者在验证阶段能够完成整个向量,那么传输部分向量v就足够了。

  流行的基于格的方案,如BLISS和TESLA,没有这个性质。这些方案中的签名是接近晶格的向量。因此,当向量被压缩时,需要为验证者生成一个额外的帮助器来推导原始向量(尽管这个帮助器只有几百位)。具体地说,如果我们用原先方案中相同的参数来参数化本文提出的方案,签名大小的差异就是这个参数的大小。

  由于采样方法的原因,这种设计上的优势并没有给出更小的签名尺寸。对于系数为[−q/2,q/2)[−q/2,q/2)的n维向量,需要n⌈logq⌉n⌈logq⌉位进行存储。相比之下,一个离散高斯向量相同的尺寸的偏差σ∼qσ∼q可以存储∼n(logq/2+2)∼n(logq/2+2)位。一个自然的问题是,是否可以使用(双峰)高斯采样[10]对模格签名。在本文中,我们对这个问题给出了肯定的回答.

  备注1。虽然使用高斯采样的方案允许更小的签名大小,但基于格点的签名方案最近的发展显示出一种向均匀拒绝采样的趋势,因为均匀采样更容易实现和确保恒定的时间。然而,使用pqNTRUSign,高斯采样使我们获得了一个额外的属性:签名聚合。

  签名聚合。签名聚合,也称为批处理验证,允许验证一组签名(在同一键下签名),其操作顺序为单个验证。在许多用例中,它是一个有用的属性。例如,对于签名软件映像的安全引导机制,签名聚合允许在一次验证整个软件映像集的同时,分别对各个软件映像进行签名(并且按照组件的方式而不是单块更新)。这允许快速启动.

  我们的方案允许批处理验证(参数经过微调)。一般来说,对于消息摘要m的签名v只要≡m mod p和v∈Lv∈L就有效。因此,对于一组签名vivi,对应于我们所拥有的一组消息mimi.

  1.∑vi≡∑mimod  p∑vi≡∑mimodp

  2.∑vi∈L∑vi∈L

  因此,我们可以简单地检查∑vi∑vi而不是检查每个v。在为我们提出的方案实现这种技术时,我们可以使用单环乘法(这通常是验证中代价最高的操作)来验证一批签名。不过我们注意到,仍然需要执行多个散列函数来获得这些消息摘要。此外,由于累积的签名在格子中是一个更大的向量(与单个签名相比),我们将要求这个累积的签名对应的格子问题也很困难。

  我们还注意到,其他基于格的方案,如BLISS和TESLA,不能轻易地提供这个属性,因为它们需要在哈希函数之前执行环操作。

2. 背景知识

  向量用小写粗体字,矩阵用大写粗体字。对于一个多项式f(x)=f0+f1x+…+fn−1xn−1f(x)=f0+f1x+…+fn−1xn−1,我们用ff表示其向量形式<f0,f1,…,fn−1>。当没有歧义时,我们有时会滥用向量和多项式的表示法。对于一个多项式向量f,f范式是∥f∥:=∑i=0n+1fi2∥f∥:=∑i=0n+1fi2和∥f∥∞:=max(∣fi∣)∥f∥∞:=max(∣fi∣)

  我们经常使用多项式环Rq:=Z[x]/F(x)Rq:=Z[x]/F(x)和F(x)=xn±1F(x)=xn±1。环Rq上多项式f(x)的循环旋转矩阵为矩阵M=(f1,f2,…,fn)T;M=(f1,f2,…,fn)T;如果f(x)=xn−1f(x)=xn−1,它是完全循环的,并且接近于循环,直到符号,如果f(x)=xn+1f(x)=xn+1。

  对于一个真实的a,我们让bae表示到a的壁橱整数。对于一个整数a,我们使用[a]q[a]q来表示a mod q,⌊a⌋p:=(a−[a]p)p/⌊a⌋p:=(a−[a]p)p/用于将a四舍五入到p的最接近倍数的运算。模运算的中心被提升,例如模q在−q/2−q/2和q/2q/2范围内返回一个整数。这些符号也扩展到向量和矩阵中。

  NTRU,SIS,LWR与格

  格LL是RnRn的离散子群,也就是d≤n个线性无关向量在RR上的所有积分组合的集合:

  L:=Zb1+Zb2+…+Zbd,bi∈RL:=Zb1+Zb2+…+Zbd,bi∈R

  B:=(b1…..bd)TB:=(b1…..bd)T称为LL的一组基,给定一个格L,找到一个不超过γ⋅λ1(L)γ⋅λ1(L)的向量称为近似最短向量问题(γ−SVPγ−SVP),其中λ1λ1是晶格中最短向量的长度。高斯函数的启发式说在一个随机格中,这第一个最小值λ1≈dim2πedet(L)1dimλ1≈2πedimdet(L)dim1在det(L)表示的行列式LL .给定一个特定的晶格L,存在一个唯一最短非零向量,发现这个向量称为独特的最短向量问题(u-SVP)

  我们把一个NTRU格看成是一个2阶的RqRq模。让f,g的系数为小于q的实数。令h=g/fh=g/f在 RqRq。与h相关的NTRU晶格定义为

  L:={(s,t)∈Rq2:t≡shmod  q}.L:={(s,t)∈Rq2:t≡shmodq}.

  已知h,认为很难找到f和g,这就是NTRU假设,可以简化为NTRU格点唯一的最短向量问题。

  我们把NTRU晶格中的向量写成v = ,其中s和t都是RqRq的元素;此外,我们将构成该向量第一部分的子向量称为s边的向量,将构成该向量第二部分的子向量称为t边的向量。

  我们将此概念扩展到适用的短整数解决问题(SIS)。回想一下SIS问题的定义如下:

  SISq,n,m,βSISq,n,m,β问题:在一个n×mn×m的随机矩阵中,其中元素皆为小于q的正整数,寻找一个最小非0向量v使得vA≡0mod  q,∣∣v∣∣2<βvA≡0modq,∣∣v∣∣2<β.

  如果将A 矩阵看出两个矩阵的上下串联,例如A=∣A1A2∣A=∣∣∣∣∣A1A2∣∣∣∣∣,则原问题变为: L:={(s,t):sA1+tA2≡0mod  q}L:={(s,t):sA1+tA2≡0modq}

  找到短的(s,t)在此点阵中提供了SIS问题的解决方案。对于n = poly(m), q⩾βmδq⩾βmδ的一些正数δδ,平均求解SIS问题与具有最近似因子 的 max{1,ββ∞/q}⋅0(βm)max{1,ββ∞/q}⋅0(βm) 最短独立向量问题一样困难;其中β∞β∞是v的无穷范数的上界。

  SIS问题有一个“双”版本,称为LWE问题。通俗地说,让m,n,q为某个正整数,设格数为由σσ参数化的χσχσ分布,例如:具有标准差为σσ的离散高斯分布,均匀随机抽样A∈Zqn×m,s,b1∈ZpnA∈Zqn×m,s,b1∈Zpn ;样品e∈χσme∈χσm计算b0=sA+emodqb0=sA+emodq;决策LWE假设表明,给定两对(A,b0),生成b0,(A,b1),b1选自均匀分布,无法区分这两对.

  我们还利用了舍入学习(LWR)问题。这可以被看作是SIVP问题的一个变体,它具有四舍五入带来的确定性误差。我们正式记录LWR问题如下:

  LWRq,r,n,mLWRq,r,n,m:均匀从随机抽样矩阵和A∈Zqn×mA∈Zqn×m和向量s∈Zqns∈Zqn,计算b=⌊sAmod  q⌋rb=⌊sAmodq⌋r;决策的LWR问题是:给定u在ZqnZqn中均匀随机采样的两对(A,b)和(A,⌊u⌋r)(A,⌊u⌋r),区分这两对。计算问题为:给定(A,b),发现s。

  假设带参数的LWRq,r,n,mLWRq,r,n,m是困难的,决策LWEq,r,n,m‘LWEq,r,n,m‘问题也是困难的。

  m≥log(q)log(2γ)⋅m‘m≥log(2γ)log(q)⋅m‘ and  q≥γ(nmβp)q≥γ(nmβp)

  对于一些γγ≥1的。就我们所知,我们不知道计算的LWR和其他假设之间的规约。

  双峰高斯分布和拒绝抽样:

  定义了均值v和标准差为σσ的n维高斯分布ρv,σ(x):=exp(−∥x−v∥22σ2)ρv,σ(x):=exp(2σ2−∥x−v∥2);当没有歧义时,我们把它简称为ρσρσ。定义了一个n维的离散高斯分布在Z上:χσ:=ρσ(x)ρσ(Zn)χσ:=ρσ(Zn)ρσ(x),其中ρσ(Zn):=∑z∈Znρσ(z)ρσ(Zn):=∑z∈Znρσ(z)是使函数变成概率分布[23]所需要的标度量.

  截断:对于一个离散高斯分布χσmχσm和τ>1τ>1

  ρσ(Zm/στmB)≤2ρσ(Zm)(τexp(1−τ22))mρσ(Zm/στmB)≤2ρσ(Zm)(τexp(21−τ2))m

  其中B是中心单位球。令τ=λ2ln2τ=λ2ln2为一维高斯将确保所有样品都以τστσ为边界的概率大于1−2−τ1−2−τ。通常情况下,对于λ=128λ=128,可以使用$tau= 13.3;对于3;对于lambda = 256,可以使用,可以使用tau= 18.8$

  拒绝抽样:设S为秘密矩阵,c为从均匀分布中抽样得到的向量,y为从离散矩阵中抽样得到的向量。考虑x = y + cS的分布,即,一个经过cS平移的高斯分布。在[28,13]中已经表明,每个样本x都泄漏了关于S的部分信息。用来密封泄漏的方法是拒绝采样,通过根据一定的标准概率接受输出,使输出分布独立于S.

  如果我们希望使输出分布与y相同,则有:

χσ(x)χcS,σ(x)≤M,χcS,σ(x)χσ(x)≤M,

  这个不等式成立

M=exp(2τσmaxc∣∣cS∣∣+maxc∣∣cS∣∣22σ2)M=exp(2σ22τσmaxc∣∣cS∣∣+maxc∣∣cS∣∣2)

  其中M为重复率。常数M决定了拒绝率,M越小,签名生成过程越高效。一种常见的选择是设置出一个常数σ=τmaxc∣∣cS∣∣σ=τmaxc∣∣cS∣∣(虽然仍然较大).:

  双峰高斯分布:非正式地说,双峰高斯分布是两个具有相同的σσ和相同的绝对值,符号相反的高斯分布的和。由上例可知,x = y±cS的分布非常接近于双峰高斯分布。如果存在一个常数M,则可以使用拒收抽样从双峰高斯分布12χcS,σ(x)+12χ−cS,σ(x)21χcS,σ(x)+21χ−cS,σ(x)得到一个新的高斯分布χσχσ,并且

χσ(x)12χcS,σ(x)+12χ−cS,σ(x)≤M21χcS,σ(x)+21χ−cS,σ(x)χσ(x)≤M

  这个不等式是成立的:

M=exp(maxc(∣∣cS∣∣2)2σ2)M=exp(2σ2maxc(∣∣cS∣∣2))

  同时,对于一个个体x = y±cS,接受它的概率为

ρ=1/(Mexp(−∣∣cS∣∣2σ2)cosh(<x,cS>σ2))ρ=1/(Mexp(−2σ2∣∣cS∣∣)cosh(σ2))

  备注2。通常,在效率和存储大小之间存在权衡。对于离散高斯分布χσχσ的列线图,其输出x的熵有上界

H(x)≤≈klog(4.1σ)H(x)≤≈klog(4.1σ)

  因此,使用霍夫曼编码,这样的向量可以有效地存储为大约k(log(σ)+2)k(log(σ)+2)位。因此,一个更小的报文会产生更小的签名σσ,但同时也会降低拒收采样的效率。

3. 具有高斯抽样的模格签名

3.1 方案

  构造:设m、n、k为3个正整数,n = k + m,设S1∈Zm×kqS1∈Zm×kq为系数小且稀疏的矩阵。为简单起见,我们假设S1S1是抽样从某个边界为β的分布中采集的,这样∣∣S1∣∣∞≤β≪q∣∣S1∣∣∞≤β≪q。在实践中可以使用一个方差小的离散高斯采样器,或均匀取样器在小的范围内。

  我们的密钥是一个矩阵S:=[pS1∣Im]∈Zq(m×n)S:=[pS1∣Im]∈Zq(m×n),它具有小的项。公钥是由一个矩阵A=[A1A2]A=[A1A2]同时SA = 0 mod q和A2是A的逆的mod q。同样,我们可以从Zqk×mZqk×m均匀得采样到样本A1,然后设置A2=−pS1A1A2=−pS1A1mod q。A1如果A2不是可逆的mod q,我们重取。SIS点阵定义为:

  $$mathcal {L}:={(u,v):u A_1+v A_2 =0 mod q},$$

  其中S是该栅格的短活板门基础。注意,上面的过程是SIS问题的标准构造,除了S1上有一个因子p。在下一小节中,我们将说明我们的构造与标准SIS问题之间的等价性.

  看一个k×m矩阵B:=A1(−A2)−1mod  qB:=A1(−A2)−1modq可能更方便。与B,晶格L可以解释为

  $$mathcal {L}:={(u,v):uB=v mod q},$$

  对于错误学习的基

PHP 网络编程技术与实例(曹衍龙) PHP 网络编程技术与实例(曹衍龙)

PHP网络编程技术详解由浅入深,全面、系统地介绍了PHP开发技术,并提供了大量实例,供读者实战演练。另外,笔者专门为本书录制了相应的配套教学视频,以帮助读者更好地学习本书内容。这些视频和书中的实例源代码一起收录于配书光盘中。本书共分4篇。第1篇是PHP准备篇,介绍了PHP的优势、开发环境及安装;第2篇是PHP基础篇,介绍了PHP中的常量与变量、运算符与表达式、流程控制以及函数;第3篇是进阶篇,介绍

PHP 网络编程技术与实例(曹衍龙) 386 查看详情 PHP 网络编程技术与实例(曹衍龙)

P=[0qImIkB]P=[0IkqImB]

  这样就可以进行有效的抽样。

  签名:我们将哈希函数H作为一个随机的oracle,在ZpnZpn上均匀输出,这允许我们从消息文摘中生成随机元素mp∈Zpnmp∈Zpn。我们写mp:=(up,vp)mp:=(up,vp),同时up∈Zpkup∈Zpk和vp∈Zpmvp∈Zpm。

  下一步是从P:u1≡upmod  pP:u1≡upmodp中采样一个向量(u1,v1)(u1,v1)要做到这一点,我们可以简单地从一个离散高斯分布的χσkχσk函数中采样一个向量r。然后计算u0=pr,u1=u0+upu0=pr,u1=u0+up,u1u1满足v1=u1Bmod  qv1=u1Bmodq,$(u_1,v_1) 是晶格中的一个向量,是晶格中的一个向量,u_1≡u_p mod p$.

  另一种查看上述过程的方法是生成一个随机向量(r,rBmod  q)(r,rBmodq)在晶格中。根据定义,矩阵[Ik∣B][Ik∣B]是L(P)L(P)的子格的一组基。此外,由于r是从一个离散的高斯分布采样,这个随机向量可以看作是一个GPV采样器L([Ik∣B])L([Ik∣B])的输出r([Ik∣B])r([Ik∣B])。如果参数σσ大于平滑参数L([Ik∣B])L([Ik∣B]),则向量r([Ik∣B])r([Ik∣B])在L([Ik∣B])L([Ik∣B])是均匀的,在ZnZn上是离散的高斯分布。然后我们取这个向量对q的模来得到精确的输出向量.

  由于v1v1在ZnZn上是离散高斯分布的,它将具有以p为模的随机系数,因此不满足全等条件。为了完成这个过程,我们需要对v1v1进行微调,使t侧也满足一致性条件:同时,我们不想破坏s边的同余条件。我们使用秘密基S=[pS1∣Im]S=[pS1∣Im]来实现这个目标。令a=vp−v1mod  pa=vp−v1modp,计算(u2,v2)=aS=(paS1,a(u2,v2)=aS=(paS1,a).注意(u2,v2)≡(0,a)(u2,v2)≡(0,a)构造对mod  pmodp,$ (u_2,v_2)$是晶格中的向量。

  最终的签名为(u,v)=(u1,v1)+(u2,v2)(u,v)=(u1,v1)+(u2,v2),很容易看出(u,v)(u,v)在∣∣v∣∣∞<q/2∣∣v∣∣∞<q/2时仍在晶格中。同时我们有

u=u1+u2=u1≡upmod  pu=u1+u2=u1≡upmodp

  以及

v=v1+v2≡v1+vp−v1≡vpmod  pv=v1+v2≡v1+vp−v1≡vpmodp

  因此,(u,v)(u,v)是我们方案的有效签名

3.2 拒绝抽样

  如前所述,候选签名(u,v)泄漏关于密钥S的信息。要密封此泄漏,需要使用拒收采样技术。上述方案的效率很大程度上取决于拒绝签名的频率。作为一个概念的证明,我们将展示拒收抽样可以用来密封信息泄漏在这里。我们将在第4节中给出一个更有效的实例,它使用双峰高斯分布。

  对u的拒收抽样。先文提到u=p(r+aS1)+upu=p(r+aS1)+up。由于p和upup都是公开的,我们需要封住来自b:=r+aS1b:=r+aS1对S1S1的泄漏。还请回忆一下,所有r的分布方式为χσkχσk。

  在v上的拒收抽样,在t边,我们不需要拒收抽样。我们有v=v1+v2v=v1+v2。首先v1=(pr+up)Bv1=(pr+up)B,它没有链接到秘钥S1S1。其次,S2=(v1−vp)mod  pS2=(v1−vp)modp也没有链接到任何密钥.

  另一种说法是,拒绝抽样对t边来说是不需要的,因为事实上,与t边相对应的密钥实际上是ImIm。事实上,我们可以把v=v1+aS2v=v1+aS2写成S2=ImS2=Im。在下一节中我们将看到,当一个秘密矩阵替代ImIm时,我们仍然需要使用拒收抽样来密封S2S2的泄漏。

  尽管如此,如果∣∣v∣∣∞∣∣v∣∣∞变得太大,导致了一个wrap-around mod q,我们确实需要重新启动。当这种情况发生时,mod q降低后,全等条件被打破.

  替代方案。在我们的构建中,我们选择做拒收抽样,这样∣∣v∣∣∞∣∣v∣∣∞不会导致任何wrap-aroud。尽管有以下两种选择,我们还是选择了这种方法。首先,签署人可以发送一个助手来指示校验人发生wrap-around的系数。这可以看作是2012中基于Ding (R) LWE的密钥交换的一种和解方法。我们不采用这种解决方案,因为它会增加签名的大小。

  其次,由于wrap-around发生的概率较低,我们可以基于模糊匹配让验证者接受签名:当t侧的大部分系数满足同余条件时接受签名。这种有前途的方法可能会削弱我们的安全,因为它使伪造更容易。出于保守目的,我们不考虑这种方法.

3.3 签名压缩

  有三个压缩源。首先,只要向量是l,验证者可以有效地只存储向量的、s边,而不是整个向量,即给定u,验证者可以重构v=uBmod  qv=uBmodq

  其次,验证者可以从b中重构u=pb+upu=pb+up,因为p和upup都是已知的。所以只需要b来验证.

  最后,由于b在拒绝采样后遵循离散高斯分布,可以使用基于代码的压缩技术来减少b的空间需求。

  最后的签名是一个k维离散高斯向量,允许霍夫曼编码。最终签名的大小为k(log(σ)+2)k(log(σ)+2)。

3.4 模拟记录

  上述签名算法必须在统计上与三(up,vp,b)(up,vp,b),分布为Upk×Upm×χσkUpk×Upm×χσk的高斯分布,其中UpUp为均匀模p,高斯分布为χσkχσk高斯分布。在不知道密码匙的情况下,可以通过以下方式模拟这样一份文本:

  1. 从χσkχσk中随机选择b   2. 设u=pb+upu=pb+up,随机取upmod  pupmodp,使∣∣u∣∣∞<q/2∣∣u∣∣∞<q/2   3. 集合v≡uBmod  qv≡uBmodq,并将v提升到区间(−q/2,q/2)(−q/2,q/2)   4. 设vp≡vmod  pvp≡vmodp

  备注3。我们正在做一个假设,经过实验验证,即step4生成一个vp≡uBmod  qmod  pvp≡uBmodqmodp,它的项都是均匀mod p

3.5 安全性

  对于公钥的安全性,很容易看出从公钥找到秘钥(或者仅仅是允许伪造的足够短的向量)的能力可以降低为解决SIS问题的能力。在本节中,我们主要关注伪造签名的困难。

  为了量化伪造的难度,我们首先引入带截断的学习问题。

  定义3 (LWTq,p,n,mLWTq,p,n,m)。让q,p,m,nq,p,m,n是p共一撇到q的正整数,均匀随机抽样一个矩阵A∈Zqn×mA∈Zqn×m q乘以m和一个向量s∈zqns∈zqn ,计算b = sA mod q mod p;决策LWT问题为:给定两对(A,b)和(A,[u]p)(A,[u]p)其中u在ZqnZqn中均匀随机采样,区分这两对。计算问题为:给定(A,b),找到s。

  如前所述,这个LWT问题可以看作是LWR问题的逆。这里我们展示了问题之间的简化。

  引理1。选择一对(p,q)使得p和r≡p−1mod  qr≡p−1modq都在qq的数量级上。那么,如果存在求解参数q的计算LWT的算法AA ,对于给定参数为q,p,n,m的任意输入(A,b)∈Zqq×m×Zpm(A,b)∈Zqq×m×Zpm,存在另一种算法BB,求解参数q,r, n, m, 的LWR,在参数为$ (A’,B’),对,对A’从从Z^n _q$中均匀随机取样。

  我们在这里简述一下证明

  证明。假设算法AA 能够解决LWT问题,即给定(A,b)它找到一个晶格向量

  - v = b mod p,并且

  - v = tA mod q 对某些t。

  然后,我们可以建立一个oracle,在输入(A,b)它找到u和t,这样

v+pu=tAmod  qv+pu=tAmodq

  对一些∣∣u∣∣∞≤⌊q2p⌋<r∣∣u∣∣∞≤⌊2pq⌋<r

  给定LWR实例(A′,B′)(A′,B′)算法BB设A=pA′A=pA′, b=b′,b=b′, r=p−1r=p−1 mod q;然后BB通过调用AA 输入(A,b).由于A′A′是均匀的,p与q是共素的,所以A在Zqn×mZqn×m上也是均匀的。同时,由于∣∣b∣∣∞≤p∣∣b∣∣∞≤p, (A,b)将是AA 的一个合法输入,因此,AA 将找到u和t,使得b + pu = tA mod q,即

rb′+u=tA′mod  q和b′=⌊tA′mod  q⌋rrb′+u=tA′modq和b′=⌊tA′modq⌋r

  因此,t是计算LWR问题的解。

  现在我们准备对伪造的难度进行量化    定理1 (Unforgeability)。让B是一个公共密钥生成按我们的方案参数q, p, n, m。对于任何新的输入消息µ,如果敌人能够打造一个签名,不可忽视ρ概率,然后有一个算法BB有相同的概率解决LWTq,p,k,mLWTq,p,k,m

  证明。首先,我们将哈希函数H建模为均匀输出在ZpnZpn上的随机预言符。此外,伪造者被要求在一个他以前没有见过的消息上签名。因此,如果算法BB能够以不可忽略的概率μμ为每一个合法的输入对象伪造签名,那么一定是AA能够伪造任何合法的mp=H(μ∣B)mp=H(μ∣B)同时,从伪造者的角度来看,任何新的向mod  pmodp向量看起来都像是一个合法的散列输出。

  其次,我们声明B与随机一致地从Zpk×mZpk×m中选择的矩阵不可区分。这是由于A与随机均匀地从Zpn×mZpn×m中选取的矩阵不可区分。回忆B=A1(−A2)−1mod  qB=A1(−A2)−1modq和A=[A1A2]A=[A1A2]。

  因此,给定LWT实例(A’,b’),伪造者无法区分A’与合法生成的公钥;它也不能区分b’和合法生成的公共消息摘要。结果,它将返回一个签名向量v,该向量将以概率ρρ递进的方式通过验证测试。从v中很容易提取出LWT问题的解。

  我们注意到,从伪造到LWR/LWT的降低如此之小,我们将需要一个相当大的p,按qq的顺序,这使得该方案的效率较低。在下一节中,我们将看到,高效的实例化使用来自著名攻击的实际参数(这也是大多数实用的基于格的签名的设计原则)。为此,我们将选择一个小的p,允许有效的拒绝抽样。

    strong unforgeability。(标准的)不可伪造性概念的一个微妙之处是,伪造者被要求签署以前从未签署过的消息。然而,强不可伪造性的概念要求攻击者不能在消息上伪造签名,即使给出了同一消息的一组签名。上述定理没有说明这一点。实际上,这里我们展示了一个修改,允许实现强大的不可伪造性。

  对于给定的消息摘要mpmp,与该消息摘要相关的所有候选签名都是原始格与pZn+mppZn+mp相交的短向量。因此,伪造的任务变成了在原始格中寻找一个满足长度要求和同余模p要求的短向量。这在[18]大致是还原到approx-cvp.

    现在,假设向攻击者提供了同一消息摘要上的一组签名,那么,攻击者在这个格子中找到另一个短向量(与没有这个列表相比)就变得更容易了,也就是说,在同一消息上生成一个新的签名。然而,我们注意到这些签名的任何线性组合都不太可能同时满足正确的模p同余条件。

  通常,我们实现强不可伪造性的解决方案是在生成消息摘要时在散列中包含一个随机的“盐”;此盐将作为签名的一部分,并在验证期间使用。这确保了相同的消息摘要出现不止一次的可能性非常小(每个消息的概率(1=p)2n(1=p)2n)。注意,这也是为基于GPV的签名[15]提供类似功能的相同技术。

  然而,由于强不可铸造性模型有时对于实际应用(即,攻击者不需要伪造新的签名,因为它已经在同一消息上获得了它们的列表),我们在有效的实例化中忽略了这个salt,以最小化签名的大小。

4. 一个使用NTRU格的实际实例化

  在上一节中,我们提出了一个基于SIS/LWT的低效模格签名方案,该方案要求n≈m log(m)。即使我们使用环的版本,这个方案仍然有些低效,因为它需要n≈log(m) – m的减少直接来自环的使用。提高效率的一种自然方法是放宽对n≈log(m)的要求(这将使底层(ring) SIS问题更容易,因此我们将从最著名的攻击中获得参数)。

  例如,我们可以把n简化为2m(在环化的情况下是2)。这使得A1A1是一个方阵,这就导致了另一个问题:

pS1A1+ImA2=0mod  ppS1A1+ImA2=0modp

  当A1A1是方阵且可逆时,我们可以很容易地从A1A1和A2A2恢复S1S1

  一个天真的补救方法是设置A2A2是私有的,因此我们将有一个秘密矩阵和[pS1∣A2][pS1∣A2]一个公共矩阵[A1Im][A1Im]也满足上述方程没有暴露S1S1。这个看似合理的解决方案带来了另一个挑战:我们无法再对向量的t边进行微调,因为现在A2A2已经不再小了。如果我们做同样的微调,u2u2的系数会非常大,总是会导致q的wrap-around。

  因此,上述问题的最终解决方案是拥有一个小型的私有A2A2。最终的关键生成是找到这样的A2A2和可逆S1S1,并设置A1=A2(pS1)−1mod  qA1=A2(pS1)−1modq。下面,我们将稍微改变符号:H:=A1,G:=A2H:=A1,G:=A2和F:=S1F:=S1

4.1 方案实施

  在下面,我们将对多项式环Rq=Zq[x]/(xN+1)Rq=Zq[x]/(xN+1)进行处理。我们的方案也适用于其他环,例如Zq[x]/(xN−1)Zq[x]/(xN−1),只是做了一些小小的修改。设f(x),g(x)f(x),g(x)和h(x)h(x)是RqRq中的3个多项式,其中f(x)f(x)和g(x)g(x)系数很小;h(x)=p−1g(x)f−1(x)h(x)=p−1g(x)f−1(x)。我们用fghfgh表示多项式的向量形式。设F、G、HF、G、H为由负循环旋转得到的矩阵。关于hh的NTRU晶格被定义

Lh={(u,v)∈Rq2:uh=v}Lh={(u,v)∈Rq2:uh=v}

  或者更确切地说,向量/矩阵形式:

Lh={(u,v):uH=vmod  q}Lh={(u,v):uH=vmodq}

  那里存在一个公共基础P=[0qININH]P=[0INqINH]和秘密发生器[pF∣G][pF∣G]。我们还要求g(x)g(x)对RpRp可逆,也就是gg对pp可逆。

  该方案的其余部分几乎与上一节中介绍的方案相同,除了两个不同之处。

  首先,我们使用双峰高斯分布来提高接受率。为了解决这个问题,我们设p = 2,使b=r±afb=r±af的符号变化在对pp作模后消失。

  其次,我们使用[pF∣G][pF∣G]而不是[pS1∣Im][pS1∣Im]来执行微观调整。这一修改确实提出了另一个问题:在签字过程中t边的向量将包含关于G的信息。更精确地说,t边的向量将是v:=v1±agv:=v1±ag,其中v1v1与RqRq上的一致不可区分,a与ZpNZpN上的一致不可区分。我们需要进行拒收采样来封闭g信息的泄漏。如[18]所示,拒收采样后,v的分布在计算上与均匀分布在(−q2+Bt;q2−Bt)(−2q+Bt;2q−Bt)表示一个公共参数BtBt,该参数依赖于q、a的(均匀)分布以及g中的+1和- 1的数量。

  为了避免混淆,我们将用MsMs表示s边的拒收率,MtMt表示t边,M表示总比率。

设计NTRU加密内容:

class NtruCipher:    N = None    p = None    q = None    f_poly = None    g_poly = None    h_poly = None    f_p_poly = None    f_q_poly = None    R_poly = None    def __init__(self, N, p, q):        self.N = N        self.p = p        self.q = q        self.R_poly = Poly(x ** N + 1, x).set_domain(ZZ)        log.info("NTRU(N={},p={},q={}) initiated".format(N, p, q))    def generate_random_keys(self):        g_poly = random_poly(self.N)        log.info("g: {}".format(g_poly))        log.info("g coeffs: {}".format(Counter(g_poly.coeffs())))        tries = 10        while tries > 0 and (self.h_poly is None):            f_poly = random_poly(self.N)            log.info("f: {}".format(f_poly))            log.info("f coeffs: {}".format(Counter(f_poly.coeffs())))            try:                self.generate_public_key(f_poly, g_poly)            except NotInvertible as ex:                log.info("Failed to invert f (tries left: {})".format(tries))                log.debug(ex)                tries -= 1        if self.h_poly is None:            raise Exception("Couldn't generate invertible f")    def generate_public_key(self, f_poly, g_poly):        self.f_poly = 2 * f_poly + 1        self.g_poly = g_poly        log.debug("Trying to invert: {}".format(self.f_poly))        self.f_p_poly = invert_poly(self.f_poly, self.R_poly, self.p)        log.debug("f_p ok!")        self.f_q_poly = invert_poly(self.f_poly, self.R_poly, self.q)        log.debug("f_q ok!")        log.info("f_p: {}".format(self.f_p_poly))        log.info("f_q: {}".format(self.f_q_poly))        log.debug("f*f_p mod (x^n - 1): {}".format(((self.f_poly * self.f_p_poly) % self.R_poly).trunc(self.p)))        log.debug("f*f_q mod (x^n - 1): {}".format(((self.f_poly * self.f_q_poly) % self.R_poly).trunc(self.q)))        p_f_q_poly = (self.p * self.f_q_poly).trunc(self.q)        log.debug("p_f_q: {}".format(p_f_q_poly))        h_before_mod = (p_f_q_poly * self.g_poly).trunc(self.q)        log.debug("h_before_mod: {}".format(h_before_mod))        self.h_poly = (2 * h_before_mod % self.R_poly).trunc(self.q)        log.info("h: {}".format(self.h_poly))    def encrypt(self, msg_poly, rand_poly):        log.info("r: {}".format(rand_poly))        log.info("r coeffs: {}".format(Counter(rand_poly.coeffs())))        log.info("msg: {}".format(msg_poly))        log.info("h: {}".format(self.h_poly))        return (((rand_poly * self.h_poly).trunc(self.q) + msg_poly) % self.R_poly).trunc(self.q)    def decrypt(self, msg_poly):        log.info("f: {}".format(self.f_poly))        log.info("f_p: {}".format(self.f_p_poly))        a_poly = ((self.f_poly * msg_poly) % self.R_poly).trunc(self.q)        log.info("a: {}".format(a_poly))        b_poly = a_poly.trunc(self.p)        return b_poly

4.2 秘钥生成

def Key_generation(N,p,q):    f_raw=mathutils.random_poly(N).trunc(2)    f_updated = p * f_raw + 1    modlist=np.zeros(N+1,int)    modlist[0]=1    modlist[-1]=1    #print(modlist)    mod = Poly(modlist, x).set_domain(ZZ)    inv_f_updated = mathutils.invert_poly(f_updated, mod, q)    #print("f:{0}".format(f_updated))    s=mathutils.random_poly(N).trunc(2)    h = ((p * inv_f_updated * s)%mod).trunc(q)    #print(s)    #print(h)    return (f_updated,(h,s))

4.3 加解密

def encryption(N,p,q,pk,m):    modlist = np.zeros(N + 1, int)    modlist[0] = 1    modlist[-1] = 1    # print(modlist)    mod = Poly(modlist, x).set_domain(ZZ)    c = ((pk[0] * pk[1] + m) % mod).trunc(q)    return cdef decryption(N,p,q,sk,c):    modlist = np.zeros(N + 1, int)    modlist[0] = 1    modlist[-1] = 1    # print(modlist)    mod = Poly(modlist, x).set_domain(ZZ)    m = ((sk * c) % mod).trunc(q).trunc(p)    return m

4.4 同态运算

def homo_add(N,p,q,c1,c2):    modlist = np.zeros(N + 1, int)    modlist[0] = 1    modlist[-1] = 1    # print(modlist)    mod = Poly(modlist, x).set_domain(ZZ)    return ((c1+c2)%mod).trunc(q)def homo_mult(N,p,q,c1,c2):    modlist = np.zeros(N + 1, int)    modlist[0] = 1    modlist[-1] = 1    # print(modlist)    mod = Poly(modlist, x).set_domain(ZZ)    return ((c1*c2)%mod).trunc(q)def evaluate(N,p,q,sk1,sk2,c):    modlist = np.zeros(N + 1, int)    modlist[0] = 1    modlist[-1] = 1    # print(modlist)    mod = Poly(modlist, x).set_domain(ZZ)    m=((sk1*sk2*c)%mod).trunc(q).trunc(p)    return m

5. 最终代码及结果

In [4]

import sys sys.path.append('/home/aistudio/wy')import numpy as np# from ntru import mathutils# from sympy.abc import x# from sympy import ZZ, Polydef Key_generation(N,p,q):    f_raw=mathutils.random_poly(N).trunc(2)    f_updated = p * f_raw + 1    modlist=np.zeros(N+1,int)    modlist[0]=1    modlist[-1]=1    #print(modlist)    mod = Poly(modlist, x).set_domain(ZZ)    inv_f_updated = mathutils.invert_poly(f_updated, mod, q)    #print("f:{0}".format(f_updated))    s=mathutils.random_poly(N).trunc(2)    h = ((p * inv_f_updated * s)%mod).trunc(q)    #print(s)    #print(h)    return (f_updated,(h,s))def encryption(N,p,q,pk,m):    modlist = np.zeros(N + 1, int)    modlist[0] = 1    modlist[-1] = 1    # print(modlist)    mod = Poly(modlist, x).set_domain(ZZ)    c = ((pk[0] * pk[1] + m) % mod).trunc(q)    return cdef decryption(N,p,q,sk,c):    modlist = np.zeros(N + 1, int)    modlist[0] = 1    modlist[-1] = 1    # print(modlist)    mod = Poly(modlist, x).set_domain(ZZ)    m = ((sk * c) % mod).trunc(q).trunc(p)    return mdef homo_add(N,p,q,c1,c2):    modlist = np.zeros(N + 1, int)    modlist[0] = 1    modlist[-1] = 1    # print(modlist)    mod = Poly(modlist, x).set_domain(ZZ)    return ((c1+c2)%mod).trunc(q)def homo_mult(N,p,q,c1,c2):    modlist = np.zeros(N + 1, int)    modlist[0] = 1    modlist[-1] = 1    # print(modlist)    mod = Poly(modlist, x).set_domain(ZZ)    return ((c1*c2)%mod).trunc(q)def evaluate(N,p,q,sk1,sk2,c):    modlist = np.zeros(N + 1, int)    modlist[0] = 1    modlist[-1] = 1    # print(modlist)    mod = Poly(modlist, x).set_domain(ZZ)    m=((sk1*sk2*c)%mod).trunc(q).trunc(p)    return mif __name__=="__main__":    N=32    p=32    q=10000723    '''因私有函数库,无法公开进行展示,此处仅对部分技术思路和实验结果进行讲解和展示。    (sk1,pk1)=Key_generation(N, p, q)    #print(sk)    #print(pk)    m1 = Poly([0,1,0,1,1], x).set_domain(ZZ)    c1=encryption(N,p,q,pk1,m1)    print("m1=",m1)    print("m1加密结果:",c1)    m1_decrypted=decryption(N,p,q,sk1,c1)    print("c1解密结果:",m1_decrypted)    (sk2, pk2) = Key_generation(N, p, q)    m2 = Poly([1,0,1,0,0], x).set_domain(ZZ)    c2=encryption(N,p,q,pk2,m2)    print("m2=",m2)    print("m2加密结果:",c2)    m2_decrypted=decryption(N,p,q,sk2,c2)    print("c2解密结果:",m2_decrypted)    #print(homo_add(5,2,97,c,c))    homo_c=homo_mult(N, p, q, c1, c2)    print("m1*m2同态乘结果:",homo_c)    homo_m=evaluate(N,p,q,sk1,sk2,homo_c)    print("m1*m2同态解密结果:",homo_m)    '''

运行结果如下:

m1= Poly(x**3 + x + 1, x, domain='ZZ')m1加密结果: Poly(3284343*x**31 + 2108998*x**30 + 3382527*x**29 - 2022312*x**28 + 1445430*x**27 - 4103553*x**26 + 2186932*x**25 - 2887823*x**24 + 1707515*x**23 - 1961609*x**22 - 4490402*x**21 - 488503*x**20 - 4820228*x**19 - 1419062*x**18 + 4663653*x**17 - 616473*x**16 - 308613*x**15 + 2530948*x**14 - 3788285*x**13 - 2906419*x**12 + 540120*x**11 + 4645349*x**10 - 869216*x**9 + 4873778*x**8 + 2887821*x**7 + 3266827*x**6 - 4884532*x**5 - 533436*x**4 - 2831953*x**3 + 2971347*x**2 + 4985141*x + 118432, x, domain='ZZ')c1解密结果: Poly(x**3 + x + 1, x, domain='ZZ')m2= Poly(x**4 + x**2, x, domain='ZZ')m2加密结果: Poly(633893*x**31 + 3141282*x**30 + 1806755*x**29 + 1074787*x**28 - 4339348*x**27 - 2038976*x**26 + 110016*x**25 - 2084644*x**24 + 941907*x**23 + 764676*x**22 - 1392117*x**21 + 4489722*x**20 + 4260836*x**19 - 4720594*x**18 - 4560990*x**17 + 4477931*x**16 + 91218*x**15 - 971510*x**14 - 2090340*x**13 + 2928978*x**12 - 2315957*x**11 + 2963446*x**10 - 4442306*x**9 + 358189*x**8 - 393412*x**7 - 4145723*x**6 + 4063545*x**5 + 2604736*x**4 + 2841033*x**3 - 2552980*x**2 + 2633358*x + 2589579, x, domain='ZZ')c2解密结果: Poly(x**4 + x**2, x, domain='ZZ')m1*m2同态乘结果: Poly(28479*x**31 - 1950186*x**30 + 4662772*x**29 + 2378350*x**28 + 3222463*x**27 - 3270780*x**26 - 3911557*x**25 + 2268506*x**24 - 4929247*x**23 - 4053986*x**22 + 2746968*x**21 + 2696063*x**20 + 2839513*x**19 - 2438726*x**18 + 1562762*x**17 - 1295123*x**16 + 345153*x**15 - 728221*x**14 - 1510487*x**13 - 1473839*x**12 + 2215256*x**11 + 350121*x**10 - 648692*x**9 - 2116576*x**8 + 1054796*x**7 - 3767592*x**6 + 1611484*x**5 + 474441*x**4 + 961208*x**3 - 953814*x**2 + 2593332*x - 1408044, x, domain='ZZ')m1*m2同态解密结果: Poly(x**7 + 2*x**5 + x**4 + x**3 + x**2, x, domain='ZZ')

以上就是基于NTRU的签名算法学习1的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/768648.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月26日 04:20:43
下一篇 2025年11月26日 04:26:06

相关推荐

  • Uniapp 中如何不拉伸不裁剪地展示图片?

    灵活展示图片:如何不拉伸不裁剪 在界面设计中,常常需要以原尺寸展示用户上传的图片。本文将介绍一种在 uniapp 框架中实现该功能的简单方法。 对于不同尺寸的图片,可以采用以下处理方式: 极端宽高比:撑满屏幕宽度或高度,再等比缩放居中。非极端宽高比:居中显示,若能撑满则撑满。 然而,如果需要不拉伸不…

    2025年12月24日
    400
  • 如何让小说网站控制台显示乱码,同时网页内容正常显示?

    如何在不影响用户界面的情况下实现控制台乱码? 当在小说网站上下载小说时,大家可能会遇到一个问题:网站上的文本在网页内正常显示,但是在控制台中却是乱码。如何实现此类操作,从而在不影响用户界面(UI)的情况下保持控制台乱码呢? 答案在于使用自定义字体。网站可以通过在服务器端配置自定义字体,并通过在客户端…

    2025年12月24日
    800
  • 如何在地图上轻松创建气泡信息框?

    地图上气泡信息框的巧妙生成 地图上气泡信息框是一种常用的交互功能,它简便易用,能够为用户提供额外信息。本文将探讨如何借助地图库的功能轻松创建这一功能。 利用地图库的原生功能 大多数地图库,如高德地图,都提供了现成的信息窗体和右键菜单功能。这些功能可以通过以下途径实现: 高德地图 JS API 参考文…

    2025年12月24日
    400
  • 如何使用 scroll-behavior 属性实现元素scrollLeft变化时的平滑动画?

    如何实现元素scrollleft变化时的平滑动画效果? 在许多网页应用中,滚动容器的水平滚动条(scrollleft)需要频繁使用。为了让滚动动作更加自然,你希望给scrollleft的变化添加动画效果。 解决方案:scroll-behavior 属性 要实现scrollleft变化时的平滑动画效果…

    2025年12月24日
    000
  • 如何为滚动元素添加平滑过渡,使滚动条滑动时更自然流畅?

    给滚动元素平滑过渡 如何在滚动条属性(scrollleft)发生改变时为元素添加平滑的过渡效果? 解决方案:scroll-behavior 属性 为滚动容器设置 scroll-behavior 属性可以实现平滑滚动。 html 代码: click the button to slide right!…

    2025年12月24日
    500
  • 如何选择元素个数不固定的指定类名子元素?

    灵活选择元素个数不固定的指定类名子元素 在网页布局中,有时需要选择特定类名的子元素,但这些元素的数量并不固定。例如,下面这段 html 代码中,activebar 和 item 元素的数量均不固定: *n *n 如果需要选择第一个 item元素,可以使用 css 选择器 :nth-child()。该…

    2025年12月24日
    200
  • 使用 SVG 如何实现自定义宽度、间距和半径的虚线边框?

    使用 svg 实现自定义虚线边框 如何实现一个具有自定义宽度、间距和半径的虚线边框是一个常见的前端开发问题。传统的解决方案通常涉及使用 border-image 引入切片图片,但是这种方法存在引入外部资源、性能低下的缺点。 为了避免上述问题,可以使用 svg(可缩放矢量图形)来创建纯代码实现。一种方…

    2025年12月24日
    100
  • 如何解决本地图片在使用 mask JS 库时出现的跨域错误?

    如何跨越localhost使用本地图片? 问题: 在本地使用mask js库时,引入本地图片会报跨域错误。 解决方案: 要解决此问题,需要使用本地服务器启动文件,以http或https协议访问图片,而不是使用file://协议。例如: python -m http.server 8000 然后,可以…

    2025年12月24日
    200
  • 旋转长方形后,如何计算其相对于画布左上角的轴距?

    绘制长方形并旋转,计算旋转后轴距 在拥有 1920×1080 画布中,放置一个宽高为 200×20 的长方形,其坐标位于 (100, 100)。当以任意角度旋转长方形时,如何计算它相对于画布左上角的 x、y 轴距? 以下代码提供了一个计算旋转后长方形轴距的解决方案: const x = 200;co…

    2025年12月24日
    000
  • 旋转长方形后,如何计算它与画布左上角的xy轴距?

    旋转后长方形在画布上的xy轴距计算 在画布中添加一个长方形,并将其旋转任意角度,如何计算旋转后的长方形与画布左上角之间的xy轴距? 问题分解: 要计算旋转后长方形的xy轴距,需要考虑旋转对长方形宽高和位置的影响。首先,旋转会改变长方形的长和宽,其次,旋转会改变长方形的中心点位置。 求解方法: 计算旋…

    2025年12月24日
    000
  • 旋转长方形后如何计算其在画布上的轴距?

    旋转长方形后计算轴距 假设长方形的宽、高分别为 200 和 20,初始坐标为 (100, 100),我们将它旋转一个任意角度。根据旋转矩阵公式,旋转后的新坐标 (x’, y’) 可以通过以下公式计算: x’ = x * cos(θ) – y * sin(θ)y’ = x * …

    2025年12月24日
    000
  • 如何让“元素跟随文本高度,而不是撑高父容器?

    如何让 元素跟随文本高度,而不是撑高父容器 在页面布局中,经常遇到父容器高度被子元素撑开的问题。在图例所示的案例中,父容器被较高的图片撑开,而文本的高度没有被考虑。本问答将提供纯css解决方案,让图片跟随文本高度,确保父容器的高度不会被图片影响。 解决方法 为了解决这个问题,需要将图片从文档流中脱离…

    2025年12月24日
    000
  • 如何计算旋转后长方形在画布上的轴距?

    旋转后长方形与画布轴距计算 在给定的画布中,有一个长方形,在随机旋转一定角度后,如何计算其在画布上的轴距,即距离左上角的距离? 以下提供一种计算长方形相对于画布左上角的新轴距的方法: const x = 200; // 初始 x 坐标const y = 90; // 初始 y 坐标const w =…

    2025年12月24日
    200
  • CSS元素设置em和transition后,为何载入页面无放大效果?

    css元素设置em和transition后,为何载入无放大效果 很多开发者在设置了em和transition后,却发现元素载入页面时无放大效果。本文将解答这一问题。 原问题:在视频演示中,将元素设置如下,载入页面会有放大效果。然而,在个人尝试中,并未出现该效果。这是由于macos和windows系统…

    2025年12月24日
    200
  • 为什么 CSS mask 属性未请求指定图片?

    解决 css mask 属性未请求图片的问题 在使用 css mask 属性时,指定了图片地址,但网络面板显示未请求获取该图片,这可能是由于浏览器兼容性问题造成的。 问题 如下代码所示: 立即学习“前端免费学习笔记(深入)”; icon [data-icon=”cloud”] { –icon-cl…

    2025年12月24日
    200
  • 如何利用 CSS 选中激活标签并影响相邻元素的样式?

    如何利用 css 选中激活标签并影响相邻元素? 为了实现激活标签影响相邻元素的样式需求,可以通过 :has 选择器来实现。以下是如何具体操作: 对于激活标签相邻后的元素,可以在 css 中使用以下代码进行设置: li:has(+li.active) { border-radius: 0 0 10px…

    2025年12月24日
    100
  • 如何模拟Windows 10 设置界面中的鼠标悬浮放大效果?

    win10设置界面的鼠标移动显示周边的样式(探照灯效果)的实现方式 在windows设置界面的鼠标悬浮效果中,光标周围会显示一个放大区域。在前端开发中,可以通过多种方式实现类似的效果。 使用css 使用css的transform和box-shadow属性。通过将transform: scale(1.…

    2025年12月24日
    200
  • 如何计算旋转后的长方形在画布上的 XY 轴距?

    旋转长方形后计算其画布xy轴距 在创建的画布上添加了一个长方形,并提供其宽、高和初始坐标。为了视觉化旋转效果,还提供了一些旋转特定角度后的图片。 问题是如何计算任意角度旋转后,这个长方形的xy轴距。这涉及到使用三角学来计算旋转后的坐标。 以下是一个 javascript 代码示例,用于计算旋转后长方…

    2025年12月24日
    000
  • 为什么我的 Safari 自定义样式表在百度页面上失效了?

    为什么在 Safari 中自定义样式表未能正常工作? 在 Safari 的偏好设置中设置自定义样式表后,您对其进行测试却发现效果不同。在您自己的网页中,样式有效,而在百度页面中却失效。 造成这种情况的原因是,第一个访问的项目使用了文件协议,可以访问本地目录中的图片文件。而第二个访问的百度使用了 ht…

    2025年12月24日
    000
  • 如何用前端实现 Windows 10 设置界面的鼠标移动探照灯效果?

    如何在前端实现 Windows 10 设置界面中的鼠标移动探照灯效果 想要在前端开发中实现 Windows 10 设置界面中类似的鼠标移动探照灯效果,可以通过以下途径: CSS 解决方案 DEMO 1: Windows 10 网格悬停效果:https://codepen.io/tr4553r7/pe…

    2025年12月24日
    000

发表回复

登录后才能评论
关注微信