diff --git a/codexvalidator/serialization/protobuf.nim b/codexvalidator/serialization/protobuf.nim deleted file mode 100644 index 1e9b06b..0000000 --- a/codexvalidator/serialization/protobuf.nim +++ /dev/null @@ -1,28 +0,0 @@ -import pkg/protobuf_serialization - -export protobuf_serialization - -type - TransactionMessage* {.proto3.} = object - version* {.fieldNumber: 1, pint.}: uint32 - kind* {.fieldNumber: 2, pint.}: uint32 - requestId* {.fieldNumber: 3.}: seq[byte] - slotIndex* {.fieldNumber: 4, pint.}: uint32 - period* {.fieldNumber: 5, pint.}: uint64 - merkleRoot* {.fieldNumber: 6.}: seq[byte] - challenge* {.fieldNumber: 7.}: seq[byte] - proof* {.fieldNumber: 8.}: Groth16ProofMessage - Groth16ProofMessage* {.proto3.} = object - a* {.fieldNumber: 1.}: G1PointMessage - b* {.fieldNumber: 2.}: G2PointMessage - c* {.fieldNumber: 3.}: G1PointMessage - G1PointMessage* {.proto3.} = object - x* {.fieldNumber: 1.}: seq[byte] - y* {.fieldNumber: 2.}: seq[byte] - G2PointMessage* {.proto3.} = object - x* {.fieldNumber: 1.}: Fp2ElementMessage - y* {.fieldNumber: 2.}: Fp2ElementMessage - Fp2ElementMessage* {.proto3.} = object - real* {.fieldNumber: 1.}: seq[byte] - imag* {.fieldNumber: 2.}: seq[byte] - diff --git a/codexvalidator/transaction.nim b/codexvalidator/transaction.nim index 2c8f98f..50efd9f 100644 --- a/codexvalidator/transaction.nim +++ b/codexvalidator/transaction.nim @@ -1,86 +1,7 @@ -import ./basics -import ./transaction/storagerequest -import ./transaction/period -import ./transaction/groth16 +import ./transaction/transaction +import ./transaction/signed +import ./transaction/serialization -export storagerequest -export period -export groth16 - -type - TransactionVersion* {.pure.} = enum - version0 - TransactionKind* {.pure.} = enum - storageProof - missingProof - Transaction* = object - requestId: StorageRequestId - slotIndex: uint32 - period: Period - merkleRoot: UInt256 - challenge: UInt256 - case kind: TransactionKind - of storageProof: - proof: Groth16Proof - of missingProof: - discard - -func storageProof*( - _: type Transaction, - requestId: StorageRequestId, - slotIndex: uint32, - period: Period, - merkleRoot: UInt256, - challenge: UInt256, - proof: Groth16Proof -): Transaction = - Transaction( - kind: TransactionKind.storageProof, - requestId: requestId, - period: period, - slotIndex: slotIndex, - merkleRoot: merkleRoot, - challenge: challenge, - proof: proof - ) - -func missingProof*( - _: type Transaction, - requestId: StorageRequestId, - slotIndex: uint32, - period: Period, - merkleRoot: UInt256, - challenge: UInt256, -): Transaction = - Transaction( - kind: TransactionKind.missingProof, - requestId: requestId, - slotIndex: slotIndex, - period: period, - merkleRoot: merkleRoot, - challenge: challenge - ) - -func version*(transaction: Transaction): TransactionVersion = - TransactionVersion.version0 - -func kind*(transaction: Transaction): TransactionKind = - transaction.kind - -func requestId*(transaction: Transaction): StorageRequestId = - transaction.requestId - -func slotIndex*(transaction: Transaction): uint32 = - transaction.slotIndex - -func period*(transaction: Transaction): Period = - transaction.period - -func merkleRoot*(transaction: Transaction): UInt256 = - transaction.merkleRoot - -func challenge*(transaction: Transaction): UInt256 = - transaction.challenge - -func proof*(transaction: Transaction): Groth16Proof = - transaction.proof +export transaction +export signed +export serialization.toBytes diff --git a/codexvalidator/serialization.nim b/codexvalidator/transaction/serialization.nim similarity index 54% rename from codexvalidator/serialization.nim rename to codexvalidator/transaction/serialization.nim index 5cc3ea6..05250d6 100644 --- a/codexvalidator/serialization.nim +++ b/codexvalidator/transaction/serialization.nim @@ -1,6 +1,33 @@ -import ./basics +import pkg/protobuf_serialization +import ../basics import ./transaction -import ./serialization/protobuf + +export protobuf_serialization + +type + TransactionMessage* {.proto3.} = object + version* {.fieldNumber: 1, pint.}: uint32 + kind* {.fieldNumber: 2, pint.}: uint32 + requestId* {.fieldNumber: 3.}: seq[byte] + slotIndex* {.fieldNumber: 4, pint.}: uint32 + period* {.fieldNumber: 5, pint.}: uint64 + merkleRoot* {.fieldNumber: 6.}: seq[byte] + challenge* {.fieldNumber: 7.}: seq[byte] + proof* {.fieldNumber: 8.}: Groth16ProofMessage + Groth16ProofMessage* {.proto3.} = object + a* {.fieldNumber: 1.}: G1PointMessage + b* {.fieldNumber: 2.}: G2PointMessage + c* {.fieldNumber: 3.}: G1PointMessage + G1PointMessage* {.proto3.} = object + x* {.fieldNumber: 1.}: seq[byte] + y* {.fieldNumber: 2.}: seq[byte] + G2PointMessage* {.proto3.} = object + x* {.fieldNumber: 1.}: Fp2ElementMessage + y* {.fieldNumber: 2.}: Fp2ElementMessage + Fp2ElementMessage* {.proto3.} = object + real* {.fieldNumber: 1.}: seq[byte] + imag* {.fieldNumber: 2.}: seq[byte] + func toBytes*(transaction: Transaction): seq[byte] = var message = TransactionMessage( diff --git a/codexvalidator/transaction/signed.nim b/codexvalidator/transaction/signed.nim new file mode 100644 index 0000000..63cd42f --- /dev/null +++ b/codexvalidator/transaction/signed.nim @@ -0,0 +1,36 @@ +import ../signatures +import ./transaction +import ./serialization + +type SignedTransaction* = object + transaction: Transaction + signer: Identifier + signature: Signature + +func init*( + _: type SignedTransaction, + transaction: Transaction, + signer: Identifier, + signature: Signature +): SignedTransaction = + SignedTransaction( + transaction: transaction, + signer: signer, + signature: signature + ) + +func sign*(identity: Identity, transaction: Transaction): SignedTransaction = + let signature = identity.sign(transaction.toBytes()) + SignedTransaction.init(transaction, identity.identifier, signature) + +func transaction*(signed: SignedTransaction): Transaction = + signed.transaction + +func signer*(signed: SignedTransaction): Identifier = + signed.signer + +func signature*(signed: SignedTransaction): Signature = + signed.signature + +func verifySignature*(signed: SignedTransaction): bool = + signed.signer.verify(signed.transaction.toBytes(), signed.signature) diff --git a/codexvalidator/transaction/transaction.nim b/codexvalidator/transaction/transaction.nim new file mode 100644 index 0000000..dea2e2a --- /dev/null +++ b/codexvalidator/transaction/transaction.nim @@ -0,0 +1,105 @@ +import ../basics +import ./storagerequest +import ./period +import ./groth16 + +export storagerequest +export period +export groth16 + +type + TransactionVersion* {.pure.} = enum + version0 + TransactionKind* {.pure.} = enum + storageProof + missingProof + Transaction* = object + requestId: StorageRequestId + slotIndex: uint32 + period: Period + merkleRoot: UInt256 + challenge: UInt256 + case kind: TransactionKind + of storageProof: + proof: Groth16Proof + of missingProof: + discard + +func storageProof*( + _: type Transaction, + requestId: StorageRequestId, + slotIndex: uint32, + period: Period, + merkleRoot: UInt256, + challenge: UInt256, + proof: Groth16Proof +): Transaction = + Transaction( + kind: TransactionKind.storageProof, + requestId: requestId, + period: period, + slotIndex: slotIndex, + merkleRoot: merkleRoot, + challenge: challenge, + proof: proof + ) + +func missingProof*( + _: type Transaction, + requestId: StorageRequestId, + slotIndex: uint32, + period: Period, + merkleRoot: UInt256, + challenge: UInt256, +): Transaction = + Transaction( + kind: TransactionKind.missingProof, + requestId: requestId, + slotIndex: slotIndex, + period: period, + merkleRoot: merkleRoot, + challenge: challenge + ) + +func version*(transaction: Transaction): TransactionVersion = + TransactionVersion.version0 + +func kind*(transaction: Transaction): TransactionKind = + transaction.kind + +func requestId*(transaction: Transaction): StorageRequestId = + transaction.requestId + +func slotIndex*(transaction: Transaction): uint32 = + transaction.slotIndex + +func period*(transaction: Transaction): Period = + transaction.period + +func merkleRoot*(transaction: Transaction): UInt256 = + transaction.merkleRoot + +func challenge*(transaction: Transaction): UInt256 = + transaction.challenge + +func proof*(transaction: Transaction): Groth16Proof = + transaction.proof + +func `==`*(a, b: Transaction): bool = + if a.kind != b.kind: + return false + if a.requestId != b.requestId: + return false + if a.slotIndex != b.slotIndex: + return false + if a.period != b.period: + return false + if a.merkleRoot != b.merkleRoot: + return false + if a.challenge != b.challenge: + return false + case a.kind + of TransactionKind.storageProof: + a.proof == b.proof + of TransactionKind.missingProof: + true diff --git a/tests/codexvalidator/examples.nim b/tests/codexvalidator/examples.nim index 13ede08..e87b3da 100644 --- a/tests/codexvalidator/examples.nim +++ b/tests/codexvalidator/examples.nim @@ -1,6 +1,7 @@ import std/random import codexvalidator/basics import codexvalidator/transaction +import codexvalidator/signatures proc example*[T: SomeInteger](_: type T): T = rand(T) @@ -67,3 +68,6 @@ proc example*(_: type Transaction): Transaction = challenge, proof ) + +proc example*(_: type Identity): Identity = + Identity.random(result) diff --git a/tests/codexvalidator/testSerialization.nim b/tests/codexvalidator/testSerialization.nim index 6a99ca9..07d8d01 100644 --- a/tests/codexvalidator/testSerialization.nim +++ b/tests/codexvalidator/testSerialization.nim @@ -1,11 +1,10 @@ import std/unittest import codexvalidator/basics import codexvalidator/transaction -import codexvalidator/serialization -import codexvalidator/serialization/protobuf +import codexvalidator/transaction/serialization import ./examples -suite "Serialization": +suite "Transaction serialization": test "serializes a transaction with protobuf": let transaction = Transaction.example diff --git a/tests/codexvalidator/testTransaction.nim b/tests/codexvalidator/testTransaction.nim index 6b35def..7b3df40 100644 --- a/tests/codexvalidator/testTransaction.nim +++ b/tests/codexvalidator/testTransaction.nim @@ -1,5 +1,6 @@ import std/unittest import codexvalidator/basics +import codexvalidator/signatures import codexvalidator/transaction import ./examples @@ -40,3 +41,20 @@ suite "Transaction": test "transactions have a fixed version": let transaction = Transaction.example check transaction.version == TransactionVersion.version0 + + test "transactions can be signed": + let identity = Identity.example + let transaction = Transaction.example + let signed = identity.sign(transaction) + check signed.transaction == transaction + check signed.signer == identity.identifier + check signed.signature == identity.sign(transaction.toBytes()) + + test "transaction signature can be verified": + let identity = Identity.example + let transaction = Transaction.example + let signed = identity.sign(transaction) + check signed.verifySignature() + let forger = Identity.example.identifier + let forged = SignedTransaction.init(transaction, forger, signed.signature) + check not forged.verifySignature()