Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
nipxx, wip draft
  • Loading branch information
0xc0de4c0ffee committed Feb 24, 2023
commit 5058eb9189ca4d9f828c21e70ce10893cf1f0405
35 changes: 35 additions & 0 deletions nipxx.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* eslint-env jest */

globalThis.crypto = require('crypto')
const {
nipxx
} = require('./lib/nostr.cjs')


let username1 = 'me@example.com'
let username2 = '0xc0de4c0ffee@0xc0de4c0ffee.eth.limo'
let address = '0xc0De4c0FFEEC0dE4C0FfeEC0de4c0fFeec0de420' // address checksummed
let caip10 = `eip155:1:${address}`
let password = 'horse staple battery'
let sig1 = '0x'.padEnd(132, 'f')
let sig2 = 'f'.padEnd(129, 'f')
let privKey = 'ad94cd8ca2877102ad92d0fa3d2a918f4903dfb0445e33930e115f56deb733b9'

test('private key from deterministic 0x+signature and identifiers', async () => {
expect(
await nipxx.privateKeyFromX(username1, caip10, sig1, password)
).toEqual(privKey)
})

test('private key from deterministic signature and identifiers', async () => {
expect(
await nipxx.privateKeyFromX(username1, caip10, sig1, password)
).toEqual(privKey)
})


test('login key from deterministic signature and identifiers', async () => {
expect(
await nipxx.signInWithX(username2, caip10, sig1, password)
).toEqual(privKey)
})
89 changes: 89 additions & 0 deletions nipxx.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import * as secp256k1 from '@noble/secp256k1'

import {
hkdf
} from '@noble/hashes/hkdf'
import {
sha256
} from '@noble/hashes/sha256'

import {
queryProfile
} from './nip05'
import {
getPublicKey
} from './keys'
import {
ProfilePointer
} from './nip19'

export async function privateKeyFromX(
username: string,
caip10: string,
sig: string,
password: string | undefined,
): Promise < string > {
if(sig.length < 64)
throw new Error("Signature too short");
let inputKey = await sha256(secp256k1.utils.hexToBytes(sig.toLowerCase().startsWith("0x")?sig.slice(2):sig))
let info = `${caip10}:${username}`
let salt = await sha256(`${info}:${password?password:""}:${sig.slice(-64)}`)
let hashKey = await hkdf(sha256, inputKey, salt, info, 42)
return secp256k1.utils.bytesToHex(secp256k1.utils.hashToPrivateKey(hashKey))
}

export async function signInWithX (
username: string,
password: string,
caip10: string,
sig: string
): Promise < {
username: string,
profile: ProfilePointer | null,
privkey: string
}> {
let profile = null
if (username.includes(".")) {
profile = await queryProfile(username)
}
let pubkey = profile?.pubkey
let privkey = await privateKeyFromX(username, password, caip10, sig)
if (pubkey != getPublicKey(privkey)) {
//return null; //??
}
// WIP
return {
username,
profile,
privkey
}
}

export let loginWithX = signInWithX

export async function registerWithX (
username: string,
password: string,
caip10: string,
sig: string
): Promise < {
username: string,
profile: ProfilePointer | null,
privkey: string
} | null > {
let profile = null
if (username.includes(".")) {
profile = await queryProfile(username)
}
let pubkey = profile?.pubkey
let privkey = await privateKeyFromX(username, password, caip10, sig)
if (pubkey != getPublicKey(privkey)) {
return null; //??
}

return {
username,
profile,
privkey
}
}