Skip to content

Instantly share code, notes, and snippets.

@shovon
Last active June 23, 2022 22:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shovon/b05a998ab0557b290244cc4e3fcd2e13 to your computer and use it in GitHub Desktop.
Save shovon/b05a998ab0557b290244cc4e3fcd2e13 to your computer and use it in GitHub Desktop.
// secp256k1
import * as bigintConversion from "bigint-conversion";
function concatUint8Array(a: Uint8Array, b: Uint8Array): Uint8Array {
const merged = new Uint8Array(a.length + b.length);
merged.set(a);
merged.set(b, a.length);
return merged;
}
function randIntInRange(range: bigint): bigint {
const buf = bigintConversion.bigintToBuf(range, true) as ArrayBuffer;
const u8a = new Uint8Array(buf).slice(1);
const randVal = crypto.getRandomValues(u8a);
return bigintConversion.bufToBigint(
concatUint8Array(new Uint8Array([(Math.random() * (u8a[0] - 0b10000000)) | 0]), randVal)
);
}
function extendedGcd(
a: bigint,
b: bigint
): { result: bigint; x: bigint; y: bigint } {
if (a === 0n) {
return { result: b, x: 0n, y: 1n };
}
const { result, x: x1, y: y1 } = extendedGcd(b % a, a);
return { result, x: y1 - (b / a) * x1, y: x1 };
}
function fastModularInverse(a: bigint, m: bigint): bigint {
const { result: g, x } = extendedGcd(a, m);
if (g != 1n) {
throw new Error("Inverse does not exist!");
}
return ((x % m) + m) % m;
}
const n =
115792089237316195423570985008687907852837564279074904382605163141518161494337n;
const G = {
x: 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
y: 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
};
function sign(privKey: bigint, hash: bigint): { r: bigint; s: bigint } {
const k = randIntInRange(n);
const r = (k * G.x) % n;
const s = (fastModularInverse(k, n) * (hash + r * privKey)) % n;
return { r, s };
}
function verify(
pubKey: { x: bigint; y: bigint },
hash: bigint,
{ r, s }: { r: bigint; s: bigint }
): boolean {
const u1 = hash * fastModularInverse(s, n);
const u2 = r * fastModularInverse(s, n);
const x = u1 * G.x + u2 * pubKey.x;
return r % n === x % n;
}
const privKey = randIntInRange(n);
const pubKey = {
x: privKey * G.x,
y: privKey * G.y,
};
console.log(pubKey);
console.log("Computing");
let v = new Uint8Array(256 / 8);
v = crypto.getRandomValues(v);
const signature = sign(privKey, bigintConversion.bufToBigint(v));
console.log(verify(pubKey, bigintConversion.bufToBigint(v), signature));
export {};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment