Java实现加密(七)国密SM2算法的签名和验签(附商用密码检测相关国家标准/国密标准下载)

目录

    • 一、国密标准中,关于SM2签名验签的定义
    • 二、SM2签名和验签的实现原理
      • 1. 前置知识
      • 2. 签名生成过程
      • 3. 验签过程
      • 4. 数学正确性证明
      • 5. 安全性与注意事项
    • 三、带userId、不带userId的区别
      • 1. 核心区别
      • 2.算法区别
        • (1) 哈希计算过程
        • (2) 签名验签流程
    • 四、Java代码实现
      • 1. Maven 依赖
      • 2. 代码实现
      • 3. 测试结果
      • 4. 签名结果解析R和S
      • 5. 在线验证
    • 五、签名的ASN.1结构解析
      • 1. ASN.1整体结构
      • 2. 字段解析
      • 3. 关键字段说明
      • 4. 为什么需要 `00` 前缀?
      • 5. 实际签名示例
      • 6. 代码验证(Java + Bouncy Castle)
    • 五、补充:商用密码检测相关标准下载
      • 1. GB/T 15843 国家标准(权限鉴别相关)
      • 2. GB/T 38540国家标准(电子 签章相关,参考)
      • 3. GM/T 0003 国密标准(SM2算法)
      • 4. GM/T 0031国密标准(电子签章相关,参考)
      • 5.其余国家标准下载
      • 6. 其余国密标准下载
      • 7. GB/T 38540 国家标准和 GM/T 0031 国密标准的应用场景差异:

一、国密标准中,关于SM2签名验签的定义

参考 《GM∕T 0003-2010 SM2椭圆曲线公钥密码算法.pdf》

其中第2部分对于数字签名的描述如下:

  • 数字签名算法 由一个 签名者 对数据产生数字签名,并由一个 验证者 验证签名的可靠性。每个签名都有一个公钥和私钥,其中私钥用于产生签名,验证者用签名者的公钥验证签名。

标准原始描述截图如下:

在这里插入图片描述

补充:《SM2椭圆曲线公钥密码算法》共分为四个部分:

  • 第1部分:总则
  • 第2部分:数字签名算法
  • 第3部分:密钥交换协议
  • 第4部分:公钥加密算法

注意:在 SM2 算法中涉及的公钥、私钥、签名的长度基本是固定的,以下为标准长度,可以比对参考长度是否争取:

标准公钥:
23BCB208E10056523D4F4090C0130D5B8898A858E8D5D9FF3B16572FA04E70E28A88459060FF5D88CC53D77407619F9B8B584317A30EDDFCA71DC4965F3ED143

标准私钥:
CBD981B9C2FC49D9E497A68EB4EA3AC2E33472CCECBA7EA803B1A1DDB3B0EBCE

标准签名数据:
R:D00C1DEFEAD263A0FEDDE0AEC26274DBB80719385BB3DDD9AB2A31FB11F378C3

R:00CE562BE2CEB0DDD0DD18E925FF00AB87BB67BB33F4234967F82EDC3798265CDF

S:F1BEDD87A2B17D7150E4ECDCFAEB0D3E34AFE5985CB4EFA39D4FDCE7B32CFBE4

在线网址:
SM2 密钥在线生成工具:https://const.net.cn/tool/sm2/genkey/
SM2 在线签名生成工具(带userId):https://const.net.cn/tool/sm2/sign/
SM2 在线验签工具(带userId):https://const.net.cn/tool/sm2/verify/


二、SM2签名和验签的实现原理

1. 前置知识

  • 椭圆曲线参数
    SM2 使用特定的椭圆曲线方程(如 y^2 = x^3 + ax + b )和公开参数:
    • 基点 G(生成元)。
    • n(基点的阶,一个大素数)。
  • 密钥对
    • 私钥 d:随机数,1 ≤ dn−1。
    • 公钥 P:椭圆曲线上的点,P = dG
  • 哈希函数
    SM3 算法(国密标准哈希函数),用于计算消息和用户ID的哈希值。

2. 签名生成过程

签名者对消息 M 生成签名 (r,s),步骤如下:

