-
Notifications
You must be signed in to change notification settings - Fork 470
feat(conformance): add open_mandate_hash derivation vectors v0 #279
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
89416b5
a655571
8ed86e9
cc8d63a
4a8a292
df0b057
e4cb6cd
32b1c5e
14b97a8
c994746
effc481
ca887f1
a0b8544
0990c9c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| # AP2 `open_mandate_hash` Conformance Vectors — v0 | ||
|
|
||
| Conformance vectors for the `open_mandate_hash` derivation rule for | ||
| `open_checkout_mandate.json`. Any AP2 implementation that derives | ||
| `open_mandate_hash` MUST reproduce these vectors byte-for-byte. | ||
|
|
||
| ## Derivation rule | ||
|
|
||
| ``` | ||
| open_mandate_hash = SHA-256(JCS_RFC8785(unsigned_open_checkout_mandate_body)) | ||
| ``` | ||
|
|
||
| **Lowercase hex output.** | ||
|
|
||
| The hash input is the mandate **claims object**, not the JWS compact form. | ||
| Re-encoding the JWS envelope MUST NOT change `open_mandate_hash`. | ||
|
|
||
| ## Vectors | ||
|
|
||
| `vectors-v0.json` — 7 vectors anchored to | ||
| `code/sdk/schemas/ap2/open_checkout_mandate.json` at schema commit | ||
| `e3d9cafa7311d90612c7f908ae9b8821ddc8735a`. | ||
|
|
||
| Each vector is structured as: | ||
|
|
||
| ```json | ||
| { | ||
| "vector_id": "ap2-omh-v0-<name>", | ||
| "mandate_body": { ... }, | ||
| "expected_jcs_bytes_b64": "<base64url of RFC 8785 canonical bytes>", | ||
| "expected_open_mandate_hash": "sha256:<lowercase-hex>", | ||
| "expectation": "reference | same_hash_as:<id> | different_hash_from:<id>" | ||
| } | ||
| ``` | ||
|
|
||
| | Vector | Pair invariant | Tests | | ||
| |---|---|---| | ||
| | `baseline-001` | reference | Canonical baseline | | ||
| | `object-key-order-002` | `same_hash_as:baseline-001` | JCS sorts object members | | ||
| | `array-order-003` | `different_hash_from:baseline-001` | Arrays are order-significant | | ||
| | `optional-fields-004` | `different_hash_from:baseline-001` | Presence ≠ absence | | ||
|
chopmob-cloud marked this conversation as resolved.
Outdated
|
||
| | `currency-minor-unit-005` | canonical form | Integer minor units only | | ||
| | `unicode-nfc-006a` | `different_hash_from:unicode-nfd-006b` | No Unicode normalisation | | ||
| | `unicode-nfd-006b` | `different_hash_from:unicode-nfc-006a` | No Unicode normalisation | | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The expectations in the table use short names (e.g., Suggested changes: | `unicode-nfc-006a` | `different_hash_from:ap2-omh-v0-unicode-nfd-006b` | No Unicode normalisation |
| `unicode-nfd-006b` | `different_hash_from:ap2-omh-v0-unicode-nfc-006a` | No Unicode normalisation | |
||
|
|
||
| The array-order and Unicode pairs catch the divergences most commonly seen | ||
| in practice: implementations that sort arrays or NFC-normalise strings will | ||
| fail the corresponding pair invariant immediately. | ||
|
|
||
| ## Cross-implementation validation | ||
|
|
||
| | Implementation | Language | Library | Result | | ||
| |---|---|---|---| | ||
| | `rfc8785@0.1.4` | Python | Trail of Bits | 7/7 + 4/4 pair invariants ✓ | | ||
| | `canonicalize@3.0.0` | JavaScript | Erdtman + Rundgren (RFC 8785 author) | 7/7 + 4/4 ✓ | | ||
|
Check warning on line 55 in code/sdk/schemas/ap2/conformance/open_mandate_hash/README.md
|
||
| | `gowebpki/jcs v1.0.1` | Go | @amavashev (AP2 maintainer) | 7/7 + 4/4 ✓ | | ||
|
Check warning on line 56 in code/sdk/schemas/ap2/conformance/open_mandate_hash/README.md
|
||
| | `cyberphone/json-canonicalization` | Java | Rundgren (RFC 8785 reference impl) | 7/7 + 4/4 ✓ | | ||
|
Check warning on line 57 in code/sdk/schemas/ap2/conformance/open_mandate_hash/README.md
|
||
| | `serde_jcs 0.2.0` | Rust | @seritalien / Vauban | 7/7 + 4/4 ✓ | | ||
| | `rfc8785` (fixed) | Python | Crest Systems | 7/7 + 4/4 ✓ | | ||
|
|
||
| Full validation history: [AP2 issue #265](https://github.com/google-agentic-commerce/AP2/issues/265) | ||
|
|
||
| ## Known implementation hazards | ||
|
|
||
| - **`json.dumps()` non-ASCII escaping** — Python's `json.dumps()` escapes | ||
| non-ASCII characters as `\uXXXX`. RFC 8785 requires literal UTF-8 bytes | ||
| for printable codepoints above U+007F. Use the `rfc8785` library instead. | ||
| This will cause failures on vectors 006a and 006b. | ||
|
|
||
| - **Array sorting** — Do not sort arrays before hashing. JCS preserves | ||
| array element order. Vector 003 catches this. | ||
|
|
||
| - **Unicode normalisation** — Do not NFC-normalise strings before hashing. | ||
| RFC 8785 makes no Unicode normalisation. Vectors 006a/006b catch this. | ||
|
|
||
| - **Float/decimal prices** — `item.price` and `amount.amount` are integers | ||
| in the currency minor unit. `10.50` MUST be encoded as `1050`. Vector | ||
| 005 catches this. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The description states that
expected_jcs_bytes_b64is thebase64urlof the JCS bytes. However, the actual values invectors-v0.jsonare encoded using standardbase64(including padding=and/characters). The description should be updated to specify standardbase64to avoid confusion for implementers.