@seda-protocol/secp256k1-vrf
Version:
A TypeScript implementation of Verifiable Random Functions (VRF) for secp256k1
118 lines • 3.33 kB
JavaScript
import { hmac } from "@noble/hashes/hmac";
import { sha256 } from "@noble/hashes/sha256";
// Secp256k1 curve order (n)
const SECP256K1_ORDER = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n;
/**
* Generates a deterministic nonce (ephemeral scalar k) using RFC 6979.
* @param secretKey The private key as bytes
* @param digest The message digest
* @returns The generated nonce as bytes
*/
export function generateNonce(secretKey, digest) {
// Convert secret key to bigint
let x;
if (typeof secretKey === "string") {
// Handle hex string
x = BigInt(`0x${secretKey.replace(/^0x/i, "")}`);
}
else if (typeof secretKey === "bigint") {
// Handle bigint
x = secretKey;
}
else {
// Handle Uint8Array or Buffer
x = bytesToBigInt(secretKey);
}
return generateSecret(SECP256K1_ORDER, x, digest);
}
/**
* Implementation of RFC 6979 nonce generation
* https://tools.ietf.org/html/rfc6979#section-3.2
*/
function generateSecret(order, x, digest) {
const qlen = bitLength(order);
const holen = digest.length;
const rolen = Math.ceil(qlen / 8);
// Initial data
const bx = Buffer.concat([int2octets(x, rolen), bits2octets(digest, order, qlen, rolen)]);
// Step B
let v = Buffer.alloc(holen, 0x01);
// Step C
let k = Buffer.alloc(holen, 0x00);
// Step D
k = hmac(sha256, k, Buffer.concat([v, Buffer.from([0x00]), bx]));
// Step E
v = hmac(sha256, k, v);
// Step F
k = hmac(sha256, k, Buffer.concat([v, Buffer.from([0x01]), bx]));
// Step G
v = hmac(sha256, k, v);
// Step H
while (true) {
// Step H1
let t = Buffer.alloc(0);
// Step H2
while (t.length < Math.ceil(qlen / 8)) {
v = Buffer.from(hmac(sha256, k, v));
t = Buffer.concat([t, v]);
}
// Step H3
const secret = bits2int(t, qlen);
if (secret > 0n && secret < order) {
return int2octets(secret, rolen);
}
k = hmac(sha256, k, Buffer.concat([v, Buffer.from([0x00])]));
v = hmac(sha256, k, v);
}
}
/**
* Convert bits to integer
* https://tools.ietf.org/html/rfc6979#section-2.3.2
*/
function bits2int(bytes, qlen) {
const vlen = bytes.length * 8;
let v = bytesToBigInt(bytes);
if (vlen > qlen) {
v = v >> BigInt(vlen - qlen);
}
return v;
}
/**
* Convert integer to octets
* https://tools.ietf.org/html/rfc6979#section-2.3.3
*/
function int2octets(v, rolen) {
const result = Buffer.alloc(rolen, 0);
let tempV = v;
for (let i = rolen - 1; i >= 0; i--) {
result[i] = Number(tempV & 0xffn);
tempV = tempV >> 8n;
}
return result;
}
/**
* Convert bits to octets
* https://tools.ietf.org/html/rfc6979#section-2.3.4
*/
function bits2octets(inp, q, qlen, rolen) {
const z1 = bits2int(inp, qlen);
const z2 = z1 - q;
if (z2 < 0n) {
return int2octets(z1, rolen);
}
return int2octets(z2, rolen);
}
/**
* Calculate bit length of a bigint
*/
function bitLength(n) {
return n.toString(2).length;
}
/**
* Convert bytes to bigint
*/
function bytesToBigInt(bytes) {
const hex = Buffer.from(bytes).toString("hex");
return BigInt(`0x${hex}`);
}
//# sourceMappingURL=nonce.js.map