Coverage Report

Created: 2026-11-12 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dcmtk/ofstd/libsrc/ofrand.cc
Line
Count
Source
1
/*
2
 *
3
 *  Copyright (C) 2021-2025, OFFIS e.V.
4
 *  All rights reserved.  See COPYRIGHT file for details.
5
 *
6
 *  This software and supporting documentation were developed by
7
 *
8
 *    OFFIS e.V.
9
 *    R&D Division Health
10
 *    Escherweg 2
11
 *    D-26121 Oldenburg, Germany
12
 *
13
 *
14
 *  Module:  ofstd
15
 *
16
 *  Author:  Marco Eichelberg, based on the reference implementation
17
 *   of the ISAAC PRNG by Bob Jenkins (Public Domain).
18
 *
19
 *  Purpose: Cryptographically secure PRNG based on Bob Jenkins's ISAAC algorithm
20
 *
21
 */
22
23
#include "dcmtk/config/osconfig.h"
24
#include "dcmtk/ofstd/ofrand.h"
25
#include "dcmtk/ofstd/ofcast.h"
26
#include "dcmtk/ofstd/ofstd.h"
27
#include "dcmtk/ofstd/ofstdinc.h"
28
#include <ctime>
29
30
31
BEGIN_EXTERN_C
32
#ifdef HAVE_SYS_TIME_H
33
#include <sys/time.h>
34
#endif
35
END_EXTERN_C
36
37
#ifdef HAVE_WINDOWS_H
38
#define WIN32_LEAN_AND_MEAN
39
#include <windows.h>
40
#endif
41
42
0
#define ind(mm,x)  ((mm)[(x>>2)&(OFRandom_SIZ-1)])
43
44
0
#define rngstep(mix,a,b,mm,m,m2,r,x) \
45
0
{ \
46
0
  x = *m;  \
47
0
  a = ((a^(mix)) + *(m2++)); \
48
0
  *(m++) = y = (ind(mm,x) + a + b); \
49
0
  *(r++) = b = (ind(mm,y>>OFRandom_SIZL) + x) & 0xffffffff; \
50
0
}
51
52
0
#define mix(a,b,c,d,e,f,g,h) \
53
0
{ \
54
0
   a^=b<<11;              d+=a; b+=c; \
55
0
   b^=(c&0xffffffff)>>2;  e+=b; c+=d; \
56
0
   c^=d<<8;               f+=c; d+=e; \
57
0
   d^=(e&0xffffffff)>>16; g+=d; e+=f; \
58
0
   e^=f<<10;              h+=e; f+=g; \
59
0
   f^=(g&0xffffffff)>>4;  a+=f; g+=h; \
60
0
   g^=h<<8;               b+=g; h+=a; \
61
0
   h^=(a&0xffffffff)>>9;  c+=h; a+=b; \
62
0
}
63
64
OFRandom::OFRandom()
65
0
: randcnt(OFRandom_SIZ)
66
, randrsl()
67
, randmem()
68
0
, randa(0)
69
0
, randb(0)
70
0
, randc(0)
71
0
{
72
   /* initialize randrsl based on the current time, CPU clock count, and process ID */
73
0
   Uint32 tm = OFstatic_cast(Uint32, time(NULL));
74
0
   Uint32 cl = OFstatic_cast(Uint32, clock());
75
0
   Uint32 pi = OFstatic_cast(Uint32, OFStandard::getProcessID());
76
77
#ifdef _WIN32
78
    ULARGE_INTEGER wintm;
79
    /* tm is number of 100ns ticks since Jan 01 1601.
80
     * We only use the lowest 32 bits of this number.
81
     */
82
    GetSystemTimeAsFileTime(OFreinterpret_cast(FILETIME *, &wintm));
83
    Uint32 tm2 = OFstatic_cast(Uint32, wintm.LowPart);
84
#else
85
0
    struct timeval posixtm;
86
0
    gettimeofday(&posixtm, NULL);
87
    /* sub-second part of current time in microseconds */
88
0
    Uint32 tm2 = OFstatic_cast(Uint32, posixtm.tv_usec);
89
0
#endif
90
91
0
   for (int i=0; i<OFRandom_SIZ; i += 4)  // OFRandom_SIZ is dividable by 4
92
0
   {
93
0
     randrsl[i] = tm++;
94
0
     randrsl[i+1] = cl++;
95
0
     randrsl[i+2] = pi++;
96
0
     randrsl[i+3] = tm2++;
97
0
   }
98
99
0
   mixSeed();
100
0
}
101
102
void OFRandom::mixSeed()
103
0
{
104
0
   int i;
105
0
   Uint32 a,b,c,d,e,f,g,h;
106
0
   a=b=c=d=e=f=g=h=0x9e3779b9;  /* the golden ratio */
107
108
0
   for (i=0; i<4; ++i) /* scramble it */
109
0
   {
110
0
     mix(a,b,c,d,e,f,g,h);
111
0
   }
112
113
   /* initialize using the contents of randrsl[] as the seed */
114
0
   for (i=0; i<OFRandom_SIZ; i+=8)
115
0
   {
116
0
     a+=randrsl[i  ]; b+=randrsl[i+1];
117
0
     c+=randrsl[i+2]; d+=randrsl[i+3];
118
0
     e+=randrsl[i+4]; f+=randrsl[i+5];
119
0
     g+=randrsl[i+6]; h+=randrsl[i+7];
120
0
     mix(a,b,c,d,e,f,g,h);
121
0
     randmem[i  ]=a; randmem[i+1]=b; randmem[i+2]=c; randmem[i+3]=d;
122
0
     randmem[i+4]=e; randmem[i+5]=f; randmem[i+6]=g; randmem[i+7]=h;
123
0
   }
124
   /* do a second pass to make all of the seed affect all of m */
125
0
   for (i=0; i<OFRandom_SIZ; i+=8)
126
0
   {
127
0
     a+=randmem[i  ]; b+=randmem[i+1];
128
0
     c+=randmem[i+2]; d+=randmem[i+3];
129
0
     e+=randmem[i+4]; f+=randmem[i+5];
130
0
     g+=randmem[i+6]; h+=randmem[i+7];
131
0
     mix(a,b,c,d,e,f,g,h);
132
0
     randmem[i  ]=a; randmem[i+1]=b; randmem[i+2]=c; randmem[i+3]=d;
133
0
     randmem[i+4]=e; randmem[i+5]=f; randmem[i+6]=g; randmem[i+7]=h;
134
0
   }
135
136
0
   isaac(); /* fill in the first set of results */}
