2023-12-21 14:24:43 +01:00
|
|
|
import std/options
|
2023-10-31 13:40:07 +01:00
|
|
|
import constantine/math/arithmetic
|
|
|
|
import constantine/math/io/io_bigints
|
2023-11-23 16:37:41 +01:00
|
|
|
import constantine/math/io/io_fields
|
2024-07-15 12:29:09 +02:00
|
|
|
import constantine/named/algebras
|
2023-12-21 14:24:43 +01:00
|
|
|
import ./types
|
2023-11-09 14:44:38 +01:00
|
|
|
|
2024-07-15 12:29:09 +02:00
|
|
|
export algebras
|
2023-10-31 13:40:07 +01:00
|
|
|
|
2023-11-08 16:01:40 +01:00
|
|
|
func fromOpenArray(_: type F, bytes: openArray[byte]): F =
|
|
|
|
F.fromBig(B.unmarshal(bytes, littleEndian))
|
|
|
|
|
|
|
|
func fromBytes*(_: type F, bytes: array[31, byte]): F =
|
2023-11-02 09:19:14 +01:00
|
|
|
## Converts bytes into a field element. The byte array is interpreted as a
|
2023-11-08 16:01:40 +01:00
|
|
|
## canonical little-endian big integer.
|
|
|
|
F.fromOpenArray(bytes)
|
|
|
|
|
2023-12-21 14:24:43 +01:00
|
|
|
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)
|
2024-07-15 12:29:09 +02:00
|
|
|
if bool(big < F.getModulus()):
|
2023-12-21 14:24:43 +01:00
|
|
|
return some(F.fromBig(big))
|
|
|
|
|
2023-11-08 16:01:40 +01:00
|
|
|
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
|
|
|
|
## set to 0.
|
|
|
|
assert marshal(result, element.toBig(), littleEndian)
|
2023-11-02 08:54:04 +01:00
|
|
|
|
2023-11-08 13:25:23 +01:00
|
|
|
iterator elements*(bytes: openArray[byte], _: type F): F =
|
2023-11-02 09:19:14 +01:00
|
|
|
## Converts bytes into field elements. The byte array is converted 31 bytes at
|
2023-11-08 16:01:40 +01:00
|
|
|
## a time with the `F.fromBytes()` function. An end marker (0x1) and
|
|
|
|
## padding (0x0's) are added to ensure unique field elements for byte
|
|
|
|
## sequences that end with 0x0's.
|
2023-10-31 13:40:07 +01:00
|
|
|
const chunkLen = 31
|
2023-11-08 16:01:40 +01:00
|
|
|
const endMarker = @[1'u8]
|
2023-11-02 08:54:04 +01:00
|
|
|
var chunkStart = 0
|
2023-11-08 16:01:40 +01:00
|
|
|
while chunkStart + chunkLen <= bytes.len:
|
|
|
|
let chunkEnd = chunkStart + chunkLen - 1
|
|
|
|
let element = F.fromOpenArray(bytes.toOpenArray(chunkStart, chunkEnd))
|
2023-11-08 13:25:23 +01:00
|
|
|
yield element
|
2023-11-02 08:54:04 +01:00
|
|
|
chunkStart += chunkLen
|
2023-11-08 16:01:40 +01:00
|
|
|
let finalChunk = bytes[chunkStart..<bytes.len] & endMarker
|
|
|
|
let finalElement = F.fromOpenArray(finalChunk)
|
|
|
|
yield finalElement
|
2023-11-23 16:37:41 +01:00
|
|
|
|
|
|
|
# Remark: since `fromInt()` does not work at compile time, this doesn't either
|
2023-11-23 17:07:17 +01:00
|
|
|
func toF*(a: SomeInteger | SomeUnsignedInt) : F =
|
|
|
|
when a is SomeInteger:
|
|
|
|
fromInt(result, a)
|
|
|
|
else:
|
|
|
|
fromUInt(result, a)
|