bigint-pedersen
Version:
This library provides an implementation of Pedersen Commitments, a cryptographic technique widely used for creating non-interactive commitments with strong security properties like homomorphic addition, subtraction, and multiplication.
160 lines (159 loc) • 6.87 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const node_crypto_1 = __importDefault(require("node:crypto"));
// Default generators used for Pedersen commitments 2048 bits
const DEFAULT_GENERRATOR = {
p: 26809931509713726881929393934746194494398623340254603267344709419072315601942996679555540094216756355587236678233714540569702209430523989668695021813296604437890318304359788997756314485945859269125843479737462443604463218788381902399300855449399051037396322952886267185109258359551031852192926751402739626602876508869021121415839940413096111104357546678095781175009153955498075194018858765387827742979958735349118653246917604244624611525479854815634983202466018180004575713519521591696136708240811991182516464514622975980528861723581513241904617248996258383305659058767475100110699861201638082703862378707771683885043n,
g: 14694709048366479129464027221654552162231585341432931962377318999942025934847016287113843845082610438342648864596204292211352777789037554666373036583465555991725379195817880960645305237325952522104983034200148307024546428877657976287930346188512720597094142204247464293250761245519119779261723963273411146882744082830584412093129194118796879284756192200391645423685054939736140301881395757172570744218623286622834433154149349915432547599900923909164711329473795689863477689485764491526200309144296452310157008762664281605341910471190481559199002869295668843736566924026726713687853270832401989537050128451073524103513n,
h: 17765657596489991520675714263237901296293034056124164028633004389675332209996154354074769630786877525226009800162272189681669177169877971481595221679593410270888654816821965825594128768184992784842796717465561468554274819536435420541299288366957240732633657201822781445626492161271460415863949862742927192243587494385007340884507735680421045822199369716080930777005181586841317821777963051535892442802540356934090568526043857667411907529156846977201816424784744487202893103864075486759926017748571705077898635217290146984276232360005039792235459612088121077743383116662969823420991352344697105133486412456447643502096n
};
// Computes base^exponent % mod using fast modular exponentiation
function modExp(base, exponent, mod) {
let result = 1n;
base = base % mod;
while (exponent > 0n) {
if (exponent & 1n) { // If exponent is odd
result = (result * base) % mod;
}
exponent = exponent >>= 1n; // Divide exponent by 2
base = (base * base) % mod;
}
return result;
}
// Miller-Rabin Primality Test to check if number n is prime
function isPrimeMillerRabin(n, k = 100) {
if (n === 2n || n === 3n)
return true;
if (n < 2n || n % 2n === 0n)
return false;
// Write n - 1 as d * 2^r
let d = n - 1n;
let r = 0n;
while (d % 2n === 0n) {
d /= 2n;
r += 1n;
}
// Witness loop
for (let i = 0; i < k; i++) {
const a = 2n + BigInt(Math.floor(Math.random() * (Number(n - 4n))));
let x = modExp(a, d, n);
if (x === 1n || x === n - 1n)
continue;
let continueOuterLoop = false;
for (let j = 0n; j < r - 1n; j++) {
x = modExp(x, 2n, n);
if (x === n - 1n) {
continueOuterLoop = true;
break;
}
}
if (!continueOuterLoop)
return false;
}
return true;
}
// Generates a prime number with specified bit size
function generatePrime(bits) {
return new Promise((resolve, reject) => {
node_crypto_1.default.generatePrime(bits, { safe: true }, (err, prime) => {
if (err)
return reject(err);
resolve(BigInt("0x" + Buffer.from(prime).toString("hex")));
});
});
}
// Produces a random bigint less than a provided modulus
function generateRandomBigInt(modulus) {
const randomBytes = node_crypto_1.default.randomBytes(modulus.toString(2).length / 8);
let randomValue = BigInt('0x' + randomBytes.toString('hex'));
return randomValue % modulus;
}
// Generates a random value used for blinding a message
function randomBlinding(bytes = 32) {
const randomBytes = node_crypto_1.default.randomBytes(bytes);
let randomValue = BigInt('0x' + randomBytes.toString('hex'));
return randomValue;
}
// Chooses a safe generator for a given prime p
async function chooseSafeGenerator(p) {
let g;
do {
g = generateRandomBigInt(p);
} while (!isGenerator(g, p)); // Ensure g is a valid generator.
return g;
}
// Verifies if a given g is a generator for prime p
function isGenerator(g, p) {
// Ensures g^(p-1)/2 % p is not 1
const orderCondition = modExp(g, (p - 1n) / 2n, p);
return orderCondition !== 1n; // True if g is a safe generator
}
// Generates Pedersen commitment parameters
async function generator(bits = 2048) {
const p = await generatePrime(bits);
const g = await chooseSafeGenerator(p);
let h = generateRandomBigInt(p);
// Ensure h is distinct from g and not equal to 1
while (h === g || h === 1n) {
h = generateRandomBigInt(p);
}
return { p, g, h };
}
// Computes modular inverse of a number modulo p
function modInverse(a, p) {
let t = 0n;
let newT = 1n;
let r = p;
let newR = a;
while (newR !== 0n) {
const quotient = r / newR;
[t, newT] = [newT, t - quotient * newT];
[r, newR] = [newR, r - quotient * newR];
}
if (r > 1n) {
throw new Error(`${a} is not invertible`);
}
if (t < 0n) {
t = t + p;
}
return t;
}
// Creates a commitment for a message m with randomness r
function commitment(m, r, parans) {
if (m < 0n)
throw new Error(`m cannot be less than zero - ${m}`);
if (r < 0n)
throw new Error(`r cannot be less than zero - ${r}`);
const gm = modExp(parans.g, m, parans.p); // Compute g^m % p
const hr = modExp(parans.h, r, parans.p); // Compute h^r % p
const C = (gm * hr) % parans.p; // Resulting commitment
return C;
}
// Adds two commitments
function sum(C1, C2, parans) {
return (C1 * C2) % parans.p; // Sum of commitments is a modular multiplication
}
// Subtracts one commitment from another
function sub(C1, C2, parans) {
return (C1 * modInverse(C2, parans.p)) % parans.p; // Subtraction involves modular inverse
}
// Multiplies a commitment by a scalar
function multiply(C, scalar, parans) {
return modExp(C, scalar, parans.p); // Multiplication is a modular exponentiation
}
const pedersen = {
DEFAULT_GENERRATOR,
modExp,
modInverse,
randomBlinding,
isPrimeMillerRabin,
generator,
commitment,
sum,
sub,
multiply,
};
exports.default = pedersen;
;