mirror of https://github.com/zcash/pasta.git
Addition chains for 5^-1 (mod p-1, q-1).
Signed-off-by: Daira Hopwood <daira@jacaranda.org>
This commit is contained in:
parent
56945c09e0
commit
ad02b756cd
|
@ -0,0 +1,123 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
class Chain(object):
|
||||
SQR_COST = 0.8
|
||||
MUL_COST = 1
|
||||
|
||||
def __init__(self):
|
||||
self.muls = 0
|
||||
self.sqrs = 0
|
||||
self.computed = set((1,))
|
||||
|
||||
def sqr(self, x, n=1):
|
||||
for i in range(n):
|
||||
assert(x in self.computed)
|
||||
self.sqrs += 1
|
||||
x = 2*x
|
||||
self.computed.add(x)
|
||||
|
||||
return x
|
||||
|
||||
def mul(self, x, y):
|
||||
assert(x in self.computed)
|
||||
assert(y in self.computed)
|
||||
assert(x != y)
|
||||
self.muls += 1
|
||||
r = x+y
|
||||
self.computed.add(r)
|
||||
return r
|
||||
|
||||
def sqrmul(self, x, n, y):
|
||||
return self.mul(self.sqr(x, n), y)
|
||||
|
||||
def cost(self):
|
||||
return self.sqrs*self.SQR_COST + self.muls*self.MUL_COST
|
||||
|
||||
def __repr__(self):
|
||||
return "%dS + %dM (%.1f)" % (self.sqrs, self.muls, self.cost())
|
||||
|
||||
|
||||
x_p = 0b11001100110011001100110011001100110011001100110011001100110011001100110011001100110011001100110011001100110011001100110011001101001110100111101110000011001001101000010000101001100000111000101110000011110000111100111111000011001100110011001100110011001101
|
||||
# a b c d e f g h i j k l m n o p q r s
|
||||
# 11001100110011
|
||||
# 111 1
|
||||
|
||||
pc = Chain()
|
||||
p1 = 1
|
||||
p10 = pc.sqr(p1)
|
||||
p11 = pc.mul(p10, p1)
|
||||
p101 = pc.mul(p10, p11)
|
||||
p110 = pc.sqr(p11)
|
||||
p111 = pc.mul(p110, p1)
|
||||
p1001 = pc.mul(p111, p10)
|
||||
p1111 = pc.mul(p1001, p110)
|
||||
pr2 = pc.sqrmul(p110, 3, p11)
|
||||
pr4 = pc.sqrmul(pr2, 8, pr2)
|
||||
pr8 = pc.sqrmul(pr4, 16, pr4)
|
||||
pr16 = pc.sqrmul(pr8, 32, pr8)
|
||||
pr32 = pc.sqrmul(pr16, 64, pr16)
|
||||
pr32a = pc.sqrmul(pr32, 5, p1001)
|
||||
pr32b = pc.sqrmul(pr32a, 8, p111)
|
||||
pr32c = pc.sqrmul(pr32b, 4, p1)
|
||||
pr32d = pc.sqrmul(pr32c, 2, pr4)
|
||||
pr32e = pc.sqrmul(pr32d, 7, p11)
|
||||
pr32f = pc.sqrmul(pr32e, 6, p1001)
|
||||
pr32g = pc.sqrmul(pr32f, 3, p101)
|
||||
pr32h = pc.sqrmul(pr32g, 5, p1)
|
||||
pr32i = pc.sqrmul(pr32h, 7, p101)
|
||||
pr32j = pc.sqrmul(pr32i, 4, p11)
|
||||
pr32k = pc.sqrmul(pr32j, 8, p111)
|
||||
pr32l = pc.sqrmul(pr32k, 4, p1)
|
||||
pr32m = pc.sqrmul(pr32l, 4, p111)
|
||||
pr32n = pc.sqrmul(pr32m, 9, p1111)
|
||||
pr32o = pc.sqrmul(pr32n, 8, p1111)
|
||||
pr32p = pc.sqrmul(pr32o, 6, p1111)
|
||||
pr32q = pc.sqrmul(pr32p, 2, p11)
|
||||
pr32r = pc.sqrmul(pr32q, 34, pr8)
|
||||
pr32s = pc.sqrmul(pr32r, 2, p1)
|
||||
assert pr32s == x_p
|
||||
print(pc)
|
||||
|
||||
x_q = 0b11001100110011001100110011001100110011001100110011001100110011001100110011001100110011001100110011001100110011001100110011001101001110100111101110000011001001101000010100001110111010010010101101011010011111001000101000000011001100110011001100110011001101
|
||||
# a b c d e f g h i j k l m n o p q r s t
|
||||
# 11001100110011
|
||||
# 111 1
|
||||
|
||||
qc = Chain()
|
||||
q1 = 1
|
||||
q10 = qc.sqr(q1)
|
||||
q11 = qc.mul(q10, q1)
|
||||
q101 = qc.mul(q10, q11)
|
||||
q110 = qc.sqr(q11)
|
||||
q111 = qc.mul(q110, q1)
|
||||
q1001 = qc.mul(q111, q10)
|
||||
q1111 = qc.mul(q1001, q110)
|
||||
qr2 = qc.sqrmul(q110, 3, q11)
|
||||
qr4 = qc.sqrmul(qr2, 8, qr2)
|
||||
qr8 = qc.sqrmul(qr4, 16, qr4)
|
||||
qr16 = qc.sqrmul(qr8, 32, qr8)
|
||||
qr32 = qc.sqrmul(qr16, 64, qr16)
|
||||
qr32a = qc.sqrmul(qr32, 5, q1001)
|
||||
qr32b = qc.sqrmul(qr32a, 8, q111)
|
||||
qr32c = qc.sqrmul(qr32b, 4, q1)
|
||||
qr32d = qc.sqrmul(qr32c, 2, qr4)
|
||||
qr32e = qc.sqrmul(qr32d, 7, q11)
|
||||
qr32f = qc.sqrmul(qr32e, 6, q1001)
|
||||
qr32g = qc.sqrmul(qr32f, 3, q101)
|
||||
# diverges here
|
||||
qr32h = qc.sqrmul(qr32g, 7, q101)
|
||||
qr32i = qc.sqrmul(qr32h, 7, q111)
|
||||
qr32j = qc.sqrmul(qr32i, 4, q111)
|
||||
qr32k = qc.sqrmul(qr32j, 5, q1001)
|
||||
qr32l = qc.sqrmul(qr32k, 5, q101)
|
||||
qr32m = qc.sqrmul(qr32l, 3, q11)
|
||||
qr32n = qc.sqrmul(qr32m, 4, q101)
|
||||
qr32o = qc.sqrmul(qr32n, 3, q101)
|
||||
qr32p = qc.sqrmul(qr32o, 6, q1111)
|
||||
qr32q = qc.sqrmul(qr32p, 4, q1001)
|
||||
qr32r = qc.sqrmul(qr32q, 6, q101)
|
||||
qr32s = qc.sqrmul(qr32r, 37, qr8)
|
||||
qr32t = qc.sqrmul(qr32s, 2, q1)
|
||||
assert qr32t == x_q
|
||||
print(qc)
|
||||
|
|
@ -36,7 +36,10 @@ class Chain(object):
|
|||
return self.mul(self.sqr(x, n), y)
|
||||
|
||||
def cost(self):
|
||||
return (self.sqrs, self.muls, self.sqrs*self.SQR_COST + self.muls*self.MUL_COST)
|
||||
return self.sqrs*self.SQR_COST + self.muls*self.MUL_COST
|
||||
|
||||
def __repr__(self):
|
||||
return "%dS + %dM (%.1f)" % (self.sqrs, self.muls, self.cost())
|
||||
|
||||
|
||||
p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
|
||||
|
@ -80,7 +83,7 @@ rr = rch.sqrmul(rq, 7, r111)
|
|||
rs = rch.sqrmul(rr, 3, r11)
|
||||
rt = rch.sqr(rs)
|
||||
assert rt == r, format(rt, 'b')
|
||||
print(rch.cost())
|
||||
print(rch)
|
||||
|
||||
|
||||
# print(format(q >> (n+1), 'b'))
|
||||
|
@ -120,4 +123,4 @@ sr = sch.sqrmul(sq, 5, s1011)
|
|||
ss = sch.sqrmul(sr, 3, s1)
|
||||
st = sch.sqr(ss, 4)
|
||||
assert st == s, format(st, 'b')
|
||||
print(sch.cost())
|
||||
print(sch)
|
|
@ -165,7 +165,7 @@ class SqrtField:
|
|||
p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
|
||||
q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
|
||||
|
||||
# see addchain.py for base costs of u^{(m-1)/2}
|
||||
# see addchain_sqrt.py for base costs of u^{(m-1)/2}
|
||||
F_p = SqrtField(p, 5, Cost(223, 23), hash_xor=0x11BE, hash_mod=1098)
|
||||
F_q = SqrtField(q, 5, Cost(223, 24), hash_xor=0x116A9E, hash_mod=1206)
|
||||
|
||||
|
|
Loading…
Reference in New Issue