Merge pull request #18 from codex-storage/convert-from-32-bytes

Convert from 32 bytes
This commit is contained in:
Ben Bierens 2024-01-18 09:09:18 +01:00 committed by GitHub
commit 74dbf15788
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 39 additions and 5 deletions

View File

@ -6,5 +6,5 @@ func compress*(a, b : F, key = zero) : F =
var x = a
var y = b
var z = key
permInplace(x, y, z)
permInPlace(x, y, z)
return x

View File

@ -1,8 +1,9 @@
import ./types
import std/options
import constantine/math/arithmetic
import constantine/math/io/io_bigints
import constantine/math/io/io_fields
import constantine/math/config/curves
import ./types
export curves
@ -14,6 +15,13 @@ func fromBytes*(_: type F, bytes: array[31, byte]): F =
## canonical little-endian big integer.
F.fromOpenArray(bytes)
func fromBytes*(_: type F, bytes: array[32, byte]): Option[F] =
## Converts bytes into a field element. The byte array is interpreted as a
## canonical little-endian big integer.
let big = B.unmarshal(bytes, littleEndian)
if bool(big < F.fieldMod()):
return some(F.fromBig(big))
func toBytes*(element: F): array[32, byte] =
## Converts a field element into its canonical representation in little-endian
## byte order. Uses at most 254 bits, the remaining most-significant bits are

View File

@ -2,7 +2,7 @@ import ./types
import ./roundfun
# the Poseidon2 permutation (mutable, in-place version)
proc permInplace*(x, y, z : var F) =
proc permInPlace*(x, y, z : var F) =
linearLayer(x, y, z)
for j in 0..3:
externalRound(j, x, y, z)
@ -14,5 +14,5 @@ proc permInplace*(x, y, z : var F) =
# the Poseidon2 permutation
func perm*(xyz: S) : S =
var (x,y,z) = xyz
permInplace(x, y, z)
permInPlace(x, y, z)
return (x,y,z)

View File

@ -38,3 +38,6 @@ func arrayFromHex*[N](
for i in low(inp)..high(inp):
tmp[i] = hexToF(inp[i], endian)
return tmp
func `==`*(a, b: F): bool =
bool(arithmetic.`==`(a, b))

View File

@ -1,5 +1,6 @@
import std/unittest
import std/sequtils
import std/options
import constantine/math/io/io_bigints
import constantine/math/io/io_fields
import constantine/math/arithmetic
@ -11,6 +12,9 @@ suite "conversion to/from bytes":
func toArray(bytes: openArray[byte]): array[31, byte] =
result[0..<bytes.len] = bytes[0..<bytes.len]
func toArray32(bytes: openArray[byte]): array[32, byte] =
result[0..<bytes.len] = bytes[0..<bytes.len]
test "converts 31 little endian bytes into a field elements":
let bytes = toArray toSeq 1'u8..31'u8
let paddedTo32 = @bytes & @[0'u8] # most significant byte is not used
@ -18,6 +22,18 @@ suite "conversion to/from bytes":
let unmarshalled = F.fromBytes(bytes)
check bool(unmarshalled == expected)
test "converts 32 little endian bytes into a field elements":
let bytes = toArray32(toSeq 1'u8..32'u8)
let expected = F.fromBig(B.unmarshal(bytes, littleEndian))
let unmarshalled = F.fromBytes(bytes).get()
check bool(unmarshalled == expected)
test "convert fails for 32 little endian bytes larger than the prime field":
let bytes = toArray32(toSeq((255'u8).repeat(32)))
let expected = F.fromBig(B.unmarshal(bytes, littleEndian))
let unmarshalled = F.fromBytes(bytes)
check not unmarshalled.isSome()
test "converts every 31 bytes into a field element":
let bytes = toSeq 1'u8..62'u8
let expected1 = F.fromBytes(bytes[0..<31].toArray)
@ -26,6 +42,13 @@ suite "conversion to/from bytes":
check bool(elements[0] == expected1)
check bool(elements[1] == expected2)
test "conversion preserves field element":
let
expected = toF(1234)
bytes = expected.toBytes()
actual = F.fromBytes(bytes).get()
check bool(expected == actual)
test "conversion from bytes adds 0x1 as an end marker":
let bytes = toSeq 1'u8..62'u8
let marker = @[1'u8]

View File

@ -15,7 +15,7 @@ suite "permutation":
var y: F = toF(1)
var z: F = toF(2)
permInplace(x, y, z)
permInPlace(x, y, z)
check toDecimal(x) == "21882471761025344482456282050943515707267606647948403374880378562101343146243"
check toDecimal(y) == "09030699330013392132529464674294378792132780497765201297316864012141442630280"