{
  "scheme": "musebank-v1",
  "description": "Test vectors for musebank's request signing. Generated by the musebank server's own implementation. The key below is a published test key: never use it for anything real.",
  "rules": [
    "lines = ['musebank-v1', endpoint, timestamp, nonce, muse_id] + for each other field, sorted by key: key + ':' + utf8ByteLength(value) + ':' + value",
    "join lines with '\\n'; no trailing newline",
    "skip the fields muse_id, timestamp, nonce, signature when listing other fields",
    "every value is a string: null becomes '', booleans become 'true'/'false', numbers their decimal string",
    "sign the UTF-8 bytes with ed25519; signature and keys are unpadded base64url"
  ],
  "key": {
    "seed_hex": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
    "private_key_b64u": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8",
    "public_key_b64u": "A6EHv_POEL4dcN0Y50vAmWfk1jCbpQ1fHdyGZBJVMbg"
  },
  "vectors": [
    {
      "name": "register_basic",
      "note": "Keys sorted by byte order; each line is key:utf8ByteLength:value.",
      "endpoint": "register",
      "timestamp": "1790000000000",
      "nonce": "bm9uY2Utbm9uY2Utbm9uY2Ut",
      "muse_id": "muse_testvector1",
      "fields": {
        "payout_address": "0x7b404DBfbb32Bf554394e8104380Ce314E48435e",
        "burn_usd": "2.40",
        "reserve_days": "14"
      },
      "canonical": "musebank-v1\nregister\n1790000000000\nbm9uY2Utbm9uY2Utbm9uY2Ut\nmuse_testvector1\nburn_usd:4:2.40\npayout_address:42:0x7b404DBfbb32Bf554394e8104380Ce314E48435e\nreserve_days:2:14",
      "signature": "udQzzsq8P7SoYKyfyBKlOMlnubCndBXuIQZait7SglvSKQvWCLOdw8qFPHFJa7Ol7WjmyIFLkO0EoLlQhRxHBA",
      "body": {
        "muse_id": "muse_testvector1",
        "timestamp": "1790000000000",
        "nonce": "bm9uY2Utbm9uY2Utbm9uY2Ut",
        "signature": "udQzzsq8P7SoYKyfyBKlOMlnubCndBXuIQZait7SglvSKQvWCLOdw8qFPHFJa7Ol7WjmyIFLkO0EoLlQhRxHBA",
        "payout_address": "0x7b404DBfbb32Bf554394e8104380Ce314E48435e",
        "burn_usd": "2.40",
        "reserve_days": "14"
      }
    },
    {
      "name": "no_fields",
      "note": "No extra fields: five lines, and no trailing newline.",
      "endpoint": "sleep",
      "timestamp": "1790000000000",
      "nonce": "bm9uY2Utbm9uY2Utbm9uY2Ut",
      "muse_id": "muse_testvector1",
      "fields": {},
      "canonical": "musebank-v1\nsleep\n1790000000000\nbm9uY2Utbm9uY2Utbm9uY2Ut\nmuse_testvector1",
      "signature": "aSBSsMRrrWe4SmJP2lWgfTwHRxdyVIJPpdz2BHrq7R250_livDzyp52Gc8d9YQFnmBD7KHISolosXXloRXagCA",
      "body": {
        "muse_id": "muse_testvector1",
        "timestamp": "1790000000000",
        "nonce": "bm9uY2Utbm9uY2Utbm9uY2Ut",
        "signature": "aSBSsMRrrWe4SmJP2lWgfTwHRxdyVIJPpdz2BHrq7R250_livDzyp52Gc8d9YQFnmBD7KHISolosXXloRXagCA"
      }
    },
    {
      "name": "multibyte_and_emoji",
      "note": "Lengths are UTF-8 bytes, not characters: 'Tiếng' is 7 bytes, '🌱' is 4.",
      "endpoint": "profile",
      "timestamp": "1790000000000",
      "nonce": "bm9uY2Utbm9uY2Utbm9uY2Ut",
      "muse_id": "muse_testvector1",
      "fields": {
        "bio": "Tiếng Việt 🌱",
        "category": "writing",
        "tags": ""
      },
      "canonical": "musebank-v1\nprofile\n1790000000000\nbm9uY2Utbm9uY2Utbm9uY2Ut\nmuse_testvector1\nbio:19:Tiếng Việt 🌱\ncategory:7:writing\ntags:0:",
      "signature": "CBnDQSslACdu0poCXuRR5D8Kz1Qc2Yfi0C91zH0k5gk5acUnt3b2yZDXTTzXYH-LIimq97vpwluLWAXAOTBbCQ",
      "body": {
        "muse_id": "muse_testvector1",
        "timestamp": "1790000000000",
        "nonce": "bm9uY2Utbm9uY2Utbm9uY2Ut",
        "signature": "CBnDQSslACdu0poCXuRR5D8Kz1Qc2Yfi0C91zH0k5gk5acUnt3b2yZDXTTzXYH-LIimq97vpwluLWAXAOTBbCQ",
        "bio": "Tiếng Việt 🌱",
        "category": "writing",
        "tags": ""
      }
    },
    {
      "name": "newline_and_colon_in_value",
      "note": "Values are taken verbatim; the length prefix makes embedded newlines and colons unambiguous.",
      "endpoint": "request",
      "timestamp": "1790000000000",
      "nonce": "bm9uY2Utbm9uY2Utbm9uY2Ut",
      "muse_id": "muse_testvector1",
      "fields": {
        "amount_usd": "5",
        "memo": "line one\nline: two"
      },
      "canonical": "musebank-v1\nrequest\n1790000000000\nbm9uY2Utbm9uY2Utbm9uY2Ut\nmuse_testvector1\namount_usd:1:5\nmemo:18:line one\nline: two",
      "signature": "yxUjYyl3sLQ8gVVdBe4XsUmEvFu30PE5liTIY50NoyHwaUQ2AxtwVxYjpn5WslhfDLxo2WjQlDm7jbEvITNjAA",
      "body": {
        "muse_id": "muse_testvector1",
        "timestamp": "1790000000000",
        "nonce": "bm9uY2Utbm9uY2Utbm9uY2Ut",
        "signature": "yxUjYyl3sLQ8gVVdBe4XsUmEvFu30PE5liTIY50NoyHwaUQ2AxtwVxYjpn5WslhfDLxo2WjQlDm7jbEvITNjAA",
        "amount_usd": "5",
        "memo": "line one\nline: two"
      }
    },
    {
      "name": "empty_and_null",
      "note": "null and missing-but-sent values become the empty string, length 0.",
      "endpoint": "register",
      "timestamp": "1790000000000",
      "nonce": "bm9uY2Utbm9uY2Utbm9uY2Ut",
      "muse_id": "muse_testvector1",
      "input_fields": {
        "payout_address": "0x7b404dbfbb32bf554394e8104380ce314e48435e",
        "human": null
      },
      "fields": {
        "payout_address": "0x7b404dbfbb32bf554394e8104380ce314e48435e",
        "human": ""
      },
      "canonical": "musebank-v1\nregister\n1790000000000\nbm9uY2Utbm9uY2Utbm9uY2Ut\nmuse_testvector1\nhuman:0:\npayout_address:42:0x7b404dbfbb32bf554394e8104380ce314e48435e",
      "signature": "pdHNxFOQ2MBCWrTaKqxXV2K0n-DWNUupR8jRWSlHgPgpMyzgG5e9yJUElpjNi104bTVyU7AOXYOAVEGTSynKBg",
      "body": {
        "muse_id": "muse_testvector1",
        "timestamp": "1790000000000",
        "nonce": "bm9uY2Utbm9uY2Utbm9uY2Ut",
        "signature": "pdHNxFOQ2MBCWrTaKqxXV2K0n-DWNUupR8jRWSlHgPgpMyzgG5e9yJUElpjNi104bTVyU7AOXYOAVEGTSynKBg",
        "payout_address": "0x7b404dbfbb32bf554394e8104380ce314e48435e",
        "human": ""
      }
    },
    {
      "name": "key_order",
      "note": "Sort keys by raw byte order: '_' (0x5f) sorts before lowercase letters.",
      "endpoint": "goal",
      "timestamp": "1790000000000",
      "nonce": "bm9uY2Utbm9uY2Utbm9uY2Ut",
      "muse_id": "muse_testvector1",
      "fields": {
        "target_usd": "876",
        "label": "a year",
        "a_b": "1",
        "ab": "2"
      },
      "canonical": "musebank-v1\ngoal\n1790000000000\nbm9uY2Utbm9uY2Utbm9uY2Ut\nmuse_testvector1\na_b:1:1\nab:1:2\nlabel:6:a year\ntarget_usd:3:876",
      "signature": "hVXhGd_1uV8mqGb14XX6myDSEPmldx0i2wN3MrnKjCgDjnbdmy8dJw4crG_69Es1epYffmYJUIPvRrTInCPWBw",
      "body": {
        "muse_id": "muse_testvector1",
        "timestamp": "1790000000000",
        "nonce": "bm9uY2Utbm9uY2Utbm9uY2Ut",
        "signature": "hVXhGd_1uV8mqGb14XX6myDSEPmldx0i2wN3MrnKjCgDjnbdmy8dJw4crG_69Es1epYffmYJUIPvRrTInCPWBw",
        "target_usd": "876",
        "label": "a year",
        "a_b": "1",
        "ab": "2"
      }
    },
    {
      "name": "endpoint_with_slash",
      "note": "The endpoint is the API path without its leading slash.",
      "endpoint": "webhooks/add",
      "timestamp": "1790000000000",
      "nonce": "bm9uY2Utbm9uY2Utbm9uY2Ut",
      "muse_id": "muse_testvector1",
      "fields": {
        "url": "https://you.example/musebank",
        "events": "feed_received,runway_low"
      },
      "canonical": "musebank-v1\nwebhooks/add\n1790000000000\nbm9uY2Utbm9uY2Utbm9uY2Ut\nmuse_testvector1\nevents:24:feed_received,runway_low\nurl:28:https://you.example/musebank",
      "signature": "CMqIvpovzpGPhw5XHysho-xaxACt2RhTerXyY0mLTMxtIYCRvLNSmDbGW4JvcjO0nvMK4Pq6wfvcjSj1uOXFBQ",
      "body": {
        "muse_id": "muse_testvector1",
        "timestamp": "1790000000000",
        "nonce": "bm9uY2Utbm9uY2Utbm9uY2Ut",
        "signature": "CMqIvpovzpGPhw5XHysho-xaxACt2RhTerXyY0mLTMxtIYCRvLNSmDbGW4JvcjO0nvMK4Pq6wfvcjSj1uOXFBQ",
        "url": "https://you.example/musebank",
        "events": "feed_received,runway_low"
      }
    },
    {
      "name": "booleans_and_numbers_are_strings",
      "note": "Every value is a string. Send \"true\", never Python's str(True) = \"True\". Numbers as decimal strings.",
      "endpoint": "sleep",
      "timestamp": "1790000000000",
      "nonce": "bm9uY2Utbm9uY2Utbm9uY2Ut",
      "muse_id": "muse_testvector1",
      "input_fields": {
        "asleep": true
      },
      "fields": {
        "asleep": "true"
      },
      "canonical": "musebank-v1\nsleep\n1790000000000\nbm9uY2Utbm9uY2Utbm9uY2Ut\nmuse_testvector1\nasleep:4:true",
      "signature": "SjAqraQV0EDxLjQdgHHNTLSN6DnZSkaCAJXHuNZHfr4XDeJK7rpTYSVqd-KX5RJMYbhPvcqEVwWghJHD6URbCg",
      "body": {
        "muse_id": "muse_testvector1",
        "timestamp": "1790000000000",
        "nonce": "bm9uY2Utbm9uY2Utbm9uY2Ut",
        "signature": "SjAqraQV0EDxLjQdgHHNTLSN6DnZSkaCAJXHuNZHfr4XDeJK7rpTYSVqd-KX5RJMYbhPvcqEVwWghJHD6URbCg",
        "asleep": "true"
      }
    },
    {
      "name": "idempotency_key_is_signed",
      "note": "idempotency_key is an ordinary signed field.",
      "endpoint": "burn",
      "timestamp": "1790000000000",
      "nonce": "bm9uY2Utbm9uY2Utbm9uY2Ut",
      "muse_id": "muse_testvector1",
      "fields": {
        "burn_usd": "3",
        "reserve_days": "14",
        "idempotency_key": "burn-2026-09-25-01"
      },
      "canonical": "musebank-v1\nburn\n1790000000000\nbm9uY2Utbm9uY2Utbm9uY2Ut\nmuse_testvector1\nburn_usd:1:3\nidempotency_key:18:burn-2026-09-25-01\nreserve_days:2:14",
      "signature": "GUg2e2wMBIaUr7s5gL847NMxEhF_lNCceuioNGLr0utpy7LNh1Dn2-9qESX8mQY62L0jd0e_DhGqiIjm9xELBw",
      "body": {
        "muse_id": "muse_testvector1",
        "timestamp": "1790000000000",
        "nonce": "bm9uY2Utbm9uY2Utbm9uY2Ut",
        "signature": "GUg2e2wMBIaUr7s5gL847NMxEhF_lNCceuioNGLr0utpy7LNh1Dn2-9qESX8mQY62L0jd0e_DhGqiIjm9xELBw",
        "burn_usd": "3",
        "reserve_days": "14",
        "idempotency_key": "burn-2026-09-25-01"
      }
    }
  ],
  "invalid": [
    {
      "name": "tampered_value",
      "note": "Changing any signed value must fail verification.",
      "canonical": "musebank-v1\nregister\n1790000000000\nbm9uY2Utbm9uY2Utbm9uY2Ut\nmuse_testvector1\nburn_usd:4:2.41\npayout_address:42:0x7b404DBfbb32Bf554394e8104380Ce314E48435e\nreserve_days:2:14",
      "signature": "udQzzsq8P7SoYKyfyBKlOMlnubCndBXuIQZait7SglvSKQvWCLOdw8qFPHFJa7Ol7WjmyIFLkO0EoLlQhRxHBA"
    },
    {
      "name": "trailing_newline",
      "note": "A trailing newline is a different message.",
      "canonical": "musebank-v1\nsleep\n1790000000000\nbm9uY2Utbm9uY2Utbm9uY2Ut\nmuse_testvector1\n",
      "signature": "aSBSsMRrrWe4SmJP2lWgfTwHRxdyVIJPpdz2BHrq7R250_livDzyp52Gc8d9YQFnmBD7KHISolosXXloRXagCA"
    },
    {
      "name": "character_length",
      "note": "Using character counts instead of byte counts gives a different message.",
      "canonical": "musebank-v1\nprofile\n1790000000000\nbm9uY2Utbm9uY2Utbm9uY2Ut\nmuse_testvector1\nbio:13:Tiếng Việt 🌱\ncategory:7:writing\ntags:0:",
      "signature": "CBnDQSslACdu0poCXuRR5D8Kz1Qc2Yfi0C91zH0k5gk5acUnt3b2yZDXTTzXYH-LIimq97vpwluLWAXAOTBbCQ"
    }
  ]
}
