mirror of
https://github.com/logos-storage/constantine.git
synced 2026-01-02 13:13:07 +00:00
move research sanity check to research/ [skip ci]
This commit is contained in:
parent
495ef4497b
commit
95114bf707
@ -63,7 +63,7 @@ Protocols are a set of routines, designed for specific goals or a combination th
|
|||||||
- integrity: the received message has not been tampered with
|
- integrity: the received message has not been tampered with
|
||||||
- non-repudiation: the sender of a message cannot repudiated it
|
- non-repudiation: the sender of a message cannot repudiated it
|
||||||
|
|
||||||
Protocols to address these goals, (authenticated) encryption, signature, traitor-tracing, etc
|
Protocols to address these goals, (authenticated) encryption, signature, traitor-tracing, etc
|
||||||
are designed.\
|
are designed.\
|
||||||
Note: some goals might be mutually exclusive, for example "plausible deniability" and "non-repudiation".
|
Note: some goals might be mutually exclusive, for example "plausible deniability" and "non-repudiation".
|
||||||
|
|
||||||
@ -112,7 +112,7 @@ The following curves are configured:
|
|||||||
|
|
||||||
With Ristretto, it can be used in bulletproofs.
|
With Ristretto, it can be used in bulletproofs.
|
||||||
- The Pasta curves (Pallas and Vesta) for the Halo 2 proof system (Zcash).
|
- The Pasta curves (Pallas and Vesta) for the Halo 2 proof system (Zcash).
|
||||||
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ and also ensure constant-time code.
|
|||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
Constantine has no dependencies, even on Nim standard library except:
|
Constantine has no dependencies, even on Nim standard library except:
|
||||||
- for testing
|
- for testing
|
||||||
- jsony for parsing json test vectors
|
- jsony for parsing json test vectors
|
||||||
- the Nim standard library for unittesting, formatting and datetime.
|
- the Nim standard library for unittesting, formatting and datetime.
|
||||||
- GMP for testing against GMP
|
- GMP for testing against GMP
|
||||||
|
|||||||
@ -548,313 +548,3 @@ func scalarMulGLV_m2w2*[scalBits; EC](
|
|||||||
# Now we need to correct if the sign miniscalar was not odd
|
# Now we need to correct if the sign miniscalar was not odd
|
||||||
P0.diff(Q, P0)
|
P0.diff(Q, P0)
|
||||||
P0.ccopy(Q, k0isOdd)
|
P0.ccopy(Q, k0isOdd)
|
||||||
|
|
||||||
# Sanity checks
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
# See page 7 of
|
|
||||||
#
|
|
||||||
# - Efficient and Secure Algorithms for GLV-Based Scalar
|
|
||||||
# Multiplication and their Implementation on GLV-GLS
|
|
||||||
# Curves (Extended Version)
|
|
||||||
# Armando Faz-Hernández, Patrick Longa, Ana H. Sánchez, 2013
|
|
||||||
# https://eprint.iacr.org/2013/158.pdf
|
|
||||||
|
|
||||||
when isMainModule:
|
|
||||||
import ../io/io_bigints
|
|
||||||
|
|
||||||
proc toString(glvSac: GLV_SAC): string =
|
|
||||||
for j in 0 ..< glvSac.M:
|
|
||||||
result.add "k" & $j & ": ["
|
|
||||||
for i in countdown(glvSac.LengthInDigits-1, 0):
|
|
||||||
result.add " " & (block:
|
|
||||||
case glvSac[j][i]
|
|
||||||
of 0: "0"
|
|
||||||
of 1: "1"
|
|
||||||
else:
|
|
||||||
raise newException(ValueError, "Unexpected encoded value: " & $glvSac[j][i])
|
|
||||||
)
|
|
||||||
result.add " ]\n"
|
|
||||||
|
|
||||||
|
|
||||||
iterator bits(u: SomeInteger): tuple[bitIndex: int32, bitValue: uint8] =
|
|
||||||
## bit iterator, starts from the least significant bit
|
|
||||||
var u = u
|
|
||||||
var idx = 0'i32
|
|
||||||
while u != 0:
|
|
||||||
yield (idx, uint8(u and 1))
|
|
||||||
u = u shr 1
|
|
||||||
inc idx
|
|
||||||
|
|
||||||
func buildLookupTable_naive[M: static int](
|
|
||||||
P: string,
|
|
||||||
endomorphisms: array[M-1, string],
|
|
||||||
lut: var array[1 shl (M-1), string],
|
|
||||||
) =
|
|
||||||
## Checking the LUT by building strings of endomorphisms additions
|
|
||||||
## This naively translates the lookup table algorithm
|
|
||||||
## Compute P[u] = P0 + u0 P1 +...+ um−2 Pm−1 for all 0≤u<2m−1, where
|
|
||||||
## u= (um−2,...,u0)_2.
|
|
||||||
## The number of additions done per entries is equal to the
|
|
||||||
## iteration variable `u` Hamming Weight
|
|
||||||
for u in 0 ..< 1 shl (M-1):
|
|
||||||
lut[u] = P
|
|
||||||
for u in 0 ..< 1 shl (M-1):
|
|
||||||
for idx, bit in bits(u):
|
|
||||||
if bit == 1:
|
|
||||||
lut[u] &= " + " & endomorphisms[idx]
|
|
||||||
|
|
||||||
func buildLookupTable_reuse[M: static int](
|
|
||||||
P: string,
|
|
||||||
endomorphisms: array[M-1, string],
|
|
||||||
lut: var array[1 shl (M-1), string],
|
|
||||||
) =
|
|
||||||
## Checking the LUT by building strings of endomorphisms additions
|
|
||||||
## This reuses previous table entries so that only one addition is done
|
|
||||||
## per new entries
|
|
||||||
lut[0] = P
|
|
||||||
for u in 1'u32 ..< 1 shl (M-1):
|
|
||||||
let msb = u.log2_vartime() # No undefined, u != 0
|
|
||||||
lut[u] = lut[u.clearBit(msb)] & " + " & endomorphisms[msb]
|
|
||||||
|
|
||||||
proc main_lut() =
|
|
||||||
const M = 4 # GLS-4 decomposition
|
|
||||||
const miniBitwidth = 4 # Bitwidth of the miniscalars resulting from scalar decomposition
|
|
||||||
|
|
||||||
var k: MultiScalar[M, miniBitwidth]
|
|
||||||
var kRecoded: GLV_SAC[M, miniBitwidth]
|
|
||||||
|
|
||||||
k[0].fromUint(11)
|
|
||||||
k[1].fromUint(6)
|
|
||||||
k[2].fromuint(14)
|
|
||||||
k[3].fromUint(3)
|
|
||||||
|
|
||||||
kRecoded.nDimMultiScalarRecoding(k)
|
|
||||||
|
|
||||||
echo "Recoded bytesize: ", sizeof(kRecoded)
|
|
||||||
echo kRecoded.toString()
|
|
||||||
|
|
||||||
var lut: array[1 shl (M-1), string]
|
|
||||||
let
|
|
||||||
P = "P0"
|
|
||||||
endomorphisms = ["P1", "P2", "P3"]
|
|
||||||
|
|
||||||
buildLookupTable_naive(P, endomorphisms, lut)
|
|
||||||
echo lut
|
|
||||||
doAssert lut[0] == "P0"
|
|
||||||
doAssert lut[1] == "P0 + P1"
|
|
||||||
doAssert lut[2] == "P0 + P2"
|
|
||||||
doAssert lut[3] == "P0 + P1 + P2"
|
|
||||||
doAssert lut[4] == "P0 + P3"
|
|
||||||
doAssert lut[5] == "P0 + P1 + P3"
|
|
||||||
doAssert lut[6] == "P0 + P2 + P3"
|
|
||||||
doAssert lut[7] == "P0 + P1 + P2 + P3"
|
|
||||||
|
|
||||||
var lut_reuse: array[1 shl (M-1), string]
|
|
||||||
buildLookupTable_reuse(P, endomorphisms, lut_reuse)
|
|
||||||
echo lut_reuse
|
|
||||||
doAssert lut == lut_reuse
|
|
||||||
|
|
||||||
main_lut()
|
|
||||||
echo "---------------------------------------------"
|
|
||||||
|
|
||||||
proc main_decomp() =
|
|
||||||
const M = 2
|
|
||||||
const scalBits = BN254_Snarks.getCurveOrderBitwidth()
|
|
||||||
const miniBits = (scalBits+M-1) div M
|
|
||||||
const L = miniBits + 1
|
|
||||||
|
|
||||||
block:
|
|
||||||
let scalar = BigInt[scalBits].fromHex(
|
|
||||||
"0x24a0b87203c7a8def0018c95d7fab106373aebf920265c696f0ae08f8229b3f3"
|
|
||||||
)
|
|
||||||
|
|
||||||
var decomp: MultiScalar[M, L]
|
|
||||||
decomp.decomposeEndo(scalar, Fp[BN254_Snarks])
|
|
||||||
|
|
||||||
doAssert: bool(decomp[0] == BigInt[L].fromHex"14928105460c820ccc9a25d0d953dbfe")
|
|
||||||
doAssert: bool(decomp[1] == BigInt[L].fromHex"13a2f911eb48a578844b901de6f41660")
|
|
||||||
|
|
||||||
block:
|
|
||||||
let scalar = BigInt[scalBits].fromHex(
|
|
||||||
"24554fa6d0c06f6dc51c551dea8b058cd737fc8d83f7692fcebdd1842b3092c4"
|
|
||||||
)
|
|
||||||
|
|
||||||
var decomp: MultiScalar[M, L]
|
|
||||||
decomp.decomposeEndo(scalar, Fp[BN254_Snarks])
|
|
||||||
|
|
||||||
doAssert: bool(decomp[0] == BigInt[L].fromHex"28cf7429c3ff8f7e82fc419e90cc3a2")
|
|
||||||
doAssert: bool(decomp[1] == BigInt[L].fromHex"457efc201bdb3d2e6087df36430a6db6")
|
|
||||||
|
|
||||||
block:
|
|
||||||
let scalar = BigInt[scalBits].fromHex(
|
|
||||||
"288c20b297b9808f4e56aeb70eabf269e75d055567ff4e05fe5fb709881e6717"
|
|
||||||
)
|
|
||||||
|
|
||||||
var decomp: MultiScalar[M, L]
|
|
||||||
decomp.decomposeEndo(scalar, Fp[BN254_Snarks])
|
|
||||||
|
|
||||||
doAssert: bool(decomp[0] == BigInt[L].fromHex"4da8c411566c77e00c902eb542aaa66b")
|
|
||||||
doAssert: bool(decomp[1] == BigInt[L].fromHex"5aa8f2f15afc3217f06677702bd4e41a")
|
|
||||||
|
|
||||||
|
|
||||||
main_decomp()
|
|
||||||
echo "---------------------------------------------"
|
|
||||||
|
|
||||||
# This tests the multiplication against the Table 1
|
|
||||||
# of the paper
|
|
||||||
|
|
||||||
# Coef Decimal Binary GLV-SAC recoded
|
|
||||||
# | k0 | | 11 | | 0 1 0 1 1 | | 1 -1 1 -1 1 |
|
|
||||||
# | k1 | = | 6 | = | 0 0 1 1 0 | = | 1 -1 0 -1 0 |
|
|
||||||
# | k2 | | 14 | | 0 1 1 1 0 | | 1 0 0 -1 0 |
|
|
||||||
# | k3 | | 3 | | 0 0 0 1 1 | | 0 0 1 -1 1 |
|
|
||||||
|
|
||||||
# i | 3 2 1 0
|
|
||||||
# -------------------+----------------------------------------------------------------------
|
|
||||||
# 2Q | 2P0+2P1+2P2 2P0+2P1+4P2 6P0+4P1+8P2+2P3 10P0+6P1+14P2+2P3
|
|
||||||
# Q + sign_i T[ki] | P0+P1+2P2 3P0+2P1+4P2+P3 5P0+3P1+7P2+P3 11P0+6P1+14P2+3P3
|
|
||||||
|
|
||||||
type Endo = enum
|
|
||||||
P0
|
|
||||||
P1
|
|
||||||
P2
|
|
||||||
P3
|
|
||||||
|
|
||||||
func buildLookupTable_reuse[M: static int](
|
|
||||||
P: Endo,
|
|
||||||
endomorphisms: array[M-1, Endo],
|
|
||||||
lut: var array[1 shl (M-1), set[Endo]],
|
|
||||||
) =
|
|
||||||
## Checking the LUT by building strings of endomorphisms additions
|
|
||||||
## This reuses previous table entries so that only one addition is done
|
|
||||||
## per new entries
|
|
||||||
lut[0].incl P
|
|
||||||
for u in 1'u32 ..< 1 shl (M-1):
|
|
||||||
let msb = u.log2_vartime() # No undefined, u != 0
|
|
||||||
lut[u] = lut[u.clearBit(msb)] + {endomorphisms[msb]}
|
|
||||||
|
|
||||||
|
|
||||||
proc mainFullMul() =
|
|
||||||
const M = 4 # GLS-4 decomposition
|
|
||||||
const miniBitwidth = 4 # Bitwidth of the miniscalars resulting from scalar decomposition
|
|
||||||
const L = miniBitwidth + 1 # Bitwidth of the recoded scalars
|
|
||||||
|
|
||||||
var k: MultiScalar[M, L]
|
|
||||||
var kRecoded: GLV_SAC[M, L]
|
|
||||||
|
|
||||||
k[0].fromUint(11)
|
|
||||||
k[1].fromUint(6)
|
|
||||||
k[2].fromuint(14)
|
|
||||||
k[3].fromUint(3)
|
|
||||||
|
|
||||||
kRecoded.nDimMultiScalarRecoding(k)
|
|
||||||
|
|
||||||
echo kRecoded.toString()
|
|
||||||
|
|
||||||
var lut: array[1 shl (M-1), set[Endo]]
|
|
||||||
let
|
|
||||||
P = P0
|
|
||||||
endomorphisms = [P1, P2, P3]
|
|
||||||
|
|
||||||
buildLookupTable_reuse(P, endomorphisms, lut)
|
|
||||||
echo lut
|
|
||||||
|
|
||||||
var Q: array[Endo, int]
|
|
||||||
|
|
||||||
# Multiplication
|
|
||||||
assert bool k[0].isOdd()
|
|
||||||
# Q = sign_l-1 P[K_l-1]
|
|
||||||
let idx = kRecoded.tableIndex(L-1)
|
|
||||||
for p in lut[int(idx)]:
|
|
||||||
Q[p] = if kRecoded[0][L-1] == 0: 1 else: -1
|
|
||||||
# Loop
|
|
||||||
for i in countdown(L-2, 0):
|
|
||||||
# Q = 2Q
|
|
||||||
for val in Q.mitems: val *= 2
|
|
||||||
echo "2Q: ", Q
|
|
||||||
# Q = Q + sign_l-1 P[K_l-1]
|
|
||||||
let idx = kRecoded.tableIndex(i)
|
|
||||||
for p in lut[int(idx)]:
|
|
||||||
Q[p] += (if kRecoded[0][i] == 0: 1 else: -1)
|
|
||||||
echo "Q + sign_l-1 P[K_l-1]: ", Q
|
|
||||||
|
|
||||||
echo Q
|
|
||||||
|
|
||||||
mainFullMul()
|
|
||||||
echo "---------------------------------------------"
|
|
||||||
|
|
||||||
func buildLookupTable_m2w2(
|
|
||||||
lut: var array[8, array[2, int]],
|
|
||||||
) =
|
|
||||||
## Build a lookup table for GLV with 2-dimensional decomposition
|
|
||||||
## and window of size 2
|
|
||||||
|
|
||||||
# with [k0, k1] the mini-scalars with digits of size 2-bit
|
|
||||||
#
|
|
||||||
# 0 = 0b000 - encodes [0b01, 0b00] ≡ P0
|
|
||||||
lut[0] = [1, 0]
|
|
||||||
# 1 = 0b001 - encodes [0b01, 0b01] ≡ P0 - P1
|
|
||||||
lut[1] = [1, -1]
|
|
||||||
# 3 = 0b011 - encodes [0b01, 0b11] ≡ P0 + P1
|
|
||||||
lut[3] = [1, 1]
|
|
||||||
# 2 = 0b010 - encodes [0b01, 0b10] ≡ P0 + 2P1
|
|
||||||
lut[2] = [1, 2]
|
|
||||||
|
|
||||||
# 4 = 0b100 - encodes [0b00, 0b00] ≡ 3P0
|
|
||||||
lut[4] = [3, 0]
|
|
||||||
# 5 = 0b101 - encodes [0b00, 0b01] ≡ 3P0 + P1
|
|
||||||
lut[5] = [3, 1]
|
|
||||||
# 6 = 0b110 - encodes [0b00, 0b10] ≡ 3P0 + 2P1
|
|
||||||
lut[6] = [3, 2]
|
|
||||||
# 7 = 0b111 - encodes [0b00, 0b11] ≡ 3P0 + 3P1
|
|
||||||
lut[7] = [3, 3]
|
|
||||||
|
|
||||||
proc mainFullMulWindowed() =
|
|
||||||
const M = 2 # GLS-2 decomposition
|
|
||||||
const miniBitwidth = 8 # Bitwidth of the miniscalars resulting from scalar decomposition
|
|
||||||
const W = 2 # Window
|
|
||||||
const L = computeRecodedLength(miniBitwidth, W)
|
|
||||||
|
|
||||||
var k: MultiScalar[M, L]
|
|
||||||
var kRecoded: GLV_SAC[M, L]
|
|
||||||
|
|
||||||
k[0].fromUint(11)
|
|
||||||
k[1].fromUint(14)
|
|
||||||
|
|
||||||
kRecoded.nDimMultiScalarRecoding(k)
|
|
||||||
|
|
||||||
echo "Recoded bytesize: ", sizeof(kRecoded)
|
|
||||||
echo kRecoded.toString()
|
|
||||||
|
|
||||||
var lut: array[8, array[range[P0..P1], int]]
|
|
||||||
buildLookupTable_m2w2(lut)
|
|
||||||
echo lut
|
|
||||||
|
|
||||||
# Assumes k[0] is odd to simplify test
|
|
||||||
# and having to conditional substract at the end
|
|
||||||
assert bool k[0].isOdd()
|
|
||||||
|
|
||||||
var Q: array[Endo, int]
|
|
||||||
var isNeg: SecretBool
|
|
||||||
|
|
||||||
let idx = kRecoded.w2TableIndex((L div 2)-1, isNeg)
|
|
||||||
for p, coef in lut[int(idx)]:
|
|
||||||
# Unneeeded by construction
|
|
||||||
# let sign = if isNeg: -1 else: 1
|
|
||||||
Q[p] = coef
|
|
||||||
|
|
||||||
# Loop
|
|
||||||
for i in countdown((L div 2)-2, 0):
|
|
||||||
# Q = 4Q
|
|
||||||
for val in Q.mitems: val *= 4
|
|
||||||
echo "4Q: ", Q
|
|
||||||
# Q = Q + sign_l-1 P[K_l-1]
|
|
||||||
let idx = kRecoded.w2TableIndex(i, isNeg)
|
|
||||||
for p, coef in lut[int(idx)]:
|
|
||||||
let sign = (if bool isNeg: -1 else: 1)
|
|
||||||
Q[p] += sign * coef
|
|
||||||
echo "Q + sign_l-1 P[K_l-1]: ", Q
|
|
||||||
|
|
||||||
echo Q
|
|
||||||
|
|
||||||
mainFullMulWindowed()
|
|
||||||
|
|||||||
@ -2,7 +2,16 @@
|
|||||||
|
|
||||||
This folder stashes experimentations before they are productionized into the library.
|
This folder stashes experimentations before they are productionized into the library.
|
||||||
|
|
||||||
|
- `GLV`: Scalar multiplication with endomorphism acceleration\
|
||||||
|
- Faster Point Multiplication on Elliptic Curves with Efficient Endomorphisms\
|
||||||
|
Robert P. Gallant, Robert J. Lambert, and Scott A. Vanstone
|
||||||
|
https://www.iacr.org/archive/crypto2001/21390189.pdf
|
||||||
|
- Efficient and Secure Algorithms for GLV-Based Scalar Multiplication and their Implementation on GLV-GLS Curves (Extended Version)\
|
||||||
|
Armando Faz-Hernández, Patrick Longa, Ana H. Sánchez, 2013\
|
||||||
|
https://eprint.iacr.org/2013/158.pdf
|
||||||
|
|
||||||
|
|
||||||
- `kzg`: KZG Polynomial Commitments\
|
- `kzg`: KZG Polynomial Commitments\
|
||||||
Constant-Size Commitments to Polynomials and Their Applications\
|
- Constant-Size Commitments to Polynomials and Their Applications\
|
||||||
Aniket Kate, Gregory M. Zaverucha, Ian Goldberg, 2010\
|
Aniket Kate, Gregory M. Zaverucha, Ian Goldberg, 2010\
|
||||||
https://www.iacr.org/archive/asiacrypt2010/6477178/6477178.pdf
|
https://www.iacr.org/archive/asiacrypt2010/6477178/6477178.pdf
|
||||||
|
|||||||
265
research/glv.nim
Normal file
265
research/glv.nim
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
# Research into the paper
|
||||||
|
|
||||||
|
# - Efficient and Secure Algorithms for GLV-Based Scalar
|
||||||
|
# Multiplication and their Implementation on GLV-GLS
|
||||||
|
# Curves (Extended Version)
|
||||||
|
# Armando Faz-Hernández, Patrick Longa, Ana H. Sánchez, 2013
|
||||||
|
# https://eprint.iacr.org/2013/158.pdf
|
||||||
|
|
||||||
|
import ../constantine/math/elliptic/ec_endomorphism_accel {.all.},
|
||||||
|
../constantine/platforms/abstractions,
|
||||||
|
../constantine/math/io/io_bigints,
|
||||||
|
../constantine/math/arithmetic
|
||||||
|
|
||||||
|
proc toString(glvSac: GLV_SAC): string =
|
||||||
|
for j in 0 ..< glvSac.M:
|
||||||
|
result.add "k" & $j & ": ["
|
||||||
|
for i in countdown(glvSac.LengthInDigits-1, 0):
|
||||||
|
result.add " " & (block:
|
||||||
|
case glvSac[j][i]
|
||||||
|
of 0: "0"
|
||||||
|
of 1: "1"
|
||||||
|
else:
|
||||||
|
raise newException(ValueError, "Unexpected encoded value: " & $glvSac[j][i])
|
||||||
|
)
|
||||||
|
result.add " ]\n"
|
||||||
|
|
||||||
|
iterator bits(u: SomeInteger): tuple[bitIndex: int32, bitValue: uint8] =
|
||||||
|
## bit iterator, starts from the least significant bit
|
||||||
|
var u = u
|
||||||
|
var idx = 0'i32
|
||||||
|
while u != 0:
|
||||||
|
yield (idx, uint8(u and 1))
|
||||||
|
u = u shr 1
|
||||||
|
inc idx
|
||||||
|
|
||||||
|
func buildLookupTable_naive[M: static int](
|
||||||
|
P: string,
|
||||||
|
endomorphisms: array[M-1, string],
|
||||||
|
lut: var array[1 shl (M-1), string],
|
||||||
|
) =
|
||||||
|
## Checking the LUT by building strings of endomorphisms additions
|
||||||
|
## This naively translates the lookup table algorithm
|
||||||
|
## Compute P[u] = P0 + u0 P1 +...+ um−2 Pm−1 for all 0≤u<2m−1, where
|
||||||
|
## u= (um−2,...,u0)_2.
|
||||||
|
## The number of additions done per entries is equal to the
|
||||||
|
## iteration variable `u` Hamming Weight
|
||||||
|
for u in 0 ..< 1 shl (M-1):
|
||||||
|
lut[u] = P
|
||||||
|
for u in 0 ..< 1 shl (M-1):
|
||||||
|
for idx, bit in bits(u):
|
||||||
|
if bit == 1:
|
||||||
|
lut[u] &= " + " & endomorphisms[idx]
|
||||||
|
|
||||||
|
func buildLookupTable_reuse[M: static int](
|
||||||
|
P: string,
|
||||||
|
endomorphisms: array[M-1, string],
|
||||||
|
lut: var array[1 shl (M-1), string],
|
||||||
|
) =
|
||||||
|
## Checking the LUT by building strings of endomorphisms additions
|
||||||
|
## This reuses previous table entries so that only one addition is done
|
||||||
|
## per new entries
|
||||||
|
lut[0] = P
|
||||||
|
for u in 1'u32 ..< 1 shl (M-1):
|
||||||
|
let msb = u.log2_vartime() # No undefined, u != 0
|
||||||
|
lut[u] = lut[u.clearBit(msb)] & " + " & endomorphisms[msb]
|
||||||
|
|
||||||
|
proc main_lut() =
|
||||||
|
const M = 4 # GLS-4 decomposition
|
||||||
|
const miniBitwidth = 4 # Bitwidth of the miniscalars resulting from scalar decomposition
|
||||||
|
|
||||||
|
var k: MultiScalar[M, miniBitwidth]
|
||||||
|
var kRecoded: GLV_SAC[M, miniBitwidth]
|
||||||
|
|
||||||
|
k[0].fromUint(11)
|
||||||
|
k[1].fromUint(6)
|
||||||
|
k[2].fromuint(14)
|
||||||
|
k[3].fromUint(3)
|
||||||
|
|
||||||
|
kRecoded.nDimMultiScalarRecoding(k)
|
||||||
|
|
||||||
|
echo "Recoded bytesize: ", sizeof(kRecoded)
|
||||||
|
echo kRecoded.toString()
|
||||||
|
|
||||||
|
var lut: array[1 shl (M-1), string]
|
||||||
|
let
|
||||||
|
P = "P0"
|
||||||
|
endomorphisms = ["P1", "P2", "P3"]
|
||||||
|
|
||||||
|
buildLookupTable_naive(P, endomorphisms, lut)
|
||||||
|
echo lut
|
||||||
|
doAssert lut[0] == "P0"
|
||||||
|
doAssert lut[1] == "P0 + P1"
|
||||||
|
doAssert lut[2] == "P0 + P2"
|
||||||
|
doAssert lut[3] == "P0 + P1 + P2"
|
||||||
|
doAssert lut[4] == "P0 + P3"
|
||||||
|
doAssert lut[5] == "P0 + P1 + P3"
|
||||||
|
doAssert lut[6] == "P0 + P2 + P3"
|
||||||
|
doAssert lut[7] == "P0 + P1 + P2 + P3"
|
||||||
|
|
||||||
|
var lut_reuse: array[1 shl (M-1), string]
|
||||||
|
buildLookupTable_reuse(P, endomorphisms, lut_reuse)
|
||||||
|
echo lut_reuse
|
||||||
|
doAssert lut == lut_reuse
|
||||||
|
|
||||||
|
main_lut()
|
||||||
|
echo "---------------------------------------------"
|
||||||
|
|
||||||
|
# This tests the multiplication against the Table 1
|
||||||
|
# of the paper
|
||||||
|
|
||||||
|
# Coef Decimal Binary GLV-SAC recoded
|
||||||
|
# | k0 | | 11 | | 0 1 0 1 1 | | 1 -1 1 -1 1 |
|
||||||
|
# | k1 | = | 6 | = | 0 0 1 1 0 | = | 1 -1 0 -1 0 |
|
||||||
|
# | k2 | | 14 | | 0 1 1 1 0 | | 1 0 0 -1 0 |
|
||||||
|
# | k3 | | 3 | | 0 0 0 1 1 | | 0 0 1 -1 1 |
|
||||||
|
|
||||||
|
# i | 3 2 1 0
|
||||||
|
# -------------------+----------------------------------------------------------------------
|
||||||
|
# 2Q | 2P0+2P1+2P2 2P0+2P1+4P2 6P0+4P1+8P2+2P3 10P0+6P1+14P2+2P3
|
||||||
|
# Q + sign_i T[ki] | P0+P1+2P2 3P0+2P1+4P2+P3 5P0+3P1+7P2+P3 11P0+6P1+14P2+3P3
|
||||||
|
|
||||||
|
type Endo = enum
|
||||||
|
P0
|
||||||
|
P1
|
||||||
|
P2
|
||||||
|
P3
|
||||||
|
|
||||||
|
func buildLookupTable_reuse[M: static int](
|
||||||
|
P: Endo,
|
||||||
|
endomorphisms: array[M-1, Endo],
|
||||||
|
lut: var array[1 shl (M-1), set[Endo]],
|
||||||
|
) =
|
||||||
|
## Checking the LUT by building strings of endomorphisms additions
|
||||||
|
## This reuses previous table entries so that only one addition is done
|
||||||
|
## per new entries
|
||||||
|
lut[0].incl P
|
||||||
|
for u in 1'u32 ..< 1 shl (M-1):
|
||||||
|
let msb = u.log2_vartime() # No undefined, u != 0
|
||||||
|
lut[u] = lut[u.clearBit(msb)] + {endomorphisms[msb]}
|
||||||
|
|
||||||
|
|
||||||
|
proc mainFullMul() =
|
||||||
|
const M = 4 # GLS-4 decomposition
|
||||||
|
const miniBitwidth = 4 # Bitwidth of the miniscalars resulting from scalar decomposition
|
||||||
|
const L = miniBitwidth + 1 # Bitwidth of the recoded scalars
|
||||||
|
|
||||||
|
var k: MultiScalar[M, L]
|
||||||
|
var kRecoded: GLV_SAC[M, L]
|
||||||
|
|
||||||
|
k[0].fromUint(11)
|
||||||
|
k[1].fromUint(6)
|
||||||
|
k[2].fromuint(14)
|
||||||
|
k[3].fromUint(3)
|
||||||
|
|
||||||
|
kRecoded.nDimMultiScalarRecoding(k)
|
||||||
|
|
||||||
|
echo kRecoded.toString()
|
||||||
|
|
||||||
|
var lut: array[1 shl (M-1), set[Endo]]
|
||||||
|
let
|
||||||
|
P = P0
|
||||||
|
endomorphisms = [P1, P2, P3]
|
||||||
|
|
||||||
|
buildLookupTable_reuse(P, endomorphisms, lut)
|
||||||
|
echo lut
|
||||||
|
|
||||||
|
var Q: array[Endo, int]
|
||||||
|
|
||||||
|
# Multiplication
|
||||||
|
assert bool k[0].isOdd()
|
||||||
|
# Q = sign_l-1 P[K_l-1]
|
||||||
|
let idx = kRecoded.tableIndex(L-1)
|
||||||
|
for p in lut[int(idx)]:
|
||||||
|
Q[p] = if kRecoded[0][L-1] == 0: 1 else: -1
|
||||||
|
# Loop
|
||||||
|
for i in countdown(L-2, 0):
|
||||||
|
# Q = 2Q
|
||||||
|
for val in Q.mitems: val *= 2
|
||||||
|
echo "2Q: ", Q
|
||||||
|
# Q = Q + sign_l-1 P[K_l-1]
|
||||||
|
let idx = kRecoded.tableIndex(i)
|
||||||
|
for p in lut[int(idx)]:
|
||||||
|
Q[p] += (if kRecoded[0][i] == 0: 1 else: -1)
|
||||||
|
echo "Q + sign_l-1 P[K_l-1]: ", Q
|
||||||
|
|
||||||
|
echo Q
|
||||||
|
|
||||||
|
mainFullMul()
|
||||||
|
echo "---------------------------------------------"
|
||||||
|
|
||||||
|
func buildLookupTable_m2w2(
|
||||||
|
lut: var array[8, array[2, int]],
|
||||||
|
) =
|
||||||
|
## Build a lookup table for GLV with 2-dimensional decomposition
|
||||||
|
## and window of size 2
|
||||||
|
|
||||||
|
# with [k0, k1] the mini-scalars with digits of size 2-bit
|
||||||
|
#
|
||||||
|
# 0 = 0b000 - encodes [0b01, 0b00] ≡ P0
|
||||||
|
lut[0] = [1, 0]
|
||||||
|
# 1 = 0b001 - encodes [0b01, 0b01] ≡ P0 - P1
|
||||||
|
lut[1] = [1, -1]
|
||||||
|
# 3 = 0b011 - encodes [0b01, 0b11] ≡ P0 + P1
|
||||||
|
lut[3] = [1, 1]
|
||||||
|
# 2 = 0b010 - encodes [0b01, 0b10] ≡ P0 + 2P1
|
||||||
|
lut[2] = [1, 2]
|
||||||
|
|
||||||
|
# 4 = 0b100 - encodes [0b00, 0b00] ≡ 3P0
|
||||||
|
lut[4] = [3, 0]
|
||||||
|
# 5 = 0b101 - encodes [0b00, 0b01] ≡ 3P0 + P1
|
||||||
|
lut[5] = [3, 1]
|
||||||
|
# 6 = 0b110 - encodes [0b00, 0b10] ≡ 3P0 + 2P1
|
||||||
|
lut[6] = [3, 2]
|
||||||
|
# 7 = 0b111 - encodes [0b00, 0b11] ≡ 3P0 + 3P1
|
||||||
|
lut[7] = [3, 3]
|
||||||
|
|
||||||
|
proc mainFullMulWindowed() =
|
||||||
|
const M = 2 # GLS-2 decomposition
|
||||||
|
const miniBitwidth = 8 # Bitwidth of the miniscalars resulting from scalar decomposition
|
||||||
|
const W = 2 # Window
|
||||||
|
const L = computeRecodedLength(miniBitwidth, W)
|
||||||
|
|
||||||
|
var k: MultiScalar[M, L]
|
||||||
|
var kRecoded: GLV_SAC[M, L]
|
||||||
|
|
||||||
|
k[0].fromUint(11)
|
||||||
|
k[1].fromUint(14)
|
||||||
|
|
||||||
|
kRecoded.nDimMultiScalarRecoding(k)
|
||||||
|
|
||||||
|
echo "Recoded bytesize: ", sizeof(kRecoded)
|
||||||
|
echo kRecoded.toString()
|
||||||
|
|
||||||
|
var lut: array[8, array[range[P0..P1], int]]
|
||||||
|
buildLookupTable_m2w2(lut)
|
||||||
|
echo lut
|
||||||
|
|
||||||
|
# Assumes k[0] is odd to simplify test
|
||||||
|
# and having to conditional substract at the end
|
||||||
|
assert bool k[0].isOdd()
|
||||||
|
|
||||||
|
var Q: array[Endo, int]
|
||||||
|
var isNeg: SecretBool
|
||||||
|
|
||||||
|
let idx = kRecoded.w2TableIndex((L div 2)-1, isNeg)
|
||||||
|
for p, coef in lut[int(idx)]:
|
||||||
|
# Unneeeded by construction
|
||||||
|
# let sign = if isNeg: -1 else: 1
|
||||||
|
Q[p] = coef
|
||||||
|
|
||||||
|
# Loop
|
||||||
|
for i in countdown((L div 2)-2, 0):
|
||||||
|
# Q = 4Q
|
||||||
|
for val in Q.mitems: val *= 4
|
||||||
|
echo "4Q: ", Q
|
||||||
|
# Q = Q + sign_l-1 P[K_l-1]
|
||||||
|
let idx = kRecoded.w2TableIndex(i, isNeg)
|
||||||
|
for p, coef in lut[int(idx)]:
|
||||||
|
let sign = (if bool isNeg: -1 else: 1)
|
||||||
|
Q[p] += sign * coef
|
||||||
|
echo "Q + sign_l-1 P[K_l-1]: ", Q
|
||||||
|
|
||||||
|
echo Q
|
||||||
|
|
||||||
|
mainFullMulWindowed()
|
||||||
Loading…
x
Reference in New Issue
Block a user