Crypto++ 入门

一、简介

Crypto++(也称为CryptoPP、libcrypto++或cryptlib)是一个免费的开源C++库,提供了多种加密方案。它由Wei Dai开发和维护,广泛应用于需要强大加密安全的各种应用程序中。该库提供了广泛的加密算法和协议的实现,包括:

  1. 对称加密算法:AES、DES、3DES、RC2、RC4、RC5、RC6、Blowfish、Twofish等。

  2. 非对称加密算法:RSA、DSA、ElGamal、ECC(椭圆曲线加密)等。

  3. 哈希函数:SHA-1、SHA-2(SHA-224、SHA-256、SHA-384、SHA-512)、MD2、MD4、MD5、RIPEMD-160等。

  4. 消息认证码(MAC):HMAC、CMAC等。

  5. 数字签名算法:DSA、ECDSA、EdDSA等。

  6. 随机数生成器:各种伪随机数生成器和真随机数生成器。

  7. 密码协议:SSL/TLS、SRP(安全远程密码协议)等。

Crypto++的设计目标是提供高性能、高质量的加密算法实现,并且易于集成到C++应用程序中。它是一个跨平台的库,支持多种操作系统,包括Windows、Linux、macOS等。

二、下载

Crypto++下载:

Crypto++ Library 8.9 | Free C++ Class Library of Cryptographic Schemes

或者Tags · weidai11/cryptopp · GitHub

cryptopp-pem下载:

PEM Pack - Crypto++ Wiki ,滚动到页面最下方下载

PEM Pack 是一个消息加密的部分实现,它允许你读取和写入 PEM 编码的密钥和参数,包括加密的私钥。该包额外提供了对 RSA、DSA、EC、ECDSA 密钥以及 Diffie-Hellman 参数的支持。该包包含五个额外的源文件,一个使用 OpenSSL 创建测试密钥的脚本,一个用于测试读取和写入密钥的 C++ 程序,以及一个用于验证由 Crypto++ 写入的密钥的脚本。

最终下载文件如下:

cryptopp-CRYPTOPP_8_7_0.zip

cryptopp-pem-master.zip

三、编译静态库

1、解压cryptopp-CRYPTOPP_8_7_0.zip

再解压cryptopp-pem-master.zip,内容全部拷贝到cryptopp-CRYPTOPP_8_7_0中

2、VS打开cryptest.sln工程

3、往子工程cryptlib中加入pem包

选中cryptlib,右击“Header Files”->添加->现有项:

  • pem.h

  • pem_common.h

右击“Source Files”->添加->现有项:

  • pem_common.cpp

  • pem_read.cpp

  • pem_write.cpp

4、修改属性页-》配置属性-》C/C++ -》代码生成-》运行库 。debug模式选"多线程调试DLL(/MDd) 或者"多线程调试(/MTd)"",release模式选择“多线程DLL(/MD)” 或者"多线程(/MT)"

5、编译生成,右击子工程cryptlib点击“生成”

6、作为SDK发布

创建文件夹cryptopp870,内部创建include文件夹(存放.h文件),创建lib文件(夹存放.lib文件)

cryptopp-CRYPTOPP_8_7_0中所有头文件复制到include中

xxx/cryptopp-CRYPTOPP_8_7_0\x64\Output中的Debug和Release文件夹复制到lib中

 运行库说明:

在 Visual C++ 中,运行库(Runtime Library)有四个主要的选项,它们在编译和链接时使用不同的设置。这些选项主要影响程序的内存管理、异常处理和调试支持等方面。以下是这四个选项的区别:

  1. 多线程 (/MT)

    • 描述:使用静态链接的多线程运行库。

    • 特点

      • 程序在运行时不需要额外的 DLL 支持,因为所有的运行库代码都被静态链接到可执行文件中。

      • 可执行文件较大,因为包含了运行库的所有代码。

      • 适用于发布版本,因为不需要依赖外部 DLL。

    • 适用场景:不需要依赖外部 DLL 的独立应用程序。

  2. 多线程调试 (/MTd)

    • 描述:使用静态链接的多线程调试运行库。

    • 特点

      • /MT 类似,但包含了调试信息,适用于调试版本。

      • 可执行文件较大,因为包含了运行库的所有代码和调试信息。

      • 适用于调试版本,因为可以提供更详细的调试信息。

    • 适用场景:需要详细调试信息的调试版本。

  3. 多线程 DLL (/MD)

    • 描述:使用动态链接的多线程运行库。

    • 特点

      • 程序在运行时需要依赖 msvcrt.dll(Microsoft Visual C++ 运行库 DLL)。

      • 可执行文件较小,因为只包含了程序自身的代码,运行库代码在 msvcrt.dll 中。

      • 适用于发布版本,因为可以减小可执行文件的大小。

    • 适用场景:需要减小可执行文件大小的发布版本。

  4. 多线程调试 DLL (/MDd)

    • 描述:使用动态链接的多线程调试运行库。

    • 特点

      • /MD 类似,但包含了调试信息,适用于调试版本。

      • 程序在运行时需要依赖 msvcrtd.dll(Microsoft Visual C++ 调试运行库 DLL)。

      • 适用于调试版本,因为可以提供更详细的调试信息。

    • 适用场景:需要详细调试信息的调试版本。