步骤 1:计算哈希值 ZAe

  • 用户ID哈希(ZA
    将用户ID(如身份证号、邮箱等)与公钥绑定,防止身份伪造:

    Z A = SM3 ( UserID ∥ 公钥坐标 ∥ 曲线参数 ) ZA = \text{SM3}(\text{UserID} \parallel \text{公钥坐标} \parallel \text{曲线参数}) ZA=SM3(UserID公钥坐标曲线参数)

  • 消息哈希(e
    结合 ZA​ 和原始消息 M

    e = SM3 ( Z A ∥ M ) e = \text{SM3}(ZA \parallel M) e=SM3(ZAM)

步骤 2:生成随机数 k

  • 随机选择 k∈[1,n−1],且每次签名必须不同(否则私钥会泄露)。

步骤 3:计算临时椭圆曲线点 (x1, y1)

( x 1 , y 1 ) = k ⋅ G (x₁, y₁) = k \cdot G (x1,y1)=kG

  • x1 的整数形式,计算 r

    r = ( e + x 1 ) m o d n r = (e + x₁) \mod n r=(e+x1)modn

    r=0r+k=n,需重新选择 k

**步骤 4:计算签名值 s

s = ( 1 + d ) − 1 ⋅ ( k − r ⋅ d ) m o d n s = (1 + d)^{-1} \cdot (k - r \cdot d) \mod n s=(1+d)1(krd)modn

  • (1+d)−1 是模 n 下的乘法逆元。
  • s=0,需重新签名。

最终签名

输出 (r,s) 作为数字签名(通常编码为 64 字节,rs 各 32 字节)。


3. 验签过程

验签者使用公钥 P 验证签名 (r, s) 的合法性:

步骤 1:检查 rs 范围

  • 确保 r, s∈[1, n−1],否则验签失败。

步骤 2:重新计算哈希值 e

  • 使用相同的 UserID 和公钥计算 ZAe(与签名过程一致)。

步骤 3:计算中间值 t

t = ( r + s ) m o d n t = (r + s) \mod n t=(r+s)modn

  • t=0,验签失败。

步骤 4:恢复临时点 (x1, y1)

( x 1 , y 1 ) = s ⋅ G + t ⋅ P (x₁, y₁) = s \cdot G + t \cdot P (x1,y1)=sG+tP

  • 利用公钥 P=d⋅G,推导如下:

    s ⋅ G + t ⋅ P = s ⋅ G + t ⋅ d ⋅ P = ( s + t ⋅ d ) ⋅ G s \cdot G + t \cdot P = s \cdot G + t \cdot d \cdot P = (s + t \cdot d) \cdot G sG+tP=sG+tdP=(s+td)G

    • 签名时:

      s ≡ ( 1 + d ) − 1 ⋅ ( k − r d ) m o d n s ≡ (1+d)^{−1} \cdot (k−rd) \mod n s(1+d)1(krd)modn

      ,代入可得:

      s + t ⋅ d ≡ k m o d n s + t \cdot d ≡ k \mod n s+tdkmodn

    • 因此恢复的点应为 k ⋅ G,即签名时的 (x1, y1)

步骤 5:验证 r 的合法性

R = ( e + x 1 ) m o d n R = (e + x₁) \mod n R=(e+x1)modn

  • 检查是否满足 R = r
    • 若成立,验签通过;否则失败。

4. 数学正确性证明

验签的关键在于通过公钥 P 和签名 (r, s) 重构出签名时的临时点 k⋅G

  1. 签名时:

    s ≡ ( 1 + d ) − 1 ( k − r d ) m o d n s \equiv (1 + d)^{-1}(k - r d) \mod n s(1+d)1(krd)modn

  2. 两边乘 (1+d) 得:

    s ( 1 + d ) ≡ k − r d m o d n s(1+d) \equiv k - rd \mod n s(1+d)krdmodn

  3. 整理后:

    k ≡ s + ( s + r ) d m o d n k \equiv s + (s + r)d \mod n ks+(s+r)dmodn

    • 注意到 t = r + s,故 k ≡ s + td mod n
  4. 验签时计算的点:

    s ⋅ G + t ⋅ P = ( s + t d ) ⋅ G = k ⋅ G s \cdot G + t \cdot P = (s + td) \cdot G = k \cdot G sG+tP=(s+td)G=kG

    • 与签名时的 (x1, y1) 一致,确保 x₁ 匹配。

5. 安全性与注意事项

  1. 随机数 k 的安全性
    • k 必须不可预测且不重复,否则攻击者可通过两次签名反推私钥(类似 ECDSA 的漏洞)。
  2. UserID 的作用
    • 绑定用户身份与公钥,防止公钥替换攻击。
  3. 哈希函数
    • 必须使用 SM3 算法,确保与国密标准兼容。
  4. 抵抗攻击
    • 基于椭圆曲线离散对数问题(ECDLP)的困难性,无法从 P=d⋅G 推导出 d

三、带userId、不带userId的区别

SM2的签名验签分为带userId和不带userId两种,主要是根据签名验签时是否需要userId作为入参来进行区分。

  • 带 UserID
    多一步预处理(计算 ZA),将用户身份、公钥和曲线参数绑定到哈希中,形成身份感知的签名
  • 不带 UserID
    跳过预处理,仅哈希原始消息,签名仅依赖公钥和消息本身。

1. 核心区别

特性带 UserID 的 SM2不带 UserID 的 SM2
哈希输入计算 `ZA = SM3(UserID
身份绑定签名与特定用户身份(UserID)强绑定仅绑定公钥和消息,无用户身份信息
安全性防止公钥替换攻击(需伪造 UserID)仅依赖公钥,易受公钥替换攻击
国密标准合规性✅符合 GM/T 0003-2012 标准❌非标准用法,通常不推荐

2.算法区别

(1) 哈希计算过程
  • 带 UserID

    1. 先计算 ZA(用户身份哈希):

      Z A = SM3 ( UserID ∥ 公钥坐标 ∥ 曲线参数 ) ZA = \text{SM3}(\text{UserID} \parallel \text{公钥坐标} \parallel \text{曲线参数}) ZA=SM3(UserID公钥坐标曲线参数)

    2. 再计算消息哈希 e

      e = SM3 ( Z A ∥ M ) e = \text{SM3}(ZA \parallel M) e=SM3(ZAM)

    • 作用:将用户身份、公钥和消息绑定,确保签名无法被其他用户复用。
  • 不带 UserID
    直接计算消息哈希:

    e = SM3 ( Z A ∥ M ) e = \text{SM3}(ZA \parallel M) e=SM3(ZAM)

    • 风险:攻击者可替换公钥,伪造签名(缺乏身份绑定)。
(2) 签名验签流程
  • 带 UserID

    • 签名

      r = ( e + x 1 ) m o d n ( x 1 来自 k ⋅ G ) r = (e + x₁) \mod n \space\space\space\space\space (x₁来自 k\cdot G) r=(e+x1)modn     (x1来自kG)

      s = ( 1 + d ) − 1 ⋅ ( k − r ⋅ d ) m o d n s = (1+d)^{-1} \cdot (k - r \cdot d) \mod n s=(1+d)1(krd)modn

    • 验签
      验签方需使用相同的 UserID 重新计算 ZAe,否则验签失败。

  • 不带 UserID
    跳过 ZA 计算,直接使用 e = SM3(M),其余步骤相同。


四、Java代码实现

1. Maven 依赖

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

2. 代码实现

SM2WithUserIdExample.java

import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithID;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.util.encoders.Hex;import java.security.*;public class SM2WithUserIdExample {static {Security.addProvider(new BouncyCastleProvider());}// SM2曲线参数private static final ECNamedCurveParameterSpec SM2_SPEC = ECNamedCurveTable.getParameterSpec("sm2p256v1");public static void main(String[] args) throws Exception {// 生成SM2密钥对KeyPair keyPair = generateSM2KeyPair();System.out.println("Public Key: " + Hex.toHexString(keyPair.getPublic().getEncoded()));System.out.println("Private Key: " + Hex.toHexString(keyPair.getPrivate().getEncoded()));// 用户IDbyte[] userId = "1234567812345678".getBytes();// 待签名的消息String message = "Hello, SM2!";// 使用用户ID进行签名byte[] signature = signWithUserId(keyPair.getPrivate(), userId, message.getBytes());System.out.println("Signature: " + Hex.toHexString(signature));// 使用用户ID进行验签boolean isValid = verifyWithUserId(keyPair.getPublic(), userId, message.getBytes(), signature);System.out.println("Signature valid: " + isValid);}// 生成SM2密钥对public static KeyPair generateSM2KeyPair() throws Exception {KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC");keyPairGenerator.initialize(SM2_SPEC, new SecureRandom());return keyPairGenerator.generateKeyPair();}// 使用用户ID进行签名public static byte[] signWithUserId(PrivateKey privateKey, byte[] userId, byte[] message) throws Exception {ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(((java.security.interfaces.ECPrivateKey) privateKey).getS(),new ECDomainParameters(SM2_SPEC.getCurve(), SM2_SPEC.getG(), SM2_SPEC.getN()));SM2Signer signer = new SM2Signer();signer.init(true, new ParametersWithID(privKey, userId));signer.update(message, 0, message.length);return signer.generateSignature();}// 使用用户ID进行验签public static boolean verifyWithUserId(PublicKey publicKey, byte[] userId, byte[] message, byte[] signature) throws Exception {java.security.spec.ECPoint publicPoint = ((java.security.interfaces.ECPublicKey) publicKey).getW();org.bouncycastle.math.ec.ECPoint bcPublicPoint = SM2_SPEC.getCurve().createPoint(publicPoint.getAffineX(),publicPoint.getAffineY());ECPublicKeyParameters pubKey = new ECPublicKeyParameters(bcPublicPoint,new ECDomainParameters(SM2_SPEC.getCurve(), SM2_SPEC.getG(), SM2_SPEC.getN()));SM2Signer verifier = new SM2Signer();verifier.init(false, new ParametersWithID(pubKey, userId));verifier.update(message, 0, message.length);return verifier.verifySignature(signature);}
}

3. 测试结果

在这里插入图片描述

Public Key: 04d1a1065f36c116040a5aef12c2f9f34fd26a0af4e639f6602f9ad252fdaddcbe62bb4c7e065b6391822ec56e6822baded04bd98cf909a846e4a17b61cc9ae7de
Private Key: 308193020100301306072a8648ce3d020106082a811ccf5501822d047930770201010420c9e443b10c9f567cfa014f2982a307bf5473612540fc597a1bffa4be8f277b9ca00a06082a811ccf5501822da14403420004d1a1065f36c116040a5aef12c2f9f34fd26a0af4e639f6602f9ad252fdaddcbe62bb4c7e065b6391822ec56e6822baded04bd98cf909a846e4a17b61cc9ae7de
Message: 48656c6c6f2c20534d3221
Signature: 3046022100a3a8ed43fd20d85edfc72744eebf58a205b8c92e87dd7c286770f2e9f22aee68022100fcab418b2961cce41f514fe1851d85266cef66cf5178201778b570e8eebb8d9f
Signature valid: true

4. 签名结果解析R和S

签名内容实际是16进制ASN.1格式的字节流,我们可以使用工具网站进行在线解析。

  • 解析网站: https://the-x.cn/zh-cn/encodings/Asn1.aspx

解析结果如下:

在这里插入图片描述

  • R:A3A8ED43FD20D85EDFC72744EEBF58A205B8C92E87DD7C286770F2E9F22AEE68
  • S:FCAB418B2961CCE41F514FE1851D85266CEF66CF5178201778B570E8EEBB8D9F

5. 在线验证

  • 验证网址: https://const.net.cn/tool/sm2/verify/

我们将对应的公钥、原文、签名(R+S)按照十六进制格式输入之后就可以成功验证了。

注意:

1.公钥信息需要去除04前缀;
2.原文不要直接输入,需要转换为十六进制;
3.签名的R、S需要去除00前缀。

在这里插入图片描述

如果验证结果为空,页面会展示具体的报错原因,在如下图所示的位置:

(例如公钥没有去除 04 前缀时的报错)

在这里插入图片描述


五、签名的ASN.1结构解析

我们将上一步代码生成示例的原签名和解析后的 R、S 进行拆分比对:

在这里插入图片描述

可以发现签名的拼接规律如下:

完整签名=3046+022100+R+022100+S

看到这里,恭喜你!你已经发现了ASN.1结构的规律!

1. ASN.1整体结构

SM2 签名默认输出为 DER 编码的 ASN.1 格式,包含两个整数 rs。完整编码结构如下:

SEQUENCE (30) → 包含两个 INTEGER (02)│├── INTEGER (02) → r└── INTEGER (02) → s

2. 字段解析

3046022100...022100... 为例:

字节位置值(Hex)含义
0-130SEQUENCE 标签,表示后续是一个结构体。
246SEQUENCE 长度,表示后续 70 字节(0x46 = 70)是序列内容。
3-5022100INTEGER 标签和长度,表示 r 是一个 32 字节(0x21 = 33,含前缀 00)的正整数。
6-37...r 的具体值(32 字节)。
38-40022100INTEGER 标签和长度,表示 s 是一个 32 字节的正整数。
41-72...s 的具体值(32 字节)。

3. 关键字段说明

1) 3046

  • 30:ASN.1 的 SEQUENCE 标签(表示复合结构)。
  • 46:序列的 总长度(70 字节),计算如下:
    • r 部分:02(标签) + 21(长度) + 00(前缀) + 32 字节 = 35 字节。
    • s 部分:同上,35 字节。
    • 总计:35 + 35 = 70 字节 → 0x46

2) 022100

  • 02:ASN.1 的 INTEGER 标签。
  • 21:整数的长度(33 字节,包含前缀 00)。
  • 00:前缀字节(因 r/s 的最高位为 1,需补 00 避免被当作负数)。

4. 为什么需要 00 前缀?

  • 规则:若整数的最高位(MSB)为 1,需补 00 避免被误认为是负数(ASN.1 的 INTEGER 是带符号的)。
  • 示例
    • r 的第一个字节是 0x8F(二进制 10001111),需补 00 变为 008F...
    • r 的第一个字节是 0x3F(二进制 00111111),无需补 00

5. 实际签名示例

假设签名值为:

3046022100A1B2C3...32字节)022100D4E5F6...32字节)
  • 解析
    • 30 46:SEQUENCE,长度 70 字节。
    • 02 21 00r 是 33 字节(含前缀 00),实际值 32 字节。
    • A1B2C3...r 的具体数据。
    • 02 21 00s 是 33 字节(含前缀 00),实际值 32 字节。
    • D4E5F6...s 的具体数据。

6. 代码验证(Java + Bouncy Castle)

import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.util.encoders.Hex;public class SM2SignatureParser {public static void main(String[] args) {String derSignature = "3046022100A1B2C3...022100D4E5F6..."; // 示例签名byte[] signatureBytes = Hex.decode(derSignature);// 解析 DER 编码ASN1Sequence sequence = ASN1Sequence.getInstance(signatureBytes);BigInteger r = ((ASN1Integer) sequence.getObjectAt(0)).getValue();BigInteger s = ((ASN1Integer) sequence.getObjectAt(1)).getValue();System.out.println("r: " + r.toString(16));System.out.println("s: " + s.toString(16));}
}

五、补充:商用密码检测相关标准下载

1. GB/T 15843 国家标准(权限鉴别相关)

15843标准共分为6部分,第1部分为总则。

《GB∕T 15843.1-2017 信息技术 安全技术 实体鉴别 第1部分:总则.pdf》
《GB∕T 15843.2-2024 网络安全技术 实体鉴别 第2部分:采用鉴别式加密的机制.pdf》
《GB∕T 15843.3-2023 信息技术 安全技术 实体鉴别 第3部分:采用数字签名技术的机制.pdf》
《GB∕T 15843.4-2024 网络安全技术 实体鉴别 第4部分:采用密码校验函数的机制.pdf》
《GB∕T 15843.5-2005 信息技术 安全技术 实体鉴别 第5部分:使用零知识技术的机制.pdf》
《GB∕T 15843.6-2018 信息技术 安全技术 实体鉴别 第6部分:采用人工数据传递的机制.pdf》

下载地址: https://share.weiyun.com/bEAhW1Ec

如果只是为了检测时满足国家标准,最简单地可以参考第2部分的单次鉴别。

在这里插入图片描述

2. GB/T 38540国家标准(电子 签章相关,参考)

《GB∕T 38540-2020 信息安全技术 安全电子签章密码技术规范.pdf》

下载地址: https://share.weiyun.com/Mw2EwyZl

3. GM/T 0003 国密标准(SM2算法)

《GM∕T 0003-2010 SM2椭圆曲线公钥密码算法.pdf》

下载地址: https://share.weiyun.com/PvwgP2sM

4. GM/T 0031国密标准(电子签章相关,参考)

《GMT 0031-2014 安全电子签章密码技术规范.pdf》

下载地址: https://share.weiyun.com/VA5zlwVW

5.其余国家标准下载

全国网络安全标准化技术委员会:https://www.tc260.org.cn/front/bzcx/yfgbcx.html

(该地址可以下载国家标准文件,但是仅供参考,部分国家标准搜索不到。)

6. 其余国密标准下载

区别于国家标准有版权限制,国密标准可以直接在官方网站进行下载。

国家密码管理局-官网地址: https://www.oscca.gov.cn/sca/index.shtml

例如,我们下载SM3标准,可以先进行搜索,如下所示:

在这里插入图片描述

搜索之后可以看到下面有相关的文件,点击就可以直接下载了。

在这里插入图片描述

在这里插入图片描述

7. GB/T 38540 国家标准和 GM/T 0031 国密标准的应用场景差异:

场景GB/T 38540适用性GM/T 0031适用性
国际化业务(如跨境电子合同)✅ 优先采用❌ 不适用
政府/金融等关键领域可选✅ 强制符合
商用密码产品认证❌ 无法用于过密评✅ 必需符合

整理完毕,完结撒花~🌻





参考地址:

1.SM2 签名验签 注意事项,https://blog.csdn.net/softt/article/details/141570577

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

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

相关文章

Feign接口调用失败降级机制

是的&#xff0c;通过 FallbackFactory 实现的降级逻辑在 Feign 接口调用失败时会被触发&#xff0c;但需要注意以下关键点以确保降级生效&#xff1a; 一、代码有效性分析 降级逻辑是否生效&#xff1f; • 是的&#xff0c;当 Feign 调用 BaseServiceFeign 接口的 updateMoni…

React-JSX语法

1、React和Vue的区别 &#xff08;1&#xff09;设计理念&#xff1a;react是一个声明式UI库&#xff0c;强调的是函数式编程&#xff0c;学习难度较高&#xff0c;vue是渐进式框架&#xff0c;学习难度较低 &#xff08;2&#xff09;模板语法&#xff1a;react使用的是JSX语…

RocketMQ 主题与队列的协同作用解析(既然队列存储在不同的集群中,那要主题有什么用呢?)---管理命令、配置安装

学习之前呢需要会使用linux的基础命令 一.RocketMQ 主题与队列的协同作用解析 在 RocketMQ 中&#xff0c;‌主题&#xff08;Topic&#xff09;‌与‌队列&#xff08;Queue&#xff09;‌的协同设计实现了消息系统的逻辑抽象与物理存储分离。虽然队列实际存储在不同集群的 B…

三菱FX PLC频率采集

基于高速计数器&#xff0c;计算从X点输入方波个数&#xff0c;定时提取计数器值&#xff0c;换算得到频率。直接通过定时器数值判断来实现定时计数的精度不高&#xff0c;提高精度需要考虑定时中断方式。 初始化寄存器&#xff0c;通过M8235&#xff0c;M8236复位来选择C235&a…

一种专用车辆智能配电模块的设计解析:技术革新与未来展望

关键词&#xff1a;智能配电模块、STM32、CAN总线、电子开关、新能源汽车 引言&#xff1a;传统配电系统的痛点与智能化转型 传统配电系统依赖继电器和保险丝&#xff0c;存在体积大、寿命短、智能化低等缺陷&#xff08;如图1&#xff09;。而新能源汽车和无人驾驶技术对配电…

python——异常

1、定义 异常是在代码执行过程中发生的&#xff0c;它会影响到程序的正常运行。python程序不会自动来进行异常处理。python中常见异常父类&#xff1a;Exception。 2、常见异常 TypeError&#xff1a;类型错误异常。ValueError&#xff1a;值的异常。KeyError&#xff1a;键…

深入浅出Sentinel:分布式系统的流量防卫兵

引言 在当今的微服务架构和分布式系统中&#xff0c;服务间的依赖关系错综复杂&#xff0c;一个服务的故障可能会像多米诺骨牌一样引发整个系统的崩溃。如何有效地保护系统免受突发流量、不稳定依赖服务的影响&#xff0c;成为每个架构师和开发者必须面对的挑战。今天&#xf…

leetcode0106. 从中序与后序遍历序列构造二叉树-medium

1 题目&#xff1a;从中序与后序遍历序列构造二叉树 官方标定难度&#xff1a;中 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入…

【Pandas】pandas DataFrame rsub

Pandas2.2 DataFrame Binary operator functions 方法描述DataFrame.add(other)用于执行 DataFrame 与另一个对象&#xff08;如 DataFrame、Series 或标量&#xff09;的逐元素加法操作DataFrame.add(other[, axis, level, fill_value])用于执行 DataFrame 与另一个对象&…

【信息系统项目管理师】高分论文:论人力资源管理与成本管理(医院信息系统)

更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 论文一、规划人力资源管理二、组建项目团队三、建设项目团队四、管理项目团队论文 一个完善的医院信息系统通常由上百个子系统构成,而这些系统随着医院发展需求逐步建设的,他们来源于不同厂家,基于不同的技…

【python】如何将python程序封装为cpython的库

python程序在发布时&#xff0c;往往会打包为cpython的库&#xff0c;并且根据应用服务器的不同架构&#xff08;x86/aarch64&#xff09;&#xff0c;以及python的不同版本&#xff0c;封装的输出类型也是非常多。本文介绍不同架构指定python下的代码打包方式&#xff1a; 首…

Android 14 修改侧滑手势动画效果

涉及关键类 SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt 修改如下&#xff1a; 一&#xff0c;覆盖系统的默认手势效果 SystemUI/src/com/andro…

RHEL与CentOS:从同源到分流的开源操作系统演进

RHEL与CentOS&#xff1a;从同源到分流的开源操作系统演进 一、核心关系&#xff1a;源代码的重构与社区化 RHEL&#xff08;Red Hat Enterprise Linux&#xff09;与CentOS&#xff08;Community ENTerprise Operating System&#xff09;的关系可以概括为“同源异构”。RHE…

EFISH-SBC-RK3588 —— 厘米级定位 × 旗舰算力 × 工业级可靠‌

一、核心参数速览‌ ‌类别‌ ‌技术规格‌ ‌处理器‌ RK3588 八核&#xff08;4Cortex-A762.4GHz 4Cortex-A551.8GHz&#xff09; Mali-G610 GPU 6 TOPS NPU ‌定位能力‌ 双天线差分 GNSS&#xff08;GPS/北斗/GLONASS/Galileo&#xff09;&#xff0c;支持 RTK 动态…

【Unity 与c++通信】Unity与c++通信注意事项,参数传递

一、在Unity中使用c代码 Unity想调用C代码&#xff0c;则需要c开发人员打包成so库。 在Unity中通过DllImport&#xff0c;和dll一样调用。 需要注意的点&#xff1a; C代码需要extern"C"来封装成dll 因为unity默认使用c语言调用外部接口&#xff0c;会对c代码进行命…

DeepSeek+Mermaid:轻松实现可视化图表自动化生成(附实战演练)

目录 一、引言&#xff1a;AI 与图表的梦幻联动二、DeepSeek&#xff1a;大语言模型新星崛起2.1 DeepSeek 全面剖析2.2 多场景应用示例2.2.1 文本生成2.2.2 代码编写 三、Mermaid&#xff1a;代码式图表绘制专家3.1 Mermaid 基础探秘3.2 语法与图表类型详解3.2.1 流程图&#x…

霍格软件测试-JMeter高级性能测试一期

课程大小&#xff1a;32.2G 课程下载&#xff1a;https://download.csdn.net/download/m0_66047725/90631395 更多资源下载&#xff1a;关注我 当下BAT、TMD等互联网一线企业已几乎不再招募传统测试工程师&#xff0c;而只招测试开发工程师&#xff01;在软件测试技术栈迭代…

【Python数据库编程实战】从SQL到ORM的完整指南

目录 前言技术背景与价值当前技术痛点解决方案概述目标读者说明 一、技术原理剖析核心概念图解核心作用讲解关键技术模块说明技术选型对比 二、实战演示环境配置要求核心代码实现案例1&#xff1a;SQLite基础操作案例2&#xff1a;MySQL连接池案例3&#xff1a;SQLAlchemy ORM …

第1讲|R语言绘图体系总览(Base、ggplot2、ComplexHeatmap等)

目录 第1讲|R语言绘图体系总览 ✨ 引言:为什么R绘图如此重要? 🧩 1. Base绘图系统 🧩 2. ggplot2生态系统 🧩 3. ComplexHeatmap超级热图系统 🧩 4. 其他特色绘图库(快速了解) ✏️ 小结一句话 📅 预告下一讲 第1讲|R语言绘图体系总览 (Base、ggplot…

银行卡归属地查询的快速入门:API接口性能与安全兼备的高效实现

在金融和支付领域&#xff0c;获取银行卡的归属信息是一个常见的需求。**万维易源提供的“银行卡归属信息查询”API为开发者和企业提供了高效、便捷的银行卡信息查询服务&#xff0c;可以通过简单的接口调用获取银行卡的归属地、银行名称、电话号码、网址、卡种、银联Luhn效验和…