mirror of
https://github.com/emmansun/gmsm.git
synced 2025-09-16 03:43:50 +08:00
![github-actions[bot]](/assets/img/avatar_default.png)
* build(deps): bump github/codeql-action from 3.29.11 to 3.30.0 (#361) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.29.11 to 3.30.0. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](3c3833e0f8...2d92b76c45
) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 3.30.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump codecov/codecov-action from 5.5.0 to 5.5.1 (#362) Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5.5.0 to 5.5.1. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](fdcc847654...5a1091511a
) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-version: 5.5.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump actions/setup-go from 5.5.0 to 6.0.0 (#363) Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5.5.0 to 6.0.0. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](d35c59abb0...4469467582
) --- updated-dependencies: - dependency-name: actions/setup-go dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump github/codeql-action from 3.30.0 to 3.30.1 (#364) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.30.0 to 3.30.1. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](2d92b76c45...f1f6e5f6af
) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 3.30.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump step-security/harden-runner from 2.13.0 to 2.13.1 (#367) Bumps [step-security/harden-runner](https://github.com/step-security/harden-runner) from 2.13.0 to 2.13.1. - [Release notes](https://github.com/step-security/harden-runner/releases) - [Commits](ec9f2d5744...f4a75cfd61
) --- updated-dependencies: - dependency-name: step-security/harden-runner dependency-version: 2.13.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump github/codeql-action from 3.30.1 to 3.30.2 (#368) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.30.1 to 3.30.2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](f1f6e5f6af...d3678e237b
) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 3.30.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat(mlkem): initialize mlkem from golang standard library * chore(mlkem): refactoring, reduce alloc times * build(deps): bump github/codeql-action from 3.30.2 to 3.30.3 (#369) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.30.2 to 3.30.3. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](d3678e237b...192325c861
) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 3.30.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * doc(README): include MLKEM --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Sun Yimin <emmansun@users.noreply.github.com>
272 lines
7.2 KiB
Go
272 lines
7.2 KiB
Go
// Copyright 2023 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.
|
|
|
|
//go:build go1.24
|
|
|
|
package mlkem
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"math/big"
|
|
mathrand "math/rand/v2"
|
|
"strconv"
|
|
"testing"
|
|
)
|
|
|
|
func TestFieldReduce(t *testing.T) {
|
|
for a := range uint32(2*q*q) {
|
|
got := fieldReduce(a)
|
|
exp := fieldElement(a % q)
|
|
if got != exp {
|
|
t.Fatalf("reduce(%d) = %d, expected %d", a, got, exp)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFieldAdd(t *testing.T) {
|
|
for a := range fieldElement(q) {
|
|
for b := range fieldElement(q) {
|
|
got := fieldAdd(a, b)
|
|
exp := (a + b) % q
|
|
if got != exp {
|
|
t.Fatalf("%d + %d = %d, expected %d", a, b, got, exp)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFieldSub(t *testing.T) {
|
|
for a := range fieldElement(q) {
|
|
for b := range fieldElement(q) {
|
|
got := fieldSub(a, b)
|
|
exp := (a - b + q) % q
|
|
if got != exp {
|
|
t.Fatalf("%d - %d = %d, expected %d", a, b, got, exp)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFieldMul(t *testing.T) {
|
|
for a := range fieldElement(q) {
|
|
for b := range fieldElement(q) {
|
|
got := fieldMul(a, b)
|
|
exp := fieldElement((uint32(a) * uint32(b)) % q)
|
|
if got != exp {
|
|
t.Fatalf("%d * %d = %d, expected %d", a, b, got, exp)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDecompressCompress(t *testing.T) {
|
|
for _, bits := range []uint8{1, 4, 10} {
|
|
for a := uint16(0); a < 1<<bits; a++ {
|
|
f := decompress(a, bits)
|
|
if f >= q {
|
|
t.Fatalf("decompress(%d, %d) = %d >= q", a, bits, f)
|
|
}
|
|
got := compress(f, bits)
|
|
if got != a {
|
|
t.Fatalf("compress(decompress(%d, %d), %d) = %d", a, bits, bits, got)
|
|
}
|
|
}
|
|
|
|
for a := fieldElement(0); a < q; a++ {
|
|
c := compress(a, bits)
|
|
if c >= 1<<bits {
|
|
t.Fatalf("compress(%d, %d) = %d >= 2^bits", a, bits, c)
|
|
}
|
|
got := decompress(c, bits)
|
|
diff := min(a-got, got-a, a-got+q, got-a+q)
|
|
ceil := q / (1 << bits)
|
|
if diff > fieldElement(ceil) {
|
|
t.Fatalf("decompress(compress(%d, %d), %d) = %d (diff %d, max diff %d)",
|
|
a, bits, bits, got, diff, ceil)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func CompressRat(x fieldElement, d uint8) uint16 {
|
|
if x >= q {
|
|
panic("x out of range")
|
|
}
|
|
if d <= 0 || d >= 12 {
|
|
panic("d out of range")
|
|
}
|
|
|
|
precise := big.NewRat((1<<d)*int64(x), q) // (2ᵈ / q) * x == (2ᵈ * x) / q
|
|
|
|
// FloatString rounds halves away from 0, and our result should always be positive,
|
|
// so it should work as we expect. (There's no direct way to round a Rat.)
|
|
rounded, err := strconv.ParseInt(precise.FloatString(0), 10, 64)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// If we rounded up, `rounded` may be equal to 2ᵈ, so we perform a final reduction.
|
|
return uint16(rounded % (1 << d))
|
|
}
|
|
|
|
func TestCompress(t *testing.T) {
|
|
for d := 1; d < 12; d++ {
|
|
for n := range q {
|
|
expected := CompressRat(fieldElement(n), uint8(d))
|
|
result := compress(fieldElement(n), uint8(d))
|
|
if result != expected {
|
|
t.Errorf("compress(%d, %d): got %d, expected %d", n, d, result, expected)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func DecompressRat(y uint16, d uint8) fieldElement {
|
|
if y >= 1<<d {
|
|
panic("y out of range")
|
|
}
|
|
if d <= 0 || d >= 12 {
|
|
panic("d out of range")
|
|
}
|
|
|
|
precise := big.NewRat(q*int64(y), 1<<d) // (q / 2ᵈ) * y == (q * y) / 2ᵈ
|
|
|
|
// FloatString rounds halves away from 0, and our result should always be positive,
|
|
// so it should work as we expect. (There's no direct way to round a Rat.)
|
|
rounded, err := strconv.ParseInt(precise.FloatString(0), 10, 64)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// If we rounded up, `rounded` may be equal to q, so we perform a final reduction.
|
|
return fieldElement(rounded % q)
|
|
}
|
|
|
|
func TestDecompress(t *testing.T) {
|
|
for d := 1; d < 12; d++ {
|
|
for n := 0; n < (1 << d); n++ {
|
|
expected := DecompressRat(uint16(n), uint8(d))
|
|
result := decompress(uint16(n), uint8(d))
|
|
if result != expected {
|
|
t.Errorf("decompress(%d, %d): got %d, expected %d", n, d, result, expected)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func randomRingElement() ringElement {
|
|
var r ringElement
|
|
for i := range r {
|
|
r[i] = fieldElement(mathrand.IntN(q))
|
|
}
|
|
return r
|
|
}
|
|
|
|
func TestEncodeDecode(t *testing.T) {
|
|
f := randomRingElement()
|
|
b := make([]byte, 12*n/8)
|
|
rand.Read(b)
|
|
|
|
// Compare ringCompressAndEncode to ringCompressAndEncodeN.
|
|
e1 := ringCompressAndEncode(nil, f, 10)
|
|
e2 := ringCompressAndEncode10(nil, f)
|
|
if !bytes.Equal(e1, e2) {
|
|
t.Errorf("ringCompressAndEncode = %x, ringCompressAndEncode10 = %x", e1, e2)
|
|
}
|
|
e1 = ringCompressAndEncode(nil, f, 4)
|
|
e2 = ringCompressAndEncode4(nil, f)
|
|
if !bytes.Equal(e1, e2) {
|
|
t.Errorf("ringCompressAndEncode = %x, ringCompressAndEncode4 = %x", e1, e2)
|
|
}
|
|
e1 = ringCompressAndEncode(nil, f, 1)
|
|
e2 = ringCompressAndEncode1(nil, f)
|
|
if !bytes.Equal(e1, e2) {
|
|
t.Errorf("ringCompressAndEncode = %x, ringCompressAndEncode1 = %x", e1, e2)
|
|
}
|
|
|
|
// Compare ringDecodeAndDecompress to ringDecodeAndDecompressN.
|
|
g1 := ringDecodeAndDecompress(b[:encodingSize10], 10)
|
|
g2 := ringDecodeAndDecompress10((*[encodingSize10]byte)(b))
|
|
if g1 != g2 {
|
|
t.Errorf("ringDecodeAndDecompress = %v, ringDecodeAndDecompress10 = %v", g1, g2)
|
|
}
|
|
g1 = ringDecodeAndDecompress(b[:encodingSize4], 4)
|
|
g2 = ringDecodeAndDecompress4((*[encodingSize4]byte)(b))
|
|
if g1 != g2 {
|
|
t.Errorf("ringDecodeAndDecompress = %v, ringDecodeAndDecompress4 = %v", g1, g2)
|
|
}
|
|
g1 = ringDecodeAndDecompress(b[:encodingSize1], 1)
|
|
g2 = ringDecodeAndDecompress1((*[encodingSize1]byte)(b))
|
|
if g1 != g2 {
|
|
t.Errorf("ringDecodeAndDecompress = %v, ringDecodeAndDecompress1 = %v", g1, g2)
|
|
}
|
|
|
|
// Round-trip ringCompressAndEncode and ringDecodeAndDecompress.
|
|
for d := 1; d < 12; d++ {
|
|
encodingSize := d * n / 8
|
|
g := ringDecodeAndDecompress(b[:encodingSize], uint8(d))
|
|
out := ringCompressAndEncode(nil, g, uint8(d))
|
|
if !bytes.Equal(out, b[:encodingSize]) {
|
|
t.Errorf("roundtrip failed for d = %d", d)
|
|
}
|
|
}
|
|
|
|
// Round-trip ringCompressAndEncodeN and ringDecodeAndDecompressN.
|
|
g := ringDecodeAndDecompress10((*[encodingSize10]byte)(b))
|
|
out := ringCompressAndEncode10(nil, g)
|
|
if !bytes.Equal(out, b[:encodingSize10]) {
|
|
t.Errorf("roundtrip failed for specialized 10")
|
|
}
|
|
g = ringDecodeAndDecompress4((*[encodingSize4]byte)(b))
|
|
out = ringCompressAndEncode4(nil, g)
|
|
if !bytes.Equal(out, b[:encodingSize4]) {
|
|
t.Errorf("roundtrip failed for specialized 4")
|
|
}
|
|
g = ringDecodeAndDecompress1((*[encodingSize1]byte)(b))
|
|
out = ringCompressAndEncode1(nil, g)
|
|
if !bytes.Equal(out, b[:encodingSize1]) {
|
|
t.Errorf("roundtrip failed for specialized 1")
|
|
}
|
|
}
|
|
|
|
func BitRev7(n uint8) uint8 {
|
|
if n>>7 != 0 {
|
|
panic("not 7 bits")
|
|
}
|
|
var r uint8
|
|
r |= n >> 6 & 0b0000_0001
|
|
r |= n >> 4 & 0b0000_0010
|
|
r |= n >> 2 & 0b0000_0100
|
|
r |= n /**/ & 0b0000_1000
|
|
r |= n << 2 & 0b0001_0000
|
|
r |= n << 4 & 0b0010_0000
|
|
r |= n << 6 & 0b0100_0000
|
|
return r
|
|
}
|
|
|
|
func TestZetas(t *testing.T) {
|
|
ζ := big.NewInt(17)
|
|
q := big.NewInt(q)
|
|
for k, zeta := range zetas {
|
|
// ζ^BitRev7(k) mod q
|
|
exp := new(big.Int).Exp(ζ, big.NewInt(int64(BitRev7(uint8(k)))), q)
|
|
if big.NewInt(int64(zeta)).Cmp(exp) != 0 {
|
|
t.Errorf("zetas[%d] = %v, expected %v", k, zeta, exp)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGammas(t *testing.T) {
|
|
ζ := big.NewInt(17)
|
|
q := big.NewInt(q)
|
|
for k, gamma := range gammas {
|
|
// ζ^2BitRev7(i)+1
|
|
exp := new(big.Int).Exp(ζ, big.NewInt(int64(BitRev7(uint8(k)))*2+1), q)
|
|
if big.NewInt(int64(gamma)).Cmp(exp) != 0 {
|
|
t.Errorf("gammas[%d] = %v, expected %v", k, gamma, exp)
|
|
}
|
|
}
|
|
}
|