Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

base Drand Quicknet contract #201

Merged
merged 28 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
bdb73da
hash_to_field py ok
feltroidprime Sep 17, 2024
b6dbdc2
hash to curve skeleton
feltroidprime Sep 18, 2024
fd7373a
h2c ok
feltroidprime Sep 18, 2024
2d7ceed
drand client
feltroidprime Sep 18, 2024
75f85d8
move risc0_utils to utils
feltroidprime Sep 18, 2024
1b5aa4f
add quicknet public key
feltroidprime Sep 18, 2024
e3553e7
correct G2 point deserialize
feltroidprime Sep 19, 2024
742169a
add u512_mod_p_bls
feltroidprime Sep 24, 2024
3eb59c1
add io tools
feltroidprime Sep 24, 2024
0e44ddb
prints wip
feltroidprime Sep 24, 2024
108ff61
hash_to_field
feltroidprime Sep 24, 2024
a549399
map_to_curve "should" work.
feltroidprime Sep 26, 2024
bf4f30e
fix b0
feltroidprime Sep 26, 2024
881c636
add drand_test
feltroidprime Sep 26, 2024
e28e545
fix hash_to_field
feltroidprime Sep 26, 2024
00aa8fd
map_to_curve ok
feltroidprime Sep 27, 2024
cc966e4
hash to curve OK
feltroidprime Sep 28, 2024
560a94d
drand client api fallback
feltroidprime Sep 29, 2024
4dfa177
start quicknet contract
feltroidprime Sep 29, 2024
1c0607a
Fix G2 deserialization.
feltroidprime Sep 30, 2024
4948df0
"compare Fp2" ...
feltroidprime Sep 30, 2024
c044ca6
rm prints
feltroidprime Sep 30, 2024
3e9b815
compressed G2 deserialize sign still broken somehow
feltroidprime Sep 30, 2024
aa68a7a
rm prints
feltroidprime Sep 30, 2024
5d42d07
drand verify contract & devnet test
feltroidprime Sep 30, 2024
2af0b50
temp fix for broken deserialization
feltroidprime Sep 30, 2024
d373ab7
test multiple round in drand pytest
feltroidprime Sep 30, 2024
4203c18
Merge branch 'main' into bls-sig
feltroidprime Sep 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions hydra/garaga/algebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down
74 changes: 60 additions & 14 deletions hydra/garaga/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"
Expand Down Expand Up @@ -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
Expand All @@ -191,6 +201,7 @@ def __init__(
b,
fp_generator,
*(self.to_weierstrass(Gx, Gy)),
swu_params,
)

def to_weierstrass(self, x_twisted, y_twisted):
Expand Down Expand Up @@ -326,6 +337,7 @@ def bit(value, index):
0x12C85EA5DB8C6DEB4AAB71808DCB408FE3D1E7690C43D37B4CE6CC0166FA7DAA,
0x90689D0585FF075EC9E99AD690C3395BC4B313370B38EF355ACDADCD122975B,
),
swu_params=None,
),
BLS12_381_ID: PairingCurve(
cairo_zero_namespace_name="bls",
Expand Down Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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
Expand All @@ -407,6 +426,7 @@ def bit(value, index):
fp_generator=6,
Gx=0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A,
Gy=0x6666666666666666666666666666666666666666666666666666666666666658,
swu_params=None,
),
}

Expand Down Expand Up @@ -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:
"""
Expand All @@ -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):
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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":
"""
Expand All @@ -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":
"""
Expand All @@ -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)
Expand Down
Loading
Loading