mirror of
https://github.com/logos-storage/constantine.git
synced 2026-01-08 16:13:14 +00:00
Replace Limb terminology by Word
This commit is contained in:
parent
27e2d2d2bc
commit
9b1dc4ca30
@ -39,16 +39,16 @@
|
|||||||
|
|
||||||
import ./word_types
|
import ./word_types
|
||||||
|
|
||||||
type Limb* = Ct[uint64]
|
type Word* = Ct[uint64]
|
||||||
const LimbBitSize* = sizeof(Limb) * 8 - 1
|
const WordBitSize* = sizeof(Word) * 8 - 1
|
||||||
## Limbs are 63-bit by default
|
## Limbs are 63-bit by default
|
||||||
|
|
||||||
func words_required(bits: static int): static int =
|
func words_required(bits: static int): static int =
|
||||||
(bits + LimbBitSize - 1) div LimbBitSize
|
(bits + WordBitSize - 1) div WordBitSize
|
||||||
|
|
||||||
type
|
type
|
||||||
BigInt*[bits: static int] = object
|
BigInt*[bits: static int] = object
|
||||||
limbs*: array[bits.words_required, Limb]
|
limbs*: array[bits.words_required, Word]
|
||||||
|
|
||||||
const HighLimb* = (not Ct[uint64](0)) shr 1
|
const HighLimb* = (not Ct[uint64](0)) shr 1
|
||||||
## This represents 0x7F_FF_FF_FF__FF_FF_FF_FF
|
## This represents 0x7F_FF_FF_FF__FF_FF_FF_FF
|
||||||
@ -56,7 +56,7 @@ const HighLimb* = (not Ct[uint64](0)) shr 1
|
|||||||
## This biggest representable number in our limbs.
|
## This biggest representable number in our limbs.
|
||||||
## i.e. The most significant bit is never set at the end of each function
|
## i.e. The most significant bit is never set at the end of each function
|
||||||
|
|
||||||
template `[]`*(a: Bigint, idx: int): Limb =
|
template `[]`*(a: Bigint, idx: int): Word =
|
||||||
a.limbs[idx]
|
a.limbs[idx]
|
||||||
|
|
||||||
# ############################################################
|
# ############################################################
|
||||||
@ -75,38 +75,38 @@ template `[]`*(a: Bigint, idx: int): Limb =
|
|||||||
# We don't specialise for the control word, any optimizing compiler
|
# We don't specialise for the control word, any optimizing compiler
|
||||||
# will keep it in registers.
|
# will keep it in registers.
|
||||||
|
|
||||||
template addImpl[bits](result: CTBool[Limb], a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Limb]) =
|
template addImpl[bits](result: CTBool[Word], a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Word]) =
|
||||||
## Constant-time big integer in-place addition
|
## Constant-time big integer in-place addition
|
||||||
## Returns if addition carried
|
## Returns if addition carried
|
||||||
for i in static(0 ..< a.limbs.len):
|
for i in static(0 ..< a.limbs.len):
|
||||||
let new_a = a.limbs[i] + b.limbs[i] + Limb(result)
|
let new_a = a.limbs[i] + b.limbs[i] + Word(result)
|
||||||
result = new_a.isMsbSet()
|
result = new_a.isMsbSet()
|
||||||
a[i] = ctl.mux(new_a and HighLimb, a)
|
a[i] = ctl.mux(new_a and HighLimb, a)
|
||||||
|
|
||||||
func add*[bits](a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Limb]): CTBool[Limb] =
|
func add*[bits](a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Word]): CTBool[Word] =
|
||||||
## Constant-time big integer in-place addition
|
## Constant-time big integer in-place addition
|
||||||
## Returns the "carry flag"
|
## Returns the "carry flag"
|
||||||
result.addImpl(a, b, ctl)
|
result.addImpl(a, b, ctl)
|
||||||
|
|
||||||
func add*[bits](a: var BigInt[bits], b: static BigInt[bits], ctl: CTBool[Limb]): CTBool[Limb] =
|
func add*[bits](a: var BigInt[bits], b: static BigInt[bits], ctl: CTBool[Word]): CTBool[Word] =
|
||||||
## Constant-time big integer in-place addition
|
## Constant-time big integer in-place addition
|
||||||
## Returns the "carry flag". Specialization for B being a compile-time constant (usually a modulus).
|
## Returns the "carry flag". Specialization for B being a compile-time constant (usually a modulus).
|
||||||
result.addImpl(a, b, ctl)
|
result.addImpl(a, b, ctl)
|
||||||
|
|
||||||
template subImpl[bits](result: CTBool[Limb], a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Limb]) =
|
template subImpl[bits](result: CTBool[Word], a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Word]) =
|
||||||
## Constant-time big integer in-place substraction
|
## Constant-time big integer in-place substraction
|
||||||
## Returns the "borrow flag"
|
## Returns the "borrow flag"
|
||||||
for i in static(0 ..< a.limbs.len):
|
for i in static(0 ..< a.limbs.len):
|
||||||
let new_a = a.limbs[i] - b.limbs[i] - Limb(result)
|
let new_a = a.limbs[i] - b.limbs[i] - Word(result)
|
||||||
result = new_a.isMsbSet()
|
result = new_a.isMsbSet()
|
||||||
a[i] = ctl.mux(new_a and HighLimb, a)
|
a[i] = ctl.mux(new_a and HighLimb, a)
|
||||||
|
|
||||||
func sub*[bits](a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Limb]): CTBool[Limb] =
|
func sub*[bits](a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Word]): CTBool[Word] =
|
||||||
## Constant-time big integer in-place addition
|
## Constant-time big integer in-place addition
|
||||||
## Returns the "carry flag"
|
## Returns the "carry flag"
|
||||||
result.subImpl(a, b, ctl)
|
result.subImpl(a, b, ctl)
|
||||||
|
|
||||||
func sub*[bits](a: var BigInt[bits], b: static BigInt[bits], ctl: CTBool[Limb]): CTBool[Limb] =
|
func sub*[bits](a: var BigInt[bits], b: static BigInt[bits], ctl: CTBool[Word]): CTBool[Word] =
|
||||||
## Constant-time big integer in-place addition
|
## Constant-time big integer in-place addition
|
||||||
## Returns the "carry flag". Specialization for B being a compile-time constant (usually a modulus).
|
## Returns the "carry flag". Specialization for B being a compile-time constant (usually a modulus).
|
||||||
result.subImpl(a, b, ctl)
|
result.subImpl(a, b, ctl)
|
||||||
|
|||||||
@ -36,16 +36,16 @@ type
|
|||||||
# ############################################################
|
# ############################################################
|
||||||
|
|
||||||
const
|
const
|
||||||
True = ctrue(Limb)
|
True = ctrue(Word)
|
||||||
False = cfalse(Limb)
|
False = cfalse(Word)
|
||||||
|
|
||||||
template add(a: var Fp, b: Fp, ctl: CTBool[Limb]): CTBool[Limb] =
|
template add(a: var Fp, b: Fp, ctl: CTBool[Word]): CTBool[Word] =
|
||||||
add(a.value, b.value, ctl)
|
add(a.value, b.value, ctl)
|
||||||
|
|
||||||
template sub(a: var Fp, b: Fp, ctl: CTBool[Limb]): CTBool[Limb] =
|
template sub(a: var Fp, b: Fp, ctl: CTBool[Word]): CTBool[Word] =
|
||||||
sub(a.value, b.value, ctl)
|
sub(a.value, b.value, ctl)
|
||||||
|
|
||||||
template `[]`(a: Fp, idx: int): Limb =
|
template `[]`(a: Fp, idx: int): Word =
|
||||||
a.value.limbs[idx]
|
a.value.limbs[idx]
|
||||||
|
|
||||||
# ############################################################
|
# ############################################################
|
||||||
@ -69,39 +69,39 @@ func `+`*(a, b: Fp): Fp =
|
|||||||
ctl = ctl or not sub(result, Fp.P, False)
|
ctl = ctl or not sub(result, Fp.P, False)
|
||||||
sub(result, Fp.P, ctl)
|
sub(result, Fp.P, ctl)
|
||||||
|
|
||||||
template scaleadd_impl(a: var Fp, c: Limb) =
|
template scaleadd_impl(a: var Fp, c: Word) =
|
||||||
## Scale-accumulate
|
## Scale-accumulate
|
||||||
##
|
##
|
||||||
## With a word W = 2^LimbBitSize and a field Fp
|
## With a word W = 2^WordBitSize and a field Fp
|
||||||
## Does a <- a * W + c (mod p)
|
## Does a <- a * W + c (mod p)
|
||||||
const len = a.value.limbs.len
|
const len = a.value.limbs.len
|
||||||
|
|
||||||
when Fp.P.bits <= LimbBitSize:
|
when Fp.P.bits <= WordBitSize:
|
||||||
# If the prime fits in a single limb
|
# If the prime fits in a single limb
|
||||||
var q: Limb
|
var q: Word
|
||||||
|
|
||||||
# (hi, lo) = a * 2^63 + c
|
# (hi, lo) = a * 2^63 + c
|
||||||
let hi = a[0] shr 1 # 64 - 63 = 1
|
let hi = a[0] shr 1 # 64 - 63 = 1
|
||||||
let lo = a[0] shl LimbBitSize or c # Assumes most-significant bit in c is not set
|
let lo = a[0] shl WordBitSize or c # Assumes most-significant bit in c is not set
|
||||||
unsafe_div2n1n(q, a[0], hi, lo, Fp.P.limbs[0]) # (hi, lo) mod P
|
unsafe_div2n1n(q, a[0], hi, lo, Fp.P.limbs[0]) # (hi, lo) mod P
|
||||||
|
|
||||||
else:
|
else:
|
||||||
## Multiple limbs
|
## Multiple limbs
|
||||||
let hi = a[^1] # Save the high word to detect carries
|
let hi = a[^1] # Save the high word to detect carries
|
||||||
const R = Fp.P.bits and LimbBitSize # R = bits mod 64
|
const R = Fp.P.bits and WordBitSize # R = bits mod 64
|
||||||
|
|
||||||
when R == 0: # If the number of bits is a multiple of 64
|
when R == 0: # If the number of bits is a multiple of 64
|
||||||
let a1 = a[^2] #
|
let a1 = a[^2] #
|
||||||
let a0 = a[^1] #
|
let a0 = a[^1] #
|
||||||
moveMem(a[1], a[0], (len-1) * Limb.sizeof) # we can just shift words
|
moveMem(a[1], a[0], (len-1) * Word.sizeof) # we can just shift words
|
||||||
a[0] = c # and replace the first one by c
|
a[0] = c # and replace the first one by c
|
||||||
const p0 = Fp.P[^1]
|
const p0 = Fp.P[^1]
|
||||||
else: # Need to deal with partial word shifts at the edge.
|
else: # Need to deal with partial word shifts at the edge.
|
||||||
let a1 = ((a[^2] shl (LimbBitSize-R)) or (a[^3] shr R)) and HighLimb
|
let a1 = ((a[^2] shl (WordBitSize-R)) or (a[^3] shr R)) and HighLimb
|
||||||
let a0 = ((a[^1] shl (LimbBitSize-R)) or (a[^2] shr R)) and HighLimb
|
let a0 = ((a[^1] shl (WordBitSize-R)) or (a[^2] shr R)) and HighLimb
|
||||||
moveMem(a[1], a[0], (len-1) * Limb.sizeof)
|
moveMem(a[1], a[0], (len-1) * Word.sizeof)
|
||||||
a[0] = c
|
a[0] = c
|
||||||
const p0 = ((Fp.P[^1] shl (LimbBitSize-R)) or (Fp.P[^2] shr R)) and HighLimb
|
const p0 = ((Fp.P[^1] shl (WordBitSize-R)) or (Fp.P[^2] shr R)) and HighLimb
|
||||||
|
|
||||||
# p0 has its high bit set. (a0, a1)/p0 fits in a limb.
|
# p0 has its high bit set. (a0, a1)/p0 fits in a limb.
|
||||||
# Get a quotient q, at most we will be 2 iterations off
|
# Get a quotient q, at most we will be 2 iterations off
|
||||||
@ -109,8 +109,8 @@ template scaleadd_impl(a: var Fp, c: Limb) =
|
|||||||
|
|
||||||
let
|
let
|
||||||
a_hi = a0 shr 1 # 64 - 63 = 1
|
a_hi = a0 shr 1 # 64 - 63 = 1
|
||||||
a_lo = (a0 shl LimbBitSize) or a1
|
a_lo = (a0 shl WordBitSize) or a1
|
||||||
var q, r: Limb
|
var q, r: Word
|
||||||
q = unsafe_div2n1n(q, r, a_hi, a_lo, p0) # Estimate quotient
|
q = unsafe_div2n1n(q, r, a_hi, a_lo, p0) # Estimate quotient
|
||||||
q = mux( # If n_hi == divisor
|
q = mux( # If n_hi == divisor
|
||||||
a0 == b0, HighLimb, # Quotient == HighLimb (0b0111...1111)
|
a0 == b0, HighLimb, # Quotient == HighLimb (0b0111...1111)
|
||||||
@ -121,26 +121,26 @@ template scaleadd_impl(a: var Fp, c: Limb) =
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Now substract a*2^63 - q*p
|
# Now substract a*2^63 - q*p
|
||||||
var carry = Limb(0)
|
var carry = Word(0)
|
||||||
var over_p = Limb(1) # Track if quotient than the modulus
|
var over_p = Word(1) # Track if quotient than the modulus
|
||||||
|
|
||||||
for i in static(0 ..< Fp.P.limbs.len):
|
for i in static(0 ..< Fp.P.limbs.len):
|
||||||
var qp_lo: Limb
|
var qp_lo: Word
|
||||||
|
|
||||||
block: # q*p
|
block: # q*p
|
||||||
qp_hi: Limb
|
qp_hi: Word
|
||||||
unsafe_extendedPrecMul(qp_hi, qp_lo, q, Fp.P[i]) # q * p
|
unsafe_extendedPrecMul(qp_hi, qp_lo, q, Fp.P[i]) # q * p
|
||||||
assert qp_lo.isMsbSet.not
|
assert qp_lo.isMsbSet.not
|
||||||
assert carry.isMsbSet.not
|
assert carry.isMsbSet.not
|
||||||
qp_lo += carry # Add carry from previous limb
|
qp_lo += carry # Add carry from previous limb
|
||||||
let qp_carry = qp_lo.isMsbSet
|
let qp_carry = qp_lo.isMsbSet
|
||||||
carry = mux(qp_carry, qp_hi + Limb(1), qp_hi) # New carry
|
carry = mux(qp_carry, qp_hi + Word(1), qp_hi) # New carry
|
||||||
|
|
||||||
qp_lo = qp_lo and HighLimb # Normalize to u63
|
qp_lo = qp_lo and HighLimb # Normalize to u63
|
||||||
|
|
||||||
block: # a*2^63 - q*p
|
block: # a*2^63 - q*p
|
||||||
a[i] -= qp_lo
|
a[i] -= qp_lo
|
||||||
carry += Limb(a[i].isMsbSet) # Adjust if borrow
|
carry += Word(a[i].isMsbSet) # Adjust if borrow
|
||||||
a[i] = a[i] and HighLimb # Normalize to u63
|
a[i] = a[i] and HighLimb # Normalize to u63
|
||||||
|
|
||||||
over_p = mux(
|
over_p = mux(
|
||||||
@ -159,16 +159,16 @@ template scaleadd_impl(a: var Fp, c: Limb) =
|
|||||||
add(a, Fp.P, neg)
|
add(a, Fp.P, neg)
|
||||||
sub(a, Fp.P, tooBig)
|
sub(a, Fp.P, tooBig)
|
||||||
|
|
||||||
func scaleadd*(a: var Fp, c: Limb) =
|
func scaleadd*(a: var Fp, c: Word) =
|
||||||
## Scale-accumulate modulo P
|
## Scale-accumulate modulo P
|
||||||
##
|
##
|
||||||
## With a word W = 2^LimbBitSize and a field Fp
|
## With a word W = 2^WordBitSize and a field Fp
|
||||||
## Does a <- a * W + c (mod p)
|
## Does a <- a * W + c (mod p)
|
||||||
scaleadd_impl(a, c)
|
scaleadd_impl(a, c)
|
||||||
|
|
||||||
func scaleadd*(a: var Fp, c: static Limb) =
|
func scaleadd*(a: var Fp, c: static Word) =
|
||||||
## Scale-accumulate modulo P
|
## Scale-accumulate modulo P
|
||||||
##
|
##
|
||||||
## With a word W = 2^LimbBitSize and a field Fp
|
## With a word W = 2^WordBitSize and a field Fp
|
||||||
## Does a <- a * W + c (mod p)
|
## Does a <- a * W + c (mod p)
|
||||||
scaleadd_impl(a, c)
|
scaleadd_impl(a, c)
|
||||||
|
|||||||
@ -18,7 +18,7 @@ from bitops import fastLog2
|
|||||||
# This will only be used at compile-time
|
# This will only be used at compile-time
|
||||||
# so no constant-time worries (it is constant-time if using the De Bruijn multiplication)
|
# so no constant-time worries (it is constant-time if using the De Bruijn multiplication)
|
||||||
|
|
||||||
func montyMagic*(M: static BigInt): static Limb =
|
func montyMagic*(M: static BigInt): static Word =
|
||||||
## Returns the Montgomery domain magic number for the input modulus:
|
## Returns the Montgomery domain magic number for the input modulus:
|
||||||
## -1/M[0] mod LimbSize
|
## -1/M[0] mod LimbSize
|
||||||
## M[0] is the least significant limb of M
|
## M[0] is the least significant limb of M
|
||||||
@ -63,7 +63,7 @@ func montyMagic*(M: static BigInt): static Limb =
|
|||||||
|
|
||||||
const
|
const
|
||||||
M0 = M.limbs[0]
|
M0 = M.limbs[0]
|
||||||
k = fastLog2(LimbBitSize)
|
k = fastLog2(WordBitSize)
|
||||||
|
|
||||||
result = M0 # Start from an inverse of M0 modulo 2, M0 is odd and it's own inverse
|
result = M0 # Start from an inverse of M0 modulo 2, M0 is odd and it's own inverse
|
||||||
for _ in static(0 ..< k):
|
for _ in static(0 ..< k):
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user