mirror of
https://github.com/emmansun/gmsm.git
synced 2025-09-15 11:28:03 +08:00
Merge develop into main (#370)
* 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>
This commit is contained in:
parent
86095a396f
commit
1979d24faa
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
||||
goVer: ['1.23', '1.24']
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@ -26,7 +26,7 @@ jobs:
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
||||
with:
|
||||
go-version: ${{ matrix.goVer }}
|
||||
|
||||
@ -44,7 +44,7 @@ jobs:
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
if: ${{ matrix.goVer == '1.24' }}
|
||||
uses: codecov/codecov-action@fdcc8476540edceab3de004e990f80d881c6cc00 # v5.5.0
|
||||
uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
|
||||
with:
|
||||
files: ./coverage1.txt,./coverage2.txt
|
||||
env:
|
||||
|
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
@ -28,7 +28,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@ -37,12 +37,12 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.5
|
||||
uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3.29.5
|
||||
with:
|
||||
languages: go
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.5
|
||||
uses: github/codeql-action/autobuild@192325c86100d080feab897ff886c34abd4c83a3 # v3.29.5
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.5
|
||||
uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3.29.5
|
||||
|
4
.github/workflows/licenses.yml
vendored
4
.github/workflows/licenses.yml
vendored
@ -14,12 +14,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
||||
with:
|
||||
go-version: '1.23'
|
||||
- name: Install go-licenses
|
||||
|
4
.github/workflows/macos.yml
vendored
4
.github/workflows/macos.yml
vendored
@ -15,14 +15,14 @@ jobs:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
||||
with:
|
||||
go-version: 1.23
|
||||
|
||||
|
2
.github/workflows/pre-release.yml
vendored
2
.github/workflows/pre-release.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
4
.github/workflows/scorecard.yml
vendored
4
.github/workflows/scorecard.yml
vendored
@ -34,7 +34,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@ -78,6 +78,6 @@ jobs:
|
||||
# Upload the results to GitHub's code scanning dashboard (optional).
|
||||
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.5
|
||||
uses: github/codeql-action/upload-sarif@192325c86100d080feab897ff886c34abd4c83a3 # v3.29.5
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
4
.github/workflows/test_ppc64.yaml
vendored
4
.github/workflows/test_ppc64.yaml
vendored
@ -23,12 +23,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
|
4
.github/workflows/test_qemu.yml
vendored
4
.github/workflows/test_qemu.yml
vendored
@ -22,12 +22,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
|
4
.github/workflows/test_riscv64.yaml
vendored
4
.github/workflows/test_riscv64.yaml
vendored
@ -22,12 +22,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
|
4
.github/workflows/test_s390x.yaml
vendored
4
.github/workflows/test_s390x.yaml
vendored
@ -22,12 +22,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
|
4
.github/workflows/test_sm_ni.yml
vendored
4
.github/workflows/test_sm_ni.yml
vendored
@ -22,12 +22,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
|
@ -40,6 +40,8 @@ ShangMi (SM) cipher suites for Golang, referred to as **GMSM**, is a secure, hig
|
||||
|
||||
- **DRBG** - Random Number Generation Using Deterministic Random Bit Generators, for detail, please reference **NIST Special Publication 800-90A** and **GM/T 0105-2021**: CTR-DRBG using derivation function and HASH-DRBG. NIST related implementations are tested with part of NIST provided test vectors. It's **NOT** concurrent safe! You can also use [randomness](https://github.com/Trisia/randomness) tool to check the generated random bits.
|
||||
|
||||
- **MLKEM** - NIST FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard.
|
||||
|
||||
- **MLDSA** - NIST FIPS 204 Module-Lattice-Based Digital Signature Standard.
|
||||
|
||||
- **SLHDSA** - NIST FIPS 205 Stateless Hash-Based Digital Signature Standard
|
||||
|
@ -53,6 +53,8 @@ Go语言商用密码软件,简称**GMSM**,一个安全、高性能、易于
|
||||
|
||||
- **DRBG** - 《GM/T 0105-2021软件随机数发生器设计指南》实现。本实现同时支持**NIST Special Publication 800-90A**(部分) 和 **GM/T 0105-2021**,NIST相关实现使用了NIST提供的测试数据进行测试。本实现**不支持并发使用**。
|
||||
|
||||
- **MLKEM** - NIST FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard实现,基于Golang标准库,支持所有三组参数集(ML-KEM-512/ML-KEM-768/ML-KEM-1024)。
|
||||
|
||||
- **MLDSA** - NIST FIPS 204 Module-Lattice-Based Digital Signature Standard实现。
|
||||
|
||||
- **SLHDSA** - NIST FIPS 205 Stateless Hash-Based Digital Signature Standard实现。
|
||||
|
568
mlkem/field.go
Normal file
568
mlkem/field.go
Normal file
@ -0,0 +1,568 @@
|
||||
// Copyright 2024 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 (
|
||||
"crypto/sha3"
|
||||
"errors"
|
||||
|
||||
"github.com/emmansun/gmsm/internal/byteorder"
|
||||
)
|
||||
|
||||
// fieldElement is an integer modulo q, an element of ℤ_q. It is always reduced.
|
||||
type fieldElement uint16
|
||||
|
||||
// fieldCheckReduced checks that a value a is < q.
|
||||
func fieldCheckReduced(a uint16) (fieldElement, error) {
|
||||
if a >= q {
|
||||
return 0, errors.New("unreduced field element")
|
||||
}
|
||||
return fieldElement(a), nil
|
||||
}
|
||||
|
||||
// fieldReduceOnce reduces a value a < 2q.
|
||||
func fieldReduceOnce(a uint16) fieldElement {
|
||||
x := a - q
|
||||
// If x underflowed, then x >= 2¹⁶ - q > 2¹⁵, so the top bit is set.
|
||||
x += (x >> 15) * q
|
||||
return fieldElement(x)
|
||||
}
|
||||
|
||||
func fieldAdd(a, b fieldElement) fieldElement {
|
||||
x := uint16(a + b)
|
||||
return fieldReduceOnce(x)
|
||||
}
|
||||
|
||||
func fieldSub(a, b fieldElement) fieldElement {
|
||||
x := uint16(a - b + q)
|
||||
return fieldReduceOnce(x)
|
||||
}
|
||||
|
||||
const (
|
||||
barrettMultiplier = 5039 // 2¹² * 2¹² / q
|
||||
barrettShift = 24 // log₂(2¹² * 2¹²)
|
||||
)
|
||||
|
||||
// fieldReduce reduces a value a < 2q² using Barrett reduction, to avoid
|
||||
// potentially variable-time division.
|
||||
func fieldReduce(a uint32) fieldElement {
|
||||
quotient := uint32((uint64(a) * barrettMultiplier) >> barrettShift)
|
||||
return fieldReduceOnce(uint16(a - quotient*q))
|
||||
}
|
||||
|
||||
func fieldMul(a, b fieldElement) fieldElement {
|
||||
x := uint32(a) * uint32(b)
|
||||
return fieldReduce(x)
|
||||
}
|
||||
|
||||
// fieldMulSub returns a * (b - c). This operation is fused to save a
|
||||
// fieldReduceOnce after the subtraction.
|
||||
func fieldMulSub(a, b, c fieldElement) fieldElement {
|
||||
x := uint32(a) * uint32(b-c+q)
|
||||
return fieldReduce(x)
|
||||
}
|
||||
|
||||
// fieldAddMul returns a * b + c * d. This operation is fused to save a
|
||||
// fieldReduceOnce and a fieldReduce.
|
||||
func fieldAddMul(a, b, c, d fieldElement) fieldElement {
|
||||
x := uint32(a) * uint32(b)
|
||||
x += uint32(c) * uint32(d)
|
||||
return fieldReduce(x)
|
||||
}
|
||||
|
||||
// compress maps a field element uniformly to the range 0 to 2ᵈ-1, according to
|
||||
// FIPS 203, Definition 4.7.
|
||||
func compress(x fieldElement, d uint8) uint16 {
|
||||
// We want to compute (x * 2ᵈ) / q, rounded to nearest integer, with 1/2
|
||||
// rounding up (see FIPS 203, Section 2.3).
|
||||
|
||||
// Barrett reduction produces a quotient and a remainder in the range [0, 2q),
|
||||
// such that dividend = quotient * q + remainder.
|
||||
dividend := uint32(x) << d // x * 2ᵈ
|
||||
quotient := uint32(uint64(dividend) * barrettMultiplier >> barrettShift)
|
||||
remainder := dividend - quotient*q
|
||||
|
||||
// Since the remainder is in the range [0, 2q), not [0, q), we need to
|
||||
// portion it into three spans for rounding.
|
||||
//
|
||||
// [ 0, q/2 ) -> round to 0
|
||||
// [ q/2, q + q/2 ) -> round to 1
|
||||
// [ q + q/2, 2q ) -> round to 2
|
||||
//
|
||||
// We can convert that to the following logic: add 1 if remainder > q/2,
|
||||
// then add 1 again if remainder > q + q/2.
|
||||
//
|
||||
// Note that if remainder > x, then ⌊x⌋ - remainder underflows, and the top
|
||||
// bit of the difference will be set.
|
||||
quotient += (q/2 - remainder) >> 31 & 1
|
||||
quotient += (q + q/2 - remainder) >> 31 & 1
|
||||
|
||||
// quotient might have overflowed at this point, so reduce it by masking.
|
||||
var mask uint32 = (1 << d) - 1
|
||||
return uint16(quotient & mask)
|
||||
}
|
||||
|
||||
// decompress maps a number x between 0 and 2ᵈ-1 uniformly to the full range of
|
||||
// field elements, according to FIPS 203, Definition 4.8.
|
||||
func decompress(y uint16, d uint8) fieldElement {
|
||||
// We want to compute (y * q) / 2ᵈ, rounded to nearest integer, with 1/2
|
||||
// rounding up (see FIPS 203, Section 2.3).
|
||||
|
||||
dividend := uint32(y) * q
|
||||
quotient := dividend >> d // (y * q) / 2ᵈ
|
||||
|
||||
// The d'th least-significant bit of the dividend (the most significant bit
|
||||
// of the remainder) is 1 for the top half of the values that divide to the
|
||||
// same quotient, which are the ones that round up.
|
||||
quotient += dividend >> (d - 1) & 1
|
||||
|
||||
// quotient is at most (2¹¹-1) * q / 2¹¹ + 1 = 3328, so it didn't overflow.
|
||||
return fieldElement(quotient)
|
||||
}
|
||||
|
||||
// ringElement is a polynomial, an element of R_q, represented as an array
|
||||
// according to FIPS 203, Section 2.4.4.
|
||||
type ringElement [n]fieldElement
|
||||
|
||||
// polyAdd adds two ringElements or nttElements.
|
||||
func polyAdd[T ~[n]fieldElement](a, b T) (s T) {
|
||||
for i := range s {
|
||||
s[i] = fieldAdd(a[i], b[i])
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// polySub subtracts two ringElements or nttElements.
|
||||
func polySub[T ~[n]fieldElement](a, b T) (s T) {
|
||||
for i := range s {
|
||||
s[i] = fieldSub(a[i], b[i])
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// polyByteEncode appends the 384-byte encoding of f to b.
|
||||
//
|
||||
// It implements ByteEncode₁₂, according to FIPS 203, Algorithm 5.
|
||||
func polyByteEncode[T ~[n]fieldElement](b []byte, f T) []byte {
|
||||
out, B := sliceForAppend(b, encodingSize12)
|
||||
for i := 0; i < n; i += 2 {
|
||||
x := uint32(f[i]) | uint32(f[i+1])<<12
|
||||
B[0] = uint8(x)
|
||||
B[1] = uint8(x >> 8)
|
||||
B[2] = uint8(x >> 16)
|
||||
B = B[3:]
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// polyByteDecode decodes the 384-byte encoding of a polynomial, checking that
|
||||
// all the coefficients are properly reduced. This fulfills the "Modulus check"
|
||||
// step of ML-KEM Encapsulation.
|
||||
//
|
||||
// It implements ByteDecode₁₂, according to FIPS 203, Algorithm 6.
|
||||
func polyByteDecode[T ~[n]fieldElement](b []byte) (T, error) {
|
||||
if len(b) != encodingSize12 {
|
||||
return T{}, errors.New("mlkem: invalid encoding length")
|
||||
}
|
||||
var f T
|
||||
for i := 0; i < n; i += 2 {
|
||||
d := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16
|
||||
const mask12 = 0b1111_1111_1111
|
||||
var err error
|
||||
if f[i], err = fieldCheckReduced(uint16(d & mask12)); err != nil {
|
||||
return T{}, errors.New("mlkem: invalid polynomial encoding")
|
||||
}
|
||||
if f[i+1], err = fieldCheckReduced(uint16(d >> 12)); err != nil {
|
||||
return T{}, errors.New("mlkem: invalid polynomial encoding")
|
||||
}
|
||||
b = b[3:]
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// 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(in []byte, n int) (head, tail []byte) {
|
||||
if total := len(in) + n; cap(in) >= total {
|
||||
head = in[:total]
|
||||
} else {
|
||||
head = make([]byte, total)
|
||||
copy(head, in)
|
||||
}
|
||||
tail = head[len(in):]
|
||||
return
|
||||
}
|
||||
|
||||
// ringCompressAndEncode1 appends a 32-byte encoding of a ring element to s,
|
||||
// compressing one coefficients per bit.
|
||||
//
|
||||
// It implements Compress₁, according to FIPS 203, Definition 4.7,
|
||||
// followed by ByteEncode₁, according to FIPS 203, Algorithm 5.
|
||||
func ringCompressAndEncode1(s []byte, f ringElement) []byte {
|
||||
s, b := sliceForAppend(s, encodingSize1)
|
||||
for i := range b {
|
||||
b[i] = 0
|
||||
}
|
||||
for i := range f {
|
||||
b[i/8] |= uint8(compress(f[i], 1) << (i % 8))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ringDecodeAndDecompress1 decodes a 32-byte slice to a ring element where each
|
||||
// bit is mapped to 0 or ⌈q/2⌋.
|
||||
//
|
||||
// It implements ByteDecode₁, according to FIPS 203, Algorithm 6,
|
||||
// followed by Decompress₁, according to FIPS 203, Definition 4.8.
|
||||
func ringDecodeAndDecompress1(b *[encodingSize1]byte) ringElement {
|
||||
var f ringElement
|
||||
for i := range f {
|
||||
b_i := b[i/8] >> (i % 8) & 1
|
||||
const halfQ = (q + 1) / 2 // ⌈q/2⌋, rounded up per FIPS 203, Section 2.3
|
||||
f[i] = fieldElement(b_i) * halfQ // 0 decompresses to 0, and 1 to ⌈q/2⌋
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// ringCompressAndEncode4 appends a 128-byte encoding of a ring element to s,
|
||||
// compressing two coefficients per byte.
|
||||
//
|
||||
// It implements Compress₄, according to FIPS 203, Definition 4.7,
|
||||
// followed by ByteEncode₄, according to FIPS 203, Algorithm 5.
|
||||
func ringCompressAndEncode4(s []byte, f ringElement) []byte {
|
||||
s, b := sliceForAppend(s, encodingSize4)
|
||||
for i := 0; i < n; i += 2 {
|
||||
b[i/2] = uint8(compress(f[i], 4) | compress(f[i+1], 4)<<4)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ringDecodeAndDecompress4 decodes a 128-byte encoding of a ring element where
|
||||
// each four bits are mapped to an equidistant distribution.
|
||||
//
|
||||
// It implements ByteDecode₄, according to FIPS 203, Algorithm 6,
|
||||
// followed by Decompress₄, according to FIPS 203, Definition 4.8.
|
||||
func ringDecodeAndDecompress4(b *[encodingSize4]byte) ringElement {
|
||||
var f ringElement
|
||||
for i := 0; i < n; i += 2 {
|
||||
f[i] = fieldElement(decompress(uint16(b[i/2]&0b1111), 4))
|
||||
f[i+1] = fieldElement(decompress(uint16(b[i/2]>>4), 4))
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// ringCompressAndEncode10 appends a 320-byte encoding of a ring element to s,
|
||||
// compressing four coefficients per five bytes.
|
||||
//
|
||||
// It implements Compress₁₀, according to FIPS 203, Definition 4.7,
|
||||
// followed by ByteEncode₁₀, according to FIPS 203, Algorithm 5.
|
||||
func ringCompressAndEncode10(s []byte, f ringElement) []byte {
|
||||
s, b := sliceForAppend(s, encodingSize10)
|
||||
for i := 0; i < n; i += 4 {
|
||||
var x uint64
|
||||
x |= uint64(compress(f[i], 10))
|
||||
x |= uint64(compress(f[i+1], 10)) << 10
|
||||
x |= uint64(compress(f[i+2], 10)) << 20
|
||||
x |= uint64(compress(f[i+3], 10)) << 30
|
||||
b[0] = uint8(x)
|
||||
b[1] = uint8(x >> 8)
|
||||
b[2] = uint8(x >> 16)
|
||||
b[3] = uint8(x >> 24)
|
||||
b[4] = uint8(x >> 32)
|
||||
b = b[5:]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ringDecodeAndDecompress10 decodes a 320-byte encoding of a ring element where
|
||||
// each ten bits are mapped to an equidistant distribution.
|
||||
//
|
||||
// It implements ByteDecode₁₀, according to FIPS 203, Algorithm 6,
|
||||
// followed by Decompress₁₀, according to FIPS 203, Definition 4.8.
|
||||
func ringDecodeAndDecompress10(bb *[encodingSize10]byte) ringElement {
|
||||
b := bb[:]
|
||||
var f ringElement
|
||||
for i := 0; i < n; i += 4 {
|
||||
x := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32
|
||||
b = b[5:]
|
||||
f[i] = fieldElement(decompress(uint16(x>>0&0b11_1111_1111), 10))
|
||||
f[i+1] = fieldElement(decompress(uint16(x>>10&0b11_1111_1111), 10))
|
||||
f[i+2] = fieldElement(decompress(uint16(x>>20&0b11_1111_1111), 10))
|
||||
f[i+3] = fieldElement(decompress(uint16(x>>30&0b11_1111_1111), 10))
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// ringCompressAndEncode appends an encoding of a ring element to s,
|
||||
// compressing each coefficient to d bits.
|
||||
//
|
||||
// It implements Compress, according to FIPS 203, Definition 4.7,
|
||||
// followed by ByteEncode, according to FIPS 203, Algorithm 5.
|
||||
func ringCompressAndEncode(s []byte, f ringElement, d uint8) []byte {
|
||||
var b byte
|
||||
var bIdx uint8
|
||||
for i := range n {
|
||||
c := compress(f[i], d)
|
||||
var cIdx uint8
|
||||
for cIdx < d {
|
||||
b |= byte(c>>cIdx) << bIdx
|
||||
bits := min(8-bIdx, d-cIdx)
|
||||
bIdx += bits
|
||||
cIdx += bits
|
||||
if bIdx == 8 {
|
||||
s = append(s, b)
|
||||
b = 0
|
||||
bIdx = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
if bIdx != 0 {
|
||||
panic("mlkem: internal error: bitsFilled != 0")
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ringDecodeAndDecompress decodes an encoding of a ring element where
|
||||
// each d bits are mapped to an equidistant distribution.
|
||||
//
|
||||
// It implements ByteDecode, according to FIPS 203, Algorithm 6,
|
||||
// followed by Decompress, according to FIPS 203, Definition 4.8.
|
||||
func ringDecodeAndDecompress(b []byte, d uint8) ringElement {
|
||||
var f ringElement
|
||||
var bIdx uint8
|
||||
for i := 0; i < n; i++ {
|
||||
var c uint16
|
||||
var cIdx uint8
|
||||
for cIdx < d {
|
||||
c |= uint16(b[0]>>bIdx) << cIdx
|
||||
c &= (1 << d) - 1
|
||||
bits := min(8-bIdx, d-cIdx)
|
||||
bIdx += bits
|
||||
cIdx += bits
|
||||
if bIdx == 8 {
|
||||
b = b[1:]
|
||||
bIdx = 0
|
||||
}
|
||||
}
|
||||
f[i] = fieldElement(decompress(c, d))
|
||||
}
|
||||
if len(b) != 0 {
|
||||
panic("mlkem: internal error: leftover bytes")
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// ringCompressAndEncode5 appends a 160-byte encoding of a ring element to s,
|
||||
// compressing eight coefficients per five bytes.
|
||||
//
|
||||
// It implements Compress₅, according to FIPS 203, Definition 4.7,
|
||||
// followed by ByteEncode₅, according to FIPS 203, Algorithm 5.
|
||||
func ringCompressAndEncode5(s []byte, f ringElement) []byte {
|
||||
return ringCompressAndEncode(s, f, 5)
|
||||
}
|
||||
|
||||
// ringDecodeAndDecompress5 decodes a 160-byte encoding of a ring element where
|
||||
// each five bits are mapped to an equidistant distribution.
|
||||
//
|
||||
// It implements ByteDecode₅, according to FIPS 203, Algorithm 6,
|
||||
// followed by Decompress₅, according to FIPS 203, Definition 4.8.
|
||||
func ringDecodeAndDecompress5(bb *[encodingSize5]byte) ringElement {
|
||||
return ringDecodeAndDecompress(bb[:], 5)
|
||||
}
|
||||
|
||||
// ringCompressAndEncode11 appends a 352-byte encoding of a ring element to s,
|
||||
// compressing eight coefficients per eleven bytes.
|
||||
//
|
||||
// It implements Compress₁₁, according to FIPS 203, Definition 4.7,
|
||||
// followed by ByteEncode₁₁, according to FIPS 203, Algorithm 5.
|
||||
func ringCompressAndEncode11(s []byte, f ringElement) []byte {
|
||||
return ringCompressAndEncode(s, f, 11)
|
||||
}
|
||||
|
||||
// ringDecodeAndDecompress11 decodes a 352-byte encoding of a ring element where
|
||||
// each eleven bits are mapped to an equidistant distribution.
|
||||
//
|
||||
// It implements ByteDecode₁₁, according to FIPS 203, Algorithm 6,
|
||||
// followed by Decompress₁₁, according to FIPS 203, Definition 4.8.
|
||||
func ringDecodeAndDecompress11(bb *[encodingSize11]byte) ringElement {
|
||||
return ringDecodeAndDecompress(bb[:], 11)
|
||||
}
|
||||
|
||||
// samplePolyCBD draws a ringElement from the special Dη distribution given a
|
||||
// stream of random bytes generated by the PRF function, according to FIPS 203,
|
||||
// Algorithm 8 and Definition 4.3.
|
||||
func samplePolyCBD(s []byte, b, η byte) ringElement {
|
||||
prf := sha3.NewSHAKE256()
|
||||
prf.Write(s)
|
||||
prf.Write([]byte{b})
|
||||
var B [maxBytesOf64Mulη]byte
|
||||
prf.Read(B[:64*η])
|
||||
|
||||
// SamplePolyCBD simply draws four (2η) bits for each coefficient, and adds
|
||||
// the first two and subtracts the last two.
|
||||
|
||||
var f ringElement
|
||||
switch η {
|
||||
case 2:
|
||||
for i := 0; i < n; i += 2 {
|
||||
b := B[i/2]
|
||||
b_7, b_6, b_5, b_4 := b>>7, b>>6&1, b>>5&1, b>>4&1
|
||||
b_3, b_2, b_1, b_0 := b>>3&1, b>>2&1, b>>1&1, b&1
|
||||
f[i] = fieldSub(fieldElement(b_0+b_1), fieldElement(b_2+b_3))
|
||||
f[i+1] = fieldSub(fieldElement(b_4+b_5), fieldElement(b_6+b_7))
|
||||
}
|
||||
case 3:
|
||||
for i := 0; i < n; i += 4 {
|
||||
j := (i >> 2) * 3
|
||||
|
||||
bits := uint32(B[j]) | uint32(B[j+1])<<8 | uint32(B[j+2])<<16
|
||||
for k := range 4 {
|
||||
off := 6 * k
|
||||
sum := ((bits >> off) & 1) + ((bits >> (off + 1)) & 1) + ((bits >> (off + 2)) & 1)
|
||||
sub := ((bits >> (off + 3)) & 1) + ((bits >> (off + 4)) & 1) + ((bits >> (off + 5)) & 1)
|
||||
f[i+k] = fieldSub(fieldElement(sum), fieldElement(sub))
|
||||
}
|
||||
}
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// nttElement is an NTT representation, an element of T_q, represented as an
|
||||
// array according to FIPS 203, Section 2.4.4.
|
||||
type nttElement [n]fieldElement
|
||||
|
||||
// gammas are the values ζ^2BitRev7(i)+1 mod q for each index i, according to
|
||||
// FIPS 203, Appendix A (with negative values reduced to positive).
|
||||
var gammas = [128]fieldElement{17, 3312, 2761, 568, 583, 2746, 2649, 680, 1637, 1692, 723, 2606, 2288, 1041, 1100, 2229, 1409, 1920, 2662, 667, 3281, 48, 233, 3096, 756, 2573, 2156, 1173, 3015, 314, 3050, 279, 1703, 1626, 1651, 1678, 2789, 540, 1789, 1540, 1847, 1482, 952, 2377, 1461, 1868, 2687, 642, 939, 2390, 2308, 1021, 2437, 892, 2388, 941, 733, 2596, 2337, 992, 268, 3061, 641, 2688, 1584, 1745, 2298, 1031, 2037, 1292, 3220, 109, 375, 2954, 2549, 780, 2090, 1239, 1645, 1684, 1063, 2266, 319, 3010, 2773, 556, 757, 2572, 2099, 1230, 561, 2768, 2466, 863, 2594, 735, 2804, 525, 1092, 2237, 403, 2926, 1026, 2303, 1143, 2186, 2150, 1179, 2775, 554, 886, 2443, 1722, 1607, 1212, 2117, 1874, 1455, 1029, 2300, 2110, 1219, 2935, 394, 885, 2444, 2154, 1175}
|
||||
|
||||
// nttMul multiplies two nttElements.
|
||||
//
|
||||
// It implements MultiplyNTTs, according to FIPS 203, Algorithm 11.
|
||||
func nttMul(f, g nttElement) nttElement {
|
||||
var h nttElement
|
||||
// We use i += 2 for bounds check elimination. See https://go.dev/issue/66826.
|
||||
for i := 0; i < 256; i += 2 {
|
||||
a0, a1 := f[i], f[i+1]
|
||||
b0, b1 := g[i], g[i+1]
|
||||
h[i] = fieldAddMul(a0, b0, fieldMul(a1, b1), gammas[i/2])
|
||||
h[i+1] = fieldAddMul(a0, b1, a1, b0)
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// zetas are the values ζ^BitRev7(k) mod q for each index k, according to FIPS
|
||||
// 203, Appendix A.
|
||||
var zetas = [128]fieldElement{1, 1729, 2580, 3289, 2642, 630, 1897, 848, 1062, 1919, 193, 797, 2786, 3260, 569, 1746, 296, 2447, 1339, 1476, 3046, 56, 2240, 1333, 1426, 2094, 535, 2882, 2393, 2879, 1974, 821, 289, 331, 3253, 1756, 1197, 2304, 2277, 2055, 650, 1977, 2513, 632, 2865, 33, 1320, 1915, 2319, 1435, 807, 452, 1438, 2868, 1534, 2402, 2647, 2617, 1481, 648, 2474, 3110, 1227, 910, 17, 2761, 583, 2649, 1637, 723, 2288, 1100, 1409, 2662, 3281, 233, 756, 2156, 3015, 3050, 1703, 1651, 2789, 1789, 1847, 952, 1461, 2687, 939, 2308, 2437, 2388, 733, 2337, 268, 641, 1584, 2298, 2037, 3220, 375, 2549, 2090, 1645, 1063, 319, 2773, 757, 2099, 561, 2466, 2594, 2804, 1092, 403, 1026, 1143, 2150, 2775, 886, 1722, 1212, 1874, 1029, 2110, 2935, 885, 2154}
|
||||
|
||||
// ntt maps a ringElement to its nttElement representation.
|
||||
//
|
||||
// It implements NTT, according to FIPS 203, Algorithm 9.
|
||||
func ntt(f ringElement) nttElement {
|
||||
k := 1
|
||||
for len := 128; len >= 2; len /= 2 {
|
||||
for start := 0; start < 256; start += 2 * len {
|
||||
zeta := zetas[k]
|
||||
k++
|
||||
// Bounds check elimination hint.
|
||||
f, flen := f[start:start+len], f[start+len:start+len+len]
|
||||
for j := 0; j < len; j++ {
|
||||
t := fieldMul(zeta, flen[j])
|
||||
flen[j] = fieldSub(f[j], t)
|
||||
f[j] = fieldAdd(f[j], t)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nttElement(f)
|
||||
}
|
||||
|
||||
// inverseNTT maps a nttElement back to the ringElement it represents.
|
||||
//
|
||||
// It implements NTT⁻¹, according to FIPS 203, Algorithm 10.
|
||||
func inverseNTT(f nttElement) ringElement {
|
||||
k := 127
|
||||
for len := 2; len <= 128; len *= 2 {
|
||||
for start := 0; start < 256; start += 2 * len {
|
||||
zeta := zetas[k]
|
||||
k--
|
||||
// Bounds check elimination hint.
|
||||
f, flen := f[start:start+len], f[start+len:start+len+len]
|
||||
for j := 0; j < len; j++ {
|
||||
t := f[j]
|
||||
f[j] = fieldAdd(t, flen[j])
|
||||
flen[j] = fieldMulSub(zeta, flen[j], t)
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := range f {
|
||||
f[i] = fieldMul(f[i], 3303) // 3303 = 128⁻¹ mod q
|
||||
}
|
||||
return ringElement(f)
|
||||
}
|
||||
|
||||
// sampleNTT draws a uniformly random nttElement from a stream of uniformly
|
||||
// random bytes generated by the XOF function, according to FIPS 203,
|
||||
// Algorithm 7.
|
||||
func sampleNTT(rho []byte, ii, jj byte) nttElement {
|
||||
B := sha3.NewSHAKE128()
|
||||
B.Write(rho)
|
||||
B.Write([]byte{ii, jj})
|
||||
|
||||
// SampleNTT essentially draws 12 bits at a time from r, interprets them in
|
||||
// little-endian, and rejects values higher than q, until it drew 256
|
||||
// values. (The rejection rate is approximately 19%.)
|
||||
//
|
||||
// To do this from a bytes stream, it draws three bytes at a time, and
|
||||
// splits them into two uint16 appropriately masked.
|
||||
//
|
||||
// r₀ r₁ r₂
|
||||
// |- - - - - - - -|- - - - - - - -|- - - - - - - -|
|
||||
//
|
||||
// Uint16(r₀ || r₁)
|
||||
// |- - - - - - - - - - - - - - - -|
|
||||
// |- - - - - - - - - - - -|
|
||||
// d₁
|
||||
//
|
||||
// Uint16(r₁ || r₂)
|
||||
// |- - - - - - - - - - - - - - - -|
|
||||
// |- - - - - - - - - - - -|
|
||||
// d₂
|
||||
//
|
||||
// Note that in little-endian, the rightmost bits are the most significant
|
||||
// bits (dropped with a mask) and the leftmost bits are the least
|
||||
// significant bits (dropped with a right shift).
|
||||
|
||||
var a nttElement
|
||||
var j int // index into a
|
||||
var buf [24]byte // buffered reads from B
|
||||
off := len(buf) // index into buf, starts in a "buffer fully consumed" state
|
||||
for {
|
||||
if off >= len(buf) {
|
||||
B.Read(buf[:])
|
||||
off = 0
|
||||
}
|
||||
d1 := byteorder.LEUint16(buf[off:]) & 0b1111_1111_1111
|
||||
d2 := byteorder.LEUint16(buf[off+1:]) >> 4
|
||||
off += 3
|
||||
if d1 < q {
|
||||
a[j] = fieldElement(d1)
|
||||
j++
|
||||
}
|
||||
if j >= len(a) {
|
||||
break
|
||||
}
|
||||
if d2 < q {
|
||||
a[j] = fieldElement(d2)
|
||||
j++
|
||||
}
|
||||
if j >= len(a) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
271
mlkem/field_test.go
Normal file
271
mlkem/field_test.go
Normal file
@ -0,0 +1,271 @@
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
177
mlkem/generate.go
Normal file
177
mlkem/generate.go
Normal file
@ -0,0 +1,177 @@
|
||||
// Copyright 2024 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 ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"go/ast"
|
||||
"go/format"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var replacements512 = map[string]string{
|
||||
"k": "k512",
|
||||
"η1": "η1_512",
|
||||
"η2": "η2_512",
|
||||
|
||||
"CiphertextSize768": "CiphertextSize512",
|
||||
"EncapsulationKeySize768": "EncapsulationKeySize512",
|
||||
"DecapsulationKeySize768": "DecapsulationKeySize512",
|
||||
|
||||
"encryptionKey": "encryptionKey512",
|
||||
"decryptionKey": "decryptionKey512",
|
||||
|
||||
"EncapsulationKey768": "EncapsulationKey512",
|
||||
"NewEncapsulationKey768": "NewEncapsulationKey512",
|
||||
"parseEK": "parseEK512",
|
||||
|
||||
"kemEncaps": "kemEncaps512",
|
||||
"pkeEncrypt": "pkeEncrypt512",
|
||||
|
||||
"DecapsulationKey768": "DecapsulationKey512",
|
||||
"NewDecapsulationKey768": "NewDecapsulationKey512",
|
||||
"NewDecapsulationKeyFromSeed768": "NewDecapsulationKeyFromSeed512",
|
||||
"newKeyFromSeed": "newKeyFromSeed512",
|
||||
|
||||
"kemDecaps": "kemDecaps512",
|
||||
"pkeDecrypt": "pkeDecrypt512",
|
||||
|
||||
"GenerateKey768": "GenerateKey512",
|
||||
"GenerateKeyInternal768": "GenerateKeyInternal512",
|
||||
"generateKey": "generateKey512",
|
||||
|
||||
"kemKeyGen": "kemKeyGen512",
|
||||
}
|
||||
|
||||
var replacements1024 = map[string]string{
|
||||
"k": "k1024",
|
||||
"η1": "η1_1024",
|
||||
"η2": "η2_1024",
|
||||
|
||||
"CiphertextSize768": "CiphertextSize1024",
|
||||
"EncapsulationKeySize768": "EncapsulationKeySize1024",
|
||||
"DecapsulationKeySize768": "DecapsulationKeySize1024",
|
||||
|
||||
"encryptionKey": "encryptionKey1024",
|
||||
"decryptionKey": "decryptionKey1024",
|
||||
|
||||
"EncapsulationKey768": "EncapsulationKey1024",
|
||||
"NewEncapsulationKey768": "NewEncapsulationKey1024",
|
||||
"parseEK": "parseEK1024",
|
||||
|
||||
"kemEncaps": "kemEncaps1024",
|
||||
"pkeEncrypt": "pkeEncrypt1024",
|
||||
|
||||
"DecapsulationKey768": "DecapsulationKey1024",
|
||||
"NewDecapsulationKey768": "NewDecapsulationKey1024",
|
||||
"NewDecapsulationKeyFromSeed768": "NewDecapsulationKeyFromSeed1024",
|
||||
"newKeyFromSeed": "newKeyFromSeed1024",
|
||||
|
||||
"kemDecaps": "kemDecaps1024",
|
||||
"pkeDecrypt": "pkeDecrypt1024",
|
||||
|
||||
"GenerateKey768": "GenerateKey1024",
|
||||
"GenerateKeyInternal768": "GenerateKeyInternal1024",
|
||||
"generateKey": "generateKey1024",
|
||||
|
||||
"kemKeyGen": "kemKeyGen1024",
|
||||
"kemPCT": "kemPCT1024",
|
||||
|
||||
"encodingSize4": "encodingSize5",
|
||||
"encodingSize10": "encodingSize11",
|
||||
"ringCompressAndEncode4": "ringCompressAndEncode5",
|
||||
"ringCompressAndEncode10": "ringCompressAndEncode11",
|
||||
"ringDecodeAndDecompress4": "ringDecodeAndDecompress5",
|
||||
"ringDecodeAndDecompress10": "ringDecodeAndDecompress11",
|
||||
}
|
||||
|
||||
func replaceIdentifiers(inputFile, outputFile *string, replacements map[string]string) {
|
||||
fset := token.NewFileSet()
|
||||
f, err := parser.ParseFile(fset, *inputFile, nil, parser.SkipObjectResolution|parser.ParseComments)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
cmap := ast.NewCommentMap(fset, f, f.Comments)
|
||||
|
||||
// Drop header comments.
|
||||
cmap[ast.Node(f)] = nil
|
||||
|
||||
// Remove top-level consts used across the main and generated files.
|
||||
var newDecls []ast.Decl
|
||||
for _, decl := range f.Decls {
|
||||
switch d := decl.(type) {
|
||||
case *ast.GenDecl:
|
||||
if d.Tok == token.CONST {
|
||||
continue // Skip const declarations
|
||||
}
|
||||
if d.Tok == token.IMPORT {
|
||||
cmap[decl] = nil // Drop pre-import comments.
|
||||
}
|
||||
}
|
||||
newDecls = append(newDecls, decl)
|
||||
}
|
||||
f.Decls = newDecls
|
||||
|
||||
// Replace identifiers.
|
||||
ast.Inspect(f, func(n ast.Node) bool {
|
||||
switch x := n.(type) {
|
||||
case *ast.Ident:
|
||||
if replacement, ok := replacements[x.Name]; ok {
|
||||
x.Name = replacement
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
// Replace identifiers in comments.
|
||||
for _, c := range f.Comments {
|
||||
for _, l := range c.List {
|
||||
for k, v := range replacements {
|
||||
if k == "k" || k == "l" {
|
||||
continue
|
||||
}
|
||||
l.Text = strings.ReplaceAll(l.Text, k, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out, err := os.Create(*outputFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
out.WriteString(`// Copyright 2025 Sun Yimin. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// Code generated by generate.go. DO NOT EDIT.
|
||||
|
||||
//go:build go1.24
|
||||
|
||||
`)
|
||||
|
||||
f.Comments = cmap.Filter(f).Comments()
|
||||
err = format.Node(out, fset, f)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func main() {
|
||||
inputFile := flag.String("mlkem768", "", "")
|
||||
outputFile512 := flag.String("mlkem512", "", "")
|
||||
outputFile1024 := flag.String("mlkem1024", "", "")
|
||||
flag.Parse()
|
||||
|
||||
replaceIdentifiers(inputFile, outputFile512, replacements512)
|
||||
replaceIdentifiers(inputFile, outputFile1024, replacements1024)
|
||||
}
|
412
mlkem/mlkem1024.go
Normal file
412
mlkem/mlkem1024.go
Normal file
@ -0,0 +1,412 @@
|
||||
// Copyright 2025 Sun Yimin. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// Code generated by generate.go. DO NOT EDIT.
|
||||
|
||||
//go:build go1.24
|
||||
|
||||
package mlkem
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha3"
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
// A DecapsulationKey1024 is the secret key used to decapsulate a shared key from a
|
||||
// ciphertext. It includes various precomputed values.
|
||||
type DecapsulationKey1024 struct {
|
||||
d [32]byte // decapsulation key seed
|
||||
z [32]byte // implicit rejection sampling seed
|
||||
|
||||
ρ [32]byte // rho, sampleNTT seed for A, stored for the encapsulation key
|
||||
h [32]byte // H(ek), stored for ML-KEM.Decaps_internal
|
||||
|
||||
encryptionKey1024
|
||||
decryptionKey1024
|
||||
}
|
||||
|
||||
// Seed returns the decapsulation key as a 64-byte seed in the "d || z" form.
|
||||
//
|
||||
// The decapsulation key must be kept secret.
|
||||
func (dk *DecapsulationKey1024) Seed() []byte {
|
||||
var b [SeedSize]byte
|
||||
copy(b[:], dk.d[:])
|
||||
copy(b[32:], dk.z[:])
|
||||
return b[:]
|
||||
}
|
||||
|
||||
// Bytes returns the decapsulation key as a byte slice
|
||||
// using the full expanded NIST encoding.
|
||||
func (dk *DecapsulationKey1024) Bytes() []byte {
|
||||
b := make([]byte, 0, DecapsulationKeySize1024)
|
||||
|
||||
// ByteEncode₁₂(s)
|
||||
for i := range dk.s {
|
||||
b = polyByteEncode(b, dk.s[i])
|
||||
}
|
||||
|
||||
// ByteEncode₁₂(t) || ρ
|
||||
for i := range dk.t {
|
||||
b = polyByteEncode(b, dk.t[i])
|
||||
}
|
||||
b = append(b, dk.ρ[:]...)
|
||||
|
||||
// H(ek) || z
|
||||
b = append(b, dk.h[:]...)
|
||||
b = append(b, dk.z[:]...)
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// EncapsulationKey returns the public encapsulation key necessary to produce
|
||||
// ciphertexts.
|
||||
func (dk *DecapsulationKey1024) EncapsulationKey() *EncapsulationKey1024 {
|
||||
return &EncapsulationKey1024{
|
||||
ρ: dk.ρ,
|
||||
h: dk.h,
|
||||
encryptionKey1024: dk.encryptionKey1024,
|
||||
}
|
||||
}
|
||||
|
||||
// An EncapsulationKey1024 is the public key used to produce ciphertexts to be
|
||||
// decapsulated by the corresponding [DecapsulationKey1024].
|
||||
type EncapsulationKey1024 struct {
|
||||
ρ [32]byte // sampleNTT seed for A
|
||||
h [32]byte // H(ek)
|
||||
encryptionKey1024
|
||||
}
|
||||
|
||||
// Bytes returns the encapsulation key as a byte slice.
|
||||
func (ek *EncapsulationKey1024) Bytes() []byte {
|
||||
// The actual logic is in a separate function to outline this allocation.
|
||||
b := make([]byte, 0, EncapsulationKeySize1024)
|
||||
return ek.bytes(b)
|
||||
}
|
||||
|
||||
func (ek *EncapsulationKey1024) bytes(b []byte) []byte {
|
||||
for i := range ek.t {
|
||||
b = polyByteEncode(b, ek.t[i])
|
||||
}
|
||||
b = append(b, ek.ρ[:]...)
|
||||
return b
|
||||
}
|
||||
|
||||
// encryptionKey1024 is the parsed and expanded form of a PKE encryption key.
|
||||
type encryptionKey1024 struct {
|
||||
t [k1024]nttElement // ByteDecode₁₂(ek[:384k])
|
||||
a [k1024 * k1024]nttElement // A[i*k+j] = sampleNTT(ρ, j, i)
|
||||
}
|
||||
|
||||
// decryptionKey1024 is the parsed and expanded form of a PKE decryption key.
|
||||
type decryptionKey1024 struct {
|
||||
s [k1024]nttElement // ByteDecode₁₂(dk[:decryptionKey1024Size])
|
||||
}
|
||||
|
||||
// GenerateKey1024 generates a new decapsulation key. The decapsulation key must be kept secret.
|
||||
// See FIPS 203, Algorithm 19.
|
||||
func GenerateKey1024(rand io.Reader) (*DecapsulationKey1024, error) {
|
||||
// The actual logic is in a separate function to outline this allocation.
|
||||
dk := &DecapsulationKey1024{}
|
||||
return generateKey1024(dk, rand)
|
||||
}
|
||||
|
||||
func generateKey1024(dk *DecapsulationKey1024, rand io.Reader) (*DecapsulationKey1024, error) {
|
||||
var d [32]byte
|
||||
if _, err := io.ReadFull(rand, d[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var z [32]byte
|
||||
if _, err := io.ReadFull(rand, z[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kemKeyGen1024(dk, &d, &z)
|
||||
return dk, nil
|
||||
}
|
||||
|
||||
// NewDecapsulationKeyFromSeed1024 parses a decapsulation key from a 64-byte
|
||||
// seed in the "d || z" form. The seed must be uniformly random.
|
||||
func NewDecapsulationKeyFromSeed1024(seed []byte) (*DecapsulationKey1024, error) {
|
||||
// The actual logic is in a separate function to outline this allocation.
|
||||
dk := &DecapsulationKey1024{}
|
||||
return newKeyFromSeed1024(dk, seed)
|
||||
}
|
||||
|
||||
func newKeyFromSeed1024(dk *DecapsulationKey1024, seed []byte) (*DecapsulationKey1024, error) {
|
||||
if len(seed) != SeedSize {
|
||||
return nil, errors.New("mlkem: invalid seed length")
|
||||
}
|
||||
d := (*[32]byte)(seed[:32])
|
||||
z := (*[32]byte)(seed[32:])
|
||||
kemKeyGen1024(dk, d, z)
|
||||
|
||||
return dk, nil
|
||||
}
|
||||
|
||||
// NewDecapsulationKey1024 parses a decapsulation key from its expanded NIST format.
|
||||
func NewDecapsulationKey1024(b []byte) (*DecapsulationKey1024, error) {
|
||||
if len(b) != DecapsulationKeySize1024 {
|
||||
return nil, errors.New("mlkem: invalid decapsulation key length")
|
||||
}
|
||||
|
||||
dk := &DecapsulationKey1024{}
|
||||
for i := range dk.s {
|
||||
var err error
|
||||
dk.s[i], err = polyByteDecode[nttElement](b[:encodingSize12])
|
||||
if err != nil {
|
||||
return nil, errors.New("mlkem: invalid secret key encoding")
|
||||
}
|
||||
b = b[encodingSize12:]
|
||||
}
|
||||
|
||||
ek, err := NewEncapsulationKey1024(b[:EncapsulationKeySize1024])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dk.ρ = ek.ρ
|
||||
dk.h = ek.h
|
||||
dk.encryptionKey1024 = ek.encryptionKey1024
|
||||
b = b[EncapsulationKeySize1024:]
|
||||
|
||||
if !bytes.Equal(dk.h[:], b[:32]) {
|
||||
return nil, errors.New("mlkem: inconsistent H(ek) in encoded bytes")
|
||||
}
|
||||
|
||||
copy(dk.z[:], b[32:])
|
||||
|
||||
return dk, nil
|
||||
}
|
||||
|
||||
// kemKeyGen1024 generates a decapsulation key.
|
||||
//
|
||||
// It implements ML-KEM.KeyGen_internal according to FIPS 203, Algorithm 16, and
|
||||
// K-PKE.KeyGen according to FIPS 203, Algorithm 13. The two are merged to save
|
||||
// copies and allocations.
|
||||
func kemKeyGen1024(dk *DecapsulationKey1024, d, z *[32]byte) {
|
||||
dk.d = *d
|
||||
dk.z = *z
|
||||
|
||||
g := sha3.New512()
|
||||
g.Write(d[:])
|
||||
g.Write([]byte{k1024}) // Module dimension as a domain separator.
|
||||
G := g.Sum(make([]byte, 0, 64))
|
||||
ρ, σ := G[:32], G[32:] // rho, sigma
|
||||
dk.ρ = [32]byte(ρ)
|
||||
|
||||
A := &dk.a
|
||||
for i := range byte(k1024) {
|
||||
for j := range byte(k1024) {
|
||||
A[i*k1024+j] = sampleNTT(ρ, j, i)
|
||||
}
|
||||
}
|
||||
|
||||
var N byte
|
||||
s := &dk.s
|
||||
for i := range s {
|
||||
s[i] = ntt(samplePolyCBD(σ, N, η1_1024))
|
||||
N++
|
||||
}
|
||||
e := make([]nttElement, k1024)
|
||||
for i := range e {
|
||||
e[i] = ntt(samplePolyCBD(σ, N, η1_1024))
|
||||
N++
|
||||
}
|
||||
|
||||
t := &dk.t
|
||||
for i := range t { // t = A ◦ s + e
|
||||
t[i] = e[i]
|
||||
for j := range s {
|
||||
t[i] = polyAdd(t[i], nttMul(A[i*k1024+j], s[j]))
|
||||
}
|
||||
}
|
||||
|
||||
H := sha3.New256()
|
||||
ek := dk.EncapsulationKey().Bytes()
|
||||
H.Write(ek)
|
||||
H.Sum(dk.h[:0])
|
||||
}
|
||||
|
||||
// Encapsulate generates a shared key and an associated ciphertext from an
|
||||
// encapsulation key.
|
||||
//
|
||||
// The shared key must be kept secret. See FIPS 203, Algorithm 20.
|
||||
func (ek *EncapsulationKey1024) Encapsulate(rand io.Reader) (sharedKey, ciphertext []byte, err error) {
|
||||
// The actual logic is in a separate function to outline this allocation.
|
||||
var cc [CiphertextSize1024]byte
|
||||
return ek.encapsulate(&cc, rand)
|
||||
}
|
||||
|
||||
func (ek *EncapsulationKey1024) encapsulate(cc *[CiphertextSize1024]byte, rand io.Reader) (sharedKey, ciphertext []byte, err error) {
|
||||
var m [messageSize]byte
|
||||
if _, err := io.ReadFull(rand, m[:]); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
sharedKey, ciphertext = kemEncaps1024(cc, ek, &m)
|
||||
return sharedKey, ciphertext, nil
|
||||
}
|
||||
|
||||
// EncapsulateInternal is a derandomized version of Encapsulate, exclusively for
|
||||
// use in tests.
|
||||
func (ek *EncapsulationKey1024) EncapsulateInternal(m *[32]byte) (sharedKey, ciphertext []byte) {
|
||||
cc := &[CiphertextSize1024]byte{}
|
||||
return kemEncaps1024(cc, ek, m)
|
||||
}
|
||||
|
||||
// kemEncaps1024 generates a shared key and an associated ciphertext.
|
||||
//
|
||||
// It implements ML-KEM.Encaps_internal according to FIPS 203, Algorithm 17.
|
||||
func kemEncaps1024(cc *[CiphertextSize1024]byte, ek *EncapsulationKey1024, m *[messageSize]byte) (K, c []byte) {
|
||||
g := sha3.New512()
|
||||
g.Write(m[:])
|
||||
g.Write(ek.h[:])
|
||||
G := g.Sum(nil)
|
||||
K, r := G[:SharedKeySize], G[SharedKeySize:]
|
||||
c = pkeEncrypt1024(cc, &ek.encryptionKey1024, m, r)
|
||||
return K, c
|
||||
}
|
||||
|
||||
// NewEncapsulationKey1024 parses an encapsulation key from its encoded form.
|
||||
// If the encapsulation key is not valid, NewEncapsulationKey1024 returns an error.
|
||||
func NewEncapsulationKey1024(encapsulationKey []byte) (*EncapsulationKey1024, error) {
|
||||
// The actual logic is in a separate function to outline this allocation.
|
||||
ek := &EncapsulationKey1024{}
|
||||
return parseEK1024(ek, encapsulationKey)
|
||||
}
|
||||
|
||||
// parseEK1024 parses an encryption key from its encoded form.
|
||||
//
|
||||
// It implements the initial stages of K-PKE.Encrypt according to FIPS 203,
|
||||
// Algorithm 14.
|
||||
func parseEK1024(ek *EncapsulationKey1024, ekPKE []byte) (*EncapsulationKey1024, error) {
|
||||
if len(ekPKE) != EncapsulationKeySize1024 {
|
||||
return nil, errors.New("mlkem: invalid encapsulation key length")
|
||||
}
|
||||
|
||||
h := sha3.New256()
|
||||
h.Write(ekPKE)
|
||||
h.Sum(ek.h[:0])
|
||||
|
||||
for i := range ek.t {
|
||||
var err error
|
||||
ek.t[i], err = polyByteDecode[nttElement](ekPKE[:encodingSize12])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ekPKE = ekPKE[encodingSize12:]
|
||||
}
|
||||
copy(ek.ρ[:], ekPKE)
|
||||
|
||||
for i := range byte(k1024) {
|
||||
for j := range byte(k1024) {
|
||||
ek.a[i*k1024+j] = sampleNTT(ek.ρ[:], j, i)
|
||||
}
|
||||
}
|
||||
|
||||
return ek, nil
|
||||
}
|
||||
|
||||
// pkeEncrypt1024 encrypt a plaintext message.
|
||||
//
|
||||
// It implements K-PKE.Encrypt according to FIPS 203, Algorithm 14, although the
|
||||
// computation of t and AT is done in parseEK1024.
|
||||
func pkeEncrypt1024(cc *[CiphertextSize1024]byte, ex *encryptionKey1024, m *[messageSize]byte, rnd []byte) []byte {
|
||||
var N byte
|
||||
r, e1 := make([]nttElement, k1024), make([]ringElement, k1024)
|
||||
for i := range r {
|
||||
r[i] = ntt(samplePolyCBD(rnd, N, η1_1024))
|
||||
N++
|
||||
}
|
||||
for i := range e1 {
|
||||
e1[i] = samplePolyCBD(rnd, N, η2_1024)
|
||||
N++
|
||||
}
|
||||
e2 := samplePolyCBD(rnd, N, η2_1024)
|
||||
|
||||
u := make([]ringElement, k1024) // NTT⁻¹(AT ◦ r) + e1
|
||||
for i := range u {
|
||||
u[i] = e1[i]
|
||||
for j := range r {
|
||||
// Note that i and j are inverted, as we need the transposed of A.
|
||||
u[i] = polyAdd(u[i], inverseNTT(nttMul(ex.a[j*k1024+i], r[j])))
|
||||
}
|
||||
}
|
||||
|
||||
μ := ringDecodeAndDecompress1(m)
|
||||
|
||||
var vNTT nttElement // t⊺ ◦ r
|
||||
for i := range ex.t {
|
||||
vNTT = polyAdd(vNTT, nttMul(ex.t[i], r[i]))
|
||||
}
|
||||
v := polyAdd(polyAdd(inverseNTT(vNTT), e2), μ)
|
||||
|
||||
c := cc[:0]
|
||||
for _, f := range u {
|
||||
c = ringCompressAndEncode11(c, f)
|
||||
}
|
||||
c = ringCompressAndEncode5(c, v)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// Decapsulate generates a shared key from a ciphertext and a decapsulation key.
|
||||
// If the ciphertext is not valid, Decapsulate returns an error.
|
||||
//
|
||||
// The shared key must be kept secret.
|
||||
func (dk *DecapsulationKey1024) Decapsulate(ciphertext []byte) (sharedKey []byte, err error) {
|
||||
if len(ciphertext) != CiphertextSize1024 {
|
||||
return nil, errors.New("mlkem: invalid ciphertext length")
|
||||
}
|
||||
c := (*[CiphertextSize1024]byte)(ciphertext)
|
||||
// Note that the hash check (step 3 of the decapsulation input check from
|
||||
// FIPS 203, Section 7.3) is foregone as a DecapsulationKey is always
|
||||
// validly generated by ML-KEM.KeyGen_internal.
|
||||
return kemDecaps1024(dk, c), nil
|
||||
}
|
||||
|
||||
// kemDecaps1024 produces a shared key from a ciphertext.
|
||||
//
|
||||
// It implements ML-KEM.Decaps_internal according to FIPS 203, Algorithm 18.
|
||||
func kemDecaps1024(dk *DecapsulationKey1024, c *[CiphertextSize1024]byte) (K []byte) {
|
||||
m := pkeDecrypt1024(&dk.decryptionKey1024, c)
|
||||
g := sha3.New512()
|
||||
g.Write(m[:])
|
||||
g.Write(dk.h[:])
|
||||
G := g.Sum(make([]byte, 0, 64))
|
||||
Kprime, r := G[:SharedKeySize], G[SharedKeySize:]
|
||||
J := sha3.NewSHAKE256()
|
||||
J.Write(dk.z[:])
|
||||
J.Write(c[:])
|
||||
Kout := make([]byte, SharedKeySize)
|
||||
J.Read(Kout)
|
||||
var cc [CiphertextSize1024]byte
|
||||
c1 := pkeEncrypt1024(&cc, &dk.encryptionKey1024, (*[32]byte)(m), r)
|
||||
|
||||
subtle.ConstantTimeCopy(subtle.ConstantTimeCompare(c[:], c1), Kout, Kprime)
|
||||
return Kout
|
||||
}
|
||||
|
||||
// pkeDecrypt1024 decrypts a ciphertext.
|
||||
//
|
||||
// It implements K-PKE.Decrypt according to FIPS 203, Algorithm 15,
|
||||
// although s is retained from kemKeyGen1024.
|
||||
func pkeDecrypt1024(dx *decryptionKey1024, c *[CiphertextSize1024]byte) []byte {
|
||||
u := make([]ringElement, k1024)
|
||||
for i := range u {
|
||||
b := (*[encodingSize11]byte)(c[encodingSize11*i : encodingSize11*(i+1)])
|
||||
u[i] = ringDecodeAndDecompress11(b)
|
||||
}
|
||||
|
||||
b := (*[encodingSize5]byte)(c[encodingSize11*k1024:])
|
||||
v := ringDecodeAndDecompress5(b)
|
||||
|
||||
var mask nttElement // s⊺ ◦ NTT(u)
|
||||
for i := range dx.s {
|
||||
mask = polyAdd(mask, nttMul(dx.s[i], ntt(u[i])))
|
||||
}
|
||||
w := polySub(v, inverseNTT(mask))
|
||||
|
||||
return ringCompressAndEncode1(nil, w)
|
||||
}
|
336
mlkem/mlkem1024_test.go
Normal file
336
mlkem/mlkem1024_test.go
Normal file
File diff suppressed because one or more lines are too long
412
mlkem/mlkem512.go
Normal file
412
mlkem/mlkem512.go
Normal file
@ -0,0 +1,412 @@
|
||||
// Copyright 2025 Sun Yimin. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// Code generated by generate.go. DO NOT EDIT.
|
||||
|
||||
//go:build go1.24
|
||||
|
||||
package mlkem
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha3"
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
// A DecapsulationKey512 is the secret key used to decapsulate a shared key from a
|
||||
// ciphertext. It includes various precomputed values.
|
||||
type DecapsulationKey512 struct {
|
||||
d [32]byte // decapsulation key seed
|
||||
z [32]byte // implicit rejection sampling seed
|
||||
|
||||
ρ [32]byte // rho, sampleNTT seed for A, stored for the encapsulation key
|
||||
h [32]byte // H(ek), stored for ML-KEM.Decaps_internal
|
||||
|
||||
encryptionKey512
|
||||
decryptionKey512
|
||||
}
|
||||
|
||||
// Seed returns the decapsulation key as a 64-byte seed in the "d || z" form.
|
||||
//
|
||||
// The decapsulation key must be kept secret.
|
||||
func (dk *DecapsulationKey512) Seed() []byte {
|
||||
var b [SeedSize]byte
|
||||
copy(b[:], dk.d[:])
|
||||
copy(b[32:], dk.z[:])
|
||||
return b[:]
|
||||
}
|
||||
|
||||
// Bytes returns the decapsulation key as a byte slice
|
||||
// using the full expanded NIST encoding.
|
||||
func (dk *DecapsulationKey512) Bytes() []byte {
|
||||
b := make([]byte, 0, DecapsulationKeySize512)
|
||||
|
||||
// ByteEncode₁₂(s)
|
||||
for i := range dk.s {
|
||||
b = polyByteEncode(b, dk.s[i])
|
||||
}
|
||||
|
||||
// ByteEncode₁₂(t) || ρ
|
||||
for i := range dk.t {
|
||||
b = polyByteEncode(b, dk.t[i])
|
||||
}
|
||||
b = append(b, dk.ρ[:]...)
|
||||
|
||||
// H(ek) || z
|
||||
b = append(b, dk.h[:]...)
|
||||
b = append(b, dk.z[:]...)
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// EncapsulationKey returns the public encapsulation key necessary to produce
|
||||
// ciphertexts.
|
||||
func (dk *DecapsulationKey512) EncapsulationKey() *EncapsulationKey512 {
|
||||
return &EncapsulationKey512{
|
||||
ρ: dk.ρ,
|
||||
h: dk.h,
|
||||
encryptionKey512: dk.encryptionKey512,
|
||||
}
|
||||
}
|
||||
|
||||
// An EncapsulationKey512 is the public key used to produce ciphertexts to be
|
||||
// decapsulated by the corresponding [DecapsulationKey512].
|
||||
type EncapsulationKey512 struct {
|
||||
ρ [32]byte // sampleNTT seed for A
|
||||
h [32]byte // H(ek)
|
||||
encryptionKey512
|
||||
}
|
||||
|
||||
// Bytes returns the encapsulation key as a byte slice.
|
||||
func (ek *EncapsulationKey512) Bytes() []byte {
|
||||
// The actual logic is in a separate function to outline this allocation.
|
||||
b := make([]byte, 0, EncapsulationKeySize512)
|
||||
return ek.bytes(b)
|
||||
}
|
||||
|
||||
func (ek *EncapsulationKey512) bytes(b []byte) []byte {
|
||||
for i := range ek.t {
|
||||
b = polyByteEncode(b, ek.t[i])
|
||||
}
|
||||
b = append(b, ek.ρ[:]...)
|
||||
return b
|
||||
}
|
||||
|
||||
// encryptionKey512 is the parsed and expanded form of a PKE encryption key.
|
||||
type encryptionKey512 struct {
|
||||
t [k512]nttElement // ByteDecode₁₂(ek[:384k])
|
||||
a [k512 * k512]nttElement // A[i*k+j] = sampleNTT(ρ, j, i)
|
||||
}
|
||||
|
||||
// decryptionKey512 is the parsed and expanded form of a PKE decryption key.
|
||||
type decryptionKey512 struct {
|
||||
s [k512]nttElement // ByteDecode₁₂(dk[:decryptionKey512Size])
|
||||
}
|
||||
|
||||
// GenerateKey512 generates a new decapsulation key. The decapsulation key must be kept secret.
|
||||
// See FIPS 203, Algorithm 19.
|
||||
func GenerateKey512(rand io.Reader) (*DecapsulationKey512, error) {
|
||||
// The actual logic is in a separate function to outline this allocation.
|
||||
dk := &DecapsulationKey512{}
|
||||
return generateKey512(dk, rand)
|
||||
}
|
||||
|
||||
func generateKey512(dk *DecapsulationKey512, rand io.Reader) (*DecapsulationKey512, error) {
|
||||
var d [32]byte
|
||||
if _, err := io.ReadFull(rand, d[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var z [32]byte
|
||||
if _, err := io.ReadFull(rand, z[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kemKeyGen512(dk, &d, &z)
|
||||
return dk, nil
|
||||
}
|
||||
|
||||
// NewDecapsulationKeyFromSeed512 parses a decapsulation key from a 64-byte
|
||||
// seed in the "d || z" form. The seed must be uniformly random.
|
||||
func NewDecapsulationKeyFromSeed512(seed []byte) (*DecapsulationKey512, error) {
|
||||
// The actual logic is in a separate function to outline this allocation.
|
||||
dk := &DecapsulationKey512{}
|
||||
return newKeyFromSeed512(dk, seed)
|
||||
}
|
||||
|
||||
func newKeyFromSeed512(dk *DecapsulationKey512, seed []byte) (*DecapsulationKey512, error) {
|
||||
if len(seed) != SeedSize {
|
||||
return nil, errors.New("mlkem: invalid seed length")
|
||||
}
|
||||
d := (*[32]byte)(seed[:32])
|
||||
z := (*[32]byte)(seed[32:])
|
||||
kemKeyGen512(dk, d, z)
|
||||
|
||||
return dk, nil
|
||||
}
|
||||
|
||||
// NewDecapsulationKey512 parses a decapsulation key from its expanded NIST format.
|
||||
func NewDecapsulationKey512(b []byte) (*DecapsulationKey512, error) {
|
||||
if len(b) != DecapsulationKeySize512 {
|
||||
return nil, errors.New("mlkem: invalid decapsulation key length")
|
||||
}
|
||||
|
||||
dk := &DecapsulationKey512{}
|
||||
for i := range dk.s {
|
||||
var err error
|
||||
dk.s[i], err = polyByteDecode[nttElement](b[:encodingSize12])
|
||||
if err != nil {
|
||||
return nil, errors.New("mlkem: invalid secret key encoding")
|
||||
}
|
||||
b = b[encodingSize12:]
|
||||
}
|
||||
|
||||
ek, err := NewEncapsulationKey512(b[:EncapsulationKeySize512])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dk.ρ = ek.ρ
|
||||
dk.h = ek.h
|
||||
dk.encryptionKey512 = ek.encryptionKey512
|
||||
b = b[EncapsulationKeySize512:]
|
||||
|
||||
if !bytes.Equal(dk.h[:], b[:32]) {
|
||||
return nil, errors.New("mlkem: inconsistent H(ek) in encoded bytes")
|
||||
}
|
||||
|
||||
copy(dk.z[:], b[32:])
|
||||
|
||||
return dk, nil
|
||||
}
|
||||
|
||||
// kemKeyGen512 generates a decapsulation key.
|
||||
//
|
||||
// It implements ML-KEM.KeyGen_internal according to FIPS 203, Algorithm 16, and
|
||||
// K-PKE.KeyGen according to FIPS 203, Algorithm 13. The two are merged to save
|
||||
// copies and allocations.
|
||||
func kemKeyGen512(dk *DecapsulationKey512, d, z *[32]byte) {
|
||||
dk.d = *d
|
||||
dk.z = *z
|
||||
|
||||
g := sha3.New512()
|
||||
g.Write(d[:])
|
||||
g.Write([]byte{k512}) // Module dimension as a domain separator.
|
||||
G := g.Sum(make([]byte, 0, 64))
|
||||
ρ, σ := G[:32], G[32:] // rho, sigma
|
||||
dk.ρ = [32]byte(ρ)
|
||||
|
||||
A := &dk.a
|
||||
for i := range byte(k512) {
|
||||
for j := range byte(k512) {
|
||||
A[i*k512+j] = sampleNTT(ρ, j, i)
|
||||
}
|
||||
}
|
||||
|
||||
var N byte
|
||||
s := &dk.s
|
||||
for i := range s {
|
||||
s[i] = ntt(samplePolyCBD(σ, N, η1_512))
|
||||
N++
|
||||
}
|
||||
e := make([]nttElement, k512)
|
||||
for i := range e {
|
||||
e[i] = ntt(samplePolyCBD(σ, N, η1_512))
|
||||
N++
|
||||
}
|
||||
|
||||
t := &dk.t
|
||||
for i := range t { // t = A ◦ s + e
|
||||
t[i] = e[i]
|
||||
for j := range s {
|
||||
t[i] = polyAdd(t[i], nttMul(A[i*k512+j], s[j]))
|
||||
}
|
||||
}
|
||||
|
||||
H := sha3.New256()
|
||||
ek := dk.EncapsulationKey().Bytes()
|
||||
H.Write(ek)
|
||||
H.Sum(dk.h[:0])
|
||||
}
|
||||
|
||||
// Encapsulate generates a shared key and an associated ciphertext from an
|
||||
// encapsulation key.
|
||||
//
|
||||
// The shared key must be kept secret. See FIPS 203, Algorithm 20.
|
||||
func (ek *EncapsulationKey512) Encapsulate(rand io.Reader) (sharedKey, ciphertext []byte, err error) {
|
||||
// The actual logic is in a separate function to outline this allocation.
|
||||
var cc [CiphertextSize512]byte
|
||||
return ek.encapsulate(&cc, rand)
|
||||
}
|
||||
|
||||
func (ek *EncapsulationKey512) encapsulate(cc *[CiphertextSize512]byte, rand io.Reader) (sharedKey, ciphertext []byte, err error) {
|
||||
var m [messageSize]byte
|
||||
if _, err := io.ReadFull(rand, m[:]); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
sharedKey, ciphertext = kemEncaps512(cc, ek, &m)
|
||||
return sharedKey, ciphertext, nil
|
||||
}
|
||||
|
||||
// EncapsulateInternal is a derandomized version of Encapsulate, exclusively for
|
||||
// use in tests.
|
||||
func (ek *EncapsulationKey512) EncapsulateInternal(m *[32]byte) (sharedKey, ciphertext []byte) {
|
||||
cc := &[CiphertextSize512]byte{}
|
||||
return kemEncaps512(cc, ek, m)
|
||||
}
|
||||
|
||||
// kemEncaps512 generates a shared key and an associated ciphertext.
|
||||
//
|
||||
// It implements ML-KEM.Encaps_internal according to FIPS 203, Algorithm 17.
|
||||
func kemEncaps512(cc *[CiphertextSize512]byte, ek *EncapsulationKey512, m *[messageSize]byte) (K, c []byte) {
|
||||
g := sha3.New512()
|
||||
g.Write(m[:])
|
||||
g.Write(ek.h[:])
|
||||
G := g.Sum(nil)
|
||||
K, r := G[:SharedKeySize], G[SharedKeySize:]
|
||||
c = pkeEncrypt512(cc, &ek.encryptionKey512, m, r)
|
||||
return K, c
|
||||
}
|
||||
|
||||
// NewEncapsulationKey512 parses an encapsulation key from its encoded form.
|
||||
// If the encapsulation key is not valid, NewEncapsulationKey512 returns an error.
|
||||
func NewEncapsulationKey512(encapsulationKey []byte) (*EncapsulationKey512, error) {
|
||||
// The actual logic is in a separate function to outline this allocation.
|
||||
ek := &EncapsulationKey512{}
|
||||
return parseEK512(ek, encapsulationKey)
|
||||
}
|
||||
|
||||
// parseEK512 parses an encryption key from its encoded form.
|
||||
//
|
||||
// It implements the initial stages of K-PKE.Encrypt according to FIPS 203,
|
||||
// Algorithm 14.
|
||||
func parseEK512(ek *EncapsulationKey512, ekPKE []byte) (*EncapsulationKey512, error) {
|
||||
if len(ekPKE) != EncapsulationKeySize512 {
|
||||
return nil, errors.New("mlkem: invalid encapsulation key length")
|
||||
}
|
||||
|
||||
h := sha3.New256()
|
||||
h.Write(ekPKE)
|
||||
h.Sum(ek.h[:0])
|
||||
|
||||
for i := range ek.t {
|
||||
var err error
|
||||
ek.t[i], err = polyByteDecode[nttElement](ekPKE[:encodingSize12])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ekPKE = ekPKE[encodingSize12:]
|
||||
}
|
||||
copy(ek.ρ[:], ekPKE)
|
||||
|
||||
for i := range byte(k512) {
|
||||
for j := range byte(k512) {
|
||||
ek.a[i*k512+j] = sampleNTT(ek.ρ[:], j, i)
|
||||
}
|
||||
}
|
||||
|
||||
return ek, nil
|
||||
}
|
||||
|
||||
// pkeEncrypt512 encrypt a plaintext message.
|
||||
//
|
||||
// It implements K-PKE.Encrypt according to FIPS 203, Algorithm 14, although the
|
||||
// computation of t and AT is done in parseEK512.
|
||||
func pkeEncrypt512(cc *[CiphertextSize512]byte, ex *encryptionKey512, m *[messageSize]byte, rnd []byte) []byte {
|
||||
var N byte
|
||||
r, e1 := make([]nttElement, k512), make([]ringElement, k512)
|
||||
for i := range r {
|
||||
r[i] = ntt(samplePolyCBD(rnd, N, η1_512))
|
||||
N++
|
||||
}
|
||||
for i := range e1 {
|
||||
e1[i] = samplePolyCBD(rnd, N, η2_512)
|
||||
N++
|
||||
}
|
||||
e2 := samplePolyCBD(rnd, N, η2_512)
|
||||
|
||||
u := make([]ringElement, k512) // NTT⁻¹(AT ◦ r) + e1
|
||||
for i := range u {
|
||||
u[i] = e1[i]
|
||||
for j := range r {
|
||||
// Note that i and j are inverted, as we need the transposed of A.
|
||||
u[i] = polyAdd(u[i], inverseNTT(nttMul(ex.a[j*k512+i], r[j])))
|
||||
}
|
||||
}
|
||||
|
||||
μ := ringDecodeAndDecompress1(m)
|
||||
|
||||
var vNTT nttElement // t⊺ ◦ r
|
||||
for i := range ex.t {
|
||||
vNTT = polyAdd(vNTT, nttMul(ex.t[i], r[i]))
|
||||
}
|
||||
v := polyAdd(polyAdd(inverseNTT(vNTT), e2), μ)
|
||||
|
||||
c := cc[:0]
|
||||
for _, f := range u {
|
||||
c = ringCompressAndEncode10(c, f)
|
||||
}
|
||||
c = ringCompressAndEncode4(c, v)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// Decapsulate generates a shared key from a ciphertext and a decapsulation key.
|
||||
// If the ciphertext is not valid, Decapsulate returns an error.
|
||||
//
|
||||
// The shared key must be kept secret.
|
||||
func (dk *DecapsulationKey512) Decapsulate(ciphertext []byte) (sharedKey []byte, err error) {
|
||||
if len(ciphertext) != CiphertextSize512 {
|
||||
return nil, errors.New("mlkem: invalid ciphertext length")
|
||||
}
|
||||
c := (*[CiphertextSize512]byte)(ciphertext)
|
||||
// Note that the hash check (step 3 of the decapsulation input check from
|
||||
// FIPS 203, Section 7.3) is foregone as a DecapsulationKey is always
|
||||
// validly generated by ML-KEM.KeyGen_internal.
|
||||
return kemDecaps512(dk, c), nil
|
||||
}
|
||||
|
||||
// kemDecaps512 produces a shared key from a ciphertext.
|
||||
//
|
||||
// It implements ML-KEM.Decaps_internal according to FIPS 203, Algorithm 18.
|
||||
func kemDecaps512(dk *DecapsulationKey512, c *[CiphertextSize512]byte) (K []byte) {
|
||||
m := pkeDecrypt512(&dk.decryptionKey512, c)
|
||||
g := sha3.New512()
|
||||
g.Write(m[:])
|
||||
g.Write(dk.h[:])
|
||||
G := g.Sum(make([]byte, 0, 64))
|
||||
Kprime, r := G[:SharedKeySize], G[SharedKeySize:]
|
||||
J := sha3.NewSHAKE256()
|
||||
J.Write(dk.z[:])
|
||||
J.Write(c[:])
|
||||
Kout := make([]byte, SharedKeySize)
|
||||
J.Read(Kout)
|
||||
var cc [CiphertextSize512]byte
|
||||
c1 := pkeEncrypt512(&cc, &dk.encryptionKey512, (*[32]byte)(m), r)
|
||||
|
||||
subtle.ConstantTimeCopy(subtle.ConstantTimeCompare(c[:], c1), Kout, Kprime)
|
||||
return Kout
|
||||
}
|
||||
|
||||
// pkeDecrypt512 decrypts a ciphertext.
|
||||
//
|
||||
// It implements K-PKE.Decrypt according to FIPS 203, Algorithm 15,
|
||||
// although s is retained from kemKeyGen512.
|
||||
func pkeDecrypt512(dx *decryptionKey512, c *[CiphertextSize512]byte) []byte {
|
||||
u := make([]ringElement, k512)
|
||||
for i := range u {
|
||||
b := (*[encodingSize10]byte)(c[encodingSize10*i : encodingSize10*(i+1)])
|
||||
u[i] = ringDecodeAndDecompress10(b)
|
||||
}
|
||||
|
||||
b := (*[encodingSize4]byte)(c[encodingSize10*k512:])
|
||||
v := ringDecodeAndDecompress4(b)
|
||||
|
||||
var mask nttElement // s⊺ ◦ NTT(u)
|
||||
for i := range dx.s {
|
||||
mask = polyAdd(mask, nttMul(dx.s[i], ntt(u[i])))
|
||||
}
|
||||
w := polySub(v, inverseNTT(mask))
|
||||
|
||||
return ringCompressAndEncode1(nil, w)
|
||||
}
|
336
mlkem/mlkem512_test.go
Normal file
336
mlkem/mlkem512_test.go
Normal file
@ -0,0 +1,336 @@
|
||||
// Copyright 2025 Sun Yimin. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.24
|
||||
|
||||
package mlkem
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// https://github.com/usnistgov/ACVP-Server/blob/master/gen-val/json-files/ML-KEM-keyGen-FIPS203/internalProjection.json
|
||||
var kenGen512InternalProjectionCases = []struct {
|
||||
tcId int
|
||||
seed string
|
||||
ek string
|
||||
dk string
|
||||
}{
|
||||
{
|
||||
1,
|
||||
"BBA3C0F5DF044CDF4D9CAA53CA15FDE26F34EB3541555CFC54CA9C31B964D0C80A64FDD51A8D91B3166C4958A94EFC3166A4F5DF680980B878DB8371B7624C96",
|
||||
"1CAB32BE749CA76124EE19907B9CCB7FD30F8B2C38DC970E81F9956C97A8BD3C6E37B07C29E60BB2B75C5258B572626A859ABA89DB3AABC571424618B26310278B8EC4E76ED07A10B864AABF37BFC9F364731050631421BFCB1C3B9153D4316A95089197A027AB80B39C362CE6D97EFF422244FB81AAF67354F03894CC25B2707939A4A06D302C59D106EB743678DAA3F1D1C3F46B03F0DAA0641835A548363180744E6B6235B84DB9A4628279A6EF7231499208E657A3F9BB6E3F782606B79FC9A38723576FA80898E8A6887D94C3ED774E46A86CFE705B34C6B5535865329C5A4A820F9114CE9A9C68495C726368B9E073CBBE627A7DE419F7F7B4AD221576F91FB1E66CFF9651BD6C25E3CC9CA49A570CF041E457658072B684E714BD6A86B3D05C7597A729E12E512C8D7E5B5C27049EFB0AC0E085B1B88347BFD314B4E4AB4B8875A489ADB8C9AE28008BAD36AAAD24683563BFAF19BDA8677AB7BAC7E33C3087B84A45246A2AB1AEF397750D386ACDAC63C87506166A0FAE18773F530E74545D54BC670DD7353B75B16373CB8A6269AF37097EE1B1640458153132AD80AB64F7A599B8670E301205043C136C56CA5A06DBFABA3204671C1B237B18824555B5DDB206A74ACE637005B363238378BDA5E198AD69B85CBB399E8B07CB899F9E93CF6CF62FCAFC9E4D77363CA2149E92197F2133223799C182CF5F182ECD35B5FDFCBF0A93A1350198F2F244F3216B442A22FDDB2F4F3BB8CBF0168D0220AA725A0E287DF08079A1DBB8747C02F0C2C829759A5D95B6237522E7F71AB5669390377E03A93AB7FC7E9FD6BB59C1B9B8CC966141B0BA6796E66829D6A403B1F5816C8557EE8841031B2ED6C6CCFE8A55B39B9273F8BA050B1B328C7B9A238A7B8324F16A7A474C0B5721B9C8246531E19208838356F3337768BCB3397B4E01CC26175B67A66DFCD11F07B295C20AB484A60E7D086DB39B8301845B654A484462508FA78506357BBBF42DBAC157BCA7769C099A0B1894D4A17256F504EBE50BE284656F653845A26B00856D76A8A5A166CD09D04705261EBAFA20687A1068D9B9E28326848B67A0A3994D2DBA4B7A8F623B901E17CBEE610847A2903301C58287",
|
||||
"C8D473A9EA0987F356FB309356A39E766633746B8FBAF03D588495E4B1CC87E4B283C871514182D3E1844D9ACB4FA5948BC38D85E05478BB699E41170FA593F7D74226D4597655C5DE80AC8C79181EE750121685C71797D3B5C240676637C7BDEBA61969508C3FABB4CD97CC53C529EBC993C4B883B2B52F42789F64C022620B624B8107E0E55FFE29280BB005DC66A83A0A219A0080F8E656729B29CBF8AA7866358694C94E477E499A055C8A8ECAC7338F461897329ED02B1EF0F0AB627B71B5322692268578B11E5EC203E674251C0182C10C775971247537358C0651EF21704CC68B57D5CF61C627C0AB30DE5743FB027B40D86071531F0C8B67092BAC18361FACEC1BFC53C65D512B3911156A991F462C8588D638526389E3CAAC808809EB7B50ACB83A10142C954B9AC938B983133D5D024303790DF848B7FB06AE4C751DAEDBAF08728A96C481B5A84B53FA37DEEAC6174C745F3C0821553CC88858C3DB392570AA388624CFA98E7232970B746BCF301642D92F3E452E3BF99E24329C470A57B31AA765C8952333A334102605BB8099555230287F07A813109C427E692393540FAD769831756701B481611472A060CA1E7C34F9412371C7658F4C69C9C0BC956404B88AB27BC89ED7F751E51781D95A1D0DCC476E7A8FD4A54272B5A9679B0227176D481035A3864FD747B52739B8FA801713BC0757347BC96A022487BFA5A3C0E30B9FBEAA6838553D9111351FF49A73970263B39CDF180F163972AB993C1630A89A06A2FF69A274F27A819C3727E2244B23163B320DD568B227B6589A402A5E16333C70C4D3264CAC8A80BDC64705675788CC20FE083635D25C89F387F5B39580737F06287F236B7CCCA4CC3A69AC0E84B33B20BA7661B8BA9B575CC555DC820481FA9941A8C259D962273536B36B0BB1E434B18A63BE405583925CCA14001FF9AA28EA7FFF525ABA151944607056F6CD5052C823D00F33651BFBF428257B388544654E9A14F2E595BB4CC5D5929A03F62BC2DC6C6B885D86969B298A06F0294CAE69337944C4AEB5B22E126AEB02BD34083637299D2C41080481C61CAB32BE749CA76124EE19907B9CCB7FD30F8B2C38DC970E81F9956C97A8BD3C6E37B07C29E60BB2B75C5258B572626A859ABA89DB3AABC571424618B26310278B8EC4E76ED07A10B864AABF37BFC9F364731050631421BFCB1C3B9153D4316A95089197A027AB80B39C362CE6D97EFF422244FB81AAF67354F03894CC25B2707939A4A06D302C59D106EB743678DAA3F1D1C3F46B03F0DAA0641835A548363180744E6B6235B84DB9A4628279A6EF7231499208E657A3F9BB6E3F782606B79FC9A38723576FA80898E8A6887D94C3ED774E46A86CFE705B34C6B5535865329C5A4A820F9114CE9A9C68495C726368B9E073CBBE627A7DE419F7F7B4AD221576F91FB1E66CFF9651BD6C25E3CC9CA49A570CF041E457658072B684E714BD6A86B3D05C7597A729E12E512C8D7E5B5C27049EFB0AC0E085B1B88347BFD314B4E4AB4B8875A489ADB8C9AE28008BAD36AAAD24683563BFAF19BDA8677AB7BAC7E33C3087B84A45246A2AB1AEF397750D386ACDAC63C87506166A0FAE18773F530E74545D54BC670DD7353B75B16373CB8A6269AF37097EE1B1640458153132AD80AB64F7A599B8670E301205043C136C56CA5A06DBFABA3204671C1B237B18824555B5DDB206A74ACE637005B363238378BDA5E198AD69B85CBB399E8B07CB899F9E93CF6CF62FCAFC9E4D77363CA2149E92197F2133223799C182CF5F182ECD35B5FDFCBF0A93A1350198F2F244F3216B442A22FDDB2F4F3BB8CBF0168D0220AA725A0E287DF08079A1DBB8747C02F0C2C829759A5D95B6237522E7F71AB5669390377E03A93AB7FC7E9FD6BB59C1B9B8CC966141B0BA6796E66829D6A403B1F5816C8557EE8841031B2ED6C6CCFE8A55B39B9273F8BA050B1B328C7B9A238A7B8324F16A7A474C0B5721B9C8246531E19208838356F3337768BCB3397B4E01CC26175B67A66DFCD11F07B295C20AB484A60E7D086DB39B8301845B654A484462508FA78506357BBBF42DBAC157BCA7769C099A0B1894D4A17256F504EBE50BE284656F653845A26B00856D76A8A5A166CD09D04705261EBAFA20687A1068D9B9E28326848B67A0A3994D2DBA4B7A8F623B901E17CBEE610847A2903301C5828747D4B351E049B7757A2545602C398D2EBCF7C28804BCC8862E270D7324AB435E0A64FDD51A8D91B3166C4958A94EFC3166A4F5DF680980B878DB8371B7624C96",
|
||||
},
|
||||
{
|
||||
2,
|
||||
"00C7E4AB727C202A92869BE37F8A7CBAE63A67463C3A54000F1A3290B987E96F3764A9B01F8C411BEB6DACF298CC30841FEB65A10D6DEBA9780338B4970B983E",
|
||||
"C4A019A8941B1C639C0C6698AAA051E3B9C78BF7A15005A92AB3C6AB30AE974682F517B96F743889696F6F75BDDF6C9A588963AE04477FD52396C3B904459A3DAA39D5939F33817E8F20CD70860915F3B59FB088FFF98C0AFAAEFE352344681A249BCD0529B3578B4123D35C88E14F67616B1E19B28D027AB7988680CB3B1C257257D36FC3A2B81E18B1F918AB9EB650874135AAD478E3F5B34526856F81A3C32541781127F82304FE86BE29A70D489177FA5B9292882BDC58B5756043C558CC50D666D888C70762C71FAA5A0014A1E573B080016BFB17172D8B1B563C64AC39B536D568DA1853D00968334C412A26AE9272B0606A98C6199E96417A946B8780988445BC867050B5CA9904B6322DC059993068B02C09C9C9C2B00E719F45FBAF183B02CA258C95239E5A4993376B7BC47A8D2751C75C59B3AAA90640379ACB0A66B1ECA226D95E377CBC47B7210422BE338283404496D8A29C8553417E38818547ACB6213D7892248BA7746626B562CB1209871A058A92E85248B37185DD3393D7C95C9C36159CD646A7713B47A60EF33825F4F7CCBBC07B4AF88C25A553D11C3D637859818387013806D5A24914FBC7E6D58977674598CC57CF632148C6BFBE24878F318E1471B08EBC90DB01978A837A86C36C3ED14E69F7C771C32939B7AAA28498A038B558F75779D5C2C0736003C91864206E52A296F949058069ADC15033251890309A3F94D97A2716992C7745F8A991D10653E6F480F7A912C6619B0BD85926F8A2A9885112ABB1C3604EFA6B84301A2ABD0A5D6FC29C8B16C98AFA817B41ACF90C9776D603FC7A6B8DF22377E26105D159D35C1089ACAE7B7427DDB6B01E1CAE79FB8AFAA6917C16BB4DCA544B3CB121D00F4921CDF10BBF4437588351623153C916908BD5824684DCAA5B4C44EE9B1063405F723CA60EB52E0B75B7BF67BFD6D34F5AA94657B3AD1BD4CC8D0566BA35C501A78BCF8183D5A52D2E5C4E606AC09C29ABE5A539A280AB838B66A261BADE2028C1D1A9C352B4C6F1919BDA72C2C213D3EA9586C73E0E2C3486D9B199FAA0EA8B039EE9C3EE3B8E1380CE3C0E2BA2E81C9745BD63054616AD78EC8AC8C44B08CC4A217CA320DE7476805E",
|
||||
"B0618E21C291A7D7228F2B5624037B382628A90A89D0213D54E20CA6989BF887A5F0E03256F660264724A5518830B5BA681153C512454CC47A3CEC3E49F3B300A928B05316155C0CF2E069BD6084B52C30422878064B6CB3535FB5485491E6874AA00D820770D0E55A6CAB40F3F4117E764EA43C62A3912943B6096CC41FF87ACA0C140AA37A8C49170E355B60CBF16399A00508989A316CB99426BCC9B9054AE7B46DD3B9CE703CA98C4E8FF6759D2006E66114027B92DCC40F9B2C7402A7C9EE7849955BA9FB35543427701F4C9267F65CD37640265192EB085AA5F02DBEB7125D77145E9B1BDD330E2E687E50789F9D814F4587C3030A5FF95724E62AA84490ACA3C2C76AEC24C29C82385597A9A4395506B21160BF5360133BF709F016817AA5CA266A9556BAA4CA71050B0A71400B97AF4C07782711EC290ED3799C91967AA5E9000BC670F295B53DA415EF8BA631F178F98C747AFC5673D61FC6C280FEB37467D09C80257FBCC02C6D14A48AFB72C7499AF802614D24352750CFD7956B9C77BF92B561AD4365E3666DCBE8033793BEFCC9C5AB572838B4BF459CB1A9822D410B0C6CFB5CA55723FFA555A197657E9A7DE72BCB76995D2E0BAA71409301B07AAAD1A092C3020C1032628109D11C1D46F50A739CB63497BA48BBA556E5A17F629E1D965C356809A3456BEF572234064EE79B9D68169628D8AF01DB25B138B27C6129F493522E40B81A91632CCC41B772CDC2211C10D07422272DD0967C9BB52C52832BA807C7642587C608A0748A32B8766A2C3345AAB527700C49AF887582A049D490B053D34B9A9B038C63AD829969FA706C93B906736A897C9C7187430CFC980116B73E018C7F3FB6420C8046EA86977FAA904597313555C4700594225CA3C9B61F789A59CC350DEEE23D37D5A585672446560C6F38278C0C595B61258BA9430393B1171AA24A530BA37999ED395FE2050A15D9AE74751177890137333B01850BD1535788946817EC1FC604AC2C01C6E23720236BB329172AEFE096B5F93252DC6BB6D82C369AA14822AA92667578CA1238958DA72188D0BBA63DD7B6C4A019A8941B1C639C0C6698AAA051E3B9C78BF7A15005A92AB3C6AB30AE974682F517B96F743889696F6F75BDDF6C9A588963AE04477FD52396C3B904459A3DAA39D5939F33817E8F20CD70860915F3B59FB088FFF98C0AFAAEFE352344681A249BCD0529B3578B4123D35C88E14F67616B1E19B28D027AB7988680CB3B1C257257D36FC3A2B81E18B1F918AB9EB650874135AAD478E3F5B34526856F81A3C32541781127F82304FE86BE29A70D489177FA5B9292882BDC58B5756043C558CC50D666D888C70762C71FAA5A0014A1E573B080016BFB17172D8B1B563C64AC39B536D568DA1853D00968334C412A26AE9272B0606A98C6199E96417A946B8780988445BC867050B5CA9904B6322DC059993068B02C09C9C9C2B00E719F45FBAF183B02CA258C95239E5A4993376B7BC47A8D2751C75C59B3AAA90640379ACB0A66B1ECA226D95E377CBC47B7210422BE338283404496D8A29C8553417E38818547ACB6213D7892248BA7746626B562CB1209871A058A92E85248B37185DD3393D7C95C9C36159CD646A7713B47A60EF33825F4F7CCBBC07B4AF88C25A553D11C3D637859818387013806D5A24914FBC7E6D58977674598CC57CF632148C6BFBE24878F318E1471B08EBC90DB01978A837A86C36C3ED14E69F7C771C32939B7AAA28498A038B558F75779D5C2C0736003C91864206E52A296F949058069ADC15033251890309A3F94D97A2716992C7745F8A991D10653E6F480F7A912C6619B0BD85926F8A2A9885112ABB1C3604EFA6B84301A2ABD0A5D6FC29C8B16C98AFA817B41ACF90C9776D603FC7A6B8DF22377E26105D159D35C1089ACAE7B7427DDB6B01E1CAE79FB8AFAA6917C16BB4DCA544B3CB121D00F4921CDF10BBF4437588351623153C916908BD5824684DCAA5B4C44EE9B1063405F723CA60EB52E0B75B7BF67BFD6D34F5AA94657B3AD1BD4CC8D0566BA35C501A78BCF8183D5A52D2E5C4E606AC09C29ABE5A539A280AB838B66A261BADE2028C1D1A9C352B4C6F1919BDA72C2C213D3EA9586C73E0E2C3486D9B199FAA0EA8B039EE9C3EE3B8E1380CE3C0E2BA2E81C9745BD63054616AD78EC8AC8C44B08CC4A217CA320DE7476805EA1CBE5BF3592B77207A8C0C8E3FAA7EF66DEB7C18CE8CCF387A76B39CB4ECB723764A9B01F8C411BEB6DACF298CC30841FEB65A10D6DEBA9780338B4970B983E",
|
||||
},
|
||||
{
|
||||
3,
|
||||
"99683B23ACDA10B8FE4A877FFDAFA3974CA82812119B26FBC3CFD8D13268BCE951DA028C3ED5E25860B2F5C7334317DFB9F263FBA3C4AA9CF579F98F33706AF4",
|
||||
"08C9A217A9BB0BB90955E2A5513488D9675316D1086C7774218649373C5EF425003EFCA50CE8B2A9349847C011CC421968F990010969BB879FD0D91A28074E9FF06988521EDC12B3AA1A466B955D481A095BBB15AD0130B11953176B5573E379D4E42609C6967A339C3B7453498CBBD4489F54DA0B8ED42A24DC6AA00515F7586703F1C612C6A57AF2B6CABB1991ACAF980104B17A5E1C097A67C46637E380DB91CE6FB612EA35C194200EFB96029B980FDF2B3D36A0561392A89C788676B48A771CA6A47229C0907355317E9EB88903F17792048FAAD182E2C065E30B63FFDA51B69554B0344E27895C4D924CA5FA80BED6AC0A372877454F98C77C4C699D9259BBE30A810BF163CB5817E9339C17151F9678BDA7E00BA1C965F1FB6193753CFC964D82EC36528490DE2539D830CA20FCB232FA3973511D40B1334FF2AC016CCB271CB06432BFD3BA5C7060785D2C3A32AAA4C0762EE873A91955657F49C7B2972106EBBCA39442A3C9490D7A4805F39DAB8A29E08B89A2F80EBE678B200A3DBB376511F62F1A77383F32B6EAB75F462030F75C95719517A4311FD25977B31537C804904B2C0297B63499A0965009B926237965158E9B7963F4A41574306EBD66C80BA4C3B5BB2BD77131C79794985B0EBF0CC351CCBE5BF92611E793C8308F0A8B5CD544556FA0C4DF25656554A1C5D43E79751200B3546929B7975538493B71B2FA40EA0747FD784D6177554D18340A940C89A40E36C84186E9748E1B478C16252E729F84536050E7C448B14FB8687696497412A5A2F8929EA6FB67FF9119331908BB24195D03ABA2C21439191E2539B0DAB826082572521181E69575AA31000FA627D3E80C5EB8BFBA688F69595AAE845AB9AA1955C01CE84674EE16682A1816725A3A8C884532BB9DBA6CACADF9C48446C2D1AA94B46930A180109D3197CC7398A7659C20ECCA63462AC508687314859C08038B5BB7FAE5C2E03AA7F348629CF423D491A5B45791A8A33BDAF101CE05A40C48CFD27930BE98762D79017E109040CB5E7CD66E49F5BFC84744627643E6EA2BEC647FE2D216663352E7D90067DB55732D97E0668D8B44A04821F740E4A04265E2A7AAA4EAB8734262008F55",
|
||||
"1ABC8DB637C626CB70D4CA58323140DEFABBCE522D4F55614B512B041C98DCDA87781770279A2A63E985538CB6E1EB800637269CA0AE0AF075FE91AD25A5C264C51AA3245B987C679EFB92BD0CA6FAB6543E04513DB5777FA98FE495C8695B91BC123F86C55F9632017DC82D4AB79A67DA61B167044979CDD8C4CB57749733CC8B5C4C344F475AA949386A97C8EE666C13C53F43296AC7D76837C6C20EC28D6A550848EC67648284A479646821A66F0358B80A85C73009045C9A17F2ABC556676F838DFB250A35D1073DA307AC83B20DD7A6E3099A2CB423FD07C25619405E86C2D6C3B447EC8201572099ABC17476A2E67B4C878918FFC0A59D21175A32096247A1FBE922050A029B5A88D11430B5A02DA8864B5C637204075DE7986AEB3089F007CA3784331FF33715DB9D436C8A81B203310900192718F8E2342376C042AC92E51C86BAF22A6467332789AC7C4424E619668C57876E053EA8E0B19B78714C22B4E4F32D0F0917ECB64E8DCCB25BC5379B60A43B1AC81CB763429B0F6C89C01BB44F5B184EAED62720CBB8823C3B80A6AC4CF8047D3C625D24B36CE7C8A87A637FFC4704E7181F341477FA139314A5EC91329829C80A09C2D965108A8CAB974A297B495E0C9779E2740F94E361C9D1C4E81185EFA37BB745566797CEFD8B0834ACA9F774A13E799E61694C14EC9CEE903FEC595C4DC853740379485B8F28F04EA2304423B3C74530840F3041DF684846A89B5B8C1619F04356EB24ADB79803D0110114BE9EA962B84A0D936500B9DAC99E1A924FA1515C2CA7F3C745B922BA58458FFF71A18A990B33923C40D2359FE58ACCD6A548B62A8D26A5A50CC439E07BAEF230D2161367C3AB46619497BC5F9DA7430969BA48D9CD1DE500B9A76B017600B999CBC2A828298B94A88AB6CB3738CD6BAF3C299AC6AC6029B8289F4A276F6C6FAA20B7393940B10B7650FB430430AB12BB29EBFA6AB263A2AF1AA880C730B2D655C2C67066D7A06064B91ED90F7BBB559D0B7B20C4721EB907F469A0AC9B975816A0F3038AC53040637A9FB8276F33C93097B579E8B7CDCAF1214F175108C9A217A9BB0BB90955E2A5513488D9675316D1086C7774218649373C5EF425003EFCA50CE8B2A9349847C011CC421968F990010969BB879FD0D91A28074E9FF06988521EDC12B3AA1A466B955D481A095BBB15AD0130B11953176B5573E379D4E42609C6967A339C3B7453498CBBD4489F54DA0B8ED42A24DC6AA00515F7586703F1C612C6A57AF2B6CABB1991ACAF980104B17A5E1C097A67C46637E380DB91CE6FB612EA35C194200EFB96029B980FDF2B3D36A0561392A89C788676B48A771CA6A47229C0907355317E9EB88903F17792048FAAD182E2C065E30B63FFDA51B69554B0344E27895C4D924CA5FA80BED6AC0A372877454F98C77C4C699D9259BBE30A810BF163CB5817E9339C17151F9678BDA7E00BA1C965F1FB6193753CFC964D82EC36528490DE2539D830CA20FCB232FA3973511D40B1334FF2AC016CCB271CB06432BFD3BA5C7060785D2C3A32AAA4C0762EE873A91955657F49C7B2972106EBBCA39442A3C9490D7A4805F39DAB8A29E08B89A2F80EBE678B200A3DBB376511F62F1A77383F32B6EAB75F462030F75C95719517A4311FD25977B31537C804904B2C0297B63499A0965009B926237965158E9B7963F4A41574306EBD66C80BA4C3B5BB2BD77131C79794985B0EBF0CC351CCBE5BF92611E793C8308F0A8B5CD544556FA0C4DF25656554A1C5D43E79751200B3546929B7975538493B71B2FA40EA0747FD784D6177554D18340A940C89A40E36C84186E9748E1B478C16252E729F84536050E7C448B14FB8687696497412A5A2F8929EA6FB67FF9119331908BB24195D03ABA2C21439191E2539B0DAB826082572521181E69575AA31000FA627D3E80C5EB8BFBA688F69595AAE845AB9AA1955C01CE84674EE16682A1816725A3A8C884532BB9DBA6CACADF9C48446C2D1AA94B46930A180109D3197CC7398A7659C20ECCA63462AC508687314859C08038B5BB7FAE5C2E03AA7F348629CF423D491A5B45791A8A33BDAF101CE05A40C48CFD27930BE98762D79017E109040CB5E7CD66E49F5BFC84744627643E6EA2BEC647FE2D216663352E7D90067DB55732D97E0668D8B44A04821F740E4A04265E2A7AAA4EAB8734262008F55BA5847B144C55CB6F43370E75F26C97B32E62B786D7F0E68D590846B65A9D85551DA028C3ED5E25860B2F5C7334317DFB9F263FBA3C4AA9CF579F98F33706AF4",
|
||||
},
|
||||
}
|
||||
|
||||
func TestKeyGen512ACVP(t *testing.T) {
|
||||
for i, tc := range kenGen512InternalProjectionCases {
|
||||
seed, _ := hex.DecodeString(tc.seed)
|
||||
ek, _ := hex.DecodeString(tc.ek)
|
||||
dk, _ := hex.DecodeString(tc.dk)
|
||||
|
||||
dk1, err := NewDecapsulationKeyFromSeed512(seed)
|
||||
if err != nil {
|
||||
t.Fatalf("case %d: NewDecapsulationKeyFromSeed512: %v", i, err)
|
||||
}
|
||||
if !bytes.Equal(dk1.Bytes(), dk) {
|
||||
t.Fatalf("case %d: decapsulation key mismatch", i)
|
||||
}
|
||||
ek1, err := NewEncapsulationKey512(ek)
|
||||
if err != nil {
|
||||
t.Fatalf("case %d: NewEncapsulationKey512: %v", i, err)
|
||||
}
|
||||
if !bytes.Equal(ek1.Bytes(), ek) {
|
||||
t.Fatalf("case %d: encapsulation key mismatch", i)
|
||||
}
|
||||
|
||||
dk2, err := NewDecapsulationKey512(dk)
|
||||
if err != nil {
|
||||
t.Fatalf("case %d: NewDecapsulationKey512: %v", i, err)
|
||||
}
|
||||
if !bytes.Equal(dk2.Bytes(), dk) {
|
||||
t.Fatalf("case %d: decapsulation key mismatch", i)
|
||||
}
|
||||
if !bytes.Equal(dk2.EncapsulationKey().Bytes(), ek) {
|
||||
t.Fatalf("case %d: encapsulation key mismatch", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateKey512_Success(t *testing.T) {
|
||||
// Provide enough random bytes for d and z (64 bytes)
|
||||
randBytes := make([]byte, 64)
|
||||
for i := range randBytes {
|
||||
randBytes[i] = byte(i)
|
||||
}
|
||||
r := &mockRand{data: randBytes}
|
||||
key, err := GenerateKey512(r)
|
||||
if err != nil {
|
||||
t.Fatalf("expected success, got error: %v", err)
|
||||
}
|
||||
if key == nil {
|
||||
t.Fatal("expected non-nil key")
|
||||
}
|
||||
// Check that the key's seed matches the input
|
||||
seed := key.Seed()
|
||||
if !bytes.Equal(seed[:32], randBytes[:32]) || !bytes.Equal(seed[32:], randBytes[32:]) {
|
||||
t.Errorf("key.Seed() does not match input random bytes")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateKey512_ErrorOnD(t *testing.T) {
|
||||
// Simulate error when reading d
|
||||
r := &mockRand{err: errors.New("fail on d")}
|
||||
_, err := GenerateKey512(r)
|
||||
if err == nil || err.Error() != "fail on d" {
|
||||
t.Fatalf("expected error 'fail on d', got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateKey512_ErrorOnZ(t *testing.T) {
|
||||
// Simulate error when reading z (first read ok, second fails)
|
||||
r := &mockRand{data: make([]byte, 32), err: errors.New("fail on z")}
|
||||
// The first 32 bytes will be read for d, then error for z
|
||||
_, err := GenerateKey512(io.MultiReader(
|
||||
bytes.NewReader(r.data),
|
||||
&mockRand{err: r.err},
|
||||
))
|
||||
if err == nil || err.Error() != "fail on z" {
|
||||
t.Fatalf("expected error 'fail on z', got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewDecapsulationKey512_InvalidLength(t *testing.T) {
|
||||
// Too short
|
||||
short := make([]byte, DecapsulationKeySize512-1)
|
||||
_, err := NewDecapsulationKey512(short)
|
||||
if err == nil || err.Error() != "mlkem: invalid decapsulation key length" {
|
||||
t.Fatalf("expected invalid decapsulation key length error, got: %v", err)
|
||||
}
|
||||
// Too long
|
||||
long := make([]byte, DecapsulationKeySize512+1)
|
||||
_, err = NewDecapsulationKey512(long)
|
||||
if err == nil || err.Error() != "mlkem: invalid decapsulation key length" {
|
||||
t.Fatalf("expected invalid decapsulation key length error, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/usnistgov/ACVP-Server/blob/master/gen-val/json-files/ML-KEM-encapDecap-FIPS203/internalProjection.json
|
||||
var encap512InternalProjectionCases = []struct {
|
||||
tcId int
|
||||
ek string
|
||||
dk string
|
||||
c string
|
||||
k string
|
||||
m string
|
||||
}{
|
||||
{
|
||||
1,
|
||||
"ADB031A018722F19C25829150A8B94297C9519173A2C908AEBF76F86C9724A0354300C6AB58A90C7B18A2E828B5FD2CDEACA9810EC00FD8CBB22AA6AE641B5824055A91B27C1F73518953913FA2037D295F42B7E34AABE90D72A2453B215D886EBE28779D76F4830B01A73291B5A7186454A91D665B9E6C04FE808F76AC25E298B97195999F866DBFABD571B59549787F5E316A0C65F3E9132089B219E11712D245AF955ACBFA36D37BB2DFD570ECF90941BD369E8023B2FF65F04D5408FA84531604A5EACCF3D62221429A1D6B1BE5FEB04EBA0BB698B6B6AE4CF72317D96E99B0A840AB55C275B9979BB231926D7140FC9B8C8124B87532E854113532A809C714D492746BEA7C30AA869DD780B77D0BADBBA9D9FE6A09780B1EE7076F5E3CAF5F470D004CB53098BFA340248835EC782B34D612C53701259D2583360935D8B5F25051BF196214D1CC6B33A8A47F41A65B5A143DB3651885214307B0D938F9D253672A4587EBC6D9743A3AFB35A3098149B27C3EA0BAAC5942D9A92856EB0447D1709ED70A673AA1FEBA5398A821FA21B215FD78866C29B1E75C50815CC3F093B7CA70717A10CCF8C1880072230163008AA675A17759937CA672A56BBA772C527A5F9F12D53267419559A7A1A0A3003B64D34ABC8F4294210B140F517BEE86F393BB577E6A41EB64A4EF633C8BA941314528B67A24F4829E99C96BF92022307A763A9086F7C597340C8FBBB0689DC1D28800BAD710422A9334A406B203101A6C97A3D00AC6C095735E22CBC60B3A0760C8B0268FB5BB3D7D0543BAB599FD326608264EA477EE8F8C178898FE7387F15A6B40B13B069D3B574967F8487309495420F20B23456CF6D010AB19CABA9B27CAE79B09D7084D1863359B40F205556456AAD5F92A5A36B49B737866901CF6FB47B59A9C5783C2C5FD95087DA417F7410708290B619B701852B051272AE0428263C28CB025E1C1103B2718A0DDA5FC30394600879AF509B62C57B88A018FEDB09642872591582ABB4AC1408A5750902589406E2479D3BC5AD8016610D7BA18D984EBD951393FC2B83446D474AC8E2A634F66F181976B8C14F6078DE84113D8E728FAC101A23C86300D795CAE9875436CC",
|
||||
"C1C9276205D0DAD6447DC94A5E2C36E754499B42595E75BFBFC15B8AA2615204A33EA62DA190398B341384C1BDD7B9BC547A976594BFA20C20BA9754302A0FF17616C83A3997C9CBF6F7031D9A5977BC58C1058FE15C3101981578B48B09DB07B035C220753C0766992C035FFF0836B3120B06D40200C6484DEA3618491FC446A2C95B94332512AEC61A8453B2251794A0929859E03925A31B0DABC9E9F88E30B2C364F9858CDA1D7A525F913B51BCDA41BB8635F9202253EA4EC1B7882E541A9A1411B66034212209D7F7B08B960832395280628742728B3BB0037AE07FABBC7CB89289DC9996B5894E203C5F24E77EF33B77AF513D3203B32F7258D663BA48A49B0249CC837AA35966C4CFB5774E96AB689613B6565C17DB0273268CFF2A2F391A018FD972BE165C1FA3A6B6587830EAB75D6B4FD3750EF7820727E9CC5D3869219A690FA58A966C80715AB23D7B042111733B8A3AD70674415277BF0C70F225B7BD775E639CB88FC06005CB135F752E02C66C0A197AFF56544EE13A0F8C2119C4B410168F16D779CD7590B77CADC18269B1AB84F1C562FAA94342279BBFFA58961032F794562D288D2F9683F00C06CD5A7B923002729947814811397487C4972579604288695DE054576F872501F02D98399A4369B636AAA84C04A9C87B1B3A3A7DE79B6ECBD49AAB705652CBABA6A1C91153277726203784BBDAE16703FC77F5AB273AB7376A033A15F3CB19872AA113633291416A85A5ADF9BC164BA9E32C991D85CFFE9B391EC06055B7BAA5A59053546EC6DA129896BE628820089B31A1ECB6AC91C5184428D4C582FA9A4841A6B66D500657A456D378BF6EBA41F9EB57CBE8227DE06751FB9AE058981A105604095E0F0943E79C715ABA8ADE8A2250D600BED71B42E7CCC676909CA78EF9823B60C14B4FE565C63237E9E10EE3761D5B677F9AD809E3E13301C601E1F36B5860C3828B9E7634C3ECC53541CBAA5460AC94270C530C617E9866097C20BFF5B879F642BAD352A2E6254CA4184C1022DD8297CF2CBCDC6292FAF5BB9051226D489D8A5979F5C810DC9819210B309E3A71ADB031A018722F19C25829150A8B94297C9519173A2C908AEBF76F86C9724A0354300C6AB58A90C7B18A2E828B5FD2CDEACA9810EC00FD8CBB22AA6AE641B5824055A91B27C1F73518953913FA2037D295F42B7E34AABE90D72A2453B215D886EBE28779D76F4830B01A73291B5A7186454A91D665B9E6C04FE808F76AC25E298B97195999F866DBFABD571B59549787F5E316A0C65F3E9132089B219E11712D245AF955ACBFA36D37BB2DFD570ECF90941BD369E8023B2FF65F04D5408FA84531604A5EACCF3D62221429A1D6B1BE5FEB04EBA0BB698B6B6AE4CF72317D96E99B0A840AB55C275B9979BB231926D7140FC9B8C8124B87532E854113532A809C714D492746BEA7C30AA869DD780B77D0BADBBA9D9FE6A09780B1EE7076F5E3CAF5F470D004CB53098BFA340248835EC782B34D612C53701259D2583360935D8B5F25051BF196214D1CC6B33A8A47F41A65B5A143DB3651885214307B0D938F9D253672A4587EBC6D9743A3AFB35A3098149B27C3EA0BAAC5942D9A92856EB0447D1709ED70A673AA1FEBA5398A821FA21B215FD78866C29B1E75C50815CC3F093B7CA70717A10CCF8C1880072230163008AA675A17759937CA672A56BBA772C527A5F9F12D53267419559A7A1A0A3003B64D34ABC8F4294210B140F517BEE86F393BB577E6A41EB64A4EF633C8BA941314528B67A24F4829E99C96BF92022307A763A9086F7C597340C8FBBB0689DC1D28800BAD710422A9334A406B203101A6C97A3D00AC6C095735E22CBC60B3A0760C8B0268FB5BB3D7D0543BAB599FD326608264EA477EE8F8C178898FE7387F15A6B40B13B069D3B574967F8487309495420F20B23456CF6D010AB19CABA9B27CAE79B09D7084D1863359B40F205556456AAD5F92A5A36B49B737866901CF6FB47B59A9C5783C2C5FD95087DA417F7410708290B619B701852B051272AE0428263C28CB025E1C1103B2718A0DDA5FC30394600879AF509B62C57B88A018FEDB09642872591582ABB4AC1408A5750902589406E2479D3BC5AD8016610D7BA18D984EBD951393FC2B83446D474AC8E2A634F66F181976B8C14F6078DE84113D8E728FAC101A23C86300D795CAE9875436CC17073137259AE58DA42855C429CB69DE93930C35FA796F80C774DC812AD0B9F6E2FC8C99012BB954AB3FDCBD6F6522CF7A0A59C511B330C6B72C0493BA70AA3C",
|
||||
"3244E86669E69F0F238E3CD7F03EF31C4D3CF48CEF726955F06EB5099367310D5D9FC70D48A573458837319BD1691D1A699A68F7A9A8DB73D03620E9E4BC4B088E5E9C5E3638EB3354F6EF3C5E7AE5D57D0571F078E174CFBD6EAE2FD76DC2BED5A907EBA531E89B1BA8D2A8EBE7B4CA0DE96BFF28D278A70549AA0635BE50096F297F7BEF92C6AE9C11C4204CFF07E0598F14495AEFBD207B760DAD34FC0AD8F4000A1911F89FA3B59410C8151B9A8914AA71269EB7E2C329586D3C08F3F10939A497717CCFA3EC5082D46750905CEB703106C2D3E5CD71F138704A20898B5F80F5FDA03C08F8894C2874DE32DFF5C27EA0437A44663C0D6F6B85332AD0F5A0E48D1638BBD281797AF1ADED5C5F1EB87D4723E17BCA439EC469489A371A402EEEAADF1A1BD7C7DA409E9A6414E744167DF13AA1ED9EBDB354BC0DD04190DBA3EC48E5D1DB61C54FE881F8A1DA32EB512F2423EA7F9015DC8C2C3D5B5FEA438A88E6C877A6F4ED17FAB8918E53887996D23956502ED9D3D07BBE8EC899AF55813D39CCF6C2700AC8805517317338655A221268E654839C49D83344A1DE0E75FDD63549B7D57258601C1C74B0FDEF80CAB109C54393A7669E4BDB5CDD3BC21731C1E467784DC6A165194487A94FDAA9C177A0BD4AB009B7D7BBD9EEBDA386492F7903CA7C4345A41271D8B6816B1AC0841B8DB7E2D518B3A2B70386CB5BA159A11FC50420F94C001E1F8F0268A2E0A4A12485C08D0BB696CAC92C8866DE78F18BA7C0E5C4C2F450EAB9E2B126DBA80EF70FFB611A010EC3AA9FBCFB2058C2491B331E63AE27321C0098B49C9F7BD409C70DA376A338317217AF310788772E2A95D1BCC29355B486E3B1FA11753C7D39802D183AAE86C3CAD2EB4E70B3C679E47F01D7FDA48B629E5B8AF315847D20BE7A64EA4A16AB9B237F00A9DC659E01735290902F243E866129F120CF3EC01CD668A9827AB419B7F9994A305782C6CB82801C4DA0B9032034B890A761182E4108EF016AE48AE32ED05544EFC7AADC9D219B4E2F7E892EE58130B7413AD2CD6B5E04CEB2593E06165E37BC8BE981EEE1C638",
|
||||
"6C832560DFE97BECADFBB340EE31AE868A73120806EED02839518E5627D32968",
|
||||
"E8D6BAC09B25469BEE582A7DEE9BD21890CD3F0AF4D7E19E30B3E24E657C149C",
|
||||
},
|
||||
{
|
||||
2,
|
||||
"CE22B227E25D5B5422E53ABD78D6B80AF94A4BFC15AC6A39C56602C1B29934F456E23C9FB9BA568E4C2B3E7B8D6AF7A8AEB4A7AC94A57453CE6E05AC505B1F6785BB024B6EA9744E6C7874472AAFFF7B0F58A5ABFD2424F9E3B8AB9A4813A19FCCD2CE35E1C45829BB5888A9D6C14E351618F72B9135FA0677B91FD0EB84F997C5FFE7C45FB03067238FB5C880469079CB13620DEBB9A4E5247E08247B1C588666CE43EB6377C33741F2372CD14FC9D6BD9F53997FD92A1059AD5FC261EE89561AD26EB7C88A95370CFEA4A76A9CB5DF32996E5C060AA1CB8F39B8AC9956BD037AE3C750F255AED4B56E44317ABAC0442BF484F43896B2493A53568A6123444FC50E6A3B81A6223BE973902CD64C03F233B0B638538B57BE5A43F11BA31B93CF15D32844E48AAFEA0DB277A19E9A395496366D9C9AD2341BE34C58941692A1DC7570626202A5185903466CEA91B7078C357787967493569760C348ABF7C223EAB1365F455C85306ECF8BB951C0727FB94B89790A75D03782B568589B194A80C049DA498347C50B26447F5C8334B70C9EF74EB65C1DA2429B11942D0D57BB14415C6442973F079B1881AD9D5C71657757AB2A2650EC252292ADD1AC2967B9CA1158A6D2E5BBD55211D24874753CC673A8A689B8021010BFA2A8938F3B6F68549C326A221EB86BF7D98A8ED708BBC95AA6D51F8CF94ED374A1C0585F36BC7F22CBA513449942363F37D167CFCA6A38588147F101E26B5F818C2C67B515D7802DF57437BE9567D77A5164B4A061AA0EF019CF1E9024FAC61F43812B47846185C4BA2B4A7A3CD51CDACB558DF8101C2326EA8B4313C91C043542D7B53EF8B83AE02AAEDA2749B2913CC65487D408C463233750A4CF3913957F270753745CA8450BBD113877C3A9D370643D5BC13D0B4D6D979C9BC197BCA91EA0DC004575C7F8CCC08DA501356A4197AB34F34554DD461FD9C3A94A37C90FB864BAEC31D26B7E0D83853C48C896018D67113C4BD723362B87DA964C56027E820B6412282BA7A5819E7A9E4DD27E8C778B8EB8AC7C21BEFEA4192A9468BFC13BC08B079042152012250A0E9261D5B0B540A09464A54EF02AD0F1255ADC57F034529127DA186DCE9527",
|
||||
"D910660105C412B3698D043171C1CC9AF2CC65AA019765034FD94AB6F11613DBB80223371970AB05EB3F325686B6A771EE3324DB5BCD32726B0BC760FFDC486AE473D31521E3EB8B5B5A9E0E7A1DA8104E39752D2A32BC08130F2902C8ED33C8A9E6A670AAB329D170A171AE7450686A0CA980BB8C4203AFCC3985C5E5130AE598EFBA572C316149FC9AD4774FC154A7E12662389849C27A64B0B4A53193A83F50AD6A3A4BEC9A5707F09FBEAA360DD1837E217E1AF335DBC120B5C61FC5260B81408AB9793C431CCB0C9624FDBB687B0699DBC93445363E7A4BA9A644630E4B9B1D03BFB7DCC18AD3182E6891D33927FB9188739043D774C06830C48E84286C817F4259340A366D4EE0141917924551C822ACBEBE57BBDFF58774E780F82B9E4F375CA1D14C344A401759A0D8277494EBCA2955753D7B4A01B3B864E66ED2B644EBA073F8805F8E07208799871E7777EFF5A539AA57D3C55AA9844C3EEA456EF5877A5C1F637993C1021307F8C97CD1165AC837078877691B0B8B7B05295C8F7E7C15406636E18B9E3E98C1F0C522A292BE59B974939C293158290A503BD84456E73351C6495284F46FDA0544D9BCBB54189658975AE1E5BBF4F0410FE3355A33AAABD6335026B55CB2CF2B21CA581BB8A2055EDC918BA3570128E392BF10C55A0BCB97C977ABDB8784253908900D6CEC33B2428FEBE6A426274120C27ABF1AC0FB81C622DA0DF7972E201A28D788A761D9242E63B68A7A7B2E67840BF76382F2159E2C425CA69BB1FAB1FEE66AA0B89E4AB8A2781649676124301CAB6BC4B790B1C26AF36C90B2691C50157D153424AC22444B13BF297AEFFCA74196B2F6A7456A80213B381C6D776296A7173B6A28CE16C41AFA657C7911EAD7354F2770C8FB1E06878841738B51C95371D690A8BBA1D5AB098B9041F2A3B9EAF07DF6DC315DA273BF0503DAC3190B27A0CEC78E3FC4456E51C9DCB65C702A777FB0727266AEF47B2A7EF61BA475B60CB2CC30C039D3CC87A05AA72A252EE043CBFB173BA13015BF08C382CAAAC1367CEE779D0AE6BA0F5435B9241496A581ACB36C3ED212CE22B227E25D5B5422E53ABD78D6B80AF94A4BFC15AC6A39C56602C1B29934F456E23C9FB9BA568E4C2B3E7B8D6AF7A8AEB4A7AC94A57453CE6E05AC505B1F6785BB024B6EA9744E6C7874472AAFFF7B0F58A5ABFD2424F9E3B8AB9A4813A19FCCD2CE35E1C45829BB5888A9D6C14E351618F72B9135FA0677B91FD0EB84F997C5FFE7C45FB03067238FB5C880469079CB13620DEBB9A4E5247E08247B1C588666CE43EB6377C33741F2372CD14FC9D6BD9F53997FD92A1059AD5FC261EE89561AD26EB7C88A95370CFEA4A76A9CB5DF32996E5C060AA1CB8F39B8AC9956BD037AE3C750F255AED4B56E44317ABAC0442BF484F43896B2493A53568A6123444FC50E6A3B81A6223BE973902CD64C03F233B0B638538B57BE5A43F11BA31B93CF15D32844E48AAFEA0DB277A19E9A395496366D9C9AD2341BE34C58941692A1DC7570626202A5185903466CEA91B7078C357787967493569760C348ABF7C223EAB1365F455C85306ECF8BB951C0727FB94B89790A75D03782B568589B194A80C049DA498347C50B26447F5C8334B70C9EF74EB65C1DA2429B11942D0D57BB14415C6442973F079B1881AD9D5C71657757AB2A2650EC252292ADD1AC2967B9CA1158A6D2E5BBD55211D24874753CC673A8A689B8021010BFA2A8938F3B6F68549C326A221EB86BF7D98A8ED708BBC95AA6D51F8CF94ED374A1C0585F36BC7F22CBA513449942363F37D167CFCA6A38588147F101E26B5F818C2C67B515D7802DF57437BE9567D77A5164B4A061AA0EF019CF1E9024FAC61F43812B47846185C4BA2B4A7A3CD51CDACB558DF8101C2326EA8B4313C91C043542D7B53EF8B83AE02AAEDA2749B2913CC65487D408C463233750A4CF3913957F270753745CA8450BBD113877C3A9D370643D5BC13D0B4D6D979C9BC197BCA91EA0DC004575C7F8CCC08DA501356A4197AB34F34554DD461FD9C3A94A37C90FB864BAEC31D26B7E0D83853C48C896018D67113C4BD723362B87DA964C56027E820B6412282BA7A5819E7A9E4DD27E8C778B8EB8AC7C21BEFEA4192A9468BFC13BC08B079042152012250A0E9261D5B0B540A09464A54EF02AD0F1255ADC57F034529127DA186DCE95274FF27A9AF1C9074D3439797A96CC512AEE5D09BEA36A6BAE4C5D1A75943D02C56290C092088A99E4C5A6ED16C739BCBF33E640CE33D7DE20714305EF61BA2B96",
|
||||
"C3D565942112A5B216850124DF528E6792119D688EC12BB9438F83AAF57DD05B1AD9DBDDF482949BB880E4F76FE77AAEB0946B4A5F5A2BBCC8E5C055360B765049D57411E2D3DC201611BEB7B665B7F92453245A668147D1308DE2991F57581E207FA8860890FE3CDB97E35482C38C2761C1CFBF1075F2DA1EEF3B93EBB98B448780183D61E1A70E6EC407669B3734907C5212C6915A368535F6D0DD5C31B0C0800E3374B69B53D2E497BCA88EA5E8A4266A31DDA6D263F7888A85E5E648E79862F0C5B4CDBBD4DAD72D758532553569E16EA6C73FC2F82B65D074F710663E5D17A5FAD1B05152F05E9005714CB395918E59B275BD90B6B9AE588C7984B481E459CDBFBC0E00F0422C7C8EECC783EA6CA1BEAF970E6BBCD54061210FF24FE504D9756C79BF746531EC958244623F89ED87AB48B6CCF28BA18E43298B7E5C3F3EC2E3B669F427762375DA779D206CC889337429DF1A1AD02E0268B8F9F479A573067C9493C1A65CDFA7E7DD2FFA7001423D39C0AFF53910C404E2334420493395EF2C8C2E1F01D2D2F82F7DB8D2FCD30ACD1679D943A9E705AC35F9D10BA9464D6EC52FF86610DE36C79B639B5634776F68203A1D6FC8FD892BDE9F59978C35446C0D4A684108ECCFFC631FD09031932C7435C5EA2E89A25FC08F0196980F2B940CD4D4429AE195ACF14AD8042C09D39A3EE7DC1D1344A8BF5A530BF7C7270482E408FE33E6584C826D2495A5379948F4E90CEACA48757572B086A02AE005EB238C28EFA1D3E9343866C2B5865565FED01CC54D1B1C16148435B0B39F73676FBA06D0FD57B287CA05C7FD0F97B69E62B1A8B2457EBBC8CC4CAAC82EE1A7FDC30649DEDC7129146C6E44E1EF1CCE2BE004E13A276F3E06E8D2801D3EC2616C81CEC6439C9A3827337E20705BAF6F30941673CC8E773188333A76C1C2B04F2D259BB61AEC2B72F846F1C7B2D50582D641F49E61AB4F0828DC732676C3208123F990B9384364A9607905FF155E0107B51624ABACF1DCF48EB93A39E117D9B802EAFD59732D6D7E94E9C7F33AB68908DC87ACAF80EF4BEEA4CCB535C3559519A7E81C",
|
||||
"F833AEC5841D7F3CA0B188221245745D66B374ED8C3C04AE3522ADE7F973F8D5",
|
||||
"971B2D3905A306927C18F0F72D9F58CD3FAC6238C902C3AE679449F6CDB91235",
|
||||
},
|
||||
{
|
||||
3,
|
||||
"F5496665F95ED5240696B112B542863122ABC8E23D1F647E1FD74464F167A58B69BDC21A4AF7991290292B43B6EF692541C144B8E72E004A5C1BBC02528B3F02BCB6F2751B06454C9EF7324C051243268C936CB19FE1CCFB29C85D50AA963B4137484823753A5037128D00BE20302796F2920E0948BF9559EF9CA2E2240F40A01CFB4B0C0C54A476FC75980369CBE976A6AC423C8087B94417B926B706B0B5573B16A14B2BB06A167F75A050D200CF20AA3B6B91A9C9893D08A9264599E6C0563F031EFC250B0137983257B80BAB1C43A010E7C53B52A095D9A19F3FA64D2B6C181B580E14669FA05C4E18BB2924D221F36AB92DE8BAAB514C1788CA5AF83A90929784506AB8205765433D7F1693873631E3605FE72A4B50211D807A4EF3D80110B6009046258B97A5DDDB9D1FD15A0346118C7290FD07760A54C83092C806FAB456467CC862682DC5906ABC53DD0AA0BCA5A23D2B85DC711A88AAB092E47C2CB3B69D85938B3C4A262168A3741B5E4CB8DC227DF7C71EA83230A05A2625D04F9CD774A76BBD9E9BA3099C4462F97E30B56942EA48B8566225A45549C21004C89B66900B6A7898232A385839396338A773651F72060D04B1994C282B6CE733C946A97D6B202BE92458A0AC9EF092AF1336EBF46CC1A99D735C4B8AF04AB7607093122C54764A3EDA4676062A35261BBC67C688E9A053F830BAD186FDCB10BCB42E1AEA2AF3D390B0568882246646003CAC4C291D494F14649C778A293803640BB2A59343A114C13407C06AE68665F4414747A19782440C49B6C814B91FE03019576440C8F361FE256F2AF70EF807ADBFB275304606A793A2CDB984BF043703F71C233C6B92257D66916B52C41EFCF115E03100C292055F0BC89D2102E9755203065836E963F0058E52C18CF8190D97829B2661AAB25A2AE89993B8F1756A86370B4884F0C70F60CB73D74C98BE394396E97427650493EBA03ECC2C1A6BB638488BAFF015D5D0CE17403B664517BE6B19F0B17A4DE2B2976415307334BC715B74B8A9EC5BC41A0A8A0C6CC4EF6420D1551C260026E6A58A80434FF58776044492E6A9DD1B70197DF7A3701EE36CBC3EE64CD5646DDEFC65E8B3AB813F85297148",
|
||||
"FA17500FF65A5BA64AA1796700C2C6F5ECAEA31C7446F35A3FC1659440A554D85CCDE8A0BD2075ABAC60A708B423AB62DA6C18411B6FF1E25C66A92F0DDA925471AF9E95CAB8877B4F6A6F7887CA1CF84F76A9CB7B28052A20C112C88277A57D8F3731D85CC2B31050632240A4C435C09C81409B6CB73CAD79F2B9CD2085A8FB4F3B9862F6205E82501C7D964CA1AB1FFF9A9585D67636906AA5242C6E342522BC3FFCDC744780299FECC8C62C930AAC34CCD55FC617A5D42A63BFF1CC8D50BC60662A9DF4B6B96183F02B95693236564782B4C7CFFC2A8938A132D1C45AC4313E2D775A882864EEAC9C6142AAF4955DEB67304F96C77D1CAB886858457A19CF03235351922DD65E94607085D4C32868AF3966B0B1C541A0412EA113AD360513C4B5014AE20CB3B6311D07A4A4323FED5C650307856B7578C64211A8C259A29AA52ED869D9D74EF318CB10F485F7769247D3B7B4D000E41967C3C7140FAA37C7C79C927BA7B5042F13F674EC1B9C61A929DD59BA88BA3F25AB9C3AF3C38056A23B35854AE4246C3167F4317BAEF0C53B385B2F45616F363E02B9492D064A0C67430383047E18B550F79B4EA996FFC76669DC4EF604B7FAFB9B0D6C54FFB658C740459DFB21CB984D9B336111A9AE82C0CF1D0321D9809AE9E0AEF1CA0F68B1A8607C678CFB4695122C5988C3EEA38DBAA864A8DBBFEAF32A96216AD1CA7560A34D1F3A55203B5E9F847045481203FB40C6136D2D630ADCD9B17A056F07713F4D34421922C05FB96E6E577D90D5B62D6B0960603B569647CF385C7B333680012876C0A49C9853C953BBF8B483839B483D211C340035CCB99969323852F05F03729474F90BCDF44F52FA0399AC66CA811DF1776541B686639119E956203A369DA8D9958D9187FEF8C99BAB0B40E277D256856C45BE55C0BEF6C699245C42BC1050E32C76B335454EEA94692223A1DA8955D1359AD2C69441924098C074F9CD32932A6793359C9A6CC0F7340E798CA3DC046FAA9BDA791CB0E5A80C1414C0E21E94A290BA01CB87981791ECCD4F0610E9792789D16CD26AC1FB7A312E636F95B06BF5496665F95ED5240696B112B542863122ABC8E23D1F647E1FD74464F167A58B69BDC21A4AF7991290292B43B6EF692541C144B8E72E004A5C1BBC02528B3F02BCB6F2751B06454C9EF7324C051243268C936CB19FE1CCFB29C85D50AA963B4137484823753A5037128D00BE20302796F2920E0948BF9559EF9CA2E2240F40A01CFB4B0C0C54A476FC75980369CBE976A6AC423C8087B94417B926B706B0B5573B16A14B2BB06A167F75A050D200CF20AA3B6B91A9C9893D08A9264599E6C0563F031EFC250B0137983257B80BAB1C43A010E7C53B52A095D9A19F3FA64D2B6C181B580E14669FA05C4E18BB2924D221F36AB92DE8BAAB514C1788CA5AF83A90929784506AB8205765433D7F1693873631E3605FE72A4B50211D807A4EF3D80110B6009046258B97A5DDDB9D1FD15A0346118C7290FD07760A54C83092C806FAB456467CC862682DC5906ABC53DD0AA0BCA5A23D2B85DC711A88AAB092E47C2CB3B69D85938B3C4A262168A3741B5E4CB8DC227DF7C71EA83230A05A2625D04F9CD774A76BBD9E9BA3099C4462F97E30B56942EA48B8566225A45549C21004C89B66900B6A7898232A385839396338A773651F72060D04B1994C282B6CE733C946A97D6B202BE92458A0AC9EF092AF1336EBF46CC1A99D735C4B8AF04AB7607093122C54764A3EDA4676062A35261BBC67C688E9A053F830BAD186FDCB10BCB42E1AEA2AF3D390B0568882246646003CAC4C291D494F14649C778A293803640BB2A59343A114C13407C06AE68665F4414747A19782440C49B6C814B91FE03019576440C8F361FE256F2AF70EF807ADBFB275304606A793A2CDB984BF043703F71C233C6B92257D66916B52C41EFCF115E03100C292055F0BC89D2102E9755203065836E963F0058E52C18CF8190D97829B2661AAB25A2AE89993B8F1756A86370B4884F0C70F60CB73D74C98BE394396E97427650493EBA03ECC2C1A6BB638488BAFF015D5D0CE17403B664517BE6B19F0B17A4DE2B2976415307334BC715B74B8A9EC5BC41A0A8A0C6CC4EF6420D1551C260026E6A58A80434FF58776044492E6A9DD1B70197DF7A3701EE36CBC3EE64CD5646DDEFC65E8B3AB813F85297148937D2E5BC317BA84AE3F9C11E41AD14F26504C8C010F2F71E5532767E255E3452E61FE4FA73C922F49DB415D0543153DF506CEC47659F7C1187210C669F25186",
|
||||
"573CED7759FA816716C2B6E4A3E0089F25CD5A8F3972932C5EC8C501BB948D7A2A126192DBBE683C64A0D8605F36100A7B4B30D54ECBA0C849FF10AE4304CC41337045E60A003AE14280235CBB0866FD0F60F7B832142A9FD2B11A884B53B144E2E4F9C8F5F95A8C19DE0E6A5413FE1CE157FCC638C02A1ACDBFF56301FBCA71F3C8EED4203E649B7764C69B9E4FBA2782F00C7DFF8E0E09E9443F3C9C48E13B4010619C570895D3870C91E87CC74792CCEC7A9463E231D01ABCC1D63A5092F59129A1393D44D811C6CCCD9084565EF031E4B30DC56F849F8F3641AB824F1A598BD7963070B334A0E1A81DE64008577E28348D3E452EA14815D52EAC8ADE4E1F1C2FA5F3B95EBCDCDAC0EFF04BE97843B130443870EEF5B4F5A11F6FC048FA7507862B4C872B133484CA639D34A27BD0C2CF9DCC63D760E27EB50B7890EDB74F8BDCB64B4AC252BFE5B4F74106823134DBB7CEF4CF29D8812B15BC82035804D7ABD0B5D88870B59337EA720035123FB5D3471C96FC8D7B386095D828D4C71D1588080242657BDF6789A7CDC227FFDF5462B59D76D8CC29B5FAFE9099638532E1FE5D3C73E1A6C0A37DD36E00CC2DAAE2EAED9EA6D3D39A7AC6522F66C27207887A447199C98A6B80E9822F0CF23F29BBC402C5C3533A0DC3DCD181613FE1367F734D25C5EEF731D069302584CFFF7DBA2F7023A216E0946EFA4ACC3969E99B022B3C56FCE869C746E0D9F4CC528306056EEB7E32CDF523C63CAA84B6E543F49791ED6A0867A7D6C62C64AE560EEFA3BE94CA3FA7F6118C6D35958E29CBD44E0AD682DFFA302EC398B1ED9D72DB649B1518A50116C70314CE4590B8004205EAB8B6AC68AF5CD932C24CFD02BF9414C3B3727E4FB138E984D0BB1E7E4CBAE823294E7DEFFA4D8CC075D2A8F9A891A31FA3D8665D029872DF083DF75D7E47BA24FB3EF7CEFD4A6B09E496661903E784C450BCAE25C15DC1BC91F75146839E884F564F5233BB5CCA8C2F723037B68F596A9DC509D40A33AB192207D53CDF22F592D7F516524A2FD474AA9D14855C4FAE1E028DEAF78237BDC8420B91035D60273385",
|
||||
"4161D690B5985FF27B6C385CD3810477523EC7BF1943B743224DB59F0277EF6E",
|
||||
"A9E1CAAAB831808A51837DFEAB3669CC6C6E5C8C44AB3ADAB32D245C13CC812E",
|
||||
},
|
||||
{
|
||||
4,
|
||||
"B449808E533DB80176A324BCA4DC33E161CC79DABD92E8667149CB23721C2A8A1A251755D3F879D744B13A2C14E685ADAFA298786B40D0559D1BC50C3B82BAF860BDD004AC5825759C6596E45BB46B4647EFC4C7D0321A8149CC6A71323C05330BC984E0C703F23437603076228BBC4B7182263A1DA83B9EDEFC7584D2326E973A1978C0F046801F884E1DC0498583B5BD098E9C49BBA5C7A6630C412D02966C2A80C63587BB5A438A45BBA9621A071ACDB4C91118038F78932A552417DD43821CE7C995B95FBF295482F2905637C5217970C7F1B8BE0B87471C4146467102F08549EA266D8A8536898C7538440DFA60FFA9B91A3B3097655891573DD93A8CCBF81C2D4C10D6B0CAC0B92ABD918428A66DF9A2B7DD440101D83DD88150E4FA6B66AA5FC1A1CA9854245FA72B8C7980546C380A68C84DBBA2F08621FF8727095B0711F9307C876766FC95724CC4558741AE6A23595CA94CD4B9CE303E25846BDBF3192DA867816B1F12E62BFB7977712101CAB11A7F90C9F6820CFD07412F254F8E8B2A1E51C5F4806630C764A04C70D8D56DD2C072610B6333F58E46D782C52B7B44C4A17EC45B1ED03E17CAB6D0F203A7379EE0615EA2E48553231CA6C88D7398908205D038950AFEA34C727917C5F2ABE4AB4DCDF28AB6811E50D07930FB292CA3048442A8C45B37B66C653239A9EEBA2C0D9462C5114D577515C0D6663FCBAC93C3B3E91610FDF4242B506F5815839C929CEED957D0E45D2597BADE830990C9362D9C2B4C08AF4640757D0B954A142FC0058168BB8BAAD6A47250C7A1B1CE9187674D614D0712548D90C5237B0F740A800A015CA9B303CC4416CC8A4DBF84A0CAA49D36A76A747A42D1CB12036817CED21E3F487152A29509F6B4CAD80145322F1EE07D91917282B63E79419B659590AC62481F76161D996DFAC02290100D51249879C1443CD786A37C9A16611C980880C80124A6D493E6F35C7D4B9BC996090ED3482BE37E1F4637B5C57BF295605E949392883AE845CA143CBEC523BAAF09B27EB84A1C57798EB2BD884217B91887BB88C5A561B91CD4A3150806DEB20CC37A81F190693D16F71B6F62EA0CE9A3DBAA109888F67A0DBAA6809811E5EB26",
|
||||
"5DDA60E497BCE1B357AF952F87EB170CF7CADCB452250382AFA60BC2B83C4A94CD1CE1CFB2DA011D93793DD0907BE8CAA121A585C20A1B1253025B8974E78AD297814A7523A6D7CF25478FA46141C22C1ADD5834A164575153784486AC46D48F9DF19650E0CA0594523CCA83C09CCB61808032FB7FD06B899A1BB02C978E1D565E144B0FF0E598514775CCC98C730309B82A9947B60DED9A74D9D20696971979C8449F31AA4C3B32D3A682FD1C5217059261169A1613789AC38FE371825EC910239A11682ACCC0A239FAF3159630A1B7D95B647686606100088B246473BD216184D4B97E3CD717E72B370E769346431B4D2A3632B133D394B7C3A3A3AF7871BA091B52027D5EF935B2A2771DB352DD34C959C0C83A22514EFBB99C639301E4C9B6792CA220B43AF14370C1CA8C9814AD839EEE629397E9C102EA6E716C0757604E9D229AE2D93D93BA69C10325A67404DE7C857C492D14A16DBD383314785C2A572566A067F613816ED044A857B310A601C9B6698900498F603ED15C33B6F30535548BBA2B6CD22146800952477469E9CC404383A53013487D9985C293617AE97FB1C33E90B229865620E746B9B7D699565C57ED0ABAADF88BD6D4B6F3B39C458C30EC77AB5E9188AE63245D5942531A043FE297336315102AA715BC014A2A21992AB8511248435ABBC408B54DB4583EF1133AD2A16779190D6807C3B46CDED9CBDCCB069EF576B98804BFF92F2752281C268908465B0CE3B169E4A03DD036485138C8A4157B0B2F463BC458D3A1EEAB82864C01160631DB973456AA431C055A4AA2208CE300B7F2BFAFBC6EA7A1C53E729348444E445571A6FB1A6EFC1A01318CD3C3505D74C86C2667C8C262BB527646C170AC9751513701890BCDCE6B179C721BBBE4C71A528B7C294D5E634E80A523F812631EC55702A1649F02283FD071C771647661B92AF7C227C133997169C3AA31CC078588000F0AC397F9D47F39F9557D92CCD2676AF80072BF5225A4AA0D3C8733F9B133061CA93857291658ACAB204884D900700CB1E1886FC9F5746FAA0C68D08C1B77B278869F12CC8ACC8A85B449808E533DB80176A324BCA4DC33E161CC79DABD92E8667149CB23721C2A8A1A251755D3F879D744B13A2C14E685ADAFA298786B40D0559D1BC50C3B82BAF860BDD004AC5825759C6596E45BB46B4647EFC4C7D0321A8149CC6A71323C05330BC984E0C703F23437603076228BBC4B7182263A1DA83B9EDEFC7584D2326E973A1978C0F046801F884E1DC0498583B5BD098E9C49BBA5C7A6630C412D02966C2A80C63587BB5A438A45BBA9621A071ACDB4C91118038F78932A552417DD43821CE7C995B95FBF295482F2905637C5217970C7F1B8BE0B87471C4146467102F08549EA266D8A8536898C7538440DFA60FFA9B91A3B3097655891573DD93A8CCBF81C2D4C10D6B0CAC0B92ABD918428A66DF9A2B7DD440101D83DD88150E4FA6B66AA5FC1A1CA9854245FA72B8C7980546C380A68C84DBBA2F08621FF8727095B0711F9307C876766FC95724CC4558741AE6A23595CA94CD4B9CE303E25846BDBF3192DA867816B1F12E62BFB7977712101CAB11A7F90C9F6820CFD07412F254F8E8B2A1E51C5F4806630C764A04C70D8D56DD2C072610B6333F58E46D782C52B7B44C4A17EC45B1ED03E17CAB6D0F203A7379EE0615EA2E48553231CA6C88D7398908205D038950AFEA34C727917C5F2ABE4AB4DCDF28AB6811E50D07930FB292CA3048442A8C45B37B66C653239A9EEBA2C0D9462C5114D577515C0D6663FCBAC93C3B3E91610FDF4242B506F5815839C929CEED957D0E45D2597BADE830990C9362D9C2B4C08AF4640757D0B954A142FC0058168BB8BAAD6A47250C7A1B1CE9187674D614D0712548D90C5237B0F740A800A015CA9B303CC4416CC8A4DBF84A0CAA49D36A76A747A42D1CB12036817CED21E3F487152A29509F6B4CAD80145322F1EE07D91917282B63E79419B659590AC62481F76161D996DFAC02290100D51249879C1443CD786A37C9A16611C980880C80124A6D493E6F35C7D4B9BC996090ED3482BE37E1F4637B5C57BF295605E949392883AE845CA143CBEC523BAAF09B27EB84A1C57798EB2BD884217B91887BB88C5A561B91CD4A3150806DEB20CC37A81F190693D16F71B6F62EA0CE9A3DBAA109888F67A0DBAA6809811E5EB26F1A56A1BE44CD860B6AB94C5A96A136A642EE8AC85A139AEE1DEBC92F7C415797F6828F70EC49463EEB056EE33762A2209E588FA1843B235FF7C77AE0A3A6C02",
|
||||
"D2EA52F54453BCBF2DE9BC50A06B67FEE98090961FC5BCBFE683C371B5B8902DB0F4A64B309C87609562D42E04DDEF4196F0339ECB2AE2224D70FAD4134F696B538DC3FAC029C7E7F7423A0B72D65B66B1C350AE0E0F5263944E5B117B62A0AD9F55C301EA46EAD5B0F568548F4C67DB306C2DD9D7D390E60DEDABF330FF230793F18B1E8C1AB3F54B299E75F6ABB6119A38685F4C31B34559731419D978C85A8B40182C53BD0D9C26830F0EF765BD80DDD30BA2DE9CB26A7E41B94EDB69F40442371B54D35D891852B723BE176F43FE8B59E5D8EA7D7C7ED0638414D5CCE5F990D746F45331E1D80C2EF2E58086AD3D855ED717AA53C37DB52C253C124A1DC9D04AD9F126B4AF2FDED47926019B49E96842D41E77121BF977DC8728D3638FCE43BAEA29D485CD0CB6062F4EA8547E760781538523745E4477F22E4D346F07D26A5E445C55451F8440370FE2362741CBA3818B779AA5415CE934EA3D96C3A139CB76355DC84299D6795BB36402A7B964A5310B1B80A35D01CD14B7B5BC885A217D66FA94D829C724BD8939337F3FCFD899045F4C4A2AA4E3A2BED4B76436F7492C633B48F2440315B5AAD00C338D6E854B46C01D87741ADC07FF0C2E72F95FD8484CAB327F504F3FD7292070C0EBC0C4099129CBE2239B66AD4CF6A5CBD8689CD1F6C8A486BF2FDE9AC1A97FEEA82A27DF9ED44E8CBD2E727E845FDD0DFA48EE6CCD62BCB1603E48E5EC3756566EDBD1023AAF453C63053D647D77D984CC6D37FEB793B3C0602D2BD2A4ACAF67CEA9618C62ED0D70934CA63C830230D41D0D68A8FFBCB3D50330F9B0871846066F3E53846EB023E115485B3B5EB9F354191C9C310FB77D28E23FAF43EEE86DF8EECAEC1CC6DBF6E7C62DA537D2FAB0E43B21DDCF57829151FAA7F5D2004D40750DF420A96CE55DB30200FE63655777F0F6B6011B58FDD232A6B31195D367699CBFA3AA40FFEB742A8816FC83DC21379DBC001432634DD7D40F6356F2093F184E610AA6E64500D976B1FE1EF1F49DEA5B50063ADA2814840D101D3933E23AD6CD8E8910191CA4242AA91D5EB06046C7A671B19C",
|
||||
"7528672FF512CE81FF014D5C96834AF516FE383FA424D4F7F143310808CC7E91",
|
||||
"4DCF56F1BD29253C98117410BA20609FA9F95749986751D68E9AB639F4F78D80",
|
||||
},
|
||||
}
|
||||
|
||||
func TestEncapsulate512ACVP(t *testing.T) {
|
||||
for i, tc := range encap512InternalProjectionCases {
|
||||
ek, _ := hex.DecodeString(tc.ek)
|
||||
dk, _ := hex.DecodeString(tc.dk)
|
||||
c, _ := hex.DecodeString(tc.c)
|
||||
k, _ := hex.DecodeString(tc.k)
|
||||
m, _ := hex.DecodeString(tc.m)
|
||||
|
||||
ek1, err := NewEncapsulationKey512(ek)
|
||||
if err != nil {
|
||||
t.Fatalf("case %d: NewEncapsulationKey512: %v", i, err)
|
||||
}
|
||||
if !bytes.Equal(ek1.Bytes(), ek) {
|
||||
t.Fatalf("case %d: encapsulation key mismatch", i)
|
||||
}
|
||||
k1, c1 := ek1.EncapsulateInternal((*[32]byte)(m))
|
||||
if !bytes.Equal(c1, c) {
|
||||
t.Fatalf("case %d: ciphertext mismatch", i)
|
||||
}
|
||||
if !bytes.Equal(k1, k) {
|
||||
t.Fatalf("case %d: shared secret mismatch", i)
|
||||
}
|
||||
|
||||
dk1, err := NewDecapsulationKey512(dk)
|
||||
if err != nil {
|
||||
t.Fatalf("case %d: NewDecapsulationKey512: %v", i, err)
|
||||
}
|
||||
if !bytes.Equal(dk1.Bytes(), dk) {
|
||||
t.Fatalf("case %d: decapsulation key mismatch", i)
|
||||
}
|
||||
|
||||
k2, err := dk1.Decapsulate(c)
|
||||
if err != nil {
|
||||
t.Fatalf("case %d: Decapsulate: %v", i, err)
|
||||
}
|
||||
if !bytes.Equal(k2, k) {
|
||||
t.Fatalf("case %d: shared secret mismatch", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/usnistgov/ACVP-Server/blob/master/gen-val/json-files/ML-KEM-encapDecap-FIPS203/internalProjection.json
|
||||
var decap512InternalProjectionCases = []struct {
|
||||
tcId int
|
||||
ek string
|
||||
dk string
|
||||
c string
|
||||
k string
|
||||
success bool
|
||||
}{
|
||||
{
|
||||
76,
|
||||
"70EC19B39348974173A550A5C52A248E191D46640799A4365F3C254757350B65764984180A9ABC9048679D6A84C61B7405EC82A403B79569C024CACA55D79BE23C943C159DDADB17011820C7D88D54071FC8AB142727BE747BBD253A26E92071DC34716F5037D1988A889302621A8465D08ABFD2215D97575D730C9495617EF3B69D0C7AA79965CA985BC147797D9688116A20F9626BAB1997FCEAACBFB439D655A566B0A4BD08472265439C00CE487955EBEA094AD00A6A5AC6FB9359F3C11A6E4B3B6C714F70F8A7B8B6524572B34B758DA270753B697415A964170374548B9D1FE43FD80C62A4D951E28182F2848B044A8352E11F5198547B71215E6287DFF13A18287148277883926396D9A07C0B0139577E4923AC41C9C31F0B6067C88B94CBB9921513ACF0AE80D7779D72C666B256B72A777B56A2D12007797B7BE6657650EB42B1060AADC5157FB819EBF707E51637CD8469645196765A2EBFE8483D62C5E2422C27BCA84E5A0F69F45609928A7E51948A9464D5093CF463A39C26447126C684160F3A4298EA0B5B0973A15403CDDF286BEBFA587FFBB5BFA7692A404ABE3BB14014AEAC418900E4588676A5E7A21553F50037262E3DD6253A8BBD985A679F638F709545AB322F6DE71192FB60C0A368A3B06C8CF5267D792D6C2518EA0A27855635E3E68891C141123A1F8C80AA5300B151AC9AE4342334265C457CA8809891EFF12B398A8465F25508836EE3075C898822BA7675AC359D80E85FF84112C8502932016E24531FB24AA0F744B8252B3D89B4A41721BFD779A826AA46F00720B9592A12307B27EB2B5502987AB477161B72F31BB8EF2C2F4EA83823B72CB16532768508835852A701C3522A7B71DA1CD8B5CCA512117990709797C8AAEA3B300B79A28460D22A2C3527CBB8529AA667064FA2039E22AD5ED740BFA353EB04B74A9C9328266561A76A12EC2C33766697DABBDE92A712B81712D2C4E1F335AA642774441E917650F8D92278A8C0444214A774B7996463527756935171D9FA61D0B50454F74ED50831EB3138DB7374A35387BBCB23E40388BB9228C3A66CDD2222524D7CB8DAE2E70FE3D97847AC35824F5D58B54DD943A440DBFF421642",
|
||||
"54301038DA5911366D16C417BFD96AEB85C5DA4AA45AF32F88A700BB9A973AB62684A052D793379B3C2B253B01A4E512AB34C8D8A76F5EBA5F1B28451A66632872C489F3CA606C6B36336895C032386BB35E98B43C8136350616CCF82A4C24816F4354B7C197940A62537BB36F2B8DE32A6AF6CAA100845FB62184B82B29DCE2662CA94D93FB027DB3C8EF858D4223540E79AD5D204C99637FB66718CD04782E149A07354D6FB2C742A9849506BDDECC0548367421FA2B8599443C74192D6B4B67CC5E16F8880087AC578ABCADB5492CC1AC6916CE73AB2858797134676260B22B28B4A8917C5ABD876EDA706CE381AA4985827D492A736652DD6C1DADD10ADF045DBF416158B0384A991D8501BAA9A714B82788C263C16858C81B978FD353126222A46E1587718872BB11513CDA3A88B6547BC464CD612548E581DFE106382428BA8452A86AC6ECB50B7B3C1CBEA571513C63B8741A2CB82C5055CDB2CB00CE9036C220A25C1BA21891B520D435342136D0C15AAFC12DBCC810E9C256D397A3D23A6287282AAEC038649151886A19F9B583806839EE86A12D131FB3E6A1CA1C9CC48626037B5F3DA74C8A025CC61A76078B07D00AA6DAD32C4147CDAADB4DF644A8DBF4222C47AEEF774BDAFA5A48258BDEA84E7B8B6A5CA09243589EF7F1C249A2B344068FC8D874C33B6C4C2782EA86AADE7C10EFDCC93FB993147A3B636127711195C121C7506759389373F896843991125D5A0AB8FB34595166A9109DC2D19AE2738444716C9C21BD06DC8145458ACBA30981A95F8E141BD17B17A3F645E9B63747E370E8D873937A858048614F0645F4B461EF769D2A696706C2811E756163E4746BF00CFFC556AD7A2F0804A6BEDC6A59B1546727C602A99397C50FF818721D5319F63B058D03BC9DE57C1DB74FE14A0D083C25B17886200633D230946DE0A148781735555CCE797040BB479FA733C2A808EE1CB9A285CF863CBDB47172F3A68EEA614736C73C71FA4AD82C6CF13C5CD3179AD296BF3BD6815D13CBFF75A3A99B4824B7560227BE0BD809BD43AED7D951ECDB7273719560DCC0E8C13F70EC19B39348974173A550A5C52A248E191D46640799A4365F3C254757350B65764984180A9ABC9048679D6A84C61B7405EC82A403B79569C024CACA55D79BE23C943C159DDADB17011820C7D88D54071FC8AB142727BE747BBD253A26E92071DC34716F5037D1988A889302621A8465D08ABFD2215D97575D730C9495617EF3B69D0C7AA79965CA985BC147797D9688116A20F9626BAB1997FCEAACBFB439D655A566B0A4BD08472265439C00CE487955EBEA094AD00A6A5AC6FB9359F3C11A6E4B3B6C714F70F8A7B8B6524572B34B758DA270753B697415A964170374548B9D1FE43FD80C62A4D951E28182F2848B044A8352E11F5198547B71215E6287DFF13A18287148277883926396D9A07C0B0139577E4923AC41C9C31F0B6067C88B94CBB9921513ACF0AE80D7779D72C666B256B72A777B56A2D12007797B7BE6657650EB42B1060AADC5157FB819EBF707E51637CD8469645196765A2EBFE8483D62C5E2422C27BCA84E5A0F69F45609928A7E51948A9464D5093CF463A39C26447126C684160F3A4298EA0B5B0973A15403CDDF286BEBFA587FFBB5BFA7692A404ABE3BB14014AEAC418900E4588676A5E7A21553F50037262E3DD6253A8BBD985A679F638F709545AB322F6DE71192FB60C0A368A3B06C8CF5267D792D6C2518EA0A27855635E3E68891C141123A1F8C80AA5300B151AC9AE4342334265C457CA8809891EFF12B398A8465F25508836EE3075C898822BA7675AC359D80E85FF84112C8502932016E24531FB24AA0F744B8252B3D89B4A41721BFD779A826AA46F00720B9592A12307B27EB2B5502987AB477161B72F31BB8EF2C2F4EA83823B72CB16532768508835852A701C3522A7B71DA1CD8B5CCA512117990709797C8AAEA3B300B79A28460D22A2C3527CBB8529AA667064FA2039E22AD5ED740BFA353EB04B74A9C9328266561A76A12EC2C33766697DABBDE92A712B81712D2C4E1F335AA642774441E917650F8D92278A8C0444214A774B7996463527756935171D9FA61D0B50454F74ED50831EB3138DB7374A35387BBCB23E40388BB9228C3A66CDD2222524D7CB8DAE2E70FE3D97847AC35824F5D58B54DD943A440DBFF4216429146E2AC9383962420545163D6F82456E1B93E22A1B2E6875ADA12D4E194AE93EF5C3485EEBBE1BB13C560480DC3471CD950EB300CF2D18F38CAE7575B133526",
|
||||
"9068502093766BB27635F12F3569794C54227CB1828128AEFC5B715CDCD1E9080D59FB218D17EA0D212D158DDB5ED0FFDB4FA9401F4F23387D32AC8B788CFB7A319114425138744002648B07D5216A3EFB4964BC72E98A6EA2939FAF372CAB44CD5D8A929F66C41D644118ACDE5DA2F09B87F8A1F41F55924A7784D8552790CDF256958E35324381902D9A006FAE02933B017A8E55931B6A0CC8CE3B5723D85DE4C4585FAEC0BD80986224CDAEA443556EBF8BCFDE162C258B9E0AB00C2B9DE0190384C61988BCF362BD0493D40D276FFE4873811EF2851204626342921BFB6A75EB6079F58C030AB1D9C1844078E61C29DB88B5FDC463B7AD3F770E1CB8B526BD9B9A5AFADADAED0368BEE0FFABD9ADFEB0FBF6E6DC7A36115BA47A292D454D7A31F5601BD8BD5435B2EF464A474E37B12B7794F356F905FDBEB248B44003F2B43B925CDB98017A68A15B8B90E2D6DAB1B72AC2921CA92F55B3453C2865DECC094E77EC1E70F99A14CE22BBBF7D3C25F1ECBF96478D84DB4EB1F5E077777214CDA31165C2790172EF778435B56B712E3C5C6B2FDFA3B40B45F7065731EC1E33A8FB300F9FD1EAB14A77E5D8367329E0F834A76E889EC2C8F80E5C1098055F2D517EC381A01F37B1AA3923894D90E1A25A8F55D3DB782ADCD644A1B8A168BBF263C77F34B1A3388E76528FD4F91BFDD7D6499EF99CF663964421FFBB6C17CA9456A2E6A3681298628FA728D3FCFB3BDB65A22E7CFC962FB83007F249D543696A8EFBD9A3DBC7C090F2C82B38E76ACB653F18E78407EFDEA120AE61CDCC8C28CAD984D776B69FB201BA3E154F3C87F53CF84DEF777E50BE420DDFB9734065B8D541F983E69E7FB2B48A186BF8338F3234A0B785B2BA63AA875B28EEE98843C48F60BA500E93067F283155A21905836AC33CA8B06790DD800DD000CC42171775A07F704229FB6F9E5123ED032148DD0EC616530B98A68BE3DBAD2A5D24FFABEFD6D78F4484C8A9969DB7480F54A3DDAB445D3C6C489A9E296B612591A027D624032CD1B11452FEA69A178006E8429BEAB1FC089098BE7EA3D73518F3F5E7B59843",
|
||||
"32FE0534E517EC8F87A25578EA047417EC479EECE897D2BA5F9D41A521FAEDCC",
|
||||
false,
|
||||
},
|
||||
{
|
||||
77,
|
||||
"770AB5FCCA728F659556C212F9925F28493CD3C2A60AD743830769F9B387422AC46385C88F4A10D8C43764F5200E810D20AB9A7AEB5C8B100CB751C55B301976D7BD4F0A1DE7D7CFBF0379CC6B9844B16749B8C6659824B65C2659A430914B322289B88D51324772C4A507CBAF240436AAC23950088E41973FCC487F57BD1D14321664AFC6EA2B66403C881509BE445933528A4F97C2A5B86F1CBC08816484F9432241A09E16D6B6C7068F0356505227216127AF9506250E59ADA3AB4611D7BA4A999621241A3D8C4FE0E7CBAE2492B6F44E6AFCA27F33940E3233F5A382549B9DA2C52B9BC99A8BDC1E541B274987A5BC4A272F330F725856220961C659CD9BA534716C5A113B53CD243D5C907FD6E1B2CDE69090B40314B7CA85F2185F9401FA758C3FD8AD91441A6DCB88B7350B753CC06AE5A1FBCB4DF61CAE1DFC7E60C28C7787654A068DD06821983AAED658C110BC19C2FC61E76CAA65D9C0914887A77571B3E63CD63A437028BC03DC8F69346585D023F01465E430220607948619975FAC993703CF60055D9AF28EAA1A2CE412322D11497DF22137380714B701DAE205EF308E2EB8A1B0B09ADB896BB8AB3F34F9BA2695056B7785FD51ACD043CDC1919C6B0335D7E7BDD1C43693582ED5E71D534163A48C45796B43E98BCB3DF47E075B8AE3E96A640CA659747B287C4714113DDCCBC83D37C54022CD321409BE74C331900CB17A72DC27BB6D4401D974B4E236B82F894EF5DC9A7A29091AB475D584B52D9672DDBC8D63B0BDB51554709041CC07CDEE435F39463C04BA0DC2B4C085AAC7822AA4BA50CD470A75C53A7C1318839DF4086D8A8D3510780081112453134F15601F810895B287195866FC237669F5B212C002F62B2130952B99BAC4E0AB002FA915520A715A41B1D541CB54CB7DD0291655F14FD2D0B3D802C9D6CB569FC815B69B1A0787463104A30AB34E7BD732FEEA3C8CC8764FE199947513889942B7C110482C9A1477348C3C3B491060A78B8299490E4DBABD22B054929BA77EE31922E1439D15B530A0C307E72C2F9C568622301DFA261C885A6F66399DC79E593486B11FF236B8367BF6864A1A596448FC251898A3C89CCD0B551131182654",
|
||||
"3B5879284A33A6204C06F84BF91843CF9B23CD8256E3D23BD1012325686138F40E435275298A614D30950D98B00F59AE6A04BBC37510D4DCBE738B90530B455B048DF4F4AF191B59DB8A3D37C83190D425D40014775B507D43A2E2204B9AA6B6241057663A782A411419F0A0E1E8A4D7F5995B197114E832C7FAB5F2D69923D53A46F07C403038C29219EF228DA1746ED27978D9723D09EA6D6F32856D8B5589382AF4F32D2DDA0EADF342ED3248EB0CCB7B9424FCE6432F8A3892A24D610B9F35B7A4D63B918203BEF239C07277433D8122EDA503C3D596B7C670893051286044EA919BB4863AB6A7CD8D43255C099CE1DB832B109CC24C1B15BCA2F5383F03CC7263775AD39A90DE6A1E1CBB4EE8683295353FDE05478CFBB4C5249500FAA9D35B264E36494F009D8CEA06AC096FF3965DE5980B8E8485149B6912BA7B8E935341755AC67499647391A181158F3AC719F3B36CA0624B6C6F26800904609759B0C5D4270ACCAA01159C4235685D1B079624576C73F498A3F9A37B5090FD6010960C3EC9D7A1D95C3749DC3E225B800D2B8F3B597090F0B83CB315B7A43FB69151AD2B2EF21C8E3D6028A650716BD96F466BAEC316A230232B59A97D371C3DF6D2476C51C64F48271EA38AAE9C8EACD1A0F9318DFBC273D382CDFC0043B0C47B35834EB2069A0E306A53826C49C7A69AE3442947C37ED01F55E9411146870DA50194E778CAF71A7561429D1AC02AC362FAD196CE1331BF2A00001DA290F2B136B92B576C2831717908682412462AF101C3ED3685180112D41A73BB164553F9B79CA71F0932693A630E4209BEBE7BAA7AEA295150B1B827716F47464204258F414BDB6C5FFFC42249C782494A4268F60BC5C195AE9C1EFD778CBC15AF2003B3DAB7336AF5037BFB4EED702EC887AF43EBA616414914B08493D53ED9F89EC2805EA1B40B634610B458236A2ACA1610565350234E9B23BE27166FB8ABDB441138F44E79D8541C3AAE85FC553FB884CCA95E6C84325DF29E112B6D863444A52721F5A5A6D0DB5A65564A545633CB121A927136408C16763191EB10270E6A1604B486770AB5FCCA728F659556C212F9925F28493CD3C2A60AD743830769F9B387422AC46385C88F4A10D8C43764F5200E810D20AB9A7AEB5C8B100CB751C55B301976D7BD4F0A1DE7D7CFBF0379CC6B9844B16749B8C6659824B65C2659A430914B322289B88D51324772C4A507CBAF240436AAC23950088E41973FCC487F57BD1D14321664AFC6EA2B66403C881509BE445933528A4F97C2A5B86F1CBC08816484F9432241A09E16D6B6C7068F0356505227216127AF9506250E59ADA3AB4611D7BA4A999621241A3D8C4FE0E7CBAE2492B6F44E6AFCA27F33940E3233F5A382549B9DA2C52B9BC99A8BDC1E541B274987A5BC4A272F330F725856220961C659CD9BA534716C5A113B53CD243D5C907FD6E1B2CDE69090B40314B7CA85F2185F9401FA758C3FD8AD91441A6DCB88B7350B753CC06AE5A1FBCB4DF61CAE1DFC7E60C28C7787654A068DD06821983AAED658C110BC19C2FC61E76CAA65D9C0914887A77571B3E63CD63A437028BC03DC8F69346585D023F01465E430220607948619975FAC993703CF60055D9AF28EAA1A2CE412322D11497DF22137380714B701DAE205EF308E2EB8A1B0B09ADB896BB8AB3F34F9BA2695056B7785FD51ACD043CDC1919C6B0335D7E7BDD1C43693582ED5E71D534163A48C45796B43E98BCB3DF47E075B8AE3E96A640CA659747B287C4714113DDCCBC83D37C54022CD321409BE74C331900CB17A72DC27BB6D4401D974B4E236B82F894EF5DC9A7A29091AB475D584B52D9672DDBC8D63B0BDB51554709041CC07CDEE435F39463C04BA0DC2B4C085AAC7822AA4BA50CD470A75C53A7C1318839DF4086D8A8D3510780081112453134F15601F810895B287195866FC237669F5B212C002F62B2130952B99BAC4E0AB002FA915520A715A41B1D541CB54CB7DD0291655F14FD2D0B3D802C9D6CB569FC815B69B1A0787463104A30AB34E7BD732FEEA3C8CC8764FE199947513889942B7C110482C9A1477348C3C3B491060A78B8299490E4DBABD22B054929BA77EE31922E1439D15B530A0C307E72C2F9C568622301DFA261C885A6F66399DC79E593486B11FF236B8367BF6864A1A596448FC251898A3C89CCD0B5511311826546E56B6967EE923E5733561D5A4BF940CAAC4960BF60CB769A40E396BFC370F094A00986D708AC731B420FDC11FCB071BDA0786A23F80269341AE270B8ED6844B",
|
||||
"30991222B8EA47530F7C703D85BF4357F61F47615539781920EFFDF067172E32EF1BA77B21670ECA074C4B2401BB591B21CA0F4BFBA9F8BE4A26A9DE2ECEAA8303A91073C0C91205DAF6DDB17D35104969C5036BA722B176F6A3E6D92E1E5EDDAD9A6A3561F7E5338BA2B163702E297F9C6F27C5BCB7975139DFF287B739D2053BBC4307946B89DF3D9C963379B932DDBA015A6EA396E729996F7FF573A0C24040DE323E60B95B2197C89127661DB35D44588E132742B62949EA45D3E8527F0B2B71295E0943F1FA1F87D3B3EF11F840B59E2BBB10AA22B687FF23D22CDA109D5CE33F3527FEA041579793530226009D48CAE3E499FD0ECCD036D04B8DA21F939908E53F5BBBE41DBACAF3A7F9F5839D479BA0909F0DF0B2C8CD7AE8B11F160B16EBA19656744AC38D9AEE3A31E698380B3B9483E3A5F3C3B3767C519ACBB515706B1F192B16AA7B1E0B8178F28C65CAB578368DE5BD0DD5691B659293B3B212A5547E60727F69B33D3938A301572FDD931F5F71E7C647BF9CB4B3A8B294E2A17CF504319278648E59DA78F0FC5BBAD5ABC37551C30AAB853CC50DF796F308EC99D56A2348954EDAF7AF6E4D62FA6B1BB6FAC370226F47F1A91E2BC6731875C09CCBF8E635745DEF1A607F15BA774E7A1FCE8822C07916D352BF24DE6218350C5356D627411F884623496620500337654DBB8048D58DB94BCD8BF18ADFF7EAFE9DC8687156F426379FF0D57B880B8F86FD94861CF865DB231B9ADF9FCC53A7D8E5BEC45EF2EDEEAF2109F35A365C1287AC81D18EF302C9313B357870DB914E2E8300440A0C44E3940FAB6B35F1BC4BDF9B7A54EEC634897F1F715A334E553F2AEF6ECCD13966364CB942CA7C91A90EE2ED924DAD7F7A0907A56323BA787967F687E1C8BAB45976E20AE14301139E989E4257EC9F87728F4AC56A5F0588D96908FF7DD901AC4FBD8AB336EAC865377DCE7C22B4E8193F17769E1C1D6A2365D21715F014E9634834EEC80E4F6C97FDFDA6559BA2F88F81CA57A03AED25A0D818E7823BD08713E1667815A5E4776ACE6FB5658053E6DD38A01AA0AA9819802BD83E",
|
||||
"6621D11567D58EAC3CDFBEB9C69DB0E7AFC4C97C252D98B4770C5F6AF98C83DB",
|
||||
true,
|
||||
},
|
||||
{
|
||||
78,
|
||||
"22664886862835E6188D53C21FDC5EAF7849E078832E004CE79A7BBF122E6E59885608002C170077E98440039870E03FCB890D94001A98482EE6644097FB2BF39A93DA8811B951C6B905229A40BB97727EFAC92D266C4AAEC5623C17C1982A25D4859E362A030D191BD9E11D5CEB145E7482FFDC38ED17AAD859BE642072F55B4EDAFA4AC438B3DFB793A910BEA792780A801E70D2AF76283B60238DEE9A63011C343A586BA54CBB0C77CBBB3C8470C09F1A9C57A42436D3ECB89DC0CD711591FC674878A8317BB833D8DB10D217CC02883A1FBA2CFE3770F46721A7C9AC0045BE9F14487CE6992CC0CB1871CEADC3BA0627CFEBEB974B457D3B7953922CB0F5134918B006CAC669FB0B180BA00FEF56912B99A2C23B095E0A1F65F5611C879D4B519FB7E27153284725749C8D321178BB83C33AA9B547129E780B6C958E69192090FB3E2D69AF3B44A923276B4D5998A3349E5E291291B613B579800B12BE0805063755032A219916A5B9807A7A74A0A833F14F2F940465D970EFC7B7F8D93AE6D554A61085BE277DB5709AF4F1AE3F331B6C8900B24697978B7F69F1B3800B3606F23D90A683E44995F4A1451FA4322E03BA4E32120C5B6E6F8218B67A42D2A54467D672297B4F5CF51131180261276548F1ADD6C985415C15C3D00D83108BF34A6077EACCF7789865341B9594AC3C3781D15336696325C811842335AA43E2146B9176EA251ECCEC7F3E18C8E7F11CA7B09AF0CC14995515D80AB090711520D9BC8CD7353187BCD7D2BC4FD19911E11D904959617B4A30EA844E6292CDE42E46D2A013635C1C38C2D42BCFA68C928B6196B9EA75E6626DC7B17849205838B4C794511DED5B19CDB76CCFBC175F6B94E4E5CC5FC3C940C836C7F86BCAB3BAA860CFC3F1C8C088ABC684A243DCA306B27C2200AD1A31261B4C3C163B99E3022D8F79C9B4989AFDC32F5D93134FD57AE2A7B8381319E9FC2266F457CEE24440307417429AA259CF7DF5865A290404D73FB638BA6341316D8AA69FF605FD23453C34BC015B915D723815285FC200966C03CA84828A37579C86418D5433748669A56C447FCAF3F7A27F8BE433449CF232282A0FC0F55F6387EC0CDBAF615987A153",
|
||||
"65BAA3F5C74319F488D378CD416C312E8B5FB189A3991741B4035E1E15B261E350004A4DA438725888AC54BBAA2C9406E303CDB2D9765A0352A22A28BF80CE51CB4234397119B3C5AAE2324BCC0FF6620605373366A474621A949B90888A12BA91FCB68CC9C42070B2AFCC54095236497583DEE7947A3258A6D33672C2B1FE8A02EA9CC34A045C91C5AD3AB72973888C46B8CC383015DC12476551BADDE250D2D84E7B06B7D5984B55A6918023C41EC9648CBC706BC61EF3C041C96822265C092DF204BFA25A9A16754B165AEE58607F2CB9BAFC05F548164C96483A846C3892A6553422E99B1D0099B946FBAA4C320D8187BA9928C574B448613B18EC7BA7AD5C4042642FD04260F5E5600E22AA69051642D0A2AC2BBF5142B69A69B4865AC9FC8B25F71B93F8CCC2C601717D85AE5267116EEA467F54656999CDB365076CEB052D4B4698B361C0B9B02B7BC10129972AC64B1CC65EE0AAB59D401AB41A245BF10F0D58393587CED798786EA87A56F48121E3CF0420BDB438A4E292CB33B6B371D8850D290C8C93627D2B428566014A82AAFF496E809BAC64538A2A52B6FFAA0852574D8A648A5CE81A17471EABF3CBE2F34B6E54C01CE079CFF4AF0CC60F820C64BA30755B20CD06420BCB9156055624599C1F8B8292A668468BE0836FC47383EB8B74E2118E918FC499C64E146276B17E5E015BA85863D9920D8A299F90CB09C178018B895CE6F0828246247CD0B9C86B4F885350CA6167E90953E9397B5EDC0A71866C087A9A8C1A6A3E895BAA78303337479AC256BAD692FC0A9ADB58C2A152A9E382B11956AE30263E74AA7BF1D79B3B98800B7C82E81A0C3AA2CBF4A8CC1D13B3ACE8B3502361ADC694E7684278164C810642771B04085122DD408228606B939550892B01A05B347B2135B5568B4E13C250BC1CD14396A3B756450BC864D7C9346CA4879178DE1A0D5DD82E09F9A938B40C37C4407DA787DC7149875C3E927BA166528054001FF103BFCFD2C1AB933C17E10F1F12779AA44207C960BCF7330D415832050713B438C0482651A5B10B850A828964EEB26196A84AF4AC2922664886862835E6188D53C21FDC5EAF7849E078832E004CE79A7BBF122E6E59885608002C170077E98440039870E03FCB890D94001A98482EE6644097FB2BF39A93DA8811B951C6B905229A40BB97727EFAC92D266C4AAEC5623C17C1982A25D4859E362A030D191BD9E11D5CEB145E7482FFDC38ED17AAD859BE642072F55B4EDAFA4AC438B3DFB793A910BEA792780A801E70D2AF76283B60238DEE9A63011C343A586BA54CBB0C77CBBB3C8470C09F1A9C57A42436D3ECB89DC0CD711591FC674878A8317BB833D8DB10D217CC02883A1FBA2CFE3770F46721A7C9AC0045BE9F14487CE6992CC0CB1871CEADC3BA0627CFEBEB974B457D3B7953922CB0F5134918B006CAC669FB0B180BA00FEF56912B99A2C23B095E0A1F65F5611C879D4B519FB7E27153284725749C8D321178BB83C33AA9B547129E780B6C958E69192090FB3E2D69AF3B44A923276B4D5998A3349E5E291291B613B579800B12BE0805063755032A219916A5B9807A7A74A0A833F14F2F940465D970EFC7B7F8D93AE6D554A61085BE277DB5709AF4F1AE3F331B6C8900B24697978B7F69F1B3800B3606F23D90A683E44995F4A1451FA4322E03BA4E32120C5B6E6F8218B67A42D2A54467D672297B4F5CF51131180261276548F1ADD6C985415C15C3D00D83108BF34A6077EACCF7789865341B9594AC3C3781D15336696325C811842335AA43E2146B9176EA251ECCEC7F3E18C8E7F11CA7B09AF0CC14995515D80AB090711520D9BC8CD7353187BCD7D2BC4FD19911E11D904959617B4A30EA844E6292CDE42E46D2A013635C1C38C2D42BCFA68C928B6196B9EA75E6626DC7B17849205838B4C794511DED5B19CDB76CCFBC175F6B94E4E5CC5FC3C940C836C7F86BCAB3BAA860CFC3F1C8C088ABC684A243DCA306B27C2200AD1A31261B4C3C163B99E3022D8F79C9B4989AFDC32F5D93134FD57AE2A7B8381319E9FC2266F457CEE24440307417429AA259CF7DF5865A290404D73FB638BA6341316D8AA69FF605FD23453C34BC015B915D723815285FC200966C03CA84828A37579C86418D5433748669A56C447FCAF3F7A27F8BE433449CF232282A0FC0F55F6387EC0CDBAF615987A1537E35FD4ECF80F07D398BD1A4F057647C17838F8427212A33DC3D3E7052AD61DB62ECC47A3A06302A8383E1A465EDCF1BF3523A84F5549859A8CA5C0905DEBA3E",
|
||||
"596D8F70598FC6837434DBC18E9891D67735460FE00248E49E07EEDCD2A36C07B37ADB63AB0DD98294B799CD8CE664D09F567A7B52C2BAC89F32366101983529D97586951B9EE52A1B48B51D87F47444D6D3A0F3F5A7063B621C6152ED5FD7A1B06903CB88D2817CC000ACD3C81A6F236CF4A268FEA9388E61EFE62FCFE21D93B8D872E31AC4C84AA8F6A66C419BD9D03EBD11A00BBB3AC07DC806A32783AADDE4B41FA8743A330CA590F5E2076F738A147999D8AA983E67E8D8CB663EEC7A693CE9E48016BDE8511484EEB22232142F6778B0AC3096F14EE5C0131C966171B3CDA96F815D8A6A4668B20F65593543B19656E3C7315523E2FBF3936D050DAFF6E260CF196A2CC83D1C5A8949D1B38E331083565E8683CFB4485D256B7E5CD128FDB516745DE86E402A67DF21FABB2B64E804225ACC7D0435D83261DB47EDC234BE5497469740C2160C793E84EB061D8612093B242D0396588333F4A3CAAE8A456F7D8F29A790CF7569530EDAA4FD2A93F9CAAE4FC4C6CD1D873153351D082B3C9FDF7C644C36D168485CB8C71E96258A3750A89BC3E4EFCB2C81130D7B2CEA9A3277F3919C193B69677DC2BD290F473DE11562974D4AD9E4CA19598E63CF0442763B1A17E00E58207FF2403FBBA79B393C885BCFADAF31AE41FD124CEBCD1AFE38A05CD7B03CE692CC4984C5EC72EEDA9ED85F8575E96CB06569B938AD6E8E78316B3FD099504D1B254D8BC1379B77D61A83D47270FEA6E2455CBAE336A2AAE8FDE479FC405D2F1AD2F54ADEC49B9C2999BA2694C42F88E8AED706DDB9CFD9E9A560FEFB52ABBEA30A09128ABC1780D8099736AF4D4F208EADEA47A1700F2D8C7765C497ED9E23E3A73EA0159F4F7BFB137ED5E6239737743323CACD84E172CD0B451D7F3232BBB6A61AA267D7F5A06A285A2FEEBB13705C824AF5E760017604AB15FB2D68E21A71198B78A6A7969012403AC2DCABED2DE26D65FC5877878EB1456F9F66DC09D66F7F66C127828E1C6E92D8BBD50D2F15AA16AAE3F38759250AF9E02EBBE9DDBEB16F7523FBD8B1473F1D2A3AC7C7FF8EBE0A5D8B764B00D190",
|
||||
"0F138749C455FE4615FF58200C7D4CE24FFD8709C305C53C26AA9E340E8A73EE",
|
||||
false,
|
||||
},
|
||||
{
|
||||
79,
|
||||
"2F29C94A9C9351A321F262343BB7777A8B46CAB624E3F4BCB5704258B462F9EA711146AB34E748A1F08D000249FD73655CE748552909B3AA5546B54A72EA5980B957636B05EB14AA616C1B8B5AA78A5279A46B23B513132AFB85C963409E40CEFCB74F71C75298A670F7C0632C302444C7CE74F643E27B03AF93A76490374632BBFAD0C2AC84BA2BE4579C32237EC701177312B68458AF3B039F431C2658BD54041398D94F39848199C8763A2AB170C421853C7FA19C0A9ED89B665B13CE3553F6C8BA4C745327B3B10B0CABBEEC2D2C11277F359E86547D1E901F0BC44126F3242850AA7A3A00E4FB2923049205EAC160C24CA1B32280B0C0CB788857A54D223548C7505A5DCC5D29D7189595BB5CC070AA23149D376AADD75DE42A611E157C00B797735A3FEA3B59E0EC46E58A0FCB48606D033CF8D75E6592CC89448732D78B30B754F3AB7066F85C57F45E7FC035A7F08496225171373818F765FC02817BAB6FAE432CF0EC38C0779ACE7231041B8047869227DC01202419B83A7B8B87A74468036D9A2CF0C5892EE9CC85F89A32039A0D3A219D0365C600125BCC15CF607C737732D7AB5A27367ACA464571B0839DF379A79880F5B7BFF1FCC4AB69A047166800204C733B3A72FC566C2C280788CFE36A1FA9F63189B0382E683A4ED417D755A20B9895652C1E26B628BF19915D06B8320AA997531E298926F0F268C97C936B1896CC51050411338AC8088CF4A333C847384C9DC766CDB1BA531199C08B0266F1D24331E941224B2617EA9D1EAC33024939041007B5F840100B7E5437306D2A72A3B439E3D355817C78EF28332123797466A0F873A33AA76BC0B42E33C109F3EC8733785C2D03B4E64C3A5A1988C1C4947142CAE75965A610AF5D9849D6056DD9A45E8A8705C04306850B13FA295D36164F486B3440F62951F79BBA12747497C31167BE94D1A9D424373B4B377AE18299C85EE375B0312004D71C107E3ABB12CCA8AA50935ED1AA64477D866BA940C6441D44B006D22AF62960F62478BF978222DCB90E454CCD33BD9AE06F3EB34F5B576C4C9146A4514DD33258A0B6562A5EBC6A8FC1B5F15C9CDDF7EE64417FB722AE52086868BC807BF19B472AF32A",
|
||||
"D01B6395019BCB1318A6670DBA709588C0A734256B3CCB44E6F2A002B91B9DFBC68E18C1957B3EE8C5464C00215E41907C7B6C1E0C20F62B294E8686627CA3181AA1377C25B5F79355B31BC0C14776621A014302DB2119F9BA4F0AD653F9B4AD562BB14760802AEC8B10348403289C9ADA8C1F39A4CBDA9648589ECFD09DE6AA0BE97AA8F0A13644F23D8E505E1076B415DC078B659E63A50D04A53E680980B2E90241435AA0810CC76016F0010E7CF8B2A9A0B1F0A75CC068CAFB4A5AFCD74CBADA6456D83A4D460D978025A89B379F2294D61BBF0A344611635335CC05DD24BC800C48845930F90538C5854D9862B059F952A25B3D2D6BB3E70141EEA769BDB31F42467C16E6509DF8A0A24477916A28B623A555E47079C61EB7B7A5431085AE7457F696812CC49D0DB242FB42B3A58A6B405289974BC34DF24C8E09C63BB81F109468B112668CBB408AA13AA1F2B4EB79A419ACC2B3C05807679E8EC60951B266D621319EBC289F8709E903478D150448FB00B142BEAC93BADAB7703D5CC4ECD78A05121B4182501CE62E4A3BBA65CA6C57156622CB624F844172B0CD3B376E1E008A25E0A8BF982927E154C55A82EC276DA312C2721570F835C51C131E7A011D26F52A90E5BAB0B813EA41C7BB3BC7FAC789775286B1D115CBB865BF96324FA99A3180B7D1A8B7C2B539411302EA62020611359659C2AE0062B1C52C83B7B94A831EC9036A79025689A70C14C44BF590A914A3325392827F6820B96961E7CB2E88B56A1F706C6027A18BD3AB8998124D8C73251A8CCAB2771A630BA448318562061755B6F271063100C4DF788030113F5A8768EEAC11B31A1F0A81C5D14002242409F35B2725AA68FC4087A22321F122B672E101052C3EE59571A9B71C17976C3220C070C0A4641B73B007CD51A5561BF0AC24B58A1DE1443EB38B794822C4148843746C44E6458FC92F1BF4289E3178CBA74521D792DD297D93D15FED878F9021B8F1DAB90D6259C354CC9B4A383A58800C42547F9A13A4F809F5C05EED58C6C98A878FF432ADBAAE218A9C283CBF45D527ECF8A4B867ACD7576957D1C12F29C94A9C9351A321F262343BB7777A8B46CAB624E3F4BCB5704258B462F9EA711146AB34E748A1F08D000249FD73655CE748552909B3AA5546B54A72EA5980B957636B05EB14AA616C1B8B5AA78A5279A46B23B513132AFB85C963409E40CEFCB74F71C75298A670F7C0632C302444C7CE74F643E27B03AF93A76490374632BBFAD0C2AC84BA2BE4579C32237EC701177312B68458AF3B039F431C2658BD54041398D94F39848199C8763A2AB170C421853C7FA19C0A9ED89B665B13CE3553F6C8BA4C745327B3B10B0CABBEEC2D2C11277F359E86547D1E901F0BC44126F3242850AA7A3A00E4FB2923049205EAC160C24CA1B32280B0C0CB788857A54D223548C7505A5DCC5D29D7189595BB5CC070AA23149D376AADD75DE42A611E157C00B797735A3FEA3B59E0EC46E58A0FCB48606D033CF8D75E6592CC89448732D78B30B754F3AB7066F85C57F45E7FC035A7F08496225171373818F765FC02817BAB6FAE432CF0EC38C0779ACE7231041B8047869227DC01202419B83A7B8B87A74468036D9A2CF0C5892EE9CC85F89A32039A0D3A219D0365C600125BCC15CF607C737732D7AB5A27367ACA464571B0839DF379A79880F5B7BFF1FCC4AB69A047166800204C733B3A72FC566C2C280788CFE36A1FA9F63189B0382E683A4ED417D755A20B9895652C1E26B628BF19915D06B8320AA997531E298926F0F268C97C936B1896CC51050411338AC8088CF4A333C847384C9DC766CDB1BA531199C08B0266F1D24331E941224B2617EA9D1EAC33024939041007B5F840100B7E5437306D2A72A3B439E3D355817C78EF28332123797466A0F873A33AA76BC0B42E33C109F3EC8733785C2D03B4E64C3A5A1988C1C4947142CAE75965A610AF5D9849D6056DD9A45E8A8705C04306850B13FA295D36164F486B3440F62951F79BBA12747497C31167BE94D1A9D424373B4B377AE18299C85EE375B0312004D71C107E3ABB12CCA8AA50935ED1AA64477D866BA940C6441D44B006D22AF62960F62478BF978222DCB90E454CCD33BD9AE06F3EB34F5B576C4C9146A4514DD33258A0B6562A5EBC6A8FC1B5F15C9CDDF7EE64417FB722AE52086868BC807BF19B472AF32AE511FAA0E231976722B8C8DA3A15116AB0407F3C7209D421D97969800A933F9742B5A904C6C1477F268EDD8106D88618B002F3A2D0FBB72682CD37B51F9BEC47",
|
||||
"3856C757D2A5FCCD231A1669ECE3832AF80E5AE832F3B1314ABFF54CDBB94ECBE156D3E93FC4705C46D0E662468EFFBB514DEAA24C384DF4F0BB2B3442D6C67926B5D4EBC6DE170AE0A420EF7319F3A52B6F7726CD47F743B86CB5AE06610FE485932D9B6EA9CDE8023A978DBD0DB5C5DD30AEC898A042C825F0143A32DE320EA97CC36B1625D652342F716F61446EE2355435A9FC043DCD68C6BA0C15AF81A50EE394CFAF9558C6247A6E83826FB48ACAA574F26FF137676348EF1FD80EACE7A20EF6A5150CA1F094A9C31794E3C20CE6CFA71AAC394072432CB4442C6BC7D9AACDF493949CB4E9F33B1946ACFAB8ED5C7D978E43DF907848996F9CDF2CEAEDCF4CFFDA1F18AB30EE1F68F505B4C3A1CCFAF492944506101FD2432667B4D1DBA381C3401BCEB2FCD93CEE7D506E63D97081D4721A453BB96009CD58122AA3B2BADC079EC0358C6C8051D58DBBAE2DB9EA7A28668A2B2FB35D90A542212C7ED4C149416B5CA79B9CCA8B608062A0F3E8E6801D86C8295BD1BA1A078935ACEF1C9DC52F126E83B79927A361167C4DA101FE8C42C20E3AD167D28A73E22093E12EABC39A1C0B3A295C3049104E1E9772D3A4A76D829D9BAB22958C14C301488287936EADE7FCBF43744E71B35A23DF0BD07D2D89C468CE3F8E1BE589B202D74B2D4DECC09FB919EFEA56166CF385C40E113FFFC570178044ABADE35172614DEDF9FA93D91AD8218655C8519D5871986C16320D845D5A5231DC1E04335A26AAD213341A5946680FE9F22CC7BBEB660EEEC1CE9BBC92D497A9ACB21642F9CB52D19AC26B774FCF8817350E301E77CD294ADDA779672597BAD395F4913A45E0346A41C14C0A473928F89B92A7075B63E7929E1FD45077D0401356705DD9B6B75D5044605017A9139B19559DB18C3B931DD71A532C861AF40D18D15C63531F1545D337BA1A30841CDA6AB7D6EAFAA4798E4E6980F7718EAE92775DD8460569B05440DCE3789E6D743E695B5B1BAB0C9DE9C666C1595BBEDF69E80445DD53DBAEBEA126E45479CD6472D5F97840475EB1E52F7984ED651C07B82D584A07D9099C353DDA",
|
||||
"ACB0CD384DA7C8A0E5187025297286AD154E9E37448D9D0E798BAE24FA7A6727",
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
func TestDecapsulate512ACVP(t *testing.T) {
|
||||
for i, tc := range decap512InternalProjectionCases {
|
||||
//ek, _ := hex.DecodeString(tc.ek)
|
||||
dk, _ := hex.DecodeString(tc.dk)
|
||||
c, _ := hex.DecodeString(tc.c)
|
||||
k, _ := hex.DecodeString(tc.k)
|
||||
|
||||
dk1, err := NewDecapsulationKey512(dk)
|
||||
if err != nil {
|
||||
t.Fatalf("case %d: NewDecapsulationKey512: %v", i, err)
|
||||
}
|
||||
if !tc.success {
|
||||
c[0] ^= 0xFF // Corrupt the ciphertext to force failure
|
||||
}
|
||||
k1, err := dk1.Decapsulate(c)
|
||||
if tc.success {
|
||||
if err != nil {
|
||||
t.Fatalf("case %d: Decapsulate: %v", i, err)
|
||||
}
|
||||
if !bytes.Equal(k1, k) {
|
||||
t.Fatalf("case %d: shared secret mismatch", i)
|
||||
}
|
||||
} else {
|
||||
if bytes.Equal(k1, k) {
|
||||
t.Fatalf("case %d: decapsulation should have failed", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkKeyGen512(b *testing.B) {
|
||||
var seed [64]byte
|
||||
rand.Read(seed[:])
|
||||
b.ResetTimer()
|
||||
for b.Loop() {
|
||||
if _, err := NewDecapsulationKeyFromSeed512(seed[:]); err != nil {
|
||||
b.Fatalf("NewDecapsulationKeyFromSeed512 failed: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncapsulateInternal512(b *testing.B) {
|
||||
tc := encap512InternalProjectionCases[0]
|
||||
ek, _ := hex.DecodeString(tc.ek)
|
||||
m, _ := hex.DecodeString(tc.m)
|
||||
ek1, err := NewEncapsulationKey512(ek)
|
||||
if err != nil {
|
||||
b.Fatalf("NewEncapsulationKey512: %v", err)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for b.Loop() {
|
||||
ek1.EncapsulateInternal((*[32]byte)(m))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDecapsulate512(b *testing.B) {
|
||||
tc := decap512InternalProjectionCases[0]
|
||||
dk, _ := hex.DecodeString(tc.dk)
|
||||
c, _ := hex.DecodeString(tc.c)
|
||||
|
||||
dk1, err := NewDecapsulationKey512(dk)
|
||||
if err != nil {
|
||||
b.Fatalf("NewDecapsulationKey512: %v", err)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for b.Loop() {
|
||||
if _, err := dk1.Decapsulate(c); err != nil {
|
||||
b.Fatalf("Decapsulate: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
484
mlkem/mlkem768.go
Normal file
484
mlkem/mlkem768.go
Normal file
@ -0,0 +1,484 @@
|
||||
// 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.
|
||||
|
||||
// Package mlkem implements the quantum-resistant key encapsulation method
|
||||
// ML-KEM (formerly known as Kyber), as specified in [NIST FIPS 203].
|
||||
//
|
||||
// [NIST FIPS 203]: https://doi.org/10.6028/NIST.FIPS.203
|
||||
//
|
||||
//go:build go1.24
|
||||
|
||||
package mlkem
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha3"
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
// This package targets security, correctness, simplicity, readability, and
|
||||
// reviewability as its primary goals. All critical operations are performed in
|
||||
// constant time.
|
||||
//
|
||||
// Variable and function names, as well as code layout, are selected to
|
||||
// facilitate reviewing the implementation against the NIST FIPS 203 document.
|
||||
//
|
||||
// Reviewers unfamiliar with polynomials or linear algebra might find the
|
||||
// background at https://words.filippo.io/kyber-math/ useful.
|
||||
//
|
||||
// This file implements the recommended parameter set ML-KEM-768. The ML-KEM-1024
|
||||
// parameter set implementation is auto-generated from this file.
|
||||
//
|
||||
|
||||
const (
|
||||
// ML-KEM global constants.
|
||||
n = 256
|
||||
q = 3329
|
||||
maxBytesOf64Mulη = 192
|
||||
|
||||
// encodingSizeX is the byte size of a ringElement or nttElement encoded
|
||||
// by ByteEncode_X (FIPS 203, Algorithm 5).
|
||||
encodingSize12 = n * 12 / 8
|
||||
encodingSize11 = n * 11 / 8
|
||||
encodingSize10 = n * 10 / 8
|
||||
encodingSize5 = n * 5 / 8
|
||||
encodingSize4 = n * 4 / 8
|
||||
encodingSize1 = n * 1 / 8
|
||||
|
||||
messageSize = encodingSize1
|
||||
|
||||
SharedKeySize = 32
|
||||
SeedSize = 32 + 32
|
||||
)
|
||||
|
||||
// ML-KEM-768 parameters.
|
||||
const (
|
||||
k = 3
|
||||
η1 = 2 // eta1
|
||||
η2 = 2 // eta2
|
||||
|
||||
CiphertextSize768 = k*encodingSize10 + encodingSize4
|
||||
EncapsulationKeySize768 = k*encodingSize12 + 32
|
||||
DecapsulationKeySize768 = k*encodingSize12 + EncapsulationKeySize768 + 32 + 32
|
||||
)
|
||||
|
||||
// ML-KEM-512 parameters.
|
||||
const (
|
||||
k512 = 2
|
||||
η1_512 = 3
|
||||
η2_512 = 2
|
||||
|
||||
CiphertextSize512 = k512*encodingSize10 + encodingSize4
|
||||
EncapsulationKeySize512 = k512*encodingSize12 + 32
|
||||
DecapsulationKeySize512 = k512*encodingSize12 + EncapsulationKeySize512 + 32 + 32
|
||||
)
|
||||
|
||||
// ML-KEM-1024 parameters.
|
||||
const (
|
||||
k1024 = 4
|
||||
η1_1024 = 2
|
||||
η2_1024 = 2
|
||||
|
||||
CiphertextSize1024 = k1024*encodingSize11 + encodingSize5
|
||||
EncapsulationKeySize1024 = k1024*encodingSize12 + 32
|
||||
DecapsulationKeySize1024 = k1024*encodingSize12 + EncapsulationKeySize1024 + 32 + 32
|
||||
)
|
||||
|
||||
// A DecapsulationKey768 is the secret key used to decapsulate a shared key from a
|
||||
// ciphertext. It includes various precomputed values.
|
||||
type DecapsulationKey768 struct {
|
||||
d [32]byte // decapsulation key seed
|
||||
z [32]byte // implicit rejection sampling seed
|
||||
|
||||
ρ [32]byte // rho, sampleNTT seed for A, stored for the encapsulation key
|
||||
h [32]byte // H(ek), stored for ML-KEM.Decaps_internal
|
||||
|
||||
encryptionKey
|
||||
decryptionKey
|
||||
}
|
||||
|
||||
// Seed returns the decapsulation key as a 64-byte seed in the "d || z" form.
|
||||
//
|
||||
// The decapsulation key must be kept secret.
|
||||
func (dk *DecapsulationKey768) Seed() []byte {
|
||||
var b [SeedSize]byte
|
||||
copy(b[:], dk.d[:])
|
||||
copy(b[32:], dk.z[:])
|
||||
return b[:]
|
||||
}
|
||||
|
||||
// Bytes returns the decapsulation key as a byte slice
|
||||
// using the full expanded NIST encoding.
|
||||
func (dk *DecapsulationKey768) Bytes() []byte {
|
||||
b := make([]byte, 0, DecapsulationKeySize768)
|
||||
|
||||
// ByteEncode₁₂(s)
|
||||
for i := range dk.s {
|
||||
b = polyByteEncode(b, dk.s[i])
|
||||
}
|
||||
|
||||
// ByteEncode₁₂(t) || ρ
|
||||
for i := range dk.t {
|
||||
b = polyByteEncode(b, dk.t[i])
|
||||
}
|
||||
b = append(b, dk.ρ[:]...)
|
||||
|
||||
// H(ek) || z
|
||||
b = append(b, dk.h[:]...)
|
||||
b = append(b, dk.z[:]...)
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// EncapsulationKey returns the public encapsulation key necessary to produce
|
||||
// ciphertexts.
|
||||
func (dk *DecapsulationKey768) EncapsulationKey() *EncapsulationKey768 {
|
||||
return &EncapsulationKey768{
|
||||
ρ: dk.ρ,
|
||||
h: dk.h,
|
||||
encryptionKey: dk.encryptionKey,
|
||||
}
|
||||
}
|
||||
|
||||
// An EncapsulationKey768 is the public key used to produce ciphertexts to be
|
||||
// decapsulated by the corresponding [DecapsulationKey768].
|
||||
type EncapsulationKey768 struct {
|
||||
ρ [32]byte // sampleNTT seed for A
|
||||
h [32]byte // H(ek)
|
||||
encryptionKey
|
||||
}
|
||||
|
||||
// Bytes returns the encapsulation key as a byte slice.
|
||||
func (ek *EncapsulationKey768) Bytes() []byte {
|
||||
// The actual logic is in a separate function to outline this allocation.
|
||||
b := make([]byte, 0, EncapsulationKeySize768)
|
||||
return ek.bytes(b)
|
||||
}
|
||||
|
||||
func (ek *EncapsulationKey768) bytes(b []byte) []byte {
|
||||
for i := range ek.t {
|
||||
b = polyByteEncode(b, ek.t[i])
|
||||
}
|
||||
b = append(b, ek.ρ[:]...)
|
||||
return b
|
||||
}
|
||||
|
||||
// encryptionKey is the parsed and expanded form of a PKE encryption key.
|
||||
type encryptionKey struct {
|
||||
t [k]nttElement // ByteDecode₁₂(ek[:384k])
|
||||
a [k * k]nttElement // A[i*k+j] = sampleNTT(ρ, j, i)
|
||||
}
|
||||
|
||||
// decryptionKey is the parsed and expanded form of a PKE decryption key.
|
||||
type decryptionKey struct {
|
||||
s [k]nttElement // ByteDecode₁₂(dk[:decryptionKeySize])
|
||||
}
|
||||
|
||||
// GenerateKey768 generates a new decapsulation key. The decapsulation key must be kept secret.
|
||||
// See FIPS 203, Algorithm 19.
|
||||
func GenerateKey768(rand io.Reader) (*DecapsulationKey768, error) {
|
||||
// The actual logic is in a separate function to outline this allocation.
|
||||
dk := &DecapsulationKey768{}
|
||||
return generateKey(dk, rand)
|
||||
}
|
||||
|
||||
func generateKey(dk *DecapsulationKey768, rand io.Reader) (*DecapsulationKey768, error) {
|
||||
var d [32]byte
|
||||
if _, err := io.ReadFull(rand, d[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var z [32]byte
|
||||
if _, err := io.ReadFull(rand, z[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kemKeyGen(dk, &d, &z)
|
||||
return dk, nil
|
||||
}
|
||||
|
||||
// NewDecapsulationKeyFromSeed768 parses a decapsulation key from a 64-byte
|
||||
// seed in the "d || z" form. The seed must be uniformly random.
|
||||
func NewDecapsulationKeyFromSeed768(seed []byte) (*DecapsulationKey768, error) {
|
||||
// The actual logic is in a separate function to outline this allocation.
|
||||
dk := &DecapsulationKey768{}
|
||||
return newKeyFromSeed(dk, seed)
|
||||
}
|
||||
|
||||
func newKeyFromSeed(dk *DecapsulationKey768, seed []byte) (*DecapsulationKey768, error) {
|
||||
if len(seed) != SeedSize {
|
||||
return nil, errors.New("mlkem: invalid seed length")
|
||||
}
|
||||
d := (*[32]byte)(seed[:32])
|
||||
z := (*[32]byte)(seed[32:])
|
||||
kemKeyGen(dk, d, z)
|
||||
|
||||
return dk, nil
|
||||
}
|
||||
|
||||
// NewDecapsulationKey768 parses a decapsulation key from its expanded NIST format.
|
||||
func NewDecapsulationKey768(b []byte) (*DecapsulationKey768, error) {
|
||||
if len(b) != DecapsulationKeySize768 {
|
||||
return nil, errors.New("mlkem: invalid decapsulation key length")
|
||||
}
|
||||
|
||||
dk := &DecapsulationKey768{}
|
||||
for i := range dk.s {
|
||||
var err error
|
||||
dk.s[i], err = polyByteDecode[nttElement](b[:encodingSize12])
|
||||
if err != nil {
|
||||
return nil, errors.New("mlkem: invalid secret key encoding")
|
||||
}
|
||||
b = b[encodingSize12:]
|
||||
}
|
||||
|
||||
ek, err := NewEncapsulationKey768(b[:EncapsulationKeySize768])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dk.ρ = ek.ρ
|
||||
dk.h = ek.h
|
||||
dk.encryptionKey = ek.encryptionKey
|
||||
b = b[EncapsulationKeySize768:]
|
||||
|
||||
if !bytes.Equal(dk.h[:], b[:32]) {
|
||||
return nil, errors.New("mlkem: inconsistent H(ek) in encoded bytes")
|
||||
}
|
||||
|
||||
copy(dk.z[:], b[32:])
|
||||
|
||||
return dk, nil
|
||||
}
|
||||
|
||||
// kemKeyGen generates a decapsulation key.
|
||||
//
|
||||
// It implements ML-KEM.KeyGen_internal according to FIPS 203, Algorithm 16, and
|
||||
// K-PKE.KeyGen according to FIPS 203, Algorithm 13. The two are merged to save
|
||||
// copies and allocations.
|
||||
func kemKeyGen(dk *DecapsulationKey768, d, z *[32]byte) {
|
||||
dk.d = *d
|
||||
dk.z = *z
|
||||
|
||||
g := sha3.New512()
|
||||
g.Write(d[:])
|
||||
g.Write([]byte{k}) // Module dimension as a domain separator.
|
||||
G := g.Sum(make([]byte, 0, 64))
|
||||
ρ, σ := G[:32], G[32:] // rho, sigma
|
||||
dk.ρ = [32]byte(ρ)
|
||||
|
||||
A := &dk.a
|
||||
for i := range byte(k) {
|
||||
for j := range byte(k) {
|
||||
A[i*k+j] = sampleNTT(ρ, j, i)
|
||||
}
|
||||
}
|
||||
|
||||
var N byte
|
||||
s := &dk.s
|
||||
for i := range s {
|
||||
s[i] = ntt(samplePolyCBD(σ, N, η1))
|
||||
N++
|
||||
}
|
||||
e := make([]nttElement, k)
|
||||
for i := range e {
|
||||
e[i] = ntt(samplePolyCBD(σ, N, η1))
|
||||
N++
|
||||
}
|
||||
|
||||
t := &dk.t
|
||||
for i := range t { // t = A ◦ s + e
|
||||
t[i] = e[i]
|
||||
for j := range s {
|
||||
t[i] = polyAdd(t[i], nttMul(A[i*k+j], s[j]))
|
||||
}
|
||||
}
|
||||
|
||||
H := sha3.New256()
|
||||
ek := dk.EncapsulationKey().Bytes()
|
||||
H.Write(ek)
|
||||
H.Sum(dk.h[:0])
|
||||
}
|
||||
|
||||
// Encapsulate generates a shared key and an associated ciphertext from an
|
||||
// encapsulation key.
|
||||
//
|
||||
// The shared key must be kept secret. See FIPS 203, Algorithm 20.
|
||||
func (ek *EncapsulationKey768) Encapsulate(rand io.Reader) (sharedKey, ciphertext []byte, err error) {
|
||||
// The actual logic is in a separate function to outline this allocation.
|
||||
var cc [CiphertextSize768]byte
|
||||
return ek.encapsulate(&cc, rand)
|
||||
}
|
||||
|
||||
func (ek *EncapsulationKey768) encapsulate(cc *[CiphertextSize768]byte, rand io.Reader) (sharedKey, ciphertext []byte, err error) {
|
||||
var m [messageSize]byte
|
||||
if _, err := io.ReadFull(rand, m[:]); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
sharedKey, ciphertext = kemEncaps(cc, ek, &m)
|
||||
return sharedKey, ciphertext, nil
|
||||
}
|
||||
|
||||
// EncapsulateInternal is a derandomized version of Encapsulate, exclusively for
|
||||
// use in tests.
|
||||
func (ek *EncapsulationKey768) EncapsulateInternal(m *[32]byte) (sharedKey, ciphertext []byte) {
|
||||
cc := &[CiphertextSize768]byte{}
|
||||
return kemEncaps(cc, ek, m)
|
||||
}
|
||||
|
||||
// kemEncaps generates a shared key and an associated ciphertext.
|
||||
//
|
||||
// It implements ML-KEM.Encaps_internal according to FIPS 203, Algorithm 17.
|
||||
func kemEncaps(cc *[CiphertextSize768]byte, ek *EncapsulationKey768, m *[messageSize]byte) (K, c []byte) {
|
||||
g := sha3.New512()
|
||||
g.Write(m[:])
|
||||
g.Write(ek.h[:])
|
||||
G := g.Sum(nil)
|
||||
K, r := G[:SharedKeySize], G[SharedKeySize:]
|
||||
c = pkeEncrypt(cc, &ek.encryptionKey, m, r)
|
||||
return K, c
|
||||
}
|
||||
|
||||
// NewEncapsulationKey768 parses an encapsulation key from its encoded form.
|
||||
// If the encapsulation key is not valid, NewEncapsulationKey768 returns an error.
|
||||
func NewEncapsulationKey768(encapsulationKey []byte) (*EncapsulationKey768, error) {
|
||||
// The actual logic is in a separate function to outline this allocation.
|
||||
ek := &EncapsulationKey768{}
|
||||
return parseEK(ek, encapsulationKey)
|
||||
}
|
||||
|
||||
// parseEK parses an encryption key from its encoded form.
|
||||
//
|
||||
// It implements the initial stages of K-PKE.Encrypt according to FIPS 203,
|
||||
// Algorithm 14.
|
||||
func parseEK(ek *EncapsulationKey768, ekPKE []byte) (*EncapsulationKey768, error) {
|
||||
if len(ekPKE) != EncapsulationKeySize768 {
|
||||
return nil, errors.New("mlkem: invalid encapsulation key length")
|
||||
}
|
||||
|
||||
h := sha3.New256()
|
||||
h.Write(ekPKE)
|
||||
h.Sum(ek.h[:0])
|
||||
|
||||
for i := range ek.t {
|
||||
var err error
|
||||
ek.t[i], err = polyByteDecode[nttElement](ekPKE[:encodingSize12])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ekPKE = ekPKE[encodingSize12:]
|
||||
}
|
||||
copy(ek.ρ[:], ekPKE)
|
||||
|
||||
for i := range byte(k) {
|
||||
for j := range byte(k) {
|
||||
ek.a[i*k+j] = sampleNTT(ek.ρ[:], j, i)
|
||||
}
|
||||
}
|
||||
|
||||
return ek, nil
|
||||
}
|
||||
|
||||
// pkeEncrypt encrypt a plaintext message.
|
||||
//
|
||||
// It implements K-PKE.Encrypt according to FIPS 203, Algorithm 14, although the
|
||||
// computation of t and AT is done in parseEK.
|
||||
func pkeEncrypt(cc *[CiphertextSize768]byte, ex *encryptionKey, m *[messageSize]byte, rnd []byte) []byte {
|
||||
var N byte
|
||||
r, e1 := make([]nttElement, k), make([]ringElement, k)
|
||||
for i := range r {
|
||||
r[i] = ntt(samplePolyCBD(rnd, N, η1))
|
||||
N++
|
||||
}
|
||||
for i := range e1 {
|
||||
e1[i] = samplePolyCBD(rnd, N, η2)
|
||||
N++
|
||||
}
|
||||
e2 := samplePolyCBD(rnd, N, η2)
|
||||
|
||||
u := make([]ringElement, k) // NTT⁻¹(AT ◦ r) + e1
|
||||
for i := range u {
|
||||
u[i] = e1[i]
|
||||
for j := range r {
|
||||
// Note that i and j are inverted, as we need the transposed of A.
|
||||
u[i] = polyAdd(u[i], inverseNTT(nttMul(ex.a[j*k+i], r[j])))
|
||||
}
|
||||
}
|
||||
|
||||
μ := ringDecodeAndDecompress1(m)
|
||||
|
||||
var vNTT nttElement // t⊺ ◦ r
|
||||
for i := range ex.t {
|
||||
vNTT = polyAdd(vNTT, nttMul(ex.t[i], r[i]))
|
||||
}
|
||||
v := polyAdd(polyAdd(inverseNTT(vNTT), e2), μ)
|
||||
|
||||
c := cc[:0]
|
||||
for _, f := range u {
|
||||
c = ringCompressAndEncode10(c, f)
|
||||
}
|
||||
c = ringCompressAndEncode4(c, v)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// Decapsulate generates a shared key from a ciphertext and a decapsulation key.
|
||||
// If the ciphertext is not valid, Decapsulate returns an error.
|
||||
//
|
||||
// The shared key must be kept secret.
|
||||
func (dk *DecapsulationKey768) Decapsulate(ciphertext []byte) (sharedKey []byte, err error) {
|
||||
if len(ciphertext) != CiphertextSize768 {
|
||||
return nil, errors.New("mlkem: invalid ciphertext length")
|
||||
}
|
||||
c := (*[CiphertextSize768]byte)(ciphertext)
|
||||
// Note that the hash check (step 3 of the decapsulation input check from
|
||||
// FIPS 203, Section 7.3) is foregone as a DecapsulationKey is always
|
||||
// validly generated by ML-KEM.KeyGen_internal.
|
||||
return kemDecaps(dk, c), nil
|
||||
}
|
||||
|
||||
// kemDecaps produces a shared key from a ciphertext.
|
||||
//
|
||||
// It implements ML-KEM.Decaps_internal according to FIPS 203, Algorithm 18.
|
||||
func kemDecaps(dk *DecapsulationKey768, c *[CiphertextSize768]byte) (K []byte) {
|
||||
m := pkeDecrypt(&dk.decryptionKey, c)
|
||||
g := sha3.New512()
|
||||
g.Write(m[:])
|
||||
g.Write(dk.h[:])
|
||||
G := g.Sum(make([]byte, 0, 64))
|
||||
Kprime, r := G[:SharedKeySize], G[SharedKeySize:]
|
||||
J := sha3.NewSHAKE256()
|
||||
J.Write(dk.z[:])
|
||||
J.Write(c[:])
|
||||
Kout := make([]byte, SharedKeySize)
|
||||
J.Read(Kout)
|
||||
var cc [CiphertextSize768]byte
|
||||
c1 := pkeEncrypt(&cc, &dk.encryptionKey, (*[32]byte)(m), r)
|
||||
|
||||
subtle.ConstantTimeCopy(subtle.ConstantTimeCompare(c[:], c1), Kout, Kprime)
|
||||
return Kout
|
||||
}
|
||||
|
||||
// pkeDecrypt decrypts a ciphertext.
|
||||
//
|
||||
// It implements K-PKE.Decrypt according to FIPS 203, Algorithm 15,
|
||||
// although s is retained from kemKeyGen.
|
||||
func pkeDecrypt(dx *decryptionKey, c *[CiphertextSize768]byte) []byte {
|
||||
u := make([]ringElement, k)
|
||||
for i := range u {
|
||||
b := (*[encodingSize10]byte)(c[encodingSize10*i : encodingSize10*(i+1)])
|
||||
u[i] = ringDecodeAndDecompress10(b)
|
||||
}
|
||||
|
||||
b := (*[encodingSize4]byte)(c[encodingSize10*k:])
|
||||
v := ringDecodeAndDecompress4(b)
|
||||
|
||||
var mask nttElement // s⊺ ◦ NTT(u)
|
||||
for i := range dx.s {
|
||||
mask = polyAdd(mask, nttMul(dx.s[i], ntt(u[i])))
|
||||
}
|
||||
w := polySub(v, inverseNTT(mask))
|
||||
|
||||
return ringCompressAndEncode1(nil, w)
|
||||
}
|
355
mlkem/mlkem768_test.go
Normal file
355
mlkem/mlkem768_test.go
Normal file
@ -0,0 +1,355 @@
|
||||
// Copyright 2025 Sun Yimin. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.24
|
||||
|
||||
package mlkem
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// https://github.com/usnistgov/ACVP-Server/blob/master/gen-val/json-files/ML-KEM-keyGen-FIPS203/internalProjection.json
|
||||
var kenGen768InternalProjectionCases = []struct {
|
||||
tcId int
|
||||
seed string
|
||||
ek string
|
||||
dk string
|
||||
}{
|
||||
{
|
||||
26,
|
||||
"A2B4BCA315A6EA4600B4A316E09A2578AA1E8BCE919C8DF3A96C71C843F5B38BD6BF055CB7B375E3271ED131F1BA31F83FEF533A239878A71074578B891265D1",
|
||||
"5219C4CC17C35A828F3E21B2AB7496805C99EE041FCA0158A3314F07D053F364C887A6825958A625965D4885C2CB355E83A3C1BBB15446F891D2D24F145632CF06A5EE1A278CD3064A79AD53193853E4CEA654448A4297CEA3C9E87561629680F588953B858074292ED31C20DDD983E805D07BB9CFADD823C7900B604286C0184738CA04E0DA8289540E329605EFAA5960AAC0FD0760006C1F1993426CC7BEA22BCBB3CC02E099B828E82F94045DFACB1D9FB315582B20D1B41476FC43AC4680647259FE9B51371223446C82E0BBAEA132913E2B96EA11950C450F25854EE4FA4921193C8F1C66D61B8265C7072B046F0C532141D51D9919C80733C1BD3C5A6D77CCB3A1938C95C1E4E866D1D65C78297B3B32CA3C4143E6A215C609A36A1B13BAA17981D42B7FF4C715AC806DC491560032A5A2BB30E476A266C6E4A4A065D9698DB08132608136082689B1B648B49063C98324706A43876507FC690893900F8166E1D52ADCC44848D864B8BA0933B32DAA63435F11065915C5D5D879EDCC136FA8515B0260B9536C316120B4904921805521C0232DA126E2A9C5323976ABC73B5AB892E59B01A194B6446C1B73217FBBA855AC887AFA58A8F15A768EF968D775267E050150C7A8237C1024F9421C210D97907B2A144736E3B58E01C48947B1C62655E380256491CEBE400F52493D9033A29D6C9AE80B33E8C38584B30A31A37B15E85F5E82B73157408A5399A957190CBA905F1713C9ACA53AA32923CACB8269436A56BC02932189C7139D8463D0DC540621875E9A7DFEF020E7E83696C7612BC2A7DE7148D7075C31F257766301FA5A06E00582DCE15C6FB3195AF43078D79B110B5DC0789BE3A32132737FEB247DF8D2216F272C3D5BA700C52ED7E3A2795CCFE3072CD1D1B533939AC58A065A8A9FE85441ED291D43869E25307737A5155A095C5056A204326F944A9FC8F7035C931A61033CC2DB6ECEC08AAE0045A6542080C1A7BBD699902A2ECBE3A1F9AA95FC6222C6C6AB7BF96EDB3450E029B0CE104DBBFA0A49B8044EE1BB63B33BCFAA8A6A450194CC577D490A549B6C42D6816F444AAE8B8A4F62AFFD17664E957E2BA245A864BAB8D28E82CAB9FAC3BCD707AAC19A5EE58A3925DC7059BA1B9E7A798EC987E1924342C54E5D935A6699B6D9AA78E4738B0CEC6C57D8228C86881A14A3B57065BBE5653BD92B5BD5A9888B1B1E9B017ECA1A788CBC3A283A9F7B00D3F55B138CA26C33CD2CA3BA632A0735596162AA6C9D10968F53305D35CEC4395CA0489FF631A3EF661264A22ACB535DCC1313CD6917BFE3B5B8FC3B8016CA0DFB151623C92F95701DCC4140459B52EB796FDA60FB429651052D2C16B550FA035CC1374C87A439077713769C728B766BC75A609B70BBC14AF84A3C70519C3211ACAD58BF7C14C15F1AA86FCC1DF55580A2F9BBBC31B6B0EAAB379481CE9966F7FA6487C611BA5B3E8F8307FA35CD5248C8AB351B63ABC4BA005871A97751F01E5143302C757A65E411AF7B26F22076C7A1CF7E2B0055E80D7116CA2B3056BF8754BCFA9095D0CE99715CC4512F10125C5A500DABB7C11F5B0408377900621BE851B7A3602576650B84191749F30AC635A9E2212400769DE8E1915F26BA198AF8E53DACB598711738DA8C583A388E027A59",
|
||||
"E6F634F0A3771ED789D6842321E147B6010ADA7B6B0B105949F90AEBECCA062C494743AD3BE35A23C9BAA0E4CB83E65C9EB8BBC42433F0AC671ED9544A37C0CD704D1C24343ACA7BEBB538C7051186BC624A9A98F536874C3A15E145732A591ECE600C78028426BB8A7AF22757296EB968B5E3553721DB6BD507A5BE5742F45AA3E134383499400BDAC0C8607FAD647F41A2B547A631F971224C93570141C844662F96D9A3A32B6DB1C93F2A2B82E6B370B7D91EB9F9B8D551C8C2F3CEA6C2711379969467ABF7041848BB05E619A7B63CC2F9DAC97C05457911470EC7B4CD380528D695604B6F042394524C5C77415C3CA15FA64A9E16B240ED12CFF0A48AF72743916C469593B89D8510BFEC58A0532948D80D32A11FCE265ACBE6C21751507FD72366EB5EDD650344268757A715F27B28BEB4CF80347DCFCA34BB92A046955AA39590C2397A223ACB42B94B938329CB6A9C4253137531C54D2100966B9A8C96110A412AD2DC4480FAB04D05B93087AE8E4A1616526A48F38CAA920C6F495CA9E488776551630010C46C375DE52AA5EC23CCE9BCCE6663F1678B9F4325D1A961D551A02B046320F52272382DA8D565563A4CAC7419830B6C5F95629B3441727CCCB4892BA765B212221147076872361A0A31AA7C50403976042DA5486D287D143083646A90C6F1CA4037868E8478952829FD4C7E84187894F28CCD58170CF107FE74AF5A0CCFC849A71EEA4860080100310259FAA59C477C7002BD93385B8DA14E57891585253AE0CAA66BC3A33F052512788828916F0AC3C9C4FA6E31AC4088BC6A47F29386E467FEA414EDFA9194D30CE0770D3ACB1C1162312ACC64FF2793A2AC4E990726D1739E467A4BA8221169137AD1069EED5112EFF648F2353CCA4B4F8469CD29D05F2684236AA3AB3B019E6635AB53AC456D2C9D83152554655F8D6B4F75E23870677F492A2BBA53913B535A0B54113193B4122A5331585EDCC42C9361A08C173F73E4182F85B15DFC6F795269C88A19C4FB7D7D33AEA8144000827C57E73AFE87C6D9B646B1B1BE560672C858531D835BC3DA21B1407DB74A9D6B729F5BB6CA1AD086F3C2461D78A29A21238B0434594058BCDB125EE56F3B606D8C7A17CA5C3D6F876A3061BA5B65B97F033D3889AA74302D1EA268531354A707756EB60E621AC959E5AB5875790E6477D5C91A3C06593B976010F054AC6B4D54D452E5302E8E332CA6457CF2527DDFCC3B5462C7171105F9E24C8D299CA348CE9DB678E041A135893E16AC9CCB2BACCC202F7BF7B3DB1C8C5D567FE3E3C233024C75D369D7CC1093B2C2EC9094D020A8782ABFBFB89FF199517B0A4BB81C7455A64D9C07897877422D6ACCEEFA16EA242E0CEC8B5EF20C85E82E2DCAC3A3030B211A600B520B7D66B58AC317B0F65518F20EF26AB5B7D8AA729210A92B12FF115B43540509156CC247B4BCB34C313B3A38228D4BACB7E1E934FD40CB42322B6E618670E17A725CB37CB20210E000678393DE6A5D40786CBE019DAEF867F2A0B8F1827F48C0C04305357B82BAB80CC144A6997228A846D9CB49E32B865858A7601F55CB8127DA0BEA4437F017502AC8709E428309F6A252C69042C973BA104A5219C4CC17C35A828F3E21B2AB7496805C99EE041FCA0158A3314F07D053F364C887A6825958A625965D4885C2CB355E83A3C1BBB15446F891D2D24F145632CF06A5EE1A278CD3064A79AD53193853E4CEA654448A4297CEA3C9E87561629680F588953B858074292ED31C20DDD983E805D07BB9CFADD823C7900B604286C0184738CA04E0DA8289540E329605EFAA5960AAC0FD0760006C1F1993426CC7BEA22BCBB3CC02E099B828E82F94045DFACB1D9FB315582B20D1B41476FC43AC4680647259FE9B51371223446C82E0BBAEA132913E2B96EA11950C450F25854EE4FA4921193C8F1C66D61B8265C7072B046F0C532141D51D9919C80733C1BD3C5A6D77CCB3A1938C95C1E4E866D1D65C78297B3B32CA3C4143E6A215C609A36A1B13BAA17981D42B7FF4C715AC806DC491560032A5A2BB30E476A266C6E4A4A065D9698DB08132608136082689B1B648B49063C98324706A43876507FC690893900F8166E1D52ADCC44848D864B8BA0933B32DAA63435F11065915C5D5D879EDCC136FA8515B0260B9536C316120B4904921805521C0232DA126E2A9C5323976ABC73B5AB892E59B01A194B6446C1B73217FBBA855AC887AFA58A8F15A768EF968D775267E050150C7A8237C1024F9421C210D97907B2A144736E3B58E01C48947B1C62655E380256491CEBE400F52493D9033A29D6C9AE80B33E8C38584B30A31A37B15E85F5E82B73157408A5399A957190CBA905F1713C9ACA53AA32923CACB8269436A56BC02932189C7139D8463D0DC540621875E9A7DFEF020E7E83696C7612BC2A7DE7148D7075C31F257766301FA5A06E00582DCE15C6FB3195AF43078D79B110B5DC0789BE3A32132737FEB247DF8D2216F272C3D5BA700C52ED7E3A2795CCFE3072CD1D1B533939AC58A065A8A9FE85441ED291D43869E25307737A5155A095C5056A204326F944A9FC8F7035C931A61033CC2DB6ECEC08AAE0045A6542080C1A7BBD699902A2ECBE3A1F9AA95FC6222C6C6AB7BF96EDB3450E029B0CE104DBBFA0A49B8044EE1BB63B33BCFAA8A6A450194CC577D490A549B6C42D6816F444AAE8B8A4F62AFFD17664E957E2BA245A864BAB8D28E82CAB9FAC3BCD707AAC19A5EE58A3925DC7059BA1B9E7A798EC987E1924342C54E5D935A6699B6D9AA78E4738B0CEC6C57D8228C86881A14A3B57065BBE5653BD92B5BD5A9888B1B1E9B017ECA1A788CBC3A283A9F7B00D3F55B138CA26C33CD2CA3BA632A0735596162AA6C9D10968F53305D35CEC4395CA0489FF631A3EF661264A22ACB535DCC1313CD6917BFE3B5B8FC3B8016CA0DFB151623C92F95701DCC4140459B52EB796FDA60FB429651052D2C16B550FA035CC1374C87A439077713769C728B766BC75A609B70BBC14AF84A3C70519C3211ACAD58BF7C14C15F1AA86FCC1DF55580A2F9BBBC31B6B0EAAB379481CE9966F7FA6487C611BA5B3E8F8307FA35CD5248C8AB351B63ABC4BA005871A97751F01E5143302C757A65E411AF7B26F22076C7A1CF7E2B0055E80D7116CA2B3056BF8754BCFA9095D0CE99715CC4512F10125C5A500DABB7C11F5B0408377900621BE851B7A3602576650B84191749F30AC635A9E2212400769DE8E1915F26BA198AF8E53DACB598711738DA8C583A388E027A597CA0C2CBBF4FBF28DE8C479D4473C339D96B89C34A4E5FCBCF7728BDFB43B945D6BF055CB7B375E3271ED131F1BA31F83FEF533A239878A71074578B891265D1",
|
||||
},
|
||||
{
|
||||
27,
|
||||
"6DBB99AE6889AF01DA387D7D99BD4E91BACB11A6051B14AECD4C96F30CD9F9D9360557CADDFCF5FEE7C0DE6A363F095757588C35A3FD11C58677AB5E8797C2B8",
|
||||
"BC02284C2B36002A8E002311D6FA3ED17088D6157E76867ED2110B7E50A9F0380893253026D833BE84A75E745CB9291F4E513EB41C68053575FE27893159C353DA6FB2C87757476A269331BB52268F39362DE69968F410C8167FB7195B6DBC3280B9AA5E28CF60071D2DD54323897701591931B6CE4CA0B087EA160A5A067C53665EDA6019E243A86883344041E3639126A2016F4321E3F39507E55F97BA0EF5F447E707BDF62A7609922DBDFC283ADB3CB7B10A083746BDC3B077BC1CEE06CE666B027BCB6E743B974D495D2D0183ECA61369EA52DD4BCDC1A54A8A08B8286A984143559554CAB503CCA2095D5AE54782B2586A778D4D3B6631114D7F543F467076B0CA9157729871DB0BF80065B9824835143B556419AACB9D39BA836E07274D1920682592046C83A37B8795603410B360C1E6B8FAACA706F8C613F97A1A82AB0F28A6239866D834BE02680B542A84ED50B4E98586231657C97A2B3121433914A17C20928E6734B45A8622CCCE69C71D367923447264CC72C26FC4986C26882557B342229AFCF7A8A8B716FEDB2FD2060708F99B6A826CF69551D0A90B4E7B9EC96C0B01F02481804124EA56604585F2B6284C205BDB795906A5C53508BA0627611DA8656600CA36908287A00FB8228B26863570977FF958B315A867488CB142B51377199BBDC2403B3679E34CC476C8929059503CB26838958934AACD0D4B67F69807B70855538C25E246569AD400E4F276CEC425D1229A8485AC5AF650C35A2F1730876FF943A4F6AAF0918EF5B543717298D6AC2D0F08C431D5876D669E2A64A0C6658947FB682B476E2CA04DAA743188200C6F79BF9AD23D78364625CA84D73C70258183AF2CAEB483B2C1F5B24A59B57911149FFC7442B8540561433014582ED6A361210E69575555497498508B86522DF2AB3FCCF64B19A9B8C84B32B8F681F51B97965294CF400CD08643FE9551117940D12338B7E9AB47343036AAC3DA4001428629AE8C362B1977259483B4156E5EC510436158664831BABC05807883B4832D2819305AC8CAA1177115A914C789C864574974F22058F2AAA36A0A31F465B4C52F34C70C28E47D35A1255FD31511A419EA9450A3A2ABB6AB68A544CA3E58CD398129F3A275305AA76AB42643725D3AC97E20690750DA9D340739C8D00A7B710BDE654732AA7C95D3304D7445D5E16C1AE64F99EC98B886AA10B3324F61105718BE0CC25B3A4A3A41C1653C0A255001BD51724BC843A1C5DA4A1350C0A40AC5258B17D725652E6CB4B5606D3CE877FD010ACF776D8A5145ACA06EED684082368C48BBB0284B8F502569E3342AE08619649B700C343E74243DE0A18803DAA6A6D2CBFBDACBACE53A4A5C10F7E7BCD6294B388C982FD794F3377EA9414C4DE70643A82A2F7A7A1B145AF0B1394A4B9399083D0EA8A35AC2BBC5D45D3B06AEAE511DE342AF6674CFA962A1E126BEC7F1252F892CD565596B3099BF60B332D58929C7B1ABB9CCC6D315D36930CAB08527F2776F76992AB977F615CBF8C1773DF0941DA095920806D36AA0F0884256807FF10726C12128FC337B299206050626A18116FE29215DF3817F1BC9EDDBBE2CA26ECCE15A325A9E566345F32A64D868AEBE124F044B0610E9C45A440D855C8F5AAED9A5E09369935779F1B56B9E",
|
||||
"54DB18751A289F68B462D90388629B33088C2AD32A834380B9E7AAE7DB510DC26747A7C958ABACC04944C0715195420DCB58BB0EB30D9C933DF4994BF242B2FB2C723AEB926A7B3700A01F0A94A50DB845D234B64D790014CB912D887FEE572558EABB46E1C11F41BBD2615BA8F75F8D3CA6611991025A3393F5AA186B809C5BC04CC59A36057A0F91CC77825025C30F9229BACF75013A586C31A124187671F15C6AEAA9A802A065223850F683638D759D2DD6C14F9C7262E9CEBFD9585284528B686400358CEB3198238AA8F8469886228D59DAAC5F9AB6CD753F3C27BB61F06D4F66C9B64BAD6BE1B461F4940802991BF07A8E9144CFD9A854469163E62FD76528CDF9CDAF559A627040CEA414208744AC8754FD8B13060A7E314B15935B5965558B85585F3AD9C2D59B1137B8B191FC5506C23568F6868586C41C22BA0712BAA24757E4E5BAA4758DA57B6C925766149B768ECACBE7391F52773CC3F89C7929AEECDCA343077584458D3A57AE43304112CB903D7A762B23C46DDC2D26394E4F2B5FA1A2416B493F44D36278009D87303BA6AB340483A5E8962C03D486E5B77EC352ABF1B3C758424165C9C696F496202A71E36105C381B4B8AB924C9AB69A01639412152FDC59B28A612B66704CC64DAB003542C541008D77EB86A7B8F1201DD77BBCDCCB37100DD7343BFD87679EF4B9C62023C186AAC7D3C235CA642B594D806B65872ABA86603D5BAC3D71C5329A89A3AE7591D8354DB5B4C354F6B0AE603BE5373E12146F25493E73A7BAE75C952EC412FEF18DF2E77A210695EC7969FE564F204C9496497F1F0968ADBA11613749EFC524BEB3519295C4A05570DE6344D9632F8FF74482A612F5E7C0463B4D6895A44E964C87B930E57B7033A253980009A6712C382CA66487902341207E2331EBC6C904E6AA53A57724633626124574E4144609CF9D5B6727877FE6C53526EC6742D889CD8B045B22C4DED3637228BF3FBC1216C750C449BA5EB0645FD8A7B9F35E45DCBC4AF4C960C522DB339E16A7881F9A551894CC19565B9F329719B9A6CD81838EF2A8ED2308148601092A20C712C3B393896E47712FA42C2B197514821DB28524AAEA7DE87229BF62401F12B99C38C8C039A7D212A5E404866D7A8288A9B1BE63A0A6C980FF39C3BB2C6DAC7464E05B657AF585C6F0620E63A640146D2E9C3C12D05328F343BB409C7CCAAEE0000C7C8921C31C2DBBC3B374A51A1B135FCD2740081740B06C413A41A519F1CE18916DA0519D132943FDD392D5B855441126EB238AEC989CC2D663B9F575D790407A5265471CC32BC6993BCBBD063C4DF69C8ECAC96B8539BA9A3BC532955825EB7F3DEB4351385EF6C53AB81CAA7A92AD1FC839C7DB1065FB5F53B17DC5C0137ED1BA6D9BCC5D037D1B96909F98CB3F74B5F4CA1AA593C50E39A55D363641453F2A7A1481D4BE66FBA27DE5088783466D0CCC82A8625C91814D966281B977276715886313A83BCFD00659A295C62AC970A904C31F118E35A900E3CC711F9C8E5D73A970E13F574A3030188B2EF9203EE6A92FF7096E97998470B77446B293AACC15432FE0F207659844C9B29C87C751D4080656B2951116317B194CB686AABC02284C2B36002A8E002311D6FA3ED17088D6157E76867ED2110B7E50A9F0380893253026D833BE84A75E745CB9291F4E513EB41C68053575FE27893159C353DA6FB2C87757476A269331BB52268F39362DE69968F410C8167FB7195B6DBC3280B9AA5E28CF60071D2DD54323897701591931B6CE4CA0B087EA160A5A067C53665EDA6019E243A86883344041E3639126A2016F4321E3F39507E55F97BA0EF5F447E707BDF62A7609922DBDFC283ADB3CB7B10A083746BDC3B077BC1CEE06CE666B027BCB6E743B974D495D2D0183ECA61369EA52DD4BCDC1A54A8A08B8286A984143559554CAB503CCA2095D5AE54782B2586A778D4D3B6631114D7F543F467076B0CA9157729871DB0BF80065B9824835143B556419AACB9D39BA836E07274D1920682592046C83A37B8795603410B360C1E6B8FAACA706F8C613F97A1A82AB0F28A6239866D834BE02680B542A84ED50B4E98586231657C97A2B3121433914A17C20928E6734B45A8622CCCE69C71D367923447264CC72C26FC4986C26882557B342229AFCF7A8A8B716FEDB2FD2060708F99B6A826CF69551D0A90B4E7B9EC96C0B01F02481804124EA56604585F2B6284C205BDB795906A5C53508BA0627611DA8656600CA36908287A00FB8228B26863570977FF958B315A867488CB142B51377199BBDC2403B3679E34CC476C8929059503CB26838958934AACD0D4B67F69807B70855538C25E246569AD400E4F276CEC425D1229A8485AC5AF650C35A2F1730876FF943A4F6AAF0918EF5B543717298D6AC2D0F08C431D5876D669E2A64A0C6658947FB682B476E2CA04DAA743188200C6F79BF9AD23D78364625CA84D73C70258183AF2CAEB483B2C1F5B24A59B57911149FFC7442B8540561433014582ED6A361210E69575555497498508B86522DF2AB3FCCF64B19A9B8C84B32B8F681F51B97965294CF400CD08643FE9551117940D12338B7E9AB47343036AAC3DA4001428629AE8C362B1977259483B4156E5EC510436158664831BABC05807883B4832D2819305AC8CAA1177115A914C789C864574974F22058F2AAA36A0A31F465B4C52F34C70C28E47D35A1255FD31511A419EA9450A3A2ABB6AB68A544CA3E58CD398129F3A275305AA76AB42643725D3AC97E20690750DA9D340739C8D00A7B710BDE654732AA7C95D3304D7445D5E16C1AE64F99EC98B886AA10B3324F61105718BE0CC25B3A4A3A41C1653C0A255001BD51724BC843A1C5DA4A1350C0A40AC5258B17D725652E6CB4B5606D3CE877FD010ACF776D8A5145ACA06EED684082368C48BBB0284B8F502569E3342AE08619649B700C343E74243DE0A18803DAA6A6D2CBFBDACBACE53A4A5C10F7E7BCD6294B388C982FD794F3377EA9414C4DE70643A82A2F7A7A1B145AF0B1394A4B9399083D0EA8A35AC2BBC5D45D3B06AEAE511DE342AF6674CFA962A1E126BEC7F1252F892CD565596B3099BF60B332D58929C7B1ABB9CCC6D315D36930CAB08527F2776F76992AB977F615CBF8C1773DF0941DA095920806D36AA0F0884256807FF10726C12128FC337B299206050626A18116FE29215DF3817F1BC9EDDBBE2CA26ECCE15A325A9E566345F32A64D868AEBE124F044B0610E9C45A440D855C8F5AAED9A5E09369935779F1B56B9E9C9032984AE72B7D5E0732A29EC29D8BBC4252A31454185710D280C223A47899360557CADDFCF5FEE7C0DE6A363F095757588C35A3FD11C58677AB5E8797C2B8",
|
||||
},
|
||||
{
|
||||
28,
|
||||
"7725321C56F925868FF834F5D1EE90A70332AA9283434E122C60A8D474AC6C0F00F6EEC72778E02ACD04BB056113C571982E45018BEAC566EC59953724F38A4B",
|
||||
"EAD840B81B03BFE75805595DCF0808B83738AF14C758920F80E209D68B9192C5CF0DA397A0BC9A702295B8AC3826DA6F427C9281D937CBE4686F70713B39021CDCB96D71405D4CAFE4068CCDB64643E7540E571DAC0019D3F1235CA8161AE68592223E674C07AC76286C95BB17E78110317840064485D7B16DDB830C807BEC506CDA14C957DAB843781B977A439C612F52A944AB2B6E6A1C221B886097EC4259B0661E550B58376A56F7A62ACCB7A8B94CA02B1797B62497B88B0035623F26086D14122CBC9EB7486B0BC2A8BE25985B2019906977CE971D928347DA5756EBB65835764EEB6B52BA123E61BBC5123645346168597C1194C80ABB26C74EF6500AC6B180C190C28C9041AAACF5371C41373BEDC686BB73B583F46217F31F01B66DCCBC9BD6627DC03250B7E52C690261BE97B42FCCC63EB443952143F5734EF4D336C5311D0B2820A1AA715CBC1A106117BC7159FDF32FDA33C82653727466BB14ECB98FF06E2808CDEC540A2276B34FD633349367576AB50360C88992A675128400DCB07999A2B3978547735BF8A202EEFACE1960AA6649CC08582E92DC928F30BC0E3CA45EF8159F928842CA75A01A013B1A5CD55554274A6D2BC39A4796A129017E7A91A79CE22665940F5F711660ECC5101C230BF927146486AB6546C4E4BB3D8C7D877769B3BA7FE0162397DA4583D30B343862205CAA6D0CBE57000D6F9384D73C6ECB3AB773599B73FAA2F9258EF467BD6266273D1214C103399019751B240C128021F1E698110559B2C56FE32223CDD90D04B766CA425AF66458D8E66BB7029D147CA11E778B5323216C3081D0A6596A7AB5FE886E9C9ACEBA705A3B751F19165916C5855AE29D34D10FBCD68A60C38023243CB1C22D30261292E01D31300569777B099C77F5351FF77C2BA5C09F584CBB6CCB84F11AA264C310FDF253B271CD6450B85F040FF8262F2113141BA3B45E1550D6084BC84A50202B19D23A92CAB5B8C6838F49D99AADD6592B1842EA251F71F3A6707C55C3EC0A3A0314C9A4530F9AC4FBF83B9B73510229B136D5989990B71954BB3889CE54944E01039AC7A9B4EBEC47805A9C51298A7F867BEBDACA71D7AE2012AE2B855CD7C97BA0E14EDE7B8508935D3B0192743B3AE7D3628166AC251A012C59034CD30B8258A159432A62DA317E8A993DC07C8DB73E5B3478D208875D6AC9B64CB36D0B1979AB9D553843BF054CA687B316414E846CB5E305B68C00A8B1C903C7C0CCD03970317C6A1F9A8646B5CABF5112BE01B868402620883E46DAA256228A8092648BA61FF57805E0D03A06C46AD1411CA8E3A95FA73904D3246AF0C4AADA2C582906B54180E9569C86A76B5F88091EB9165F3528B92A8C0549B097FC2A3398A226B224EEEBBE3B3A96066A2C0F884A60FAAAF9E97122C89582395B192172F661B775E09C6662CCB64169BEEC4924E96AB257BA514617161B8F7B316CE0512090DC627D59C4F3A39EAC068554C075E29628383477E5C493150B04D1249D61E6A09E2B323BE503A6512BB119A262B8ADDFB43612654DDF685981063E14DB0DC025520BF20FA3BBCF81D779A98300A4E0A6B6516DA6442968C7BADC129B3D458A1ED8ADA5301E5C3FAF68F13D6DBFA29987FB14563E8C6BEE4EEC9B8AB5F504A8BC1A724E6005",
|
||||
"C397104AE63A279795F3243F6EAC3A74AA0B414C822A668664826003F7CEDC2667819773E4C3AF895502D22C3BC95A9887F84DE421197861964FC88E3299B16226250F701A1C1C97357884F2A20E8FBC08E84C3ED233B6B261BBD3973ABD6B1F5172C59AEC4DE0BB676417528B43A2688A831C0889AA96113640ABEF499B1AB7B67B355DA2B9A26E0CCAB9848CFDDAAB994B8E0FBB090F5C332E6CAB63D8ACD1D0B80DC68B755A2274FBC524346A93DCB5F27956CDC73B429B71410C7C75E4683440A1179851C77220354C998C47CC29EC4A87A2A44B3C69EBBBB572534B3C1B14F90041E6ECC4400041EB729E9487064E44CDFF33A352904421D8A2BBC34D1275A475C61160440DA4E2785F140B327BA35F247ED1D66EC8A05A44E4298DC72764877BD369B78A287CC7DC6B58132C43841E9B6924AAC38F6D4BC4D4FB2E32FB5E54E0963C54C8058522AF21B7FE435B5EE3801A0BBB21088DEF77B20A466A5EB8C8D3D71ABA4705C0D6C23476BBF9918B6271CC041217B41A0E0EE885EA0B5334F64A5BC0199F73675C0593A0369429818E0227B8A4556EF83AC492D8A572F126004C1E2CBABEF335312F3256A3E6B42B4150FFA21E183588664B465C5CBF14D9A8C58CB33D4955C80939351C1D8A959BBFB210730906C546C60D747AECF15DDF571769524553BCCFE6CA3422830CEBD61C5A3C541E20B8AB9C44061B4BE888A01F429C03128CCF2B2EE53555D42A3F77E04CEEE46B0BDB3A84B4CD3BBBCA9DACA71426666934095A862E94710B862C31985517A49A9C1B175E9C4A63B2C055B2548BCCFB14329B35EBA1CB302972073480E913AA1BA9399F63610220133E6ABD02E47740A56CCF16B620308261692CA0A56FD6554A59C8ABBCB26156F69034C30C2D1B89730627A8036818458D4DA70E4A954572F095BB64ACF346473481A67DAB2023539C3111B205E414A24483632C4C548B6BA9375D758C597C322DFD89288E4B676034B36CB695C571960232B94396B9E08924FDD882429A143E451855F65B3EA661B573878C083EEB20BD7F5A142E386DC8A45AFD000072B8544D74B7FA472FE03C0F36A310FC54C354B0A22F62145C5BAF1BAB5DEEC678AAB4B89F4A49012088F1307FE02421B7B2B53335871984678295C8423BA60F834BAA9642811902B91AA23344B85628C242F183AFCC27F0E18A9C683C9C7484BE82CF6E17C03DD5A558326C6D4974B28261DF45639FB15B18C9BB3F8B2CA0951C6DD2C3C6853DA8402CF1D625CE4C7D1EDC8BE31CC2C761B540F5121F739A4256A47E396C81419020C324DCB29AB577C7995850748A41D0176E7513A8FA9252F9730E44D2220A8BA3641CA4C9B5A2D193415288730D9434BD9AAD79D27B98F16217D52241D0606CF5424B27318346B954E805E0507C87A741F4FB1FDCE454DB18B845E90732724858AB02AF10B7150C3AA11C1FE4C6B836A0065FB724C1D77D1DE0BB2867B26925882B915D4928159CF421A59A4243E990C3C17E1AD792141CB3D2DBCEEA7648FB91A60D8A62C65A9B2C765F2C1582F10513485093519AAD55D2B08A18C6F29B38768859F5150CFA4537DA470B38645A4F8126BD696A6BF9715634B70F3B1DEAD840B81B03BFE75805595DCF0808B83738AF14C758920F80E209D68B9192C5CF0DA397A0BC9A702295B8AC3826DA6F427C9281D937CBE4686F70713B39021CDCB96D71405D4CAFE4068CCDB64643E7540E571DAC0019D3F1235CA8161AE68592223E674C07AC76286C95BB17E78110317840064485D7B16DDB830C807BEC506CDA14C957DAB843781B977A439C612F52A944AB2B6E6A1C221B886097EC4259B0661E550B58376A56F7A62ACCB7A8B94CA02B1797B62497B88B0035623F26086D14122CBC9EB7486B0BC2A8BE25985B2019906977CE971D928347DA5756EBB65835764EEB6B52BA123E61BBC5123645346168597C1194C80ABB26C74EF6500AC6B180C190C28C9041AAACF5371C41373BEDC686BB73B583F46217F31F01B66DCCBC9BD6627DC03250B7E52C690261BE97B42FCCC63EB443952143F5734EF4D336C5311D0B2820A1AA715CBC1A106117BC7159FDF32FDA33C82653727466BB14ECB98FF06E2808CDEC540A2276B34FD633349367576AB50360C88992A675128400DCB07999A2B3978547735BF8A202EEFACE1960AA6649CC08582E92DC928F30BC0E3CA45EF8159F928842CA75A01A013B1A5CD55554274A6D2BC39A4796A129017E7A91A79CE22665940F5F711660ECC5101C230BF927146486AB6546C4E4BB3D8C7D877769B3BA7FE0162397DA4583D30B343862205CAA6D0CBE57000D6F9384D73C6ECB3AB773599B73FAA2F9258EF467BD6266273D1214C103399019751B240C128021F1E698110559B2C56FE32223CDD90D04B766CA425AF66458D8E66BB7029D147CA11E778B5323216C3081D0A6596A7AB5FE886E9C9ACEBA705A3B751F19165916C5855AE29D34D10FBCD68A60C38023243CB1C22D30261292E01D31300569777B099C77F5351FF77C2BA5C09F584CBB6CCB84F11AA264C310FDF253B271CD6450B85F040FF8262F2113141BA3B45E1550D6084BC84A50202B19D23A92CAB5B8C6838F49D99AADD6592B1842EA251F71F3A6707C55C3EC0A3A0314C9A4530F9AC4FBF83B9B73510229B136D5989990B71954BB3889CE54944E01039AC7A9B4EBEC47805A9C51298A7F867BEBDACA71D7AE2012AE2B855CD7C97BA0E14EDE7B8508935D3B0192743B3AE7D3628166AC251A012C59034CD30B8258A159432A62DA317E8A993DC07C8DB73E5B3478D208875D6AC9B64CB36D0B1979AB9D553843BF054CA687B316414E846CB5E305B68C00A8B1C903C7C0CCD03970317C6A1F9A8646B5CABF5112BE01B868402620883E46DAA256228A8092648BA61FF57805E0D03A06C46AD1411CA8E3A95FA73904D3246AF0C4AADA2C582906B54180E9569C86A76B5F88091EB9165F3528B92A8C0549B097FC2A3398A226B224EEEBBE3B3A96066A2C0F884A60FAAAF9E97122C89582395B192172F661B775E09C6662CCB64169BEEC4924E96AB257BA514617161B8F7B316CE0512090DC627D59C4F3A39EAC068554C075E29628383477E5C493150B04D1249D61E6A09E2B323BE503A6512BB119A262B8ADDFB43612654DDF685981063E14DB0DC025520BF20FA3BBCF81D779A98300A4E0A6B6516DA6442968C7BADC129B3D458A1ED8ADA5301E5C3FAF68F13D6DBFA29987FB14563E8C6BEE4EEC9B8AB5F504A8BC1A724E600585E42177479AC364C343E26B4BDD480D14F1A7487FF4C64E37850C5D1B4EFC9600F6EEC72778E02ACD04BB056113C571982E45018BEAC566EC59953724F38A4B",
|
||||
},
|
||||
}
|
||||
|
||||
func TestKeyGen768ACVP(t *testing.T) {
|
||||
for i, tc := range kenGen768InternalProjectionCases {
|
||||
seed, _ := hex.DecodeString(tc.seed)
|
||||
ek, _ := hex.DecodeString(tc.ek)
|
||||
dk, _ := hex.DecodeString(tc.dk)
|
||||
|
||||
dk1, err := NewDecapsulationKeyFromSeed768(seed)
|
||||
if err != nil {
|
||||
t.Fatalf("case %d: NewDecapsulationKeyFromSeed768: %v", i, err)
|
||||
}
|
||||
if !bytes.Equal(dk1.Bytes(), dk) {
|
||||
t.Fatalf("case %d: decapsulation key mismatch", i)
|
||||
}
|
||||
ek1, err := NewEncapsulationKey768(ek)
|
||||
if err != nil {
|
||||
t.Fatalf("case %d: NewEncapsulationKey768: %v", i, err)
|
||||
}
|
||||
if !bytes.Equal(ek1.Bytes(), ek) {
|
||||
t.Fatalf("case %d: encapsulation key mismatch", i)
|
||||
}
|
||||
|
||||
dk2, err := NewDecapsulationKey768(dk)
|
||||
if err != nil {
|
||||
t.Fatalf("case %d: NewDecapsulationKey768: %v", i, err)
|
||||
}
|
||||
if !bytes.Equal(dk2.Bytes(), dk) {
|
||||
t.Fatalf("case %d: decapsulation key mismatch", i)
|
||||
}
|
||||
if !bytes.Equal(dk2.EncapsulationKey().Bytes(), ek) {
|
||||
t.Fatalf("case %d: encapsulation key mismatch", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mockRand implements io.Reader and returns the given bytes or error.
|
||||
type mockRand struct {
|
||||
data []byte
|
||||
err error
|
||||
}
|
||||
|
||||
func (m *mockRand) Read(p []byte) (int, error) {
|
||||
if m.err != nil {
|
||||
return 0, m.err
|
||||
}
|
||||
n := copy(p, m.data)
|
||||
m.data = m.data[n:]
|
||||
if n < len(p) {
|
||||
return n, io.EOF
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func TestGenerateKey768_Success(t *testing.T) {
|
||||
// Provide enough random bytes for d and z (64 bytes)
|
||||
randBytes := make([]byte, 64)
|
||||
for i := range randBytes {
|
||||
randBytes[i] = byte(i)
|
||||
}
|
||||
r := &mockRand{data: randBytes}
|
||||
key, err := GenerateKey768(r)
|
||||
if err != nil {
|
||||
t.Fatalf("expected success, got error: %v", err)
|
||||
}
|
||||
if key == nil {
|
||||
t.Fatal("expected non-nil key")
|
||||
}
|
||||
// Check that the key's seed matches the input
|
||||
seed := key.Seed()
|
||||
if !bytes.Equal(seed[:32], randBytes[:32]) || !bytes.Equal(seed[32:], randBytes[32:]) {
|
||||
t.Errorf("key.Seed() does not match input random bytes")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateKey768_ErrorOnD(t *testing.T) {
|
||||
// Simulate error when reading d
|
||||
r := &mockRand{err: errors.New("fail on d")}
|
||||
_, err := GenerateKey768(r)
|
||||
if err == nil || err.Error() != "fail on d" {
|
||||
t.Fatalf("expected error 'fail on d', got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateKey768_ErrorOnZ(t *testing.T) {
|
||||
// Simulate error when reading z (first read ok, second fails)
|
||||
r := &mockRand{data: make([]byte, 32), err: errors.New("fail on z")}
|
||||
// The first 32 bytes will be read for d, then error for z
|
||||
_, err := GenerateKey768(io.MultiReader(
|
||||
bytes.NewReader(r.data),
|
||||
&mockRand{err: r.err},
|
||||
))
|
||||
if err == nil || err.Error() != "fail on z" {
|
||||
t.Fatalf("expected error 'fail on z', got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewDecapsulationKey768_InvalidLength(t *testing.T) {
|
||||
// Too short
|
||||
short := make([]byte, DecapsulationKeySize768-1)
|
||||
_, err := NewDecapsulationKey768(short)
|
||||
if err == nil || err.Error() != "mlkem: invalid decapsulation key length" {
|
||||
t.Fatalf("expected invalid decapsulation key length error, got: %v", err)
|
||||
}
|
||||
// Too long
|
||||
long := make([]byte, DecapsulationKeySize768+1)
|
||||
_, err = NewDecapsulationKey768(long)
|
||||
if err == nil || err.Error() != "mlkem: invalid decapsulation key length" {
|
||||
t.Fatalf("expected invalid decapsulation key length error, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/usnistgov/ACVP-Server/blob/master/gen-val/json-files/ML-KEM-encapDecap-FIPS203/internalProjection.json
|
||||
var encap768InternalProjectionCases = []struct {
|
||||
tcId int
|
||||
ek string
|
||||
dk string
|
||||
c string
|
||||
k string
|
||||
m string
|
||||
}{
|
||||
{
|
||||
26,
|
||||
"F255CE47334283B8622BE7CE76D7354E3C4FE3F6C44F6BB25C9864EE0BAEB5765950D88F438263CE8B5A7A4C0FC4C95F10C477A7521F9BB458B8AA55D2E43BDC86B72F0930EE428B4C5A9C7116310F2AA5CB03AC1603C811959EA9012D69CBCE40B37CD890999CC74FF375C66F048B240363343CB795998856D560F4C712938C79466864D20B0BE95419C9EA6A8E7203A1986D10B606691242CEF630941B116458A41C83B7DC5B06A97C840B116F2CE9CFA87A1C1AA8C4FAC137DE8498E8749B3638404271539B247183A32E7E4413B6400E0F295788084EEA93B4A7653341005672D908C62B64B11B48414B505F3036EE56CC4DA88FEF27B2DA974C9DD38C150090B5B8A29BD7C5975A8A959549044B4DAED52A7FA68335308F40C9B768C5821F78CF068A694978964F597408D09759A19578624C64DC18EAB23082E599EC488DFE016E4BA58977E15B715C612496310219B9B4775CB51C5DF03B934F7473AA58A57C602CF17C5993D30F52D753AC56BACA1A994742BC50435E179A262B3C8EECE1513955C593E7508B945F6E95CC4268CBD45B2504082FB8B23D8906946A74AC2FB676BDBC39DF76B9B8450F49D283C622784565B76B96084DFC099EC2279E5BC13492561B4439E32324B0050C5FE6451974BF0D72750AC58BAC046D218AC397F65532ACC7800246ED1C8094FC807306BF88E2816AD13B06F2898CA87C486A124B618156A090B1058722ABAE389AB5612CA2C2766DDEF98202A6AB1097B392404EA151788528B07544325F851B4DEAA2495138F929BBB4026042B0A8CD3CB0A7D061927A717D4877E0D9A409D6B125361C99090AFDF922A776ACADA2B6A84522134B089D4B428020C83061A87816C6A59263E636B5B2ECBCA6A64E29600948D5B0B45600B8D473A65B450B766D0251B6915898BC3C1C2C53B9679121F1F06CFB9604DE0051FF4B093939C907AB18C2988646A90481BB99F4153611C138BE34BE163B3ABAC44354A774E9CB54FB29903367C78D275467499D22E83A11CA9B8445BE9DF3CB612069222A8715A495D115B4BC2457AB731AE7EC1BD8EC9722CA980958180AC2BD67898F4A72A675106D66981B2E923C0BA40E3234655D00B25D6462591C9C9C7A53491489D57A77B2510D08B95B9C61C1784BA752F4A73023742ECB985DFB37808B16D6C283CD4A06C5A3AC401855E1DABE63F9668BF7A661946B18230A1A5A7C19DA66ED08151E77A624F579D4E44ABE023A1CD33459FCC3F1A6589426634D062D0A75A387A0B7B8D802A66B2106E01264500915B97307C85ECF331BCAC35E4AA243C837876D858AFA8B510C342708B38093B2CD35D1BA68DA0544794D172C6CA8850A7F847B56998D8E0B0A17144FB6F443E3679767CA91B80A6CAA8BB0E22BBAC01C0EAE1604B8A243911672B3748C7F18C531E3783D522039130057198D6F0989E99641AB718DA123710BDB67B3B75EC66BA9CF459FE06C7C4F7959DD7281FF155940B09FB14AA55CD40B963CA3312C05B36A5207C989428C16E5D288ADB18A66F74617CA39DB8AA612D706DFEC884C457AECD1AAB598195B4AC971529FB7A883492235E62112064A0F6FF5BF4F1619A0D03B96B5112009966B2DF7C2F300B6F295DF7FA2C453E1949DF6405309DF7575C7656C245EDCA9F6",
|
||||
"B8E17544C0493C200F8B15C8973A25BE28AD58442B916C8074439E2D12CB2A4623065658C80017F8475419C9A7FADC988888ADE32B540AA77539C49F10B4A0FFE6A21271192A3908E0583DC8788301C31777D116B5759B5F189CFABA11CBD976067810BF939F91579440FA86FAC692D125811329701381B97175317ADC60BBC7585FC07F65A92B67978684C225B960439C147C06D11D0423896257BF8FC89E3FE8021AC3A6C81192B3F96DA3B250024541D92759BBF77AE36A1C9B1B1AB01B0B7F2B9917A579FC265D05D4360AC547B8D2AC68998181C1A5E3C4284B51B16E3BA69989B431C86BFC91C62DD804F2678EE6E71FD3CA84E9636CE728C0EC80B752807F09EB732B8C9CC2A15B84A303BE1C0087391C4D36A55F36BCB8347365E9CE33980380FB628FF0BC1A6A0FC19C89AAC71304473EBABA772EAA95EE37A28E6665D6345647F72EEAF429113096A8322B3F4BA18FE73C056A7DBE746512A022AFBC59B39422AED579A8C0C738F5BE2D22BBD467CF34CA75768200984739EBE97F31A87F620A3EE13B378739CB0C71AD2F44B20EAAA1A4C61B9CE88F1F84312EB50B34080D83074F16624A7AB7CA236787F7112A455A9DC0BCB8D6FC4D3E52AB9A2373A5338BACE0C528B62A4BEABC2562199BBC1BF98839ED771BEAA68262E8CC7AC51C9DE4615FD34DBEC61D653CA374C4524308C7987B7F772B16FEE02557F32ABB8C721992BEAD8A5DBB838183791B9AC61F507C1DC7C51DD505AC61622B0CB36F7F987B5AD75ED1922C2BC187EEA661DD12794DF5C460D7477669213E733E4D9553FE9850F1A9388CC582F137433D9CA52F074B5320C89B763C97F64D4B9B8F7772CA6D70ADB7D818FA47367B6A91A3418777FC0B67C30FCF4B9D550792E8DC5E4FA8304F317698E7A303B83195D6A49BA51B20FC8F1A549094D62ABF79AE05742686E35945A0AAF7881760B55279341D12599FDEF65B8B512690DC84B204507822754DEC900F30085BC872E258595EF525D141A71AE54F8AD19AFC893B1844761156A04646BCC57BC203D05DCBE015DBA9993A381525204AA9797F94406D9BA1AC96B600405459AD578A414542A598BF81698EA22BB88C6656B2DB7915298A083CBE7F309A5A517CBEDBB8FF9A53CFA4C5BDA3A9843807C0604C25F29C2A135A1BC015467206E2D4AE0B6422373C251E0C39E3276C7782B5CA1969CBD731AF6CCC058324C7830FF97946A89C5D75C8629D745C8BC8A0549A7993088CA0484139E012EACA09158B249488A2B8A07A57253D4AD30BA8A28B7BD3828214942D2B90DBEBC017688C366C2ED8189969334F81452EBD08A3A24A09813A2C98F3C9C2E23AAC4785ACE990E66866C4846892E9558D1121A993BDDBE0540D7791F7F0AE6A994E1C65014DA6C0EB7C4882BAC510B9637A637EF8FC1A42D6150FB437B681601F859FFAF9C0CB89A514098C91E53E13F1BEE032C819060B82692D4CFC60F27C8D746C3C879A1B1749C35AAA695EDA372B7A41272C9598D33064726867041B09C684F55A3118E64EBDC028ABB8C8D6CA6ACE566D2B2C7C15BA3EE301B867C84A7AB75C3C1434C3E551206911F5FA7A870C513A289768867EF120C308FB2DF255CE47334283B8622BE7CE76D7354E3C4FE3F6C44F6BB25C9864EE0BAEB5765950D88F438263CE8B5A7A4C0FC4C95F10C477A7521F9BB458B8AA55D2E43BDC86B72F0930EE428B4C5A9C7116310F2AA5CB03AC1603C811959EA9012D69CBCE40B37CD890999CC74FF375C66F048B240363343CB795998856D560F4C712938C79466864D20B0BE95419C9EA6A8E7203A1986D10B606691242CEF630941B116458A41C83B7DC5B06A97C840B116F2CE9CFA87A1C1AA8C4FAC137DE8498E8749B3638404271539B247183A32E7E4413B6400E0F295788084EEA93B4A7653341005672D908C62B64B11B48414B505F3036EE56CC4DA88FEF27B2DA974C9DD38C150090B5B8A29BD7C5975A8A959549044B4DAED52A7FA68335308F40C9B768C5821F78CF068A694978964F597408D09759A19578624C64DC18EAB23082E599EC488DFE016E4BA58977E15B715C612496310219B9B4775CB51C5DF03B934F7473AA58A57C602CF17C5993D30F52D753AC56BACA1A994742BC50435E179A262B3C8EECE1513955C593E7508B945F6E95CC4268CBD45B2504082FB8B23D8906946A74AC2FB676BDBC39DF76B9B8450F49D283C622784565B76B96084DFC099EC2279E5BC13492561B4439E32324B0050C5FE6451974BF0D72750AC58BAC046D218AC397F65532ACC7800246ED1C8094FC807306BF88E2816AD13B06F2898CA87C486A124B618156A090B1058722ABAE389AB5612CA2C2766DDEF98202A6AB1097B392404EA151788528B07544325F851B4DEAA2495138F929BBB4026042B0A8CD3CB0A7D061927A717D4877E0D9A409D6B125361C99090AFDF922A776ACADA2B6A84522134B089D4B428020C83061A87816C6A59263E636B5B2ECBCA6A64E29600948D5B0B45600B8D473A65B450B766D0251B6915898BC3C1C2C53B9679121F1F06CFB9604DE0051FF4B093939C907AB18C2988646A90481BB99F4153611C138BE34BE163B3ABAC44354A774E9CB54FB29903367C78D275467499D22E83A11CA9B8445BE9DF3CB612069222A8715A495D115B4BC2457AB731AE7EC1BD8EC9722CA980958180AC2BD67898F4A72A675106D66981B2E923C0BA40E3234655D00B25D6462591C9C9C7A53491489D57A77B2510D08B95B9C61C1784BA752F4A73023742ECB985DFB37808B16D6C283CD4A06C5A3AC401855E1DABE63F9668BF7A661946B18230A1A5A7C19DA66ED08151E77A624F579D4E44ABE023A1CD33459FCC3F1A6589426634D062D0A75A387A0B7B8D802A66B2106E01264500915B97307C85ECF331BCAC35E4AA243C837876D858AFA8B510C342708B38093B2CD35D1BA68DA0544794D172C6CA8850A7F847B56998D8E0B0A17144FB6F443E3679767CA91B80A6CAA8BB0E22BBAC01C0EAE1604B8A243911672B3748C7F18C531E3783D522039130057198D6F0989E99641AB718DA123710BDB67B3B75EC66BA9CF459FE06C7C4F7959DD7281FF155940B09FB14AA55CD40B963CA3312C05B36A5207C989428C16E5D288ADB18A66F74617CA39DB8AA612D706DFEC884C457AECD1AAB598195B4AC971529FB7A883492235E62112064A0F6FF5BF4F1619A0D03B96B5112009966B2DF7C2F300B6F295DF7FA2C453E1949DF6405309DF7575C7656C245EDCA9F6D63A7F9914381C8093835899CF0C93056F03C56A1B64382AB764A8DA2E4C50610624F2A4AF5E82AB4B0F15E6CAC2D552CAEF57F3B78AE4551260AC71B007279F",
|
||||
"4EE24D9E0858B36DC755A9389F4FDBF438DB8FBFDDD2E2A41FBFE7313693E87B2BD86A2A5C95286840A2E477F4AAC12F28319D892C30FE9A120A09713369A17D5EC459C7E5DCD402F9049BF6FF0F7D07A7F18D4C1E3E0429BF6D501EEDD33E114423A5C4692738096101EC79233F20C58A6EA7E855C4E608DA7C9EE086EEAFE296F3214BD0B9264AE18069342AB493BBEE267401FEDAE19D5F9224A11D911505CB3200C65F17C91F88FBE25621402C939F071C48D6BC6ACD207C8C215E2FF23AB5FAD94F2CE61003C99DE15195B36ADE08864043CAEA49D4EA1D550978C49455B06AFB4BA4F0C178D30F953D47F0258370FE8E686802085FDCB25598DE439CEEA186F848AE2E4ACF526E03755D0A89A941A08C5610C96DFB3F47C693E7E899E1DD38DFD9126F3D05751234ABB82D2BBA4D347823B97293AE2B58FD3C71D2216797DA1CA453D600C5A9A6B36CA23B9450894A894A42C40B38871F1E9E84B40A04112CC9A4B6E7B8DE59CAE5D8389687DBB1EA078F3CC93DC5D0788A671530D9FFDE5F2CB6A558AB38E038D59ED1EF1FEE381AFB6DE0A77E1333FC5B0FE3EA2DCDB84FB33795449AC6DC322F4E5E09B2A462D3750BA426C04271903CFE9A3F02221B69E474F24B7DB608492C01AAC3F2FA472A2469B6A8A949A67C567D139D6F40B00DF1AAC1E6456FFAA646E0DEBD79907905F28076F78ECB3DD1A6493A40F3D1F8D89C71AD15D22162264D0AA73581AF7A77EEA43B856370182348034810E60A902604B724E09EA4638AAB039982A64EF02C9C21259A381BFD3BF298EFE4285CB538F79BE01CCEE1A4A903A80132942AC6BCD4425BD197EF014E7DBEFFDFDD5AAD00DA2A5E8DE4FFF1E8E97F23F3F4BE38970AC09CB99D252CF2736059CFDE177EA6B36EA329B9DC541C3DCE61FAC504908857184C936C1A1C4AC0C8DDE9A66B4F3AAADEAB2DBEB2F2E6422A49A6B9C223DF25A34720717253DA6DCFC0A825553A1D2884E01A97060886FC30A1AD50E52C46F6F9B87274AD6369FCE4FDF3FF6A5D62D4AC82CBCECE902E4DE4214B71A2CA547C536380DCA26F63F2BE71B01EAC68F42AD1399D390404AA5539A5995254836FE6CF59C490B13CAC01C69E50CDC0EBA1C2F9978F4223AA38DA33639ABE933B40F6E2751515EFAC9896465041D3922A4B043897083F7CC6DAF1FD87B970BB6D1D5E48B599FE6CD2AFBA5FCE17E4BD4B0217E879FAE34FC227EC132D6F7141A48D14DED57729164A1D2B0BEF89A16244EE114AB4E108648B7E80A7DD502B0DBD0C38AF1D85AF6966BFB8E54237000A3F18C48EFEB93ED62B41A9B341361D0D7AE75D63A3A34DCEE329996AB0630553F38BC0DA148419162A31D386745C818E2691411A7927E49822AAE9EA918BF49D6809290B57C1BA5EC212F135AC0B8EE945C0510CFED4DB5A84B617BA1525E996486728E1DB87B6E99CC9A7EC4399B063D3943FE4EB1933E90365A4916CA8D67D064DF7D5B8DFC51E337247CAC3CFFAEDC5523276CDCB82B130D8E1C3FB6D7D69",
|
||||
"B2425299020BCF563B8EBE0512F0479941335A75A32B8D10BFF60E5548B64672",
|
||||
"5BD922AF345AB90F297D0A82EA39527A648E4977AB56242E2AC0ED9A2CC66F10",
|
||||
},
|
||||
{
|
||||
27,
|
||||
"8E8107F8F9701A9B6B01F05D964539605B87CAD36A2797604D3983D0603F7522650312A8707B64F1F4CB12D8886321BF7EA1CC28F3982554A3FFC664B706C76C429785EAC08D8954517315A418A5181A2D882C51623C9E3623545BBA8511C8BC0993880391BCEFF86A1A0717D09079A1C33C8E9C97BB520F273684B2AAC1D4D18A70D490AD0A6627F0537460C095364A42FA08A21AA6D24255F6B2660B1B64839846F6E030814CC58B188FD1D142D4DC3EC5319773817287BB82EE5479E0A1A498E1671D615162D8C5B38068B61643832300FDA1B41EABA31C5B9854A07B62D8B2C591898D92BEE3CC01710810EEF3288FEB3AD9FB58F8D39F76A128EFC764FE269345EC76613AB0A41A746496445FA705AEA7094A4542A8E59F83B380E0BC663247765C3B685B33C01CE7806C80B037D22053E6B155D516CCF2C010F97575527AC7A5C3D1AA659063AF2D0B0D915A1B57C75C707A179DA035A9E1CA3977B91B8330930C4DB5BB2501308747C0A709C34142A3627BCC2952FCA704D749E3723231672187DC1CF61C087A2384FE727BE3AA7BB00240E2395B979B0DFB942D38F3825E72132395348F7C6CBBB800C3C36F8D4818D584C19B124AC9A728F7714760625B5FE877C855BE65B01BBCE106A24A2F7208696E73A22A27522566AADD8A73A050914D362932902B8EC8429E5C15CB427965A87F190625B6452C32896F5776318B15CE2F3060B296A1BB72A4C36B5CFCC97B9668713F85575280C1085B20D8B35D993A27DBECB97DB218B3C297B2E60C8384B05DF2C7234C750669864A5BBF76B9902F00A05BD74429E57C1B24C6BC28B6BE2C9EA5C46213D92C4E29828DC1B10DA786106106C7689014009B1B1C022093AB7CECB44D4998B0838BBF912C81269051655691135B5CD45F84D715F3C7B56DA3314D8783BD0213C0C33038116042D116DCA41226974483C6A4B8A2A319690FC0B1BEDCA3B02925A01C13472AB9A565778D44242D3B1776FDFC15C4F18969623E01A453AFBC6F2C264CFEAA8AD14B39F96B55EEDA5CB8C391A31773CBAA77E8481B5E26ABC8D531430B0931F36BAF28B96FD646AFB71195D58BFA1686A7247F9A69A5D20C0516694E760451199A25A55457BD17674B4CBFC5AA201ED0CCE77172951170342B3091181DC22B7CA70213D1A38B9D757E87961A4CA7BC18E22F0626850A794E3C2A5D5B5001B194486CC0CC880467FCF3B55B3492648980C961333E6C516EC4298A7112EFE459E1E92E821C74D5896CDF229A798529EB5048088A4D9BB105E54C006A5C15A46923909272AFA9B6D5661F7AF16D15A698D213C51D771AD0B14BA641C762A292EC5A0372D63501B5BECBF24731E283DC4246E3652A5544BFE99A71D05974CC2B9DDCB34C0AD9A057BA0DF05C56B8854E01655BAF21C9A5079983D322525049E0811103A101BB5163538C6D27A477B4F956F1967F445A2201D990D304755EEA5482813089A3C4911031FB49B380D13FA2C8A9BA7B439B3B5102B832DC65387FA41B4E7959BCB790ABC51BC30608555A80C4984AF0B80CBD1829FAB6C7BAF870D7B76D55672456FC3AAE7A4FA466CF64B43482E53DFFD1862F32BE3718CE4D21C57B894A3193C3DC8A03A34AA37806B6A35925C365EB01B4835F4AE98AC69080870E7CC1",
|
||||
"70D81B5F999C92B7340CC167324C63876AC6F212803BEC7657661423D640BA4019D983C2E16803E72AA3D9A83E7EB79076A3A02C9263E55C052ECAC18AE7C97339CDA6BC1AB6261F533B25D831A4FDCB41CAC346F4B6666D6C2BEC0BB158448A374A84F0009550B39BAADA23E0C331A315505B28265719CEA80C8FC1803449346B7EE7A6D215BDA924AE81ABC7CD8666B521C5E76012B84754EF50738297AA0093A9CD4AA4391146B149BB9A90BBFFC1638CDAADCAE019B05A9017E82C9E39A0A8C2B72702AF10FC3C1222621D9B2AAF70302C1A603B704CE79992EB608A16373139D35782966ADBD71A1DD261D4D42CA8117F1AC66793A54C9263137A159C1320512FF19C5CCC855F8B2D6A106186A69B036878382B94D0510E34F01383126A5C3393D9015F36E4CD0CD1458F88744E03C7B3060BD5A3380296860C388769639F888A4FD1EB389F2214F90B68BAB87712493DB9980C92148281584DBD51094C99BE4DE54223F11D1C1AC6EC5139AE66344990CB22392440B556DD8901440545AF815C2DCA70078A6E320B4274E76C6B50073302AC67D348839037A1E1491A79517D6B902E532575475731FC2D3404552BAB025E037B5AB476E2E18B5CB0092B215D31998F9EA5361E9AA4A2CC5E99808BC0909BCD42485E725383824E31394C7BFAA8095C0D6D92973C30A1D4B8AE6BDB72AE28CA6FA132DE11C20ABB0BC6C311A1541BCE0C67F06B43F3607AE0447C6D59C2E2B0233AA037D74CA4BF8174D9EC833506A0F74A03766A4FB2A84957F7CAEDBA27AECA2FC347794CEAB2E482B61F8451F7888E0A94078BDB7D3A791452CA8AF76A86F6822D12A123799C0D02D7BC16D63DB5993A1CA88F29B9A33BD662790BBBADE71242319C75FA29891552FD0BB5E3636C254BB9913A678616CE72E6CB14F82D1449C65E3170EF29947F598A57C508847556940820BE751C538617546B9D25044214382F80A9768FB7A4519B34E3B1B417520B6FB60899E5086168B07246AADFA7C3D5505791BCBDFFB9B18DC3B86F3488D51A9D2BDC3326A0ADD86C2E4A7AABF67CB5FA77BC66482DC20106EB1B40FC3C6CEEE2B46347AC3373AA6490AF74957C75F18510D017F8CCBAEDC50E20F6A619436EEF562657BA42944A50D7BC446EEB1792A47A8BD13C0855BDAAA168AB93B877A8B9BCE30F2403CA80E9499A279E9DD67C8E0B3297C4A13EEA1757912F83D842974188F6122ECF754D8566BEAD96794B372EDE02C77EFAC0AD616B032269FE73ACB4C585DB91C29BF12A07B9BAB21770ED4423E03C09F348C2D9946479F835A183748FB09F630AAC93F22E7E56C7FD47328A0A125CB1B6B58A92BC3CC643685EC769203D4447FDCA7F3CD64FEC5B5636E8C5C2AB8E1C58B858431E7DC163A177A4ADA5C3EB7A45AF9558325A5068748E14B9CEFBEC4C4E751B0D6CB46D6CA1E38605732826299CB44DD1B275E540E82B427A0AB6909BBF583B67CF0A4CEDC168FE1345E7218E7027345DA80754758119630783299CE9E054AF3A42015C12F8B733BC508F45F4AD23260FA7B6C15BF638EFBA86BE2C91EB799D7DB45E80A004D2A3BA403C8FBE30713F8C59C990968B01AE16231B0DA74CBFC6788E8107F8F9701A9B6B01F05D964539605B87CAD36A2797604D3983D0603F7522650312A8707B64F1F4CB12D8886321BF7EA1CC28F3982554A3FFC664B706C76C429785EAC08D8954517315A418A5181A2D882C51623C9E3623545BBA8511C8BC0993880391BCEFF86A1A0717D09079A1C33C8E9C97BB520F273684B2AAC1D4D18A70D490AD0A6627F0537460C095364A42FA08A21AA6D24255F6B2660B1B64839846F6E030814CC58B188FD1D142D4DC3EC5319773817287BB82EE5479E0A1A498E1671D615162D8C5B38068B61643832300FDA1B41EABA31C5B9854A07B62D8B2C591898D92BEE3CC01710810EEF3288FEB3AD9FB58F8D39F76A128EFC764FE269345EC76613AB0A41A746496445FA705AEA7094A4542A8E59F83B380E0BC663247765C3B685B33C01CE7806C80B037D22053E6B155D516CCF2C010F97575527AC7A5C3D1AA659063AF2D0B0D915A1B57C75C707A179DA035A9E1CA3977B91B8330930C4DB5BB2501308747C0A709C34142A3627BCC2952FCA704D749E3723231672187DC1CF61C087A2384FE727BE3AA7BB00240E2395B979B0DFB942D38F3825E72132395348F7C6CBBB800C3C36F8D4818D584C19B124AC9A728F7714760625B5FE877C855BE65B01BBCE106A24A2F7208696E73A22A27522566AADD8A73A050914D362932902B8EC8429E5C15CB427965A87F190625B6452C32896F5776318B15CE2F3060B296A1BB72A4C36B5CFCC97B9668713F85575280C1085B20D8B35D993A27DBECB97DB218B3C297B2E60C8384B05DF2C7234C750669864A5BBF76B9902F00A05BD74429E57C1B24C6BC28B6BE2C9EA5C46213D92C4E29828DC1B10DA786106106C7689014009B1B1C022093AB7CECB44D4998B0838BBF912C81269051655691135B5CD45F84D715F3C7B56DA3314D8783BD0213C0C33038116042D116DCA41226974483C6A4B8A2A319690FC0B1BEDCA3B02925A01C13472AB9A565778D44242D3B1776FDFC15C4F18969623E01A453AFBC6F2C264CFEAA8AD14B39F96B55EEDA5CB8C391A31773CBAA77E8481B5E26ABC8D531430B0931F36BAF28B96FD646AFB71195D58BFA1686A7247F9A69A5D20C0516694E760451199A25A55457BD17674B4CBFC5AA201ED0CCE77172951170342B3091181DC22B7CA70213D1A38B9D757E87961A4CA7BC18E22F0626850A794E3C2A5D5B5001B194486CC0CC880467FCF3B55B3492648980C961333E6C516EC4298A7112EFE459E1E92E821C74D5896CDF229A798529EB5048088A4D9BB105E54C006A5C15A46923909272AFA9B6D5661F7AF16D15A698D213C51D771AD0B14BA641C762A292EC5A0372D63501B5BECBF24731E283DC4246E3652A5544BFE99A71D05974CC2B9DDCB34C0AD9A057BA0DF05C56B8854E01655BAF21C9A5079983D322525049E0811103A101BB5163538C6D27A477B4F956F1967F445A2201D990D304755EEA5482813089A3C4911031FB49B380D13FA2C8A9BA7B439B3B5102B832DC65387FA41B4E7959BCB790ABC51BC30608555A80C4984AF0B80CBD1829FAB6C7BAF870D7B76D55672456FC3AAE7A4FA466CF64B43482E53DFFD1862F32BE3718CE4D21C57B894A3193C3DC8A03A34AA37806B6A35925C365EB01B4835F4AE98AC69080870E7CC14BB77F9E61F9A7C46CE816743B511574AFA4B490BF2BF55221114A9D72B3A08273BECED57093AFA374BCDA7E84F949E12F1BD8E51F4FC3C51DE0A7B314BCC004",
|
||||
"C0B435307F5CBA65E17F2FF8B2D435874A6D44F618EC5FA2444FDDD281E5E19EF12ADBFF26371451A27E40210635659274BDAC8B6A3377DCCA959D19BB3EEFACDF814D131740F6B7EE6C97320E5E7901A55E3D274B5D5B9557274E566AAA2A8DBF9541BCA317AFF7EB383BC6B89A1A542885249A263B1F33DA8C1B2D034FB0B0E680085437733F4644B8E197C9BC25147E79080F1AFA644A507A2C0D2962B6E9A43C9DE42078AF346FB5CA30447AD74CF93A43846C1ABFABB56758C7233BD410823F88B29E6B492BEDBCF18AC3B8A6801E0C188E044E3353DD858D2E4D0D9AD90CFA137D4149C9C44176E7B2F7A38FBCDED715DE5526885ADA3717D265DE4768EC121C01997E4F9DCBE796D26D047145E24FB62EE5ED154A170624F22DBD89E01D1C7C156D4DFB2C6F6D6DFB7577F561C5D41D5E0AFB1B638B26DB8118C99AE5AC8D827AC7F5072B1EF56FB13EB070C01AFF1C92A97842C9580B7390B40D156017A85E15E7992611D980F5D6982DA0657AACAB159722AA9852833E82E7409328253E925A1E67F6925576C33AC518523AEA22283B8EB7F0C9D6BA161756DDA12052068B6016A4D553175E33D35147A12D0B058F2424B1F499DD18AC9C58EE1B037111ED00989D188871269F9C0A397A293C20BEE7BA7F09C8866152A1410482D3D7466AAAC16B73328FDA74DD670A815E1BEDAC97D90D0F6264C0CC7D10956E9D0E2640EEFD7357BA98B53EFC932B650E24FD7C43C9984545B117E1ABC15E25D72DCBCF4469596585CA642AAF1F14CE711B0360BBC5C8FA08CC092983213CD5CE94F7ECDFC438B360FC46591141B3E6DB212125306C86CD9896D251C404AEF8816DAD9A2762B4518AF3D73FE44C45CC2C85A2C695D5C7209BAA7F5B99B229C9D5B51E4C3DA8D98721951B60813CC011B6016B92CD1D835EE17FF6E4B1BA511016D5816791317BF85F410C9A753A2A31E5C60AAA85BDC0F7ABAB63114F47A3AD35D3FA4C7F3434C4D6F40DC8C5B7A328CCBC8CD7375A690A812C091B3523B0B4725B9EF932911A558470D43FCE3D74F41898C7E325FB244D1AF27803B06259C31049F45BD6AC5B4AA3266D008A56EA2F6952982CAACFB9D228560D366ADA3F30C51594B986676C014FCB09A6671003000B7613A4934CED2D5ED6FDB824CDD22333C7212FF28C03D6FEEA1B824004C0854C8AF138B6FF35CABD555894CF1052199280174BB3112762758E5C9FD235FB46F21A3DA88840B9DDD2C1A8E11B302369D7E8BE8A39246782B57DF531452F9DF9E02AF353E6860A740B983852DEE17DA7995D821F8B02935F2459FB2E0E75C86646972915849BD191C0EA731F4B21E68AA2377006CDFAC3DF9DF98E1F47B8757F2BD3AE409CD7BDF35E9813248E016D75615EFEAA2F4FFACE232AC496B6BD0F2A91641766BF3BD461EE9429A917FD49E44AEDD43E2FDFB9C20868D8B89AB288756152ABB563344A05C309B20A2EBA905D8C27518D1801F6B428109ED7922474019B44FC08E7B84E377E373174655B8F0338",
|
||||
"E8AF40EF16C053F4CE74A82AFD44AD3129FF72FB6CCE84A4C8F729B66133BCB7",
|
||||
"F3430DAE17CEDEF4BBACBDECDE7FEE0522D6A9AF90ED76B13B312E7A86E5310F",
|
||||
},
|
||||
{
|
||||
28,
|
||||
"62387A619993B5D9567CE83676994DC54C46D6E380A8944E0DC60DD6312460E698CFA6AEC0AB440C3A3D93F21F65A05B42933CA538108BE5235F8A69B505CC2ED84CC0606EEC5B1449BC5F12048074F05985429AFB6C9FBB7140C28019BF783CE9877749516CFC76969925A09451A277893CE3280AD7DACED8C66615E074D4716103CA5C10757027995F8F98ACD141AFDB4CB1531089525BAA01B906BA4ABD0D6C186ADC3B96691965A883034C53E50268BF8A6CD954115FF64D6C9630CEF8288E6395C2EA011CBB3170F79DFA0759F1D1CDC475059FFCC375DBA3AD9B064230833060C803182957F80EC9772DC235A58B16C38A365176F3147C5B524AA13E2296A36F2964C1638FD8F7570CC572D7D69E2B81985C580A9B8BBFF08A3FCC757FEE6040FDEC7852A32A05D51D8FF338C0730242CA6DB2A4BAEE99C29749A33E1396FC680B6A7589089477DCF44FEA18AA2C925900203200AD14585239F0727B4387530BF68F7E077E62A108581C8127FB1C5DBB5E04582E746894D2516995434D81380FFD374A0641776B218E38C978622A5BE4EC6072E38A1F0289B060C2DEC91E7F763702F17803A58F094250D2E1670C7B90F0778365E8BFEB2B3556B168FE55B854089E52E0A2B8D832DA57AE355091C876AE67B367CA866A1C3597AD4CCF4E5B2FCE0788593141D2C0CB6B3C9B80D3445F992EBFE98F26DA68D03669503A0EC696B430B2217ED9C4B6CB22BB3A91D6AA6C1A2A3F3615BF67C5B420EABE7159363F525E5AF9049D4C0C9ED197DD7B6F8B4C2F6604C8CEA75771A3AEEC0C0E8D1C8A6AE94FC8485206217CF785677E34C458795D6303403F7AA427763C5ADC4DFFC8C2FD422870B876FAAC6D334931F0D760ACF4092A0727F1935855B20698B5C8B2879576A25D9A9B93862079DC02CC30C731FDB7021C9631C43230A6FC6DDA1956F3EA01DCAA64354060CD4C67E1149915A423FCE3166272B2E3B71E3BB509AE978D88859B55E50D338B703E1B1D77D44212E00D510695974A07B8250053B7129889769B4991B5083E05D0054FC4CEA18C0A4291298578BD53B11D174C6FAEBB6E5919B2E7BB7A4CA9C94E45ACC1674D5D994D2AF81CAAC6A153334A1B770937F14DC2696721665F87751B608C921B985215F40EB28BA632533119618A97D0766FD7807318571EF8305175724E54CA261A03B8243B7D1087F70A39A7FCBB0B223CBD11AEFEA9BBA4833FBED98ED48120B3CB507C2C272E7A6EE6C92EE5401B65345182C31901F1C0A82743C2512A392C3B6BB73FADD89131FBB65610C9407C62860B7EF894CD353C02E347424185C27A06209914444FBA9C751CC27D50527531B282A6C503594571CA89759C345632AD2AC24DAE862EE091C4F421194ACCC9F45792B69C12215B878A4ACE975B295C672288472A2B5CB3865C787F7A3DB60608E648A11E6BBCA38456F93CB4CE2C31FF1B660A096832E518B6B7032C20ADB3830E982430EFE661C3E50802487CEEDB0FD8A004A7263483F1B41227B96C207EB1B2131082CD85244310AB6D09D4A73D436BF3E8A275ABBEAD804968F9A5ADF2264F897463D71FB09A797EA500B671C0062C04B911606293B8C7BA6186C2A2DDF074C2A6F36D35796EF0FF1CF8E47273048F82A8F00AA9040D87CB0586D968",
|
||||
"47D60DEDCB1A694A5F55A066C4E61A4305346BFA8F03BA2FC7E01456471A9C1C02B2F471A3DB9D10056FC048652C545621000DB032386D2ACDFD81119F781CA0D14DCFA78C700B700BBCC55D3A3951BB82FC662F1B26C9A4F360EE266CA49585E696625D9787CEEA807E8506B4A38302969298BCB15A4219460C653A965370D14CD7874E711791CE719880F4A61E086A560457B1B002A9B739292A4459CB415F76A4597C2325599BCF18CB44E7CF3F53091054CD3024543494ADE226BE9D4541930AB14CB82268863B9B569EA528BAF3601FAB2831F1C29B4C4A712699B144CCBC63C90FB1E1779046CBA85AB61E23A97E57477FD84F022B20839B2F967B761CF3916BCB2D088850BFE2BD3CC40DFC5170CD7086F1D61380F338EFA2BEF1950315635BAB527745790495692664D1A55B3912DCF0AC797291F98249EE91660FDC8A67407F47C3B39B0857F1E1A2C0082D3716C0F7D0AD35229A795A3EE41A130BE53BE1173A94D3BC712B9F4CD86D5594A2C87A25642311ED45230B1839DB7050B8CC7D2DE99D90E32D5C2C9DE82BC56FA850886C6B549CA86E480E3373092B5ACB628C497DE3A789167DE055740B9C3960A52E1C54A99CB5B4221B7B1B90BA04E0949B39735F8956C30748C0CA7D6641CA97B87C30E7BF57E02166175E411A046645CF4B1C63D7C383A46A957A74593BA694E2446462231FACCA0BFA3B19AA469022C89B48D436BF4C4411549115D44857B27718754A2E7A025A693C858A594D52AE839465188693D8D7A449F3747CA88B0429795331AC53B565A0BC44B13B7D73FAC5AF606BBBEB73BDA8429136C3EB77928A3879507A6212216E6060095E2294F2C6B708883877D73970D306072B411ACA1A51EC1B64DA86F71098C46C4C2908C9AAB11B4D5BAFF7B205F1A1772454450F2A84723B87BB4A6B7CD5B07300A2EFF9A2A4BABE32320B7D268EBCCA1C42BBCEB9964950B71F507A2070F73BEFE482F4BB4750D2C6868AB1A42C6BD731A85EC036329B122E937B2786961B76060AA0961971C90887B468A23A3CE8C21E2AC2B6C6613F0539AB48946E6920211894CE970E9F671FC3105BFC7A7655A667E5A6775EA970BDD37D289489090A292E8CBB72D78A86F697752CAF79AB6840684356CB2E5D632C64B986A4174B05CC3DAED01F4CD286413CA8486AC310C61797815797433C38CA6352504237486C11CB383AC3C1A957586EF69BCF52A091F10884A515474BC423C11630446E1F7B98D7906FC4295F00473094A01B325A246875A90704B44349A460F6663BD6BE2B954CEA2794DC802AB6160400634726D07B40157A63DBAAC7EC5D371502E51C0A99461B8FD23FE6492684E76466C661C886BDCC16ABACB56E1DE361E6F4864BE32EC3B58558444C612B91351A7AAB3C415D475CF2A86EDAA91BB9B5B7FF8184824B2D9D36509E00348366483B0080883786F2353CDF459100D9AA21B279189C4652F24071C9BBAA5A697B03756EA3AB084407E41CCD2B66B044D83070D49AFD0716FC79AA0820BAD5CCCF26379DF4432E87C4A8C5B85F181222333BC7D7E5CE35252CE42CB518BBBFF00BA03959989370974388B7F0B64D6697B631145E9C5036D8174362387A619993B5D9567CE83676994DC54C46D6E380A8944E0DC60DD6312460E698CFA6AEC0AB440C3A3D93F21F65A05B42933CA538108BE5235F8A69B505CC2ED84CC0606EEC5B1449BC5F12048074F05985429AFB6C9FBB7140C28019BF783CE9877749516CFC76969925A09451A277893CE3280AD7DACED8C66615E074D4716103CA5C10757027995F8F98ACD141AFDB4CB1531089525BAA01B906BA4ABD0D6C186ADC3B96691965A883034C53E50268BF8A6CD954115FF64D6C9630CEF8288E6395C2EA011CBB3170F79DFA0759F1D1CDC475059FFCC375DBA3AD9B064230833060C803182957F80EC9772DC235A58B16C38A365176F3147C5B524AA13E2296A36F2964C1638FD8F7570CC572D7D69E2B81985C580A9B8BBFF08A3FCC757FEE6040FDEC7852A32A05D51D8FF338C0730242CA6DB2A4BAEE99C29749A33E1396FC680B6A7589089477DCF44FEA18AA2C925900203200AD14585239F0727B4387530BF68F7E077E62A108581C8127FB1C5DBB5E04582E746894D2516995434D81380FFD374A0641776B218E38C978622A5BE4EC6072E38A1F0289B060C2DEC91E7F763702F17803A58F094250D2E1670C7B90F0778365E8BFEB2B3556B168FE55B854089E52E0A2B8D832DA57AE355091C876AE67B367CA866A1C3597AD4CCF4E5B2FCE0788593141D2C0CB6B3C9B80D3445F992EBFE98F26DA68D03669503A0EC696B430B2217ED9C4B6CB22BB3A91D6AA6C1A2A3F3615BF67C5B420EABE7159363F525E5AF9049D4C0C9ED197DD7B6F8B4C2F6604C8CEA75771A3AEEC0C0E8D1C8A6AE94FC8485206217CF785677E34C458795D6303403F7AA427763C5ADC4DFFC8C2FD422870B876FAAC6D334931F0D760ACF4092A0727F1935855B20698B5C8B2879576A25D9A9B93862079DC02CC30C731FDB7021C9631C43230A6FC6DDA1956F3EA01DCAA64354060CD4C67E1149915A423FCE3166272B2E3B71E3BB509AE978D88859B55E50D338B703E1B1D77D44212E00D510695974A07B8250053B7129889769B4991B5083E05D0054FC4CEA18C0A4291298578BD53B11D174C6FAEBB6E5919B2E7BB7A4CA9C94E45ACC1674D5D994D2AF81CAAC6A153334A1B770937F14DC2696721665F87751B608C921B985215F40EB28BA632533119618A97D0766FD7807318571EF8305175724E54CA261A03B8243B7D1087F70A39A7FCBB0B223CBD11AEFEA9BBA4833FBED98ED48120B3CB507C2C272E7A6EE6C92EE5401B65345182C31901F1C0A82743C2512A392C3B6BB73FADD89131FBB65610C9407C62860B7EF894CD353C02E347424185C27A06209914444FBA9C751CC27D50527531B282A6C503594571CA89759C345632AD2AC24DAE862EE091C4F421194ACCC9F45792B69C12215B878A4ACE975B295C672288472A2B5CB3865C787F7A3DB60608E648A11E6BBCA38456F93CB4CE2C31FF1B660A096832E518B6B7032C20ADB3830E982430EFE661C3E50802487CEEDB0FD8A004A7263483F1B41227B96C207EB1B2131082CD85244310AB6D09D4A73D436BF3E8A275ABBEAD804968F9A5ADF2264F897463D71FB09A797EA500B671C0062C04B911606293B8C7BA6186C2A2DDF074C2A6F36D35796EF0FF1CF8E47273048F82A8F00AA9040D87CB0586D96885B34A8FF209DDD6CAF616A2883C143BFDF14DB231E98CB119C2656D1175BD0FE1A8F78CBF6F01A3878C8B0C421B83005D834A668E52F982855D5C943A1D93EE",
|
||||
"FD8CF594954FE5FC75D774B4390EC1678B676770C602B7C128070BD331D260AB21D1F99C726729B6FBF8D699EA133B1665F63DA83F737E938A41B865339D10ECD26940BE601870478E0D9E2FC2BA385BCCC0A786318D9600B5E8F269DEEAFCFCF61D5138FD905ACCB595D239F7643263DF754C55FECAB8F07DA82DFBF590EB6E175F6283879BF589B052B9CA2130B7025C47931A8AFDEF26B3843F6D2C701A7C3075EAF545D07E6280F261CE1EE3EB967F889651430C89693B6853F8B9FC32D758C6947ED409BA4FC00238E490059995A81F7013133C6BF4D508D30E3CEA08C0D84ADC2C1A465FF538405201B31CEEA71CD1568B98B17F4856571150674745C5858D770EA4D91E40148DD056C0D8C938B380FACCCB2743BB2D728C11F665717CA0C271316496331F8A2583FB1C2B3E53D668C3F485993F14DDF234B7AEFDC95FAFC99CAF0F44845E5D7F727B70036F5909C54B56B3CD842C89907408E600C14C7C00AC09540AEE9D25619CABBC3178184F2E9CDF0A3892FFDAA75C7EEB4F28CC9EA0AA8A1F63E4A9F9373075214C7B51D606B79F12E95D7645CD2D0158DF5D70C409FCB01ABDAD1FE33ADA0065F3DE67D49BFE9919C74B8941953B2864AC797A2CC5B2FD887B1C0C9FF1C9203D230EDB5A59DEF96F8BE673D1955422C7C16FB7EADB3DB33748D0413E94A5F85D9A020733629F93574D8687D78AA1D97A10D9B1392166B1E0D0B6F235CB8EB8A5CA56981511B2805D7728589F75E5065E40B911CC7253B67012B6370222BC1EEA263424C307F3F4BDE39EFF597F31787164545EBD1387BF88A717F1B5194947A5CA44BDE7A176D50D1EA7E372D95737606743A714E64CF4C1ABF8A2DF7BDC9A15A8925C502E2DEAC0CB2CF127E25DD002D4D36785A3042E8712943CF3E9441DAFF33855A8F2E1DBAFB723FC789A174ACAA808E574020B252C3E99B0B170FDF0C68AD6039D593B3B3B96E408AF85E7CBE60B275F4C0E3E1C0E793DCBEEE8B8A8BD3BAB92B263C0F6AD2971F462537ED9ABC092CE6FE617B33BF731EDD9DF66D6E626E5F173CBE0B246B3A0D977B28CAB98B5EE4857C7E620525F51D8F6A83668768CFD68E5B8EC2E0A1A17B4BA5792CBFCFECF0962DCFEE00E220B438CD75F672B2BE7E17EA85D4070E12D2EA716D9710E52F9025324BAE8A76DA34DBF531629411CACDD7D5CC982FBF2BD6D5D481CE758A431C6908092B77750DDE6859F1E09620B535857B082E72416F39B7169D57C1151593976F5782609B5CF4BDA74D9C8654E3AA8C420540ADC732593AAAAAFFDDCE25CD9B554B9EA31900A93E06C5CC761F592074425083A4C7746D05B138E234DF6AB7FE0B24A900E03DE7AC166DBEF702E5920D023DC828655609C9CC0EFA2297BB26C439889B099B3C7642323719F6B28E8C7E8D92FC92B69772ABBE5DCC47EF31C37BFCA8EED7BDEF7941A986576001009DBEA7213A096D1A51A3F27DDEB653160837914AF4F960009E541ABD0A669DCC54FD6261D4D3F3371E8BB3B59C8E38EF4EE",
|
||||
"D5722BD3F338D3A4AAACBDE95E2768BFDCA819F719BADD1C8FAACF859FE65EA0",
|
||||
"DEAE13A40F060C5A154826D5FDAC7C271E2A7C8BD3FCC211027F4B7C2E67C0FC",
|
||||
},
|
||||
{
|
||||
29,
|
||||
"C17292BC117476F81C319CC2523875F5309794D2B7AA85AC7AFC08AED5B283F5A16A7274F80A484D9292D440B4DD4537C0E37040835ABA5562314069E5262E8218C191686459E80201379760D55054F11D53647135A5A62972C7EC5C9A426A8D8FD9C712B4B510A670CF54A1CE3127EAB80A3F8BB0AA228E5C22A3794767CC040DF13764CB6953FEA762269BC8D5D169619C80E0160D990A3BB41297086110050145D8EA48BF503C4C6414BE732B2BA83F583B3EDE75C486D56949A2AEBC82459526BBA71525301C178B2B0FB5A7C2CAC480473280D50BCBDDA21C876B3A6B99BD32C27A1A081E36BA72DEC599FA976DA3180DEC4A8B134196E5E01122A266CFD79AABBA26F18336DF74593E296CDC0A770EB80F08D3290607AE95867D1FA5A05E4521910304D20320145219F3737AEEA8C5A94A63AADC06ECE1AAD714C25C244360DC49FD79847FFB2D0BA20DE374A1B5F54DA9B3A0EF5824E339BC58B552FDDC72045B1FD8FBA920874DB50961C3D4BF0D1A1212EC58C9720DA1FCCF3D7711EB4A5C205744B3AC0AD571AC8D9C345ABC571E65112686361402393FEA6712DC323D88132699738B89287388388A149638993629F8B59AE623ABC37FABC385D36CADBD6C6F54B97310A06BB5323C42A66F973237A626AFCE620DCB88967BE7C8BAC479D6C1887201BB44E1A75AC351754135A81C799F26358B9C7948B564D6C88DCC075EEE7A256EC49861CB2E8F28422E362F4D6ACE1E94AA6CAA1E15DAC4D6F0683B156A71807CEE810915F4ADF68736387C7089B24355D21465A7BB71B3CCC5989C54C9B7C5B2823B496A2FD23A7A994A7788B91FA14D05306D86125F33F342A11AC53CC8838859CC0740B6CDDB9B2E53C4A2D13391967A5E3197998494699AC84028B751399ACE998E26B818B94CBEF78AC97170990431BA7BA22B8891CDCBF62413D585AD6488CCDA194DF89222699BC77A71B43A80A95336F978967116B7059153CF344B02B0CFD78BAE7547849DD106A3170A99FBCE07067D06354A0E86C6D106A2F513A839660CA2942A51D9A463027EC2E5B574B795D59BC3BFA406B6A99BED62A63B37B27C5B40C45871C5CB503D062E255C48D2835FDF89467250CCC4EAA32DEC2B05C04E555C5FBCE3CDC6C855E6545062B4C8D4599D83717F03124727E45B5383BD3AF08144E7BADF062F1F2009336078A7A62CF2706642B2BDA323C43495CD8C067D8914640CB8660759970F665F8E282C9CAC647D709AD600AB8B67C9DE7A36A1482C2A94AA1E214CEE1A68566649CA5B8553A6404934219BF1C07657C82F48C3BDB00BC0B394327C75102BC10B5756AD404930CA4DC8ABA2486875AFA58BD81B83F08B9FEDF802626518B9441C0049A98CB0C8E5F132A0738ACBF323B3577EC906940871947F856C591047C1C66883F040A6995117B8AB51E5B88207A84E3C7239266B13790C561876C99C64DA8B9465627C59FB1F740951C906B540B592BD6467E16324594974E6933C6E509708B56D41766D4A59597BCB5AB902B86CA3B4F8AC29DD4CA359A8C3CC70563B0CAB3E559C3F1507F54C2FA61A383D217071C4C704514150AACBD9B02000A48DE2605AFC8A142B49B95CCA44A9CEDE035327B2BC1B770BC0C3EE6DBD74FC9D3948A46E4429FF6D3B5CC6A018",
|
||||
"28618473E6A45C1040379B1842365919C38BC8C99DD01287415A0B9D953DF81C49041609E1FB5743A7B9343B0BC83AA84D110549C97C009D17591808B99A5EC9FB9BAF1C35579BA4A7885BF99325C31182B68B69DE0B53646A1BBD642C02E11E454B5D9D738D65EA6808C2CDA62C45C7007ADD85B71F429B288A02B0BC7BD9A37FF1514872377DF280989B0111F8A0919059B233CAAD62AC17EB74AADFE27A0A9BCA4549AC8FA442DE966AD3D14CE3D6B8318CB427C73801818441AA732B166795225AA6C41C9FA42FCE7B5F3BC67102A828E3B39AFA3AA685849A96D8CA4FAC010BB2914F43A45DE731BD86C2C2C6ADDB511D6E8A8B36B183A7C63969F70A57CA461BF62F42A4322201BA64F8894A3276227836D97B14E2A80D380B418628CB2CB6A6E17647D97AA023874263ACC546F14429D7B6DDB41E96A19AD5B3011AD8C442536B4972A1BD1B428B828016B842A7D90DF1D73106E1C8ED01627C6B02BC362D796870973B96850A709E48967910C4FAD9C7CBBC547E339FD144AA6878B130B8A1D9035959BCA8906278975875627799B342C2FEA83B04D322F4004F0F9ACD5900449DAB8514B7719D3537CA86AC0E77B19737B0B10540B43266A33742897B8B0EF473F1A4C63BD18EEBF45C064921F87218DA36C7D7C27DF489386408C0735C3AAE980571B02D760B0A0D486E9685164E9599A382912FDA21990CC23342283BFB87D168BFBB4ABF42AA762A477F08758D871B8C819A08DC1A3125D188CD8681FB08B45248615C2973A47B155E13375917484DF1B548889508B0CC633CBA71D6BC842097C937441EEB3104C50BD4945DF723720784A7222CAC29CC302B66C7987C8BDA037FD3A75F67F8AAE2318C71E14F9868CDD49833A9520B440607431C562E4B23E7215B043B62EF51655272935FF61BE6393A13ECAB8307ADB2A58531361D4EAC2F58C8A64E089EDD5B5035C45FAE557E3945089EE8B330579BEF2169C2E3C596E08DB3C97463CA4D0D553829066DE23AB97ECB2D242B13222CAF60C3C7C437B85B289B415086DB4711208B5E48D77155D667B0109821A0932AF950D48A7ED8961D7388252CB21C0AA8260DB8A9A1E0277382206DE1C0BB933526C254498778EE14694D01307695030EF17DFBE6287E35613BC301F946924C7C349B7BC62F3407A0804579D461A3CA7D6F318FC7687755966968D73275B79F5874AC3EF936786272449A2FD6E7B8000A58BDC2388803C7EE94A0138B1D51B313EE3503C19A675AD25C8A4081C98A1B3A9201D0A3C9767921491BB703E5097FF04E2B749AD7CA37682C68EDB769AB7C76F6F623659549567563E0244C3ADBBB9706774C225CFF4832C962CE58E09DF6673F8E88A848B270A7892B1C447F28044CB3C231F1692E76549069D6762257048AEA42AC37B0EA930DED6534C6FAC43D80754BF067DDC717D7D541FBDA2F0CB67A97DC2E1D6B6FE79CA738B57029AC54E1EC95CE832F0FE12B6AB2B6BDF6287FEBAE32667DB2669B94F74D5031082C54CB1E6AA60314453514067A6B8D43BBA41B8B1CF1C6686636A5DD47B35302660FFC95EE00085AF31C15DA091922AEEA66A30873C511C45CA3804079269E9690591F2436C17292BC117476F81C319CC2523875F5309794D2B7AA85AC7AFC08AED5B283F5A16A7274F80A484D9292D440B4DD4537C0E37040835ABA5562314069E5262E8218C191686459E80201379760D55054F11D53647135A5A62972C7EC5C9A426A8D8FD9C712B4B510A670CF54A1CE3127EAB80A3F8BB0AA228E5C22A3794767CC040DF13764CB6953FEA762269BC8D5D169619C80E0160D990A3BB41297086110050145D8EA48BF503C4C6414BE732B2BA83F583B3EDE75C486D56949A2AEBC82459526BBA71525301C178B2B0FB5A7C2CAC480473280D50BCBDDA21C876B3A6B99BD32C27A1A081E36BA72DEC599FA976DA3180DEC4A8B134196E5E01122A266CFD79AABBA26F18336DF74593E296CDC0A770EB80F08D3290607AE95867D1FA5A05E4521910304D20320145219F3737AEEA8C5A94A63AADC06ECE1AAD714C25C244360DC49FD79847FFB2D0BA20DE374A1B5F54DA9B3A0EF5824E339BC58B552FDDC72045B1FD8FBA920874DB50961C3D4BF0D1A1212EC58C9720DA1FCCF3D7711EB4A5C205744B3AC0AD571AC8D9C345ABC571E65112686361402393FEA6712DC323D88132699738B89287388388A149638993629F8B59AE623ABC37FABC385D36CADBD6C6F54B97310A06BB5323C42A66F973237A626AFCE620DCB88967BE7C8BAC479D6C1887201BB44E1A75AC351754135A81C799F26358B9C7948B564D6C88DCC075EEE7A256EC49861CB2E8F28422E362F4D6ACE1E94AA6CAA1E15DAC4D6F0683B156A71807CEE810915F4ADF68736387C7089B24355D21465A7BB71B3CCC5989C54C9B7C5B2823B496A2FD23A7A994A7788B91FA14D05306D86125F33F342A11AC53CC8838859CC0740B6CDDB9B2E53C4A2D13391967A5E3197998494699AC84028B751399ACE998E26B818B94CBEF78AC97170990431BA7BA22B8891CDCBF62413D585AD6488CCDA194DF89222699BC77A71B43A80A95336F978967116B7059153CF344B02B0CFD78BAE7547849DD106A3170A99FBCE07067D06354A0E86C6D106A2F513A839660CA2942A51D9A463027EC2E5B574B795D59BC3BFA406B6A99BED62A63B37B27C5B40C45871C5CB503D062E255C48D2835FDF89467250CCC4EAA32DEC2B05C04E555C5FBCE3CDC6C855E6545062B4C8D4599D83717F03124727E45B5383BD3AF08144E7BADF062F1F2009336078A7A62CF2706642B2BDA323C43495CD8C067D8914640CB8660759970F665F8E282C9CAC647D709AD600AB8B67C9DE7A36A1482C2A94AA1E214CEE1A68566649CA5B8553A6404934219BF1C07657C82F48C3BDB00BC0B394327C75102BC10B5756AD404930CA4DC8ABA2486875AFA58BD81B83F08B9FEDF802626518B9441C0049A98CB0C8E5F132A0738ACBF323B3577EC906940871947F856C591047C1C66883F040A6995117B8AB51E5B88207A84E3C7239266B13790C561876C99C64DA8B9465627C59FB1F740951C906B540B592BD6467E16324594974E6933C6E509708B56D41766D4A59597BCB5AB902B86CA3B4F8AC29DD4CA359A8C3CC70563B0CAB3E559C3F1507F54C2FA61A383D217071C4C704514150AACBD9B02000A48DE2605AFC8A142B49B95CCA44A9CEDE035327B2BC1B770BC0C3EE6DBD74FC9D3948A46E4429FF6D3B5CC6A018A390D967C94B4967EC22008DB7FBFF797DDDA62D6ABF1A67A99B82DF587B1294DBB1C363EB427CB804DC543D969492479C0A876B43A9D2F095D4F8FC890096EF",
|
||||
"6E77D8BF4CD2AE8E84DE27558C41CF8B63DBF07295C86F83DCD9CF4C4E0AC14503AB3AF4491225037291A7F0BF6B51DC2E3966E093FA8B217C35407F2C5408730D2FFBA39E6DDE33150F804A36EFF671534FC99DB0A76C8516CEB28431CCCE0ECB54D66F73CB283DA9635F5E6496BA0D3BFF33F6DE9AC9F780964368E3D0175E64BFC2DAE50544789CAC7BC439642E678361D99FA6DE85252E72B39DBC5F32B3B45BBFFE90D53032B00A8E831316CB1858FF3EC0EC4E22459AF83D8AA09BBC6823DF580723466260351ACD562C9F8E8AEB82587F4DDD7D26644A990C71E2A6385F648ACCB25FBCCB31704753E9C0BFCB71A433A51C3C0DA5118A7A7E69F3C8AB0EE3F7116DD50DC5C18002AE10179093C25340B00506206443D1D8C9210CEA277F7BBAEF4BD5097237B7D0DE65D524DD6C7D467B8162EF2BE60AA304082799D4253785A65F9CC5D75413FD0ADD22E9019A9CFC7D3060DD86AA10A218B050E6C2B12EECD5646C539E3D7D87B06896D3D6AB902EDC8D162AC34C5C6C2DE155D1094BCEA464E90393C63BC6FFAB862CBC4F68E899E0872B52A403D37A21810EA9D0FE376397C6A1848D225DE562A968C16177045F86FEB2F53D19A95E674DE446FA87E0BCAC9EBF77243E4AF6C55B0585CD1ADC300888AB14CA518192F63DE4786AC9FBD83DF4D794932D5027B17F75B32941251A87CB2958B92494E33B5BAB965B212E557B0647492F361A371298FB7C4D424731C28ED389B90EF3EAF5F71E601227F8BD915EBB8063B95911EE50AC3BA994E5AD96BAABAABB32D0E7948BB91468F9C8D5EADE554728CA2794322A72CE728B80C2D8D306B6B5C7C3D867748BF413128B0AF6587CA9424226254C8D2BE7C6174038CC926FFAB6139BF1674DB51F1C86333DB231543169E12A1828D16C11C9A8040C02BFC1B92300C3FE3B38FC01AA7A0E7C73890F934A5DFDF16720A536F01AD67531049E705C2A909E7FAF4979D2E39DF685271026C6F7E91B5A891034059827FB57651F1750388C1908613A8F0E7C0BCC85291C18A52883A1A6FD65B56C8BC9A058F1031916B46AA8309C7239059179D72CD093EA624111DE89A7CED0B3C92975DB293179F6C0324E9CE674125F8B667C87812FC59683F59C07E9C4A793CD840EC6CB728DC1AA49CC78D7F1BB7D8466ED1D55AA45EACF6C6CFA250E4CB9F2B597E28D69F38F2BE852B2DB2257ACFFEE310E65A5CF90F4B3928850D5FB5B5057EDECD31F71A42AE075158C2AD90E5745712134D4232EA5054B81F4A70D3D970BDA0874449CE73A87188BC85D9EEA568C23FCBDF00B8051FFA5786D9B719B3BE00572BC994A6FAA576F283CE683434879DAEA7E9164E42E0D290532FCA15ED478BB1C4EB6D0E43801562E09292DDBBEC0B2DCA4F0F9DA0463FC81C4B2576B9900443294EA5EA8FCEB18AC3177B9F53B7FCC8B68B02BCD8AC97DCFCA990830DCA3DC473AE12CB56B634FE1D7497BC360E16922331D3266B798BFAA8AE75155837EEF39B28A42DD3F706A052292889D",
|
||||
"63094ADED32451C9C6EE792A7495715B0AA36191F3C0C80E92E9D2BE48301483",
|
||||
"C4316DD26DF672F2C733AFA75904229B722CEC9C4A5ADAA24C6DAA6D6FA57194",
|
||||
},
|
||||
}
|
||||
|
||||
func TestEncapsulate768ACVP(t *testing.T) {
|
||||
for i, tc := range encap768InternalProjectionCases {
|
||||
ek, _ := hex.DecodeString(tc.ek)
|
||||
dk, _ := hex.DecodeString(tc.dk)
|
||||
c, _ := hex.DecodeString(tc.c)
|
||||
k, _ := hex.DecodeString(tc.k)
|
||||
m, _ := hex.DecodeString(tc.m)
|
||||
|
||||
ek1, err := NewEncapsulationKey768(ek)
|
||||
if err != nil {
|
||||
t.Fatalf("case %d: NewEncapsulationKey768: %v", i, err)
|
||||
}
|
||||
if !bytes.Equal(ek1.Bytes(), ek) {
|
||||
t.Fatalf("case %d: encapsulation key mismatch", i)
|
||||
}
|
||||
k1, c1 := ek1.EncapsulateInternal((*[32]byte)(m))
|
||||
if !bytes.Equal(c1, c) {
|
||||
t.Fatalf("case %d: ciphertext mismatch", i)
|
||||
}
|
||||
if !bytes.Equal(k1, k) {
|
||||
t.Fatalf("case %d: shared secret mismatch", i)
|
||||
}
|
||||
|
||||
dk1, err := NewDecapsulationKey768(dk)
|
||||
if err != nil {
|
||||
t.Fatalf("case %d: NewDecapsulationKey768: %v", i, err)
|
||||
}
|
||||
if !bytes.Equal(dk1.Bytes(), dk) {
|
||||
t.Fatalf("case %d: decapsulation key mismatch", i)
|
||||
}
|
||||
|
||||
k2, err := dk1.Decapsulate(c)
|
||||
if err != nil {
|
||||
t.Fatalf("case %d: Decapsulate: %v", i, err)
|
||||
}
|
||||
if !bytes.Equal(k2, k) {
|
||||
t.Fatalf("case %d: shared secret mismatch", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/usnistgov/ACVP-Server/blob/master/gen-val/json-files/ML-KEM-encapDecap-FIPS203/internalProjection.json
|
||||
var decap768InternalProjectionCases = []struct {
|
||||
tcId int
|
||||
ek string
|
||||
dk string
|
||||
c string
|
||||
k string
|
||||
success bool
|
||||
}{
|
||||
{
|
||||
86,
|
||||
"1F2962ECA97FE4A63D64804B5B259F2025197F0B0EA9996326D24736553ABF113594E122AAC2C62936C1BD75689E240CED9BCE098212067776023A4954376EAA342687195E548160835224283A4606207C6C939376030C91BC3FCD6466810C5FA361488824B35C693DD8FB56DE2412B86A9ADB28384F908B23ABBD28307CCF834D3CB29F3E1AAC65806F4084974CD7037E2B84F645733FD660D3C246076706856B2415B0A234A29A76532DD6D6320BD06AA459768FB067C7B28B8C89258C2354EC5926D23BA388C14E39A63F61D23D705B1B850C58804856934892DAA452007B2ED01C6196995C55C647F3F58BE2D27AF8845C2334AD27687A25E50BB6BC90058B181D7197C5331088B7AC1D18038AA9920145887247C805102B95F57235783A4847130E47566A60469575651F0137608395D010567B7866C8505E6DBB6F6728959C128C382414FA53C461850E7783CCA1B4265008642581A06BB0C410D2A791D0977669188C6231A4A3390DAC1B15243E41D57843C53E309A3DEE5BB0991A85109A716800866259054FE1CC59FB6A96A75C8503517EFB5517E8170376512A53C861FA35AC8C4B5E63756247042690BD67BB8E0C7C9E8F05C5CE48CAB0F1425E329072F87401634211241738C2CE97208C6A6AB609F03EF13387AC6C08A3FA61E53632677507711A25C1FA3454D86D7BFC75E668100D6A6A03086142275383E291097104356A0848724BD95C3CD89CCECE97421BDC67B0FC8AA0E0C2460B4AADD9033CFC60EF04AA6F39566E89793DDC0481109E532566D90525EDE57E8B756FDA7190BB89937DABBE2AF4239961CFDAD37F1E4B5BED5A4CB5637163840716A1CE2F2036975A640B6A7EF308690D66750CA05B9058772828BC458AA9CE47116EF459B01C292010B7449207EDE7AA38AB20F10280E316298E9C86B3B4B94E718B85798D5567C96531A6CF84BC806AB85E156A34447B15FA9FA5BBA5F1087189BB9D4561885B2547DBC5BC081C1A268A9EBEE5CB1D4147545044D11933F43871ADA5495C894793645B0BC472407BCDC5ECCE19F219C98532882381739B94E2366BAE2C543E68116BC30974149E59318DF3336204C22063E4481E688FE2634D790773E243A325AACA07AC65EED5BBB092B6371B519BC01067849E6BA3C5D9B4AF5D073BC84BB472C123F2C72C4B191C85405D63C148B368399ECCC42F208F62E75E14408BEB14101EE4249D2418C359AB05E5A3B60A5465637EC6A31419EAAB9458A285F684404C4A94425FF6806150C7111AD2A77C0616D45CAE9024BE5DE259FFD6C3C0E509DF484F2D219D5F3CB596BB763D4BA6C3521789FC840142A42D510F14EA44B3E9B573A49F9B0879CA5A5E0606639A7C67A7674124E2423339126FB019E00BBB5031A1AB9B3A71190459A16EBB0A196DD9CD5A152179082AFA9436B647A68111439DC325EA777BCA84ADDBD62FDFB61009A54FEB495A166BB35C9C426A678E6E2958BF52138F68711D623B41C7B4A97A241B17B3C37720FBF04BA3C175C96A4CED4C3FD0E4CFBB345A0CF48A7C0870E4353CA02B92A204A9C03A6287BA8E1CFA50B91C2E2674CF93382A72E8B9E0214504B97C18D60351F689392A8E44AA2C57DAAABE4CE52E3CDC2BB436DCBDECEBAE89BD2E392F0370092A66B4F0",
|
||||
"BDB614FFC9BA80A3BBC1899EC855448E2734BBA74116181D1503CFF0B497C832B75998A5CBA94C76C2CCA25904F574080DFCB7B4E64D5D7547B2C2C5E4CAAE550098BA50BD6DA47EFD10A67C2502A8C7B42F4B2696846FD849706C014A6CD8B828012B4BF41BCE0041E27A4245231B954B958B1400A7721FDDE369C488BE6AF043A8C0A9CD0CBBE132A2F303BB57A4ADFA02CB12717B2EEA905381B110E61A6B506B45392F45313C51756D80B27B9398C1F3F1A74655AC08AB6801F651A1A378DE128F63D4BACE138330025FA3882BAA630C98A070395697D4756D7F0521EDFA065D36A7491B53A371080F97CA1FA0B93E544DBEE4815B92AC2EFB9005113D583A731E17B713A68373D5AF07E32520B1958FD9643B4CA70E601472002141A12424726114AC1FA65801C8659846E8A1D42C53BB0A3BECACB43161C7DB707351485258C4C373754E9774AC09482CE92A24EBE959973A5E12606440777B22471C3EC015F2673EA3B4AB844778EAEA88302446EE790C2E954B29738A90287EFDA113125170488964EA551451955656A788BFE4C58A7AC4A9F2BFA2DB2C91C69DBB332FC4B231DBF1B4AA914BC63C1C37380C2395874EC1C517F0C79DD0B85054668D93CB2922917F9593D49292353C8A0208A26C37738EF146E92A2E10C49904F324AFE1820EFA0AC5E5A4AB3585A097B6D35C88DD57B5AC0241C21A5DE1A581D5416C11CB1AF1B79374C746FFFA4DF658CC6881BCD5C875E925223AE8A56924422EE9091B21BEBE841C37B8506B097E3F3BC20342AE00307745AACED7090547C1882D32C60BDA724CD156ABF8A11DA1BB054A8BAB5C44B474084FA13FE2949310EB64239338BEB36BD86ACC923C4320510220545D8EEC2F77EA364870B58404126B501CAB238BACA52040DA2037D541D574A6E7C30B9877AD540512BE2B41AAF888295B1A38C0CCE4F023BFEA82EC0217BE5A7D6A6515C399ADE1AA911336718524AD916A186FB488DA793D214486F0E231AAB6075C0A04D6406286684D65484B8520438F021FB4C55AFC5A4C35D97F0036480E65A8EF894C938B42ED023A4B966D235479012594BAEA06E6E86DF73C9DFB000F748C8140AB49341B5952F5862EB73E8503B4125997384B11208972D1DA3D320064459B6D714A4151696A843B872626B051D219F8238BFE480182D93F70752319B8AAF7360494038BE5700F2E9B86E83812744989B4921469F8A4B41C682ED329203B00257A950BD5435B224E4699729CE58D3855293C62C44EEA5D2CF96B4063A10C8ACE2DEB53FA79B8A1E77F955A6A48B38119FA6B8106301A25849F9030C86A2889BC75C147C90D6525DC532745391E717C70DB15007423C06E8BAA23277FC896B757536C2BA5A2605397E015A84AB216635B2366C7BF1364CF87D3CC61A31A57A6949AF77AD5990ED54122D4082813754079765C999266C3E961E674C1F7D03F9D258C1976950A120E0E31CF6239362FF38E395935B5E29D40C5BFBBDC63C25855A372C3656C243AA135E8492F3890615CC75B3A25221DB72670E465E1B45128B131395B4F0AE3BB09E94965983FDF6A54AF087AE4F32DD7837AEBF893212306D8B6AC1765758466908A3A641F2962ECA97FE4A63D64804B5B259F2025197F0B0EA9996326D24736553ABF113594E122AAC2C62936C1BD75689E240CED9BCE098212067776023A4954376EAA342687195E548160835224283A4606207C6C939376030C91BC3FCD6466810C5FA361488824B35C693DD8FB56DE2412B86A9ADB28384F908B23ABBD28307CCF834D3CB29F3E1AAC65806F4084974CD7037E2B84F645733FD660D3C246076706856B2415B0A234A29A76532DD6D6320BD06AA459768FB067C7B28B8C89258C2354EC5926D23BA388C14E39A63F61D23D705B1B850C58804856934892DAA452007B2ED01C6196995C55C647F3F58BE2D27AF8845C2334AD27687A25E50BB6BC90058B181D7197C5331088B7AC1D18038AA9920145887247C805102B95F57235783A4847130E47566A60469575651F0137608395D010567B7866C8505E6DBB6F6728959C128C382414FA53C461850E7783CCA1B4265008642581A06BB0C410D2A791D0977669188C6231A4A3390DAC1B15243E41D57843C53E309A3DEE5BB0991A85109A716800866259054FE1CC59FB6A96A75C8503517EFB5517E8170376512A53C861FA35AC8C4B5E63756247042690BD67BB8E0C7C9E8F05C5CE48CAB0F1425E329072F87401634211241738C2CE97208C6A6AB609F03EF13387AC6C08A3FA61E53632677507711A25C1FA3454D86D7BFC75E668100D6A6A03086142275383E291097104356A0848724BD95C3CD89CCECE97421BDC67B0FC8AA0E0C2460B4AADD9033CFC60EF04AA6F39566E89793DDC0481109E532566D90525EDE57E8B756FDA7190BB89937DABBE2AF4239961CFDAD37F1E4B5BED5A4CB5637163840716A1CE2F2036975A640B6A7EF308690D66750CA05B9058772828BC458AA9CE47116EF459B01C292010B7449207EDE7AA38AB20F10280E316298E9C86B3B4B94E718B85798D5567C96531A6CF84BC806AB85E156A34447B15FA9FA5BBA5F1087189BB9D4561885B2547DBC5BC081C1A268A9EBEE5CB1D4147545044D11933F43871ADA5495C894793645B0BC472407BCDC5ECCE19F219C98532882381739B94E2366BAE2C543E68116BC30974149E59318DF3336204C22063E4481E688FE2634D790773E243A325AACA07AC65EED5BBB092B6371B519BC01067849E6BA3C5D9B4AF5D073BC84BB472C123F2C72C4B191C85405D63C148B368399ECCC42F208F62E75E14408BEB14101EE4249D2418C359AB05E5A3B60A5465637EC6A31419EAAB9458A285F684404C4A94425FF6806150C7111AD2A77C0616D45CAE9024BE5DE259FFD6C3C0E509DF484F2D219D5F3CB596BB763D4BA6C3521789FC840142A42D510F14EA44B3E9B573A49F9B0879CA5A5E0606639A7C67A7674124E2423339126FB019E00BBB5031A1AB9B3A71190459A16EBB0A196DD9CD5A152179082AFA9436B647A68111439DC325EA777BCA84ADDBD62FDFB61009A54FEB495A166BB35C9C426A678E6E2958BF52138F68711D623B41C7B4A97A241B17B3C37720FBF04BA3C175C96A4CED4C3FD0E4CFBB345A0CF48A7C0870E4353CA02B92A204A9C03A6287BA8E1CFA50B91C2E2674CF93382A72E8B9E0214504B97C18D60351F689392A8E44AA2C57DAAABE4CE52E3CDC2BB436DCBDECEBAE89BD2E392F0370092A66B4F02AC3FDAD8D8F210A271603D045F95EC94C2A38EF4985F2E72EDDF9EEA90CA3F0FDE3F9D49FA98B44BA6D37FC13524B7FF2435B88410255345590DA7870813873",
|
||||
"E3C563F0E5A3E2A6FF16EC3630EA56BA17647ED1236BD957021549825E806DE8924E3AF298F5D3CF2D462E31082180D2C2964ED80D3E7D92E5227E01B9B740F1E2D111FB379AF7A92320EF8BAC44A2591C7438B7F916C1508C45106E2EE3629F28FD280D725C382D647C894E60C2B109843D5DB59ABFD52B4B98E86773CBC75C8989239C288A79AB1D6608FA6EF287BB0431391C0CFD73504AB24D10A2F8FA5F3C3F38D9BD48607889E160CAA09818830472038F9F6CC2F7AFDBC45870B434F421743E1E0FD019D5C41101D9DAC014472C4FEEF0A9EF980E7F276CC7F1E1513A64172428A4A091A4C9A6A009EE5621E37B179EBAAC0D122A8BF42AE861EA420473D2C8F9EF3F4EECA11AAF8863BC66310EE5233797134E849A01992149CDF637BE74F0292988572A38AC86959CB67DECF3B3C3BCCCF186F917476DEE06727EA819A51ED1EE6F3228F4A0322032759D74BEF9703BC185A59492A79A67109FD6786130AB0D41F346D59FEAB3F3FEEC1270904B1504FCF463E9B4B40FA9B5266582A8031F0B200954FD080E207C9B40608C499D49FF752D9D1A4FB5F91264085D9E1A4A1A1FC91B5C5B3DBFA5D1EF5FCDF289206F611610B948644CFF3632229AF44D2971E3FD85E88E6936DA82DDD8815EA1A5DD6DD3DFC03259F604FEFC59CD4F9FC6AB4E9D8001A747546455B9629CCDCF5C4058D57C20DB6C9EEBF7C4ECBF76784FC2C9A08B5414F02EE7C93A38201BDFF31068786FBF98654F0A32B188B891BC59D683E08BB2D6906594CD02B232DAE179BD5C10CA0F7323A0016876BD80AE16265AE3A96204665A01758FFA9EAD686D3BC22D92899633520437994D73EEAC9A2E55C1EBCC3D07229B2E5202DAC0285B2BD600437CFEFE98EC02B13977359FE4E51EA9FFCC287C88211BB220A3F0E52D5D97B547B2369CBBF46512DFC304D72EE1664C91BA5E75B2B1D089EA9C02BBB7E390FCB2EE60E56FCAFFC3E3FEEA01FD8D5212783BF71AA94BA94813325A0249E55BD4337B7BD662D6641DEA484962E04DB7B42522837991D1048E9785E3BC297B2106ACA4968DDC1D05BED81DCD061D21DCFDB82D79CE3853E8B2089A8FE150F3F34CA7BF540D8044D8E40CA3EFC66F1778EC0E131F922E28D8B62B4050042064360515B5A88032F82AC618C9356678CC77F3C4B3456C61462232D92094B29A139E975D1DBD2B2E5A8BD6AD7A3CB9EB9BC0C0144B2178EE709B2D8EFDE65FDF3630565FA83910C9C3CC179F4613467294FE778A33636AE26AA9C2EF2D0FF2D648D3F8E2B9E20D434EB8BE0AD4B57E87B92A6D3572D8DFCD38B2DF6D77C5C8C25612EB7A3E0C0791003DDDCFA723841749A6AB9A9A5AFB098E1A82390FEF7A0FED281D7DA116B830524B5B4319F93DB15081136B5B06F8FB289018B47BE3302C193C8236015CEAC96916E39E4E8C032398056DA8C57F7D0F0A0A88B8B91D5D4D2A37CC5F0B8935BA7FA7AC4A0E0D87ED501B6196B7A4014226667F0F0EBC221BAEB63C7947D8677BFD625403F99F74",
|
||||
"F8497107CE0D948FF5BF6E039E3CC4EBFDF5E9409EF77171A1E4BB2165713A3B",
|
||||
false,
|
||||
},
|
||||
{
|
||||
87,
|
||||
"6A3A01EA24AE603A99613B63596360748386C8F33EDAD3AD33C5620DBB58FE81B76B960A28C8A893F7930F2583AB0431CB15B6D0EA97EE76045FECB2FEE09BE411B8AB827236C67D65C4B548A43999134D4FA3735629CFBF3314EC955194C8BDAE1B6B32635F27427DF0C8103639CBF7301C4C36B896E853C2377C5C155C9DEC611D1B6BBABB6777B6A95DA79B5456007B30CED6BB4547056C7B08B703A774114B036DC081BC896BED96C8F7C8BEC4EC945CB78E21503F04F849C053A9B7E1CA5E080325972FF9310B12B04BFDDA31AEE5C45E7BA024133BE2B7B389D22D3C9AB4CA34A31FA902571ABD0C267DC23157787B368F1352BA6A0F9D04187AD29CDCBC382DCACE8E31869CC2C7A55097AECC218FA68509D289833988EDC26B23B4CE26954A15041465A7287E372CC6213F7988768D105030DACD01B73B5F2145020287ADB92D63DB8D8E16A231618D4DD97851335C68811789428E8A8280519A81A215774B103981614224E35592647823E633E951646A1912721C0AD5BC21DE84734E285653B0858E5B325699B5E31C027B266E7E82C6473072A9E49B0B8C28BCD163ABCC7A3F3251601B4719F2894F1089FBB37F1F760079C6286525551BE7AC73E52926B28FF3F89A663043CC3C5FE2BC0312C3A0E1206583633F0747013C42A541E5CD53142D19D06B7E930CE1F68485D700BFAC9A71977C37A28CB11C703AA04FE533B58F6826ACC1AFBF25CB7B0A7890C427FE7069120315313C0A45C18C2EEA868243B4F46A03622C911A98ABBD7C2EA3305A5237AE76838350EC1512314A7CFB19549283CF2866F3FC3F429168A461034830BC4FCC2A7259BA6A49B256CA9066086A1BFA64712A7E5EF40BCC758B5A600C2717216839BEBEF900EDFBA4126C89047328A9849E80A596FA930D666099A9978085508F9AE8CD1A1325B4082457045A923410C84A0EF382BEA75420883C4E3E43183E8B9BB02A7030051526055910A835AF9053BFD66B378CB978AAB14B629F88839F3A4A7F985BCFEE440939359C7FF98B668202149045F68418466C45E76517F9F7389A683B47897A608A2F85800F7795BE75799DFD597057FA3F86C84CD52A4140758AE45B51F80262DD56337562A974B942DCD20EA2BC5C52F225DAF5A80BE0AED045A7E812819F646D28B0578D042C8B77C8341B46102BC881A738DDBB43411B43C41813C4C28D75400BAD4902ECE7C899FC7FEEE32C78D70165DBBDD139BA3EB2210EE3C1F6BC2B31C8C73B1A54657346C3D322B243AF797A93E7129B17FBCD3C7B9CE49216472BB6DF1B2F41BA4EC3813EE6DB3898F19643C38FFAF3880101B08DE8370ABAA82D91BFDE31B8F78CB85474A3BF06844A233E65884303CABDD1BB52F23C01512871A6FB50DCD3A2417140DAB019A11BC10176C5C83BB138CC2BB45369FB74995613CCF71426CC45536586A9ECEB63877494C4789E62B33BE19B87AC40357DE584F11B236E389B26A5578232478E56B798FA77E6366EC15046B38B4BEE0255FB6AC0B8B928F9F3849417B7C76A396D0B58DE16C709E58D5C523DCB6C7EF74C60960886926B4F5B472A7D2B419DB06592691B0F7299EE970B8ECA7F74B1258AD17C087C8EA0F1AA37C40C631CFC95ABCC465F6315C54C7531FF559F19B952406FF1BE2C2C",
|
||||
"DD30BACFE52565345BDB2157888B5694438242E2A2792B5E3696C516F8AD1D893DA3FA1907ABC9F0E627866C30B1BCB4887C7291D0381F2976C690ACFA571184112F11251E38C61DE8E727198515FF2696BC8002000D0C1AD542360652EBBA33F5F8A037F50E146400BF12247B73A7045369272753B2DB9A5B13614CA446634B9513D3A050C155E879537CEC6E93634B3DC067DEDB1A6A378DC9674AF3F09A6726B346F5A1EE069C1356626D7126380745C7B065D5528735B36355A8260F3216DED3CDB1F6780B8BBFA409B67A266F097429C0E808D1F2479617AF9A05712E7731298455611A66C2584C8888B691F23B574A463FA8CDAD2802CB14BF83AA31D5D946ED55097A24CA024696148A3126DB4E69AB82EDC9024C4734FE182E45E8766732750ED443726A578E39484A90721A28CBB0E03DD72931405516F53001D57C4CA4EA2E171CC27AD896F2A8C6A5877C5338374DAC8DF4D762C1D97BC735430B33CF62BBC2D0A0A3FA8401B54C0BB77A46FFE5AD73FC2A5D285A1137052ED028DB79988A4323D0F8105C58AD9FB47BED3A60A8811FA2C55B187AC7DADCC42AC09B2EEA3609A06A68EB47B28025419B9C702BCAF06C38C86C7640629C89D7A486990D62433A66327A687A4CCCFBBEF4C0947966C991573592B78E54E7ABD5A9CD17D6930933936E049121C568CC013D415C23CBB2125F5A3B1FF58FA795B4E16B8C44A94FFCC344D035BDEDC45698A2A205414416A49F4E2A06281C9D254462C070AA8B7974180B3FAF81A7257034B7752EA315A1F4DC64418470EFBA37B228C0E5826C40D31519865D0DD07004B21B0D57872FBA2A00245C2702CF2C8AB91C5A5AF8F40614FBB1279C66C4F2405B4221EDBB8B35FC5EB65707559A29A04939C5990633680771D76E302616DA2A5384D875E5F2C3ACD4C96FA74CF88090B22540478161BBC14B8B6121607239056022EA3947EF661D72B12227889C2E1C266A7A60C014BE19E0328817104027475CBC78CE2C85012017EDDC0F7CEA11C8EA72AD3338498292BEEA4B8A7129D71B1927FAC2A6921DFB87C425F9CCBDE2BDD01C685E3CAE52425070C5C00EC8745FA538E4F96F72D89214E042F19734D7E57952D0833C72276CC93D9991A1AD99AE0CB5886FB83367C967CA65A7AFD022DF404DB0625FBF2C50F0D8812FE2BB1DB4351C7CCA96018A07A6AA62255655A59319AA9A0F130387AC5EB3BA4591A68130523A6D023F57D7801C71BF2237A17FB3590B240FB03037675A56CB85A68EC0C4FBEC98A1C534EAA4C1AFA1B7A012AE871C2EA6B34B3E661A90713C66A0A527676143CAB465205ED21B1E82050343B62CCBF875A2B13D752AA9007426D52661E6E1C42446B7FA632332498B53DC68D780264E1638BE1B24C6323BFF427030130A3091772988789CFC65369C98CF6A6BCFDC99CB477D0D120531C8AF46613228CC687DB38E984C269FA225E61B4B5EDC4246849CE2578BC7519881055D00295DFB560152F435E7A800F5E2BF2299A2BEBA0F0EA63D2B3550AAE2518EE80948E9961BB74D5B5B8C65C2C7C2229158B017B9250B2200809C8466387831C08B791FCA10D2DB3800429B35279310403566934BABE1776A3A01EA24AE603A99613B63596360748386C8F33EDAD3AD33C5620DBB58FE81B76B960A28C8A893F7930F2583AB0431CB15B6D0EA97EE76045FECB2FEE09BE411B8AB827236C67D65C4B548A43999134D4FA3735629CFBF3314EC955194C8BDAE1B6B32635F27427DF0C8103639CBF7301C4C36B896E853C2377C5C155C9DEC611D1B6BBABB6777B6A95DA79B5456007B30CED6BB4547056C7B08B703A774114B036DC081BC896BED96C8F7C8BEC4EC945CB78E21503F04F849C053A9B7E1CA5E080325972FF9310B12B04BFDDA31AEE5C45E7BA024133BE2B7B389D22D3C9AB4CA34A31FA902571ABD0C267DC23157787B368F1352BA6A0F9D04187AD29CDCBC382DCACE8E31869CC2C7A55097AECC218FA68509D289833988EDC26B23B4CE26954A15041465A7287E372CC6213F7988768D105030DACD01B73B5F2145020287ADB92D63DB8D8E16A231618D4DD97851335C68811789428E8A8280519A81A215774B103981614224E35592647823E633E951646A1912721C0AD5BC21DE84734E285653B0858E5B325699B5E31C027B266E7E82C6473072A9E49B0B8C28BCD163ABCC7A3F3251601B4719F2894F1089FBB37F1F760079C6286525551BE7AC73E52926B28FF3F89A663043CC3C5FE2BC0312C3A0E1206583633F0747013C42A541E5CD53142D19D06B7E930CE1F68485D700BFAC9A71977C37A28CB11C703AA04FE533B58F6826ACC1AFBF25CB7B0A7890C427FE7069120315313C0A45C18C2EEA868243B4F46A03622C911A98ABBD7C2EA3305A5237AE76838350EC1512314A7CFB19549283CF2866F3FC3F429168A461034830BC4FCC2A7259BA6A49B256CA9066086A1BFA64712A7E5EF40BCC758B5A600C2717216839BEBEF900EDFBA4126C89047328A9849E80A596FA930D666099A9978085508F9AE8CD1A1325B4082457045A923410C84A0EF382BEA75420883C4E3E43183E8B9BB02A7030051526055910A835AF9053BFD66B378CB978AAB14B629F88839F3A4A7F985BCFEE440939359C7FF98B668202149045F68418466C45E76517F9F7389A683B47897A608A2F85800F7795BE75799DFD597057FA3F86C84CD52A4140758AE45B51F80262DD56337562A974B942DCD20EA2BC5C52F225DAF5A80BE0AED045A7E812819F646D28B0578D042C8B77C8341B46102BC881A738DDBB43411B43C41813C4C28D75400BAD4902ECE7C899FC7FEEE32C78D70165DBBDD139BA3EB2210EE3C1F6BC2B31C8C73B1A54657346C3D322B243AF797A93E7129B17FBCD3C7B9CE49216472BB6DF1B2F41BA4EC3813EE6DB3898F19643C38FFAF3880101B08DE8370ABAA82D91BFDE31B8F78CB85474A3BF06844A233E65884303CABDD1BB52F23C01512871A6FB50DCD3A2417140DAB019A11BC10176C5C83BB138CC2BB45369FB74995613CCF71426CC45536586A9ECEB63877494C4789E62B33BE19B87AC40357DE584F11B236E389B26A5578232478E56B798FA77E6366EC15046B38B4BEE0255FB6AC0B8B928F9F3849417B7C76A396D0B58DE16C709E58D5C523DCB6C7EF74C60960886926B4F5B472A7D2B419DB06592691B0F7299EE970B8ECA7F74B1258AD17C087C8EA0F1AA37C40C631CFC95ABCC465F6315C54C7531FF559F19B952406FF1BE2C2C55A5817F1A9B11AAEC3112029860E6400D99E57DF796A8B775C8C5060D4C3DF45BA1405A293656507D39C8FC3990BD23E6735715792EFF440A9BEC79C7F5FDE9",
|
||||
"690D3DA51B1D22BA09AA62B4FD6EADFB4C587C34FC434C62225B9D132DEDFA5774B4ADFA213EDB328DFD6056CEE8F96EC1454C85F8037021F22879FF0BD7FE1386BF272021522F774F10C4C9F7A53E18E3A7023DEA1C3BC8BC76EA8FCD2BE2442A655F2E34F3F102919B4C336B177B038A0CDE0A2A49787E89AB005999F1AC733A04B867D557AFEC7502368CF8DED96CDA58FD0C0426767AC2EDF808F8A03B45D72B30D354C9792FEF5213E7928399F09E2DE540F4826ED72F86C02637738ACF28B28CBC8D45D5A7A0F4AC5A1B7CDA2FE6AE3872C6985E61E259311D5201A540B4351DA0E794F3BBAAB916E2603633741A7878BF61B3B344715D6DCD614ECDE5EDEDAB3DCF4DB03582CF12B764179ED88FCF5FDB0A550522468E04A5FCB297EA78C1DC6DB4CB868F7B1D0B195A16CADB15C28DFE7D2ACD9C2399B6461ED22D000F3368E88BF12F32BFE6B749B4665978C297314DB35122C7D04738E38F7B4CD8246FD36B93624CDC7F0BB10FB482479EF1E1FFB2F85094C9806D160467832D604FF7945CE2D6BCDF15802BC2CECB90FA3F109987BBB377B4E0B092B64F712E3605B3B11E3377453538EB28406243C9C182858650F70CA9AAE1B8E00E3699D2C47038F2AF7076CA6C2330542FE680D79C463F60F80192F85F6BFA0AD455712840F0E25DFDE29CB98A68FD2EB4DAE3C536967D5C4615788AD70A5451ACC78A5419979EB35F83E2DEC8A9EF3DF19A73225832FC6EF76A19159E38DE1BD15B6931F4D47C25024AB2DFB0A800EDB9E070E1FB3628B8236AD227AC3F6603F1866C4CFD669F992C50C06C1986868330C4889B3A9F77DEBC702F3A6337A549B1F51FFBB7201B04287DFA6BF3144160DED6206B5AA1F9A03CC0D56FC53EE55C8CD9A23344BCFBE1439904A3FE6A225D3DC16BF0BDE2B53F90CC0064C4A7DA29E93A84585161D6B367063DF1AD2639E94F0F61455225AA72C294936293831B7F221D209D30317FE4D68507822BF667C8175F23ACDB14000715D26AB3303C46D2E9741F03A73C5FF80B50E2750744D747E295A6DC2D6B9C5D12F0D711267F46E61D25388A5AD57F8ED0EF9CF99311A6A14D0EC5AA5BD8046755921930406B786BB015F4C5B1326650CF8A6EA2FFA758C4F3250F235CF4A824807BFF10BF54910A610B1361B156980ABDE86D087FA133CABE34FC5EED86C3332B86A84742ABF33144B8B08E3E22C845A5E0C2ABD786DA7A7E01DEE4558365857B384CC3F398D74E157CCDBEBF8ABA82AB7804303ED27E280BF68AC3122F6881B3F75C0F5BBB69F6C02C4712FF8B9D1822686CBC441A4C81BB54DF79C90E32A2C5464C0453954DE231AA0D01A0FBB868B4467D1AB6035A9F0C85C1C4016F586B7B6E653689331949380A00CC8ABBB265089606F65E324FEE9AF4CDF02B1F6685AFAA05E2DC9AA17AF7E8131D1F1E3D2FFDB9592C9C57CCDD619274D547FE2285A8989DE7926C654DCAED5613CB4DD4A2E0BBF9BAA7DA1A0F7628C924927EC3C339A38E73C219CC79EDB4904F97",
|
||||
"8B6AA77088CC998C2E6B42ACA57DBF3FAB786DFF66ACB017B2ACB48FDBC73D07",
|
||||
false,
|
||||
},
|
||||
{
|
||||
89,
|
||||
"BE0412D99A23CB207074F8A203A4421678ACFA3A225FA5C560055E8D380187EC6845DA3BD3611FD6E917DEE3CF2830C52C026BBA8A6A31578B942484F0079E88B2AC05D7C453D73D3716BEE80C698A323D2D5331B046B86AE007AD40CCE3927A75F4894432C7D235B4B6610A792920D5F0CBEA389235784EA91BA02BFBA238A79FA2ACB6B2A91DBA4BCD0678796D0BB4357B4BDD849762F4A7CBC69D163C7874C9ADC92B01EAE8AE616461CC89ADF41C415E484B94BA43FCE7AF7B520A598B35429809C109CD7C048B9C67C70124B597C1979A7A31B7156CEEF849C720B39406A32D1B639D18A1D0E462699181B9523FFF361AC995BF1127A4E5046C32F1A1E102CDFC431B060975A7437EB765BFE9A486CE6A52E3E33CEA47766EAA9BAFC819F248B0520313EDEB524CC6BE7771C75E96AA1096507CB18E9B101CBC21132A7337D78C0684E07C3AB8260E2070A3825EBC625F8851CC3E653011DB01DB07CC6B350A68652E31AB630FD373B75A1099A72C35441B9B6127B99469F95B503C663C9B3634A212936B3023FB4B50E8186619B00925639F52453979DB24D2B8CAACD61094D1B14C9597DF53339105C1A6D89BD6D626BD6C5D0E1BABF903CA8B4B48420A137B729A2EBAB17FB434EE258EA5F4CF9B9B1F58E85E343292981C0D02C4003F52B2F37CB3E7CA65AEB8A7F2EAC05634457581A9ECDC487223691263B696F8BD1D685770256AEA5A94DB60AE05A501835848E2F8CE8BD7CF5D1365E6120E18D456366B19E9F1ADE4C552050A02CEA89B8F99BF89B36C08232E13F79A25310934E23FA4ACA724761E12B32322F2744D93A6E4B0997B019C6857952369035F284D60D70581C593BF4B5749987B2E569941860E1619AD1D524469E987B7261F2274739699935291656D114525400984865B91895EC6C39EC54925BE2581D24A62D7B2785C2C697FD61C14C28D1A9568C9C331E3D749BA6597D9BC94CF391A7E3AA57C52C7ACBA8A6A85941BDC59CF57CA46336B25FB9BA93CCF8719A0057969A764399EF2CC3A81AA1C4534E195151389432BB43EC54A2DB2DAAEE068921A6A275333AF3A66C22E924C9CCBCD298663D6C4048BB09E8785387F8A291B3C15E72CAC44C6360EAB290F633FAAF4B023D000B03371EC885EBEE4684ED39A3BD03A390A0F7FC72F5E9B8574A23098404E7F4620C7A8411370B2AD8813DCC91011670FD3A29C088303725CB2425C783AE71539C75F96C1B1B395BD936C118B0BCA994627F32A6B53A187884453CAC606C39B81937670FA915A36F44FDF00D0AF0CBABA707A9FCC3672123D4EDBC1E7F30692400CE8E83E198A5CB692CED4363D7781095E12961BD27AFE1948C8F7259E336A2531082A2978C72BC67AD30BCA086C51A7BCD57B7B15F64E332C1F91AB6015105893917102530459C218DEEB58F5DC9DA5262B7D8A3159B43154F8597E5C57CF37400A2C560081B098DC2C20F6B5CCECC6BCF5B96184B0F7475076317C2EE5482ED83FE058108F762958E610041963937930C3AA3E6985423A33A07E77613F7236F0D9911AF49344A15D77C02A68F19C661704EF515871659F050251BF4CA9074A1A2B1A028FCB92E8053DFCAA319334C6443FDC1F8EADE4EF0C36949A1D36B440747C8D27DEF2FE62C033D6C17CBCC8C6",
|
||||
"A7F68B43898F7383B09F0C6EE0D97377D454D528132DA90AC55819A461B58424BB95C7C00A246F04F8B03D3C9D62389AC2B45DD6D43F32072C86E03812909650C52A0104A42696C5E1F389EE4A8775A9A063737A5AB41D8C0C0B8C49C822D7351C1A63BE677D49018CF18311775926746520D650C1C31C0BDB6B570C96BA6B06915815C0FCF6B32F583E80C2B7A84B805ACA39F676426A463E59D6C904042761833CD4C0C0336B00D7E158DC774C5C58BD71458C7C74459682245A03B3C8B8522B7448C3A98432C48495E51E7B401EAA8669707C16F36B72FF21623838B31B496D56B12C0747587325A59509379D2706670C573F85ACA0F426119254D5519D759232C5087B84520F2459148DC6A86184662BC368BC2C83FE0CA7BE156C67C05025A1161BD1380DA39BCA2C99EF727B4DD90D99C21209B573803953129C4DC82A279ACA0A73833C5BE189187546519C2E17EA895CEC1EA7D46594297FF43CBFB7D54466B21F1DD4B72116C10B6198553AA0273CC6F38CA9F9011985012AB4F44C7DC13B00A10F646456D9B29CFDC368FA610C49F1BBF75B5759480A43CACAF99C8BBCB5873CE1CC0D091F6282CB6D1A9FC34459AD0333C88A1C7FA3132DD2B415F809235A101162120CE0BB53C435EED595E01273622CB6A33222477634104A64909A2CA19956D0E0CBDC6A8A611128DF161217856737100205E1B1E9EC844C447E4A4BC538157D5EF37A81F3BFC0F347CF14BD3F75C18F53A777CB0D381B0AECCCABE4005515C911A2C4C7123447DFC93964262FF05A45D969551240BAE60B41ED698AF8E5193BF409862759599C598AC63460F991D47A18A7E7A101964E756603D3A4747A10179CD77FFC1614B5B15D028B7F5794BF7E46B09DF68EEA6744ED117EB241B59095177314194E6C9BFB3049AF1CCE267880E810A855BC5A30177996C22CEBFB58A93331395C52C0809813A2600EB2CE358473DD9A25D8C149F515A5CE10335E0A716D1A09AA817ED6959E18B79ABA93A7CA25562E458A294B767AC5BC860756E2393DAF0507F185C7DE839D2E70885885973B561A660A8E497C0999F99D6C7C66AFA2C1A098A5088685F330969B3526D09758CC8964E3B543DDA6177312507730AEB98C3EA4E4C9478499DD676D2634A7BD69BC2FF8CAEC434BE2F58428334B4014255C4654BCC3A46B737E486C424DC019EF071FDFC817AB7B35362313D7787C73EA9B411CBABB5526441999C6E9ACDBD581987A4A88A421FBF42691A36629A37E7ACA126A7BC68A9BBDCF270F2EFC8E12C328B39A6C80D24496931C012769559A8042F0C2B81158AD77493949987295947AB5CA8EB13B2D668990291CCDD0703FC046C38301CFC350EAB92B9307A685D9BC43E4105F8BB286745E60A4A37E6966F2F7B558F8427DC17A122143C12271A276A0C6D28FF8410C236B68C8CC75D46B403F430716192A47FC7A8BC2CD11528870F7A5AB52A752609D42A05250538E1CC07B4E278CF2977D14F9BB1BA701D771915ED65903BB5CDBC5C1FCFA1D4B04A43AA4B48D946A5B124E3789AF2C34BBAD31A17839653E849E2B917230824887193568FAAC42F533CDF4B31009950EDB065CDC498536A3101876BE0412D99A23CB207074F8A203A4421678ACFA3A225FA5C560055E8D380187EC6845DA3BD3611FD6E917DEE3CF2830C52C026BBA8A6A31578B942484F0079E88B2AC05D7C453D73D3716BEE80C698A323D2D5331B046B86AE007AD40CCE3927A75F4894432C7D235B4B6610A792920D5F0CBEA389235784EA91BA02BFBA238A79FA2ACB6B2A91DBA4BCD0678796D0BB4357B4BDD849762F4A7CBC69D163C7874C9ADC92B01EAE8AE616461CC89ADF41C415E484B94BA43FCE7AF7B520A598B35429809C109CD7C048B9C67C70124B597C1979A7A31B7156CEEF849C720B39406A32D1B639D18A1D0E462699181B9523FFF361AC995BF1127A4E5046C32F1A1E102CDFC431B060975A7437EB765BFE9A486CE6A52E3E33CEA47766EAA9BAFC819F248B0520313EDEB524CC6BE7771C75E96AA1096507CB18E9B101CBC21132A7337D78C0684E07C3AB8260E2070A3825EBC625F8851CC3E653011DB01DB07CC6B350A68652E31AB630FD373B75A1099A72C35441B9B6127B99469F95B503C663C9B3634A212936B3023FB4B50E8186619B00925639F52453979DB24D2B8CAACD61094D1B14C9597DF53339105C1A6D89BD6D626BD6C5D0E1BABF903CA8B4B48420A137B729A2EBAB17FB434EE258EA5F4CF9B9B1F58E85E343292981C0D02C4003F52B2F37CB3E7CA65AEB8A7F2EAC05634457581A9ECDC487223691263B696F8BD1D685770256AEA5A94DB60AE05A501835848E2F8CE8BD7CF5D1365E6120E18D456366B19E9F1ADE4C552050A02CEA89B8F99BF89B36C08232E13F79A25310934E23FA4ACA724761E12B32322F2744D93A6E4B0997B019C6857952369035F284D60D70581C593BF4B5749987B2E569941860E1619AD1D524469E987B7261F2274739699935291656D114525400984865B91895EC6C39EC54925BE2581D24A62D7B2785C2C697FD61C14C28D1A9568C9C331E3D749BA6597D9BC94CF391A7E3AA57C52C7ACBA8A6A85941BDC59CF57CA46336B25FB9BA93CCF8719A0057969A764399EF2CC3A81AA1C4534E195151389432BB43EC54A2DB2DAAEE068921A6A275333AF3A66C22E924C9CCBCD298663D6C4048BB09E8785387F8A291B3C15E72CAC44C6360EAB290F633FAAF4B023D000B03371EC885EBEE4684ED39A3BD03A390A0F7FC72F5E9B8574A23098404E7F4620C7A8411370B2AD8813DCC91011670FD3A29C088303725CB2425C783AE71539C75F96C1B1B395BD936C118B0BCA994627F32A6B53A187884453CAC606C39B81937670FA915A36F44FDF00D0AF0CBABA707A9FCC3672123D4EDBC1E7F30692400CE8E83E198A5CB692CED4363D7781095E12961BD27AFE1948C8F7259E336A2531082A2978C72BC67AD30BCA086C51A7BCD57B7B15F64E332C1F91AB6015105893917102530459C218DEEB58F5DC9DA5262B7D8A3159B43154F8597E5C57CF37400A2C560081B098DC2C20F6B5CCECC6BCF5B96184B0F7475076317C2EE5482ED83FE058108F762958E610041963937930C3AA3E6985423A33A07E77613F7236F0D9911AF49344A15D77C02A68F19C661704EF515871659F050251BF4CA9074A1A2B1A028FCB92E8053DFCAA319334C6443FDC1F8EADE4EF0C36949A1D36B440747C8D27DEF2FE62C033D6C17CBCC8C60DF10A55B73E721350FF5FFDF8C9717103B3F242F12FCF292DE0CE75194E2E59678218BE4EAA47762D1ABE76C755C76249BC0DEA1C5C1625531BD1F86FA0AFDA",
|
||||
"6C69EB30D9636EBA9EE14BC92EE730720D39E189AE3ABD96367580845A82F27C6C85F7135BC2471553CF1B0E0F092D87AEE9AE24649D6BC910A6C6B432F20993E562C5A1777BD801A7F1C05FD3A9E8DF57A187CF2637F99C6E24B5DCEAA64DB892796803DE9C1B6EB9E297440F7051D668F4781764F84CE499D6E7F6E4086C1F9B862260630E1B3E6C4BE52EC4FD99670A345659E4D865E5DBFD19D6412B4C9D31003D36EB9A1DE2ECD3A495B9E5A44D51BF85610EA867C9F4F1F09E10667A4919207628B2FD91330BADFD44CF491CADA6FA9AECDE5E20CE8AECC2986647F2656869E6201D851AC8176D98DCADC5ABD396B0C4B468871D0EB9332C264AC7550CBA62F77655110C4D15DA73A641F67A7821D7C7EA81CD4DD1BEFC5CC056883E74EB8DC985CA193ABEB30865A59C86167DFB51F96891D604577572D61623950D5CBC20F2752E6C65662950F7D69C4E6D883830326539DBEE1A1E683D74E1B261AD1D825D57FABC3512A405B172BE7AC22479E4D2F834009337726751CA617A95A6E915E50755FD644D600AB670EEB5F1CF097CC521A7EFE8A712E52FC91634EF0A3B87B91370444661674D9F1D0766DE59CEDC70CE0E78EC062F7A50DFA575897BB4A758FC7D49A92C6CDCA5020C0408A7830106529CCD6CBED34B0D5CA2AB68F27CA869ACCFF363BD546CD6EB6ED3589BBAE0D7E3101C71D63220140CE0146DC2A038B4C32749A4B99C3D9666688582984FBCC82F79FEF746180D05B8574FC42BE26E35961E01F2EB634CAC23BDA5D798C7264223524A040C9EF7D42673C7F6B0F2611467580EAAD9FFCAE0291962A98EC23C7351D620EA02723A6493E6354ABE0373FBC77DCDD022025F8C7F94C3476A0E400AA7414F6E50584E14B7DE84968F47083CB228924551191FA1031FEE39CF9A0494A18E34FE269F980A15594A6F68499FB01BCED9DAD187DB29842D928755F618D08B3F44A243257D7EBECADE361D47758A3E3B6E06601E4F409D2208F36397300978FE8173082851DEC328325BA05676848B9198E46966EEFDE2DC72417841E82F9848FFF6BE528F147648F881CF9718E6B1F7E0E20C6A1B37C5EED42DC6B982CB2232802CB71E83123DB105E6DD068BCBBDFA964C9955B2D93B7776EEBA03C5650C631D8F05AD84AD7D8190ACFFBA4977607AB8CB19788BDC7323A7A1D91B7AF8BE6A4386ADB47BEA4B4D93C01665CD605D5677B9A2B75A7BEE386FB1DABA09ED209915616BC544167B97C9E23DE77B757D5B98E63CCA9051B6D882313B4477D10B04128E6FBA7E1EAE23FBFB64C8D091EE233FCDEE91A0EA195CE511C3DF4B24C17B9D36389EF5CEB3BEE6D9A50ED35E3BB72E95040851A4AD2910CE6EC35A17AD1715DA7BD121190876203457836838B0415A53F62F9A6C4CB2B1B8E811FD78023FB5A119214D192B813E9B82B82574D36A5DFB1EA9A03D20ED2DF12A04944FB9BA283E0B290BA7370B5098A328AA70A1455CF166EC6A6DDC0704FCDE258E1F7363B4A46B4AD1B6E749D7CB8F",
|
||||
"F5D303C2E38227359BA4A64727A9424DE88D41EEC961697385529C4587980D62",
|
||||
true,
|
||||
},
|
||||
{
|
||||
90,
|
||||
"83E76806808ACAAA120286650F965DEDBC6E00E13563B5547A345981FBB177A6CD6598B358F56C3B272AA2106FC8901FEC0633391BA78DD344D17A219C3AA103A8B078BB3451D690D81AB22B858231850672A92270D95209F01123E6620B043F8B64ABF9252087365E51B8789B76995EE0098CB2AAEEA6760935A9390746EAD04270B91CB08B87ED1905335895D766CB8D229AE939A154A0680C583FD2D0CD71009D8D26A9B6F90C5A463125BC63ED2165BBC12AFD5866518110C4E809CED8932F5149EEA59FE806091906CE6D53AAD7045A69A74540C738B4E948FB470073D35DC6A536475AC8A037A1DB842D742A2D2A41C708C9125EA746D309981B51719CB31A7BA412DD11AD1C1C33C7810F016498EDBA6938D00BE7902E20AC9EFAC7C8E0A22FA5EA711B0ABBA13BBE5138A11244B81AE04C65987B7A5428430980BE57575881260B1780DAF3086C94AEDD0295A793414552B2168300A5A9B077F82FB8A2B697C7CAD06078184896C0D87BD5F8A6A967266E051A2E984B335A88D59285D06775B7F25C48F431A735BC9837AF8383365D8CC06052416B826B3A888314696B7CF67F20C2345CF1113A666A1A63B878610D24744FFD9B8F8A889F3E065ECE25827E137E33E56956FC60CC2423CC6AB8F272AF00179D98E014BE1A2D6DB202399B272CC33AFB2B0F1F502636CB1CB74279D66884F0169E2FE334F268ABDCA372B36084A784B34AD0998BD742263B2119C65527F61C11816724D577B1E77A911A5D9C005F10106A7E8C6292716E27B55EDA339A7A88C62AE166FC324BCB8529C4115969E1C28237977D70C950B31C50D036B0B5584273CCF9B87250666365029F3287429C69943E488C053240B2707EF6CA58D8C840766250853A4BDB938A258B004F0705F0DA8D2D97C753884319D7A2CBBCB357DBCC1134039D205BFDA3306F61C4E28C1271112353B827A2A98996135DBD76B04D4545DDD4B111184B2A787B326A3C0466159114A9BF6C801780BAABFBB578096B73245B3EAA17161530DA777306BA614AEC5D60376288AC7F0E66A4989B93920C37F18A2F91F045DA13A2E7777FB3922A48E9211962A4E9A47BFE467B707091AF86BF8CEB111EFC9745BAA22300C447C28181721AC8A7B51C9470A8F999B7E2268ADC327C160A3F42CCA0C9094DFB65BBAA5CB0153F85225E5C83AEAC55932F19B6A9E077E2BCA1E0221EF4191DD53940063799BEE5B0A5336B6D8324A1A6AC5A865071CAC33C6930974C0A54675BE7392B8227C09EB59706442618F68FCF5977D19C06B5EC6AB8D5C3F5712B96F20ED16A1E170B40219B003A5A453E5B58AB92A786FCAFAE855D3FA66724125D069251CD04277CB1B2065728E7B4437A9954CF711616C25156353194D336F75080BD706ADFFC51D1F7163662B0F84B625226249D15CF7C33206F5249E7325548149421620852F2BECEC6BA28476935BB0F27E181E9508B9838A51DC68EBC70653ED8B5E2D68DD9895F5223A418C49951B5CCCA8494D86AB2E6D773FBB55884E2AC16DC9418100A774548E4A95AF4265772E9A3A082CED78AB81CF15DCC1C24F7D4889CC606A137B29C31A1BDAC4FB050ACB1D28D9C07B3D9973DB9A763044A6F13AF75A46DC7D480380940F9D688DE684BDF867C21EF4BDBF50908DB04",
|
||||
"37782D0B89341726615D95246DA633E2BCA9D71B477B77150CACB7BB5A0ED4565644A2565EBBC4AD742AC5718F3A63518D3818A3FC31DC5552EE033522622AB75027BCC39C741B3524E51A26D12C02628BC363AA0D908330B356A412911BDB8042768FACE36B02E5126DEB6592590AC5D867EF937A2BDC3A74930C183411342AB5D0E77031859F3877A1E71B9C50200EFA04730D5A223760A62BD4B1F0615A0EA902492404523AC1F485253CC10BAB97503808C565808DEB9B3176532975638923678002E232AD68666539407AE1CEF8129702C8B58E69060DB422C49B67426214F7DB20C2FC857F52B174D6C93BE90B4A58811EE27E453382E12918652CA9F0313A8BECB7D8D7C9EC4830142539BDD92582D00234503D6FD8CE12F806A5381232D6BF0F0391EF8A1B288038FCAA98956C546AF47327009CA65326521A553F2A4E3983B052B3420D20303D378C6AF110B3451CCD5A4AE4AA83F7B2C20BC27542318690FBB2F542A3A51930E04B9FB6109C15F72B825656586C8B76F54F5382ABFE34CF91471922C9BD2D600003156C621579A0C61626A7C2D0BB7AFF95863A89C3D4722916397601630DE0E158AA9B5974A95107E0ABB6A66308123241275613C210495CAD017202508464847B4BE8792D4DC9017BD94FCE873A30C0A587A16CC7941413785AB6969CC90C47235847AD4CB1769835F195871712AA467C5DF1B30D06BB907C6519CA4AA3DC9884262339D4441C078049995BAD49FB8FD95219EA3CCF17C17F97213AD862710A60CAED990D5CF01919764218D672D9B5050AF0524A7AC67B8A38A4FA5C755050F9431584970BF6775F2609559F3807FBCA6EB67B9C67F6B0A0B4B527D563BEB415AC4989473758E31BBDC8F517911B1E431B88B7E871EA33A052FB1D2536032C561DDEB6526E652E1DF338E9C179539C891421AAF6067F550052140B89E5942E42337A1DB8CC3D88760A1498D5F407497925238A79A0B469FB2BBA70D93195F4017E0008FCC65D0635C9FDBB74EC4C4C50455E1E5B893D03764861964A9C3703FBC6A6FA557D34AA5C352D67C370DE7608E83670A48692FEB4CA17B842BCC8AAC7B0AA4546A607157DD2529182703E8AF6818E836635C428E136BDEED6678F962B1CE847D993B5F7B57370390B74261909A3963264A21DD4886A812A44CA2CB82A06EBD7C1280CA993F542EB36CB656A140471195A56C750073906B6115DC17A93E79D7E6037883349EF3B0469E984B8D63BA932BC592A09643B7C675567B676B25E46AEBC61265872CE01F61F75E4AA086B82B2F51364C3065CD880078933F606B114DACEB97AC9B535115F8166B5E9C1E23C1BD6406534A0209DC96063632682185E8E8C6B86FA3B073AA765718C8E42BBCCC16D1137270374C12A076295B0B61060341148BD64BB5553D2AE933274A034CE5CD62DE96118947877A934A28AF22F5F3410722C22B4839DC72AC2DD8222FCFB918A81ABB2422B30313484292695478F521396114A8FF0FBCCFE94A028743A7FC34EB9DBAD283C891E6A18765812FFB658EA58842BBB1232EAABDB332BA111BE36100745A842F8F3B19809C2E3C554BA3B312042C17F298FE7C1910E6774B934C283E76806808ACAAA120286650F965DEDBC6E00E13563B5547A345981FBB177A6CD6598B358F56C3B272AA2106FC8901FEC0633391BA78DD344D17A219C3AA103A8B078BB3451D690D81AB22B858231850672A92270D95209F01123E6620B043F8B64ABF9252087365E51B8789B76995EE0098CB2AAEEA6760935A9390746EAD04270B91CB08B87ED1905335895D766CB8D229AE939A154A0680C583FD2D0CD71009D8D26A9B6F90C5A463125BC63ED2165BBC12AFD5866518110C4E809CED8932F5149EEA59FE806091906CE6D53AAD7045A69A74540C738B4E948FB470073D35DC6A536475AC8A037A1DB842D742A2D2A41C708C9125EA746D309981B51719CB31A7BA412DD11AD1C1C33C7810F016498EDBA6938D00BE7902E20AC9EFAC7C8E0A22FA5EA711B0ABBA13BBE5138A11244B81AE04C65987B7A5428430980BE57575881260B1780DAF3086C94AEDD0295A793414552B2168300A5A9B077F82FB8A2B697C7CAD06078184896C0D87BD5F8A6A967266E051A2E984B335A88D59285D06775B7F25C48F431A735BC9837AF8383365D8CC06052416B826B3A888314696B7CF67F20C2345CF1113A666A1A63B878610D24744FFD9B8F8A889F3E065ECE25827E137E33E56956FC60CC2423CC6AB8F272AF00179D98E014BE1A2D6DB202399B272CC33AFB2B0F1F502636CB1CB74279D66884F0169E2FE334F268ABDCA372B36084A784B34AD0998BD742263B2119C65527F61C11816724D577B1E77A911A5D9C005F10106A7E8C6292716E27B55EDA339A7A88C62AE166FC324BCB8529C4115969E1C28237977D70C950B31C50D036B0B5584273CCF9B87250666365029F3287429C69943E488C053240B2707EF6CA58D8C840766250853A4BDB938A258B004F0705F0DA8D2D97C753884319D7A2CBBCB357DBCC1134039D205BFDA3306F61C4E28C1271112353B827A2A98996135DBD76B04D4545DDD4B111184B2A787B326A3C0466159114A9BF6C801780BAABFBB578096B73245B3EAA17161530DA777306BA614AEC5D60376288AC7F0E66A4989B93920C37F18A2F91F045DA13A2E7777FB3922A48E9211962A4E9A47BFE467B707091AF86BF8CEB111EFC9745BAA22300C447C28181721AC8A7B51C9470A8F999B7E2268ADC327C160A3F42CCA0C9094DFB65BBAA5CB0153F85225E5C83AEAC55932F19B6A9E077E2BCA1E0221EF4191DD53940063799BEE5B0A5336B6D8324A1A6AC5A865071CAC33C6930974C0A54675BE7392B8227C09EB59706442618F68FCF5977D19C06B5EC6AB8D5C3F5712B96F20ED16A1E170B40219B003A5A453E5B58AB92A786FCAFAE855D3FA66724125D069251CD04277CB1B2065728E7B4437A9954CF711616C25156353194D336F75080BD706ADFFC51D1F7163662B0F84B625226249D15CF7C33206F5249E7325548149421620852F2BECEC6BA28476935BB0F27E181E9508B9838A51DC68EBC70653ED8B5E2D68DD9895F5223A418C49951B5CCCA8494D86AB2E6D773FBB55884E2AC16DC9418100A774548E4A95AF4265772E9A3A082CED78AB81CF15DCC1C24F7D4889CC606A137B29C31A1BDAC4FB050ACB1D28D9C07B3D9973DB9A763044A6F13AF75A46DC7D480380940F9D688DE684BDF867C21EF4BDBF50908DB04620C3BA3112D18C0B347C5A0CFE56E720693645641009674E2E2F6E5DA0447A798028E8157DBAAFD5B9370227C9D876818A9A4F7D23D9567BF413F3383F8F1AB",
|
||||
"F58D542A5D03DD8D622D2D61E9CC759873479DB67359DAB471DE0C6945505EF8EF61734E84EF78D5A36EEA0FE8E6006B0741C415A225834C644AFB29E4CBF207C24F7760024BA27F1BFAB5A9EC712C3A81FC2F232736BA2CA69AA2F9CA7AC17EEB89A193493800951C71812E4E2134680B3BE6FFCE9508C791EB19494D86F9192990D0745AEFED3A83B24A6E7C8C2BA6CB536D2710C49D2C3122D090B95E57C8E1DECDBAD54BF7CC1E76E79448EBAAD77284E35FA03567FC692D2D8E674D7D805899BD00C35615FAC52298BAE7D87C7CAFA3734E95FC8C7EABD0C3224BBDF0F32B61491C1C060DCDD2492516CC4419DAD6AFEF3B96A1504A9F0CE09F1774E607F3E9AC4484F41B7AF8BE402EFB12680AE98B71557562A8C1D3486C5998515D9BF87CD173F5A79BA90EEEDDFF7E0F323D8920C41A80320CCFB2157A0E9148FAFDA7FD68828E5B612B373342872F3FDB0F77F2339D96BB49D2F5E172E0523C04DE0E3C80C89F5640B84FD8B372AFB3319150D7057A9293EA36A53275FC778BE736F468AB4FDDCEF2CB40D42AB8C834B5DC08C1E3B9E7CFEA61373A46595FD2E3DCC164C7B5212F98D3AAD9FE7E08585E0111265ED71F94725E3E4D9873487C407C74B03EE254EC8D9B041D817E6E9D0827626438822595FF14503D0257F04D99352C5BB09DEC0696804260516684308C1B7B60D86A27F724D10080FA4A2B70C90090C9D3DBBB2D681EA2EDF35A73AEB3A77E4338C5631E0842AC53137379E8A653291CDE9CC3421B2417A0C59A1A3E4AF60F455FB01A65E9BCD415B77D6486495D453BA9ED0C79237313D89019FAA1BF89EF849A752389CC2A8D1E677DB68A4E4CD81A2CB9F09E0531C11BB6FCF0FAD67507A86B174F45C033B1988C6B433E9E66CA7CA69A39446FFE2B219C9A9B3CB808C067E781765991665FB40B5780E307B39C370EF01C6000660827D5CAD3E1BBD28BCE05AC0443A2806EFB93CCA9C7ED3C18FA6D58C99C5E6B6AF785636384643BD2E24F6A705012AD7A4D2E6B94CC9908C086F13515C42EFC4CDEFEB2645D106AE385D4014B983DF6A099438954586928D46476A2E70E36147B8F57DC498DC564C62CAB6C00638895D864438E8C3FB075449A7636BAD20A0C8BD433BA1C6B4E3E8E42ABD6AFD23CD6D76A4DEEBF898F699094F1E2EC5E857142C0EC0FE724F040A02CF191D2DDC0A4880D89A0ECAFF00BFD2E26588180EC93B6E3ACE0D45573CBE0B836A9547D12F00BE77B059B0F73FF36827033795F877CD347ABEE7222697440A8EE6F9F9D4747C7DF26C92CAD12747AC6442066CBEEE4B072F5E1809724B462BDD86309A08C96E23D8BDC7006129C41CD1524E9DB13475F8DBB58B9F8EE722FFEFE0628AFD711A1A66CC03F7A1D26A321093179877A1E9CB223CD688F65772C1F550C86FD9025B58F6A1DC9CEC65816EBFB2CB405526F797A500B52EA73AFE592E7A63BE79D6E2ABFE03D528154C0E8D277C844EFA398B346D96F41376FD969356114854C1997D53189404F499165",
|
||||
"44CC405E3BB0A9F51A180A86213D036ED58AA0D226804E717B9C2A475DE58E75",
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
func TestDecapsulate768ACVP(t *testing.T) {
|
||||
for i, tc := range decap768InternalProjectionCases {
|
||||
//ek, _ := hex.DecodeString(tc.ek)
|
||||
dk, _ := hex.DecodeString(tc.dk)
|
||||
c, _ := hex.DecodeString(tc.c)
|
||||
k, _ := hex.DecodeString(tc.k)
|
||||
|
||||
dk1, err := NewDecapsulationKey768(dk)
|
||||
if err != nil {
|
||||
t.Fatalf("case %d: NewDecapsulationKey768: %v", i, err)
|
||||
}
|
||||
if !tc.success {
|
||||
c[0] ^= 0xFF // Corrupt the ciphertext to force failure
|
||||
}
|
||||
k1, err := dk1.Decapsulate(c)
|
||||
if tc.success {
|
||||
if err != nil {
|
||||
t.Fatalf("case %d: Decapsulate: %v", i, err)
|
||||
}
|
||||
if !bytes.Equal(k1, k) {
|
||||
t.Fatalf("case %d: shared secret mismatch", i)
|
||||
}
|
||||
} else {
|
||||
if bytes.Equal(k1, k) {
|
||||
t.Fatalf("case %d: decapsulation should have failed", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkKeyGen768(b *testing.B) {
|
||||
var seed [64]byte
|
||||
rand.Read(seed[:])
|
||||
b.ResetTimer()
|
||||
for b.Loop() {
|
||||
if _, err := NewDecapsulationKeyFromSeed768(seed[:]); err != nil {
|
||||
b.Fatalf("NewDecapsulationKeyFromSeed768 failed: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func BenchmarkEncapsulateInternal768(b *testing.B) {
|
||||
tc := encap768InternalProjectionCases[0]
|
||||
ek, _ := hex.DecodeString(tc.ek)
|
||||
m, _ := hex.DecodeString(tc.m)
|
||||
ek1, err := NewEncapsulationKey768(ek)
|
||||
if err != nil {
|
||||
b.Fatalf("NewEncapsulationKey768: %v", err)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for b.Loop() {
|
||||
ek1.EncapsulateInternal((*[32]byte)(m))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDecapsulate768(b *testing.B) {
|
||||
tc := decap768InternalProjectionCases[0]
|
||||
dk, _ := hex.DecodeString(tc.dk)
|
||||
c, _ := hex.DecodeString(tc.c)
|
||||
|
||||
dk1, err := NewDecapsulationKey768(dk)
|
||||
if err != nil {
|
||||
b.Fatalf("NewDecapsulationKey768: %v", err)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for b.Loop() {
|
||||
if _, err := dk1.Decapsulate(c); err != nil {
|
||||
b.Fatalf("Decapsulate: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user