Skip to content

Commit

Permalink
Merge pull request #936 from ScorexFoundation/new-sigma-js
Browse files Browse the repository at this point in the history
Export missing classes to JS
  • Loading branch information
aslesarenko authored Dec 13, 2023
2 parents ef1fd14 + b252834 commit 4a01b4e
Show file tree
Hide file tree
Showing 50 changed files with 1,802 additions and 493 deletions.
27 changes: 17 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ For development of Ergo applications using JVM languages (Java/Scala/Kotlin/etc)
a better alternative is to use
[Appkit](https://github.com/ergoplatform/ergo-appkit).

The library is cross-compiled to JS using Scala.js and the main abstractions can be used
from JS directly by importing [NPM module](https://www.npmjs.com/package/sigmastate-js).
See [README](sigma-js/README.md) for details.

## Sigma Language Background

Every coin in Bitcoin is protected by a program in the stack-based Script
Expand Down Expand Up @@ -93,19 +97,21 @@ This library is
on Maven repository and can be added to the SBT configuration of Scala project.

```scala
libraryDependencies += "org.scorexfoundation" %% "sigma-state" % "5.0.6"
libraryDependencies += "org.scorexfoundation" %% "sigma-state" % "5.0.14"
```

## Repository Organization

| sub-module | description |
|-------------|-------------------------------------------------------------------------------------------|
| common | Used in all other submodules and contain basic utility classes |
| core-lib | Contains core classes such as Coll, BigInt used by interpreter |
| docs | Collection of documents |
| graph-ir | Implementation of graph-based intermediate representation of ErgoTree, which is used in by ErgoScript compiler |
| interpreter | Implementation of ErgoTree Interpreter |
| sc | Implementation of ErgoScript compiler |
| sub-module | description |
|-------------|------------------------------------------------------------------------------------|
| core | contains core classes of Sigma library |
| data | contains classes for working with ErgoTree, addresses and all related serializers |
| docs | Collection of documents |
| interpreter | contains an implementation of ErgoTree Interpreter |
| sdk | contains and implementation of transaction reduction and signing |
| parsers | contains an implementation of ErgoScript parsers using FastParse library |
| sc | contains an implementation of ErgoScript compiler |
| sigma-js | root directory of sigmastate-js JS module (see [package.json](sigma-js/README.md)) |

## Contributing

Expand Down Expand Up @@ -151,12 +157,13 @@ innovative and intelligent tools for profiling Java and .NET applications.

- [Ergo Site](https://ergoplatform.org/en/)
- [Ergo Sources](https://github.com/ergoplatform/ergo)
- [Sigma-js](https://www.npmjs.com/package/sigmastate-js)
- [Ergo Appkit](https://github.com/ergoplatform/ergo-appkit)
- [Ergo Appkit Examples](https://github.com/aslesarenko/ergo-appkit-examples)
- [ergo-android](https://github.com/aslesarenko/ergo-android)
- [ergo-wallet-android](https://github.com/MrStahlfelge/ergo-wallet-android)
- [ErgoTree Specification](https://ergoplatform.org/docs/ErgoTree.pdf)
- [Ergo Documents](https://ergoplatform.org/en/documents/)
- [Ergo Documents](https://docs.ergoplatform.org/)



1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ lazy val sdk = crossProject(JVMPlatform, JSPlatform)
commonDependenies2,
testingDependencies2,
scodecBitsDependency,
circeDependency,
publish / skip := true
)
.jvmSettings(
Expand Down
2 changes: 1 addition & 1 deletion core/js/src/main/scala/sigma/js/GroupElement.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class GroupElement(val point: Ecp) extends js.Object {
}
}

@JSExportTopLevel("GroupElementObj")
@JSExportTopLevel("GroupElement$")
object GroupElement extends js.Object {
/** Creates a new [[GroupElement]] from the given hex string (ASN.1 encoding)
* representation of the underlying [[sigmastate.crypto.Platform.Point]].
Expand Down
20 changes: 19 additions & 1 deletion core/js/src/main/scala/sigma/js/Isos.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package sigma.js

import sigma.{Coll, Colls}
import sigma.data.{Iso, RType}
import sigma.data.{CBigInt, Iso, RType}

import java.math.BigInteger
import scala.reflect.ClassTag
import scala.scalajs.js
import scala.scalajs.js.JSConverters.JSRichOption
Expand All @@ -26,4 +27,21 @@ object Isos {
override def from(x: IndexedSeq[B]): js.Array[A] = js.Array(x.map(iso.from): _*)
}

implicit val isoBigInt: Iso[js.BigInt, sigma.BigInt] = new Iso[js.BigInt, sigma.BigInt] {
override def to(x: js.BigInt): sigma.BigInt = {
CBigInt(new BigInteger(x.toString(10)))
}

override def from(x: sigma.BigInt): js.BigInt = {
val bi = x.asInstanceOf[CBigInt].wrappedValue
val s = bi.toString(10)
js.BigInt(s)
}
}

implicit val isoBigIntToLong: Iso[js.BigInt, Long] = new Iso[js.BigInt, Long] {
override def to(x: js.BigInt): Long = java.lang.Long.parseLong(x.toString(10))

override def from(x: Long): js.BigInt = js.BigInt(x.toString)
}
}
8 changes: 8 additions & 0 deletions core/js/src/main/scala/sigma/js/JsWrapper.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package sigma.js

import scala.scalajs.js

/** Base trait for all JS wrappers over some Scala type T. */
trait JsWrapper[T] extends js.Object {
def wrappedValue: T
}
20 changes: 16 additions & 4 deletions core/js/src/main/scala/sigma/js/SigmaProp.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package sigma.js

import sigma.data.{ProveDlog, SigmaBoolean}
import sigma.data.{ProveDHTuple, ProveDlog, SigmaBoolean}

import scala.scalajs.js
import scala.scalajs.js.annotation.JSExportTopLevel
Expand All @@ -10,14 +10,26 @@ import scala.scalajs.js.annotation.JSExportTopLevel
class SigmaProp(val sigmaBoolean: SigmaBoolean) extends js.Object {
}

@JSExportTopLevel("SigmaPropObj")
@JSExportTopLevel("SigmaProp$")
object SigmaProp extends js.Object {
/** Creates a new [[SigmaProp]] from the given hex string of public key.
* @param pointHex hex representation of elliptic curve point (ASN.1 encoded)
* @see CryptoFacade.getASN1Encoding, GroupElement.fromPointHex, Point
*/
def fromPointHex(pointHex: String): SigmaProp = {
val point = GroupElement.fromPointHex(pointHex).point
new SigmaProp(ProveDlog(point))
val ge = GroupElement.fromPointHex(pointHex)
dlog(ge)
}

/** @param publicKey a [[GroupElement]] representing public key of discrete logarithm signature protocol
* @return a new [[SigmaProp]] value representing public key of discrete logarithm signature protocol.
*/
def dlog(publicKey: GroupElement): SigmaProp = {
new SigmaProp(ProveDlog(publicKey.point))
}

/** Construct a new [[SigmaProp]] value representing public key of Diffie Hellman signature protocol. */
def dht(g: GroupElement, h: GroupElement, u: GroupElement, v: GroupElement): SigmaProp = {
new SigmaProp(ProveDHTuple(g.point, h.point, u.point, v.point))
}
}
10 changes: 8 additions & 2 deletions core/js/src/main/scala/sigma/js/Type.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sigma.js

import sigma.data.RType
import sigma.Evaluation
import sigma.data.{Iso, RType}

import scala.scalajs.js
import scala.scalajs.js.annotation.JSExportTopLevel
Expand All @@ -17,7 +18,7 @@ class Type(final val rtype: RType[_]) extends js.Object {
override def toString = s"Type($rtype)"
}

@JSExportTopLevel("TypeObj")
@JSExportTopLevel("Type$")
object Type extends js.Object {
/** Descriptor of ErgoScript type Byte. */
val Byte = new Type(sigma.ByteType)
Expand Down Expand Up @@ -75,4 +76,9 @@ object Type extends js.Object {
def collType(elemType: Type): Type = {
new Type(sigma.collRType(elemType.rtype))
}

implicit val isoToSType: Iso[Type, sigma.ast.SType] = new Iso[Type, sigma.ast.SType] {
override def to(x: Type): sigma.ast.SType = Evaluation.rtypeToSType(x.rtype)
override def from(x: sigma.ast.SType): Type = new Type(Evaluation.stypeToRType(x))
}
}
15 changes: 15 additions & 0 deletions core/js/src/main/scala/sigma/js/Utils.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package sigma.js

import scorex.util.encode.Base16

import scala.scalajs.js
import scala.scalajs.js.annotation.JSExportTopLevel
import scala.scalajs.js.typedarray.Int8Array

@JSExportTopLevel("Utils")
object Utils extends js.Object {
/** Convert an Int8Array to a hex string. */
def int8ArrayToHex(arr: Int8Array): String = {
Base16.encode(arr.toArray)
}
}
2 changes: 1 addition & 1 deletion core/js/src/main/scala/sigma/js/Value.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class Value(val data: Any, val tpe: Type) extends js.Object {
}
}

@JSExportTopLevel("ValueObj")
@JSExportTopLevel("Value$")
object Value extends js.Object {
/** Maximal positive value of ES type Long */
val MaxLong = js.BigInt("0x7fffffffffffffff")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class CollOverArray[@specialized A](val toArray: Array[A], val builder: CollBuil
// in v5.0 and above this fixes the ClassCastException problem
safeConcatArrays_v5(toArray, other.toArray)(tA.classTag)
} else {
CollectionUtil.concatArrays(toArray, other.toArray)
CollectionUtil.concatArrays_v4(toArray, other.toArray)
}
builder.fromArray(result)
}
Expand Down
4 changes: 2 additions & 2 deletions core/shared/src/main/scala/sigma/util/CollectionUtil.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import scala.collection.compat._
object CollectionUtil {

/** @deprecated shouldn't be used other than for backwards compatibility with v3.x, v4.x. */
def concatArrays[T](xs: Array[T], ys: Array[T]): Array[T] = {
def concatArrays_v4[T](xs: Array[T], ys: Array[T]): Array[T] = {
val len = xs.length + ys.length
val result = (xs match {
case _: Array[AnyRef] => new Array[AnyRef](len) // creates an array with invalid type descriptor (i.e. when T == Tuple2)
Expand All @@ -31,7 +31,7 @@ object CollectionUtil {
* This method takes ClassTag to create proper resulting array.
* Can be used in v5.0 and above.
*/
def concatArrays_v5[T:ClassTag](arr1: Array[T], arr2: Array[T]): Array[T] = {
def concatArrays[T:ClassTag](arr1: Array[T], arr2: Array[T]): Array[T] = {
val l1 = arr1.length
val l2 = arr2.length
val length: Int = l1 + l2
Expand Down
2 changes: 1 addition & 1 deletion core/shared/src/main/scala/sigma/util/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ package object util {
final def safeConcatArrays_v5[A](arr1: Array[A], arr2: Array[A])
(implicit tA: ClassTag[A]): Array[A] = {
checkLength[A](arr1.length + arr2.length)
CollectionUtil.concatArrays_v5(arr1, arr2)
CollectionUtil.concatArrays(arr1, arr2)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,18 @@ class CollectionUtilTests extends BaseTests {
test("concatArrays") {
val xs = Array[Byte](1,2,3)
val ys = Array[Byte](4,5,6)
val zs = concatArrays(xs, ys)
val zs = concatArrays_v4(xs, ys)
assertResult(Array[Byte](1, 2, 3, 4, 5, 6))(zs)

val pairs = xs.zip(ys)
// this reproduces the problem which takes place in v3.x, v4.x (ErgoTree v0, v1)
an[Throwable] should be thrownBy(concatArrays(pairs, pairs))
an[Throwable] should be thrownBy(concatArrays_v4(pairs, pairs))

// and this is the fix in v5.0
concatArrays_v5(pairs, pairs) shouldBe Array((1, 4), (2, 5), (3, 6), (1, 4), (2, 5), (3, 6))
concatArrays(pairs, pairs) shouldBe Array((1, 4), (2, 5), (3, 6), (1, 4), (2, 5), (3, 6))

val xOpts = xs.map(Option(_))
concatArrays_v5(xOpts, xOpts) shouldBe Array(Some(1), Some(2), Some(3), Some(1), Some(2), Some(3))
concatArrays(xOpts, xOpts) shouldBe Array(Some(1), Some(2), Some(3), Some(1), Some(2), Some(3))
}

def joinSeqs(l: Seq[Int], r: Seq[Int]) =
Expand Down
Loading

0 comments on commit 4a01b4e

Please sign in to comment.