hi all,
I've worked through the UOV spec a bit, and found a minor typo and two possible considerations:
- In 3.2.2 ExpandP(seed_pk), the spec says "The m matrices are expanded in an interleaved fashion, in column-major order.", the description of the order and section 3.3 "Encoding of epk" however, point to this being a typo, and the public key being expanded and stored in row-major order (as opposed to the trapdoor, which needs to be column-major for some optimizations)
- As written, public key expansion is a one-way function. It would be trivial to make it into a two way function, by either prefixing the public seed (adding 16 bytes of overhead), or using the public seed as the first 16 bytes of the public key, i.e. making the matrices P1/P2 to be seed_pk || AES-CTR(seed_pk). This would allow the use of the standard 7 function API (keygen, sign, verify, parse_pk, parse_sk, serialize_pk, serialize_sk) using the expanded public key as in-memory representation.
- As written, the public seed is independent from the private seed. It might be worth considering making seed_pk a hash of seed_sk, to make the private key format more rigid, not allowing for two honestly created public keys to share the public key seeds.
As a bonus, and purely for the list's amusement, I have attached an implementation of UOV verify that acts as its own expanded public key (written with shell and python, so you can check the source code before executing a random file downloaded from the internet).
The signature is for "This is a message", and
./quovine "This is a message" sig
should print "Verified", and, if I did not mess up any row/column major order, so should any round 2 compatible implementation using the executable as an expanded public key.
Sophie
--