Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Square Root: addition chain for Bandersnatch and banderwagon #356

Merged
merged 1 commit into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading