diff --git a/demo/demo.css b/demo/demo.css deleted file mode 100644 index 6912bee..0000000 --- a/demo/demo.css +++ /dev/null @@ -1,50 +0,0 @@ -p { - margin: 0.4em 0 0.2em; -} - -input[type=text] { - width: 500px; -} - -.alice, .bob { - margin: 1em; - width: 550px; - padding: 10px; -} - -.alice { - border: 2px solid grey; - border-left-width: 20px; -} - -.bob { - border: 2px solid grey; - border-right-width: 20px; -} - -.messageleft, .messageright { - margin: 1em; - background-color: grey; - height: 30px; - text-align: center; - color: #fff; - line-height: 30px; - width: 590px; -} - -.messageleft .arrow, .messageright .arrow { - border-top: 15px solid #fff; - border-bottom: 15px solid #fff; - width: 0; - height: 0; -} - -.messageright .arrow { - float: right; - border-left: 15px solid grey; -} - -.messageleft .arrow { - float: left; - border-right: 15px solid grey; -} diff --git a/demo/split-key.html b/demo/split-key.html deleted file mode 100644 index 82175bd..0000000 --- a/demo/split-key.html +++ /dev/null @@ -1,194 +0,0 @@ - - - -Two-party ECDSA signature generation - - - - - -

Two-party ECDSA signature generation

-

Initialization

-
-

Alice starts out with her share of the private key d1

-
- - -
-

And a Paillier keypair pk/sk

-
- - -
-
- - -
-
- - -
-
- - -
-
-
-

Bob starts out with his share d2 of the private key d

-
- - -
-
-

Protocol

-
-

First Alice generates her share of the one-time secret k1

-
- - -
-

And its inverse z1 = (k1)-1 mod n

-
- - -
-

She also calculates Q1 = k1G

-
- - -
-

She then encrypts z1 using Paillier to create α = Epk(z1)

-
- - -
-

And β = Epk(d1z1 mod n)

-
- - -
-

And also generates an encrypted blinding factor A = Epk(c) for some c ∈ [1, nP/nEC]

-
- - -
-

Alice composes the encrypted signature σ1 = (α ×pk e) +pk (β ×pk r) +pk (A ×pk n)

-
- - -
-

She deterministically rerandomizes it to receive σ1' = σ1HASH(σ1)n mod n2

-
- - -
-

And decrypts σ1' to receive s1

-
- - -
-

And v', the randomizing factor in σ1'

-
- - -
-
-
-Q1, α, β, message, e, pk, A, s1, v' -
-
-

Bob validates Q1 by ensuring that -

    -
  1. Q1 ≠ O
  2. -
  3. xQ1 and yQ1 are in the interval [1,n - 1]
  4. -
  5. yQ12 ≡ xQ13 + axQ1 + b (mod p)
  6. -
  7. nQ1 = O
  8. -

-

And verifies the message to be signed

-

He then verifies s1 as a valid signature

-

Bob also calculates σ1' from α, β and A

-
- - -
-

And verifies it matches Epk(s1, v')

-

He then generates his share k2 of the private one-time value k

-
- - -
-

And its inverse z2 = (k2)-1 mod n

-
- - -
-

He can calculate r = xQ where Q(xQ, yQ) = k2Q1

-
- - -
-

And Q2 = k2G

-
- - -
-

Bob prepares a random value B ∈ [1, nP/nEC] to use for blinding

-

- - -
-

Finally he calculates σ = (α ×pk z2e) +pk (β ×pk z2d2r) +pk Epk(BnEC)

-
- - -
-
-
-Q2, r, σ -
-
-

Alice confirms Q2 is a valid public point -

    -
  1. Q2 ≠ O
  2. -
  3. xQ2 and yQ2 are in the interval [1,n - 1]
  4. -
  5. yQ22 ≡ xQ23 + axQ2 + b (mod p)
  6. -
  7. nQ2 = O
  8. -

-

She now calculates r = xQ where Q = k1Q2 and matches it against what Bob claimed

-

She decrypts σ to receive s = Dsk(σ)

-
- - -
-

She verifies the signature using r and the combined public key before publishing.

-
- - -
-
- - diff --git a/demo/split-key.js b/demo/split-key.js deleted file mode 100644 index 0ded297..0000000 --- a/demo/split-key.js +++ /dev/null @@ -1,283 +0,0 @@ -var window = this; - -importScripts( - "../src/crypto-js/crypto.js", - "../src/crypto-js/sha256.js", - "../src/jsbn/prng4.js", - "../src/jsbn/rng.js", - "../src/jsbn/jsbn.js", - "../src/jsbn/jsbn2.js", - - "../src/jsbn/ec.js", - "../src/jsbn/sec.js", - "../src/events/eventemitter.js", - "../src/bitcoin.js", - "../src/util.js", - "../src/base58.js", - - "../src/address.js", - "../src/ecdsa.js", - "../src/paillier.js" -); - -function hex(value) { - if ("function" === typeof value.getEncoded) { - return Crypto.util.bytesToHex(value.getEncoded()); - } else if ("function" === typeof value.toByteArrayUnsigned) { - return Crypto.util.bytesToHex(value.toByteArrayUnsigned()); - } else if (Array.isArray(value)) { - return Crypto.util.bytesToHex(value); - } - return value; -}; -function ff(field, value) { - value = hex(value); - postMessage({ "cmd": "ff", "field": field, "value": value }); -}; - -function log() { - postMessage({ "cmd": "log", "args": Array.prototype.slice.apply(arguments) }); -}; - -function start() { - var ecparams = getSECCurveByName("secp256k1"); - var rng = new SecureRandom(); - - var G = ecparams.getG(); - var n = ecparams.getN(); - - G.validate(); - - var Alice = function (pubShare) { - this.d1 = Bitcoin.ECDSA.getBigRandom(n); - ff('d1', this.d1); - - this.paillier = Bitcoin.Paillier.generate(n.bitLength()*2+ - Math.floor(Math.random()*10)); - - ff('p1_n', this.paillier.pub.n); - ff('p1_g', this.paillier.pub.g); - ff('p1_l', this.paillier.l); - ff('p1_m', this.paillier.m); - }; - var Bob = function () { - this.d2 = Bitcoin.ECDSA.getBigRandom(n); - ff('d2', this.d2); - }; - - Alice.prototype.getPub = function (P) { - if (this.pub) return this.pub; - - P.validate(); - - return this.pub = P.multiply(this.d1).getEncoded(); - }; - - Alice.prototype.getPubShare = function () { - return G.multiply(this.d1); - }; - - Bob.prototype.getPubShare = function () { - return G.multiply(this.d2); - }; - - Alice.prototype.step1 = function (message) { - var hash = Crypto.SHA256(Crypto.SHA256(message, {asBytes: true}), {asBytes: true}); - this.e = BigInteger.fromByteArrayUnsigned(hash).mod(n); - - this.k1 = Bitcoin.ECDSA.getBigRandom(n); - ff('k1', this.k1); - - this.z1 = this.k1.modInverse(n); - ff('z1', this.z1); - - var Q_1 = G.multiply(this.k1); - ff('q1', Q_1); - - var alpha = this.paillier.encrypt(this.z1); - ff('alpha', alpha); - - var beta = this.paillier.encrypt(this.d1.multiply(this.z1).mod(n)); - ff('beta', beta); - - var r_1 = Q_1.getX().toBigInteger().mod(n); - var A = this.paillier.encrypt(Bitcoin.ECDSA.getBigRandom(this.paillier.n.divide(n))); - ff('A', A); - var s_a = this.paillier.multiply(alpha, this.e); - var s_b = this.paillier.multiply(beta, r_1); - var sigma_1 = this.paillier.addCrypt(this.paillier.addCrypt(s_a, s_b), this.paillier.multiply(A, n)); - ff('sigma_1', sigma_1); - - var e = Crypto.SHA256(sigma_1.toByteArrayUnsigned(), {asBytes: true}); - e = BigInteger.fromByteArrayUnsigned(e); - var sigma_1n = this.paillier.rerandomize(sigma_1, e); - ff('sigma_1n', sigma_1n); - - var s_1 = this.paillier.decrypt(sigma_1n); - ff('s_1', s_1); - var v_n = this.paillier.decryptR(sigma_1n, s_1); - ff('v_n', v_n); - - return { - Q_1: Q_1, - P_1: this.getPubShare(), - alpha: alpha, - beta: beta, - message: message, - paillier: this.paillier.pub, - A: A, - s_1: s_1, - v_n: v_n - }; - }; - - Bob.prototype.step2 = function (pkg) { - // ... In real life we would check that message is a valid transaction and - // does what we want. - - // Throws exception on error - pkg.Q_1.validate(); - - var hash = Crypto.SHA256(Crypto.SHA256(message, {asBytes: true}), {asBytes: true}); - this.e = BigInteger.fromByteArrayUnsigned(hash).mod(n); - - this.paillier = pkg.paillier; - this.alpha = pkg.alpha; - this.beta = pkg.beta; - - var r_1 = pkg.Q_1.getX().toBigInteger().mod(n); - var testSig = Bitcoin.ECDSA.serializeSig(r_1, pkg.s_1.mod(n)); - if (!Bitcoin.ECDSA.verify(hash, testSig, pkg.P_1.getEncoded())) { - throw new Error('Verification of s1 failed.'); - } - - // Verify that alpha and beta are valid by generating and verifying sigma_1n - var s_a_1 = this.paillier.multiply(this.alpha, this.e); - var s_b_1 = this.paillier.multiply(this.beta, r_1); - var sigma_1 = this.paillier.addCrypt(this.paillier.addCrypt(s_a_1, s_b_1), this.paillier.multiply(pkg.A, n)); - - var e = Crypto.SHA256(sigma_1.toByteArrayUnsigned(), {asBytes: true}); - e = BigInteger.fromByteArrayUnsigned(e); - var sigma_1n = this.paillier.rerandomize(sigma_1, e); - ff('sigma_1n_b', sigma_1n); - - var sigma_1_verify = this.paillier.encrypt(pkg.s_1, pkg.v_n); - if (!sigma_1n.equals(sigma_1_verify)) { - throw new Error('Sigma ciphertext did not match expected value.'); - } - - this.k2 = Bitcoin.ECDSA.getBigRandom(n); - ff('k2', this.k2); - - this.z2 = this.k2.modInverse(n); - ff('z2', this.z2); - - var Q_2 = G.multiply(this.k2); - ff('q2', Q_2); - - var Q = pkg.Q_1.multiply(this.k2); - this.r = Q.getX().toBigInteger().mod(n); - ff('r', this.r); - - if (this.r.equals(BigInteger.ZERO)) { - throw new Error('r must not be zero.'); - } - - var B = Bitcoin.ECDSA.getBigRandom(this.paillier.n.divide(n)); - ff('B', B); - - var p = this.paillier; - var s_a = p.multiply(this.alpha, this.e.multiply(this.z2)); - var s_b = p.multiply(this.beta, this.r.multiply(this.d2).multiply(this.z2)); - var sigma = p.add(p.addCrypt(s_a, s_b), B.multiply(n)); - ff('sigma', sigma); - - return { - Q_2: Q_2, - r: this.r, - sigma: sigma - }; - }; - - Alice.prototype.step3 = function (pkg) { - pkg.Q_2.validate(); - - var Q = pkg.Q_2.multiply(this.k1); - this.r = Q.getX().toBigInteger().mod(n); - - if (!this.r.equals(pkg.r)) { - throw new Error('Could not confirm value for r.'); - } - - if (this.r.equals(BigInteger.ZERO)) { - throw new Error('r must not be zero.'); - } - - var s = this.paillier.decrypt(pkg.sigma).mod(n); - ff('s', s); - - var sig = Bitcoin.ECDSA.serializeSig(this.r, s); - - var hash = this.e.toByteArrayUnsigned(); - if (!Bitcoin.ECDSA.verify(hash, sig, this.getPub())) { - throw new Error('Signature failed to verify.'); - } - - return { - r: this.r, - s: s - }; - }; - - var message = "testmessage"; - - var bob = new Bob(); - var pubShare = bob.getPubShare(); - - var alice = new Alice(pubShare); - var pub = alice.getPub(pubShare); - - var pkg1 = alice.step1(message); - var pkg2 = bob.step2(pkg1); - var pkg3 = alice.step3(pkg2); - - var sig = Bitcoin.ECDSA.serializeSig(pkg3.r, pkg3.s); - - var kChk = alice.k1.multiply(bob.k2); - var rChk = G.multiply(kChk).getX().toBigInteger(); - log("r :", hex(pkg3.r)); - log("r/CHK:", hex(rChk)); - - var hash = Crypto.SHA256(Crypto.SHA256(message, {asBytes: true}), {asBytes: true}); - var eChk = BigInteger.fromByteArrayUnsigned(hash).mod(n); - var dChk = alice.d1.multiply(bob.d2); - var sChk = kChk.modInverse(n).multiply(eChk.add(dChk.multiply(rChk))).mod(n); - log("s :", hex(pkg3.s)); - log("s/CHK:", hex(sChk)); - - var sigChk = Bitcoin.ECDSA.serializeSig(rChk, sChk); - log("sig :", hex(sig)); - log("sig/CHK:", hex(sigChk)); - - var ver = Bitcoin.ECDSA.verify(hash, sig, pub); - log("ver :", ver); - log("ver/CHK:", Bitcoin.ECDSA.verify(hash, sigChk, pub)); - log("ver/CTL:", Bitcoin.ECDSA.verify(hash, Bitcoin.ECDSA.sign(hash, dChk), pub)); - ff("result", ver ? "SIGNATURE VALID" : "SIGNATURE INVALID"); - - var priv = Bitcoin.ECDSA.getBigRandom(n); - pub = G.multiply(priv).getEncoded(); - log("ver/GEN:", Bitcoin.ECDSA.verify(hash, Bitcoin.ECDSA.sign(hash, priv), pub)); -}; - -self.onmessage = function (event) { - try { - start(); - } catch(e) { - var stack = e.stack.replace(/^[^\(]+?[\n$]/gm, '') - .replace(/^\s+at\s+/gm, '') - .replace(/^Object.\s*\(/gm, '{anonymous}()@') - .split('\n'); - log(e+'\n'+stack); - } -};