基于JPBC的无证书聚合签名方案实现
基于JPBC的无证书聚合签名方案实现
摘要
一开始签名方案是基于PKI的,无证书签名起源于 基于身份密码体制, 2009 年第一篇无证书签名方案1被提出,随后出现了一些列方案2,3;包括无配对的无证书聚合签名方案4,更多内容参考文献5.
暂时没有看见无证书聚合签名方案实现相关的代码,本文基于JPBC库实现,使用方法可以参考B站视频。也可以使用C++和PBC库实现。
方案概述
本文方案是基于论文3描述的。
Setup:
给定安全参数 κ ∈ Z \kappa \in Z κ∈Z,KGC选择两个循环群 G 1 G_1 G1 、 G 2 G_2 G2,其阶均为素数 q q q , G 1 G_1 G1 的生成元 P P P,计算可接受的配对 e : G 1 × G 1 → G 2 e:G_1×G_1→G_2 e:G1×G1→G2 。 KGC 随机选择主密钥 s ∈ Z q ∗ s\in Z_q^\ast s∈Zq∗ ,设置 P p u b = s P P_{pub}=sP Ppub=sP ,选择加密哈希函数 H 1 : { 0 , 1 } ∗ → G 1 H_1:\{0,1\}^\ast→G_1 H1:{0,1}∗→G1 , H 2 : { 0 , 1 } ∗ → G 1 H_2:\{0,1\}^\ast→G_1 H2:{0,1}∗→G1, H 3 : { 0 , 1 } ∗ → Z q ∗ H_3:\{0,1\}^\ast→Z_q^\ast H3:{0,1}∗→Zq∗. 系统参数为 { q , G 1 , G 2 , e , P , P p u b , H 1 , H 2 , H 3 } \{q,G_1,G_2,e,P,P_{pub},H_1,H_2,H_3 \} {q,G1,G2,e,P,Ppub,H1,H2,H3}, 主密钥是s。
PartialKeyGen:
给定用户身份 I D i ∈ { 0 , 1 } ∗ ID_i\in \{0,1\}^\ast IDi∈{0,1}∗,KGC首先计算 Q I D i = H 1 ( I D i ) Q_{ID_i }=H_1 (ID_i) QIDi=H1(IDi)。 然后,它设置该用户的部分密钥 p s k I D i = s Q ( I D i ) psk_{ID_i }=sQ_(ID_i ) pskIDi=sQ(IDi)并将其通过安全通道传输给对应用户。 用户可以通过检查是否正确来检查其正确性 e ( p s k I D i , P ) = e ( Q I D i , P p u b ) e(psk_{ID_i },P)=e(Q_{ID_i },P_{pub}) e(pskIDi,P)=e(QIDi,Ppub)。
UserKeyGen:
用户 I D i ID_i IDi随机选择值 x I D i ∈ Z q ∗ x_{ID_i }\in Z_q^\ast xIDi∈Zq∗作为他的用户私钥 u s k I D i usk_{ID_i } uskIDi,并且计算用户公钥 u p k I D i = x I D i P upk_{ID_i}=x_{ID_i } P upkIDi=xIDiP。
Sign:
对于消息 m i ∈ 0 , 1 ∗ m_i∈{0,1}^\ast mi∈0,1∗,选择状态信息 ∆ ∆ ∆(选择公开参数作为状态信息),具有 I D i ID_i IDi身份的签名者执行以下步骤:
- 选择随机数 r i ∈ Z q ∗ r_i∈Z_q^\ast ri∈Zq∗并且计算 U i = r i P ∈ G 1 U_i=r_i P∈G_1 Ui=riP∈G1.
- 计算 Q = H 2 ( ∆ ) , h i = H 3 ( m i , I D i , u p k I D i , U i ) Q=H_2(∆),h_i=H_3(m_i,ID_i,upk_{ID_i},U_i) Q=H2(∆),hi=H3(mi,IDi,upkIDi,Ui)
- 计算 V i = p s k I D i + r i ⋅ Q + h i ⋅ x i ⋅ P p u b V_i=psk_{ID_i }+r_i⋅Q+h_i⋅x_i⋅P_{pub} Vi=pskIDi+ri⋅Q+hi⋅xi⋅Ppub.
输出 ( U i , V i ) (U_i,V_i ) (Ui,Vi)作为 m i m_i mi的签名。
Verify :
给定一个消息 m i m_i mi签名 ( U i , V i ) (U_i,V_i ) (Ui,Vi),其对应的身份为 I D i ID_i IDi和公钥 u p k I D i upk_{ID_i} upkIDi,计算 Q ( I D i ) = H 1 ( I D i ) , Q = H 2 ( ∆ ) Q_(ID_i )=H_1 (ID_i ),Q=H_2 (∆) Q(IDi)=H1(IDi),Q=H2(∆) ,
h i = H 3 ( m i , I D i , u p k I D i , U i ) h_i=H_3 (m_i,ID_i,upk_{ID_i },U_i ) hi=H3(mi,IDi,upkIDi,Ui)
如果等式 e ( V i , P ) = e ( h i ⋅ u p k I D i + Q I D i , P p u b ) e ( U i , Q ) e(V_i,P)=e(h_i⋅upk_{ID_i }+Q_{ID_i },P_{pub} )e(U_i,Q) e(Vi,P)=e(hi⋅upkIDi+QIDi,Ppub)e(Ui,Q) 成立,接收签名;否则拒绝。
Aggregate:
任何人都可以充当聚合签名生成器, 对于n个用户的聚合集 { U 1 , … , U n } \{U_1,…,U_n\} {U1,…,Un}其对应身份为 { I D 1 , … , I D n } \{ID_1,…,ID_n \} {ID1,…,IDn}以及对应公钥 { u p k 1 , … , u p k n } \{upk_1,…,upk_n\} {upk1,…,upkn},对应消息签名对为 { ( m 1 , σ 1 = ( U 1 , V 1 ) ) , … , ( m n , σ n = ( U n , V n ) ) } \{(m_1,σ_1=(U_1,V_1 )),…,(m_n,σ_n=(U_n,V_n))\} {(m1,σ1=(U1,V1)),…,(mn,σn=(Un,Vn))},
聚合签名计算: V = ∑ i = 1 n V i V=∑_{i=1}^n V_i V=∑i=1nVi, 将 σ = ( U 1 , … , U n , V ) σ=(U_1,…,U_n,V) σ=(U1,…,Un,V)作为聚合签名。
Aggregate-Verify:
验证聚合签名 σ = ( U 1 , … , U n , V ) σ=(U_1,…,U_n,V) σ=(U1,…,Un,V)由n个用户 { U 1 , … , U n } \{U_1,…,U_n\} {U1,…,Un}身份为 { I D 1 , … , I D n } \{ID_1,…,ID_n\} {ID1,…,IDn}和对应的公钥 { u p k 1 , … , u p k n } \{upk_1,…,upk_n\} {upk1,…,upkn};关于消息 { m 1 , … , m n } \{m_1,…,m_n \} {m1,…,mn} 验证者执行以下操作:
计算 Q I D i = H 1 ( I D i ) , Q = H 2 ( ∆ ) , h i = H 3 ( m i , I D i , u p k I D i , U i ) , i = 1 , … , n Q_{ID_i }=H_1 (ID_i ),Q=H_2 (∆),h_i=H_3 (m_i,ID_i,upk_{ID_i },U_i ),i=1,…,n QIDi=H1(IDi),Q=H2(∆),hi=H3(mi,IDi,upkIDi,Ui),i=1,…,n.
验证: e ( V , P ) = e ( ∑ i = 1 n [ h i ⋅ u p k I D i + Q I D i ] , P p u b ) e ( ∑ i = 1 n U i , Q ) e(V,P)=e(∑_{i=1}^n [h_i⋅upk_{ID_i}+Q_{ID_i} ] ,P_{pub} )e(∑_{i=1}^n U_i ,Q) e(V,P)=e(∑i=1n[hi⋅upkIDi+QIDi],Ppub)e(∑i=1nUi,Q).如果满足则通过;否则验证失败。
代码实现
整体思路, 将相关密钥信息作为文件保存(序列化后可以通过网络传输),根据方案不同的功能设计不同的函数。
关于文件a_181_603.properties的内容
type=a
q=98826429041171753291515535532523512299028170537954154869719707264887274916552228805607584116490046284509883309001532457986879277885241872021906840932513241346999389365188296460009947
h=32243626948934860887488490158437299489453513352745889246437755713701521031193083418924110592954582395114812811896992400310730276
r=3064991081731777546575510593831386635550174528483098623
exp2=181
exp1=127
sign1=-1
sign0=-1
代码
import it.unisa.dia.gas.jpbc.Element;
import it.unisa.dia.gas.jpbc.Pairing;
import it.unisa.dia.gas.plaf.jpbc.pairing.PairingFactory;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;public class CLAS {//生成公私钥对,并保存到文件中public static void Setup(String pairingParametersFileName, String pubParamFileName, String KGC_SK_FileName) {Pairing bp = PairingFactory.getPairing(pairingParametersFileName);//G1的生成元PElement P = bp.getG1().newRandomElement().getImmutable();//计算主私钥和公钥Element s = bp.getZr().newRandomElement().getImmutable();Element P_Pub = P.mulZn(s);Properties pubParamProp = new Properties();//后面对写的元素统一采用如下方法:首先将元素转为字节数组,然后进行Base64编码为可读字符串pubParamProp.setProperty("P", Base64.getEncoder().encodeToString(P.toBytes()));pubParamProp.setProperty("P_Pub", Base64.getEncoder().encodeToString(P_Pub.toBytes()));storePropToFile(pubParamProp, pubParamFileName);Properties param_s = new Properties();//私钥不存入公开参数中,由KGC自己保存param_s.setProperty("s", Base64.getEncoder().encodeToString(s.toBytes()));storePropToFile(param_s, KGC_SK_FileName);}//根据用户id生成私钥public static void PartialPrivateKeyGen(String pairingParametersFileName, String id, String KGC_SK_FileName) throws NoSuchAlgorithmException {Pairing bp = PairingFactory.getPairing(pairingParametersFileName);//使用HASH 将 id 转为QIDbyte[] idHash = HASH(id);Element QID = bp.getG1().newElementFromHash(idHash, 0, idHash.length).getImmutable();//从文件中读取 主私钥Properties mskProp = loadPropFromFile(KGC_SK_FileName);String sString = mskProp.getProperty("s");Element s = bp.getZr().newElementFromBytes(Base64.getDecoder().decode(sString)).getImmutable(); //Base64编码后对应的恢复元素的方法//计算用户私钥, 这里应该将私钥安全的传输给用户//方便模拟,统一存入一个文件中Element psk_ID = QID.powZn(s).getImmutable();Properties pskProp = new Properties();pskProp.setProperty("psk", Base64.getEncoder().encodeToString(psk_ID.toBytes()));storePropToFile(pskProp, id + ".properties");}//生成用户私钥public static void UserKeyGen(String pairingParametersFileName, String pubParamFileName, String id) {Pairing bp = PairingFactory.getPairing(pairingParametersFileName);//从文件中读取公钥Properties pkProp = loadPropFromFile(pubParamFileName);String PString = pkProp.getProperty("P");Element P = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(PString)).getImmutable();//生成随机数x,作为用户的私钥Element x = bp.getZr().newRandomElement().getImmutable();//计算用户公钥Element upk = P.mulZn(x);Properties userProp = new Properties();userProp.setProperty("usk", Base64.getEncoder().encodeToString(x.toBytes()));userProp.setProperty("upk", Base64.getEncoder().encodeToString(upk.toBytes()));storePropToFile(userProp, id + ".properties");}//签名public static Element[] Sign(String pairingParametersFileName, String pubParamFileName, String id, byte[] message) throws NoSuchAlgorithmException {Pairing bp = PairingFactory.getPairing(pairingParametersFileName);//获取公开参数Properties pubProp = loadPropFromFile(pubParamFileName);Element P = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(pubProp.getProperty("P"))).getImmutable();Element P_Pub = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(pubProp.getProperty("P_Pub"))).getImmutable();//获取用户自己的信息Properties userProp = loadPropFromFile(id + ".properties");Element upk = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(userProp.getProperty("upk"))).getImmutable();Element x = bp.getZr().newElementFromBytes(Base64.getDecoder().decode(userProp.getProperty("usk"))).getImmutable();Element psk = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(userProp.getProperty("psk"))).getImmutable();//选择随机数Element r = bp.getZr().newRandomElement();Element U = P.mulZn(r).getImmutable();//获取状态信息,将公开参数作为状态信息String p = pubProp.getProperty("P");String pPub = pubProp.getProperty("P_Pub");byte[] hash = HASH(p + pPub);Element Q = hashToG(bp, hash);// 计算m, id, upk,U组合的hash值byte[] res = hashCombination(message, id.getBytes(), upk.toBytes(), U.toBytes());Element h = hashToZ(bp, res);Element V = P_Pub.mulZn(x).mulZn(h).add(Q.mulZn(r)).add(psk).getImmutable();Element[] sigma = new Element[2];sigma[0] = U;sigma[1] = V;return sigma;}//验证public static boolean Verify(String pairingParametersFileName, String pubParamFileName, String id, byte[] message, Element[] sigma) throws NoSuchAlgorithmException {Pairing bp = PairingFactory.getPairing(pairingParametersFileName);//使用sha1 将 id 转为QIDbyte[] idHash = HASH(id);Element QID = bp.getG1().newElementFromHash(idHash, 0, idHash.length).getImmutable();//获取公开参数Properties pubProp = loadPropFromFile(pubParamFileName);Element P = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(pubProp.getProperty("P"))).getImmutable();Element P_Pub = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(pubProp.getProperty("P_Pub"))).getImmutable();//获取状态信息,将公开参数作为状态信息String p = pubProp.getProperty("P");String pPub = pubProp.getProperty("P_Pub");byte[] hash = HASH(p + pPub);Element Q = hashToG(bp, hash);//获取用户的公钥,Properties userProp = loadPropFromFile(id + ".properties");Element upk = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(userProp.getProperty("upk"))).getImmutable();// 计算m, id, upk,U组合的hash值byte[] res = hashCombination(message, id.getBytes(), upk.toBytes(), sigma[0].toBytes());Element h = hashToZ(bp, res);Element left = bp.pairing(sigma[1], P);Element right = bp.pairing(QID.add(upk.mulZn(h)), P_Pub).mul(bp.pairing(sigma[0], Q));return left.isEqual(right);}//聚合签名, U_1,U_2,...,U_n,Vpublic static Element[] Aggregate(List<Element[]> sigmaList) {Element[] res = new Element[sigmaList.size() + 1];Element[] init = sigmaList.get(0);res[0] = init[0];Element V = init[1];for (int i = 1; i < sigmaList.size(); i++) {res[i] = sigmaList.get(i)[0];V = V.add(sigmaList.get(1)[1]);}res[sigmaList.size()] = V;return res;}// 聚合签名验证public static boolean AggregateVerify(String pairingParametersFileName, String pubParamFileName, String[] idx, byte[][] message, Element[] sigma) throws NoSuchAlgorithmException {Pairing bp = PairingFactory.getPairing(pairingParametersFileName);Element[] QIDX = new Element[idx.length];for (int i = 0; i < idx.length; i++) {byte[] idHash = HASH(idx[i]);Element QID = bp.getG1().newElementFromHash(idHash, 0, idHash.length).getImmutable();QIDX[i] = QID;}//获取公开参数信息Properties pubProp = loadPropFromFile(pubParamFileName);Element P = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(pubProp.getProperty("P"))).getImmutable();Element P_Pub = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(pubProp.getProperty("P_Pub"))).getImmutable();String p = pubProp.getProperty("P");String pPub = pubProp.getProperty("P_Pub");byte[] hash = HASH(p + pPub);Element Q = hashToG(bp, hash);Element[] PKX = new Element[idx.length];for (int i = 0; i < idx.length; i++) {Properties userProp = loadPropFromFile(idx[i] + ".properties");Element upk = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(userProp.getProperty("upk"))).getImmutable();PKX[i] = upk;}Element[] hx = new Element[idx.length];for (int i = 0; i < idx.length; i++) {byte[] res = hashCombination(message[i], idx[i].getBytes(), PKX[i].toBytes(), sigma[i].toBytes());Element h = hashToZ(bp, res);hx[i] = h;}Element left = bp.pairing(sigma[idx.length], P);Element U = sigma[0];for (int i = 1; i < idx.length; i++) {U = U.add(sigma[i]);}Element part = QIDX[0].add(PKX[0].mulZn(hx[0]));for (int i = 1; i < idx.length; i++) {part = part.add(QIDX[i].add(PKX[i].mulZn(hx[i])));}Element right = bp.pairing(part, P_Pub).mul(bp.pairing(U, Q));return left.isEqual(right);}//一种可行的组合方法public static byte[] hashCombination(byte[] message, byte[] id, byte[] upk, byte[] U) throws NoSuchAlgorithmException {int m_len = message.length, id_len = id.length, upk_len = upk.length, u_len = U.length;int total_len = m_len + id_len + upk_len + u_len;byte[] res = new byte[total_len];for (int i = 0; i < m_len; i++) {res[i] = message[i];}for (int i = 0; i < id_len; i++) {res[i + m_len] = id[i];}for (int i = 0; i < upk_len; i++) {res[i + m_len + id_len] = upk[i];}for (int i = 0; i < u_len; i++) {res[i + m_len + id_len + upk_len] = U[i];}MessageDigest instance = MessageDigest.getInstance("SHA-256");instance.update(res);return instance.digest();}public static void storePropToFile(Properties prop, String fileName) {try (FileOutputStream out = new FileOutputStream(fileName, true)) {prop.store(out, null);} catch (IOException e) {e.printStackTrace();System.out.println(fileName + " save failed!");System.exit(-1);}}public static Properties loadPropFromFile(String fileName) {Properties prop = new Properties();try (FileInputStream in = new FileInputStream(fileName)) {prop.load(in);} catch (IOException e) {e.printStackTrace();System.out.println(fileName + " load failed!");System.exit(-1);}return prop;}public static byte[] HASH(String content) throws NoSuchAlgorithmException {MessageDigest instance = MessageDigest.getInstance("SHA-1");instance.update(content.getBytes());return instance.digest();}public static Element hashToG(Pairing pb, byte[] code) {return pb.getG1().newElementFromHash(code, 0, code.length).getImmutable();}public static Element hashToZ(Pairing pb, byte[] code) {return pb.getZr().newElementFromHash(code, 0, code.length).getImmutable();}public static void main(String[] args) throws Exception {String pairingParametersFileName = "a_181_603.properties";String idAlice = "alice@example.com";String idBob = "bob@example.com";String pubParamFileName = "data/pub.properties";String KGCFileName = "data/kgc.properties";Setup(pairingParametersFileName, pubParamFileName, KGCFileName);PartialPrivateKeyGen(pairingParametersFileName, idAlice, KGCFileName);PartialPrivateKeyGen(pairingParametersFileName, idBob, KGCFileName);UserKeyGen(pairingParametersFileName, pubParamFileName, idAlice);UserKeyGen(pairingParametersFileName, pubParamFileName, idBob);String message_a = "Alice,This is a message from Alice!";String message_b = "Bob,This is a message from Bob!";Element[] sigma1 = Sign(pairingParametersFileName, pubParamFileName, idAlice, message_a.getBytes());Element[] sigma2 = Sign(pairingParametersFileName, pubParamFileName, idBob, message_b.getBytes());boolean result = Verify(pairingParametersFileName, pubParamFileName, idAlice, message_a.getBytes(), sigma1);System.out.println("Alice 验证签名通过? " + result);result = Verify(pairingParametersFileName, pubParamFileName, idBob, message_b.getBytes(), sigma2);System.out.println("Bob 验证签名通过? " + result);List<Element[]> sigmaList = new ArrayList<>();sigmaList.add(sigma1);sigmaList.add(sigma2);Element[] SIGMA = Aggregate(sigmaList);String[] idx = {idAlice, idBob};byte[][] message = {message_a.getBytes(), message_b.getBytes()};
// message[0][1] = 1;//假如消息被篡改result = AggregateVerify(pairingParametersFileName, pubParamFileName, idx, message, SIGMA);System.out.println("聚合签名验证通过? " + result);}}
参考文献
-
A new certificateless aggregate signature scheme
-
Cryptanalysis and improvement of a certificateless aggregate signature scheme
-
A certificateless aggregate signature scheme for healthcare wireless sensor network
-
Efficient certificateless aggregate signcryption scheme without bilinear pairings
-
Security issues in IoT applications using certificateless aggregate signcryption schemes: An overview
相关文章:
基于JPBC的无证书聚合签名方案实现
基于JPBC的无证书聚合签名方案实现 摘要 一开始签名方案是基于PKI的,无证书签名起源于 基于身份密码体制, 2009 年第一篇无证书签名方案1被提出,随后出现了一些列方案2,3;包括无配对的无证书聚合签名方案4,更多内容参考文献5. 暂时没有看见…...
FreeRTOS内存管理分析
目录 heap_1.c内存管理算法 heap_2.c内存管理算法 heap_3.c内存管理算法 heap_4.c内存管理算法 heap_5.c内存管理算法 内存管理对应用程序和操作系统来说非常重要,而内存对于嵌入式系统来说是寸土寸金的资源,FreeRTOS操作系统将内核与内存管理分开实…...
hashMap索引原理
平日里面经常使用map这种数据结构,令人称奇的是他的访问速度为什么那么快?为什么可以通过key以接近O(1)的速度查找? 一、基础数据结构特点分析 1.1数组 查找的时间复杂度为O(1) 插入时间复杂度为O(n) 1.2链表 查找的时间复杂度为O(n) 插…...
qcow2、raw、vmdk等镜像格式工具
如果没有qemu,可以从这里下载安装:https://qemu.weilnetz.de/w64/...
GaussDB新特性Ustore存储引擎介绍
1、 Ustore和Astore存储引擎介绍 Ustore存储引擎,又名In-place Update存储引擎(原地更新),是openGauss 内核新增的一种存储模式。此前的版本使用的行存储引擎是Append Update(追加更新)模式。相比于Append…...
人工智能基础_机器学习046_OVR模型多分类器的使用_逻辑回归OVR建模与概率预测---人工智能工作笔记0086
首先我们来看一下什么是OVR分类.我们知道sigmoid函数可以用来进行二分类,那么多分类怎么实现呢?其中一个方法就是使用OVR进行把多分类转换成二分类进行计算. OVR,全称One-vs-Rest,是一种将多分类问题转化为多个二分类子问题的策略。在这种策略中,多分类问题被分解为若干个二…...
【LeetCode刷题-链表】--23.合并K个升序链表
23.合并K个升序链表 方法:顺序合并 在前面已经知道合并两个升序链表的前提下,用一个变量ans来维护以及合并的链表,第i次循环把第i个链表和ans合并,答案保存到ans中 /*** Definition for singly-linked list.* public class List…...
强化学习笔记
这里写自定义目录标题 参考资料基础知识16.3 有模型学习16.3.1 策略评估16.3.2 策略改进16.3.3 策略迭代16.3.3 值迭代 16.4 免模型学习16.4.1 蒙特卡罗强化学习16.4.2 时序差分学习Sarsa算法:同策略算法(on-policy):行为策略是目…...
经典双指针算法试题(一)
📘北尘_:个人主页 🌎个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上,不忘来时的初心 文章目录 一、移动零1、题目讲解2、讲解算法原理3、代码实现 二、复写零1、题目讲解2、讲解算法原理3、…...
MATLAB | 绘图复刻(十三) | 带NaN图例的地图绘制
有粉丝问我地图绘制如何添加NaN,大概像这样: 或者这样: 直接上干货: 原始绘图 假设我们有这样的一张图地图,注意运行本文代码需要去matlab官网下载Mapping Toolbox工具箱,但是其实原理都是相似的&…...
netty整合websocket(完美教程)
websocket的介绍: WebSocket是一种在网络通信中的协议,它是独立于HTTP协议的。该协议基于TCP/IP协议,可以提供双向通讯并保有状态。这意味着客户端和服务器可以进行实时响应,并且这种响应是双向的。WebSocket协议端口通常是80&am…...
选择PC示波器的10种理由!
PC示波器(PCs)在测试仪器领域中的关键项目上正迅速地取代传统的数字存储示波器(DSOs),其中有十个理由: 小巧和便携示波器利用你的PC显示器实现大屏幕和精细彩色显示信号存储只受限于你的PC存储器大小捕捉波…...
【pytorch深度学习 应用篇02】训练中loss图的解读,训练中的问题与经验汇总
文章目录 loss图解析train loss ↘ \searrow ↘ ↗ \nearrow ↗ 先降后升 loss图解析 train loss ↘ \searrow ↘ 不断下降,test loss ↗ \nearrow ↗ 不断上升:原因很多,我是把workers1,batchSize8192train loss ↘ \searro…...
uniapp 微信小程序如何实现多个item列表的分享
以下代码是某个循环里面的item <button class"cu-btn" style"background-color: transparent;padding: 0;"open-type"share" :data-tree"item.treeId" :data-project"item.projectId"v-if"typeId1 && userI…...
.NET 8 正式 GA 遥遥领先
.NET 8 一正式 已正式 GA。 微软称 .NET 8 提供了数以千计的性能、稳定性和安全性改进,以及平台和工具增强功能,有助于提高开发者的工作效率和创新速度。 比如 .NET 8 为 Android 和 WASM 引入了全新的 AOT 模式、改进 System.Text.Json,以…...
2216. 美化数组的最少删除数 --力扣 --JAVA
题目 给你一个下标从 0 开始的整数数组 nums ,如果满足下述条件,则认为数组 nums 是一个 美丽数组 : nums.length 为偶数对所有满足 i % 2 0 的下标 i ,nums[i] ! nums[i 1] 均成立 注意,空数组同样认为是美丽数组。…...
DDD 领域驱动设计
文章目录 请解释下什么是 DDD 领域驱动设计DDD 的四层领域模型是怎样的?包含哪些基础概念?DDD 中的贫血模型和充血模型有什么区别在 DDD 中,如何处理模型的聚合和聚合根DDD 中的实体和值对象有什么区别?在 DDD 中,如何…...
转型做视频了,博客就是稿子,继续坚持写博客,同时发布视频,能写博客说明思路清晰了,能再讲明白,理解就更透彻了,紧跟上时代发展。
1,今天特别记录下,B站给开通了《合集》功能 最近使用视频制作了几个视频。播放量还不错,最好的已经到了 2.6K了。 然后粉丝也涨到了 200个。 添加链接描述 紧跟时代:从写博客到录视频,粉丝大涨,突破200个&…...
小众市场:探索跨境电商中的利基领域
随着全球数字化和互联网的普及,跨境电子商务已经成为了一个蓬勃发展的产业。从亚马逊到阿里巴巴,大型电商平台已经占据了很大一部分市场份额。 然而,在这个竞争激烈的领域,寻找小众市场和利基领域可能是一种成功的策略。本文将探…...
C++中的mutable关键字
mutable是C中的一个关键字,它用来修饰类的成员变量。 当我们将一个成员变量声明为mutable时,就意味着这个成员变量可以被类的任何方法修改,即使这个方法是const类型的。这是因为mutable关键字可以打破const类型的限制,使得const类…...
Ctool:开发者的“瑞士军刀“,告别工具切换的烦恼
Ctool:开发者的"瑞士军刀",告别工具切换的烦恼 【免费下载链接】Ctool 程序开发常用工具 chrome / edge / firefox / utools / windows / linux / mac 项目地址: https://gitcode.com/gh_mirrors/ct/Ctool 深夜两点,屏幕前的…...
Taotoken用量看板如何帮助团队管理AI调用成本
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 Taotoken用量看板如何帮助团队管理AI调用成本 作为团队的技术负责人,在引入大模型能力支持多个业务项目时,…...
终极键盘打字练习指南:Qwerty Learner 免费安装与使用教程
终极键盘打字练习指南:Qwerty Learner 免费安装与使用教程 【免费下载链接】qwerty-learner 为键盘工作者设计的单词记忆与英语肌肉记忆锻炼软件 / Words learning and English muscle memory training software designed for keyboard workers 项目地址: https:/…...
英雄联盟段位修改终极指南:5分钟掌握LeaguePrank伪装技巧
英雄联盟段位修改终极指南:5分钟掌握LeaguePrank伪装技巧 【免费下载链接】LeaguePrank 项目地址: https://gitcode.com/gh_mirrors/le/LeaguePrank 你是否想过在英雄联盟中展示不同的段位给好友看?LeaguePrank正是为你量身打造的段位修改神器&a…...
基于个人知识库的AI幕僚长:构建私有化、流程化的智能工作流系统
1. 项目概述:一个真正为你工作的AI“幕僚长”如果你和我一样,每天被淹没在会议纪要、邮件、日历事件和零散的笔记里,总感觉信息过载,却又抓不住重点,那么这个项目可能就是为你量身定做的。我把它叫做“AI幕僚长”&…...
AI驱动CD流水线性能跃迁:实测QPS提升3.8倍、部署失败率下降92.6%的5个核心改造点
更多请点击: https://intelliparadigm.com 第一章:AI原生持续交付:2026奇点智能技术大会部署流水线优化 在2026奇点智能技术大会上,AI原生持续交付(AI-Native CI/CD)成为核心实践范式——它不再将AI模型视…...
3步构建企业级KMS激活架构:从单机到集群的智能演进
3步构建企业级KMS激活架构:从单机到集群的智能演进 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO KMS_VL_ALL_AIO作为一款智能激活脚本,彻底解决了Windows与Office的批量…...
别再死记硬背了!用Python+NumPy手把手带你理解LTI系统的零极点与频率响应
用PythonNumPy实战解析LTI系统的零极点与频率响应 数字信号处理的理论常常让初学者感到抽象难懂,尤其是当教科书堆满数学公式时。但如果我们换一种方式——用代码和可视化来探索这些概念,一切突然变得清晰起来。本文将带你用Python和NumPy库,…...
对比直连与通过Taotoken调用大模型的延迟与稳定性体验
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 对比直连与通过Taotoken调用大模型的延迟与稳定性体验 在构建依赖大模型能力的应用时,开发者通常会面临一个选择&#…...
5分钟搞定网盘限速:免费开源下载助手终极指南
5分钟搞定网盘限速:免费开源下载助手终极指南 【免费下载链接】baiduyun 油猴脚本 - 一个免费开源的网盘下载助手 项目地址: https://gitcode.com/gh_mirrors/ba/baiduyun 还在为网盘下载速度慢如蜗牛而烦恼吗?每次下载大文件都要等待数小时甚至数…...
