diff --git a/codexvalidator.nimble b/codexvalidator.nimble index 34dd9ea..7ecd3bc 100644 --- a/codexvalidator.nimble +++ b/codexvalidator.nimble @@ -4,3 +4,4 @@ description = "Validation network for Codex" license = "MIT" requires "https://github.com/codex-storage/nim-mysticeti >= 0.1.0 & < 0.2.0" +requires "https://github.com/codex-storage/nim-stint-versioned.git >= 1.0.0 & < 2.0.0" diff --git a/codexvalidator/basics.nim b/codexvalidator/basics.nim new file mode 100644 index 0000000..0145102 --- /dev/null +++ b/codexvalidator/basics.nim @@ -0,0 +1,7 @@ +import std/sequtils + +export sequtils + +import pkg/stint + +export stint diff --git a/codexvalidator/transaction.nim b/codexvalidator/transaction.nim new file mode 100644 index 0000000..bd0613c --- /dev/null +++ b/codexvalidator/transaction.nim @@ -0,0 +1,67 @@ +import ./basics +import ./transaction/slotid +import ./transaction/period +import ./transaction/groth16 + +export slotid +export period +export groth16 + +type + TransactionVersion* {.pure.} = enum + version0 + TransactionKind* {.pure.} = enum + storageProof + missingProof + Transaction* = object + slotId: SlotId + period: Period + inputs: seq[UInt256] + case kind: TransactionKind + of storageProof: + proof: Groth16Proof + of missingProof: + discard + +proc storageProof*( + _: type Transaction, + slotId: SlotId, + period: Period, + inputs: seq[UInt256], + proof: Groth16Proof +): Transaction = + Transaction( + kind: TransactionKind.storageProof, + slotId: slotId, + period: period, + inputs: inputs, + proof: proof + ) + +proc missingProof*( + _: type Transaction, + slotId: SlotId, + period: Period, + inputs: seq[UInt256], +): Transaction = + Transaction( + kind: TransactionKind.missingProof, + slotId: slotId, + period: period, + inputs: inputs + ) + +func version*(transaction: Transaction): TransactionVersion = + TransactionVersion.version0 + +func slotId*(transaction: Transaction): SlotId = + transaction.slotId + +func period*(transaction: Transaction): Period = + transaction.period + +func inputs*(transaction: Transaction): seq[UInt256] = + transaction.inputs + +func proof*(transaction: Transaction): Groth16Proof = + transaction.proof diff --git a/codexvalidator/transaction/groth16.nim b/codexvalidator/transaction/groth16.nim new file mode 100644 index 0000000..0c043c0 --- /dev/null +++ b/codexvalidator/transaction/groth16.nim @@ -0,0 +1,56 @@ +import ../basics + +type + Groth16Proof* = object + a: G1Point + b: G2Point + c: G1Point + G1Point* = object + x: UInt256 + y: UInt256 + Fp2Element* = object + ## A field element F_{p^2} encoded as `real + i * imag` + real: UInt256 + imag: UInt256 + G2Point* = object + x: Fp2Element + y: Fp2Element + +func init*(_: type Groth16Proof, a: G1Point, b: G2Point, c: G1Point): Groth16Proof = + Groth16Proof(a: a, b: b, c: c) + +func a*(proof: Groth16Proof): G1Point = + proof.a + +func b*(proof: Groth16Proof): G2Point = + proof.b + +func c*(proof: Groth16Proof): G1Point = + proof.c + +func init*(_: type G1Point, x, y: UInt256): G1Point = + G1Point(x: x, y: y) + +func x*(point: G1Point): UInt256 = + point.x + +func y*(point: G1Point): UInt256 = + point.y + +func init*(_: type G2Point, x, y: Fp2Element): G2Point = + G2Point(x: x, y: y) + +func x*(point: G2Point): Fp2Element = + point.x + +func y*(point: G2Point): Fp2Element = + point.y + +func init*(_: type Fp2Element, real, imag: UInt256): Fp2Element = + Fp2Element(real: real, imag: imag) + +func real*(element: Fp2Element): UInt256 = + element.real + +func imag*(element: Fp2Element): UInt256 = + element.imag diff --git a/codexvalidator/transaction/period.nim b/codexvalidator/transaction/period.nim new file mode 100644 index 0000000..b7c18d5 --- /dev/null +++ b/codexvalidator/transaction/period.nim @@ -0,0 +1,4 @@ +type Period* = distinct uint64 + +func `$`*(period: Period): string {.borrow.} +func `==`*(a, b: Period): bool {.borrow.} diff --git a/codexvalidator/transaction/slotid.nim b/codexvalidator/transaction/slotid.nim new file mode 100644 index 0000000..1dfcaf9 --- /dev/null +++ b/codexvalidator/transaction/slotid.nim @@ -0,0 +1,4 @@ +type SlotId* = distinct array[32, byte] + +func `$`*(slotId: SlotId): string {.borrow.} +func `==`*(a, b: SlotId): bool {.borrow.} diff --git a/tests/codexvalidator/examples.nim b/tests/codexvalidator/examples.nim new file mode 100644 index 0000000..c980644 --- /dev/null +++ b/tests/codexvalidator/examples.nim @@ -0,0 +1,54 @@ +import std/random +import codexvalidator/basics +import codexvalidator/transaction + +proc example*[T: SomeInteger](_: type T): T = + rand(T) + +proc example*(_: type UInt256): UInt256 = + UInt256.fromBytesBE(array[32, byte].example) + +proc example*[T, length](_: type array[length, T]): array[length, T] = + for i in result.low..result.high: + result[i] = T.example + +proc example*[T](_: type seq[T], length = 0..10): seq[T] = + let len = rand(length) + newSeqWith(len, T.example) + +proc example*(_: type SlotId): SlotId = + SlotId(array[32, byte].example) + +proc example*(_: type Period): Period = + Period(uint64.example) + +proc example*(_: type G1Point): G1Point = + G1Point.init(UInt256.example, UInt256.example) + +proc example*(_: type Fp2Element): Fp2Element = + Fp2Element.init(UInt256.example, UInt256.example) + +proc example*(_: type G2Point): G2Point = + G2Point.init( + Fp2Element.example, + Fp2Element.example + ) + +proc example*(_: type Groth16Proof): Groth16Proof = + Groth16Proof.init( + G1Point.example, + G2Point.example, + G1Point.example + ) + +proc example*(_: type Transaction): Transaction = + let kind = [TransactionKind.storageProof, TransactionKind.missingProof].sample + let slotId = SlotId.example + let period = Period.example + let inputs = seq[UInt256].example + case kind + of TransactionKind.missingProof: + Transaction.missingProof(slotId, period, inputs) + of TransactionKind.storageProof: + let proof = Groth16Proof.example + Transaction.storageProof(slotId, period, inputs, proof) diff --git a/tests/codexvalidator/testTransaction.nim b/tests/codexvalidator/testTransaction.nim new file mode 100644 index 0000000..9558558 --- /dev/null +++ b/tests/codexvalidator/testTransaction.nim @@ -0,0 +1,27 @@ +import std/unittest +import codexvalidator/basics +import codexvalidator/transaction +import ./examples + +suite "Transaction": + + test "a transaction can contain a storage proof": + let slotId = SlotId.example + let period = Period.example + let inputs = seq[UInt256].example + let proof = Groth16Proof.example + let transaction = Transaction.storageProof(slotId, period, inputs, proof) + check transaction.proof == proof + + test "a transaction can indicate a missing storage proof": + let slotId = SlotId.example + let period = Period.example + let inputs = seq[UInt256].example + let transaction = Transaction.missingProof(slotId, period, inputs) + check transaction.slotId == slotId + check transaction.period == period + check transaction.inputs == inputs + + test "transactions have a fixed version": + let transaction = Transaction.example + check transaction.version == TransactionVersion.version0 diff --git a/tests/nim.cfg b/tests/nim.cfg new file mode 100644 index 0000000..0f840a1 --- /dev/null +++ b/tests/nim.cfg @@ -0,0 +1 @@ +--path:".." diff --git a/tests/tests.nim b/tests/tests.nim new file mode 100644 index 0000000..aeebbae --- /dev/null +++ b/tests/tests.nim @@ -0,0 +1,3 @@ +import ./codexvalidator/testTransaction + +{.warning[UnusedImport]:off.}