137
138
void OFRandom::seed(Uint32 sval)
139
0
{
140
0
   for (int i=0; i<OFRandom_SIZ; i++)
141
0
   {
142
0
     randrsl[i] = sval;
143
0
   }
144
0
   randa = 0;
145
0
   randb = 0;
146
0
   randc = 0;
147
0
   mixSeed();
148
0
}
149
150
void OFRandom::isaac()
151
0
{
152
0
   Uint32 x,y,*m,*m2,*mend;
153
0
   Uint32 *r = randrsl;
154
0
   Uint32 a = randa;
155
0
   Uint32 b = randb + (++randc);
156
0
   for (m = randmem, mend = m2 = m+(OFRandom_SIZ/2); m<mend; )
157
0
   {
158
0
      rngstep( a<<13, a, b, randmem, m, m2, r, x);
159
0
      rngstep( (a & 0xffffffff) >>6 , a, b, randmem, m, m2, r, x);
160
0
      rngstep( a<<2 , a, b, randmem, m, m2, r, x);
161
0
      rngstep( (a & 0xffffffff) >>16, a, b, randmem, m, m2, r, x);
162
0
   }
163
0
   for (m2 = randmem; m2<mend; )
164
0
   {
165
0
      rngstep( a<<13, a, b, randmem, m, m2, r, x);
166
0
      rngstep( (a & 0xffffffff) >>6 , a, b, randmem, m, m2, r, x);
167
0
      rngstep( a<<2 , a, b, randmem, m, m2, r, x);
168
0
      rngstep( (a & 0xffffffff) >>16, a, b, randmem, m, m2, r, x);
169
0
   }
170
0
   randb = b; randa = a;
171
0
   randcnt = OFRandom_SIZ;
172
0
}
173
174
Uint32 OFRandom::getRND32()
175
0
{
176
  // check if we still have random numbers left
177
0
  if (randcnt == 0) isaac();
178
179
  // we use the random numbers from last to first
180
0
  return randrsl[--randcnt];
181
0
}
182
183
Uint16 OFRandom::getRND16()
184
0
{
185
  // use one 32-bit random number and ignore the extra bits
186
0
  return OFstatic_cast(Uint16, getRND32());
187
0
}
188
189
Uint8 OFRandom::getRND8()
190
0
{
191
  // use one 32-bit random number and ignore the extra bits
192
0
  return OFstatic_cast(Uint8, getRND32());
193
0
}
194
195
Uint64 OFRandom::getRND64()
196
0
{
197
  // get a 32-bit random number
198
0
  Uint64 result = getRND32();
199
  // shift into upper 32 bits of the 64-bit word
200
0
  result <<= 32;
201
  // get a second 32-bit random number
202
0
  result |= getRND32();
203
0
  return result;
204
0
}