This repository has been archived by the owner on Sep 19, 2024. It is now read-only.
generated from huff-language/huff-project-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Huffd1.sage
144 lines (118 loc) · 4.78 KB
/
Huffd1.sage
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
from sage.all import GF, FiniteField, PolynomialRing, Polynomial, is_prime
from typing import List
# proof of concept in Sage
class HUFFD1:
F: FiniteField # type: ignore
Fx: PolynomialRing # type: ignore
total_supply: int
order: int
basises: List[Polynomial]
balances: Polynomial
def __init__(
self, order: int, total_supply: int, coeff_size: int, owners: List[int]
) -> None:
assert is_prime(order)
self.order = order
self.F = GF(order)
self.Fx = self.F["x"]
self.total_supply = total_supply
self.coeff_size = coeff_size
# basis
self.basises = [self.__compute_basis(t) for t in range(self.total_supply)]
# interpolation
# NOTE: original idea was to interpolate for some owners, but if all tokens belong to owner
# at the first step, we can simply assign owner as the constant polynomial
# also, doing interpolation requires a lot more work in Huff, such as XGCD for divison and such.
self.balances = self.__interpolate_basis(self.basises, owners)
for t in range(self.total_supply):
assert self.ownerOf(t) == owners[t]
def __compute_basis(self, t):
"""
Compute the Lagrange basis polynomial over field `F` for a given token id `t`
where the total supply is `n`.
"""
p: Polynomial = self.Fx([1])
for i in range(self.total_supply):
if i != t:
p *= self.Fx([-i, 1])
p /= self.F(t - i)
return p
def __interpolate_basis(self, bs, vals):
"""
Given the basis vectors for `n` tokens, and values for each token,
interpolate a polynomial.
"""
assert len(bs) == len(vals)
p = self.Fx([0])
for i in range(len(bs)):
p += bs[i] * self.F(vals[i])
return p
def __pad_coeff(self, val: int) -> str:
"""
Remove 0x, and left-pad 0s.
"""
return hex(val)[2:].rjust(self.coeff_size * 2, "0")
def ownerOf(self, t: int):
assert t < self.total_supply
return self.balances(t)
def balanceOf(self, addr: int):
ans = 0
for t in range(self.total_supply):
ans += 1 if self.ownerOf(t) == addr else 0
return ans
def transferFrom(self, src: int, dest: int, t: int):
assert t < self.total_supply
assert self.ownerOf(t) == src
# P'(x) = P(x) + L_t(x)(to - from)
self.balances = self.balances + self.basises[t] * (dest - src)
def print_owners(self):
for t in range(self.total_supply):
print(t, hex(self.ownerOf(t)))
def print_coeffs(self):
for coeff in self.balances.coefficients():
print(hex(coeff))
def print_basis_polys(self):
for t in range(self.total_supply):
print("t = ", t)
# sparse=False so that 0s are returned too
for c in self.basises[t].coefficients(sparse=False):
print(self.__pad_coeff(c))
def export_basis_table(self):
body = "0x"
for t in range(self.total_supply):
# sparse=False so that 0s are returned too
for c in self.basises[t].coefficients(sparse=False):
body += self.__pad_coeff(c)
code = "#define table Basis {\n " + body + "\n}"
code = code + "\n#define constant TOTAL_SUPPLY = " + hex(self.total_supply)
code = code + "\n#define constant COEFF_SIZE = " + hex(self.coeff_size)
code = code + "\n#define constant ORDER = " + hex(self.order)
path = "./src/data/Basis" + str(self.total_supply) + ".huff"
with open(path, "w") as _file:
_file.write(code)
print("exported basis table to: " + path)
# OWNER = 0xE175a857Fdefd7308D4B79936A5E31afa7bDD4aC # my address
# TOTAL_SUPPLY = 0xFF # number of tokens
# COEFF_SIZE = 0x14 # number of bytes
# ORDER = 0xffffffffffffffffffffffffffffffffffffffd1 # largest 160-bit prime
if __name__ == "__main__":
TOTAL_SUPPLY = 10 # degree of polynomial + 1
COEFF_SIZE = 20 # bytes
ORDER = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD1 # order of finite field for coefficients
OWNER = 0x1
assert OWNER < ORDER # order must be larger than the owner (address)
assert ORDER <= 2 ** (COEFF_SIZE * 8) # order must fit into the coefficient size
huffd1 = HUFFD1(
ORDER, TOTAL_SUPPLY, COEFF_SIZE, [OWNER for _ in range(TOTAL_SUPPLY)]
)
for t in range(TOTAL_SUPPLY):
assert huffd1.ownerOf(t) == OWNER
huffd1.print_basis_polys()
# print(huffd1.bs[0])
# test transfer
NEW_OWNER = 0x9
assert huffd1.ownerOf(0) == OWNER
huffd1.transferFrom(OWNER, NEW_OWNER, 0)
assert huffd1.ownerOf(0) == NEW_OWNER
# export table for Huff
huffd1.export_basis_table()