digest 3.2.1-java → 3.3.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fd920ad0b031fd02eef7dcd794262cfe46036609989fc22b62879eb29d39658a
4
- data.tar.gz: f3e4d408d42eaf8a2a55070f3999d4224d49e17ce60cb5ab2dfafd7432b04c25
3
+ metadata.gz: 38a4e6158ff60fed79aee97551d7a1d59e51ed04b924a1a722c459663dee8807
4
+ data.tar.gz: b7b5775a2e636c8b3c9412b41308c87fe016d8099cb481724c06bc091bec9e94
5
5
  SHA512:
6
- metadata.gz: 1f3fe160be2cc1707c393433cb763faba5ed751e8a300c59997756fec3f6ee8883147911e8f957e8b1b6f08919ab98b52c86b1e245ab5ebc1d24d06160535c7b
7
- data.tar.gz: ab27ad07eaeeb2734bac974b33e8bff20f621d452320aa7b009a1c2553a4349c342cc5c70453cc0c0aa92b2b6b92c843263e306b85647b9ce890b30dccd93dfc
6
+ metadata.gz: d27a3d5a2bc2a2daf1ea25fca62461c0b172d3042dd65a447331357f8c975471826e470d30ed1bac99e463df30100ccf691796c508599d42c547171e81ca3437
7
+ data.tar.gz: 8e154a83b2b2d5c8e60ef26ec4e2b56d7de4ef437c8e11f35e1a3ae93aa26f819085e3907f708d2c4ff802506c431693d65913f40452d5edf3a825e62133ec51
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Digest
2
2
 
