package mldsa
import (
)
const (
q = 8380417
R = 4294967296
RR = 2365951
qNegInv = 4236238847
one = 4193792
minusOne = 4186625
)
type fieldElement uint32
var errUnreducedFieldElement = errors.New("mldsa: unreduced field element")
func ( uint32) (fieldElement, error) {
if >= q {
return 0, errUnreducedFieldElement
}
return fieldMontgomeryMul(fieldElement(), RR), nil
}
func (, uint32) fieldElement {
:= - + q
return fieldMontgomeryMul(fieldElement(), RR)
}
func ( fieldElement) uint32 {
return uint32(fieldMontgomeryReduce(uint64()))
}
func ( fieldElement) int32 {
:= int32(fieldFromMontgomery())
return constantTimeSelectLessOrEqual(, q/2, , -q)
}
func ( fieldElement) uint32 {
:= int32(fieldFromMontgomery())
return uint32(constantTimeSelectLessOrEqual(, q/2, , q-))
}
func ( uint32) fieldElement {
, := bits.Sub64(uint64(), uint64(q), 0)
return fieldElement( + *q)
}
func (, fieldElement) fieldElement {
:= uint32( + )
return fieldReduceOnce()
}
func (, fieldElement) fieldElement {
:= uint32( - + q)
return fieldReduceOnce()
}
func (, fieldElement) fieldElement {
:= uint64() * uint64()
return fieldMontgomeryReduce()
}
func ( uint64) fieldElement {
:= uint32() * qNegInv
:= ( + uint64()*q) >> 32
return fieldReduceOnce(uint32())
}
func (, , fieldElement) fieldElement {
:= uint64() * uint64(-+q)
return fieldMontgomeryReduce()
}
func (, , , fieldElement) fieldElement {
:= uint64() * uint64()
+= uint64() * uint64()
return fieldMontgomeryReduce()
}
const n = 256
type ringElement [n]fieldElement
func [ ~[n]fieldElement](, ) ( ) {
for := range {
[] = fieldAdd([], [])
}
return
}
func [ ~[n]fieldElement](, ) ( ) {
for := range {
[] = fieldSub([], [])
}
return
}
type nttElement [n]fieldElement
var zetas = [256]fieldElement{4193792, 25847, 5771523, 7861508, 237124, 7602457, 7504169, 466468, 1826347, 2353451, 8021166, 6288512, 3119733, 5495562, 3111497, 2680103, 2725464, 1024112, 7300517, 3585928, 7830929, 7260833, 2619752, 6271868, 6262231, 4520680, 6980856, 5102745, 1757237, 8360995, 4010497, 280005, 2706023, 95776, 3077325, 3530437, 6718724, 4788269, 5842901, 3915439, 4519302, 5336701, 3574422, 5512770, 3539968, 8079950, 2348700, 7841118, 6681150, 6736599, 3505694, 4558682, 3507263, 6239768, 6779997, 3699596, 811944, 531354, 954230, 3881043, 3900724, 5823537, 2071892, 5582638, 4450022, 6851714, 4702672, 5339162, 6927966, 3475950, 2176455, 6795196, 7122806, 1939314, 4296819, 7380215, 5190273, 5223087, 4747489, 126922, 3412210, 7396998, 2147896, 2715295, 5412772, 4686924, 7969390, 5903370, 7709315, 7151892, 8357436, 7072248, 7998430, 1349076, 1852771, 6949987, 5037034, 264944, 508951, 3097992, 44288, 7280319, 904516, 3958618, 4656075, 8371839, 1653064, 5130689, 2389356, 8169440, 759969, 7063561, 189548, 4827145, 3159746, 6529015, 5971092, 8202977, 1315589, 1341330, 1285669, 6795489, 7567685, 6940675, 5361315, 4499357, 4751448, 3839961, 2091667, 3407706, 2316500, 3817976, 5037939, 2244091, 5933984, 4817955, 266997, 2434439, 7144689, 3513181, 4860065, 4621053, 7183191, 5187039, 900702, 1859098, 909542, 819034, 495491, 6767243, 8337157, 7857917, 7725090, 5257975, 2031748, 3207046, 4823422, 7855319, 7611795, 4784579, 342297, 286988, 5942594, 4108315, 3437287, 5038140, 1735879, 203044, 2842341, 2691481, 5790267, 1265009, 4055324, 1247620, 2486353, 1595974, 4613401, 1250494, 2635921, 4832145, 5386378, 1869119, 1903435, 7329447, 7047359, 1237275, 5062207, 6950192, 7929317, 1312455, 3306115, 6417775, 7100756, 1917081, 5834105, 7005614, 1500165, 777191, 2235880, 3406031, 7838005, 5548557, 6709241, 6533464, 5796124, 4656147, 594136, 4603424, 6366809, 2432395, 2454455, 8215696, 1957272, 3369112, 185531, 7173032, 5196991, 162844, 1616392, 3014001, 810149, 1652634, 4686184, 6581310, 5341501, 3523897, 3866901, 269760, 2213111, 7404533, 1717735, 472078, 7953734, 1723600, 6577327, 1910376, 6712985, 7276084, 8119771, 4546524, 5441381, 6144432, 7959518, 6094090, 183443, 7403526, 1612842, 4834730, 7826001, 3919660, 8332111, 7018208, 3937738, 1400424, 7534263, 1976782}
func ( ringElement) nttElement {
var uint8
for := 128; >= 8; /= 2 {
for := 0; < 256; += 2 * {
++
:= zetas[]
, := [:+], [+:++]
for := 0; < ; += 2 {
:= fieldMontgomeryMul(, [])
[] = fieldSub([], )
[] = fieldAdd([], )
= fieldMontgomeryMul(, [+1])
[+1] = fieldSub([+1], )
[+1] = fieldAdd([+1], )
}
}
}
for := 0; < 256; += 8 {
++
:= zetas[]
:= fieldMontgomeryMul(, [+4])
[+4] = fieldSub([], )
[] = fieldAdd([], )
= fieldMontgomeryMul(, [+5])
[+5] = fieldSub([+1], )
[+1] = fieldAdd([+1], )
= fieldMontgomeryMul(, [+6])
[+6] = fieldSub([+2], )
[+2] = fieldAdd([+2], )
= fieldMontgomeryMul(, [+7])
[+7] = fieldSub([+3], )
[+3] = fieldAdd([+3], )
}
for := 0; < 256; += 4 {
++
:= zetas[]
:= fieldMontgomeryMul(, [+2])
[+2] = fieldSub([], )
[] = fieldAdd([], )
= fieldMontgomeryMul(, [+3])
[+3] = fieldSub([+1], )
[+1] = fieldAdd([+1], )
}
for := 0; < 256; += 2 {
++
:= zetas[]
:= fieldMontgomeryMul(, [+1])
[+1] = fieldSub([], )
[] = fieldAdd([], )
}
return nttElement()
}
func ( nttElement) ringElement {
var uint8 = 255
for := 0; < 256; += 2 {
:= zetas[]
--
:= []
[] = fieldAdd(, [+1])
[+1] = fieldMontgomeryMulSub(, [+1], )
}
for := 0; < 256; += 4 {
:= zetas[]
--
:= []
[] = fieldAdd(, [+2])
[+2] = fieldMontgomeryMulSub(, [+2], )
= [+1]
[+1] = fieldAdd(, [+3])
[+3] = fieldMontgomeryMulSub(, [+3], )
}
for := 0; < 256; += 8 {
:= zetas[]
--
:= []
[] = fieldAdd(, [+4])
[+4] = fieldMontgomeryMulSub(, [+4], )
= [+1]
[+1] = fieldAdd(, [+5])
[+5] = fieldMontgomeryMulSub(, [+5], )
= [+2]
[+2] = fieldAdd(, [+6])
[+6] = fieldMontgomeryMulSub(, [+6], )
= [+3]
[+3] = fieldAdd(, [+7])
[+7] = fieldMontgomeryMulSub(, [+7], )
}
for := 8; < 256; *= 2 {
for := 0; < 256; += 2 * {
:= zetas[]
--
, := [:+], [+:++]
for := 0; < ; += 2 {
:= []
[] = fieldAdd(, [])
[] = fieldMontgomeryMulSub(, [], )
= [+1]
[+1] = fieldAdd(, [+1])
[+1] = fieldMontgomeryMulSub(, [+1], )
}
}
}
for := range {
[] = fieldMontgomeryMul([], 16382)
}
return ringElement()
}
func (, nttElement) ( nttElement) {
for := range {
[] = fieldMontgomeryMul([], [])
}
return
}
func ( []byte, , byte) nttElement {
:= sha3.NewShake128()
.Write()
.Write([]byte{, })
var nttElement
var int
var [168]byte
:= len()
for < n {
if >= len() {
.Read([:])
= 0
}
:= uint32([]) | uint32([+1])<<8 | uint32([+2])<<16
+= 3
, := fieldToMontgomery( & 0b01111111_11111111_11111111)
if != nil {
continue
}
[] =
++
}
return
}
func ( []byte, byte, parameters) ringElement {
:= sha3.NewShake256()
.Write()
.Write([]byte{, 0})
var ringElement
var int
var [136]byte
:= len()
for {
if >= len() {
.Read([:])
= 0
}
:= [] & 0x0F
:= [] >> 4
++
, := coeffFromHalfByte(, )
if {
[] =
++
}
if >= len() {
break
}
, = coeffFromHalfByte(, )
if {
[] =
++
}
if >= len() {
break
}
}
return
}
func ( []byte, parameters) ringElement {
:= sha3.NewShake256()
.Write()
:= make([]byte, 8)
.Read()
var ringElement
for := 256 - .τ; < 256; ++ {
:= make([]byte, 1)
.Read()
for [0] > byte() {
.Read()
}
[] = [[0]]
:= + .τ - 256
:= ([/8] >> ( % 8)) & 1
if == 0 {
[[0]] = one
} else {
[[0]] = minusOne
}
}
return
}
func ( byte, parameters) (fieldElement, bool) {
if > 15 {
panic("internal error: half-byte out of range")
}
switch .η {
case 2:
if > 14 {
return 0, false
}
const = 0x3334
const = 16
:= (uint32() * ) >>
:= uint32() - *5
return fieldSubToMontgomery(2, ), true
case 4:
if > 8 {
return 0, false
}
return fieldSubToMontgomery(4, uint32()), true
default:
panic("internal error: unsupported η")
}
}
func ( fieldElement) ( uint16, fieldElement) {
:= fieldFromMontgomery()
:= + 1<<12 - 1
>>= 13
:= fieldSubToMontgomery(, <<13)
return uint16(),
}
func ( ringElement, parameters) [n]byte {
var [n]byte
switch .γ2 {
case 32:
for := range n {
[] = highBits32(fieldFromMontgomery([]))
}
case 88:
for := range n {
[] = highBits88(fieldFromMontgomery([]))
}
default:
panic("mldsa: internal error: unsupported γ2")
}
return
}
func ( ringElement, [n]byte, parameters) [n]byte {
var [n]byte
switch .γ2 {
case 32:
for := range n {
[] = useHint32([], [])
}
case 88:
for := range n {
[] = useHint88([], [])
}
default:
panic("mldsa: internal error: unsupported γ2")
}
return
}
func (, , ringElement, parameters) ( [n]byte, int) {
switch .γ2 {
case 32:
for := range n {
[] = makeHint32([], [], [])
+= int([])
}
case 88:
for := range n {
[] = makeHint88([], [], [])
+= int([])
}
default:
panic("mldsa: internal error: unsupported γ2")
}
return ,
}
func ( uint32) byte {
:= ( + 127) >> 7
= (*1025 + (1 << 21)) >> 22
&= 0b1111
return byte()
}
func ( fieldElement) ( byte, int32) {
:= fieldFromMontgomery()
= highBits32()
= int32() - int32()*2*(q-1)/32
= constantTimeSelectLessOrEqual(q/2+1, , -q, )
return ,
}
func ( fieldElement, byte) byte {
const = 16
, := decompose32()
if == 1 {
if > 0 {
= ( + 1) %
} else {
= ( - 1) %
}
}
return
}
func (, , fieldElement) byte {
:= fieldSub(, )
:= highBits32(fieldFromMontgomery())
:= highBits32(fieldFromMontgomery(fieldAdd(, )))
return byte(constanttime.ByteEq(, ) ^ 1)
}
func ( uint32) byte {
:= ( + 127) >> 7
= (*11275 + (1 << 23)) >> 24
= constantTimeSelectEqual(, 44, 0, )
return byte()
}
func ( fieldElement) ( byte, int32) {
:= fieldFromMontgomery()
= highBits88()
= int32() - int32()*2*(q-1)/88
= constantTimeSelectLessOrEqual(q/2+1, , -q, )
return ,
}
func ( fieldElement, byte) byte {
const = 44
, := decompose88()
if == 1 {
if > 0 {
if == -1 {
= 0
} else {
++
}
} else {
if == 0 {
= - 1
} else {
--
}
}
}
return
}
func (, , fieldElement) byte {
:= fieldSub(, )
:= highBits88(fieldFromMontgomery())
:= highBits88(fieldFromMontgomery(fieldAdd(, )))
return byte(constanttime.ByteEq(, ) ^ 1)
}
func ( []byte, ringElement, parameters) []byte {
switch .γ1 {
case 17:
return bitPack18(, )
case 19:
return bitPack20(, )
default:
panic("mldsa: internal error: unsupported γ1")
}
}
func ( []byte, ringElement) []byte {
, := sliceForAppend(, 18*n/8)
const = 1 << 17
for := 0; < n; += 4 {
:= - fieldCenteredMod([])
[0] = byte( << 0)
[1] = byte( >> 8)
[2] = byte( >> 16)
:= - fieldCenteredMod([+1])
[2] |= byte( << 2)
[3] = byte( >> 6)
[4] = byte( >> 14)
:= - fieldCenteredMod([+2])
[4] |= byte( << 4)
[5] = byte( >> 4)
[6] = byte( >> 12)
:= - fieldCenteredMod([+3])
[6] |= byte( << 6)
[7] = byte( >> 2)
[8] = byte( >> 10)
= [4*18/8:]
}
return
}
func ( []byte, ringElement) []byte {
, := sliceForAppend(, 20*n/8)
const = 1 << 19
for := 0; < n; += 2 {
:= - fieldCenteredMod([])
[0] = byte( << 0)
[1] = byte( >> 8)
[2] = byte( >> 16)
:= - fieldCenteredMod([+1])
[2] |= byte( << 4)
[3] = byte( >> 4)
[4] = byte( >> 12)
= [2*20/8:]
}
return
}
func ( []byte, parameters) ringElement {
switch .γ1 {
case 17:
return bitUnpack18()
case 19:
return bitUnpack20()
default:
panic("mldsa: internal error: unsupported γ1")
}
}
func ( []byte) ringElement {
if len() != 18*n/8 {
panic("mldsa: internal error: invalid bitUnpack18 input length")
}
const = 1 << 17
const = 1<<18 - 1
var ringElement
for := 0; < n; += 4 {
:= uint32([0]) | uint32([1])<<8 | uint32([2])<<16
[+0] = fieldSubToMontgomery(, &)
:= uint32([2])>>2 | uint32([3])<<6 | uint32([4])<<14
[+1] = fieldSubToMontgomery(, &)
:= uint32([4])>>4 | uint32([5])<<4 | uint32([6])<<12
[+2] = fieldSubToMontgomery(, &)
:= uint32([6])>>6 | uint32([7])<<2 | uint32([8])<<10
[+3] = fieldSubToMontgomery(, &)
= [4*18/8:]
}
return
}
func ( []byte) ringElement {
if len() != 20*n/8 {
panic("mldsa: internal error: invalid bitUnpack20 input length")
}
const = 1 << 19
const = 1<<20 - 1
var ringElement
for := 0; < n; += 2 {
:= uint32([0]) | uint32([1])<<8 | uint32([2])<<16
[+0] = fieldSubToMontgomery(, &)
:= uint32([2])>>4 | uint32([3])<<4 | uint32([4])<<12
[+1] = fieldSubToMontgomery(, &)
= [2*20/8:]
}
return
}
func ( []byte, int) (, []byte) {
if := len() + ; cap() >= {
= [:]
} else {
= make([]byte, )
copy(, )
}
= [len():]
return
}
func (, , , int32) int32 {
return int32(constanttime.Select(constanttime.LessOrEq(int(), int()), int(), int()))
}
func (, , , uint32) uint32 {
return uint32(constanttime.Select(constanttime.Eq(int32(), int32()), int(), int()))
}
func ( int32) uint32 {
return uint32(constantTimeSelectLessOrEqual(0, , , -))
}