Closed mratsim closed 2 weeks ago
Notice that if not in an UncheckedArray or a seq, the following compiles
import std/bitops
const WordBitWidth = sizeof(pointer) * 8
func wordsRequired*(bits: int): int {.inline.} =
const divShiftor = fastLog2(uint32(WordBitWidth))
result = (bits + WordBitWidth - 1) shr divShiftor
type
Algebra* = enum
BLS12_381
BigInt*[bits: static int] = object
limbs*: array[wordsRequired(bits), uint]
Fr*[Name: static Algebra] = object
residue_form*: BigInt[255]
Fp*[Name: static Algebra] = object
residue_form*: BigInt[381]
FF*[Name: static Algebra] = Fp[Name] or Fr[Name]
type
EC_ShortW_Aff*[F] = object
## Elliptic curve point for a curve in Short Weierstrass form
## y² = x³ + a x + b
##
## over a field F
x*, y*: F
template getScalarField*(EC: type EC_ShortW_Aff): untyped =
Fr[EC.F.Name]
# ------------------------------------------------------------------------------
type IpaProof*[logN: static int, EC] = object
L*{.align: 64.}: array[logN, EC]
R*{.align: 64.}: array[logN, EC]
a0*: getScalarField(EC) # compiles
# a0*: EC.getScalarField() # Error: in expression 'EC.getScalarField()': identifier expected, but found 'EC.getScalarField'
func new*(T: type IpaProof): T =
discard
# ------------------------------------------------------------------------------
proc main() =
let proof = IpaProof[8, EC_ShortW_Aff[Fp[BLS12_381]]].new()
main()
!nim c
import std/bitops
const WordBitWidth = sizeof(pointer) * 8
func wordsRequired*(bits: int): int {.inline.} =
const divShiftor = fastLog2(uint32(WordBitWidth))
result = (bits + WordBitWidth - 1) shr divShiftor
type
Algebra* = enum
BLS12_381
BigInt*[bits: static int] = object
limbs*: array[wordsRequired(bits), uint]
Fr*[Name: static Algebra] = object
residue_form*: BigInt[255]
Fp*[Name: static Algebra] = object
residue_form*: BigInt[381]
FF*[Name: static Algebra] = Fp[Name] or Fr[Name]
type
EC_ShortW_Aff*[F] = object
## Elliptic curve point for a curve in Short Weierstrass form
## y² = x³ + a x + b
##
## over a field F
x*, y*: F
type FieldKind* = enum
kBaseField
kScalarField
template getBigInt*[Name: static Algebra](T: type FF[Name]): untyped =
## Get the underlying BigInt type.
typeof(default(T).mres)
func bits*[Name: static Algebra](T: type FF[Name]): static int =
T.getBigInt().bits
template getScalarField*(EC: type EC_ShortW_Aff): untyped =
Fr[EC.F.Name]
# ------------------------------------------------------------------------------
type
ECFFT_Descriptor*[EC] = object
## Metadata for FFT on Elliptic Curve
order*: int
# rootsOfUnity*: ptr UncheckedArray[BigInt[EC.getScalarField().bits()]] # Error: in expression 'EC.getScalarField()': identifier expected, but found 'EC.getScalarField'
rootsOfUnity*: ptr UncheckedArray[BigInt[getScalarField(EC).bits()]] # Compiler SIGSEGV: Illegal Storage Access
func new*(T: type ECFFT_Descriptor): T =
discard
# ------------------------------------------------------------------------------
proc main() =
let ctx = ECFFT_Descriptor[EC_ShortW_Aff[Fp[BLS12_381]]].new()
main()
0 (0 bytes)
```cpp
```
2024-07-18T13:01:38
2024-07-18T13:01:38
0 (0 bytes)
```cpp
```
2024-07-18T13:01:42
2024-07-18T13:01:42
0 (0 bytes)
```cpp
```
2024-07-18T13:01:45
2024-07-18T13:01:45
0 (0 bytes)
```cpp
```
2024-07-18T13:01:48
2024-07-18T13:01:49
0 (0 bytes)
```cpp
```
2024-07-18T13:01:52
2024-07-18T13:01:52
0 (0 bytes)
```cpp
```
2024-07-18T13:01:55
2024-07-18T13:01:55
0 (0 bytes)
```cpp
```
2024-07-18T13:01:57
2024-07-18T13:01:57
0 (0 bytes)
```cpp
```
2024-07-18T13:01:59
2024-07-18T13:02:00
11.4.0
14.0.0
20.4
2024-07-18T13:01:11Z
2
nim c --run -d:nimDebug -d:nimDebugDlOpen -d:ssl -d:nimDisableCertificateValidation --forceBuild:on --colors:off --verbosity:0 --hints:off --lineTrace:off --nimcache:/home/runner/work/Nim/Nim --out:/home/runner/work/Nim/Nim/temp /home/runner/work/Nim/Nim/temp.nim
:robot: Bug found in 24 minutes
bisecting 8
commits at 0
commits per second
I have both this and #23855 working in a complicated PR (#23411) but in the test code of both issues I have defined getBigInt
as:
template getBigInt*[Name: static Algebra](T: type FF[Name]): untyped =
## Get the underlying BigInt type.
typeof(default(T).residue_form)
since in #23855 it's not defined and in this one it uses a .mres
field which is actually undeclared.
Unfortunately only the code in the issues compile + the length of the bigint arrays are computed correctly, but the complex node in ECFFT_Descriptor doesn't get instantiated properly yet and breaks sigmatch when trying to match the ECFFT_Descriptor type against generic procs. Maybe that'll be sorted out as well but just a heads up that a new issue might be needed if things still don't work
Wow, thanks, that seems like a very involved debugging session full of footguns.
Yeah it took a while lol, I ended up needing to debug the compiler on constantine itself because the workaround for this issue broke too. I couldn't figure out that it was the niche interaction with sigmatch that couldn't instantiate it so I couldn't come up with simpler test code, and I didn't think the required change in semgnrc
would even work because it completely breaks a lot of code if enabled in generic procs and not generic types.
Good news is I know why the remaining instantiation issue happens and have a fix for it in #23194, the compiler converts any expressions matching a static
parameter (in this case a call with tyFromExpr
matches bits: static int
) into an nkStaticExpr
with a tyStatic
type, and static types for some reason completely avoid instantiation. We can get away with just avoiding this conversion if the type is tyFromExpr
for this issue to work, but actually instantiating tyStatic
fixes 1 issue completely rather than partially so I'll include it as well since it doesn't seem to break anything.
A slight modification to #23853, depending if we use method call syntax or function call syntax we get either identifier expected or a compiler segfault on uninitialized value