总结:

  • /MT/MTd 使用静态链接,适用于不需要依赖外部 DLL 的独立应用程序。

  • /MD/MDd 使用动态链接,适用于需要减小可执行文件大小或依赖外部 DLL 的应用程序。

  • 调试版本通常使用 /MTd/MDd,因为它们包含了调试信息,有助于调试。

在选择运行库选项时,需要根据具体的需求和项目配置来决定使用哪个选项。确保所有相关的库和模块都使用相同的运行库选项,以避免链接错误。

例如,如果你有一个静态库 mylib.lib 是用 /MD 选项编译的,那么任何使用 mylib.lib 的可执行文件或 DLL 也必须使用 /MD 选项进行编译。

四、使用示例

VS配置:

新建一个测试工程,添加依赖库

属性页-》配置属性-》C/C++ -》常规-》附加包含目录,输入头文件路径E:\3rdparty\dist\cryptopp870\include

属性页-》配置属性-》链接器-》常规-》附加库目录,输入lib文件路径E:\3rdparty\dist\cryptopp870\lib\Debug

属性页-》配置属性-》链接器-》输入-》附加依赖项,添加cryptlib.lib

QT配置:


CONFIG(debug, debug|release) {
    QMAKE_CXXFLAGS_DEBUG += /MTd    # 或/MDd
}

CONFIG(release, debug|release) {
    QMAKE_CXXFLAGS_RELEASE += /MT   # 或/MD
}

win32:CONFIG(release, debug|release): LIBS += -L$$PWD/cryptopp870/lib/Release/ -lcryptlib
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/cryptopp870/lib/Debug/ -lcryptlib

INCLUDEPATH += $$PWD/cryptopp870/include
DEPENDPATH += $$PWD/cryptopp870/include

win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/cryptopp870/lib/Release/libcryptlib.a
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/cryptopp870/lib/Debug/libcryptlib.a
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/cryptopp870/lib/Release/cryptlib.lib
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/cryptopp870/lib/Debug/cryptlib.lib

4.1、RSA非对称加密

#include <iostream>
#include <string>
#include <rsa.h>
#include <osrng.h>
#include <base64.h>
#include <files.h>
#include <pem.h>

using namespace std;
using namespace CryptoPP;

class RSAKeyManager {
public:
    RSAKeyManager() {}

    void GenerateKeys(int keySize = 2048) {
        AutoSeededRandomPool rng;
        privateKey.GenerateRandomWithKeySize(rng, keySize);
        publicKey = RSA::PublicKey(privateKey);
    }

    std::string GetPrivateKeyPEM() const {
        std::string privateKeyPEM;
        StringSink privateKeySink(privateKeyPEM);
        PEM_Save(privateKeySink, privateKey);
        return privateKeyPEM;
    }

    std::string GetPublicKeyPEM() const {
        std::string publicKeyPEM;
        StringSink publicKeySink(publicKeyPEM);
        PEM_Save(publicKeySink, publicKey);
        return publicKeyPEM;
    }

    void SavePrivateKey(const char* filename) const {
        FileSink file(filename);
        PEM_Save(file, privateKey);
    }

    void SavePublicKey(const char* filename) const {
        FileSink file(filename);
        PEM_Save(file, publicKey);
    }

    void LoadPrivateKey(const char* filename) {
        FileSource file(filename, true);
        PEM_Load(file, privateKey);
    }

    void LoadPublicKey(const char* filename) {
        FileSource file(filename, true);
        PEM_Load(file, publicKey);
    }

