From 6d561f8eed090d5e7a728de4d8c60bb692c737e0 Mon Sep 17 00:00:00 2001 From: Arshdeep Date: Mon, 1 Jun 2026 21:47:09 +0530 Subject: [PATCH] [VC-1161] update tn-alloc Schema --- registry.json | 2 +- tn-alloc/example-tn-alloc.json | 46 +++--- tn-alloc/index.md | 71 ++++++++- tn-alloc/tn-alloc.schema.json | 277 ++++++++++++++++++++++----------- 4 files changed, 277 insertions(+), 119 deletions(-) diff --git a/registry.json b/registry.json index 14f952d..65e581c 100644 --- a/registry.json +++ b/registry.json @@ -16,7 +16,7 @@ "EHFdm3U_4nML6lo-q_xDTO8183hC9HlWif2l4ycNo8TW": "ovc-org-vet/ovc-org-vet.schema.json", "EG68irpfVX667KCLwG85Cn1Mp3sCe38ftARyQJrxP2kF": "proof-of-control/proof-of-control.schema.json", "EPy_7LE3tVdl8qEKN5i4L8eAgIM-1I51-DNiewmcq-fe": "tcr-vetting/tcr-vetting.schema.json", - "EFvnoHDY7I-kaBBeKlbDbkjG4BaI0nKLGadxBdjMGgSQ": "tn-alloc/tn-alloc.schema.json", + "EIEe3CAVep2SfJFidtPJNwJtfEAwYt2SQ4vln2nl-rrf": "tn-alloc/tn-alloc.schema.json", "EGEebb1pVRcZ6OXHlYitl5DNh-LDrMWPwRtstiKiDhRy": "tn/tn.schema.json", "EH6ekLjSr8V32WyFbGe1zXjTzFs9PkTYmupJ9H65O14g": "vLEI/acdc/ecr-authorization-vlei-credential.json", "EEy9PkikFcANV1l7EHukCeXqrzT1hNZjGlUk7wuMO5jw": "vLEI/acdc/legal-entity-engagement-context-role-vLEI-credential.json", diff --git a/tn-alloc/example-tn-alloc.json b/tn-alloc/example-tn-alloc.json index dbe32ea..b84f5eb 100644 --- a/tn-alloc/example-tn-alloc.json +++ b/tn-alloc/example-tn-alloc.json @@ -1,32 +1,34 @@ { - "v": "ACDC10JSON0003cd_", - "d": "EEeg55Yr01gDyCScFUaE2QgzC7IOjQRpX2sTckFZp1RP", + "v": "ACDC10JSON00040b_", + "d": "ELqKnm3DBEM1gqd9jrBiZOBgXPJe3nL0Bdl-6Y9WToaF", "u": "0AC8kpfo-uHQvxkuGZdlSjGy", "i": "EANghOmfYKURt3rufd9JNzQDw_7sQFxnDlIew4C3YCnM", "ri": "EDoSO5PEPLsstDr_XXa8aHAf0YKfPlJQcxZvkpMSzQDB", - "s": "EFvnoHDY7I-kaBBeKlbDbkjG4BaI0nKLGadxBdjMGgSQ", + "s": "EIEe3CAVep2SfJFidtPJNwJtfEAwYt2SQ4vln2nl-rrf", "a": { - "d": "ECFFejktQA0ThTqLtAUTmW46unVGf28I_arbBFnIwnWB", - "u": "0ADSLntzn8x8eNU6PhUF26hk", - "i": "EERawEn-XgvmDR_-2ESVUVC6pW-rkqBkxMTsL36HosAz", - "dt": "2024-12-20T20:40:57.888000+00:00", - "numbers": { - "rangeStart": "+1801361002", - "rangeEnd": "+1801361009" - }, - "channel": "voice", - "doNotOriginate": false + "d": "EGSM6KZWVOXxmoNHlNNYBllu4DXs9Xx5-UhOnpTnDCO7", + "u": "0ADSLntzn8x8eNU6PhUF26hk", + "i": "EERawEn-XgvmDR_-2ESVUVC6pW-rkqBkxMTsL36HosAz", + "dt": "2024-12-20T20:40:57.888000+00:00", + "numbers": [ + "+1801361001-+1801361002", + "+1801361005" + ], + "channel": [ + "voice" + ] }, "e": { - "d": "EI9qlgiDbMeJ7JTZTJfVanUFAoa0TMz281loi63nCSAH", - "tnalloc": { - "n": "EG16t8CpJROovnGpgEW1_pLxH5nSBs1xQCbRexINYJgz", - "s": "EFvnoHDY7I-kaBBeKlbDbkjG4BaI0nKLGadxBdjMGgSQ", - "o": "I2I" - } + "d": "EBY3ewECLPVjjk96hojtlfw826eL_pR_9BmjPHCpOq9i", + "tnalloc": { + "n": "EG16t8CpJROovnGpgEW1_pLxH5nSBs1xQCbRexINYJgz", + "s": "EIEe3CAVep2SfJFidtPJNwJtfEAwYt2SQ4vln2nl-rrf", + "o": "I2I" + } }, "r": { - "d": "EJFhpp0uU7D7PKooYM5QIO1hhPKTjHE18sR4Dn0GFscR", - "perBrand": "Issuees agree not to share the phone number with other brands which may have a common owner but which will make it difficult to consistently identify the originator of traffic." + "d": "EFC5aL2PUkGzu0BdKxWwL-jGkdqzKH8UQMrJg8T0HeYW", + "governance": "Issued under governance published at https://provenant.net/governance/tn-alloc/", + "noSharing": "Issuees agree not to share or lend the allocated telephone number(s) to other parties in a way that would make it difficult to consistently identify the originator of traffic." } -} \ No newline at end of file +} diff --git a/tn-alloc/index.md b/tn-alloc/index.md index 7992f6c..eb5a718 100644 --- a/tn-alloc/index.md +++ b/tn-alloc/index.md @@ -1,5 +1,70 @@ -## Telephone Number (TN) Allocation Credentials +## Telephone Number Allocation Credential -#### Purpose +### Purpose -These credentials document the issuee's right to use a phone number to make phone calls. \ No newline at end of file +This credential proves that an enterprise or individual holds the **right to use (RTU)** one or more specific telephone numbers. The right-to-use may come directly from a telecommunications regulator or may be sub-allocated through a telephone number provider. The credential is channel-agnostic: the same number can carry voice calls, SMS messages, or both, and a single Telephone Number Allocation Credential covers the number regardless of channel. + +### Why this credential matters + +In telephony fraud and spam ecosystems, a caller or sender can trivially spoof any number they choose. Downstream recipients — call analytics platforms, carriers, campaign registries — have no way to distinguish a legitimate originator from a bad actor by looking at the calling number alone. The Telephone Number Allocation Credential establishes a cryptographic chain of custody from the regulator (who originally assigned the number block) to the enterprise that legitimately operates the number today. + +A verifier who holds this credential, together with the edges that chain back to the regulating authority, has a strong basis to assert that a call or message from the claimed number was originated by the holder of this credential — and only that holder. + +### Schema + +See [tn-alloc.schema.json](tn-alloc.schema.json). + +### Number expressions + +The `numbers` attribute is an array of **number expressions**. Each expression is either: + +- A **single E.164 number** — e.g., `+15551234567` +- An **inclusive range** — two E.164 numbers joined by a hyphen, e.g., `+15551230000-+15551239999` + +All numbers in a single credential must share the **same granting authority** — the issuer uses a single edge to point to the party that granted the right to use those numbers. If a holder has numbers from two different source authorities, they must hold two separate credentials. + +Verifiers evaluate each expression in the array. For a single number, it must match exactly. For a range, the number under test must be numerically between the start and end values, inclusive. + +### Multichannel readiness + +This schema supports both **voice** and **SMS** use cases without modification: + +- For **voice**, the holder uses the credential to assert origin identity when initiating a call. +- For **SMS / A2P campaigns**, the holder presents this credential to a campaign registry (e.g., The Campaign Registry) as proof of number ownership before campaign provisioning. The credential does not carry a campaign ID — campaign-level attributes belong in a separate campaign credential that references this one. + +The optional `channel` field can narrow the scope of the credential to a specific channel or set of channels. If omitted, no channel restriction is implied — the credential is valid for any use of the allocated numbers. If present, it is an array of one or both of `"sms"` and `"voice"`. + +| `channel` value | Meaning | +|---|---| +| `["voice"]` | Numbers are allocated for voice use only. | +| `["sms"]` | Numbers are allocated for SMS use only. | +| `["sms", "voice"]` | Numbers are allocated for both channels. | +| *(omitted)* | No channel restriction; allocation is channel-agnostic. | + +This design keeps number ownership and campaign intent cleanly separated, avoiding schema proliferation and making it easy to reuse the same number credential across multiple campaigns or channels over time. + +### Optional fields + +| Field | Type | Purpose | +|---|---|---| +| `channel` | array of `"sms"` / `"voice"` | Restricts the credential to specific channels. Omit for channel-agnostic allocation. | +| `startDate` | ISO-8601 datetime | Earliest date from which the allocation is valid. Useful for proving long-term continuous ownership. | +| `endDate` | ISO-8601 datetime | Expiry date of the allocation. If absent, the allocation is open-ended and governed solely by credential revocation. | + +### Edge structure + +The `e` (edges) block is optional to accommodate **regulators** who originate numbers directly and have no parent issuer. When present, the edges block may contain: + +| Edge | Required in block? | Purpose | +|---|---|---| +| `tnalloc` | No | Chain to a parent Telephone Number Allocation Credential, proving sub-allocation authority all the way back to the regulator. | +| `issuer` | No | Links to an identity credential (e.g., OVC Org Identity, vLEI) that proves who the issuer is. Intentionally generic — does not constrain the schema of the identity credential. | + +### Rules and governance + +The `r` (rules) block must contain: + +- **`noSharing`** — The credential holder agrees not to share or lend the allocated numbers to other parties in a way that would obscure traffic origin. This rule exists because phone numbers are the accountability anchor for calls and messages: if a number is informally lent, regulators and recipients lose the ability to trace bad traffic back to a responsible party. +- **`governance`** — A statement identifying the governance framework under which this credential was issued. Issuers must populate this field with the URI of their applicable governance document. + +The act of issuing or accepting this credential constitutes binding acceptance of these rules. \ No newline at end of file diff --git a/tn-alloc/tn-alloc.schema.json b/tn-alloc/tn-alloc.schema.json index f540ea4..c5b944a 100644 --- a/tn-alloc/tn-alloc.schema.json +++ b/tn-alloc/tn-alloc.schema.json @@ -1,11 +1,10 @@ { - "$id": "EFvnoHDY7I-kaBBeKlbDbkjG4BaI0nKLGadxBdjMGgSQ", - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "TN Allocation Credential", - "description": "TN Allocation credential proves an enterpise has the right to use(RTU) specific telephone numbers, either directly from a regulator or through a telephone number provider.", + "$id": "EIEe3CAVep2SfJFidtPJNwJtfEAwYt2SQ4vln2nl-rrf", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Telephone Number Allocation Credential", + "description": "Telephone Number Allocation credential proves an enterprise has the right to use (RTU) specific telephone numbers, either directly from a regulator or through a telephone number provider.", "type": "object", - "credentialType": "TNAllocationCredential", - "version": "1.0.0", + "version": "2.0.0", "required": [ "v", "d", @@ -18,28 +17,52 @@ ], "properties": { "v": { - "description": "Version", - "type": "string" + "description": "Version string using ACDC conventions, encoding protocol, serialization, and size.", + "type": "string", + "pattern": "^ACDC[0-9]{2}[A-Z]{4}[0-9a-f]{6}_$", + "examples": [ + "ACDC10JSON000345_" + ] }, "d": { - "description": "Credential SAID", - "type": "string" + "description": "SAID of the credential (Blake3-256 digest in CESR compact encoding).", + "type": "string", + "pattern": "^E[A-Za-z0-9_-]{43}$", + "examples": [ + "EBwNam2e0mYdTx0i9xv78AIm16g1XCkQO8f8yJXaxmJC" + ] }, "u": { - "description": "A salty nonce", - "type": "string" + "description": "A salty nonce (high-entropy random value) used to prevent rainbow-table attacks on the credential SAID.", + "type": "string", + "examples": [ + "0AHcgNghkDaG7ts1Bv8wkv3b" + ] }, "i": { - "description": "Issuer AID", - "type": "string" + "description": "AID of the issuer (the party asserting the telephone number allocation right).", + "type": "string", + "pattern": "^[A-Za-z0-9_-]{44}$", + "examples": [ + "EDC0Sj0CPYd70zUSY2ehvm7Z4kwZigugiA84wuS7lK2H", + "BCmx-dBiozRlK5MfRnznAHl9kmXjB3t-zxrE3hIIYkeS" + ] }, "ri": { - "description": "Credential status registry", - "type": "string" + "description": "SAID of the issuer's ACDC credential status registry.", + "type": "string", + "pattern": "^E[A-Za-z0-9_-]{43}$", + "examples": [ + "EOkdwKgeEF-Ww2d61uhHjAo13rjJROdbdIaxORQJRV2G" + ] }, "s": { - "description": "Schema SAID", - "type": "string" + "description": "SAID of this schema (Blake3-256 digest in CESR compact encoding).", + "type": "string", + "pattern": "^E[A-Za-z0-9_-]{43}$", + "examples": [ + "EI8g4_JZ0zA50yihhsb-RXvOEcsI8TSN7PJrNgIbAUH1" + ] }, "a": { "oneOf": [ @@ -48,7 +71,7 @@ "type": "string" }, { - "$id": "EGgYbtyoE0qGfYfZWZ1lAd-UoWu_2OjqMcms_75s4atv", + "$id": "EFC0ZCw01iPYBFdHHK3EaR_YZYOewvcf3GASJHd5MFBp", "description": "Attributes block", "type": "object", "required": [ @@ -56,75 +79,116 @@ "u", "i", "dt", - "numbers", - "channel", - "doNotOriginate" + "numbers" ], "properties": { "d": { - "description": "Attributes block SAID", - "type": "string" + "description": "SAID of the attributes block (Blake3-256 digest in CESR compact encoding).", + "type": "string", + "pattern": "^E[A-Za-z0-9_-]{43}$", + "examples": [ + "EGgYbtyoE0qGfYfZWZ1lAd-UoWu_2OjqMcms_75s4atv" + ] }, "u": { - "description": "A salty nonce", - "type": "string" + "description": "A salty nonce for the attributes block, enabling selective disclosure.", + "type": "string", + "examples": [ + "0AHcgNghkDaG7ts1Bv8wkv3b" + ] }, "i": { - "description": "Recipient Brand AID", - "type": "string" + "description": "AID of the credential recipient \u2014 the enterprise or individual that holds the right to use the allocated telephone numbers.", + "type": "string", + "pattern": "^[A-Za-z0-9_-]{44}$", + "examples": [ + "EAZz0-cvLBLfqw3TRo-J0kBzM1TEwQ6a_v_892uH3Yjz" + ] }, "dt": { - "description": "Issuance date time", + "description": "Issuance date-time (when the ACDC was signed), as an ISO-8601 datetime string with timezone.", + "type": "string", "format": "date-time", - "type": "string" + "examples": [ + "2024-01-15T10:30:00.000000+00:00" + ] }, "numbers": { - "description": "Telephone Numbers allocated to enterpise either as a list of specific numbers or a range of numbers", - "type": "object", - "properties": { - "tn": { - "description": "Specific telephone numbers list", - "type": "array", - "uniqueItems": true, - "minItems": 1, - "items": { - "type": "string", - "description": "Telephone number in E164 format", - "pattern": "[+][0-9]{7,15}" - } - }, - "rangeStart": { - "description": "Range start number in E164 format, inclusive of this number. If provided, rangeEnd must also be provided", - "type": "string" - }, - "rangeEnd": { - "description": "Range end number in E164 format, inclusive of this number. If provided, rangeStart must also be provided", - "type": "string" - } + "description": "Array of number expressions representing telephone numbers allocated to the enterprise. Each expression is either a single E164 number (e.g., '+15551234567') or an inclusive range denoted by a hyphen between two E164 numbers (e.g., '+15551230000-+15551239999'). All numbers in a single credential must share the same granting authority.", + "type": "array", + "uniqueItems": true, + "minItems": 1, + "items": { + "type": "string", + "description": "A single E164 telephone number or an inclusive range. Single number: '+' followed by 7-15 digits. Range: two E164 numbers separated by a hyphen (e.g., '+15551230000-+15551239999').", + "pattern": "^\\+[0-9]{7,15}(-\\+[0-9]{7,15})?$" }, - "additionalProperties": false + "examples": [ + [ + "+15551234567" + ], + [ + "+15551230000-+15551239999" + ], + [ + "+15551234567", + "+442071234567" + ], + [ + "+15551230000-+15551239999", + "+15558880000-+15558889999" + ], + [ + "+15551234567", + "+15559876543", + "+442071234567", + "+81312345678" + ] + ] }, "channel": { - "description": "Communication channel for which number will be used (e.g., sms, voice, etc.)", - "type": "string", - "pattern": "sms|voice" - }, - "doNotOriginate": { - "description": "True or False based on condition if telephone number is a 'do not originate' number (inbound only)", - "type": "boolean" + "description": "Optional list of communication channels for which these numbers are allocated. If omitted, no channel restriction is implied. Use 'sms' for A2P/P2P messaging, 'voice' for voice calls, or both to indicate dual-channel use.", + "type": "array", + "uniqueItems": true, + "minItems": 1, + "items": { + "type": "string", + "enum": [ + "sms", + "voice" + ] + }, + "examples": [ + [ + "voice" + ], + [ + "sms" + ], + [ + "sms", + "voice" + ] + ] }, "startDate": { - "description": "Start date", + "description": "Optional start date from which the telephone number allocation is valid (ISO-8601). Useful for proving long-term continuous ownership of a number.", + "type": "string", "format": "date-time", - "type": "string" + "examples": [ + "2020-06-01T00:00:00.000000+00:00" + ] }, "endDate": { - "description": "Expiration date", + "description": "Optional expiration date of the telephone number allocation (ISO-8601). If omitted, the allocation is considered open-ended and subject only to credential revocation.", + "type": "string", "format": "date-time", - "type": "string" + "examples": [ + "2026-06-01T00:00:00.000000+00:00" + ] } }, - "additionalProperties": false + "additionalProperties": true } ] }, @@ -135,16 +199,20 @@ "type": "string" }, { - "$id": "ED-ETRO9FOiEgvK8P66Rut-Cun-0aZ5FbgTlngPf9yVT", + "$id": "EGymY-9Iie1aYzIT5_SN9OniMb4dJRSt0jzfOk57WRo6", "description": "Edges block", "type": "object", "properties": { "d": { - "description": "Edges block SAID", - "type": "string" + "description": "SAID of the edges block.", + "type": "string", + "pattern": "^E[A-Za-z0-9_-]{43}$", + "examples": [ + "ED-ETRO9FOiEgvK8P66Rut-Cun-0aZ5FbgTlngPf9yVT" + ] }, "tnalloc": { - "description": "Chain to a TN allocation (RTU) credential that proves with a valid chain back to the regulator", + "description": "Chain to a telephone number allocation (RTU) credential that proves with a valid chain back to the regulator", "type": "object", "required": [ "n", @@ -153,17 +221,25 @@ ], "properties": { "n": { - "description": "SAID of TN allocation credential", - "type": "string" + "description": "SAID of a parent telephone number allocation credential that grants the issuer the right to sub-allocate.", + "type": "string", + "pattern": "^E[A-Za-z0-9_-]{43}$", + "examples": [ + "EBwNam2e0mYdTx0i9xv78AIm16g1XCkQO8f8yJXaxmJC" + ] }, "s": { - "description": "SAID of TN allocation schema", - "type": "string" + "description": "SAID of the telephone number allocation schema that the chained credential must satisfy.", + "type": "string", + "pattern": "^E[A-Za-z0-9_-]{43}$", + "examples": [ + "EI8g4_JZ0zA50yihhsb-RXvOEcsI8TSN7PJrNgIbAUH1" + ] }, "o": { - "description": "Operator indicating issuer AID of this ACDC MUST be the Issuee AID of the node this Edge points to.", + "description": "Issuer-To-Issuee, operator indicating issuer AID of this ACDC MUST be the Issuee AID of the node this Edge points to.", "type": "string", - "const": "I2I" + "default": "I2I" } }, "additionalProperties": false @@ -173,17 +249,25 @@ "type": "object", "properties": { "n": { - "description": "SAID of a credential that proves the identity of the issuer", - "type": "string" + "description": "SAID of a credential that proves the identity of the issuer (e.g., an OVC Org Identity or vLEI credential).", + "type": "string", + "pattern": "^E[A-Za-z0-9_-]{43}$", + "examples": [ + "EG_rp79RWfT97mfVCiptp73PVKr26QHa-kAbMkTPqAno" + ] }, "s": { - "description": "SAID of credential schema that proves the identity of the issuer", - "type": "string" + "description": "SAID of the schema that the issuer identity credential must satisfy.", + "type": "string", + "pattern": "^E[A-Za-z0-9_-]{43}$", + "examples": [ + "ENPE4hUQ8Peu84tEcCni3koOQFOnBrDB0rg_at2NRhV9" + ] }, "o": { - "description": "Operator indicating issuer AID of this ACDC MUST be the Issuee AID of the node this Edge points to.", + "description": "Not-Issuer-To-Issuee, operator indicating Issuer AID of this ACDC MAY or MAY not be the Issuee AID of the node that this Edge points to", "type": "string", - "const": "NI2I" + "default": "NI2I" } }, "additionalProperties": false, @@ -194,10 +278,9 @@ ] } }, - "additionalProperties": false, + "additionalProperties": true, "required": [ - "d", - "tnalloc" + "d" ] } ] @@ -209,25 +292,33 @@ "type": "string" }, { - "$id": "EHIN5MfIpe7_by-Rl7oVK6dDg1o096wds_gwtcsZInzj", + "$id": "EHrfdac4wurHKKoMsdBxgbYttUYXnsGVvmUL_J9xMJKt", "description": "Rules detail", "type": "object", "required": [ "d", - "perBrand" + "governance" ], "properties": { "d": { - "description": "Rule section SAID", - "type": "string" + "description": "SAID of the rules block.", + "type": "string", + "pattern": "^E[A-Za-z0-9_-]{43}$" + }, + "governance": { + "description": "Statement identifying the governance framework under which this credential was issued.", + "type": "string", + "examples": [ + "Issued under governance published at https://provenant.net/governance/tn-alloc/" + ] }, - "perBrand": { - "description": "perBrand Disclaimer", + "noSharing": { + "description": "No Sharing Disclaimer", "oneOf": [ { "description": "simple compact rule form", "type": "string", - "const": "Issuees agree not to share the phone number with other brands which may have a common owner but which will make it difficult to consistently identify the originator of traffic." + "default": "Issuees agree not to share or lend the allocated telephone number(s) to other parties in a way that would make it difficult to consistently identify the originator of traffic." }, { "description": "Rule detail", @@ -236,7 +327,7 @@ "l": { "description": "Associated legal language", "type": "string", - "const": "Issuees agree not to share the phone number with other brands which may have a common owner but which will make it difficult to consistently identify the originator of traffic." + "default": "Issuees agree not to share or lend the allocated telephone number(s) to other parties in a way that would make it difficult to consistently identify the originator of traffic." } }, "required": [ @@ -247,7 +338,7 @@ ] } }, - "additionalProperties": false + "additionalProperties": true } ] }