Nautilus Trader Lighter 签名交易 Oracle:以闭源签名器为基准的 L2 交易字节级等价验证方案

发布时间:2026/9/11 11:06:20
Nautilus Trader Lighter 签名交易 Oracle:以闭源签名器为基准的 L2 交易字节级等价验证方案 Nautilus Trader Lighter 签名交易 Oracle以闭源签名器为基准的 L2 交易字节级等价验证方案【免费下载链接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture项目地址: https://gitcode.com/GitHub_Trending/na/nautilus_trader本篇技术指南聚焦 nautilus_trader 仓库中 Lighter 适配器crates/adapters/lighter的签名交易 Oraclesigning tx oracle机制。它通过加载lighter-pythonSDK 自带的闭源签名器动态库对交易关键型 L2 交易类型运行确定性输入并将权威的tx_info、tx_hash、签名字节与公钥字节固化为 JSON fixture供 Rust 端测试断言与官方签名器输出的字节级等价性。读完本文你将掌握这套以闭源 SDK 为行为基准oracle的测试方法论、fixture 的数据结构、生成脚本的运行方式以及 Rust 侧如何借助 Poseidon2 哈希与 ecgfp5 曲线 Schnorr 签名完成字节等价、验签与自签回环三层验证。为什么需要 Oracle三层签章正确性门禁Lighter 是一个 L2 交易所其交易签名栈由三层构成nautilus_trader 对每一层设置了对应的验证门禁gate第一层底层密码学原语Goldilocks 域p 2^64 - 2^32 1、quintic 扩展域Fp5、ecgfp5 曲线、Poseidon2 哈希、Schnorr 签名的行为由仓库内开源的 Go 参考实现elliottech/poseidon_crypto等生成的 fixture 向量验证第二层本文主题SDK oracle 门禁官方编译的闭源签名器在此被当作行为基准oracle检查确保我们的哈希组装、域元素编码与签名布局和官方产物一致第三层最终门禁对测试网testnet的实盘往返测试live round-trip testing验证 sequencer 真正接受什么。从源码结构看这一分层在 signing/mod.rs 的模块说明中有明确表述ecgfp5 曲线与 Poseidon2 哈希的参考向量固化为 fixtures而官方lighter-go/lighter-pythonSDK 封装的是闭源编译签名器测试网往返测试是最终正确性门禁。本文描述的 Oracle 正是中间这一关键一环。Oracle 的构成生成脚本 JSON fixture Rust 测试Oracle 由三部分组成分别位于仓库的以下位置组成路径作用生成脚本crates/adapters/lighter/tests/oracle-py/generate_oracle.py通过 ctypes 加载闭源签名器.so驱动其对确定性输入签名并输出 fixture交易 fixturecrates/adapters/lighter/test_data/signing_tx_oracle.json固化tx_info/tx_hash/sig等权威输出认证令牌 fixturecrates/adapters/lighter/test_data/signing_auth_token_oracle.json固化 REST/WS 认证令牌的签名输出Rust 消费方crates/adapters/lighter/src/signing/tx/encode.rs#[cfg(test)] mod tests加载 fixture 并断言字节等价认证令牌消费方crates/adapters/lighter/src/signing/auth_token.rs用同一摘要重算并验证 oracle 令牌生成脚本使用include_str!在编译期把 fixture 直接嵌入测试二进制const ORACLE_JSON: str include_str!(concat!( env!(CARGO_MANIFEST_DIR), /test_data/signing_tx_oracle.json, ));这意味着 fixture 一旦被修改测试即随之生效无需任何运行时文件读取天然保证了可复现与可审计。向量形状Vector Shape每个条目固化什么每个 fixture 条目遵循 README 中给出的 JSON 结构字段语义如下{ kind: create_order, chain_id: 300, sk: hex 40 bytes, account_index: 12345, api_key_index: 5, expired_at: 1777804107504, nonce: 42, fields: {market_index: 0, ...: ...}, tx_type: 14, tx_info: json string emitted by the signer, tx_hash: hex 40 bytes; the signed message hash, sig: hex 80 bytes; s_le || e_le }关键字段说明kind交易种类判别符测试侧据此筛选向量可选值为create_order、cancel_order、modify_order、cancel_all_orders、update_leverage、approve_integratorchain_id固定为 300testnet见脚本中CHAIN_ID_TESTNET 300sk40 字节80 个 hex 字符的确定性私钥所有向量共用。脚本注释说明该字节串arbitrary but non-trivial保证底层标量的每个 limb 都取非零值从而充分覆盖标量运算路径account_index/api_key_index/nonce/expired_at签名上下文TxContext的四个要素fields该交易类型的业务字段订单参数、integrator 归因、杠杆参数等tx_type交易类型判别符与脚本中TX_TYPE_L2_*常量对应tx_info签名器吐出的权威 JSON 字符串含 base64 编码的Sigtx_hash40 字节小端编码的签名消息哈希即 sequencer 侧回显的tx_hashsig80 字节签名按s_le || e_le布局。在 Rust 测试的OracleVector反序列化结构中见 encode.rsexpired_at和nonce独立于fields单独解析。一个值得注意的细节expired_at是由脚本从签名器返回的tx_info_decoded[ExpiredAt]回读并写入 fixture 的——因为闭源签名器在 FFI 内部会以墙钟时间自动填充该字段Rust 侧必须读回它才能重建相同的哈希预映像见build_vector的注释。这保证了输入被完整固化是字节等价断言成立的前提。如何运行克隆上游 SDK 并执行生成脚本README 给出完整运行方式适用于 Linuxgit clone --depth 1 https://github.com/elliottech/lighter-python.git /tmp/lighter-python cd crates/adapters/lighter/tests/oracle-py python3 generate_oracle.py \ --signer /tmp/lighter-python/lighter/signers/lighter-signer-linux-amd64.so \ --out ../../test_data/signing_tx_oracle.json \ --auth-out ../../test_data/signing_auth_token_oracle.json各参数说明--signer必填闭源签名器共享库路径。该.so随lighter-python包分发macOS 上应改用lighter-signer-darwin-arm64.dylib脚本 help 文本也列出了{so,dylib,dll}三种形态--out必填L2 交易 Oracle fixture 的输出路径--auth-out可选设置后脚本还会驱动签名器的CreateAuthToken对固定的(deadline, account_index, api_key_index)三元组签名并把签好的 REST/WS 认证令牌写入该 JSON 文件。Rust 侧在 auth_token.rs 中加载它对同一消息重算摘要并验证令牌内嵌签名。运行前提与可复现保证脚本以固定私钥fixed_private_key()初始化签名器并合成固定的ExpiredAt因此连续多次运行会产出字节一致的tx_hash与tx_info除Sig外Sig本身是非确定性的上游签名器每次调用都会抽取新的随机 noncek。所以 fixture 固化的是输入和结果tx_hash以支持确定性字节等价而签名字节仅作为验签侧往返verify-side round trip的见证该程序已提交入库以保障可复现性但它不属于 crate 的构建产物——不会被编译进 crate只在签名器版本升级或新增交易类型时由人工手动运行。生成脚本还固定了上游版本指纹以增强可追溯性UPSTREAM_VERSION 1.1.2 UPSTREAM_REVISION 6957dd8a1b36894ca9580be0d51de30aeea3bd4a这些信息连同许可证声明Apache-2.0SDK 仓库编译签名器以二进制形式分发被写入 fixture 的metadata块。生成脚本内部ctypes FFI 绑定与确定性输入设计generate_oracle.py的核心机制是ctypes动态加载签名器共享库并镜像其 FFI 结构体与函数签名。FFI 结构体镜像脚本用两个ctypes.Structure精确对应签名器的 C ABISignedTxResponse(txType: u8, txInfo: ptr, txHash: ptr, messageToSign: ptr, err: ptr)是Sign*系列函数的返回结构StrOrErr(str: ptr, err: ptr)是CreateAuthToken的返回结构。所有 Go 分配的 C 字符串通过take_str读取并以lib.Free(ptr)释放避免内存泄漏。setup_lib为每个函数逐一绑定argtypes/restype包括CreateClient、SignCreateOrder、SignCancelOrder、SignModifyOrder、SignCancelAllOrders、SignUpdateLeverage、SignApproveIntegrator、CreateAuthToken。覆盖的交易类型与判别符脚本顶部以常量形式固化了与lighter-go一致的 tx 类型判别符常量值说明TX_TYPE_L2_CREATE_ORDER14创建订单TX_TYPE_L2_CANCEL_ORDER15取消订单TX_TYPE_L2_CANCEL_ALL_ORDERS16取消全部订单TX_TYPE_L2_MODIFY_ORDER17修改订单TX_TYPE_L2_UPDATE_LEVERAGE20更新杠杆TX_TYPE_L2_APPROVE_INTEGRATOR45批准 integrator每个gen_*函数在解码响应后都会用decode_expected校验返回的tx_type是否与预期一致防止签名器行为漂移。确定性输入矩阵nonce 0–16build_tx_vectors以严格递增的 nonce 顺序构造了一组高覆盖的向量集从源码可以看出其刻意覆盖的分支CreateOrder 基准向量nonce0限价 GTT 卖单0.1 ETH 4050 USDCbase_amount1000price405000均以 tick 计is_askTrue带 integrator 归因的 CreateOrdernonce1integrator_account_index723813、integrator_taker_fee250、integrator_maker_fee100覆盖非空L2TxAttributes的聚合哈希路径CancelOrdernonce2按client_order_index取消ModifyOrdernonce3改量与改价ApproveIntegratornonce4非交易关键路径买入 reduce-only 的 CreateOrdernonce5覆盖is_askFalse与reduce_onlyTrueskip_nonce1 的 CancelOrdernonce6覆盖 cancel 哈希上的属性聚合分支及{4:1}JSON 形态skip_nonce1 的 ApproveIntegratornonce7同一门禁在 approve 路径上带 integrator 归因的 ModifyOrdernonce8覆盖 modify 上的聚合哈希分支基准 modify 向量 integrator 槽全零会短路到 body 摘要四种条件单nonce9–12Stop losstype2、Stop loss limittype3、Take profittype4、Take profit limittype5其中市价触发类要求 IOCtime_in_force0限价触发类使用 GTTtime_in_force1均携带非零 trigger price账户级立即取消 CancelAllOrdersnonce13cancel_all_market_index255是上游的 nil 哨兵值与 Rust 端发出的账户级 payload 一致UpdateLeveragenonce14initial_margin_fraction5005%即 20 倍杠杆、margin_mode1isolated生产形态 integrator 归因nonce15–16仅使用 integrator 账户索引、费用覆盖为零的部分映射形态分别覆盖 create 与 modify。认证令牌 Oracle 的向量设计build_auth_vectors生成令牌向量固定一组 deadline 让预映像中出现不同的 ASCII 片段fixed_deadlines [ 1_700_000_000, 1_777_809_907, 1_999_999_999, 1_111_111_111, 1_234_567_890, ]每个 deadline 在(api_key_index5, account_index12345)的种子槽位上签名此外额外注册api_key_index0的客户端CreateClient对每个(api_key, account)组合是必需的在deadline1888888888上再生成一条向量以覆盖标量第二 limb 路径。Rust 侧的三重断言字节等价、验签、自签回环在 signing/tx/encode.rs 的#[cfg(test)] mod tests中每个oracle_tx_hash_matches_*测试对每类向量依次执行三个断言README 对此有明确描述1.assert_hash_matchestx_hash字节等价用 fixture 中的fields与上下文重建强类型的*TxInfo调用compute_tx_hash(tx, chain_id)断言输出与 fixture 中的tx_hash十六进制字符串完全一致。哈希组装是确定性的。fn assert_hash_matchesT: LighterTx(tx: T, v: OracleVector) { let got compute_tx_hash(tx, v.chain_id); assert_eq!(bytes_to_hex(got), v.tx_hash, {}: tx_hash diverged, v.kind); }这背后是 encode.rs 中compute_tx_hash_fp5的双分支管线把[chain_id, tx_type, nonce, expired_at, account_index, api_key_index, ...body]组装为域元素预映像经hash_to_quintic_extension得到单一Fp5摘要若L2TxAttributes非空再把(type, value)对序列哈希成第二个Fp5对body_digest || attributes_digest再做一次 Poseidon2hash_two_to_quintic属性为空则短路为 body 摘要最终Fp5编码为 40 字节规范小端即签名消息哈希与交易所侧的tx_hash。注意L2TxAttributes的规范化顺序type 1–4 升序integrator 账户索引、taker 费、maker 费、skip_nonce见 types.rs以及body || attributes的聚合顺序都是与 sequencer 字节等价的承重设计直接来自上游txtypes.L2TxAttributes.AggregateTxHash。2.assert_oracle_sig_verifies上游签名被我们的验签接受从 fixture 的sk派生公钥用我们自己的compute_tx_hash重算哈希断言pk.verify(hashed, sig)通过。这一断言的作用是把关我们的域/曲线/哈希/Schnorr 解码器与闭源签名器输出的一致性——如果域元素编码或 Poseidon2 参数与官方不一致验签必然失败。3.assert_round_trip_sign同一私钥下的自签回环用同样的sk、显式k从sk字节派生并异或0x01保证非零且规范对同一哈希签名断言自签产生的tx_hash仍与 fixture 字节等价自签签名能被我们自己的verify接受。由于上游每次抽取新k签名器的Sig与我们的Sig不会字节相同但两者都是同一哈希的合法签名。该断言证明了即使不用 oracle 的随机签名我们的显式k签名路径也自洽。tx_info 的字节级 JSON 等价模 Sig除哈希与验签外测试还断言 wire JSON 的字节等价create_order_json_byte_equals_oracle_modulo_sig、modify_order_json_byte_equals_oracle_modulo_sig、cancel_all_orders_json_byte_equals_oracle_modulo_sig、update_leverage_json_byte_equals_oracle_modulo_sig、approve_integrator_json_byte_equals_oracle_modulo_sig等测试用redact_sig将随机Sig替换为占位符后逐字节比较 JSON 字符串。这验证了 encode.rs 中TxInfoJson渲染器与上游 Go marshaling 的字段顺序一致如AccountIndex/ApiKeyIndex前置、ExpiredAt/Nonce后置、空属性输出null、skip_nonce 输出{4:1}这是 sequencer 在sendTx上期望的精确形态。覆盖完整性守卫测试fixture 之外测试还包含若干元断言确保向量集合本身不过期oracle_covers_conditional_create_order_type断言 fixture 中存在 type 2/3/4/5 四种条件单向量oracle_covers_production_integrator_attributes断言 create/modify 存在 integrator 账户索引为723813、费用为零的生产形态向量。认证令牌Auth TokenOracle 的验证路径Lighter 交易所对长连接客户端以ASCII 消息上的 Schnorr 签名做认证签名字符串原样放入 REST 的Authorization头与 WebSocket 订阅握手。认证令牌管线与 Go 参考ConstructAuthToken一致见 auth_token.rs渲染message {deadline}:{account_index}:{api_key_index}将 ASCII 字节按 8 字节小端分块末块补零每块解码为规范 Goldilocks 元素Fp对[Fp]运行hash_to_quintic_extension得到单一Fp5摘要用(sk, k)走标准 Schnorr 绑定签名拼接{message}:{hex(sig)}其中sig是规范 80 字节s_le || e_le布局的小写十六进制。注意认证令牌的哈希路径与交易compute_tx_hash不同令牌把消息当作不透明 ASCII 按原始小端字节打包进 limb而交易把每个字段编码为Fp域整数。Rust 侧测试oracle_auth_tokens_verify_against_our_hashauth_token.rs对signing_auth_token_oracle.json的每个向量断言令牌前缀message与auth_token_message(deadline, account_index, api_key_index)重建值一致用hash_auth_message重算摘要在派生公钥下断言内嵌签名验证通过。令牌向量的metadata.note也明确说明Sig 非确定性随机 kRust 侧在派生公钥下验证每个 oracle 令牌而不是断言签名字节相等。与底层密码学模块的关系Oracle 验证的是哈希组装 域编码 签名布局与官方一致性而底层原语本身的正确性由更底层的 fixture 向量保证——test_data目录中并列存放着signing_field_goldilocks_vectors.jsonsigning_field_quintic_vectors.jsonsigning_curve_ecgfp5_vectors.jsonsigning_hash_poseidon2_vectors.jsonsigning_schnorr_vectors.json这些向量与fuzz_pornin_diff_*差分测试对照 Pornin 的 MIT 许可参考实现逐字节断言代数运算共同构成第一层门禁Oracle 则在其之上构成第二层形成底层原语可证正确 → 上层组装与官方一致 → 最终 sequencer 实盘接受的完整验证链。何时需要重新生成 fixtureREADME 明确指出该程序不构建进 crate仅在两种情况下人工运行上游签名器版本升级UPSTREAM_VERSION/UPSTREAM_REVISION指纹变化后应重新生成 fixture 并提交确保 Rust 测试始终对最新签名器行为做字节等价断言新增交易类型当 Lighter 增加新的 L2 交易类型时需要在脚本中新增gen_*函数与TX_TYPE_L2_*判别符并补充对应的确定性输入向量。由于Sig随机重新生成的 fixture 中sig字段会变化但tx_hash与tx_info模 Sig必须保持稳定——若重新生成后tx_hash漂移说明上游签名器行为已变需要同步排查 Rust 端编码实现。小结Lighter 签名交易 Oracle 是 nautilus_trader 在闭源依赖可信化上的一个典型工程实践无法审计官方签名器源码就用确定性输入把它变成可复现的测试基准。通过 generate_oracle.py 生成的signing_tx_oracle.json与signing_auth_token_oracle.jsonRust 侧得以对每种交易类型执行哈希字节等价 上游签名验签 显式k自签回环 wire JSON 字节等价模 Sig的全套断言最终以字段顺序锁定、属性聚合承重、上游版本指纹化的方式把 L2 交易签名的正确性牢牢锚定在可复现、可审计的 fixture 之上。【免费下载链接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture项目地址: https://gitcode.com/GitHub_Trending/na/nautilus_trader创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考