【密码学实战】Java 实现 SM2 国密算法(签名带id、验签及 C1C3C2 加密解密)

前言

SM2是中国国家密码管理局发布的椭圆曲线公钥密码算法标准(GB/T 32918),属于国密算法体系。与RSA和ECDSA相比,SM2在相同安全强度下密钥更短、计算效率更高。本文将介绍如何在Java中实现SM2的密钥生成数字签名验签加密解密功能。

一、结果验证

1.代码运行结果

1.1 不带id签名验签代码运行结果

在这里插入图片描述

1.2 带id签名验签代码运行结果

在这里插入图片描述

1.3 SM2加密解密代码运行结果

在这里插入图片描述

2.工具验证结果

2.1 不带id签名验签工具运行结果

在这里插入图片描述

2.2 带id签名验签工具运行结果

在这里插入图片描述

2.3 SM2加密解密工具运行结果

在这里插入图片描述

二、SM2签名原理

SM2签名过程的核心是利用私钥对消息进行签名,生成签名值 (r, s)。具体步骤如下:

  1. 计算消息的哈希值
    使用SM3哈希算法对消息 M 进行哈希处理,得到哈希值 e

  2. 生成随机数
    选择一个随机数 k,满足 1 < k < n,其中 n 是椭圆曲线的阶。

  3. 计算椭圆曲线点
    使用随机数 k 计算椭圆曲线上的点 Q = kG,其中 G 是椭圆曲线的基点。取点 Qx 坐标 x1

  4. 计算签名值 r
    计算 r = (e + x1) mod n。如果 r = 0r + k = n,则重新选择随机数 k

  5. 计算签名值 s
    计算 s = (1 + d)^{-1} * (k - r * d) mod n,其中 d 是私钥。

  6. 输出签名结果
    签名结果为 (r, s),通常以字节数组的形式存储和传输。

三、SM2验签原理

SM2验签过程的核心是利用公钥验证签名的有效性。具体步骤如下:

  1. 计算消息的哈希值
    使用SM3哈希算法对消息 M 进行哈希处理,得到哈希值 e

  2. 计算值 t
    计算 t = (r + s) mod n,其中 rs 是签名值。

  3. 计算椭圆曲线点
    计算点 R = sG + tP,其中 G 是椭圆曲线的基点,P 是签名者的公钥。取点 Rx 坐标 x1

  4. 验证签名
    验证等式 r = (e + x1) mod n 是否成立。如果成立,则签名有效;否则,签名无效。

四、SM2签名与验签的Java实现

1. 添加依赖

pom.xml中添加Bouncy Castle依赖:

<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.70</version>
</dependency>

2. 生成密钥对

