View Javadoc
1   /*
2    * GordianKnot: Security Suite
3    * Copyright 2012-2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  package io.github.tonywasher.joceanus.gordianknot.impl.ext.digests;
18  
19  import io.github.tonywasher.joceanus.gordianknot.impl.ext.params.GordianBlake3Parameters;
20  import org.bouncycastle.crypto.ExtendedDigest;
21  import org.bouncycastle.crypto.Xof;
22  import org.bouncycastle.util.Memoable;
23  import org.bouncycastle.util.Pack;
24  
25  import java.util.ArrayDeque;
26  import java.util.Arrays;
27  import java.util.Deque;
28  
29  /**
30   * Blake3 implementation. Donated to BouncyCastle.
31   */
32  public class GordianBlake3Digest
33          implements ExtendedDigest, Memoable, Xof {
34      /**
35       * Already outputting error.
36       */
37      private static final String ERR_OUTPUTTING = "Already outputting";
38  
39      /**
40       * Number of Words.
41       */
42      private static final int NUMWORDS = 8;
43  
44      /**
45       * Number of Rounds.
46       */
47      private static final int ROUNDS = 7;
48  
49      /**
50       * Buffer length.
51       */
52      private static final int BLOCKLEN = NUMWORDS * Integer.BYTES * 2;
53  
54      /**
55       * Chunk length.
56       */
57      private static final int CHUNKLEN = 1024;
58  
59      /**
60       * ChunkStart Flag.
61       */
62      private static final int CHUNKSTART = 0b00000001;
63  
64      /**
65       * ChunkEnd Flag.
66       */
67      private static final int CHUNKEND = 0b00000010;
68  
69      /**
70       * Parent Flag.
71       */
72      private static final int PARENT = 0b00000100;
73  
74      /**
75       * Root Flag.
76       */
77      private static final int ROOT = 0b00001000;
78  
79      /**
80       * KeyedHash Flag.
81       */
82      private static final int KEYEDHASH = 0b00010000;
83  
84      /**
85       * DeriveContext Flag.
86       */
87      private static final int DERIVECONTEXT = 0b00100000;
88  
89      /**
90       * DeriveKey Flag.
91       */
92      private static final int DERIVEKEY = 0b01000000;
93  
94      /**
95       * Chaining0 State Locations.
96       */
97      private static final int CHAINING0 = 0;
98  
99      /**
100      * Chaining1 State Location.
101      */
102     private static final int CHAINING1 = 1;
103 
104     /**
105      * Chaining2 State Location.
106      */
107     private static final int CHAINING2 = 2;
108 
109     /**
110      * Chaining3 State Location.
111      */
112     private static final int CHAINING3 = 3;
113 
114     /**
115      * Chaining4 State Location.
116      */
117     private static final int CHAINING4 = 4;
118 
119     /**
120      * Chaining5 State Location.
121      */
122     private static final int CHAINING5 = 5;
123 
124     /**
125      * Chaining6 State Location.
126      */
127     private static final int CHAINING6 = 6;
128 
129     /**
130      * Chaining7 State Location.
131      */
132     private static final int CHAINING7 = 7;
133 
134     /**
135      * IV0 State Locations.
136      */
137     private static final int IV0 = 8;
138 
139     /**
140      * IV1 State Location.
141      */
142     private static final int IV1 = 9;
143 
144     /**
145      * IV2 State Location.
146      */
147     private static final int IV2 = 10;
148 
149     /**
150      * IV3 State Location.
151      */
152     private static final int IV3 = 11;
153 
154     /**
155      * Count0 State Location.
156      */
157     private static final int COUNT0 = 12;
158 
159     /**
160      * Count1 State Location.
161      */
162     private static final int COUNT1 = 13;
163 
164     /**
165      * DataLen State Location.
166      */
167     private static final int DATALEN = 14;
168 
169     /**
170      * Flags State Location.
171      */
172     private static final int FLAGS = 15;
173 
174     /**
175      * Message word permutations.
176      */
177     private static final byte[] SIGMA = {2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8};
178 
179     /**
180      * Rotation constants.
181      */
182     private static final byte[] ROTATE = {16, 12, 8, 7};
183 
184     /**
185      * Blake3 Initialization Vector.
186      */
187     private static final int[] IV = {
188             0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
189     };
190 
191     /**
192      * The byte input/output buffer.
193      */
194     private final byte[] theBuffer = new byte[BLOCKLEN];
195 
196     /**
197      * The key.
198      */
199     private final int[] theK = new int[NUMWORDS];
200 
201     /**
202      * The chaining value.
203      */
204     private final int[] theChaining = new int[NUMWORDS];
205 
206     /**
207      * The state.
208      */
209     private final int[] theV = new int[NUMWORDS << 1];
210 
211     /**
212      * The message Buffer.
213      */
214     private final int[] theM = new int[NUMWORDS << 1];
215 
216     /**
217      * The indices.
218      */
219     private final byte[] theIndices = new byte[NUMWORDS << 1];
220 
221     /**
222      * The chainingStack.
223      */
224     private final Deque<int[]> theStack = new ArrayDeque<>();
225 
226     /**
227      * The default digestLength.
228      */
229     private final int theDigestLen;
230 
231     /**
232      * Are we outputting?
233      */
234     private boolean outputting;
235 
236     /**
237      * How many more bytes can we output?
238      */
239     private long outputAvailable;
240 
241     /**
242      * The current mode.
243      */
244     private int theMode;
245 
246     /**
247      * The output mode.
248      */
249     private int theOutputMode;
250 
251     /**
252      * The output dataLen.
253      */
254     private int theOutputDataLen;
255 
256     /**
257      * The block counter.
258      */
259     private long theCounter;
260 
261     /**
262      * The # of bytes in the current block.
263      */
264     private int theCurrBytes;
265 
266     /**
267      * The position of the next byte in the buffer.
268      */
269     private int thePos;
270 
271     /**
272      * Constructor.
273      */
274     public GordianBlake3Digest() {
275         this(BLOCKLEN >> 1);
276     }
277 
278     /**
279      * Constructor.
280      *
281      * @param pDigestLen the default digestLength
282      */
283     public GordianBlake3Digest(final int pDigestLen) {
284         theDigestLen = pDigestLen;
285         init(null);
286     }
287 
288     /**
289      * Constructor.
290      *
291      * @param pSource the source digest.
292      */
293     private GordianBlake3Digest(final GordianBlake3Digest pSource) {
294         /* Copy default digest length */
295         theDigestLen = pSource.theDigestLen;
296 
297         /* Initialise from source */
298         reset(pSource);
299     }
300 
301     @Override
302     public int getByteLength() {
303         return BLOCKLEN;
304     }
305 
306     @Override
307     public String getAlgorithmName() {
308         return "BLAKE3";
309     }
310 
311     @Override
312     public int getDigestSize() {
313         return theDigestLen;
314     }
315 
316     /**
317      * Initialise.
318      *
319      * @param pParams the parameters.
320      */
321     public void init(final GordianBlake3Parameters pParams) {
322         /* Access key/context */
323         final byte[] myKey = pParams == null ? null : pParams.getKey();
324         final byte[] myContext = pParams == null ? null : pParams.getContext();
325 
326         /* Reset the digest */
327         reset();
328 
329         /* If we have a key  */
330         if (myKey != null) {
331             /* Initialise with the key */
332             initKey(myKey);
333             Arrays.fill(myKey, (byte) 0);
334 
335             /* else if we have a context */
336         } else if (myContext != null) {
337             /* Initialise for deriving context */
338             initNullKey();
339             theMode = DERIVECONTEXT;
340 
341             /* Derive key from context */
342             update(myContext, 0, myContext.length);
343             doFinal(theBuffer, 0);
344             initKeyFromContext();
345             reset();
346 
347             /* Else init null key and reset mode */
348         } else {
349             initNullKey();
350             theMode = 0;
351         }
352     }
353 
354     @Override
355     public void update(final byte b) {
356         /* Check that we are not outputting */
357         if (outputting) {
358             throw new IllegalStateException(ERR_OUTPUTTING);
359         }
360 
361         /* If the buffer is full */
362         final int blockLen = theBuffer.length;
363         final int remainingLength = blockLen - thePos;
364         if (remainingLength == 0) {
365             /* Process the buffer */
366             compressBlock(theBuffer, 0);
367 
368             /* Reset the buffer */
369             Arrays.fill(theBuffer, (byte) 0);
370             thePos = 0;
371         }
372 
373         /* Store the byte */
374         theBuffer[thePos] = b;
375         thePos++;
376     }
377 
378     @Override
379     public void update(final byte[] pMessage,
380                        final int pOffset,
381                        final int pLen) {
382         /* Ignore null operation */
383         if (pMessage == null || pLen == 0) {
384             return;
385         }
386 
387         /* Check that we are not outputting */
388         if (outputting) {
389             throw new IllegalStateException(ERR_OUTPUTTING);
390         }
391 
392         /* Process any bytes currently in the buffer */
393         int remainingLen = 0; // left bytes of buffer
394         if (thePos != 0) {
395             /* Calculate space remaining in the buffer */
396             remainingLen = BLOCKLEN - thePos;
397 
398             /* If there is sufficient space in the buffer */
399             if (remainingLen >= pLen) {
400                 /* Copy data into byffer and return */
401                 System.arraycopy(pMessage, pOffset, theBuffer, thePos, pLen);
402                 thePos += pLen;
403                 return;
404             }
405 
406             /* Fill the buffer */
407             System.arraycopy(pMessage, pOffset, theBuffer, thePos, remainingLen);
408 
409             /* Process the buffer */
410             compressBlock(theBuffer, 0);
411 
412             /* Reset the buffer */
413             thePos = 0;
414             Arrays.fill(theBuffer, (byte) 0);
415         }
416 
417         /* process all blocks except the last one */
418         int messagePos;
419         final int blockWiseLastPos = pOffset + pLen - BLOCKLEN;
420         for (messagePos = pOffset + remainingLen; messagePos < blockWiseLastPos; messagePos += BLOCKLEN) {
421             /* Process the buffer */
422             compressBlock(pMessage, messagePos);
423         }
424 
425         /* Fill the buffer with the remaining bytes of the message */
426         final int len = pLen - messagePos;
427         System.arraycopy(pMessage, messagePos, theBuffer, 0, pOffset + len);
428         thePos += pOffset + len;
429     }
430 
431     @Override
432     public int doFinal(final byte[] pOutput,
433                        final int pOutOffset) {
434         return doFinal(pOutput, pOutOffset, getDigestSize());
435     }
436 
437     @Override
438     public int doFinal(final byte[] pOut,
439                        final int pOutOffset,
440                        final int pOutLen) {
441         /* Build the required output */
442         final int length = doOutput(pOut, pOutOffset, pOutLen);
443 
444         /* reset the underlying digest and return the length */
445         reset();
446         return length;
447     }
448 
449     @Override
450     public int doOutput(final byte[] pOut,
451                         final int pOutOffset,
452                         final int pOutLen) {
453         /* If we have not started outputting yet */
454         if (!outputting) {
455             /* Process the buffer */
456             compressFinalBlock(thePos);
457         }
458 
459         /* Reject if there is insufficient Xof remaining */
460         if (pOutLen < 0
461                 || (outputAvailable >= 0 && pOutLen > outputAvailable)) {
462             throw new IllegalArgumentException("Insufficient bytes remaining");
463         }
464 
465         /* If we have some remaining data in the current buffer */
466         int dataLeft = pOutLen;
467         int outPos = pOutOffset;
468         if (thePos < BLOCKLEN) {
469             /* Copy data from current hash */
470             final int dataToCopy = Math.min(dataLeft, BLOCKLEN - thePos);
471             System.arraycopy(theBuffer, thePos, pOut, outPos, dataToCopy);
472 
473             /* Adjust counters */
474             thePos += dataToCopy;
475             outPos += dataToCopy;
476             dataLeft -= dataToCopy;
477         }
478 
479         /* Loop until we have completed the request */
480         while (dataLeft > 0) {
481             /* Calculate the next block */
482             nextOutputBlock();
483 
484             /* Copy data from current hash */
485             final int dataToCopy = Math.min(dataLeft, BLOCKLEN);
486             System.arraycopy(theBuffer, 0, pOut, outPos, dataToCopy);
487 
488             /* Adjust counters */
489             thePos += dataToCopy;
490             outPos += dataToCopy;
491             dataLeft -= dataToCopy;
492         }
493 
494         /* Adjust outputAvailable */
495         outputAvailable -= pOutLen;
496 
497         /* Return the number of bytes transferred */
498         return pOutLen;
499     }
500 
501     @Override
502     public void reset() {
503         resetBlockCount();
504         thePos = 0;
505         outputting = false;
506         Arrays.fill(theBuffer, (byte) 0);
507     }
508 
509     @Override
510     public void reset(final Memoable pSource) {
511         /* Access source */
512         final GordianBlake3Digest mySource = (GordianBlake3Digest) pSource;
513 
514         /*  Reset counter */
515         theCounter = mySource.theCounter;
516         theCurrBytes = mySource.theCurrBytes;
517         theMode = mySource.theMode;
518 
519         /* Reset output state */
520         outputting = mySource.outputting;
521         outputAvailable = mySource.outputAvailable;
522         theOutputMode = mySource.theOutputMode;
523         theOutputDataLen = mySource.theOutputDataLen;
524 
525         /* Copy state */
526         System.arraycopy(mySource.theChaining, 0, theChaining, 0, theChaining.length);
527         System.arraycopy(mySource.theK, 0, theK, 0, theK.length);
528         System.arraycopy(mySource.theM, 0, theM, 0, theM.length);
529 
530         /* Copy stack */
531         theStack.clear();
532         for (int[] myEntry : mySource.theStack) {
533             theStack.push(myEntry.clone());
534         }
535 
536         /* Copy buffer */
537         System.arraycopy(mySource.theBuffer, 0, theBuffer, 0, theBuffer.length);
538         thePos = mySource.thePos;
539     }
540 
541     @Override
542     public GordianBlake3Digest copy() {
543         return new GordianBlake3Digest(this);
544     }
545 
546     /**
547      * Compress next block of the message.
548      *
549      * @param pMessage the message buffer
550      * @param pMsgPos  the position within the message buffer
551      */
552     private void compressBlock(final byte[] pMessage,
553                                final int pMsgPos) {
554         /* Initialise state and compress message */
555         initChunkBlock(BLOCKLEN, false);
556         initM(pMessage, pMsgPos);
557         compress();
558 
559         /* Adjust stack if we have completed a block */
560         if (theCurrBytes == 0) {
561             adjustStack();
562         }
563     }
564 
565     /**
566      * Adjust the stack.
567      */
568     private void adjustStack() {
569         /* Loop to combine blocks */
570         long myCount = theCounter;
571         while (myCount > 0) {
572             /* Break loop if we are not combining */
573             if ((myCount & 1) == 1) {
574                 break;
575             }
576 
577             /* Build the message to be hashed */
578             final int[] myLeft = theStack.pop();
579             System.arraycopy(myLeft, 0, theM, 0, NUMWORDS);
580             System.arraycopy(theChaining, 0, theM, NUMWORDS, NUMWORDS);
581 
582             /* Create parent block */
583             initParentBlock();
584             compress();
585 
586             /* Next block */
587             myCount >>= 1;
588         }
589 
590         /* Add back to the stack */
591         theStack.push(Arrays.copyOf(theChaining, NUMWORDS));
592     }
593 
594     /**
595      * Compress final block.
596      *
597      * @param pDataLen the data length
598      */
599     private void compressFinalBlock(final int pDataLen) {
600         /* Initialise state and compress message */
601         initChunkBlock(pDataLen, true);
602         initM(theBuffer, 0);
603         compress();
604 
605         /* Finalise stack */
606         processStack();
607     }
608 
609     /**
610      * Process the stack.
611      */
612     private void processStack() {
613         /* Finalise stack */
614         while (!theStack.isEmpty()) {
615             /* Build the message to be hashed */
616             final int[] myLeft = theStack.pop();
617             System.arraycopy(myLeft, 0, theM, 0, NUMWORDS);
618             System.arraycopy(theChaining, 0, theM, NUMWORDS, NUMWORDS);
619 
620             /* Create parent block */
621             initParentBlock();
622             if (theStack.isEmpty()) {
623                 setRoot();
624             }
625             compress();
626         }
627     }
628 
629     /**
630      * Perform compression.
631      */
632     private void compress() {
633         /* Initialise the buffers */
634         initIndices();
635 
636         /* Loop through the rounds */
637         for (int round = 0; round < ROUNDS - 1; round++) {
638             /* Perform the round and permuteM */
639             performRound();
640             permuteIndices();
641         }
642         performRound();
643         adjustChaining();
644     }
645 
646     /**
647      * Perform a round.
648      */
649     private void performRound() {
650         /* Apply to columns of V */
651         int idx = 0;
652         mixG(idx++, CHAINING0, CHAINING4, IV0, COUNT0);
653         mixG(idx++, CHAINING1, CHAINING5, IV1, COUNT1);
654         mixG(idx++, CHAINING2, CHAINING6, IV2, DATALEN);
655         mixG(idx++, CHAINING3, CHAINING7, IV3, FLAGS);
656 
657         /* Apply to diagonals of V */
658         mixG(idx++, CHAINING0, CHAINING5, IV2, FLAGS);
659         mixG(idx++, CHAINING1, CHAINING6, IV3, COUNT0);
660         mixG(idx++, CHAINING2, CHAINING7, IV0, COUNT1);
661         mixG(idx, CHAINING3, CHAINING4, IV1, DATALEN);
662     }
663 
664     /**
665      * Initialise M from message.
666      *
667      * @param pMessage the source message
668      * @param pMsgPos  the message position
669      */
670     private void initM(final byte[] pMessage,
671                        final int pMsgPos) {
672         /* Copy message bytes into word array */
673         for (int i = 0; i < NUMWORDS << 1; i++) {
674             theM[i] = Pack.littleEndianToInt(pMessage, pMsgPos + i * Integer.BYTES);
675         }
676     }
677 
678     /**
679      * Adjust Chaining after compression.
680      */
681     private void adjustChaining() {
682         /* If we are outputting */
683         if (outputting) {
684             /* Adjust full state */
685             for (int i = 0; i < NUMWORDS; i++) {
686                 theV[i] ^= theV[i + NUMWORDS];
687                 theV[i + NUMWORDS] ^= theChaining[i];
688             }
689 
690             /* Output state to buffer */
691             for (int i = 0; i < NUMWORDS << 1; i++) {
692                 Pack.intToLittleEndian(theV[i], theBuffer, i * Integer.BYTES);
693             }
694             thePos = 0;
695 
696             /* Else just build chain value */
697         } else {
698             /* Combine V into Chaining */
699             for (int i = 0; i < NUMWORDS; i++) {
700                 theChaining[i] = theV[i] ^ theV[i + NUMWORDS];
701             }
702         }
703     }
704 
705     /**
706      * Mix function G.
707      *
708      * @param msgIdx the message index
709      * @param posA   position A in V
710      * @param posB   position B in V
711      * @param posC   position C in V
712      * @param posD   poistion D in V
713      */
714     private void mixG(final int msgIdx,
715                       final int posA,
716                       final int posB,
717                       final int posC,
718                       final int posD) {
719         /* Determine indices */
720         int msg = msgIdx << 1;
721         int rot = 0;
722 
723         /* Perform the Round */
724         theV[posA] += theV[posB] + theM[theIndices[msg++]];
725         theV[posD] = rotr32(theV[posD] ^ theV[posA], ROTATE[rot++]);
726         theV[posC] += theV[posD];
727         theV[posB] = rotr32(theV[posB] ^ theV[posC], ROTATE[rot++]);
728         theV[posA] += theV[posB] + theM[theIndices[msg]];
729         theV[posD] = rotr32(theV[posD] ^ theV[posA], ROTATE[rot++]);
730         theV[posC] += theV[posD];
731         theV[posB] = rotr32(theV[posB] ^ theV[posC], ROTATE[rot]);
732     }
733 
734     /**
735      * initialise the indices.
736      */
737     private void initIndices() {
738         for (byte i = 0; i < theIndices.length; i++) {
739             theIndices[i] = i;
740         }
741     }
742 
743     /**
744      * PermuteIndices.
745      */
746     private void permuteIndices() {
747         for (byte i = 0; i < theIndices.length; i++) {
748             theIndices[i] = SIGMA[theIndices[i]];
749         }
750     }
751 
752     /**
753      * Rotate an int right.
754      *
755      * @param x   the value to rotate
756      * @param rot the number of bits to rotate
757      * @return the result
758      */
759     private static int rotr32(final int x,
760                               final int rot) {
761         return x >>> rot | (x << (Integer.SIZE - rot));
762     }
763 
764     /**
765      * Initialise null key.
766      */
767     private void initNullKey() {
768         System.arraycopy(IV, 0, theK, 0, NUMWORDS);
769     }
770 
771     /**
772      * Initialise key.
773      *
774      * @param pKey the keyBytes
775      */
776     private void initKey(final byte[] pKey) {
777         /* Copy message bytes into word array */
778         for (int i = 0; i < NUMWORDS; i++) {
779             theK[i] = Pack.littleEndianToInt(pKey, i * Integer.BYTES);
780         }
781         theMode = KEYEDHASH;
782     }
783 
784     /**
785      * Initialise key from context.
786      */
787     private void initKeyFromContext() {
788         System.arraycopy(theV, 0, theK, 0, NUMWORDS);
789         theMode = DERIVEKEY;
790     }
791 
792     /**
793      * Initialise chunk block.
794      *
795      * @param pDataLen the dataLength
796      * @param pFinal   is this the final chunk?
797      */
798     private void initChunkBlock(final int pDataLen,
799                                 final boolean pFinal) {
800         /* Initialise the block */
801         System.arraycopy(theCurrBytes == 0 ? theK : theChaining, 0, theV, 0, NUMWORDS);
802         System.arraycopy(IV, 0, theV, NUMWORDS, NUMWORDS >> 1);
803         theV[COUNT0] = (int) theCounter;
804         theV[COUNT1] = (int) (theCounter >> Integer.SIZE);
805         theV[DATALEN] = pDataLen;
806         theV[FLAGS] = theMode
807                 + (theCurrBytes == 0 ? CHUNKSTART : 0)
808                 + (pFinal ? CHUNKEND : 0);
809 
810         /* * Adjust block count */
811         theCurrBytes += pDataLen;
812         if (theCurrBytes >= CHUNKLEN) {
813             incrementBlockCount();
814             theV[FLAGS] |= CHUNKEND;
815         }
816 
817         /* If we are single chunk */
818         if (pFinal && theStack.isEmpty()) {
819             setRoot();
820         }
821     }
822 
823     /**
824      * Initialise parent block.
825      */
826     private void initParentBlock() {
827         /* Initialise the block */
828         System.arraycopy(theK, 0, theV, 0, NUMWORDS);
829         System.arraycopy(IV, 0, theV, NUMWORDS, NUMWORDS >> 1);
830         theV[COUNT0] = 0;
831         theV[COUNT1] = 0;
832         theV[DATALEN] = BLOCKLEN;
833         theV[FLAGS] = theMode | PARENT;
834     }
835 
836     /**
837      * Initialise output block.
838      */
839     private void nextOutputBlock() {
840         /* Increment the counter */
841         theCounter++;
842 
843         /* Initialise the block */
844         System.arraycopy(theChaining, 0, theV, 0, NUMWORDS);
845         System.arraycopy(IV, 0, theV, NUMWORDS, NUMWORDS >> 1);
846         theV[COUNT0] = (int) theCounter;
847         theV[COUNT1] = (int) (theCounter >> Integer.SIZE);
848         theV[DATALEN] = theOutputDataLen;
849         theV[FLAGS] = theOutputMode;
850 
851         /* Generate output */
852         compress();
853     }
854 
855     /**
856      * IncrementBlockCount.
857      */
858     private void incrementBlockCount() {
859         theCounter++;
860         theCurrBytes = 0;
861     }
862 
863     /**
864      * ResetBlockCount.
865      */
866     private void resetBlockCount() {
867         theCounter = 0;
868         theCurrBytes = 0;
869     }
870 
871     /**
872      * Set root indication.
873      */
874     private void setRoot() {
875         theV[FLAGS] |= ROOT;
876         theOutputMode = theV[FLAGS];
877         theOutputDataLen = theV[DATALEN];
878         theCounter = 0;
879         outputting = true;
880         outputAvailable = -1;
881         System.arraycopy(theV, 0, theChaining, 0, NUMWORDS);
882     }
883 }