diff --git a/addchain_5inv.py b/addchain_5inv.py new file mode 100755 index 0000000..369e366 --- /dev/null +++ b/addchain_5inv.py @@ -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) + diff --git a/addchain.py b/addchain_sqrt.py similarity index 94% rename from addchain.py rename to addchain_sqrt.py index 9f5d52e..72eca4f 100755 --- a/addchain.py +++ b/addchain_sqrt.py @@ -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) diff --git a/squareroottab.sage b/squareroottab.sage index 969683c..144e82d 100755 --- a/squareroottab.sage +++ b/squareroottab.sage @@ -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)