@cloudflare/zkp-ecdsa
Version:
zkp-ecdsa: A Typescript Implementation of ZKAttest
198 lines • 5.09 kB
JavaScript
export function verifyPosRange(a, n) {
if (!(BigInt(0) <= a && a < n)) {
throw new Error('a not in range');
}
return true;
}
export function bitLen(n) {
return n.toString(2).length;
}
export function byteLen(n) {
return Math.ceil(bitLen(n) / 8);
}
export function isOdd(n) {
return n % BigInt(2) === BigInt(1);
}
export function isEven(n) {
return n % BigInt(2) === BigInt(0);
}
export function posMod(n, p) {
let r = n % p;
if (r < BigInt(0)) {
r = (r + p) % p;
}
return r;
}
export function expMod(n, e, p) {
if (e < BigInt(0)) {
throw new Error('neg expo');
}
let r = BigInt(1), q = n, k = e;
while (k > BigInt(0)) {
if (isOdd(k)) {
r = (r * q) % p;
}
q = (q * q) % p;
k = k / BigInt(2);
}
return r;
}
export function isNonNegative(n, p) {
const pMinus1div2 = (p - BigInt(1)) >> BigInt(1);
return 0 <= n && n <= pMinus1div2;
}
export function absolute(n, p) {
return isNonNegative(n, p) ? n : posMod(-n, p);
}
export function isSquare(n, p) {
const q = (p - BigInt(1)) >> BigInt(1);
return expMod(n, q, p) === BigInt(1);
}
export function invSqrtMod(n, p) {
const q = (p + BigInt(1)) >> BigInt(2);
return expMod(invEuclid(n, p), q, p);
}
export function invMod(n, p) {
return invEuclid(n, p);
}
function extendedEuclid(X, Y) {
let a = BigInt(1), b = BigInt(0), c = BigInt(0), d = BigInt(1), x = X, y = Y, t = BigInt(0);
while (y != BigInt(0)) {
const q = x / y;
a = a - c * q;
b = b - d * q;
x = x - q * y;
t = x;
x = y;
y = t;
t = a;
a = c;
c = t;
t = b;
b = d;
d = t;
}
return {
g: x,
a: a,
b: b,
};
}
export function invEuclid(t, N) {
const res = extendedEuclid(t, N);
let inv = res.a;
if (inv < 0) {
inv += N;
}
return inv;
}
export function toBytes(n, len) {
const maxBig = BigInt(1) << (BigInt(8) * BigInt(len));
if (!(len > 0 && BigInt(0) <= n && n < maxBig)) {
throw new Error("number doesn't fit in array");
}
const ret = new Uint8Array(len);
let t = n;
for (let i = 0; i < len; i++) {
const b = t & BigInt(255);
ret[len - 1 - i] = parseInt(b.toString());
t >>= BigInt(8);
}
return ret;
}
export async function hashNums(nums) {
const numNums = nums.length, data = [], enc = new TextEncoder();
let totBytes = 0;
for (let i = 0; i < numNums; i++) {
const numBytes = enc.encode(nums[i].toString());
totBytes += numBytes.byteLength;
data.push(numBytes);
}
const tbh = new Uint8Array(totBytes + 4 * numNums);
let index = 0;
for (let i = 0; i < numNums; i++) {
tbh[index++] = (data[i].byteLength >> 24) & 0xff;
tbh[index++] = (data[i].byteLength >> 16) & 0xff;
tbh[index++] = (data[i].byteLength >> 8) & 0xff;
tbh[index++] = data[i].byteLength & 0xff;
tbh.set(data[i], index);
index += data[i].byteLength;
}
const hash = await crypto.subtle.digest('SHA-256', tbh);
return fromBytes(new Uint8Array(hash.slice(0, 10)));
}
export function fromBytes(a) {
let k = BigInt(0);
for (const ai of a) {
k <<= BigInt(8);
k |= BigInt(ai);
}
return k;
}
export function rnd(n) {
const buffer = new Uint8Array(byteLen(n));
while (true) {
crypto.getRandomValues(buffer);
const ret = fromBytes(buffer);
if (ret < n) {
return ret;
}
}
}
export function rndRange(min, max) {
return rnd(max - min + BigInt(1)) + min;
}
export function isPrime(n, iterations = 7) {
if (n === BigInt(2) || n === BigInt(3)) {
return true;
}
if (isEven(n) || n < BigInt(2)) {
return false;
}
const nminusone = n - BigInt(1);
let s = 0, d = nminusone;
while (isEven(d)) {
d >>= BigInt(1);
s++;
}
let k = iterations;
WitnessLoop: do {
const base = rnd(n - BigInt(3)) + BigInt(2);
let x = expMod(base, d, n);
if (x === BigInt(1) || x === n - BigInt(1)) {
continue;
}
for (let i = s - 1; i >= 0; i--) {
x = x ** BigInt(2) % n;
if (x === BigInt(1)) {
return false;
}
if (x === n - BigInt(1)) {
continue WitnessLoop;
}
}
return false;
} while ((k -= 1));
return true;
}
export const serdeBigInt = {
isRequired: true,
serializer: function (v) {
let s = '0x';
if (v < BigInt(0)) {
v = -v;
s = '-' + s;
}
return s + v.toString(16);
},
deserializer: function (v) {
if (!v) {
throw new Error(`the field ${this.key} is required`);
}
if (v.charAt(0) === '-') {
return -BigInt(v.slice(1));
}
return BigInt(v);
},
};
//# sourceMappingURL=big.js.map