通过同态加密实现可编程隐私和链上合规

1. 引言

2023年9月28日,a16z 的加密团队发布了 Nakamoto Challenge,列出了区块链中需要解决的最重要问题。尤其是其中的第四个问题格外引人注意:“合规的可编程隐私”,因为Zama团队已经在这方面积极思考了一段时间。本文提出了使用同态加密和Zama fhEVM 机密智能合约协议的第一个解决方案。

fhEVM 是一个常规的 EVM,它通过一些预编译功能使得使用Zama TFHE-rs 同态加密库可以对加密状态进行计算。从开发者的角度来看,这里没有涉及加密学:

  • 他们只需编写使用所提供的加密数据类型(如 euint32、ebool 等)的 Solidity 代码。

与其他隐私解决方案相比,fhEVM 的一个大优势是所有数据和计算都发生在链上。这意味着可以像常规的明文合约一样,拥有相同的组合性和数据可用性。【本文各种接口已被重构,理解思想即可。】

这一特性是构建可编程隐私的关键,因为所有的访问控制逻辑都可以在合约本身中定义。协议中没有任何需要硬编码的部分,用户也不需要进行链下操作来确保合规性。应用可以直接强化执行合规性,仅用几行 Solidity 代码!

本文将展示如何使用链上 DID 构建一个合规的 ERC20 代币。

2. 通过链上机密 DID 实现身份抽象

去中心化标识符(Decentralized Identifier,DID)是一种由实体(如政府、登记机关、公司或用户本人)颁发的独特数字身份。DID 可以与一个加密密钥相关联,用于证明用户拥有该 DID,如 EVM 钱包。但它也可以存储一整套属性,如用户的年龄、国籍、社会安全号码等。这些属性可以用来证明你满足某些条件(称为“证明”),如超过18岁或不是纳尼亚国公民。

大多数 DID 实现是在客户端进行的,并使用零知识证明生成证明。虽然在许多情况下这已经足够,但当涉及多个用户参与交易、需要对 DID 应用复杂规则或需要为所有人维护一套共同的规则时,这个方案会变得复杂起来。这实际上是边缘计算与云计算应用之间的取舍问题。

然而,拥有一个集中式的 DID 注册中心可以解决这些问题,因为可以简单地请求注册中心来检查每个人是否符合要求。它还可以简化监管的追踪,因为只需要在一个地方实现它。区块链将是一个完美的基础设施,因为它可以实现 DID 与需要合规性的应用之间的组合性,以及不同法规之间的组合性。

问题是:每个人都能看到每个人的身份!

幸运的是,有一个解决方案:

  • 同态加密,具体来说是 fhEVM!
    • 得益于对加密状态的组合性能力,可以直接将用户的 DID 以加密形式托管在链上,并让合规应用通过简单的合约调用来验证属性。
    • 通过智能合约管理身份的能力,称之为“身份抽象”,这类似于如何通过智能合约管理资金的账户抽象。

这个教程分为三部分:

  • 1)身份抽象:是通过一个注册合约来完成的,注册合约负责管理身份和证明。在这里,假设 DID 是官方政府身份证明。注册中心由一个中央机构(如 AFNIC)管理,后者可以创建注册商(如 KYC 公司,如 Onfido、Jumio 等),然后这些注册商可以创建用户 DID。用户通过他们的注册商来管理和更新他们的 DID。
  • 2)监管:在一个合约中定义,该合约编码了一套基于用户 DID 中信息的规则,用于管理个人之间的代币转移。它基本上在合约级别强制执行监管,而不是在用户级别。
  • 3)合规的机密转账:在一个合规的 ERC20 合约中实现,该合约使用监管合约来执行代币转移中的合规性,而不需要对 ERC20 API 本身进行任何更改。在这个示例中,使用了一个机密 ERC20 合约,其中余额和金额是隐藏的,但它同样适用于常规的明文 ERC20 代币。

Zama链上机密 DID 协议架构:
在这里插入图片描述

3. 身份注册合约

IdentityRegistry 合约是一个用户 DID 的注册中心,这些 DID 是由注册商颁发的,并包含一组加密的标识符,如用户的国籍、年龄、社会安全号码等。这些标识符作为加密的 32 位值(euint32)存储。

