Skip to content

Commit

Permalink
addition chain for Bandersnatch and banderwagon square root (#356)
Browse files Browse the repository at this point in the history
  • Loading branch information
mratsim committed Feb 11, 2024
1 parent 5894a8d commit 661a481
Show file tree
Hide file tree
Showing 4 changed files with 278 additions and 2 deletions.
2 changes: 1 addition & 1 deletion constantine/math/arithmetic/finite_fields.nim
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ macro addchain*(fn: untyped): untyped =
var body = newStmtList()

for i, statement in fn[^1]:
statement.expectKind({nnkCommentStmt, nnkVarSection, nnkCall, nnkInfix})
statement.expectKind({nnkCommentStmt, nnkLetSection, nnkVarSection, nnkCall, nnkInfix})

var s = statement.copyNimTree()
if i + 1 != result[^1].len:
Expand Down
138 changes: 138 additions & 0 deletions constantine/math/constants/bandersnatch_sqrt.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,141 @@ const
Bandersnatch_TonelliShanks_exponent* = BigInt[222].fromHex"0x39f6d3a994cebea4199cec0404d0ec02a9ded2017fff2dff7fffffff"
Bandersnatch_TonelliShanks_twoAdicity* = 32
Bandersnatch_TonelliShanks_root_of_unity* = Fp[Bandersnatch].fromHex"0x212d79e5b416b6f0fd56dc8d168d6c0c4024ff270b3e0941b788f500b912f1f"

# ############################################################
#
# Specialized Tonelli-Shanks for Bandersnatch
#
# ############################################################

func precompute_tonelli_shanks_addchain*(
r: var Fp[Bandersnatch],
a: Fp[Bandersnatch]) {.addchain.} =
## Does a^Bandersnatch_TonelliShanks_exponent
## via an addition-chain

var
x10 {.noInit.}: Fp[Bandersnatch]
x100 {.noInit.}: Fp[Bandersnatch]
x110 {.noInit.}: Fp[Bandersnatch]
x1100 {.noInit.}: Fp[Bandersnatch]
x10010 {.noInit.}: Fp[Bandersnatch]
x10011 {.noInit.}: Fp[Bandersnatch]
x10110 {.noInit.}: Fp[Bandersnatch]
x11000 {.noInit.}: Fp[Bandersnatch]
x11010 {.noInit.}: Fp[Bandersnatch]
x100010 {.noInit.}: Fp[Bandersnatch]
x110101 {.noInit.}: Fp[Bandersnatch]
x111011 {.noInit.}: Fp[Bandersnatch]
x1001011 {.noInit.}: Fp[Bandersnatch]
x1001101 {.noInit.}: Fp[Bandersnatch]
x1010101 {.noInit.}: Fp[Bandersnatch]
x1100111 {.noInit.}: Fp[Bandersnatch]
x1101001 {.noInit.}: Fp[Bandersnatch]
x10000011 {.noInit.}: Fp[Bandersnatch]
x10011001 {.noInit.}: Fp[Bandersnatch]
x10011101 {.noInit.}: Fp[Bandersnatch]
x10111111 {.noInit.}: Fp[Bandersnatch]
x11010111 {.noInit.}: Fp[Bandersnatch]
x11011011 {.noInit.}: Fp[Bandersnatch]
x11100111 {.noInit.}: Fp[Bandersnatch]
x11101111 {.noInit.}: Fp[Bandersnatch]
x11111111 {.noInit.}: Fp[Bandersnatch]

x10 .square(a)
x100 .square(x10)
x110 .prod(x10, x100)
x1100 .square(x110)
x10010 .prod(x110, x1100)
x10011 .prod(a, x10010)
x10110 .prod(x100, x10010)
x11000 .prod(x10, x10110)
x11010 .prod(x10, x11000)
x100010 .prod(x1100, x10110)
x110101 .prod(x10011, x100010)
x111011 .prod(x110, x110101)
x1001011 .prod(x10110, x110101)
x1001101 .prod(x10, x1001011)
x1010101 .prod(x11010, x111011)
x1100111 .prod(x10010, x1010101)
x1101001 .prod(x10, x1100111)
x10000011 .prod(x11010, x1101001)
x10011001 .prod(x10110, x10000011)
x10011101 .prod(x100, x10011001)
x10111111 .prod(x100010, x10011101)
x11010111 .prod(x11000, x10111111)
x11011011 .prod(x100, x11010111)
x11100111 .prod(x1100, x11011011)
x11101111 .prod(x11000, x11010111)
x11111111 .prod(x11000, x11100111)
# 26 operations

let a = a # Allow aliasing between r and a

# 26+28 = 54 operations
r.square_repeated(x11100111, 8)
r *= x11011011
r.square_repeated(9)
r *= x10011101
r.square_repeated(9)

# 54 + 20 = 74 operations
r *= x10011001
r.square_repeated(9)
r *= x10011001
r.square_repeated(8)
r *= x11010111

# 74 + 27 = 101 operations
r.square_repeated(6)
r *= x110101
r.square_repeated(10)
r *= x10000011
r.square_repeated(9)

# 101 + 19 = 120 operations
r *= x1100111
r.square_repeated(8)
r *= x111011
r.square_repeated(8)
r *= a

# 120 + 41 = 160 operations
r.square_repeated(14)
r *= x1001101
r.square_repeated(10)
r *= x111011
r.square_repeated(15)

# 161 + 21 = 182 operations
r *= x1010101
r.square_repeated(10)
r *= x11101111
r.square_repeated(8)
r *= x1101001

# 182 + 33 = 215 operations
r.square_repeated(16)
r *= x10111111
r.square_repeated(8)
r *= x11111111
r.square_repeated(7)

# 215 + 20 = 235 operations
r *= x1001011
r.square_repeated(9)
r *= x11111111
r.square_repeated(8)
r *= x10111111

# 235 + 26 = 261 operations
r.square_repeated(8)
r *= x11111111
r.square_repeated(8)
r *= x11111111
r.square_repeated(8)

# 261 + 3 = 264 operations
r *= x11111111
r.square()
r *= a
138 changes: 138 additions & 0 deletions constantine/math/constants/banderwagon_sqrt.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,141 @@ const
Banderwagon_TonelliShanks_exponent* = BigInt[222].fromHex"0x39f6d3a994cebea4199cec0404d0ec02a9ded2017fff2dff7fffffff"
Banderwagon_TonelliShanks_twoAdicity* = 32
Banderwagon_TonelliShanks_root_of_unity* = Fp[Banderwagon].fromHex"0x212d79e5b416b6f0fd56dc8d168d6c0c4024ff270b3e0941b788f500b912f1f"

# ############################################################
#
# Specialized Tonelli-Shanks for Banderwagon
#
# ############################################################

func precompute_tonelli_shanks_addchain*(
r: var Fp[Banderwagon],
a: Fp[Banderwagon]) {.addchain.} =
## Does a^Banderwagon_TonelliShanks_exponent
## via an addition-chain

var
x10 {.noInit.}: Fp[Banderwagon]
x100 {.noInit.}: Fp[Banderwagon]
x110 {.noInit.}: Fp[Banderwagon]
x1100 {.noInit.}: Fp[Banderwagon]
x10010 {.noInit.}: Fp[Banderwagon]
x10011 {.noInit.}: Fp[Banderwagon]
x10110 {.noInit.}: Fp[Banderwagon]
x11000 {.noInit.}: Fp[Banderwagon]
x11010 {.noInit.}: Fp[Banderwagon]
x100010 {.noInit.}: Fp[Banderwagon]
x110101 {.noInit.}: Fp[Banderwagon]
x111011 {.noInit.}: Fp[Banderwagon]
x1001011 {.noInit.}: Fp[Banderwagon]
x1001101 {.noInit.}: Fp[Banderwagon]
x1010101 {.noInit.}: Fp[Banderwagon]
x1100111 {.noInit.}: Fp[Banderwagon]
x1101001 {.noInit.}: Fp[Banderwagon]
x10000011 {.noInit.}: Fp[Banderwagon]
x10011001 {.noInit.}: Fp[Banderwagon]
x10011101 {.noInit.}: Fp[Banderwagon]
x10111111 {.noInit.}: Fp[Banderwagon]
x11010111 {.noInit.}: Fp[Banderwagon]
x11011011 {.noInit.}: Fp[Banderwagon]
x11100111 {.noInit.}: Fp[Banderwagon]
x11101111 {.noInit.}: Fp[Banderwagon]
x11111111 {.noInit.}: Fp[Banderwagon]

x10 .square(a)
x100 .square(x10)
x110 .prod(x10, x100)
x1100 .square(x110)
x10010 .prod(x110, x1100)
x10011 .prod(a, x10010)
x10110 .prod(x100, x10010)
x11000 .prod(x10, x10110)
x11010 .prod(x10, x11000)
x100010 .prod(x1100, x10110)
x110101 .prod(x10011, x100010)
x111011 .prod(x110, x110101)
x1001011 .prod(x10110, x110101)
x1001101 .prod(x10, x1001011)
x1010101 .prod(x11010, x111011)
x1100111 .prod(x10010, x1010101)
x1101001 .prod(x10, x1100111)
x10000011 .prod(x11010, x1101001)
x10011001 .prod(x10110, x10000011)
x10011101 .prod(x100, x10011001)
x10111111 .prod(x100010, x10011101)
x11010111 .prod(x11000, x10111111)
x11011011 .prod(x100, x11010111)
x11100111 .prod(x1100, x11011011)
x11101111 .prod(x11000, x11010111)
x11111111 .prod(x11000, x11100111)
# 26 operations

let a = a # Allow aliasing between r and a

# 26+28 = 54 operations
r.square_repeated(x11100111, 8)
r *= x11011011
r.square_repeated(9)
r *= x10011101
r.square_repeated(9)

# 54 + 20 = 74 operations
r *= x10011001
r.square_repeated(9)
r *= x10011001
r.square_repeated(8)
r *= x11010111

# 74 + 27 = 101 operations
r.square_repeated(6)
r *= x110101
r.square_repeated(10)
r *= x10000011
r.square_repeated(9)

# 101 + 19 = 120 operations
r *= x1100111
r.square_repeated(8)
r *= x111011
r.square_repeated(8)
r *= a

# 120 + 41 = 160 operations
r.square_repeated(14)
r *= x1001101
r.square_repeated(10)
r *= x111011
r.square_repeated(15)

# 161 + 21 = 182 operations
r *= x1010101
r.square_repeated(10)
r *= x11101111
r.square_repeated(8)
r *= x1101001

# 182 + 33 = 215 operations
r.square_repeated(16)
r *= x10111111
r.square_repeated(8)
r *= x11111111
r.square_repeated(7)

# 215 + 20 = 235 operations
r *= x1001011
r.square_repeated(9)
r *= x11111111
r.square_repeated(8)
r *= x10111111

# 235 + 26 = 261 operations
r.square_repeated(8)
r *= x11111111
r.square_repeated(8)
r *= x11111111
r.square_repeated(8)

# 261 + 3 = 264 operations
r *= x11111111
r.square()
r *= a
2 changes: 1 addition & 1 deletion constantine/math/constants/zoo_square_roots.nim
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ macro tonelliShanks*(C: static Curve, value: untyped): untyped =
return bindSym($C & "_TonelliShanks_" & $value)

func hasTonelliShanksAddchain*(C: static Curve): static bool =
when C in {BLS12_377}:
when C in {Bandersnatch, Banderwagon, BLS12_377}:
true
else:
false

0 comments on commit 661a481

Please sign in to comment.