PHP WebShell
Текущая директория: /opt/BitGoJS/node_modules/paillier-bigint/dist/esm
Просмотр файла: index.node.js
import * as bcu from 'bigint-crypto-utils';
/**
* Class for a Paillier public key
*/
class PublicKey {
/**
* Creates an instance of class PublicKey
* @param n - The public modulo
* @param g - The public generator
*/
constructor(n, g) {
this.n = n;
this._n2 = this.n ** 2n; // cache n^2
this.g = g;
}
/**
* Get the bit length of the public modulo
* @returns The bit length of the public modulo
*/
get bitLength() {
return bcu.bitLength(this.n);
}
/**
* Paillier public-key encryption
*
* @param m - A bigint representation of a plaintext message
* @param r - The random integer factor for encryption. By default is a random in (1,n)
*
* @returns The encryption of m with this public key
*/
encrypt(m, r) {
if (r === undefined) {
do {
r = bcu.randBetween(this.n);
} while (bcu.gcd(r, this.n) !== 1n);
}
return (bcu.modPow(this.g, m, this._n2) * bcu.modPow(r, this.n, this._n2)) % this._n2;
}
/**
* Homomorphic addition
*
* @param ciphertexts - n >= 2 ciphertexts (c_1,..., c_n) that are the encryption of (m_1, ..., m_n) with this public key
*
* @returns The encryption of (m_1 + ... + m_n) with this public key
*/
addition(...ciphertexts) {
return ciphertexts.reduce((sum, next) => sum * next % this._n2, 1n);
}
/**
* Pseudo-homomorphic addition of plaintext to chipertext
*
* @param ciphertext - an encryption of m1 with this public key
* @param plaintexts - 1 or more plaintexts (m_2, ..., m_n)
*
* @returns The encryption of (m_1 + ... + m_n) with this public key
*/
plaintextAddition(ciphertext, ...plaintexts) {
return plaintexts.reduce((sum, next) => sum * bcu.modPow(this.g, next, this._n2) % this._n2, ciphertext);
}
/**
* Pseudo-homomorphic Paillier multiplication
*
* @param {bigint} c - a number m encrypted with this public key
* @param {bigint | number} k - either a bigint or a number
*
* @returns {bigint} - the encryption of k·m with this public key
*/
multiply(c, k) {
return bcu.modPow(c, k, this._n2);
}
}
/**
* Class for Paillier private keys.
*/
class PrivateKey {
/**
* Creates an instance of class PrivateKey
*
* @param lambda
* @param mu
* @param publicKey
* @param p - a big prime
* @param q- a big prime
*/
constructor(lambda, mu, publicKey, p, q) {
this.lambda = lambda;
this.mu = mu;
this._p = p;
this._q = q;
this.publicKey = publicKey;
}
/**
* Get the bit length of the public modulo
* @returns The bit length of the public modulo
*/
get bitLength() {
return bcu.bitLength(this.publicKey.n);
}
/**
* Get the public modulo n=p·q
* @returns The public modulo n=p·q
*/
get n() {
return this.publicKey.n;
}
/**
* Paillier private-key decryption
*
* @param c - A bigint encrypted with the public key
*
* @returns The decryption of c with this private key
*/
decrypt(c) {
return (L(bcu.modPow(c, this.lambda, this.publicKey._n2), this.publicKey.n) * this.mu) % this.publicKey.n;
}
/**
* Recover the random factor used for encrypting a message with the complementary public key.
* The recovery function only works if the public key generator g was using the simple variant
* g = 1 + n
* It is also necessary to know p and q (usually stored in the private key)
*
* @param c - The encryption using the public of message m with random factor r
*
* @returns The random factor (mod n)
*
* @throws {RangeError}
* Cannot recover the random factor if publicKey.g != publicKey.n + 1. You should generate yout keys using the simple variant, e.g. generateRandomKeys(3072, true) )
*
* @throws {Error}
* Cannot get random factor without knowing p and q
*
*/
getRandomFactor(c) {
if (this.publicKey.g !== this.n + 1n)
throw RangeError('Cannot recover the random factor if publicKey.g != publicKey.n + 1. You should generate yout keys using the simple variant, e.g. generateRandomKeys(3072, true) )');
if (this._p === undefined || this._q === undefined) {
throw Error('Cannot get random factor without knowing p and q');
}
const m = this.decrypt(c);
const phi = (this._p - 1n) * (this._q - 1n);
const nInvModPhi = bcu.modInv(this.n, phi);
const c1 = c * (1n - m * this.n) % this.publicKey._n2;
return bcu.modPow(c1, nInvModPhi, this.n);
}
}
function L(a, n) {
return (a - 1n) / n;
}
/**
* Generates a pair private, public key for the Paillier cryptosystem.
*
* @param bitlength - The bit length of the public modulo
* @param simplevariant - Use the simple variant to compute the generator (g=n+1). This is REQUIRED if you want to be able to recover the random integer factor used when encrypting with the public key
*
* @returns A promise that resolves to a {@link KeyPair} of public, private keys
*/
async function generateRandomKeys(bitlength = 3072, simpleVariant = false) {
let p, q, n, g, lambda, mu;
// if p and q are bitLength/2 long -> 2**(bitLength - 2) <= n < 2**(bitLength)
do {
p = await bcu.prime(Math.floor(bitlength / 2) + 1);
q = await bcu.prime(Math.floor(bitlength / 2));
n = p * q;
} while (q === p || bcu.bitLength(n) !== bitlength);
if (simpleVariant) {
// If using p,q of equivalent length, a simpler variant of the key
// generation steps would be to set
// g=n+1, lambda=(p-1)(q-1), mu=lambda.invertm(n)
g = n + 1n;
lambda = (p - 1n) * (q - 1n);
mu = bcu.modInv(lambda, n);
}
else {
const n2 = n ** 2n;
g = getGenerator(n, n2);
lambda = bcu.lcm(p - 1n, q - 1n);
mu = bcu.modInv(L(bcu.modPow(g, lambda, n2), n), n);
}
const publicKey = new PublicKey(n, g);
const privateKey = new PrivateKey(lambda, mu, publicKey, p, q);
return { publicKey, privateKey };
}
/**
* Generates a pair private, public key for the Paillier cryptosystem in synchronous mode.
* Synchronous mode is NOT RECOMMENDED since it won't use workers and thus it'll be slower and may freeze thw window in browser's javascript.
*
* @param bitlength - The bit length of the public modulo
* @param simplevariant - Use the simple variant to compute the generator (g=n+1)
*
* @returns A pair of public, private keys
*/
function generateRandomKeysSync(bitlength = 3072, simpleVariant = false) {
let p, q, n, g, lambda, mu;
// if p and q are bitLength/2 long -> 2**(bitLength - 2) <= n < 2**(bitLength)
do {
p = bcu.primeSync(Math.floor(bitlength / 2) + 1);
q = bcu.primeSync(Math.floor(bitlength / 2));
n = p * q;
} while (q === p || bcu.bitLength(n) !== bitlength);
if (simpleVariant) {
// If using p,q of equivalent length, a simpler variant of the key
// generation steps would be to set
// g=n+1, lambda=(p-1)(q-1), mu=lambda.invertm(n)
g = n + 1n;
lambda = (p - 1n) * (q - 1n);
mu = bcu.modInv(lambda, n);
}
else {
const n2 = n ** 2n;
g = getGenerator(n, n2);
lambda = bcu.lcm(p - 1n, q - 1n);
mu = bcu.modInv(L(bcu.modPow(g, lambda, n2), n), n);
}
const publicKey = new PublicKey(n, g);
const privateKey = new PrivateKey(lambda, mu, publicKey, p, q);
return { publicKey, privateKey };
}
function getGenerator(n, n2) {
const alpha = bcu.randBetween(n);
const beta = bcu.randBetween(n);
return ((alpha * n + 1n) * bcu.modPow(beta, n, n2)) % n2;
}
export { PrivateKey, PublicKey, generateRandomKeys, generateRandomKeysSync };
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXgubm9kZS5qcyIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3RzL1B1YmxpY0tleS50cyIsIi4uLy4uL3NyYy90cy9Qcml2YXRlS2V5LnRzIiwiLi4vLi4vc3JjL3RzL2dlbmVyYXRlUmFuZG9tS2V5cy50cyJdLCJzb3VyY2VzQ29udGVudCI6bnVsbCwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFFQTs7O01BR3FCLFNBQVM7Ozs7OztJQVc1QixZQUFhLENBQVMsRUFBRSxDQUFTO1FBQy9CLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFBO1FBQ1YsSUFBSSxDQUFDLEdBQUcsR0FBRyxJQUFJLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQTtRQUN2QixJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQTtLQUNYOzs7OztJQU1ELElBQUksU0FBUztRQUNYLE9BQU8sR0FBRyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUE7S0FDN0I7Ozs7Ozs7OztJQVVELE9BQU8sQ0FBRSxDQUFTLEVBQUUsQ0FBVTtRQUM1QixJQUFJLENBQUMsS0FBSyxTQUFTLEVBQUU7WUFDbkIsR0FBRztnQkFDRCxDQUFDLEdBQUcsR0FBRyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUE7YUFDNUIsUUFBUSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFDO1NBQ3BDO1FBQ0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLElBQUksQ0FBQyxHQUFHLENBQUE7S0FDdEY7Ozs7Ozs7O0lBU0QsUUFBUSxDQUFFLEdBQUcsV0FBMEI7UUFDckMsT0FBTyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLElBQUksS0FBSyxHQUFHLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUE7S0FDcEU7Ozs7Ozs7OztJQVVELGlCQUFpQixDQUFFLFVBQWtCLEVBQUUsR0FBRyxVQUF5QjtRQUNqRSxPQUFPLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsSUFBSSxLQUFLLEdBQUcsR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxDQUFBO0tBQ3pHOzs7Ozs7Ozs7SUFVRCxRQUFRLENBQUUsQ0FBUyxFQUFFLENBQWdCO1FBQ25DLE9BQU8sR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQTtLQUNsQzs7O0FDN0VIOzs7TUFHcUIsVUFBVTs7Ozs7Ozs7OztJQWdCN0IsWUFBYSxNQUFjLEVBQUUsRUFBVSxFQUFFLFNBQW9CLEVBQUUsQ0FBVSxFQUFFLENBQVU7UUFDbkYsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUE7UUFDcEIsSUFBSSxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUE7UUFDWixJQUFJLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQTtRQUNYLElBQUksQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFBO1FBQ1gsSUFBSSxDQUFDLFNBQVMsR0FBRyxTQUFTLENBQUE7S0FDM0I7Ozs7O0lBTUQsSUFBSSxTQUFTO1FBQ1gsT0FBTyxHQUFHLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUE7S0FDdkM7Ozs7O0lBTUQsSUFBSSxDQUFDO1FBQ0gsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQTtLQUN4Qjs7Ozs7Ozs7SUFTRCxPQUFPLENBQUUsQ0FBUztRQUNoQixPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxFQUFFLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUE7S0FDMUc7Ozs7Ozs7Ozs7Ozs7Ozs7OztJQW1CRCxlQUFlLENBQUUsQ0FBUztRQUN4QixJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxLQUFLLElBQUksQ0FBQyxDQUFDLEdBQUcsRUFBRTtZQUFFLE1BQU0sVUFBVSxDQUFDLG1LQUFtSyxDQUFDLENBQUE7UUFDM04sSUFBSSxJQUFJLENBQUMsRUFBRSxLQUFLLFNBQVMsSUFBSSxJQUFJLENBQUMsRUFBRSxLQUFLLFNBQVMsRUFBRTtZQUNsRCxNQUFNLEtBQUssQ0FBQyxrREFBa0QsQ0FBQyxDQUFBO1NBQ2hFO1FBQ0QsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQTtRQUN6QixNQUFNLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRSxLQUFLLElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUE7UUFDM0MsTUFBTSxVQUFVLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFBO1FBQzFDLE1BQU0sRUFBRSxHQUFHLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQTtRQUNyRCxPQUFPLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxFQUFFLFVBQVUsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUE7S0FDMUM7Q0FDRjtTQUVlLENBQUMsQ0FBRSxDQUFTLEVBQUUsQ0FBUztJQUNyQyxPQUFPLENBQUMsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUE7QUFDckI7O0FDaEZBOzs7Ozs7OztBQVFPLGVBQWUsa0JBQWtCLENBQUUsWUFBb0IsSUFBSSxFQUFFLGdCQUF5QixLQUFLO0lBQ2hHLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLE1BQU0sRUFBRSxFQUFFLENBQUE7O0lBRTFCLEdBQUc7UUFDRCxDQUFDLEdBQUcsTUFBTSxHQUFHLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFBO1FBQ2xELENBQUMsR0FBRyxNQUFNLEdBQUcsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQTtRQUM5QyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQTtLQUNWLFFBQVEsQ0FBQyxLQUFLLENBQUMsSUFBSSxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxLQUFLLFNBQVMsRUFBQztJQUVuRCxJQUFJLGFBQWEsRUFBRTs7OztRQUlqQixDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQTtRQUNWLE1BQU0sR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFBO1FBQzVCLEVBQUUsR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQTtLQUMzQjtTQUFNO1FBQ0wsTUFBTSxFQUFFLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQTtRQUNsQixDQUFDLEdBQUcsWUFBWSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQTtRQUN2QixNQUFNLEdBQUcsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQTtRQUNoQyxFQUFFLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsTUFBTSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFBO0tBQ3BEO0lBRUQsTUFBTSxTQUFTLEdBQUcsSUFBSSxTQUFTLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFBO0lBQ3JDLE1BQU0sVUFBVSxHQUFHLElBQUksVUFBVSxDQUFDLE1BQU0sRUFBRSxFQUFFLEVBQUUsU0FBUyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQTtJQUM5RCxPQUFPLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxDQUFBO0FBQ2xDLENBQUM7QUFFRDs7Ozs7Ozs7O1NBU2dCLHNCQUFzQixDQUFFLFlBQW9CLElBQUksRUFBRSxnQkFBeUIsS0FBSztJQUM5RixJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxNQUFNLEVBQUUsRUFBRSxDQUFBOztJQUUxQixHQUFHO1FBQ0QsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUE7UUFDaEQsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQTtRQUM1QyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQTtLQUNWLFFBQVEsQ0FBQyxLQUFLLENBQUMsSUFBSSxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxLQUFLLFNBQVMsRUFBQztJQUVuRCxJQUFJLGFBQWEsRUFBRTs7OztRQUlqQixDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQTtRQUNWLE1BQU0sR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFBO1FBQzVCLEVBQUUsR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQTtLQUMzQjtTQUFNO1FBQ0wsTUFBTSxFQUFFLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQTtRQUNsQixDQUFDLEdBQUcsWUFBWSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQTtRQUN2QixNQUFNLEdBQUcsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQTtRQUNoQyxFQUFFLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsTUFBTSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFBO0tBQ3BEO0lBRUQsTUFBTSxTQUFTLEdBQUcsSUFBSSxTQUFTLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFBO0lBQ3JDLE1BQU0sVUFBVSxHQUFHLElBQUksVUFBVSxDQUFDLE1BQU0sRUFBRSxFQUFFLEVBQUUsU0FBUyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQTtJQUM5RCxPQUFPLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxDQUFBO0FBQ2xDLENBQUM7QUFFRCxTQUFTLFlBQVksQ0FBRSxDQUFTLEVBQUUsRUFBVTtJQUMxQyxNQUFNLEtBQUssR0FBRyxHQUFHLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFBO0lBQ2hDLE1BQU0sSUFBSSxHQUFHLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUE7SUFDL0IsT0FBTyxDQUFDLENBQUMsS0FBSyxHQUFHLENBQUMsR0FBRyxFQUFFLElBQUksR0FBRyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQTtBQUMxRDs7OzsifQ==
Выполнить команду
Для локальной разработки. Не используйте в интернете!