    void LoadPrivateKeyFromString(const std::string& privateKeyPEM) {
        StringSource source(privateKeyPEM, true);
        PEM_Load(source, privateKey);
    }

    void LoadPublicKeyFromString(const std::string& publicKeyPEM) {
        StringSource source(publicKeyPEM, true);
        PEM_Load(source, publicKey);
    }

    std::string Encrypt(const std::string& message) const {
        AutoSeededRandomPool rng;
        std::string encrypted;
        RSAES_OAEP_SHA_Encryptor encryptor(publicKey);
        StringSource(message, true,
            new PK_EncryptorFilter(rng, encryptor,
                new StringSink(encrypted)
            )
        );
        return encrypted;
    }

    std::string Decrypt(const std::string& encrypted) const {
        AutoSeededRandomPool rng;
        std::string decrypted;
        RSAES_OAEP_SHA_Decryptor decryptor(privateKey);
        StringSource(encrypted, true,
            new PK_DecryptorFilter(rng, decryptor,
                new StringSink(decrypted)
            )
        );
        return decrypted;
    }

private:
    RSA::PrivateKey privateKey;
    RSA::PublicKey publicKey;
};

int main() {
    try {
        RSAKeyManager keyManager;

        // 生成密钥对
        keyManager.GenerateKeys();

        // 将私钥和公钥转换为PEM格式
        std::string privateKeyPEM = keyManager.GetPrivateKeyPEM();
        std::cout << "RSA Private Key:" << std::endl;
        std::cout << privateKeyPEM << std::endl;

        std::string publicKeyPEM = keyManager.GetPublicKeyPEM();
        std::cout << "RSA Public Key:" << std::endl;
        std::cout << publicKeyPEM << std::endl;

        // 从字符串加载密钥对
        RSAKeyManager loadedKeyManager;
        loadedKeyManager.LoadPrivateKeyFromString(privateKeyPEM);
        loadedKeyManager.LoadPublicKeyFromString(publicKeyPEM);

        // 加密
        string message = "Hello, World!";
        string encrypted = loadedKeyManager.Encrypt(message);

        // 解密
        string decrypted = loadedKeyManager.Decrypt(encrypted);

        // 输出结果
        cout << "Original message: " << message << endl;
        cout << "Encrypted message: " << encrypted << endl;
        cout << "Decrypted message: " << decrypted << endl;
    }
    catch (const Exception& e) {
        cout << "Crypto++ exception: " << e.what() << endl;
    }
    catch (const std::exception& e) {
        cout << "Standard exception: " << e.what() << endl;
    }
    catch (...) {
        cout << "Unknown exception" << endl;
    }
    return 0;
}

4.2、RSA签名

生成密钥对、签名数据以及验证签名

#include <iostream>
#include <string>
#include <rsa.h>
#include <osrng.h>
#include <base64.h>
#include <files.h>
#include <pem.h>
#include <sha.h>
#include <hex.h>
#include <pssr.h>

using namespace std;
using namespace CryptoPP;


void GenerateKeyPair(RSA::PrivateKey& privateKey, RSA::PublicKey& publicKey) {
    AutoSeededRandomPool rng;
    privateKey.GenerateRandomWithKeySize(rng, 2048);
    publicKey = RSA::PublicKey(privateKey);
}

bool SignMessage(const string& message, const RSA::PrivateKey& privateKey, string &signature) {
    try
    {
        AutoSeededRandomPool rng;
        RSASS<PSS, SHA256>::Signer signer(privateKey);

        StringSource(message, true,
            new SignerFilter(rng, signer,
                new StringSink(signature)
            )
        );
    }
    catch (const Exception& e)
    {
        cout << "Sign exception: " << e.what() << endl;
        return false;
    }
    return true;
}

bool VerifyMessage(const string& message, const string& signature, const RSA::PublicKey& publicKey) {
    try {
        RSASS<PSS, SHA256>::Verifier verifier(publicKey);
        /* 解签使用内容+签名 */
        StringSource ss(message + signature , true,
            new SignatureVerificationFilter(verifier,
                NULL,
                SignatureVerificationFilter::THROW_EXCEPTION | SignatureVerificationFilter::PUT_MESSAGE
            )
        );
    }
    catch (const Exception& e) {
        cout << "Verifier exception: " << e.what() << endl;
        return false;
    }
    return true;
}

