mirror of
https://github.com/nostr-protocol/nips.git
synced 2024-11-10 06:09:08 -05:00
minor edits to NIP-XX
This commit is contained in:
parent
299c8b992e
commit
b2a2711af1
62
xx.md
62
xx.md
|
@ -1,65 +1,64 @@
|
||||||
NIP-XX
|
# NIP-XX
|
||||||
--
|
|
||||||
|
|
||||||
Nostr-Specific Deterministic Private Key Generation from Ethereum Wallet Signature
|
Nostr-Specific Deterministic Private Key Generation from Ethereum Wallet Signature
|
||||||
--
|
--
|
||||||
`draft` `optional` `author:0xc0de4c0ffee` `author:sshmatrix`
|
`draft` `optional` `author:0xc0de4c0ffee` `author:sshmatrix`
|
||||||
|
|
||||||
## Abstract
|
## Abstract
|
||||||
|
|
||||||
This specification provides an optional method for Nostr clients to generate deterministic private keys from Ethereum wallet signatures.
|
This specification provides an optional method for Nostr clients to generate deterministic private keys from Ethereum wallet signatures. This NIP proposes HMAC Key Derivation Function (HKDF) coupled with SHA-256 from ECDSA signatures (EIP-191) as an alternative to the Schnorr signatures (BIP-340), allowing Nostr to interact with Ethereum ecosystem.
|
||||||
|
|
||||||
## Terminology
|
## Terminology
|
||||||
### a) `username`
|
### a) Username
|
||||||
Username can be either of the following:
|
Username can be either of the following:
|
||||||
|
|
||||||
`username` or `user@domain.eth.limo` or `domain.eth.limo` or `sub.domain.eth.limo`, where,
|
`petname` or `petname@domain.eth.limo` or `domain.eth.limo` or `sub.domain.eth.limo`, where
|
||||||
|
|
||||||
- `username` is a [NIP-02](https://github.com/nostr-protocol/nips/blob/master/05.md) compatible name,
|
- `petname` is a NIP-02 compatible name,
|
||||||
- `name@domain.eth.limo` is a [NIP-05](https://github.com/nostr-protocol/nips/blob/master/05.md) compatible name,
|
- `petname@domain.eth.limo` is a NIP-05 compatible name,
|
||||||
- `domain.eth.limo` is [NIP-05](https://github.com/nostr-protocol/nips/blob/master/05.md) equivalent of
|
- `domain.eth.limo` is NIP-05 equivalent of `_@domain.eth.limo`,
|
||||||
`_@domain.eth.limo`,
|
- `sub.domain.eth.limo` is NIP-05 equivalent of `_@sub.domain.eth.limo`.
|
||||||
- `sub.domain.eth.limo` is [NIP-05](https://github.com/nostr-protocol/nips/blob/master/05.md) equivalent of
|
> a) `sub@domain.eth.limo` and `sub.domain.eth.limo` are NOT equivalent as their signatures will be different
|
||||||
`_@sub.domain.eth.limo`.
|
|
||||||
> Note : `sub@domain.eth.limo` and `sub.domain.eth.limo` are NOT same ID as their signatures will be different.
|
|
||||||
|
|
||||||
|
> b) `petname` can be the same as `domain`
|
||||||
|
|
||||||
### b) `password`
|
### b) Password
|
||||||
Password is optional string value used in HKDF salt,
|
Password is an optional string value used in HKDF salt,
|
||||||
```js
|
```js
|
||||||
let password = "horse staple battery"
|
let password = "horse staple battery"
|
||||||
let salt = await sha256(`eip155:${chainId}:${username}:${password?password:""}:${signature.slice(68)}`);
|
let salt = await sha256(`eip155:${chainId}:${username}:${password?password:""}:${signature.slice(68)}`);
|
||||||
```
|
```
|
||||||
|
|
||||||
### c) `message`
|
### c) Message
|
||||||
|
Message is text on screen that should warn the users to not sign messages indiscriminately,
|
||||||
```js
|
```js
|
||||||
let message = `Login to Nostr as ${username}\n\nImportant: Please verify the integrity and authenticity of your Nostr client before signing this message.\n${info}`
|
let message = `Login to Nostr as ${username}\n\nImportant: Please verify the integrity and authenticity of your Nostr client before signing this message.\n${info}`
|
||||||
```
|
```
|
||||||
### d) `signature`
|
### d) Signature
|
||||||
Deterministic signature from connected wallet. Signatures are 65 bytes long, `bytes1(v)+bytes32(r)+bytes32(s)`.
|
Signature is the deterministic signature from connected Ethereum wallet. Ethereum signatures `(v,r,s)` are 65 bytes long, i.e. `bytes1(v) + bytes32(r) + bytes32(s)`,
|
||||||
```js
|
```js
|
||||||
let signature = wallet.signMessage(message);
|
let signature = wallet.signMessage(message);
|
||||||
```
|
```
|
||||||
### e) `HKDF`
|
### e) HKDF (HMAC Key Derivation Function)
|
||||||
HKDF-SHA-256 is used to derive 42 bytes long hash key.
|
HKDF-SHA-256 is used to derive the 42 bytes long hash key: `hkdf(sha256, inputKey, salt, info, dkLen = 42)`
|
||||||
`hkdf(sha256, inputKey, salt, info, dkLen = 42)`
|
|
||||||
- `Input key` is SHA-256 hash of signature bytes.
|
- `Input key` is SHA-256 hash of signature bytes.
|
||||||
```js
|
```js
|
||||||
let inputKey = await sha256(hexToBytes(signature.slice(2)));
|
let inputKey = await sha256(hexToBytes(signature.slice(2)));
|
||||||
```
|
```
|
||||||
- `Salt` is SHA-256 hash of following identifier string. `signature.slice(68)` is hex `s` value of signature, last 32 bytes.
|
- `Salt` is SHA-256 hash of the following identifier string:
|
||||||
```js
|
```js
|
||||||
let salt = await sha256(`eip155:${chainId}:${username}:${password?password:""}:${signature.slice(68)}`);
|
let salt = await sha256(`eip155:${chainId}:${username}:${password?password:""}:${signature.slice(68)}`);
|
||||||
```
|
```
|
||||||
- `Info` is string with following format.
|
where, `signature.slice(68)` is hex `s` value of Ethereum signature, i.e. the last 32 bytes.
|
||||||
|
- `Info` is a string with the following format:
|
||||||
```js
|
```js
|
||||||
let info = `eip155:${chainId}:${username}:${address}`;
|
let info = `eip155:${chainId}:${username}:${address}`;
|
||||||
```
|
```
|
||||||
- `Derived Key Length` is set to 42. FIPS 186/4 B.4.1 require hash length to be >=n+8 where, n is length of final private key. (42 >= 32 + 8)
|
- Derived Key Length `dkLen` is set to 42.
|
||||||
```js
|
```js
|
||||||
let dkLen = 42;
|
let dkLen = 42;
|
||||||
```
|
```
|
||||||
- `hashToPrivateKey` function is FIPS 186-4 B.4.1 implementation to convert derived hash keys from `HKDF`to valid `secp256k1` private keys. This function is implemented in js `@noble/secp256k1` as `hashToPrivateKey`.
|
FIPS 186/4 B.4.1 requires hash length to be ≥ n+8, where n is the length of final private key, such that 42 ≥ 32 + 8
|
||||||
|
- `hashToPrivateKey` function is FIPS 186-4 B.4.1 implementation to convert hash keys derived using HKDF to valid `secp256k1` private keys. This function is implemented in JavaScript library `@noble/secp256k1` as `hashToPrivateKey()`.
|
||||||
```js
|
```js
|
||||||
let hashKey = hkdf(sha256, inputKey, salt, info, dkLen=42);
|
let hashKey = hkdf(sha256, inputKey, salt, info, dkLen=42);
|
||||||
let privKey = secp256k1.utils.hashToPrivateKey(hashKey);
|
let privKey = secp256k1.utils.hashToPrivateKey(hashKey);
|
||||||
|
@ -68,12 +67,12 @@ HKDF-SHA-256 is used to derive 42 bytes long hash key.
|
||||||
|
|
||||||
## Implementation Requirements
|
## Implementation Requirements
|
||||||
|
|
||||||
- Connected Ethereum Wallet signer MUST be EIP191 and RFC6979 compatible.
|
- Connected Ethereum wallet signer MUST be EIP191 and RFC6979 compatible.
|
||||||
- The message MUST be string formatted as `Login to Nostr as ${username}\n\nImportant: Please verify the integrity and authenticity of your Nostr client before signing this message.\n${info}`.
|
- The message MUST be string formatted as `Login to Nostr as ${username}\n\nImportant: Please verify the integrity and authenticity of your Nostr client before signing this message.\n${info}`.
|
||||||
- HKDF input key MUST be generated as the SHA-256 hash of 65 bytes signature.
|
- HKDF input key MUST be generated as the SHA-256 hash of 65 bytes signature.
|
||||||
- HKDF salt MUST be generated as SHA-256 hash of string `eip155:${chainID}:${username}:${password?password:""}:${signature.slice(68)}`.
|
- HKDF salt MUST be generated as SHA-256 hash of string `eip155:${chainID}:${username}:${password?password:""}:${signature.slice(68)}`.
|
||||||
- HKDF derived key length MUST be 42.
|
- HKDF derived key length MUST be 42.
|
||||||
- HKDF info MUST be string formatted as `eip155:${chainId}:${username}:${address}`
|
- HKDF info MUST be string formatted as `eip155:${chainId}:${username}:${address}`.
|
||||||
|
|
||||||
## JS Example
|
## JS Example
|
||||||
```js
|
```js
|
||||||
|
@ -82,7 +81,7 @@ const {hexToBytes, bytesToHex} = require('@noble/hashes/utils');
|
||||||
const {hkdf} = require('@noble/hashes/hkdf');
|
const {hkdf} = require('@noble/hashes/hkdf');
|
||||||
const {sha256} = require('@noble/hashes/sha256');
|
const {sha256} = require('@noble/hashes/sha256');
|
||||||
|
|
||||||
// const wallet = // connected ethereum wallet with ethers.js
|
// const wallet = connected ethereum wallet with ethers.js
|
||||||
let username = "me@domain.eth.limo"
|
let username = "me@domain.eth.limo"
|
||||||
let chainId = wallet.getChainId(); // get chainid from connected wallet
|
let chainId = wallet.getChainId(); // get chainid from connected wallet
|
||||||
let address = wallet.getAddress(); // get address from wallet
|
let address = wallet.getAddress(); // get address from wallet
|
||||||
|
@ -104,15 +103,16 @@ let pubKey = secp256k1.schnorr.getPublicKey(privKey);
|
||||||
## Security Considerations
|
## Security Considerations
|
||||||
|
|
||||||
- Users should always verify the integrity and authenticity of the Nostr client before signing the message.
|
- Users should always verify the integrity and authenticity of the Nostr client before signing the message.
|
||||||
- Users should ensure that they only input their Nostr username and password in trusted and secure clients.
|
- Users should ensure that they only input their Nostr Username and Password in trusted and secure clients.
|
||||||
- Implementing clients should ensure ~~..private key/security~~
|
|
||||||
|
|
||||||
|
|
||||||
## References:
|
## References:
|
||||||
- [RFC6979: Deterministic Usage of the DSA and ECDSA](https://datatracker.ietf.org/doc/html/rfc6979)
|
- [RFC6979: Deterministic Usage of the DSA and ECDSA](https://datatracker.ietf.org/doc/html/rfc6979)
|
||||||
- [RFC5869: HKDF (HMAC-based Extract-and-Expand Key Derivation Function)](https://datatracker.ietf.org/doc/html/rfc5869)
|
- [RFC5869: HKDF (HMAC-based Extract-and-Expand Key Derivation Function)](https://datatracker.ietf.org/doc/html/rfc5869)
|
||||||
- [Digital Signature Standard (DSS), FIPS 186-4 B.4.1](https://csrc.nist.gov/publications/detail/fips/186/4/final)
|
- [Digital Signature Standard (DSS), FIPS 186-4 B.4.1](https://csrc.nist.gov/publications/detail/fips/186/4/final)
|
||||||
|
- [BIP340: Schnorr Signature Standard](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki)
|
||||||
- [ERC191: Signed Data Standard](https://eips.ethereum.org/EIPS/eip-191)
|
- [ERC191: Signed Data Standard](https://eips.ethereum.org/EIPS/eip-191)
|
||||||
- [EIP155: Simple replay attack protection](https://eips.ethereum.org/EIPS/eip-155)
|
- [EIP155: Simple replay attack protection](https://eips.ethereum.org/EIPS/eip-155)
|
||||||
|
- [NIP-02: Contact List and Petnames](https://github.com/nostr-protocol/nips/blob/master/02.md)
|
||||||
|
- [NIP-05: Mapping Nostr keys to DNS-based internet identifiers](https://github.com/nostr-protocol/nips/blob/master/05.md)
|
||||||
- [@noble/hashes](https://github.com/paulmillr/noble-hashes)
|
- [@noble/hashes](https://github.com/paulmillr/noble-hashes)
|
||||||
- [@noble/secp256k1](https://github.com/paulmillr/noble-secp256k1)
|
- [@noble/secp256k1](https://github.com/paulmillr/noble-secp256k1)
|
Loading…
Reference in New Issue
Block a user