This commit is contained in:
jude committed 2023-04-10 19:05:10 +01:00
1 parent 8c5b6dbac9
commit 1647615595
8 files changed
+154 -34

No files matched your search

+83 -27
View File
@@ -16,11 +16,11 @@ class Ciphertext {
let gm = (1n + key.n * plainText) % key.n2;
// Compute g^m r^n from crt.
this.cyphertext = (gm * mod_exp(r, key.n, key.n2)) % key.n2;
this.cipherText = (gm * mod_exp(r, key.n, key.n2)) % key.n2;
// Force into range.
while (this.cyphertext < 0n) {
this.cyphertext += key.n2;
while (this.cipherText < 0n) {
this.cipherText += key.n2;
}
this.r = r;
@@ -31,30 +31,69 @@ class Ciphertext {
}
update(c) {
this.cyphertext = (this.cyphertext * c.cyphertext) % this.pubKey.n2;
this.cipherText = (this.cipherText * c.cipherText) % this.pubKey.n2;
this.r = (this.r * c.r) % this.pubKey.n2;
this.plainText += c.plainText;
// Force into range
while (this.cyphertext < 0n) {
this.cyphertext += this.pubKey.n2;
while (this.cipherText < 0n) {
this.cipherText += this.pubKey.n2;
}
}
toString() {
return "0x" + this.cyphertext.toString(16);
return "0x" + this.cipherText.toString(16);
}
prove() {
return new ZeroProofSessionProver(this);
return new ValueProofSessionProver(this);
}
asReadOnlyCyphertext() {
return new ReadOnlyCiphertext(this.pubKey, this.cyphertext);
// Construct a non-interactive proof
proveNI() {
let rp = cryptoRandom(4096);
while (rp >= this.pubKey.n) {
rp = cryptoRandom(4096);
}
let a = mod_exp(rp, this.pubKey.n, this.pubKey.n2);
let hasher = new jsSHA("SHAKE256", "HEX");
let plainText = this.plainText.toString(16);
if (plainText.length % 2 !== 0) {
plainText = "0" + plainText;
}
let aStr = a.toString(16);
if (aStr.length % 2 !== 0) {
aStr = "0" + aStr;
}
hasher.update(this.pubKey.g.toString(16));
hasher.update(plainText);
hasher.update(aStr);
let challenge = BigInt("0x" + hasher.getHash("HEX", { outputLen: 2048 }));
return {
plainText: "0x" + this.plainText.toString(16),
a: "0x" + a.toString(16),
challenge: "0x" + challenge.toString(16),
proof:
"0x" +
(
((rp % this.pubKey.n) * mod_exp(this.r, challenge, this.pubKey.n)) %
this.pubKey.n
).toString(16),
};
}
asReadOnlyCiphertext() {
return new ReadOnlyCiphertext(this.pubKey, this.cipherText);
}
}
class ZeroProofSessionProver {
class ValueProofSessionProver {
constructor(cipherText) {
this.cipherText = cipherText;
@@ -82,46 +121,63 @@ class ZeroProofSessionProver {
asVerifier() {
return this.cipherText
.asReadOnlyCyphertext()
.asReadOnlyCiphertext()
.prove(this.cipherText.plainText, this.noise());
}
}
window.Cyphertext = Ciphertext;
window.Ciphertext = Ciphertext;
export class ReadOnlyCiphertext {
constructor(key, cyphertext) {
this.cyphertext = cyphertext;
constructor(key, cipherText) {
this.cipherText = cipherText;
this.pubKey = key;
this.readOnly = true;
}
update(c) {
this.cyphertext = (this.cyphertext * c.cyphertext) % this.pubKey.n2;
this.cipherText = (this.cipherText * c.cipherText) % this.pubKey.n2;
// Force into range
while (this.cyphertext < 0n) {
this.cyphertext += this.pubKey.n2;
while (this.cipherText < 0n) {
this.cipherText += this.pubKey.n2;
}
}
prove(plainText, a) {
return new ZeroProofSessionVerifier(this, plainText, a);
return new ValueProofSessionVerifier(this, plainText, a);
}
verifyNI(statement) {
let verifier = new ValueProofSessionVerifier(
this,
BigInt(statement.plainText),
BigInt(statement.a),
BigInt(statement.challenge)
);
return verifier.verify(BigInt(statement.proof));
}
clone() {
return new ReadOnlyCiphertext(this.pubKey, this.cyphertext);
return new ReadOnlyCiphertext(this.pubKey, this.cipherText);
}
}
class ZeroProofSessionVerifier {
constructor(cipherText, plainText, a) {
class ValueProofSessionVerifier {
constructor(cipherText, plainText, a, challenge) {
// Clone, otherwise the update below will mutate the original value
this.cipherText = cipherText.clone();
this.cipherText.update(this.cipherText.pubKey.encrypt(-1n * plainText, 1n));
// Shift the challenge down by 1 to ensure it is smaller than either prime factor.
this.challenge = cryptoRandom(2048) << 1n;
if (challenge === undefined) {
// Shift the challenge down by 1 to ensure it is smaller than either prime factor.
this.challenge = cryptoRandom(2048) << 1n;
} else {
this.challenge = challenge;
}
this.a = a;
this.plainText = plainText;
@@ -130,14 +186,14 @@ class ZeroProofSessionVerifier {
verify(proof) {
// check coprimality
if (gcd(proof, this.cipherText.pubKey.n) !== 1n) return -1;
if (gcd(this.cipherText.cyphertext, this.cipherText.pubKey.n) !== 1n) return -2;
if (gcd(this.cipherText.cipherText, this.cipherText.pubKey.n) !== 1n) return -2;
if (gcd(this.a, this.cipherText.pubKey.n) !== 1n) return -3;
// check exp
return mod_exp(proof, this.cipherText.pubKey.n, this.cipherText.pubKey.n2) ===
(this.a *
mod_exp(
this.cipherText.cyphertext,
this.cipherText.cipherText,
this.challenge,
this.cipherText.pubKey.n2
)) %
@@ -147,7 +203,7 @@ class ZeroProofSessionVerifier {
}
}
window.ReadOnlyCyphertext = ReadOnlyCiphertext;
window.ReadOnlyCiphertext = ReadOnlyCiphertext;
export class PaillierPubKey {
constructor(n) {
+1
View File
@@ -5,6 +5,7 @@ import { Packet } from "./packet.js";
import { Game } from "./game.js";
import { Region } from "./map.js";
import "./dom.js";
import "./proofs.js";
export const ID = window.crypto.randomUUID();
export const game = new Game();
+17
View File
@@ -0,0 +1,17 @@
function cryptoShuffle(l) {
for (let i = 0; i < l.length - 1; i++) {}
}
window.cryptoShuffle = cryptoShuffle;
function proveRegions(regions) {
// Construct prover coins
let regionNames = Object.keys(regions.keys());
let psi = [regionNames];
// Construct verifier coins
let hasher = new jsSHA("SHA3-256", "TEXT");
hasher.update(JSON.stringify(regions));
// Construct prover proofs
}
+21
View File
@@ -0,0 +1,21 @@
/**
* A JavaScript implementation of the SHA family of hashes - defined in FIPS PUB 180-4, FIPS PUB 202,
* and SP 800-185 - as well as the corresponding HMAC implementation as defined in FIPS PUB 198-1.
*
* Copyright 2008-2022 Brian Turek, 1998-2009 Paul Johnston & Contributors
* Distributed under the BSD License
* See http://caligatio.github.com/jsSHA/ for more information
*
* Two ECMAScript polyfill functions carry the following license:
*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
* MERCHANTABLITY OR NON-INFRINGEMENT.
*
* See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
*/
!function(r,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(r="undefined"!=typeof globalThis?globalThis:r||self).jsSHA=t()}(this,(function(){"use strict";var r=function(t,n){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,t){r.__proto__=t}||function(r,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(r[n]=t[n])},r(t,n)};var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",n="ARRAYBUFFER not supported by this environment",e="UINT8ARRAY not supported by this environment";function i(r,t,n,e){var i,o,u,s=t||[0],f=(n=n||0)>>>3,a=-1===e?3:0;for(i=0;i<r.length;i+=1)o=(u=i+f)>>>2,s.length<=o&&s.push(0),s[o]|=r[i]<<8*(a+e*(u%4));return{value:s,binLen:8*r.length+n}}function o(r,o,u){switch(o){case"UTF8":case"UTF16BE":case"UTF16LE":break;default:throw new Error("encoding must be UTF8, UTF16BE, or UTF16LE")}switch(r){case"HEX":return function(r,t,n){return function(r,t,n,e){var i,o,u,s;if(0!=r.length%2)throw new Error("String of HEX type must be in byte increments");var f=t||[0],a=(n=n||0)>>>3,h=-1===e?3:0;for(i=0;i<r.length;i+=2){if(o=parseInt(r.substr(i,2),16),isNaN(o))throw new Error("String of HEX type contains invalid characters");for(u=(s=(i>>>1)+a)>>>2;f.length<=u;)f.push(0);f[u]|=o<<8*(h+e*(s%4))}return{value:f,binLen:4*r.length+n}}(r,t,n,u)};case"TEXT":return function(r,t,n){return function(r,t,n,e,i){var o,u,s,f,a,h,c,w,v=0,l=n||[0],E=(e=e||0)>>>3;if("UTF8"===t)for(c=-1===i?3:0,s=0;s<r.length;s+=1)for(u=[],128>(o=r.charCodeAt(s))?u.push(o):2048>o?(u.push(192|o>>>6),u.push(128|63&o)):55296>o||57344<=o?u.push(224|o>>>12,128|o>>>6&63,128|63&o):(s+=1,o=65536+((1023&o)<<10|1023&r.charCodeAt(s)),u.push(240|o>>>18,128|o>>>12&63,128|o>>>6&63,128|63&o)),f=0;f<u.length;f+=1){for(a=(h=v+E)>>>2;l.length<=a;)l.push(0);l[a]|=u[f]<<8*(c+i*(h%4)),v+=1}else for(c=-1===i?2:0,w="UTF16LE"===t&&1!==i||"UTF16LE"!==t&&1===i,s=0;s<r.length;s+=1){for(o=r.charCodeAt(s),!0===w&&(o=(f=255&o)<<8|o>>>8),a=(h=v+E)>>>2;l.length<=a;)l.push(0);l[a]|=o<<8*(c+i*(h%4)),v+=2}return{value:l,binLen:8*v+e}}(r,o,t,n,u)};case"B64":return function(r,n,e){return function(r,n,e,i){var o,u,s,f,a,h,c=0,w=n||[0],v=(e=e||0)>>>3,l=-1===i?3:0,E=r.indexOf("=");if(-1===r.search(/^[a-zA-Z0-9=+/]+$/))throw new Error("Invalid character in base-64 string");if(r=r.replace(/=/g,""),-1!==E&&E<r.length)throw new Error("Invalid '=' found in base-64 string");for(o=0;o<r.length;o+=4){for(f=r.substr(o,4),s=0,u=0;u<f.length;u+=1)s|=t.indexOf(f.charAt(u))<<18-6*u;for(u=0;u<f.length-1;u+=1){for(a=(h=c+v)>>>2;w.length<=a;)w.push(0);w[a]|=(s>>>16-8*u&255)<<8*(l+i*(h%4)),c+=1}}return{value:w,binLen:8*c+e}}(r,n,e,u)};case"BYTES":return function(r,t,n){return function(r,t,n,e){var i,o,u,s,f=t||[0],a=(n=n||0)>>>3,h=-1===e?3:0;for(o=0;o<r.length;o+=1)i=r.charCodeAt(o),u=(s=o+a)>>>2,f.length<=u&&f.push(0),f[u]|=i<<8*(h+e*(s%4));return{value:f,binLen:8*r.length+n}}(r,t,n,u)};case"ARRAYBUFFER":try{new ArrayBuffer(0)}catch(r){throw new Error(n)}return function(r,t,n){return function(r,t,n,e){return i(new Uint8Array(r),t,n,e)}(r,t,n,u)};case"UINT8ARRAY":try{new Uint8Array(0)}catch(r){throw new Error(e)}return function(r,t,n){return i(r,t,n,u)};default:throw new Error("format must be HEX, TEXT, B64, BYTES, ARRAYBUFFER, or UINT8ARRAY")}}function u(r,i,o,u){switch(r){case"HEX":return function(r){return function(r,t,n,e){var i,o,u="0123456789abcdef",s="",f=t/8,a=-1===n?3:0;for(i=0;i<f;i+=1)o=r[i>>>2]>>>8*(a+n*(i%4)),s+=u.charAt(o>>>4&15)+u.charAt(15&o);return e.outputUpper?s.toUpperCase():s}(r,i,o,u)};case"B64":return function(r){return function(r,n,e,i){var o,u,s,f,a,h="",c=n/8,w=-1===e?3:0;for(o=0;o<c;o+=3)for(f=o+1<c?r[o+1>>>2]:0,a=o+2<c?r[o+2>>>2]:0,s=(r[o>>>2]>>>8*(w+e*(o%4))&255)<<16|(f>>>8*(w+e*((o+1)%4))&255)<<8|a>>>8*(w+e*((o+2)%4))&255,u=0;u<4;u+=1)h+=8*o+6*u<=n?t.charAt(s>>>6*(3-u)&63):i.b64Pad;return h}(r,i,o,u)};case"BYTES":return function(r){return function(r,t,n){var e,i,o="",u=t/8,s=-1===n?3:0;for(e=0;e<u;e+=1)i=r[e>>>2]>>>8*(s+n*(e%4))&255,o+=String.fromCharCode(i);return o}(r,i,o)};case"ARRAYBUFFER":try{new ArrayBuffer(0)}catch(r){throw new Error(n)}return function(r){return function(r,t,n){var e,i=t/8,o=new ArrayBuffer(i),u=new Uint8Array(o),s=-1===n?3:0;for(e=0;e<i;e+=1)u[e]=r[e>>>2]>>>8*(s+n*(e%4))&255;return o}(r,i,o)};case"UINT8ARRAY":try{new Uint8Array(0)}catch(r){throw new Error(e)}return function(r){return function(r,t,n){var e,i=t/8,o=-1===n?3:0,u=new Uint8Array(i);for(e=0;e<i;e+=1)u[e]=r[e>>>2]>>>8*(o+n*(e%4))&255;return u}(r,i,o)};default:throw new Error("format must be HEX, B64, BYTES, ARRAYBUFFER, or UINT8ARRAY")}}var s=4294967296,f="Cannot set numRounds with MAC";function a(r,t){var n,e,i=r.binLen>>>3,o=t.binLen>>>3,u=i<<3,s=4-i<<3;if(i%4!=0){for(n=0;n<o;n+=4)e=i+n>>>2,r.value[e]|=t.value[n>>>2]<<u,r.value.push(0),r.value[e+1]|=t.value[n>>>2]>>>s;return(r.value.length<<2)-4>=o+i&&r.value.pop(),{value:r.value,binLen:r.binLen+t.bLine truncated