struct LicenseData {
    string message = "2024/6/19, 2024/7/19";
    string signature;   /* 数字签名,验证数据是否被修改 */
    string publicKey;   /* 公钥 */
};


int main() {
    try {
        RSA::PrivateKey privateKey;
        RSA::PublicKey publicKey;

        // 生成密钥对
        GenerateKeyPair(privateKey, publicKey);

        // 要签名的消息
        string message = "Hello, World!";

        // 签名消息
        string signature;
        bool b = SignMessage(message, privateKey, signature);
        cout << "signature:" << b << endl << signature << endl;

        // 验证签名
        b= VerifyMessage(message, signature, publicKey);
        if (b) {
            cout << "Signature is valid." << endl;
        }
        else {
            cout << "Signature is invalid." << endl;
        }
    }
    catch (const Exception& e) {
        cout << "Crypto++ exception: " << e.what() << endl;
    }
    catch (const std::exception& e) {
        cout << "Standard exception: " << e.what() << endl;
    }
    catch (...) {
        cout << "Unknown exception" << endl;
    }
    return 0;
}

4.3、 Base64 编码和解码

#include <iostream>
#include <string>

#include <rsa.h>
#include <osrng.h>
#include <base64.h>
#include <files.h>
#include <pem.h>

using namespace std;
using namespace CryptoPP;

class Base64 {
public:
    static std::string encode(const std::string& data) {
        std::string encoded;
        CryptoPP::Base64Encoder encoder;
        encoder.Attach(new CryptoPP::StringSink(encoded));
        encoder.Put((const byte*)data.data(), data.size());
        encoder.MessageEnd();
        return encoded;
    }

    static std::string decode(const std::string& encoded) {
        std::string decoded;
        CryptoPP::Base64Decoder decoder;
        decoder.Attach(new CryptoPP::StringSink(decoded));
        decoder.Put((const byte*)encoded.data(), encoded.size());
        decoder.MessageEnd();
        return decoded;
    }
};


int main()
{
    try {
        // 原始数据
        std::string data = "Hello, World!";

        // Base64 编码
        std::string encoded = Base64::encode(data);
        std::cout << "Encoded data: " << encoded << std::endl;

        // Base64 解码
        std::string decoded = Base64::decode(encoded);
        std::cout << "Decoded data: " << decoded << std::endl;

    }
    catch (const Exception& e) {
        cout << "Crypto++ exception: " << e.what() << endl;
    }
    catch (const std::exception& e) {
        cout << "Standard exception: " << e.what() << endl;
    }
    catch (...) {
        cout << "Unknown exception" << endl;
    }
    return 0;
}

4.4、AES对称加密

#include <iostream>
#include <string>
#include <aes.h>
#include <modes.h>
#include <filters.h>
#include <hex.h>
#include <osrng.h>

using namespace std;
using namespace CryptoPP;

class AESCipher {
public:
    AESCipher(const string& key, const string& iv) : key(key), iv(iv) {}

    string Encrypt(const string& plainText) {
        string cipherText;
        try {
            CBC_Mode<AES>::Encryption encryptor;
            encryptor.SetKeyWithIV((byte*)key.data(), key.size(), (byte*)iv.data());

            StringSource(plainText, true,
                new StreamTransformationFilter(encryptor,
                    new StringSink(cipherText)
                )
            );
        }
        catch (const Exception& e) {
            cerr << "Encryption error: " << e.what() << endl;
        }
        return cipherText;
    }

    string Decrypt(const string& cipherText) {
        string plainText;
        try {
            CBC_Mode<AES>::Decryption decryptor;
            decryptor.SetKeyWithIV((byte*)key.data(), key.size(), (byte*)iv.data());

            StringSource(cipherText, true,
                new StreamTransformationFilter(decryptor,
                    new StringSink(plainText)
                )
            );
        }
        catch (const Exception& e) {
            cerr << "Decryption error: " << e.what() << endl;
        }
        return plainText;
    }

private:
    string key;
    string iv;
};

