From 95eb2b4e285207199012937678878d6be36d0930 Mon Sep 17 00:00:00 2001 From: feltroid Prime <96737978+feltroidprime@users.noreply.github.com> Date: Mon, 30 Sep 2024 16:21:23 +0200 Subject: [PATCH 1/4] fix: Correct default option handling in garaga_ts::msmCalldataBuilder (#205) --- tools/npm/garaga_ts/src/node/api.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/npm/garaga_ts/src/node/api.ts b/tools/npm/garaga_ts/src/node/api.ts index 2e536e24..ae57f404 100644 --- a/tools/npm/garaga_ts/src/node/api.ts +++ b/tools/npm/garaga_ts/src/node/api.ts @@ -21,9 +21,9 @@ export type MsmCalldataBuilderOptons = Partial<{ export function msmCalldataBuilder(points: G1Point[], scalars: bigint[], curveId: CurveId, options: MsmCalldataBuilderOptons = {}): bigint[] { const values = points.reduce((values, point) => values.concat(point), []); - const includeDigitsDecomposition = options.includeDigitsDecomposition || true; - const includePointsAndScalars = options.includePointsAndScalars || true; - const serializeAsPureFelt252Array = options.serializeAsPureFelt252Array || false; - const risc0Mode = options.risc0Mode || false; + const includeDigitsDecomposition = options.includeDigitsDecomposition ?? true; + const includePointsAndScalars = options.includePointsAndScalars ?? true; + const serializeAsPureFelt252Array = options.serializeAsPureFelt252Array ?? false; + const risc0Mode = options.risc0Mode ?? false; return msm_calldata_builder(values, scalars, curveId, includeDigitsDecomposition, includePointsAndScalars, serializeAsPureFelt252Array, risc0Mode); } From 41e1cc01e9e02cb41968d1608891e6fa688d1a40 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 14:27:40 +0000 Subject: [PATCH 2/4] Bump next from 14.2.8 to 14.2.10 in /tools/npm/integration-test-suite/packages/web-js-esm-react (#203) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: feltroid Prime <96737978+feltroidprime@users.noreply.github.com> --- .../packages/web-js-esm-react/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/npm/integration-test-suite/packages/web-js-esm-react/package.json b/tools/npm/integration-test-suite/packages/web-js-esm-react/package.json index 778490b0..b303f0bf 100644 --- a/tools/npm/integration-test-suite/packages/web-js-esm-react/package.json +++ b/tools/npm/integration-test-suite/packages/web-js-esm-react/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "garaga": "file:../../garaga.tgz", - "next": "14.2.8", + "next": "14.2.10", "react": "^18", "react-dom": "^18" }, From 05a082b2a69dd0d4f4b236939091c10d4011ba17 Mon Sep 17 00:00:00 2001 From: feltroid Prime <96737978+feltroidprime@users.noreply.github.com> Date: Mon, 30 Sep 2024 16:36:06 +0200 Subject: [PATCH 3/4] base Drand Quicknet contract (#201) --- hydra/garaga/algebra.py | 17 +- hydra/garaga/definitions.py | 74 +- hydra/garaga/drand/client.py | 285 ++ hydra/garaga/hints/io.py | 28 +- .../precompiled_circuits/all_circuits.py | 8 + .../compilable_circuits/isogeny.py | 59 + hydra/garaga/signature.py | 412 ++ .../generator_risc0.py | 2 +- .../drand_calldata.py | 73 + .../map_to_curve.py | 132 + src/contracts/drand_quicknet/Scarb.toml | 15 + .../drand_quicknet/src/drand_verifier.cairo | 60 + .../src/drand_verifier_constants.cairo | 3571 +++++++++++++++++ src/contracts/drand_quicknet/src/lib.cairo | 2 + .../src/groth16_verifier.cairo | 2 +- src/src/basic_field_ops.cairo | 78 +- src/src/circuits.cairo | 1 + src/src/circuits/isogeny.cairo | 657 +++ src/src/definitions.cairo | 1 + src/src/ec_ops.cairo | 35 +- src/src/lib.cairo | 1 - src/src/utils.cairo | 2 + src/src/utils/drand.cairo | 832 ++++ src/src/utils/hashing.cairo | 15 +- .../{risc0_utils.cairo => utils/risc0.cairo} | 0 tests/contracts_e2e/e2e_test.py | 74 + tests/hydra/test_drand.py | 64 + tools/make/bytecode_check.sh | 5 + 28 files changed, 6467 insertions(+), 38 deletions(-) create mode 100644 hydra/garaga/drand/client.py create mode 100644 hydra/garaga/precompiled_circuits/compilable_circuits/isogeny.py create mode 100644 hydra/garaga/signature.py create mode 100644 hydra/garaga/starknet/tests_and_calldata_generators/drand_calldata.py create mode 100644 hydra/garaga/starknet/tests_and_calldata_generators/map_to_curve.py create mode 100644 src/contracts/drand_quicknet/Scarb.toml create mode 100644 src/contracts/drand_quicknet/src/drand_verifier.cairo create mode 100644 src/contracts/drand_quicknet/src/drand_verifier_constants.cairo create mode 100644 src/contracts/drand_quicknet/src/lib.cairo create mode 100644 src/src/circuits/isogeny.cairo create mode 100644 src/src/utils/drand.cairo rename src/src/{risc0_utils.cairo => utils/risc0.cairo} (100%) create mode 100644 tests/hydra/test_drand.py diff --git a/hydra/garaga/algebra.py b/hydra/garaga/algebra.py index 1310f103..c82e2c5e 100644 --- a/hydra/garaga/algebra.py +++ b/hydra/garaga/algebra.py @@ -147,10 +147,14 @@ def __rtruediv__(self, left: PyFelt | int) -> PyFelt: def is_quad_residue(self) -> bool: return legendre_symbol(self.value, self.p) == 1 - def sqrt(self) -> PyFelt: + def sqrt(self, min_root: bool = True) -> PyFelt: if not self.is_quad_residue(): raise ValueError("Cannot square root a non-quadratic residue") - return PyFelt(min(sqrt_mod(self.value, self.p, all_roots=True)), self.p) + roots = sqrt_mod(self.value, self.p, all_roots=True) + if min_root: + return PyFelt(min(roots), self.p) + else: + return PyFelt(max(roots), self.p) @dataclass(slots=True) @@ -313,8 +317,17 @@ def sqrt(self) -> Fp2: b = (Fp2.one(self.p) + alpha) ** ((self.p - 1) // 2) x = b * x0 + # Return the root as is, without forcing a specific sign return x + def lexicographically_largest(self) -> bool: + """Check if this Fp2 element is lexicographically largest.""" + if self.a1.value > (self.p - 1) // 2: + return True + if self.a1.value < (self.p - 1) // 2: + return False + return self.a0.value > (self.p - 1) // 2 + @dataclass(slots=True) class BaseField: diff --git a/hydra/garaga/definitions.py b/hydra/garaga/definitions.py index 23537c7a..a567c444 100644 --- a/hydra/garaga/definitions.py +++ b/hydra/garaga/definitions.py @@ -87,6 +87,13 @@ def get_proving_system_curve( return CurveID(curve_id) +@dataclass +class SWUParams: + A: int + B: int + Z: int + + @dataclass(slots=True, frozen=True) class WeierstrassCurve: cairo_zero_namespace_name: str @@ -99,6 +106,7 @@ class WeierstrassCurve: fp_generator: int # A generator of the field of the curve. To verify it, use is_generator function. Gx: int # x-coordinate of the generator point Gy: int # y-coordinate of the generator point + swu_params: SWUParams def to_cairo_zero(self) -> str: code = f"namespace {self.cairo_zero_namespace_name} {{\n" @@ -160,12 +168,14 @@ def __init__( fp_generator: int, Gx: int, Gy: int, + swu_params: SWUParams, ): assert a_twisted != 0 and d_twisted != 0 and a_twisted != d_twisted # Set attributes object.__setattr__(self, "d_twisted", d_twisted) object.__setattr__(self, "a_twisted", a_twisted) object.__setattr__(self, "p", p) + object.__setattr__(self, "swu_params", swu_params) # Calculate Weierstrass parameters a = ( -1 @@ -191,6 +201,7 @@ def __init__( b, fp_generator, *(self.to_weierstrass(Gx, Gy)), + swu_params, ) def to_weierstrass(self, x_twisted, y_twisted): @@ -326,6 +337,7 @@ def bit(value, index): 0x12C85EA5DB8C6DEB4AAB71808DCB408FE3D1E7690C43D37B4CE6CC0166FA7DAA, 0x90689D0585FF075EC9E99AD690C3395BC4B313370B38EF355ACDADCD122975B, ), + swu_params=None, ), BLS12_381_ID: PairingCurve( cairo_zero_namespace_name="bls", @@ -371,6 +383,11 @@ def bit(value, index): 0xCE5D527727D6E118CC9CDC6DA2E351AADFD9BAA8CBDD3A76D429A695160D12C923AC9CC3BACA289E193548608B82801, 0x606C4A02EA734CC32ACD2B02BC28B99CB3E287E85A763AF267492AB572E99AB3F370D275CEC1DA1AAA9075FF05F79BE, ), + swu_params=SWUParams( + A=0x144698A3B8E9433D693A02C96D4982B0EA985383EE66A8D8E8981AEFD881AC98936F8DA0E0F97F5CF428082D584C1D, + B=0x12E2908D11688030018B12E8753EEE3B2016C1F0F24F4070A0B9C14FCEF35EF55A23215A316CEAA5D1CC48E98E172BE0, + Z=11, + ), ), SECP256K1_ID: WeierstrassCurve( cairo_zero_namespace_name="secp256k1", @@ -383,6 +400,7 @@ def bit(value, index): fp_generator=3, Gx=0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, Gy=0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8, + swu_params=None, ), SECP256R1_ID: WeierstrassCurve( cairo_zero_namespace_name="secp256r1", @@ -395,6 +413,7 @@ def bit(value, index): fp_generator=6, Gx=0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296, Gy=0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5, + swu_params=None, ), ED25519_ID: TwistedEdwardsCurve( cairo_zero_namespace_name="ED25519", # See https://neuromancer.sk/std/other/Ed25519 @@ -407,6 +426,7 @@ def bit(value, index): fp_generator=6, Gx=0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A, Gy=0x6666666666666666666666666666666666666666666666666666666666666658, + swu_params=None, ), } @@ -528,12 +548,13 @@ class G1Point: x: int y: int curve_id: CurveID + iso_point: bool = False def __str__(self) -> str: - return f"G1Point({hex(self.x)}, {hex(self.y)}) on curve {self.curve_id}" + return f"G1Point({self.x}, {self.y}) on curve {self.curve_id}" def __hash__(self): - return hash((self.x, self.y, self.curve_id)) + return hash((self.x, self.y, self.curve_id, self.iso_point)) def __eq__(self, other: object) -> bool: """ @@ -551,6 +572,7 @@ def __eq__(self, other: object) -> bool: self.x == other.x and self.y == other.y and self.curve_id.value == other.curve_id.value + and self.iso_point == other.iso_point ) def __post_init__(self): @@ -646,8 +668,13 @@ def is_on_curve(self) -> bool: Returns: bool: True if the point is on the curve, False otherwise. """ - a = CURVES[self.curve_id.value].a - b = CURVES[self.curve_id.value].b + if self.iso_point: + a = CURVES[self.curve_id.value].swu_params.A + b = CURVES[self.curve_id.value].swu_params.B + else: + a = CURVES[self.curve_id.value].a + b = CURVES[self.curve_id.value].b + p = CURVES[self.curve_id.value].p lhs = self.y**2 % p rhs = (self.x**3 + a * self.x + b) % p @@ -722,25 +749,30 @@ def scalar_mul(self, scalar: int) -> "G1Point": if self.is_infinity(): return self if scalar == 0: - return G1Point(0, 0, self.curve_id) - + return G1Point(0, 0, self.curve_id, self.iso_point) + if self.iso_point: + a = CURVES[self.curve_id.value].swu_params.A + b = CURVES[self.curve_id.value].swu_params.B + else: + a = CURVES[self.curve_id.value].a + b = CURVES[self.curve_id.value].b # Fastecdsa C binding. x, y = curvemath.mul( str(self.x), str(self.y), str(abs(scalar)), str(CURVES[self.curve_id.value].p), - str(CURVES[self.curve_id.value].a), - str(CURVES[self.curve_id.value].b), + str(a), + str(b), str(CURVES[self.curve_id.value].n), str(CURVES[self.curve_id.value].Gx), str(CURVES[self.curve_id.value].Gy), ) # Fastecdsa already returns (0, 0) for the identity element. if scalar < 0: - return -G1Point(int(x), int(y), self.curve_id) + return -G1Point(int(x), int(y), self.curve_id, self.iso_point) else: - return G1Point(int(x), int(y), self.curve_id) + return G1Point(int(x), int(y), self.curve_id, self.iso_point) def add(self, other: "G1Point") -> "G1Point": """ @@ -761,20 +793,29 @@ def add(self, other: "G1Point") -> "G1Point": return self if self.curve_id != other.curve_id: raise ValueError("Points are not on the same curve") + if self.iso_point != other.iso_point: + raise ValueError("Points are not on the same curve") + if self.iso_point: + a = CURVES[self.curve_id.value].swu_params.A + b = CURVES[self.curve_id.value].swu_params.B + else: + a = CURVES[self.curve_id.value].a + b = CURVES[self.curve_id.value].b + x, y = curvemath.add( str(self.x), str(self.y), str(other.x), str(other.y), str(CURVES[self.curve_id.value].p), - str(CURVES[self.curve_id.value].a), - str(CURVES[self.curve_id.value].b), + str(a), + str(b), str(CURVES[self.curve_id.value].n), str(CURVES[self.curve_id.value].Gx), str(CURVES[self.curve_id.value].Gy), ) - return G1Point(int(x), int(y), self.curve_id) + return G1Point(int(x), int(y), self.curve_id, self.iso_point) def __neg__(self) -> "G1Point": """ @@ -783,7 +824,12 @@ def __neg__(self) -> "G1Point": Returns: G1Point: The negated point. """ - return G1Point(self.x, -self.y % CURVES[self.curve_id.value].p, self.curve_id) + return G1Point( + self.x, + -self.y % CURVES[self.curve_id.value].p, + self.curve_id, + self.iso_point, + ) @dataclass(frozen=True) diff --git a/hydra/garaga/drand/client.py b/hydra/garaga/drand/client.py new file mode 100644 index 00000000..8582b433 --- /dev/null +++ b/hydra/garaga/drand/client.py @@ -0,0 +1,285 @@ +import binascii +import hashlib +import random +from dataclasses import dataclass +from enum import Enum +from typing import List, Optional, Union + +import requests +from requests.exceptions import RequestException + +from garaga.definitions import CurveID, Fp2, G1Point, G2Point, get_base_field +from garaga.hints import io + + +class DrandNetwork(Enum): + default = "8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce" + quicknet = "52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971" + + +def digest_func(round_number: int) -> bytes: + assert isinstance(round_number, int) + assert 0 <= round_number < 2**64 + h = hashlib.sha256() + h.update(round_number.to_bytes(8, byteorder="big")) + return h.digest() + + +@dataclass +class NetworkInfo: + public_key: Union[G1Point, G2Point] + period: int + genesis_time: int + hash: str + group_hash: str + scheme_id: str + beacon_id: Optional[str] = None + + +@dataclass +class RandomnessBeacon: + round_number: int + randomness: int + signature: str + previous_signature: Optional[str] = None + + @property + def signature_point(self) -> G1Point | G2Point: + return deserialize_bls_point(bytes.fromhex(self.signature)) + + +BASE_URLS = [ + "https://drand.cloudflare.com", + "https://api.drand.sh", + "https://api.drand.secureweb3.com:6875/", + "https://api2.drand.sh/", + "https://api3.drand.sh/", +] + + +def make_request(endpoint: str) -> requests.Response: + base_urls = BASE_URLS.copy() + url = random.choice(base_urls) + while len(base_urls) > 0: + try: + response = requests.get(f"{url}{endpoint}") + response.raise_for_status() + return response + except RequestException as e: + print(f"Request to {url} failed: {str(e)}. Removing from list.") + base_urls.remove(url) + if len(base_urls) == 0: + raise RequestException("All URLs failed") + url = random.choice(base_urls) + + +def deserialize_bls_point(s_string: bytes) -> Union[G1Point, G2Point]: + m_byte = s_string[0] & 0xE0 + if m_byte in (0x20, 0x60, 0xE0): + raise ValueError("Invalid encoding") + + C_bit = (m_byte & 0x80) >> 7 # Compression bit + I_bit = (m_byte & 0x40) >> 6 # Infinity bit + S_bit = (m_byte & 0x20) >> 5 # Sign bit + + s_string = bytes([s_string[0] & 0x1F]) + s_string[1:] + + if I_bit == 1: + if any(b != 0 for b in s_string): + raise ValueError("Invalid encoding for point at infinity") + return ( + G1Point.infinity(CurveID.BLS12_381) + if len(s_string) in (48, 96) + else G2Point.infinity(CurveID.BLS12_381) + ) + + if C_bit == 0: + if len(s_string) == 96: # G1 point (uncompressed) + x = int.from_bytes(s_string[:48], "big") + y = int.from_bytes(s_string[48:], "big") + return G1Point(x, y, CurveID.BLS12_381) + elif len(s_string) == 192: # G2 point (uncompressed) + x0 = int.from_bytes(s_string[:48], "big") + x1 = int.from_bytes(s_string[48:96], "big") + y0 = int.from_bytes(s_string[96:144], "big") + y1 = int.from_bytes(s_string[144:], "big") + return G2Point((x0, x1), (y0, y1), CurveID.BLS12_381) + else: + raise ValueError(f"Invalid length for uncompressed point: {len(s_string)}") + else: # C_bit == 1 + x = int.from_bytes(s_string, "big") + if len(s_string) == 48: # G1 point (compressed) + field = get_base_field(CurveID.BLS12_381) + y2 = field(x**3 + 4) + y = y2.sqrt() + Y_bit = y.value & 1 + if S_bit != Y_bit: + y = -y + return G1Point(x, y.value, CurveID.BLS12_381) + elif len(s_string) == 96: # G2 point (compressed) + field = get_base_field(CurveID.BLS12_381, Fp2) + x = field((x & ((1 << 384) - 1), x >> 384)) + y2 = x**3 + field((4, 4)) + y = y2.sqrt() + + if S_bit == 1: + # Choose largest root + # print("choose largest") + if not y.lexicographically_largest(): + # print("root was not largest, negating") + y = -y + else: + # Choose smallest root + # print("choose smallest") + if y.lexicographically_largest(): + # print("root was largest, negating") + y = -y + + return G2Point( + (x.a0.value, x.a1.value), + (y.a0.value, y.a1.value), + CurveID.BLS12_381, + ) + else: + raise ValueError(f"Invalid length for compressed point: {len(s_string)}") + + +def get_chains() -> List[str]: + response = make_request("/chains") + all_chains = response.json() + # only keep chains present in DrandNetwork enum + chains = [ + chain + for chain in all_chains + if chain in [network.value for network in DrandNetwork] + ] + return chains + + +def get_chain_info(chain_hash: str) -> NetworkInfo: + response = make_request(f"/{chain_hash}/info") + data = response.json() + + # Parse the public key + public_key_hex = data["public_key"] + public_key_bytes = binascii.unhexlify(public_key_hex) + + try: + public_key = deserialize_bls_point(public_key_bytes) + except Exception as e: + public_key = G2Point.infinity(CurveID.BLS12_381) + + return NetworkInfo( + public_key=public_key, + period=data["period"], + genesis_time=data["genesis_time"], + hash=data["hash"], + group_hash=data["groupHash"], + scheme_id=data["schemeID"], + beacon_id=data.get("metadata", {}).get("beaconID"), + ) + + +def get_latest_randomness(chain_hash: str) -> RandomnessBeacon: + response = make_request(f"/{chain_hash}/public/latest") + return _parse_randomness_beacon(response.json()) + + +def get_randomness(chain_hash: str, round_number: int) -> RandomnessBeacon: + response = make_request(f"/{chain_hash}/public/{round_number}") + return _parse_randomness_beacon(response.json()) + + +def _parse_randomness_beacon(data: dict) -> RandomnessBeacon: + return RandomnessBeacon( + round_number=io.to_int(data["round"]), + randomness=int(data["randomness"], 16), + signature=data["signature"], + previous_signature=data.get("previous_signature"), + ) + + +def print_all_chain_info() -> dict[DrandNetwork, NetworkInfo]: + chains = get_chains() + print(f"Found {len(chains)} chains: {chains}") + print("-" * 40) + + chain_infos = {} + + for chain_hash in chains: + try: + info = get_chain_info(chain_hash) + chain_infos[DrandNetwork(chain_hash)] = info + print(f"Chain: {chain_hash}") + print(f" Public Key: {info.public_key}") + print(f" Period: {info.period} seconds") + print(f" Genesis Time: {info.genesis_time}") + print(f" Hash: {info.hash}") + print(f" Group Hash: {info.group_hash}") + print(f" Scheme ID: {info.scheme_id}") + if info.beacon_id: + print(f" Beacon ID: {info.beacon_id}") + print("-" * 40) + except Exception as e: + print(f"Error fetching info for chain {chain_hash}: {str(e)}") + print("-" * 40) + raise e + + return chain_infos + + +# Example usage +if __name__ == "__main__": + chain_infos = print_all_chain_info() + from garaga.modulo_circuit_structs import StructArray + from garaga.signature import hash_to_curve + + # latest_randomness = get_latest_randomness(chain_infos[DrandNetwork.default].hash) + # print("Latest randomness:", latest_randomness) + network = DrandNetwork.quicknet + chain = chain_infos[network] + print(chain.public_key) + print(-chain.public_key) + + round = get_randomness(chain.hash, 1000) + print("Randomness for round 1000:", round) + sha256 = hashlib.sha256() + sha256.update(bytes.fromhex(round.signature)) + print("randomness", sha256.hexdigest()) + print("random beacon", hex(round.randomness)) + + msg_point = hash_to_curve( + digest_func(round.round_number), CurveID.BLS12_381, "sha256" + ) + print("message", msg_point) + + from garaga.definitions import G1G2Pair + from garaga.modulo_circuit_structs import G2Line, StructArray + from garaga.precompiled_circuits.multi_miller_loop import precompute_lines + + print( + "pairing", + G1G2Pair.pair( + [ + G1G2Pair( + p=round.signature_point, q=G2Point.get_nG(CurveID.BLS12_381, 1) + ), + G1G2Pair(p=msg_point, q=-chain.public_key), + ], + curve_id=CurveID.BLS12_381, + ).value_coeffs, + ) + + lines = precompute_lines([G2Point.get_nG(CurveID.BLS12_381, 1), -chain.public_key]) + precomputed_lines = StructArray( + name="lines", + elmts=[ + G2Line(name=f"line{i}", elmts=lines[i : i + 4]) + for i in range(0, len(lines), 4) + ], + ) + + def generate_precomputed_lines_code(precomputed_lines: StructArray) -> str: + return f"pub const precomputed_lines: [G2Line; {len(precomputed_lines)//4}] = {precomputed_lines.serialize(raw=True, const=True)};" + + print(generate_precomputed_lines_code(precomputed_lines)) diff --git a/hydra/garaga/hints/io.py b/hydra/garaga/hints/io.py index c2f9fdca..2fc7167d 100644 --- a/hydra/garaga/hints/io.py +++ b/hydra/garaga/hints/io.py @@ -42,13 +42,20 @@ def to_hex_str(value: str | int): raise TypeError(f"Expected str or int, got {type(value).__name__}") +# Split a bigint into its limbs. +# Accepts int, ModuloCircuitElement, PyFelt, or bytes. +# Returns the limbs in little-endian order. +# Ie : x = d0 + d1 * base + d2 * base^2 + ... + dn * base^n +# Returns the coefficients [d0, d1, d2, ..., dn] def bigint_split( - x: int | ModuloCircuitElement | PyFelt, n_limbs: int = 4, base: int = 2**96 + x: int | ModuloCircuitElement | PyFelt | bytes, n_limbs: int = 4, base: int = 2**96 ) -> list[int]: - if isinstance(x, (ModuloCircuitElement, PyFelt)): - x = x.value - elif isinstance(x, int): + if isinstance(x, int): pass + elif isinstance(x, (ModuloCircuitElement, PyFelt)): + x = x.value + elif isinstance(x, bytes): + x = int.from_bytes(x, byteorder="big") else: raise ValueError(f"Invalid type for bigint_split: {type(x)}") @@ -62,6 +69,19 @@ def bigint_split( return coeffs[::-1] +def bytes_to_u32_array(bytes_array: bytes, name: str) -> str: + code = f"const {name}: [u32; {((len(bytes_array) + 3) // 4)}] = [" + + for i in range(0, len(bytes_array), 4): + chunk = bytes_array[i : i + 4] + + u32_value = int.from_bytes(chunk, "big") + code += f"{hex(u32_value)}, " + + code += "];" + return code + + def to_int(value: str | int | bytes) -> int: """ Convert a string or integer to an integer. Supports hexadecimal and decimal strings. diff --git a/hydra/garaga/precompiled_circuits/all_circuits.py b/hydra/garaga/precompiled_circuits/all_circuits.py index 7a7043ce..65e6236a 100644 --- a/hydra/garaga/precompiled_circuits/all_circuits.py +++ b/hydra/garaga/precompiled_circuits/all_circuits.py @@ -34,6 +34,7 @@ RHSFinalizeAccCircuit, SlopeInterceptSamePointCircuit, ) +from garaga.precompiled_circuits.compilable_circuits.isogeny import ApplyIsogenyCircuit from garaga.starknet.cli.utils import create_directory @@ -78,6 +79,7 @@ class CircuitID(Enum): MP_CHECK_FINALIZE_BLS = int.from_bytes(b"mp_check_finalize_bls", "big") FP12_MUL_ASSERT_ONE = int.from_bytes(b"fp12_mul_assert_one", "big") EVAL_E12D = int.from_bytes(b"eval_e12d", "big") + APPLY_ISOGENY = int.from_bytes(b"apply_isogeny", "big") ALL_CAIRO_CIRCUITS = { @@ -217,6 +219,12 @@ class CircuitID(Enum): "filename": "extf_mul", "curve_ids": [CurveID.BN254, CurveID.BLS12_381], }, + CircuitID.APPLY_ISOGENY: { + "class": ApplyIsogenyCircuit, + "params": None, + "filename": "isogeny", + "curve_ids": [CurveID.BLS12_381], + }, } diff --git a/hydra/garaga/precompiled_circuits/compilable_circuits/isogeny.py b/hydra/garaga/precompiled_circuits/compilable_circuits/isogeny.py new file mode 100644 index 00000000..41409a57 --- /dev/null +++ b/hydra/garaga/precompiled_circuits/compilable_circuits/isogeny.py @@ -0,0 +1,59 @@ +import garaga.modulo_circuit_structs as structs +from garaga.definitions import CurveID +from garaga.precompiled_circuits.compilable_circuits.base import ( + BaseModuloCircuit, + ModuloCircuit, + PyFelt, +) +from garaga.signature import get_isogeny_to_g1_map + + +class ApplyIsogenyCircuit(BaseModuloCircuit): + def __init__( + self, curve_id: int, auto_run: bool = True, compilation_mode: int = 1 + ) -> None: + super().__init__( + name=f"apply_isogeny_{CurveID(curve_id).name.lower()}", + input_len=2, + curve_id=curve_id, + auto_run=auto_run, + compilation_mode=compilation_mode, + ) + + def build_input(self) -> list[PyFelt]: + return [self.field(44), self.field(4)] + + def _run_circuit_inner(self, input: list[PyFelt]) -> ModuloCircuit: + circuit = ModuloCircuit( + self.name, + self.curve_id, + compilation_mode=self.compilation_mode, + ) + px, py = circuit.write_struct(structs.G1PointCircuit(name="pt", elmts=input)) + x_rational, y_rational = get_isogeny_to_g1_map(CurveID(self.curve_id)) + x_num = [ + circuit.set_or_get_constant(c) for c in x_rational.numerator.coefficients + ] + x_den = [ + circuit.set_or_get_constant(c) for c in x_rational.denominator.coefficients + ] + + y_num = [ + circuit.set_or_get_constant(c) for c in y_rational.numerator.coefficients + ] + y_den = [ + circuit.set_or_get_constant(c) for c in y_rational.denominator.coefficients + ] + + x_affine_num = circuit.eval_horner(x_num, px, "x_num") + x_affine_den = circuit.eval_horner(x_den, px, "x_den") + x_affine = circuit.div(x_affine_num, x_affine_den) + y_affine_num = circuit.eval_horner(y_num, px, "y_num") + y_affine_den = circuit.eval_horner(y_den, px, "y_den") + y_affine_eval = circuit.div(y_affine_num, y_affine_den) + y_affine = circuit.mul(y_affine_eval, py) + circuit.extend_struct_output( + structs.G1PointCircuit(name="res", elmts=[x_affine, y_affine]) + ) + + return circuit diff --git a/hydra/garaga/signature.py b/hydra/garaga/signature.py new file mode 100644 index 00000000..0579d5b4 --- /dev/null +++ b/hydra/garaga/signature.py @@ -0,0 +1,412 @@ +""" +Various tools for bls signatures or other signature schemes. +""" + +from __future__ import annotations + +import hashlib +from typing import Protocol, TypeVar + +from garaga.algebra import Polynomial, PyFelt, RationalFunction +from garaga.definitions import CURVES, CurveID, G1Point, get_base_field + +T = TypeVar("T", bound="HashProtocol") + + +class HashProtocol(Protocol): + # Attributes + block_size: int # + digest_size: int # in bytes + name: str + + # Methods + def update(self, data: bytes) -> None: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def copy(self: T) -> T: ... + + +import math + +G1_DOMAIN = DST = b"BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_" + + +MAX_DST_LENGTH = 255 +LONG_DST_PREFIX = b"H2C-OVERSIZE-DST-" + + +class ExpanderXmd: + def __init__( + self, + hash_name: str, + dst: bytes = DST, + curve_id: CurveID = CurveID.BLS12_381, + ): + self.hash_name = hash_name + self.hasher = hashlib.new(hash_name) + self.dst = dst + self.curve_id = curve_id + self.block_size = get_len_per_elem(get_base_field(curve_id).p) + + def construct_dst_prime(self) -> bytes: + if len(self.dst) > MAX_DST_LENGTH: + hasher_copy = self.hasher.copy() + hasher_copy.update(LONG_DST_PREFIX) + hasher_copy.update(self.dst) + dst_prime = hasher_copy.digest() + else: + # print(f"dst len is < {MAX_DST_LENGTH}") + dst_prime = self.dst + + dst_prime += bytes([len(dst_prime)]) + return dst_prime + + def expand_message_xmd(self, msg: bytes, n: int) -> bytes: + b_len = self.hasher.digest_size + ell = (n + (b_len - 1)) // b_len + assert ( + ell <= 255 + ), "The ratio of desired output to the output size of hash function is too large!" + + dst_prime = self.construct_dst_prime() + # print(f"dst prime {dst_prime}") + # print(f"block size {self.block_size}") + z_pad = bytes([0] * self.block_size) + # print(f"z pad {z_pad.hex()}") + # print(f"len(z_pad) (bytes) {len(z_pad)}") + assert n < (1 << 16), "Length should be smaller than 2^16" + lib_str = n.to_bytes(2, "big") + + self.hasher.update(z_pad) + self.hasher.update(msg) + # Print separately lib_str+bytes([0])+dst_prime, in one bytes object + lib_str_dst_prime = lib_str + bytes([0]) + dst_prime + # print( + # f"lib_str_dst_prime {lib_str_dst_prime}, len : {len(lib_str_dst_prime)}\n {bytes_to_u32_array(lib_str_dst_prime, 'lib_str_dst_prime')}" + # ) + self.hasher.update(lib_str_dst_prime) + # self.hasher.update(bytes([0])) + # self.hasher.update(dst_prime) + b0 = self.hasher.digest() + # print(f"b0 {b0.hex()}") + hasher = hashlib.new(self.hash_name) + hasher.update(b0) + one_dst_prime = bytes([1]) + dst_prime + hasher.update(one_dst_prime) + bi = hasher.digest() + + uniform_bytes = bi + + for i in range(2, ell + 1): + # print(f"loop: step {i}/{ell}") + # print(f"zip {list(zip(b0, bi))}") + + b0_xor_bi = bytes(x ^ y for x, y in zip(b0, bi)) + # print(f"b0_xor_bi {b0_xor_bi.hex()}") + # print( + # f"direct xor : {hex(int.from_bytes(b0, 'big') ^ int.from_bytes(bi, 'big'))}" + # ) + hasher = hashlib.new(self.hash_name) + hasher.update(b0_xor_bi) + bytes_i_dst_prime = bytes([i]) + dst_prime + # print( + # f"bytes_i_dst_prime {bytes_to_u32_array(bytes_i_dst_prime, f'bytes_{i}_dst_prime')}" + # ) + hasher.update(bytes_i_dst_prime) + bi = hasher.digest() + uniform_bytes += bi + + # print(f"len(uniform_bytes) {len(uniform_bytes)}") + # print(f"len(uniform_bytes[:n]) {len(uniform_bytes[:n])}") + return uniform_bytes[:n] + + +def get_len_per_elem(p: int, sec_param: int = 128) -> int: + """ + This function computes the length in bytes that a hash function should output + for hashing an element of type `Field`. + + :param p: The prime modulus of the base field. + :param sec_param: The security parameter. + :return: The length in bytes. + """ + # ceil(log2(p)) + base_field_size_in_bits = p.bit_length() + # ceil(log2(p)) + security_parameter + base_field_size_with_security_padding_in_bits = base_field_size_in_bits + sec_param + # ceil((ceil(log2(p)) + security_parameter) / 8) + bytes_per_base_field_elem = math.ceil( + base_field_size_with_security_padding_in_bits / 8 + ) + return bytes_per_base_field_elem + + +def hash_to_field( + message: bytes, count: int, curve_id: int, hash_name: str +) -> list[int]: + field = get_base_field(curve_id) + + expander = ExpanderXmd(hash_name, dst=DST, curve_id=curve_id) + + len_per_elem = get_len_per_elem(field.p) + len_in_bytes = count * len_per_elem + # print(f"len per elem {len_per_elem}") + # print(f"len in bytes: {len_in_bytes}") + # print(f"message {message.hex()}") + uniform_bytes = expander.expand_message_xmd(message, len_in_bytes) + # print(f"uniform bytes {uniform_bytes.hex()}") + output = [] + + for i in range(0, len_in_bytes, len_per_elem): + element = int.from_bytes(uniform_bytes[i : i + len_per_elem], "big") + # print(f"element {element.bit_length()}") + output.append(element) + + return [field(x) for x in output] + + +def hash_to_curve( + message: bytes, curve_id: CurveID, hash_name: str = "sha256" +) -> G1Point: + felt0, felt1 = hash_to_field(message, 2, curve_id, hash_name) + + pt0 = map_to_curve(felt0, curve_id) + # print(f"pt0 {pt0}\n\n") + pt1 = map_to_curve(felt1, curve_id) + # print(f"pt1 {pt1}") + assert pt0.iso_point == True, f"Point {pt0} is not an iso point" + assert pt1.iso_point == True, f"Point {pt1} is not an iso point" + + if curve_id == CurveID.BLS12_381: + x = CURVES[curve_id.value].x + n = CURVES[curve_id.value].n + cofactor = (1 - (x % n)) % n + else: + cofactor = CURVES[curve_id.value].h + + # print(f"cofactor {cofactor}") + sum = pt0.add(pt1) + assert sum.iso_point == True, f"Point {sum} is not an iso point" + + return apply_isogeny(sum).scalar_mul(cofactor) + + +def map_to_curve(field_element: PyFelt, curve_id: CurveID) -> G1Point: + field = get_base_field(curve_id) + a = field(CURVES[curve_id.value].swu_params.A) + b = field(CURVES[curve_id.value].swu_params.B) + z = field(CURVES[curve_id.value].swu_params.Z) + + u = field_element + zeta_u2 = z * u**2 + ta = zeta_u2**2 + zeta_u2 + num_x1 = b * (ta + field.one()) + + if ta.value == 0: + div = a * z + else: + div = a * -ta + + num2_x1 = num_x1**2 + div2 = div**2 + div3 = div2 * div + assert div3.value != 0 + + num_gx1 = (num2_x1 + a * div2) * num_x1 + b * div3 + + num_x2 = zeta_u2 * num_x1 + + gx1 = num_gx1 / div3 + gx1_square = gx1.is_quad_residue() + if gx1_square: + y1 = gx1.sqrt(min_root=False) + assert y1 * y1 == gx1 + else: + y1 = (z * gx1).sqrt(min_root=False) + assert y1 * y1 == z * gx1 + + y2 = zeta_u2 * u * y1 + num_x = num_x1 if gx1_square else num_x2 + y = y1 if gx1_square else y2 + x_affine = num_x / div + y_affine = -y if y.value % 2 != u.value % 2 else y + + point_on_curve = G1Point(x_affine.value, y_affine.value, curve_id, iso_point=True) + return point_on_curve + + +# https://github.com/arkworks-rs/algebra/blob/master/curves/bls12_381/src/curves/g1_swu_iso.rs + + +def get_isogeny_to_g1_map( + curve_id: CurveID, +) -> tuple[RationalFunction, RationalFunction]: + field = get_base_field(curve_id) + match curve_id.value: + case CurveID.BLS12_381.value: + return RationalFunction( + numerator=Polynomial( + [ + field(x) + for x in [ + 0x11A05F2B1E833340B809101DD99815856B303E88A2D7005FF2627B56CDB4E2C85610C2D5F2E62D6EAEAC1662734649B7, + 0x17294ED3E943AB2F0588BAB22147A81C7C17E75B2F6A8417F565E33C70D1E86B4838F2A6F318C356E834EEF1B3CB83BB, + 0xD54005DB97678EC1D1048C5D10A9A1BCE032473295983E56878E501EC68E25C958C3E3D2A09729FE0179F9DAC9EDCB0, + 0x1778E7166FCC6DB74E0609D307E55412D7F5E4656A8DBF25F1B33289F1B330835336E25CE3107193C5B388641D9B6861, + 0xE99726A3199F4436642B4B3E4118E5499DB995A1257FB3F086EEB65982FAC18985A286F301E77C451154CE9AC8895D9, + 0x1630C3250D7313FF01D1201BF7A74AB5DB3CB17DD952799B9ED3AB9097E68F90A0870D2DCAE73D19CD13C1C66F652983, + 0xD6ED6553FE44D296A3726C38AE652BFB11586264F0F8CE19008E218F9C86B2A8DA25128C1052ECADDD7F225A139ED84, + 0x17B81E7701ABDBE2E8743884D1117E53356DE5AB275B4DB1A682C62EF0F2753339B7C8F8C8F475AF9CCB5618E3F0C88E, + 0x80D3CF1F9A78FC47B90B33563BE990DC43B756CE79F5574A2C596C928C5D1DE4FA295F296B74E956D71986A8497E317, + 0x169B1F8E1BCFA7C42E0C37515D138F22DD2ECB803A0C5C99676314BAF4BB1B7FA3190B2EDC0327797F241067BE390C9E, + 0x10321DA079CE07E272D8EC09D2565B0DFA7DCCDDE6787F96D50AF36003B14866F69B771F8C285DECCA67DF3F1605FB7B, + 0x6E08C248E260E70BD1E962381EDEE3D31D79D7E22C837BC23C0BF1BC24C6B68C24B1B80B64D391FA9C8BA2E8BA2D229, + ] + ] + ), + denominator=Polynomial( + [ + field(x) + for x in [ + 0x8CA8D548CFF19AE18B2E62F4BD3FA6F01D5EF4BA35B48BA9C9588617FC8AC62B558D681BE343DF8993CF9FA40D21B1C, + 0x12561A5DEB559C4348B4711298E536367041E8CA0CF0800C0126C2588C48BF5713DAA8846CB026E9E5C8276EC82B3BFF, + 0xB2962FE57A3225E8137E629BFF2991F6F89416F5A718CD1FCA64E00B11ACEACD6A3D0967C94FEDCFCC239BA5CB83E19, + 0x3425581A58AE2FEC83AAFEF7C40EB545B08243F16B1655154CCA8ABC28D6FD04976D5243EECF5C4130DE8938DC62CD8, + 0x13A8E162022914A80A6F1D5F43E7A07DFFDFC759A12062BB8D6B44E833B306DA9BD29BA81F35781D539D395B3532A21E, + 0xE7355F8E4E667B955390F7F0506C6E9395735E9CE9CAD4D0A43BCEF24B8982F7400D24BC4228F11C02DF9A29F6304A5, + 0x772CAACF16936190F3E0C63E0596721570F5799AF53A1894E2E073062AEDE9CEA73B3538F0DE06CEC2574496EE84A3A, + 0x14A7AC2A9D64A8B230B3F5B074CF01996E7F63C21BCA68A81996E1CDF9822C580FA5B9489D11E2D311F7D99BBDCC5A5E, + 0xA10ECF6ADA54F825E920B3DAFC7A3CCE07F8D1D7161366B74100DA67F39883503826692ABBA43704776EC3A79A1D641, + 0x95FC13AB9E92AD4476D6E3EB3A56680F682B4EE96F7D03776DF533978F31C1593174E4B4B7865002D6384D168ECDD0A, + 0x1, + ] + ] + ), + ), RationalFunction( + numerator=Polynomial( + [ + field(x) + for x in [ + 1393399195776646641963150658816615410692049723305861307490980409834842911816308830479576739332720113414154429643571, + 2968610969752762946134106091152102846225411740689724909058016729455736597929366401532929068084731548131227395540630, + 122933100683284845219599644396874530871261396084070222155796123161881094323788483360414289333111221370374027338230, + 303251954782077855462083823228569901064301365507057490567314302006681283228886645653148231378803311079384246777035, + 1353972356724735644398279028378555627591260676383150667237975415318226973994509601413730187583692624416197017403099, + 3443977503653895028417260979421240655844034880950251104724609885224259484262346958661845148165419691583810082940400, + 718493410301850496156792713845282235942975872282052335612908458061560958159410402177452633054233549648465863759602, + 1466864076415884313141727877156167508644960317046160398342634861648153052436926062434809922037623519108138661903145, + 1536886493137106337339531461344158973554574987550750910027365237255347020572858445054025958480906372033954157667719, + 2171468288973248519912068884667133903101171670397991979582205855298465414047741472281361964966463442016062407908400, + 3915937073730221072189646057898966011292434045388986394373682715266664498392389619761133407846638689998746172899634, + 3802409194827407598156407709510350851173404795262202653149767739163117554648574333789388883640862266596657730112910, + 1707589313757812493102695021134258021969283151093981498394095062397393499601961942449581422761005023512037430861560, + 349697005987545415860583335313370109325490073856352967581197273584891698473628451945217286148025358795756956811571, + 885704436476567581377743161796735879083481447641210566405057346859953524538988296201011389016649354976986251207243, + 3370924952219000111210625390420697640496067348723987858345031683392215988129398381698161406651860675722373763741188, + ] + ] + ), + denominator=Polynomial( + [ + field(x) + for x in [ + 3396434800020507717552209507749485772788165484415495716688989613875369612529138640646200921379825018840894888371137, + 3907278185868397906991868466757978732688957419873771881240086730384895060595583602347317992689443299391009456758845, + 854914566454823955479427412036002165304466268547334760894270240966182605542146252771872707010378658178126128834546, + 3496628876382137961119423566187258795236027183112131017519536056628828830323846696121917502443333849318934945158166, + 1828256966233331991927609917644344011503610008134915752990581590799656305331275863706710232159635159092657073225757, + 1362317127649143894542621413133849052553333099883364300946623208643344298804722863920546222860227051989127113848748, + 3443845896188810583748698342858554856823966611538932245284665132724280883115455093457486044009395063504744802318172, + 3484671274283470572728732863557945897902920439975203610275006103818288159899345245633896492713412187296754791689945, + 3755735109429418587065437067067640634211015783636675372165599470771975919172394156249639331555277748466603540045130, + 3459661102222301807083870307127272890283709299202626530836335779816726101522661683404130556379097384249447658110805, + 742483168411032072323733249644347333168432665415341249073150659015707795549260947228694495111018381111866512337576, + 1662231279858095762833829698537304807741442669992646287950513237989158777254081548205552083108208170765474149568658, + 1668238650112823419388205992952852912407572045257706138925379268508860023191233729074751042562151098884528280913356, + 369162719928976119195087327055926326601627748362769544198813069133429557026740823593067700396825489145575282378487, + 2164195715141237148945939585099633032390257748382945597506236650132835917087090097395995817229686247227784224263055, + 1, + ] + ] + ), + ) + + case _: + raise NotImplementedError( + f"Isogeny for curve {curve_id} is not implemented" + ) + + +def apply_isogeny(pt: G1Point) -> G1Point: + assert pt.iso_point == True, f"Point {pt} is not an iso point" + field = get_base_field(pt.curve_id) + x_rational, y_rational = get_isogeny_to_g1_map(pt.curve_id) + x_affine = x_rational.evaluate(field(pt.x)) + y_affine = y_rational.evaluate(field(pt.x)) * field(pt.y) + + return G1Point(x_affine.value, y_affine.value, pt.curve_id, iso_point=False) + + +if __name__ == "__main__": + from garaga.hints.io import int_to_u384 + + field = get_base_field(CurveID.BLS12_381) + message = b"Hello, World!" + sha_message = hashlib.sha256(message).digest() + # print(f"sha_message {sha_message.hex()}") + message = sha_message + + def test_hash_to_field(message: bytes): + res = hash_to_field( + message=message, + count=2, + curve_id=CurveID.BLS12_381, + hash_name="sha256", + ) + print(f"res {[int_to_u384(x) for x in res]}") + expected = [ + 2162792105491427725912070356725320455528056118179305300106498860235975843802512462082887053454085287130500476441750, + 40368511435268498384669958495624628965655407346873103876018487738713032717501957266398124814691972213333393099218, + ] + # assert res == expected, f"Expected {expected}, got {res}" + + def test_map_to_curve(): + u = field(42) + res = map_to_curve(field_element=u, curve_id=CurveID.BLS12_381) + print(f"res {int_to_u384(res.x)} {int_to_u384(res.y)}") + + def test_isogeny(): + pt = G1Point( + x=215777581081472667122506794895079133292851844364726904952688478479828790890150439604857229658591641382171852677524, + y=1379746801043875097750009912574703067223644203712602673826050484796337984730238282465201134827010880864260517139932, + curve_id=CurveID.BLS12_381, + iso_point=True, + ) + expected = G1Point( + x=2417697449117523569926871462160078790628278460141221111171958173864939056722835940739506331591809461977867457921129, + y=2054645981348311902541581243120273427071170397909163934255295587636136055038499048700096920528935972380584458489355, + curve_id=CurveID.BLS12_381, + iso_point=False, + ) + res = apply_isogeny(pt=pt) + assert res == expected, f"Expected {expected}, got {res}" + + # test_isogeny() + + def test_hash_to_curve(message: bytes): + expected = G1Point( + x=1427986885250946460144481685485785737438296207533779678983559530346613679756132883977754715392336662418069603153756, + y=2665645453955482249178808933038784408956625041285885055194161860684118145927032784752731507519078519455031562783679, + curve_id=CurveID.BLS12_381, + ) + res = hash_to_curve( + message=message, curve_id=CurveID.BLS12_381, hash_name="sha256" + ) + + # assert res == expected, f"Expected {expected}, got {res}" + print(f"res {int_to_u384(res.x)} {int_to_u384(res.y)}") + + # test_hash_to_field(message=message) + + test_map_to_curve() + test_hash_to_curve(message=message) diff --git a/hydra/garaga/starknet/groth16_contract_generator/generator_risc0.py b/hydra/garaga/starknet/groth16_contract_generator/generator_risc0.py index 26bd8191..a0d48e4d 100644 --- a/hydra/garaga/starknet/groth16_contract_generator/generator_risc0.py +++ b/hydra/garaga/starknet/groth16_contract_generator/generator_risc0.py @@ -71,7 +71,7 @@ def gen_risc0_groth16_verifier( use garaga::definitions::{{G1Point, G1G2Pair}}; use garaga::groth16::{{multi_pairing_check_{curve_id.name.lower()}_3P_2F_with_extra_miller_loop_result}}; use garaga::ec_ops::{{G1PointTrait, G2PointTrait, ec_safe_add}}; - use garaga::risc0_utils::compute_receipt_claim; + use garaga::utils::risc0::compute_receipt_claim; use garaga::utils::calldata::{{FullProofWithHintsRisc0, deserialize_full_proof_with_hints_risc0}}; use super::{{N_FREE_PUBLIC_INPUTS, vk, ic, precomputed_lines, T}}; diff --git a/hydra/garaga/starknet/tests_and_calldata_generators/drand_calldata.py b/hydra/garaga/starknet/tests_and_calldata_generators/drand_calldata.py new file mode 100644 index 00000000..dbac2947 --- /dev/null +++ b/hydra/garaga/starknet/tests_and_calldata_generators/drand_calldata.py @@ -0,0 +1,73 @@ +import garaga.hints.io as io +from garaga.drand.client import ( + DrandNetwork, + G2Point, + digest_func, + get_chain_info, + get_randomness, +) +from garaga.signature import hash_to_curve +from garaga.starknet.tests_and_calldata_generators.map_to_curve import * +from garaga.starknet.tests_and_calldata_generators.mpcheck import ( + G1G2Pair, + MPCheckCalldataBuilder, +) + + +def drand_round_to_calldata(round_number: int) -> list[int]: + + message = digest_func(round_number) + # print(f"round {round_number} message {message}") + msg_point = hash_to_curve(message, CurveID.BLS12_381, "sha256") + + chain = get_chain_info(DrandNetwork.quicknet.value) + + round = get_randomness(chain.hash, round_number) + + ######################################## + # Temp fix before we figure out what the hell is wrong with G2 compress Deserialization sign. + check = ( + G1G2Pair.pair( + [ + G1G2Pair( + p=round.signature_point, q=G2Point.get_nG(CurveID.BLS12_381, 1) + ), + G1G2Pair(p=msg_point, q=-chain.public_key), + ], + curve_id=CurveID.BLS12_381, + ).value_coeffs + == [1] + [0] * 11 + ) + + if not check: + sig_pt = -round.signature_point + else: + sig_pt = round.signature_point + + ################### + mpc_builder = MPCheckCalldataBuilder( + curve_id=CurveID.BLS12_381, + pairs=[ + G1G2Pair(p=sig_pt, q=G2Point.get_nG(CurveID.BLS12_381, 1)), + G1G2Pair(p=msg_point, q=-chain.public_key), + ], + n_fixed_g2=2, + public_pair=None, + ) + + cd = [] + sig_pt: G1Point + cd.append(round_number) + cd.extend(io.bigint_split(sig_pt.x)) + cd.extend(io.bigint_split(sig_pt.y)) + cd.extend(build_hash_to_curve_hint(message).to_calldata()) + cd.extend(mpc_builder.serialize_to_calldata()) + + return [len(cd)] + cd + + +if __name__ == "__main__": + + drand_round_to_calldata(1) + drand_round_to_calldata(2) + # drand_round_to_calldata(3) diff --git a/hydra/garaga/starknet/tests_and_calldata_generators/map_to_curve.py b/hydra/garaga/starknet/tests_and_calldata_generators/map_to_curve.py new file mode 100644 index 00000000..3d14c575 --- /dev/null +++ b/hydra/garaga/starknet/tests_and_calldata_generators/map_to_curve.py @@ -0,0 +1,132 @@ +from dataclasses import dataclass + +import garaga.modulo_circuit_structs as structs +from garaga.algebra import PyFelt +from garaga.definitions import CURVES, CurveID, G1Point, get_base_field +from garaga.hints.io import bigint_split, int_to_u384 +from garaga.signature import apply_isogeny, hash_to_field +from garaga.starknet.tests_and_calldata_generators.msm import MSMCalldataBuilder + + +@dataclass(slots=True) +class MapToCurveHint: + gx1_is_square: bool + y1: PyFelt + y_flag: bool + + def to_cairo(self) -> str: + return f"MapToCurveHint {{ gx1_is_square: {str(self.gx1_is_square).lower()}, y1: {int_to_u384(self.y1.value, as_hex=True)}, y_flag: {str(self.y_flag).lower()} }}" + + def to_calldata(self) -> list[int]: + cd = [] + cd.append(int(self.gx1_is_square)) + cd.extend(bigint_split(self.y1.value)) + cd.append(int(self.y_flag)) + return cd + + +@dataclass(slots=True) +class HashToCurveHint: + f0_hint: MapToCurveHint + f1_hint: MapToCurveHint + scalar_mul_hint: structs.Struct + derive_point_from_x_hint: structs.Struct + + def to_cairo(self) -> str: + return f"HashToCurveHint {{ f0_hint: {self.f0_hint.to_cairo()}, f1_hint: {self.f1_hint.to_cairo()}, scalar_mul_hint: {self.scalar_mul_hint.serialize(raw=True)}, derive_point_from_x_hint: {self.derive_point_from_x_hint.serialize(raw=True)} }}" + + def to_calldata(self) -> list[int]: + cd = [] + cd.extend(self.f0_hint.to_calldata()) + cd.extend(self.f1_hint.to_calldata()) + cd.extend(self.scalar_mul_hint.serialize_to_calldata()) + cd.extend(self.derive_point_from_x_hint.serialize_to_calldata()) + return cd + + +def build_map_to_curve_hint(u: PyFelt) -> tuple[G1Point, MapToCurveHint]: + field = get_base_field(CurveID.BLS12_381) + a = field(CURVES[CurveID.BLS12_381.value].swu_params.A) + b = field(CURVES[CurveID.BLS12_381.value].swu_params.B) + z = field(CURVES[CurveID.BLS12_381.value].swu_params.Z) + + zeta_u2 = z * u**2 + ta = zeta_u2**2 + zeta_u2 + num_x1 = b * (ta + field.one()) + + if ta.value == 0: + div = a * z + else: + div = a * -ta + + num2_x1 = num_x1**2 + div2 = div**2 + div3 = div2 * div + assert div3.value != 0 + + num_gx1 = (num2_x1 + a * div2) * num_x1 + b * div3 + num_x2 = zeta_u2 * num_x1 + + gx1 = num_gx1 / div3 + gx1_square = gx1.is_quad_residue() + if gx1_square: + y1 = gx1.sqrt(min_root=False) + assert y1 * y1 == gx1 + else: + y1 = (z * gx1).sqrt(min_root=False) + assert y1 * y1 == z * gx1 + + y2 = zeta_u2 * u * y1 + y = y1 if gx1_square else y2 + y_flag = y.value % 2 == u.value % 2 + + num_x = num_x1 if gx1_square else num_x2 + x_affine = num_x / div + y_affine = -y if y.value % 2 != u.value % 2 else y + + point_on_curve = G1Point( + x_affine.value, y_affine.value, CurveID.BLS12_381, iso_point=True + ) + return point_on_curve, MapToCurveHint( + gx1_is_square=gx1_square, y1=y1, y_flag=y_flag + ) + + +def build_hash_to_curve_hint(message: bytes) -> HashToCurveHint: + felt0, felt1 = hash_to_field(message, 2, CurveID.BLS12_381.value, "sha256") + pt0, f0_hint = build_map_to_curve_hint(felt0) + pt1, f1_hint = build_map_to_curve_hint(felt1) + sum_pt = pt0.add(pt1) + # print( + # f"sum_pt: {int_to_u384(sum_pt.x, as_hex=False)} {int_to_u384(sum_pt.y, as_hex=False)}" + # ) + sum_pt = apply_isogeny(sum_pt) + # print( + # f"sum_pt: {int_to_u384(sum_pt.x, as_hex=False)} {int_to_u384(sum_pt.y, as_hex=False)}" + # ) + x = CURVES[CurveID.BLS12_381.value].x + n = CURVES[CurveID.BLS12_381.value].n + cofactor = (1 - (x % n)) % n + # print(f"cofactor: {cofactor}, hex :{hex(cofactor)}") + + msm_builder = MSMCalldataBuilder( + curve_id=CurveID.BLS12_381, points=[sum_pt], scalars=[cofactor] + ) + msm_hint, derive_point_from_x_hint = msm_builder.build_msm_hints(risc0_mode=True) + + return HashToCurveHint( + f0_hint=f0_hint, + f1_hint=f1_hint, + scalar_mul_hint=msm_hint, + derive_point_from_x_hint=derive_point_from_x_hint, + ) + + +if __name__ == "__main__": + field = get_base_field(CurveID.BLS12_381) + + import hashlib + + hint = build_hash_to_curve_hint(hashlib.sha256(b"Hello, World!").digest()) + print(hint.to_cairo()) + # print(hint.to_calldata()) diff --git a/src/contracts/drand_quicknet/Scarb.toml b/src/contracts/drand_quicknet/Scarb.toml new file mode 100644 index 00000000..23acf04c --- /dev/null +++ b/src/contracts/drand_quicknet/Scarb.toml @@ -0,0 +1,15 @@ +[package] +name = "drand_quicknet" +version = "0.1.0" +edition = "2024_07" + +[dependencies] +garaga = { path = "../.." } +starknet = "2.8.2" + +[cairo] +sierra-replace-ids = false + +[[target.starknet-contract]] +casm = true +casm-add-pythonic-hints = true diff --git a/src/contracts/drand_quicknet/src/drand_verifier.cairo b/src/contracts/drand_quicknet/src/drand_verifier.cairo new file mode 100644 index 00000000..181d9963 --- /dev/null +++ b/src/contracts/drand_quicknet/src/drand_verifier.cairo @@ -0,0 +1,60 @@ +use super::drand_verifier_constants::{G2_GEN, precomputed_lines}; + +#[starknet::interface] +trait IDrandQuicknet { + fn verify_round_and_get_randomness( + ref self: TContractState, full_proof_with_hints: Span, + ) -> Option; +} + +#[starknet::contract] +mod DrandQuicknet { + // use starknet::SyscallResultTrait; + use garaga::definitions::{G1Point, G1G2Pair}; + use garaga::pairing_check::{multi_pairing_check_bls12_381_2P_2F, MPCheckHintBLS12_381}; + // use garaga::ec_ops::{G1PointTrait, G2PointTrait}; + use garaga::utils::drand::{ + round_to_curve_bls12_381, DRAND_QUICKNET_PUBLIC_KEY, HashToCurveHint + }; + use super::{precomputed_lines, G2_GEN}; + use garaga::utils::hashing::hash_G1Point; + + // const ECIP_OPS_CLASS_HASH: felt252 = + // 0x7918f484291eb154e13d0e43ba6403e62dc1f5fbb3a191d868e2e37359f8713; + // use starknet::ContractAddress; + + #[storage] + struct Storage {} + + #[derive(Drop, Serde)] + struct DrandHint { + round_number: u64, + signature: G1Point, + hash_to_curve_hint: HashToCurveHint, + mpcheck_hint: MPCheckHintBLS12_381, + } + #[abi(embed_v0)] + impl IDrandQuicknet of super::IDrandQuicknet { + fn verify_round_and_get_randomness( + ref self: ContractState, mut full_proof_with_hints: Span, + ) -> Option { + let drand_hint: DrandHint = Serde::deserialize(ref full_proof_with_hints).unwrap(); + let message = round_to_curve_bls12_381( + drand_hint.round_number, drand_hint.hash_to_curve_hint + ); + + let check = multi_pairing_check_bls12_381_2P_2F( + pair0: G1G2Pair { p: drand_hint.signature, q: G2_GEN }, + pair1: G1G2Pair { p: message, q: DRAND_QUICKNET_PUBLIC_KEY }, + lines: precomputed_lines.span(), + hint: drand_hint.mpcheck_hint, + ); + + match check { + true => Option::Some(hash_G1Point(message)), + false => Option::None, + } + } + } +} + diff --git a/src/contracts/drand_quicknet/src/drand_verifier_constants.cairo b/src/contracts/drand_quicknet/src/drand_verifier_constants.cairo new file mode 100644 index 00000000..0013a5f8 --- /dev/null +++ b/src/contracts/drand_quicknet/src/drand_verifier_constants.cairo @@ -0,0 +1,3571 @@ +use garaga::definitions::{G2Line, G2Point, u384}; + + +pub const G2_GEN: G2Point = + G2Point { + x0: u384 { + limb0: 0xa805bbefd48056c8c121bdb8, + limb1: 0xb4510b647ae3d1770bac0326, + limb2: 0x2dc51051c6e47ad4fa403b02, + limb3: 0x24aa2b2f08f0a9126080527 + }, + x1: u384 { + limb0: 0x13945d57e5ac7d055d042b7e, + limb1: 0xb5da61bbdc7f5049334cf112, + limb2: 0x88274f65596bd0d09920b61a, + limb3: 0x13e02b6052719f607dacd3a0 + }, + y0: u384 { + limb0: 0x3baca289e193548608b82801, + limb1: 0x6d429a695160d12c923ac9cc, + limb2: 0xda2e351aadfd9baa8cbdd3a7, + limb3: 0xce5d527727d6e118cc9cdc6 + }, + y1: u384 { + limb0: 0x5cec1da1aaa9075ff05f79be, + limb1: 0x267492ab572e99ab3f370d27, + limb2: 0x2bc28b99cb3e287e85a763af, + limb3: 0x606c4a02ea734cc32acd2b0 + } + }; + +pub const precomputed_lines: [ + G2Line + ; 136] = [ + G2Line { + r0a0: u384 { + limb0: 0x36701a5831c9fb39250e2ea9, + limb1: 0x26ad0ec05ad6440f1df034cf, + limb2: 0x67cd27cf7598a85f81c23cd9, + limb3: 0x15a76ee3d8d1c3451005d560 + }, + r0a1: u384 { + limb0: 0x9009367bbf6e6aa19488df66, + limb1: 0xce5cd2ccda4704dc0e4b92b6, + limb2: 0xd7656829a6a71c42deb7dd, + limb3: 0x16d96e785c797fb5d6afcb14 + }, + r1a0: u384 { + limb0: 0x9d68b0bdf431a2f53189c109, + limb1: 0x70e39167384e44fdaf716fa4, + limb2: 0x3768099390a3f9d581d88280, + limb3: 0x4c208bdb300097927393e96 + }, + r1a1: u384 { + limb0: 0x68ab4b88cf058f147ba2cda9, + limb1: 0xce3b4d4da03cbdac75933b54, + limb2: 0x1be2f7e6eaa0f1474cb64c53, + limb3: 0x546ca700477f9c2f9def969 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x96e0f84058018a4538d64e8b, + limb1: 0xdb7b84172cb1e68ddd09eb12, + limb2: 0xcf3aaa45c2b370e810ea9361, + limb3: 0x14b92565b748c30f253912c6 + }, + r0a1: u384 { + limb0: 0x9cdcddf4728a38086aebcd7, + limb1: 0x7b8d9115b96656327dd79780, + limb2: 0xbf914addbdcbe307142bf7cc, + limb3: 0x3c50d0829bdc305ff694cc9 + }, + r1a0: u384 { + limb0: 0xcc0dbe864e35231bdec2ef76, + limb1: 0x4efa339ef551d8f751da95ba, + limb2: 0xfde5910a13d5c428549ed3f5, + limb3: 0x105e4803f5b8472a138e00b + }, + r1a1: u384 { + limb0: 0x584879d210eb30bfd6518cf2, + limb1: 0xa7c4af01b40d0e68243b050c, + limb2: 0xade596dd94a41e4aedec2196, + limb3: 0x162a46f819eba8e3b9d215f9 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xaa37b5f455262931a4a4b667, + limb1: 0xd63d75f6f171228540731ca7, + limb2: 0x1855073ef14fe67beee9ec53, + limb3: 0x703f29e5b69ff1dd1441781 + }, + r0a1: u384 { + limb0: 0x310c4b87c8dca9036f6be0c0, + limb1: 0x4b940b400d665d605ca8924b, + limb2: 0x6d53ff2907765e3888b9709e, + limb3: 0x166de077ba25fe21aafb8d8 + }, + r1a0: u384 { + limb0: 0xa28a55b43c534d6caa724f82, + limb1: 0x5f55bbeb19616aec79892386, + limb2: 0x3aacfc3b6bd889cf57af9e40, + limb3: 0x72ff7d1d3328dbb7c821e1 + }, + r1a1: u384 { + limb0: 0xd5e91f70851719038228e756, + limb1: 0xb4f970b567fc2d6738d65700, + limb2: 0x8c886fe7294c08b41dc5dcbe, + limb3: 0x782b1bf6e81fef26d367768 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x8d8ec958debf40520de5d867, + limb1: 0x57bad55eb06d937414e80cc9, + limb2: 0xcb178ebae0f48eb14ad4fba0, + limb3: 0x13aa75258cc1d54eb767a47e + }, + r0a1: u384 { + limb0: 0x7aec4216b9f9e33aa4f5af6, + limb1: 0x607eabc6cb65b9f4b850a042, + limb2: 0x1d93b61b06f4e64902410902, + limb3: 0x1860921bbe145ede9350b867 + }, + r1a0: u384 { + limb0: 0xe104b73f6d12d90e3c339c6c, + limb1: 0x27bab1ac67f3132355d4c1a0, + limb2: 0x63ecc80d6bd96b3d592f63d9, + limb3: 0xdcb608c9ce643f854507b05 + }, + r1a1: u384 { + limb0: 0xe3895865374c9b06b8d02a7f, + limb1: 0x8c09a76a05340ce642b99a1a, + limb2: 0x4a4afdbe107c0182cfe2e6e7, + limb3: 0x1056de76a10fe55b2659ea44 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x6a72f085ee4e78bd4c2aef8e, + limb1: 0xdec05cffe4a869aed2a64ee8, + limb2: 0xd41aa908b1a833b94e768d2, + limb3: 0x56ceab5d5d994dee0ca07fc + }, + r0a1: u384 { + limb0: 0xd23aad6cd3e84e398a4e7bc8, + limb1: 0xb343a6878db6ec20bcac1275, + limb2: 0x3111e14b674a67295a242cf3, + limb3: 0x39b596a976f556e5ea4016a + }, + r1a0: u384 { + limb0: 0x19fcdcac7feb1f0edbefdbf8, + limb1: 0x71bc60f1a68459eb52df6a92, + limb2: 0x2827dbba9d5d8516fb557dfb, + limb3: 0x4786cc02b147d13e701c1f5 + }, + r1a1: u384 { + limb0: 0xcb7555c0db86510eb99cfadd, + limb1: 0x43387d10f8329296e43e6610, + limb2: 0xbf6789475132950c583823a, + limb3: 0x145f508c63c10d270e027b2b + } + }, + G2Line { + r0a0: u384 { + limb0: 0x411944418a1e44d0fbd8a4bd, + limb1: 0xfa3933a100d5d920bb158196, + limb2: 0xaf6096a850d10c6ee57b7d3f, + limb3: 0x7bc245f0c719ec216f4f7e7 + }, + r0a1: u384 { + limb0: 0xd5f88a09ab7912a54504534a, + limb1: 0x6c7b84068e05767f3ac72003, + limb2: 0x2e783a6cd8933e5ce254ff56, + limb3: 0x648a93088ef22f73be5e1d5 + }, + r1a0: u384 { + limb0: 0x72f4d88bd20cecc4c1d57b8f, + limb1: 0x2164d957d0e784aca77a27b6, + limb2: 0xe45f0a865306a8c7ccf8e465, + limb3: 0x182e7e79c81e19c5e6dba3b8 + }, + r1a1: u384 { + limb0: 0xf2b21292475b313a8591d232, + limb1: 0x31975a79dd261ef9304ae69f, + limb2: 0x3fca7e570497ea425d166e3f, + limb3: 0xb1e493cae679afa3aeeb48e + } + }, + G2Line { + r0a0: u384 { + limb0: 0x7bd212f8f60967471e995a8e, + limb1: 0xec76fa31d0fd358f36ee756e, + limb2: 0xa63e06c40964532a724817c3, + limb3: 0xd860767952ed2b694b64eea + }, + r0a1: u384 { + limb0: 0xd18f8b1de21e64c50d3c6fc2, + limb1: 0x456cec057d45521c48d0b547, + limb2: 0x23fb8276293fac77c9a38c1b, + limb3: 0x1469d7cf50d58855fa523aa8 + }, + r1a0: u384 { + limb0: 0x52f1d22ea6bfc23435bf7e3b, + limb1: 0x3e2d5122467bf39f2573a57b, + limb2: 0x378db9e77f53b5b1e38981da, + limb3: 0x1015deb442db265529d8948 + }, + r1a1: u384 { + limb0: 0x73c44618fb7917b2596bd460, + limb1: 0x598ee13313073cf3232e1b37, + limb2: 0xbd63e58ae4aa477bcd459ef2, + limb3: 0x272bfde06aa8302ab8c70d6 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x84d7880d9c5ad98d07f1b961, + limb1: 0xd5be4b6e58ad745353113073, + limb2: 0x592ecc7534e44983a06d755c, + limb3: 0x15d60a0d6d8a2e4543194737 + }, + r0a1: u384 { + limb0: 0x9ba63990e4f1ea4875173006, + limb1: 0xf84fa98d5f3742b3c571f427, + limb2: 0xdd28189a4a2e3a70f78a170e, + limb3: 0x1ad5bc82425c66f655a75db + }, + r1a0: u384 { + limb0: 0x49306522c22ca321950bf155, + limb1: 0x369a747f27aa6472ebc5d290, + limb2: 0x20d8977cbe5acf112574c70a, + limb3: 0xcdc103da1aac9ec5f855b64 + }, + r1a1: u384 { + limb0: 0x74517cbd651af3940075c057, + limb1: 0x94d3802d81c93d69eb13518b, + limb2: 0x76411c393dd03e5381661629, + limb3: 0x16e57b05faef24ef64868a07 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x1a30592d98290c72cccd458b, + limb1: 0x140a621ff20376f808a589fd, + limb2: 0x49ba32b20969590620d93359, + limb3: 0x8505a11bd1aa7d53fffa788 + }, + r0a1: u384 { + limb0: 0xbedeeea8460644391170d35f, + limb1: 0xcfc8f5f9f7606a79990e9242, + limb2: 0x2747fe157739059a9b528ae0, + limb3: 0x13386caa378815cd519166ec + }, + r1a0: u384 { + limb0: 0x2adf79c700fc3a5a36c5ec26, + limb1: 0x4f168c2853c5ec65b71b40ca, + limb2: 0x7e0c13754f775e73a9419653, + limb3: 0x10616cc67745c7887ca4898e + }, + r1a1: u384 { + limb0: 0xde84fc636c0a8697ac4d8960, + limb1: 0xdd66e4fac060783909cc83c4, + limb2: 0x86edc8b2faa981346da2237c, + limb3: 0x11c912ed6ea0e8f7768ac884 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x6b6c23b2b461087f63e2fd50, + limb1: 0x8454a8c69f81cfea8edb19ba, + limb2: 0x2133ca31f8dd40f674513fd8, + limb3: 0x171663bdebf2ef26dc306e13 + }, + r0a1: u384 { + limb0: 0x6b95f25b75fe9a8aa69ae917, + limb1: 0x2f15c87206b024c108e4f4d4, + limb2: 0xc4e3e65f02f2e19326083300, + limb3: 0x16172a9e775f111d4bf432bf + }, + r1a0: u384 { + limb0: 0xc4289527cdf4e1662f27e1f9, + limb1: 0x7f6c52aaea1458a5388d10eb, + limb2: 0x4f6130d75d26097d0a4fa02a, + limb3: 0x16f8a911b684b408bbd72650 + }, + r1a1: u384 { + limb0: 0x648a1498ebbbd0e225db1ffc, + limb1: 0xa36cfb4b46195b619bb220bf, + limb2: 0xe327926a1726c7e5bb70bc97, + limb3: 0xfcef666ce7ecc2915258730 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xb5abe92a46d0ff04a4205803, + limb1: 0xdb760c98b7aad959e5dfc28d, + limb2: 0xbea9b6e4adf41fa1060713ee, + limb3: 0x75707a467e7543c28370330 + }, + r0a1: u384 { + limb0: 0x8b0715d2f6a16be8d5828197, + limb1: 0x598a8a6da7ed2bcc091f594d, + limb2: 0x18cfc9c1ee8960c06ff2c240, + limb3: 0x14061839f139644bb20e8647 + }, + r1a0: u384 { + limb0: 0xd529f0561fff46258f565dec, + limb1: 0x80402f61ae7ce96272aff23b, + limb2: 0x883367465c3a4bde2507377a, + limb3: 0x14fc234296369891318c6245 + }, + r1a1: u384 { + limb0: 0x9fdc0242b4d20c44b72c8d49, + limb1: 0x37e047238dd417acab9ea0c2, + limb2: 0xc424c8845919fe27ac23e9, + limb3: 0x151e87d65d95c3b1cc9b1de6 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xf5a9a8a9d8ecd9df033bb53b, + limb1: 0x6f13c1f15ca3c43bd8dc862c, + limb2: 0xaf9fffe39ed8b6f589e47e4f, + limb3: 0x1355d3f3bda0ba53c342406b + }, + r0a1: u384 { + limb0: 0x13c7baebedc25cd07fa0b8ea, + limb1: 0x4e29e5e7fd865c69feb81131, + limb2: 0xdcf94191f24d657ae6fc8c5c, + limb3: 0x162398b0a01eff8f7149ab6c + }, + r1a0: u384 { + limb0: 0x8cf50d2f7aa3da376e8317d5, + limb1: 0x490a7502e8f6bc788f715c7a, + limb2: 0xe6db018fa6b084ae40896c2b, + limb3: 0x184f93ce89fff4893629db4d + }, + r1a1: u384 { + limb0: 0x53e941ac4d20f05b66f3b0ec, + limb1: 0x82b8a8efafffe40798a1d5da, + limb2: 0xd08e35da426abf3dd1ce8bb, + limb3: 0xd49095a9c436bd86f9d4736 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x9bd8fa7a943e0e3a924e7492, + limb1: 0xad948685eedfe9d3ac7315ff, + limb2: 0x8148910d6004895792caa88d, + limb3: 0x1deabfaeb3374b50119ecb9 + }, + r0a1: u384 { + limb0: 0xfedf28954ae85d6e9f58c709, + limb1: 0x7c01f5d8a4b9368fc9cbb8eb, + limb2: 0xbe98bf07cbd25fe6f4ac154f, + limb3: 0x7c9b05e8adef4de506459f7 + }, + r1a0: u384 { + limb0: 0x71812aeba8c33457117bfb0, + limb1: 0xaf1a11b5a7571775ec17c1, + limb2: 0x721e08542ff85e7037b2c02f, + limb3: 0x991d1db86230da71efb4475 + }, + r1a1: u384 { + limb0: 0x4122fa433f37c5e6888de07c, + limb1: 0x144d977681671d8cd0854c34, + limb2: 0x93981673fae1df08d18161aa, + limb3: 0x145eae6a49c250f2435d1ec8 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x3ab208ad049d8dbf41ab2d8c, + limb1: 0xe8d0eafc04fe7a37f53901c8, + limb2: 0xbffd6b641b6f6961476d4a1b, + limb3: 0x16c1d585f68dee202ea9a988 + }, + r0a1: u384 { + limb0: 0x3eba0d6e9e3751e7d1b4533f, + limb1: 0x8e4692d56ab832e68469328a, + limb2: 0x9d03908cf037ee8faf6dac32, + limb3: 0x2ef973d44d5dfe1f52b48e7 + }, + r1a0: u384 { + limb0: 0x6cd551023179a5ffe150ae4b, + limb1: 0xd48575f40677168193ee4571, + limb2: 0x81320f4ef3fa7936f5865695, + limb3: 0x37748234157e4931a4f54d7 + }, + r1a1: u384 { + limb0: 0x73847e2fc69aee5b6a51756, + limb1: 0x1cfd76b51ee2e57b733742b9, + limb2: 0xe02551761eba32bebc8413bb, + limb3: 0x3136b909d615d39094ab565 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xa8af53d78f2fa38c6e213a84, + limb1: 0xc908fd45d36e147e8a3449ea, + limb2: 0x9224181cd573d3836b141129, + limb3: 0x140090a04158ea562a90ed5 + }, + r0a1: u384 { + limb0: 0x95e6526648a96a5a43488327, + limb1: 0x5f5e4c24465495ee0dcb3055, + limb2: 0x49f0985811804cda4142ca8c, + limb3: 0x9619ac570f151f7baaa7ae + }, + r1a0: u384 { + limb0: 0xc2ef8275baa5e3b836a847d7, + limb1: 0x9835333ce4136fda57f9c31e, + limb2: 0x8392d675aba184475007124a, + limb3: 0x10f9170d8f4e3130ef5a354e + }, + r1a1: u384 { + limb0: 0x4db131e9b2a50df6253da27e, + limb1: 0x3210503344192c1a1d83234c, + limb2: 0xb84a1ae100e6602d2a3eaa1d, + limb3: 0x146401ace26dcc76ec7cb805 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x9a29bb6c54b018b4ed75888b, + limb1: 0x1437b2d93b1ecc564157059c, + limb2: 0xf0add7baf8cfe1ddc30f0754, + limb3: 0x86553ec1cc3cc6a38436fbb + }, + r0a1: u384 { + limb0: 0x516be99929795e7ae5112f30, + limb1: 0xb182ffdb6110024a0018e3e7, + limb2: 0x8e468869d60b7ae7fc6004bd, + limb3: 0x4916e8c2d5820861e32013a + }, + r1a0: u384 { + limb0: 0x78554bdd8568c0e9686a510e, + limb1: 0x97bc0c8b458fe7d5dcf2264c, + limb2: 0xfcc4906709b359120a9e0158, + limb3: 0x193f60f20d1cc7f2b1bf553c + }, + r1a1: u384 { + limb0: 0x2713699297ab49a2d9bf4f6d, + limb1: 0xb396d1c4590471bf032b959c, + limb2: 0x350113633de03c6e721c7597, + limb3: 0x79ef6c98d71e95eb13fae02 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xb3bbccb4893a93d20a147b98, + limb1: 0x5c46a12e68c1dcaf7d45545, + limb2: 0xe1d3e9970b998f9ee1bfcc60, + limb3: 0xe0e611221166a37eaca4699 + }, + r0a1: u384 { + limb0: 0x255f666baafad4929f87c34d, + limb1: 0x1a1554e683a36d8c5359c91d, + limb2: 0xb351c7146573abdf82d32baf, + limb3: 0x14bc0381e2ada56e42a08f14 + }, + r1a0: u384 { + limb0: 0x84b1b1e77e26467b905fa496, + limb1: 0x28fdfc19e13b0752aba34749, + limb2: 0xeee8045d6526734c1f95307d, + limb3: 0x1e4f12f75a3db50a60aa03e + }, + r1a1: u384 { + limb0: 0xcd8114dc6e6775890632c756, + limb1: 0x3c477ef68ef5ed0c85ca0a58, + limb2: 0x706f9cac1acb2b71feb8358, + limb3: 0xeded7ab6bb655672cde9835 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x6016ea652473b7f107a77710, + limb1: 0xeb4242895460db86f361eac8, + limb2: 0x5fe77df899b1ff5607b38de2, + limb3: 0x10efb35680805c93c2bab2ca + }, + r0a1: u384 { + limb0: 0x9107262e5bb66980954e1a0f, + limb1: 0x57ab274a8a9565abc99387cb, + limb2: 0xbcd4f18d8a7e65b964541f5e, + limb3: 0xaf8d03faf1efb9183c00a2c + }, + r1a0: u384 { + limb0: 0x751a66b007c730df74908a8, + limb1: 0xf41cc4578874d56d020638c5, + limb2: 0x5230861fde86bb685b68c62f, + limb3: 0xb5d973cfd5090cd49182b06 + }, + r1a1: u384 { + limb0: 0x283597c889dd32a98401459a, + limb1: 0xb44d0ac2827551860df4a510, + limb2: 0x399fc7f05e1000db1a41c1a4, + limb3: 0xe3944c673891658df0e2ba3 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x4396189ffbd89d01fe27fa5b, + limb1: 0xe81217db1696daa3753ccd84, + limb2: 0x55c6ad903c2a3e4b9f14a8da, + limb3: 0x15f5f0afe4eeb7545fb13eb0 + }, + r0a1: u384 { + limb0: 0xd3da9931ffbf361f326b7282, + limb1: 0xc9d2464eda778b0051c1027e, + limb2: 0xb8f5f46e2bd5fc15d81b368a, + limb3: 0x1040f087e9a0b6633fa13692 + }, + r1a0: u384 { + limb0: 0xf986f1a7ae6234649c858e8a, + limb1: 0x4644ba4e2b6b06ac11907477, + limb2: 0x95bcd96412c2b77c798589bf, + limb3: 0x122a0d20337a4865af008b55 + }, + r1a1: u384 { + limb0: 0x201ad08d1e12f22740a2d61f, + limb1: 0x4ec7ca2abf73f04dd4d3c1cc, + limb2: 0xbe2da8c0b44af69f8c08bbe5, + limb3: 0x3bac9dd093b57980816b067 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xa91fa22e8afc80abea221520, + limb1: 0x5bc71539a636bbf8ebbe74f6, + limb2: 0x2922894d551b50829ba322fc, + limb3: 0x14e8b48d18e449e691aaf792 + }, + r0a1: u384 { + limb0: 0xd260160df53ab2df298a0d4c, + limb1: 0x854978d64707004860c8ebf6, + limb2: 0x20a4348de1a9dd2d5347eb55, + limb3: 0x243d4a3903c17c3cc51c2e8 + }, + r1a0: u384 { + limb0: 0xcd7b87ec09c28073ba10e0d1, + limb1: 0xa5ab4f79373898318a3e146d, + limb2: 0xe648aeb5fef1cf65d3fbd74b, + limb3: 0x2fa5e6b46df2191aabe0bef + }, + r1a1: u384 { + limb0: 0x11b43fce26bc49795004ca02, + limb1: 0x437fe31017f62de97ffc3e35, + limb2: 0x97d41632c4cd7bb50f450ba6, + limb3: 0x9b7e59a28684bed532da137 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x4527a34a70ec377ccd63a5b2, + limb1: 0x351c7771105a0a1096dd87f0, + limb2: 0x57630dce3b4db45cbad696a6, + limb3: 0xf10733fed03fc5b7ae27fc4 + }, + r0a1: u384 { + limb0: 0x53a208df401e3d6bf657857c, + limb1: 0x306991a8af53fac94e1e9b52, + limb2: 0x324634590aee6093dd239d9, + limb3: 0x855b8b1eedbf578f7498f37 + }, + r1a0: u384 { + limb0: 0x71e5471ff515d0d4982815b6, + limb1: 0x9a63281835ec15935519deca, + limb2: 0x17a64faa9e7e4ab574a3f785, + limb3: 0x134b4a48f53fff9361e1952c + }, + r1a1: u384 { + limb0: 0x56dc56f73bd268799b824fa3, + limb1: 0x4180514d6004cf446a366719, + limb2: 0x193a82567b226e738b11a0af, + limb3: 0x1498d7e7ad2a68346f7d2199 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x81e4894bdfaf54d49cb0c4d8, + limb1: 0xeb9bf46cb3dcd89325b39d09, + limb2: 0x5a8e743db320615a5a0c40cd, + limb3: 0x1850f244c5272718a19a040d + }, + r0a1: u384 { + limb0: 0x857b482a44483bf0457331c7, + limb1: 0xa67cfb7a4ea236dcedf6137a, + limb2: 0x639d1a584ec879083798355d, + limb3: 0x14240af1c0466562ca4e24f5 + }, + r1a0: u384 { + limb0: 0xb525edd6feb5970219a6995c, + limb1: 0xb1205b041c3e38e20d2fe204, + limb2: 0x8caed9ba4365ffbc1589b563, + limb3: 0xfdfce3b6d0c90f89ff5b6ff + }, + r1a1: u384 { + limb0: 0xf04c7ee058045bf0c52bcca9, + limb1: 0x25da9c7e03f90300aa977fed, + limb2: 0x5388457b2d4593b62df4c077, + limb3: 0x16cde52858fd178529b49d60 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x6c92af226aa27e2cbe8fae21, + limb1: 0xbc299acce5e8da96b6b932d, + limb2: 0xec46a86181ef1ff2f8317201, + limb3: 0x17900cb270764782b3eca3d2 + }, + r0a1: u384 { + limb0: 0x82358801a5440afa7826f03e, + limb1: 0xd09104615d27b1dba405157c, + limb2: 0xda33c37fe337917d32826e1b, + limb3: 0x1be7df7094ce56532653ce2 + }, + r1a0: u384 { + limb0: 0xd33c9c433bdeabd28a276748, + limb1: 0x5dd445f6fe3bb3070cd0d395, + limb2: 0x8b092b49f4fdf2a38337a44c, + limb3: 0x4e047a80a74764555b1ea3d + }, + r1a1: u384 { + limb0: 0xd83bc84b011c607d97684972, + limb1: 0x2b14aae22370badd22ec77ba, + limb2: 0xd29b9c7b77c3f08055bb8a9, + limb3: 0x125b416bddff21db8d6f42ed + } + }, + G2Line { + r0a0: u384 { + limb0: 0x1f7265a2588028a739940ca5, + limb1: 0x1e3d7315d69b4f1540ef139b, + limb2: 0xa239c997bf8c622c1716408, + limb3: 0xd9744d0ac86db4218e7e96d + }, + r0a1: u384 { + limb0: 0x90541dda73208a1d1eda111e, + limb1: 0xd5a4dd2c69e927e6a84d8487, + limb2: 0xbba86a67c752a3ce780b84ff, + limb3: 0x9a35294d76f0d15a59ad03e + }, + r1a0: u384 { + limb0: 0xaeae8c21bae747ea58e4eb2b, + limb1: 0x22bee27e94b3df2f9e30496a, + limb2: 0x3c490f390a6a3762549bdbf9, + limb3: 0x1777cd7c3048d009f9f72bea + }, + r1a1: u384 { + limb0: 0xec21f8b948e62cded22a7d58, + limb1: 0xb8041010b7270992a963f6df, + limb2: 0xbddd05cca8941058f062d094, + limb3: 0x10ad979954bdd8983ce4dfc2 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x6cf96397e7b79f2fc8c8275d, + limb1: 0xfc7cd3706f331af3de61fabf, + limb2: 0x78630a1ca624fae6d5770503, + limb3: 0x15ed1256df8e5e5ca95b56c8 + }, + r0a1: u384 { + limb0: 0xee76aa06cc2a711c9ed0f30e, + limb1: 0xffa3eb442aaeb1342a8a3887, + limb2: 0xcd5194bd83d804f9da8e5cda, + limb3: 0xf5886abb33616f07cfac605 + }, + r1a0: u384 { + limb0: 0x3e0ff1e7d1f926d905c0e89f, + limb1: 0x3fff1943b59d697a741845cd, + limb2: 0x4e362d7df69aa3269ea5a418, + limb3: 0x13a520fad90f72497a67b697 + }, + r1a1: u384 { + limb0: 0xce7bf1da23ccce53d8e13b8, + limb1: 0x56957fccf1163143404a68dd, + limb2: 0xd26ebbc9548a9897d0383b14, + limb3: 0x329392268b1afdd087dd27b + } + }, + G2Line { + r0a0: u384 { + limb0: 0x8f61e98d8c6cfb102fc12599, + limb1: 0x3b581910d31b036fd00d6cd, + limb2: 0x960c67926f53a7c4400c36fe, + limb3: 0x1437622871bdaa8aa8f1620b + }, + r0a1: u384 { + limb0: 0xc06e7440dac5dc6345811f4c, + limb1: 0xcfdd60e51cc453252af4fcc6, + limb2: 0x756f2c0839d3582469c0b8c6, + limb3: 0x12d66e992019751bc4b8c1bb + }, + r1a0: u384 { + limb0: 0xb0f08516779af407c735061a, + limb1: 0xaf9b916f38282785c75beb83, + limb2: 0xb386d3a1dd1445469d29c602, + limb3: 0x24dbe829c015491a29896d1 + }, + r1a1: u384 { + limb0: 0xac0f9105a6d03cc8551b7c70, + limb1: 0x4f4b9b10e54191aae0271be0, + limb2: 0x6bd62b1dce1efa964448250a, + limb3: 0x121963e40701951c40d3ccd2 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x765ce308dd13ea9ec917f81d, + limb1: 0x4c2cdefe8611811647fac337, + limb2: 0x9e01fde22386755f816c125f, + limb3: 0x249a870907df1494e56fc21 + }, + r0a1: u384 { + limb0: 0xc3cd52b28123518842661348, + limb1: 0x6678659f6f9ca9e64f594e30, + limb2: 0xbdde01f23d77cc2219a64e1, + limb3: 0xa59546d0d9d0d18614e9879 + }, + r1a0: u384 { + limb0: 0x7e7be141202ac55eb1d4a8b8, + limb1: 0x22ee295a285099a1bdc85200, + limb2: 0x7d274b729c40bb351c2bdd3c, + limb3: 0x105edf80625508ee7473afc3 + }, + r1a1: u384 { + limb0: 0x8d19d95e92eb2f4d361b91e, + limb1: 0xf6cc461a1b4bd0202cc3590b, + limb2: 0x87ebac45146065b2dc8d4bde, + limb3: 0x1375f5a114849a9f8e0c3d37 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xf3f6022a346335909994d26b, + limb1: 0xa2e674d9be45c130702c8393, + limb2: 0xda934834c7f1f4550986c5, + limb3: 0x17170963f6200ba02d7f36db + }, + r0a1: u384 { + limb0: 0xc6bd88f8f5883c00bacb7319, + limb1: 0x2865832a25d7695c70d60852, + limb2: 0xd63579f3b9eb855ce78f80e0, + limb3: 0x16f67362c8cbffc3e300d83b + }, + r1a0: u384 { + limb0: 0xd5bef1e76085837868d52daa, + limb1: 0xe17818fa8f87a1a29495c6f0, + limb2: 0x33702bc5001cd8e3bab9709c, + limb3: 0x3ee9300c2e7d74b5e5774d + }, + r1a1: u384 { + limb0: 0x79515359f6e9ac46c2da8b44, + limb1: 0x8b1d7830cfb661bc910fe5b5, + limb2: 0xa6f740bc62a497d501d49790, + limb3: 0x106645c420742d2fc191def9 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x58f86bbd730aa1df76e95257, + limb1: 0x3832640fbf5ff16fd5c86613, + limb2: 0xaf56bfc4d589fd5479b90e9a, + limb3: 0x3ca74026cf32fba56ec4ff + }, + r0a1: u384 { + limb0: 0x577775e0ba37cd47da598900, + limb1: 0xf402fb94e1c54fc0073a49b0, + limb2: 0x2e06dce324741a7e96cd8fcc, + limb3: 0x16f491b5bd383da7e70c001 + }, + r1a0: u384 { + limb0: 0xf906737c542dde2e8b5d7bf7, + limb1: 0x93d207424c8f01f866d09071, + limb2: 0x7a8dc05cf5ae45304b21d8d, + limb3: 0x1d432a9b400dc09515479f5 + }, + r1a1: u384 { + limb0: 0x533a88fd57c73a7a668d47a8, + limb1: 0x11cd23f02ff6e7610e1522a9, + limb2: 0xbb9e0293df841db5d616e680, + limb3: 0x19f2811473fbfa9dddb16249 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xb84433d5bb94067c8083df37, + limb1: 0x4a1c6dead6b06daaef49a331, + limb2: 0xf045631520d7fcf91cd6d5bc, + limb3: 0x171679be9cc2fb7fca2ffb4b + }, + r0a1: u384 { + limb0: 0xbff0ab7bce5a89764c470c2b, + limb1: 0x7c275c7485dd37e467e28e07, + limb2: 0x976153708a70bd4353e49415, + limb3: 0x137b63810a42885e3d12973a + }, + r1a0: u384 { + limb0: 0x33aaf9966841141dd4aeed0, + limb1: 0xe937c580cfbd8a3936590a47, + limb2: 0x7e2948f3ac9443871d29a3b0, + limb3: 0x17ae57245137f902685ea5f + }, + r1a1: u384 { + limb0: 0xae14ce204d876228a369b45, + limb1: 0x6e8aa97e94af3b53715ed047, + limb2: 0x346c278c809a30daf1d01b7, + limb3: 0x22e054e6e6d8bf998a85e43 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x453bf5d35812bbf0123c972a, + limb1: 0x3a9bcdec2fe60921bf629abd, + limb2: 0x8d4d0d00c4d2739ae3a0b176, + limb3: 0x9a76bae205af60fb63330d3 + }, + r0a1: u384 { + limb0: 0xa5e2fc320bd337a5e6bf6e59, + limb1: 0x649bf53444907381a7d0f976, + limb2: 0x57cfc1f1da9301aff5ef309c, + limb3: 0x79042a88c84c694ffd3fa12 + }, + r1a0: u384 { + limb0: 0x8149e3cbfdcb7c4749e0ba73, + limb1: 0x72f87f4ff2d25e09a5eae7db, + limb2: 0x1d01fadf84a7202ce4489428, + limb3: 0x15652f54b134df28e3b93c7 + }, + r1a1: u384 { + limb0: 0xa1b43fd866b4d217c50e744a, + limb1: 0xce197f05b592d754e8f84093, + limb2: 0xbc7dc9245b7e2113d675abe4, + limb3: 0x2f8afc77fac6bc37b0c7667 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x5f799d84974b34b214204be7, + limb1: 0x7e577069bef682a54f78cc32, + limb2: 0x43803af2b35c7987d12eac96, + limb3: 0x3570c7ba557421c82cfaa6c + }, + r0a1: u384 { + limb0: 0x2aa9d33a1acddb979d7c2d2f, + limb1: 0x2bb926928f20a965a10a6d22, + limb2: 0x1d650b759bafd7750c78aa91, + limb3: 0xac21b07f22d3d31ceef607b + }, + r1a0: u384 { + limb0: 0xa188a2df22f2cac6ae25fcff, + limb1: 0x15f7af3ae3fe3ab80fcbf44b, + limb2: 0x3cc65299b3a990d0b8f2dc21, + limb3: 0x720671ab41e616ac46a4d4 + }, + r1a1: u384 { + limb0: 0x8d5ce83450ecd58d21821d04, + limb1: 0x600fb56fcdc4198005433d16, + limb2: 0x60f583b87d52b7e7eae71b15, + limb3: 0xfb05f7038ebbb06ca53b3fd + } + }, + G2Line { + r0a0: u384 { + limb0: 0xa36890bfc74afe64e9f3840c, + limb1: 0x8eeaf2f380047dfe3a21b11b, + limb2: 0xeb84e8fad6b7625c837aa272, + limb3: 0x135ff64b4d73a3a2d0f886b2 + }, + r0a1: u384 { + limb0: 0x6fa3e40ac2853a97b01176dd, + limb1: 0xcd16a519987e4aabf6bd8d1, + limb2: 0xe4ee3c4f4c650fbfe5a0a370, + limb3: 0xcc7efdc19164223dbcb0b43 + }, + r1a0: u384 { + limb0: 0x9ed5597f7236b21674d039f4, + limb1: 0x5cce2f4074bfb9593d07dcab, + limb2: 0x1467dedd98c377f9f9b46e75, + limb3: 0x89f8ba7d879e18afda115ac + }, + r1a1: u384 { + limb0: 0xce1eb5fb3e129849b7af9b61, + limb1: 0xbb388e5edcc82d67d7e505d1, + limb2: 0x37f0c598b86ce85a7ccc5e90, + limb3: 0xf3dfe35088599f2eeb97849 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xb1dad5dc4b347aa8cdea64f6, + limb1: 0xcc2058c63fba33421acef87, + limb2: 0x6671bbd574e8f23a8c33a473, + limb3: 0x173c0d3a77be26a04dc370a + }, + r0a1: u384 { + limb0: 0x89c7ef66c7e6d4c7a5f1ee7b, + limb1: 0xfa29a5dde6a8d29efb1b12b3, + limb2: 0xc0f4a5b6342df0adc3da765b, + limb3: 0x154e74a84c92a5ff794fca30 + }, + r1a0: u384 { + limb0: 0x3baf5745ddfc03d1be36473, + limb1: 0x41fbbc02d24948d8a3c0efa1, + limb2: 0xeba542193a176f39572880b7, + limb3: 0xba18efa42d34eea1333f2cd + }, + r1a1: u384 { + limb0: 0x77fee73ea8d2cae877fc09bc, + limb1: 0x4b28c7e9ba63b4a2a16dc3e3, + limb2: 0x5ef0ade97bcf1bbd542b74c2, + limb3: 0x60c323e8930e93d6a8a8b53 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xb9289920fc29c178a0728467, + limb1: 0xf35e17ec8a43244f4e0efb63, + limb2: 0xa46135ade487bf1a95a36590, + limb3: 0x4597ae1f4cfcdaacff3f6 + }, + r0a1: u384 { + limb0: 0xe926fdfcdb55d8651b029bb7, + limb1: 0x741390b7035f30b98e2dcd27, + limb2: 0x697fa3901ef0c0d6f4f0693b, + limb3: 0xcc420802c358e2dedfc71d4 + }, + r1a0: u384 { + limb0: 0x404a03b34791ba0f3fa9761, + limb1: 0x50d30e7876bb541f3ef689f6, + limb2: 0x7eca4b1c1a04fdc1c58f3065, + limb3: 0xa9e0b8c0194468d35c05fbd + }, + r1a1: u384 { + limb0: 0xb370e739ea46b6699276bb50, + limb1: 0x39805df77c609ca4cb80f044, + limb2: 0x1f93a5fc91ea7ec7048f46d8, + limb3: 0x109841b0d6d23c644d831b58 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x696c2443a8baa527eef5ec6e, + limb1: 0x7c385a900f4614f62a38d2e7, + limb2: 0xecef959f527ae42bb1b2a0ed, + limb3: 0x7fac72373dec09eeaf6db37 + }, + r0a1: u384 { + limb0: 0xc84aa165d81984cbd1d40498, + limb1: 0x7ef2f6d8a1b0b82a86a8aea1, + limb2: 0x9f04cb828903af563a7ce955, + limb3: 0x1260f88b57dddd5bf01540db + }, + r1a0: u384 { + limb0: 0x7d666c3a74212ecb676ee24e, + limb1: 0x8ddff061953f45de2460c7ee, + limb2: 0xb69a343af7532ec4af3c8894, + limb3: 0x213c5dddce502302ac58fec + }, + r1a1: u384 { + limb0: 0x9b68c470206e0a6b23d993d7, + limb1: 0x8e64f45ab3906177fca690b, + limb2: 0x6b3ba9665c9e8cdb62669c9b, + limb3: 0x4535c1e41f9fe732b7c4780 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x47796752c668f86cda3eea09, + limb1: 0xabe85392bfe45c509b21188a, + limb2: 0x17747fdbb10299befbd5f562, + limb3: 0x10f206ff106da3cd9621d6a7 + }, + r0a1: u384 { + limb0: 0x19e850771140dd110fd5f601, + limb1: 0x49e65a215ab2cb29f8e19340, + limb2: 0x7c583039a8252df0d94325d4, + limb3: 0xfdd46f3792b92d70b7938c8 + }, + r1a0: u384 { + limb0: 0x2973fb308f21f4591c6768bc, + limb1: 0x7c10b3f79cbbfc0069738f2c, + limb2: 0x227581522b2559c9557982fc, + limb3: 0x146f0ce0cb299800bb8186ed + }, + r1a1: u384 { + limb0: 0x7e45c08de7497185100c82e7, + limb1: 0xf873456c3b1257743a548919, + limb2: 0x4e414c1420aa0674960bf9f, + limb3: 0x12b9b73bea8424ee57b2038 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xf52c3a9e1924d9731f45159d, + limb1: 0xb552aaa0c17ebf07b9461b81, + limb2: 0x9e0e2d36095165665a56c844, + limb3: 0xdc948cfb597299725a35f46 + }, + r0a1: u384 { + limb0: 0x37804446f6495b7f0eb8afe, + limb1: 0x8290cde2fc690a09b1e27c3a, + limb2: 0xac5737e20aed8460e392261b, + limb3: 0xcffa82f91cfb6f276a79a6 + }, + r1a0: u384 { + limb0: 0x13dd968a1b3c381b4b53e494, + limb1: 0x231f8610c0c788da31f6a767, + limb2: 0x1d90cef9842373ab0ed2113f, + limb3: 0xab763befb660bb27aeefea1 + }, + r1a1: u384 { + limb0: 0xfb0924f8b0c0076931026ead, + limb1: 0xc2303d081337f2117f9edd47, + limb2: 0xbb530c1bf25042e905ef49b5, + limb3: 0x13cf2176e8c30a76d82031ff + } + }, + G2Line { + r0a0: u384 { + limb0: 0x14e4f467f4709129c1d6d6d7, + limb1: 0x33e67ed9f2b5e1802523571, + limb2: 0x3e76ea8acb143c96671cbc65, + limb3: 0x1137f470c8f7d00baa56e5c0 + }, + r0a1: u384 { + limb0: 0xa2a95cfa92d0088ab1308e85, + limb1: 0x85a5304db0b3422f71d7ac93, + limb2: 0xbc8572953d8f42a55fe99700, + limb3: 0xf23701cea5719c6d8b0d3f3 + }, + r1a0: u384 { + limb0: 0x380e418e3c32756e123587f9, + limb1: 0x8a39d6b5872d774c57af0ba1, + limb2: 0x11473256ad05f9eaac305647, + limb3: 0xa642f0b83f002f2b82a1d3f + }, + r1a1: u384 { + limb0: 0xd5b5c903360b3614bde608b6, + limb1: 0x407e2bf83df10c320c4ddafa, + limb2: 0x3771cad615e4d7b5de69e962, + limb3: 0x105334af5850345d42c10c17 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xcdb8e16f1b850432af115daf, + limb1: 0x494ac8b75720d50e9d866f3a, + limb2: 0xda7586ede3b806d6a6384fd, + limb3: 0xb859f60d04e4ff66fdfc85f + }, + r0a1: u384 { + limb0: 0xe11de01127cbc1a326afb2b9, + limb1: 0x6eebbbb38d51a71d3170ccd7, + limb2: 0xd5cd24d22fecda4fe96bae46, + limb3: 0x101e2ac25b02edda9728dcd0 + }, + r1a0: u384 { + limb0: 0x71b27a86fd074f148f733377, + limb1: 0x6ec32a4c65f5682adf1bb4da, + limb2: 0xe8a268ef501888b89065c8ef, + limb3: 0x12f6fae4a11b2f7bae3b371a + }, + r1a1: u384 { + limb0: 0x925f04ea98dc22979ea69c0c, + limb1: 0x7778ab2882af9fc10adda60f, + limb2: 0x31b791ebfc10de4e0843db89, + limb3: 0x1884eaeeb4127c15465bd473 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xe8ab375f9e79671f77c33b38, + limb1: 0x32c9317a9c538a1808d10350, + limb2: 0x39b7c7695d2524211d5341f3, + limb3: 0x373d7203575fda92e7b4b02 + }, + r0a1: u384 { + limb0: 0x54a74ef22bb2c45a0f0992be, + limb1: 0xe9d5746328bce07da2a04f41, + limb2: 0xf657d148ed56fbf731787b28, + limb3: 0x7b03ee28e327f04166f5075 + }, + r1a0: u384 { + limb0: 0x754ae620f48dd7de6afcbb5b, + limb1: 0x488b7b5de47bfe76c7d7f1ce, + limb2: 0x5a2e05b269b38310ba8b4159, + limb3: 0x41965ba496910c39d2c8167 + }, + r1a1: u384 { + limb0: 0xe544c97bb363e3619c50c630, + limb1: 0x7fec53ec738123389016bbf, + limb2: 0xb12f6ffb0998373cb04be875, + limb3: 0x4bf5cef5067781b9809ec64 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xee52fdd902c0488821edf979, + limb1: 0x895d9ff17f5d04d1515dbb15, + limb2: 0xda20231af600be908c9165c9, + limb3: 0xa88fa0e247a85049196ed0e + }, + r0a1: u384 { + limb0: 0x1014f46d465b15781593a14d, + limb1: 0xfde315a447ebeb1e31f0c737, + limb2: 0xc264e73bcfcf21a95860cb90, + limb3: 0xa404fe10b300ee8062a4278 + }, + r1a0: u384 { + limb0: 0xde6e165032d17e0a1dd355b, + limb1: 0x9ece35a48b0dac3133bcb2ed, + limb2: 0x1dd3ea819651f9fffd805b91, + limb3: 0x2c3ab75a45f0062b01b25b5 + }, + r1a1: u384 { + limb0: 0x1d435750c14e60fcffc44b18, + limb1: 0x781f841326b5c6cd532ff483, + limb2: 0x5bdc193e27d8e3050ed4a070, + limb3: 0x5865e1a9f5de7c0a57062e0 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x4d2b6e4cdcfd83a0692003b0, + limb1: 0x41629374ff0d1ac17362c794, + limb2: 0x18b16faf0521c1c5a11c3523, + limb3: 0x18b70eb629a79ff3f9834985 + }, + r0a1: u384 { + limb0: 0xf6dd615a649c30b33d8b88ac, + limb1: 0x526f609b923d7ba3b37b63c, + limb2: 0x4289133e7279c670978cd569, + limb3: 0x11fa0abe9f21dc673b14d917 + }, + r1a0: u384 { + limb0: 0x7f14d726cf9a27a8c970bb68, + limb1: 0xe380e6b07cde1eb0fffd95e6, + limb2: 0x2c5722bd0e114b506bddd89a, + limb3: 0xd3fb948d9f8e2c898c1b3c + }, + r1a1: u384 { + limb0: 0x86aed9389c52f71bde01a5e0, + limb1: 0x4c6baca3b4494d3a4a88343a, + limb2: 0xe1083c4faf04588a29999bbc, + limb3: 0xcddd31531e910375fb212ff + } + }, + G2Line { + r0a0: u384 { + limb0: 0x203fe85e2836c465e4db22af, + limb1: 0xe308a1ed6dee139d030e8922, + limb2: 0xc7908b59711d8544aa16934d, + limb3: 0xf2b561c5d125edf292a426b + }, + r0a1: u384 { + limb0: 0xdb11824ffa56d8b1596236ef, + limb1: 0x2dba53ae227809d06646c213, + limb2: 0xeb2f93a64e027c5e4973d8ae, + limb3: 0x70e748d64796b96d4704120 + }, + r1a0: u384 { + limb0: 0x651d82f84f2464b4da2dfaa5, + limb1: 0x122eee1f6190b4da0deaaec, + limb2: 0xa3f6869c83d36b0ad97eb0d3, + limb3: 0xc58ccf6806e87f189fcbb0a + }, + r1a1: u384 { + limb0: 0x648157de5d81daa67c476971, + limb1: 0x2845a24d3190c4fecbde2fa4, + limb2: 0x72f924eac3a8d2c228a8b082, + limb3: 0x13673079ebcf601a5d5fae92 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x2d6310ed50636162786d1b75, + limb1: 0x5cac54906e73bae3b4359998, + limb2: 0xbd428c9c44f9a83980265ddd, + limb3: 0x2fc21e36ad4d0da0a00add9 + }, + r0a1: u384 { + limb0: 0x80e8a4f63bb295c1f909c9f8, + limb1: 0x76045a0b6f715c18ef69c37a, + limb2: 0x8e2d6c8495568d22744ab3f3, + limb3: 0x2b70c4ecc512e5b7a263f20 + }, + r1a0: u384 { + limb0: 0x74f73dffd0f8db5344a575d1, + limb1: 0x8e6d3150c6b50fb0f30b8d42, + limb2: 0x1caf7885c868849e8e700707, + limb3: 0x130fa43ef7b10a6b7c72a4af + }, + r1a1: u384 { + limb0: 0x1cd953b2a94a0b0460118689, + limb1: 0x5c361d5ff78164edfe007331, + limb2: 0x61315250d28c9b99d174dab6, + limb3: 0x252277581829378760d4033 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xf48b3d5c545dde843e9509d9, + limb1: 0xec087b6dc32d167683bbc860, + limb2: 0xecfa5e40ea40c9452bcaf0c9, + limb3: 0x1040fd02b48b11b85d471c89 + }, + r0a1: u384 { + limb0: 0x4fcc4443458e23010506f346, + limb1: 0x6c4848e26b5d994f5bc3e72e, + limb2: 0xfe88288f9e882ff4e9a375b9, + limb3: 0x164597b0f78ad70a7b4bc1be + }, + r1a0: u384 { + limb0: 0x755828105bc1eba4198f7dd7, + limb1: 0x6eae5a58a81935ddf455bd6, + limb2: 0x6240aac72233651a6dfb3db5, + limb3: 0xb4497d73d44dff355f96fc3 + }, + r1a1: u384 { + limb0: 0xe9e516384450aed995eae178, + limb1: 0xb13053f758b857a1479bef06, + limb2: 0xb18ba337770920df12a72642, + limb3: 0x121a732dec2700ebe307b235 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xf313b674fee5c83040549617, + limb1: 0x864b49b4b96dc11dcb31a6b2, + limb2: 0x7afa88358fa085d4db1d9e6f, + limb3: 0x10b916005fc2476498beed41 + }, + r0a1: u384 { + limb0: 0xa5f1bacd2bc2f38d4e1a34d, + limb1: 0x45d1d4d76b0b03b8d7da125b, + limb2: 0x74a0ba0ae49290dd243bdc61, + limb3: 0x185827ff9e3c833ac46e1e16 + }, + r1a0: u384 { + limb0: 0xffae650825626bdffd8ed424, + limb1: 0x126a57866536ac1d0b34b17b, + limb2: 0x517ba3e3b50188d25dc23dc8, + limb3: 0x1276dc74f1b2a7173802ff0f + }, + r1a1: u384 { + limb0: 0xa73951cadbaab9fe957c0fed, + limb1: 0xa232a5178de78c8f681635e5, + limb2: 0x30adf5deb8ee4da1fcc053b2, + limb3: 0xd840dfc0aae66492a176a2e + } + }, + G2Line { + r0a0: u384 { + limb0: 0xbec850cf3cae0ae894430855, + limb1: 0x471169ffbfc02b7ee8b53c48, + limb2: 0xf24c8150520d1054b6fc8530, + limb3: 0x2627371854bd7fa799b809f + }, + r0a1: u384 { + limb0: 0xbdc8b09d11fbd315b7aa7980, + limb1: 0x2f2fcf7338f1747f606b3a25, + limb2: 0x27fb2eb96b07297a58fabfe6, + limb3: 0x111b90bded70421c6543f89a + }, + r1a0: u384 { + limb0: 0xfdb1c553460611b281b896a7, + limb1: 0x9e417f1af210f3a016ad9c83, + limb2: 0x5908b9614188572d05b39a67, + limb3: 0x16f5fc4c7d6ca25189a5da6 + }, + r1a1: u384 { + limb0: 0xf515c6bd1b302886cb3cb5fb, + limb1: 0x6357aa94ce3eecae26fc87a3, + limb2: 0x66f86efa4a89422f8fa42672, + limb3: 0x131a1613cd2ea3831b5cdcfe + } + }, + G2Line { + r0a0: u384 { + limb0: 0x3ce32e18da41a2016fbf41b1, + limb1: 0xda3e0d01e0bbb52a301585cf, + limb2: 0xaf508b2248a1fe6ffc5d18d0, + limb3: 0x1274aa625858db0bb675b3bf + }, + r0a1: u384 { + limb0: 0x4cbc0be362614fff6f6d4898, + limb1: 0xdf8603dfa938bc22d0aa98e, + limb2: 0xaf3784151a3a1a7585c177cf, + limb3: 0xcd9b76612194b440cbd9c67 + }, + r1a0: u384 { + limb0: 0x93de5b0d4ce155335ed8a6ff, + limb1: 0x9dc6c21cddb15edd7f401cc4, + limb2: 0x2601d5b08d144c3608181a8f, + limb3: 0x872d334a6e81b6937f7580f + }, + r1a1: u384 { + limb0: 0xa90ea56305b0b457ffd7dfd9, + limb1: 0x3fd7486324393fe073a67746, + limb2: 0x22aaac8be67217e0e49366ff, + limb3: 0xdc78f4f3c40b0984ec316e + } + }, + G2Line { + r0a0: u384 { + limb0: 0x32410e4bdcd6030081ee0117, + limb1: 0x9711111255797439f6866cb6, + limb2: 0x8a1650034dda2434eadb9c77, + limb3: 0x13f6a882a25deeaef4bbe62d + }, + r0a1: u384 { + limb0: 0xcc47fc627ad939824b8320f1, + limb1: 0x3f1cb2532c6db9d1abc737e4, + limb2: 0x4883356c3277f2df6283a2ab, + limb3: 0x11e02397acfe9612a98a14f9 + }, + r1a0: u384 { + limb0: 0x1588bd50c2f4f5c5ebbe62bd, + limb1: 0x87a259e41ba48ccad1a07c48, + limb2: 0xb22b4f666071523b8a172736, + limb3: 0x96f9baf300ca7342721fd8e + }, + r1a1: u384 { + limb0: 0xf0c2d5fba2f156c3f26673ef, + limb1: 0x71558132bb663713ad20817f, + limb2: 0xb07619c97cbceccc4c0fb256, + limb3: 0x13ed85faec0618c507d395a1 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x35a50965750c7716c237772d, + limb1: 0xe96b0c22d39fbbbe7f55d6bc, + limb2: 0x40864a9ec51fc3fceddf7498, + limb3: 0x232f7c41bf2d0ca9a4a6560 + }, + r0a1: u384 { + limb0: 0xebd5d6880bc93e525c5283bd, + limb1: 0x911e6efcf7cc8f0983f3a122, + limb2: 0xeb2d53ffa24eaa0527809305, + limb3: 0x126b7366a9ba4cdc1648b905 + }, + r1a0: u384 { + limb0: 0xd7789f5359bb3bd4b674719b, + limb1: 0xecaa3bff242dc5a63ed57279, + limb2: 0x85e8faaf82c119cc47bdfe4d, + limb3: 0x1042198c5b912b48953f03ee + }, + r1a1: u384 { + limb0: 0x52c926fe4d73775c8dcc54b9, + limb1: 0x56410c723b730b245d2639ae, + limb2: 0xe6b9bc3d2b2a15155d82e48f, + limb3: 0x11772d7a9fa0b3530a88bfa + } + }, + G2Line { + r0a0: u384 { + limb0: 0x62a31df1dfbbec432d547277, + limb1: 0xafbad67ab615bf2d350b1688, + limb2: 0x1f5843187c62f057fcb3c202, + limb3: 0x2cd9ff07b37d472a54a7189 + }, + r0a1: u384 { + limb0: 0xfd689866343571218470d805, + limb1: 0x94b9219861e6e367cfd9d27b, + limb2: 0x5937c015c497d2c235302c66, + limb3: 0xfdf7276579ca6fa0076c8a9 + }, + r1a0: u384 { + limb0: 0xcc39c0acfde5d2338853dbb6, + limb1: 0x4d33a9fe71565a4342df96fd, + limb2: 0xf1c085869a954cb4994a6d7a, + limb3: 0x993491756f5c241452a5dd8 + }, + r1a1: u384 { + limb0: 0x59049f9dae7a7044e79531ad, + limb1: 0x1b01d078a53d321ef18d7b49, + limb2: 0x81acaa38fb3196010e594ce1, + limb3: 0x12c347a131f6b1191d4b563f + } + }, + G2Line { + r0a0: u384 { + limb0: 0x90b1d3aaedd7ae3ae5ef62ec, + limb1: 0x9c2237332a12d63f617991e0, + limb2: 0x88f758a89df448c1dd45282d, + limb3: 0x3c52126f27d2dd758ab0770 + }, + r0a1: u384 { + limb0: 0x8bf85f2a28b11ffbcc48f29d, + limb1: 0xb79fc38b4398e2af5a4ac3f4, + limb2: 0x877b0d7e053d12f91fa49c91, + limb3: 0x19ee364564c01cbdf0bd4257 + }, + r1a0: u384 { + limb0: 0xfbe824718174525ae3cbf681, + limb1: 0xb434f93ab3f012e5c5fab625, + limb2: 0xfaaa0bb2878017e90fb07ac6, + limb3: 0x616944a1484a78b2946360a + }, + r1a1: u384 { + limb0: 0x84c489abf936bfadd293c732, + limb1: 0xaa7ca8e76a07f14d2a712245, + limb2: 0xef338c44111cd8f2538f16e0, + limb3: 0x2f06c9cef716ae3e32a1bd1 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xa31fe2909d2e70ef0eed8a97, + limb1: 0x7cd66cae105a1a65a0469bb5, + limb2: 0x57c0d04a99e4fdd24818d48d, + limb3: 0xf143a86d061937bfc43197a + }, + r0a1: u384 { + limb0: 0xef3417fc2e604cb1afd28f22, + limb1: 0xc03449a2171f0466673fe015, + limb2: 0xb9e650989501677fe2bf4b6c, + limb3: 0x1a45a939634b50313d5b551 + }, + r1a0: u384 { + limb0: 0xc7a854c7a9f5c64683ace9b0, + limb1: 0xc0d2319347b83f932d66c058, + limb2: 0x7a12cc7266442611728385d8, + limb3: 0xfc3c7544bdb8ce9030892a9 + }, + r1a1: u384 { + limb0: 0x9adf18823ca540f0e6bf7f36, + limb1: 0xa5a5ea82ecc4affdc735afce, + limb2: 0x84c176ba131be177ad7d141b, + limb3: 0xbb932dd6da950ed35007f86 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x49369971c3fc33245bb7b9cb, + limb1: 0xce9896e5addb637375420be1, + limb2: 0x7d4c97a8e9d64c41cf2dffa1, + limb3: 0x287b1e39767a3c2d102a825 + }, + r0a1: u384 { + limb0: 0x6f6e6c10c2da68b535025ac5, + limb1: 0x9b6128f5e000427659557e1, + limb2: 0xba4e1537236425a49e10a76b, + limb3: 0xdccc3a8b263abdc2c1112a2 + }, + r1a0: u384 { + limb0: 0xf0f26fb9d99f34211c52ec21, + limb1: 0xb091a74cf88bb5563ee29bd1, + limb2: 0xb1a3c0e6479e60ec2bf5e312, + limb3: 0x6ea612bf02bd6df77f7af9a + }, + r1a1: u384 { + limb0: 0x773745b51d209d3643ac70f3, + limb1: 0xb837418d0188d5d41911d38c, + limb2: 0xae750841ca68ec61dd2fac9a, + limb3: 0x9b4aec971d45aee69870aa6 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x34fc38759fef61effd88d5eb, + limb1: 0x145b73bdd49f8b9841131ec5, + limb2: 0x5b032e13495cad2de8fc511d, + limb3: 0x14a5c34da7fefd80bfd917bf + }, + r0a1: u384 { + limb0: 0x7289910ae15b593b5d0fe9ef, + limb1: 0x321eb1200e5c9d49765ad730, + limb2: 0x7fbf84b5e04d1a87072209ff, + limb3: 0x120c78a1a8543136a69d721f + }, + r1a0: u384 { + limb0: 0x7b91d266ea9310fa2b902bf3, + limb1: 0xc3c6f100aa36d1105c43d928, + limb2: 0xcd92532364b0794355ab6fc5, + limb3: 0x3e83fd62b6b3aecc9dee3cb + }, + r1a1: u384 { + limb0: 0xdbfa72bf64242d0e4130bab1, + limb1: 0xbba2b4aa87acd80bda65c1ff, + limb2: 0x53c0d1281064d6d42f3ca6e5, + limb3: 0x7538323c443e424ba2139a2 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x9658e94dff575b044fd12535, + limb1: 0x9e633711f24267eeff96b84c, + limb2: 0xd09be055097f3f4285b74b29, + limb3: 0xeba32ca0fdf04b16e700d02 + }, + r0a1: u384 { + limb0: 0xdac31a776bf2f2a7eb8d07b1, + limb1: 0x99ff3b68fe53867aeee330e, + limb2: 0xfc016b0e19f5a9dafe6150af, + limb3: 0x1853f7c388088cef95618ee7 + }, + r1a0: u384 { + limb0: 0x25afd3c9e43a6bd85d8f83da, + limb1: 0x6636bcf8f7c4ffb03262b3ad, + limb2: 0xfab2ea835f15ffa64289aee0, + limb3: 0x19a40512a2bc92b145d4a15f + }, + r1a1: u384 { + limb0: 0x457e5f8262a3fb1f68e2ee64, + limb1: 0x2c8e29f8273ba32411548171, + limb2: 0x6b7ec622d4cf5c7605c02c7f, + limb3: 0x16d592d1bda21aa16790c116 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x418f88c2ec9095086a11212, + limb1: 0x9bbb92abebe257d874d88812, + limb2: 0xef0f443e07ba39689c54a875, + limb3: 0x15190f05d2854f4f23244780 + }, + r0a1: u384 { + limb0: 0x73562c95a5ced7285783ea44, + limb1: 0xebc6a876c7f862dd940990a4, + limb2: 0x806ab610b9ba3826809481f9, + limb3: 0xd738e6b4748294d2ef71b46 + }, + r1a0: u384 { + limb0: 0x2f88f9cb9b43366fca45401c, + limb1: 0x981bc3797c4e9ed2343a8465, + limb2: 0x10f951c9ceda971d01120a50, + limb3: 0x197593f4646346745cba98ce + }, + r1a1: u384 { + limb0: 0x6352dd6f1f276ebd12e36438, + limb1: 0xbc94e96354513cd65cbb7831, + limb2: 0x63f9809778a9e5a3a14bd9c6, + limb3: 0x12399967b752e1ae762754b4 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x1393c1940f25665663934fc8, + limb1: 0xea7d0b2339e762ea1d7417bc, + limb2: 0x38e8c939bcfc597914fa0bc4, + limb3: 0x10e5f821e745ef290f773399 + }, + r0a1: u384 { + limb0: 0x3fb68057499c7406aa1ace48, + limb1: 0x41257c93b17f3e38108e6f37, + limb2: 0x6e97eb8687dab2a2a640c57f, + limb3: 0x14df29fafe098da44c7fd33 + }, + r1a0: u384 { + limb0: 0x59456b76c2b8257a9ee80887, + limb1: 0xb92657cb2cd74cfb0e2e2af8, + limb2: 0x74366a9ca17b733790bace94, + limb3: 0x18a62b6be3320f12ef9121ed + }, + r1a1: u384 { + limb0: 0xd05f8b04255c124be737ddfb, + limb1: 0xcaf73bd136dd217b40f1b669, + limb2: 0xda811888424a2ec800ca2f97, + limb3: 0x157c5205e1188acb79fbef71 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x8b374dcb293da523769439f3, + limb1: 0x2fa24f2a394fefc00be6551e, + limb2: 0x5b56b235703e81f9581fb812, + limb3: 0xa510fba0090ee3f2da90e03 + }, + r0a1: u384 { + limb0: 0x4c287e611b512a841d227d6c, + limb1: 0xb311b662d2c9a4106ab64890, + limb2: 0x3f74ad8a1056c7ee37f181a, + limb3: 0x387ccbb5fd44513ebd1364a + }, + r1a0: u384 { + limb0: 0x238250f751fe359ea48e6612, + limb1: 0x48d78fe66c255cda27a7797a, + limb2: 0x270135167f0b9910bbe997c5, + limb3: 0x13f053dabc35bea274b5dac0 + }, + r1a1: u384 { + limb0: 0xb7350395e2c37b4d15be0abf, + limb1: 0x578ec20dcde4919879af4f9, + limb2: 0xebdad8f8ae78030cf33a9584, + limb3: 0x214f9275dbd80c3514f9cad + } + }, + G2Line { + r0a0: u384 { + limb0: 0x54863ab6d50bc9ff4874b6e6, + limb1: 0x937c0d4560eae2eee4b7ce1e, + limb2: 0x337805ebca15d19f40277942, + limb3: 0x10ff70c91cbb8869a0659bf2 + }, + r0a1: u384 { + limb0: 0x7b3cfe640c29faece9a85e53, + limb1: 0xcddbe3decddda92adfd9039a, + limb2: 0x42f145b0f85554ee195ae299, + limb3: 0x1951ff3142b9a208e5e69e59 + }, + r1a0: u384 { + limb0: 0x94a7ee20add6c18015e26733, + limb1: 0xd0f2a6ab15fefff1caa7366a, + limb2: 0x9c055a1d93c3f27e46d0b3da, + limb3: 0x60f554e35125b7f5d7aac8b + }, + r1a1: u384 { + limb0: 0xd92e5b001022ee7874cbebeb, + limb1: 0x4aed0fd23b92aebc139f77db, + limb2: 0xd2bca1fe5ad39a274c9dfeec, + limb3: 0xcfab0e5b8e8d7c7a8765b15 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x13f5a17e28b8aeda870323da, + limb1: 0x337d2b7adfbf1364a8611853, + limb2: 0xa8dd9b2b05f3350a8569d92c, + limb3: 0xddc998d17c49e6381aa6256 + }, + r0a1: u384 { + limb0: 0xde207fd9d271001c6efb9576, + limb1: 0x6c856b0c104190652dfdd937, + limb2: 0x80feca357961f12e69a3a05d, + limb3: 0x2595adff1024c23c63dec73 + }, + r1a0: u384 { + limb0: 0xd7040b7ee5b45a1422495780, + limb1: 0x13f3e065ea119be3775d97ed, + limb2: 0xeecf7ac81f371c5e390f85ec, + limb3: 0x1047da85dc9dba631527134c + }, + r1a1: u384 { + limb0: 0x7017211aee3c7150478d96ee, + limb1: 0x8c7564a3a9ef6bfd96289765, + limb2: 0x6df1f2b21ce6b08419e214c, + limb3: 0xa4e778d427042d100d7ae3e + } + }, + G2Line { + r0a0: u384 { + limb0: 0x21805f763874894483dc214c, + limb1: 0x2c02b4ccd505fbbb8d8bd064, + limb2: 0xe32a1465866e01898f1f3b14, + limb3: 0x15d2f6b35415870ddc7054f2 + }, + r0a1: u384 { + limb0: 0xf6749d4bc9865ee9e261110a, + limb1: 0x81c4e72fdd8802ef73ab15ef, + limb2: 0xb89ca852d2ba8b3590cd5301, + limb3: 0x183abed5b2d1d128fa596426 + }, + r1a0: u384 { + limb0: 0xf71ebb04aab85e83aec862c0, + limb1: 0xf473b3e5a56fd96d60f8a264, + limb2: 0x3e4b66f8493911a4a00afa1e, + limb3: 0x12be1dc90541ee9c7cb4fa59 + }, + r1a1: u384 { + limb0: 0xba5f7a9ccd0748c2fa4e54c8, + limb1: 0x1640f7800984bafe7fa1a76d, + limb2: 0x48e76aab062b19911f92bcd, + limb3: 0x72cecd9e5c7c437cbbc1e4a + } + }, + G2Line { + r0a0: u384 { + limb0: 0xdf166caff55624c628e9c39d, + limb1: 0x375583a43ba61cf4f2aadb7, + limb2: 0xf0d0784be04235e91497af3a, + limb3: 0x144cf709d68b63a9939bcd7f + }, + r0a1: u384 { + limb0: 0x9b47104ec1159ac61ff360a, + limb1: 0xfa833b0d43df77cd013e21cb, + limb2: 0xcad1fb67c8db4e6c39d8bd59, + limb3: 0x10e847c87beb83adb8a5feb + }, + r1a0: u384 { + limb0: 0xb1fd17f45af8d452043abc61, + limb1: 0xcae758a71dc8e5d49f433bca, + limb2: 0xf97f2de839369b6c827e9eeb, + limb3: 0x2e3050a5cb33641e4b5f617 + }, + r1a1: u384 { + limb0: 0x71666e0e514a3e5352f26d8a, + limb1: 0x46273d30eb76103fb756a8fe, + limb2: 0x8bdb306ed674d669da0ac3b8, + limb3: 0xf6c2f57d5d282ff86ccd9a6 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x1f078a90be515d55a39025dd, + limb1: 0xa69e73a9a0f2894ad32c28d8, + limb2: 0x406d92af351a91a43b294110, + limb3: 0xab36c91eeeaabb24820b390 + }, + r0a1: u384 { + limb0: 0x873b5a72e8ea0e7d255b970a, + limb1: 0xf64973cbec18695bfc945495, + limb2: 0x533e34319846e866ad7ddd36, + limb3: 0x1029fa62305109a4d20176b9 + }, + r1a0: u384 { + limb0: 0x429cba0cb76b0c492577722a, + limb1: 0x771bc089fee5e3632dbffa1a, + limb2: 0xa7c64b6f38e532de16959d0d, + limb3: 0xf38b71fb4269dd2e038223a + }, + r1a1: u384 { + limb0: 0xddc796c5033428b0b8111c4f, + limb1: 0x60ad337fb316c52ef8de0b21, + limb2: 0x951808daa18d3ec520bd6279, + limb3: 0x3455cf600b5f6c549f38f14 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x3c9e33deec176793b8c762c5, + limb1: 0xcdd0e402436d39a6117033db, + limb2: 0x30c585d12e787c8be912d406, + limb3: 0xf298f9a8c4459a08f210e47 + }, + r0a1: u384 { + limb0: 0x170c6ad3a877e65fe91c69db, + limb1: 0xa41f211a3763ffcdb9eb1e9b, + limb2: 0xb84a114f23f1978d9ebd06a4, + limb3: 0x60bac8f5945907e791dfcda + }, + r1a0: u384 { + limb0: 0x354e5a1eec75069b04ac0541, + limb1: 0x91be6e4159dcb28c19a4e3e2, + limb2: 0xfd452118a540f6f88b01e089, + limb3: 0x12b2b6a5dda55d157e1f8b + }, + r1a1: u384 { + limb0: 0xe47f5498f54067daeffa00b8, + limb1: 0xbccfe6edd60b7ef921ce57a1, + limb2: 0xd917099499398bfacccaba05, + limb3: 0xbb67b42bd655fa485081a90 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x8deb02d48f2ee3be7ae899ed, + limb1: 0x4b66f01a40c86e83fded6847, + limb2: 0x9c08bb4fe0abcaefc921a40, + limb3: 0x8bda1d762c986632aeaca1e + }, + r0a1: u384 { + limb0: 0x72be08cacb4795f5ddd8497f, + limb1: 0xfaddee2a55b5154b35e26966, + limb2: 0x7c67f5884f061f219cb8ff55, + limb3: 0x6d4fe75b0153bdec12dba82 + }, + r1a0: u384 { + limb0: 0xc235fffbfefdf8e9ef54d2bc, + limb1: 0x6581ebd151a1e73c53b163cb, + limb2: 0xf60ffd0dd3608c742fba7902, + limb3: 0xe9437af3be8b35cbae1f171 + }, + r1a1: u384 { + limb0: 0xdb98cff46b3033365ae5b731, + limb1: 0x19f3ec2adf9517d4533cdf7c, + limb2: 0xa60fbca3376090bf8f17f4b9, + limb3: 0x169bff5211482ee5e64f50ae + } + }, + G2Line { + r0a0: u384 { + limb0: 0x2dac7db08633bccae086b486, + limb1: 0x89b8e12695d31ec21d7bc0f0, + limb2: 0xb6b895ef82cd3e31f6f0cc3f, + limb3: 0x2785eedc1bcd70ba4ebd308 + }, + r0a1: u384 { + limb0: 0x8a0217a58db8f5cb124445ec, + limb1: 0xae392df0fd76493bd2ded923, + limb2: 0x73881097a5c82a443ee9e130, + limb3: 0x145337977ac0a11a17f3345 + }, + r1a0: u384 { + limb0: 0x82060ee8ae4f3cb6db6ad231, + limb1: 0x90e8ec63f2e39f1218f21605, + limb2: 0x4ff00df2e2cc6da42f40ca0b, + limb3: 0x96b5a0e4cf36d245f2a2213 + }, + r1a1: u384 { + limb0: 0x183bfac0d6d302cda44cc090, + limb1: 0xb8bab9cdf785cfc48b82cde3, + limb2: 0x2b99c1ff7e44f0267431fbc2, + limb3: 0x9253c3d3a7875099bb7116b + } + }, + G2Line { + r0a0: u384 { + limb0: 0x89eec90cedffb5559d9f7cd6, + limb1: 0x838145c7842da8419fcaba0e, + limb2: 0xa322ce58631513aed92ce0df, + limb3: 0x5a79df85b0a96adf6e2dab8 + }, + r0a1: u384 { + limb0: 0xf36133a552f9211634fe2feb, + limb1: 0x712f911d31ea73387b467687, + limb2: 0xfb3d98acbbe375c161f9d2a8, + limb3: 0x11b7c924610a8268c34b8259 + }, + r1a0: u384 { + limb0: 0x50e7cae27aa8b11d0d2bfe43, + limb1: 0xf88979ed0a59e7daa98895c9, + limb2: 0xdf00ec512e87f5862a699c22, + limb3: 0xcad7fd28c40cc541a820fe4 + }, + r1a1: u384 { + limb0: 0x936b0157ffd80fabb32930f9, + limb1: 0xc6bffa14bca99e467c671b75, + limb2: 0x609410c23cb1d2ce4e5e9242, + limb3: 0x5aeec94c1d7d2fb257ce4f7 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xc41d067c71069998cf8843d1, + limb1: 0xb14da36d1c97315bd61ba35, + limb2: 0x8aa0d451828d59a5f72d09dd, + limb3: 0x6032c39bd848710bcb60e49 + }, + r0a1: u384 { + limb0: 0xed46bd973c771a1b363a7d4c, + limb1: 0xf133793366e26684ef2f32b3, + limb2: 0x12ff177280c137134c3f25c4, + limb3: 0x127cf801e7f2dd085ba1a751 + }, + r1a0: u384 { + limb0: 0xdc817a66a6c7d907bae27871, + limb1: 0x7ba4fed3737fceac11ec899b, + limb2: 0x90e031e803e3d6cbe2868427, + limb3: 0x12ea6c6e770758121970dfd + }, + r1a1: u384 { + limb0: 0x70cc7c1f3299456ae1e20184, + limb1: 0xb40d30be5118767fa201dfec, + limb2: 0xccc12af1cb317ea89224e94a, + limb3: 0xdab488f3ca14571f8255bf5 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xa05df784a5a683833d2e1464, + limb1: 0x544aef13d7757e76ac4a6a2c, + limb2: 0x337b308d7d37a5e715e2c6a7, + limb3: 0x1971f0b4a71e609b35922e78 + }, + r0a1: u384 { + limb0: 0x9afd8643829c2749745e919d, + limb1: 0x3fe5162dcc95efeedb645acb, + limb2: 0x771a45a92c45f43bb070b7fd, + limb3: 0x503aa962b29d72a5d9f6cf2 + }, + r1a0: u384 { + limb0: 0x8e80c44f884a20fe7070ea42, + limb1: 0x78c55b9104f9b5b599cf0cf7, + limb2: 0x6aa9312bbcf5dad8ca58d47c, + limb3: 0xa42156c0b189a8b23065b2c + }, + r1a1: u384 { + limb0: 0x507ea5597266a41fa17c0e3e, + limb1: 0x61ca6c9ff959cacbd2e0502f, + limb2: 0xe921d3d10d8336d32c718050, + limb3: 0x15bd96df3160aaf601255ae2 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x5e4b2d8014672689adf74c5e, + limb1: 0xa727aa7b0714aee11ce04e22, + limb2: 0x2b8081578ba7e36449332477, + limb3: 0x136517c5cbf60d7fd893217d + }, + r0a1: u384 { + limb0: 0x1e6b6dce21e6c8fbc8c3059, + limb1: 0xd40eaed17a285915e6dd5328, + limb2: 0x84bb3dc7596ffeecac6c017c, + limb3: 0xe145b9da771dcb825de00b8 + }, + r1a0: u384 { + limb0: 0x73b866053fe5eda748e0cabb, + limb1: 0x402fac191721abee446bc895, + limb2: 0x4b03c3a6b6268986ca81d9ac, + limb3: 0x6b4c9aac6eed89d9f0a6121 + }, + r1a1: u384 { + limb0: 0x2af39075f96b16e132587e7, + limb1: 0x13bcad0b04e3dd70f7c5f56, + limb2: 0xda8eba78634610f509f07778, + limb3: 0x110e70b034d243106e204662 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xbb42fc51b2f0d50a3d7a6796, + limb1: 0xfcbc9d2df3136cbd1a372ac4, + limb2: 0xea313e60d4b8240679b0175e, + limb3: 0x1657a4b33e1400ef6e296282 + }, + r0a1: u384 { + limb0: 0xaf91b402ecc6cf1a742796cf, + limb1: 0xab44b72c1fc2f89b5eaa0345, + limb2: 0x9f6a20404576105e15a4930c, + limb3: 0x10992497f5f8bf4451121322 + }, + r1a0: u384 { + limb0: 0xd9355bfe72d92c6a0950eafd, + limb1: 0x89de0bfbfd06c9911cb2d6fb, + limb2: 0xe2092d1e99ab65a7a33ba1cd, + limb3: 0x1c317a68eeef4d833e396de + }, + r1a1: u384 { + limb0: 0x631d3efa10e591b7ebcb8dbc, + limb1: 0x6a4a0815d19cf339e4663ba9, + limb2: 0xe2fb7d9878d26c7c97299a01, + limb3: 0x4c4dc455aad226b744ebdd4 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x656bbea0391d35835dc24b51, + limb1: 0x3d5a46760e1d5b5be2d560bb, + limb2: 0x8ab4befe76903930bf03b6cc, + limb3: 0xde3dfb225e924a4e1dd60a6 + }, + r0a1: u384 { + limb0: 0xbf76b6d5dcffe10f806efc9c, + limb1: 0x89c3bf595b72110cd64c7807, + limb2: 0xad1b9df71cca0f160ddb2c6a, + limb3: 0xe1ae8d30b5cac8a9a485f95 + }, + r1a0: u384 { + limb0: 0xfcef3581dc552b239364bb18, + limb1: 0x1785b2ccd39c6ea191ba4ad7, + limb2: 0xb26676ceebabd25d429a9122, + limb3: 0x20c29df3088771981853b6e + }, + r1a1: u384 { + limb0: 0xe1d699d9ac66a9464fbdc974, + limb1: 0xd53858123c2581584cab83ef, + limb2: 0x8e59c936d52fd331132acf92, + limb3: 0x42a7ceaf3c3cc116eb1a41a + } + }, + G2Line { + r0a0: u384 { + limb0: 0xe51e461db9c85f42519fea6, + limb1: 0x234a9695204bd44f55ea4de6, + limb2: 0xc8d34c6b4580edfc55e023b1, + limb3: 0x16691c1bdf57ba041abb3d97 + }, + r0a1: u384 { + limb0: 0xa81022cb0b3b0c523ae71819, + limb1: 0x47f7df16fff0877b21676607, + limb2: 0xdee4fe1d3c64b3fedec56326, + limb3: 0xcfbf5ccb325675b1a3becef + }, + r1a0: u384 { + limb0: 0x6d42b9d9e765f92b0817551, + limb1: 0x352adc09dd7760a5f4208a1e, + limb2: 0x5397846e3fff77f500da6dbc, + limb3: 0xe26d685c4365e342109d0ba + }, + r1a1: u384 { + limb0: 0x9bc1051782d84793806d878b, + limb1: 0x1642edf27f040ad57feb6f89, + limb2: 0x11a5d3523a88580869d28ca2, + limb3: 0xd22ff50c5a9bd729115a889 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x1974fc785431be1e90b76cf1, + limb1: 0x5523616ad31f45b5acbb41f0, + limb2: 0x4db84aa19ed0d09fdfd72a39, + limb3: 0x4bee7a1546e6a96b8c65312 + }, + r0a1: u384 { + limb0: 0x1fff8fc0e33c70b81adce7d, + limb1: 0x5503816c20ef23cb62024c84, + limb2: 0x1d58103be6d430043405b3ef, + limb3: 0x107fb3faa9b9af026c550cd7 + }, + r1a0: u384 { + limb0: 0xed84d2bc957cddd0e6e4ad25, + limb1: 0x1800d9d9c9bdeeb05cada676, + limb2: 0x6bc88f0ada5bbcfb48988f0b, + limb3: 0x177faefe6e97b317f26d47c2 + }, + r1a1: u384 { + limb0: 0xe487165be396059ee48112a2, + limb1: 0x57fae5a95d9b810b370239e, + limb2: 0x9959f70caa80a4c337de8fdf, + limb3: 0x744e597435d3317bd2d3cee + } + }, + G2Line { + r0a0: u384 { + limb0: 0x30d36077b6d0262e218111c1, + limb1: 0xc74774ca1af660eaed4d8329, + limb2: 0x6448cecfde912a7d2029dbc, + limb3: 0xe743528ce0c94e1a76f2f60 + }, + r0a1: u384 { + limb0: 0xe1f8a574cee0dad622d6fead, + limb1: 0xcd681358d077b827cc148be2, + limb2: 0xc8fb346621601764fa91b40a, + limb3: 0x133d21c52017365921207d63 + }, + r1a0: u384 { + limb0: 0x5cb088f57e1e3f6a62571b37, + limb1: 0x4089cdf0fb67a7b1d79838b3, + limb2: 0x62401a2e57abb0652e0fee81, + limb3: 0xcc83c46ac38241e1c33aca2 + }, + r1a1: u384 { + limb0: 0xfd94f04ec006d63b4825ecfa, + limb1: 0x96ef1f9240c32fdc393b81e2, + limb2: 0x6d46c2685a1a1c50e84c8b24, + limb3: 0x1528bf72bee83f2c80884dd2 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xf1675d98caa0e86774bc637, + limb1: 0x601f3b88148d94ab340ad0d7, + limb2: 0x38be976c910e6b1d767b2184, + limb3: 0x3e03977cdee4d24405e656d + }, + r0a1: u384 { + limb0: 0xe1a8086a67acf571c0af95cf, + limb1: 0x1eda39e1440a2e311c78ae41, + limb2: 0x3bacbf4628f20f0353dc2a71, + limb3: 0x12bbfc96114eb5f664d2f89c + }, + r1a0: u384 { + limb0: 0x301cba8607d6747f45a6ac34, + limb1: 0xe736ba1686c2c9873cf10893, + limb2: 0xa0aa0fae3c9f8cab4f768c4, + limb3: 0x15a9608ffbe07f61ed31b819 + }, + r1a1: u384 { + limb0: 0x89bef3c7071d9d77cfc34894, + limb1: 0xb492c854b864451bd42b6f8d, + limb2: 0x90d08dba8607ae67e7ffe8f2, + limb3: 0x3df2c581fd145f7d0c76401 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x8f8bf2310745715d8e60675, + limb1: 0xe7983befc104f7bd4886ad3a, + limb2: 0xd6b5d3a93563b2103c29cec1, + limb3: 0x1902b1e10713c8d95829b014 + }, + r0a1: u384 { + limb0: 0x392c934ad398e9471a2a3e6f, + limb1: 0xc81c0dc22eff61dca36ea27f, + limb2: 0x4605027ef09f9b7d03fcc1c2, + limb3: 0x142c2105c569b0e7aee457f1 + }, + r1a0: u384 { + limb0: 0x86fc12d4ddb34349e58e0713, + limb1: 0x9a132e3db41060771e480d9f, + limb2: 0x6e00f3b7a9cbdf6ba01f3694, + limb3: 0xf3f4843686de973131d67ee + }, + r1a1: u384 { + limb0: 0xf7b6328930ed21138fcd8f92, + limb1: 0x354fd9f9ec8f828426279c4c, + limb2: 0x3df938a725947d029e1edf6f, + limb3: 0x1143440784148d84b5ae0952 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x186d09647ff0bba5d26ed28e, + limb1: 0x623c8f44caa6f18538e106b2, + limb2: 0x6ee87df7083a561d754b41d6, + limb3: 0x8a8a90d75fab6a61d0509a1 + }, + r0a1: u384 { + limb0: 0x6adbd952167baf9618d42d4f, + limb1: 0x321d82100a434b5583df9a0, + limb2: 0x24f6e8a30ab01f51c1f581b1, + limb3: 0x3fbeeb4073b163b3a283631 + }, + r1a0: u384 { + limb0: 0x3cbe311d6bab02eedeee8686, + limb1: 0xa954bca129b7bbed1f638f3e, + limb2: 0x256baa5a7b0901b1c39a2060, + limb3: 0xd44f3bb3b9ac2f6050e276 + }, + r1a1: u384 { + limb0: 0xbc701985313f4fd60a02502a, + limb1: 0x879d4ed1464b95cc93907b88, + limb2: 0x95c12c7e24be41f785419bee, + limb3: 0x8e3562c02b89b593503d443 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x8acd42eff277e12a1c665cd8, + limb1: 0xc8dd9dfb56ea54ca5c9d26e6, + limb2: 0x803b24ff12a9cd7524a26b87, + limb3: 0x27b1b3c904791e3fa942dcd + }, + r0a1: u384 { + limb0: 0x7a880435688221e820d4164e, + limb1: 0x9754d630e027f9217dd0fba6, + limb2: 0xee6cbf6da2000115b0cca0d8, + limb3: 0x162f5c264c2d2728aaa1f652 + }, + r1a0: u384 { + limb0: 0x314a0d54f7db63dcd3d6c0e0, + limb1: 0x793c614f53a688375ca369e8, + limb2: 0x296c4ccd5f785e294abeb492, + limb3: 0x20d58632925a8df2d3d48bd + }, + r1a1: u384 { + limb0: 0x82c581e26e2e612aceaca787, + limb1: 0xe02d73cc25449c92dfd7f088, + limb2: 0x732270a5ec065ff678b3666e, + limb3: 0x17e813008da019a1fab544c + } + }, + G2Line { + r0a0: u384 { + limb0: 0x272c29aa11aed8e43cc6141d, + limb1: 0x71ace08186410aa341601ace, + limb2: 0xb9a9aa2f3050b27084ffbc22, + limb3: 0xcbec164f80a90014457abc4 + }, + r0a1: u384 { + limb0: 0x84565ab9fffcd0062808ee35, + limb1: 0xef87eb1f3b09214ee1c6bcf7, + limb2: 0x1ac3de549632346de8521585, + limb3: 0x302f3ebfd6939b7a5be7a5 + }, + r1a0: u384 { + limb0: 0x9615b19b27deb1c37635e038, + limb1: 0x71949c2c6bb3f43004b870d9, + limb2: 0x1795921be995a5d68845a590, + limb3: 0x17c275a0f8dd134ff6e6ab1e + }, + r1a1: u384 { + limb0: 0x8b1d7f267653c440de637b02, + limb1: 0x3a5e2de261d557e994157f3c, + limb2: 0x35f5a3781402a1227675829f, + limb3: 0x18c4e5eb81e38ada34f8ab67 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x4a074239eac7dc93b8113ddd, + limb1: 0x64192efc9a09299ad173b34e, + limb2: 0x3e86b7943ceda2cc678e6719, + limb3: 0x13a3cf500109646aac4d69e3 + }, + r0a1: u384 { + limb0: 0x89c20af4b5a694d4d6d9d45d, + limb1: 0x76071bd0d45623a4cfe9647, + limb2: 0xbaeda04445ec73fe1fd859d6, + limb3: 0x12f734fc3463dc7adb90dccb + }, + r1a0: u384 { + limb0: 0xa12928a1d5d6408853a05ae7, + limb1: 0xa8fc3f1aa38f3d6554357b31, + limb2: 0xbb5e7127cb9669d52daff069, + limb3: 0x525a9e909f39cb2e32cb71a + }, + r1a1: u384 { + limb0: 0x2bf733d3a23d1446da39720e, + limb1: 0x69c363f32dc0ed3a22acc728, + limb2: 0x3eb64a364ee2cb63222dc046, + limb3: 0x1e78c4855ad25e4e08ba1eb + } + }, + G2Line { + r0a0: u384 { + limb0: 0x7116c638544720919ba1141f, + limb1: 0x38d3486b5a4d7d2b1cc7a81, + limb2: 0x9b0ce563be273a4ed3481a1d, + limb3: 0x373ac3e05382518aa76323c + }, + r0a1: u384 { + limb0: 0xf667b74f8f4e3f484c4ae08b, + limb1: 0x2206d95b2b7a7ca7e2aecdc2, + limb2: 0x64ca11d3eb4448d39f8e7009, + limb3: 0x2585d7ccdfb9e2246f24d05 + }, + r1a0: u384 { + limb0: 0xf03edce3835efea888f2bd2a, + limb1: 0x992d9468044e686d3d07216d, + limb2: 0x98d781d756b874d0bd7a7451, + limb3: 0xe44d0964d322c8cb9cbcf18 + }, + r1a1: u384 { + limb0: 0x6fc3182d07a38a7f0fca843b, + limb1: 0x551df1a531a45713e9e8c1aa, + limb2: 0xde4e92d1f38c48c0f9587009, + limb3: 0x1072fb6b01d871f8150e2fb1 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x1ed40e3c2cfcc055cd4958d6, + limb1: 0xd1453a4587d6c2ca2341043e, + limb2: 0xf79c2172e21b91ba79a5ea2d, + limb3: 0x65c82633f9d4d20c07f6ad4 + }, + r0a1: u384 { + limb0: 0xc8398341fc07277f183c17d5, + limb1: 0x86bc2e62775af5eae61d9aa, + limb2: 0x403276e7635ed1cd34473d3d, + limb3: 0x18a18bd0be954bbff600c7c1 + }, + r1a0: u384 { + limb0: 0x8b17fbda26b7133b0600c51e, + limb1: 0x48147de60df80344b55d8fb8, + limb2: 0xa0e018e36cfa14e2a39e57fe, + limb3: 0x70aed2d475ad180844d7587 + }, + r1a1: u384 { + limb0: 0xf1d8e65deba9a3605b50946b, + limb1: 0x3677c5769dea1762e0a3a25d, + limb2: 0x5d4399ba6a9742e8f2aa1928, + limb3: 0x2d57160d6c66d1e0c2f0c0 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x8477b2ca00b2aeca6e32a3c2, + limb1: 0xc6f29b461233bd0ebc643442, + limb2: 0x84af7efb348b61e615b2333d, + limb3: 0x1533c0ad4f3bdc8c8d26cea4 + }, + r0a1: u384 { + limb0: 0xc1c642702f7caf535b06e0f2, + limb1: 0xe5245d45b1adaa7c89f0db9c, + limb2: 0xfdaf6276d41ae24845843a0a, + limb3: 0xb6f912c27d4179d1cb5e992 + }, + r1a0: u384 { + limb0: 0x7338a41d8d41ba28d96db37b, + limb1: 0x51a10fe0cfd8c6d045839897, + limb2: 0xdb73279246e7073586ebb14, + limb3: 0x180e0a6b2de7e0540e582783 + }, + r1a1: u384 { + limb0: 0x4d8f0878c0af851ea8d0cff5, + limb1: 0xe24443b84e3d452bac74c32f, + limb2: 0x4e4f3f08f29048e7d791c0, + limb3: 0x107fba05f68214c93b0d00d3 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xe6882416d7bc0be138e4eeb2, + limb1: 0x1ffc8c27a2046327376e250, + limb2: 0xf96a7955cf8a3345e89477c1, + limb3: 0x31ae02e34d7d21957899dbe + }, + r0a1: u384 { + limb0: 0x148232d34a8da37b7adc99a7, + limb1: 0xd0a0095db108dfd24e92848f, + limb2: 0x89fb49e1a36591a6b189f964, + limb3: 0x1900bee131450e7d7a914ea4 + }, + r1a0: u384 { + limb0: 0x97018429f16d24bc1e7f8af0, + limb1: 0x1f68aaf8291a6decfb708b43, + limb2: 0x1f700e88b537bffef39907e4, + limb3: 0x9cb633f82c6e595f1785e5e + }, + r1a1: u384 { + limb0: 0xd8d9d3a12a0dd7b129ffda0, + limb1: 0x7a94e9da792505fe4fbdb0da, + limb2: 0xf16eaac379266d5a4210e839, + limb3: 0xc24197c1ceaa3dd3de58b21 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x3e3cc1b08d8d1fda723658bb, + limb1: 0x1cf952b752fb9ef1e82f5094, + limb2: 0xcd52c2cfed361eab29f2026, + limb3: 0x59d1335947ab746801c0537 + }, + r0a1: u384 { + limb0: 0x34f187a454a321b866885648, + limb1: 0x26461aa4e35660f0dce08465, + limb2: 0x7540c65dddc34d56adebea12, + limb3: 0x1417edadd46132f1155c1f + }, + r1a0: u384 { + limb0: 0x716255bec8b8a867659f8ec1, + limb1: 0x728375c8a3a566ce58f184ab, + limb2: 0xf3c4e74ba75e0f526ebea027, + limb3: 0x130e1557b595456ac14c74b + }, + r1a1: u384 { + limb0: 0x956347dad0355d5e6b5af3c4, + limb1: 0xef43db3b9c396c251944db86, + limb2: 0x6ee505074759d3fe9876542d, + limb3: 0x4097c38f547306cd4f3b276 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x6231a3597b09b6d5fda5c712, + limb1: 0x3f3bd12ca9ef48ef6199a7f4, + limb2: 0x6883383b5a445ca79fc407ee, + limb3: 0x141accc8970ace156fe95a36 + }, + r0a1: u384 { + limb0: 0xe0c805067330b20430c585c8, + limb1: 0x8ff3e0c3028ea8f24ee6fb30, + limb2: 0xa368fc9a21efabd91ace37d9, + limb3: 0x18b35a8fd65ba4cbd734a0ee + }, + r1a0: u384 { + limb0: 0xf4e1f73d2ed7ccded6c419de, + limb1: 0xf379cd28811f89aeea7aee67, + limb2: 0x727c64c0e714ab6ea82391e8, + limb3: 0xf454aa00efef9460f382b49 + }, + r1a1: u384 { + limb0: 0x952793660f1fe4300657022a, + limb1: 0xe8fa6c2b1aa542384940d1ec, + limb2: 0x5a1f19c729b4b225b1501e31, + limb3: 0xa5b1272b68436f9433d112f + } + }, + G2Line { + r0a0: u384 { + limb0: 0x990dd2f78bf76d63c8a1579d, + limb1: 0x324c14f20ab56d3dc480653d, + limb2: 0x21bbedea5a0b817b568c1995, + limb3: 0x127c86bb9f80d6468a5a0787 + }, + r0a1: u384 { + limb0: 0x5b66a3f1affc43619038b84d, + limb1: 0xd61e9a91a30e1c4606116992, + limb2: 0x8a3bb65c955e0ff1e2749335, + limb3: 0x18094793f6e93a6fbbe88c78 + }, + r1a0: u384 { + limb0: 0xf16deb47fddb712ce639140, + limb1: 0x6ce4afbf91551ea8bf91543e, + limb2: 0x1576ceb94ed691afe037a797, + limb3: 0x89f45701d0959ae8869f16 + }, + r1a1: u384 { + limb0: 0xd1d903d8caaa0032b50eabbb, + limb1: 0x4f16d1eedd24943ef87959c4, + limb2: 0xc2729c35e8f641933cc2b080, + limb3: 0x12a0bc7d5fef85e9964e5dd + } + }, + G2Line { + r0a0: u384 { + limb0: 0x7ee6a5f3ce669de80b52ba42, + limb1: 0xa7d66db543d3c6a626f79dea, + limb2: 0x135c684f9ac0e0a34315e044, + limb3: 0xaaafef3c4298542248b3a58 + }, + r0a1: u384 { + limb0: 0xe0b267ea1f8e8dc2b83d62e, + limb1: 0xabac56946f0699334fa765e6, + limb2: 0xee0060a937926e9b6d6adb90, + limb3: 0x13d96385b510deff2f4d1d32 + }, + r1a0: u384 { + limb0: 0x1271c3349afe8fbfd4d7ee54, + limb1: 0xc4df31a1a0ae89c5728ee819, + limb2: 0xa0de891b771af1ba8a67f8db, + limb3: 0xf69200f56879e50a92ecd6e + }, + r1a1: u384 { + limb0: 0x3260bde1e37542b8b8465e10, + limb1: 0x7c3420aa9e48318a6606ee07, + limb2: 0x126b5e1ded963ffbb6adb4e2, + limb3: 0x18d1f7ae28741bb590bb39a6 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x269fe662be1952669b367916, + limb1: 0x444dc78864cd61df2552517c, + limb2: 0x28be12e26f4b32f0652ab84d, + limb3: 0x19a30428e98bf9b0a2c79ff7 + }, + r0a1: u384 { + limb0: 0x21df9689e2fe058639581b7d, + limb1: 0x12a80b9a201864b6f46ebab1, + limb2: 0xd09d200c1fe4354e796b9b48, + limb3: 0x6bec03fbfbca091da930b62 + }, + r1a0: u384 { + limb0: 0x28188947a47cf18c9d40e8da, + limb1: 0x7bcabfacb5b01ab3628aaff2, + limb2: 0x76a7b58adfbb924378e8220d, + limb3: 0x89da3830e68cf0f2c7a55ed + }, + r1a1: u384 { + limb0: 0x16d6797ce84cbee04811bb4f, + limb1: 0xeec191427178e5b1c9c7dbb2, + limb2: 0xe59d267e616c978d17fd98d0, + limb3: 0xd301c0973bbf180e6fc4134 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x95db0469c00d953ee476c048, + limb1: 0xa412df73ae5febbec296a5fb, + limb2: 0x16b9fdec9340c8f3aefa561c, + limb3: 0xfc955cb99bde258d8760197 + }, + r0a1: u384 { + limb0: 0x83c7d7a804031b10c844d0cb, + limb1: 0xfb88180286d20648b40806c0, + limb2: 0x31368cfad1bcb8ef19b9d382, + limb3: 0x8fd02881a5331dfb0922a3b + }, + r1a0: u384 { + limb0: 0x2513b777e720406cfba171f4, + limb1: 0x9d9da48be5e4bae3bd3e8c84, + limb2: 0x8d75547712fc62f6f651762d, + limb3: 0x5f0f52ede58374df52c0643 + }, + r1a1: u384 { + limb0: 0x13d6b4aa8d9a46d5720e1b74, + limb1: 0x5b93ebf4000945ce87c9dcf1, + limb2: 0xffe34203a0c826e972d857bd, + limb3: 0x1870c14dc5ad5a661156fd61 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x13a8138427c111d431036213, + limb1: 0xc177e00de5b7215a863e9c0, + limb2: 0x97a203171990cbbb0e5ab2e5, + limb3: 0x8a0a3f26b8d3bcefb78c724 + }, + r0a1: u384 { + limb0: 0x9d1740ea8f388b69c175f646, + limb1: 0xbf6f5d96d616051ae3572d4, + limb2: 0x9bc542122a140e5461a88c52, + limb3: 0x510159112f2d409afcdecdf + }, + r1a0: u384 { + limb0: 0xf6335307702c1329032a46bc, + limb1: 0xf975ad40eedeac981c916520, + limb2: 0xc367b7993d6243a4984974d2, + limb3: 0x54b5cdb776381cc145be730 + }, + r1a1: u384 { + limb0: 0x29d26ba47472791689263678, + limb1: 0x6f7b1f34b002954f5506eae0, + limb2: 0x2f9ecd635cd4d5f6e7f08ab7, + limb3: 0xd547c2cb31b79da87b93b04 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x31f476324f857ca9daa71d3f, + limb1: 0x5b64b681867d0f5505b9f139, + limb2: 0xb89e509fc5decaef9cb221f1, + limb3: 0x5b8f08ef767ca4cf5f36622 + }, + r0a1: u384 { + limb0: 0x8f44b24a23750c8f0fa6270d, + limb1: 0x554f99004f5b1f2a21b02609, + limb2: 0x3710c6daa7cac50a8ca6de8, + limb3: 0xa3b4aea7c32a8fc4d9a662b + }, + r1a0: u384 { + limb0: 0x93f0fbf4c4d931c3a733902b, + limb1: 0x3a038220fa2da3a7087689cd, + limb2: 0x5bc677d1583979bda5797f17, + limb3: 0x11996e8759ccb1bda7042160 + }, + r1a1: u384 { + limb0: 0x1ee1d1db6f033786016fd46, + limb1: 0x2d4942546551a7b5afb1ee11, + limb2: 0x5c0b006bc71d7e27359f5f02, + limb3: 0x35c97a7e460075f4d915117 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x7a6d6eabfb0034d1a702f683, + limb1: 0x7d0e2455c9a35664ebcfb47b, + limb2: 0x32cbd0245fbdf1e7636a4217, + limb3: 0x19c09fc88eb1b1a3d18741a8 + }, + r0a1: u384 { + limb0: 0x533b4770f929349a30d265d1, + limb1: 0x2a2bd55c9677f8858218607, + limb2: 0xfdc3daccd568a7f098f996b7, + limb3: 0xda029aea876b619425b5a9b + }, + r1a0: u384 { + limb0: 0xe5b827de5b5a8d55c3f84090, + limb1: 0xd80c5371f403010197d4f105, + limb2: 0xe577025df13d2871b00bc8dc, + limb3: 0x16414390859fdc9dba5dbd65 + }, + r1a1: u384 { + limb0: 0xaa1076a6910862d36bbb1a19, + limb1: 0xcd4b0a7e1356a4c6467e7843, + limb2: 0x88f035fb25750a88b3937cc0, + limb3: 0x92167f2a0715c9e9d74c7a9 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x813cf8d46ec722731cb2e790, + limb1: 0x3ae401e3a2c43950dd3e14a5, + limb2: 0x7f1e2595a7bf3cb9644dc3a2, + limb3: 0x9a64184b516425353d3342b + }, + r0a1: u384 { + limb0: 0x1be4ad4c913b7f23ef8afc45, + limb1: 0x4b9c5ee3da9ae172d5612c39, + limb2: 0x362a12402d4cd3c50c5a5bc1, + limb3: 0xaf426e78303a8cf5a43520e + }, + r1a0: u384 { + limb0: 0x1a1fbd631479e96bc85c9b39, + limb1: 0x755e043e52470551dc47fa77, + limb2: 0x2fd80441adcf386b79dfadce, + limb3: 0x15cdd2f908202480bb0f56fb + }, + r1a1: u384 { + limb0: 0x493a7937f956ab6960bb1a74, + limb1: 0xec402c0b38b6cc4d5094363, + limb2: 0x3d52461743a5dfe63d2e7a33, + limb3: 0x92150697852cb2d08c3521b + } + }, + G2Line { + r0a0: u384 { + limb0: 0xb34c26f3f693dd84f80a2827, + limb1: 0x3a5bad99a295b14daa58eaf3, + limb2: 0x294c30f60635aa35b08a22d6, + limb3: 0x7b4843ff0c2694d4281b82b + }, + r0a1: u384 { + limb0: 0xf601429d3a9a15e87d6c6a9c, + limb1: 0x9ad779f2762b9393eaba8c6e, + limb2: 0x887c88bf51c15df955aac60, + limb3: 0x858d73304a934b9aae3be02 + }, + r1a0: u384 { + limb0: 0xb8b2d232a5e28fd350087039, + limb1: 0x72a42652def490cf16cc1d6d, + limb2: 0x225b45d85fa199dffd69ffd0, + limb3: 0x11aab051de4d3b03d63fd9c6 + }, + r1a1: u384 { + limb0: 0xe973e3abcfc1a8b46e3622d1, + limb1: 0x1da2831de5c376f4315553ec, + limb2: 0xbceaf398ecd71f612f704c01, + limb3: 0x3bdf213c9512ed9e6961848 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x3c31209a4897e0f66a542078, + limb1: 0xaca6cfb5457ca1adc99138fe, + limb2: 0x72bf4739ae7b1a8652c823a2, + limb3: 0xdd9144f8c45e6091a6714d7 + }, + r0a1: u384 { + limb0: 0xc8942e9d5abaeec4938f2308, + limb1: 0x30ff4bdf679bd4a2b87fa34c, + limb2: 0x21acf101ca7ff6cd9129e67a, + limb3: 0xda6ef8b0ede3a09d1a5c00b + }, + r1a0: u384 { + limb0: 0x2c5038a7eeaa757c15d205e, + limb1: 0xe9d28bbd2c18d52e1b9024f2, + limb2: 0x959d4240dbbc46a2c5bbb5b, + limb3: 0x9cd8b42cb440fc77607b954 + }, + r1a1: u384 { + limb0: 0xd35f7d36be1bf213c01aba98, + limb1: 0x655bc51b43c6394245778244, + limb2: 0xd626d74e22844c1a8e2cc950, + limb3: 0x28c4b291b492ca43266277d + } + }, + G2Line { + r0a0: u384 { + limb0: 0xde11ef8702d534dcae97f4d1, + limb1: 0xb7e1313492ee7c957d7c08b1, + limb2: 0x94685a26959aaaf145f46c06, + limb3: 0xbd77d859d62dfada48bdca9 + }, + r0a1: u384 { + limb0: 0xd50523e1ef354e160696adcb, + limb1: 0x4ae2fa0fb50e711c936a065f, + limb2: 0xaeb883cf2c5a9ad32ce94798, + limb3: 0x6cc3bf5598846ca25341da5 + }, + r1a0: u384 { + limb0: 0xcc6dd0380e5398c3264b9bbc, + limb1: 0xdfe3641a4969d3d49718e00e, + limb2: 0xd7b59b3160334de5eacebeed, + limb3: 0x35c0cdaf5e759016dec572e + }, + r1a1: u384 { + limb0: 0xc2d2dbc06bdb8ff543ebcea0, + limb1: 0xea4c9e638f95e42cea458d85, + limb2: 0x9aa2cb9c51ba076dd941d7c7, + limb3: 0x8052da2e0dd2dec3a95d9f2 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xabb764ac8036eb503e39861f, + limb1: 0x22e8fa738389a0378352e2d2, + limb2: 0xab10fb803ca53103ce99fc28, + limb3: 0x831ad8b93ffed9245877b44 + }, + r0a1: u384 { + limb0: 0xf721e83ab0eb9fa28b5d9349, + limb1: 0x71c18646ef565689efc545c0, + limb2: 0x590ec1d6f3abfbdb3f9f8b0d, + limb3: 0x17707d0e47e7a1044a4fd9c6 + }, + r1a0: u384 { + limb0: 0x16d0a838f9b0fc16504dd27, + limb1: 0x5ad87ce7ad12ae830368b776, + limb2: 0x62490899b4f397e09c44152f, + limb3: 0x15528a389da1580f43d95ade + }, + r1a1: u384 { + limb0: 0xa715dcbb03bc2faac9d64bc7, + limb1: 0xbd9b3ab159baa441a3ff56ad, + limb2: 0x257f876f487a6dab4fa17c81, + limb3: 0xecfcaeb005ca1b7f92bf862 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x84bef2ae28f4fb378ec1eeb6, + limb1: 0x1189e835406150f7fbe047cd, + limb2: 0x8d7fa056d5bff703455219b9, + limb3: 0x17b55cffc9c559918a9ffbca + }, + r0a1: u384 { + limb0: 0xbcd55d1a045238c11947faae, + limb1: 0xfddd35b7f062ea97fa82612f, + limb2: 0x73dbd0a4863e8634338c4c3, + limb3: 0xfd6b167fe3d1476b5da9dfe + }, + r1a0: u384 { + limb0: 0xbcf99cf3772f639491c9a228, + limb1: 0x1f8ca8645ecbeb98bb9ff5ae, + limb2: 0x82f62cc92f240ff8bc4fca5, + limb3: 0x6b4211c4d1b18ea0c5a5e4c + }, + r1a1: u384 { + limb0: 0xe60a226e7c7d83e720ce3f23, + limb1: 0xe357a6f93412eb508cc034c3, + limb2: 0x532ca9a4ca346dd2e0913328, + limb3: 0xae125a2c4b74ea5caf9317f + } + }, + G2Line { + r0a0: u384 { + limb0: 0x9ea0eee8a358bedf9bb306c6, + limb1: 0x27cbc0c2d576ed81b376df3a, + limb2: 0x284d8131858da400101172fe, + limb3: 0x6f01c5d4ccee41765be5896 + }, + r0a1: u384 { + limb0: 0xc9cca6ba98560a0a14f61b11, + limb1: 0xd4eef97cebdd8ef2a73732a, + limb2: 0x64b605444de34fc8002b43cd, + limb3: 0x16cb65875e7c30e951cccd8 + }, + r1a0: u384 { + limb0: 0x1202ef010c0cded8ddce59aa, + limb1: 0x7268537e1c67cc008bb9ba6a, + limb2: 0x34ab03d803da94a85a2a1f91, + limb3: 0xffbdd8dbe035b9aa6fa5cba + }, + r1a1: u384 { + limb0: 0x624339d3f2fb4299150fea00, + limb1: 0xf8999090b0c3b02d48cde0a1, + limb2: 0xb9c9ee775d38075030edfed8, + limb3: 0x4962ca75250846083ca0a66 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x5a6db269a838098829edba6d, + limb1: 0x67230edf9666dd5326fdd901, + limb2: 0x4faf83c8878cbaa298052a07, + limb3: 0x112b346339b3c5902a46ac8 + }, + r0a1: u384 { + limb0: 0x21277b8157638b119fcc31e4, + limb1: 0x58677ee1ee7f46f77ebafdd, + limb2: 0xd954201344c8653340beaf5, + limb3: 0x1540de56dfb2f896102f649f + }, + r1a0: u384 { + limb0: 0x7542a639e101035b31163743, + limb1: 0x16d5957af1c5d36ad26581ce, + limb2: 0xa42f7046622fa8f1537fcbb9, + limb3: 0x3173bcc714029b198352b15 + }, + r1a1: u384 { + limb0: 0xb1d8c4b69f2dd6531b317ba0, + limb1: 0xecfb946f37008a59694b6c1d, + limb2: 0x45a75c06aee99914e7ea7797, + limb3: 0x5a1008ab79da1541477a2bd + } + }, + G2Line { + r0a0: u384 { + limb0: 0x9c4a4d3c7bb2576aeac0337b, + limb1: 0x8b9250b2bed82359a757e126, + limb2: 0x2d7dd2e4d3d0945ac3d9cb88, + limb3: 0xa0bad126c265d46d51689b7 + }, + r0a1: u384 { + limb0: 0xf65a98dff64d2a0fc947454f, + limb1: 0xa50259b7484098611c2cb9fd, + limb2: 0x5a51b1c4671888accdca74af, + limb3: 0x133a4335f59c0259f1a3ff19 + }, + r1a0: u384 { + limb0: 0xdde88be699f516d731c68610, + limb1: 0xce004ded1806688e8e7c458a, + limb2: 0x932f3c1c8e56d4b9f19eb7e9, + limb3: 0x124f291f47d76455477102fe + }, + r1a1: u384 { + limb0: 0xa97c633609d63d754d4a2692, + limb1: 0x3c5ba5df2f9bb1cdcfb55e97, + limb2: 0x19aa69b7f4751e5e39459c7e, + limb3: 0x3f5780b2dcaccad745e1d15 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x6b810adc509554ded3ef3b95, + limb1: 0x95284597042e1ecd0726081e, + limb2: 0x120e66352bbc0746f23c9af9, + limb3: 0x14407db8291afdcc6767f0d6 + }, + r0a1: u384 { + limb0: 0x9736d40090182b75e8148929, + limb1: 0x3b4a1acb2265372a95f14a8b, + limb2: 0x688f573f43a95022122a84f8, + limb3: 0x6ee3cecdb39eeaa72352bea + }, + r1a0: u384 { + limb0: 0x86a4ae1d79fed79fda04bb3e, + limb1: 0xdbe8a4d79312a8b7bca3137, + limb2: 0xb002871665722703632ca373, + limb3: 0x6dad85068365251a3070c46 + }, + r1a1: u384 { + limb0: 0xe811cc9a481723566332af5c, + limb1: 0x5995536393d8252711fa1719, + limb2: 0x4b8d398526d9d7803e5e35d0, + limb3: 0x9c613e006352ea575d7f10c + } + }, + G2Line { + r0a0: u384 { + limb0: 0xdd3830612c58d544327ca0f0, + limb1: 0x1142cd575c788d8d19a24ba9, + limb2: 0x45ea7f0421cb2dd4e5b4ed7b, + limb3: 0xfb69c6a2cbfc9dfb9b01427 + }, + r0a1: u384 { + limb0: 0x875ab3c75d3a4e43d10b2503, + limb1: 0xf7cee1313a095fe9e31b7072, + limb2: 0xe85be88d689d67e6e9835268, + limb3: 0x10635d3a601f92ab21801ab8 + }, + r1a0: u384 { + limb0: 0x9eb9ef4ae7e0f7713d97450c, + limb1: 0x8dfc81038830750d79da8b26, + limb2: 0xc17475937901d8cadba451ca, + limb3: 0x6f9f723841ae3e1a88c34f4 + }, + r1a1: u384 { + limb0: 0x71e84e872166781dda7182bc, + limb1: 0x9dde7059d6c002a7f762da96, + limb2: 0x2b9353ca4892a788389ca0fd, + limb3: 0xd413552182113308d1bf463 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x44db5f922ec99665b26634e5, + limb1: 0xac41b74d5483c597704eaaac, + limb2: 0x550e72e8ac0309c515e3799, + limb3: 0x1952ab876a19a0773ce3962 + }, + r0a1: u384 { + limb0: 0xf574202e10923244624559cb, + limb1: 0xc0f8318a3d481320d441ef0a, + limb2: 0xde67bbfe352326e4915e12b3, + limb3: 0x961a1762c6fe08878fc48ab + }, + r1a0: u384 { + limb0: 0xf69e2ab32451ecc443146d68, + limb1: 0x2d1bd9f71192795f2433de38, + limb2: 0x32cd169947d915590eceb231, + limb3: 0x5a7c915f44cbc571061b333 + }, + r1a1: u384 { + limb0: 0x448a7247da14616d79b68e7e, + limb1: 0xec3301200e41cfe8a1eca52c, + limb2: 0xdadc3af8cfa96ac54608c965, + limb3: 0x17fe1a7c7ee57b63cc748535 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xcc1f58585e1d7b5bd45c4c1f, + limb1: 0x745110cbba12e028cd54150c, + limb2: 0x2ce6cbed2508c5d828082677, + limb3: 0x28a36f542a28f6997a811fc + }, + r0a1: u384 { + limb0: 0x541d567dcc7fbea97520cd94, + limb1: 0x65d407bf06f076619981fe2e, + limb2: 0xd583e9bfd967becef21bf75f, + limb3: 0xac2c40f46751f043fe2833b + }, + r1a0: u384 { + limb0: 0x92c58aae975c98038f79305, + limb1: 0x7d1ce0079826b8902c5d46d3, + limb2: 0xf99d7ba5cb12513a32fb5eec, + limb3: 0x7cc8363ce478f6d8f184c26 + }, + r1a1: u384 { + limb0: 0x8397c406c8e69df7b1cea699, + limb1: 0x4a543e21f4fd830fab085fcf, + limb2: 0x25a94f2ddc7a920fd1361d5b, + limb3: 0x16a2f7057acf7d7df785557d + } + }, + G2Line { + r0a0: u384 { + limb0: 0xd795ec8c32c9ebd1bf9f74d6, + limb1: 0x7f585c54a0e235a718bb6927, + limb2: 0xdbb23b0ee0a160580fc4c61d, + limb3: 0x18cc0bda792f81e333e2b374 + }, + r0a1: u384 { + limb0: 0xc46a2a7c259ebd088ce10740, + limb1: 0xe6a830b64d605c010a76076e, + limb2: 0xb1a119cfe08d1632021fc196, + limb3: 0xb9b519b9c1bb0eb41e2ce4e + }, + r1a0: u384 { + limb0: 0x345bf7846f464a931457dfde, + limb1: 0xc8fc5238edd2d7260a066bbf, + limb2: 0x2523af32173eba316f128bd7, + limb3: 0x32a68698a38598bd123d251 + }, + r1a1: u384 { + limb0: 0x2224558439f158cbcf42da7c, + limb1: 0x387b507d6f0320a9a2e44e6f, + limb2: 0xb29b2f37752d24d3fed9a8ea, + limb3: 0x168e24551680276e33346c1b + } + }, + G2Line { + r0a0: u384 { + limb0: 0xf8c9e8b4405badfa94226735, + limb1: 0xe35370c03766b0439ba9bc0c, + limb2: 0xefd8d2d0063990aea5570748, + limb3: 0x125e8f976f7536a2e85ea3cf + }, + r0a1: u384 { + limb0: 0x8f2d3d1bd687824c71ce27fa, + limb1: 0xd5946aef2f36a4cb42aee9b, + limb2: 0xce15918bb8dbd901b9685864, + limb3: 0xc0299d504b8b7bb5ff23b7f + }, + r1a0: u384 { + limb0: 0x9a63e8f36e7127f93b5fab1e, + limb1: 0x52d9ab603e72bca7b8fc5284, + limb2: 0x8f734c44e7ba040f4a30952b, + limb3: 0x1478222c63826742286f720 + }, + r1a1: u384 { + limb0: 0x57fd0e62234f512c20e97da2, + limb1: 0x876dd44c8838d26ecfad71b0, + limb2: 0x9c591e15eb6492035916a674, + limb3: 0x13830268b58006ff03775156 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xb2877a8ff989a065c386a33e, + limb1: 0x13d2429550f4e9f72e2e2cec, + limb2: 0xbcf8cd1b0cbec3511e153d8a, + limb3: 0xcd008fe35f202ded141f6f0 + }, + r0a1: u384 { + limb0: 0xcc3d9d00a942a5ab992f4ac8, + limb1: 0xf81023268498efbea7a1843f, + limb2: 0x561d9f10a4eaf5e417d1ccda, + limb3: 0x10ab00007abd04f36507cb22 + }, + r1a0: u384 { + limb0: 0x9b8b1ab2cc4aee0c67d4c474, + limb1: 0x9840dfe76cc0dc415191c5c, + limb2: 0x91cbd5473dbc72261d57d8f6, + limb3: 0xd47a27fa79ac6ddfb973c4b + }, + r1a1: u384 { + limb0: 0x827056816dae6b0f4c06657b, + limb1: 0x8112aa8d965353f81dd65054, + limb2: 0x8c1382e0bed39f3950578dc3, + limb3: 0x135456e60f547393ecee80e + } + }, + G2Line { + r0a0: u384 { + limb0: 0x5863cf017f4f31c0054a3612, + limb1: 0x5a1ef8d1d2c315dd8bc6212, + limb2: 0xe33ed175b6d1a029dda7c9aa, + limb3: 0x182115eb42220d34f08e487d + }, + r0a1: u384 { + limb0: 0xb90bfad204b39a3cbcac7b4, + limb1: 0x73b8d9e10bc6022a0994e39a, + limb2: 0x7f5daebc21a409de8913242d, + limb3: 0xfc2db9cb25d08faf7c832 + }, + r1a0: u384 { + limb0: 0x26d0221ad0d5ae39d7d33a8, + limb1: 0xbae8e0d584ccaa52aeab179, + limb2: 0x59de453ae38340185debc29f, + limb3: 0xc5a021a1d3134aa31cb39ed + }, + r1a1: u384 { + limb0: 0x7472a64d3fccc64229059166, + limb1: 0x361a6711e93f12f3d1cb0320, + limb2: 0x6bf192bb96314516f10b7449, + limb3: 0xcaf028327c4bc3f8af13387 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x9fbb07d0355fee63ff3debeb, + limb1: 0x91896030dd9d9080099fb74, + limb2: 0x26da14875766e45e86646226, + limb3: 0x107179b36f3ec30ed0344ffb + }, + r0a1: u384 { + limb0: 0x749309e43489bf57b329ac54, + limb1: 0x88c5acfe2820fe65ec92ff05, + limb2: 0xef5d77580008d71e56cfd7c2, + limb3: 0x8347995c6bfa9cbd21c0831 + }, + r1a0: u384 { + limb0: 0x3348804de4e8c0987c6280f3, + limb1: 0xcfc8dd305e856fb4f80eda08, + limb2: 0xb7eda62f28c44f9b55da9809, + limb3: 0x6c1e0756ca916fe6d0f1453 + }, + r1a1: u384 { + limb0: 0xecb36186ff6abf0ccb74caa, + limb1: 0xee68730c0709c13875980d99, + limb2: 0xdfb34758f87146c601b8e8df, + limb3: 0x1179b833f2d1129d7dd26307 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xd53473f5ac7b5e99de412ea4, + limb1: 0xf6c216059e7a2a6b1a09d23c, + limb2: 0x5de59d8956f5a84da299063e, + limb3: 0x159ff2806d40ff15099d5204 + }, + r0a1: u384 { + limb0: 0xfdccb0d7c9716c23df3ced8f, + limb1: 0x14e4ca22ebdbc559a20177, + limb2: 0x5b60b25f325eb68e4cbd45d, + limb3: 0x69a7d5ac5a38cce584e0b0f + }, + r1a0: u384 { + limb0: 0x903bac45b703185c327d9669, + limb1: 0xe524dad4130c677c5a3b0f31, + limb2: 0x11518ec180b31fd2f516e8b1, + limb3: 0x29448dd80ce3c75c8b0d685 + }, + r1a1: u384 { + limb0: 0x134286c732f95142935a2a98, + limb1: 0xc493200ca6cd119550bafdd3, + limb2: 0x7008cba4cae32054d22edea4, + limb3: 0x15da5ffa50e36869f0f2ac43 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x699dddd0ce8eee874e7798d1, + limb1: 0x5c3572d1a0e33576c5f95af6, + limb2: 0x71a239e87768b6642c64c2d5, + limb3: 0x193a4a988589350e15df6be4 + }, + r0a1: u384 { + limb0: 0xa05a3143096e2700aaf1ae18, + limb1: 0xdaee1baed61a3dc26f6005fc, + limb2: 0xed7d52756e553a1adfd2b266, + limb3: 0x1839757d13d8b73a5c23e083 + }, + r1a0: u384 { + limb0: 0x94b6d2f8ced6ba40bea83ca, + limb1: 0xfe22edaeb3c651a53c333676, + limb2: 0xb7a1df3d2dcc34ad47dfbaf0, + limb3: 0x81b823ad97ad3e98bcb93c8 + }, + r1a1: u384 { + limb0: 0xef6f0e083b916a69a01c63e9, + limb1: 0x8aedc8c1d6429b10db98ac62, + limb2: 0xe6834dcabb9dccf40dbf34db, + limb3: 0x15b856909992c27268ce5b40 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x5edf9450f71e9104f1c374e9, + limb1: 0xcfd112580006deba5077fd8a, + limb2: 0x289c80bcf75761bc030bda9d, + limb3: 0x142182d337d4bdd0a9dc0152 + }, + r0a1: u384 { + limb0: 0xe3f1affdcbbd3809a6881f8e, + limb1: 0x55f40359611c687f96c91dbe, + limb2: 0xb90435a9e7260873c34a0cd4, + limb3: 0x113f465ca312058e0cd541d6 + }, + r1a0: u384 { + limb0: 0x85f3a8c5d4928087f1ef8229, + limb1: 0x62e48188da4d79f1a88f24ba, + limb2: 0x58691c7e87e7ecb6e855a469, + limb3: 0x25bacfd7256f159ca3eb0e5 + }, + r1a1: u384 { + limb0: 0xfc830160c50a4b17a2dde63b, + limb1: 0x1bf46813a25e8e58ff928d53, + limb2: 0xe63b74e85e2032c28808627d, + limb3: 0x9e218f143196d00fadb36c6 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x4f15d4ea3546d4dd322abb1, + limb1: 0x46cffe5c562a996207d85447, + limb2: 0x127c1b2c8327db270f3fc752, + limb3: 0x5b1382a51a78623e84b171c + }, + r0a1: u384 { + limb0: 0x8dbc701d130e40ed21a9da2c, + limb1: 0xadd725634588d75b24dd8c16, + limb2: 0x80337504d4d5f8357c9b9979, + limb3: 0x9c23058c09980827954110a + }, + r1a0: u384 { + limb0: 0xe1d3592b03a3a53ee550de4a, + limb1: 0x34de8376defeb78769a53926, + limb2: 0x4a37ac77bdc2eb742a373cf1, + limb3: 0x152f467c23ef37b4010839bf + }, + r1a1: u384 { + limb0: 0xcb4d3b94794186d8bfb77400, + limb1: 0x7fd7599edba1d571d111a2d0, + limb2: 0x3a0264b8ec2890555793b361, + limb3: 0x17f63a07328a47cdf24b7754 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x2639eca99f5b1f6e6d095faa, + limb1: 0x7322d2c5cd33e33d6fd2e0ca, + limb2: 0x1c7bca0054ff60c0db156676, + limb3: 0x10933118bcf1940615957a6c + }, + r0a1: u384 { + limb0: 0x43e0d74cf14359d83cc60326, + limb1: 0x3d49af8c8914a76283667614, + limb2: 0xc090bf9a071c2af83528b361, + limb3: 0x14ef91f0b47d2bf1313ba159 + }, + r1a0: u384 { + limb0: 0xe45466ca7f8b6f5920570127, + limb1: 0x1554654b09b57871c2ba8a9b, + limb2: 0xf66b8bb3a005585c18db86b0, + limb3: 0xd28c63f8635e2ca59c7dc45 + }, + r1a1: u384 { + limb0: 0xdc559ff81728e932b3c79d12, + limb1: 0xec4893ef0a2c9367a4d736d6, + limb2: 0x8b0a21bcded904e222dbf14b, + limb3: 0x8c51553f23145b85ca33fbe + } + }, + G2Line { + r0a0: u384 { + limb0: 0xf5058204afaec6f2464c5a13, + limb1: 0x515da6bfc23ebf6f53f6b55b, + limb2: 0xe97a11e04bb36b2059446a4c, + limb3: 0x12fc97a16defdc7adc7476f9 + }, + r0a1: u384 { + limb0: 0x980b9772f15c2485344735fc, + limb1: 0xe64c7342b28e77acf36d03da, + limb2: 0xefd0a557cd8909bc5c9e7baf, + limb3: 0xbee5b30e2c4af8e16809197 + }, + r1a0: u384 { + limb0: 0x5fe61e5a5909262f7cad99ed, + limb1: 0xccf8e0ad8f3dba3dbeb8ec43, + limb2: 0x10378ef14243abc565883a1b, + limb3: 0x209e28d5551008fd8c913d6 + }, + r1a1: u384 { + limb0: 0x31bad5bcd6808dcb2e85caf, + limb1: 0xd37414833b060119d1f174a3, + limb2: 0xd4f73e90a51a3acc4ae687fd, + limb3: 0x18dc062c90db3cd1d20a7de1 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x7a3deb7872768f839060087e, + limb1: 0xae5017af4c09ed67c5c2e525, + limb2: 0xef2bbb3e118498031e2471f, + limb3: 0x5cf357e8473bba00386d238 + }, + r0a1: u384 { + limb0: 0x3b373a0d0a649113f5c7b2fe, + limb1: 0xa3913baa2c3f8f7499ac76a6, + limb2: 0x425aed5972aa5f4b4d21ffc7, + limb3: 0x82938f41814229b1224b32b + }, + r1a0: u384 { + limb0: 0x5b130ec9295aaeb79868e7d6, + limb1: 0xda6c9ffb04ff597a83b36114, + limb2: 0xc09586dc17dbca59627bbce4, + limb3: 0xd8431f93c66d78cf5b81228 + }, + r1a1: u384 { + limb0: 0xe35d56023ffa020c373e6d85, + limb1: 0x22972df9b6181d6397c5ee58, + limb2: 0x933a967160fc487717775d67, + limb3: 0x19c24474e43b997ab5364a65 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x39d9f0ce211a75081a35cffc, + limb1: 0xd3f3a394f77ca3a98e93c5df, + limb2: 0x85eb00d07fe02bd29ac2a3c6, + limb3: 0xb7b0d2db2cffcae60d0ecf6 + }, + r0a1: u384 { + limb0: 0x6117d9f54ded251ed87dcdbd, + limb1: 0x1eb6b7f8ce40fd2cfe030d6a, + limb2: 0xeed76c5b0d292777e93e9282, + limb3: 0xdcf9ee4e619ac48372a1fd5 + }, + r1a0: u384 { + limb0: 0xa9e439e749d4fc1bea4f893f, + limb1: 0x3a33e93d4e73b675790a1df8, + limb2: 0xdfc3e8f4f8f506c7c6669428, + limb3: 0x11adba6387d459f7f991ac32 + }, + r1a1: u384 { + limb0: 0x35efe895ea1509c6b6db31f1, + limb1: 0xeba2f9e1733b61d399cbe43d, + limb2: 0xe0ca6d0d6d5e4e234334bc4b, + limb3: 0x1641a68f159d661c924ca1ca + } + }, + G2Line { + r0a0: u384 { + limb0: 0x6acbdd11b2e3bf3c4e9a8fc7, + limb1: 0xa65c7c83d9e863106be2e6e, + limb2: 0xba622ef466154b88c6206dc0, + limb3: 0x13847679c97ef8978b3f64c9 + }, + r0a1: u384 { + limb0: 0xa29270a27fe8eff7ff52747, + limb1: 0x1b86d1ea5e2cb0e565695293, + limb2: 0x5d46595304e94133e1524dc4, + limb3: 0x5c65be3c6a8b37e95aaa472 + }, + r1a0: u384 { + limb0: 0x4c113034a2b4e8c08494656, + limb1: 0x113bdfa06dc6105f0cee337c, + limb2: 0x5ab2297e7c609e4044c01f70, + limb3: 0xe5ba46e7903db0416c5e85d + }, + r1a1: u384 { + limb0: 0x1af25f25f85e2fe5769d4db0, + limb1: 0xc25dd758f010619bdce139cb, + limb2: 0x539682ada1e9af81af49cbb4, + limb3: 0x63c25d8d6ffab7a17da8252 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x2afd7a503f72962b8035ef56, + limb1: 0x741a2724c626c073fcb7cb01, + limb2: 0xa954f9a9959cbbcf41765c4c, + limb3: 0xd255d019186fe50bbb4abdb + }, + r0a1: u384 { + limb0: 0xe1247719764debd50fb297b1, + limb1: 0x1c85bc8240e9013aa086e724, + limb2: 0x2bac98861c64cbbfaf10dfe5, + limb3: 0x17887473079a17d6114873ff + }, + r1a0: u384 { + limb0: 0xb40da2a4cd71fa1185ef523a, + limb1: 0xb9b730fd2eea88566c9d4152, + limb2: 0x3c384a7436df1edb029d3aed, + limb3: 0x89d99706a83aba945d7b48a + }, + r1a1: u384 { + limb0: 0x6576e31328774ef164f99920, + limb1: 0x3e722659df78ce6e6d049703, + limb2: 0xc5d56c8d8e6603bf62c90b81, + limb3: 0xf58e0aa466c88aa025b6401 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xee48f089c7a4594a201092eb, + limb1: 0xc9d8a7b7d87389e25b856b97, + limb2: 0x74d54bf4748e38d3b2c782b3, + limb3: 0x78af2f8549231aa92bba1b3 + }, + r0a1: u384 { + limb0: 0x61acc46ca422be84be4fee75, + limb1: 0xf425406455688e07fe496eb2, + limb2: 0x1151b627d67176b268c6b18b, + limb3: 0x157a7e87571314c4eeffcc64 + }, + r1a0: u384 { + limb0: 0xd95d245c747804a8f3bd59ab, + limb1: 0xb3c7108b5d8ce6d797a8ab29, + limb2: 0x452fc047d47ec02830b1b9c1, + limb3: 0x12ea35020ddc17232447b57c + }, + r1a1: u384 { + limb0: 0xb027d5b2037b8170fb63b93a, + limb1: 0xf317c06fee2a5ef8113fd9d3, + limb2: 0xdd1a58fc8de1d70f065c435c, + limb3: 0x11d55ce218987319447cc925 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xbda20eba312f5ae4b8188dd6, + limb1: 0xed6b03a1b59cdf81e337466, + limb2: 0x13f52774d5df8f2b53b3f9a3, + limb3: 0xa84369f18ef0ea7ea78978b + }, + r0a1: u384 { + limb0: 0xd89f88c20cdd1be266384948, + limb1: 0xb260d5b59d68bd6ce061618b, + limb2: 0xc706ec3e85485a7d5d2746c8, + limb3: 0x3610ae9e586990c2332a60b + }, + r1a0: u384 { + limb0: 0xaa640e2e801a15e4d8aa9343, + limb1: 0xce786976554ab6ed66b66295, + limb2: 0x1dbbe2c4c4a66f2fef9f4df, + limb3: 0x1599a1020ad879a8517215c8 + }, + r1a1: u384 { + limb0: 0x68f8ce25afd5a01fa9437698, + limb1: 0xf218ff065be19aa212e05aa2, + limb2: 0xa0d7125cba24d5c3b3426602, + limb3: 0x1f4d34e061c1928106f603 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x1b9ff207335fcb7b28f48654, + limb1: 0xaa059fc26f53a4b15d861e5d, + limb2: 0x7409e84a31ef57e217e3d45d, + limb3: 0x8f022244af0b719146e8cfb + }, + r0a1: u384 { + limb0: 0x1fa9d79eb0320e586c2d096a, + limb1: 0x8fde2d5c9ef41c1612865896, + limb2: 0xec88b9f86c99799b380ebac9, + limb3: 0x72c117c18b8dfa89321c27c + }, + r1a0: u384 { + limb0: 0x4570eb295684cad19e7cfded, + limb1: 0x2e204f8114c805f866cca868, + limb2: 0xba0509fc0eea7cc65c8b3dee, + limb3: 0xc7c1e717bb7b078054d3851 + }, + r1a1: u384 { + limb0: 0x25eb9fba51d76d2292c1e2bf, + limb1: 0xa43de47dba6db4c3e5c3d8b8, + limb2: 0x365ea08af8998db774b8b61e, + limb3: 0x6367ffd71d3c44095424fc7 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x2ad35ec942a6dc10be32da05, + limb1: 0xb889a7f8c178610e41752e60, + limb2: 0x130ac19123ef4bc5eff163aa, + limb3: 0xc1c8933b8eca116c8c32c9e + }, + r0a1: u384 { + limb0: 0x9b46883056c4f426647a0d1f, + limb1: 0x2bc81e6550613b15475cad1f, + limb2: 0x5c12a15bc536b16c6c8b1118, + limb3: 0x1116e31db9a099b5941e7fe9 + }, + r1a0: u384 { + limb0: 0x1b8184a1d9bad5d268b10d3e, + limb1: 0xc8196d57732ebf89f6ce1ee6, + limb2: 0xd34c8b394f605c9bc52280cd, + limb3: 0x14b9a6056022227937d6c4ee + }, + r1a1: u384 { + limb0: 0xbcbfa6c19991f2a6202faa84, + limb1: 0xf3a30cde404074949784fb8a, + limb2: 0x6bd69539f118c993bb469b75, + limb3: 0x3c8a54c44f16bc3e22144e4 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xd8934218abbe5eda42e0374, + limb1: 0x4efa70797ab04d5777f18cae, + limb2: 0x657bd72dc32622552c01c3a1, + limb3: 0x86675ec3781ecc255b9b8f + }, + r0a1: u384 { + limb0: 0xdb3cdd784259d6f00a05188, + limb1: 0x4d7d18f24dc5139d8829c6be, + limb2: 0x9067fb6cb2810aa19e5e838d, + limb3: 0x99b7b955ea60c02306dd019 + }, + r1a0: u384 { + limb0: 0x9569e6a9a6dfc936dc66c37d, + limb1: 0x8ce5600bf62265cce1600d14, + limb2: 0xe437be1358f94ae1da7ba693, + limb3: 0x26001dbd81fb98024703f0a + }, + r1a1: u384 { + limb0: 0x38347efb475ef26461922ce8, + limb1: 0x434f13930fd2a42336fc5a71, + limb2: 0xa611a973d0bf99e3535651af, + limb3: 0xf623d241cf8d903d2d48305 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x721021ae8a4f50730c3d67dc, + limb1: 0x879473ae153c9a3634074832, + limb2: 0x37c1a1dc9eb1835b698836b1, + limb3: 0x103fc06c9853a3f7112aab36 + }, + r0a1: u384 { + limb0: 0xabcfe33c5665f550278d61b4, + limb1: 0x9225061eb88a19059c6a5f6b, + limb2: 0xfea771c15b736bb9dfd64611, + limb3: 0x115d2632ad3a29006e1392bf + }, + r1a0: u384 { + limb0: 0x656457e64c7777c11b84156b, + limb1: 0xead830ab7644411a1795ddf3, + limb2: 0xbd12c37bb1cbd056fc94cd13, + limb3: 0x1698578bd5388b5de2eb808f + }, + r1a1: u384 { + limb0: 0xa3f77a7e2e3af21dabc4871, + limb1: 0x170f78723c727fb4bbc4b4a9, + limb2: 0x7090ee848cbc35a8f11b2354, + limb3: 0xc8b6a3068cd96500af13493 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x7464425eeb75a1d3a3486fba, + limb1: 0xd4f0931c31459109811008d1, + limb2: 0x5aac0cfc9b43343826136afb, + limb3: 0xf16056dd2e8b5f8240d4ac7 + }, + r0a1: u384 { + limb0: 0xee0993ef125a22747400b5ea, + limb1: 0x438805278ea9e18b001cf7da, + limb2: 0x11c5cbb3ae17332e06f5b415, + limb3: 0x134957b7abe963c5d074abc9 + }, + r1a0: u384 { + limb0: 0xacf8eb684fdd044dd83f813e, + limb1: 0xcb5dae51f81a4969f0370c67, + limb2: 0x491fc4a63ef64f17b8aa0d30, + limb3: 0x188b4199d41c95a7991f2d89 + }, + r1a1: u384 { + limb0: 0x1f69582489be9a39cb94c326, + limb1: 0xdfa20ef759cc430ed060c20b, + limb2: 0xeab00aeca148c6a408bcd34a, + limb3: 0xd6a605bcb73c8061942fb57 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x6773468ba72e40777baeb8f0, + limb1: 0x570d2473b46fc08824285612, + limb2: 0xd6ad952f46006fb353d86e0b, + limb3: 0xa08d2c3726cf2aff2c088d6 + }, + r0a1: u384 { + limb0: 0xa416cc264e8202431a4e991d, + limb1: 0xf5a5787c840a815dfa522b31, + limb2: 0xe711bc925aba1a74b7b4d4aa, + limb3: 0x868f9c19f9d55b3b7ccd898 + }, + r1a0: u384 { + limb0: 0x7baf6a74c7f41953cea5e439, + limb1: 0xcb2fed5cedcf58101434abc1, + limb2: 0x7393a96a373c39a66a6c8834, + limb3: 0xb23fcd989611b241a4105b + }, + r1a1: u384 { + limb0: 0x555b817d72aebd2464a2d59b, + limb1: 0xe7fd327dcbec3232500cda76, + limb2: 0x10b589891b97aaf0c7a54d85, + limb3: 0xbd9efb2a7eedeb7323cb190 + } + }, + G2Line { + r0a0: u384 { + limb0: 0xed72eccb4e30eeaf3b992446, + limb1: 0x14e0585cd696c72e9adb4736, + limb2: 0x7df5eabb84672fab4d4a6e10, + limb3: 0x2d6c8112234d7f18ea478ea + }, + r0a1: u384 { + limb0: 0x95586dac212579b39f39df97, + limb1: 0xff0488c63a739029f85aec22, + limb2: 0x38ce286aeea4511ddcb23d59, + limb3: 0x444323d14c7a3549b9f6b27 + }, + r1a0: u384 { + limb0: 0xac929d1bb6bfa0df5bd0b951, + limb1: 0x9a5e39e018083d89aeeaee3d, + limb2: 0xc84698d95675ba2c1b93662e, + limb3: 0xa82a23fd9338c15ba09139b + }, + r1a1: u384 { + limb0: 0x8a89d4ebf46cc78b9a67add2, + limb1: 0x1761e578b693547ecbf4817f, + limb2: 0xbd9d23d081864a636a27dce, + limb3: 0x40d68a72ee4363db50d3c92 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x9cdba5cfbe0205d55df33685, + limb1: 0x8a416e1681ead82ad2711fef, + limb2: 0xd94faace2b1209807fbb9edd, + limb3: 0xd1755cae5ede1642897673f + }, + r0a1: u384 { + limb0: 0x352a420344ca83dd4e252c7, + limb1: 0xcbcde81ff301c244dc5e006, + limb2: 0xa54df6ee2561e110ee674e3e, + limb3: 0x18ad276363a6d2c576fc7d75 + }, + r1a0: u384 { + limb0: 0x17901b259f213203281dfa4e, + limb1: 0xdca6f358c344dba951e904f0, + limb2: 0x68be1f2f4a49c00264212bb, + limb3: 0xf39b5af5b74e8e45b8940b + }, + r1a1: u384 { + limb0: 0xe2032cd4d375921e86fdc082, + limb1: 0x90f0cda4fe6f4bedd1c3872d, + limb2: 0x9236c612070666c5139ec1cf, + limb3: 0x16eecd9e2f41fc13c0b1678d + } + }, + G2Line { + r0a0: u384 { + limb0: 0xbdda2d3c31051f4071ae2945, + limb1: 0xbc66726ddee31b37d058d7e5, + limb2: 0x9f4eb741ac78b510ccf452ab, + limb3: 0x65fb0c0d47de8795557bd2f + }, + r0a1: u384 { + limb0: 0xb9c37518dd4a05df7a4d6dc1, + limb1: 0xd4ee64da91ea67b8a4525b4, + limb2: 0x73a813ffff40ee810a12214b, + limb3: 0x7f9fda3fa03c5295720441d + }, + r1a0: u384 { + limb0: 0xaa6d391bd6b4113145484e4f, + limb1: 0x86d3fa56727d8879496d1827, + limb2: 0x71223351a13a9577646c0ec3, + limb3: 0x5c4513dff602b8ec227f711 + }, + r1a1: u384 { + limb0: 0xb9b127f0cbfc3172bba7a933, + limb1: 0x10d730ec07d1e0f84c5c6c34, + limb2: 0x693e354e2246bf96f3ebf563, + limb3: 0x1163f7e15fbd10f4086aad86 + } + }, + G2Line { + r0a0: u384 { + limb0: 0x95151ea18c775b54deb3d8d2, + limb1: 0x12d5d14c1a1e5e441f80f7f0, + limb2: 0x441e9ed1c76ca5b0a9a2c673, + limb3: 0x5ed345d22ce7a2820a566a6 + }, + r0a1: u384 { + limb0: 0x85f7fcc07f1acb58e2b2b71d, + limb1: 0xf54880edf6b069d9be9739e7, + limb2: 0xb25f1683eedccd9cddb2592e, + limb3: 0x1287330ba9caab2bef8676e5 + }, + r1a0: u384 { + limb0: 0x418096781d6bdd8438f7d0fa, + limb1: 0xde2b0883a520a29780fe7f9, + limb2: 0x858acb343f8b338095664988, + limb3: 0x1213109d451b7b62be0e7837 + }, + r1a1: u384 { + limb0: 0x13c30921c6ad44eef236dc4e, + limb1: 0x97d1525a1c3fa2dfe5f32aa7, + limb2: 0x7071a595e981dc71b225c544, + limb3: 0x6f31cf2562cca8a820178ab + } + }, +]; diff --git a/src/contracts/drand_quicknet/src/lib.cairo b/src/contracts/drand_quicknet/src/lib.cairo new file mode 100644 index 00000000..207d774b --- /dev/null +++ b/src/contracts/drand_quicknet/src/lib.cairo @@ -0,0 +1,2 @@ +mod drand_verifier; +mod drand_verifier_constants; diff --git a/src/contracts/risc0_verifier_bn254/src/groth16_verifier.cairo b/src/contracts/risc0_verifier_bn254/src/groth16_verifier.cairo index bf39848a..7e5d8704 100644 --- a/src/contracts/risc0_verifier_bn254/src/groth16_verifier.cairo +++ b/src/contracts/risc0_verifier_bn254/src/groth16_verifier.cairo @@ -13,7 +13,7 @@ mod Risc0Groth16VerifierBN254 { use garaga::definitions::{G1Point, G1G2Pair}; use garaga::groth16::{multi_pairing_check_bn254_3P_2F_with_extra_miller_loop_result}; use garaga::ec_ops::{G1PointTrait, G2PointTrait, ec_safe_add}; - use garaga::risc0_utils::compute_receipt_claim; + use garaga::utils::risc0::compute_receipt_claim; use garaga::utils::calldata::{FullProofWithHintsRisc0, deserialize_full_proof_with_hints_risc0}; use super::{N_FREE_PUBLIC_INPUTS, vk, ic, precomputed_lines, T}; diff --git a/src/src/basic_field_ops.cairo b/src/src/basic_field_ops.cairo index dca9a1ac..09ddf4de 100644 --- a/src/src/basic_field_ops.cairo +++ b/src/src/basic_field_ops.cairo @@ -1,5 +1,5 @@ use core::circuit::{ - RangeCheck96, AddMod, MulMod, u384, CircuitElement, CircuitInput, circuit_add, circuit_sub, + RangeCheck96, AddMod, MulMod, u384, u96, CircuitElement, CircuitInput, circuit_add, circuit_sub, circuit_mul, circuit_inverse, EvalCircuitResult, EvalCircuitTrait, CircuitOutputsTrait, CircuitModulus, AddInputResultTrait, CircuitInputs, CircuitInputAccumulator }; @@ -9,6 +9,12 @@ use core::circuit::CircuitElement as CE; use core::circuit::CircuitInput as CI; use garaga::definitions::E12D; +const POW_2_32_252: felt252 = 0x100000000; +const POW_2_64_252: felt252 = 0x10000000000000000; + +const POW_2_256_384: u384 = u384 { limb0: 0x0, limb1: 0x0, limb2: 0x10000000000000000, limb3: 0x0 }; + + fn neg_mod_p(a: u384, p: u384) -> u384 { let in1 = CircuitElement::> {}; let in2 = CircuitElement::> {}; @@ -27,6 +33,18 @@ fn neg_mod_p(a: u384, p: u384) -> u384 { return outputs.get_output(neg); } + +fn is_even_u384(a: u384) -> bool { + let in1 = CircuitElement::> {}; + let modulus = TryInto::<_, CircuitModulus>::try_into([2, 0, 0, 0]).unwrap(); + let outputs = (in1,).new_inputs().next_2(a).done_2().eval(modulus).unwrap(); + let limb0: felt252 = outputs.get_output(in1).limb0.into(); + match limb0 { + 0 => true, + _ => false, + } +} + #[inline(always)] fn compute_yInvXnegOverY_BN254(x: u384, y: u384) -> (u384, u384) { let in1 = CircuitElement::> {}; @@ -86,6 +104,64 @@ fn compute_yInvXnegOverY_BLS12_381(x: u384, y: u384) -> (u384, u384) { return (outputs.get_output(yInv), outputs.get_output(xNegOverY)); } +// Takes big endian u512 and returns a u384 mod bls12_381 +// u512 = low_256 + high_256 * 2^256 +// u512 % p = (low_256 + high_256 * 2^256) % p +// = (low_256 % p + high_256 * 2^256 % p) % p +fn u512_mod_bls12_381(a_high: [u32; 8], a_low: [u32; 8]) -> u384 { + let low = CircuitElement::> {}; + let high = CircuitElement::> {}; + let shift = CircuitElement::> {}; + let high_shifted = circuit_mul(high, shift); + let res = circuit_add(low, high_shifted); + + let modulus = TryInto::< + _, CircuitModulus + >::try_into( + [ + 0xb153ffffb9feffffffffaaab, + 0x6730d2a0f6b0f6241eabfffe, + 0x434bacd764774b84f38512bf, + 0x1a0111ea397fe69a4b1ba7b6 + ] + ) + .unwrap(); // BLS12_381 prime field modulus + + let [al_0, al_1, al_2, al_3, al_4, al_5, al_6, al_7] = a_low; + let ll0: felt252 = al_7.into() + al_6.into() * POW_2_32_252 + al_5.into() * POW_2_64_252; + let ll1: felt252 = al_4.into() + al_3.into() * POW_2_32_252 + al_2.into() * POW_2_64_252; + let ll2: felt252 = al_1.into() + al_0.into() * POW_2_32_252; + + let low_256 = u384 { + limb0: ll0.try_into().unwrap(), + limb1: ll1.try_into().unwrap(), + limb2: ll2.try_into().unwrap(), + limb3: 0 + }; + + let [ah_0, ah_1, ah_2, ah_3, ah_4, ah_5, ah_6, ah_7] = a_high; + let hl0: felt252 = ah_7.into() + ah_6.into() * POW_2_32_252 + ah_5.into() * POW_2_64_252; + let hl1: felt252 = ah_4.into() + ah_3.into() * POW_2_32_252 + ah_2.into() * POW_2_64_252; + let hl2: felt252 = ah_1.into() + ah_0.into() * POW_2_32_252; + let high_256 = u384 { + limb0: hl0.try_into().unwrap(), + limb1: hl1.try_into().unwrap(), + limb2: hl2.try_into().unwrap(), + limb3: 0 + }; + + let outputs = (res,) + .new_inputs() + .next_2(low_256) + .next_2(high_256) + .next_2(POW_2_256_384) + .done_2() + .eval(modulus) + .unwrap(); + + return outputs.get_output(res); +} + fn add_mod_p(a: u384, b: u384, p: u384) -> u384 { let in1 = CircuitElement::> {}; let in2 = CircuitElement::> {}; diff --git a/src/src/circuits.cairo b/src/src/circuits.cairo index 1dfee082..c3f93370 100644 --- a/src/src/circuits.cairo +++ b/src/src/circuits.cairo @@ -2,3 +2,4 @@ mod ec; mod dummy; mod multi_pairing_check; mod extf_mul; +mod isogeny; diff --git a/src/src/circuits/isogeny.cairo b/src/src/circuits/isogeny.cairo new file mode 100644 index 00000000..7af82c5f --- /dev/null +++ b/src/src/circuits/isogeny.cairo @@ -0,0 +1,657 @@ +use core::circuit::{ + RangeCheck96, AddMod, MulMod, u384, u96, CircuitElement, CircuitInput, circuit_add, circuit_sub, + circuit_mul, circuit_inverse, EvalCircuitResult, EvalCircuitTrait, CircuitOutputsTrait, + CircuitModulus, AddInputResultTrait, CircuitInputs, CircuitDefinition, CircuitData, + CircuitInputAccumulator +}; +use garaga::core::circuit::AddInputResultTrait2; +use core::circuit::CircuitElement as CE; +use core::circuit::CircuitInput as CI; +use garaga::definitions::{ + get_a, get_b, get_p, get_g, get_min_one, G1Point, G2Point, E12D, u288, E12DMulQuotient, + G1G2Pair, BNProcessedPair, BLSProcessedPair, MillerLoopResultScalingFactor, G2Line +}; +use garaga::ec_ops::{SlopeInterceptOutput, FunctionFeltEvaluations, FunctionFelt}; +use core::option::Option; + +#[inline(always)] +fn run_BLS12_381_APPLY_ISOGENY_BLS12_381_circuit(pt: G1Point) -> (G1Point,) { + // CONSTANT stack + let in0 = CE::< + CI<0> + > {}; // 0x11a05f2b1e833340b809101dd99815856b303e88a2d7005ff2627b56cdb4e2c85610c2d5f2e62d6eaeac1662734649b7 + let in1 = CE::< + CI<1> + > {}; // 0x17294ed3e943ab2f0588bab22147a81c7c17e75b2f6a8417f565e33c70d1e86b4838f2a6f318c356e834eef1b3cb83bb + let in2 = CE::< + CI<2> + > {}; // 0xd54005db97678ec1d1048c5d10a9a1bce032473295983e56878e501ec68e25c958c3e3d2a09729fe0179f9dac9edcb0 + let in3 = CE::< + CI<3> + > {}; // 0x1778e7166fcc6db74e0609d307e55412d7f5e4656a8dbf25f1b33289f1b330835336e25ce3107193c5b388641d9b6861 + let in4 = CE::< + CI<4> + > {}; // 0xe99726a3199f4436642b4b3e4118e5499db995a1257fb3f086eeb65982fac18985a286f301e77c451154ce9ac8895d9 + let in5 = CE::< + CI<5> + > {}; // 0x1630c3250d7313ff01d1201bf7a74ab5db3cb17dd952799b9ed3ab9097e68f90a0870d2dcae73d19cd13c1c66f652983 + let in6 = CE::< + CI<6> + > {}; // 0xd6ed6553fe44d296a3726c38ae652bfb11586264f0f8ce19008e218f9c86b2a8da25128c1052ecaddd7f225a139ed84 + let in7 = CE::< + CI<7> + > {}; // 0x17b81e7701abdbe2e8743884d1117e53356de5ab275b4db1a682c62ef0f2753339b7c8f8c8f475af9ccb5618e3f0c88e + let in8 = CE::< + CI<8> + > {}; // 0x80d3cf1f9a78fc47b90b33563be990dc43b756ce79f5574a2c596c928c5d1de4fa295f296b74e956d71986a8497e317 + let in9 = CE::< + CI<9> + > {}; // 0x169b1f8e1bcfa7c42e0c37515d138f22dd2ecb803a0c5c99676314baf4bb1b7fa3190b2edc0327797f241067be390c9e + let in10 = CE::< + CI<10> + > {}; // 0x10321da079ce07e272d8ec09d2565b0dfa7dccdde6787f96d50af36003b14866f69b771f8c285decca67df3f1605fb7b + let in11 = CE::< + CI<11> + > {}; // 0x6e08c248e260e70bd1e962381edee3d31d79d7e22c837bc23c0bf1bc24c6b68c24b1b80b64d391fa9c8ba2e8ba2d229 + let in12 = CE::< + CI<12> + > {}; // 0x8ca8d548cff19ae18b2e62f4bd3fa6f01d5ef4ba35b48ba9c9588617fc8ac62b558d681be343df8993cf9fa40d21b1c + let in13 = CE::< + CI<13> + > {}; // 0x12561a5deb559c4348b4711298e536367041e8ca0cf0800c0126c2588c48bf5713daa8846cb026e9e5c8276ec82b3bff + let in14 = CE::< + CI<14> + > {}; // 0xb2962fe57a3225e8137e629bff2991f6f89416f5a718cd1fca64e00b11aceacd6a3d0967c94fedcfcc239ba5cb83e19 + let in15 = CE::< + CI<15> + > {}; // 0x3425581a58ae2fec83aafef7c40eb545b08243f16b1655154cca8abc28d6fd04976d5243eecf5c4130de8938dc62cd8 + let in16 = CE::< + CI<16> + > {}; // 0x13a8e162022914a80a6f1d5f43e7a07dffdfc759a12062bb8d6b44e833b306da9bd29ba81f35781d539d395b3532a21e + let in17 = CE::< + CI<17> + > {}; // 0xe7355f8e4e667b955390f7f0506c6e9395735e9ce9cad4d0a43bcef24b8982f7400d24bc4228f11c02df9a29f6304a5 + let in18 = CE::< + CI<18> + > {}; // 0x772caacf16936190f3e0c63e0596721570f5799af53a1894e2e073062aede9cea73b3538f0de06cec2574496ee84a3a + let in19 = CE::< + CI<19> + > {}; // 0x14a7ac2a9d64a8b230b3f5b074cf01996e7f63c21bca68a81996e1cdf9822c580fa5b9489d11e2d311f7d99bbdcc5a5e + let in20 = CE::< + CI<20> + > {}; // 0xa10ecf6ada54f825e920b3dafc7a3cce07f8d1d7161366b74100da67f39883503826692abba43704776ec3a79a1d641 + let in21 = CE::< + CI<21> + > {}; // 0x95fc13ab9e92ad4476d6e3eb3a56680f682b4ee96f7d03776df533978f31c1593174e4b4b7865002d6384d168ecdd0a + let in22 = CE::> {}; // 0x1 + let in23 = CE::< + CI<23> + > {}; // 0x90d97c81ba24ee0259d1f094980dcfa11ad138e48a869522b52af6c956543d3cd0c7aee9b3ba3c2be9845719707bb33 + let in24 = CE::< + CI<24> + > {}; // 0x134996a104ee5811d51036d776fb46831223e96c254f383d0f906343eb67ad34d6c56711962fa8bfe097e75a2e41c696 + let in25 = CE::< + CI<25> + > {}; // 0xcc786baa966e66f4a384c86a3b49942552e2d658a31ce2c344be4b91400da7d26d521628b00523b8dfe240c72de1f6 + let in26 = CE::< + CI<26> + > {}; // 0x1f86376e8981c217898751ad8746757d42aa7b90eeb791c09e4a3ec03251cf9de405aba9ec61deca6355c77b0e5f4cb + let in27 = CE::< + CI<27> + > {}; // 0x8cc03fdefe0ff135caf4fe2a21529c4195536fbe3ce50b879833fd221351adc2ee7f8dc099040a841b6daecf2e8fedb + let in28 = CE::< + CI<28> + > {}; // 0x16603fca40634b6a2211e11db8f0a6a074a7d0d4afadb7bd76505c3d3ad5544e203f6326c95a807299b23ab13633a5f0 + let in29 = CE::< + CI<29> + > {}; // 0x4ab0b9bcfac1bbcb2c977d027796b3ce75bb8ca2be184cb5231413c4d634f3747a87ac2460f415ec961f8855fe9d6f2 + let in30 = CE::< + CI<30> + > {}; // 0x987c8d5333ab86fde9926bd2ca6c674170a05bfe3bdd81ffd038da6c26c842642f64550fedfe935a15e4ca31870fb29 + let in31 = CE::< + CI<31> + > {}; // 0x9fc4018bd96684be88c9e221e4da1bb8f3abd16679dc26c1e8b6e6a1f20cabe69d65201c78607a360370e577bdba587 + let in32 = CE::< + CI<32> + > {}; // 0xe1bba7a1186bdb5223abde7ada14a23c42a0ca7915af6fe06985e7ed1e4d43b9b3f7055dd4eba6f2bafaaebca731c30 + let in33 = CE::< + CI<33> + > {}; // 0x19713e47937cd1be0dfd0b8f1d43fb93cd2fcbcb6caf493fd1183e416389e61031bf3a5cce3fbafce813711ad011c132 + let in34 = CE::< + CI<34> + > {}; // 0x18b46a908f36f6deb918c143fed2edcc523559b8aaf0c2462e6bfe7f911f643249d9cdf41b44d606ce07c8a4d0074d8e + let in35 = CE::< + CI<35> + > {}; // 0xb182cac101b9399d155096004f53f447aa7b12a3426b08ec02710e807b4633f06c851c1919211f20d4c04f00b971ef8 + let in36 = CE::< + CI<36> + > {}; // 0x245a394ad1eca9b72fc00ae7be315dc757b3b080d4c158013e6632d3c40659cc6cf90ad1c232a6442d9d3f5db980133 + let in37 = CE::< + CI<37> + > {}; // 0x5c129645e44cf1102a159f748c4a3fc5e673d81d7e86568d9ab0f5d396a7ce46ba1049b6579afb7866b1e715475224b + let in38 = CE::< + CI<38> + > {}; // 0x15e6be4e990f03ce4ea50b3b42df2eb5cb181d8f84965a3957add4fa95af01b2b665027efec01c7704b456be69c8b604 + let in39 = CE::< + CI<39> + > {}; // 0x16112c4c3a9c98b252181140fad0eae9601a6de578980be6eec3232b5be72e7a07f3688ef60c206d01479253b03663c1 + let in40 = CE::< + CI<40> + > {}; // 0x1962d75c2381201e1a0cbd6c43c348b885c84ff731c4d59ca4a10356f453e01f78a4260763529e3532f6102c2e49a03d + let in41 = CE::< + CI<41> + > {}; // 0x58df3306640da276faaae7d6e8eb15778c4855551ae7f310c35a5dd279cd2eca6757cd636f96f891e2538b53dbf67f2 + let in42 = CE::< + CI<42> + > {}; // 0x16b7d288798e5395f20d23bf89edb4d1d115c5dbddbcd30e123da489e726af41727364f2c28297ada8d26d98445f5416 + let in43 = CE::< + CI<43> + > {}; // 0xbe0e079545f43e4b00cc912f8228ddcc6d19c9f0f69bbb0542eda0fc9dec916a20b15dc0fd2ededda39142311a5001d + let in44 = CE::< + CI<44> + > {}; // 0x8d9e5297186db2d9fb266eaac783182b70152c65550d881c5ecd87b6f0f5a6449f38db9dfa9cce202c6477faaf9b7ac + let in45 = CE::< + CI<45> + > {}; // 0x166007c08a99db2fc3ba8734ace9824b5eecfdfa8d0cf8ef5dd365bc400a0051d5fa9c01a58b1fb93d1a1399126a775c + let in46 = CE::< + CI<46> + > {}; // 0x16a3ef08be3ea7ea03bcddfabba6ff6ee5a4375efa1f4fd7feb34fd206357132b920f5b00801dee460ee415a15812ed9 + let in47 = CE::< + CI<47> + > {}; // 0x1866c8ed336c61231a1be54fd1d74cc4f9fb0ce4c6af5920abc5750c4bf39b4852cfe2f7bb9248836b233d9d55535d4a + let in48 = CE::< + CI<48> + > {}; // 0x167a55cda70a6e1cea820597d94a84903216f763e13d87bb5308592e7ea7d4fbc7385ea3d529b35e346ef48bb8913f55 + let in49 = CE::< + CI<49> + > {}; // 0x4d2f259eea405bd48f010a01ad2911d9c6dd039bb61a6290e591b36e636a5c871a5c29f4f83060400f8b49cba8f6aa8 + let in50 = CE::< + CI<50> + > {}; // 0xaccbb67481d033ff5852c1e48c50c477f94ff8aefce42d28c0f9a88cea7913516f968986f7ebbea9684b529e2561092 + let in51 = CE::< + CI<51> + > {}; // 0xad6b9514c767fe3c3613144b45f1496543346d98adf02267d5ceef9a00d9b8693000763e3b90ac11e99b138573345cc + let in52 = CE::< + CI<52> + > {}; // 0x2660400eb2e4f3b628bdd0d53cd76f2bf565b94e72927c1cb748df27942480e420517bd8714cc80d1fadc1326ed06f7 + let in53 = CE::< + CI<53> + > {}; // 0xe0fa1d816ddc03e6b24255e0d7819c171c40f65e273b853324efcd6356caa205ca2f570f13497804415473a1d634b8f + + // INPUT stack + let (in54, in55) = (CE::> {}, CE::> {}); + let t0 = circuit_mul(in11, in54); // Eval x_num Horner step: multiply by z + let t1 = circuit_add(in10, t0); // Eval x_num Horner step: add coefficient_10 + let t2 = circuit_mul(t1, in54); // Eval x_num Horner step: multiply by z + let t3 = circuit_add(in9, t2); // Eval x_num Horner step: add coefficient_9 + let t4 = circuit_mul(t3, in54); // Eval x_num Horner step: multiply by z + let t5 = circuit_add(in8, t4); // Eval x_num Horner step: add coefficient_8 + let t6 = circuit_mul(t5, in54); // Eval x_num Horner step: multiply by z + let t7 = circuit_add(in7, t6); // Eval x_num Horner step: add coefficient_7 + let t8 = circuit_mul(t7, in54); // Eval x_num Horner step: multiply by z + let t9 = circuit_add(in6, t8); // Eval x_num Horner step: add coefficient_6 + let t10 = circuit_mul(t9, in54); // Eval x_num Horner step: multiply by z + let t11 = circuit_add(in5, t10); // Eval x_num Horner step: add coefficient_5 + let t12 = circuit_mul(t11, in54); // Eval x_num Horner step: multiply by z + let t13 = circuit_add(in4, t12); // Eval x_num Horner step: add coefficient_4 + let t14 = circuit_mul(t13, in54); // Eval x_num Horner step: multiply by z + let t15 = circuit_add(in3, t14); // Eval x_num Horner step: add coefficient_3 + let t16 = circuit_mul(t15, in54); // Eval x_num Horner step: multiply by z + let t17 = circuit_add(in2, t16); // Eval x_num Horner step: add coefficient_2 + let t18 = circuit_mul(t17, in54); // Eval x_num Horner step: multiply by z + let t19 = circuit_add(in1, t18); // Eval x_num Horner step: add coefficient_1 + let t20 = circuit_mul(t19, in54); // Eval x_num Horner step: multiply by z + let t21 = circuit_add(in0, t20); // Eval x_num Horner step: add coefficient_0 + let t22 = circuit_mul(in22, in54); // Eval x_den Horner step: multiply by z + let t23 = circuit_add(in21, t22); // Eval x_den Horner step: add coefficient_9 + let t24 = circuit_mul(t23, in54); // Eval x_den Horner step: multiply by z + let t25 = circuit_add(in20, t24); // Eval x_den Horner step: add coefficient_8 + let t26 = circuit_mul(t25, in54); // Eval x_den Horner step: multiply by z + let t27 = circuit_add(in19, t26); // Eval x_den Horner step: add coefficient_7 + let t28 = circuit_mul(t27, in54); // Eval x_den Horner step: multiply by z + let t29 = circuit_add(in18, t28); // Eval x_den Horner step: add coefficient_6 + let t30 = circuit_mul(t29, in54); // Eval x_den Horner step: multiply by z + let t31 = circuit_add(in17, t30); // Eval x_den Horner step: add coefficient_5 + let t32 = circuit_mul(t31, in54); // Eval x_den Horner step: multiply by z + let t33 = circuit_add(in16, t32); // Eval x_den Horner step: add coefficient_4 + let t34 = circuit_mul(t33, in54); // Eval x_den Horner step: multiply by z + let t35 = circuit_add(in15, t34); // Eval x_den Horner step: add coefficient_3 + let t36 = circuit_mul(t35, in54); // Eval x_den Horner step: multiply by z + let t37 = circuit_add(in14, t36); // Eval x_den Horner step: add coefficient_2 + let t38 = circuit_mul(t37, in54); // Eval x_den Horner step: multiply by z + let t39 = circuit_add(in13, t38); // Eval x_den Horner step: add coefficient_1 + let t40 = circuit_mul(t39, in54); // Eval x_den Horner step: multiply by z + let t41 = circuit_add(in12, t40); // Eval x_den Horner step: add coefficient_0 + let t42 = circuit_inverse(t41); + let t43 = circuit_mul(t21, t42); + let t44 = circuit_mul(in38, in54); // Eval y_num Horner step: multiply by z + let t45 = circuit_add(in37, t44); // Eval y_num Horner step: add coefficient_14 + let t46 = circuit_mul(t45, in54); // Eval y_num Horner step: multiply by z + let t47 = circuit_add(in36, t46); // Eval y_num Horner step: add coefficient_13 + let t48 = circuit_mul(t47, in54); // Eval y_num Horner step: multiply by z + let t49 = circuit_add(in35, t48); // Eval y_num Horner step: add coefficient_12 + let t50 = circuit_mul(t49, in54); // Eval y_num Horner step: multiply by z + let t51 = circuit_add(in34, t50); // Eval y_num Horner step: add coefficient_11 + let t52 = circuit_mul(t51, in54); // Eval y_num Horner step: multiply by z + let t53 = circuit_add(in33, t52); // Eval y_num Horner step: add coefficient_10 + let t54 = circuit_mul(t53, in54); // Eval y_num Horner step: multiply by z + let t55 = circuit_add(in32, t54); // Eval y_num Horner step: add coefficient_9 + let t56 = circuit_mul(t55, in54); // Eval y_num Horner step: multiply by z + let t57 = circuit_add(in31, t56); // Eval y_num Horner step: add coefficient_8 + let t58 = circuit_mul(t57, in54); // Eval y_num Horner step: multiply by z + let t59 = circuit_add(in30, t58); // Eval y_num Horner step: add coefficient_7 + let t60 = circuit_mul(t59, in54); // Eval y_num Horner step: multiply by z + let t61 = circuit_add(in29, t60); // Eval y_num Horner step: add coefficient_6 + let t62 = circuit_mul(t61, in54); // Eval y_num Horner step: multiply by z + let t63 = circuit_add(in28, t62); // Eval y_num Horner step: add coefficient_5 + let t64 = circuit_mul(t63, in54); // Eval y_num Horner step: multiply by z + let t65 = circuit_add(in27, t64); // Eval y_num Horner step: add coefficient_4 + let t66 = circuit_mul(t65, in54); // Eval y_num Horner step: multiply by z + let t67 = circuit_add(in26, t66); // Eval y_num Horner step: add coefficient_3 + let t68 = circuit_mul(t67, in54); // Eval y_num Horner step: multiply by z + let t69 = circuit_add(in25, t68); // Eval y_num Horner step: add coefficient_2 + let t70 = circuit_mul(t69, in54); // Eval y_num Horner step: multiply by z + let t71 = circuit_add(in24, t70); // Eval y_num Horner step: add coefficient_1 + let t72 = circuit_mul(t71, in54); // Eval y_num Horner step: multiply by z + let t73 = circuit_add(in23, t72); // Eval y_num Horner step: add coefficient_0 + let t74 = circuit_mul(in22, in54); // Eval y_den Horner step: multiply by z + let t75 = circuit_add(in53, t74); // Eval y_den Horner step: add coefficient_14 + let t76 = circuit_mul(t75, in54); // Eval y_den Horner step: multiply by z + let t77 = circuit_add(in52, t76); // Eval y_den Horner step: add coefficient_13 + let t78 = circuit_mul(t77, in54); // Eval y_den Horner step: multiply by z + let t79 = circuit_add(in51, t78); // Eval y_den Horner step: add coefficient_12 + let t80 = circuit_mul(t79, in54); // Eval y_den Horner step: multiply by z + let t81 = circuit_add(in50, t80); // Eval y_den Horner step: add coefficient_11 + let t82 = circuit_mul(t81, in54); // Eval y_den Horner step: multiply by z + let t83 = circuit_add(in49, t82); // Eval y_den Horner step: add coefficient_10 + let t84 = circuit_mul(t83, in54); // Eval y_den Horner step: multiply by z + let t85 = circuit_add(in48, t84); // Eval y_den Horner step: add coefficient_9 + let t86 = circuit_mul(t85, in54); // Eval y_den Horner step: multiply by z + let t87 = circuit_add(in47, t86); // Eval y_den Horner step: add coefficient_8 + let t88 = circuit_mul(t87, in54); // Eval y_den Horner step: multiply by z + let t89 = circuit_add(in46, t88); // Eval y_den Horner step: add coefficient_7 + let t90 = circuit_mul(t89, in54); // Eval y_den Horner step: multiply by z + let t91 = circuit_add(in45, t90); // Eval y_den Horner step: add coefficient_6 + let t92 = circuit_mul(t91, in54); // Eval y_den Horner step: multiply by z + let t93 = circuit_add(in44, t92); // Eval y_den Horner step: add coefficient_5 + let t94 = circuit_mul(t93, in54); // Eval y_den Horner step: multiply by z + let t95 = circuit_add(in43, t94); // Eval y_den Horner step: add coefficient_4 + let t96 = circuit_mul(t95, in54); // Eval y_den Horner step: multiply by z + let t97 = circuit_add(in42, t96); // Eval y_den Horner step: add coefficient_3 + let t98 = circuit_mul(t97, in54); // Eval y_den Horner step: multiply by z + let t99 = circuit_add(in41, t98); // Eval y_den Horner step: add coefficient_2 + let t100 = circuit_mul(t99, in54); // Eval y_den Horner step: multiply by z + let t101 = circuit_add(in40, t100); // Eval y_den Horner step: add coefficient_1 + let t102 = circuit_mul(t101, in54); // Eval y_den Horner step: multiply by z + let t103 = circuit_add(in39, t102); // Eval y_den Horner step: add coefficient_0 + let t104 = circuit_inverse(t103); + let t105 = circuit_mul(t73, t104); + let t106 = circuit_mul(t105, in55); + + let modulus = TryInto::< + _, CircuitModulus + >::try_into( + [ + 0xb153ffffb9feffffffffaaab, + 0x6730d2a0f6b0f6241eabfffe, + 0x434bacd764774b84f38512bf, + 0x1a0111ea397fe69a4b1ba7b6 + ] + ) + .unwrap(); // BLS12_381 prime field modulus + + let mut circuit_inputs = (t43, t106,).new_inputs(); + // Prefill constants: + + circuit_inputs = circuit_inputs + .next_span(APPLY_ISOGENY_BLS12_381_BLS12_381_CONSTANTS.span()); // in0 - in53 + + // Fill inputs: + circuit_inputs = circuit_inputs.next_2(pt.x); // in54 + circuit_inputs = circuit_inputs.next_2(pt.y); // in55 + + let outputs = circuit_inputs.done_2().eval(modulus).unwrap(); + let res: G1Point = G1Point { x: outputs.get_output(t43), y: outputs.get_output(t106) }; + return (res,); +} +const APPLY_ISOGENY_BLS12_381_BLS12_381_CONSTANTS: [ + u384 + ; 54] = [ + u384 { + limb0: 0xf2e62d6eaeac1662734649b7, + limb1: 0xf2627b56cdb4e2c85610c2d5, + limb2: 0xd99815856b303e88a2d7005f, + limb3: 0x11a05f2b1e833340b809101d + }, + u384 { + limb0: 0xf318c356e834eef1b3cb83bb, + limb1: 0xf565e33c70d1e86b4838f2a6, + limb2: 0x2147a81c7c17e75b2f6a8417, + limb3: 0x17294ed3e943ab2f0588bab2 + }, + u384 { + limb0: 0x2a09729fe0179f9dac9edcb0, + limb1: 0x6878e501ec68e25c958c3e3d, + limb2: 0xd10a9a1bce032473295983e5, + limb3: 0xd54005db97678ec1d1048c5 + }, + u384 { + limb0: 0xe3107193c5b388641d9b6861, + limb1: 0xf1b33289f1b330835336e25c, + limb2: 0x7e55412d7f5e4656a8dbf25, + limb3: 0x1778e7166fcc6db74e0609d3 + }, + u384 { + limb0: 0x301e77c451154ce9ac8895d9, + limb1: 0x86eeb65982fac18985a286f, + limb2: 0xe4118e5499db995a1257fb3f, + limb3: 0xe99726a3199f4436642b4b3 + }, + u384 { + limb0: 0xcae73d19cd13c1c66f652983, + limb1: 0x9ed3ab9097e68f90a0870d2d, + limb2: 0xf7a74ab5db3cb17dd952799b, + limb3: 0x1630c3250d7313ff01d1201b + }, + u384 { + limb0: 0xc1052ecaddd7f225a139ed84, + limb1: 0x9008e218f9c86b2a8da25128, + limb2: 0x8ae652bfb11586264f0f8ce1, + limb3: 0xd6ed6553fe44d296a3726c3 + }, + u384 { + limb0: 0xc8f475af9ccb5618e3f0c88e, + limb1: 0xa682c62ef0f2753339b7c8f8, + limb2: 0xd1117e53356de5ab275b4db1, + limb3: 0x17b81e7701abdbe2e8743884 + }, + u384 { + limb0: 0x96b74e956d71986a8497e317, + limb1: 0xa2c596c928c5d1de4fa295f2, + limb2: 0x63be990dc43b756ce79f5574, + limb3: 0x80d3cf1f9a78fc47b90b335 + }, + u384 { + limb0: 0xdc0327797f241067be390c9e, + limb1: 0x676314baf4bb1b7fa3190b2e, + limb2: 0x5d138f22dd2ecb803a0c5c99, + limb3: 0x169b1f8e1bcfa7c42e0c3751 + }, + u384 { + limb0: 0x8c285decca67df3f1605fb7b, + limb1: 0xd50af36003b14866f69b771f, + limb2: 0xd2565b0dfa7dccdde6787f96, + limb3: 0x10321da079ce07e272d8ec09 + }, + u384 { + limb0: 0xb64d391fa9c8ba2e8ba2d229, + limb1: 0x23c0bf1bc24c6b68c24b1b80, + limb2: 0x81edee3d31d79d7e22c837bc, + limb3: 0x6e08c248e260e70bd1e9623 + }, + u384 { + limb0: 0xbe343df8993cf9fa40d21b1c, + limb1: 0x9c9588617fc8ac62b558d681, + limb2: 0x4bd3fa6f01d5ef4ba35b48ba, + limb3: 0x8ca8d548cff19ae18b2e62f + }, + u384 { + limb0: 0x6cb026e9e5c8276ec82b3bff, + limb1: 0x126c2588c48bf5713daa884, + limb2: 0x98e536367041e8ca0cf0800c, + limb3: 0x12561a5deb559c4348b47112 + }, + u384 { + limb0: 0x7c94fedcfcc239ba5cb83e19, + limb1: 0xfca64e00b11aceacd6a3d096, + limb2: 0xbff2991f6f89416f5a718cd1, + limb3: 0xb2962fe57a3225e8137e629 + }, + u384 { + limb0: 0x3eecf5c4130de8938dc62cd8, + limb1: 0x54cca8abc28d6fd04976d524, + limb2: 0x7c40eb545b08243f16b16551, + limb3: 0x3425581a58ae2fec83aafef + }, + u384 { + limb0: 0x1f35781d539d395b3532a21e, + limb1: 0x8d6b44e833b306da9bd29ba8, + limb2: 0x43e7a07dffdfc759a12062bb, + limb3: 0x13a8e162022914a80a6f1d5f + }, + u384 { + limb0: 0xc4228f11c02df9a29f6304a5, + limb1: 0xa43bcef24b8982f7400d24b, + limb2: 0x506c6e9395735e9ce9cad4d, + limb3: 0xe7355f8e4e667b955390f7f + }, + u384 { + limb0: 0x8f0de06cec2574496ee84a3a, + limb1: 0x4e2e073062aede9cea73b353, + limb2: 0xe0596721570f5799af53a189, + limb3: 0x772caacf16936190f3e0c63 + }, + u384 { + limb0: 0x9d11e2d311f7d99bbdcc5a5e, + limb1: 0x1996e1cdf9822c580fa5b948, + limb2: 0x74cf01996e7f63c21bca68a8, + limb3: 0x14a7ac2a9d64a8b230b3f5b0 + }, + u384 { + limb0: 0xabba43704776ec3a79a1d641, + limb1: 0x74100da67f39883503826692, + limb2: 0xafc7a3cce07f8d1d7161366b, + limb3: 0xa10ecf6ada54f825e920b3d + }, + u384 { + limb0: 0x4b7865002d6384d168ecdd0a, + limb1: 0x76df533978f31c1593174e4b, + limb2: 0xb3a56680f682b4ee96f7d037, + limb3: 0x95fc13ab9e92ad4476d6e3e + }, + u384 { limb0: 0x1, limb1: 0x0, limb2: 0x0, limb3: 0x0 }, + u384 { + limb0: 0x9b3ba3c2be9845719707bb33, + limb1: 0x2b52af6c956543d3cd0c7aee, + limb2: 0x4980dcfa11ad138e48a86952, + limb3: 0x90d97c81ba24ee0259d1f09 + }, + u384 { + limb0: 0x962fa8bfe097e75a2e41c696, + limb1: 0xf906343eb67ad34d6c56711, + limb2: 0x76fb46831223e96c254f383d, + limb3: 0x134996a104ee5811d51036d7 + }, + u384 { + limb0: 0x28b00523b8dfe240c72de1f6, + limb1: 0xc344be4b91400da7d26d5216, + limb2: 0x6a3b49942552e2d658a31ce2, + limb3: 0xcc786baa966e66f4a384c8 + }, + u384 { + limb0: 0x9ec61deca6355c77b0e5f4cb, + limb1: 0x9e4a3ec03251cf9de405aba, + limb2: 0xd8746757d42aa7b90eeb791c, + limb3: 0x1f86376e8981c217898751a + }, + u384 { + limb0: 0x99040a841b6daecf2e8fedb, + limb1: 0x79833fd221351adc2ee7f8dc, + limb2: 0xa21529c4195536fbe3ce50b8, + limb3: 0x8cc03fdefe0ff135caf4fe2 + }, + u384 { + limb0: 0xc95a807299b23ab13633a5f0, + limb1: 0x76505c3d3ad5544e203f6326, + limb2: 0xb8f0a6a074a7d0d4afadb7bd, + limb3: 0x16603fca40634b6a2211e11d + }, + u384 { + limb0: 0x460f415ec961f8855fe9d6f2, + limb1: 0x5231413c4d634f3747a87ac2, + limb2: 0x27796b3ce75bb8ca2be184cb, + limb3: 0x4ab0b9bcfac1bbcb2c977d0 + }, + u384 { + limb0: 0xfedfe935a15e4ca31870fb29, + limb1: 0xfd038da6c26c842642f64550, + limb2: 0x2ca6c674170a05bfe3bdd81f, + limb3: 0x987c8d5333ab86fde9926bd + }, + u384 { + limb0: 0xc78607a360370e577bdba587, + limb1: 0x1e8b6e6a1f20cabe69d65201, + limb2: 0x1e4da1bb8f3abd16679dc26c, + limb3: 0x9fc4018bd96684be88c9e22 + }, + u384 { + limb0: 0xdd4eba6f2bafaaebca731c30, + limb1: 0x6985e7ed1e4d43b9b3f7055, + limb2: 0xada14a23c42a0ca7915af6fe, + limb3: 0xe1bba7a1186bdb5223abde7 + }, + u384 { + limb0: 0xce3fbafce813711ad011c132, + limb1: 0xd1183e416389e61031bf3a5c, + limb2: 0x1d43fb93cd2fcbcb6caf493f, + limb3: 0x19713e47937cd1be0dfd0b8f + }, + u384 { + limb0: 0x1b44d606ce07c8a4d0074d8e, + limb1: 0x2e6bfe7f911f643249d9cdf4, + limb2: 0xfed2edcc523559b8aaf0c246, + limb3: 0x18b46a908f36f6deb918c143 + }, + u384 { + limb0: 0x919211f20d4c04f00b971ef8, + limb1: 0xc02710e807b4633f06c851c1, + limb2: 0x4f53f447aa7b12a3426b08e, + limb3: 0xb182cac101b9399d1550960 + }, + u384 { + limb0: 0x1c232a6442d9d3f5db980133, + limb1: 0x13e6632d3c40659cc6cf90ad, + limb2: 0x7be315dc757b3b080d4c1580, + limb3: 0x245a394ad1eca9b72fc00ae + }, + u384 { + limb0: 0x6579afb7866b1e715475224b, + limb1: 0xd9ab0f5d396a7ce46ba1049b, + limb2: 0x48c4a3fc5e673d81d7e86568, + limb3: 0x5c129645e44cf1102a159f7 + }, + u384 { + limb0: 0xfec01c7704b456be69c8b604, + limb1: 0x57add4fa95af01b2b665027e, + limb2: 0x42df2eb5cb181d8f84965a39, + limb3: 0x15e6be4e990f03ce4ea50b3b + }, + u384 { + limb0: 0xf60c206d01479253b03663c1, + limb1: 0xeec3232b5be72e7a07f3688e, + limb2: 0xfad0eae9601a6de578980be6, + limb3: 0x16112c4c3a9c98b252181140 + }, + u384 { + limb0: 0x63529e3532f6102c2e49a03d, + limb1: 0xa4a10356f453e01f78a42607, + limb2: 0x43c348b885c84ff731c4d59c, + limb3: 0x1962d75c2381201e1a0cbd6c + }, + u384 { + limb0: 0x36f96f891e2538b53dbf67f2, + limb1: 0xc35a5dd279cd2eca6757cd6, + limb2: 0x6e8eb15778c4855551ae7f31, + limb3: 0x58df3306640da276faaae7d + }, + u384 { + limb0: 0xc28297ada8d26d98445f5416, + limb1: 0x123da489e726af41727364f2, + limb2: 0x89edb4d1d115c5dbddbcd30e, + limb3: 0x16b7d288798e5395f20d23bf + }, + u384 { + limb0: 0xfd2ededda39142311a5001d, + limb1: 0x542eda0fc9dec916a20b15dc, + limb2: 0xf8228ddcc6d19c9f0f69bbb0, + limb3: 0xbe0e079545f43e4b00cc912 + }, + u384 { + limb0: 0xdfa9cce202c6477faaf9b7ac, + limb1: 0xc5ecd87b6f0f5a6449f38db9, + limb2: 0xac783182b70152c65550d881, + limb3: 0x8d9e5297186db2d9fb266ea + }, + u384 { + limb0: 0xa58b1fb93d1a1399126a775c, + limb1: 0x5dd365bc400a0051d5fa9c01, + limb2: 0xace9824b5eecfdfa8d0cf8ef, + limb3: 0x166007c08a99db2fc3ba8734 + }, + u384 { + limb0: 0x801dee460ee415a15812ed9, + limb1: 0xfeb34fd206357132b920f5b0, + limb2: 0xbba6ff6ee5a4375efa1f4fd7, + limb3: 0x16a3ef08be3ea7ea03bcddfa + }, + u384 { + limb0: 0xbb9248836b233d9d55535d4a, + limb1: 0xabc5750c4bf39b4852cfe2f7, + limb2: 0xd1d74cc4f9fb0ce4c6af5920, + limb3: 0x1866c8ed336c61231a1be54f + }, + u384 { + limb0: 0xd529b35e346ef48bb8913f55, + limb1: 0x5308592e7ea7d4fbc7385ea3, + limb2: 0xd94a84903216f763e13d87bb, + limb3: 0x167a55cda70a6e1cea820597 + }, + u384 { + limb0: 0x4f83060400f8b49cba8f6aa8, + limb1: 0xe591b36e636a5c871a5c29f, + limb2: 0x1ad2911d9c6dd039bb61a629, + limb3: 0x4d2f259eea405bd48f010a0 + }, + u384 { + limb0: 0x6f7ebbea9684b529e2561092, + limb1: 0x8c0f9a88cea7913516f96898, + limb2: 0x48c50c477f94ff8aefce42d2, + limb3: 0xaccbb67481d033ff5852c1e + }, + u384 { + limb0: 0xe3b90ac11e99b138573345cc, + limb1: 0x7d5ceef9a00d9b8693000763, + limb2: 0xb45f1496543346d98adf0226, + limb3: 0xad6b9514c767fe3c3613144 + }, + u384 { + limb0: 0x8714cc80d1fadc1326ed06f7, + limb1: 0xcb748df27942480e420517bd, + limb2: 0x53cd76f2bf565b94e72927c1, + limb3: 0x2660400eb2e4f3b628bdd0d + }, + u384 { + limb0: 0xf13497804415473a1d634b8f, + limb1: 0x324efcd6356caa205ca2f570, + limb2: 0xd7819c171c40f65e273b853, + limb3: 0xe0fa1d816ddc03e6b24255e + } +]; + +#[cfg(test)] +mod tests { + use core::traits::TryInto; + + use core::circuit::{ + RangeCheck96, AddMod, MulMod, u96, CircuitElement, CircuitInput, circuit_add, circuit_sub, + circuit_mul, circuit_inverse, EvalCircuitResult, EvalCircuitTrait, u384, + CircuitOutputsTrait, CircuitModulus, AddInputResultTrait, CircuitInputs + }; + use garaga::definitions::{ + G1Point, G2Point, E12D, E12DMulQuotient, G1G2Pair, BNProcessedPair, BLSProcessedPair, + MillerLoopResultScalingFactor, G2Line + }; + use garaga::ec_ops::{SlopeInterceptOutput, FunctionFeltEvaluations, FunctionFelt}; + + use super::{run_BLS12_381_APPLY_ISOGENY_BLS12_381_circuit}; +} diff --git a/src/src/definitions.cairo b/src/src/definitions.cairo index 0d80087a..6b18afe6 100644 --- a/src/src/definitions.cairo +++ b/src/src/definitions.cairo @@ -581,6 +581,7 @@ struct E12DMulQuotient { // scalar_to_base_neg3_le(0xD201000000010000**2) +const BLS_X_SEED_SQ: u128 = 0xac45a4010001a4020000000100000000; const BLS_X_SEED_SQ_EPNS: (felt252, felt252, felt252, felt252) = (49064175553473225114813626085204666029, 278052985706122803179667203045598799533, -1, -1); diff --git a/src/src/ec_ops.cairo b/src/src/ec_ops.cairo index 26322051..d562896a 100644 --- a/src/src/ec_ops.cairo +++ b/src/src/ec_ops.cairo @@ -7,7 +7,7 @@ use core::circuit::{ }; use garaga::definitions::{ get_a, get_b, get_p, get_g, get_min_one, get_b2, get_n, G1Point, G2Point, BLS_X_SEED_SQ_EPNS, - G1PointZero, THIRD_ROOT_OF_UNITY_BLS12_381_G1, u384Serde + BLS_X_SEED_SQ, G1PointZero, THIRD_ROOT_OF_UNITY_BLS12_381_G1, u384Serde }; use core::option::Option; use core::poseidon::hades_permutation; @@ -44,6 +44,7 @@ impl G1PointImpl of G1PointTrait { x: mul_mod_p(THIRD_ROOT_OF_UNITY_BLS12_381_G1, *self.x, p), y: *self.y }, BLS_X_SEED_SQ_EPNS, + BLS_X_SEED_SQ, msm_hint.unwrap(), derive_point_from_x_hint.unwrap(), curve_index @@ -288,6 +289,7 @@ struct DerivePointFromXHint { fn scalar_mul_g1_fixed_small_scalar( point: G1Point, scalar_epns: (felt252, felt252, felt252, felt252), + scalar: u128, hint: MSMHintSmallScalar, derive_point_from_x_hint: DerivePointFromXHint, curve_index: usize @@ -303,7 +305,7 @@ fn scalar_mul_g1_fixed_small_scalar( // Hash everything to obtain a x coordinate. let (s0, s1, s2): (felt252, felt252, felt252) = hades_permutation( - 'MSM_G1', 0, 1 + 'MSM_G1_U128', 0, 1 ); // Init Sponge state let (s0, s1, s2) = hades_permutation( s0 + curve_index.into(), s1 + 1.into(), s2 @@ -317,8 +319,7 @@ fn scalar_mul_g1_fixed_small_scalar( // Hash result point let (s0, s1, s2) = hint.Q.update_hash_state(s0, s1, s2); // Hash scalar. - let (ep, en, _, _) = scalar_epns; - let (s0, _s1, _s2) = core::poseidon::hades_permutation(s0 + ep, s1 + en, s2); + let (s0, _s1, _s2) = core::poseidon::hades_permutation(s0 + scalar.into(), s1, s2); let random_point: G1Point = derive_ec_point_from_X( s0, @@ -332,15 +333,23 @@ fn scalar_mul_g1_fixed_small_scalar( random_point, get_a(curve_index), curve_index ); // Verify Q = scalar * P - zk_ecip_check( - array![point].span(), - array![scalar_epns], - hint.Q, - 1, - mb, - hint.SumDlogDiv, - random_point, - curve_index + + let (lhs) = ec::run_EVAL_FN_CHALLENGE_DUPL_1P_circuit( + A0: random_point, + A2: G1Point { x: mb.x_A2, y: mb.y_A2 }, + coeff0: mb.coeff0, + coeff2: mb.coeff2, + SumDlogDiv: hint.SumDlogDiv, + curve_index: curve_index + ); + let rhs = compute_rhs_ecip( + points: array![point].span(), + m_A0: mb.m_A0, + b_A0: mb.b_A0, + x_A0: random_point.x, + epns: array![scalar_epns], + Q_result: hint.Q, + curve_index: curve_index ); return hint.Q; diff --git a/src/src/lib.cairo b/src/src/lib.cairo index de6064d5..6afee496 100644 --- a/src/src/lib.cairo +++ b/src/src/lib.cairo @@ -7,7 +7,6 @@ pub mod groth16; pub mod basic_field_ops; mod tests; pub mod core; -pub mod risc0_utils; #[cfg(test)] diff --git a/src/src/utils.cairo b/src/src/utils.cairo index f115035b..bb7d9d1d 100644 --- a/src/src/utils.cairo +++ b/src/src/utils.cairo @@ -1,6 +1,8 @@ pub mod neg_3; pub mod hashing; pub mod calldata; +pub mod risc0; +pub mod drand; use core::circuit::{u384, u96}; diff --git a/src/src/utils/drand.cairo b/src/src/utils/drand.cairo new file mode 100644 index 00000000..4f25fbe8 --- /dev/null +++ b/src/src/utils/drand.cairo @@ -0,0 +1,832 @@ +use core::sha256::compute_sha256_u32_array; +use garaga::utils::usize_assert_eq; +use core::circuit::{ + RangeCheck96, AddMod, MulMod, u384, u96, CircuitElement, CircuitInput, circuit_add, circuit_sub, + circuit_mul, circuit_inverse, EvalCircuitResult, EvalCircuitTrait, CircuitOutputsTrait, + CircuitModulus, AddInputResultTrait, CircuitInputs, CircuitInputAccumulator +}; +use garaga::core::circuit::AddInputResultTrait2; +use garaga::definitions::{G1Point, G2Point, u384Serde}; +use garaga::basic_field_ops::{u512_mod_bls12_381, is_even_u384}; +use core::num::traits::Zero; +use garaga::ec_ops::{ + ec_safe_add, scalar_mul_g1_fixed_small_scalar, MSMHintSmallScalar, DerivePointFromXHint, + FunctionFelt, msm_g1_u128 +}; +use garaga::circuits::isogeny::run_BLS12_381_APPLY_ISOGENY_BLS12_381_circuit; +use garaga::circuits::ec::run_ADD_EC_POINT_circuit; +// Chain: 52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971 +// Public Key: +// G2Point(x=(2020076495541918814736776030432697997716141464538799718886374996015782362070437455929656164150586936230283253179482, +// 586231829158603972936263795113906716025771067144631327612230935308837823978471744132589153452744931590357767971921), +// y=(1791278522428100783277199431487181031376873968689022069271761201187685493801088467849610331824611383166297460070456, +// 3748041376541174045371877684805027382480271890984968787916314231755985669195299696440090936404461850913289003455520), +// curve_id=) +// Period: 3 seconds +// Genesis Time: 1692803367 +// Hash: 52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971 +// Group Hash: f477d5c89f21a17c863a7f937c6a6d15859414d2be09cd448d4279af331c5d3e +// Scheme ID: bls-unchained-g1-rfc9380 +// Beacon ID: quicknet +// ---------------------------------------- +// Note : Negated to use in pairing check. +const DRAND_QUICKNET_PUBLIC_KEY: G2Point = + G2Point { + x0: u384 { + limb0: 0x4bc09e76eae8991ef5ece45a, + limb1: 0xbd274ca73bab4af5a6e9c76a, + limb2: 0x3aaf4bcb5ed66304de9cf809, + limb3: 0xd1fec758c921cc22b0e17e6 + }, + x1: u384 { + limb0: 0x6a0a6c3ac6a5776a2d106451, + limb1: 0xb90022d3e760183c8c4b450b, + limb2: 0xcad3912212c437e0073e911f, + limb3: 0x3cf0f2896adee7eb8b5f01f + }, + y0: u384 { + limb0: 0xdfd038b83dbad4e0fbae5838, + limb1: 0x942ea644bed4152aa6d85248, + limb2: 0x43812423f8525883c7e472fa, + limb3: 0xba35f3379c4e4d1e3a70b08 + }, + y1: u384 { + limb0: 0xd9aa8e74b5823224c149d420, + limb1: 0x1851f5129301fe6603fc716a, + limb2: 0x9b84512e61a5e814e923569d, + limb3: 0x1859fcf74bc8a580a828f6e0 + } + }; + +const a_iso_swu: u384 = + u384 { + limb0: 0xa0e0f97f5cf428082d584c1d, + limb1: 0xd8e8981aefd881ac98936f8d, + limb2: 0xc96d4982b0ea985383ee66a8, + limb3: 0x144698a3b8e9433d693a02 + }; +const b_iso_swu: u384 = + u384 { + limb0: 0x316ceaa5d1cc48e98e172be0, + limb1: 0xa0b9c14fcef35ef55a23215a, + limb2: 0x753eee3b2016c1f0f24f4070, + limb3: 0x12e2908d11688030018b12e8 + }; + +const z_iso_swu: u384 = u384 { limb0: 11, limb1: 0, limb2: 0, limb3: 0 }; + + +const NZ_POW2_32_64: NonZero = 0x100000000; +// lib_str + bytes([0]) + dst_prime +// LIB_DST = b'\x00\x80\x00BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_+' +// bytes len : 47. +const LIB_DST: [ + u32 + ; 11] = [ + 0x800042, + 0x4c535f53, + 0x49475f42, + 0x4c533132, + 0x33383147, + 0x315f584d, + 0x443a5348, + 0x412d3235, + 0x365f5353, + 0x57555f52, + 0x4f5f4e55, +]; + +const LIB_DST_LAST_WORD: u32 = 0x4c5f2b; + + +const I_DST_PRIME: [ + u32 + ; 10] = [ + 0x5f534947, + 0x5f424c53, + 0x31323338, + 0x3147315f, + 0x584d443a, + 0x5348412d, + 0x3235365f, + 0x53535755, + 0x5f524f5f, + 0x4e554c5f, +]; +const I_DST_PRIME_LAST_WORD: u32 = 0x2b; + +fn get_i_dst_prime_first_word(i: usize) -> u32 { + return i.into() * 0x1000000 + 0x424c53; +} + +#[derive(Drop, Serde)] +struct MapToCurveHint { + gx1_is_square: bool, + y1: u384, + y_flag: bool, // true if y and u have same parity, false otherwise +} + +#[derive(Drop, Serde)] +struct HashToCurveHint { + f0_hint: MapToCurveHint, + f1_hint: MapToCurveHint, + scalar_mul_hint: MSMHintSmallScalar, + derive_point_from_x_hint: DerivePointFromXHint, +} + + +// Like hash to curve but we start with the drand round number for simplicity. +fn round_to_curve_bls12_381(round: u64, hash_to_curve_hint: HashToCurveHint,) -> G1Point { + let message = round_to_message(round); + return hash_to_curve_bls12_381(message, hash_to_curve_hint); +} + +#[inline] +fn hash_to_curve_bls12_381(message: [u32; 8], hash_to_curve_hint: HashToCurveHint,) -> G1Point { + let (felt0, felt1) = hash_to_two_bls_felts(message); + let pt0 = map_to_curve(felt0, hash_to_curve_hint.f0_hint); + let pt1 = map_to_curve(felt1, hash_to_curve_hint.f1_hint); + + let (sum) = run_ADD_EC_POINT_circuit(pt0, pt1, 1); + let (sum) = run_BLS12_381_APPLY_ISOGENY_BLS12_381_circuit(sum); + + // clear cofactor : + let res = scalar_mul_g1_fixed_small_scalar( + sum, + BLS_COFACTOR_EPNS, + BLS_COFACTOR, + hash_to_curve_hint.scalar_mul_hint, + hash_to_curve_hint.derive_point_from_x_hint, + 1 + ); + return res; +} + + +// x = BLS seed +// n = BLS12_381 EC prime order subgroup +// cofactor = (1 - (x % n)) % n +// const bls_cofactor: u128 = 0xd201000000010001; +const BLS_COFACTOR_EPNS: (felt252, felt252, felt252, felt252) = + (12124305939094075449, 3008070283847567304, 1, -1); +const BLS_COFACTOR: u128 = 0xd201000000010001; + +// "digest function" +fn round_to_message(round: u64) -> [u32; 8] { + let (high, low) = DivRem::div_rem(round, NZ_POW2_32_64); + let mut array: Array = array![]; + array.append(high.try_into().unwrap()); + array.append(low.try_into().unwrap()); + return compute_sha256_u32_array(input: array, last_input_word: 0, last_input_num_bytes: 0); +} + + +#[inline] +fn xor_u32_array(a: [u32; 8], b: [u32; 8]) -> [u32; 8] { + let [a0, a1, a2, a3, a4, a5, a6, a7] = a; + let [b0, b1, b2, b3, b4, b5, b6, b7] = b; + return [a0 ^ b0, a1 ^ b1, a2 ^ b2, a3 ^ b3, a4 ^ b4, a5 ^ b5, a6 ^ b6, a7 ^ b7]; +} + +const POW_2_32: u128 = 0x100000000; +const POW_2_64: u128 = 0x10000000000000000; +const POW_2_96: u128 = 0x100000000000000000000; + +fn u32_array_to_u256(d: [u32; 8]) -> u256 { + let [d0, d1, d2, d3, d4, d5, d6, d7] = d; + let high: felt252 = d0.into() * POW_2_96.into() + + d1.into() * POW_2_64.into() + + d2.into() * POW_2_32.into() + + d3.into(); + let low: felt252 = d4.into() * POW_2_96.into() + + d5.into() * POW_2_64.into() + + d6.into() * POW_2_32.into() + + d7.into(); + + return u256 { low: low.try_into().unwrap(), high: high.try_into().unwrap() }; +} + +fn hash_to_two_bls_felts(message: [u32; 8]) -> (u384, u384) { + let mut array: Array = array![]; + // Pad with 64 0-bytes. In u32, this is 64 / 4 = 16 elements. + // "Z_padd" + array.append(0); + array.append(0); + array.append(0); + array.append(0); + array.append(0); + array.append(0); + array.append(0); + array.append(0); + array.append(0); + array.append(0); + array.append(0); + array.append(0); + array.append(0); + array.append(0); + array.append(0); + array.append(0); + // msg. 8*4 = 32 bytes + for v in message.span() { + array.append(*v); + }; + // LIB_DST 47 bytes + for v in LIB_DST.span() { + array.append(*v); + }; + // Total : 64 + 32 + 47 = 143 bytes = 1144 bits. + let b0 = compute_sha256_u32_array( + input: array, last_input_word: LIB_DST_LAST_WORD, last_input_num_bytes: 3 + ); + let mut array: Array = array![]; + for v in b0.span() { + array.append(*v); + }; + + array.append(get_i_dst_prime_first_word(1)); + for v in I_DST_PRIME.span() { + array.append(*v); + }; + let bi = compute_sha256_u32_array( + input: array, last_input_word: I_DST_PRIME_LAST_WORD, last_input_num_bytes: 1 + ); + let bi_xor_b0 = xor_u32_array(bi, b0); + let mut array: Array = array![]; + + for v in bi_xor_b0.span() { + array.append(*v); + }; + array.append(get_i_dst_prime_first_word(2)); + for v in I_DST_PRIME.span() { + array.append(*v); + }; + + let bi_1 = compute_sha256_u32_array(array, I_DST_PRIME_LAST_WORD, 1); + + let bi1_xor_b0 = xor_u32_array(bi_1, b0); + let mut array: Array = array![]; + for v in bi1_xor_b0.span() { + array.append(*v); + }; + array.append(get_i_dst_prime_first_word(3)); + for v in I_DST_PRIME.span() { + array.append(*v); + }; + let bi_2 = compute_sha256_u32_array(array, I_DST_PRIME_LAST_WORD, 1); + + let bi2_xor_b0 = xor_u32_array(bi_2, b0); + let mut array: Array = array![]; + for v in bi2_xor_b0.span() { + array.append(*v); + }; + array.append(get_i_dst_prime_first_word(4)); + for v in I_DST_PRIME.span() { + array.append(*v); + }; + let bi_3 = compute_sha256_u32_array(array, I_DST_PRIME_LAST_WORD, 1); + + return (u512_mod_bls12_381(bi, bi_1), u512_mod_bls12_381(bi_2, bi_3)); +} + + +fn map_to_curve(_u: u384, hint: MapToCurveHint) -> G1Point { + let (neg_ta, num_x1) = map_to_curve_inner_1(_u); + let (gx1, div) = map_to_curve_inner_2(neg_ta, num_x1); + match hint.gx1_is_square { + true => map_to_curve_inner_final_quad_res(num_x1, gx1, hint.y1, hint.y_flag, div, _u), + false => map_to_curve_inner_final_not_quad_res(num_x1, hint.y1, hint.y_flag, div, _u, gx1), + } +} + +fn map_to_curve_inner_1(_u: u384) -> (u384, u384) { + let z = CircuitElement::> {}; + let u = CircuitElement::> {}; + let zero = CircuitElement::> {}; + let one = CircuitElement::> {}; + let b = CircuitElement::> {}; + + let u2 = circuit_mul(u, u); + let zeta_u2 = circuit_mul(z, u2); + let zeta_u2_square = circuit_mul(zeta_u2, zeta_u2); + let ta = circuit_add(zeta_u2_square, zeta_u2); + let neg_ta = circuit_sub(zero, ta); + let num_x1 = circuit_mul(b, circuit_add(ta, one)); + + let modulus = TryInto::< + _, CircuitModulus + >::try_into( + [ + 0xb153ffffb9feffffffffaaab, + 0x6730d2a0f6b0f6241eabfffe, + 0x434bacd764774b84f38512bf, + 0x1a0111ea397fe69a4b1ba7b6 + ] + ) + .unwrap(); // BLS12_381 prime field modulus + + let outputs = (neg_ta, num_x1) + .new_inputs() + .next_2(z_iso_swu) + .next_2(_u) + .next_2([0, 0, 0, 0]) + .next_2([1, 0, 0, 0]) + .next_2(b_iso_swu) + .done_2() + .eval(modulus) + .unwrap(); + + return (outputs.get_output(neg_ta), outputs.get_output(num_x1)); +} + +fn map_to_curve_inner_2(_neg_ta: u384, _num_x1: u384) -> (u384, u384) { + let neg_ta_or_z = CircuitElement::> {}; + let a = CircuitElement::> {}; + let b = CircuitElement::> {}; + // let quad_res_correction = CircuitElement::> {}; + // let y1_hint = CircuitElement::> {}; + let num_x1 = CircuitElement::> {}; + // let zeta_u2 = CircuitElement::> {}; + // let u = CircuitElement::> {}; + + let div = circuit_mul(a, neg_ta_or_z); + let num2_x1 = circuit_mul(num_x1, num_x1); + let div2 = circuit_mul(div, div); + let div3 = circuit_mul(div2, div); + // num_gx1 = (num2_x1 + a * div2) * num_x1 + b * div3 + + let num_gx1 = circuit_add( + circuit_mul(circuit_add(num2_x1, circuit_mul(a, div2)), num_x1), circuit_mul(b, div3) + ); + + // let num_x2 = circuit_mul(zeta_u2, num_x1); + + let gx1 = circuit_mul(num_gx1, circuit_inverse(div3)); + + // let gx1_quad_res = circuit_mul(gx1, quad_res_correction); + // let check = circuit_sub(gx1_quad_res, circuit_mul(y1_hint, y1_hint)); + + // let y2 = circuit_mul(zeta_u2, circuit_mul(u, y1_hint)); + + let _neg_ta_or_z = match _neg_ta.is_zero() { + true => z_iso_swu, + false => _neg_ta, + }; + + // let _quad_res_correction = match hint.gx1_is_square { + // true => u384 { limb0: 0x1, limb1: 0x0, limb2: 0x0, limb3: 0x0, }, + // false => z_iso_swu, + // }; + + let modulus = TryInto::< + _, CircuitModulus + >::try_into( + [ + 0xb153ffffb9feffffffffaaab, + 0x6730d2a0f6b0f6241eabfffe, + 0x434bacd764774b84f38512bf, + 0x1a0111ea397fe69a4b1ba7b6 + ] + ) + .unwrap(); // BLS12_381 prime field modulus + + let outputs = (gx1, div) + .new_inputs() + .next_2(_neg_ta_or_z) + .next_2(a_iso_swu) + .next_2(b_iso_swu) + .next_2(_num_x1) + .done_2() + .eval(modulus) + .unwrap(); + + return (outputs.get_output(gx1), outputs.get_output(div)); +} + + +fn map_to_curve_inner_final_quad_res( + _num_x1: u384, _gx1: u384, _y1_hint: u384, __parity_flag: bool, _div: u384, u: u384 +) -> G1Point { + let num_x1 = CircuitElement::> {}; + let gx1 = CircuitElement::> {}; + let y1_hint = CircuitElement::> {}; + let parity_flag = CircuitElement::> {}; + let div = CircuitElement::> {}; + + let check = circuit_sub(gx1, circuit_mul(y1_hint, y1_hint)); + let x_affine = circuit_mul(num_x1, circuit_inverse(div)); + let y_affine = circuit_mul(parity_flag, y1_hint); + + let modulus = TryInto::< + _, CircuitModulus + >::try_into( + [ + 0xb153ffffb9feffffffffaaab, + 0x6730d2a0f6b0f6241eabfffe, + 0x434bacd764774b84f38512bf, + 0x1a0111ea397fe69a4b1ba7b6 + ] + ) + .unwrap(); // BLS12_381 prime field modulus + + // Flag = -1 if y%2 !=u%1 ; 1 if y%2 == u%2. + + let _parity_flag: u384 = match __parity_flag { + true => u384 { limb0: 0x1, limb1: 0x0, limb2: 0x0, limb3: 0x0, }, + false => crate::definitions::get_min_one(curve_index: 1), + }; + + let outputs = (x_affine, y_affine, check,) + .new_inputs() + .next_2(_num_x1) + .next_2(_gx1) + .next_2(_y1_hint) + .next_2(_parity_flag) + .next_2(_div) + .done_2() + .eval(modulus) + .unwrap(); + + let chk = outputs.get_output(check); + assert(chk == Zero::zero(), 'm2cI wrong square root'); + // Verify parity. base is even so high parts doesn't affect parity. + // (l0 + l1*2^b + l2*2^2b + l3*2^3b % 2 + // l0 % 2 + (l1 % 2)*2^b % 2 + (l2 % 2)*2^2b % 2 + (l3 % 2)*2^3b % 2 + // 2^b = 0 for all b>=1 + // so u384 % 2 = limb0 % 2. + match __parity_flag { + true => assert(is_even_u384(_y1_hint) == is_even_u384(u), 'm2cI wrong parity'), + false => assert(is_even_u384(_y1_hint) != is_even_u384(u), 'm2cI wrong parity'), + } + + return G1Point { x: outputs.get_output(x_affine), y: outputs.get_output(y_affine) }; +} + + +fn map_to_curve_inner_final_not_quad_res( + _num_x1: u384, _y1_hint: u384, __parity_flag: bool, _div: u384, _u: u384, _gx1: u384 +) -> G1Point { + let num_x1 = CircuitElement::> {}; + let y1_hint = CircuitElement::> {}; + let parity_flag = CircuitElement::> {}; + let div = CircuitElement::> {}; + let u = CircuitElement::> {}; + let gx1 = CircuitElement::> {}; + let z = CircuitElement::> {}; + + let u2 = circuit_mul(u, u); + let zeta_u2 = circuit_mul(z, u2); + let gx1_quad_res = circuit_mul(gx1, z); + let check = circuit_sub(gx1_quad_res, circuit_mul(y1_hint, y1_hint)); + let y2 = circuit_mul(zeta_u2, circuit_mul(u, y1_hint)); + let num_x = circuit_mul(zeta_u2, num_x1); + let x_affine = circuit_mul(num_x, circuit_inverse(div)); + let y_affine = circuit_mul(parity_flag, y2); + + // Flag = -1 if y%2 !=u%1 ; 1 if y%2 == u%2. + let _parity_flag: u384 = match __parity_flag { + true => u384 { limb0: 0x1, limb1: 0x0, limb2: 0x0, limb3: 0x0, }, + false => crate::definitions::get_min_one(curve_index: 1), + }; + let modulus = TryInto::< + _, CircuitModulus + >::try_into( + [ + 0xb153ffffb9feffffffffaaab, + 0x6730d2a0f6b0f6241eabfffe, + 0x434bacd764774b84f38512bf, + 0x1a0111ea397fe69a4b1ba7b6 + ] + ) + .unwrap(); // BLS12_381 prime field modulus + + let outputs = (x_affine, y_affine, check,) + .new_inputs() + .next_2(_num_x1) + .next_2(_y1_hint) + .next_2(_parity_flag) + .next_2(_div) + .next_2(_u) + .next_2(_gx1) + .next_2(z_iso_swu) + .done_2() + .eval(modulus) + .unwrap(); + + let chk = outputs.get_output(check); + assert(chk == Zero::zero(), 'm2cII wrong square root'); + + // Verify parity. base is even so high parts doesn't affect parity. + match __parity_flag { + true => assert( + is_even_u384(outputs.get_output(y2)) == is_even_u384(_u), 'm2cI wrong parity' + ), + false => assert( + is_even_u384(outputs.get_output(y2)) != is_even_u384(_u), 'm2cI wrong parity' + ), + } + return G1Point { x: outputs.get_output(x_affine), y: outputs.get_output(y_affine) }; +} + + +#[cfg(test)] +mod tests { + use super::{ + DRAND_QUICKNET_PUBLIC_KEY, hash_to_two_bls_felts, u384, G1Point, MapToCurveHint, + map_to_curve, HashToCurveHint, MSMHintSmallScalar, DerivePointFromXHint, + hash_to_curve_bls12_381, FunctionFelt, run_BLS12_381_APPLY_ISOGENY_BLS12_381_circuit + }; + use garaga::ec_ops::{G2PointTrait}; + + #[test] + fn test_drand_quicknet_public_key() { + DRAND_QUICKNET_PUBLIC_KEY.assert_on_curve(1); + } + #[test] + fn test_hash_to_two_bls_felts() { + // sha256("Hello, World!") + let message: [u32; 8] = [ + 0xdffd6021, + 0xbb2bd5b0, + 0xaf676290, + 0x809ec3a5, + 0x3191dd81, + 0xc7f70a4b, + 0x28688a36, + 0x2182986f, + ]; + let (a, b) = hash_to_two_bls_felts(message); + + assert_eq!( + a, + u384 { + limb0: 0x3424dff585d947fedf210456, + limb1: 0xd67576428da87a9356340b2e, + limb2: 0x135e368f3927494b3933a985, + limb3: 0x85a31dc6b81af709df9ba4e + } + ); + assert_eq!( + b, + u384 { + limb0: 0xdb509060a0293b7d9e20ae9, + limb1: 0x189ad7a1508b89604e165848, + limb2: 0x74a42a64a63d7c9dd6bfec2c, + limb3: 0x1049922d5dcd716806ccfa3e + } + ); + } + + #[test] + fn test_map_to_curve() { + let u = u384 { limb0: 42, limb1: 0x0, limb2: 0x0, limb3: 0x0, }; + + let expected = G1Point { + x: u384 { + limb0: 0x1c94f3121ca3e1454e60bded, + limb1: 0xe09a5f66977f922ae74baf50, + limb2: 0xa471b958de9a5099a84aca44, + limb3: 0x923f1e3115dc78a457fffa1 + }, + y: u384 { + limb0: 0xaa8806e6b469554a91758ec, + limb1: 0xdbfb03df4a53a534ac80def7, + limb2: 0xb81c6297bbac342050bff567, + limb3: 0xfb9022e050807db4b155d87 + } + }; + let hint = MapToCurveHint { + gx1_is_square: false, + y1: u384 { + limb0: 0x8c74c126c6351052ebf1965, + limb1: 0x979aba6acb3e5dfca5581a51, + limb2: 0x49e43c123f4e034706485bde, + limb3: 0x152ffaf0e2cd3fbbb102b5e1 + }, + y_flag: false + }; + let res = map_to_curve(u, hint); + assert_eq!(res, expected); + } + + #[test] + fn test_isogeny() { + let pt = G1Point { + x: u384 { + limb0: 0xfe95b6d6dc4c28b03aa82194, + limb1: 0xc06a9cdc69f9d39a1cb3c132, + limb2: 0xc0637d447baf4f55d4658b59, + limb3: 0x166e53a3af1733961f92e08 + }, + y: u384 { + limb0: 0x5dc860b68c76e432263e15dc, + limb1: 0x8c9990a0f89eadd580f71395, + limb2: 0xaf300dff12d93cfe32b45c5d, + limb3: 0x8f6e2a59628049aecb84109 + } + }; + + let expected = G1Point { + x: u384 { + limb0: 0x5fad5b4abf0d9b5a5500069, + limb1: 0x88e3293255d2172755b29514, + limb2: 0x2562887a0b9a729cf8f6f807, + limb3: 0xfb545dd46e90e6f6bd679a1 + }, + y: u384 { + limb0: 0xbea8d03c186753a97b5e8e0b, + limb1: 0xbe3e7a1eb25cf6d7fa6f686d, + limb2: 0x72026b41a862ff1fa8508191, + limb3: 0xd596c01e510faf25030e9a5 + }, + }; + let (res) = run_BLS12_381_APPLY_ISOGENY_BLS12_381_circuit(pt); + assert_eq!(res, expected); + } + #[test] + fn test_hash_to_curve() { + let message: [u32; 8] = [ + 0xdffd6021, + 0xbb2bd5b0, + 0xaf676290, + 0x809ec3a5, + 0x3191dd81, + 0xc7f70a4b, + 0x28688a36, + 0x2182986f, + ]; + let hint = HashToCurveHint { + f0_hint: MapToCurveHint { + gx1_is_square: true, + y1: u384 { + limb0: 0xf26e7fd3c2733a0413db4463, + limb1: 0xa1562d011f360461be8e36dd, + limb2: 0x84a83147a7e7a1311a712501, + limb3: 0x1290f63f6daa85ad6bf7088a + }, + y_flag: false + }, + f1_hint: MapToCurveHint { + gx1_is_square: false, + y1: u384 { + limb0: 0xb88f6c46cebe267f9e2afa6c, + limb1: 0xa845982734193f6f44e49212, + limb2: 0x63e1f53f7553752da88fb12c, + limb3: 0xd613d3f488be39870f05a5c + }, + y_flag: false + }, + scalar_mul_hint: MSMHintSmallScalar { + Q: G1Point { + x: u384 { + limb0: 0x931f614913b4e856c2a5dd1b, + limb1: 0xce68eade0d43210615956b1d, + limb2: 0x4f2c8c74301387552679068d, + limb3: 0xcc12bfa116dae0017adb178 + }, + y: u384 { + limb0: 0x6b02cc408fda040be6918d1e, + limb1: 0x325a198e22c4131c6fed473b, + limb2: 0xf0bbbddfea59e5a96a11bd20, + limb3: 0xeb05659d43180b59cee2ea0 + } + }, + SumDlogDiv: FunctionFelt { + a_num: array![ + u384 { + limb0: 0xe9547e3c22c368f3668c26d2, + limb1: 0x75bc3174101565eeb65968d6, + limb2: 0x3afe08b77f8913061d67f0b2, + limb3: 0xc3a508ed77d2e5fd684d134 + }, + u384 { limb0: 0x3f41b003a7dbf839, limb1: 0x0, limb2: 0x0, limb3: 0x0 } + ] + .span(), + a_den: array![ + u384 { + limb0: 0xe992bce6bcd56741b4be8dda, + limb1: 0x975f2e11a8fc4e110f1b44ba, + limb2: 0xc1e9530f84e3a7e0a46d33e1, + limb3: 0x88dd6a0666b7d5a4c14ea85 + }, + u384 { + limb0: 0x4d6f4786473f4ff1643a5ee, + limb1: 0x25cb9788a504f44e94bddec4, + limb2: 0xe8adc9bc8ead85ba812bddf7, + limb3: 0x53655ff5e6a7e350e3028ac + }, + u384 { limb0: 0x1, limb1: 0x0, limb2: 0x0, limb3: 0x0 } + ] + .span(), + b_num: array![ + u384 { + limb0: 0x743a827dc9c4737c7a70322d, + limb1: 0x7bfda798292e0429f35febf0, + limb2: 0x7bca28663f0d7795d8629dc2, + limb3: 0x1eb8b6c2989bb00ee12bd00 + }, + u384 { + limb0: 0xdc2fa95b1c3dadfa185f4ff4, + limb1: 0x9daea3eea2647b9adc25d4ea, + limb2: 0x24dbf64222ab9fcb34052520, + limb3: 0x124e8c93a451aaeb0b256a + }, + u384 { + limb0: 0x3e58c1d601349a222ca499e8, + limb1: 0x6c6aaf8d55c9039164e09e20, + limb2: 0xfb431077e445c903bc81ed03, + limb3: 0xc08aa0954aa40b81be4fdf9 + } + ] + .span(), + b_den: array![ + u384 { + limb0: 0xf4f6f39b39569d06d2fa8cbd, + limb1: 0xf64be5a5ad4042201dc112ec, + limb2: 0xc4599f66af1753fd9e2fbcc6, + limb3: 0x8364897602e0ecee5380260 + }, + u384 { + limb0: 0x135bd1e191cfd3fc590e97b8, + limb1: 0x972e5e229413d13a52f77b10, + limb2: 0xa2b726f23ab616ea04af77dc, + limb3: 0x14d957fd79a9f8d438c0a2b3 + }, + u384 { limb0: 0x4, limb1: 0x0, limb2: 0x0, limb3: 0x0 }, + u384 { + limb0: 0xe992bce6bcd56741b4be8dda, + limb1: 0x975f2e11a8fc4e110f1b44ba, + limb2: 0xc1e9530f84e3a7e0a46d33e1, + limb3: 0x88dd6a0666b7d5a4c14ea85 + }, + u384 { + limb0: 0x4d6f4786473f4ff1643a5ee, + limb1: 0x25cb9788a504f44e94bddec4, + limb2: 0xe8adc9bc8ead85ba812bddf7, + limb3: 0x53655ff5e6a7e350e3028ac + }, + u384 { limb0: 0x1, limb1: 0x0, limb2: 0x0, limb3: 0x0 } + ] + .span() + }, + }, + derive_point_from_x_hint: DerivePointFromXHint { + y_last_attempt: u384 { + limb0: 0xb41227cd42b7ef71d89d05e6, + limb1: 0x3cc2397220b0e255eb196131, + limb2: 0x6e445b08463f6f4d96d3e54, + limb3: 0x2d18f52270acbae6773fc2d + }, + g_rhs_sqrt: array![ + u384 { + limb0: 0x489c3c21e68b52fc13551cc7, + limb1: 0xbb28e4fee8814d3f2f01d56d, + limb2: 0x80fb27b5cbf818227f16956b, + limb3: 0x591848cb4740509e9519aa6 + }, + u384 { + limb0: 0x49a5971b41da691b6c54c9ce, + limb1: 0x4934d801184f79e0bd159c78, + limb2: 0xb65685c7a705678007327db4, + limb3: 0x878b66031665700502ead64 + }, + u384 { + limb0: 0x8cc9746861ef5ebb714c1aad, + limb1: 0x3f2d8a4b2b9b1e0c15f8a888, + limb2: 0x72b4b3e003c80b045232c974, + limb3: 0x6f360afb566d59ae9d3dcb1 + }, + u384 { + limb0: 0xc1dafeb229958918d6f807bf, + limb1: 0x82f92ae44451b0c83ca491d3, + limb2: 0xa547d45e3abd786d7e4bd18a, + limb3: 0xb04d1504a41448451e1bf6d + }, + u384 { + limb0: 0x62564d5dadfa6951c74d9994, + limb1: 0x938bc3286f0b2fc8671794d8, + limb2: 0xd176d81898f67fe46da9c716, + limb3: 0x297c2b03926eec52554f824 + } + ], + } + }; + + let expected = G1Point { + x: u384 { + limb0: 0x931f614913b4e856c2a5dd1b, + limb1: 0xce68eade0d43210615956b1d, + limb2: 0x4f2c8c74301387552679068d, + limb3: 0xcc12bfa116dae0017adb178 + }, + y: u384 { + limb0: 0x6b02cc408fda040be6918d1e, + limb1: 0x325a198e22c4131c6fed473b, + limb2: 0xf0bbbddfea59e5a96a11bd20, + limb3: 0xeb05659d43180b59cee2ea0 + }, + }; + let res = hash_to_curve_bls12_381(message, hint); + assert_eq!(res, expected); + } +} + diff --git a/src/src/utils/hashing.cairo b/src/src/utils/hashing.cairo index 7a8af7df..0374cdad 100644 --- a/src/src/utils/hashing.cairo +++ b/src/src/utils/hashing.cairo @@ -1,6 +1,8 @@ use core::poseidon::hades_permutation; use core::circuit::{u384, u96}; -use garaga::definitions::{E12D, u288, G1G2Pair, E12DMulQuotient, MillerLoopResultScalingFactor}; +use garaga::definitions::{ + E12D, u288, G1G2Pair, G1Point, E12DMulQuotient, MillerLoopResultScalingFactor +}; #[derive(Copy, Drop)] struct PoseidonState { @@ -410,3 +412,14 @@ pub fn hash_G1G2Pair( return (s0, s1, s2); } + +pub fn hash_G1Point(point: G1Point) -> felt252 { + let base: felt252 = 79228162514264337593543950336; // 2**96 + let in_1: felt252 = point.x.limb0.into() + base * point.x.limb1.into(); + let in_2: felt252 = point.x.limb2.into() + base * point.x.limb3.into(); + let (s0, s1, s2) = hades_permutation(in_1, in_2, 2); + let in_1 = s0 + point.y.limb0.into() + base * point.y.limb1.into(); + let in_2 = s1 + point.y.limb2.into() + base * point.y.limb3.into(); + let (s0, s1, s2) = hades_permutation(in_1, in_2, s2); + return s0; +} diff --git a/src/src/risc0_utils.cairo b/src/src/utils/risc0.cairo similarity index 100% rename from src/src/risc0_utils.cairo rename to src/src/utils/risc0.cairo diff --git a/tests/contracts_e2e/e2e_test.py b/tests/contracts_e2e/e2e_test.py index 7a929c9b..467e3bf8 100644 --- a/tests/contracts_e2e/e2e_test.py +++ b/tests/contracts_e2e/e2e_test.py @@ -21,6 +21,9 @@ from garaga.starknet.groth16_contract_generator.parsing_utils import ( find_item_from_key_patterns, ) +from garaga.starknet.tests_and_calldata_generators.drand_calldata import ( + drand_round_to_calldata, +) CONTRACTS_PATH = Path("src/contracts") @@ -147,3 +150,74 @@ async def test_groth16_contracts(account_devnet: BaseAccount, contract_info: dic await invoke_result.wait_for_acceptance() print(f"Invoke result : {invoke_result.status}") + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + "contract_info", + [ + { + "contract_project": SmartContractProject( + smart_contract_folder=CONTRACTS_PATH / "drand_quicknet" + ) + }, + ], +) +async def test_drand_contract(account_devnet: BaseAccount, contract_info: dict): + account = account_devnet + contract_project: SmartContractProject = contract_info["contract_project"] + + print(f"ACCOUNT {hex(account.address)}, NONCE {await account.get_nonce()}") + + drand_class_hash, drand_abi = await contract_project.declare_class_hash(account) + + print(f"Declared contract class hash: {hex(drand_class_hash)}") + + # Deploy the drand contract + precomputed_address = compute_address( + class_hash=drand_class_hash, + constructor_calldata=[], + salt=pedersen_hash(to_int(account.address), 1), + deployer_address=DEPLOYER_ADDRESS, + ) + + try_contract = await get_contract_if_exists(account, precomputed_address) + if try_contract is None: + deploy_result = await Contract.deploy_contract_v1( + account=account, + class_hash=drand_class_hash, + abi=drand_abi, + deployer_address=DEPLOYER_ADDRESS, + auto_estimate=True, + salt=1, + cairo_version=1, + ) + await deploy_result.wait_for_acceptance() + + contract = deploy_result.deployed_contract + else: + print(f"Contract already deployed at {hex(precomputed_address)}") + contract = try_contract + + print(f"Deployed contract address: {hex(contract.address)}") + print(f"Deployed contract: {contract.functions}") + + function_call: ContractFunction = find_item_from_key_patterns( + contract.functions, ["verify_round_and_get_randomness"] + ) + + for drand_round in range(1, 5): + prepare_invoke = PreparedFunctionInvokeV3( + to_addr=function_call.contract_data.address, + calldata=drand_round_to_calldata(drand_round), + selector=function_call.get_selector(function_call.name), + l1_resource_bounds=None, + _contract_data=function_call.contract_data, + _client=function_call.client, + _account=function_call.account, + _payload_transformer=function_call._payload_transformer, + ) + + invoke_result: InvokeResult = await prepare_invoke.invoke(auto_estimate=True) + + await invoke_result.wait_for_acceptance() diff --git a/tests/hydra/test_drand.py b/tests/hydra/test_drand.py new file mode 100644 index 00000000..30207213 --- /dev/null +++ b/tests/hydra/test_drand.py @@ -0,0 +1,64 @@ +import hashlib + +import pytest + +from garaga.definitions import CurveID, G2Point +from garaga.drand.client import ( + DrandNetwork, + digest_func, + get_randomness, + print_all_chain_info, +) +from garaga.signature import hash_to_curve + + +@pytest.mark.parametrize("round_number", list(range(1, 5)) + list(range(1000, 1005))) +def test_drand_sig_verification(round_number: int): + chain_infos = print_all_chain_info() + + network = DrandNetwork.quicknet + chain = chain_infos[network] + + round = get_randomness(chain.hash, round_number) + print(f"Randomness for round {round_number}:", round) + sha256 = hashlib.sha256() + sha256.update(bytes.fromhex(round.signature)) + print("randomness", sha256.hexdigest()) + print("random beacon", hex(round.randomness)) + + msg_point = hash_to_curve( + digest_func(round.round_number), CurveID.BLS12_381, "sha256" + ) + print("message", msg_point) + + from garaga.definitions import G1G2Pair + + # Temp fix before we figure out correct deserialization of message point. + if ( + G1G2Pair.pair( + [ + G1G2Pair( + p=round.signature_point, q=G2Point.get_nG(CurveID.BLS12_381, 1) + ), + G1G2Pair(p=msg_point, q=-chain.public_key), + ], + curve_id=CurveID.BLS12_381, + ).value_coeffs + == [1] + [0] * 11 + ): + print("Signature verification passed") + elif ( + G1G2Pair.pair( + [ + G1G2Pair( + p=round.signature_point, q=G2Point.get_nG(CurveID.BLS12_381, 1) + ), + G1G2Pair(p=msg_point, q=chain.public_key), + ], + curve_id=CurveID.BLS12_381, + ).value_coeffs + == [1] + [0] * 11 + ): + print("Signature verification passed") + else: + print("Signature verification failed") diff --git a/tools/make/bytecode_check.sh b/tools/make/bytecode_check.sh index 6e29fae5..097478d8 100755 --- a/tools/make/bytecode_check.sh +++ b/tools/make/bytecode_check.sh @@ -18,3 +18,8 @@ cd ../universal_ecip scarb build bytecode_length=$(jq '.bytecode | length' ./target/dev/universal_ecip_UniversalECIP.compiled_contract_class.json) echo "Bytecode length ECIP: $bytecode_length" + +cd ../drand_quicknet +scarb build +bytecode_length=$(jq '.bytecode | length' ./target/dev/drand_quicknet_DrandQuicknet.compiled_contract_class.json) +echo "Bytecode length DRAND: $bytecode_length" From fa27403e6aa2c968a369c6da6ddfbd8da36a42f3 Mon Sep 17 00:00:00 2001 From: feltroid Prime <96737978+feltroidprime@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:38:13 +0200 Subject: [PATCH 4/4] Add Copy trait to msm hints structs. (#204) --- .../groth16_contract_generator/generator.py | 2 +- .../tests_and_calldata_generators/msm.py | 2 +- src/Scarb.toml | 2 + .../src/groth16_verifier.cairo | 2 +- .../src/groth16_verifier.cairo | 2 +- .../src/groth16_verifier.cairo | 2 +- src/src/ec_ops.cairo | 33 +-- src/src/tests/msm_tests.cairo | 189 +++++++++++------- src/src/utils/drand.cairo | 3 +- src/src/utils/hashing.cairo | 2 +- 10 files changed, 141 insertions(+), 98 deletions(-) diff --git a/hydra/garaga/starknet/groth16_contract_generator/generator.py b/hydra/garaga/starknet/groth16_contract_generator/generator.py index a4d5cb57..109e3587 100644 --- a/hydra/garaga/starknet/groth16_contract_generator/generator.py +++ b/hydra/garaga/starknet/groth16_contract_generator/generator.py @@ -8,7 +8,7 @@ from garaga.starknet.cli.utils import create_directory from garaga.starknet.groth16_contract_generator.parsing_utils import Groth16VerifyingKey -ECIP_OPS_CLASS_HASH = 0x7918F484291EB154E13D0E43BA6403E62DC1F5FBB3A191D868E2E37359F8713 +ECIP_OPS_CLASS_HASH = 0x2672F1F079CCBAFE1BE4A20A76421B509FCFB406CBF6818563ED812EDAEB3A3 def precompute_lines_from_vk(vk: Groth16VerifyingKey) -> StructArray: diff --git a/hydra/garaga/starknet/tests_and_calldata_generators/msm.py b/hydra/garaga/starknet/tests_and_calldata_generators/msm.py index 285cf854..9aa36591 100644 --- a/hydra/garaga/starknet/tests_and_calldata_generators/msm.py +++ b/hydra/garaga/starknet/tests_and_calldata_generators/msm.py @@ -126,7 +126,7 @@ def build_derive_point_from_x_hint( name="derive_point_from_x_hint", elmts=[ structs.u384(name="y_last_attempt", elmts=[y]), - structs.u384Array(name="g_rhs_sqrt", elmts=roots), + structs.u384Span(name="g_rhs_sqrt", elmts=roots), ], ) diff --git a/src/Scarb.toml b/src/Scarb.toml index 5dda0905..3673e6a6 100644 --- a/src/Scarb.toml +++ b/src/Scarb.toml @@ -9,6 +9,8 @@ repository = "https://github.com/keep-starknet-strange/garaga" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html +[cairo] +sierra-replace-ids = false [dependencies] diff --git a/src/contracts/groth16_example_bls12_381/src/groth16_verifier.cairo b/src/contracts/groth16_example_bls12_381/src/groth16_verifier.cairo index 351d5585..8db892d7 100644 --- a/src/contracts/groth16_example_bls12_381/src/groth16_verifier.cairo +++ b/src/contracts/groth16_example_bls12_381/src/groth16_verifier.cairo @@ -17,7 +17,7 @@ mod Groth16VerifierBLS12_381 { use super::{N_PUBLIC_INPUTS, vk, ic, precomputed_lines}; const ECIP_OPS_CLASS_HASH: felt252 = - 0x7918f484291eb154e13d0e43ba6403e62dc1f5fbb3a191d868e2e37359f8713; + 0x2672f1f079ccbafe1be4a20a76421b509fcfb406cbf6818563ed812edaeb3a3; use starknet::ContractAddress; #[storage] diff --git a/src/contracts/groth16_example_bn254/src/groth16_verifier.cairo b/src/contracts/groth16_example_bn254/src/groth16_verifier.cairo index c3d3a9b7..e35f49c6 100644 --- a/src/contracts/groth16_example_bn254/src/groth16_verifier.cairo +++ b/src/contracts/groth16_example_bn254/src/groth16_verifier.cairo @@ -17,7 +17,7 @@ mod Groth16VerifierBN254 { use super::{N_PUBLIC_INPUTS, vk, ic, precomputed_lines}; const ECIP_OPS_CLASS_HASH: felt252 = - 0x7918f484291eb154e13d0e43ba6403e62dc1f5fbb3a191d868e2e37359f8713; + 0x2672f1f079ccbafe1be4a20a76421b509fcfb406cbf6818563ed812edaeb3a3; use starknet::ContractAddress; #[storage] diff --git a/src/contracts/risc0_verifier_bn254/src/groth16_verifier.cairo b/src/contracts/risc0_verifier_bn254/src/groth16_verifier.cairo index 7e5d8704..9032567f 100644 --- a/src/contracts/risc0_verifier_bn254/src/groth16_verifier.cairo +++ b/src/contracts/risc0_verifier_bn254/src/groth16_verifier.cairo @@ -18,7 +18,7 @@ mod Risc0Groth16VerifierBN254 { use super::{N_FREE_PUBLIC_INPUTS, vk, ic, precomputed_lines, T}; const ECIP_OPS_CLASS_HASH: felt252 = - 0x7918f484291eb154e13d0e43ba6403e62dc1f5fbb3a191d868e2e37359f8713; + 0x2672f1f079ccbafe1be4a20a76421b509fcfb406cbf6818563ed812edaeb3a3; use starknet::ContractAddress; #[storage] diff --git a/src/src/ec_ops.cairo b/src/src/ec_ops.cairo index d562896a..c8f12a49 100644 --- a/src/src/ec_ops.cairo +++ b/src/src/ec_ops.cairo @@ -188,13 +188,13 @@ fn get_DERIVE_POINT_FROM_X_circuit( // If z does not have a square root in Fp, then g*z has a square root in Fp*. // Note: there is exactly (p-1)//2 square roots in Fp*. fn derive_ec_point_from_X( - mut x: felt252, y_last_attempt: u384, mut g_rhs_sqrt: Array, curve_index: usize, + mut x: felt252, y_last_attempt: u384, mut g_rhs_sqrt: Span, curve_index: usize, ) -> G1Point { let mut attempt: felt252 = 0; while let Option::Some(root) = g_rhs_sqrt.pop_front() { let x_u384: u384 = x.into(); let res: DerivePointFromXOutput = get_DERIVE_POINT_FROM_X_circuit( - x_u384, root, curve_index + x_u384, *root, curve_index ); assert!( res.should_be_rhs_or_g_rhs == res.g_rhs, "grhs!=(sqrt(g*rhs))^2 in attempt {attempt}" @@ -220,7 +220,7 @@ fn derive_ec_point_from_X( // from the constant term. // No information about the degrees of the polynomials is stored here as they are derived // implicitely from the MSM size. -#[derive(Drop, Debug, PartialEq, Serde)] +#[derive(Drop, Debug, Copy, PartialEq, Serde)] struct FunctionFelt { a_num: Span, a_den: Span, @@ -264,7 +264,7 @@ impl FunctionFeltImpl of FunctionFeltTrait { } } -#[derive(Drop, Debug, PartialEq, Serde)] +#[derive(Drop, Debug, PartialEq, Serde, Copy)] struct MSMHint { Q_low: G1Point, Q_high: G1Point, @@ -280,10 +280,10 @@ struct MSMHintSmallScalar { SumDlogDiv: FunctionFelt, } -#[derive(Drop, Debug, PartialEq, Serde)] +#[derive(Drop, Debug, PartialEq, Serde, Copy)] struct DerivePointFromXHint { y_last_attempt: u384, - g_rhs_sqrt: Array, + g_rhs_sqrt: Span, } fn scalar_mul_g1_fixed_small_scalar( @@ -352,6 +352,7 @@ fn scalar_mul_g1_fixed_small_scalar( curve_index: curve_index ); + u384_assert_eq(lhs, rhs); return hint.Q; } @@ -756,7 +757,7 @@ mod tests { limb3: 0x0 } ]; - let result = derive_ec_point_from_X(x, y, grhs_roots, 0); + let result = derive_ec_point_from_X(x, y, grhs_roots.span(), 0); assert!( result .x == u384 { @@ -788,7 +789,7 @@ mod tests { limb3: 0x19972c66940a5bb4365da67 } ]; - let result = derive_ec_point_from_X(x, y, grhs_roots, 1); + let result = derive_ec_point_from_X(x, y, grhs_roots.span(), 1); assert!( result .x == u384 { @@ -838,7 +839,7 @@ mod tests { limb3: 0x0 } ]; - let result = derive_ec_point_from_X(x, y, grhs_roots, 2); + let result = derive_ec_point_from_X(x, y, grhs_roots.span(), 2); assert!( result .x == u384 { @@ -870,7 +871,7 @@ mod tests { limb3: 0x0 } ]; - let result = derive_ec_point_from_X(x, y, grhs_roots, 3); + let result = derive_ec_point_from_X(x, y, grhs_roots.span(), 3); assert!( result .x == u384 { @@ -895,7 +896,7 @@ mod tests { limb3: 0x0 }; let grhs_roots: Array = array![]; - let result = derive_ec_point_from_X(x, y, grhs_roots, 4); + let result = derive_ec_point_from_X(x, y, grhs_roots.span(), 4); assert!( result .x == u384 { @@ -945,7 +946,7 @@ mod tests { limb3: 0x0 } ]; - let result = derive_ec_point_from_X(x, y, grhs_roots, 0); + let result = derive_ec_point_from_X(x, y, grhs_roots.span(), 0); assert!( result .x == u384 { @@ -1001,7 +1002,7 @@ mod tests { limb3: 0x6de8fe79d9b161443b37f30 } ]; - let result = derive_ec_point_from_X(x, y, grhs_roots, 1); + let result = derive_ec_point_from_X(x, y, grhs_roots.span(), 1); assert!( result .x == u384 { @@ -1033,7 +1034,7 @@ mod tests { limb3: 0x0 } ]; - let result = derive_ec_point_from_X(x, y, grhs_roots, 2); + let result = derive_ec_point_from_X(x, y, grhs_roots.span(), 2); assert!( result .x == u384 { @@ -1065,7 +1066,7 @@ mod tests { limb3: 0x0 } ]; - let result = derive_ec_point_from_X(x, y, grhs_roots, 3); + let result = derive_ec_point_from_X(x, y, grhs_roots.span(), 3); assert!( result .x == u384 { @@ -1090,7 +1091,7 @@ mod tests { limb3: 0x0 }; let grhs_roots: Array = array![]; - let result = derive_ec_point_from_X(x, y, grhs_roots, 4); + let result = derive_ec_point_from_X(x, y, grhs_roots.span(), 4); assert!( result .x == u384 { diff --git a/src/src/tests/msm_tests.cairo b/src/src/tests/msm_tests.cairo index 5714c51d..80c401ab 100644 --- a/src/src/tests/msm_tests.cairo +++ b/src/src/tests/msm_tests.cairo @@ -113,7 +113,7 @@ mod msm_tests { limb2: 0x17eef8e7e4dd2e33, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -439,7 +439,8 @@ mod msm_tests { limb2: 0xa77478d31681d27, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -1150,7 +1151,8 @@ mod msm_tests { limb2: 0x28d10e632d4cdfe, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -2118,7 +2120,8 @@ mod msm_tests { limb2: 0x389aece1d572174, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -3325,7 +3328,8 @@ mod msm_tests { limb2: 0x5aebe1de22216b3, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -4754,7 +4758,8 @@ mod msm_tests { limb2: 0x102d47bb7b7e4d92, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -6419,7 +6424,8 @@ mod msm_tests { limb2: 0xa7a92c20fb674bc, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -8308,7 +8314,7 @@ mod msm_tests { limb2: 0x286a6b83050eda6, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -10440,7 +10446,8 @@ mod msm_tests { limb2: 0x1319538ffcd9861c, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -12799,7 +12806,8 @@ mod msm_tests { limb2: 0x36e979a3ceed10c, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -15388,7 +15396,7 @@ mod msm_tests { limb2: 0x13209b4f6a3b53df, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -18233,7 +18241,8 @@ mod msm_tests { limb2: 0x17da0d2c1a6cce02, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -18566,7 +18575,7 @@ mod msm_tests { limb2: 0xe7801e5dd2b70de9e4b1af57, limb3: 0x4b3b4eaca402c3b711f869b }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -18887,7 +18896,8 @@ mod msm_tests { limb2: 0xcc9039d4ba7ae8849e2f2064, limb3: 0x680f0068cb18a987654e66b } - ], + ] + .span(), }; let points = array![ G1Point { @@ -19592,7 +19602,7 @@ mod msm_tests { limb2: 0xbb5dafe124843cb2bf90ab58, limb3: 0x83df3d15b1ef9fb0abffd31 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -20563,7 +20573,8 @@ mod msm_tests { limb2: 0xb0b842334cbf5da22303c7a8, limb3: 0x4b5164e3cf33838c501c0e2 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -21761,7 +21772,7 @@ mod msm_tests { limb2: 0x70ba2a6ba7d96fa80ec23619, limb3: 0x9e843ecc36bafe34d9513fe }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -23201,7 +23212,8 @@ mod msm_tests { limb2: 0xd2b1bd8d9c6aed4ca5be0ca9, limb3: 0x84bbbc9c25115aaf2db8def } - ], + ] + .span(), }; let points = array![ G1Point { @@ -24874,7 +24886,8 @@ mod msm_tests { limb2: 0x8e5548b15295112b7831f535, limb3: 0xcee9cbda118cca782fe3a25 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -26768,7 +26781,7 @@ mod msm_tests { limb2: 0x6d847ecc351fb1f050353675, limb3: 0x7eeb377d5057bb147ae0afd }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -28889,7 +28902,7 @@ mod msm_tests { limb2: 0x59f54c8f417889d865cf3818, limb3: 0x64b86a449d7113ec3eaed88 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -31253,7 +31266,8 @@ mod msm_tests { limb2: 0x80bdc6a367271e5941835e3e, limb3: 0x5a967044175bf27e03552b4 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -33863,7 +33877,8 @@ mod msm_tests { limb2: 0xb3fee67cb7d20ad1caa393cd, limb3: 0x2b78180e1348e774aea87a6 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -36692,7 +36707,7 @@ mod msm_tests { limb2: 0xb47d8b97def7714621056367, limb3: 0xbffcee71f25077a76d7fa2e }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -37025,7 +37040,7 @@ mod msm_tests { limb2: 0x31036fb2f551a296, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -37341,7 +37356,7 @@ mod msm_tests { limb2: 0x1f68715a44c3ef82, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -38070,7 +38085,8 @@ mod msm_tests { limb2: 0x605b9279af8c238f, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -39036,7 +39052,7 @@ mod msm_tests { limb2: 0x5bd3733f6a58e95e, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -40250,7 +40266,8 @@ mod msm_tests { limb2: 0x24474dc1b4ec30e, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -41694,7 +41711,8 @@ mod msm_tests { limb2: 0x1bb9579d9fd2a72f, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -43386,7 +43404,8 @@ mod msm_tests { limb2: 0x440e5687c738a344, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -45293,7 +45312,7 @@ mod msm_tests { limb2: 0x3019a414e4103e2d, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -47434,7 +47453,7 @@ mod msm_tests { limb2: 0x62781e49e2780ee9, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -49834,7 +49853,8 @@ mod msm_tests { limb2: 0x4d9150ed646d9cf4, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -52439,7 +52459,7 @@ mod msm_tests { limb2: 0x1764c4a79c00c331, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -55278,7 +55298,7 @@ mod msm_tests { limb2: 0x5681ef803a412634, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -55611,7 +55631,7 @@ mod msm_tests { limb2: 0x7812a16bfa702609, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -55927,7 +55947,7 @@ mod msm_tests { limb2: 0x18f1b81a89a11888, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -56641,7 +56661,8 @@ mod msm_tests { limb2: 0x5b10679078ad2a2c, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -57602,7 +57623,7 @@ mod msm_tests { limb2: 0x3a8245bec86922cd, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -58823,7 +58844,8 @@ mod msm_tests { limb2: 0x1d002c3bcbf3e0da, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -60262,7 +60284,8 @@ mod msm_tests { limb2: 0x641481f2efa5f9e9, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -61943,7 +61966,8 @@ mod msm_tests { limb2: 0x46a6e1a69a9e3238, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -63852,7 +63876,8 @@ mod msm_tests { limb2: 0x420dad0d168bbbce, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -66001,7 +66026,8 @@ mod msm_tests { limb2: 0x5b20c35ef876ade2, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -68372,7 +68398,8 @@ mod msm_tests { limb2: 0x349926a5b5f5ab1c, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -70997,7 +71024,8 @@ mod msm_tests { limb2: 0x3bdf1cd7526e4ad6, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -73850,7 +73878,8 @@ mod msm_tests { limb2: 0x290ab7b904a1cae7, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -74183,7 +74212,7 @@ mod msm_tests { limb2: 0x2fb2291daeffdfce, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -74495,7 +74524,7 @@ mod msm_tests { limb2: 0x2a61add1aea2f3a5, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -75225,7 +75254,8 @@ mod msm_tests { limb2: 0x2980af51bc30759d, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -76182,7 +76212,7 @@ mod msm_tests { limb2: 0x1ab08f1129580430, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -77370,7 +77400,7 @@ mod msm_tests { limb2: 0x3865182dc9e9b24, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -78789,7 +78819,7 @@ mod msm_tests { limb2: 0x324bbab4008bbe74, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -80451,7 +80481,8 @@ mod msm_tests { limb2: 0x31c7dff6a184320b, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -82335,7 +82366,7 @@ mod msm_tests { limb2: 0x3426a5d8b2c8a800, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -84460,7 +84491,8 @@ mod msm_tests { limb2: 0x2bb962b1065586bc, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -86819,7 +86851,8 @@ mod msm_tests { limb2: 0x2e16c5afda2cc7c6, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -89402,7 +89435,7 @@ mod msm_tests { limb2: 0x1a35e333bc24f91c, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -92220,7 +92253,7 @@ mod msm_tests { limb2: 0x22f305051b370945, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -92553,7 +92586,7 @@ mod msm_tests { limb2: 0x17eef8e7e4dd2e33, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -92879,7 +92912,8 @@ mod msm_tests { limb2: 0xa77478d31681d27, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -93590,7 +93624,8 @@ mod msm_tests { limb2: 0x28d10e632d4cdfe, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -93770,7 +93805,7 @@ mod msm_tests { limb2: 0xe7801e5dd2b70de9e4b1af57, limb3: 0x4b3b4eaca402c3b711f869b }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -94091,7 +94126,8 @@ mod msm_tests { limb2: 0xcc9039d4ba7ae8849e2f2064, limb3: 0x680f0068cb18a987654e66b } - ], + ] + .span(), }; let points = array![ G1Point { @@ -94796,7 +94832,7 @@ mod msm_tests { limb2: 0xbb5dafe124843cb2bf90ab58, limb3: 0x83df3d15b1ef9fb0abffd31 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -94976,7 +95012,7 @@ mod msm_tests { limb2: 0x31036fb2f551a296, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -95292,7 +95328,7 @@ mod msm_tests { limb2: 0x1f68715a44c3ef82, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -96021,7 +96057,8 @@ mod msm_tests { limb2: 0x605b9279af8c238f, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -96201,7 +96238,7 @@ mod msm_tests { limb2: 0x7812a16bfa702609, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -96517,7 +96554,7 @@ mod msm_tests { limb2: 0x18f1b81a89a11888, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -97231,7 +97268,8 @@ mod msm_tests { limb2: 0x5b10679078ad2a2c, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { @@ -97411,7 +97449,7 @@ mod msm_tests { limb2: 0x2fb2291daeffdfce, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -97723,7 +97761,7 @@ mod msm_tests { limb2: 0x2a61add1aea2f3a5, limb3: 0x0 }, - g_rhs_sqrt: array![], + g_rhs_sqrt: array![].span(), }; let points = array![ G1Point { @@ -98453,7 +98491,8 @@ mod msm_tests { limb2: 0x2980af51bc30759d, limb3: 0x0 } - ], + ] + .span(), }; let points = array![ G1Point { diff --git a/src/src/utils/drand.cairo b/src/src/utils/drand.cairo index 4f25fbe8..da775fe2 100644 --- a/src/src/utils/drand.cairo +++ b/src/src/utils/drand.cairo @@ -807,7 +807,8 @@ mod tests { limb2: 0xd176d81898f67fe46da9c716, limb3: 0x297c2b03926eec52554f824 } - ], + ] + .span(), } }; diff --git a/src/src/utils/hashing.cairo b/src/src/utils/hashing.cairo index 0374cdad..31970bb8 100644 --- a/src/src/utils/hashing.cairo +++ b/src/src/utils/hashing.cairo @@ -420,6 +420,6 @@ pub fn hash_G1Point(point: G1Point) -> felt252 { let (s0, s1, s2) = hades_permutation(in_1, in_2, 2); let in_1 = s0 + point.y.limb0.into() + base * point.y.limb1.into(); let in_2 = s1 + point.y.limb2.into() + base * point.y.limb3.into(); - let (s0, s1, s2) = hades_permutation(in_1, in_2, s2); + let (s0, _, _) = hades_permutation(in_1, in_2, s2); return s0; }