Closed steveluscher closed 2 years ago
Important: It only partially addresses it, many cases are still left w/o solution.
Quite a few libraries re-calculate public keys. There is no issue in doing that, instead of half-solutions.
Hey @steveluscher, nice to see a fellow Solana developer here! I guess this repo has been getting lots of eyes on it lately after the whole Slope wallet private key hack. It definitely seems like freezing these byte arrays is a smart choice. I'll definitely take a look at this code when I get back to my laptop in a few hours!
Preamble
Discussion
Overspecification
It's a common thing to see an API overspecified. This means that its input types overstate what the implementation needs to function. APIs like
nacl.sign.detached
, for instance, ask that you bring aUint8Array
when really all the implementation requires is:thing[1]
)length
property that is anumber
tweetnacl
doesn't need any of the other features offered by theUint8Array
interface, like.every()
or.byteLength
or any of that. The only other thing offered by that type is a guarantee that each element is a number between 0–255, but that can be either ignored (signatures will be junk otherwise) or validated at runtime.Frozen objects
Uint8Array
can not be frozen byObject.freeze
which is useful to prevent runtime mutation. Now that the inputs tonacl.sign.detached
are specified just enough, we can actually return plain arrays that can be frozen. This is a runtime protection against the values being mutated.Opaque/branded types
Next, we can apply a type system level protection against the values being mutated.
The idea here is that the only value for
secretKey
that can be supplied tonacl.sign.detached
was something that was produced bynacl.sign.keyPair.*
. If you try to pass an array that you constructed outside ofnacl.sign.keyPair
, it will fail to typecheck.Also, if you try to mutate the value that you received from
nacl.sign.keyPair
, it will fail to typecheck.Benchmarks
Related to #247.