3
- ![CI](https://github.com/ruby/digest/workflows/CI/badge.svg?branch=master&event=push)
3
+ [![CI](https://github.com/ruby/digest/actions/workflows/ci.yml/badge.svg?branch=master&event=push)](https://github.com/ruby/digest/actions/workflows/ci.yml)
4
4
 
5
5
  This module provides a framework for message digest libraries.
6
6
 
@@ -78,6 +78,9 @@ SHA2 family::
78
78
  SHA512
79
79
  SHA384
80
80
  SHA256
81
+ BLAKE3::
82
+ As Digest::BLAKE3, producing a 256-bit digest.
83
+ See https://github.com/BLAKE3-team/BLAKE3.
81
84
  ```
82
85
 
83
86
  The latest versions of the FIPS publications can be found here: http://csrc.nist.gov/publications/PubsFIPS.html.
@@ -0,0 +1,127 @@
1
+ /*
2
+ **** BEGIN LICENSE BLOCK *****
3
+ * BSD 2-Clause License
4
+ *
5
+ * Copyright (c) 2026, Olle Jonsson
6
+ * All rights reserved.
7
+ *
8
+ * Redistribution and use in source and binary forms, with or without
9
+ * modification, are permitted provided that the following conditions are met:
10
+ *
11
+ * 1. Redistributions of source code must retain the above copyright notice, this
12
+ * list of conditions and the following disclaimer.
13
+ *
14
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
15
+ * this list of conditions and the following disclaimer in the documentation
16
+ * and/or other materials provided with the distribution.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ ***** END LICENSE BLOCK *****/
29
+
30
+ package org.jruby.ext.digest;
31
+
32
+ import java.io.IOException;
33
+
34
+ import org.jruby.Ruby;
35
+ import org.jruby.RubyClass;
36
+ import org.jruby.RubyFixnum;
37
+ import org.jruby.RubyModule;
38
+ import org.jruby.RubyObject;
39
+ import org.jruby.RubyString;
40
+ import org.jruby.anno.JRubyClass;
41
+ import org.jruby.anno.JRubyMethod;
42
+ import org.jruby.api.Access;
43
+ import org.jruby.runtime.ThreadContext;
44
+ import org.jruby.runtime.Visibility;
45
+ import org.jruby.runtime.builtin.IRubyObject;
46
+ import org.jruby.runtime.load.Library;
47
+ import org.jruby.util.ByteList;
48
+
49
+ public class CRC32 implements Library {
50
+
51
+ public void load(final Ruby runtime, boolean wrap) throws IOException {
52
+ runtime.getLoadService().require("digest");
53
+ ThreadContext context = runtime.getCurrentContext();
54
+ RubyModule Digest = Access.getModule(context, "Digest");
55
+ RubyClass Base = Digest.getClass(context, "Base");
56
+ RubyClass crc32 = Digest.defineClassUnder(context, "CRC32", Base, DigestCRC32::new);
57
+ crc32.defineMethods(context, DigestCRC32.class);
58
+ }
59
+
60
+ private static final class CloneableCRC32 extends java.util.zip.CRC32 implements Cloneable {
61
+ @Override
62
+ public CloneableCRC32 clone() throws CloneNotSupportedException {
63
+ return (CloneableCRC32) super.clone();
64
+ }
65
+ }
66
+
67
+ @JRubyClass(name="Digest::CRC32", parent="Digest::Base")
68
+ public static class DigestCRC32 extends RubyObject {
69
+ private static final long serialVersionUID = -2811470471354871234L;
70
+
71
+ private transient CloneableCRC32 crc = new CloneableCRC32();
72
+
73
+ public DigestCRC32(Ruby runtime, RubyClass type) {
74
+ super(runtime, type);
75
+ }
76
+
77
+ @JRubyMethod(required = 1, visibility = Visibility.PRIVATE)
78
+ @Override
79
+ public IRubyObject initialize_copy(ThreadContext context, IRubyObject obj) {
80
+ if (this == obj) return this;
81
+ DigestCRC32 from = (DigestCRC32) obj;
82
+ this.checkFrozen();
83
+ try {
84
+ this.crc = from.crc.clone();
85
+ } catch (CloneNotSupportedException e) {
86
+ throw getRuntime().newRaiseException(getRuntime().getTypeError(), "Could not initialize copy of Digest::CRC32");
87
+ }
88
+ return this;
89
+ }
90
+
91
+ @JRubyMethod(name = {"update", "<<"}, required = 1)
92
+ public IRubyObject update(IRubyObject obj) {
93
+ ByteList bytes = obj.convertToString().getByteList();
94
+ crc.update(bytes.getUnsafeBytes(), bytes.getBegin(), bytes.getRealSize());
95
+ return this;
96
+ }
97
+
98
+ @JRubyMethod()
99
+ public IRubyObject finish() {
100
+ long val = crc.getValue();
101
+ crc.reset();
102
+ byte[] digest = new byte[] {
103
+ (byte)(val >>> 24),
104
+ (byte)(val >>> 16),
105
+ (byte)(val >>> 8),
106
+ (byte) val
107
+ };
108
+ return RubyString.newStringNoCopy(getRuntime(), digest);
109
+ }
110
+
111
+ @JRubyMethod()
112
+ public IRubyObject reset() {
113
+ crc.reset();
114
+ return this;
115
+ }
116
+
117
+ @JRubyMethod()
118
+ public IRubyObject digest_length() {
119
+ return RubyFixnum.newFixnum(getRuntime(), 4);
120
+ }
121
+
122
+ @JRubyMethod()
123
+ public IRubyObject block_length() {
124
+ return RubyFixnum.newFixnum(getRuntime(), 8);
125
+ }
126
+ }
127
+ }
@@ -49,6 +49,8 @@ import org.jruby.RubyString;
49
49
  import org.jruby.anno.JRubyClass;
50
50
  import org.jruby.anno.JRubyMethod;
51
51
  import org.jruby.anno.JRubyModule;
52
+ import org.jruby.api.Access;
53
+ import org.jruby.api.Define;
52
54
  import org.jruby.exceptions.RaiseException;
53
55
  import org.jruby.runtime.Block;
54
56
  import org.jruby.runtime.ThreadContext;
@@ -56,6 +58,7 @@ import org.jruby.runtime.Visibility;
56
58
  import org.jruby.runtime.builtin.IRubyObject;
57
59
  import org.jruby.util.ArraySupport;
58
60
  import org.jruby.util.ByteList;
61
+ import org.jruby.util.TypeConverter;
59
62
  import org.jruby.util.log.Logger;
60
63
  import org.jruby.util.log.LoggerFactory;
61
64
 
@@ -91,15 +94,16 @@ public class RubyDigest {
91
94
  }
92
95
  catch (Throwable t) { /* provider is not available */ }
93
96
 
94
- RubyModule mDigest = runtime.defineModule("Digest");
95
- mDigest.defineAnnotatedMethods(RubyDigest.class);
96
- RubyModule mDigestInstance = mDigest.defineModuleUnder("Instance");
97
- mDigestInstance.defineAnnotatedMethods(DigestInstance.class);
98
- RubyClass cDigestClass = mDigest.defineClassUnder("Class", runtime.getObject(), DigestClass::new);
99
- cDigestClass.defineAnnotatedMethods(DigestClass.class);
100
- cDigestClass.includeModule(mDigestInstance);
101
- RubyClass cDigestBase = mDigest.defineClassUnder("Base", cDigestClass, DigestBase::new);
102
- cDigestBase.defineAnnotatedMethods(DigestBase.class);
97
+ ThreadContext context = runtime.getCurrentContext();
98
+ RubyModule mDigest = Define.defineModule(context, "Digest");
99
+ mDigest.defineMethods(context, RubyDigest.class);
100
+ RubyModule mDigestInstance = mDigest.defineModuleUnder(context, "Instance");
101
+ mDigestInstance.defineMethods(context, DigestInstance.class);
102
+ RubyClass cDigestClass = mDigest.defineClassUnder(context, "Class", runtime.getObject(), DigestClass::new);
103
+ cDigestClass.defineMethods(context, DigestClass.class);
104
+ cDigestClass.includeModule(context, mDigestInstance);
105
+ RubyClass cDigestBase = mDigest.defineClassUnder(context, "Base", cDigestClass, DigestBase::new);
106
+ cDigestBase.defineMethods(context, DigestBase.class);
103
107
  }
104
108
 
105
109
  private static MessageDigest createMessageDigest(final String name) throws NoSuchAlgorithmException {
@@ -196,9 +200,10 @@ public class RubyDigest {
196
200
 
197
201
  public static void createDigestMD5(Ruby runtime) {
198
202
  runtime.getLoadService().require("digest");
199
- RubyModule Digest = runtime.getModule("Digest");
200
- RubyClass Base = Digest.getClass("Base");
201
- RubyClass MD5 = Digest.defineClassUnder("MD5", Base, Base.getAllocator());
203
+ ThreadContext context = runtime.getCurrentContext();
204
+ RubyModule Digest = Access.getModule(context, "Digest");
205
+ RubyClass Base = Digest.getClass(context, "Base");
206
+ RubyClass MD5 = Digest.defineClassUnder(context, "MD5", Base, Base.getAllocator());
202
207
  MD5.setInternalVariable("metadata", new Metadata("MD5", 64));
203
208
  }
204
209
 
@@ -207,17 +212,19 @@ public class RubyDigest {
207
212
  if(provider == null) {
208
213
  throw runtime.newLoadError("RMD160 not supported without BouncyCastle");
209
214
  }
210
- RubyModule Digest = runtime.getModule("Digest");
211
- RubyClass Base = Digest.getClass("Base");
212
- RubyClass RMD160 = Digest.defineClassUnder("RMD160", Base, Base.getAllocator());
215
+ ThreadContext context = runtime.getCurrentContext();
216
+ RubyModule Digest = Access.getModule(context, "Digest");
217
+ RubyClass Base = Digest.getClass(context, "Base");
218
+ RubyClass RMD160 = Digest.defineClassUnder(context, "RMD160", Base, Base.getAllocator());
213
219
  RMD160.setInternalVariable("metadata", new Metadata("RIPEMD160", 64));
214
220
  }
215
221
 
216
222
  public static void createDigestSHA1(Ruby runtime) {
217
223
  runtime.getLoadService().require("digest");
218
- RubyModule Digest = runtime.getModule("Digest");
219
- RubyClass Base = Digest.getClass("Base");
220
- RubyClass SHA1 = Digest.defineClassUnder("SHA1", Base, Base.getAllocator());
224
+ ThreadContext context = runtime.getCurrentContext();
225
+ RubyModule Digest = Access.getModule(context, "Digest");
226
+ RubyClass Base = Digest.getClass(context, "Base");
227
+ RubyClass SHA1 = Digest.defineClassUnder(context, "SHA1", Base, Base.getAllocator());
221
228
  SHA1.setInternalVariable("metadata", new Metadata("SHA1", 64));
222
229
  }
223
230
 
@@ -231,55 +238,57 @@ public class RubyDigest {
231
238
  ex.initCause(e);
232
239
  throw ex;
233
240
  }
234
- final RubyModule Digest = runtime.getModule("Digest");
235
- final RubyClass Base = Digest.getClass("Base");
236
- RubyClass SHA256 = Digest.defineClassUnder("SHA256", Base, Base.getAllocator());
241
+ ThreadContext context = runtime.getCurrentContext();
242
+ final RubyModule Digest = Access.getModule(context, "Digest");
243
+ final RubyClass Base = Digest.getClass(context, "Base");
244
+ RubyClass SHA256 = Digest.defineClassUnder(context, "SHA256", Base, Base.getAllocator());
237
245
  SHA256.setInternalVariable("metadata", new Metadata("SHA-256", 64));
238
- RubyClass SHA384 = Digest.defineClassUnder("SHA384", Base, Base.getAllocator());
246
+ RubyClass SHA384 = Digest.defineClassUnder(context, "SHA384", Base, Base.getAllocator());
239
247
  SHA384.setInternalVariable("metadata", new Metadata("SHA-384", 128));
240
- RubyClass SHA512 = Digest.defineClassUnder("SHA512", Base, Base.getAllocator());
248
+ RubyClass SHA512 = Digest.defineClassUnder(context, "SHA512", Base, Base.getAllocator());
241
249
  SHA512.setInternalVariable("metadata", new Metadata("SHA-512", 128));
242
250
  }
243
251
 
244
252
  public static void createDigestBubbleBabble(Ruby runtime) {
245
253
  runtime.getLoadService().require("digest");
246
- RubyModule Digest = runtime.getModule("Digest");
247
- RubyClass Base = Digest.getClass("Base");
248
- RubyClass MD5 = Digest.defineClassUnder("BubbleBabble", Base, Base.getAllocator());
254
+ ThreadContext context = runtime.getCurrentContext();
255
+ RubyModule Digest = Access.getModule(context, "Digest");
256
+ RubyClass Base = Digest.getClass(context, "Base");
257
+ RubyClass MD5 = Digest.defineClassUnder(context, "BubbleBabble", Base, Base.getAllocator());
249
258
  MD5.setInternalVariable("metadata", new Metadata("BubbleBabble", 64));
250
259
  }
251
260
 
252
261
  @JRubyModule(name = "Digest::Instance")
253
262
  public static class DigestInstance {
254
263
 
255
- private static IRubyObject throwUnimplError(IRubyObject self, String name) {
256
- throw self.getRuntime().newRuntimeError(String.format("%s does not implement %s()", self.getMetaClass().getRealClass().getName(), name));
264
+ private static IRubyObject throwUnimplError(ThreadContext context, IRubyObject self, String name) {
265
+ throw self.getRuntime().newRuntimeError(String.format("%s does not implement %s()", self.getMetaClass().getRealClass().getName(context), name));
257
266
  }
258
267
 
259
268
  /* instance methods that should be overridden */
260
269
  @JRubyMethod(name = {"update", "<<"}, required = 1)
261
270
  public static IRubyObject update(ThreadContext context, IRubyObject self, IRubyObject arg) {
262
- return throwUnimplError(self, "update");
271
+ return throwUnimplError(context, self, "update");
263
272
  }
264
273
 
265
274
  @JRubyMethod()
266
275
  public static IRubyObject finish(ThreadContext context, IRubyObject self) {
267
- return throwUnimplError(self, "finish");
276
+ return throwUnimplError(context, self, "finish");
268
277
  }
269
278
 
270
279
  @JRubyMethod()
271
280
  public static IRubyObject reset(ThreadContext context, IRubyObject self) {
272
- return throwUnimplError(self, "reset");
281
+ return throwUnimplError(context, self, "reset");
273
282
  }
274
283
 
275
284
  @JRubyMethod()
276
285
  public static IRubyObject digest_length(ThreadContext context, IRubyObject self) {
277
- return digest(context, self, null).convertToString().bytesize();
286
+ return digest(context, self, null).convertToString().bytesize(context);
278
287
  }
279
288
 
280
289
  @JRubyMethod()
281
290
  public static IRubyObject block_length(ThreadContext context, IRubyObject self) {
282
- return throwUnimplError(self, "block_length");
291
+ return throwUnimplError(context, self, "block_length");
283
292
  }
284
293
 
285
294
  /* instance methods that may be overridden */
@@ -288,21 +297,23 @@ public class RubyDigest {
288
297
  if(oth.isNil()) return context.fals;
289
298
 
290
299
  RubyString str1, str2;
291
- RubyModule instance = (RubyModule)context.runtime.getModule("Digest").getConstantAt("Instance");
300
+ RubyModule instance = (RubyModule)Access.getModule(context, "Digest").getConstantAt(context, "Instance");
292
301
  if (oth.getMetaClass().getRealClass().hasModuleInHierarchy(instance)) {
293
302
  str1 = digest(context, self, null).convertToString();
294
303
  str2 = digest(context, oth, null).convertToString();
295
304
  } else {
296
305
  str1 = to_s(context, self).convertToString();
297
- str2 = oth.convertToString();
306
+ IRubyObject converted = TypeConverter.checkStringType(context.runtime, oth);
307
+ if (converted.isNil()) return context.fals;
308
+ str2 = (RubyString) converted;
298
309
  }
299
- boolean ret = str1.bytesize().eql(str2.bytesize()) && (str1.eql(str2));
310
+ boolean ret = str1.bytesize(context).eql(str2.bytesize(context)) && (str1.eql(str2));
300
311
  return ret ? context.tru : context.fals;
301
312
  }
302
313
 
303
314
  @JRubyMethod()
304
315
  public static IRubyObject inspect(ThreadContext context, IRubyObject self) {
305
- return RubyString.newStringNoCopy(self.getRuntime(), ByteList.plain("#<" + self.getMetaClass().getRealClass().getName() + ": " + hexdigest(context, self, null) + ">"));
316
+ return RubyString.newStringNoCopy(self.getRuntime(), ByteList.plain("#<" + self.getMetaClass().getRealClass().getName(context) + ": " + hexdigest(context, self, null) + ">"));
306
317
  }
307
318
 
308
319
  /* instance methods that need not usually be overridden */
@@ -364,6 +375,8 @@ public class RubyDigest {
364
375
 
365
376
  @JRubyClass(name="Digest::Class")
366
377
  public static class DigestClass extends RubyObject {
378
+ private static final long serialVersionUID = 1956465293454003972L;
379
+
367
380
  public DigestClass(Ruby runtime, RubyClass type) {
368
381
  super(runtime, type);
369
382
  }
@@ -397,13 +410,16 @@ public class RubyDigest {
397
410
 
398
411
  @JRubyClass(name="Digest::Base")
399
412
  public static class DigestBase extends RubyObject {
400
- private MessageDigest algo;
413
+ private static final long serialVersionUID = -2526926208784906213L;
414
+
415
+ private transient MessageDigest algo;
401
416
  private int blockLength = 0;
402
417
 
403
418
  public DigestBase(Ruby runtime, RubyClass type) {
404
419
  super(runtime,type);
405
420
 
406
- if(type == runtime.getModule("Digest").getClass("Base")) {
421
+ ThreadContext context = runtime.getCurrentContext();
422
+ if(type == Access.getModule(context, "Digest").getClass(context, "Base")) {
407
423
  throw runtime.newNotImplementedError("Digest::Base is an abstract class");
408
424
  }
409
425
 
@@ -433,7 +449,7 @@ public class RubyDigest {
433
449
 
434
450
  @JRubyMethod(required = 1, visibility = Visibility.PRIVATE)
435
451
  @Override
436
- public IRubyObject initialize_copy(IRubyObject obj) {
452
+ public IRubyObject initialize_copy(ThreadContext context, IRubyObject obj) {
437
453
  if (this == obj) return this;
438
454
 
439
455
  DigestBase from = (DigestBase) obj;
@@ -444,7 +460,7 @@ public class RubyDigest {
444
460
  }
445
461
  catch (CloneNotSupportedException e) {
446
462
  String name = from.algo.getAlgorithm();
447
- throw getRuntime().newTypeError("Could not initialize copy of digest (" + name + ")");
463
+ throw getRuntime().newRaiseException(getRuntime().getTypeError(), "Could not initialize copy of digest (" + name + ")");
448
464
  }
449
465
  return this;
450
466
  }
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest.jar"
4
+ JRuby::Util.load_ext("org.jruby.ext.digest.CRC32")
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Digest
4
- VERSION = "3.2.1"
4
+ # The version string
5
+ VERSION = "3.3.0"
5
6
  end
data/lib/digest.jar CHANGED
Binary file
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: digest
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.1
4
+ version: 3.3.0
5
5
  platform: java
6
6
  authors:
7
7
  - Akinori MUSHA
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-10-31 00:00:00.000000000 Z
10
+ date: 2026-10-08 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: Provides a framework for message digest libraries.
13
13
  email:
@@ -19,6 +19,7 @@ files:
19
19
  - LICENSE.txt
20
20
  - README.md
21
21
  - ext/java/org/jruby/ext/digest/BubbleBabble.java
22
+ - ext/java/org/jruby/ext/digest/CRC32.java
22
23
  - ext/java/org/jruby/ext/digest/DigestLibrary.java
23
24
  - ext/java/org/jruby/ext/digest/MD5.java
24
25
  - ext/java/org/jruby/ext/digest/RMD160.java
@@ -26,6 +27,7 @@ files:
26
27
  - ext/java/org/jruby/ext/digest/SHA1.java
27
28
  - ext/java/org/jruby/ext/digest/SHA2.java
28
29
  - ext/java/org/jruby/ext/digest/lib/digest/bubblebabble.rb
30
+ - ext/java/org/jruby/ext/digest/lib/digest/crc32.rb
29
31
  - ext/java/org/jruby/ext/digest/lib/digest/loader.rb
30
32
  - ext/java/org/jruby/ext/digest/lib/digest/md5.rb
31
33
  - ext/java/org/jruby/ext/digest/lib/digest/rmd160.rb
@@ -56,7 +58,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
56
58
  - !ruby/object:Gem::Version
57
59
  version: '0'
58
60
  requirements: []
59
- rubygems_version: 3.7.2
61
+ rubygems_version: 4.0.22
60
62
  specification_version: 4
61
63
  summary: Provides a framework for message digest libraries.
62
64
  test_files: []