int main() {
    // 生成随机的密钥和初始化向量(IV)
    AutoSeededRandomPool rng;
    byte key[AES::DEFAULT_KEYLENGTH];
    byte iv[AES::BLOCKSIZE];
    rng.GenerateBlock(key, sizeof(key));
    rng.GenerateBlock(iv, sizeof(iv));

    string keyStr(reinterpret_cast<char*>(key), sizeof(key));
    string ivStr(reinterpret_cast<char*>(iv), sizeof(iv));

    AESCipher aes(keyStr, ivStr);

    string plainText = "Hello, World!";
    string encryptedText = aes.Encrypt(plainText);
    string decryptedText = aes.Decrypt(encryptedText);

    cout << "Original Text: " << plainText << endl;
    cout << "Encrypted Text: " << encryptedText << endl;
    cout << "Decrypted Text: " << decryptedText << endl;

    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

线程池概念、线程池的不同创建方式、线程池的拒绝策略

文章目录 &#x1f490;线程池概念以及什么是工厂模式&#x1f490;标准库中的线程池&#x1f490;什么是工厂模式&#xff1f;&#x1f490;ThreadPoolExecutor&#x1f490;模拟实现线程池 &#x1f490;线程池概念以及什么是工厂模式 线程的诞生是因为&#xff0c;频繁的创…

原Veritas(华睿泰)中国研发中心敏捷教练、项目集经理郑鹤琳受邀为第十三届中国PMO大会演讲嘉宾

全国PMO专业人士年度盛会 原Veritas&#xff08;华睿泰中国&#xff09;中国研发中心敏捷教练、项目集经理郑鹤琳女士受邀为PMO评论主办的2024第十三届中国PMO大会演讲嘉宾&#xff0c;演讲议题为“敏捷项目管理-知行合一”。大会将于6月29-30日在北京举办&#xff0c;敬请关注…

LabVIEW与数字孪生

LabVIEW与数字孪生技术在工业自动化、智慧城市、医疗设备和航空航天等领域应用广泛&#xff0c;具备实时数据监控、虚拟仿真和优化决策等特点。开发过程中需注意数据准确性、系统集成和网络安全问题&#xff0c;以确保数字孪生模型的可靠性和有效性。 经典应用&#xff1a;LabV…

数据挖掘常见算法(分类算法)

K&#xff0d;近邻算法&#xff08;KNN&#xff09; K-近邻分类法的基本思想&#xff1a;通过计算每个训练数据到待分类元组Zu的距离&#xff0c;取和待分类元组距离最近的K个训练数据&#xff0c;K个数据中哪个类别的训练数据占多数&#xff0c;则待分类元组Zu就属于哪个类别…

win10 修改远程桌面端口,在Win10上修改远程桌面端口的要怎么操作

在Windows 10上修改远程桌面端口是一个涉及系统配置的过程&#xff0c;这通常是为了增强安全性或满足特定网络环境的需要。 一、通过注册表编辑器修改远程桌面端口 1. 打开注册表编辑器&#xff1a; - 按下Win R组合键&#xff0c;打开“运行”对话框。 - 在“运行”对话框…

结构体 (一)

在我们C语言中&#xff0c;为我们提供了不同的内置类型&#xff0c;例如&#xff1a;char 、short 、int 、long 、float 、double 等等&#xff0c;但是呢&#xff0c;仅仅只有这些内置类型是远远不够的&#xff0c;当我们想要描述一名学生&#xff0c;一本书&#xff0c;一件…

Linux:目录和文件管理命令2

目录 一、Linux目录结构&#xff1a; 二、查看文件 2.1、cat 命令——显示并连接&#xff08;Concatenate&#xff09;文件的内容 2.2、more 和 less 命令——分页查看文件内容 2.3、head 和 tail 命令——查看文件开头或末尾的部分内容 三、统计和检索文件内容 3.1、wc…

不知大家信不信,竟有这么巧的事,我领导的老婆,竟然是我老婆的下属,我在想要不要利用下这层关系,改善下领导对我的态度,领导怕老婆

职场如战场&#xff0c;每个人都身不由己。每天上班&#xff0c;除了要面对堆积如山的工作&#xff0c;还要小心应对来自领导的“狂风暴雨”。最近&#xff0c;我无意间发现领导一个秘密&#xff0c;这个秘密让我对职场关系和人性都产生了新的思考。 故事要从那天晚上说起。我…

ARM相关理论知识

一、计算机的组成 1.输入设备&#xff1a;将数据与程序转换成计算机能够识别&#xff0c;存储&#xff0c;运算的形式&#xff0c;输送到计算机中。 2.输出设备&#xff1a;将计算机对程序和数据的运算结果输送到计算机外部设备 3.控制器&#xff1a;由程序技术器&#xff0…

《数字图像处理》实验报告一

一、实验任务与要求 1、用 matlab 编写空间域点处理操作处理给定的几幅图像&#xff0c;要求&#xff1a; 使用 imread 读取当前工作目录下的图像设计点处理操作并用代码实现处理用 imnshow 显示处理后的图像用 imwrite 保存处理后的图像 2、提交内容&#xff1a;m文件 实验…

【ChatBI】超轻量Python库Vanna快速上手,对接oneapi

oneapi 准备 首先确保你有oneapi &#xff0c;然后申请 kimi的api 需要去Moonshot AI - 开放平台 然后添加一个api key 然后打开oneapi的渠道界面&#xff0c;添加kimi。 然后点击 测试&#xff0c; 如果能生成响应时间&#xff0c;就是配置正确。 然后创建令牌 http:…

渗透测试基础(六) MS10-046漏洞攻击

1. 漏洞介绍 1.1 漏洞介绍 Microsoft Windows快捷方式LNK文件自动执行代码漏洞。Windows支持使用快捷方式或LNK文件。LNK文件是指向本地文件的引用,点击LNK文件与点击快捷方式所制定的目标具有相同效果。Windows没有正确的处理LNK文件,特制的LNK文件可能导致Windows自动执行…

微服务(服务治理)

服务远程调用时存在的问题 注册中心原理 服务治理中的三个角色分别是什么&#xff1f; 服务提供者&#xff1a;暴露服务接口&#xff0c;供其它服务调用服务消费者&#xff1a;调用其它服务提供的接口注册中心&#xff1a;记录并监控微服务各实例状态&#xff0c;推送服务变更信…

MIT6.s081 2021 Lab Utilities

Boot xv6 按照示例切换到 util 分支后&#xff0c;看到目录下包含 Makefile 文件&#xff0c;执行 make qemu 即可。 sleep 思路 借助系统调用 sleep 实现一个命令行程序&#xff0c;关键是要找到封装了系统调用的 C 函数的位置&#xff0c;根据提示&#xff1a; … user/u…

物联网系统运维——实验备份与恢复,数据镜像软件DRBD介绍,DRBD的安装和应用,extundelete的安装和应用(重点),环境准备,配置设置

一.数据备份 1.数据备份的重要性 备份是系统中需要考虑的最重要的事项,虽然这在系统的整个规划,开发和测试过程中甚至占不到1%,看似不太重要且默默无闻的工作只有到恢复的时候才能真正体现出其重要性,任何数据的丢失与数据宕机&#xff0c;都是不可以被接收的。 2.数据备份策…

oracle 11g rac安装grid 执行root脚本add vip -n 。。。on node= ... failedFailed 错误处理

问题&#xff1a; CRS-4402: The CSS daemon was started in exclusive mode but found an active CSS daemon on node racdg1-1, number 1, and is terminating An active cluster was found during exclusive startup, restarting to join the cluster PRCN-2050 : The requ…

程序员学长 | 快速学会一个算法,Transformer(下)

本文来源公众号“程序员学长”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;快速学习一个算法&#xff0c;Transformer&#xff08;二&#xff09; 今天我们来继续分享 Transformer 模型的第二部分&#xff0c;解码器部分。 建…

热虹吸管的传热计算

热对称管和热管通过使用中空管内的两相流体&#xff0c;在特定的距离上传输大量的热量。 更广泛使用的热管使用吸芯结构将液体输送回热端&#xff0c;而热虹吸管是一个简单的空心管&#xff0c;使用重力。 由于缺乏吸芯结构&#xff0c;使得热虹吸管比传统的热管便宜得多。 然…

自学指南:必备书籍清单--近100本R语言及生物信息相关书籍

R语言是一种功能丰富的编程语言&#xff0c;数据处理、统计分析是大家所熟知的基本功能。开源免费、活跃的全球社区、灵活可扩展等优点促使R语言飞速发展。目前&#xff0c;CRAN 软件包存储库包含 20446 个可用软件包&#xff0c;涵盖了从生物信息到金融分析等广泛的应用领域。…

vue3.0(十五)内置组件Teleport和Suspense

文章目录 一、Teleport1.基本用法2.禁用Teleport3.多个 Teleport 共享目标4.搭配组件 二、 Suspense1.什么是Suspense2.异步依赖3.加载中状态4.事件5.错误处理6.和其他组件结合注意 一、Teleport <Teleport> 是一个内置组件&#xff0c;它可以将一个组件内部的一部分模板…