@@ -115,6 +115,7 @@ public void reset() {
115115 * Updates this hash state using the provided bytes.
116116 *
117117 * @param in source array to update data from
118+ * @throws NullPointerException if in is null
118119 */
119120 public void update (final byte [] in ) {
120121 Objects .requireNonNull (in );
@@ -127,9 +128,12 @@ public void update(final byte[] in) {
127128 * @param in source array to update data from
128129 * @param offset where in the array to begin reading bytes
129130 * @param length number of bytes to update
131+ * @throws NullPointerException if in is null
132+ * @throws IndexOutOfBoundsException if offset or length are negative or if offset + length is greater than the
133+ * length of the provided array
130134 */
131135 public void update (final byte [] in , final int offset , final int length ) {
132- Objects . requireNonNull (in );
136+ checkBufferArgs (in , offset , length );
133137 engineState .inputData (in , offset , length );
134138 }
135139
@@ -138,8 +142,10 @@ public void update(final byte[] in, final int offset, final int length) {
138142 * previously finalized bytes. Note that this can finalize up to 2<sup>64</sup> bytes per instance.
139143 *
140144 * @param out destination array to finalize bytes into
145+ * @throws NullPointerException if out is null
141146 */
142147 public void doFinalize (final byte [] out ) {
148+ Objects .requireNonNull (out );
143149 doFinalize (out , 0 , out .length );
144150 }
145151
@@ -150,9 +156,12 @@ public void doFinalize(final byte[] out) {
150156 * @param out destination array to finalize bytes into
151157 * @param offset where in the array to begin writing bytes to
152158 * @param length number of bytes to finalize
159+ * @throws NullPointerException if out is null
160+ * @throws IndexOutOfBoundsException if offset or length are negative or if offset + length is greater than the
161+ * length of the provided array
153162 */
154163 public void doFinalize (final byte [] out , final int offset , final int length ) {
155- Objects . requireNonNull (out );
164+ checkBufferArgs (out , offset , length );
156165 engineState .outputHash (out , offset , length );
157166 }
158167
@@ -161,8 +170,12 @@ public void doFinalize(final byte[] out, final int offset, final int length) {
161170 *
162171 * @param nrBytes number of bytes to finalize
163172 * @return requested number of finalized bytes
173+ * @throws IllegalArgumentException if nrBytes is negative
164174 */
165175 public byte [] doFinalize (final int nrBytes ) {
176+ if (nrBytes < 0 ) {
177+ throw new IllegalArgumentException ("Requested bytes must be non-negative" );
178+ }
166179 final byte [] hash = new byte [nrBytes ];
167180 doFinalize (hash );
168181 return hash ;
@@ -183,6 +196,8 @@ public static Blake3 initHash() {
183196 *
184197 * @param key 32-byte secret key
185198 * @return fresh Blake3 instance in keyed mode using the provided key
199+ * @throws NullPointerException if key is null
200+ * @throws IllegalArgumentException if key is not 32 bytes
186201 */
187202 public static Blake3 initKeyedHash (final byte [] key ) {
188203 Objects .requireNonNull (key );
@@ -199,6 +214,7 @@ public static Blake3 initKeyedHash(final byte[] key) {
199214 *
200215 * @param kdfContext a globally unique key-derivation context byte string to separate key derivation contexts from each other
201216 * @return fresh Blake3 instance in key derivation mode
217+ * @throws NullPointerException if kdfContext is null
202218 */
203219 public static Blake3 initKeyDerivationFunction (final byte [] kdfContext ) {
204220 Objects .requireNonNull (kdfContext );
@@ -214,6 +230,7 @@ public static Blake3 initKeyDerivationFunction(final byte[] kdfContext) {
214230 *
215231 * @param data source array to absorb data from
216232 * @return 32-byte hash squeezed from the provided data
233+ * @throws NullPointerException if data is null
217234 */
218235 public static byte [] hash (final byte [] data ) {
219236 final Blake3 blake3 = Blake3 .initHash ();
@@ -227,13 +244,28 @@ public static byte[] hash(final byte[] data) {
227244 * @param key 32-byte secret key
228245 * @param data source array to absorb data from
229246 * @return 32-byte mac squeezed from the provided data
247+ * @throws NullPointerException if key or data are null
230248 */
231249 public static byte [] keyedHash (final byte [] key , final byte [] data ) {
232250 final Blake3 blake3 = Blake3 .initKeyedHash (key );
233251 blake3 .update (data );
234252 return blake3 .doFinalize (OUT_LEN );
235253 }
236254
255+ private static void checkBufferArgs (byte [] buffer , int offset , int length ) {
256+ Objects .requireNonNull (buffer );
257+ if (offset < 0 ) {
258+ throw new IndexOutOfBoundsException ("Offset must be non-negative" );
259+ }
260+ if (length < 0 ) {
261+ throw new IndexOutOfBoundsException ("Length must be non-negative" );
262+ }
263+ if (offset > buffer .length - length ) {
264+ throw new IndexOutOfBoundsException (
265+ "Offset " + offset + " and length " + length + " out of bounds with buffer length " + buffer .length );
266+ }
267+ }
268+
237269 private static void packInt (final int value , final byte [] dst , final int off , final int len ) {
238270 for (int i = 0 ; i < len ; i ++) {
239271 dst [off + i ] = (byte ) (value >>> i * Byte .SIZE );
0 commit comments