Skip to content

Instantly share code, notes, and snippets.

View random-range.js
function calculateParameters(range) {
let bitsNeeded = 0;
let bytesNeeded = 0;
let mask = 1;
while (range > 0) {
if (bitsNeeded % 8 === 0) bytesNeeded += 1;
bitsNeeded += 1;
mask = mask << 1 | 1; /* 0x00001111 -> 0x00011111 */
range = range >>> 1; /* 0x01000000 -> 0x00100000 */
}
@paulmillr
paulmillr / metamask-sign.md
Last active September 10, 2023 13:36
Tracing cryptography in Metamask dependencies
View metamask-sign.md

Tracing cryptography in Metamask dependencies

Metamask uses noble for low-level cryptography operations, such as signature creation. The audit path as per Sep 2023, where every item is name of NPM package:

flowchart TD;
    MM[metamask-extension] -->|imports KeyringController| MMKC["@metamask/keyring-controller"];
    MMKC -->|imports HDKeyring| MMHD["@metamask/eth-hd-keyring"];
 MMKC --&gt;|imports SimpleKeyring| MMSK["@metamask/eth-simple-keyring"];
@paulmillr
paulmillr / noble-vs-elliptic.js
Last active July 26, 2023 08:29
Timing differences between different keys in noble and elliptic
View noble-vs-elliptic.js
import { secp256k1 } from '@noble/curves/secp256k1';
import elliptic from 'elliptic';
import { mark } from 'micro-bmark';
const EC = elliptic.ec;
(async () => {
var ec = new EC('secp256k1');
const a = '0000000000000000000000000000000000000000000000000000000000000003';
const b = '3000000000000000000000000000000000000000000000000000000000000000';
@paulmillr
paulmillr / hybrid-pkg.md
Created March 27, 2023 14:32
Why writing hybrid Common.js + ESM NPM packages is hard
View hybrid-pkg.md
  • BigInt literals are not supported in React Native 0.70 (current as per Feb 2023)
  • ESM (ECMAScript modules) are not supported in Electron, Jest
    • Electron needs pre-compilation step aka bundler
    • Jest has experimental esm flag, also can be replaced with micro-should
  • Common.js modules (legacy node.js modules) are not supported in browsers, Deno
    • Browsers can be worked around with UMD wrapper
      • Doesn’t play well with ESM in-browser imports
  • Import issues
    • file a.ts imports b.ts
  • .ts imports are not allowed in js/node/browser
@paulmillr
paulmillr / jacobi.js
Created March 3, 2023 00:52
jacobi symbol for bigints
View jacobi.js
function jacobi(a, n) {
if (n <= 0n) throw new Error('n must be positive integer');
if (n % 2n === 0n) throw new Error('n must be odd');
a %= n;
let result = 1;
while (a !== 0n) {
while (a % 2n === 0n) {
a /= 2n;
let n_mod_8 = n % 8n;
if (n_mod_8 === 3n || n_mod_8 === 5n) {
View strauss-shamir.js
multiplyAndAddUnsafe(Q: ProjectivePoint, a: bigint, b: bigint): ProjectivePoint | undefined {
// R=R*2+P //bits from a,b = 1,0
// R=R*2 //bits from a,b = 0,0
// R=R*2+Q //bits from a,b = 0,1
// R=R*2+P+Q //bits from a,b = 1,1
const G: ProjectivePoint = this;
const spl = (a: bigint) => a.toString(2).padStart(max, '0').split('').map(i => Number(i));
const max = Math.max(ut.bitLen(a), ut.bitLen(b));
const aBits = spl(a);
const bBits = spl(b);
View exports-package-json.js
const files = `
a.ts
b.ts`.trim().split('\n');
files.forEach(file => {
file = file.replace(/\.\w+$/, '')
console.log(`
"./${file}": {
"types": "./lib/${file}.d.ts",
"import": "./lib/esm/${file}.js",
View micro-rlp.ts
import * as P from 'micro-packed';
export type Input = string | number | Uint8Array | bigint | List | null;
export type List = Input[];
// length: first 3 bit !== 111 ? 6 bit length : 3bit lenlen
const rlpLen = () =>
P.wrap({
encodeStream(w: P.Writer, value: number) {
if (value < 56) return w.bits(value, 6);
w.bits(0b111, 3);
@paulmillr
paulmillr / guide.md
Last active April 10, 2023 09:04
Sign git commits with ssh key
View guide.md

Sign git commits with ssh key

  • git version must be >= 2.34. Earlier versions don't support gpg.format ssh (signing commits with ssh keys).

    If you're printing signature keys in git log by using %GK %GF %GP %GT in git.format.pretty, earlier versions will crash when doing git log with following error:

    BUG: gpg-interface.c:284: bad signature

  • OpenSSH version must be >= 8.8. Earlier versions don't support valid-after,valid-before options.

View noble-fun.md

Fun parts of developing noble-hashes and scure-base

  • Base58 is quadratic (O(n^2)). Basically you can’t encode 1MB of data with it. This has been found with our DoS tests, which we employ for scure-base and noble-hashes. See README for more details
  • Hashes are additionally tested against huge multi-gig inputs, scrypt/pbkdf2 are tested against all possible combination of options. They take 2 hours to run on a decent machine
  • Hashes are actually faster than many wasm alternatives. A single sha256 hashing of 32 bytes of data takes 888 nanoseconds on mac with M1
  • The last fact is extremely remarkable, because we do not employ loop unrolls in the code. A loop unroll is when you’re writing code which could have been executed in loop like for (let step = 0; step &lt; 64), but instead, you’re writing every iteration step-by-step. Which incr