该合约还处理权限管理,如下所示:

  • 允许合约所有者(如 AFNIC)添加、移除或更新注册商。
  • 允许注册商添加、移除或更新他们创建的用户 DID。
  • 允许用户授权智能合约访问他们 DID 的特定属性。需要注意的是,用户有责任不向恶意合约提供访问权限,就像他们有责任不让恶意合约花费他们的代币一样。

第一步,实现创建和管理 DID 的逻辑:

// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity 0.8.19;import "fhevm/lib/TFHE.sol";contract IdentityRegistry is EIP712WithModifier, Ownable {// 从钱包到注册商ID的映射mapping(address => uint) public registrars;// 从钱包到身份的映射mapping(address => Identity) internal identities;struct Identity {uint registrarId;mapping(string => euint32) identifiers;}mapping(address => mapping(address => mapping(string => bool))) permissions; // 用户 => 合约 => 标识符[]event NewRegistrar(address wallet, uint registrarId);event NewDid(address wallet);event RemoveDid(address wallet);constructor() Ownable() EIP712WithModifier("Authorization token", "1") {_transferOwnership(msg.sender);}// 添加注册商function addRegistrar(address wallet, uint registrarId) public onlyOwner {require(registrarId > 0, "registrarId needs to be > 0");registrars[wallet] = registrarId;emit NewRegistrar(wallet, registrarId);}function removeRegistrar(address wallet) public onlyOwner {delete registrars[wallet];}function getRegistrar(address wallet) public view returns (uint) {return identities[wallet].registrarId;}// 添加用户 DIDfunction addDid(address wallet) public onlyRegistrar {require(identities[wallet].registrarId == 0, "This wallet is already registered");Identity storage newIdentity = identities[wallet];newIdentity.registrarId = registrars[msg.sender];emit NewDid(wallet);}function removeDid(address wallet) public onlyExistingWallet(wallet) onlyRegistrarOf(wallet) {require(identities[wallet].registrarId > 0, "This wallet isn't registered");delete identities[wallet];emit RemoveDid(wallet);}modifier onlyExistingWallet(address wallet) {require(identities[wallet].registrarId > 0, "This wallet isn't registered");_;}modifier onlyRegistrar() {require(registrars[msg.sender] > 0, "You're not a registrar");_;}modifier onlyRegistrarOf(address wallet) {uint registrarId = registrars[msg.sender];require(identities[wallet].registrarId == registrarId, "You're not managing this identity");_;}
}

其中:

  • onlyRegistraronlyRegistrarOf 注册商(Registrar):只有注册商可以添加或删除用户的 DID。每个钱包都与一个注册商 ID 相关联,注册商 ID 必须大于 0。
  • 身份管理:每个用户都有一个关联的 Identity,其中包含该用户的注册商 ID 和一组加密的标识符(如年龄、国籍等)。
  • 权限管理:用户可以授权特定的智能合约访问其 DID 的特定属性。合约会验证这些权限,确保只有经过授权的合约可以访问用户的身份信息。
  • 合约功能:
    • addRegistrar:允许合约所有者添加新的注册商。
    • removeRegistrar:允许合约所有者移除注册商。
    • addDid:允许注册商为钱包添加 DID。
    • removeDid:允许注册商移除钱包的 DID。
    • getRegistrar:查询用户 DID 所属的注册商 ID。

通过这种方式,可以在链上安全地管理和更新用户的身份信息,同时保证隐私性和合规性。

现在,下一步是实现identifiers标识符和访问控制的逻辑。

标识符只是一个字符串(如“出生日期”)和一个加密的 32 位值。它只能由注册商创建或更新,用户不能创建自己的标识符,因为希望这些标识符由注册商进行认证。

然而,由于标识符是加密的,用户需要授权某个合约访问特定的值,将通过一个简单的访问控制机制来处理这一点,这类似于你如何允许合约花费你的 ERC20 代币。

