• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hyperledger / identus-cloud-agent / 8966726859

06 May 2024 09:08AM UTC coverage: 49.434% (+0.09%) from 49.343%
8966726859

Pull #1015

patlo-iog
build: remove explicit bouncy libs

Signed-off-by: Pat Losoponkul <pat.losoponkul@iohk.io>
Pull Request #1015: fix: remove prism-crypto dependency

28 of 35 new or added lines in 7 files covered. (80.0%)

221 existing lines in 60 files now uncovered.

7335 of 14838 relevant lines covered (49.43%)

0.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.77
/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/revocation/BitString.scala
1
package org.hyperledger.identus.pollux.vc.jwt.revocation
2

3
import org.hyperledger.identus.pollux.vc.jwt.revocation.BitStringError.{DecodingError, EncodingError, IndexOutOfBounds}
4
import zio.{IO, UIO, ZIO}
5

6
import java.io.{ByteArrayInputStream, ByteArrayOutputStream}
7
import java.util
8
import java.util.Base64
9
import java.util.zip.{GZIPInputStream, GZIPOutputStream}
10

11
class BitString private (val bitSet: util.BitSet, val size: Int) {
12
  def setRevokedInPlace(index: Int, value: Boolean): IO[IndexOutOfBounds, Unit] =
1✔
13
    if (index >= size) ZIO.fail(IndexOutOfBounds(s"bitIndex >= $size: $index"))
1✔
14
    else ZIO.attempt(bitSet.set(index, value)).mapError(t => IndexOutOfBounds(t.getMessage))
1✔
15

16
  def isRevoked(index: Int): IO[IndexOutOfBounds, Boolean] =
1✔
17
    if (index >= size) ZIO.fail(IndexOutOfBounds(s"bitIndex >= $size: $index"))
1✔
18
    else ZIO.attempt(bitSet.get(index)).mapError(t => IndexOutOfBounds(t.getMessage))
1✔
19

20
  def revokedCount(): UIO[Int] = ZIO.succeed(bitSet.stream().count().toInt)
1✔
21

22
  def encoded: IO[EncodingError, String] = {
1✔
23
    for {
1✔
24
      bitSetByteArray <- ZIO.succeed(bitSet.toByteArray)
1✔
25
      /*
26
      This is where the size constructor parameter comes into play (i.e. the initial bitstring size requested by the user).
27
      Interestingly, the underlying 'bitSet.toByteArray()' method only returns the byte array that are 'in use', which means the bytes needed to hold the current bits that are set to true.
28
      E.g. Calling toByteArray on a BitSet of size 64, where all bits are false, will return an empty array. The same BitSet with the fourth bit set to true will return 1 byte. And so on...
29
      So, the paddingByteArray is used to fill the gap between what BitSet returns and what was requested by the user.
30
      If the BitString size is 131.072 and no VC is revoked, the final encoding (as per the spec) should account for all bits, and no only those that are revoked.
31
      The (x + 7) / 8) is used to calculate the number of bytes needed to store a bit array of size x.
32
       */
33
      paddingByteArray = new Array[Byte](((size + 7) / 8) - bitSetByteArray.length)
1✔
34
      baos = new ByteArrayOutputStream()
1✔
35
      _ <- (for {
1✔
36
        gzipOutputStream <- ZIO.attempt(new GZIPOutputStream(baos))
1✔
37
        _ <- ZIO.attempt(gzipOutputStream.write(bitSetByteArray))
1✔
38
        _ <- ZIO.attempt(gzipOutputStream.write(paddingByteArray))
1✔
39
        _ <- ZIO.attempt(gzipOutputStream.close())
1✔
UNCOV
40
      } yield ()).mapError(t => EncodingError(t.getMessage))
×
41
    } yield {
1✔
42
      Base64.getUrlEncoder.encodeToString(baos.toByteArray)
1✔
43
    }
44
  }
45
}
46

47
object BitString {
48
  /*
49
   The minimum size of the bit string according to the VC Status List 2021 specification.
50
   As per the spec "... a minimum revocation bitstring of 131.072, or 16KB uncompressed... is enough to give holders an adequate amount of herd privacy"
51
   Cf. https://www.w3.org/TR/vc-status-list/#revocation-bitstring-length
52
   */
53
  val MIN_SL2021_SIZE: Int = 131072
54

55
  def getInstance(): IO[BitStringError, BitString] = getInstance(MIN_SL2021_SIZE)
1✔
56

57
  def getInstance(size: Int): IO[BitStringError, BitString] = {
1✔
58
    if (size % 8 != 0) ZIO.fail(BitStringError.InvalidSize("Bit string size should be a multiple of 8"))
1✔
59
    else ZIO.succeed(BitString(new util.BitSet(size), size))
1✔
60
  }
61

62
  def valueOf(b64Value: String): IO[DecodingError, BitString] = {
1✔
63
    for {
1✔
64
      ba <- ZIO.attempt(Base64.getUrlDecoder.decode(b64Value)).mapError(t => DecodingError(t.getMessage))
1✔
65
    } yield {
66
      val bais = new ByteArrayInputStream(ba)
1✔
67
      val gzipInputStream = new GZIPInputStream(bais)
1✔
68
      val byteArray = gzipInputStream.readAllBytes()
1✔
69
      BitString(util.BitSet.valueOf(byteArray), byteArray.length * 8)
1✔
70
    }
71
  }
72
}
73

74
sealed trait BitStringError
75

76
object BitStringError {
77
  final case class InvalidSize(message: String) extends BitStringError
78
  final case class EncodingError(message: String) extends BitStringError
79
  final case class DecodingError(message: String) extends BitStringError
80
  final case class IndexOutOfBounds(message: String) extends BitStringError
81
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc