Specification
The specification defines version 1 of the DKDS protocol. It is normative: an implementation conforms when it meets every requirement stated in it and produces the expected result for every test vector.
1. Introduction#
A DKDS stamp is a QR code printed on a document. It contains the key facts of the document, the domain name of the issuer, the time of issue and a digital signature over all of these. The public key needed to check the signature is published in the DNS records of the issuer's domain. Any party can verify a stamp without an account, a registry or an intermediary.
A valid stamp establishes that the holder of the domain signed the stamp, that its facts have not been altered since, and when it was signed. It does not establish that the facts are true, or that the document it is printed on matches it; the reader makes that comparison.
1.1 Conformance language#
The key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT and MAY are to be interpreted as described in BCP 14 (RFC 2119, RFC 8174) when, and only when, they appear in capitals.
1.2 Roles#
- Issuer: the organisation that holds a domain, publishes a key under it and signs stamps.
- Verifier: software that reads a stamp, retrieves the key and reports an outcome.
- Reader: the person who uses a verifier and compares the result with the document.
1.3 Notation#
Integers are unsigned and big-endian. || denotes concatenation of byte strings. ASCII strings in
quotes denote their bytes, without a terminator. Hexadecimal values are written 0x2A.
2. Structure#
DKDS is defined as five layers. Each layer has one function and depends only on the layers named below.
| Layer | Function | Defined in | Depends on |
|---|---|---|---|
| Carrier | Represents the envelope as a QR code | Section 3 | The envelope as an opaque byte string |
| Envelope | Holds the header, payload and signature | Section 4 | Payload and signature as byte strings |
| Payload | Holds the issuer's facts | Section 5 | Nothing |
| Signature | Protects the envelope against alteration | Section 6 | A message, a public key, an algorithm |
| Key discovery | Maps a domain and key ID to a public key | Section 7 | A domain and a key ID |
A protocol version fixes every choice in every layer. Nothing within a version is optional or negotiable. Section 11 describes how later versions change one layer at a time.
3. Carrier#
3.1 Text form#
The text form of a stamp is the ASCII string "DKDS:" followed by the Base45 encoding (RFC 9285)
of the envelope:
text = "DKDS:" || Base45(envelope)The text MUST consist of exactly these characters, with nothing before or after them. It is at most 1,637 characters long, which limits the envelope to 1,088 bytes.
3.2 Base45#
Base45 encoding and decoding follow RFC 9285, with these requirements on decoding:
- every character MUST be in the Base45 alphabet; there is no case folding;
- a group of three characters whose value exceeds 65,535 is invalid;
- a final group of one character is invalid;
- a final group of two characters whose value exceeds 255 is invalid.
Under these rules every envelope has exactly one text form.
3.3 QR code#
The text form is encoded as one QR code (ISO/IEC 18004) in alphanumeric mode, with error correction level M. The full text, including the prefix, uses only the QR alphanumeric character set. A stamp uses QR version 27 or lower; a verifier MUST read every version up to and including 27.
A document MAY carry several stamps. Each is verified independently.
4. Envelope#
4.1 Layout#
| Field | Size | Content |
|---|---|---|
version |
1 byte | 0x01 |
domain_len |
1 byte | Length of domain in bytes |
domain |
domain_len bytes |
The issuer's domain name (4.2) |
keyid_len |
1 byte | Length of key_id, 1 to 16 |
key_id |
keyid_len bytes |
Key identifier (4.3) |
issued_at |
4 bytes | Time of signing, in seconds since 1970-01-01T00:00:00Z, excluding leap seconds |
payload_len |
2 bytes | Length of payload in bytes, at least 1 |
payload |
payload_len bytes |
Section 5 |
signature |
the remaining bytes | Section 6; at least 1 byte |
The envelope is at most 1,088 bytes. The part of the envelope before signature is called the
signed part.
4.2 Domain#
domain is an ASCII domain name with no trailing dot. It MUST satisfy all of the following:
- it consists of at least two labels separated by
.; - each label is 1 to 63 characters from
atoz,0to9and-; - no label begins or ends with
-; - a label whose third and fourth characters are
--MUST begin withxn--; - for a label that begins with
xn--, the characters afterxn--MUST be valid Punycode (RFC 3492). Decoding them MUST produce a string that contains no forbidden code point (Appendix B), and encoding that string with Punycode MUST reproduce exactly the characters afterxn--. (A label whose decoded form is ASCII only always ends with-, and is already excluded by the rule on hyphens.)
The Unicode form of the domain is the domain with every xn-- label replaced by its decoded
string. These rules are purely algorithmic: they need no Unicode character tables, so every verifier
reaches the same result. Whether the Unicode form is a valid internationalised domain name under
IDNA2008 (RFC 5891) is not checked here; verifiers report doubtful names as warnings (9.3).
The lookup name is key_id || "._dkds." || domain. It MUST be at most 253 characters long.
4.3 Key ID#
key_id is 1 to 16 characters from a to z and 0 to 9. It identifies one key of the issuer.
4.4 Version#
0x01 identifies this version. 0x00 and 0xFF are reserved and never assigned. Any other value
identifies a version this document does not define.
5. Payload#
5.1 Encoding#
The payload is a list of fields, encoded as below and then compressed with raw DEFLATE (RFC 1951).
The compressed bytes are the payload field of the envelope.
count 1 byte number of fields, 1 to 255
then, for each field, in display order:
name_len 1 byte 1 to 255
name name_len bytes, UTF-8
value_len 2 bytes 0 to 65,535
value value_len bytes, UTF-8Every field is a name and a value, both text. There are no other types.
5.2 Rules#
A payload is valid only if all of the following hold:
- the DEFLATE stream is valid and ends exactly at the end of
payload; - the decompressed data is at most 16,384 bytes; a decoder MUST stop decompressing once this limit is exceeded;
- the field list ends exactly at the end of the decompressed data;
- every name and value is valid UTF-8 (RFC 3629) and contains no forbidden code point (Appendix B);
- no two names are equal, compared byte for byte.
Values MAY be empty. Issuers SHOULD use Unicode Normalization Form C; verifiers do not check it.
6. Signature#
6.1 Signed message#
The signed message is the ASCII string "DKDS" followed by the signed part of the envelope:
message = "DKDS" || signed_partThe prefix "DKDS" is not transmitted. It ensures that a DKDS signature cannot be valid as a
signature in another protocol that signs different data.
6.2 Algorithm#
The algorithm is named by the key record (section 7), never by the stamp. This version defines one
algorithm, ed25519.
6.3 Ed25519#
Ed25519 is used as defined in RFC 8032, section 5.1, with the following rules, which remove the
differences between implementations. The public key A is 32 bytes. The signature is 64 bytes,
R || S, where R and S are 32 bytes each.
Verification fails if any of the following holds:
- the signature is not exactly 64 bytes long;
S, read as a little-endian integer, is greater than or equal to the group orderL;AorRdoes not decode to a point on the curve, or encoding the decoded point again does not reproduce the same 32 bytes (this rejects every non-canonical encoding);AorRis a point of small order (one of the 8 points whose order divides 8);- with
k = SHA-512(R || A || message)read as a little-endian integer moduloL, the encoding of the point[S]B - [k]Ais not byte-for-byte equal toR.
This is the cofactorless verification equation of RFC 8032, section 5.1.7, with the canonicality and small-order checks made mandatory. It matches the behaviour of libsodium. Many other Ed25519 libraries do not perform checks 2 to 4; an implementation using such a library MUST perform the missing checks itself before calling it. The test vectors contain one signature for each check.
7. Key discovery#
7.1 Location#
The key for a stamp is published as a DNS TXT record at the lookup name <key_id>._dkds.<domain>.
The record MAY be reached through a CNAME, which the verifier follows as for any DNS query.
7.2 Record format#
The record is a tag list. If the TXT record consists of several character strings, they are joined without separators before parsing.
record = tag *( sep tag ) [ sep ] *WSP
tag = *WSP name *WSP "=" *WSP value *WSP
sep = ";"
name = ALPHA *( ALPHA / DIGIT / "_" )
value = *( %x21-3A / %x3C-7E ) ; visible ASCII except ";"
WSP = %x20 / %x09 ; space or tabDefined tags:
| Tag | Required | Value |
|---|---|---|
v |
yes; MUST be the first tag | DKDS1 |
k |
yes | The algorithm. This version defines ed25519. |
p |
yes | The public key in Base64 (RFC 4648, section 4) with padding, in canonical form: encoding the decoded bytes again reproduces the value exactly. For ed25519 it decodes to exactly 32 bytes. An empty value means the key is revoked. |
Each tag appears at most once. Unknown tags are ignored. Tag names and the values of v and k are
case-sensitive.
Example:
k2026._dkds.northwind.example. TXT "v=DKDS1; k=ed25519; p=6kpsY+KcUgq+9VB7Ey7F+ZVHdq6+vnuSQh7qaRRG0iw="7.3 Selecting the record#
Of the TXT records at the lookup name, only those whose first tag is v=DKDS1 are considered. There
MUST be exactly one such record, and it MUST parse according to 7.2; otherwise no usable key exists
at the name.
7.4 Revocation#
An issuer revokes a key by replacing its record with one whose p tag is empty:
v=DKDS1; k=ed25519; p=. Every stamp signed with a revoked key is invalid, including stamps signed
before the revocation, because a holder of a stolen key can choose any issued_at.
8. Verification#
8.1 Outcomes#
Verification ends in exactly one of the following outcomes. These identifiers are used by verifiers, test vectors and conformance tests.
| Outcome | Meaning |
|---|---|
valid |
The stamp was signed with the key published for its domain and key ID. |
malformed |
The stamp, or its payload, does not conform to this specification. |
unsupported |
The stamp uses a version, or its key uses an algorithm, that the verifier does not implement. |
key-not-found |
The DNS answer contains no usable key record at the lookup name. |
key-revoked |
The key record exists and marks the key as revoked. |
invalid-signature |
The signature does not verify. |
unavailable |
The key could not be retrieved, for example because of a timeout, a server failure, a DNSSEC validation failure or disagreeing resolvers. The stamp may be checked again later. |
8.2 Procedure#
A verifier performs these steps in order. The first step that fails determines the outcome. No step may be skipped or reordered.
- The text form satisfies section 3.1 and 3.2. Otherwise:
malformed. - The decoded envelope is at least one byte long and its first byte is not
0x00or0xFF. Otherwise:malformed. - The first byte is
0x01. Otherwise:unsupported. - The envelope satisfies section 4: every length field is within its bounds and within the
envelope,
domainandkey_idsatisfy 4.2 and 4.3, the lookup name is at most 253 characters,payload_lenis at least 1, and at least 1 byte remains forsignature. Otherwise:malformed. issued_atis no more than 600 seconds after the verifier's current time. Otherwise:malformed.- Query the lookup name for TXT records. If no answer is obtained:
unavailable. If the answer contains no usable record (7.3), including when the name does not exist:key-not-found. - The record's
ptag is not empty. Otherwise:key-revoked. - The verifier implements the algorithm named by
k. Otherwise:unsupported. - The value of
pdecodes as required for the algorithm. Otherwise:key-not-found. - The signature verifies under section 6. Otherwise:
invalid-signature. - The payload satisfies section 5. Otherwise:
malformed. - The outcome is
valid.
A verifier makes no DNS query for a stamp that fails steps 1 to 5. The payload is decompressed and parsed only after the signature has been verified.
9. Verifier requirements#
9.1 Display#
On valid, a verifier MUST display, in this order:
- the outcome;
- the domain, prominently; if it contains
xn--labels, in its Unicode form (4.2), with the ASCII form available; - the issue time, with an explicit time zone: either UTC or local time with its offset;
- whether the DNS answer was validated with DNSSEC;
- any warnings (9.3);
- every field, in order, with names and values exactly as signed.
Items 1 to 5 are the verifier's own statements. They MUST be visually distinct from the fields, and
the fields MUST be presented under a heading that identifies them as statements of the issuer. A
field named, for example, Issued by must never be confusable with the verifier's own display of the
domain.
On any other outcome, a verifier MUST NOT display the fields.
9.2 DNS#
A verifier SHOULD query two independent resolvers. If both answer and the answers differ, the outcome
is unavailable. If only one answers, its answer is used, and the verifier notes that only one
resolver was reached.
A DNS answer that fails DNSSEC validation is treated as no answer (unavailable). An answer from an
unsigned zone is used, and reported as not validated under 9.1.
A verifier MAY remember keys it has seen before, and SHOULD warn when the key record of a domain it has seen changes or disappears.
9.3 Warnings#
A verifier SHOULD check the domain for lookalike risks: mixed scripts, confusable characters (Unicode Technical Standard #39), and small differences from domains the reader has verified before. These checks produce warnings. They MUST NOT change the outcome, which is determined only by section 8.
10. Issuer requirements#
- A key published for DKDS MUST NOT be used for any other purpose.
- A key ID MUST NOT be reused for a different key. Changing the key behind a key ID invalidates every stamp signed with the old key.
- An issuer SHOULD keep every key record published for as long as documents signed with it are expected to be verified. A key that is no longer used for signing stays published; a key that may be compromised is revoked (7.4).
- Each stamp SHOULD contain at least one field that identifies the subject of the document, such as a name, and one that identifies the document, such as a number. Without these, a valid stamp can be copied onto another document unnoticed.
- Field values SHOULD be written exactly as they are printed on the document, so that the reader can compare them character by character.
- An issuer SHOULD print stamps black on white, at a module size of at least 0.33 mm, with a quiet zone of 4 modules. At that module size, a stamp of about 640 envelope bytes is about 3.5 cm wide, and one of the maximum size about 4.4 cm.
11. Versioning#
Each layer can change in a later version without changing the others:
- Signature algorithms are added by defining a new
kvalue. The envelope and the record version stay the same. A verifier that does not implement the algorithm reportsunsupported. - Envelope or payload changes require a new
versionbyte value. - Key record changes that affect verification require a new record version (
v=DKDS2). Tags that do not affect verification may be added toDKDS1records, because unknown tags are ignored. - Carriers other than the QR code may be defined for the same envelope. A carrier transports the envelope unchanged.
12. Security considerations#
- Lookalike domains. The protocol proves which domain signed a stamp, not that the reader recognises it. Verifiers display the domain prominently and warn about lookalikes (9.3).
- Stolen keys. A thief can sign stamps with any issue time. Revocation (7.4) therefore invalidates all stamps of the key. Short-lived keys limit the number of legitimate stamps affected.
- Forged DNS answers. DNSSEC prevents them where the issuer's zone is signed. Verifiers report whether it was (9.1) and compare resolvers (9.2).
- Lapsed domains. Whoever holds a domain can publish keys under it and sign stamps with any issue time. A valid stamp therefore means that the current holder of the domain vouches for it.
- Untrue content. A stamp shows who made a statement, not whether it is correct.
- Copied stamps. A stamp can be copied onto another document. The reader detects this by comparing the fields with the document; issuer requirement 4 makes that comparison meaningful.
- Hostile input. Every length is bounded, decompression stops at 16,384 bytes, no DNS query is made for a malformed stamp, and the payload is parsed only after the signature verifies.
- Display spoofing. Forbidden code points (Appendix B) prevent text that displays differently from what was signed. The separation in 9.1 prevents fields from imitating the verifier.
- Confidentiality. None. Anyone who scans a stamp can read every field.
- Quantum computers. A large quantum computer could forge Ed25519 signatures. A post-quantum
algorithm can be introduced as a new
kvalue (section 11), within the 1,088-byte limit only for algorithms with small signatures.
Appendix A. Limits#
| Item | Limit |
|---|---|
| Text form | 1,637 characters |
| Envelope | 1,088 bytes |
| Lookup name | 253 characters |
| Domain label | 1 to 63 characters |
| Key ID | 1 to 16 characters |
| Fields | 1 to 255 |
| Field name | 1 to 255 bytes |
| Field value | 0 to 65,535 bytes |
| Decompressed payload | 16,384 bytes |
| Clock tolerance | 600 seconds |
Appendix B. Forbidden code points#
Names and values MUST NOT contain any of the following:
| Code points | Description |
|---|---|
| U+0000 to U+001F, U+007F to U+009F | Control characters (Unicode category Cc), including line breaks and tabs |
| U+061C | Arabic letter mark |
| U+200E, U+200F | Left-to-right and right-to-left marks |
| U+202A to U+202E | Bidirectional embeddings and overrides |
| U+2066 to U+2069 | Bidirectional isolates |
| U+2028, U+2029 | Line and paragraph separators |
| U+FEFF | Byte order mark |
| U+FDD0 to U+FDEF | Noncharacters |
| U+FFFE, U+FFFF, and the last two code points of every plane (U+1FFFE, U+1FFFF, ... U+10FFFE, U+10FFFF) | Noncharacters |
Zero-width joiners (U+200C, U+200D) are allowed, because several scripts need them.
Appendix C. Example#
This example is produced by tools/example.mjs, which follows this specification and decodes
its own output as a check. The private key is 32 bytes of 0x07; it is published here and
MUST NOT be used for anything else.
C.1 Fields#
| # | Name | Value |
|---|---|---|
| 1 | Supplier | Northwind B.V. |
| 2 | Invoice no. | 2026-0917 |
| 3 | Date | 2026-09-30 |
| 4 | Customer | Harbour Logistics B.V. |
| 5 | Amount | 4,812.50 EUR |
| 6 | Pay to IBAN | NL91 ABNA 0417 1643 00 |
| 7 | Due | 2026-10-30 |
The field list is 172 bytes; compressed with raw DEFLATE it is 155 bytes.
C.2 Envelope#
version 1 B 01
domain_len 1 B 11
domain 17 B 6e 6f 72 74 68 77 69 6e 64 2e 65 78 61 6d 70 6c
65
keyid_len 1 B 05
key_id 5 B 6b 32 30 32 36
issued_at 4 B 6a bc cf 90
payload_len 2 B 00 9b
payload 155 B 35 cd 41 0b 82 30 18 80 e1 41 51 96 d1 d1 f3 f7
03 72 7c 53 b3 3c ce 0c 12 44 a2 a8 bb 99 d4 20
37 99 5b d1 bf 0f a2 8e ef e5 79 c7 ce d1 76 dd
43 34 9a cc 4b a5 cd fd 25 e4 15 52 7a a6 6e 2e
9f 4a d4 0d 48 45 c9 24 c0 20 f6 31 61 ab 61 56
99 86 4c 7f ed 87 e8 6c 6c 6f 54 db 68 e2 ed 2a
7d 51 56 43 a1 6e a2 37 a2 ee bf d0 88 b7 ca 4a
43 66 d1 62 cd 02 ba 44 d8 9e 0e ee be 7a 83 51
90 a7 bc 24 5e 59 24 0c 78 5a 72 c0 88 ad 80 c5
51 08 88 83 cc fe 4f 0c fd 10 3f
signature 64 B 3f ef 0c 62 53 5e 86 94 89 bd 4c cf e8 9e 1d 54
37 35 86 69 80 1d 37 71 ad 16 50 90 5a 48 ee 16
46 cc 4a a1 4e 4a 10 19 0e ff 87 0e 5b c4 53 2a
11 28 3e 46 ff 30 a6 77 4b 2a e1 b2 90 33 2b 05Envelope: 250 bytes. Issued at 2026-09-30T09:00:00Z (1790758800).
C.3 Text form#
380 characters:
DKDS:360B/D5LED9DZED-TCB$CBECP9EVYC$OD846P*65*N99I/RJU.PLK1R368D
GQB8:2JHOQAAVDLE7QA-U7UN1KU8+EL5KJC34JHJANQ./163IK0TUBPRLQX/RBT6
9$PA/K50WO$S9JA 1LA+5VK9PU10$83T4N74-A6/TLT.A0:GY7G78H VDF3E8XR/
USWG5WCAXO8H:DM1798UEGQPANLH9-:C3MCNF0TV87:J88U/LF0EAA9L+Q45CB.P
1OJBDFO1.LN.OO31ZTGX6W+S1J22W38KP1COAR0HQIH/V9FIT%V33:6T:G$8GI07
U*LE8ARIBK4UY.8PJ9H+9Q12E+1E3H2RB5NAR72C*7XBW02LRM9/NSFAIXJ5The line breaks are for presentation only; the text form contains none.
C.4 Key record#
k2026._dkds.northwind.example. TXT "v=DKDS1; k=ed25519; p=6kpsY+KcUgq+9VB7Ey7F+ZVHdq6+vnuSQh7qaRRG0iw="Test vectors#
The test vectors accompany the specification. Each vector is a stamp, the conditions under which it is verified, and the result that a conforming verifier must produce. The set contains 145 vectors:
| Outcome | Vectors |
|---|---|
valid |
21 |
malformed |
83 |
invalid-signature |
17 |
key-not-found |
17 |
unsupported |
4 |
key-revoked |
2 |
unavailable |
1 |
Where a rule has a limit, there is a vector at the limit that is valid and a vector one step past it that is not, for example a lookup name of 253 and of 254 characters, and a decompressed payload of 16,384 and of 16,385 bytes. Each vector names the section of the specification that it tests, so that an implementation can be tested one section at a time while it is being written.
Files#
| File | Content |
|---|---|
| vectors.json | The vectors. |
| vectors.schema.json | A JSON Schema (draft 2020-12) describing vectors.json. |
| specification.md | This specification as a Markdown file. |
Using the vectors#
For each vector, a test harness:
- gives the verifier the string
text, exactly as a QR scanner would deliver it; - sets the verifier's clock to
now(Unix seconds); - answers the verifier's DNS queries from the
dnsobject, and records the names queried; - compares the outcome with
expected.outcome, and the names queried withexpected.queries; - for a
validoutcome, also comparesdomain,domain_unicode,key_id,issued_at,dnssecandfields(names and values, in order).
A verifier passes the vectors when all five comparisons succeed for every vector. A complete harness is about 50 lines long.
{
"id": "valid-appendix-c",
"section": "Appendix C",
"description": "The example of Appendix C.",
"text": "DKDS:360B/D5LED9DZED-TCB$CBECP9EVYC$OD846P*65*N99I/RJU…",
"now": 1790800000,
"dns": {
"k2026._dkds.northwind.example": {
"result": "answer",
"txt": [["v=DKDS1; k=ed25519; p=6kpsY+KcUgq+9VB7Ey7F+ZVHdq6+vnuSQh7qaRRG0iw="]],
"dnssec": false
}
},
"expected": {
"outcome": "valid",
"queries": ["k2026._dkds.northwind.example"],
"domain": "northwind.example",
"domain_unicode": "northwind.example",
"key_id": "k2026",
"issued_at": 1790758800,
"dnssec": false,
"fields": [["Supplier", "Northwind B.V."], ["Invoice no.", "2026-0917"], ["Date", "2026-09-30"],
["Customer", "Harbour Logistics B.V."], ["Amount", "4,812.50 EUR"],
["Pay to IBAN", "NL91 ABNA 0417 1643 00"], ["Due", "2026-10-30"]]
}
}The first vector, with its text shortened and its intermediate values omitted.
Simulated DNS#
The dns object maps a DNS name to what a resolver returns for it:
result |
Meaning | The verifier sees |
|---|---|---|
answer |
The name exists. txt lists its TXT records, each as a list of character strings to be joined without separators. dnssec states whether the answer was validated. |
the records |
cname |
The name is an alias for target. |
whatever target resolves to |
nxdomain |
The name does not exist. | no records |
failure |
No answer could be obtained. | a lookup failure |
A name that does not appear in dns does not exist. A name absent from expected.queries must not be
queried at all: several vectors require that a malformed stamp is rejected without any DNS query
(section 8.2). failure stands for every way of not obtaining an answer: a timeout, a server failure,
a DNSSEC validation failure, or two resolvers that disagree (section 9.2).
Intermediate values#
Valid vectors carry an intermediate object with the envelope, the signed message and the
uncompressed field list in hexadecimal. These values are not part of the comparison; they help to
locate a fault when a valid vector fails.
Requirements not covered#
Some requirements cannot be checked by comparing outputs and must be tested in another way.
| Requirement | Section | Reason |
|---|---|---|
| Reading the QR code | 3.3 | The vectors start from the decoded text. Decoding the image is left to a QR library. |
| What the verifier displays, and how | 9.1 | Display is visual and requires review rather than comparison. |
| Using two resolvers | 9.2 | The vectors model the combined result of the lookup, not the resolvers individually. |
| Lookalike warnings | 9.3 | Warnings are heuristics and never change the outcome. |
| Issuer requirements | 10 | They concern how issuers operate, not what a stamp contains. |
Ed25519 libraries#
Section 6.3 requires checks that many Ed25519 libraries do not perform. When the 17 signature vectors were run through two common forms of verification, both accepted stamps that the specification rejects:
| Vector | Specification | OpenSSL (Node.js 24) | Cofactored (ZIP-215) |
|---|---|---|---|
signature-r-identity |
reject | accept | accept |
signature-r-mixed-order |
reject | reject | accept |
signature-key-identity |
reject | accept | accept |
signature-key-non-canonical |
reject | accept | accept |
signature-key-order-2 |
reject | reject | accept |
signature-key-mixed-order-k1 |
reject | reject | accept |
signature-key-mixed-order-k0 |
accept | accept | accept |
All other signature vectors were rejected by all three. In the same test, libsodium (libsodium-wrappers 0.7.15) agreed with the specification on all 17 signature vectors, so a verifier built on libsodium needs no additional checks. An implementation built on another library performs the missing checks of section 6.3 itself before calling it.
Test keys#
The vectors are signed with two keys whose seeds are published in vectors.json: 32 bytes of 0x07
(the key of Appendix C) and 32 bytes of 0x08. Anyone can sign with these keys. They must never be
used for anything other than testing.
Stability#
- The
idof a vector never changes, and the meaning of a vector never changes. - New vectors may be added. Removing a vector is a change to the specification and is recorded as such.
- The vectors are generated deterministically: generating them twice produces identical files.