├── tsconfig.json ├── .gitignore ├── bin └── publish.sh ├── shadow-cljs.edn ├── src └── nuid │ ├── zk │ ├── js │ │ └── lib.cljs │ ├── protocol.cljc │ ├── lib.cljc │ ├── js.cljs │ └── knizk.cljc │ └── zk.cljc ├── test └── nuid_zk_test.ts ├── deps.edn ├── LICENSE-MIT.md ├── package.json ├── README.md ├── ts └── main.d.ts └── LICENSE-APACHE.md /tsconfig.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # clj 2 | .cpcache 3 | 4 | # npm 5 | node_modules 6 | 7 | # shadow-cljs 8 | .shadow-cljs 9 | target 10 | 11 | # nREPL 12 | .nrepl-port -------------------------------------------------------------------------------- /bin/publish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | npm run build 4 | 5 | if npm test; then 6 | npm publish 7 | else 8 | echo "Can't publish to NPM, tests failed!" 9 | exit 1 10 | fi 11 | -------------------------------------------------------------------------------- /shadow-cljs.edn: -------------------------------------------------------------------------------- 1 | {:deps {:aliases [:cljs]} 2 | :builds 3 | {:node 4 | {:target :node-library, 5 | :exports-var nuid.zk.js/exports, 6 | :output-to "target/node/nuid_zk.js"}}} 7 | -------------------------------------------------------------------------------- /src/nuid/zk/js/lib.cljs: -------------------------------------------------------------------------------- 1 | (ns nuid.zk.js.lib 2 | (:require 3 | [clojure.spec.alpha :as s] 4 | [nuid.lib :as lib] 5 | [nuid.zk.lib :as zk.lib])) 6 | 7 | (defn ->js 8 | ([data] 9 | (->> 10 | (zk.lib/stringify data) 11 | (clj->js))) 12 | ([spec data] 13 | (->> 14 | (s/unform spec data) 15 | (->js)))) 16 | 17 | (defn ->clj 18 | ([data] 19 | (->> 20 | (js->clj data :keywordize-keys true) 21 | (zk.lib/keywordize))) 22 | ([spec data] 23 | (->> 24 | (->clj data) 25 | (s/conform spec)))) 26 | 27 | (def credential-key? 28 | (into 29 | (hash-set) 30 | (map lib/fqn) 31 | zk.lib/credential-keys)) 32 | -------------------------------------------------------------------------------- /src/nuid/zk/protocol.cljc: -------------------------------------------------------------------------------- 1 | (ns nuid.zk.protocol 2 | (:require 3 | [nuid.ident.zk :as ident.zk])) 4 | 5 | (def protocols ident.zk/protocols) 6 | (def default ::knizk) 7 | 8 | (defmulti pub :nuid.zk/protocol) 9 | (defmulti proof :nuid.zk/protocol) 10 | (defmulti verified? :nuid.zk/protocol) 11 | (defmulti credential :nuid.zk/protocol) 12 | 13 | (defmulti parameters-multi-spec :nuid.zk/protocol) 14 | (defmulti credential-multi-spec :nuid.zk/protocol) 15 | (defmulti challenge-multi-spec :nuid.zk/protocol) 16 | (defmulti provable-multi-spec :nuid.zk/protocol) 17 | (defmulti proof-multi-spec :nuid.zk/protocol) 18 | (defmulti verifiable-multi-spec :nuid.zk/protocol) 19 | (defmulti verified-multi-spec :nuid.zk/protocol) 20 | -------------------------------------------------------------------------------- /src/nuid/zk.cljc: -------------------------------------------------------------------------------- 1 | (ns nuid.zk 2 | (:require 3 | [clojure.spec.alpha :as s] 4 | [nuid.zk.knizk] 5 | [nuid.zk.protocol :as protocol])) 6 | 7 | (def protocols protocol/protocols) 8 | (def pub protocol/pub) 9 | (def proof protocol/proof) 10 | (def verified? protocol/verified?) 11 | (def credential protocol/credential) 12 | 13 | (s/def ::protocol protocols) 14 | (s/def ::parameters (s/multi-spec protocol/parameters-multi-spec ::protocol)) 15 | (s/def ::credential (s/multi-spec protocol/credential-multi-spec ::protocol)) 16 | (s/def ::challenge (s/multi-spec protocol/challenge-multi-spec ::protocol)) 17 | (s/def ::provable (s/multi-spec protocol/provable-multi-spec ::protocol)) 18 | (s/def ::proof (s/multi-spec protocol/proof-multi-spec ::protocol)) 19 | (s/def ::verifiable (s/multi-spec protocol/verifiable-multi-spec ::protocol)) 20 | (s/def ::verified (s/multi-spec protocol/verified-multi-spec ::protocol)) 21 | -------------------------------------------------------------------------------- /test/nuid_zk_test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert' 2 | import * as zk from '../target/node/nuid_zk' // '@nuid/zk' uncomment for type checking 3 | 4 | describe('zk typescript definitions', () => { 5 | it('supports roundtrip credential creation, challenging, and proving', () => { 6 | const secret = 'secrets are good' 7 | const verified = zk.verifiableFromSecret(secret) 8 | assert.ok(verified) 9 | const credential: zk.Credential = zk.credentialFromVerifiable(verified) 10 | assert.ok(credential) 11 | const challenge: zk.Challenge = zk.defaultChallengeFromCredential(credential) 12 | assert.ok(challenge) 13 | const proof: zk.Proof = zk.proofFromSecretAndChallenge(secret, challenge) 14 | assert.ok(proof) 15 | const verified2: zk.VerifiedCredential = zk.verifiableFromProofAndChallenge(proof, challenge) 16 | assert.ok(verified2) 17 | assert.strictEqual( 18 | verified['nuid.zk.knizk/pub']['nuid.elliptic.curve/point'], 19 | verified2['nuid.zk.knizk/pub']['nuid.elliptic.curve/point'] 20 | ) 21 | }) 22 | }) 23 | -------------------------------------------------------------------------------- /deps.edn: -------------------------------------------------------------------------------- 1 | {:deps 2 | {org.clojure/clojure {:mvn/version "1.10.1"}, 3 | nuid/elliptic 4 | {:git/url "https://github.com/nuid/elliptic.git", 5 | :sha "0c573a0bfc5ecf3792d5d2fd63b8e82b544fbe9e"}, 6 | nuid/base64 7 | {:git/url "https://github.com/nuid/base64.git", 8 | :sha "1973314afc3710a045d617830a8fa64d86cecb11"}, 9 | nuid/cryptography 10 | {:git/url "https://github.com/nuid/cryptography.git", 11 | :sha "46667476309e5d0172a447851c205222491441a1"}, 12 | nuid/bn 13 | {:git/url "https://github.com/nuid/bn.git", 14 | :sha "30036cd9bf7654fef3987b57887878b1d8f8f76b"}, 15 | org.clojure/test.check {:mvn/version "1.0.0"}, 16 | nuid/ident 17 | {:git/url "https://github.com/nuid/ident.git", 18 | :sha "f4b9ef164b175f515f032aa194a17727d71eedb4"}, 19 | nuid/spec 20 | {:git/url "https://github.com/nuid/spec.git", 21 | :sha "ad05529d0cddaf703c501e1513a45db0ff91acfe"}, 22 | nuid/lib 23 | {:git/url "https://github.com/nuid/lib.git", 24 | :sha "93fec185a33d5abc59d8ec234ed57abe3b3d61f5"}}, 25 | :aliases 26 | {:cljs {:extra-deps {thheller/shadow-cljs {:mvn/version "2.11.23"}}}}, 27 | :paths ["src"]} 28 | -------------------------------------------------------------------------------- /LICENSE-MIT.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 NuID, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nuid/zk", 3 | "version": "0.1.1", 4 | "description": "Cross-platform zero knowledge facilities", 5 | "main": "target/node/nuid_zk.js", 6 | "files": [ 7 | "LICENSE*", 8 | "ts/main.d.ts" 9 | ], 10 | "scripts": { 11 | "build": "rm -rf target && shadow-cljs release node", 12 | "test": "ts-mocha test/**/*_test.ts" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/nuid/zk.git" 17 | }, 18 | "keywords": [], 19 | "author": "NuID, Inc.", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/nuid/zk/issues" 23 | }, 24 | "homepage": "https://github.com/nuid/zk", 25 | "dependencies": { 26 | "bn.js": "^5.2.0", 27 | "brorand": "^1.1.0", 28 | "buffer": "^5.7.1", 29 | "elliptic": "^6.5.4", 30 | "hash.js": "^1.1.7", 31 | "scryptsy": "^2.1.0" 32 | }, 33 | "devDependencies": { 34 | "@types/expect": "^24.3.0", 35 | "@types/mocha": "^8.2.2", 36 | "mocha": "^8.3.2", 37 | "shadow-cljs": "^2.11.23", 38 | "source-map-support": "^0.5.19", 39 | "ts-mocha": "^8.0.0", 40 | "typescript": "^4.2.4" 41 | }, 42 | "types": "ts/main.d.ts" 43 | } 44 | -------------------------------------------------------------------------------- /src/nuid/zk/lib.cljc: -------------------------------------------------------------------------------- 1 | (ns nuid.zk.lib 2 | (:require 3 | [clojure.set :as set] 4 | [clojure.spec.alpha :as s] 5 | [clojure.walk :as walk] 6 | [nuid.ident.cryptography :as ident.crypt] 7 | [nuid.ident.elliptic :as ident.elliptic] 8 | [nuid.ident.zk :as ident.zk] 9 | [nuid.lib :as lib] 10 | [nuid.spec.lib :as spec.lib] 11 | [nuid.zk :as zk] 12 | [nuid.zk.knizk :as knizk] 13 | [nuid.zk.protocol :as protocol])) 14 | 15 | (defn default-challenge-parameters 16 | [] 17 | (into 18 | {::zk/protocol ::protocol/knizk} 19 | (knizk/default-challenge-parameters))) 20 | 21 | (defn default-challenge 22 | [] 23 | (s/conform 24 | ::zk/challenge 25 | (default-challenge-parameters))) 26 | 27 | (defn tag-secret 28 | [{:nuid.zk/keys [protocol]} secret] 29 | (case protocol 30 | ::protocol/knizk {::knizk/secret secret})) 31 | 32 | (def credential-keys 33 | (into 34 | (hash-set) 35 | (mapcat spec.lib/keys-spec->keys) 36 | #{::knizk/credential})) 37 | 38 | (def fqns 39 | (into 40 | (hash-set) 41 | (map lib/fqn) 42 | (set/union 43 | ident.elliptic/curve-ids 44 | ident.crypt/hash-algorithms 45 | ident.crypt/string-normalization-forms 46 | ident.zk/protocols))) 47 | 48 | (defn -postwalk-stringify 49 | [x] 50 | (if (or (keyword? x) (symbol? x)) 51 | (lib/fqn x) 52 | x)) 53 | 54 | (defn -postwalk-keywordize 55 | [x] 56 | (if (fqns x) 57 | (keyword x) 58 | x)) 59 | 60 | (def stringify 61 | (partial walk/postwalk -postwalk-stringify)) 62 | 63 | (def keywordize 64 | (partial walk/postwalk -postwalk-keywordize)) 65 | -------------------------------------------------------------------------------- /src/nuid/zk/js.cljs: -------------------------------------------------------------------------------- 1 | (ns nuid.zk.js 2 | (:require 3 | [clojure.spec.alpha :as s] 4 | [goog.object :as obj] 5 | [nuid.cryptography.hash :as hash] 6 | [nuid.cryptography.hash.algorithm :as hash.alg] 7 | [nuid.elliptic.curve.point :as point] 8 | [nuid.spec.lib :as spec.lib] 9 | [nuid.zk :as zk] 10 | [nuid.zk.js.lib :as js.lib] 11 | [nuid.zk.knizk :as knizk] 12 | [nuid.zk.lib :as lib] 13 | [nuid.zk.protocol :as zk.protocol])) 14 | 15 | (defn verifiableFromSecret 16 | [secret] 17 | (let [challenge (lib/default-challenge) 18 | secret (lib/tag-secret challenge secret) 19 | pub (zk/pub (into challenge secret)) 20 | proof (zk/proof (merge challenge pub secret)) 21 | verifiable (merge challenge pub proof)] 22 | (js.lib/->js ::zk/verifiable verifiable))) 23 | 24 | (def -isVerified 25 | (comp 26 | (complement s/invalid?) 27 | (partial js.lib/->clj ::zk/verified))) 28 | 29 | (defn isVerified 30 | [verifiable] 31 | (try 32 | (-isVerified verifiable) 33 | (catch :default _ 34 | false))) 35 | 36 | (defn -credential-filter 37 | [_ k _] 38 | (js.lib/credential-key? k)) 39 | 40 | (defn credentialFromVerifiable 41 | [verifiable] 42 | (let [filtered (obj/filter verifiable -credential-filter) 43 | values (obj/getValues filtered)] 44 | (apply js/Object.assign values))) 45 | 46 | (defn defaultChallengeFromCredential 47 | [credential] 48 | (let [credential (js.lib/->clj credential) 49 | pub (spec.lib/select-keys ::point/parameters credential) 50 | keyfn (->> 51 | (hash.alg/parameters-multi-spec credential) 52 | (spec.lib/keys-spec->keys) 53 | (into #{::hash/algorithm}) 54 | (select-keys credential)) 55 | challenge (into 56 | (knizk/default-challenge-parameters) 57 | {::zk/protocol ::zk.protocol/knizk 58 | ::knizk/pub pub 59 | ::knizk/keyfn keyfn})] 60 | (js.lib/->js ::zk/challenge challenge))) 61 | 62 | (defn proofFromSecretAndChallenge 63 | [secret challenge] 64 | (let [challenge (js.lib/->clj ::zk/challenge challenge) 65 | secret (lib/tag-secret challenge secret) 66 | proof (zk/proof (into challenge secret)) 67 | protocol (::zk/protocol challenge) 68 | tagged (assoc proof ::zk/protocol protocol)] 69 | (js.lib/->js ::zk/proof tagged))) 70 | 71 | (defn verifiableFromProofAndChallenge 72 | [proof challenge] 73 | (js/Object.assign challenge proof)) 74 | 75 | (def exports 76 | #js {:verifiableFromSecret verifiableFromSecret 77 | :isVerified isVerified 78 | :credentialFromVerifiable credentialFromVerifiable 79 | :defaultChallengeFromCredential defaultChallengeFromCredential 80 | :proofFromSecretAndChallenge proofFromSecretAndChallenge 81 | :verifiableFromProofAndChallenge verifiableFromProofAndChallenge}) 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | # nuid.zk 4 | 5 | Cross-platform zero knowledge proofs. 6 | 7 | Git issues and other communications are warmly welcomed. [dev@nuid.io](mailto:dev@nuid.io) 8 | 9 | ## Requirements 10 | 11 | [`jvm`](https://www.java.com/en/download/), [`node + npm`](https://nodejs.org/en/download/), [`clj`](https://clojure.org/guides/getting_started), [`shadow-cljs`](https://shadow-cljs.github.io/docs/UsersGuide.html#_installation) 12 | 13 | ## Clojure and ClojureScript 14 | 15 | ### tools.deps: 16 | 17 | `{nuid/zk {:git/url "https://github.com/nuid/zk" :sha "..."}}` 18 | 19 | ### usage: 20 | 21 | ``` 22 | $ clj # or shadow-cljs node-repl 23 | => (require 24 | #?@(:clj 25 | ['[clojure.spec-alpha2.gen :as gen] 26 | '[clojure.spec-alpha2 :as s]] 27 | :cljs 28 | ['[clojure.spec.gen.alpha :as gen] 29 | '[clojure.test.check.generators] 30 | '[clojure.spec.alpha :as s]]) 31 | '[nuid.cryptography :as crypt] 32 | '[nuid.zk :as zk]) 33 | 34 | => (def parameters (gen/generate (s/gen ::zk/parameters))) 35 | => (def secret "high entropy ✅") 36 | => (def pub (zk/pub (assoc parameters :secret secret))) 37 | => (def nonce (gen/generate (s/gen ::crypt/nonce))) 38 | => (def parameters (merge parameters {:pub pub :nonce nonce})) 39 | 40 | => (def good-proof (zk/proof (merge parameters {:secret secret}))) 41 | => (def bad-proof (zk/proof (merge parameters {:secret "garbage 🚮"}))) 42 | 43 | => (zk/verified? (merge parameters good-proof)) 44 | => (zk/verified? (merge parameters bad-proof)) 45 | ``` 46 | 47 | ## JavaScript 48 | 49 | ### node: 50 | 51 | ```bash 52 | $ npm install -s @nuid/zk 53 | $ node 54 | > var Zk = require('@nuid/zk'); 55 | 56 | // client context, sign up 57 | > var secret = "high entropy ✅" 58 | > var verifiable = Zk.verifiableFromSecret(secret); 59 | > var json = JSON.stringify(verifiable); 60 | 61 | // server context, sign up 62 | > var verifiable = JSON.parse(json); 63 | > Zk.isVerified(verifiable) 64 | > var credential = Zk.credentialFromVerifiable(verifiable); // persist credential (db, ledger, ...) 65 | 66 | // server context, sign in 67 | > var challenge = Zk.defaultChallengeFromCredential(credential); // retrieve credential (db, ledger, ...) 68 | > var json = JSON.stringify(challenge); 69 | 70 | // client context, sign in 71 | > var challenge = JSON.parse(json); 72 | > var proof = Zk.proofFromSecretAndChallenge(secret, challenge); 73 | > var json = JSON.stringify(proof); 74 | 75 | // server context, sign in 76 | > var proof = JSON.parse(json); 77 | > var verifiable = Zk.verifiableFromProofAndChallenge(proof, challenge) 78 | > Zk.isVerified(verifiable) ? /* verified */ : /* unverified */ ; 79 | ``` 80 | 81 | ### browser: 82 | 83 | The `npm` package is browser-compatible in Webpack-like workflows. 84 | 85 | ## Java 86 | 87 | To call `nuid.zk` from Java or other JVM languages, use one of the recommended interop strategies ([var/IFn](https://clojure.org/reference/java_interop#_calling_clojure_from_java) or [uberjar/aot](https://push-language.hampshire.edu/t/calling-clojure-code-from-java/865)). Doing so may require modifications or additions to the API for convenience. 88 | 89 | ## CLR 90 | 91 | [Coming soon](https://github.com/bcgit/bc-csharp) 92 | 93 | ## Notes 94 | 95 | The purpose of `nuid.zk` and sibling `nuid` libraries (e.g. [`nuid.bn`](https://github.com/nuid/bn)) is to abstract over platform-specific differences and provide a common interface to fundamental dependencies. This allows us to express dependent logic (e.g. [`nuid.zk`](https://github.com/nuid/zk)) once in pure Clojure(Script), and use it from each of the host platforms (Java, JavaScript, CLR). This is particularly useful for generating and verifying proofs across service boundaries. 96 | 97 | ## Licensing 98 | 99 | Apache v2.0 or MIT 100 | 101 | ## ⚠️ Disclaimer 102 | 103 | This library is [property tested](https://github.com/clojure/test.check#testcheck) to help verify implementation, but has not yet been audited by an independent third party. 104 | -------------------------------------------------------------------------------- /src/nuid/zk/knizk.cljc: -------------------------------------------------------------------------------- 1 | (ns nuid.zk.knizk 2 | (:require 3 | [clojure.spec.alpha :as s] 4 | [clojure.spec.gen.alpha :as gen] 5 | [clojure.test.check.generators] 6 | [nuid.base64 :as base64] 7 | [nuid.bn :as bn] 8 | [nuid.cryptography.bn :as crypt.bn] 9 | [nuid.cryptography.hash :as hash] 10 | [nuid.cryptography.hash.algorithm :as hash.alg] 11 | [nuid.cryptography.hash.bn :as hash.bn] 12 | [nuid.elliptic.curve.point :as point] 13 | [nuid.elliptic.curve :as curve] 14 | [nuid.spec.lib :as spec.lib] 15 | [nuid.zk.protocol :as protocol])) 16 | 17 | (s/def ::secret 18 | (s/with-gen 19 | (s/and string? seq) 20 | (fn [] (gen/string-ascii)))) 21 | 22 | (s/def ::curve ::curve/curve) 23 | (s/def ::hashfn ::hash.bn/hashfn) 24 | (s/def ::keyfn ::hash.bn/keyfn) 25 | (s/def ::pub ::point/point) 26 | (s/def ::pri ::bn/bn) 27 | (s/def ::nonce ::crypt.bn/nonce) 28 | 29 | (s/def ::parameters 30 | (s/keys 31 | :req 32 | [::curve 33 | ::hashfn 34 | ::keyfn])) 35 | 36 | (s/def ::credential 37 | (s/keys 38 | :req 39 | [::keyfn 40 | ::pub])) 41 | 42 | (s/def ::challenge 43 | (s/keys 44 | :req 45 | [::curve 46 | ::hashfn 47 | ::keyfn 48 | ::nonce] 49 | :opt 50 | [::pub])) 51 | 52 | (s/def ::provable 53 | (s/and 54 | (s/keys 55 | :req 56 | [::curve 57 | ::hashfn 58 | ::keyfn 59 | ::pub 60 | ::nonce 61 | (or 62 | ::secret 63 | ::pri)]))) 64 | 65 | (s/def ::c ::bn/bn) 66 | (s/def ::s ::bn/bn) 67 | 68 | (s/def ::proof 69 | (s/keys 70 | :req [::c ::s])) 71 | 72 | (s/def ::verifiable 73 | (s/keys 74 | :req 75 | [::curve 76 | ::hashfn 77 | ::pub 78 | ::nonce 79 | ::c 80 | ::s])) 81 | 82 | (defmethod protocol/pub ::protocol/knizk 83 | [{::keys [curve keyfn pri secret]}] 84 | {::pub (point/mul 85 | (curve/base curve) 86 | (or pri (keyfn secret)))}) 87 | 88 | (defmethod protocol/proof ::protocol/knizk 89 | [{::keys [curve hashfn keyfn pub pri secret nonce]}] 90 | (let [q (curve/order curve) 91 | r (crypt.bn/generate-secure-random-lt 32 q) 92 | A (point/mul (curve/base curve) r) 93 | c (hashfn (str (base64/encode pub) 94 | (bn/str nonce 16) 95 | (base64/encode A))) 96 | x (or pri (keyfn secret)) 97 | s (bn/mod (bn/add (bn/mul c x) r) q)] 98 | {::c c ::s s})) 99 | 100 | (defmethod protocol/verified? ::protocol/knizk 101 | [{::keys [curve hashfn pub nonce c s]}] 102 | (let [A (point/add (point/mul (curve/base curve) s) 103 | (point/neg (point/mul pub c))) 104 | H (hashfn (str (base64/encode pub) 105 | (bn/str nonce 16) 106 | (base64/encode A)))] 107 | (bn/eq? H c))) 108 | 109 | (s/def ::verified 110 | (s/with-gen 111 | (s/and 112 | ::verifiable 113 | protocol/verified?) 114 | (fn [] 115 | (->> 116 | (s/gen ::parameters) 117 | (gen/fmap (fn [m] (assoc m ::nonce (gen/generate (s/gen ::crypt.bn/nonce))))) 118 | (gen/fmap (fn [m] (assoc m ::secret (gen/generate (s/gen ::secret))))) 119 | (gen/fmap (fn [m] (assoc m :nuid.zk/protocol ::protocol/knizk))) 120 | (gen/fmap (fn [m] (merge m (protocol/pub m)))) 121 | (gen/fmap (fn [m] (merge m (protocol/proof m)))))))) 122 | 123 | (defn credential 124 | [x] 125 | (spec.lib/select-keys ::credential x)) 126 | 127 | (defmethod protocol/credential ::protocol/knizk 128 | [x] 129 | (->> 130 | (spec.lib/keys-spec->keys ::credential) 131 | (into #{:nuid.zk/protocol}) 132 | (select-keys x))) 133 | 134 | (defmethod protocol/parameters-multi-spec ::protocol/knizk [_] ::parameters) 135 | (defmethod protocol/credential-multi-spec ::protocol/knizk [_] ::credential) 136 | (defmethod protocol/challenge-multi-spec ::protocol/knizk [_] ::challenge) 137 | (defmethod protocol/provable-multi-spec ::protocol/knizk [_] ::provable) 138 | (defmethod protocol/proof-multi-spec ::protocol/knizk [_] ::proof) 139 | (defmethod protocol/verifiable-multi-spec ::protocol/knizk [_] ::verifiable) 140 | (defmethod protocol/verified-multi-spec ::protocol/knizk [_] ::verified) 141 | 142 | (defn default-challenge-parameters 143 | [] 144 | {::curve {::curve/id ::curve/secp256k1} 145 | ::hashfn (hash/default-parameters {::hash/algorithm ::hash.alg/sha256}) 146 | ::keyfn (hash/default-parameters {::hash/algorithm ::hash.alg/scrypt}) 147 | ::nonce (s/unform ::crypt.bn/nonce (gen/generate (s/gen ::crypt.bn/nonce)))}) 148 | -------------------------------------------------------------------------------- /ts/main.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for @nuid/zk 2 | // Project: @nuid/zk 3 | // Definitions by: NuID Developers 4 | 5 | declare module "@nuid/zk" { 6 | 7 | // Bare types 8 | export type KnizkProtocol = "nuid.zk.protocol/knizk" 9 | 10 | export type CurveFnSECP256K1 = "nuid.elliptic.curve/secp256k1" 11 | 12 | export type StringNormalizationNFKC = "string.normalization/NFKC" 13 | 14 | export type HashAlgorithmSHA256 = "nuid.cryptography.hash.algorithm/sha256" 15 | export type HashAlgorithmScrypt = "nuid.cryptography.hash.algorithm/scrypt" 16 | 17 | // Unions 18 | export type Protocol = KnizkProtocol 19 | export type CurveFn = CurveFnSECP256K1 20 | export type StringNormalization = StringNormalizationNFKC 21 | export type HashAlgorithm = 22 | HashAlgorithmSHA256 23 | | HashAlgorithmScrypt 24 | 25 | // Interfaces 26 | export interface Credential { 27 | "nuid.cryptography.hash/algorithm": HashAlgorithmScrypt, 28 | "nuid.cryptography.base64/salt": string, 29 | "string.normalization/form": StringNormalizationNFKC, 30 | "nuid.cryptography.hash.algorithm.scrypt/N": number, 31 | "nuid.cryptography.hash.algorithm.scrypt/r": number, 32 | "nuid.cryptography.hash.algorithm.scrypt/p": number, 33 | "nuid.cryptography.hash.algorithm.scrypt/length": number, 34 | "nuid.elliptic.curve/parameters": { 35 | "nuid.elliptic.curve/id": CurveFnSECP256K1 36 | }, 37 | "nuid.elliptic.curve/point": string 38 | } 39 | 40 | export interface KnizkCredential { 41 | "nuid.zk/protocol": KnizkProtocol, 42 | "nuid.zk.knizk/curve": { 43 | "nuid.elliptic.curve/id": CurveFnSECP256K1 44 | }, 45 | "nuid.zk.knizk/hashfn": { 46 | "string.normalization/form": StringNormalizationNFKC, 47 | "nuid.cryptography.hash/algorithm": HashAlgorithmSHA256 48 | }, 49 | "nuid.zk.knizk/keyfn": { 50 | "nuid.cryptography.hash/algorithm": HashAlgorithmScrypt, 51 | "nuid.cryptography.base64/salt": string, 52 | "string.normalization/form": StringNormalizationNFKC, 53 | "nuid.cryptography.hash.algorithm.scrypt/N": number, 54 | "nuid.cryptography.hash.algorithm.scrypt/r": number, 55 | "nuid.cryptography.hash.algorithm.scrypt/p": number, 56 | "nuid.cryptography.hash.algorithm.scrypt/length": number 57 | }, 58 | "nuid.zk.knizk/nonce": string, 59 | "nuid.zk.knizk/pub": { 60 | "nuid.elliptic.curve/parameters": { 61 | "nuid.elliptic.curve/id": CurveFnSECP256K1 62 | }, 63 | "nuid.elliptic.curve/point": string 64 | }, 65 | "nuid.zk.knizk/c": string, 66 | "nuid.zk.knizk/s": string 67 | } 68 | 69 | export interface KnizkChallenge { 70 | "nuid.zk/protocol": KnizkProtocol, 71 | "nuid.zk.knizk/curve": { 72 | "nuid.elliptic.curve/id": CurveFnSECP256K1 73 | }, 74 | "nuid.zk.knizk/hashfn": { 75 | "string.normalization/form": StringNormalizationNFKC, 76 | "nuid.cryptography.hash/algorithm": HashAlgorithmSHA256 77 | }, 78 | "nuid.zk.knizk/keyfn": { 79 | "nuid.cryptography.hash/algorithm": HashAlgorithmScrypt, 80 | "nuid.cryptography.base64/salt": string, 81 | "string.normalization/form": StringNormalizationNFKC, 82 | "nuid.cryptography.hash.algorithm.scrypt/N": number, 83 | "nuid.cryptography.hash.algorithm.scrypt/r": number, 84 | "nuid.cryptography.hash.algorithm.scrypt/p": number, 85 | "nuid.cryptography.hash.algorithm.scrypt/length": number 86 | }, 87 | "nuid.zk.knizk/nonce": string, 88 | "nuid.zk.knizk/pub": { 89 | "nuid.elliptic.curve/parameters": { 90 | "nuid.elliptic.curve/id": CurveFnSECP256K1 91 | }, 92 | "nuid.elliptic.curve/point": string 93 | } 94 | } 95 | 96 | export interface KnizkProof { 97 | "nuid.zk/protocol": KnizkProtocol, 98 | "nuid.zk.knizk/c": string, 99 | "nuid.zk.knizk/s": string 100 | } 101 | 102 | // Primary Unions 103 | export type VerifiedCredential = KnizkCredential 104 | export type Challenge = KnizkChallenge 105 | export type Proof = KnizkProof 106 | 107 | // Functions 108 | export function verifiableFromSecret(secret: string): VerifiedCredential; 109 | export function isVerified(verifiedCredential: VerifiedCredential): boolean; 110 | export function credentialFromVerifiable(verifiedCredential: VerifiedCredential): Credential; 111 | export function defaultChallengeFromCredential(credential: Credential): Challenge; 112 | export function proofFromSecretAndChallenge(secret: string, challenge: Challenge): Proof; 113 | export function verifiableFromProofAndChallenge(proof: Proof, challenge: Challenge): VerifiedCredential; 114 | } 115 | -------------------------------------------------------------------------------- /LICENSE-APACHE.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2019 NuID, Inc. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------