Use from R
The noqtis R package bundles the C library: nothing else to install,
and randomness comes from the operating system, never from R’s random
number generator (set.seed() does not make keys repeat).
From r-universe, with binaries for Windows, macOS and Linux:
install.packages("noqtis", repos = c("https://rootcoder007.r-universe.dev", "https://cloud.r-project.org"))install.packages("noqtis") from CRAN works once CRAN has reviewed the
package.
Seal the folder behind an analysis
Section titled “Seal the folder behind an analysis”library(noqtis)d <- file.path(tempdir(), "results")dir.create(file.path(d, "data"), recursive = TRUE)writeLines(c("a,b", "1,2"), file.path(d, "data", "in.csv"))writeLines("r", file.path(d, "report.txt"))
k <- nqkeygen("ML-DSA-65")nqseal(d, k$sk, k$pk, "ML-DSA-65", meta = '{"project":"tutorial"}')r <- nqcheck(d, k$pk)attr(r, "ok")
cat("edited\n", file = file.path(d, "report.txt"), append = TRUE)r <- nqcheck(d, k$pk)attr(r, "ok")r[!r$ok, ]
sig <- nqsign(k$sk, "the results in table 2", "ML-DSA-65", ctx = "app-v1")nqverify(k$pk, "the results in table 2", sig, "ML-DSA-65", ctx = "app-v1")nqverify(k$pk, "the results in table 2", sig, "ML-DSA-65")
kk <- nqkeygen("ML-KEM-768")e <- nqencap(kk$pk, "ML-KEM-768")identical(nqdecap(kk$sk, e$ct, "ML-KEM-768"), e$ss)nqhash("abc", "sha3-256", hex = TRUE)A key made with noqtis keygen loads with nqreadkey("me")$key, and
nqwritekey() writes one the command line reads.
Run with Rscript prov.R (or source("prov.R", echo = TRUE)), the
interesting lines print:
> attr(r, "ok")[1] TRUE> attr(r, "ok")[1] FALSE> r[!r$ok, ] check ok detail16 file FALSE report.txt: size differs> nqverify(k$pk, "the results in table 2", sig, "ML-DSA-65", ctx = "app-v1")[1] TRUE> nqverify(k$pk, "the results in table 2", sig, "ML-DSA-65")[1] FALSE> identical(nqdecap(kk$sk, e$ct, "ML-KEM-768"), e$ss)[1] TRUE> nqhash("abc", "sha3-256", hex = TRUE)[1] "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"nqseal(dir, sk, pk, alg, meta)writesnoqtis.jsonandnoqtis.siginto the folder;metais one string of JSON text, signed with the manifest.nqcheck(dir, pk)returns a data frame with one row per check (check,ok,detail);attr(r, "ok")isTRUEonly when every check passed. Withoutpkit accepts the key in the seal, and a row says so.- Keys, signatures and ciphertexts are raw vectors in the standards’
encodings, so they can be saved with
writeBin()and checked by any conforming implementation.
An identity card for your key
Section titled “An identity card for your key”An identity card ties your signing key to your name and ORCID iD, signed
by the key itself; publish it with the key, and noqtis check --card
names you as the sealer of your capsules.
library(noqtis)k <- nqkeygen("ML-DSA-65")card <- nqidcard(k$sk, k$pk, "ML-DSA-65", "Ada Lovelace", orcid = "https://orcid.org/0000-0002-1825-0097")writeBin(card, file.path(tempdir(), "ada.card"))
v <- nqidcheck(file.path(tempdir(), "ada.card"), k$pk)v$namev$orcididentical(v$key_sha256, nqhash(k$pk, "sha256", hex = TRUE))
bad <- charToRaw(sub("Ada", "Eve", rawToChar(card)))is.null(nqidcheck(bad))inherits(try(nqidcard(k$sk, k$pk, "ML-DSA-65", "Ada Lovelace", orcid = "0000-0002-1825-0098"), silent = TRUE), "try-error")> v$name[1] "Ada Lovelace"> v$orcid[1] "0000-0002-1825-0097"> identical(v$key_sha256, nqhash(k$pk, "sha256", hex = TRUE))[1] TRUE> is.null(nqidcheck(bad))[1] TRUE[1] TRUEThe card holds the bare ORCID iD, whose check digit must be right. A
changed card does not verify (NULL), and an iD with a wrong check
digit is refused. The card is self-signed, so give v$key_sha256 where
people already know you, or let them pin your public key.
In a reproducible workflow
Section titled “In a reproducible workflow”Seal the output folder as the last step of the analysis script, and
publish the public key with the paper or the data release. A reader
checks the folder they downloaded with nqcheck(dir, pk), or with the
noqtis check -p key.pub dir command, which reads the same capsule.
The package’s vignette (vignette("noqtis")) and help pages
(?nqseal, ?nqsign) cover every function.