Sign Nitro states

This commit is contained in:
Mark Spanbroek 2021-03-02 07:37:38 +01:00
parent 34072f4749
commit 8ddd78ed68
4 changed files with 97 additions and 0 deletions

View File

@ -5,5 +5,6 @@ description = "Nitro state channels"
requires "nim >= 1.2.6 & < 2.0.0"
requires "nimcrypto >= 0.5.4 & < 0.6.0"
requires "secp256k1"
requires "stint"
requires "stew"

48
nitro/signature.nim Normal file
View File

@ -0,0 +1,48 @@
import pkg/nimcrypto
import pkg/secp256k1
import pkg/stew/byteutils
import ./state
export toPublicKey
type
PrivateKey* = SkSecretKey
PublicKey* = SkPublicKey
Signature* = SkRecoverableSignature
proc rng(data: var openArray[byte]): bool =
randomBytes(data) == data.len
proc random*(_: type PrivateKey): PrivateKey =
PrivateKey.random(rng).get()
proc `$`*(key: PrivateKey): string =
key.toHex()
proc parse*(_: type PrivateKey, s: string): PrivateKey =
SkSecretKey.fromHex(s).tryGet()
proc sign(key: PrivateKey, data: openArray[byte]): Signature =
let hash = keccak256.digest(data).data
key.signRecoverable(SkMessage(hash))
proc signMessage(key: PrivateKey, message: openArray[byte]): Signature =
# https://eips.ethereum.org/EIPS/eip-191
var data: seq[byte]
data.add("\x19Ethereum Signed Message:\n".toBytes)
data.add(($message.len).toBytes)
data.add(message)
key.sign(data)
proc sign*(key: PrivateKey, state: State): Signature =
key.signMessage(hashState(state))
proc `$`*(signature: Signature): string =
var bytes = signature.toRaw()
bytes[64] += 27
bytes.toHex()
proc parse*(_: type Signature, s: string): Signature =
var bytes = array[65, byte].fromHex(s)
bytes[64] -= 27
SkRecoverableSignature.fromRaw(bytes).tryGet()

View File

@ -0,0 +1,47 @@
import std/unittest
import pkg/nimcrypto
import pkg/secp256k1
import pkg/stew/byteutils
import pkg/nitro/state
import pkg/nitro/signature
import ./examples
suite "signature":
test "signs state hashes":
let state = State.example
let privateKey = PrivateKey.random()
let publicKey = privateKey.toPublicKey()
let signature = privateKey.sign(state)
let message = hashState(state)
let data = "\x19Ethereum Signed Message:\n32".toBytes & @message
let hash = keccak256.digest(data).data
check recover(signature, SkMessage(hash)).tryGet() == publicKey
test "produces the same signatures as the javascript implementation":
let state =State(
channel: Channel(
chainId: 0x1.u256,
nonce: 1,
participants: @[
EthAddress.fromHex("0x8a64E10FF40Bc9C90EA5750313dB5e036495c10E")
]
),
outcome: Outcome(@[]),
turnNum: 1,
isFinal: false,
appData: @[0'u8],
appDefinition: EthAddress.default,
challengeDuration: 5
)
let seckey = PrivateKey.parse(
"41b0f5f91967dded8af487277874f95116094cc6004ac2b2169b5b6a87608f3e"
)
let expected = Signature.parse(
"9b966cf0065586d59c8b9eb475ac763c96ad8316b81061238f32968a631f9e21" &
"251363c193c78c89b3eb2fec23f0ea5c3c72acff7d1f27430cfb84b9da9831fb" &
"1c"
)
check seckey.sign(state) == expected

View File

@ -2,5 +2,6 @@ import ./nitro/testAbi
import ./nitro/testChannel
import ./nitro/testOutcome
import ./nitro/testState
import ./nitro/testSignature
{.warning[UnusedImport]: off.}