@@ -91,62 +91,60 @@ pub fn (mut c Cipher) xor_key_stream(mut dst []u8, src []u8) {
9191 if dst.len < src.len {
9292 panic ('chacha20/chacha: dst buffer is to small' )
9393 }
94-
95- mut idx := 0
96- mut src_len := src.len
97-
98- dst = unsafe { dst[..src_len] }
94+ dst = unsafe { dst[..src.len] }
9995 if subtle.inexact_overlap (dst, src) {
10096 panic ('chacha20: invalid buffer overlap' )
10197 }
98+ // index of position within src bytes
99+ mut idx := 0
102100
103- // We adapt and ports the go version here
104- // First, drain any remaining key stream
101+ // First, try to drain any remaining key stream from internal buffer
105102 if c.length != 0 {
106103 // remaining keystream on internal buffer
107104 mut kstream := c.block[block_size - c.length..]
108- if src_len < kstream.len {
109- kstream = unsafe { kstream[..src_len ] }
105+ if src.len < kstream.len {
106+ kstream = unsafe { kstream[..src.len ] }
110107 }
108+ // xors every bytes in src with bytes from key stream and stored into dst
111109 for i, b in kstream {
112110 dst[idx + i] = src[idx + i] ^ b
113111 }
114- // updates the idx for dst and src
112+ // updates position and internal buffer length.
113+ // when c.length reaches the block_size, we reset it for future use.
115114 c.length - = kstream.len
116115 idx + = kstream.len
117- src_len - = kstream.len
116+ if c.length == block_size {
117+ unsafe { c.block.reset () }
118+ c.length = 0
119+ }
118120 }
119-
120- // take the most full bytes of multiples block_size from the src,
121- // build the keystream from the cipher's state and stores the result
122- // into dst
123- full := src_len - src_len % block_size
124- if full > 0 {
125- src_block := unsafe { src[idx..idx + full] }
126- c.Stream.keystream_with_blocksize (mut dst[idx..idx + full], src_block) or {
127- c.Stream.overflow = true
128- panic ('chacha20: xor_key_stream leads to counter overflow' )
121+ // process for remaining unprocessed src bytes
122+ mut remains := unsafe { src[idx..] }
123+ nr_blocks := remains.len / block_size
124+
125+ // process for full block_size-d message
126+ for i := 0 ; i < nr_blocks; i++ {
127+ // for every block_sized message, we generates 64-bytes block key stream
128+ // and then xor-ing this block with generated key stream
129+ block := unsafe { remains[i * block_size..(i + 1 ) * block_size] }
130+ ks := c.keystream () or { panic (err) }
131+ for j, b in ks {
132+ dst[idx + j] = block[j] ^ b
129133 }
134+ // updates position
135+ idx + = block_size
130136 }
131- idx + = full
132- src_len - = full
133-
134- // If we have a partial block, pad it for keystream_with_blocksize, and
135- // keep the leftover keystream for the next invocation.
136- if src_len > 0 {
137- // Make sure, internal buffer cleared or the old garbaged data from previous call still there
138- // See the issue at https://github.com/vlang/v/issues/24043
139- unsafe { c.block.reset () } // = []u8{len: block_size}
140- // copy the last src block to internal buffer, and performs
141- // keystream_with_blocksize on this buffer, and stores into remaining dst
142- _ := copy (mut c.block, src[idx..])
143- c.Stream.keystream_with_blocksize (mut c.block, c.block) or {
144- c.Stream.overflow = true
145- panic ('chacha20: xor_key_stream leads to counter overflow' )
137+
138+ // process for remaining partial block
139+ if remains.len % block_size != 0 {
140+ last_block := unsafe { remains[nr_blocks * block_size..] }
141+ // generates one 64-bytes keystream block
142+ c.block = c.keystream () or { panic (err) }
143+ for i, b in last_block {
144+ dst[idx + i] = b ^ c.block[i]
146145 }
147- n := copy (mut dst[idx..], c.block)
148- // the length of remaining bytes of unprocessed keystream
149- c.length = block_size - n
146+ c.length = block_size - last_block.len
147+ idx + = last_block.len
150148 }
151149}
152150
@@ -181,7 +179,9 @@ pub fn (mut c Cipher) free() {
181179 }
182180}
183181
184- // reset quickly sets all Cipher's fields to default value
182+ // reset quickly sets all Cipher's fields to default value.
183+ // This method will be deprecated.
184+ @[deprecated_after: '2025-11-30' ]
185185@[unsafe ]
186186pub fn (mut c Cipher) reset () {
187187 c.Stream.reset ()
0 commit comments