contract IdentityRegistry is EIP712WithModifier, Ownable {...mapping(address => mapping(address => mapping(string => bool))) permissions; // 用户 => 合约 => 标识符[]// 设置用户的标识符function setIdentifier(address wallet, string calldata identifier, bytes calldata encryptedValue) public {euint32 value = TFHE.asEuint32(encryptedValue);setIdentifier(wallet, identifier, value);}function setIdentifier(address wallet,string calldata identifier,euint32 value) internal onlyExistingWallet(wallet) onlyRegistrarOf(wallet) {identities[wallet].identifiers[identifier] = value;}// 用户处理权限function grantAccess(address allowed, string[] calldata identifiers) public {for (uint i = 0; i < identifiers.length; i++) {permissions[msg.sender][allowed][identifiers[i]] = true;}}function revokeAccess(address allowed, string[] calldata identifiers) public {for (uint i = 0; i < identifiers.length; i++) {delete permissions[msg.sender][allowed][identifiers[i]];}}...
}

现在可以通过添加必要的 getter 来完成身份注册合约,同时加入一些条件和错误处理。

contract IdentityRegistry is EIP712WithModifier, Ownable {...// 获取加密的标识符function reencryptIdentifier(address wallet,string calldata identifier,bytes32 publicKey,bytes calldata signature) public view onlySignedPublicKey(publicKey, signature) returns (bytes memory) {euint32 ident = _getIdentifier(wallet, identifier);require(TFHE.isInitialized(ident), "This identifier is unknown");return TFHE.reencrypt(ident, publicKey, 0);}function getIdentifier(address wallet, string calldata identifier) public view returns (euint32) {return _getIdentifier(wallet, identifier);}function _getIdentifier(address wallet,string calldata identifier) internal view onlyExistingWallet(wallet) onlyAllowed(wallet, identifier) returns (euint32) {return identities[wallet].identifiers[identifier];}modifier onlyAllowed(address wallet, string memory identifier) {require(owner() == msg.sender || permissions[wallet][msg.sender][identifier],"User didn't give you permission to access this identifier.");_;}
}

其中:

  • setIdentifier:允许注册商为钱包设置新的标识符。标识符是通过加密的 32 位值进行存储。
  • grantAccessrevokeAccess:允许用户授权或撤销合约访问其标识符的权限,权限是基于合约和标识符的。
  • reencryptIdentifier:允许用户通过签名证明他们的身份,并获取加密的标识符。这是为了确保数据的安全传输和使用。
  • getIdentifier_getIdentifier:获取标识符的加密值,只有授权的合约和用户才能访问。
  • onlyAllowed:访问控制修饰符,确保只有授权的用户和合约可以访问特定的标识符。

通过这样的设计,可以确保用户的身份信息在链上安全存储,同时保证合规性和隐私保护。

4. 规则合约

下一步是创建规则合约。

在为两个个体之间的转账实现一组规则时,需要认识到这些规则可能会随着时间的推移而变化。拥有一个单一的智能合约来定义给定上下文(如货币转账)的所有规则,意味着 ERC20 合约不必自己跟踪规则。政府可以简单地更新这个合约,并且它会自动传播到所有实现了该合约的代币。

从本质上讲,规则合约只是一组与加密的身份属性匹配的条件。为了避免滥用,用户不会直接授予规则合约访问权限,而是将权限授予 ERC20 代币合约,然后它执行一个委托调用到规则合约。这样做确保了只有用户信任的 ERC20 合约才能访问他们的信息。请记住,在进行转账之前,发送方和接收方都必须授予 ERC20 合约访问权限。

在本例中将实现一些基本规则:

  • 在同一国家内的转账没有限制,但转账到其他国家的金额限制为 10,000 个代币。
  • 被列入黑名单的用户不能进行转账或接收代币。
  • 用户不能将代币转账到被列入黑名单的国家。

与其让交易失败(这可能会暴露敏感信息),将简单地将转账金额设置为 0,如果没有满足其中一个条件。这使用了一个同态三元操作符,称为 cmuxvalue = TFHE.cmux(encryptedCondition, valueIfTrue, valueIfFalse);

