// Copyright 2025 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package mldsaimport ()const ( q = 8380417// 2²³ - 2¹³ + 1R = 4294967296// 2³²RR = 2365951// R² mod q, aka R in the Montgomery domain qNegInv = 4236238847// -q⁻¹ mod R (q * qNegInv ≡ -1 mod R) one = 4193792// R mod q, aka 1 in the Montgomery domain minusOne = 4186625// (q - 1) * R mod q, aka -1 in the Montgomery domain)// fieldElement is an element n of ℤ_q in the Montgomery domain, represented as// an integer x in [0, q) such that x ≡ n * R (mod q) where R = 2³².type fieldElement uint32var errUnreducedFieldElement = errors.New("mldsa: unreduced field element")// fieldToMontgomery checks that a value a is < q, and converts it to// Montgomery form.func fieldToMontgomery( uint32) (fieldElement, error) {if >= q {return0, errUnreducedFieldElement }// a * R² * R⁻¹ ≡ a * R (mod q)returnfieldMontgomeryMul(fieldElement(), RR), nil}// fieldSubToMontgomery converts a difference a - b to Montgomery form.// a and b must be < q. (This bound can probably be relaxed.)func fieldSubToMontgomery(, uint32) fieldElement { := - + qreturnfieldMontgomeryMul(fieldElement(), RR)}// fieldFromMontgomery converts a value a in Montgomery form back to// standard representation.func fieldFromMontgomery( fieldElement) uint32 {// (a * R) * 1 * R⁻¹ ≡ a (mod q)returnuint32(fieldMontgomeryReduce(uint64()))}// fieldCenteredMod returns r mod± q, the value r reduced to the range// [−(q−1)/2, (q−1)/2].func fieldCenteredMod( fieldElement) int32 { := int32(fieldFromMontgomery())// x <= q / 2 ? x : x - qreturnconstantTimeSelectLessOrEqual(, q/2, , -q)}// fieldInfinityNorm returns the infinity norm ||r||∞ of r, or the absolute// value of r centered around 0.func fieldInfinityNorm( fieldElement) uint32 { := int32(fieldFromMontgomery())// x <= q / 2 ? x : |x - q| // |x - q| = -(x - q) = q - x because x < q => x - q < 0returnuint32(constantTimeSelectLessOrEqual(, q/2, , q-))}// fieldReduceOnce reduces a value a < 2q.func fieldReduceOnce( uint32) fieldElement { , := bits.Sub64(uint64(), uint64(q), 0)returnfieldElement( + *q)}// fieldAdd returns a + b mod q.func fieldAdd(, fieldElement) fieldElement { := uint32( + )returnfieldReduceOnce()}// fieldSub returns a - b mod q.func fieldSub(, fieldElement) fieldElement { := uint32( - + q)returnfieldReduceOnce()}// fieldMontgomeryMul returns a * b * R⁻¹ mod q.func fieldMontgomeryMul(, fieldElement) fieldElement { := uint64() * uint64()returnfieldMontgomeryReduce()}// fieldMontgomeryReduce returns x * R⁻¹ mod q for x < q * R.func fieldMontgomeryReduce( uint64) fieldElement { := uint32() * qNegInv := ( + uint64()*q) >> 32returnfieldReduceOnce(uint32())}// fieldMontgomeryMulSub returns a * (b - c). This operation is fused to save a// fieldReduceOnce after the subtraction.func fieldMontgomeryMulSub(, , fieldElement) fieldElement { := uint64() * uint64(-+q)returnfieldMontgomeryReduce()}// fieldMontgomeryAddMul returns a * b + c * d. This operation is fused to save// a fieldReduceOnce and a fieldReduce.func fieldMontgomeryAddMul(, , , fieldElement) fieldElement { := uint64() * uint64() += uint64() * uint64()returnfieldMontgomeryReduce()}const n = 256// ringElement is a polynomial, an element of R_q.type ringElement [n]fieldElement// polyAdd adds two ringElements or nttElements.func polyAdd[ ~[n]fieldElement](, ) ( ) {for := range { [] = fieldAdd([], []) }return}// polySub subtracts two ringElements or nttElements.func polySub[ ~[n]fieldElement](, ) ( ) {for := range { [] = fieldSub([], []) }return}// nttElement is an NTT representation, an element of T_q.type nttElement [n]fieldElement// zetas are the values ζ^BitRev₈(k) mod q for each index k, converted to the// Montgomery domain.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}// ntt maps a ringElement to its nttElement representation.//// It implements NTT, according to FIPS 203, Algorithm 9.func ntt( ringElement) nttElement {varuint8for := 128; >= 8; /= 2 {for := 0; < 256; += 2 * { ++ := zetas[]// Bounds check elimination hint. , := [:+], [+:++]for := 0; < ; += 2 { := fieldMontgomeryMul(, []) [] = fieldSub([], ) [] = fieldAdd([], )// Unroll by 2 for performance. = fieldMontgomeryMul(, [+1]) [+1] = fieldSub([+1], ) [+1] = fieldAdd([+1], ) } } }// Unroll len = 4, 2, and 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([], ) }returnnttElement()}// inverseNTT maps a nttElement back to the ringElement it represents.//// It implements NTT⁻¹, according to FIPS 203, Algorithm 10.func inverseNTT( nttElement) ringElement {varuint8 = 255// Unroll len = 1, 2, and 4.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[] --// Bounds check elimination hint. , := [:+], [+:++]for := 0; < ; += 2 { := [] [] = fieldAdd(, [])// -z * (t - flen[j]) = z * (flen[j] - t) [] = fieldMontgomeryMulSub(, [], )// Unroll by 2 for performance. = [+1] [+1] = fieldAdd(, [+1]) [+1] = fieldMontgomeryMulSub(, [+1], ) } } }for := range { [] = fieldMontgomeryMul([], 16382) // 16382 = 256⁻¹ * R mod q }returnringElement()}// nttMul multiplies two nttElements.func nttMul(, nttElement) ( nttElement) {for := range { [] = fieldMontgomeryMul([], []) }return}// sampleNTT samples an nttElement uniformly at random from the seed rho and the// indices s and r. It implements Step 3 of ExpandA, RejNTTPoly, and// CoeffFromThreeBytes from FIPS 204, passing in ρ, s, and r instead of ρ'.func sampleNTT( []byte, , byte) nttElement { := sha3.NewShake128() .Write() .Write([]byte{, })varnttElementvarint// index into avar [168]byte// buffered reads from B, matching the rate of SHAKE-128 := len() // index into buf, starts in a "buffer fully consumed" statefor < n {if >= len() { .Read([:]) = 0 } := uint32([]) | uint32([+1])<<8 | uint32([+2])<<16 += 3 , := fieldToMontgomery( & 0b01111111_11111111_11111111) // 23 bitsif != nil {continue } [] = ++ }return}// sampleBoundedPoly samples a ringElement with coefficients in [−η, η] from the// seed rho and the index r. It implements RejBoundedPoly and CoeffFromHalfByte// from FIPS 204, passing in ρ and r separately from ExpandS.func sampleBoundedPoly( []byte, byte, parameters) ringElement { := sha3.NewShake256() .Write() .Write([]byte{, 0}) // IntegerToBytes(r, 2)varringElementvarintvar [136]byte// buffered reads from H, matching the rate of SHAKE-256 := len() // index into buf, starts in a "buffer fully consumed" statefor {if >= len() { .Read([:]) = 0 } := [] & 0x0F := [] >> 4 ++ , := coeffFromHalfByte(, )if { [] = ++ }if >= len() {break } , = coeffFromHalfByte(, )if { [] = ++ }if >= len() {break } }return}// sampleInBall samples a ringElement with coefficients in {−1, 0, 1}, and τ// non-zero coefficients. It is not constant-time.func sampleInBall( []byte, parameters) ringElement { := sha3.NewShake256() .Write() := make([]byte, 8) .Read()varringElementfor := 256 - .τ; < 256; ++ { := make([]byte, 1) .Read()for [0] > byte() { .Read() } [] = [[0]]// c[j] = (−1) ^ h[i+τ−256], where h are the bits in s in little-endian. // That is, -1⁰ = 1 if the bit is 0, -1¹ = -1 if it is 1. := + .τ - 256 := ([/8] >> ( % 8)) & 1if == 0 { [[0]] = one } else { [[0]] = minusOne } }return}// coeffFromHalfByte implements CoeffFromHalfByte from FIPS 204.//// It maps a value in [0, 15] to a coefficient in [−η, η]func coeffFromHalfByte( byte, parameters) (fieldElement, bool) {if > 15 {panic("internal error: half-byte out of range") }switch .η {case2:// Return z = 2 − (b mod 5), which maps from // // b = ( 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ) // // to // // b%5 = ( 4, 3, 2, 1, 0, 4, 3, 2, 1, 0, 4, 3, 2, 1, 0 ) // // to // // z = ( -2, -1, 0, 1, 2, -2, -1, 0, 1, 2, -2, -1, 0, 1, 2 ) //if > 14 {return0, false }// Calculate b % 5 with Barrett reduction, to avoid a potentially // variable-time division.const = 0x3334// ⌈2¹⁶ / 5⌉const = 16// log₂(2¹⁶) := (uint32() * ) >> := uint32() - *5returnfieldSubToMontgomery(2, ), truecase4:// Return z = 4 − b, which maps from // // b = ( 8, 7, 6, 5, 4, 3, 2, 1, 0 ) // // to // // z = ( −4, -3, -2, -1, 0, 1, 2, 3, 4 ) //if > 8 {return0, false }returnfieldSubToMontgomery(4, uint32()), truedefault:panic("internal error: unsupported η") }}// power2Round implements Power2Round from FIPS 204.//// It separates the bottom d = 13 bits of each 23-bit coefficient, rounding the// high part based on the low part, and correcting the low part accordingly.func power2Round( fieldElement) ( uint16, fieldElement) { := fieldFromMontgomery()// Add 2¹² - 1 to round up r1 by one if r0 > 2¹². // r is at most 2²³ - 2¹³ + 1, so rr + (2¹² - 1) won't overflow 23 bits. := + 1<<12 - 1 >>= 13// r1 <= 2¹⁰ - 1 // r1 * 2¹³ <= (2¹⁰ - 1) * 2¹³ = 2²³ - 2¹³ < q := fieldSubToMontgomery(, <<13)returnuint16(), }// highBits implements HighBits from FIPS 204.func highBits( ringElement, parameters) [n]byte {var [n]byteswitch .γ2 {case32:for := rangen { [] = highBits32(fieldFromMontgomery([])) }case88:for := rangen { [] = highBits88(fieldFromMontgomery([])) }default:panic("mldsa: internal error: unsupported γ2") }return}// useHint implements UseHint from FIPS 204.//// It is not constant-time.func useHint( ringElement, [n]byte, parameters) [n]byte {var [n]byteswitch .γ2 {case32:for := rangen { [] = useHint32([], []) }case88:for := rangen { [] = useHint88([], []) }default:panic("mldsa: internal error: unsupported γ2") }return}// makeHint implements MakeHint from FIPS 204.func makeHint(, , ringElement, parameters) ( [n]byte, int) {switch .γ2 {case32:for := rangen { [] = makeHint32([], [], []) += int([]) }case88:for := rangen { [] = makeHint88([], [], []) += int([]) }default:panic("mldsa: internal error: unsupported γ2") }return , }// highBits32 implements HighBits from FIPS 204 for γ2 = (q - 1) / 32.func highBits32( uint32) byte {// The implementation is based on the reference implementation and on // BoringSSL. There are exhaustive tests in TestDecompose that compare it to // a straightforward implementation of Decompose from the spec, so for our // purposes it only has to work and be constant-time. := ( + 127) >> 7 = (*1025 + (1 << 21)) >> 22 &= 0b1111returnbyte()}// decompose32 implements Decompose from FIPS 204 for γ2 = (q - 1) / 32.//// r1 is in [0, 15].func decompose32( fieldElement) ( byte, int32) { := fieldFromMontgomery() = highBits32()// r - r1 * (2 * γ2) mod± q = int32() - int32()*2*(q-1)/32 = constantTimeSelectLessOrEqual(q/2+1, , -q, )return , }// useHint32 implements UseHint from FIPS 204 for γ2 = (q - 1) / 32.func useHint32( fieldElement, byte) byte {const = 16// (q − 1) / (2 * γ2) , := decompose32()if == 1 {if > 0 { = ( + 1) % } else {// Underflow is safe, because it operates modulo 256 (since the type // is byte), which is a multiple of m. = ( - 1) % } }return}// makeHint32 implements MakeHint from FIPS 204 for γ2 = (q - 1) / 32.func makeHint32(, , fieldElement) byte {// v1 = HighBits(r + z) = HighBits(w - cs2 + ct0 - ct0) = HighBits(w - cs2) := fieldSub(, ) := highBits32(fieldFromMontgomery())// r1 = HighBits(r) = HighBits(w - cs2 + ct0) := highBits32(fieldFromMontgomery(fieldAdd(, )))returnbyte(constanttime.ByteEq(, ) ^ 1)}// highBits88 implements HighBits from FIPS 204 for γ2 = (q - 1) / 88.func highBits88( uint32) byte {// Like highBits32, this is exhaustively tested in TestDecompose. := ( + 127) >> 7 = (*11275 + (1 << 23)) >> 24 = constantTimeSelectEqual(, 44, 0, )returnbyte()}// decompose88 implements Decompose from FIPS 204 for γ2 = (q - 1) / 88.//// r1 is in [0, 43].func decompose88( fieldElement) ( byte, int32) { := fieldFromMontgomery() = highBits88()// r - r1 * (2 * γ2) mod± q = int32() - int32()*2*(q-1)/88 = constantTimeSelectLessOrEqual(q/2+1, , -q, )return , }// useHint88 implements UseHint from FIPS 204 for γ2 = (q - 1) / 88.func useHint88( fieldElement, byte) byte {const = 44// (q − 1) / (2 * γ2) , := decompose88()if == 1 {if > 0 {// (r1 + 1) mod m, for r1 in [0, m-1]if == -1 { = 0 } else { ++ } } else {// (r1 - 1) % m, for r1 in [0, m-1]if == 0 { = - 1 } else { -- } } }return}// makeHint88 implements MakeHint from FIPS 204 for γ2 = (q - 1) / 88.func makeHint88(, , fieldElement) byte {// Same as makeHint32 above. := fieldSub(, ) := highBits88(fieldFromMontgomery()) := highBits88(fieldFromMontgomery(fieldAdd(, )))returnbyte(constanttime.ByteEq(, ) ^ 1)}// bitPack implements BitPack(r mod± q, γ₁-1, γ₁), which packs the centered// coefficients of r into little-endian γ1+1-bit chunks. It appends to buf.//// It must only be applied to r with coefficients in [−γ₁+1, γ₁], as// guaranteed by the rejection conditions in Sign.func bitPack( []byte, ringElement, parameters) []byte {switch .γ1 {case17:returnbitPack18(, )case19:returnbitPack20(, )default:panic("mldsa: internal error: unsupported γ1") }}// bitPack18 implements BitPack(r mod± q, 2¹⁷-1, 2¹⁷), which packs the centered// coefficients of r into little-endian 18-bit chunks. It appends to buf.//// It must only be applied to r with coefficients in [−2¹⁷+1, 2¹⁷], as// guaranteed by the rejection conditions in Sign.func bitPack18( []byte, ringElement) []byte { , := sliceForAppend(, 18*n/8)const = 1 << 17for := 0; < n; += 4 {// b - [−2¹⁷+1, 2¹⁷] = [0, 2²⁸-1] := - 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}// bitPack20 implements BitPack(r mod± q, 2¹⁹-1, 2¹⁹), which packs the centered// coefficients of r into little-endian 20-bit chunks. It appends to buf.//// It must only be applied to r with coefficients in [−2¹⁹+1, 2¹⁹], as// guaranteed by the rejection conditions in Sign.func bitPack20( []byte, ringElement) []byte { , := sliceForAppend(, 20*n/8)const = 1 << 19for := 0; < n; += 2 {// b - [−2¹⁹+1, 2¹⁹] = [0, 2²⁰-1] := - 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}// bitUnpack implements BitUnpack(v, 2^γ1-1, 2^γ1), which unpacks each γ1+1 bits// in little-endian into a coefficient in [-2^γ1+1, 2^γ1].func bitUnpack( []byte, parameters) ringElement {switch .γ1 {case17:returnbitUnpack18()case19:returnbitUnpack20()default:panic("mldsa: internal error: unsupported γ1") }}// bitUnpack18 implements BitUnpack(v, 2¹⁷-1, 2¹⁷), which unpacks each 18 bits// in little-endian into a coefficient in [-2¹⁷+1, 2¹⁷].func bitUnpack18( []byte) ringElement {iflen() != 18*n/8 {panic("mldsa: internal error: invalid bitUnpack18 input length") }const = 1 << 17const = 1<<18 - 1varringElementfor := 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}// bitUnpack20 implements BitUnpack(v, 2¹⁹-1, 2¹⁹), which unpacks each 20 bits// in little-endian into a coefficient in [-2¹⁹+1, 2¹⁹].func bitUnpack20( []byte) ringElement {iflen() != 20*n/8 {panic("mldsa: internal error: invalid bitUnpack20 input length") }const = 1 << 19const = 1<<20 - 1varringElementfor := 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}// sliceForAppend takes a slice and a requested number of bytes. It returns a// slice with the contents of the given slice followed by that many bytes and a// second slice that aliases into it and contains only the extra bytes. If the// original slice has sufficient capacity then no allocation is performed.func sliceForAppend( []byte, int) (, []byte) {if := len() + ; cap() >= { = [:] } else { = make([]byte, )copy(, ) } = [len():]return}// constantTimeSelectLessOrEqual returns yes if a <= b, no otherwise, in constant time.func constantTimeSelectLessOrEqual(, , , int32) int32 {returnint32(constanttime.Select(constanttime.LessOrEq(int(), int()), int(), int()))}// constantTimeSelectEqual returns yes if a == b, no otherwise, in constant time.func constantTimeSelectEqual(, , , uint32) uint32 {returnuint32(constanttime.Select(constanttime.Eq(int32(), int32()), int(), int()))}// constantTimeAbs returns the absolute value of x in constant time.func constantTimeAbs( int32) uint32 {returnuint32(constantTimeSelectLessOrEqual(0, , , -))}
The pages are generated with Goldsv0.8.3-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.