upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfiatjaf <fiatjaf@gmail.com>2025-05-04 07:00:09 -0300
committerfiatjaf <fiatjaf@gmail.com>2025-05-04 07:00:09 -0300
commit4de6a69931f918b6608f60d7d566805d06ba2b18 (patch)
tree4dbf712abfd38101d61c308cb7d9433b312d0947
parent5b7d3382009332f737bca8fdffce291e8d7935b9 (diff)
allow NIP-44 to encrypt more than 65535 bytes.
-rw-r--r--44.md31
1 files changed, 22 insertions, 9 deletions
diff --git a/44.md b/44.md
index a7c13f1..a6d1325 100644
--- a/44.md
+++ b/44.md
@@ -84,10 +84,12 @@ NIP-44 version 2 has the following design characteristics:
84 - Slice 76-byte HKDF output into: `chacha_key` (bytes 0..32), `chacha_nonce` (bytes 32..44), `hmac_key` (bytes 44..76) 84 - Slice 76-byte HKDF output into: `chacha_key` (bytes 0..32), `chacha_nonce` (bytes 32..44), `hmac_key` (bytes 44..76)
854. Add padding 854. Add padding
86 - Content must be encoded from UTF-8 into byte array 86 - Content must be encoded from UTF-8 into byte array
87 - Validate plaintext length. Minimum is 1 byte, maximum is 65535 bytes 87 - Validate plaintext length. Minimum is 1 byte, maximum is 4294967296 bytes
88 - Padding format is: `[plaintext_length: u16][plaintext][zero_bytes]` 88 - Padding format is: `[plaintext_length: u16][plaintext][zero_bytes]`
89 - Padding algorithm is related to powers-of-two, with min padded msg size of 32 bytes 89 - Padding algorithm is related to powers-of-two, with min padded msg size of 32 bytes
90 - Plaintext length is encoded in big-endian as first 2 bytes of the padded blob 90 - Plaintext length is encoded in big-endian:
91 - if smaller than 65536, as a u16 in the first 2 bytes of the padded blob;
92 - if greater than 65536, the first the first 6 bytes of the padded blob, the first 2 being zero and the other 4 being the actual encoded length as u32
915. Encrypt padded content 935. Encrypt padded content
92 - Use ChaCha20, with key and nonce from step 3 94 - Use ChaCha20, with key and nonce from step 3
936. Calculate MAC (message authentication code) 956. Calculate MAC (message authentication code)
@@ -124,7 +126,9 @@ validation rules, refer to BIP-340.
1246. Decrypt ciphertext 1266. Decrypt ciphertext
125 - Use ChaCha20 with key and nonce from step 3 127 - Use ChaCha20 with key and nonce from step 3
1267. Remove padding 1287. Remove padding
127 - Read the first two BE bytes of plaintext that correspond to plaintext length 129 - Read the first 2 bytes,
130 - if they're zero, read the next 4 bytes as the u32 big-endian plaintext length;
131 - otherwise interpret those 2 bytes as the u16 plaintext length
128 - Verify that the length of sliced plaintext matches the value of the two BE bytes 132 - Verify that the length of sliced plaintext matches the value of the two BE bytes
129 - Verify that calculated padding from step 3 of the [encryption](#Encryption) process matches the actual padding 133 - Verify that calculated padding from step 3 of the [encryption](#Encryption) process matches the actual padding
130 134
@@ -148,8 +152,6 @@ validation rules, refer to BIP-340.
148 - `x[i:j]`, where `x` is a byte array and `i, j <= 0` returns a `(j - i)`-byte array with a copy of the 152 - `x[i:j]`, where `x` is a byte array and `i, j <= 0` returns a `(j - i)`-byte array with a copy of the
149 `i`-th byte (inclusive) to the `j`-th byte (exclusive) of `x`. 153 `i`-th byte (inclusive) to the `j`-th byte (exclusive) of `x`.
150- Constants `c`: 154- Constants `c`:
151 - `min_plaintext_size` is 1. 1 byte msg is padded to 32 bytes.
152 - `max_plaintext_size` is 65535 (64kB - 1). It is padded to 65536 bytes.
153- Functions 155- Functions
154 - `base64_encode(string)` and `base64_decode(bytes)` are Base64 ([RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648), with padding) 156 - `base64_encode(string)` and `base64_decode(bytes)` are Base64 ([RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648), with padding)
155 - `concat` refers to byte array concatenation 157 - `concat` refers to byte array concatenation
@@ -182,16 +184,27 @@ def calc_padded_len(unpadded_len):
182def pad(plaintext): 184def pad(plaintext):
183 unpadded = utf8_encode(plaintext) 185 unpadded = utf8_encode(plaintext)
184 unpadded_len = len(plaintext) 186 unpadded_len = len(plaintext)
185 if (unpadded_len < c.min_plaintext_size or 187 if (unpadded_len < 1 or
186 unpadded_len > c.max_plaintext_size): raise Exception('invalid plaintext length') 188 unpadded_len > 4294967295): raise Exception('invalid plaintext length')
187 prefix = write_u16_be(unpadded_len) 189 if unpadded_len > 65536:
190 prefix = concat(
191 [0, 0],
192 write_u32_be(unpadded_len),
193 )
194 else:
195 prefix = write_u16_be(unpadded_len)
188 suffix = zeros(calc_padded_len(unpadded_len) - unpadded_len) 196 suffix = zeros(calc_padded_len(unpadded_len) - unpadded_len)
189 return concat(prefix, unpadded, suffix) 197 return concat(prefix, unpadded, suffix)
190 198
191# Converts padded bytearray to unpadded plaintext 199# Converts padded bytearray to unpadded plaintext
192def unpad(padded): 200def unpad(padded):
193 unpadded_len = read_uint16_be(padded[0:2]) 201 unpadded_len = read_uint16_be(padded[0:2])
194 unpadded = padded[2:2+unpadded_len] 202 if unpadded_len == 0:
203 unpadded_len = read_uint32_be(padded[2:6])
204 unpadded = padded[6:6+unpadded_len]
205 else:
206 unpadded = padded[2:2+unpadded_len]
207
195 if (unpadded_len == 0 or 208 if (unpadded_len == 0 or
196 len(unpadded) != unpadded_len or 209 len(unpadded) != unpadded_len or
197 len(padded) != 2 + calc_padded_len(unpadded_len)): raise Exception('invalid padding') 210 len(padded) != 2 + calc_padded_len(unpadded_len)): raise Exception('invalid padding')