summaryrefslogtreecommitdiff
path: root/src/ByteUtils.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/ByteUtils.scala')
-rw-r--r--src/ByteUtils.scala114
1 files changed, 114 insertions, 0 deletions
diff --git a/src/ByteUtils.scala b/src/ByteUtils.scala
new file mode 100644
index 0000000..723164d
--- /dev/null
+++ b/src/ByteUtils.scala
@@ -0,0 +1,114 @@
+package ixee.cryptopals.utils
+
+import FunctionUtils.tup
+import ConversionUtils._
+
+object ByteUtils {
+ trait SizedNumeric[T] {
+ def manifest: Manifest[T]
+ def byteSize: Int
+ def bitSize: Int
+ def fromLong(l: Long): T
+ def toLong(l: T): Long
+ def buildFrom[U : SizedNumeric : BitOps](from: U): T = fromLong(from.toLong)
+ def truncate[U : SizedNumeric : BitOps](from: U): T = buildFrom(from)
+ override def toString = s"SizedNumeric[${manifest}]"
+ }
+
+ trait BitOps[T] {
+ def @>>>(t: T, x: Int): T
+ def @<<(t: T, x: Int): T
+ def @|(a: T, b: T): T
+ def @&(a: T, b: T): T
+ def @^(a: T, b: T): T
+ def @+(a: T, b: T): T
+ def @-(a: T, b: T): T
+ }
+
+ implicit val byteOps: BitOps[Byte] = new BitOps[Byte] {
+ def @>>>(t: Byte, x: Int): Byte = (t >>> x).toByte
+ def @<<(t: Byte, x: Int): Byte = (t << x).toByte
+ def @|(a: Byte, b: Byte): Byte = (a | b).toByte
+ def @&(a: Byte, b: Byte): Byte = (a & b).toByte
+ def @^(a: Byte, b: Byte): Byte = (a ^ b).toByte
+ def @+(a: Byte, b: Byte): Byte = (a + b).toByte
+ def @-(a: Byte, b: Byte): Byte = (a - b).toByte
+ }
+
+ implicit val intOps: BitOps[Int] = new BitOps[Int] {
+ def @>>>(t: Int, x: Int): Int = t >>> x
+ def @<<(t: Int, x: Int): Int = (t << x)
+ def @|(a: Int, b: Int): Int = a | b
+ def @&(a: Int, b: Int): Int = a & b
+ def @^(a: Int, b: Int): Int = a ^ b
+ def @+(a: Int, b: Int): Int = a + b
+ def @-(a: Int, b: Int): Int = a - b
+ }
+
+ implicit class WithBitOpts[T : BitOps](x: T) {
+ def @>>>(b: Int): T = implicitly[BitOps[T]].@>>>(x, b)
+ def @<<(b: Int): T = implicitly[BitOps[T]].@<<(x, b)
+ def @|(b: T): T = implicitly[BitOps[T]].@|(x, b)
+ def @&(b: T): T = implicitly[BitOps[T]].@&(x, b)
+ def @^(b: T): T = implicitly[BitOps[T]].@^(x, b)
+ def @+(b: T): T = implicitly[BitOps[T]].@+(x, b)
+ def @-(b: T): T = implicitly[BitOps[T]].@-(x, b)
+ }
+
+ implicit class SizedWithByteInfo[T : SizedNumeric : BitOps](x: T) {
+ def byteSize = implicitly[SizedNumeric[T]].byteSize
+ def octetSize = byteSize * 2
+ def bitSize = implicitly[SizedNumeric[T]].bitSize
+ def toLong = implicitly[SizedNumeric[T]].toLong(x)
+ def liftedTo[U : SizedNumeric]: U = {
+ val uSize = implicitly[SizedNumeric[U]]
+ val tSize = implicitly[SizedNumeric[T]]
+ if (uSize.byteSize < tSize.byteSize) {
+ throw new RuntimeException(s"Target size ($uSize) is smaller than the source size ($tSize)")
+ }
+
+ uSize.buildFrom(x)
+ }
+ def hex: String = s"%0${octetSize}x" format x
+ def bitsSet: Int = {
+ var bits = 0
+ var num = x
+
+ while (num.toLong > 0) {
+ bits = bits + 1
+ num = num @& (num @- 1.truncatedTo[T])
+ }
+
+ bits
+ }
+ def truncatedTo[U : SizedNumeric]: U = {
+ implicitly[SizedNumeric[U]].truncate(x)
+ }
+ }
+
+ def sizedNumeric[T : Manifest](bytes: Int)(from: Long => T)(to: T => Long) = new SizedNumeric[T] {
+ def manifest = implicitly[Manifest[T]]
+ def byteSize = bytes
+ def bitSize = bytes * 8
+ def toLong(t: T) = to(t)
+ def fromLong(l: Long) = from(l)
+ }
+
+ implicit val intSized = sizedNumeric(4) { x: Long => x.toInt } { _.toLong }
+ implicit val shortized = sizedNumeric(2) { x: Long => x.toShort } { _.toLong }
+ implicit val byteSized = sizedNumeric(1) { x: Long => x.toByte } { _.toLong }
+
+ implicit class SeqByteOps[T : SizedNumeric : BitOps](seq: Seq[T]) {
+ def xor(other: Seq[T]): Seq[T] =
+ seq.zip(other).map(tup(_ @^ _))
+ }
+
+ def hammingDistance(a: String, b: String): Int =
+ hammingDistance(a.asBytes, b.asBytes)
+
+ def hammingDistance[T : BitOps : SizedNumeric](a: Seq[T], b: Seq[T]): Int =
+ (a xor b).map(_.bitsSet).reduce(_ @+ _)
+
+ def avgHammingDistance[T : BitOps : SizedNumeric](xs: Seq[Seq[T]]): Double =
+ xs.sliding(2).map({ case Stream(a: Seq[T], b: Seq[T]) => hammingDistance(a, b) }).reduce(_ @+ _) / xs.length.toDouble
+}