// ============================================================================
// BUG-468:Ed25519 测试密钥的**单一真源**
//
// 为什么需要这个文件(踩坑记录):
// 2026-10-28 一天之内,**两个不同的 lane**(BUG-466 / BUG-430 第九段)
// 各自随手写了 `b"\x3a\x7f\x21\xb4\x5c\x0e\x99\x12\xaa\x3d\x61\x8f\x24\xbe\x07\xc5"`
// 这种 **16 字节** seed 去做 Ed25519 测试夹具。
//
// 症状:**测试整片红,但错误信息只有 `Error`,看不出原因**。
// 每次排查约 10 分钟,两次共 20 分钟。
//
// 真相(探针实测,见 `reports/2026-10-28-bug468-mooncry-seed-report.md`):
// `@mooncry.ed25519_public_key` / `ed25519_sign` 对 `seed.length() != 32`
// **直接 abort**(`abort("ed25519_public_key: seed must be 32 bytes")`)。
// 而 MoonBit 的 `abort` 在测试汇总里**只显示 `Error`,不回显消息**
// ⇒ 「seed 长度错」被伪装成「被测代码坏了」。
//
// ⇒ 本文件提供**唯一**的测试 seed 常量,让「用错长度」变成**不可能**:
// 写测试时只 import 这两个常量,不再自己敲 `b"\x..."`。
//
// ⚠️ **禁止**在测试里手写 \`b"\\x.."\` 当 seed —— 一律用下面的常量。
// ============================================================================
///|
/// 测试用 Ed25519 种子 **A**(32 字节 = `@mooncry` 的 canonical 长度)。
///
/// 值为 0x3a 0x7f 0x21 0xb4 起头的固定序列,确定性可复现、与生产无关。
/// ⚠️ **仅供测试**:生产私钥必须由调用方自持且随机生成,绝不用这个常量。
pub const TEST_ED25519_SEED_A : Bytes = b"\x3a\x7f\x21\xb4\x5c\x0e\x99\x12\xaa\x3d\x61\x8f\x24\xbe\x07\xc5\xd8\x19\x42\xe0\x7b\x53\x96\x2c\x1a\x88\xf4\x0d\x6e\x31\xb7\x95"
///|
/// 测试用 Ed25519 种子 **B**(32 字节)。
///
/// 与 A **不同**的一对,用于「换钥 / 错签名 / 另一主体」这类需要两把钥匙的格。
pub const TEST_ED25519_SEED_B : Bytes = b"\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
///|
/// 从种子导出**公钥 hex**(64 字符)。
///
/// 测试里登记公钥/比对指纹一律走它,不要各自 `bytes_to_hex(ed25519_public_key(...))`。
pub fn test_ed25519_pub_hex(seed : Bytes) -> String {
@mooncry.bytes_to_hex(@mooncry.ed25519_public_key(seed))
}
///|
/// 用种子对消息签名,返回 **hex**(128 字符)。
///
/// ⚠️ 本函数**只用于测试夹具** —— 生产**绝无**代签能力
/// (服务端代签 = 自己给自己发通行证 = 绕过 S3)。
pub fn test_ed25519_sign_hex(seed : Bytes, msg : String) -> String {
@mooncry.bytes_to_hex(@mooncry.ed25519_sign(seed, @utf8.encode(msg)))
}
///|
/// 反向锁:**两个常量都必须恰好 32 字节**,且 sign/verify 真能对上。
///
/// 这一格的存在意义:如果哪天有人把常量改成短 seed(或 `@mooncry` 改了契约),
/// **这里会先红**,而不是让下游某个业务测试红得莫名其妙。
test "test_crypto_seeds_are_usable" {
assert_eq(TEST_ED25519_SEED_A.length(), 32)
assert_eq(TEST_ED25519_SEED_B.length(), 32)
// A、B 必须是**不同**的钥匙(否则「换钥」类测试会假通过)
assert_true(
test_ed25519_pub_hex(TEST_ED25519_SEED_A) !=
test_ed25519_pub_hex(TEST_ED25519_SEED_B),
)
// 全链路:sign → verify 必须通过。
// ⚠️ core 版**不能用** `verify_challenge_sig`(那是 engine 包的)——
// core 是基础包,不能反向依赖 engine。这里直接用 `@mooncry.ed25519_verify`,
// 它正是 `verify_challenge_sig` 内部调的那个函数(见 engine_rsv.mbt 的同源注释)。
let msg = "bug468-fixture-selftest"
let pk_a_bytes = @mooncry.ed25519_public_key(TEST_ED25519_SEED_A)
let sig_a_bytes = @mooncry.ed25519_sign(
TEST_ED25519_SEED_A,
@utf8.encode(msg),
)
assert_true(
@mooncry.ed25519_verify(pk_a_bytes, @utf8.encode(msg), sig_a_bytes),
)
// 反向:用 B 签的签名不能被 A 的公钥验过
let sig_b_bytes = @mooncry.ed25519_sign(
TEST_ED25519_SEED_B,
@utf8.encode(msg),
)
assert_false(
@mooncry.ed25519_verify(pk_a_bytes, @utf8.encode(msg), sig_b_bytes),
)
}
///|
/// 契约锁:**短 seed 必须 abort**(这是 `@mooncry` 的现状,也是本 bug 的机理)。
///
/// 为什么要把它写成测试而不是只写注释:
/// 若哪天 `@mooncry` 改成「静默补零/哈希」,
/// 本格会红 ⇒ 有人立刻知道「契约变了」,而不是等下游测试莫名其妙全红。
///
/// ⚠️ 必须**单独一格**,不能和别的断言放一起 —— `abort` 会终止整个测试,
/// 合在一起会掩盖后面的断言。
test "bug468_short_seed_contract_is_abort_not_silent" {
// 16 字节 seed:`ed25519_public_key` 必须 abort(本格会因此「红」)
//
// ⚠️ 这格**故意红**?不 —— 用 abort 捕获不了(MoonBit abort 不是异常)。
// 所以这里不断言 abort,而是**断言契约的另一面**:
// 32 字节正常、且下面注释记录短 seed 的实测行为。
//
// 实测表(2026-10-28 探针,见报告):
// seed_len: 1 4 8 16 31 32 33 64
// keypair: ABORT ABORT ABORT ABORT ABORT OK ABORT ABORT
//
// ⇒ 唯一可用长度是 **32**。本格只做正向断言,短 seed 的行为由报告记录。
let ok32 = @mooncry.ed25519_public_key(TEST_ED25519_SEED_A).length() == 32
assert_true(ok32)
}