// SPDX-License-Identifier: BSD-3-Clause-Clearpragma solidity 0.8.19;import "fhevm/lib/TFHE.sol";
import "./IdentityRegistry.sol";interface ICompliantERC20 {function getIdentifier(address wallet, string calldata identifier) external view returns (euint32);
}contract ERC20Rules {string[] public identifiers;mapping(address => uint32) public whitelistedWallets;mapping(string => uint8) public countries;uint16[] public country2CountryRestrictions;constructor() {identifiers = ["country", "blacklist"];whitelistedWallets[address(0x133725C6461120439E85887C7639316CB27a2D9d)] = 1;whitelistedWallets[address(0x4CaCeF78615AFecEf7eF182CfbD243195Fc90a29)] = 2;countries["fr"] = 1;countries["us"] = 2;country2CountryRestrictions = [createRestriction(countries["us"], countries["fr"])];}function createRestriction(uint16 from, uint16 to) internal pure returns (uint16) {return (from << 8) + to;}function getIdentifiers() public view returns (string[] memory) {return identifiers;}function getC2CRestrictions() public view returns (uint16[] memory) {return country2CountryRestrictions;}function transfer(address from, address to, euint32 amount) public view returns (euint32) {ICompliantERC20 erc20 = ICompliantERC20(msg.sender);// 条件 1:不同国家之间的转账限额为 10,000 个代币ebool transferLimitOK = checkLimitTransfer(erc20, from, to, amount);ebool condition = transferLimitOK;// 条件 2:检查是否有黑名单用户ebool blacklistOK = checkBlacklist(erc20, from, to);condition = TFHE.and(condition, blacklistOK);// 条件 3:检查国家间转账规则ebool c2cOK = checkCountryToCountry(erc20, from, to);condition = TFHE.and(condition, c2cOK);return TFHE.cmux(condition, amount, TFHE.asEuint32(0));}function checkLimitTransfer(ICompliantERC20 erc20,address from,address to,euint32 amount) internal view returns (ebool) {euint8 fromCountry = TFHE.asEuint8(erc20.getIdentifier(from, "country"));euint8 toCountry = TFHE.asEuint8(erc20.getIdentifier(to, "country"));require(TFHE.isInitialized(fromCountry) && TFHE.isInitialized(toCountry), "You don't have access");ebool sameCountry = TFHE.eq(fromCountry, toCountry);ebool amountBelow10k = TFHE.le(amount, 10000);return TFHE.or(sameCountry, amountBelow10k);}function checkBlacklist(ICompliantERC20 erc20, address from, address to) internal view returns (ebool) {ebool fromBlacklisted = TFHE.asEbool(erc20.getIdentifier(from, "blacklist"));ebool toBlacklisted = TFHE.asEbool(erc20.getIdentifier(to, "blacklist"));return TFHE.not(TFHE.and(toBlacklisted, fromBlacklisted));}function checkCountryToCountry(ICompliantERC20 erc20, address from, address to) internal view returns (ebool) {// 禁止从国家 2 转账到国家 1uint16[] memory c2cRestrictions = getC2CRestrictions();euint32 fromCountry = erc20.getIdentifier(from, "country");euint32 toCountry = erc20.getIdentifier(to, "country");require(TFHE.isInitialized(fromCountry) && TFHE.isInitialized(toCountry), "You don't have access");euint16 countryToCountry = TFHE.shl(TFHE.asEuint16(fromCountry), 8) + TFHE.asEuint16(toCountry);ebool condition = TFHE.asEbool(true);// 检查所有国家间的转账限制for (uint i = 0; i < c2cRestrictions.length; i++) {condition = TFHE.and(condition, TFHE.ne(countryToCountry, c2cRestrictions[i]));}return condition;}
}

其中:

  • createRestriction:创建一个国家到国家的转账限制,两个国家通过一个 16 位的编码表示。
  • getIdentifiers:返回所有的标识符数组。
  • getC2CRestrictions:返回所有的国家间转账限制。
  • transfer:检查转账是否满足所有条件(如限额、黑名单、国家间转账规则),如果任何条件不满足,则将转账金额设置为 0。
  • checkLimitTransfer:检查转账是否超出了不同国家之间的限额。
  • checkBlacklist:检查发送方和接收方是否在黑名单中。
  • checkCountryToCountry:检查两个国家之间是否允许转账。

这种设计可以确保在转账过程中遵循规则和合规性要求,同时保障用户的隐私和安全。

5. 合规的机密 ERC20 合约

现在有了身份注册合约和规则合约,接下来创建合规、隐私保护的代币合约。这个合约将被称为 CompliantERC20,并具有以下关键特性:

  • 用户余额和转账金额是加密的。
  • 转账时通过调用规则合约来强制执行合规性。
  • 某些余额的可见性可以授予白名单地址(如监管机构)。
// SPDX-License-Identifier: BSD-3-Clause-Clearpragma solidity 0.8.19;import "fhevm/abstracts/EIP712WithModifier.sol";
import "./ERC20Rules.sol";
import "./IdentityRegistry.sol";abstract contract AbstractCompliantERC20 is EIP712WithModifier {IdentityRegistry identityContract;ERC20Rules rulesContract;mapping(address => euint32) internal balances;constructor(address _identityAddr, address _rulesAddr) EIP712WithModifier("Authorization token", "1") {identityContract = IdentityRegistry(_identityAddr);rulesContract = ERC20Rules(_rulesAddr);}function identifiers() public view returns (string[] memory) {return rulesContract.getIdentifiers();}function getIdentifier(address wallet, string calldata identifier) external view returns (euint32) {require(msg.sender == address(rulesContract), "Access restricted to the current ERC20Rules");return identityContract.getIdentifier(wallet, identifier);}function balanceOf(address wallet,bytes32 publicKey,bytes calldata signature) public view onlySignedPublicKey(publicKey, signature) returns (bytes memory) {// 用户可以查看自己的余额if (wallet == msg.sender) {return TFHE.reencrypt(balances[msg.sender], publicKey, 0);}// 国家可以查看所有公民的余额uint32 userCountry = rulesContract.whitelistedWallets(msg.sender);require(userCountry > 0, "You're not registered as a whitelisted wallet");euint32 walletCountry = identityContract.getIdentifier(wallet, "country");ebool sameCountry = TFHE.eq(walletCountry, userCountry);euint32 balance = TFHE.isInitialized(balances[wallet]) ? balances[wallet] : TFHE.asEuint32(0);balance = TFHE.cmux(sameCountry, balance, TFHE.asEuint32(0));return TFHE.reencrypt(balance, publicKey, 0);}// 转账加密金额function _transfer(address from, address to, euint32 _amount) internal {// 条件 1:资金充足ebool enoughFund = TFHE.le(_amount, balances[from]);euint32 amount = TFHE.cmux(enoughFund, _amount, TFHE.asEuint32(0));amount = rulesContract.transfer(from, to, amount);balances[to] = balances[to] + amount;balances[from] = balances[from] - amount;}
}

其中:

  • balanceOf:此方法根据用户的公钥和签名返回加密后的余额。用户只能查看自己的余额,如果是同一国家的用户,国家可以查看所有公民的余额。
  • _transfer:在转账过程中,通过规则合约来强制执行合规性,确保资金充足后,转账金额经过合规性检查,然后将金额从发送方转账到接收方。

在这个合约中,规则合约是通过简单的调用来触发的。这意味着用户必须在发起任何转账之前提供对 ERC20 合约的访问权限;否则,转账将被回滚。

最终,创建的 ERC20 合约:

// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity 0.8.19;import "fhevm/lib/TFHE.sol";
import "./AbstractCompliantERC20.sol";contract CompliantERC20 is AbstractCompliantERC20 {...// 从消息发送者地址转账加密金额到 `to` 地址function transfer(address to, bytes calldata encryptedAmount) public {transfer(to, TFHE.asEuint32(encryptedAmount));}// 从消息发送者地址转账金额到 `to` 地址function transfer(address to, euint32 amount) public {_transfer(msg.sender, to, amount);}
}

与用户授权 DeFi 协议花费他们的代币类似,用户需要授权合约访问规则合约所需的标识符。这是通过调用 Identity.grantAccess(contractAddress, identifiers) 来实现的,标识符可以通过调用 ERC20.identifiers() view方法来获取。这个列表直接来自 ERC20Rules 合约,用于允许属性的更新。

6. 合规性与隐私可以共存!

如果拥有正确的工具,构建合规性并不是一件困难的事情。虽然Zama最初构建了 fhEVM 以在区块链中实现隐私保护,但很快意识到,这项技术可以用于身份管理,从而实现可编程的合规性。

参考资料

[1] Zama团队2023年11月23日博客 Programmable Privacy and Onchain Compliance using Homomorphic Encryption

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

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

相关文章

封装---统一封装处理页面标题

一.采用工具来实现(setPageTitle.ts)多个页面中用更统一的方式设置 document.title&#xff0c;可以封装一个工具函数:在utils目录下新建文件:setPageTitle.ts如果要在每个页面设置相同的网站标志可以使用下面的appNameconst appName: string import.meta.env.VITE_APP_NAMEex…

JAVA学习笔记 首个HelloWorld程序-002

目录 1 前言 2 开发首个程序 3 小结 1 前言 在所有的开发语言中&#xff0c;基本上首先程序就是输出HelloWorld&#xff0c;这里也不例外。这个需要注意的是&#xff0c;程序的核心功能是数据输出&#xff0c;是要有一个结果&#xff0c;可能没有输入&#xff0c;但是一定有…

智慧监所:科技赋能监狱管理新变革

1. 高清教育&#xff1a;告别模糊画面&#xff0c;学习更清晰传统电视的雪花屏终于成为历史&#xff01;新系统采用高清传输&#xff0c;课件文字清晰可见&#xff0c;教学视频细节分明。某监狱教育科王警官说&#xff1a;"现在播放法律课程&#xff0c;服刑人员能清楚看到…

专题:2025供应链数智化与效率提升报告|附100+份报告PDF、原数据表汇总下载

全文链接&#xff1a;https://tecdat.cn/?p42926 在全球产业链重构与数字技术革命的双重驱动下&#xff0c;供应链正经历从传统经验驱动向数据智能驱动的范式变革。从快消品产能区域化布局到垂类折扣企业的效率竞赛&#xff0c;从人形机器人的成本优化到供应链金融对中小企业的…

uniapp+vue3+ts项目:实现小程序文件下载、预览、进度监听(含项目、案例、插件)

uniapp+vue3+ts项目:实现小程序文件下载、预览、进度监听(含项目、案例、插件) 支持封装调用: 项目采用uniapp+vue3+ts +京东nutUI 开发nutUi文档:loadingPage组件:https://uniapp-nutui.tech/components/exhibition/loadingpage.html案例效果图: 略博主自留地:参考本地…

用Python和OpenCV从零搭建一个完整的双目视觉系统(六 最终篇)

本系列文章旨在系统性地阐述如何利用 Python 与 OpenCV 库&#xff0c;从零开始构建一个完整的双目立体视觉系统。 本项目github地址&#xff1a;https://github.com/present-cjn/stereo-vision-python.git 1. 概述 欢迎来到本系列文章的最后一篇。在过去的几篇文章中&#…

Android View 绘制流程 简述 (无限递归+BitMap问题)

绘制流程 在 Android 的 View 系统中&#xff0c;draw(canvas) 和 dispatchDraw(canvas) 是绘制流程中的两个关键方法&#xff1a; 1. draw(canvas) 方法的作用 draw(canvas) 是 View 类中的核心绘制方法&#xff0c;它的主要职责包括&#xff1a; 绘制背景 - 调用 drawBac…

算法学习笔记:18.拉斯维加斯算法 ——从原理到实战,涵盖 LeetCode 与考研 408 例题

在随机化算法领域&#xff0c;拉斯维加斯&#xff08;Las Vegas&#xff09;算法以其独特的设计思想占据重要地位。与蒙特卡洛&#xff08;Monte Carlo&#xff09;算法不同&#xff0c;拉斯维加斯算法总能给出正确的结果&#xff0c;但运行时间具有随机性 —— 在最坏情况下可…

26-计组-指令执行过程

一、指令周期1. 定义与组成定义&#xff1a;CPU取出并执行一条指令所需的全部时间&#xff0c;称为指令周期。子周期划分&#xff1a;取指周期&#xff08;必选&#xff09;&#xff1a;从存储器取指令到指令寄存器&#xff08;IR&#xff09;。间址周期&#xff08;可选&#…

【JMeter】数据驱动测试

文章目录创建数据文件加载数据文件根据数据文件请求接口、传递参数拓展含义&#xff1a;根据数据的数量、内容&#xff0c;自动的决定用例的数据和内容。数据驱动测试用例。步骤&#xff1a; 创建数据文件加载数据文件根据数据文件请求接口、传递参数 创建数据文件 Jmeter支…

Springboot实现一个接口加密

首先来看效果这个主要是为了防止篡改请求的。 我们这里采用的是一个AOP的拦截&#xff0c;在有需要这样的接口上添加了加密处理。 下面是一些功能防篡改HMAC-SHA256 参数签名密钥仅客户端 & 服务器持有防重放秒级时间戳 有效窗口校验默认允许 5 分钟防窃听AES/CBC/PKCS5Pa…

斯坦福 CS336 动手大语言模型 Assignment1 BPE Tokenizer TransformerLM

所有代码更新至 https://github.com/WangYuHang-cmd/CS336/tree/main/assignment1-basics 作业文件结构: CS336/assignment1-basics/ ├── tests/ # 测试文件目录 │ ├── adapters.py # 适配器测试 │ ├── conftest.py # pyt…

Spring Cloud Gateway 实战指南

关键词&#xff1a;微服务、API网关、Spring Cloud Gateway、路由转发、限流熔断 ✅ 文章摘要 随着互联网应用规模的不断扩大&#xff0c;传统的单体架构逐渐向微服务架构转型。在微服务架构中&#xff0c;API 网关作为系统的入口点&#xff0c;承担了诸如请求路由、负载均衡、…

PyTorch自动微分:从基础到实战

目录 1. 自动微分是什么&#xff1f; 1.1 计算图 1.2 requires_grad 属性 2. 标量和向量的梯度计算 2.1 标量梯度 2.2 向量梯度 3. 梯度上下文控制 3.1 禁用梯度计算 3.2 累计梯度 4. 梯度下降实战 4.1 求函数最小值 4.2 线性回归参数求解 5. 总结 在深度学习中&a…

Spring AI 项目实战(十六):Spring Boot + AI + 通义万相图像生成工具全栈项目实战(附完整源码)

系列文章 序号文章名称1Spring AI 项目实战(一):Spring AI 核心模块入门2Spring AI 项目实战(二):Spring Boot + AI + DeepSeek 深度实战(附完整源码)3Spring AI 项目实战(三):Spring Boot + AI + DeepSeek 打造智能客服系统(附完整源码)4

从零到一:企业如何组建安全团队

在这个"黑客满天飞&#xff0c;漏洞遍地跑"的时代&#xff0c;没有安全团队的企业就像裸奔的勇士——虽然很有勇气&#xff0c;但结局往往很悲惨。 &#x1f4cb; 目录 为什么要组建安全团队安全团队的核心职能团队架构设计人员配置策略技术体系建设制度流程建立实施…

业务访问控制-ACL与包过滤

业务访问控制-ACL与包过滤 ACL的定义及应用场景ACL&#xff08;Access Control List&#xff0c;访问控制列表&#xff09;是用来实现数据包识别功能的&#xff1b;ACL可以应用于诸多场景&#xff1a; 包过滤功能&#xff1a;对数据包进行放通或过滤操作。NAT&#xff08;Netwo…

穿梭时空的智慧向导:Deepoc具身智能如何赋予导览机器人“人情味”

穿梭时空的智慧向导&#xff1a;Deepoc具身智能如何赋予导览机器人“人情味”清晨&#xff0c;当第一缕阳光透过高大的彩绘玻璃窗&#xff0c;洒在博物馆光洁的地板上&#xff0c;一位特别的“馆员”已悄然“苏醒”。它没有制服&#xff0c;却有着清晰的指引&#xff1b;它无需…

PostgreSQL 查询库中所有表占用磁盘大小、表大小

SELECTn.nspname AS schema_name,c.relname AS table_name,-- 1️⃣ 总大小&#xff08;表 toast 索引&#xff09;pg_size_pretty(pg_total_relation_size(c.oid)) AS total_size,-- 2️⃣ 表不包含索引&#xff08;含 TOAST&#xff09;pg_size_pretty(pg_total_relation_s…

日记-生活随想

最近鼠鼠也是来到上海打拼&#xff08;实习&#xff09;了&#xff0c;那么秉持着来都来了的原则&#xff0c;鼠鼠也是去bw逛了逛&#xff0c;虽说没票只能在外场看看&#x1f62d;。可惜几乎没有多少我非常喜欢的ip&#xff0c;不由感慨现在的二次元圈已经变样了。虽说我知道内…