mirror of
https://github.com/nostr-protocol/nips.git
synced 2025-12-09 16:48:50 +00:00
Compare commits
2 Commits
code-follo
...
bigger-nip
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8782df594 | ||
|
|
4de6a69931 |
31
44.md
31
44.md
@@ -84,10 +84,12 @@ NIP-44 version 2 has the following design characteristics:
|
|||||||
- Slice 76-byte HKDF output into: `chacha_key` (bytes 0..32), `chacha_nonce` (bytes 32..44), `hmac_key` (bytes 44..76)
|
- Slice 76-byte HKDF output into: `chacha_key` (bytes 0..32), `chacha_nonce` (bytes 32..44), `hmac_key` (bytes 44..76)
|
||||||
4. Add padding
|
4. Add padding
|
||||||
- Content must be encoded from UTF-8 into byte array
|
- Content must be encoded from UTF-8 into byte array
|
||||||
- Validate plaintext length. Minimum is 1 byte, maximum is 65535 bytes
|
- Validate plaintext length. Minimum is 1 byte, maximum is 4294967296 bytes
|
||||||
- Padding format is: `[plaintext_length: u16][plaintext][zero_bytes]`
|
- Padding format is: `[plaintext_length: u16][plaintext][zero_bytes]`
|
||||||
- Padding algorithm is related to powers-of-two, with min padded msg size of 32 bytes
|
- Padding algorithm is related to powers-of-two, with min padded msg size of 32 bytes
|
||||||
- Plaintext length is encoded in big-endian as first 2 bytes of the padded blob
|
- Plaintext length is encoded in big-endian:
|
||||||
|
- if smaller than 65536, as a u16 in the first 2 bytes of the padded blob;
|
||||||
|
- if greater than 65536, the first 6 bytes of the padded blob, the first 2 being zero and the other 4 being the actual encoded length as u32
|
||||||
5. Encrypt padded content
|
5. Encrypt padded content
|
||||||
- Use ChaCha20, with key and nonce from step 3
|
- Use ChaCha20, with key and nonce from step 3
|
||||||
6. Calculate MAC (message authentication code)
|
6. Calculate MAC (message authentication code)
|
||||||
@@ -124,7 +126,9 @@ validation rules, refer to BIP-340.
|
|||||||
6. Decrypt ciphertext
|
6. Decrypt ciphertext
|
||||||
- Use ChaCha20 with key and nonce from step 3
|
- Use ChaCha20 with key and nonce from step 3
|
||||||
7. Remove padding
|
7. Remove padding
|
||||||
- Read the first two BE bytes of plaintext that correspond to plaintext length
|
- Read the first 2 bytes,
|
||||||
|
- if they're zero, read the next 4 bytes as the u32 big-endian plaintext length;
|
||||||
|
- otherwise interpret those 2 bytes as the u16 plaintext length
|
||||||
- Verify that the length of sliced plaintext matches the value of the two BE bytes
|
- Verify that the length of sliced plaintext matches the value of the two BE bytes
|
||||||
- Verify that calculated padding from step 3 of the [encryption](#Encryption) process matches the actual padding
|
- Verify that calculated padding from step 3 of the [encryption](#Encryption) process matches the actual padding
|
||||||
|
|
||||||
@@ -148,8 +152,6 @@ validation rules, refer to BIP-340.
|
|||||||
- `x[i:j]`, where `x` is a byte array and `i, j <= 0` returns a `(j - i)`-byte array with a copy of the
|
- `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`.
|
`i`-th byte (inclusive) to the `j`-th byte (exclusive) of `x`.
|
||||||
- Constants `c`:
|
- Constants `c`:
|
||||||
- `min_plaintext_size` is 1. 1 byte msg is padded to 32 bytes.
|
|
||||||
- `max_plaintext_size` is 65535 (64kB - 1). It is padded to 65536 bytes.
|
|
||||||
- Functions
|
- Functions
|
||||||
- `base64_encode(string)` and `base64_decode(bytes)` are Base64 ([RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648), with padding)
|
- `base64_encode(string)` and `base64_decode(bytes)` are Base64 ([RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648), with padding)
|
||||||
- `concat` refers to byte array concatenation
|
- `concat` refers to byte array concatenation
|
||||||
@@ -182,16 +184,27 @@ def calc_padded_len(unpadded_len):
|
|||||||
def pad(plaintext):
|
def pad(plaintext):
|
||||||
unpadded = utf8_encode(plaintext)
|
unpadded = utf8_encode(plaintext)
|
||||||
unpadded_len = len(plaintext)
|
unpadded_len = len(plaintext)
|
||||||
if (unpadded_len < c.min_plaintext_size or
|
if (unpadded_len < 1 or
|
||||||
unpadded_len > c.max_plaintext_size): raise Exception('invalid plaintext length')
|
unpadded_len > 4294967295): raise Exception('invalid plaintext length')
|
||||||
prefix = write_u16_be(unpadded_len)
|
if unpadded_len > 65536:
|
||||||
|
prefix = concat(
|
||||||
|
[0, 0],
|
||||||
|
write_u32_be(unpadded_len),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
prefix = write_u16_be(unpadded_len)
|
||||||
suffix = zeros(calc_padded_len(unpadded_len) - unpadded_len)
|
suffix = zeros(calc_padded_len(unpadded_len) - unpadded_len)
|
||||||
return concat(prefix, unpadded, suffix)
|
return concat(prefix, unpadded, suffix)
|
||||||
|
|
||||||
# Converts padded bytearray to unpadded plaintext
|
# Converts padded bytearray to unpadded plaintext
|
||||||
def unpad(padded):
|
def unpad(padded):
|
||||||
unpadded_len = read_uint16_be(padded[0:2])
|
unpadded_len = read_uint16_be(padded[0:2])
|
||||||
unpadded = padded[2:2+unpadded_len]
|
if unpadded_len == 0:
|
||||||
|
unpadded_len = read_uint32_be(padded[2:6])
|
||||||
|
unpadded = padded[6:6+unpadded_len]
|
||||||
|
else:
|
||||||
|
unpadded = padded[2:2+unpadded_len]
|
||||||
|
|
||||||
if (unpadded_len == 0 or
|
if (unpadded_len == 0 or
|
||||||
len(unpadded) != unpadded_len or
|
len(unpadded) != unpadded_len or
|
||||||
len(padded) != 2 + calc_padded_len(unpadded_len)): raise Exception('invalid padding')
|
len(padded) != 2 + calc_padded_len(unpadded_len)): raise Exception('invalid padding')
|
||||||
|
|||||||
Reference in New Issue
Block a user