-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
fixes #23784 notes that before #23477, it didn't fold paths containing `addr`/`unsafeAddr` because it retained the form of the magic function: `mAddr`.
- Loading branch information
Showing
2 changed files
with
158 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
discard """ | ||
joinable: false | ||
""" | ||
|
||
|
||
# debug ICE: genCheckedRecordField | ||
# apparently after https://github.com/nim-lang/Nim/pull/23477 | ||
|
||
# bug #23784 | ||
|
||
import std/bitops, std/macros | ||
|
||
# -------------------------------------------------------------- | ||
|
||
type Algebra = enum | ||
BN254_Snarks | ||
|
||
type SecretWord* = distinct uint64 | ||
const WordBitWidth* = sizeof(SecretWord) * 8 | ||
|
||
func wordsRequired*(bits: int): int {.inline.} = | ||
const divShiftor = fastLog2(WordBitWidth) | ||
result = (bits + WordBitWidth - 1) shr divShiftor | ||
|
||
type | ||
BigInt*[bits: static int] = object | ||
limbs*: array[bits.wordsRequired, SecretWord] # <--- crash points to here | ||
|
||
# -------------------------------------------------------------- | ||
|
||
const CurveBitWidth = [ | ||
BN254_Snarks: 254 | ||
] | ||
|
||
const BN254_Snarks_Modulus = BigInt[254](limbs: [SecretWord 0x1, SecretWord 0x2, SecretWord 0x3, SecretWord 0x4]) | ||
const BN254_Snarks_Order = BigInt[254](limbs: [SecretWord 0x1, SecretWord 0x1, SecretWord 0x2, SecretWord 0x2]) | ||
|
||
func montyOne*(M: BigInt[254]): BigInt[254] = | ||
## Returns "1 (mod M)" in the Montgomery domain. | ||
## This is equivalent to R (mod M) in the natural domain | ||
BigInt[254](limbs: [SecretWord 0x1, SecretWord 0x1, SecretWord 0x1, SecretWord 0x1]) | ||
|
||
|
||
{.experimental: "dynamicBindSym".} | ||
|
||
type | ||
DerivedConstantMode* = enum | ||
kModulus | ||
kOrder | ||
|
||
macro genDerivedConstants*(mode: static DerivedConstantMode): untyped = | ||
## Generate constants derived from the main constants | ||
## | ||
## For example | ||
## - the Montgomery magic constant "R^2 mod N" in ROM | ||
## For each curve under the private symbol "MyCurve_R2modP" | ||
## - the Montgomery magic constant -1/P mod 2^Wordbitwidth | ||
## For each curve under the private symbol "MyCurve_NegInvModWord | ||
## - ... | ||
|
||
# Now typedesc are NimNode and there is no way to translate | ||
# NimNode -> typedesc easily so we can't | ||
# "for curve in low(Curve) .. high(Curve):" | ||
# As an ugly workaround, we count | ||
# The item at position 0 is a pragma | ||
result = newStmtList() | ||
|
||
template used(name: string): NimNode = | ||
nnkPragmaExpr.newTree( | ||
ident(name), | ||
nnkPragma.newTree(ident"used") | ||
) | ||
|
||
let ff = if mode == kModulus: "_Fp" else: "_Fr" | ||
|
||
for curveSym in low(Algebra) .. high(Algebra): | ||
let curve = $curveSym | ||
let M = if mode == kModulus: bindSym(curve & "_Modulus") | ||
else: bindSym(curve & "_Order") | ||
|
||
# const MyCurve_montyOne = montyOne(MyCurve_Modulus) | ||
result.add newConstStmt( | ||
used(curve & ff & "_MontyOne"), newCall( | ||
bindSym"montyOne", | ||
M | ||
) | ||
) | ||
|
||
# -------------------------------------------------------------- | ||
|
||
{.experimental: "dynamicBindSym".} | ||
|
||
genDerivedConstants(kModulus) | ||
genDerivedConstants(kOrder) | ||
|
||
proc bindConstant(ff: NimNode, property: string): NimNode = | ||
# Need to workaround https://github.com/nim-lang/Nim/issues/14021 | ||
# which prevents checking if a type FF[Name] = Fp[Name] or Fr[Name] | ||
# was instantiated with Fp or Fr. | ||
# getTypeInst only returns FF and sameType doesn't work. | ||
# so quote do + when checks. | ||
let T = getTypeInst(ff) | ||
T.expectKind(nnkBracketExpr) | ||
doAssert T[0].eqIdent("typedesc") | ||
|
||
let curve = | ||
if T[1].kind == nnkBracketExpr: # typedesc[Fp[BLS12_381]] as used internally | ||
# doAssert T[1][0].eqIdent"Fp" or T[1][0].eqIdent"Fr", "Found ident: '" & $T[1][0] & "' instead of 'Fp' or 'Fr'" | ||
T[1][1].expectKind(nnkIntLit) # static enum are ints in the VM | ||
$Algebra(T[1][1].intVal) | ||
else: # typedesc[bls12381_fp] alias as used for C exports | ||
let T1 = getTypeInst(T[1].getImpl()[2]) | ||
if T1.kind != nnkBracketExpr or | ||
T1[1].kind != nnkIntLit: | ||
echo T.repr() | ||
echo T1.repr() | ||
echo getTypeInst(T1).treerepr() | ||
error "getTypeInst didn't return the full instantiation." & | ||
" Dealing with types in macros is hard, complain at https://github.com/nim-lang/RFCs/issues/44" | ||
$Algebra(T1[1].intVal) | ||
|
||
let curve_fp = bindSym(curve & "_Fp_" & property) | ||
let curve_fr = bindSym(curve & "_Fr_" & property) | ||
result = quote do: | ||
when `ff` is Fp: | ||
`curve_fp` | ||
elif `ff` is Fr: | ||
`curve_fr` | ||
else: | ||
{.error: "Unreachable, received type: " & $`ff`.} | ||
|
||
# -------------------------------------------------------------- | ||
|
||
template matchingBigInt*(Name: static Algebra): untyped = | ||
## BigInt type necessary to store the prime field Fp | ||
# Workaround: https://github.com/nim-lang/Nim/issues/16774 | ||
# as we cannot do array accesses in type section. | ||
# Due to generic sandwiches, it must be exported. | ||
BigInt[CurveBitWidth[Name]] | ||
|
||
type | ||
Fp*[Name: static Algebra] = object | ||
mres*: matchingBigInt(Name) | ||
|
||
macro getMontyOne*(ff: type Fp): untyped = | ||
## Get one in Montgomery representation (i.e. R mod P) | ||
result = bindConstant(ff, "MontyOne") | ||
|
||
func getOne*(T: type Fp): T {.noInit, inline.} = | ||
result = cast[ptr T](unsafeAddr getMontyOne(T))[] | ||
|
||
# -------------------------------------------------------------- | ||
proc foo(T: Fp) = | ||
discard T | ||
|
||
let a = Fp[BN254_Snarks].getOne() | ||
foo(a) # oops this was a leftover that broke the bisect. |