Addition chains for 5^-1 (mod p-1, q-1).

Signed-off-by: Daira Hopwood <daira@jacaranda.org>
This commit is contained in:
Daira Hopwood 2020-12-12 16:46:32 +00:00
parent 56945c09e0
commit ad02b756cd
3 changed files with 130 additions and 4 deletions

123
addchain_5inv.py Executable file
View File

@ -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)

View File

@ -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)

View File

@ -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)