// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2026 Wilder Management Inc. (d/b/a Wilder Robotics) <rob@wilder-robotics.com>
// pask-wire is licensed Apache-2.0. No commercial agreement is required to use,
// modify or redistribute it; see LICENSING.md in the workspace root.
//! Byte-exact tests for the #67 candidate-entry derivation.
//!
//! These test vectors are synthetic derivation fixtures, not verified proofs
//! or registration alignments. They are independently generated using the
//! `scripts/gen_test_vectors_67.py` script (Python 3.8+, cbor2 >= 6.0) and hardcoded
//! here. The Rust implementation must reproduce the exact expected bytes.
//!
//! See `scripts/gen_test_vectors_67.py` for the generator
//! and `pask_-04_design_67_v3_consolidated.md` for the design.
#![cfg(test)]
use pask_wire::derive_candidate_entry;
fn hex_decode(s: &str) -> Vec<u8> {
let bytes = (0..s.len())
.step_by(2)
.map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap());
bytes.collect()
}
// ===========================================================================
// Independently generated test vectors
// ===========================================================================
// TV1: Standard untagged COSE_Sign1 (full wilder.pser/0.5 Transparent Statement)
const TV1_COSE: &str = "845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35a059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const TV1_CANDIDATE: &str = "845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35a059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const TV1_LEAF: &str = "1dd2694297e6c577726b9819fdd54a23f867fec86a382584e6bd9659e87537d2";
// TV2: Tag-18 wrapped COSE_Sign1 (same content as TV1)
const TV2_COSE: &str = "d2845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35a059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
// TV3: Transparent Statement with one receipt (acceptance invariant: same as TV1)
const TV3_COSE: &str = "845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35a107815850bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb59017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
// TV4: Transparent Statement with two receipts (acceptance invariant: same as TV1)
const TV4_COSE: &str = "845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35a107825850cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc5850dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd59017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
// TV5: Tampered payload (different candidate entry and leaf hash)
const TV5_COSE: &str = "845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35a059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3162222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const TV5_LEAF: &str = "1ddfecc2f78a43378889ed7e7b5adcf7f15ac3ba6e4ef502ccf261f1b7db1135";
// --- Outer-encoding test vectors ---
// TV6: Short protected header (3 bytes, 1-byte bstr header 0x43)
const TV6_COSE: &str = "8443a10127a059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const TV6_CANDIDATE: &str = "8443a10127a059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const TV6_LEAF: &str = "3a15ec6e616e7dcbe3d17d23d93dc63454336cba29d997fc69470f1f635ad740";
// TV7: Protected header length 10 (1-byte bstr header 0x4a)
const TV7_COSE: &str = "844aa20127036573686f7274a059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const TV7_CANDIDATE: &str = "844aa20127036573686f7274a059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const TV7_LEAF: &str = "c49287d94904cc371c5e82798e93a185f8058c0fb4627d5f895dfc7acabebf2f";
// TV8: Protected header length 25 (2-byte bstr header 0x58 0x19)
const TV8_COSE: &str = "845819a2012703743031323334353637383961626364656630313233a059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const TV8_CANDIDATE: &str = "845819a2012703743031323334353637383961626364656630313233a059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const TV8_LEAF: &str = "3eac21bee018737c1649079b100dc67accd4fb2065d39de934f59666f8c2c21e";
// TV9: Empty payload (length 0, 1-byte bstr header 0x40)
const TV9_COSE: &str = "845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35a0405840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const TV9_CANDIDATE: &str = "845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35a0405840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const TV9_LEAF: &str = "2a9f50255c2e672daf302ea1539b6eef9bddd8f436bac9c054012be0bf68e362";
// TV10: Short signature (8 bytes, 1-byte bstr header 0x48)
const TV10_COSE: &str = "845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35a059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d484242424242424242";
const TV10_CANDIDATE: &str = "845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35a059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d484242424242424242";
const TV10_LEAF: &str = "85136b2253756719693a7823e93d8445bfc38d2e780faaf5f6fe9316dde64e3b";
// --- Negative test vectors ---
const NV_DETACHED: &str = "845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35a0f65840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const NV_BAD_TAG: &str = "d863845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35a059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const NV_TRAILING: &str = "845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35a059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa00";
const NV_UH_INT: &str = "845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e350059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const NV_UH_NULL: &str = "845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35f659017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const NV_UH_ARRAY: &str = "845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35810159017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const NV_UH_TEXT: &str = "845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35696e6f742061206d617059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const NV_UH_BYTES: &str = "845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35496e6f742061206d617059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const NV_PH_INT: &str = "8400a059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const NV_PL_INT: &str = "845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35a0182a5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const NV_SIG_INT: &str = "845834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35a059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d182a";
const NV_3_ELEM: &str = "835834a2012703782e6170706c69636174696f6e2f707365722b6a736f6e3b2070726f66696c653d77696c6465722e707365722f302e35a059017e7b2273706563223a2277696c6465722e707365722f302e35222c227473223a22323032352d30392d31325431343a30303a30305a222c226e6f744265666f7265223a22323032352d30392d31325431333a30303a30305a222c226e6f744166746572223a22323032352d30392d31325431353a30303a30305a222c227375626a656374223a7b22736974655f6964223a227265732d303031227d2c226174746573746174696f6e223a7b227769746e6573734b6579223a226b65793a7465653a7265732d3030312d7769746e6573732d3031222c2262696e64696e674d6f6465223a224449524543545f5749544e455353222c2265766964656e6365223a227265662d303031227d2c2270726f76656e616e6365223a7b2273636f7065223a22756e69742d3161222c22636861696e223a7b2268617368223a2230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030227d7d7d";
const NV_NON_ARRAY: &str = "182a";
// ===========================================================================
// Tests
// ===========================================================================
#[test]
fn tv1_standard_untagged() {
let cose = hex_decode(TV1_COSE);
let expected = hex_decode(TV1_CANDIDATE);
let result = derive_candidate_entry(&cose).unwrap();
assert_eq!(result, expected);
}
#[test]
fn tv2_tag_18_wrapped() {
let cose = hex_decode(TV2_COSE);
let expected = hex_decode(TV1_CANDIDATE);
let result = derive_candidate_entry(&cose).unwrap();
assert_eq!(result, expected);
}
#[test]
fn tv3_one_receipt_acceptance_invariant() {
let cose = hex_decode(TV3_COSE);
let expected = hex_decode(TV1_CANDIDATE);
let result = derive_candidate_entry(&cose).unwrap();
assert_eq!(result, expected);
}
#[test]
fn tv4_two_receipts_acceptance_invariant() {
let cose = hex_decode(TV4_COSE);
let expected = hex_decode(TV1_CANDIDATE);
let result = derive_candidate_entry(&cose).unwrap();
assert_eq!(result, expected);
}
#[test]
fn tv5_tampered_payload() {
let cose = hex_decode(TV5_COSE);
let result = derive_candidate_entry(&cose).unwrap();
// Must differ from TV1 candidate entry
assert_ne!(result, hex_decode(TV1_CANDIDATE));
}
#[test]
fn tv1_leaf_hash() {
let cose = hex_decode(TV1_COSE);
let candidate = derive_candidate_entry(&cose).unwrap();
let leaf = pask_wire::candidate_leaf_hash(&candidate);
assert_eq!(hex::encode(leaf), TV1_LEAF);
}
#[test]
fn tv5_leaf_hash() {
let cose = hex_decode(TV5_COSE);
let candidate = derive_candidate_entry(&cose).unwrap();
let leaf = pask_wire::candidate_leaf_hash(&candidate);
assert_eq!(hex::encode(leaf), TV5_LEAF);
}
#[test]
fn tv1_receipts_share_leaf_hash() {
let cose1 = hex_decode(TV1_COSE);
let cose3 = hex_decode(TV3_COSE);
let cose4 = hex_decode(TV4_COSE);
let candidate1 = derive_candidate_entry(&cose1).unwrap();
let candidate3 = derive_candidate_entry(&cose3).unwrap();
let candidate4 = derive_candidate_entry(&cose4).unwrap();
assert_eq!(candidate1, candidate3);
assert_eq!(candidate1, candidate4);
}
#[test]
fn tv5_differs_from_tv1() {
let cose1 = hex_decode(TV1_COSE);
let cose5 = hex_decode(TV5_COSE);
let candidate1 = derive_candidate_entry(&cose1).unwrap();
let candidate5 = derive_candidate_entry(&cose5).unwrap();
assert_ne!(candidate1, candidate5);
}
// --- Outer-encoding tests ---
#[test]
fn tv6_short_protected_header_1byte_bstr() {
// Protected header is 3 bytes, uses 1-byte bstr header (0x43)
let cose = hex_decode(TV6_COSE);
let expected = hex_decode(TV6_CANDIDATE);
let result = derive_candidate_entry(&cose).unwrap();
assert_eq!(result, expected);
}
#[test]
fn tv6_leaf_hash() {
let cose = hex_decode(TV6_COSE);
let candidate = derive_candidate_entry(&cose).unwrap();
let leaf = pask_wire::candidate_leaf_hash(&candidate);
assert_eq!(hex::encode(leaf), TV6_LEAF);
}
#[test]
fn tv7_protected_header_len_10_1byte_bstr() {
// Protected header is 10 bytes, uses 1-byte bstr header (0x4a)
let cose = hex_decode(TV7_COSE);
let expected = hex_decode(TV7_CANDIDATE);
let result = derive_candidate_entry(&cose).unwrap();
assert_eq!(result, expected);
}
#[test]
fn tv7_leaf_hash() {
let cose = hex_decode(TV7_COSE);
let candidate = derive_candidate_entry(&cose).unwrap();
let leaf = pask_wire::candidate_leaf_hash(&candidate);
assert_eq!(hex::encode(leaf), TV7_LEAF);
}
#[test]
fn tv8_protected_header_len_25_2byte_bstr() {
// Protected header is 25 bytes, uses 2-byte bstr header (0x58 0x19)
let cose = hex_decode(TV8_COSE);
let expected = hex_decode(TV8_CANDIDATE);
let result = derive_candidate_entry(&cose).unwrap();
assert_eq!(result, expected);
}
#[test]
fn tv8_leaf_hash() {
let cose = hex_decode(TV8_COSE);
let candidate = derive_candidate_entry(&cose).unwrap();
let leaf = pask_wire::candidate_leaf_hash(&candidate);
assert_eq!(hex::encode(leaf), TV8_LEAF);
}
#[test]
fn tv9_empty_payload_1byte_bstr() {
// Payload is empty (0 bytes), uses 1-byte bstr header (0x40)
let cose = hex_decode(TV9_COSE);
let expected = hex_decode(TV9_CANDIDATE);
let result = derive_candidate_entry(&cose).unwrap();
assert_eq!(result, expected);
}
#[test]
fn tv9_leaf_hash() {
let cose = hex_decode(TV9_COSE);
let candidate = derive_candidate_entry(&cose).unwrap();
let leaf = pask_wire::candidate_leaf_hash(&candidate);
assert_eq!(hex::encode(leaf), TV9_LEAF);
}
#[test]
fn tv10_short_signature_1byte_bstr() {
// Signature is 8 bytes, uses 1-byte bstr header (0x48)
let cose = hex_decode(TV10_COSE);
let expected = hex_decode(TV10_CANDIDATE);
let result = derive_candidate_entry(&cose).unwrap();
assert_eq!(result, expected);
}
#[test]
fn tv10_leaf_hash() {
let cose = hex_decode(TV10_COSE);
let candidate = derive_candidate_entry(&cose).unwrap();
let leaf = pask_wire::candidate_leaf_hash(&candidate);
assert_eq!(hex::encode(leaf), TV10_LEAF);
}
// --- Negative tests ---
#[test]
fn nv_detached_payload_rejected() {
let cose = hex_decode(NV_DETACHED);
assert!(derive_candidate_entry(&cose).is_err());
}
#[test]
fn nv_unsupported_tag_rejected() {
let cose = hex_decode(NV_BAD_TAG);
assert!(derive_candidate_entry(&cose).is_err());
}
#[test]
fn nv_trailing_bytes_rejected() {
let cose = hex_decode(NV_TRAILING);
assert!(derive_candidate_entry(&cose).is_err());
}
#[test]
fn nv_unprotected_header_integer_rejected() {
let cose = hex_decode(NV_UH_INT);
assert!(derive_candidate_entry(&cose).is_err());
}
#[test]
fn nv_unprotected_header_null_rejected() {
let cose = hex_decode(NV_UH_NULL);
assert!(derive_candidate_entry(&cose).is_err());
}
#[test]
fn nv_unprotected_header_array_rejected() {
let cose = hex_decode(NV_UH_ARRAY);
assert!(derive_candidate_entry(&cose).is_err());
}
#[test]
fn nv_unprotected_header_text_rejected() {
let cose = hex_decode(NV_UH_TEXT);
assert!(derive_candidate_entry(&cose).is_err());
}
#[test]
fn nv_unprotected_header_bytes_rejected() {
let cose = hex_decode(NV_UH_BYTES);
assert!(derive_candidate_entry(&cose).is_err());
}
#[test]
fn nv_protected_header_integer_rejected() {
let cose = hex_decode(NV_PH_INT);
assert!(derive_candidate_entry(&cose).is_err());
}
#[test]
fn nv_payload_integer_rejected() {
let cose = hex_decode(NV_PL_INT);
assert!(derive_candidate_entry(&cose).is_err());
}
#[test]
fn nv_signature_integer_rejected() {
let cose = hex_decode(NV_SIG_INT);
assert!(derive_candidate_entry(&cose).is_err());
}
#[test]
fn nv_three_element_array_rejected() {
let cose = hex_decode(NV_3_ELEM);
assert!(derive_candidate_entry(&cose).is_err());
}
#[test]
fn nv_non_array_rejected() {
let cose = hex_decode(NV_NON_ARRAY);
assert!(derive_candidate_entry(&cose).is_err());
}
#[test]
fn nv_empty_input_rejected() {
assert!(derive_candidate_entry(&[]).is_err());
}
#[test]
fn nv_invalid_cbor_rejected() {
let cose = hex_decode("ffffff");
assert!(derive_candidate_entry(&cose).is_err());
}