Skip to content

Instantly share code, notes, and snippets.

@CMCDragonkai
Created December 8, 2023 01:31
Show Gist options
  • Save CMCDragonkai/fb9ef04fe3359e100b0f2a0a775b7353 to your computer and use it in GitHub Desktop.
Save CMCDragonkai/fb9ef04fe3359e100b0f2a0a775b7353 to your computer and use it in GitHub Desktop.
Ed25519 Derive Public Key from Private Key
// Extracted from https://github.com/paulmillr/noble-ed25519/blob/main/index.ts
// This is a minimal implementation of taking a 32 byte (256 bit) private key and deriving the public key
const hashed = await crypto.subtle.digest('SHA-512', privateKey); // data is Uint8Array or ArrayBuffer
type Bytes = Uint8Array;
const head = hashed.slice(0, 32); // slice creates a copy, unlike subarray
head[0] &= 248; // Clamp bits: 0b1111_1000,
head[31] &= 127; // 0b0111_1111,
head[31] |= 64; // 0b0100_0000
const mod = (a: bigint, b = P) => { let r = a % b; return r >= 0n ? r : b + r; }; // mod division
const padh = (num: number | bigint, pad: number) => num.toString(16).padStart(pad, '0')
const b2h = (b: Bytes): string => Array.from(b).map(e => padh(e, 2)).join(''); // bytes to hex
const u8n = (data?: any) => new Uint8Array(data); // creates Uint8Array
const err = (m = ''): never => { throw new Error(m); }; // error helper, messes-up stack trace
const au8 = (a: unknown, l?: number): Bytes => // is Uint8Array (of specific length)
!(a instanceof Uint8Array) || (typeof l === 'number' && l > 0 && a.length !== l) ?
err('Uint8Array of valid length expected') : a;
const b2n_LE = (b: Bytes): bigint => BigInt('0x' + b2h(u8n(au8(b)).reverse())); // bytes LE to num
const N = 2n ** 252n + 27742317777372353535851937790883648493n; // curve's (group) order
const modL_LE = (hash: Bytes): bigint => mod(b2n_LE(hash), N); // modulo L; but little-endian
const scalar = modL_LE(head); // modular division over curve order
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment