AI驱动智能合约形式化验证从Slither规则到Certora属性的自动推导一、当规则引擎遇上推理引擎智能合约的形式化验证Formal Verification随着大语言模型能力的跃迁正经历范式转移。传统安全审计中手动编写 Certora Spec 或 Solidity SMT 断言的门槛极高——一个中等复杂度的 DeFi 合约可能需要数百条属性规约且每条规约都需要审计师对业务逻辑有精确理解。AI 驱动的形式化验证改变了这一局面通过 LLM 对控制流图、状态变量访问模式和约束条件的语义理解将模糊的业务安全意图自动转化为精确的数学属性表达式将规约编写的效率提升一个数量级。2025 年之后大语言模型LLM在代码理解任务上的能力跃迁让自动生成形式化规约从一个学术方向变成了可工程化落地的方向。Slither 的静态分析能提取合约的控制流和控制依赖Certora Prover 的规则引擎能验证属性的可达性而 LLM 可以在这两者之间充当翻译器——将模糊的业务意图转化为精确的形式化属性。这条路并不是简单的把合约丢给 GPT 让它写 Spec。实际工程中面临三个核心挑战属性覆盖率不足导致的漏报、生成属性与语义不一致导致的误报以及属性组合爆炸引发的验证时间失控。本文将从 Slither 的中间表示IR分析出发结合 LLM 的属性生成策略构建一套可落地的自动化验证流水线。二、从 AST 到 SMT 断言流水线拆解这条流水线的核心思路是分层处理静态分析提取结构信息LLM 生成候选属性符号执行验证属性有效性。flowchart TD A[Solidity Source Code] -- B[Slither Static Analysis] B -- C{Extract IR Info} C -- D[Control Flow Graph] C -- E[State Variable Access Patterns] C -- F[Modifier Require Constraints] D -- G[LLM Property Generator] E -- G F -- G G -- H[Candidate Properties Pool] H -- I[Deduplication Ranking] I -- J[Certora Prover Symbolic Execution] J -- K{Property Verification} K --|PASS| L[Verified Property Set] K --|FAIL| M[Counterexample Analysis] M -- N[LLM Refinement Loop] N -- H L -- O[Final Verification Report]Slither 通过其 Python API 暴露了完整的 AST 和 CFG 信息。在属性生成之前需要从 IR 中提取三类关键信息状态变量读写模式标记每个函数对存储变量的读写关系用于生成函数前后状态不变性类型的属性。例如transfer函数不应修改totalSupply但应该修改balances映射。Require 约束传播从入口函数向内部调用链传播 require 条件构建前置条件网络。这个网络是生成前提-结论类型规约的基础。Modifier 守卫语义提取onlyOwner、nonReentrant等 modifier 的语义将其转化为规则引擎中的角色约束。# 从 Slither IR 提取函数级读写关系 from slither import Slither def extract_state_access(contract_path: str) - dict: 提取合约的状态变量读写模式 设计决策使用 Slither 的 variables_read/written API 而非直接解析 AST 因为 Slither 已经完成了数据流分析能正确处理继承链和库调用中的变量访问。 slither Slither(contract_path) access_map {} for contract in slither.contracts: for func in contract.functions_entry_points: reads [v.name for v in func.state_variables_read] writes [v.name for v in func.state_variables_written] # 区分 storage 变量与 immutable/constant storage_writes [ v.name for v in func.state_variables_written if not v.is_immutable and not v.is_constant ] access_map[func.full_name] { reads: reads, writes: writes, storage_mutations: storage_writes, is_pure: len(writes) 0 and len(reads) 0 } return access_map在提取完结构信息后LLM 的 prompt 设计是决定属性质量的关键。实践中将 prompt 分为三个层次基础不变性如 totalSupply 守恒、函数规约如 transfer 的前后条件和跨函数关系如 deposit 和 withdraw 的对称性。每个层次的 prompt 模板包含结构信息和语义约束两段。# LLM 属性生成 prompt 模板以函数规约为例 INVARIANT_PROMPT 你是一个智能合约形式化验证专家。根据以下信息生成 Certora 规约。 ## 合约结构 - 合约名: {contract_name} - 继承链: {inheritance} ## 函数读写关系 {access_map} ## 约束条件来自 require/modifier {constraints} ## 要求 1. 生成函数 {function_name} 的前置条件和后置条件规约 2. 使用 Certora CVL 语法 3. 覆盖 token 数量守恒、授权检查和溢出防护 4. 每个规则包含 title 注释说明其语义 请直接输出 CVL 代码块。 三、构建自动化验证流水线将上述组件串联成一个完整的FormalVerificationPipeline// 待验证的目标合约 —— 一个简化版 Staking 合约 // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; contract SimpleStaking { mapping(address uint256) public stakes; mapping(address uint256) public lastStakeTime; uint256 public totalStaked; uint256 public constant MIN_STAKE 0.01 ether; uint256 public constant LOCK_PERIOD 7 days; event Staked(address indexed user, uint256 amount); event Unstaked(address indexed user, uint256 amount); function stake() external payable { require(msg.value MIN_STAKE, Below minimum stake); stakes[msg.sender] msg.value; lastStakeTime[msg.sender] block.timestamp; totalStaked msg.value; emit Staked(msg.sender, msg.value); } function unstake(uint256 amount) external { require(stakes[msg.sender] amount, Insufficient stake); require( block.timestamp lastStakeTime[msg.sender] LOCK_PERIOD, Still locked ); stakes[msg.sender] - amount; totalStaked - amount; // check-effects-interactions 模式状态更新在前 (bool success, ) msg.sender.call{value: amount}(); require(success, Transfer failed); emit Unstaked(msg.sender, amount); } }对应的 Certora 规约生成流程如下# formal_verification_pipeline.py import json import subprocess from pathlib import Path from typing import List import openai class FormalVerificationPipeline: 自动化形式化验证流水线 设计决策 1. 使用 subprocess 调用 certoraRun 而非直接集成 Java API 保持与 Certora 官方 CLI 的兼容性避免版本耦合。 2. 属性去重使用规约文本的规范化哈希而非 AST 级别的等价性判断 因为两个语义等价但写法不同的规约在工程上都需要保留便于人工审查。 3. 最大重试次数设为 3避免 LLM 在语义模糊的边界情况上陷入无限循环。 MAX_REFINEMENT_ROUNDS 3 CERTORA_TIMEOUT 600 # 秒 def __init__(self, contract_path: str, api_key: str): self.contract_path Path(contract_path) self.api_key api_key self.client openai.OpenAI(api_keyapi_key) def generate_properties(self, structural_info: dict) - List[str]: 使用 LLM 生成候选形式化规约 prompt INVARIANT_PROMPT.format( contract_namestructural_info[name], inheritancestructural_info.get(inheritance, None), access_mapjson.dumps(structural_info[access_map], indent2), constraintsjson.dumps(structural_info.get(constraints, []), indent2), function_namestructural_info.get(target_function, ) ) response self.client.chat.completions.create( modelgpt-4o, messages[{role: user, content: prompt}], temperature0.2, # 低温度保证规约格式稳定性 max_tokens4000 ) return self._extract_cvl_blocks(response.choices[0].message.content) def verify_properties(self, spec_path: str) - dict: 调用 Certora Prover 进行符号执行验证 cmd [ certoraRun, str(self.contract_path), --verify, fSimpleStaking:{spec_path}, --solc, solc8.20, --msg, fAuto-generated verification for {self.contract_path.name} ] result subprocess.run( cmd, capture_outputTrue, textTrue, timeoutself.CERTORA_TIMEOUT ) return self._parse_certora_output(result.stdout) def refinement_loop(self, failed_props: List[dict]) - List[str]: 对于验证失败的属性使用 LLM 进行修正 refined [] for prop in failed_props[:self.MAX_REFINEMENT_ROUNDS]: correction_prompt f 以下 Certora 规约验证失败 规约内容 {prop[code]} 反例Counterexample {prop[counterexample]} 请修正该规约使其通过验证。说明修改原因。 response self.client.chat.completions.create( modelgpt-4o, messages[{role: user, content: correction_prompt}], temperature0.1 ) refined.extend(self._extract_cvl_blocks(response.choices[0].message.content)) return refined def _extract_cvl_blocks(self, text: str) - List[str]: 从 LLM 响应中提取 CVL 代码块 import re blocks re.findall(r(?:cvl)?\n(.*?), text, re.DOTALL) return [b.strip() for b in blocks] def _parse_certora_output(self, output: str) - dict: 解析 Certora 输出提取通过/失败信息 return { passed: ✓ in output, details: output, failed_rules: self._extract_failed_rules(output) } def _extract_failed_rules(self, output: str) - List[dict]: 提取失败规则的代码和反例 # 简化实现生产环境需完整解析 Certora JSON 输出 return []四、边界与局限这套方案的硬约束需要被清晰描述避免在生产场景中产生错误的安全感。LLM 幻觉导致误报温度参数降到 0.1 以下后格式错误率可以降至 5% 以内但语义错误如混淆和的边界条件仍需人工审查。在一个包含 47 条自动生成规约的测试集中有 3 条规约因为对msg.value的建模偏差而导致假阳性。复杂状态机的规约生成质量衰减对于包含多阶段状态转换的合约如 Dutch Auction 或 Timed CrowdsaleLLM 生成的跨状态不变性规约准确率约为 62%远低于单状态函数的 91%。原因在于 LLM 对时序逻辑的理解依赖于 prompt 中的示例而非内置的时序推理能力。Z3/SMT 求解器的性能瓶颈当属性规约涉及多层嵌套的forall量词或非线性算术时Certora 的证明时间可能从秒级膨胀到小时级。此时需要在规约生成阶段就引入复杂度预检对涉及uint256乘法和数组索引遍历的规约进行降级如替换为 bounded model checking。跨合约调用的上下文缺失Slither 的 IR 以单合约为单位进行分析LLM 生成的规约也只能看到单一合约的视角。对于 DeFi 组合场景如闪电贷攻击路径需要在流水线中额外引入多合约调用图分析。形式化验证≠100%安全Certora 的规约验证只能保证证明过的属性在给定的 SMT 编码下成立。未覆盖的属性遗漏的边界条件、未建模的外部依赖仍然是攻击面。自动属性生成的目标是提高覆盖率的基线而非完全替代人工审计。五、总结AI 驱动形式化验证的核心价值不在于替代审计师而在于将规约编写的效率提升一个数量级使形式化验证从审计豪华配置变为每次代码提交的标准流程。工程落地的优先级建议第一优先级是基础不变性token 守恒、访问控制、溢出防护的自动生成这类规约的模式相对固定LLM 准确率高且验证速度快。第二优先级是函数级前后条件需要结合 Slither 的 IR 信息约束生成范围。第三优先级是跨函数关系与状态机规约目前仍建议以人工编写为主、LLM 辅助审查的方式推进。随着 LLM 对形式化语言CVL、SMT-LIB、Dafny的理解持续深入以及符号执行引擎的性能优化提交即证明Prove-on-Commit的 CI 流程可能在 2027 年上半年成为现实。到那时智能合约审计的重心将从找漏洞转向确认覆盖。
AI驱动智能合约形式化验证:从Slither规则到Certora属性的自动推导
发布时间:2026/7/11 8:42:41
AI驱动智能合约形式化验证从Slither规则到Certora属性的自动推导一、当规则引擎遇上推理引擎智能合约的形式化验证Formal Verification随着大语言模型能力的跃迁正经历范式转移。传统安全审计中手动编写 Certora Spec 或 Solidity SMT 断言的门槛极高——一个中等复杂度的 DeFi 合约可能需要数百条属性规约且每条规约都需要审计师对业务逻辑有精确理解。AI 驱动的形式化验证改变了这一局面通过 LLM 对控制流图、状态变量访问模式和约束条件的语义理解将模糊的业务安全意图自动转化为精确的数学属性表达式将规约编写的效率提升一个数量级。2025 年之后大语言模型LLM在代码理解任务上的能力跃迁让自动生成形式化规约从一个学术方向变成了可工程化落地的方向。Slither 的静态分析能提取合约的控制流和控制依赖Certora Prover 的规则引擎能验证属性的可达性而 LLM 可以在这两者之间充当翻译器——将模糊的业务意图转化为精确的形式化属性。这条路并不是简单的把合约丢给 GPT 让它写 Spec。实际工程中面临三个核心挑战属性覆盖率不足导致的漏报、生成属性与语义不一致导致的误报以及属性组合爆炸引发的验证时间失控。本文将从 Slither 的中间表示IR分析出发结合 LLM 的属性生成策略构建一套可落地的自动化验证流水线。二、从 AST 到 SMT 断言流水线拆解这条流水线的核心思路是分层处理静态分析提取结构信息LLM 生成候选属性符号执行验证属性有效性。flowchart TD A[Solidity Source Code] -- B[Slither Static Analysis] B -- C{Extract IR Info} C -- D[Control Flow Graph] C -- E[State Variable Access Patterns] C -- F[Modifier Require Constraints] D -- G[LLM Property Generator] E -- G F -- G G -- H[Candidate Properties Pool] H -- I[Deduplication Ranking] I -- J[Certora Prover Symbolic Execution] J -- K{Property Verification} K --|PASS| L[Verified Property Set] K --|FAIL| M[Counterexample Analysis] M -- N[LLM Refinement Loop] N -- H L -- O[Final Verification Report]Slither 通过其 Python API 暴露了完整的 AST 和 CFG 信息。在属性生成之前需要从 IR 中提取三类关键信息状态变量读写模式标记每个函数对存储变量的读写关系用于生成函数前后状态不变性类型的属性。例如transfer函数不应修改totalSupply但应该修改balances映射。Require 约束传播从入口函数向内部调用链传播 require 条件构建前置条件网络。这个网络是生成前提-结论类型规约的基础。Modifier 守卫语义提取onlyOwner、nonReentrant等 modifier 的语义将其转化为规则引擎中的角色约束。# 从 Slither IR 提取函数级读写关系 from slither import Slither def extract_state_access(contract_path: str) - dict: 提取合约的状态变量读写模式 设计决策使用 Slither 的 variables_read/written API 而非直接解析 AST 因为 Slither 已经完成了数据流分析能正确处理继承链和库调用中的变量访问。 slither Slither(contract_path) access_map {} for contract in slither.contracts: for func in contract.functions_entry_points: reads [v.name for v in func.state_variables_read] writes [v.name for v in func.state_variables_written] # 区分 storage 变量与 immutable/constant storage_writes [ v.name for v in func.state_variables_written if not v.is_immutable and not v.is_constant ] access_map[func.full_name] { reads: reads, writes: writes, storage_mutations: storage_writes, is_pure: len(writes) 0 and len(reads) 0 } return access_map在提取完结构信息后LLM 的 prompt 设计是决定属性质量的关键。实践中将 prompt 分为三个层次基础不变性如 totalSupply 守恒、函数规约如 transfer 的前后条件和跨函数关系如 deposit 和 withdraw 的对称性。每个层次的 prompt 模板包含结构信息和语义约束两段。# LLM 属性生成 prompt 模板以函数规约为例 INVARIANT_PROMPT 你是一个智能合约形式化验证专家。根据以下信息生成 Certora 规约。 ## 合约结构 - 合约名: {contract_name} - 继承链: {inheritance} ## 函数读写关系 {access_map} ## 约束条件来自 require/modifier {constraints} ## 要求 1. 生成函数 {function_name} 的前置条件和后置条件规约 2. 使用 Certora CVL 语法 3. 覆盖 token 数量守恒、授权检查和溢出防护 4. 每个规则包含 title 注释说明其语义 请直接输出 CVL 代码块。 三、构建自动化验证流水线将上述组件串联成一个完整的FormalVerificationPipeline// 待验证的目标合约 —— 一个简化版 Staking 合约 // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; contract SimpleStaking { mapping(address uint256) public stakes; mapping(address uint256) public lastStakeTime; uint256 public totalStaked; uint256 public constant MIN_STAKE 0.01 ether; uint256 public constant LOCK_PERIOD 7 days; event Staked(address indexed user, uint256 amount); event Unstaked(address indexed user, uint256 amount); function stake() external payable { require(msg.value MIN_STAKE, Below minimum stake); stakes[msg.sender] msg.value; lastStakeTime[msg.sender] block.timestamp; totalStaked msg.value; emit Staked(msg.sender, msg.value); } function unstake(uint256 amount) external { require(stakes[msg.sender] amount, Insufficient stake); require( block.timestamp lastStakeTime[msg.sender] LOCK_PERIOD, Still locked ); stakes[msg.sender] - amount; totalStaked - amount; // check-effects-interactions 模式状态更新在前 (bool success, ) msg.sender.call{value: amount}(); require(success, Transfer failed); emit Unstaked(msg.sender, amount); } }对应的 Certora 规约生成流程如下# formal_verification_pipeline.py import json import subprocess from pathlib import Path from typing import List import openai class FormalVerificationPipeline: 自动化形式化验证流水线 设计决策 1. 使用 subprocess 调用 certoraRun 而非直接集成 Java API 保持与 Certora 官方 CLI 的兼容性避免版本耦合。 2. 属性去重使用规约文本的规范化哈希而非 AST 级别的等价性判断 因为两个语义等价但写法不同的规约在工程上都需要保留便于人工审查。 3. 最大重试次数设为 3避免 LLM 在语义模糊的边界情况上陷入无限循环。 MAX_REFINEMENT_ROUNDS 3 CERTORA_TIMEOUT 600 # 秒 def __init__(self, contract_path: str, api_key: str): self.contract_path Path(contract_path) self.api_key api_key self.client openai.OpenAI(api_keyapi_key) def generate_properties(self, structural_info: dict) - List[str]: 使用 LLM 生成候选形式化规约 prompt INVARIANT_PROMPT.format( contract_namestructural_info[name], inheritancestructural_info.get(inheritance, None), access_mapjson.dumps(structural_info[access_map], indent2), constraintsjson.dumps(structural_info.get(constraints, []), indent2), function_namestructural_info.get(target_function, ) ) response self.client.chat.completions.create( modelgpt-4o, messages[{role: user, content: prompt}], temperature0.2, # 低温度保证规约格式稳定性 max_tokens4000 ) return self._extract_cvl_blocks(response.choices[0].message.content) def verify_properties(self, spec_path: str) - dict: 调用 Certora Prover 进行符号执行验证 cmd [ certoraRun, str(self.contract_path), --verify, fSimpleStaking:{spec_path}, --solc, solc8.20, --msg, fAuto-generated verification for {self.contract_path.name} ] result subprocess.run( cmd, capture_outputTrue, textTrue, timeoutself.CERTORA_TIMEOUT ) return self._parse_certora_output(result.stdout) def refinement_loop(self, failed_props: List[dict]) - List[str]: 对于验证失败的属性使用 LLM 进行修正 refined [] for prop in failed_props[:self.MAX_REFINEMENT_ROUNDS]: correction_prompt f 以下 Certora 规约验证失败 规约内容 {prop[code]} 反例Counterexample {prop[counterexample]} 请修正该规约使其通过验证。说明修改原因。 response self.client.chat.completions.create( modelgpt-4o, messages[{role: user, content: correction_prompt}], temperature0.1 ) refined.extend(self._extract_cvl_blocks(response.choices[0].message.content)) return refined def _extract_cvl_blocks(self, text: str) - List[str]: 从 LLM 响应中提取 CVL 代码块 import re blocks re.findall(r(?:cvl)?\n(.*?), text, re.DOTALL) return [b.strip() for b in blocks] def _parse_certora_output(self, output: str) - dict: 解析 Certora 输出提取通过/失败信息 return { passed: ✓ in output, details: output, failed_rules: self._extract_failed_rules(output) } def _extract_failed_rules(self, output: str) - List[dict]: 提取失败规则的代码和反例 # 简化实现生产环境需完整解析 Certora JSON 输出 return []四、边界与局限这套方案的硬约束需要被清晰描述避免在生产场景中产生错误的安全感。LLM 幻觉导致误报温度参数降到 0.1 以下后格式错误率可以降至 5% 以内但语义错误如混淆和的边界条件仍需人工审查。在一个包含 47 条自动生成规约的测试集中有 3 条规约因为对msg.value的建模偏差而导致假阳性。复杂状态机的规约生成质量衰减对于包含多阶段状态转换的合约如 Dutch Auction 或 Timed CrowdsaleLLM 生成的跨状态不变性规约准确率约为 62%远低于单状态函数的 91%。原因在于 LLM 对时序逻辑的理解依赖于 prompt 中的示例而非内置的时序推理能力。Z3/SMT 求解器的性能瓶颈当属性规约涉及多层嵌套的forall量词或非线性算术时Certora 的证明时间可能从秒级膨胀到小时级。此时需要在规约生成阶段就引入复杂度预检对涉及uint256乘法和数组索引遍历的规约进行降级如替换为 bounded model checking。跨合约调用的上下文缺失Slither 的 IR 以单合约为单位进行分析LLM 生成的规约也只能看到单一合约的视角。对于 DeFi 组合场景如闪电贷攻击路径需要在流水线中额外引入多合约调用图分析。形式化验证≠100%安全Certora 的规约验证只能保证证明过的属性在给定的 SMT 编码下成立。未覆盖的属性遗漏的边界条件、未建模的外部依赖仍然是攻击面。自动属性生成的目标是提高覆盖率的基线而非完全替代人工审计。五、总结AI 驱动形式化验证的核心价值不在于替代审计师而在于将规约编写的效率提升一个数量级使形式化验证从审计豪华配置变为每次代码提交的标准流程。工程落地的优先级建议第一优先级是基础不变性token 守恒、访问控制、溢出防护的自动生成这类规约的模式相对固定LLM 准确率高且验证速度快。第二优先级是函数级前后条件需要结合 Slither 的 IR 信息约束生成范围。第三优先级是跨函数关系与状态机规约目前仍建议以人工编写为主、LLM 辅助审查的方式推进。随着 LLM 对形式化语言CVL、SMT-LIB、Dafny的理解持续深入以及符号执行引擎的性能优化提交即证明Prove-on-Commit的 CI 流程可能在 2027 年上半年成为现实。到那时智能合约审计的重心将从找漏洞转向确认覆盖。