diff --git a/constantine.nimble b/constantine.nimble index 0b7efc4..b291c7b 100644 --- a/constantine.nimble +++ b/constantine.nimble @@ -20,4 +20,4 @@ task test, "Run all tests": test "", "tests/test_io.nim" test "", "tests/test_bigints.nim" test "", "tests/test_bigints_multimod.nim" - # test " -d:testingCurves", "tests/test_field_fp.nim" + test "", "tests/test_bigints_vs_gmp.nim" diff --git a/constantine/io/README.md b/constantine/io/README.md index 9c30eac..9b5e234 100644 --- a/constantine/io/README.md +++ b/constantine/io/README.md @@ -1 +1,7 @@ # I/O and serialization + +## References + +- Standards for Efficient Cryptography Group (SECG), + "SEC 1: Elliptic Curve Cryptography", May 2009, + http://www.secg.org/sec1-v2.pdf diff --git a/constantine/io/io.nim b/constantine/io/io_bigints.nim similarity index 94% rename from constantine/io/io.nim rename to constantine/io/io_bigints.nim index 9719275..da2bf44 100644 --- a/constantine/io/io.nim +++ b/constantine/io/io_bigints.nim @@ -100,6 +100,13 @@ func fromUint*( ## and store it into a BigInt of size `bits` result.fromRawUint(cast[array[sizeof(src), byte]](src), cpuEndian) +func fromUint*( + dst: var BigInt, + src: SomeUnsignedInt) = + ## Parse a regular unsigned integer + ## and store it into a BigInt of size `bits` + dst.fromRawUint(cast[array[sizeof(src), byte]](src), cpuEndian) + # ############################################################ # # Serialising from internal representation to canonical format @@ -122,7 +129,7 @@ template littleEndianXX[T: uint16 or uint32 or uint64](outp: pointer, inp: ptr T elif T is uint16: littleEndian16(outp, inp) -func dumpRawUintLE( +func serializeRawUintLE( dst: var openarray[byte], src: BigInt) {.inline.}= ## Serialize a bigint into its canonical little-endian representation @@ -168,7 +175,7 @@ func dumpRawUintLE( dst[dst_idx+i] = byte(lo shr ((tail-i)*8)) return -func dumpRawUint*( +func serializeRawUint*( dst: var openarray[byte], src: BigInt, dstEndianness: static Endianness) = @@ -186,7 +193,7 @@ func dumpRawUint*( zeroMem(dst, dst.len) when dstEndianness == littleEndian: - dumpRawUintLE(dst, src) + serializeRawUintLE(dst, src) else: {.error: "Not implemented at the moment".} @@ -327,7 +334,7 @@ func fromHex*(T: type BigInt, s: string): T = # 2. Convert canonical uint to Big Int result.fromRawUint(bytes, littleEndian) -func dumpHex*(big: BigInt, order: static Endianness = bigEndian): string = +func toHex*(big: BigInt, order: static Endianness = bigEndian): string = ## Stringify an int to hex. ## Note. Leading zeros are not removed. ## Result is prefixed with 0x @@ -338,9 +345,10 @@ func dumpHex*(big: BigInt, order: static Endianness = bigEndian): string = ## Regardless of the machine endianness the output will be big-endian hex. ## ## For example a BigInt representing 10 will be - ## - 0x0A for BigInt[8] - ## - 0x000A for BigInt[16] - ## - 0x00000000_0000000A for BigInt[64] + ## - 0x0a for BigInt[8] + ## - 0x000a for BigInt[16] + ## - 0x00000000_0000000a for BigInt[64] + ## (underscore added for docuentation readability only) ## ## CT: ## - no leaks @@ -348,7 +356,7 @@ func dumpHex*(big: BigInt, order: static Endianness = bigEndian): string = # 1. Convert Big Int to canonical uint const canonLen = (big.bits + 8 - 1) div 8 var bytes: array[canonLen, byte] - dumpRawUint(bytes, big, cpuEndian) + serializeRawUint(bytes, big, cpuEndian) # 2 Convert canonical uint to hex result = bytes.toHex(order) diff --git a/tests/test_bigints.nim b/tests/test_bigints.nim index cef30df..3d89c68 100644 --- a/tests/test_bigints.nim +++ b/tests/test_bigints.nim @@ -7,7 +7,7 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import unittest, random, strutils, - ../constantine/io/io, + ../constantine/io/io_bigints, ../constantine/math/bigints_checked, ../constantine/config/common, ../constantine/primitives/constant_time diff --git a/tests/test_bigints_multimod.nim b/tests/test_bigints_multimod.nim index cbddb62..c7bc856 100644 --- a/tests/test_bigints_multimod.nim +++ b/tests/test_bigints_multimod.nim @@ -10,7 +10,7 @@ import # Standard library unittest, random, strutils, # Third-party - ../constantine/io/io, + ../constantine/io/io_bigints, ../constantine/math/[bigints_raw, bigints_checked], ../constantine/primitives/constant_time diff --git a/tests/test_bigints_vs_gmp.nim b/tests/test_bigints_vs_gmp.nim index ff4d03c..577e38c 100644 --- a/tests/test_bigints_vs_gmp.nim +++ b/tests/test_bigints_vs_gmp.nim @@ -12,7 +12,7 @@ import # Third-party gmp, stew/byteutils, # Internal - ../constantine/io/io, + ../constantine/io/io_bigints, ../constantine/math/[bigints_raw, bigints_checked], ../constantine/primitives/constant_time @@ -138,7 +138,7 @@ proc main() = discard mpz_export(rGMP[0].addr, rW.addr, GMP_LeastSignificantWordFirst, 1, GMP_WordNativeEndian, 0, r) var rConstantine: array[mLen, byte] - dumpRawUint(rConstantine, rTest, littleEndian) + serializeRawUint(rConstantine, rTest, littleEndian) # echo "rGMP: ", rGMP.toHex() # echo "rConstantine: ", rConstantine.toHex() diff --git a/tests/test_field_fp.nim b/tests/test_finite_fields.nim similarity index 70% rename from tests/test_field_fp.nim rename to tests/test_finite_fields.nim index 50f8cd4..ec61c46 100644 --- a/tests/test_field_fp.nim +++ b/tests/test_finite_fields.nim @@ -7,4 +7,11 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import unittest, random, - ../constantine/[io, bigints, primitives, field_fp] + ../constantine/math/[io, primitives, finite_fields] + +proc main() = + suite "Basic arithmetic over finite fields": + test "Addition mod 101": + block: + var x: Fp[Fake101] + x.fromUint() diff --git a/tests/test_io.nim b/tests/test_io.nim index 198b2ce..8df825c 100644 --- a/tests/test_io.nim +++ b/tests/test_io.nim @@ -7,7 +7,7 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import unittest, random, - ../constantine/io/io, + ../constantine/io/io_bigints, ../constantine/config/common, ../constantine/math/bigints_checked @@ -34,7 +34,7 @@ proc main() = let big = BigInt[64].fromRawUint(x_bytes, littleEndian) # It's fine even on big-endian platform. We only want the byte-pattern var r_bytes: array[8, byte] - dumpRawUint(r_bytes, big, littleEndian) + serializeRawUint(r_bytes, big, littleEndian) check: x_bytes == r_bytes block: # "Little-endian" - single random @@ -43,7 +43,7 @@ proc main() = let big = BigInt[64].fromRawUint(x_bytes, littleEndian) # It's fine even on big-endian platform. We only want the byte-pattern var r_bytes: array[8, byte] - dumpRawUint(r_bytes, big, littleEndian) + serializeRawUint(r_bytes, big, littleEndian) check: x_bytes == r_bytes block: # "Little-endian" - 10 random cases @@ -53,28 +53,28 @@ proc main() = let big = BigInt[64].fromRawUint(x_bytes, littleEndian) # It's fine even on big-endian platform. We only want the byte-pattern var r_bytes: array[8, byte] - dumpRawUint(r_bytes, big, littleEndian) + serializeRawUint(r_bytes, big, littleEndian) check: x_bytes == r_bytes test "Round trip on elliptic curve constants": block: # Secp256k1 - https://en.bitcoin.it/wiki/Secp256k1 const p = "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f" let x = BigInt[256].fromHex(p) - let hex = x.dumpHex(bigEndian) + let hex = x.toHex(bigEndian) check: p == hex block: # BN254 - https://github.com/ethereum/py_ecc/blob/master/py_ecc/fields/field_properties.py const p = "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47" let x = BigInt[254].fromHex(p) - let hex = x.dumpHex(bigEndian) + let hex = x.toHex(bigEndian) check: p == hex block: # BLS12-381 - https://github.com/ethereum/py_ecc/blob/master/py_ecc/fields/field_properties.py const p = "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab" let x = BigInt[381].fromHex(p) - let hex = x.dumpHex(bigEndian) + let hex = x.toHex(bigEndian) check: p == hex