mirror of
https://github.com/nostr-protocol/nips.git
synced 2024-12-22 16:35:52 -05:00
nip-44: remove author names and arbitrary line-breaks.
This commit is contained in:
parent
822b70a565
commit
4199f20236
66
44.md
66
44.md
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
## Encrypted Payloads (Versioned)
|
## Encrypted Payloads (Versioned)
|
||||||
|
|
||||||
`optional` `author:paulmillr` `author:staab`
|
`optional`
|
||||||
|
|
||||||
The NIP introduces a new data format for keypair-based encryption. This NIP is versioned
|
The NIP introduces a new data format for keypair-based encryption. This NIP is versioned
|
||||||
to allow multiple algorithm choices to exist simultaneously.
|
to allow multiple algorithm choices to exist simultaneously.
|
||||||
|
@ -22,12 +22,11 @@ The scheme has a number of important shortcomings:
|
||||||
- Limited message size leak: padding only partially obscures true message length
|
- Limited message size leak: padding only partially obscures true message length
|
||||||
- No attachments: they are not supported
|
- No attachments: they are not supported
|
||||||
|
|
||||||
Lack of forward secrecy is partially mitigated: 1) the messages
|
Lack of forward secrecy is partially mitigated by these two factors:
|
||||||
should only be stored on relays, specified by the user, instead of a set of
|
1. the messages should only be stored on relays, specified by the user, instead of a set of all public relays.
|
||||||
all public relays 2) the relays are supposed to regularly delete older messages.
|
2. the relays are supposed to regularly delete older messages.
|
||||||
|
|
||||||
For risky situations, users should chat in specialized E2EE messaging software and limit use
|
For risky situations, users should chat in specialized E2EE messaging software and limit use of nostr to exchanging contacts.
|
||||||
of nostr to exchanging contacts.
|
|
||||||
|
|
||||||
## Dependence on NIP-01
|
## Dependence on NIP-01
|
||||||
|
|
||||||
|
@ -35,14 +34,9 @@ It's not enough to use NIP-44 for encryption: the output must also be signed.
|
||||||
|
|
||||||
In nostr case, the payload is serialized and signed as per NIP-01 rules.
|
In nostr case, the payload is serialized and signed as per NIP-01 rules.
|
||||||
|
|
||||||
The same event can be serialized in two different ways,
|
The same event can be serialized in two different ways, resulting in two distinct signatures. So, it's important to ensure serialization rules, which are defined in NIP-01, are the same across different NIP-44 implementations.
|
||||||
resulting in two distinct signatures. So, it's important
|
|
||||||
to ensure serialization rules, which are defined in NIP-01,
|
|
||||||
are the same across different NIP-44 implementations.
|
|
||||||
|
|
||||||
After serialization, the event is signed by Schnorr signature over secp256k1,
|
After serialization, the event is signed by Schnorr signature over secp256k1, defined in BIP340. It's important to ensure the key and signature validity as per BIP340 rules.
|
||||||
defined in BIP340. It's important to ensure the key and signature validity as
|
|
||||||
per BIP340 rules.
|
|
||||||
|
|
||||||
## Versions
|
## Versions
|
||||||
|
|
||||||
|
@ -56,18 +50,12 @@ Currently defined encryption algorithms:
|
||||||
|
|
||||||
The algorithm choices are justified in a following way:
|
The algorithm choices are justified in a following way:
|
||||||
|
|
||||||
- Encrypt-then-mac-then-sign instead of encrypt-then-sign-then-mac:
|
- Encrypt-then-mac-then-sign instead of encrypt-then-sign-then-mac: only events wrapped in NIP-01 signed envelope are currently accepted by nostr.
|
||||||
only events wrapped in NIP-01 signed envelope are currently accepted by nostr.
|
- ChaCha instead of AES: it's faster and has [better security against multi-key attacks](https://datatracker.ietf.org/doc/draft-irtf-cfrg-aead-limits/)
|
||||||
- ChaCha instead of AES: it's faster and has
|
- ChaCha instead of XChaCha: XChaCha has not been standardized. Also, we don't need xchacha's improved collision resistance of nonces: every message has a new (key, nonce) pair.
|
||||||
[better security against multi-key attacks](https://datatracker.ietf.org/doc/draft-irtf-cfrg-aead-limits/)
|
- HMAC-SHA256 instead of Poly1305: polynomial MACs are much easier to forge SHA256 instead of SHA3 or BLAKE: it is already used in nostr. Also blake's
|
||||||
- ChaCha instead of XChaCha: XChaCha has not been standardized. Also, we don't need xchacha's improved
|
speed advantage is smaller in non-parallel environments - Custom padding instead of padmé: better leakage reduction for small messages
|
||||||
collision resistance of nonces: every message has a new (key, nonce) pair.
|
- Base64 encoding instead of an other compression algorithm: it is widely available, and is already used in nostr
|
||||||
- HMAC-SHA256 instead of Poly1305: polynomial MACs are much easier to forge
|
|
||||||
- SHA256 instead of SHA3 or BLAKE: it is already used in nostr. Also blake's
|
|
||||||
speed advantage is smaller in non-parallel environments
|
|
||||||
- Custom padding instead of padmé: better leakage reduction for small messages
|
|
||||||
- Base64 encoding instead of an other compression algorithm: it is widely available,
|
|
||||||
and is already used in nostr
|
|
||||||
|
|
||||||
### Functions and operations
|
### Functions and operations
|
||||||
|
|
||||||
|
@ -77,12 +65,7 @@ The algorithm choices are justified in a following way:
|
||||||
comprised of methods `hkdf_extract(IKM, salt)` and `hkdf_expand(OKM, info, L)`
|
comprised of methods `hkdf_extract(IKM, salt)` and `hkdf_expand(OKM, info, L)`
|
||||||
- `chacha20(key, nonce, data)` is ChaCha20 [(RFC 8439)](https://datatracker.ietf.org/doc/html/rfc8439), with starting counter set to 0
|
- `chacha20(key, nonce, data)` is ChaCha20 [(RFC 8439)](https://datatracker.ietf.org/doc/html/rfc8439), with starting counter set to 0
|
||||||
- `hmac_sha256(key, message)` is HMAC [(RFC 2104)](https://datatracker.ietf.org/doc/html/rfc2104)
|
- `hmac_sha256(key, message)` is HMAC [(RFC 2104)](https://datatracker.ietf.org/doc/html/rfc2104)
|
||||||
- `secp256k1_ecdh(priv_a, pub_b)` is multiplication of point B by
|
- `secp256k1_ecdh(priv_a, pub_b)` is multiplication of point B by scalar a (`a ⋅ B`), defined in [BIP340](https://github.com/bitcoin/bips/blob/e918b50731397872ad2922a1b08a5a4cd1d6d546/bip-0340.mediawiki). The operation produces shared point, and we encode the shared point's 32-byte x coordinate, using method `bytes(P)` from BIP340. Private and public keys must be validated as per BIP340: pubkey must be a valid, on-curve point, and private key must be a scalar in range `[1, secp256k1_order - 1]`
|
||||||
scalar a (`a ⋅ B`), defined in
|
|
||||||
[BIP340](https://github.com/bitcoin/bips/blob/e918b50731397872ad2922a1b08a5a4cd1d6d546/bip-0340.mediawiki).
|
|
||||||
The operation produces shared point, and we encode the shared point's 32-byte x coordinate,
|
|
||||||
using method `bytes(P)` from BIP340. Private and public keys must be validated
|
|
||||||
as per BIP340: pubkey must be a valid, on-curve point, and private key must be a scalar in range `[1, secp256k1_order - 1]`
|
|
||||||
- Operators
|
- Operators
|
||||||
- `x[i:j]`, where `x` is a byte array and `i, j <= 0`,
|
- `x[i:j]`, where `x` is a byte array and `i, j <= 0`,
|
||||||
returns a `(j - i)`-byte array with a copy of the `i`-th byte (inclusive) to the `j`-th byte (exclusive) of `x`
|
returns a `(j - i)`-byte array with a copy of the `i`-th byte (inclusive) to the `j`-th byte (exclusive) of `x`
|
||||||
|
@ -225,15 +208,11 @@ def decrypt(payload, conversation_key):
|
||||||
- Validate that AAD (nonce) is 32 bytes
|
- Validate that AAD (nonce) is 32 bytes
|
||||||
7. Base64-encode (with padding) params: `concat(version, nonce, ciphertext, mac)`
|
7. Base64-encode (with padding) params: `concat(version, nonce, ciphertext, mac)`
|
||||||
|
|
||||||
After encryption, it's necessary to sign it. Use NIP-01 to serialize the event,
|
After encryption, it's necessary to sign it. Use NIP-01 to serialize the event, with result base64 assigned to event's `content`. Then, use NIP-01 to sign the event using schnorr signature scheme over secp256k1.
|
||||||
with result base64 assigned to event's `content`. Then, use NIP-01 to sign
|
|
||||||
the event using schnorr signature scheme over secp256k1.
|
|
||||||
|
|
||||||
#### Decryption
|
#### Decryption
|
||||||
|
|
||||||
Before decryption, it's necessary to validate the message's pubkey and signature.
|
Before decryption, it's necessary to validate the message's pubkey and signature. The public key must be a valid non-zero secp256k1 curve point, and signature must be valid secp256k1 schnorr signature. For exact validation rules, refer to BIP-340.
|
||||||
The public key must be a valid non-zero secp256k1 curve point, and signature must be valid
|
|
||||||
secp256k1 schnorr signature. For exact validation rules, refer to BIP-340.
|
|
||||||
|
|
||||||
1. Check if first payload's character is `#`
|
1. Check if first payload's character is `#`
|
||||||
- `#` is an optional future-proof flag that means non-base64 encoding is used
|
- `#` is an optional future-proof flag that means non-base64 encoding is used
|
||||||
|
@ -260,11 +239,9 @@ secp256k1 schnorr signature. For exact validation rules, refer to BIP-340.
|
||||||
|
|
||||||
## Tests and code
|
## Tests and code
|
||||||
|
|
||||||
A collection of implementations in different languages is
|
A collection of implementations in different languages is available at https://github.com/paulmillr/nip44.
|
||||||
available [on GitHub](https://github.com/paulmillr/nip44).
|
|
||||||
|
|
||||||
We publish extensive test vectors. Instead of having it in the
|
We publish extensive test vectors. Instead of having it in the document directly, a sha256 checksum of vectors is provided:
|
||||||
document directly, a sha256 checksum of vectors is provided:
|
|
||||||
|
|
||||||
269ed0f69e4c192512cc779e78c555090cebc7c785b609e338a62afc3ce25040 nip44.vectors.json
|
269ed0f69e4c192512cc779e78c555090cebc7c785b609e338a62afc3ce25040 nip44.vectors.json
|
||||||
|
|
||||||
|
@ -286,11 +263,8 @@ The file also contains intermediate values. A quick guidance with regards to its
|
||||||
- `valid.get_conversation_key`: calculate conversation_key from secret key sec1 and public key pub2
|
- `valid.get_conversation_key`: calculate conversation_key from secret key sec1 and public key pub2
|
||||||
- `valid.get_message_keys`: calculate chacha_key, chacha_nocne, hmac_key from conversation_key and nonce
|
- `valid.get_message_keys`: calculate chacha_key, chacha_nocne, hmac_key from conversation_key and nonce
|
||||||
- `valid.calc_padded_len`: take unpadded length (first value), calculate padded length (second value)
|
- `valid.calc_padded_len`: take unpadded length (first value), calculate padded length (second value)
|
||||||
- `valid.encrypt_decrypt`: emulate real conversation. Calculate
|
- `valid.encrypt_decrypt`: emulate real conversation. Calculate pub2 from sec2, verify conversation_key from (sec1, pub2), encrypt, verify payload, then calculate pub1 from sec1, verify conversation_key from (sec2, pub1), decrypt, verify plaintext.
|
||||||
pub2 from sec2, verify conversation_key from (sec1, pub2), encrypt, verify payload,
|
- `valid.encrypt_decrypt_long_msg`: same as previous step, but instead of a full plaintext and payload, their checksum is provided.
|
||||||
then calculate pub1 from sec1, verify conversation_key from (sec2, pub1), decrypt, verify plaintext.
|
|
||||||
- `valid.encrypt_decrypt_long_msg`: same as previous step, but instead of a full plaintext and payload,
|
|
||||||
their checksum is provided.
|
|
||||||
- `invalid.encrypt_msg_lengths`
|
- `invalid.encrypt_msg_lengths`
|
||||||
- `invalid.get_conversation_key`: calculating converastion_key must throw an error
|
- `invalid.get_conversation_key`: calculating converastion_key must throw an error
|
||||||
- `invalid.decrypt`: decrypting message content must throw an error
|
- `invalid.decrypt`: decrypting message content must throw an error
|
||||||
|
|
Loading…
Reference in New Issue
Block a user