/*** 生成SM2密钥对。** @return 生成的密钥对(包含公钥和私钥)* @throws Exception 如果密钥生成过程中发生错误*/public static KeyPair generateKeyPair() throws Exception {// 添加Bouncy Castle安全提供者Security.addProvider(new BouncyCastleProvider());// 获取SM2椭圆曲线参数(使用sm2p256v1曲线)ECParameterSpec sm2Spec = ECNamedCurveTable.getParameterSpec("sm2p256v1");// 创建EC密钥对生成器实例KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC");// 初始化密钥对生成器,指定椭圆曲线参数和随机数生成器kpg.initialize(sm2Spec, new SecureRandom());// 生成密钥对并返回return kpg.generateKeyPair();}

3. 签名不带ID

 /*** 使用SM2算法进行签名(不使用用户ID)。** @param data       待签名的数据(字节数组)* @param privateKey 签名使用的私钥* @return 签名结果(字节数组)* @throws Exception 如果签名过程中发生错误*/public static String signNoId(byte[] data, PrivateKey privateKey) throws Exception {// 创建SM2签名实例,指定使用SM3哈希算法Signature signature = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), BouncyCastleProvider.PROVIDER_NAME);// 初始化签名器,使用私钥signature.initSign(privateKey);// 更新待签名的数据signature.update(data);// 生成签名byte[] signatureBytes = signature.sign();// 解析 DER 编码的签名结果ASN1Sequence sequence = ASN1Sequence.getInstance(signatureBytes);BigInteger r = ASN1Integer.getInstance(sequence.getObjectAt(0)).getValue();BigInteger s = ASN1Integer.getInstance(sequence.getObjectAt(1)).getValue();// 打印 r 和 s 的值System.out.println("r 的十六进制值: " + r.toString(16));System.out.println("s 的十六进制值: " + s.toString(16));// 将 r 和 s 拼接为 64 字节的签名结果byte[] rBytes = to32Bytes(r);byte[] sBytes = to32Bytes(s);byte[] rawSignature = new byte[64];System.arraycopy(rBytes, 0, rawSignature, 0, 32);System.arraycopy(sBytes, 0, rawSignature, 32, 32);// 生成签名并返回return Hex.toHexString(rawSignature);}

4. 验签不带ID

/*** 验证SM2签名(不使用用户ID)** @param data       待验证的数据(明文)* @param signature  签名数据(字节数组)* @param publicKey  公钥* @return 验签结果(true表示成功,false表示失败)* @throws Exception 如果验签过程中发生错误*/public static boolean verifyNoId(byte[] data, byte[] signature, PublicKey publicKey) throws Exception {// 初始化SM2签名算法(使用SM3哈希算法)Signature verifier = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), BouncyCastleProvider.PROVIDER_NAME);// 初始化验证器,使用公钥verifier.initVerify(publicKey);// 更新待验证的数据verifier.update(data);// 将 r 和 s 拼接格式的签名结果转换为 DER 编码格式byte[] derSignature = convertRawSignatureToDER(signature);// 验证签名return verifier.verify(derSignature);}

5. 测试代码

public static void main(String[] args) throws Exception {// 生成密钥对KeyPair keyPair = generateKeyPair();PublicKey publicKey = keyPair.getPublic();PrivateKey privateKey = keyPair.getPrivate();// 提取公钥的 x 和 y 坐标String publicKeyX = ((ECPublicKey) publicKey).getQ().getAffineXCoord().toBigInteger().toString(16);String publicKeyY = ((ECPublicKey) publicKey).getQ().getAffineYCoord().toBigInteger().toString(16);// 拼接 x 和 y 坐标String publicKeyXY = publicKeyX + publicKeyY;System.out.println("X: " + publicKeyX);System.out.println("Y: " + publicKeyY);//System.out.println("公钥: " + publicKeyXY);// 打印私钥的十六进制表示BigInteger privateKeyD = ((ECPrivateKey) privateKey).getD();System.out.println("私钥HEX: " + privateKeyD.toString(16));// 待签名数据String data = "12345";String newData = "1234567";byte[] dataBytes = data.getBytes();//System.out.printf("原文: "+data);byte[] newDat = newData.getBytes();//System.out.printf("原文修改: "+newData);// 签名String signature = signNoId(dataBytes, privateKey);System.out.println("签名结果: " + signature);// 验签boolean isValid = verifyNoId(dataBytes, Hex.decode(signature), publicKey);System.out.println("验签值: " + isValid);// 修改原文验签boolean isVa = verifyNoId(newDat, Hex.decode(signature), publicKey);System.out.println("修改原文验签结果: " + isVa);System.out.printf("==========================================================: ");// 签名带idString dataID = "12345";String dataNew = "123456";String userId ="1234567812345678";String signatureId = signWithID(privateKey, publicKey, dataID, userId);System.out.println("带id签名结果: " + signatureId);// 验签带idboolean isValidId = verifyWithID(publicKey, dataID, userId, Hex.decode(signatureId));System.out.println("带id验签值: " + isValidId);// 验签带id原文修改验证boolean isValidIdNew = verifyWithID(publicKey, dataNew, userId, Hex.decode(signatureId));System.out.println("带id验签值原文修改: " + isValidIdNew);}

五 、SM2带ID签名与验签Java实现

SM2签名标准要求计算哈希值时包含用户身份标识(ID),默认ID为空字符串。但在实际应用中(如金融场景),需明确指定用户ID(如身份证号、手机号等)。以下是Java实现方法:

1.算法原理解析

SM2签名算法中,用户ID(即userId)被用于生成一个关键值 ZA,其目的是将用户身份与密钥绑定,增强安全性。具体步骤如下:

  1. ZA值计算
    ZA通过哈希函数(SM3)生成,计算公式为:

    复制

    ZA = HASH( ENTLA || ID || a || b || xG || yG || xA || yA )
    
    • ENTLA:用户ID的比特长度(占2字节,如ID长度256比特则值为0x0100)
    • ID:用户自定义标识(如身份证号、手机号)
    • a, b:椭圆曲线方程参数
    • (xG, yG):椭圆曲线基点坐标
    • (xA, yA):签名方的公钥坐标
  2. 签名过程

    • 输入:私钥、待签名数据M、用户ID
    • 输出:签名结果(r, s)
    1. 计算 ZA(如上)
    2. 计算 e = HASH(ZA || M)
    3. 生成随机数k,计算椭圆曲线点(x1, y1) = [k]G
    4. 计算 r = (e + x1) mod n
    5. 若r=0或r+k=n,则重新生成k
    6. 计算 s = ((1 + d)^−1 * (k − r * d)) mod n(d为私钥)
    7. 返回(r, s)
    
  3. 验签过程

    • 输入:公钥、签名(r, s)、原始数据M、用户ID
    • 输出:验签结果(true/false)
    1. 校验r和s是否在[1, n-1]范围内
    2. 计算 ZA(与签名方相同ID)
    3. 计算 e = HASH(ZA || M)
    4. 计算 t = (r + s) mod n
    5. 计算椭圆曲线点(x1, y1) = [s]G + [t]P(P为公钥)
    6. 验证 R = (e + x1) mod n 是否等于r
    

2.代码实现

  1. 带ID的签名
/*** 使用 SM2 算法进行带用户 ID 的签名,并返回 r 和 s 的拼接结果** @param privateKey 私钥* @param publicKey  公钥* @param data       待签名的数据* @param userId     用户 ID(如企业编号、用户身份证等)* @return 签名结果(Hex 编码的字符串,64 字节)* @throws Exception 如果签名过程中发生错误*/public static String signWithID(PrivateKey privateKey, PublicKey publicKey, String data, String userId) throws Exception {// 将私钥转换为 ECPrivateKeyParametersECPrivateKeyParameters ecPrivateKey = convertPrivateKey(privateKey);// 将公钥转换为 ECPublicKeyParametersECPublicKeyParameters ecPublicKey = convertPublicKey(publicKey);// 创建 SM2 签名器SM2Signer signer = new SM2Signer(new SM3Digest());// 初始化签名器,传入私钥和用户 IDsigner.init(true, new ParametersWithID(ecPrivateKey, userId.getBytes(StandardCharsets.UTF_8)));// 更新待签名的数据signer.update(data.getBytes(StandardCharsets.UTF_8), 0, data.length());// 生成签名byte[] signResult = signer.generateSignature();// 解析 DER 编码的签名结果ASN1Sequence sequence = ASN1Sequence.getInstance(signResult);BigInteger r = ASN1Integer.getInstance(sequence.getObjectAt(0)).getValue();BigInteger s = ASN1Integer.getInstance(sequence.getObjectAt(1)).getValue();// 打印 r 和 s 的值System.out.println("r 的十六进制值: " + r.toString(16));System.out.println("s 的十六进制值: " + s.toString(16));// 将 r 和 s 拼接为 64 字节的签名结果byte[] rBytes = to32Bytes(r);byte[] sBytes = to32Bytes(s);byte[] rawSignature = new byte[64];System.arraycopy(rBytes, 0, rawSignature, 0, 32);System.arraycopy(sBytes, 0, rawSignature, 32, 32);// 返回 Hex 编码的签名结果return Hex.toHexString(rawSignature);}
  1. 带ID的验签
/*** 使用 SM2 算法进行带用户 ID 的验签** @param publicKey  公钥* @param data       待验签的数据* @param userId     用户 ID(必须与签名时一致)* @param signature  签名结果(字节数组,r 和 s 的拼接格式)* @return 验签结果(true 表示验签成功,false 表示验签失败)* @throws Exception 如果验签过程中发生错误*/public static boolean verifyWithID(PublicKey publicKey, String data, String userId, byte[] signature) throws Exception {// 将公钥转换为 ECPublicKeyParametersECPublicKeyParameters ecPublicKey = convertPublicKey(publicKey);// 创建 SM2 验签器SM2Signer verifier = new SM2Signer(new SM3Digest());// 初始化验签器,传入公钥和用户 IDverifier.init(false, new ParametersWithID(ecPublicKey, userId.getBytes(StandardCharsets.UTF_8)));// 更新待验签的数据verifier.update(data.getBytes(StandardCharsets.UTF_8), 0, data.length());// 将 r 和 s 拼接格式的签名结果转换为 DER 编码格式byte[] derSignature = convertRawSignatureToDER(signature);// 验签return verifier.verifySignature(derSignature);}

六、SM2加密与解密Java实现

1.SM2加密原理

  1. SM2加密过程主要基于椭圆曲线的数学特性,通过公钥对明文数据进行加密。具体步骤如下:

    1. 选择椭圆曲线参数
      • 使用椭圆曲线参数(如sm2p256v1),这些参数包括椭圆曲线方程的系数、基点G以及基点的阶n
    2. 生成随机数k
      • 选择一个随机数k1 < k < n),用于生成椭圆曲线上的一个点R = [k]G
    3. 计算密文
      • 使用公钥P(签名方的公钥)和随机点R,根据SM2的加密公式计算密文。SM2支持两种加密模式:
        • C1C3C2模式:密文格式为C1 || C3 || C2
        • C1C2C3模式:密文格式为C1 || C2 || C3
      • 其中:
        • C1是随机点R的编码。
        • C2是经过加密的明文数据。
        • C3是消息的哈希值,用于验证数据完整性。
    4. 输出密文
      • 将计算得到的C1C2C3拼接成最终的密文。

2.SM2解密原理

解密过程是加密的逆操作,使用私钥对密文进行解密,还原出原始明文。具体步骤如下:

  1. 解析密文
    • 将密文拆分为C1C2C3
  2. 计算椭圆曲线点
    • 使用私钥dC1中的点R,根据SM2的解密公式计算椭圆曲线上的一个点。
  3. 还原明文
    • 利用椭圆曲线的数学特性,结合C1C2C3,通过解密公式还原出原始明文。
  4. 验证数据完整性
    • 使用C3验证解密后的数据是否被篡改。

3.代码实现

  1. 添加依赖

pom.xml中添加Bouncy Castle依赖:

<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.70</version>
</dependency>
  1. 生成密钥对
  /*** 生成SM2密钥对*/public static KeyPair generateSM2KeyPair() throws Exception {// 获取SM2椭圆曲线参数X9ECParameters ecParameters = GMNamedCurves.getByName("sm2p256v1");ECParameterSpec ecSpec = new ECParameterSpec(ecParameters.getCurve(),ecParameters.getG(),ecParameters.getN(),ecParameters.getH());// 创建密钥对生成器KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC");keyPairGenerator.initialize(ecSpec, new SecureRandom());return keyPairGenerator.generateKeyPair();}
  1. 公钥加密
 /*** SM2加密(C1C3C2模式)* @param publicKey 公钥* @param data 待加密数据* @return 加密后的字节数组(C1C3C2格式)*/public static byte[] encrypt(BCECPublicKey publicKey, byte[] data) throws Exception {// 获取椭圆曲线参数ECDomainParameters domainParams = new ECDomainParameters(publicKey.getParameters().getCurve(),publicKey.getParameters().getG(),publicKey.getParameters().getN());// 创建加密引擎(默认输出C1C3C2格式)SM2Engine engine = new SM2Engine(SM2Engine.Mode.C1C3C2);// 初始化加密引擎ECPublicKeyParameters pubKeyParams = new ECPublicKeyParameters(publicKey.getQ(),domainParams);engine.init(true, new ParametersWithRandom(pubKeyParams, new SecureRandom()));return engine.processBlock(data, 0, data.length);}
  1. 私钥解密
/*** SM2解密(C1C3C2模式)* @param privateKey 私钥* @param cipherData 密文数据(C1C3C2格式)* @return 解密后的字节数组*/public static byte[] decrypt(BCECPrivateKey privateKey, byte[] cipherData) throws Exception {// 获取椭圆曲线参数ECDomainParameters domainParams = new ECDomainParameters(privateKey.getParameters().getCurve(),privateKey.getParameters().getG(),privateKey.getParameters().getN());// 创建解密引擎(设置为C1C3C2模式)SM2Engine engine = new SM2Engine(SM2Engine.Mode.C1C3C2);// 初始化解密引擎ECPrivateKeyParameters priKeyParams = new ECPrivateKeyParameters(privateKey.getD(),domainParams);engine.init(false, priKeyParams);return engine.processBlock(cipherData, 0, cipherData.length);}

注意事项

  1. 密钥管理:私钥需安全存储(如密码机或云密码机等)
  2. 性能优化:加解密大数据时建议使用SM4对称加密配合SM2密钥交换
  3. ID编码userId.getBytes() 需与业务方约定编码格式(如UTF-8、HEX等)
  4. 长度限制:ID长度建议不超过65535字节(规范限制)
  5. 跨系统交互:与其他系统(如C++、Go)对接时需确认ID处理逻辑一致性

总结

希望这篇文章对你有所帮助!如果觉得不错,别忘了关注哦!

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

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

相关文章

网络原理---TCP/IP

活动发起人小虚竹 想对你说&#xff1a; 这是一个以写作博客为目的的创作活动&#xff0c;旨在鼓励大学生博主们挖掘自己的创作潜能&#xff0c;展现自己的写作才华。如果你是一位热爱写作的、想要展现自己创作才华的小伙伴&#xff0c;那么&#xff0c;快来参加吧&#xff01…

【大语言模型笔记进阶一步】提示语设计学习笔记,跳出框架思维,自己构建提示词

一、大语言模型应用场景 1. 文本生成 文本创作&#xff1a; 诗歌故事&#xff0c;剧本&#xff0c;推文帖子 摘要与改写&#xff1a; 长文本摘要与简化&#xff0c;多语言翻译与本地化 结构化生成&#xff1a; 表格&#xff0c;根据需求生成代码片段&#xff0c;API文档生成…

Unity XR-XR Interaction Toolkit开发使用方法(十一)组件介绍(XR Interactable)

目录 一、插件介绍 二、主要组件 XR Interaction Manager XR Controller XR Interactor XR Direct Interactor XR Ray Interactor XR Socket Interactor XR Gaze Interactor XR Interaction Group 三、XR Interactable 1、组件介绍 2、核心功能与特点 交互类型支…

Spring Boot spring-boot-maven-plugin 参数配置详解

一 spring-boot-maven-plugin 插件的5个Goals spring-boot:repackage&#xff0c;默认goal。在mvn package之后&#xff0c;再次打包可执行的jar/war&#xff0c;同时保留mvn package生成的jar/war为.origin&#xff1b;重新打包存在的jar或者war包从而使他们可以在命令行使用…

eMMC安全简介

1. 引言 术语“信息安全”涵盖多种不同的设计特性。一般而言&#xff0c; 信息安全是指通过实践防止信息遭受未经授权的访问、使用、披露、中断、篡改、检查、记录或销毁。 信息安全的三大核心目标为 机密性&#xff08;Confidentiality&#xff09;、完整性&#xff08;Integr…

Python 数据结构 2.时间复杂度和空间复杂度

Life is a journey —— 25.2.28 一、引例&#xff1a;穷举法 1.单层循环 所谓穷举法&#xff0c;就是我们通常所说的枚举&#xff0c;就是把所有情况都遍历了的意思。 例&#xff1a;给定n&#xff08;n ≤ 1000&#xff09;个元素ai&#xff0c;求其中奇数有多少个 判断一…

FFmpeg-chapter3-读取视频流(原理篇)

ffmpeg网站&#xff1a;About FFmpeg 1 库介绍 &#xff08;1&#xff09;libavutil是一个包含简化编程函数的库&#xff0c;包括随机数生成器、数据结构、数学例程、核心多媒体实用程序等等。 &#xff08;2&#xff09;libavcodec是一个包含音频/视频编解码器的解码器和编…

面试(进阶) —虚拟列表在什么场景使用,如何实现?

面试(进阶) —虚拟列表在什么场景使用&#xff0c;如何实现&#xff1f; 在前端开发中&#xff0c;当需要渲染大量数据时&#xff0c;传统的渲染方式往往会遇到性能瓶颈。一次性将大量数据渲染到DOM中&#xff0c;不仅会导致页面加载缓慢&#xff0c;还可能占用大量内存&#x…

Linux Mem -- 关于AArch64 MTE功能的疑问

目录 1.虚拟地址和物理地址映射完成后&#xff0c;才可以设置虚拟地址对应的memory tag &#xff1f; 2.各种memory allocator中的address tag从哪来&#xff0c;怎么产生&#xff1f; 2.1 vmalloc allocator 2.2 slub分配器 2.3 用户可以指定IRG指令产生的address tag 3.kasan…

python-leetcode-颜色分类

75. 颜色分类 - 力扣&#xff08;LeetCode&#xff09; class Solution:def sortColors(self, nums: List[int]) -> None:"""Do not return anything, modify nums in-place instead."""low, mid, high 0, 0, len(nums) - 1while mid < h…

ArcGIS Pro技巧实战:高效矢量化天地图地表覆盖图

在地理信息系统&#xff08;GIS&#xff09;领域&#xff0c;地表覆盖图的矢量化是一项至关重要的任务。天地图作为中国国家级的地理信息服务平台&#xff0c;提供了丰富且详尽的地表覆盖数据。然而&#xff0c;这些数据通常以栅格格式存在&#xff0c;不利于进行空间分析和数据…

【江科大STM32】TIM输出比较(学习笔记)

本章图片文字内容也为重要知识&#xff0c;请马住&#xff01; 输出比较简介 OC&#xff08;Output Compare&#xff09;输出比较输出比较可以通过比较CNT与CCR寄存器值的关系&#xff0c;来对输出电平进行置1、置0或翻转的操作&#xff0c;用于输出一定频率和占空比的PWM波形…

【网络安全 | 漏洞挖掘】利用文件上传功能的 IDOR 和 XSS 劫持会话

未经许可,不得转载。 本文涉及漏洞均已修复。 文章目录 前言正文前言 想象这样一个场景:一个专门处理敏感文档的平台,如保险理赔或身份验证系统,却因一个设计疏漏而成为攻击者的“金矿”。在对某个保险门户的文件上传功能进行测试时,我意外发现了一个可导致大规模账户接管…

飞算 JavaAI 如何让微服务开发快人一步?

在当今竞争激烈的软件开发领域&#xff0c;微服务架构因其灵活性和可扩展性备受青睐。然而&#xff0c;微服务开发过程复杂&#xff0c;从需求分析到最终代码实现&#xff0c;每个环节都需要耗费大量时间和精力。飞算 JavaAI 的出现&#xff0c;犹如一道曙光&#xff0c;为开发…

Python—Excel全字段转json文件(极速版+GUI界面打包)

目录 专栏导读1、背景介绍2、库的安装3、核心代码4、完整代码(简易版)5、进阶版(GUI)总结专栏导读 🌸 欢迎来到Python办公自动化专栏—Python处理办公问题,解放您的双手 🏳️‍🌈 博客主页:请点击——> 一晌小贪欢的博客主页求关注 👍 该系列文章专栏:请点击——…

2025年光电科学与智能传感国际学术会议(ICOIS 2025)

重要信息 官网&#xff1a;www.ic-icois.org 时间&#xff1a;2025年3月14-16日 地点&#xff1a;中国-长春 简介 2025年光电科学与智能传感国际学术会议&#xff08;ICOIS 2025&#xff09;将于2025年3月14-16日在中国-长春隆重召开。会议将围绕“光学光电”、“智能传感”…

企业微信里可以使用的企业内刊制作工具,FLBOOK

如何让员工及时了解公司动态、行业资讯、学习专业知识&#xff0c;并有效沉淀企业文化&#xff1f;一份高质量的企业内刊是不可或缺的。现在让我来教你该怎么制作企业内刊吧 1.登录与上传 访问FLBOOK官网&#xff0c;注册账号后上传排版好的文档 2.选择模板 FLBOOK提供了丰富的…

YOLOv5 + SE注意力机制:提升目标检测性能的实践

一、引言 目标检测是计算机视觉领域的一个重要任务&#xff0c;广泛应用于自动驾驶、安防监控、工业检测等领域。YOLOv5作为YOLO系列的最新版本&#xff0c;以其高效性和准确性在实际应用中表现出色。然而&#xff0c;随着应用场景的复杂化&#xff0c;传统的卷积神经网络在处…

跟我学C++中级篇——定时器的设计

一、定时器 谈到定时器&#xff0c;理论上讲是各种语言和各种设计都无法避开的一个技术点。对于定时器来说&#xff0c;表面上就是一种时间间隔的处理约定&#xff0c;但对程序来说&#xff0c;可能就是设计层面、接口层面和库或框架以及系统应用的一个大集合。不同的系统&…

智能机器人加速进化:AI大模型与传感器的双重buff加成

Deepseek不仅可以在手机里为你解答现在的困惑、占卜未来的可能&#xff0c;也将成为你的贴心生活帮手&#xff01; 2月21日&#xff0c;追觅科技旗下Dreamehome APP正式接入DeepSeek-R1大模型&#xff0c;2月24日发布的追觅S50系列扫地机器人也成为市面上首批搭载DeepSeek-R1的…