From 90d75657facfac97d7ebeb77f334eb5631212fcc Mon Sep 17 00:00:00 2001 From: Bas Westerbaan Date: Tue, 18 Apr 2023 14:11:16 +0200 Subject: [PATCH 01/47] Add TurboShake{128,256} --- internal/sha3/keccakf.go | 12 ++- internal/sha3/sha3.go | 7 +- internal/sha3/sha3_test.go | 38 +++++++++- internal/sha3/shake.go | 36 +++++++++ pke/kyber/internal/common/sample.go | 2 +- sign/dilithium/mode2/internal/sample.go | 4 +- sign/dilithium/mode2aes/internal/sample.go | 4 +- sign/dilithium/mode3/internal/sample.go | 4 +- sign/dilithium/mode3aes/internal/sample.go | 4 +- sign/dilithium/mode5/internal/sample.go | 4 +- sign/dilithium/mode5aes/internal/sample.go | 4 +- simd/keccakf1600/example_test.go | 2 +- simd/keccakf1600/f1600x.go | 42 +++++++---- simd/keccakf1600/f1600x2_arm64.go | 6 +- simd/keccakf1600/f1600x2_arm64.s | 10 ++- simd/keccakf1600/f1600x4_amd64.go | 4 +- simd/keccakf1600/f1600x4_amd64.s | 17 +++-- simd/keccakf1600/f1600x4stubs_amd64.go | 3 +- simd/keccakf1600/f1600x_test.go | 85 +++++++++++++++------- simd/keccakf1600/fallback.go | 4 +- simd/keccakf1600/internal/asm/go.mod | 5 +- simd/keccakf1600/internal/asm/go.sum | 59 +++++++++++---- simd/keccakf1600/internal/asm/src.go | 9 ++- 23 files changed, 271 insertions(+), 94 deletions(-) diff --git a/internal/sha3/keccakf.go b/internal/sha3/keccakf.go index ab19d0ad1..1755fd1e6 100644 --- a/internal/sha3/keccakf.go +++ b/internal/sha3/keccakf.go @@ -6,13 +6,21 @@ package sha3 // KeccakF1600 applies the Keccak permutation to a 1600b-wide // state represented as a slice of 25 uint64s. +// If turbo is true, applies the 12-round variant instead of the +// regular 24-round variant. // nolint:funlen -func KeccakF1600(a *[25]uint64) { +func KeccakF1600(a *[25]uint64, turbo bool) { // Implementation translated from Keccak-inplace.c // in the keccak reference code. var t, bc0, bc1, bc2, bc3, bc4, d0, d1, d2, d3, d4 uint64 - for i := 0; i < 24; i += 4 { + i := 0 + + if turbo { + i = 12 + } + + for ; i < 24; i += 4 { // Combines the 5 steps in each round into 2 steps. // Unrolls 4 rounds per loop and spreads some steps across rounds. diff --git a/internal/sha3/sha3.go b/internal/sha3/sha3.go index b35cd006b..01806d7d1 100644 --- a/internal/sha3/sha3.go +++ b/internal/sha3/sha3.go @@ -51,6 +51,7 @@ type State struct { // Specific to SHA-3 and SHAKE. outputLen int // the default output size in bytes state spongeDirection // whether the sponge is absorbing or squeezing + turbo bool // Whether we're using 12 rounds instead of 24 } // BlockSize returns the rate of sponge underlying this hash function. @@ -86,11 +87,11 @@ func (d *State) permute() { xorIn(d, d.buf()) d.bufe = 0 d.bufo = 0 - KeccakF1600(&d.a) + KeccakF1600(&d.a, d.turbo) case spongeSqueezing: // If we're squeezing, we need to apply the permutation before // copying more output. - KeccakF1600(&d.a) + KeccakF1600(&d.a, d.turbo) d.bufe = d.rate d.bufo = 0 copyOut(d, d.buf()) @@ -136,7 +137,7 @@ func (d *State) Write(p []byte) (written int, err error) { // The fast path; absorb a full "rate" bytes of input and apply the permutation. xorIn(d, p[:d.rate]) p = p[d.rate:] - KeccakF1600(&d.a) + KeccakF1600(&d.a, d.turbo) } else { // The slow path; buffer the input until we can fill the sponge, and then xor it in. todo := d.rate - bufl diff --git a/internal/sha3/sha3_test.go b/internal/sha3/sha3_test.go index b4850afa7..b3b5e3d38 100644 --- a/internal/sha3/sha3_test.go +++ b/internal/sha3/sha3_test.go @@ -161,13 +161,23 @@ func sequentialBytes(size int) []byte { return result } +// BenchmarkPermutationFunctionTurbo measures the speed of the permutation +// function with no input data. +func BenchmarkPermutationFunctionTurbo(b *testing.B) { + b.SetBytes(int64(200)) + var lanes [25]uint64 + for i := 0; i < b.N; i++ { + KeccakF1600(&lanes, true) + } +} + // BenchmarkPermutationFunction measures the speed of the permutation function // with no input data. func BenchmarkPermutationFunction(b *testing.B) { b.SetBytes(int64(200)) var lanes [25]uint64 for i := 0; i < b.N; i++ { - KeccakF1600(&lanes) + KeccakF1600(&lanes, false) } } @@ -220,6 +230,9 @@ func BenchmarkShake256_MTU(b *testing.B) { benchmarkShake(b, NewShake256(), 135 func BenchmarkShake256_16x(b *testing.B) { benchmarkShake(b, NewShake256(), 16, 1024) } func BenchmarkShake256_1MiB(b *testing.B) { benchmarkShake(b, NewShake256(), 1024, 1024) } +func BenchmarkTurboShake128_1MiB(b *testing.B) { benchmarkShake(b, NewTurboShake128(0x37), 1024, 1024) } +func BenchmarkTurboShake256_1MiB(b *testing.B) { benchmarkShake(b, NewTurboShake256(0x37), 1024, 1024) } + func BenchmarkSha3_512_1MiB(b *testing.B) { benchmarkHash(b, New512(), 1024, 1024) } func Example_sum() { @@ -247,3 +260,26 @@ func Example_mac() { fmt.Printf("%x\n", h) // Output: 78de2974bd2711d5549ffd32b753ef0f5fa80a0db2556db60f0987eb8a9218ff } + +func TestTurboShake128(t *testing.T) { + out := make([]byte, 64) + TurboShakeSum128(out, []byte{}, 0x07) + if hex.EncodeToString(out) != "5a223ad30b3b8c66a243048cfced430f54e7529287d15150b973133adfac6a2ffe2708e73061e09a4000168ba9c8ca1813198f7bbed4984b4185f2c2580ee623" { + t.Fatal() + } + + h := NewTurboShake128(0x07) + out = make([]byte, 10032) + _, _ = h.Read(out) + if hex.EncodeToString(out[len(out)-32:]) != "7593a28020a3c4ae0d605fd61f5eb56eccd27cc3d12ff09f78369772a460c55d" { + t.Fatal() + } + + out = make([]byte, 32) + TurboShakeSum128(out, []byte{0xff}, 0x06) + if hex.EncodeToString(out) != "8ec9c66465ed0d4a6c35d13506718d687a25cb05c74cca1e42501abd83874a67" { + t.Fatal() + } + + // TODO all tests +} diff --git a/internal/sha3/shake.go b/internal/sha3/shake.go index b92c5b7d7..2a14d78a3 100644 --- a/internal/sha3/shake.go +++ b/internal/sha3/shake.go @@ -57,6 +57,17 @@ func NewShake128() State { return State{rate: rate128, dsbyte: dsbyteShake} } +// NewTurboShake128 creates a new TurboSHAKE128 variable-output-length ShakeHash. +// Its generic security strength is 128 bits against all attacks if at +// least 32 bytes of its output are used. +// D is the domain separation byte and must be between 0x01 and 0x7f inclusive. +func NewTurboShake128(D byte) State { + if D == 0 || D > 0x7f { + panic("turboshake: D out of range") + } + return State{rate: rate128, dsbyte: D, turbo: true} +} + // NewShake256 creates a new SHAKE256 variable-output-length ShakeHash. // Its generic security strength is 256 bits against all attacks if // at least 64 bytes of its output are used. @@ -64,6 +75,17 @@ func NewShake256() State { return State{rate: rate256, dsbyte: dsbyteShake} } +// NewTurboShake256 creates a new TurboSHAKE256 variable-output-length ShakeHash. +// Its generic security strength is 256 bits against all attacks if +// at least 64 bytes of its output are used. +// D is the domain separation byte and must be between 0x01 and 0x7f inclusive. +func NewTurboShake256(D byte) State { + if D == 0 || D > 0x7f { + panic("turboshake: D out of range") + } + return State{rate: rate256, dsbyte: D, turbo: true} +} + // ShakeSum128 writes an arbitrary-length digest of data into hash. func ShakeSum128(hash, data []byte) { h := NewShake128() @@ -77,3 +99,17 @@ func ShakeSum256(hash, data []byte) { _, _ = h.Write(data) _, _ = h.Read(hash) } + +// TurboShakeSum128 writes an arbitrary-length digest of data into hash. +func TurboShakeSum128(hash, data []byte, D byte) { + h := NewTurboShake128(D) + _, _ = h.Write(data) + _, _ = h.Read(hash) +} + +// TurboShakeSum256 writes an arbitrary-length digest of data into hash. +func TurboShakeSum256(hash, data []byte, D byte) { + h := NewTurboShake256(D) + _, _ = h.Write(data) + _, _ = h.Read(hash) +} diff --git a/pke/kyber/internal/common/sample.go b/pke/kyber/internal/common/sample.go index 1f15f32c8..ed5a33dd9 100644 --- a/pke/kyber/internal/common/sample.go +++ b/pke/kyber/internal/common/sample.go @@ -100,7 +100,7 @@ func (p *Poly) DeriveNoise2(seed []byte, nonce uint8) { // Can only be called when DeriveX4Available is true. func PolyDeriveUniformX4(ps [4]*Poly, seed *[32]byte, xs, ys [4]uint8) { var perm keccakf1600.StateX4 - state := perm.Initialize() + state := perm.Initialize(false) // Absorb the seed in the four states for i := 0; i < 4; i++ { diff --git a/sign/dilithium/mode2/internal/sample.go b/sign/dilithium/mode2/internal/sample.go index db5aac8cb..fa866293c 100644 --- a/sign/dilithium/mode2/internal/sample.go +++ b/sign/dilithium/mode2/internal/sample.go @@ -20,7 +20,7 @@ var DeriveX4Available = keccakf1600.IsEnabledX4() && !UseAES // Can only be called when DeriveX4Available is true. func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { var perm keccakf1600.StateX4 - state := perm.Initialize() + state := perm.Initialize(false) // Absorb the seed in the four states for i := 0; i < 4; i++ { @@ -248,7 +248,7 @@ func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { // This function is currently not used (yet). func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed *[32]byte) { var perm keccakf1600.StateX4 - state := perm.Initialize() + state := perm.Initialize(false) // Absorb the seed in the four states for i := 0; i < 4; i++ { diff --git a/sign/dilithium/mode2aes/internal/sample.go b/sign/dilithium/mode2aes/internal/sample.go index db5aac8cb..fa866293c 100644 --- a/sign/dilithium/mode2aes/internal/sample.go +++ b/sign/dilithium/mode2aes/internal/sample.go @@ -20,7 +20,7 @@ var DeriveX4Available = keccakf1600.IsEnabledX4() && !UseAES // Can only be called when DeriveX4Available is true. func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { var perm keccakf1600.StateX4 - state := perm.Initialize() + state := perm.Initialize(false) // Absorb the seed in the four states for i := 0; i < 4; i++ { @@ -248,7 +248,7 @@ func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { // This function is currently not used (yet). func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed *[32]byte) { var perm keccakf1600.StateX4 - state := perm.Initialize() + state := perm.Initialize(false) // Absorb the seed in the four states for i := 0; i < 4; i++ { diff --git a/sign/dilithium/mode3/internal/sample.go b/sign/dilithium/mode3/internal/sample.go index c6ae31dd0..ccde1f2ed 100644 --- a/sign/dilithium/mode3/internal/sample.go +++ b/sign/dilithium/mode3/internal/sample.go @@ -18,7 +18,7 @@ var DeriveX4Available = keccakf1600.IsEnabledX4() && !UseAES // Can only be called when DeriveX4Available is true. func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { var perm keccakf1600.StateX4 - state := perm.Initialize() + state := perm.Initialize(false) // Absorb the seed in the four states for i := 0; i < 4; i++ { @@ -246,7 +246,7 @@ func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { // This function is currently not used (yet). func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed *[32]byte) { var perm keccakf1600.StateX4 - state := perm.Initialize() + state := perm.Initialize(false) // Absorb the seed in the four states for i := 0; i < 4; i++ { diff --git a/sign/dilithium/mode3aes/internal/sample.go b/sign/dilithium/mode3aes/internal/sample.go index db5aac8cb..fa866293c 100644 --- a/sign/dilithium/mode3aes/internal/sample.go +++ b/sign/dilithium/mode3aes/internal/sample.go @@ -20,7 +20,7 @@ var DeriveX4Available = keccakf1600.IsEnabledX4() && !UseAES // Can only be called when DeriveX4Available is true. func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { var perm keccakf1600.StateX4 - state := perm.Initialize() + state := perm.Initialize(false) // Absorb the seed in the four states for i := 0; i < 4; i++ { @@ -248,7 +248,7 @@ func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { // This function is currently not used (yet). func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed *[32]byte) { var perm keccakf1600.StateX4 - state := perm.Initialize() + state := perm.Initialize(false) // Absorb the seed in the four states for i := 0; i < 4; i++ { diff --git a/sign/dilithium/mode5/internal/sample.go b/sign/dilithium/mode5/internal/sample.go index db5aac8cb..fa866293c 100644 --- a/sign/dilithium/mode5/internal/sample.go +++ b/sign/dilithium/mode5/internal/sample.go @@ -20,7 +20,7 @@ var DeriveX4Available = keccakf1600.IsEnabledX4() && !UseAES // Can only be called when DeriveX4Available is true. func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { var perm keccakf1600.StateX4 - state := perm.Initialize() + state := perm.Initialize(false) // Absorb the seed in the four states for i := 0; i < 4; i++ { @@ -248,7 +248,7 @@ func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { // This function is currently not used (yet). func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed *[32]byte) { var perm keccakf1600.StateX4 - state := perm.Initialize() + state := perm.Initialize(false) // Absorb the seed in the four states for i := 0; i < 4; i++ { diff --git a/sign/dilithium/mode5aes/internal/sample.go b/sign/dilithium/mode5aes/internal/sample.go index db5aac8cb..fa866293c 100644 --- a/sign/dilithium/mode5aes/internal/sample.go +++ b/sign/dilithium/mode5aes/internal/sample.go @@ -20,7 +20,7 @@ var DeriveX4Available = keccakf1600.IsEnabledX4() && !UseAES // Can only be called when DeriveX4Available is true. func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { var perm keccakf1600.StateX4 - state := perm.Initialize() + state := perm.Initialize(false) // Absorb the seed in the four states for i := 0; i < 4; i++ { @@ -248,7 +248,7 @@ func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { // This function is currently not used (yet). func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed *[32]byte) { var perm keccakf1600.StateX4 - state := perm.Initialize() + state := perm.Initialize(false) // Absorb the seed in the four states for i := 0; i < 4; i++ { diff --git a/simd/keccakf1600/example_test.go b/simd/keccakf1600/example_test.go index 8c2e4c875..0385de4ee 100644 --- a/simd/keccakf1600/example_test.go +++ b/simd/keccakf1600/example_test.go @@ -38,7 +38,7 @@ func Example() { // type is used to ensure that the encapsulated [100]uint64 is aligned // properly to be used efficiently with vector instructions.) var perm keccakf1600.StateX4 - state := perm.Initialize() + state := perm.Initialize(false) // state is initialized with zeroes. As the messages fit within one // block, we only need to write the messages, domain separators diff --git a/simd/keccakf1600/f1600x.go b/simd/keccakf1600/f1600x.go index 7ce0c2ef8..20ac96f00 100644 --- a/simd/keccakf1600/f1600x.go +++ b/simd/keccakf1600/f1600x.go @@ -17,6 +17,7 @@ package keccakf1600 import ( + "runtime" "unsafe" "github.com/cloudflare/circl/internal/sha3" @@ -37,6 +38,9 @@ type StateX4 struct { // Offset into a that is 32 byte aligned. offset int + + // If true, permute will use 12-round keccak instead of 24-round keccak + turbo bool } // StateX2 contains state for the two-way permutation including the two @@ -53,6 +57,9 @@ type StateX2 struct { // Offset into a that is 32 byte aligned. offset int + + // If true, permute will use 12-round keccak instead of 24-round keccak + turbo bool } // IsEnabledX4 returns true if the architecture supports a four-way SIMD @@ -61,15 +68,14 @@ func IsEnabledX4() bool { return cpu.X86.HasAVX2 } // IsEnabledX2 returns true if the architecture supports a two-way SIMD // implementation provided in this package. -func IsEnabledX2() bool { - // After Go 1.16 the flag cpu.ARM64.HasSHA3 is no longer exposed. - return false -} +func IsEnabledX2() bool { return enabledX2 } // Initialize the state and returns the buffer on which the four permutations // will act: a uint64 slice of length 100. The first permutation will act // on {a[0], a[4], ..., a[96]}, the second on {a[1], a[5], ..., a[97]}, etc. -func (s *StateX4) Initialize() []uint64 { +// If turbo is true, applies 12-round variant instead of the usual 24. +func (s *StateX4) Initialize(turbo bool) []uint64 { + s.turbo = turbo rp := unsafe.Pointer(&s.a[0]) // uint64s are always aligned by a multiple of 8. Compute the remainder @@ -87,7 +93,9 @@ func (s *StateX4) Initialize() []uint64 { // Initialize the state and returns the buffer on which the two permutations // will act: a uint64 slice of length 50. The first permutation will act // on {a[0], a[2], ..., a[48]} and the second on {a[1], a[3], ..., a[49]}. -func (s *StateX2) Initialize() []uint64 { +// If turbo is true, applies 12-round variant instead of the usual 24. +func (s *StateX2) Initialize(turbo bool) []uint64 { + s.turbo = turbo rp := unsafe.Pointer(&s.a[0]) // uint64s are always aligned by a multiple of 8. Compute the remainder @@ -106,9 +114,9 @@ func (s *StateX2) Initialize() []uint64 { // returned from Initialize(). func (s *StateX4) Permute() { if IsEnabledX4() { - permuteSIMDx4(s.a[s.offset:]) + permuteSIMDx4(s.a[s.offset:], s.turbo) } else { - permuteScalarX4(s.a[s.offset:]) // A slower generic implementation. + permuteScalarX4(s.a[s.offset:], s.turbo) // A slower generic implementation. } } @@ -116,34 +124,40 @@ func (s *StateX4) Permute() { // returned from Initialize(). func (s *StateX2) Permute() { if IsEnabledX2() { - permuteSIMDx2(s.a[s.offset:]) + permuteSIMDx2(s.a[s.offset:], s.turbo) } else { - permuteScalarX2(s.a[s.offset:]) // A slower generic implementation. + permuteScalarX2(s.a[s.offset:], s.turbo) // A slower generic implementation. } } -func permuteScalarX4(a []uint64) { +func permuteScalarX4(a []uint64, turbo bool) { var buf [25]uint64 for i := 0; i < 4; i++ { for j := 0; j < 25; j++ { buf[j] = a[4*j+i] } - sha3.KeccakF1600(&buf) + sha3.KeccakF1600(&buf, turbo) for j := 0; j < 25; j++ { a[4*j+i] = buf[j] } } } -func permuteScalarX2(a []uint64) { +func permuteScalarX2(a []uint64, turbo bool) { var buf [25]uint64 for i := 0; i < 2; i++ { for j := 0; j < 25; j++ { buf[j] = a[2*j+i] } - sha3.KeccakF1600(&buf) + sha3.KeccakF1600(&buf, turbo) for j := 0; j < 25; j++ { a[2*j+i] = buf[j] } } } + +var enabledX2 bool + +func init() { + enabledX2 = runtime.GOARCH == "arm64" && runtime.GOOS == "darwin" +} diff --git a/simd/keccakf1600/f1600x2_arm64.go b/simd/keccakf1600/f1600x2_arm64.go index 75461dd7c..44f05436a 100644 --- a/simd/keccakf1600/f1600x2_arm64.go +++ b/simd/keccakf1600/f1600x2_arm64.go @@ -5,9 +5,9 @@ package keccakf1600 import "github.com/cloudflare/circl/internal/sha3" -func permuteSIMDx2(state []uint64) { f1600x2ARM(&state[0], &sha3.RC) } +func permuteSIMDx2(state []uint64, turbo bool) { f1600x2ARM(&state[0], &sha3.RC, turbo) } -func permuteSIMDx4(state []uint64) { permuteScalarX4(state) } +func permuteSIMDx4(state []uint64, turbo bool) { permuteScalarX4(state, turbo) } //go:noescape -func f1600x2ARM(state *uint64, rc *[24]uint64) +func f1600x2ARM(state *uint64, rc *[24]uint64, turbo bool) diff --git a/simd/keccakf1600/f1600x2_arm64.s b/simd/keccakf1600/f1600x2_arm64.s index 1e8547f9b..68dd0e37b 100644 --- a/simd/keccakf1600/f1600x2_arm64.s +++ b/simd/keccakf1600/f1600x2_arm64.s @@ -4,8 +4,8 @@ #include "textflag.h" -// func f1600x2ARM(state *uint64, rc *[24]uint64) -TEXT ·f1600x2ARM(SB), NOSPLIT, $0-16 +// func f1600x2ARM(state *uint64, rc *[24]uint64, turbo bool) +TEXT ·f1600x2ARM(SB), NOSPLIT, $0-17 MOVD state+0(FP), R0 MOVD rc+8(FP), R1 MOVD R0, R2 @@ -19,6 +19,12 @@ TEXT ·f1600x2ARM(SB), NOSPLIT, $0-16 VLD1.P 64(R0), [V20.B16, V21.B16, V22.B16, V23.B16] VLD1.P (R0), [V24.B16] + MOVBU turbo+16(FP), R4 + CBZ R4, loop + + SUB $12, R3, R3 + ADD $96, R1, R1 + loop: // Execute theta but without xorring into the state yet. VEOR3 V10.B16, V5.B16, V0.B16, V25.B16 diff --git a/simd/keccakf1600/f1600x4_amd64.go b/simd/keccakf1600/f1600x4_amd64.go index ac5c658d5..669ce65f4 100644 --- a/simd/keccakf1600/f1600x4_amd64.go +++ b/simd/keccakf1600/f1600x4_amd64.go @@ -2,6 +2,6 @@ package keccakf1600 import "github.com/cloudflare/circl/internal/sha3" -func permuteSIMDx4(state []uint64) { f1600x4AVX2(&state[0], &sha3.RC) } +func permuteSIMDx4(state []uint64, turbo bool) { f1600x4AVX2(&state[0], &sha3.RC, turbo) } -func permuteSIMDx2(state []uint64) { permuteScalarX2(state) } +func permuteSIMDx2(state []uint64, turbo bool) { permuteScalarX2(state, turbo) } diff --git a/simd/keccakf1600/f1600x4_amd64.s b/simd/keccakf1600/f1600x4_amd64.s index 194981f10..314a85553 100644 --- a/simd/keccakf1600/f1600x4_amd64.s +++ b/simd/keccakf1600/f1600x4_amd64.s @@ -1,15 +1,20 @@ // Code generated by command: go run src.go -out ../../f1600x4_amd64.s -stubs ../../f1600x4stubs_amd64.go -pkg keccakf1600. DO NOT EDIT. -// +build amd64 +//go:build amd64 #include "textflag.h" -// func f1600x4AVX2(state *uint64, rc *[24]uint64) +// func f1600x4AVX2(state *uint64, rc *[24]uint64, turbo bool) // Requires: AVX, AVX2 -TEXT ·f1600x4AVX2(SB), NOSPLIT, $0-16 - MOVQ state+0(FP), AX - MOVQ rc+8(FP), CX - MOVQ $0x0000000000000006, DX +TEXT ·f1600x4AVX2(SB), NOSPLIT, $0-17 + MOVQ state+0(FP), AX + MOVQ rc+8(FP), CX + MOVQ $0x0000000000000006, DX + MOVBQZX turbo+16(FP), BX + TESTQ BX, BX + JZ loop + MOVQ $0x0000000000000003, DX + ADDQ $0x60, CX loop: VMOVDQA (AX), Y0 diff --git a/simd/keccakf1600/f1600x4stubs_amd64.go b/simd/keccakf1600/f1600x4stubs_amd64.go index 76c6cf999..de289441e 100644 --- a/simd/keccakf1600/f1600x4stubs_amd64.go +++ b/simd/keccakf1600/f1600x4stubs_amd64.go @@ -1,9 +1,8 @@ // Code generated by command: go run src.go -out ../../f1600x4_amd64.s -stubs ../../f1600x4stubs_amd64.go -pkg keccakf1600. DO NOT EDIT. //go:build amd64 -// +build amd64 package keccakf1600 //go:noescape -func f1600x4AVX2(state *uint64, rc *[24]uint64) +func f1600x4AVX2(state *uint64, rc *[24]uint64, turbo bool) diff --git a/simd/keccakf1600/f1600x_test.go b/simd/keccakf1600/f1600x_test.go index 09e83bba6..cd0cae40f 100644 --- a/simd/keccakf1600/f1600x_test.go +++ b/simd/keccakf1600/f1600x_test.go @@ -1,6 +1,9 @@ package keccakf1600 -import "testing" +import ( + "reflect" + "testing" +) // From the Keccak code package. var permutationOfZeroes = [25]uint64{ @@ -16,10 +19,10 @@ var permutationOfZeroes = [25]uint64{ } func TestKeccakF1600x2(t *testing.T) { - test := func(t *testing.T, f func(s *StateX2, a []uint64)) { + test := func(t *testing.T, turbo bool, f func(s *StateX2, a []uint64)) { t.Helper() var state StateX2 - a := state.Initialize() + a := state.Initialize(turbo) f(&state, a) for i := 0; i < 25; i++ { for j := 0; j < 2; j++ { @@ -31,18 +34,18 @@ func TestKeccakF1600x2(t *testing.T) { } t.Run("Generic", func(t *testing.T) { - test(t, func(s *StateX2, a []uint64) { permuteScalarX2(a) }) + test(t, false, func(s *StateX2, a []uint64) { permuteScalarX2(a, false) }) }) t.Run("SIMD", func(t *testing.T) { - test(t, func(s *StateX2, a []uint64) { s.Permute() }) + test(t, false, func(s *StateX2, a []uint64) { s.Permute() }) }) } func TestKeccakF1600x4(t *testing.T) { - test := func(t *testing.T, f func(s *StateX4, a []uint64)) { + test := func(t *testing.T, turbo bool, f func(s *StateX4, a []uint64)) { t.Helper() var state StateX4 - a := state.Initialize() + a := state.Initialize(turbo) f(&state, a) for i := 0; i < 25; i++ { for j := 0; j < 4; j++ { @@ -54,45 +57,77 @@ func TestKeccakF1600x4(t *testing.T) { } t.Run("Generic", func(t *testing.T) { - test(t, func(s *StateX4, a []uint64) { permuteScalarX4(a) }) + test(t, false, func(s *StateX4, a []uint64) { permuteScalarX4(a, false) }) }) t.Run("SIMD", func(t *testing.T) { - test(t, func(s *StateX4, a []uint64) { s.Permute() }) + test(t, false, func(s *StateX4, a []uint64) { s.Permute() }) }) } +func TestTurboX2(t *testing.T) { + var state1, state2 StateX2 + a1 := state1.Initialize(true) + a2 := state2.Initialize(true) + permuteScalarX2(a1, true) + state2.Permute() + if !reflect.DeepEqual(a1, a2) { + t.Fatal() + } +} + +func TestTurboX4(t *testing.T) { + var state1, state2 StateX4 + a1 := state1.Initialize(true) + a2 := state2.Initialize(true) + permuteScalarX4(a1, true) + state2.Permute() + if !reflect.DeepEqual(a1, a2) { + t.Fatal() + } +} + func BenchmarkF1600x2(b *testing.B) { - benchmark := func(b *testing.B, f func(s *StateX2, a []uint64)) { + benchmark := func(b *testing.B, turbo bool, f func(s *StateX2, a []uint64)) { var state StateX2 - a := state.Initialize() + a := state.Initialize(turbo) for i := 0; i < b.N; i++ { f(&state, a) } } - b.Run("Generic", func(b *testing.B) { - benchmark(b, func(s *StateX2, a []uint64) { permuteScalarX2(a) }) - }) - b.Run("SIMD", func(b *testing.B) { - benchmark(b, func(s *StateX2, a []uint64) { s.Permute() }) - }) + bench2 := func(b *testing.B, turbo bool) { + b.Run("Generic", func(b *testing.B) { + benchmark(b, turbo, func(s *StateX2, a []uint64) { permuteScalarX2(a, turbo) }) + }) + b.Run("SIMD", func(b *testing.B) { + benchmark(b, turbo, func(s *StateX2, a []uint64) { s.Permute() }) + }) + } + + b.Run("Regular", func(b *testing.B) { bench2(b, false) }) + b.Run("Turbo", func(b *testing.B) { bench2(b, true) }) } func BenchmarkF1600x4(b *testing.B) { - benchmark := func(b *testing.B, f func(s *StateX4, a []uint64)) { + benchmark := func(b *testing.B, turbo bool, f func(s *StateX4, a []uint64)) { var state StateX4 - a := state.Initialize() + a := state.Initialize(turbo) for i := 0; i < b.N; i++ { f(&state, a) } } - b.Run("Generic", func(b *testing.B) { - benchmark(b, func(s *StateX4, a []uint64) { permuteScalarX4(a) }) - }) - b.Run("SIMD", func(b *testing.B) { - benchmark(b, func(s *StateX4, a []uint64) { s.Permute() }) - }) + bench2 := func(b *testing.B, turbo bool) { + b.Run("Generic", func(b *testing.B) { + benchmark(b, turbo, func(s *StateX4, a []uint64) { permuteScalarX4(a, turbo) }) + }) + b.Run("SIMD", func(b *testing.B) { + benchmark(b, turbo, func(s *StateX4, a []uint64) { s.Permute() }) + }) + } + + b.Run("Regular", func(b *testing.B) { bench2(b, false) }) + b.Run("Turbo", func(b *testing.B) { bench2(b, true) }) } diff --git a/simd/keccakf1600/fallback.go b/simd/keccakf1600/fallback.go index 5d56c09bf..5287c1f5d 100644 --- a/simd/keccakf1600/fallback.go +++ b/simd/keccakf1600/fallback.go @@ -3,6 +3,6 @@ package keccakf1600 -func permuteSIMDx2(state []uint64) { permuteScalarX2(state) } +func permuteSIMDx2(state []uint64, turbo bool) { permuteScalarX2(state, turbo) } -func permuteSIMDx4(state []uint64) { permuteScalarX4(state) } +func permuteSIMDx4(state []uint64, turbo bool) { permuteScalarX4(state, turbo) } diff --git a/simd/keccakf1600/internal/asm/go.mod b/simd/keccakf1600/internal/asm/go.mod index 3858e4ef6..0837457e6 100644 --- a/simd/keccakf1600/internal/asm/go.mod +++ b/simd/keccakf1600/internal/asm/go.mod @@ -2,4 +2,7 @@ module github.com/cloudflare/circl/simd/keccakf1600/internal/asm go 1.12 -require github.com/mmcloughlin/avo v0.0.0-20200523190732-4439b6b2c061 +require ( + github.com/mmcloughlin/avo v0.5.0 + golang.org/x/tools v0.8.0 // indirect +) diff --git a/simd/keccakf1600/internal/asm/go.sum b/simd/keccakf1600/internal/asm/go.sum index b292bf5c7..7c3f9b64a 100644 --- a/simd/keccakf1600/internal/asm/go.sum +++ b/simd/keccakf1600/internal/asm/go.sum @@ -1,24 +1,51 @@ -github.com/mmcloughlin/avo v0.0.0-20200523190732-4439b6b2c061 h1:UCU8+cLbbvyxi0sQ9fSeoEhZgvrrD9HKMtX6Gmc1vk8= -github.com/mmcloughlin/avo v0.0.0-20200523190732-4439b6b2c061/go.mod h1:wqKykBG2QzQDJEzvRkcS8x6MiSJkF52hXZsXcjaB3ls= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -golang.org/x/arch v0.0.0-20190909030613-46d78d1859ac/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= +github.com/mmcloughlin/avo v0.5.0 h1:nAco9/aI9Lg2kiuROBY6BhCI/z0t5jEvJfjWbL8qXLU= +github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/arch v0.1.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200425043458-8463f397d07c h1:iHhCR0b26amDCiiO+kBguKZom9aMF+NrFxh9zeKR/XU= -golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= +golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/simd/keccakf1600/internal/asm/src.go b/simd/keccakf1600/internal/asm/src.go index acb381e8b..1ccfde35a 100644 --- a/simd/keccakf1600/internal/asm/src.go +++ b/simd/keccakf1600/internal/asm/src.go @@ -14,7 +14,7 @@ func main() { ConstraintExpr("amd64") // Must be called on 32 byte aligned memory. - TEXT("f1600x4AVX2", NOSPLIT, "func(state *uint64, rc *[24]uint64)") + TEXT("f1600x4AVX2", NOSPLIT, "func(state *uint64, rc *[24]uint64, turbo bool)") Pragma("noescape") @@ -31,6 +31,13 @@ func main() { superRound := GP64() MOVQ(U64(6), superRound) // count down. + turbo := Load(Param("turbo"), GP64()) + TESTQ(turbo, turbo) + JZ(LabelRef("loop")) + + MOVQ(U64(3), superRound) // Skip 3 * 4 = 12 rounds + ADDQ(Imm(8*12), rcPtr) + // XXX Because our AVX2 is significantly larger, it might better not // to group four rounds together, but simply loop over the rounds // themselves. From caa4d7bc1b4353279df3491caf38e3608fac4a67 Mon Sep 17 00:00:00 2001 From: Bas Westerbaan Date: Wed, 19 Apr 2023 00:23:19 +0200 Subject: [PATCH 02/47] Add KangarooTwelve draft -10 --- internal/sha3/sha3.go | 4 + internal/sha3/shake.go | 4 + xof/k12/k12.go | 377 +++++++++++++++++++++++++++++++++++++++++ xof/k12/k12_test.go | 96 +++++++++++ 4 files changed, 481 insertions(+) create mode 100644 xof/k12/k12.go create mode 100644 xof/k12/k12_test.go diff --git a/internal/sha3/sha3.go b/internal/sha3/sha3.go index 01806d7d1..a0df5aa6c 100644 --- a/internal/sha3/sha3.go +++ b/internal/sha3/sha3.go @@ -194,3 +194,7 @@ func (d *State) Sum(in []byte) []byte { _, _ = dup.Read(hash) return append(in, hash...) } + +func (d *State) IsAbsorbing() bool { + return d.state == spongeAbsorbing +} diff --git a/internal/sha3/shake.go b/internal/sha3/shake.go index 2a14d78a3..77817f758 100644 --- a/internal/sha3/shake.go +++ b/internal/sha3/shake.go @@ -113,3 +113,7 @@ func TurboShakeSum256(hash, data []byte, D byte) { _, _ = h.Write(data) _, _ = h.Read(hash) } + +func (d *State) SwitchDS(D byte) { + d.dsbyte = D +} diff --git a/xof/k12/k12.go b/xof/k12/k12.go new file mode 100644 index 000000000..ba8567744 --- /dev/null +++ b/xof/k12/k12.go @@ -0,0 +1,377 @@ +// k12 implements the KangarooTwelve XOF. +// +// KangarooTwelve is being standardised at the CFFRG working group +// of the IRTF. This package implements draft 10. +// +// https://datatracker.ietf.org/doc/draft-irtf-cfrg-kangarootwelve/10/ +package k12 + +import ( + "encoding/binary" + + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/simd/keccakf1600" +) + +const chunkSize = 8192 // aka B + +// KangarooTwelve splits the message into chunks of 8192 bytes each. +// The first chunk is absorbed directly in a TurboSHAKE128 instance, which +// we call the stalk. The subsequent chunks aren't absorbed directly, but +// instead their hash is absorbed: they're like leafs on a stalk. +// If we have a fast TurboSHAKE128 available, we buffer chunks until we have +// enough to do the parallel TurboSHAKE128. If not, we absorb directly into +// a separate TurboSHAKE128 state. + +type State struct { + initialTodo int // Bytes left to absorb for the first chunk. + + stalk sha3.State + + context []byte // context string "C" provided by the user + + // buffer of incoming data so we can do parallel TurboSHAKE128: + // nil when we haven't aborbed the first chunk yet; + // empty if we have, but we do not have a fast parallel TurboSHAKE128; + // and chunkSize*lanes in length if we have. + buf []byte + + offset int // offset in buf or bytes written to leaf + + // Number of chunk hashes ("CV_i") absorbed into the stalk. + chunk uint + + // TurboSHAKE128 instance to compute the leaf in case we don't have + // a fast parallel TurboSHAKE128, viz when lanes == 1. + leaf *sha3.State + + lanes uint8 // number of TurboSHAKE128s to compute in parallel +} + +// NewDraft10 creates a new instance of Kangaroo12 draft version -10. +func NewDraft10(c []byte) State { + var lanes byte = 1 + + if keccakf1600.IsEnabledX4() { + lanes = 4 + } else if keccakf1600.IsEnabledX2() { + lanes = 2 + } + + return newDraft10(c, lanes) +} + +func newDraft10(c []byte, lanes byte) State { + return State{ + initialTodo: chunkSize, + stalk: sha3.NewTurboShake128(0x07), + context: c, + lanes: lanes, + } +} + +func (s *State) Reset() { + s.initialTodo = chunkSize + s.stalk.Reset() + s.stalk.SwitchDS(0x07) + s.buf = nil + s.offset = 0 + s.chunk = 0 +} + +func Draft10Sum(hash []byte, msg []byte, c []byte) { + // TODO Tweak number of lanes depending on the length of the message + s := NewDraft10(c) + _, _ = s.Write(msg) + _, _ = s.Read(hash) +} + +func (s *State) Write(p []byte) (int, error) { + written := len(p) + + // The first chunk is written directly to the stalk. + if s.initialTodo > 0 { + taken := s.initialTodo + if len(p) < taken { + taken = len(p) + } + headP := p[:taken] + _, _ = s.stalk.Write(headP) + s.initialTodo -= taken + p = p[taken:] + } + + if len(p) == 0 { + return written, nil + } + + // If this is the first bit of data written after the initial chunk, + // we're out of the fast-path and allocate some buffers. + if s.buf == nil { + if s.lanes != 1 { + s.buf = make([]byte, int(s.lanes)*chunkSize) + } else { + // We create the buffer to signal we're past the first chunk, + // but do not use it. + s.buf = make([]byte, 0) + h := sha3.NewTurboShake128(0x0B) + s.leaf = &h + } + _, _ = s.stalk.Write([]byte{0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) + s.stalk.SwitchDS(0x06) + } + + // If we're just using one lane, we don't need to cache in a buffer + // for parallel hashing. Instead, we feed directly to TurboSHAKE. + if s.lanes == 1 { + for len(p) > 0 { + // Write to current leaf. + to := chunkSize - s.offset + if len(p) < to { + to = len(p) + } + _, _ = s.leaf.Write(p[:to]) + p = p[to:] + s.offset += to + + // Did we fill the chunk? + if s.offset == chunkSize { + var cv [32]byte + _, _ = s.leaf.Read(cv[:]) + _, _ = s.stalk.Write(cv[:]) + s.leaf.Reset() + s.offset = 0 + s.chunk++ + } + } + + return written, nil + } + + // If we can't fill all our lanes or the buffer isn't empty, we write the + // data to the buffer. + if s.offset != 0 || len(p) < len(s.buf) { + to := len(s.buf) - s.offset + if len(p) < to { + to = len(p) + } + p2 := p[:to] + p = p[to:] + copy(s.buf[s.offset:], p2) + s.offset += to + } + + // Absorb the buffer if we filled it + if s.offset == len(s.buf) { + s.writeX(s.buf) + s.offset = 0 + } + + // Note that at this point we may assume that s.offset = 0 if len(p) != 0 + if len(p) != 0 && s.offset != 0 { + panic("shouldn't happen") + } + + // Absorb a bunch of chunks at the same time. + if len(p) >= int(s.lanes)*chunkSize { + p = s.writeX(p) + } + + // Put the remainder in the buffer. + if len(p) > 0 { + copy(s.buf, p) + s.offset = len(p) + } + + return written, nil +} + +// Absorb a multiple of a multiple of lanes * chunkSize. +// Returns the remainder. +func (s *State) writeX(p []byte) []byte { + switch s.lanes { + case 4: + return s.writeX4(p) + default: + return s.writeX2(p) + } +} + +func (s *State) writeX4(p []byte) []byte { + for len(p) >= 4*chunkSize { + var x4 keccakf1600.StateX4 + a := x4.Initialize(true) + + for offset := 0; offset < 48*168; offset += 168 { + for i := 0; i < 21; i++ { + a[i*4] ^= binary.LittleEndian.Uint64( + p[8*i+offset:], + ) + a[i*4+1] ^= binary.LittleEndian.Uint64( + p[chunkSize+8*i+offset:], + ) + a[i*4+2] ^= binary.LittleEndian.Uint64( + p[chunkSize*2+8*i+offset:], + ) + a[i*4+3] ^= binary.LittleEndian.Uint64( + p[chunkSize*3+8*i+offset:], + ) + } + + x4.Permute() + } + + for i := 0; i < 16; i++ { + a[i*4] ^= binary.LittleEndian.Uint64( + p[8*i+48*168:], + ) + a[i*4+1] ^= binary.LittleEndian.Uint64( + p[chunkSize+8*i+48*168:], + ) + a[i*4+2] ^= binary.LittleEndian.Uint64( + p[chunkSize*2+8*i+48*168:], + ) + a[i*4+3] ^= binary.LittleEndian.Uint64( + p[chunkSize*3+8*i+48*168:], + ) + } + + a[16*4] ^= 0x0b + a[16*4+1] ^= 0x0b + a[16*4+2] ^= 0x0b + a[16*4+3] ^= 0x0b + a[20*4] ^= 0x80 << 56 + a[20*4+1] ^= 0x80 << 56 + a[20*4+2] ^= 0x80 << 56 + a[20*4+3] ^= 0x80 << 56 + + x4.Permute() + + var buf [32 * 4]byte + for i := 0; i < 4; i++ { + binary.LittleEndian.PutUint64(buf[8*i:], a[4*i]) + binary.LittleEndian.PutUint64(buf[32+8*i:], a[4*i+1]) + binary.LittleEndian.PutUint64(buf[32*2+8*i:], a[4*i+2]) + binary.LittleEndian.PutUint64(buf[32*3+8*i:], a[4*i+3]) + } + + _, _ = s.stalk.Write(buf[:]) + p = p[chunkSize*4:] + s.chunk += 4 + } + + return p +} + +func (s *State) writeX2(p []byte) []byte { + // TODO On M2 Pro, 1/3 of the time is spent on this function + // and LittleEndian.Uint64 excluding the actual permutation. + // Rewriting in assembler might be worthwhile. + for len(p) >= 2*chunkSize { + var x2 keccakf1600.StateX2 + a := x2.Initialize(true) + + for offset := 0; offset < 48*168; offset += 168 { + for i := 0; i < 21; i++ { + a[i*2] ^= binary.LittleEndian.Uint64( + p[8*i+offset:], + ) + a[i*2+1] ^= binary.LittleEndian.Uint64( + p[chunkSize+8*i+offset:], + ) + } + + x2.Permute() + } + + for i := 0; i < 16; i++ { + a[i*2] ^= binary.LittleEndian.Uint64( + p[8*i+48*168:], + ) + a[i*2+1] ^= binary.LittleEndian.Uint64( + p[chunkSize+8*i+48*168:], + ) + } + + a[16*2] ^= 0x0b + a[16*2+1] ^= 0x0b + a[20*2] ^= 0x80 << 56 + a[20*2+1] ^= 0x80 << 56 + + x2.Permute() + + var buf [32 * 2]byte + for i := 0; i < 4; i++ { + binary.LittleEndian.PutUint64(buf[8*i:], a[2*i]) + binary.LittleEndian.PutUint64(buf[32+8*i:], a[2*i+1]) + } + + _, _ = s.stalk.Write(buf[:]) + p = p[chunkSize*2:] + s.chunk += 2 + } + + return p +} + +func (s *State) Read(p []byte) (int, error) { + if s.stalk.IsAbsorbing() { + // Write context string C + _, _ = s.Write(s.context) + + // Write length_encode( |C| ) + var buf [9]byte + binary.BigEndian.PutUint64(buf[:8], uint64(len(s.context))) + + // Find first non-zero digit in big endian encoding of context length + i := 0 + for buf[i] == 0 && i < 8 { + i++ + } + + buf[8] = byte(8 - i) // number of bytes to represent |C| + _, _ = s.Write(buf[i:]) + + // We need to write the chunk number if we're past the first chunk. + if s.buf != nil { + // Write last remaining chunk(s) + var cv [32]byte + if s.lanes == 1 { + if s.offset != 0 { + _, _ = s.leaf.Read(cv[:]) + _, _ = s.stalk.Write(cv[:]) + s.chunk++ + } + } else { + remainingBuf := s.buf[:s.offset] + for len(remainingBuf) > 0 { + h := sha3.NewTurboShake128(0x0B) + to := chunkSize + if len(remainingBuf) < to { + to = len(remainingBuf) + } + _, _ = h.Write(remainingBuf[:to]) + _, _ = h.Read(cv[:]) + _, _ = s.stalk.Write(cv[:]) + s.chunk++ + remainingBuf = remainingBuf[to:] + } + } + + // Write length_encode( chunk ) + binary.BigEndian.PutUint64(buf[:8], uint64(s.chunk)) + + // Find first non-zero digit in big endian encoding of number of chunks + i = 0 + for buf[i] == 0 && i < 8 { + i++ + } + + buf[8] = byte(8 - i) // number of bytes to represent number of chunks. + _, _ = s.stalk.Write(buf[i:]) + _, _ = s.stalk.Write([]byte{0xff, 0xff}) + } + } + + return s.stalk.Read(p) +} diff --git a/xof/k12/k12_test.go b/xof/k12/k12_test.go new file mode 100644 index 000000000..a5be5b05e --- /dev/null +++ b/xof/k12/k12_test.go @@ -0,0 +1,96 @@ +package k12 + +import ( + "encoding/hex" + "testing" +) + +// See draft-irtf-cfrg-kangarootwelve-10 §4. +// https://datatracker.ietf.org/doc/draft-irtf-cfrg-kangarootwelve/10/ +func ptn(n int) []byte { + buf := make([]byte, n) + for i := 0; i < n; i++ { + buf[i] = byte(i % 0xfb) + } + return buf +} + +func testK12(t *testing.T, msg []byte, c []byte, l int, want string) { + do := func(lanes byte, writeSize int) { + h := newDraft10(c, lanes) + msg2 := msg + for len(msg2) > 0 { + to := writeSize + if len(msg2) < to { + to = len(msg2) + } + _, _ = h.Write(msg2[:to]) + msg2 = msg2[to:] + } + buf := make([]byte, l) + _, _ = h.Read(buf) + got := hex.EncodeToString(buf) + if want != got { + t.Fatalf("%s != %s (lanes=%d, writeSize=%d )", want, got, lanes, writeSize) + } + } + + for _, lanes := range []byte{1, 2, 4} { + for _, writeSize := range []int{7919, 1024, 8 * 1024} { + do(lanes, writeSize) + } + } +} + +func TestK12(t *testing.T) { + // I-D test vectors + testK12(t, []byte{}, []byte{}, 32, "1ac2d450fc3b4205d19da7bfca1b37513c0803577ac7167f06fe2ce1f0ef39e5") + i := 17 + testK12(t, ptn(i), []byte{}, 32, "6bf75fa2239198db4772e36478f8e19b0f371205f6a9a93a273f51df37122888") + i *= 17 + testK12(t, ptn(i), []byte{}, 32, "0c315ebcdedbf61426de7dcf8fb725d1e74675d7f5327a5067f367b108ecb67c") + i *= 17 + testK12(t, ptn(i), []byte{}, 32, "cb552e2ec77d9910701d578b457ddf772c12e322e4ee7fe417f92c758f0d59d0") + i *= 17 + testK12(t, ptn(i), []byte{}, 32, "8701045e22205345ff4dda05555cbb5c3af1a771c2b89baef37db43d9998b9fe") + i *= 17 + testK12(t, ptn(i), []byte{}, 32, "844d610933b1b9963cbdeb5ae3b6b05cc7cbd67ceedf883eb678a0a8e0371682") + i *= 17 + testK12(t, ptn(i), []byte{}, 32, "3c390782a8a4e89fa6367f72feaaf13255c8d95878481d3cd8ce85f58e880af8") + testK12(t, []byte{}, ptn(1), 32, "fab658db63e94a246188bf7af69a133045f46ee984c56e3c3328caaf1aa1a583") + testK12(t, []byte{0xff}, ptn(41), 32, "d848c5068ced736f4462159b9867fd4c20b808acc3d5bc48e0b06ba0a3762ec4") + testK12(t, []byte{0xff, 0xff, 0xff}, ptn(41*41), 32, "c389e5009ae57120854c2e8c64670ac01358cf4c1baf89447a724234dc7ced74") + testK12(t, []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, ptn(41*41*41), 32, "75d2f86a2e644566726b4fbcfc5657b9dbcf070c7b0dca06450ab291d7443bcf") + + // Cornercases + testK12(t, ptn(chunkSize), []byte{}, 16, "48f256f6772f9edfb6a8b661ec92dc93") + testK12(t, ptn(chunkSize+1), []byte{}, 16, "bb66fe72eaea5179418d5295ee134485") + testK12(t, ptn(2*chunkSize), []byte{}, 16, "82778f7f7234c83352e76837b721fbdb") + testK12(t, ptn(2*chunkSize+1), []byte{}, 16, "5f8d2b943922b451842b4e82740d0236") + testK12(t, ptn(3*chunkSize), []byte{}, 16, "f4082a8fe7d1635aa042cd1da63bf235") + testK12(t, ptn(3*chunkSize+1), []byte{}, 16, "38cb940999aca742d69dd79298c6051c") +} + +func BenchmarkK12_100B(b *testing.B) { benchmarkK12(b, 100, 1) } +func BenchmarkK12_10K(b *testing.B) { benchmarkK12(b, 10000, 1) } +func BenchmarkK12_100K(b *testing.B) { benchmarkK12(b, 10000, 10) } +func BenchmarkK12_1M(b *testing.B) { benchmarkK12(b, 10000, 100) } +func BenchmarkK12_10M(b *testing.B) { benchmarkK12(b, 10000, 1000) } + +func benchmarkK12(b *testing.B, size, num int) { + b.StopTimer() + h := NewDraft10([]byte{}) + data := make([]byte, size) + d := make([]byte, 32) + + b.SetBytes(int64(size * num)) + b.StartTimer() + + for i := 0; i < b.N; i++ { + h.Reset() + for j := 0; j < num; j++ { + _, _ = h.Write(data) + } + _, _ = h.Read(d) + } +} From 75b147d005a72687172aaaae62e06878ea16e7db Mon Sep 17 00:00:00 2001 From: Bas Westerbaan Date: Wed, 3 May 2023 23:25:51 +0200 Subject: [PATCH 03/47] Add KangarooTwelve as XOF --- README.md | 1 + xof/k12/k12.go | 23 +++++++++++++++++++++++ xof/xof.go | 13 +++++++++++++ xof/xof_test.go | 6 ++++++ 4 files changed, 43 insertions(+) diff --git a/README.md b/README.md index ece67cf5c..502263fbe 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ go get -u github.com/cloudflare/circl #### XOF: eXtendable Output Functions - [FIPS 202](https://doi.org/10.6028/NIST.FIPS.202): SHAKE128 and SHAKE256 - [BLAKE2X](https://www.blake2.net/blake2x.pdf): BLAKE2XB and BLAKE2XS + - [KangarooTwelve](https://keccak.team/kangarootwelve.html): KangarooTwelve #### Zero-knowledge Proofs - [Schnorr](./zk/dl): Prove knowledge of the Discrete Logarithm. diff --git a/xof/k12/k12.go b/xof/k12/k12.go index ba8567744..16b56f74f 100644 --- a/xof/k12/k12.go +++ b/xof/k12/k12.go @@ -79,6 +79,29 @@ func (s *State) Reset() { s.chunk = 0 } +func (s *State) Clone() State { + stalk := s.stalk.Clone().(*sha3.State) + ret := State{ + initialTodo: s.initialTodo, + stalk: *stalk, + context: s.context, + offset: s.offset, + chunk: s.chunk, + lanes: s.lanes, + } + + if s.leaf != nil { + ret.leaf = s.leaf.Clone().(*sha3.State) + } + + if s.buf != nil { + ret.buf = make([]byte, len(s.buf)) + copy(ret.buf, s.buf) + } + + return ret +} + func Draft10Sum(hash []byte, msg []byte, c []byte) { // TODO Tweak number of lanes depending on the length of the message s := NewDraft10(c) diff --git a/xof/xof.go b/xof/xof.go index 7e4ceab8b..33485cac5 100644 --- a/xof/xof.go +++ b/xof/xof.go @@ -10,6 +10,8 @@ import ( "io" "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/xof/k12" + "golang.org/x/crypto/blake2b" "golang.org/x/crypto/blake2s" ) @@ -38,6 +40,7 @@ const ( SHAKE256 BLAKE2XB BLAKE2XS + K12D10 ) func (x ID) New() XOF { @@ -54,6 +57,9 @@ func (x ID) New() XOF { case BLAKE2XS: x, _ := blake2s.NewXOF(blake2s.OutputLengthUnknown, nil) return blake2xs{x} + case K12D10: + x := k12.NewDraft10([]byte{}) + return k12d10{&x} default: panic("crypto: requested unavailable XOF function") } @@ -70,3 +76,10 @@ func (s blake2xb) Clone() XOF { return blake2xb{s.XOF.Clone()} } type blake2xs struct{ blake2s.XOF } func (s blake2xs) Clone() XOF { return blake2xs{s.XOF.Clone()} } + +type k12d10 struct{ *k12.State } + +func (s k12d10) Clone() XOF { + x := s.State.Clone() + return k12d10{&x} +} diff --git a/xof/xof_test.go b/xof/xof_test.go index c62b7bd76..023157e86 100644 --- a/xof/xof_test.go +++ b/xof/xof_test.go @@ -53,6 +53,12 @@ var allVectors = []vector{ out: "0650cde4df888a06eada0f0fecb3c17594304b4a03fdd678182f27db1238b174", outLen: 32, }, + { + id: xof.K12D10, + in: "The quick brown fox jumps over the lazy dog", + out: "b4f249b4f77c58df170aa4d1723db1127d82f1d98d25ddda561ada459cd11a48", + outLen: 32, + }, } func TestXof(t *testing.T) { From 4da78653064e14884ee3bc3eba208268e1b0f843 Mon Sep 17 00:00:00 2001 From: Christopher Patton Date: Wed, 3 May 2023 16:06:08 -0700 Subject: [PATCH 04/47] xof/k12: Fix a typo in the package documentation CFFRG -> CFRG --- xof/k12/k12.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xof/k12/k12.go b/xof/k12/k12.go index 16b56f74f..3c503a186 100644 --- a/xof/k12/k12.go +++ b/xof/k12/k12.go @@ -1,6 +1,6 @@ // k12 implements the KangarooTwelve XOF. // -// KangarooTwelve is being standardised at the CFFRG working group +// KangarooTwelve is being standardised at the CFRG working group // of the IRTF. This package implements draft 10. // // https://datatracker.ietf.org/doc/draft-irtf-cfrg-kangarootwelve/10/ From 5fabdc712055166da1e52a981a7f3cafd904f971 Mon Sep 17 00:00:00 2001 From: armfazh Date: Tue, 30 May 2023 09:13:16 -0600 Subject: [PATCH 05/47] Set CIRCL version for generated assembler code. --- go.sum | 2 - pke/kyber/internal/common/amd64.s | 10 +-- pke/kyber/internal/common/asm/go.mod | 12 +++- pke/kyber/internal/common/asm/go.sum | 50 +++++++++----- pke/kyber/internal/common/stubs_amd64.go | 1 - sign/dilithium/internal/common/amd64.s | 2 +- sign/dilithium/internal/common/asm/go.mod | 12 +++- sign/dilithium/internal/common/asm/go.sum | 68 ++++++++----------- sign/dilithium/internal/common/stubs_amd64.go | 1 - 9 files changed, 84 insertions(+), 74 deletions(-) diff --git a/go.sum b/go.sum index 615559e01..e48cb252d 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -github.com/bwesterb/go-ristretto v1.2.2 h1:S2C0mmSjCLS3H9+zfXoIoKzl+cOncvBvt6pE+zTm5Ms= -github.com/bwesterb/go-ristretto v1.2.2/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bwesterb/go-ristretto v1.2.3 h1:1w53tCkGhCQ5djbat3+MH0BAQ5Kfgbt56UZQ/JMzngw= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a h1:diz9pEYuTIuLMJLs3rGDkeaTsNyRs6duYdFyPAxzE/U= diff --git a/pke/kyber/internal/common/amd64.s b/pke/kyber/internal/common/amd64.s index d8205465e..f721482fb 100644 --- a/pke/kyber/internal/common/amd64.s +++ b/pke/kyber/internal/common/amd64.s @@ -1,6 +1,6 @@ // Code generated by command: go run src.go -out ../amd64.s -stubs ../stubs_amd64.go -pkg common. DO NOT EDIT. -// +build amd64 +//go:build amd64 #include "textflag.h" @@ -1445,11 +1445,11 @@ TEXT ·mulHatAVX2(SB), NOSPLIT, $8-24 MOVQ a+8(FP), CX MOVQ b+16(FP), DX LEAQ ·ZetasAVX2+0(SB), BX - MOVL $0xfffff301, BP - VMOVD BP, X0 + MOVL $0xfffff301, SI + VMOVD SI, X0 VPBROADCASTW X0, Y14 - MOVL $0x00000d01, BP - VMOVD BP, X0 + MOVL $0x00000d01, SI + VMOVD SI, X0 VPBROADCASTW X0, Y15 VMOVDQU (CX), Y0 VMOVDQU 32(CX), Y1 diff --git a/pke/kyber/internal/common/asm/go.mod b/pke/kyber/internal/common/asm/go.mod index c39319777..808d89b60 100644 --- a/pke/kyber/internal/common/asm/go.mod +++ b/pke/kyber/internal/common/asm/go.mod @@ -1,10 +1,16 @@ module github.com/cloudflare/circl/pke/kyber/internal/common/asm -go 1.12 +go 1.19 require ( - github.com/cloudflare/circl v0.0.0 - github.com/mmcloughlin/avo v0.0.0-20200523190732-4439b6b2c061 + github.com/cloudflare/circl v1.3.3 + github.com/mmcloughlin/avo v0.5.0 +) + +require ( + golang.org/x/mod v0.10.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/tools v0.9.1 // indirect ) replace github.com/cloudflare/circl => ../../../../../ diff --git a/pke/kyber/internal/common/asm/go.sum b/pke/kyber/internal/common/asm/go.sum index 6e063275f..f3739bc21 100644 --- a/pke/kyber/internal/common/asm/go.sum +++ b/pke/kyber/internal/common/asm/go.sum @@ -1,25 +1,41 @@ -github.com/mmcloughlin/avo v0.0.0-20200523190732-4439b6b2c061 h1:UCU8+cLbbvyxi0sQ9fSeoEhZgvrrD9HKMtX6Gmc1vk8= -github.com/mmcloughlin/avo v0.0.0-20200523190732-4439b6b2c061/go.mod h1:wqKykBG2QzQDJEzvRkcS8x6MiSJkF52hXZsXcjaB3ls= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -golang.org/x/arch v0.0.0-20190909030613-46d78d1859ac/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= +github.com/mmcloughlin/avo v0.5.0 h1:nAco9/aI9Lg2kiuROBY6BhCI/z0t5jEvJfjWbL8qXLU= +github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/arch v0.1.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200425043458-8463f397d07c h1:iHhCR0b26amDCiiO+kBguKZom9aMF+NrFxh9zeKR/XU= -golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/pke/kyber/internal/common/stubs_amd64.go b/pke/kyber/internal/common/stubs_amd64.go index dd869993e..cf14cff91 100644 --- a/pke/kyber/internal/common/stubs_amd64.go +++ b/pke/kyber/internal/common/stubs_amd64.go @@ -1,7 +1,6 @@ // Code generated by command: go run src.go -out ../amd64.s -stubs ../stubs_amd64.go -pkg common. DO NOT EDIT. //go:build amd64 -// +build amd64 package common diff --git a/sign/dilithium/internal/common/amd64.s b/sign/dilithium/internal/common/amd64.s index 079fa0926..90953ac1e 100644 --- a/sign/dilithium/internal/common/amd64.s +++ b/sign/dilithium/internal/common/amd64.s @@ -1,6 +1,6 @@ // Code generated by command: go run src.go -out ../amd64.s -stubs ../stubs_amd64.go -pkg common. DO NOT EDIT. -// +build amd64 +//go:build amd64 #include "textflag.h" diff --git a/sign/dilithium/internal/common/asm/go.mod b/sign/dilithium/internal/common/asm/go.mod index bb642eebd..926100d22 100644 --- a/sign/dilithium/internal/common/asm/go.mod +++ b/sign/dilithium/internal/common/asm/go.mod @@ -1,10 +1,16 @@ module github.com/cloudflare/circl/sign/dilithium/internal/common/asm -go 1.12 +go 1.19 require ( - github.com/cloudflare/circl v0.0.0 - github.com/mmcloughlin/avo v0.0.0-20200523190732-4439b6b2c061 + github.com/cloudflare/circl v1.3.3 + github.com/mmcloughlin/avo v0.5.0 +) + +require ( + golang.org/x/mod v0.10.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/tools v0.9.1 // indirect ) replace github.com/cloudflare/circl => ../../../../../ diff --git a/sign/dilithium/internal/common/asm/go.sum b/sign/dilithium/internal/common/asm/go.sum index ba25410b0..f3739bc21 100644 --- a/sign/dilithium/internal/common/asm/go.sum +++ b/sign/dilithium/internal/common/asm/go.sum @@ -1,55 +1,41 @@ -github.com/bwesterb/go-ristretto v1.2.0 h1:xxWOVbN5m8NNKiSDZXE1jtZvZnC6JSJ9cYFADiZcWtw= -github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= -github.com/mmcloughlin/avo v0.0.0-20200523190732-4439b6b2c061 h1:UCU8+cLbbvyxi0sQ9fSeoEhZgvrrD9HKMtX6Gmc1vk8= -github.com/mmcloughlin/avo v0.0.0-20200523190732-4439b6b2c061/go.mod h1:wqKykBG2QzQDJEzvRkcS8x6MiSJkF52hXZsXcjaB3ls= -github.com/mmcloughlin/mathfmt v0.0.0-20210827041835-ecadbc79eaea/go.mod h1:Tcp/zLGAs4YPf2siEot3D6LbsIbw5rE0l++B657piRk= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -golang.org/x/arch v0.0.0-20190909030613-46d78d1859ac/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= +github.com/mmcloughlin/avo v0.5.0 h1:nAco9/aI9Lg2kiuROBY6BhCI/z0t5jEvJfjWbL8qXLU= +github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/arch v0.1.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210902050250-f475640dd07b h1:S7hKs0Flbq0bbc9xgYt4stIEG1zNDFqyrPwAX2Wj/sE= -golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200425043458-8463f397d07c h1:iHhCR0b26amDCiiO+kBguKZom9aMF+NrFxh9zeKR/XU= -golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20201105001634-bc3cf281b174/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/sign/dilithium/internal/common/stubs_amd64.go b/sign/dilithium/internal/common/stubs_amd64.go index 2739e1c88..97451507f 100644 --- a/sign/dilithium/internal/common/stubs_amd64.go +++ b/sign/dilithium/internal/common/stubs_amd64.go @@ -1,7 +1,6 @@ // Code generated by command: go run src.go -out ../amd64.s -stubs ../stubs_amd64.go -pkg common. DO NOT EDIT. //go:build amd64 -// +build amd64 package common From 946a259d2256285cd86d9012e88a984ba3299e9e Mon Sep 17 00:00:00 2001 From: Tanya Verma Date: Wed, 31 May 2023 16:33:11 -0700 Subject: [PATCH 06/47] Add tkn20 benchmarks --- abe/cpabe/tkn20/bench_test.go | 265 ++++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 abe/cpabe/tkn20/bench_test.go diff --git a/abe/cpabe/tkn20/bench_test.go b/abe/cpabe/tkn20/bench_test.go new file mode 100644 index 000000000..11a43f1d4 --- /dev/null +++ b/abe/cpabe/tkn20/bench_test.go @@ -0,0 +1,265 @@ +package tkn20 + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "fmt" + "strconv" + "strings" + "testing" + + "golang.org/x/crypto/nacl/box" +) + +type abeTestCase struct { + desc string + attrs Attributes + policy Policy + msk SystemSecretKey + pk PublicKey +} + +var testCases []abeTestCase + +var ( + msg = []byte("drink your ovaltine now") + longMsg = []byte(strings.Repeat("a", 10000)) +) + +func generateAttrs() Attributes { + benchableAttrs := make(map[string]string, 50) + for i := 0; i < 50; i++ { + benchableAttrs["k"+strconv.Itoa(i)] = "v" + strconv.Itoa(i) + } + attrs := Attributes{} + attrs.FromMap(benchableAttrs) + return attrs +} + +func generatePolicy() string { + var policyBuilder strings.Builder + for i := 0; i < 50; i++ { + policyBuilder.WriteString("k") + policyBuilder.WriteString(strconv.Itoa(i)) + policyBuilder.WriteString(":v") + policyBuilder.WriteString(strconv.Itoa(i)) + if i != 49 { + if i%2 == 0 { + policyBuilder.WriteString(" and ") + } else { + policyBuilder.WriteString(" or ") + } + } + } + return policyBuilder.String() +} + +func init() { + smallPolicy := Policy{} + _ = smallPolicy.FromString("(k1:v1 or k1:v2) and not k2:v3") + smallAttrs := Attributes{} + smallAttrs.FromMap(map[string]string{"k1": "v2", "k2": "v4"}) + longPolicy := Policy{} + _ = longPolicy.FromString(generatePolicy()) + testCases = []abeTestCase{ + { + desc: "smallPolicy/Attrs", + attrs: smallAttrs, + policy: smallPolicy, + }, + { + desc: "longPolicy/Attrs", + attrs: generateAttrs(), + policy: longPolicy, + }, + } + var err error + for i := range testCases { + testCases[i].pk, testCases[i].msk, err = Setup(rand.Reader) + if err != nil { + panic(err) + } + } +} + +func BenchmarkTKN20KeyGen(b *testing.B) { + for _, tc := range testCases { + b.Run(fmt.Sprintf("keygen:%s", tc.desc), func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := tc.msk.KeyGen(rand.Reader, tc.attrs) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkRSAKeyGen(b *testing.B) { + for i := 0; i < b.N; i++ { + _, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkX25519KeyGen(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _, err := box.GenerateKey(rand.Reader) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkTKN20Encrypt(b *testing.B) { + for _, tc := range testCases { + b.Run(fmt.Sprintf("encrypt:%s", tc.desc), func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := tc.pk.Encrypt(rand.Reader, tc.policy, msg) + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkRSAEncrypt(b *testing.B) { + privKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + b.Fatal(err) + } + pubKey := privKey.PublicKey + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := rsa.EncryptPKCS1v15(rand.Reader, &pubKey, msg) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkX25519Encrypt(b *testing.B) { + pubKey, _, err := box.GenerateKey(rand.Reader) + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := box.SealAnonymous(nil, msg, pubKey, rand.Reader) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkTKN20Decrypt(b *testing.B) { + for _, tc := range testCases { + b.Run(fmt.Sprintf("decrypt:%s", tc.desc), func(b *testing.B) { + userKey, err := tc.msk.KeyGen(rand.Reader, tc.attrs) + if err != nil { + b.Fatal(err) + } + ciphertext, err := tc.pk.Encrypt(rand.Reader, tc.policy, msg) + if err != nil { + b.Fatal(err) + } + keyBytes, _ := userKey.MarshalBinary() + pubKeyBytes, _ := tc.pk.MarshalBinary() + // longCt is only benchmarked to measure size overhead + longCt, err := tc.pk.Encrypt(rand.Reader, tc.policy, longMsg) + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err = userKey.Decrypt(ciphertext) + if err != nil { + b.Fatal(err) + } + } + b.ReportMetric(float64(len(pubKeyBytes)), "public_key_size") + b.ReportMetric(float64(len(keyBytes)), "attribute_secret_key_size") + b.ReportMetric(float64(len(ciphertext)-len(msg)), "ciphertext_bytes_overhead_32b_msg") + b.ReportMetric(float64(len(longCt)-len(longMsg)), "ciphertext_bytes_overhead_10kb_msg") + }) + } +} + +func BenchmarkRSADecrypt(b *testing.B) { + privKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + b.Fatal(err) + } + pubKey := privKey.PublicKey + ct, err := rsa.EncryptPKCS1v15(rand.Reader, &pubKey, msg) + if err != nil { + b.Fatal(err) + } + // longCt is only benchmarked to measure size overhead + longCt, err := rsaEncrypt(longMsg, &privKey.PublicKey) + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := rsa.DecryptPKCS1v15(rand.Reader, privKey, ct) + if err != nil { + b.Fatal(err) + } + } + b.ReportMetric(float64(privKey.PublicKey.Size()), "public_key_size") + b.ReportMetric(float64(len(x509.MarshalPKCS1PrivateKey(privKey))), "secret_key_size") + b.ReportMetric(float64(len(ct)-len(msg)), "ciphertext_bytes_overhead") + b.ReportMetric(float64(len(longCt)-len(longMsg)), "ciphertext_bytes_overhead_10kb_msg") +} + +func BenchmarkX25519Decrypt(b *testing.B) { + pubKey, privKey, err := box.GenerateKey(rand.Reader) + if err != nil { + b.Fatal(err) + } + ct, err := box.SealAnonymous(nil, msg, pubKey, rand.Reader) + if err != nil { + b.Fatal(err) + } + // longCt is only benchmarked to measure size overhead + longCt, err := box.SealAnonymous(nil, longMsg, pubKey, rand.Reader) + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, ok := box.OpenAnonymous(nil, ct, pubKey, privKey) + if !ok { + b.Fatal(err) + } + } + b.ReportMetric(float64(len(pubKey)), "public_key_size") + b.ReportMetric(float64(len(privKey)), "secret_key_size") + b.ReportMetric(float64(len(ct)-len(msg)), "ciphertext_bytes_overhead_32b_msg") + b.ReportMetric(float64(len(longCt)-len(longMsg)), "ciphertext_bytes_overhead_10kb_msg") +} + +func rsaEncrypt(data []byte, pubKey *rsa.PublicKey) ([]byte, error) { + chunkSize := 245 // Max chunk size for 2048 bit key with PKCS1v15 padding + var ct []byte + for len(data) > 0 { + if len(data) < chunkSize { + chunkSize = len(data) + } + chunk := data[:chunkSize] + data = data[chunkSize:] + encryptedChunk, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, chunk) + if err != nil { + return nil, err + } + ct = append(ct, encryptedChunk...) + } + return ct, nil +} From afe0bef2abf8a5f708d8d9388b093c9551139381 Mon Sep 17 00:00:00 2001 From: Christopher Wood Date: Thu, 6 Jul 2023 07:04:20 -0400 Subject: [PATCH 07/47] Add partially blind RSA implementation (#445) * Add partially blind RSA implementation See the specification for more information: https://datatracker.ietf.org/doc/html/draft-amjad-cfrg-partially-blind-rsa-00 * Apply linter * Drop internal PrepareRandom function and rename the type * Remove a couple more dead things * Address Bas comments * Apply changes from code review * Shuffle around the package contents per Armando's feedback * Add safe prime check for the partially blind RSA constructor * gofumptd * Update blindsign/blindrsa/brsa.go Co-authored-by: Armando Faz * Update blindsign/blindrsa/brsa.go Co-authored-by: Armando Faz * Update blindsign/blindrsa/common.go Co-authored-by: Armando Faz * Armando's comments on brsa * File perms * Update blindsign/blindrsa/partiallyblindrsa/pbrsa.go Co-authored-by: Armando Faz * Update blindsign/blindrsa/partiallyblindrsa/pbrsa.go Co-authored-by: Armando Faz * Update blindsign/blindrsa/partiallyblindrsa/pbrsa.go Co-authored-by: Armando Faz * Update blindsign/blindrsa/partiallyblindrsa/pbrsa.go Co-authored-by: Armando Faz * Update blindsign/blindrsa/partiallyblindrsa/pbrsa.go Co-authored-by: Armando Faz * Final Armando pass * Update blindsign/blindrsa/partiallyblindrsa/pbrsa_test.go Co-authored-by: Armando Faz * Fix comment * Refactoring to hide internals. * Updates based on latest draft changes * Add test vector verification --------- Co-authored-by: Armando Faz Co-authored-by: armfazh --- blindsign/blindrsa/blindrsa.go | 342 ----------------- blindsign/blindrsa/brsa.go | 323 ++++++++++++++++ .../{blindrsa_test.go => brsa_test.go} | 234 ++++++++---- blindsign/blindrsa/internal/common/common.go | 145 +++++++ .../blindrsa/{ => internal/common}/pss.go | 104 ++++- .../blindrsa/{ => internal/common}/rsa.go | 71 +--- blindsign/blindrsa/internal/keys/big_keys.go | 57 +++ blindsign/blindrsa/partiallyblindrsa/pbrsa.go | 334 ++++++++++++++++ .../blindrsa/partiallyblindrsa/pbrsa_test.go | 356 ++++++++++++++++++ blindsign/blindsign.go | 42 --- blindsign/doc.go | 2 + 11 files changed, 1489 insertions(+), 521 deletions(-) delete mode 100644 blindsign/blindrsa/blindrsa.go create mode 100644 blindsign/blindrsa/brsa.go rename blindsign/blindrsa/{blindrsa_test.go => brsa_test.go} (51%) create mode 100644 blindsign/blindrsa/internal/common/common.go rename blindsign/blindrsa/{ => internal/common}/pss.go (58%) rename blindsign/blindrsa/{ => internal/common}/rsa.go (65%) create mode 100644 blindsign/blindrsa/internal/keys/big_keys.go create mode 100644 blindsign/blindrsa/partiallyblindrsa/pbrsa.go create mode 100644 blindsign/blindrsa/partiallyblindrsa/pbrsa_test.go delete mode 100644 blindsign/blindsign.go create mode 100644 blindsign/doc.go diff --git a/blindsign/blindrsa/blindrsa.go b/blindsign/blindrsa/blindrsa.go deleted file mode 100644 index f0b9fdae4..000000000 --- a/blindsign/blindrsa/blindrsa.go +++ /dev/null @@ -1,342 +0,0 @@ -package blindrsa - -// This package implements the blind RSA protocol based on the CFRG specification: -// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-02 - -import ( - "crypto" - "crypto/rand" - "crypto/rsa" - "crypto/sha256" - "crypto/sha512" - "crypto/subtle" - "errors" - "hash" - "io" - "math/big" - - "github.com/cloudflare/circl/blindsign" -) - -var errUnsupportedHashFunction = errors.New("unsupported hash function") - -// An RSAVerifier represents a Verifier in the RSA blind signature protocol. -// It carries state needed to produce and validate an RSA blind signature. -type RSAVerifier struct { - // Public key of the Signer - pk *rsa.PublicKey - - // Identifier of the cryptographic hash function used in producing the message signature - cryptoHash crypto.Hash - - // Hash function used in producing the message signature - hash hash.Hash -} - -// A DeterminsiticRSAVerifier is an RSAVerifier that supports deterministic signatures. -type DeterminsiticRSAVerifier struct { - // Public key of the Signer - pk *rsa.PublicKey - - // Identifier of the cryptographic hash function used in producing the message signature - cryptoHash crypto.Hash - - // Hash function used in producing the message signature - hash hash.Hash -} - -func convertHashFunction(hash crypto.Hash) hash.Hash { - switch hash { - case crypto.SHA256: - return sha256.New() - case crypto.SHA384: - return sha512.New384() - case crypto.SHA512: - return sha512.New() - default: - panic(errUnsupportedHashFunction) - } -} - -// NewDeterministicRSAVerifier creates a new RSAVerifier using the corresponding Signer parameters. -func NewDeterministicRSAVerifier(pk *rsa.PublicKey, hash crypto.Hash) DeterminsiticRSAVerifier { - h := convertHashFunction(hash) - return DeterminsiticRSAVerifier{ - pk: pk, - cryptoHash: hash, - hash: h, - } -} - -// NewRSAVerifier creates a new RSAVerifier using the corresponding Signer parameters. -func NewRSAVerifier(pk *rsa.PublicKey, hash crypto.Hash) RSAVerifier { - h := convertHashFunction(hash) - return RSAVerifier{ - pk: pk, - cryptoHash: hash, - hash: h, - } -} - -func encodeMessageEMSAPSS(message []byte, key *rsa.PublicKey, hash hash.Hash, salt []byte) ([]byte, error) { - hash.Reset() // Ensure the hash state is cleared - hash.Write(message) - digest := hash.Sum(nil) - hash.Reset() - emBits := key.N.BitLen() - 1 - encodedMsg, err := emsaPSSEncode(digest[:], emBits, salt, hash) - return encodedMsg, err -} - -func generateBlindingFactor(random io.Reader, key *rsa.PublicKey) (*big.Int, *big.Int, error) { - randReader := random - if randReader == nil { - randReader = rand.Reader - } - r, err := rand.Int(randReader, key.N) - if err != nil { - return nil, nil, err - } - - if r.Sign() == 0 { - r = bigOne - } - rInv := new(big.Int).ModInverse(r, key.N) - if rInv == nil { - return nil, nil, ErrInvalidBlind - } - - return r, rInv, nil -} - -func fixedBlind(message, salt []byte, r, rInv *big.Int, pk *rsa.PublicKey, hash hash.Hash) ([]byte, blindsign.VerifierState, error) { - encodedMsg, err := encodeMessageEMSAPSS(message, pk, hash, salt) - if err != nil { - return nil, nil, err - } - - m := new(big.Int).SetBytes(encodedMsg) - - bigE := big.NewInt(int64(pk.E)) - x := new(big.Int).Exp(r, bigE, pk.N) - z := new(big.Int).Set(m) - z.Mul(z, x) - z.Mod(z, pk.N) - - kLen := (pk.N.BitLen() + 7) / 8 - blindedMsg := make([]byte, kLen) - z.FillBytes(blindedMsg) - - return blindedMsg, RSAVerifierState{ - encodedMsg: encodedMsg, - pk: pk, - hash: hash, - salt: salt, - rInv: rInv, - }, nil -} - -// Blind initializes the blind RSA protocol using an input message and source of randomness. The -// signature is deterministic. This function fails if randomness was not provided. -// -// See the specification for more details: -// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-02#section-5.1.1 -func (v DeterminsiticRSAVerifier) Blind(random io.Reader, message []byte) ([]byte, blindsign.VerifierState, error) { - if random == nil { - return nil, nil, ErrInvalidRandomness - } - - r, rInv, err := generateBlindingFactor(random, v.pk) - if err != nil { - return nil, nil, err - } - - return fixedBlind(message, nil, r, rInv, v.pk, v.hash) -} - -func verifyMessageSignature(message, signature []byte, saltLength int, pk *rsa.PublicKey, hash crypto.Hash) error { - h := convertHashFunction(hash) - h.Write(message) - digest := h.Sum(nil) - - err := rsa.VerifyPSS(pk, hash, digest, signature, &rsa.PSSOptions{ - Hash: hash, - SaltLength: saltLength, - }) - return err -} - -// Verify verifies the input (message, signature) pair and produces an error upon failure. -func (v DeterminsiticRSAVerifier) Verify(message, signature []byte) error { - return verifyMessageSignature(message, signature, 0, v.pk, v.cryptoHash) -} - -// Blind initializes the blind RSA protocol using an input message and source of randomness. The -// signature includes a randomly generated PSS salt whose length equals the size of the underlying -// hash function. This function fails if randomness was not provided. -// -// See the specification for more details: -// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-02#section-5.1.1 -func (v RSAVerifier) Blind(random io.Reader, message []byte) ([]byte, blindsign.VerifierState, error) { - if random == nil { - return nil, nil, ErrInvalidRandomness - } - - salt := make([]byte, v.hash.Size()) - _, err := io.ReadFull(random, salt) - if err != nil { - return nil, nil, err - } - - r, rInv, err := generateBlindingFactor(random, v.pk) - if err != nil { - return nil, nil, err - } - - return fixedBlind(message, salt, r, rInv, v.pk, v.hash) -} - -// FixedBlind runs the Blind function with fixed blind and salt inputs. -func (v RSAVerifier) FixedBlind(message, blind, salt []byte) ([]byte, blindsign.VerifierState, error) { - if blind == nil { - return nil, nil, ErrInvalidRandomness - } - - r := new(big.Int).SetBytes(blind) - rInv := new(big.Int).ModInverse(r, v.pk.N) - if rInv == nil { - return nil, nil, ErrInvalidBlind - } - - return fixedBlind(message, salt, r, rInv, v.pk, v.hash) -} - -// Verify verifies the input (message, signature) pair and produces an error upon failure. -func (v RSAVerifier) Verify(message, signature []byte) error { - return verifyMessageSignature(message, signature, v.hash.Size(), v.pk, v.cryptoHash) -} - -// An RSAVerifierState carries state needed to complete the blind signature protocol -// as a verifier. -type RSAVerifierState struct { - // Public key of the Signer - pk *rsa.PublicKey - - // Hash function used in producing the message signature - hash hash.Hash - - // The hashed and encoded message being signed - encodedMsg []byte - - // The salt used when encoding the message - salt []byte - - // Inverse of the blinding factor produced by the Verifier - rInv *big.Int -} - -func verifyBlindSignature(pub *rsa.PublicKey, hashed, sig []byte) error { - m := new(big.Int).SetBytes(hashed) - bigSig := new(big.Int).SetBytes(sig) - - c := encrypt(new(big.Int), pub, bigSig) - if subtle.ConstantTimeCompare(m.Bytes(), c.Bytes()) == 1 { - return nil - } else { - return rsa.ErrVerification - } -} - -// Finalize computes and outputs the final signature, if it's valid. Otherwise, it returns an error. -// -// See the specification for more details: -// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-02#section-5.1.3 -func (state RSAVerifierState) Finalize(data []byte) ([]byte, error) { - kLen := (state.pk.N.BitLen() + 7) / 8 - if len(data) != kLen { - return nil, ErrUnexpectedSize - } - - z := new(big.Int).SetBytes(data) - s := new(big.Int).Set(state.rInv) - s.Mul(s, z) - s.Mod(s, state.pk.N) - - sig := make([]byte, kLen) - s.FillBytes(sig) - - err := verifyBlindSignature(state.pk, state.encodedMsg, sig) - if err != nil { - return nil, err - } - - return sig, nil -} - -// CopyBlind returns an encoding of the blind value used in the protocol. -func (state RSAVerifierState) CopyBlind() []byte { - r := new(big.Int).ModInverse(state.rInv, state.pk.N) - return r.Bytes() -} - -// CopySalt returns an encoding of the per-message salt used in the protocol. -func (state RSAVerifierState) CopySalt() []byte { - salt := make([]byte, len(state.salt)) - copy(salt, state.salt) - return salt -} - -// An RSASigner represents the Signer in the blind RSA protocol. -// It carries the raw RSA private key used for signing blinded messages. -type RSASigner struct { - // An RSA private key - sk *rsa.PrivateKey -} - -// NewRSASigner creates a new Signer for the blind RSA protocol using an RSA private key. -func NewRSASigner(sk *rsa.PrivateKey) RSASigner { - return RSASigner{ - sk: sk, - } -} - -// BlindSign blindly computes the RSA operation using the Signer's private key on the blinded -// message input, if it's of valid length, and returns an error should the function fail. -// -// See the specification for more details: -// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-02#section-5.1.2 -func (signer RSASigner) BlindSign(data []byte) ([]byte, error) { - kLen := (signer.sk.N.BitLen() + 7) / 8 - if len(data) != kLen { - return nil, ErrUnexpectedSize - } - - m := new(big.Int).SetBytes(data) - if m.Cmp(signer.sk.N) > 0 { - return nil, ErrInvalidMessageLength - } - - s, err := decryptAndCheck(rand.Reader, signer.sk, m) - if err != nil { - return nil, err - } - - blindSig := make([]byte, kLen) - s.FillBytes(blindSig) - - return blindSig, nil -} - -var ( - // ErrUnexpectedSize is the error used if the size of a parameter does not match its expected value. - ErrUnexpectedSize = errors.New("blindsign/blindrsa: unexpected input size") - - // ErrInvalidMessageLength is the error used if the size of a protocol message does not match its expected value. - ErrInvalidMessageLength = errors.New("blindsign/blindrsa: invalid message length") - - // ErrInvalidBlind is the error used if the blind generated by the Verifier fails. - ErrInvalidBlind = errors.New("blindsign/blindrsa: invalid blind") - - // ErrInvalidRandomness is the error used if caller did not provide randomness to the Blind() function. - ErrInvalidRandomness = errors.New("blindsign/blindrsa: invalid random parameter") -) diff --git a/blindsign/blindrsa/brsa.go b/blindsign/blindrsa/brsa.go new file mode 100644 index 000000000..390de6940 --- /dev/null +++ b/blindsign/blindrsa/brsa.go @@ -0,0 +1,323 @@ +package blindrsa + +// This package implements the blind RSA protocol based on the CFRG specification: +// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures +// +// Blind RSA is an example of a blind signature protocol is a two-party protocol +// for computing a digital signature. One party (the server) holds the signing +// key, and the other (the client) holds the message input. Blindness +// ensures that the server does not learn anything about the client's +// input during the BlindSign step. + +import ( + "crypto" + "crypto/rand" + "crypto/rsa" + "hash" + "io" + "math/big" + + "github.com/cloudflare/circl/blindsign/blindrsa/internal/common" + "github.com/cloudflare/circl/blindsign/blindrsa/internal/keys" +) + +// An randomBRSAVerifier represents a Verifier in the RSA blind signature protocol. +// It carries state needed to produce and validate an RSA signature produced +// using the blind RSA protocol. +type randomBRSAVerifier struct { + // Public key of the Signer + pk *rsa.PublicKey + + // Identifier of the cryptographic hash function used in producing the message signature + cryptoHash crypto.Hash + + // Hash function used in producing the message signature + hash hash.Hash +} + +// A determinsiticBRSAVerifier is a BRSAVerifier that supports deterministic signatures. +type determinsiticBRSAVerifier struct { + // Public key of the Signer + pk *rsa.PublicKey + + // Identifier of the cryptographic hash function used in producing the message signature + cryptoHash crypto.Hash + + // Hash function used in producing the message signature + hash hash.Hash +} + +// Verifier is a type that implements the client side of the blind RSA +// protocol, described in https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures +type Verifier interface { + // Blind initializes the blind RSA protocol using an input message and source of randomness. The + // signature is deterministic. This function fails if randomness was not provided. + Blind(random io.Reader, message []byte) ([]byte, VerifierState, error) + + // FixedBlind runs the Blind function with fixed blind and salt inputs. + FixedBlind(message, blind, salt []byte) ([]byte, VerifierState, error) + + // Verify verifies the input (message, signature) pair and produces an error upon failure. + Verify(message, signature []byte) error + + // Hash returns the hash function associated with the Verifier. + Hash() hash.Hash +} + +// NewDeterministicVerifier creates a new DeterminsiticBRSAVerifier using the corresponding Signer parameters. +// This corresponds to the RSABSSA-SHA384-PSSZERO-Deterministic variant. See the specification for more details: +// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures#name-rsabssa-variants +func NewDeterministicVerifier(pk *rsa.PublicKey, hash crypto.Hash) Verifier { + h := common.ConvertHashFunction(hash) + return determinsiticBRSAVerifier{ + pk: pk, + cryptoHash: hash, + hash: h, + } +} + +// Hash returns the hash function associated with the BRSAVerifier. +func (v determinsiticBRSAVerifier) Hash() hash.Hash { + return v.hash +} + +// NewVerifier creates a new BRSAVerifier using the corresponding Signer parameters. +// This corresponds to the RSABSSA-SHA384-PSS-Deterministic variant. See the specification for more details: +// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures#name-rsabssa-variants +func NewVerifier(pk *rsa.PublicKey, hash crypto.Hash) Verifier { + h := common.ConvertHashFunction(hash) + return randomBRSAVerifier{ + pk: pk, + cryptoHash: hash, + hash: h, + } +} + +// Hash returns the hash function associated with the BRSAVerifier. +func (v randomBRSAVerifier) Hash() hash.Hash { + return v.hash +} + +func fixedBlind(message, salt []byte, r, rInv *big.Int, pk *rsa.PublicKey, hash hash.Hash) ([]byte, VerifierState, error) { + encodedMsg, err := common.EncodeMessageEMSAPSS(message, pk.N, hash, salt) + if err != nil { + return nil, VerifierState{}, err + } + + m := new(big.Int).SetBytes(encodedMsg) + + bigE := big.NewInt(int64(pk.E)) + x := new(big.Int).Exp(r, bigE, pk.N) + z := new(big.Int).Set(m) + z.Mul(z, x) + z.Mod(z, pk.N) + + kLen := (pk.N.BitLen() + 7) / 8 + blindedMsg := make([]byte, kLen) + z.FillBytes(blindedMsg) + + return blindedMsg, VerifierState{ + encodedMsg: encodedMsg, + pk: pk, + hash: hash, + salt: salt, + rInv: rInv, + }, nil +} + +// Blind initializes the blind RSA protocol using an input message and source of randomness. The +// signature is deterministic. This function fails if randomness was not provided. +// +// See the specification for more details: +// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-02#section-5.1.1 +func (v determinsiticBRSAVerifier) Blind(random io.Reader, message []byte) ([]byte, VerifierState, error) { + if random == nil { + return nil, VerifierState{}, common.ErrInvalidRandomness + } + + r, rInv, err := common.GenerateBlindingFactor(random, v.pk.N) + if err != nil { + return nil, VerifierState{}, err + } + + return fixedBlind(message, nil, r, rInv, v.pk, v.hash) +} + +// FixedBlind runs the Blind function with fixed blind and salt inputs. +func (v determinsiticBRSAVerifier) FixedBlind(message, blind, salt []byte) ([]byte, VerifierState, error) { + if blind == nil { + return nil, VerifierState{}, common.ErrInvalidRandomness + } + + r := new(big.Int).SetBytes(blind) + if r.Cmp(v.pk.N) >= 0 { + return nil, VerifierState{}, common.ErrInvalidBlind + } + rInv := new(big.Int).ModInverse(r, v.pk.N) + if rInv == nil { + return nil, VerifierState{}, common.ErrInvalidBlind + } + + return fixedBlind(message, salt, r, rInv, v.pk, v.hash) +} + +// Verify verifies the input (message, signature) pair and produces an error upon failure. +func (v determinsiticBRSAVerifier) Verify(message, signature []byte) error { + return common.VerifyMessageSignature(message, signature, 0, keys.NewBigPublicKey(v.pk), v.cryptoHash) +} + +// Blind initializes the blind RSA protocol using an input message and source of randomness. The +// signature includes a randomly generated PSS salt whose length equals the size of the underlying +// hash function. This function fails if randomness was not provided. +// +// See the specification for more details: +// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-02#section-5.1.1 +func (v randomBRSAVerifier) Blind(random io.Reader, message []byte) ([]byte, VerifierState, error) { + if random == nil { + return nil, VerifierState{}, common.ErrInvalidRandomness + } + + salt := make([]byte, v.hash.Size()) + _, err := io.ReadFull(random, salt) + if err != nil { + return nil, VerifierState{}, err + } + + r, rInv, err := common.GenerateBlindingFactor(random, v.pk.N) + if err != nil { + return nil, VerifierState{}, err + } + + return fixedBlind(message, salt, r, rInv, v.pk, v.hash) +} + +// FixedBlind runs the Blind function with fixed blind and salt inputs. +func (v randomBRSAVerifier) FixedBlind(message, blind, salt []byte) ([]byte, VerifierState, error) { + if blind == nil { + return nil, VerifierState{}, common.ErrInvalidRandomness + } + + r := new(big.Int).SetBytes(blind) + if r.Cmp(v.pk.N) >= 0 { + return nil, VerifierState{}, common.ErrInvalidBlind + } + + rInv := new(big.Int).ModInverse(r, v.pk.N) + if rInv == nil { + return nil, VerifierState{}, common.ErrInvalidBlind + } + + return fixedBlind(message, salt, r, rInv, v.pk, v.hash) +} + +// Verify verifies the input (message, signature) pair and produces an error upon failure. +func (v randomBRSAVerifier) Verify(message, signature []byte) error { + return common.VerifyMessageSignature(message, signature, v.hash.Size(), keys.NewBigPublicKey(v.pk), v.cryptoHash) +} + +// An VerifierState carries state needed to complete the blind signature protocol +// as a verifier. +type VerifierState struct { + // Public key of the Signer + pk *rsa.PublicKey + + // Hash function used in producing the message signature + hash hash.Hash + + // The hashed and encoded message being signed + encodedMsg []byte + + // The salt used when encoding the message + salt []byte + + // Inverse of the blinding factor produced by the Verifier + rInv *big.Int +} + +// Finalize computes and outputs the final signature, if it's valid. Otherwise, it returns an error. +// +// See the specification for more details: +// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-02#section-5.1.3 +func (state VerifierState) Finalize(data []byte) ([]byte, error) { + kLen := (state.pk.N.BitLen() + 7) / 8 + if len(data) != kLen { + return nil, common.ErrUnexpectedSize + } + + z := new(big.Int).SetBytes(data) + s := new(big.Int).Set(state.rInv) + s.Mul(s, z) + s.Mod(s, state.pk.N) + + sig := make([]byte, kLen) + s.FillBytes(sig) + + err := common.VerifyBlindSignature(keys.NewBigPublicKey(state.pk), state.encodedMsg, sig) + if err != nil { + return nil, err + } + + return sig, nil +} + +// CopyBlind returns an encoding of the blind value used in the protocol. +func (state VerifierState) CopyBlind() []byte { + r := new(big.Int).ModInverse(state.rInv, state.pk.N) + return r.Bytes() +} + +// CopySalt returns an encoding of the per-message salt used in the protocol. +func (state VerifierState) CopySalt() []byte { + salt := make([]byte, len(state.salt)) + copy(salt, state.salt) + return salt +} + +// An Signer represents the Signer in the blind RSA protocol. +// It carries the raw RSA private key used for signing blinded messages. +type Signer struct { + // An RSA private key + sk *rsa.PrivateKey +} + +// NewSigner creates a new Signer for the blind RSA protocol using an RSA private key. +func NewSigner(sk *rsa.PrivateKey) Signer { + return Signer{ + sk: sk, + } +} + +// BlindSign blindly computes the RSA operation using the Signer's private key on the blinded +// message input, if it's of valid length, and returns an error should the function fail. +// +// See the specification for more details: +// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-02#section-5.1.2 +func (signer Signer) BlindSign(data []byte) ([]byte, error) { + kLen := (signer.sk.N.BitLen() + 7) / 8 + if len(data) != kLen { + return nil, common.ErrUnexpectedSize + } + + m := new(big.Int).SetBytes(data) + if m.Cmp(signer.sk.N) > 0 { + return nil, common.ErrInvalidMessageLength + } + + s, err := common.DecryptAndCheck(rand.Reader, keys.NewBigPrivateKey(signer.sk), m) + if err != nil { + return nil, err + } + + blindSig := make([]byte, kLen) + s.FillBytes(blindSig) + + return blindSig, nil +} + +var ( + ErrUnexpectedSize = common.ErrUnexpectedSize + ErrInvalidMessageLength = common.ErrInvalidMessageLength + ErrInvalidBlind = common.ErrInvalidBlind + ErrInvalidRandomness = common.ErrInvalidRandomness + ErrUnsupportedHashFunction = common.ErrUnsupportedHashFunction +) diff --git a/blindsign/blindrsa/blindrsa_test.go b/blindsign/blindrsa/brsa_test.go similarity index 51% rename from blindsign/blindrsa/blindrsa_test.go rename to blindsign/blindrsa/brsa_test.go index a7d4f8bfd..ec002608e 100644 --- a/blindsign/blindrsa/blindrsa_test.go +++ b/blindsign/blindrsa/brsa_test.go @@ -14,79 +14,91 @@ import ( "math/big" "os" "testing" - - "github.com/cloudflare/circl/blindsign" ) -// 4096-bit RSA private key +// 2048-bit RSA private key const testPrivateKey = ` -----BEGIN RSA PRIVATE KEY----- -MIIJKQIBAAKCAgEA1zDOiz7HM2tIpPWJdWTYfIdicpjyG6S/NOeTEUKHXA5Sxa7z -Ii1n6GEkQD5DbQE269gG3jdzBCf4FPfwSF6s6TAVRx0U5W84JOi8X75Ez2fiQcdk -KsOjlFKig/+AaE3b1mkpo3HQHlD+7x+u5/Y/POtLXOrLk54GpVjCprzP2W+3QW0+ -3OFRvHsKZYLwzpmnwOfVeTsT1BKSEF5RDhqgDggpdaE4Zt+vOgpRwN0ey2TMVcxg -fKGBO1+R/Y6cudsY/9gayYWmz91cwqC4peTp+h6l8UnBZiFVuwcclSGMrprkr2Ez -Ubr0cLFZe7mExeqDJvmK/2T3K2C80DX2uXDrbt0vnyGA1aqKF+1AAFavP6pSBLc8 -ibTq2moFfdPdqdjhizptI0fBAn4nEfIet9lv71DMPayy9czDbkwTirdZU5dK3nSY -L4W5H0GWVNOQN44uparjPxtKz1NNBt4vEUrP3YjW1wj00rZGqBErD+GBSJkW4rpc -Y0zfm5V2LR4SAWlILdJ/lZEycFB5/EoA7uHzU6gcHoEK3iDQcNg5J3Fp4JFQwIYF -r+fOoq7EHS+Fwq97711Xc0O0OF4sbBWZJsHIJn0AQzuIutMUpd3O9Yk2Em8d2Np7 -VyjaGS9UswTmD0CI5bBiBAT4Klk52XXmcURTpTPBcsiptLXal26mClqpH+8CAwEA -AQKCAgAndTKaQ8OhAQ4L+V3gIcK0atq5aqQSP44z9DZ6VrmdPp8c0myQmsTPzmgo -Q4J3jV51tmHkA0TawT1zEteDXaDVDVUJeiKnw1IHKonIAIp7gW/yYc5TLRZkjxZv -n7z64zPpR9UzvB3OQUnNrQCUVgnYcMib3A3CHprXXMQscLioBR0UKST6uXIUXndU -j8L6DyC8dYYmOZf0LgeMas7wCB/LEuIPSKWf72og+V1uQN1xrCTvoo8aqz6YFXke -hjTku3EFEKoww4oH2W413eSdvrDMhSwmZ0DIKlqe9bne+oziQ1KleexAE0jZFRv0 -XNsks1CjJ+S92dScpptYjlyUOklg76ErgZAlUQnxHGbZE6Apb3aE1X5HACfTUOPP -YZND7jRaGOrtVami2ScHXs/dbzmH9CoKH2SZ8CL08N7isaLmIT99w+g1iTtb9nh7 -178y7TiUxqUw6K6C8/xk2NZIfxzD0AJTt+18P0ZEcEYSjKPU1FOMH3fvkh9k+J4N -Fx7uUU7zEvSJAX6w1N87lL7giq6eZO8geg7L+N0MtujnIOqkFyVej4JJVqYmnQ1s -dqBvebXsQqNxVeOLyZiNs6Zlh0AVnB/Utd5Js9IbD27Vo0ruSCw9GojldLzC2ufA -IWb89sBG7+z04yDB+jMA4OtpnT7TJEiIkLh3SfNo4tZ7sXaFcQKCAQEA8ONRIFhp -wrwyG/a87KSp2h43glhT/Fu3yZA5S2sZayaFjWjHi99JHYbFnor1moNAqBL1VH9U -+FOyOrGd6T04FUoT8uyqC3WR6Ls2fTMBcqpohUa51gORavEyrqAk3c/Ok/0sWLt9 -G2RpZoywv33RNslGgB6KEMO2f+HZJgItNYo+hzHjfR52QVu3pQpQLA9gQpikcnlE -8u7ihvpO9qRdN5xIjswWlHuTJc7em/IF5HKmVuSE8RCgK5Jh48BAsr0MeI8YNhLN -o70njdAFCmyXEibJ8+QiXn84rmoKHuh/vRoKG/JyI8U3DcS819Y4J0esPwNP53se -6jZFucLB2RXS1wKCAQEA5LDJ7j+ERblxiZ+NXmIpQqpIjTZCUrvXLVVJMK+hKbQd -D5uFJ+6UkfIR3782Qsf5Hr5N1N+k54FJawIyqxiY8Aq9RM60a5wKkhaGvTx0PWYo -q3W3Oq6BiNlqHMmV12HysSVXYzriw8vRlTK1kN32eaops4/SgHNB0RFnsSobkAWB -VE0/w9tYlyiniLoXceMpMk+dvFqitX8aC61zZmOq5MMcMb9+FIMoWU1SbhB8j50A -f07dge8/uP79N32ReLGnFRd8PECdJYvhYclGeNpHICefni5lF65JmWGNSUgtgM6/ -93SEIylBVEGOdo+lrn7PPf1o60H4htbPpUPGc5iQqQKCAQEAvvCwoZ7zVjSu05Ok -9T8gk5BYF63EBMj+yXrUr39ZSqHiQtDHO4vl/M2TX7RuMefQHGnKpQu5Yo2VPQkF -TpgEGHv7jBckQqkS2xNqgZsojqec6efB7m4tmkNOFTVDg77w1EVeHYegB1J0aaEj -iOZGK9MnWu7aKae4xW1UHtii1UmbfraAx/CZc/0reFrQadxWRPORhlux146baLqI -VOC8MxRiPy5ux4uce9+afKo/GXH3f/Drn9m53E/P4CPIJOXNONLUMih9cEjDTZmS -JU0mAnFUq0ouJBFb8ISFOTK57j7xvG1VJB1zIirMNZnMMPaTBe+uKqJhQu16H2DN -HzI5SQKCAQBT8lVdoHE0ivsTcr8ZC11r/Ef/lhBIgG1fVbQ1K/Mz9MrKJON/IgPl -gv9uq6kGYJOg5mh5oNLOrFW/8yGYTsItMzQA4wO1kKUMtTomkt90fmCld+OXpeEk -0/IwuQrI8kp9HmDyqvX8u3+mjeO6VtAYHw+Ju1yhDC33ybTPgs51UqADywuCIK1n -Z2QAO5dJlgJUVodnUbnyd8Ke0L/QsPtVWA2scUedzftstIZyopimuxIoqVGEVceF -aAyZZv2UWVok0ucm0u0ckDlehNzalf2P3xunnA494BtiMz4CzXzukHZFJr8ujQFP -JXVfLiG6aRA4CCKQYToSfR3h43wgiLtpAoIBAQDIYZ6ItfsRCekvXJ2dssEcOwtF -kyG3/k1K9Ap+zuCTL3MQkyhzG8O44Vi2xvf9RtmGH+S1bNpFv+Bvvw5l5Jioak7Z -qNjTxenzyrIjHRscOQCIKfVMz09YVP5cK47hjNv/sAiqdZuhOzTDFWISlwEjoOLH -vur13VOY1QqHAglmm3s5V+UNm8pUB/vmzphWjzElIe2mpn1ubrGhEm7H2vxD4tg5 -uRFjhHPVbsEVakWgkbkUhdj6Qm68gJO55JIBRimUe8OdEhVOqM8H4G8/s93K1dVO -b5tL+JXMipkSpSlmUFCGysfz6V++3fT1kp+YmAgqSwv9WxO/1aC6RcLr9Xo8 +MIIEowIBAAKCAQEAyxrta2qV9bHOATpM/KsluUsuZKIwNOQlCn6rQ8DfOowSmTrx +KxEZCNS0cb7DHUtsmtnN2pBhKi7pA1I+beWiJNawLwnlw3TQz+Adj1KcUAp4ovZ5 +CPpoK1orQwyB6vGvcte155T8mKMTknaHl1fORTtSbvm/bOuZl5uEI7kPRGGiKvN6 +qwz1cz91l6vkTTHHMttooYHGy75gfYwOUuBlX9mZbcWE7KC+h6+814ozfRex26no +KLvYHikTFxROf/ifVWGXCbCWy7nqR0zq0mTCBz/kl0DAHwDhCRBgZpg9IeX4Pwhu +LoI8h5zUPO9wDSo1Kpur1hLQPK0C2xNLfiJaXwIDAQABAoIBAC8wm3c4tYz3efDJ +Ffgi38n0kNvq3x5636xXj/1XA8a7otqdWklyWIm3uhEvjG/zBVHZRz4AC8NcUOFn +q3+nOgwrIZZcS1klfBrAbL3PKOhj9nGOqMKQQ8HG2oRilJD9BJG/UtFyyVnBkhuW +lJxyV0e4p8eHGZX6C56xEHuoVMbDKm9HR8XRwwTHRn1VsICqIzo6Uv/fJhFMu1Qf ++mtpa3oJb43P9pygirWO+w+3U6pRhccwAWlrvOjAmeP0Ndy7/gXn26rSPbKmWcI6 +3VIUB/FQsa8tkFTEFkIp1oQLejKk+EgUk66JWc8K6o3vDDyfdbmjTHVxi3ByyNur +F87+ykkCgYEA73MLD1FLwPWdmV/V+ZiMTEwTXRBc1W1D7iigNclp9VDAzXFI6ofs +3v+5N8hcZIdEBd9W6utHi/dBiEogDuSjljPRCqPsQENm2itTHzmNRvvI8wV1KQbP +eJOd0vPMl5iup8nYL+9ASfGYeX5FKlttKEm4ZIY0XUsx9pERoq4PlEsCgYEA2STJ +68thMWv9xKuz26LMQDzImJ5OSQD0hsts9Ge01G/rh0Dv/sTzO5wtLsiyDA/ZWkzB +8J+rO/y2xqBD9VkYKaGB/wdeJP0Z+n7sETetiKPbXPfgAi7VAe77Rmst/oEcGLUg +tm+XnfJSInoLU5HmtIdLg0kcQLVbN5+ZMmtkPb0CgYBSbhczmbfrYGJ1p0FBIFvD +9DiCRBzBOFE3TnMAsSqx0a/dyY7hdhN8HSqE4ouz68DmCKGiU4aYz3CW23W3ysvp +7EKdWBr/cHSazGlcCXLyKcFer9VKX1bS2nZtZZJb6arOhjTPI5zNF8d2o5pp33lv +chlxOaYTK8yyZfRdPXCNiwKBgQDV77oFV66dm7E9aJHerkmgbIKSYz3sDUXd3GSv +c9Gkj9Q0wNTzZKXkMB4P/un0mlTh88gMQ7PYeUa28UWjX7E/qwFB+8dUmA1VUGFT +IVEW06GXuhv46p0wt3zXx1dcbWX6LdJaDB4MHqevkiDAqHntmXLbmVd9pXCGn/a2 +xznO3QKBgHkPJPEiCzRugzgN9UxOT5tNQCSGMOwJUd7qP0TWgvsWHT1N07JLgC8c +Yg0f1rCxEAQo5BVppiQFp0FA7W52DUnMEfBtiehZ6xArW7crO91gFRqKBWZ3Jjyz +/JcS8m5UgQxC8mmb/2wLD5TDvWw+XCfjUgWmvqIi5dcJgmuTAn5X -----END RSA PRIVATE KEY-----` -func loadPrivateKey(t *testing.T) *rsa.PrivateKey { +func loadPrivateKey() (*rsa.PrivateKey, error) { block, _ := pem.Decode([]byte(testPrivateKey)) if block == nil || block.Type != "RSA PRIVATE KEY" { - t.Fatal("PEM private key decoding failed") + return nil, fmt.Errorf("PEM private key decoding failed") } privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { - t.Fatal(err) + return nil, err + } + + return privateKey, nil +} + +func mustDecodeHex(h string) []byte { + b, err := hex.DecodeString(h) + if err != nil { + panic(err) } + return b +} - return privateKey +func loadStrongRSAKey() *rsa.PrivateKey { + // https://gist.github.com/chris-wood/b77536febb25a5a11af428afff77820a + pEnc := "dcd90af1be463632c0d5ea555256a20605af3db667475e190e3af12a34a3324c46a3094062c59fb4b249e0ee6afba8bee14e0276d126c99f4784b23009bf6168ff628ac1486e5ae8e23ce4d362889de4df63109cbd90ef93db5ae64372bfe1c55f832766f21e94ea3322eb2182f10a891546536ba907ad74b8d72469bea396f3" + qEnc := "f8ba5c89bd068f57234a3cf54a1c89d5b4cd0194f2633ca7c60b91a795a56fa8c8686c0e37b1c4498b851e3420d08bea29f71d195cfbd3671c6ddc49cf4c1db5b478231ea9d91377ffa98fe95685fca20ba4623212b2f2def4da5b281ed0100b651f6db32112e4017d831c0da668768afa7141d45bbc279f1e0f8735d74395b3" + NEnc := "d6930820f71fe517bf3259d14d40209b02a5c0d3d61991c731dd7da39f8d69821552e2318d6c9ad897e603887a476ea3162c1205da9ac96f02edf31df049bd55f142134c17d4382a0e78e275345f165fbe8e49cdca6cf5c726c599dd39e09e75e0f330a33121e73976e4facba9cfa001c28b7c96f8134f9981db6750b43a41710f51da4240fe03106c12acb1e7bb53d75ec7256da3fddd0718b89c365410fce61bc7c99b115fb4c3c318081fa7e1b65a37774e8e50c96e8ce2b2cc6b3b367982366a2bf9924c4bafdb3ff5e722258ab705c76d43e5f1f121b984814e98ea2b2b8725cd9bc905c0bc3d75c2a8db70a7153213c39ae371b2b5dc1dafcb19d6fae9" + eEnc := "010001" + dEnc := "4e21356983722aa1adedb084a483401c1127b781aac89eab103e1cfc52215494981d18dd8028566d9d499469c25476358de23821c78a6ae43005e26b394e3051b5ca206aa9968d68cae23b5affd9cbb4cb16d64ac7754b3cdba241b72ad6ddfc000facdb0f0dd03abd4efcfee1730748fcc47b7621182ef8af2eeb7c985349f62ce96ab373d2689baeaea0e28ea7d45f2d605451920ca4ea1f0c08b0f1f6711eaa4b7cca66d58a6b916f9985480f90aca97210685ac7b12d2ec3e30a1c7b97b65a18d38a93189258aa346bf2bc572cd7e7359605c20221b8909d599ed9d38164c9c4abf396f897b9993c1e805e574d704649985b600fa0ced8e5427071d7049d" + + p := new(big.Int).SetBytes(mustDecodeHex(pEnc)) + q := new(big.Int).SetBytes(mustDecodeHex(qEnc)) + N := new(big.Int).SetBytes(mustDecodeHex(NEnc)) + e := new(big.Int).SetBytes(mustDecodeHex(eEnc)) + d := new(big.Int).SetBytes(mustDecodeHex(dEnc)) + + primes := make([]*big.Int, 2) + primes[0] = p + primes[1] = q + + key := &rsa.PrivateKey{ + PublicKey: rsa.PublicKey{ + N: N, + E: int(e.Int64()), + }, + D: d, + Primes: primes, + } + + return key } -func runSignatureProtocol(signer RSASigner, verifier blindsign.Verifier, message []byte, random io.Reader) ([]byte, error) { +func runSignatureProtocol(signer Signer, verifier Verifier, message []byte, random io.Reader) ([]byte, error) { blindedMsg, state, err := verifier.Blind(random, message) if err != nil { return nil, err @@ -121,10 +133,13 @@ func runSignatureProtocol(signer RSASigner, verifier blindsign.Verifier, message func TestRoundTrip(t *testing.T) { message := []byte("hello world") - key := loadPrivateKey(t) + key, err := loadPrivateKey() + if err != nil { + t.Fatal(err) + } - verifier := NewRSAVerifier(&key.PublicKey, crypto.SHA512) - signer := NewRSASigner(key) + verifier := NewVerifier(&key.PublicKey, crypto.SHA512) + signer := NewSigner(key) sig, err := runSignatureProtocol(signer, verifier, message, rand.Reader) if err != nil { @@ -137,10 +152,13 @@ func TestRoundTrip(t *testing.T) { func TestDeterministicRoundTrip(t *testing.T) { message := []byte("hello world") - key := loadPrivateKey(t) + key, err := loadPrivateKey() + if err != nil { + t.Fatal(err) + } - verifier := NewDeterministicRSAVerifier(&key.PublicKey, crypto.SHA512) - signer := NewRSASigner(key) + verifier := NewDeterministicVerifier(&key.PublicKey, crypto.SHA512) + signer := NewSigner(key) sig, err := runSignatureProtocol(signer, verifier, message, rand.Reader) if err != nil { @@ -153,12 +171,15 @@ func TestDeterministicRoundTrip(t *testing.T) { func TestDeterministicBlindFailure(t *testing.T) { message := []byte("hello world") - key := loadPrivateKey(t) + key, err := loadPrivateKey() + if err != nil { + t.Fatal(err) + } - verifier := NewDeterministicRSAVerifier(&key.PublicKey, crypto.SHA512) - signer := NewRSASigner(key) + verifier := NewDeterministicVerifier(&key.PublicKey, crypto.SHA512) + signer := NewSigner(key) - _, err := runSignatureProtocol(signer, verifier, message, nil) + _, err = runSignatureProtocol(signer, verifier, message, nil) if err == nil { t.Fatal("Expected signature generation to fail with empty randomness") } @@ -166,10 +187,13 @@ func TestDeterministicBlindFailure(t *testing.T) { func TestRandomSignVerify(t *testing.T) { message := []byte("hello world") - key := loadPrivateKey(t) + key, err := loadPrivateKey() + if err != nil { + t.Fatal(err) + } - verifier := NewRSAVerifier(&key.PublicKey, crypto.SHA512) - signer := NewRSASigner(key) + verifier := NewVerifier(&key.PublicKey, crypto.SHA512) + signer := NewSigner(key) sig1, err := runSignatureProtocol(signer, verifier, message, rand.Reader) if err != nil { @@ -202,10 +226,13 @@ func (r *mockRandom) Read(p []byte) (n int, err error) { func TestFixedRandomSignVerify(t *testing.T) { message := []byte("hello world") - key := loadPrivateKey(t) + key, err := loadPrivateKey() + if err != nil { + t.Fatal(err) + } - verifier := NewRSAVerifier(&key.PublicKey, crypto.SHA512) - signer := NewRSASigner(key) + verifier := NewVerifier(&key.PublicKey, crypto.SHA512) + signer := NewSigner(key) mockRand := &mockRandom{0} sig1, err := runSignatureProtocol(signer, verifier, message, mockRand) @@ -329,7 +356,11 @@ func (tvl *testVectorList) UnmarshalJSON(data []byte) error { } func verifyTestVector(t *testing.T, vector testVector) { - key := loadPrivateKey(t) + key, err := loadPrivateKey() + if err != nil { + t.Fatal(err) + } + key.PublicKey.N = vector.n key.PublicKey.E = vector.e key.D = vector.d @@ -344,10 +375,10 @@ func verifyTestVector(t *testing.T, vector testVector) { t.Fatal("Failed to compute blind inverse") } - signer := NewRSASigner(key) - verifier := NewRSAVerifier(&key.PublicKey, crypto.SHA384) + signer := NewSigner(key) + verifier := NewVerifier(&key.PublicKey, crypto.SHA384) - blindedMsg, state, err := fixedBlind(vector.msg, vector.salt, r, rInv, verifier.pk, verifier.hash) + blindedMsg, state, err := fixedBlind(vector.msg, vector.salt, r, rInv, &key.PublicKey, verifier.Hash()) if err != nil { t.Fatal(err) } @@ -362,8 +393,8 @@ func verifyTestVector(t *testing.T, vector testVector) { t.Fatal(err) } - if !bytes.Equal(state.(RSAVerifierState).encodedMsg, vector.encodedMessage) { - t.Errorf("Encoded message mismatch: expected %x, got %x", state.(RSAVerifierState).encodedMsg, vector.encodedMessage) + if !bytes.Equal(state.encodedMsg, vector.encodedMessage) { + t.Errorf("Encoded message mismatch: expected %x, got %x", state.encodedMsg, vector.encodedMessage) } if !bytes.Equal(sig, vector.sig) { @@ -387,3 +418,48 @@ func TestVectors(t *testing.T) { verifyTestVector(t, vector) } } + +func BenchmarkBRSA(b *testing.B) { + message := []byte("hello world") + key := loadStrongRSAKey() + + verifier := NewVerifier(&key.PublicKey, crypto.SHA512) + signer := NewSigner(key) + + var err error + var blindedMsg []byte + var state VerifierState + b.Run("Blind", func(b *testing.B) { + for n := 0; n < b.N; n++ { + blindedMsg, state, err = verifier.Blind(rand.Reader, message) + if err != nil { + b.Fatal(err) + } + } + }) + + var blindedSig []byte + b.Run("BlindSign", func(b *testing.B) { + for n := 0; n < b.N; n++ { + blindedSig, err = signer.BlindSign(blindedMsg) + if err != nil { + b.Fatal(err) + } + } + }) + + var sig []byte + b.Run("Finalize", func(b *testing.B) { + for n := 0; n < b.N; n++ { + sig, err = state.Finalize(blindedSig) + if err != nil { + b.Fatal(err) + } + } + }) + + err = verifier.Verify(message, sig) + if err != nil { + b.Fatal(err) + } +} diff --git a/blindsign/blindrsa/internal/common/common.go b/blindsign/blindrsa/internal/common/common.go new file mode 100644 index 000000000..cc2688c41 --- /dev/null +++ b/blindsign/blindrsa/internal/common/common.go @@ -0,0 +1,145 @@ +package common + +import ( + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/sha512" + "crypto/subtle" + "errors" + "hash" + "io" + "math/big" + + "github.com/cloudflare/circl/blindsign/blindrsa/internal/keys" +) + +// ConvertHashFunction converts a crypto.Hash function to an equivalent hash.Hash type. +func ConvertHashFunction(hash crypto.Hash) hash.Hash { + switch hash { + case crypto.SHA256: + return sha256.New() + case crypto.SHA384: + return sha512.New384() + case crypto.SHA512: + return sha512.New() + default: + panic(ErrUnsupportedHashFunction) + } +} + +// EncodeMessageEMSAPSS hashes the input message and then encodes it using PSS encoding. +func EncodeMessageEMSAPSS(message []byte, N *big.Int, hash hash.Hash, salt []byte) ([]byte, error) { + hash.Reset() // Ensure the hash state is cleared + hash.Write(message) + digest := hash.Sum(nil) + hash.Reset() + emBits := N.BitLen() - 1 + encodedMsg, err := emsaPSSEncode(digest[:], emBits, salt, hash) + return encodedMsg, err +} + +// GenerateBlindingFactor generates a blinding factor and its multiplicative inverse +// to use for RSA blinding. +func GenerateBlindingFactor(random io.Reader, N *big.Int) (*big.Int, *big.Int, error) { + randReader := random + if randReader == nil { + randReader = rand.Reader + } + r, err := rand.Int(randReader, N) + if err != nil { + return nil, nil, err + } + + if r.Sign() == 0 { + r.SetInt64(1) + } + rInv := new(big.Int).ModInverse(r, N) + if rInv == nil { + return nil, nil, ErrInvalidBlind + } + + return r, rInv, nil +} + +// VerifyMessageSignature verifies the input message signature against the expected public key +func VerifyMessageSignature(message, signature []byte, saltLength int, pk *keys.BigPublicKey, hash crypto.Hash) error { + h := ConvertHashFunction(hash) + h.Write(message) + digest := h.Sum(nil) + + err := verifyPSS(pk, hash, digest, signature, &rsa.PSSOptions{ + Hash: hash, + SaltLength: saltLength, + }) + return err +} + +// DecryptAndCheck checks that the private key operation is consistent (fault attack detection). +func DecryptAndCheck(random io.Reader, priv *keys.BigPrivateKey, c *big.Int) (m *big.Int, err error) { + m, err = decrypt(random, priv, c) + if err != nil { + return nil, err + } + + // In order to defend against errors in the CRT computation, m^e is + // calculated, which should match the original ciphertext. + check := encrypt(new(big.Int), priv.Pk.N, priv.Pk.E, m) + if c.Cmp(check) != 0 { + return nil, errors.New("rsa: internal error") + } + return m, nil +} + +// VerifyBlindSignature verifies the signature of the hashed and encoded message against the input public key. +func VerifyBlindSignature(pub *keys.BigPublicKey, hashed, sig []byte) error { + m := new(big.Int).SetBytes(hashed) + bigSig := new(big.Int).SetBytes(sig) + + c := encrypt(new(big.Int), pub.N, pub.E, bigSig) + if subtle.ConstantTimeCompare(m.Bytes(), c.Bytes()) == 1 { + return nil + } else { + return rsa.ErrVerification + } +} + +func saltLength(opts *rsa.PSSOptions) int { + if opts == nil { + return rsa.PSSSaltLengthAuto + } + return opts.SaltLength +} + +func verifyPSS(pub *keys.BigPublicKey, hash crypto.Hash, digest []byte, sig []byte, opts *rsa.PSSOptions) error { + if len(sig) != pub.Size() { + return rsa.ErrVerification + } + s := new(big.Int).SetBytes(sig) + m := encrypt(new(big.Int), pub.N, pub.E, s) + emBits := pub.N.BitLen() - 1 + emLen := (emBits + 7) / 8 + if m.BitLen() > emLen*8 { + return rsa.ErrVerification + } + em := m.FillBytes(make([]byte, emLen)) + return emsaPSSVerify(digest, em, emBits, saltLength(opts), hash.New()) +} + +var ( + // ErrUnexpectedSize is the error used if the size of a parameter does not match its expected value. + ErrUnexpectedSize = errors.New("blindsign/blindrsa: unexpected input size") + + // ErrInvalidMessageLength is the error used if the size of a protocol message does not match its expected value. + ErrInvalidMessageLength = errors.New("blindsign/blindrsa: invalid message length") + + // ErrInvalidBlind is the error used if the blind generated by the Verifier fails. + ErrInvalidBlind = errors.New("blindsign/blindrsa: invalid blind") + + // ErrInvalidRandomness is the error used if caller did not provide randomness to the Blind() function. + ErrInvalidRandomness = errors.New("blindsign/blindrsa: invalid random parameter") + + // ErrUnsupportedHashFunction is the error used if the specified hash is not supported. + ErrUnsupportedHashFunction = errors.New("blindsign/blindrsa: unsupported hash function") +) diff --git a/blindsign/blindrsa/pss.go b/blindsign/blindrsa/internal/common/pss.go similarity index 58% rename from blindsign/blindrsa/pss.go rename to blindsign/blindrsa/internal/common/pss.go index 79ab75a87..000b1664f 100644 --- a/blindsign/blindrsa/pss.go +++ b/blindsign/blindrsa/internal/common/pss.go @@ -26,7 +26,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -package blindrsa +package common // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -35,6 +35,8 @@ package blindrsa // This file implements the RSASSA-PSS signature scheme according to RFC 8017. import ( + "bytes" + "crypto/rsa" "errors" "hash" ) @@ -126,3 +128,103 @@ func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byt // 13. Output EM. return em, nil } + +func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error { + // See RFC 8017, Section 9.1.2. + + hLen := hash.Size() + if sLen == rsa.PSSSaltLengthEqualsHash { + sLen = hLen + } + emLen := (emBits + 7) / 8 + if emLen != len(em) { + return errors.New("rsa: internal error: inconsistent length") + } + + // 1. If the length of M is greater than the input limitation for the + // hash function (2^61 - 1 octets for SHA-1), output "inconsistent" + // and stop. + // + // 2. Let mHash = Hash(M), an octet string of length hLen. + if hLen != len(mHash) { + return rsa.ErrVerification + } + + // 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop. + if emLen < hLen+sLen+2 { + return rsa.ErrVerification + } + + // 4. If the rightmost octet of EM does not have hexadecimal value + // 0xbc, output "inconsistent" and stop. + if em[emLen-1] != 0xbc { + return rsa.ErrVerification + } + + // 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and + // let H be the next hLen octets. + db := em[:emLen-hLen-1] + h := em[emLen-hLen-1 : emLen-1] + + // 6. If the leftmost 8 * emLen - emBits bits of the leftmost octet in + // maskedDB are not all equal to zero, output "inconsistent" and + // stop. + var bitMask byte = 0xff >> (8*emLen - emBits) + if em[0] & ^bitMask != 0 { + return rsa.ErrVerification + } + + // 7. Let dbMask = MGF(H, emLen - hLen - 1). + // + // 8. Let DB = maskedDB \xor dbMask. + mgf1XOR(db, hash, h) + + // 9. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in DB + // to zero. + db[0] &= bitMask + + // If we don't know the salt length, look for the 0x01 delimiter. + if sLen == rsa.PSSSaltLengthAuto { + psLen := bytes.IndexByte(db, 0x01) + if psLen < 0 { + return rsa.ErrVerification + } + sLen = len(db) - psLen - 1 + } + + // 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero + // or if the octet at position emLen - hLen - sLen - 1 (the leftmost + // position is "position 1") does not have hexadecimal value 0x01, + // output "inconsistent" and stop. + psLen := emLen - hLen - sLen - 2 + for _, e := range db[:psLen] { + if e != 0x00 { + return rsa.ErrVerification + } + } + if db[psLen] != 0x01 { + return rsa.ErrVerification + } + + // 11. Let salt be the last sLen octets of DB. + salt := db[len(db)-sLen:] + + // 12. Let + // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ; + // M' is an octet string of length 8 + hLen + sLen with eight + // initial zero octets. + // + // 13. Let H' = Hash(M'), an octet string of length hLen. + var prefix [8]byte + hash.Write(prefix[:]) + hash.Write(mHash) + hash.Write(salt) + + h0 := hash.Sum(nil) + + // 14. If H = H', output "consistent." Otherwise, output "inconsistent." + if !bytes.Equal(h0, h) { // TODO: constant time? + return rsa.ErrVerification + } + return nil +} diff --git a/blindsign/blindrsa/rsa.go b/blindsign/blindrsa/internal/common/rsa.go similarity index 65% rename from blindsign/blindrsa/rsa.go rename to blindsign/blindrsa/internal/common/rsa.go index 648d2730b..d39b4a276 100644 --- a/blindsign/blindrsa/rsa.go +++ b/blindsign/blindrsa/internal/common/rsa.go @@ -26,15 +26,16 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -package blindrsa +package common import ( "crypto/rand" "crypto/rsa" - "errors" "hash" "io" "math/big" + + "github.com/cloudflare/circl/blindsign/blindrsa/internal/keys" ) var ( @@ -77,21 +78,20 @@ func mgf1XOR(out []byte, hash hash.Hash, seed []byte) { } } -func encrypt(c *big.Int, pub *rsa.PublicKey, m *big.Int) *big.Int { - e := big.NewInt(int64(pub.E)) - c.Exp(m, e, pub.N) +func encrypt(c *big.Int, N *big.Int, e *big.Int, m *big.Int) *big.Int { + c.Exp(m, e, N) return c } // decrypt performs an RSA decryption, resulting in a plaintext integer. If a // random source is given, RSA blinding is used. -func decrypt(random io.Reader, priv *rsa.PrivateKey, c *big.Int) (m *big.Int, err error) { +func decrypt(random io.Reader, priv *keys.BigPrivateKey, c *big.Int) (m *big.Int, err error) { // TODO(agl): can we get away with reusing blinds? - if c.Cmp(priv.N) > 0 { + if c.Cmp(priv.Pk.N) > 0 { err = rsa.ErrDecryption return } - if priv.N.Sign() == 0 { + if priv.Pk.N.Sign() == 0 { return nil, rsa.ErrDecryption } @@ -105,75 +105,32 @@ func decrypt(random io.Reader, priv *rsa.PrivateKey, c *big.Int) (m *big.Int, er var r *big.Int ir = new(big.Int) for { - r, err = rand.Int(random, priv.N) + r, err = rand.Int(random, priv.Pk.N) if err != nil { return } if r.Cmp(bigZero) == 0 { r = bigOne } - ok := ir.ModInverse(r, priv.N) + ok := ir.ModInverse(r, priv.Pk.N) if ok != nil { break } } - bigE := big.NewInt(int64(priv.E)) - rpowe := new(big.Int).Exp(r, bigE, priv.N) // N != 0 + rpowe := new(big.Int).Exp(r, priv.Pk.E, priv.Pk.N) // N != 0 cCopy := new(big.Int).Set(c) cCopy.Mul(cCopy, rpowe) - cCopy.Mod(cCopy, priv.N) + cCopy.Mod(cCopy, priv.Pk.N) c = cCopy } - if priv.Precomputed.Dp == nil { - m = new(big.Int).Exp(c, priv.D, priv.N) - } else { - // We have the precalculated values needed for the CRT. - m = new(big.Int).Exp(c, priv.Precomputed.Dp, priv.Primes[0]) - m2 := new(big.Int).Exp(c, priv.Precomputed.Dq, priv.Primes[1]) - m.Sub(m, m2) - if m.Sign() < 0 { - m.Add(m, priv.Primes[0]) - } - m.Mul(m, priv.Precomputed.Qinv) - m.Mod(m, priv.Primes[0]) - m.Mul(m, priv.Primes[1]) - m.Add(m, m2) - - for i, values := range priv.Precomputed.CRTValues { - prime := priv.Primes[2+i] - m2.Exp(c, values.Exp, prime) - m2.Sub(m2, m) - m2.Mul(m2, values.Coeff) - m2.Mod(m2, prime) - if m2.Sign() < 0 { - m2.Add(m2, prime) - } - m2.Mul(m2, values.R) - m.Add(m, m2) - } - } + m = new(big.Int).Exp(c, priv.D, priv.Pk.N) if ir != nil { // Unblind. m.Mul(m, ir) - m.Mod(m, priv.N) + m.Mod(m, priv.Pk.N) } return m, nil } - -func decryptAndCheck(random io.Reader, priv *rsa.PrivateKey, c *big.Int) (m *big.Int, err error) { - m, err = decrypt(random, priv, c) - if err != nil { - return nil, err - } - - // In order to defend against errors in the CRT computation, m^e is - // calculated, which should match the original ciphertext. - check := encrypt(new(big.Int), &priv.PublicKey, m) - if c.Cmp(check) != 0 { - return nil, errors.New("rsa: internal error") - } - return m, nil -} diff --git a/blindsign/blindrsa/internal/keys/big_keys.go b/blindsign/blindrsa/internal/keys/big_keys.go new file mode 100644 index 000000000..f6ab42983 --- /dev/null +++ b/blindsign/blindrsa/internal/keys/big_keys.go @@ -0,0 +1,57 @@ +package keys + +import ( + "crypto/rsa" + "math/big" +) + +// BigPublicKey is the same as an rsa.PublicKey struct, except the public +// key is represented as a big integer as opposed to an int. For the partially +// blind scheme, this is required since the public key will typically be +// any value in the RSA group. +type BigPublicKey struct { + N *big.Int + E *big.Int +} + +// Size returns the size of the public key. +func (pub *BigPublicKey) Size() int { + return (pub.N.BitLen() + 7) / 8 +} + +// Marshal encodes the public key exponent (e). +func (pub *BigPublicKey) Marshal() []byte { + buf := make([]byte, (pub.E.BitLen()+7)/8) + pub.E.FillBytes(buf) + return buf +} + +// NewBigPublicKey creates a BigPublicKey from a rsa.PublicKey. +func NewBigPublicKey(pk *rsa.PublicKey) *BigPublicKey { + return &BigPublicKey{ + N: pk.N, + E: new(big.Int).SetInt64(int64(pk.E)), + } +} + +// CustomPublicKey is similar to rsa.PrivateKey, containing information needed +// for a private key used in the partially blind signature protocol. +type BigPrivateKey struct { + Pk *BigPublicKey + D *big.Int + P *big.Int + Q *big.Int +} + +// NewBigPrivateKey creates a BigPrivateKey from a rsa.PrivateKey. +func NewBigPrivateKey(sk *rsa.PrivateKey) *BigPrivateKey { + return &BigPrivateKey{ + Pk: &BigPublicKey{ + N: sk.N, + E: new(big.Int).SetInt64(int64(sk.PublicKey.E)), + }, + D: sk.D, + P: sk.Primes[0], + Q: sk.Primes[1], + } +} diff --git a/blindsign/blindrsa/partiallyblindrsa/pbrsa.go b/blindsign/blindrsa/partiallyblindrsa/pbrsa.go new file mode 100644 index 000000000..f168b3e56 --- /dev/null +++ b/blindsign/blindrsa/partiallyblindrsa/pbrsa.go @@ -0,0 +1,334 @@ +// Package partiallyblindrsa implements a partially blind RSA protocol. +package partiallyblindrsa + +import ( + "crypto" + "crypto/rand" + "crypto/rsa" + "encoding/binary" + "errors" + "hash" + "io" + "math/big" + + "github.com/cloudflare/circl/blindsign/blindrsa/internal/common" + "github.com/cloudflare/circl/blindsign/blindrsa/internal/keys" + "golang.org/x/crypto/hkdf" +) + +func encodeMessageMetadata(message, metadata []byte) []byte { + lenBuffer := []byte{'m', 's', 'g', 0, 0, 0, 0} + + binary.BigEndian.PutUint32(lenBuffer[3:], uint32(len(metadata))) + framedMetadata := append(lenBuffer, metadata...) + return append(framedMetadata, message...) +} + +// A randomizedVerifier represents a Verifier in the partially blind RSA signature protocol. +// It carries state needed to produce and validate an RSA signature produced +// using the blind RSA protocol. +type randomizedVerifier struct { + // Public key of the Signer + pk *keys.BigPublicKey + + // Identifier of the cryptographic hash function used in producing the message signature + cryptoHash crypto.Hash + + // Hash function used in producing the message signature + hash hash.Hash +} + +// NewVerifier creates a new PBRSAVerifier using the corresponding Signer parameters. +// This corresponds to the RSAPBSSA-SHA384-PSS-Deterministic variant. See the specification for more details: +// https://datatracker.ietf.org/doc/html/draft-amjad-cfrg-partially-blind-rsa#name-rsapbssa-variants +func NewVerifier(pk *rsa.PublicKey, hash crypto.Hash) Verifier { + h := common.ConvertHashFunction(hash) + return randomizedVerifier{ + pk: keys.NewBigPublicKey(pk), + cryptoHash: hash, + hash: h, + } +} + +// derivePublicKey tweaks the public key based on the input metadata. +// +// See the specification for more details: +// https://datatracker.ietf.org/doc/html/draft-amjad-cfrg-partially-blind-rsa-00#name-public-key-augmentation +// +// See the following issue for more discussion on HKDF vs hash-to-field: +// https://github.com/cfrg/draft-irtf-cfrg-hash-to-curve/issues/202 +func derivePublicKey(h crypto.Hash, pk *keys.BigPublicKey, metadata []byte) *keys.BigPublicKey { + // expandLen = ceil((ceil(log2(\lambda)/2) + k) / 8), where k is the security parameter of the suite (e.g., k = 128). + // We stretch the input metadata beyond \lambda bits s.t. the output bytes are indifferentiable from truly random bytes + lambda := pk.N.BitLen() / 2 + expandLen := uint((lambda + 128) / 8) + + hkdfSalt := make([]byte, (pk.N.BitLen()+7)/8) + pk.N.FillBytes(hkdfSalt) + hkdfInput := append([]byte("key"), append(metadata, 0x00)...) + + hkdf := hkdf.New(h.New, hkdfInput, hkdfSalt, []byte("PBRSA")) + bytes := make([]byte, expandLen) + _, err := hkdf.Read(bytes) + if err != nil { + panic(err) + } + + // H_MD(D) = 1 || G(x), where G(x) is output of length \lambda-2 bits + // We do this by sampling \lambda bits, clearing the top two bits (so the output is \lambda-2 bits) + // and setting the bottom bit (so the result is odd). + newE := new(big.Int).SetBytes(bytes[:lambda/8]) + newE.SetBit(newE, 0, 1) + newE.SetBit(newE, lambda-1, 0) + newE.SetBit(newE, lambda-2, 0) + + // Compute e_MD = e * H_MD(D) + return &keys.BigPublicKey{ + N: pk.N, + E: newE, + } +} + +// deriveKeyPair tweaks the private key using the metadata as input. +// +// See the specification for more details: +// https://datatracker.ietf.org/doc/html/draft-amjad-cfrg-partially-blind-rsa-00#name-private-key-augmentation +func deriveKeyPair(h crypto.Hash, sk *keys.BigPrivateKey, metadata []byte) *keys.BigPrivateKey { + // pih(N) = (p-1)(q-1) + pm1 := new(big.Int).Set(sk.P) + pm1.Sub(pm1, new(big.Int).SetInt64(int64(1))) + qm1 := new(big.Int).Set(sk.Q) + qm1.Sub(qm1, new(big.Int).SetInt64(int64(1))) + phi := new(big.Int).Mul(pm1, qm1) + + // d = e^-1 mod phi(N) + pk := derivePublicKey(h, sk.Pk, metadata) + bigE := new(big.Int).Mod(pk.E, phi) + d := new(big.Int).ModInverse(bigE, phi) + return &keys.BigPrivateKey{ + Pk: pk, + D: d, + P: sk.P, + Q: sk.Q, + } +} + +func fixedPartiallyBlind(message, salt []byte, r, rInv *big.Int, pk *keys.BigPublicKey, hash hash.Hash) ([]byte, VerifierState, error) { + encodedMsg, err := common.EncodeMessageEMSAPSS(message, pk.N, hash, salt) + if err != nil { + return nil, VerifierState{}, err + } + + m := new(big.Int).SetBytes(encodedMsg) + + bigE := pk.E + x := new(big.Int).Exp(r, bigE, pk.N) + z := new(big.Int).Set(m) + z.Mul(z, x) + z.Mod(z, pk.N) + + kLen := (pk.N.BitLen() + 7) / 8 + blindedMsg := make([]byte, kLen) + z.FillBytes(blindedMsg) + + return blindedMsg, VerifierState{ + encodedMsg: encodedMsg, + pk: pk, + hash: hash, + salt: salt, + rInv: rInv, + }, nil +} + +// Verifier is a type that implements the client side of the partially blind RSA +// protocol, described in https://datatracker.ietf.org/doc/html/draft-amjad-cfrg-partially-blind-rsa-00 +type Verifier interface { + // Blind initializes the partially blind RSA protocol using an input message and source of + // randomness. The signature includes a randomly generated PSS salt whose length equals the + // size of the underlying hash function. This function fails if randomness was not provided. + Blind(random io.Reader, message, metadata []byte) ([]byte, VerifierState, error) + + // FixedBlind initializes the partially blind RSA protocol using an input message, metadata, and randomness values. + FixedBlind(message, metadata, salt, blind, blindInv []byte) ([]byte, VerifierState, error) + + // Verify verifies the input (message, signature) pair using the augmented public key + // and produces an error upon failure. + Verify(message, signature, metadata []byte) error + + // Hash returns the hash function associated with the Verifier. + Hash() hash.Hash +} + +// Blind initializes the partially blind RSA protocol using an input message and source of randomness. The +// signature includes a randomly generated PSS salt whose length equals the size of the underlying +// hash function. This function fails if randomness was not provided. +// +// See the specification for more details: +// https://datatracker.ietf.org/doc/html/draft-amjad-cfrg-partially-blind-rsa-00#name-blind +func (v randomizedVerifier) Blind(random io.Reader, message, metadata []byte) ([]byte, VerifierState, error) { + if random == nil { + return nil, VerifierState{}, common.ErrInvalidRandomness + } + + salt := make([]byte, v.hash.Size()) + _, err := io.ReadFull(rand.Reader, salt) + if err != nil { + return nil, VerifierState{}, err + } + + r, rInv, err := common.GenerateBlindingFactor(random, v.pk.N) + if err != nil { + return nil, VerifierState{}, err + } + + return v.FixedBlind(message, metadata, salt, r.Bytes(), rInv.Bytes()) +} + +// FixedBlind initializes the partially blind RSA using fixed randomness as input. +func (v randomizedVerifier) FixedBlind(message, metadata, salt, blind, blindInv []byte) ([]byte, VerifierState, error) { + r := new(big.Int).SetBytes(blind) + rInv := new(big.Int).SetBytes(blindInv) + metadataKey := derivePublicKey(v.cryptoHash, v.pk, metadata) + inputMsg := encodeMessageMetadata(message, metadata) + return fixedPartiallyBlind(inputMsg, salt, r, rInv, metadataKey, v.hash) +} + +// Verify verifies the input (message, signature) pair using the augmented public key +// and produces an error upon failure. +// +// See the specification for more details: +// https://datatracker.ietf.org/doc/html/draft-amjad-cfrg-partially-blind-rsa-00#name-verification-2 +func (v randomizedVerifier) Verify(message, metadata, signature []byte) error { + metadataKey := derivePublicKey(v.cryptoHash, v.pk, metadata) + inputMsg := encodeMessageMetadata(message, metadata) + return common.VerifyMessageSignature(inputMsg, signature, v.hash.Size(), metadataKey, v.cryptoHash) +} + +// Hash returns the hash function associated with the Verifier. +func (v randomizedVerifier) Hash() hash.Hash { + return v.hash +} + +// A VerifierState carries state needed to complete the blind signature protocol +// as a verifier. +type VerifierState struct { + // Public key of the Signer + pk *keys.BigPublicKey + + // Hash function used in producing the message signature + hash hash.Hash + + // The hashed and encoded message being signed + encodedMsg []byte + + // The salt used when encoding the message + salt []byte + + // Inverse of the blinding factor produced by the Verifier + rInv *big.Int +} + +// Finalize computes and outputs the final signature, if it's valid. Otherwise, it returns an error. +// +// See the specification for more details: +// https://datatracker.ietf.org/doc/html/draft-amjad-cfrg-partially-blind-rsa-00#name-finalize +func (state VerifierState) Finalize(data []byte) ([]byte, error) { + kLen := (state.pk.N.BitLen() + 7) / 8 + if len(data) != kLen { + return nil, common.ErrUnexpectedSize + } + + z := new(big.Int).SetBytes(data) + s := new(big.Int).Set(state.rInv) + s.Mul(s, z) + s.Mod(s, state.pk.N) + + sig := make([]byte, kLen) + s.FillBytes(sig) + + err := common.VerifyBlindSignature(state.pk, state.encodedMsg, sig) + if err != nil { + return nil, err + } + + return sig, nil +} + +// CopyBlind returns an encoding of the blind value used in the protocol. +func (state VerifierState) CopyBlind() []byte { + r := new(big.Int).ModInverse(state.rInv, state.pk.N) + return r.Bytes() +} + +// CopySalt returns an encoding of the per-message salt used in the protocol. +func (state VerifierState) CopySalt() []byte { + salt := make([]byte, len(state.salt)) + copy(salt, state.salt) + return salt +} + +// An Signer represents the Signer in the blind RSA protocol. +// It carries the raw RSA private key used for signing blinded messages. +type Signer struct { + // An RSA private key + sk *keys.BigPrivateKey + h crypto.Hash +} + +// isSafePrime returns true if the input prime p is safe, i.e., p = (2 * q) + 1 for some prime q +func isSafePrime(p *big.Int) bool { + q := new(big.Int).Set(p) + q.Sub(q, big.NewInt(1)) + q.Div(q, big.NewInt(2)) + return q.ProbablyPrime(20) +} + +// NewSigner creates a new Signer for the blind RSA protocol using an RSA private key. +func NewSigner(sk *rsa.PrivateKey, h crypto.Hash) (Signer, error) { + bigSk := keys.NewBigPrivateKey(sk) + if !(isSafePrime(bigSk.P) && isSafePrime(bigSk.Q)) { + return Signer{}, ErrInvalidPrivateKey + } + + return Signer{ + sk: bigSk, + h: h, + }, nil +} + +// BlindSign blindly computes the RSA operation using the Signer's private key on the blinded +// message input, if it's of valid length, and returns an error should the function fail. +// +// See the specification for more details: +// https://datatracker.ietf.org/doc/html/draft-amjad-cfrg-partially-blind-rsa-00#name-blindsign +func (signer Signer) BlindSign(data, metadata []byte) ([]byte, error) { + kLen := (signer.sk.Pk.N.BitLen() + 7) / 8 + if len(data) != kLen { + return nil, common.ErrUnexpectedSize + } + + m := new(big.Int).SetBytes(data) + if m.Cmp(signer.sk.Pk.N) > 0 { + return nil, common.ErrInvalidMessageLength + } + + skPrime := deriveKeyPair(signer.h, signer.sk, metadata) + + s, err := common.DecryptAndCheck(rand.Reader, skPrime, m) + if err != nil { + return nil, err + } + + blindSig := make([]byte, kLen) + s.FillBytes(blindSig) + + return blindSig, nil +} + +var ( + // ErrInvalidPrivateKey is the error used if a private key is invalid + ErrInvalidPrivateKey = errors.New("blindsign/blindrsa/partiallyblindrsa: invalid private key") + ErrUnexpectedSize = common.ErrUnexpectedSize + ErrInvalidMessageLength = common.ErrInvalidMessageLength + ErrInvalidRandomness = common.ErrInvalidRandomness +) diff --git a/blindsign/blindrsa/partiallyblindrsa/pbrsa_test.go b/blindsign/blindrsa/partiallyblindrsa/pbrsa_test.go new file mode 100644 index 000000000..6e4690d1f --- /dev/null +++ b/blindsign/blindrsa/partiallyblindrsa/pbrsa_test.go @@ -0,0 +1,356 @@ +package partiallyblindrsa + +import ( + "bytes" + "crypto" + "crypto/rand" + "crypto/rsa" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "math/big" + "os" + "testing" + + "github.com/cloudflare/circl/blindsign/blindrsa/internal/keys" +) + +const ( + pbrsaTestVectorOutEnvironmentKey = "PBRSA_TEST_VECTORS_OUT" + pbrsaTestVectorInEnvironmentKey = "PBRSA_TEST_VECTORS_IN" +) + +func loadStrongRSAKey() *rsa.PrivateKey { + // https://gist.github.com/chris-wood/b77536febb25a5a11af428afff77820a + pEnc := "dcd90af1be463632c0d5ea555256a20605af3db667475e190e3af12a34a3324c46a3094062c59fb4b249e0ee6afba8bee14e0276d126c99f4784b23009bf6168ff628ac1486e5ae8e23ce4d362889de4df63109cbd90ef93db5ae64372bfe1c55f832766f21e94ea3322eb2182f10a891546536ba907ad74b8d72469bea396f3" + qEnc := "f8ba5c89bd068f57234a3cf54a1c89d5b4cd0194f2633ca7c60b91a795a56fa8c8686c0e37b1c4498b851e3420d08bea29f71d195cfbd3671c6ddc49cf4c1db5b478231ea9d91377ffa98fe95685fca20ba4623212b2f2def4da5b281ed0100b651f6db32112e4017d831c0da668768afa7141d45bbc279f1e0f8735d74395b3" + NEnc := "d6930820f71fe517bf3259d14d40209b02a5c0d3d61991c731dd7da39f8d69821552e2318d6c9ad897e603887a476ea3162c1205da9ac96f02edf31df049bd55f142134c17d4382a0e78e275345f165fbe8e49cdca6cf5c726c599dd39e09e75e0f330a33121e73976e4facba9cfa001c28b7c96f8134f9981db6750b43a41710f51da4240fe03106c12acb1e7bb53d75ec7256da3fddd0718b89c365410fce61bc7c99b115fb4c3c318081fa7e1b65a37774e8e50c96e8ce2b2cc6b3b367982366a2bf9924c4bafdb3ff5e722258ab705c76d43e5f1f121b984814e98ea2b2b8725cd9bc905c0bc3d75c2a8db70a7153213c39ae371b2b5dc1dafcb19d6fae9" + eEnc := "010001" + dEnc := "4e21356983722aa1adedb084a483401c1127b781aac89eab103e1cfc52215494981d18dd8028566d9d499469c25476358de23821c78a6ae43005e26b394e3051b5ca206aa9968d68cae23b5affd9cbb4cb16d64ac7754b3cdba241b72ad6ddfc000facdb0f0dd03abd4efcfee1730748fcc47b7621182ef8af2eeb7c985349f62ce96ab373d2689baeaea0e28ea7d45f2d605451920ca4ea1f0c08b0f1f6711eaa4b7cca66d58a6b916f9985480f90aca97210685ac7b12d2ec3e30a1c7b97b65a18d38a93189258aa346bf2bc572cd7e7359605c20221b8909d599ed9d38164c9c4abf396f897b9993c1e805e574d704649985b600fa0ced8e5427071d7049d" + + p := new(big.Int).SetBytes(mustDecodeHex(pEnc)) + q := new(big.Int).SetBytes(mustDecodeHex(qEnc)) + N := new(big.Int).SetBytes(mustDecodeHex(NEnc)) + e := new(big.Int).SetBytes(mustDecodeHex(eEnc)) + d := new(big.Int).SetBytes(mustDecodeHex(dEnc)) + + primes := make([]*big.Int, 2) + primes[0] = p + primes[1] = q + + key := &rsa.PrivateKey{ + PublicKey: rsa.PublicKey{ + N: N, + E: int(e.Int64()), + }, + D: d, + Primes: primes, + } + + return key +} + +func runPBRSA(signer Signer, verifier Verifier, message, metadata []byte, random io.Reader) ([]byte, error) { + blindedMsg, state, err := verifier.Blind(random, message, metadata) + if err != nil { + return nil, err + } + + kLen := (signer.sk.Pk.N.BitLen() + 7) / 8 + if len(blindedMsg) != kLen { + return nil, fmt.Errorf("Protocol message (blind message) length mismatch, expected %d, got %d", kLen, len(blindedMsg)) + } + + blindedSig, err := signer.BlindSign(blindedMsg, metadata) + if err != nil { + return nil, err + } + + if len(blindedSig) != kLen { + return nil, fmt.Errorf("Protocol message (blind signature) length mismatch, expected %d, got %d", kLen, len(blindedMsg)) + } + + sig, err := state.Finalize(blindedSig) + if err != nil { + return nil, err + } + + err = verifier.Verify(message, metadata, sig) + if err != nil { + return nil, err + } + + return sig, nil +} + +func mustDecodeHex(h string) []byte { + b, err := hex.DecodeString(h) + if err != nil { + panic(err) + } + return b +} + +func TestPBRSARoundTrip(t *testing.T) { + message := []byte("hello world") + metadata := []byte("metadata") + key := loadStrongRSAKey() + + hash := crypto.SHA384 + verifier := NewVerifier(&key.PublicKey, hash) + signer, err := NewSigner(key, hash) + if err != nil { + t.Fatal(err) + } + + sig, err := runPBRSA(signer, verifier, message, metadata, rand.Reader) + if err != nil { + t.Fatal(err) + } + if sig == nil { + t.Fatal("nil signature output") + } +} + +type encodedPBRSATestVector struct { + Message string `json:"msg"` + Info string `json:"info"` + P string `json:"p"` + Q string `json:"q"` + D string `json:"d"` + E string `json:"e"` + N string `json:"N"` + Eprime string `json:"eprime"` + Blind string `json:"blind"` + Salt string `json:"salt"` + Request string `json:"blinded_msg"` + Response string `json:"blinded_sig"` + Signature string `json:"sig"` +} + +type rawPBRSATestVector struct { + privateKey *rsa.PrivateKey + message []byte + info []byte + infoKey []byte + blind []byte + salt []byte + request []byte + response []byte + signature []byte +} + +func mustHex(d []byte) string { + return hex.EncodeToString(d) +} + +func (tv rawPBRSATestVector) MarshalJSON() ([]byte, error) { + pEnc := mustHex(tv.privateKey.Primes[0].Bytes()) + qEnc := mustHex(tv.privateKey.Primes[1].Bytes()) + nEnc := mustHex(tv.privateKey.N.Bytes()) + e := new(big.Int).SetInt64(int64(tv.privateKey.PublicKey.E)) + eEnc := mustHex(e.Bytes()) + dEnc := mustHex(tv.privateKey.D.Bytes()) + ePrimeEnc := mustHex(tv.infoKey) + return json.Marshal(encodedPBRSATestVector{ + P: pEnc, + Q: qEnc, + D: dEnc, + E: eEnc, + N: nEnc, + Eprime: ePrimeEnc, + Message: mustHex(tv.message), + Info: mustHex(tv.info), + Blind: mustHex(tv.blind), + Salt: mustHex(tv.salt), + Request: mustHex(tv.request), + Response: mustHex(tv.response), + Signature: mustHex(tv.signature), + }) +} + +func generatePBRSATestVector(t *testing.T, msg, metadata []byte) rawPBRSATestVector { + key := loadStrongRSAKey() + + hash := crypto.SHA384 + verifier := NewVerifier(&key.PublicKey, hash) + signer, err := NewSigner(key, hash) + if err != nil { + t.Fatal(err) + } + + publicKey := keys.NewBigPublicKey(&key.PublicKey) + metadataKey := derivePublicKey(hash, publicKey, metadata) + + blindedMsg, state, err := verifier.Blind(rand.Reader, msg, metadata) + if err != nil { + t.Fatal(err) + } + + blindedSig, err := signer.BlindSign(blindedMsg, metadata) + if err != nil { + t.Fatal(err) + } + + sig, err := state.Finalize(blindedSig) + if err != nil { + t.Fatal(err) + } + + err = verifier.Verify(msg, metadata, sig) + if err != nil { + t.Fatal(err) + } + + return rawPBRSATestVector{ + message: msg, + info: metadata, + privateKey: key, + infoKey: metadataKey.Marshal(), + salt: state.CopySalt(), + blind: state.CopyBlind(), + request: blindedMsg, + response: blindedSig, + signature: sig, + } +} + +func verifyTestVector(t *testing.T, vector rawPBRSATestVector) { + key := loadStrongRSAKey() + + key.PublicKey.N = vector.privateKey.N + key.PublicKey.E = vector.privateKey.E + key.D = vector.privateKey.D + key.Primes[0] = vector.privateKey.Primes[0] + key.Primes[1] = vector.privateKey.Primes[1] + key.Precomputed.Dp = nil // Remove precomputed CRT values + + hash := crypto.SHA384 + signer, err := NewSigner(key, hash) + if err != nil { + t.Fatal(err) + } + verifier := NewVerifier(&key.PublicKey, crypto.SHA384) + + r := new(big.Int).SetBytes(vector.blind) + rInv := new(big.Int).ModInverse(r, key.N) + if r == nil { + t.Fatal("Failed to compute blind inverse") + } + + blindedMsg, state, err := verifier.FixedBlind(vector.message, vector.info, vector.salt, r.Bytes(), rInv.Bytes()) + if err != nil { + t.Fatal(err) + } + + blindSig, err := signer.BlindSign(blindedMsg, vector.info) + if err != nil { + t.Fatal(err) + } + + sig, err := state.Finalize(blindSig) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(sig, vector.signature) { + t.Errorf("Signature mismatch: expected %x, got %x", sig, vector.signature) + } +} + +func TestPBRSAGenerateTestVector(t *testing.T) { + testCases := []struct { + msg []byte + metadata []byte + }{ + { + []byte("hello world"), + []byte("metadata"), + }, + { + []byte("hello world"), + []byte(""), + }, + { + []byte(""), + []byte("metadata"), + }, + { + []byte(""), + []byte(""), + }, + } + + vectors := []rawPBRSATestVector{} + for _, testCase := range testCases { + vectors = append(vectors, generatePBRSATestVector(t, testCase.msg, testCase.metadata)) + } + + for _, vector := range vectors { + verifyTestVector(t, vector) + } + + // Encode the test vectors + encoded, err := json.Marshal(vectors) + if err != nil { + t.Fatalf("Error producing test vectors: %v", err) + } + + var outputFile string + if outputFile = os.Getenv(pbrsaTestVectorOutEnvironmentKey); len(outputFile) > 0 { + err := os.WriteFile(outputFile, encoded, 0o600) + if err != nil { + t.Fatalf("Error writing test vectors: %v", err) + } + } +} + +func BenchmarkPBRSA(b *testing.B) { + message := []byte("hello world") + metadata := []byte("good doggo") + key := loadStrongRSAKey() + + hash := crypto.SHA384 + verifier := NewVerifier(&key.PublicKey, hash) + signer, err := NewSigner(key, hash) + if err != nil { + b.Fatal(err) + } + + var blindedMsg []byte + var state VerifierState + b.Run("Blind", func(b *testing.B) { + for n := 0; n < b.N; n++ { + blindedMsg, state, err = verifier.Blind(rand.Reader, message, metadata) + if err != nil { + b.Fatal(err) + } + } + }) + + var blindedSig []byte + b.Run("BlindSign", func(b *testing.B) { + for n := 0; n < b.N; n++ { + blindedSig, err = signer.BlindSign(blindedMsg, metadata) + if err != nil { + b.Fatal(err) + } + } + }) + + var sig []byte + b.Run("Finalize", func(b *testing.B) { + for n := 0; n < b.N; n++ { + sig, err = state.Finalize(blindedSig) + if err != nil { + b.Fatal(err) + } + } + }) + + err = verifier.Verify(message, metadata, sig) + if err != nil { + b.Fatal(err) + } +} diff --git a/blindsign/blindsign.go b/blindsign/blindsign.go deleted file mode 100644 index dabba89e4..000000000 --- a/blindsign/blindsign.go +++ /dev/null @@ -1,42 +0,0 @@ -// Package blindsign provides a blind signature protocol. -// -// A blind signature protocol is a two-party protocol for computing -// a digital signature. One party (the server) holds the signing key, -// and the other (the client) holds the message input. Blindness -// ensures that the server does not learn anything about the client's -// input during the BlindSign step. -package blindsign - -import "io" - -// A Verifier represents a specific instance of a blind signature verifier. -type Verifier interface { - // Blind produces an encoded protocol message and VerifierState based on - // the input message and Signer's public key. - Blind(random io.Reader, message []byte) ([]byte, VerifierState, error) - - // Verify verifies a (message, signature) pair over and produces an error - // if the signature is invalid. - Verify(message, signature []byte) error -} - -// A VerifierState represents the protocol state used to run and complete a -// specific blind signature protocol. -type VerifierState interface { - // Finalize completes the blind signature protocol and produces a signature - // over the corresponding Verifier-provided message. - Finalize(data []byte) ([]byte, error) - - // CopyBlind returns an encoding of the blind value used in the protocol. - CopyBlind() []byte - - // CopySalt returns an encoding of the per-message salt used in the protocol. - CopySalt() []byte -} - -// A Signer represents a specific instance of a blind signature signer. -type Signer interface { - // Blindly signs the input message using the Signer's private key - // and produces an encoded blind signature protocol message as output. - BlindSign(data []byte) ([]byte, error) -} diff --git a/blindsign/doc.go b/blindsign/doc.go new file mode 100644 index 000000000..e9ebecd9b --- /dev/null +++ b/blindsign/doc.go @@ -0,0 +1,2 @@ +// Package blindsign provides blind signature schemes. +package blindsign From c6e36610df7a47c5822e161cbd169bdc9e2ab636 Mon Sep 17 00:00:00 2001 From: Nadim Kobeissi Date: Sun, 9 Jul 2023 14:02:04 +0200 Subject: [PATCH 08/47] Update doc.go Fix typo. --- ecc/bls12381/doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecc/bls12381/doc.go b/ecc/bls12381/doc.go index 83da41d4d..d7e07e54b 100644 --- a/ecc/bls12381/doc.go +++ b/ecc/bls12381/doc.go @@ -1,6 +1,6 @@ // Package bls12381 provides bilinear pairings using the BLS12-381 curve. // -// A pairing system consists of three groups G1 and G2 (adiitive notation) and +// A pairing system consists of three groups G1 and G2 (additive notation) and // Gt (multiplicative notation) of the same order. // Scalars can be used interchangeably between groups. // From 099d3138029043ea98dbc60e9b451a6d8b75cce6 Mon Sep 17 00:00:00 2001 From: armfazh Date: Mon, 17 Jul 2023 17:35:01 -0700 Subject: [PATCH 09/47] Key generation for threshold RSA (safe primes). --- math/primes.go | 34 ++++++++++++++++++++ math/primes_test.go | 46 +++++++++++++++++++++++++++ tss/doc.go | 1 + tss/rsa/rsa_threshold.go | 60 +++++++++++++++++++++++++++++++++++ tss/rsa/rsa_threshold_test.go | 11 +++++++ 5 files changed, 152 insertions(+) create mode 100644 math/primes.go create mode 100644 math/primes_test.go diff --git a/math/primes.go b/math/primes.go new file mode 100644 index 000000000..158fd83a7 --- /dev/null +++ b/math/primes.go @@ -0,0 +1,34 @@ +package math + +import ( + "crypto/rand" + "io" + "math/big" +) + +// IsSafePrime reports whether p is (probably) a safe prime. +// The prime p=2*q+1 is safe prime if both p and q are primes. +// Note that ProbablyPrime is not suitable for judging primes +// that an adversary may have crafted to fool the test. +func IsSafePrime(p *big.Int) bool { + pdiv2 := new(big.Int).Rsh(p, 1) + return p.ProbablyPrime(20) && pdiv2.ProbablyPrime(20) +} + +// SafePrime returns a number of the given bit length that is a safe prime with high probability. +// The number returned p=2*q+1 is a safe prime if both p and q are primes. +// SafePrime will return error for any error returned by rand.Read or if bits < 2. +func SafePrime(random io.Reader, bits int) (*big.Int, error) { + one := big.NewInt(1) + p := new(big.Int) + for { + q, err := rand.Prime(random, bits-1) + if err != nil { + return nil, err + } + p.Lsh(q, 1).Add(p, one) + if p.ProbablyPrime(20) { + return p, nil + } + } +} diff --git a/math/primes_test.go b/math/primes_test.go new file mode 100644 index 000000000..6075c0177 --- /dev/null +++ b/math/primes_test.go @@ -0,0 +1,46 @@ +package math + +import ( + "crypto/rand" + "fmt" + "math/big" + "testing" + + "github.com/cloudflare/circl/internal/test" +) + +func TestSafePrime(t *testing.T) { + firstSafePrimes := []int64{ + 5, 7, 11, 23, 47, 59, 83, 107, 167, 179, 227, 263, 347, 359, 383, 467, + 479, 503, 563, 587, 719, 839, 863, 887, 983, 1019, 1187, 1283, 1307, + 1319, 1367, 1439, 1487, 1523, 1619, 1823, 1907, 2027, 2039, 2063, 2099, + 2207, 2447, 2459, 2579, 2819, 2879, 2903, 2963, 2999, 3023, 3119, 3167, + 3203, 3467, 3623, 3779, 3803, 3863, 3947, 4007, 4079, 4127, 4139, 4259, + 4283, 4547, 4679, 4703, 4787, 4799, 4919, 5087, 5099, 5387, 5399, 5483, + 5507, 5639, 5807, 5879, 5927, 5939, 6047, 6599, 6659, 6719, 6779, 6827, + 6899, 6983, 7079, 7187, 7247, 7523, 7559, 7607, 7643, 7703, 7727, + } + + p := new(big.Int) + for _, pi := range firstSafePrimes { + p.SetInt64(pi) + test.CheckOk(IsSafePrime(p), fmt.Sprintf("it should be a safe prime p=%v", p), t) + } +} + +func TestIsSafePrime(t *testing.T) { + for i := 1; i < 5; i++ { + bits := 128 * i + t.Run(fmt.Sprint(bits), func(t *testing.T) { + p, err := SafePrime(rand.Reader, bits) + test.CheckNoErr(t, err, "safeprime failed") + test.CheckOk(IsSafePrime(p), fmt.Sprintf("it should be a safe prime p=%v", p), t) + }) + } +} + +func BenchmarkSafePrime(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _ = SafePrime(rand.Reader, 256) + } +} diff --git a/tss/doc.go b/tss/doc.go index 547e8491e..f3e650b43 100644 --- a/tss/doc.go +++ b/tss/doc.go @@ -1 +1,2 @@ +// Package tss provides threshold signature schemes. package tss diff --git a/tss/rsa/rsa_threshold.go b/tss/rsa/rsa_threshold.go index d4afd460e..424b8236b 100644 --- a/tss/rsa/rsa_threshold.go +++ b/tss/rsa/rsa_threshold.go @@ -1,3 +1,11 @@ +// Package rsa provides RSA threshold signature scheme. +// +// This package implements the Protocol 1 of "Practical Threshold Signatures" +// by Victor Shoup [1]. +// +// # References +// +// [1] https://www.iacr.org/archive/eurocrypt2000/1807/18070209-new.pdf package rsa import ( @@ -9,8 +17,60 @@ import ( "io" "math" "math/big" + + cmath "github.com/cloudflare/circl/math" ) +// GenerateKey generates a RSA keypair for its use in RSA threshold signatures. +// Internally, the modulus is the product of two safe primes. The time +// consumed by this function is relatively longer than the regular +// GenerateKey function from the crypto/rsa package. +func GenerateKey(random io.Reader, bits int) (*rsa.PrivateKey, error) { + p, err := cmath.SafePrime(random, bits/2) + if err != nil { + return nil, err + } + + var q *big.Int + n := new(big.Int) + found := false + for !found { + q, err = cmath.SafePrime(random, bits-p.BitLen()) + if err != nil { + return nil, err + } + + // check for different primes. + if p.Cmp(q) != 0 { + n.Mul(p, q) + // check n has the desired bitlength. + if n.BitLen() == bits { + found = true + } + } + } + + one := big.NewInt(1) + pminus1 := new(big.Int).Sub(p, one) + qminus1 := new(big.Int).Sub(q, one) + totient := new(big.Int).Mul(pminus1, qminus1) + + priv := new(rsa.PrivateKey) + priv.Primes = []*big.Int{p, q} + priv.N = n + priv.E = 65537 + priv.D = new(big.Int) + e := big.NewInt(int64(priv.E)) + ok := priv.D.ModInverse(e, totient) + if ok == nil { + return nil, errors.New("public key is not coprime to phi(n)") + } + + priv.Precompute() + + return priv, nil +} + // l or `Players`, the total number of Players. // t, the number of corrupted Players. // k=t+1 or `Threshold`, the number of signature shares needed to obtain a signature. diff --git a/tss/rsa/rsa_threshold_test.go b/tss/rsa/rsa_threshold_test.go index c4f29c424..82fc224d6 100644 --- a/tss/rsa/rsa_threshold_test.go +++ b/tss/rsa/rsa_threshold_test.go @@ -7,13 +7,24 @@ import ( "crypto/rsa" _ "crypto/sha256" "errors" + "fmt" "io" "math/big" "testing" + + "github.com/cloudflare/circl/internal/test" ) var ONE = big.NewInt(1) +func TestGenerateKey(t *testing.T) { + // [Warning]: this is only for tests, use a secure bitlen above 2048 bits. + bitlen := 128 + key, err := GenerateKey(rand.Reader, bitlen) + test.CheckNoErr(t, err, "failed to create key") + test.CheckOk(key.Validate() == nil, fmt.Sprintf("key is not valid: %v", key), t) +} + func createPrivateKey(p, q *big.Int, e int) *rsa.PrivateKey { return &rsa.PrivateKey{ PublicKey: rsa.PublicKey{ From b6a5470c8bc140d99a2e2af19f961ad99f27804d Mon Sep 17 00:00:00 2001 From: armfazh Date: Wed, 6 Sep 2023 15:54:11 -0700 Subject: [PATCH 10/47] Bumping Go version for CI jobs. --- .github/workflows/ci-actions.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-actions.yml b/.github/workflows/ci-actions.yml index 6cf57619a..9ea681219 100644 --- a/.github/workflows/ci-actions.yml +++ b/.github/workflows/ci-actions.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - GOVER: ['1.20', '1.19'] + GOVER: ['1.21.1', '1.20.8'] steps: - name: Setup Go-${{ matrix.GOVER }} uses: actions/setup-go@v3 @@ -47,7 +47,7 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - CFG: [[arm64, arm64v8, '1.20']] + CFG: [[arm64, arm64v8, '1.21.1']] steps: - uses: actions/checkout@v3 - name: Enabling Docker Experimental @@ -72,7 +72,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v3 with: - go-version: '1.20' + go-version: '1.21.1' - name: Build as Static run: make circl_static - name: Build as Plugin @@ -88,7 +88,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v3 with: - go-version: '1.20' + go-version: '1.21.1' - name: Produce Coverage run: go test -coverprofile=./coverage.txt ./... - name: Upload Codecov @@ -108,7 +108,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v3 with: - go-version: '1.20' + go-version: '1.21.1' - name: Building run: go build -v ./... - name: Testing From fb86491a42637750dc763de7e425150660a930a9 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:34:21 -0400 Subject: [PATCH 11/47] spelling: absorbed Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- xof/k12/k12.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xof/k12/k12.go b/xof/k12/k12.go index 3c503a186..bbd33d117 100644 --- a/xof/k12/k12.go +++ b/xof/k12/k12.go @@ -31,7 +31,7 @@ type State struct { context []byte // context string "C" provided by the user // buffer of incoming data so we can do parallel TurboSHAKE128: - // nil when we haven't aborbed the first chunk yet; + // nil when we haven't absorbed the first chunk yet; // empty if we have, but we do not have a fast parallel TurboSHAKE128; // and chunkSize*lanes in length if we have. buf []byte From cc4fe1c0deee8e9a91f278b01a2ec94caa732535 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:34:34 -0400 Subject: [PATCH 12/47] spelling: according Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- dh/sidh/internal/p434/core.go | 2 +- dh/sidh/internal/p503/core.go | 2 +- dh/sidh/internal/p751/core.go | 2 +- dh/sidh/internal/templates/core.gotemp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dh/sidh/internal/p434/core.go b/dh/sidh/internal/p434/core.go index 3660252ac..78022b6c3 100644 --- a/dh/sidh/internal/p434/core.go +++ b/dh/sidh/internal/p434/core.go @@ -9,7 +9,7 @@ import ( ) // ----------------------------------------------------------------------------- -// Functions for traversing isogeny trees acoording to strategy. Key type 'A' is +// Functions for traversing isogeny trees according to strategy. Key type 'A' is // // Traverses isogeny tree in order to compute xR, xP, xQ and xQmP needed diff --git a/dh/sidh/internal/p503/core.go b/dh/sidh/internal/p503/core.go index 02ccfb8c6..cda3e0b5f 100644 --- a/dh/sidh/internal/p503/core.go +++ b/dh/sidh/internal/p503/core.go @@ -9,7 +9,7 @@ import ( ) // ----------------------------------------------------------------------------- -// Functions for traversing isogeny trees acoording to strategy. Key type 'A' is +// Functions for traversing isogeny trees according to strategy. Key type 'A' is // // Traverses isogeny tree in order to compute xR, xP, xQ and xQmP needed diff --git a/dh/sidh/internal/p751/core.go b/dh/sidh/internal/p751/core.go index e22356077..a79ff035e 100644 --- a/dh/sidh/internal/p751/core.go +++ b/dh/sidh/internal/p751/core.go @@ -9,7 +9,7 @@ import ( ) // ----------------------------------------------------------------------------- -// Functions for traversing isogeny trees acoording to strategy. Key type 'A' is +// Functions for traversing isogeny trees according to strategy. Key type 'A' is // // Traverses isogeny tree in order to compute xR, xP, xQ and xQmP needed diff --git a/dh/sidh/internal/templates/core.gotemp b/dh/sidh/internal/templates/core.gotemp index d9abdd87f..b2d10ba64 100644 --- a/dh/sidh/internal/templates/core.gotemp +++ b/dh/sidh/internal/templates/core.gotemp @@ -9,7 +9,7 @@ import ( ) // ----------------------------------------------------------------------------- -// Functions for traversing isogeny trees acoording to strategy. Key type 'A' is +// Functions for traversing isogeny trees according to strategy. Key type 'A' is // // Traverses isogeny tree in order to compute xR, xP, xQ and xQmP needed From 7f4276e52267e0dae79db68f9181a61e6bf3e944 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Tue, 5 Sep 2023 17:43:55 -0400 Subject: [PATCH 13/47] spelling: alice Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- dh/sidh/sidh_test.go | 8 ++++---- dh/sidh/sike_test.go | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/dh/sidh/sidh_test.go b/dh/sidh/sidh_test.go index 7219b96c4..36fb7e6ca 100644 --- a/dh/sidh/sidh_test.go +++ b/dh/sidh/sidh_test.go @@ -582,13 +582,13 @@ func BenchmarkSharedSecretBobP434(b *testing.B) { func ExamplePrivateKey() { // import "github.com/cloudflare/circl/dh/sidh" - // Allice's key pair + // Alice's key pair prvA := NewPrivateKey(Fp503, KeyVariantSidhA) pubA := NewPublicKey(Fp503, KeyVariantSidhA) // Bob's key pair prvB := NewPrivateKey(Fp503, KeyVariantSidhB) pubB := NewPublicKey(Fp503, KeyVariantSidhB) - // Generate keypair for Allice + // Generate keypair for Alice err := prvA.Generate(rand.Reader) if err != nil { fmt.Print(err) @@ -603,11 +603,11 @@ func ExamplePrivateKey() { // Buffers storing shared secret ssA := make([]byte, prvA.SharedSecretSize()) ssB := make([]byte, prvA.SharedSecretSize()) - // Allice calculates shared secret with hers private + // Alice calculates shared secret with hers private // key and Bob's public key prvA.DeriveSecret(ssA[:], pubB) // Bob calculates shared secret with hers private - // key and Allice's public key + // key and Alice's public key prvB.DeriveSecret(ssB[:], pubA) // Check if ssA == ssB fmt.Printf("%t\n", bytes.Equal(ssA, ssB)) diff --git a/dh/sidh/sike_test.go b/dh/sidh/sike_test.go index 0d5961c9c..b153e2368 100644 --- a/dh/sidh/sike_test.go +++ b/dh/sidh/sike_test.go @@ -530,13 +530,13 @@ func BenchmarkEncaps(b *testing.B) { benchSike(b, &tdataSike, benchmarkEncaps) } func BenchmarkDecaps(b *testing.B) { benchSike(b, &tdataSike, benchmarkDecaps) } func ExampleKEM() { - // Allice's key pair + // Alice's key pair prvA := NewPrivateKey(Fp503, KeyVariantSike) pubA := NewPublicKey(Fp503, KeyVariantSike) // Bob's key pair prvB := NewPrivateKey(Fp503, KeyVariantSike) pubB := NewPublicKey(Fp503, KeyVariantSike) - // Generate keypair for Allice + // Generate keypair for Alice err := prvA.Generate(rand.Reader) if err != nil { panic(err) @@ -555,7 +555,7 @@ func ExampleKEM() { ct := make([]byte, kem.CiphertextSize()) ssE := make([]byte, kem.SharedSecretSize()) ssD := make([]byte, kem.SharedSecretSize()) - // Allice performs encapsulation with Bob's public key + // Alice performs encapsulation with Bob's public key err = kem.Encapsulate(ct, ssE, pubB) if err != nil { panic(err) @@ -567,12 +567,12 @@ func ExampleKEM() { } fmt.Printf("%t\n", bytes.Equal(ssE, ssD)) - // Bob performs encapsulation with Allices's public key + // Bob performs encapsulation with Alice's public key err = kem.Encapsulate(ct, ssE, pubA) if err != nil { panic(err) } - // Allice performs decapsulation with hers key pair + // Alice performs decapsulation with hers key pair err = kem.Decapsulate(ssD, prvA, pubA, ct) if err != nil { panic(err) From b15252a295492ccae85c353dd20edf078d46823c Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 03:28:41 -0400 Subject: [PATCH 14/47] spelling: arbitrary Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- pke/kyber/internal/common/poly.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pke/kyber/internal/common/poly.go b/pke/kyber/internal/common/poly.go index f6842152b..d72f35d36 100644 --- a/pke/kyber/internal/common/poly.go +++ b/pke/kyber/internal/common/poly.go @@ -43,7 +43,7 @@ func (p *Poly) normalizeGeneric() { // Multiplies p in-place by the Montgomery factor 2¹⁶. // -// Coefficients of p can be artbitray. Resulting coefficients are bounded +// Coefficients of p can be arbitrary. Resulting coefficients are bounded // in absolute value by q. func (p *Poly) ToMont() { for i := 0; i < N; i++ { From 150880c592ff7f7af05734001d8913bcb8e0b079 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:37:15 -0400 Subject: [PATCH 15/47] spelling: butterflies Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- pke/kyber/internal/common/asm/src.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pke/kyber/internal/common/asm/src.go b/pke/kyber/internal/common/asm/src.go index 451f8f81c..fd3a6dae9 100644 --- a/pke/kyber/internal/common/asm/src.go +++ b/pke/kyber/internal/common/asm/src.go @@ -121,7 +121,7 @@ func subAVX2() { // Why these permutations? There are two reasons: these are reasonable // easy to implement and they pull sequential butterflies in the NTT apart. // Recall, namely, that on the fifth layer of the NTT we're computing -// butteflies between indices +// butterflies between indices // // abcd0fgh abcd1fgh // From b6e37ef74af8a405a9799d4f333879c69a7f423d Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:37:49 -0400 Subject: [PATCH 16/47] spelling: ciphertext Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- abe/cpabe/tkn20/internal/tkn/bk.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abe/cpabe/tkn20/internal/tkn/bk.go b/abe/cpabe/tkn20/internal/tkn/bk.go index e68897a31..1d3fc3657 100644 --- a/abe/cpabe/tkn20/internal/tkn/bk.go +++ b/abe/cpabe/tkn20/internal/tkn/bk.go @@ -243,7 +243,7 @@ func (p *Policy) ExtractFromCiphertext(ct []byte) error { } macData, _, err := removeLenPrefixed(rest) if err != nil { - return fmt.Errorf("invalid ciphetext") + return fmt.Errorf("invalid ciphertext") } C1, _, err := removeLenPrefixed(macData) if err != nil { From 17f6d07c08315d3b1823da6b58173efa0b134d10 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 03:30:38 -0400 Subject: [PATCH 17/47] spelling: cofactor Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- dh/csidh/csidh.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dh/csidh/csidh.go b/dh/csidh/csidh.go index 286a31ed3..5b6b549bb 100644 --- a/dh/csidh/csidh.go +++ b/dh/csidh/csidh.go @@ -66,7 +66,7 @@ func (s *fpRngGen) randFp(v *fp, rng io.Reader) { // cofactorMul helper implements batch cofactor multiplication as described // in the ia.cr/2018/383 (algo. 3). Returns tuple of two booleans, first indicates // if function has finished successfully. In case first return value is true, -// second return value indicates if curve represented by coffactor 'a' is +// second return value indicates if curve represented by cofactor 'a' is // supersingular. // Implementation uses divide-and-conquer strategy and recursion in order to // speed up calculation of Q_i = [(p+1)/l_i] * P. From 180417f2ec72c43523ce7ecae4b7ae12d8c91ba7 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:38:06 -0400 Subject: [PATCH 18/47] spelling: compatibility Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- sign/ed25519/ed25519.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sign/ed25519/ed25519.go b/sign/ed25519/ed25519.go index 08ca65d79..2c73c26fb 100644 --- a/sign/ed25519/ed25519.go +++ b/sign/ed25519/ed25519.go @@ -1,7 +1,7 @@ // Package ed25519 implements Ed25519 signature scheme as described in RFC-8032. // // This package provides optimized implementations of the three signature -// variants and maintaining closer compatiblilty with crypto/ed25519. +// variants and maintaining closer compatibility with crypto/ed25519. // // | Scheme Name | Sign Function | Verification | Context | // |-------------|-------------------|---------------|-------------------| From e57c142a74c9e796f54c0e1920c301b0197658d1 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:38:38 -0400 Subject: [PATCH 19/47] spelling: compliant Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- group/ristretto255.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/group/ristretto255.go b/group/ristretto255.go index c1312c18f..cd077d34c 100644 --- a/group/ristretto255.go +++ b/group/ristretto255.go @@ -100,7 +100,7 @@ func (g ristrettoGroup) HashToElementNonUniform(b, dst []byte) Element { } func (g ristrettoGroup) HashToElement(msg, dst []byte) Element { - // Compliaint with draft-irtf-cfrg-hash-to-curve. + // Compliant with draft-irtf-cfrg-hash-to-curve. // Appendix B - Hashing to ristretto255 // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-14#appendix-B // SuiteID: ristretto255_XMD:SHA-512_R255MAP_RO_ From d12f3338e770b65757a0c077c5748dd3ad501200 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:38:57 -0400 Subject: [PATCH 20/47] spelling: convenient Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- pke/kyber/internal/common/amd64.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pke/kyber/internal/common/amd64.go b/pke/kyber/internal/common/amd64.go index 79629160a..6ffd94b1f 100644 --- a/pke/kyber/internal/common/amd64.go +++ b/pke/kyber/internal/common/amd64.go @@ -10,7 +10,7 @@ import ( // ZetasAVX2 contains all ζ used in NTT (like the Zetas array), but also // the values int16(zeta * 62209) for each zeta, which is used in // Montgomery reduction. There is some duplication and reordering as -// compared to Zetas to make it more covenient for use with AVX2. +// compared to Zetas to make it more convenient for use with AVX2. var ZetasAVX2 = [...]int16{ // level 1: int16(Zetas[1]*62209) and Zetas[1] 31499, 2571, From f0b91028171f35bdcaae346925c9b86f5fc66888 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:39:45 -0400 Subject: [PATCH 21/47] spelling: decapsulation Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- dh/sidh/sike_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dh/sidh/sike_test.go b/dh/sidh/sike_test.go index b153e2368..9fa2316b0 100644 --- a/dh/sidh/sike_test.go +++ b/dh/sidh/sike_test.go @@ -338,7 +338,7 @@ func testKAT(t *testing.T, v sikeVec) { } err := v.kem.Decapsulate(ssGot, prvKey, pubKey, ct) - CheckNoErr(t, err, "sike test: can't perform degcapsulation KAT") + CheckNoErr(t, err, "sike test: can't perform decapsulation KAT") if !bytes.Equal(ssGot, ssExpected) { t.Fatalf("KAT decapsulation failed\n") } From 3052013a63d5bafae149212da7155cc71db31c09 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:40:05 -0400 Subject: [PATCH 22/47] spelling: deterministic Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- blindsign/blindrsa/brsa.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/blindsign/blindrsa/brsa.go b/blindsign/blindrsa/brsa.go index 390de6940..c303b484e 100644 --- a/blindsign/blindrsa/brsa.go +++ b/blindsign/blindrsa/brsa.go @@ -35,8 +35,8 @@ type randomBRSAVerifier struct { hash hash.Hash } -// A determinsiticBRSAVerifier is a BRSAVerifier that supports deterministic signatures. -type determinsiticBRSAVerifier struct { +// A deterministicBRSAVerifier is a BRSAVerifier that supports deterministic signatures. +type deterministicBRSAVerifier struct { // Public key of the Signer pk *rsa.PublicKey @@ -64,12 +64,12 @@ type Verifier interface { Hash() hash.Hash } -// NewDeterministicVerifier creates a new DeterminsiticBRSAVerifier using the corresponding Signer parameters. +// NewDeterministicVerifier creates a new DeterministicBRSAVerifier using the corresponding Signer parameters. // This corresponds to the RSABSSA-SHA384-PSSZERO-Deterministic variant. See the specification for more details: // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures#name-rsabssa-variants func NewDeterministicVerifier(pk *rsa.PublicKey, hash crypto.Hash) Verifier { h := common.ConvertHashFunction(hash) - return determinsiticBRSAVerifier{ + return deterministicBRSAVerifier{ pk: pk, cryptoHash: hash, hash: h, @@ -77,7 +77,7 @@ func NewDeterministicVerifier(pk *rsa.PublicKey, hash crypto.Hash) Verifier { } // Hash returns the hash function associated with the BRSAVerifier. -func (v determinsiticBRSAVerifier) Hash() hash.Hash { +func (v deterministicBRSAVerifier) Hash() hash.Hash { return v.hash } @@ -130,7 +130,7 @@ func fixedBlind(message, salt []byte, r, rInv *big.Int, pk *rsa.PublicKey, hash // // See the specification for more details: // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-02#section-5.1.1 -func (v determinsiticBRSAVerifier) Blind(random io.Reader, message []byte) ([]byte, VerifierState, error) { +func (v deterministicBRSAVerifier) Blind(random io.Reader, message []byte) ([]byte, VerifierState, error) { if random == nil { return nil, VerifierState{}, common.ErrInvalidRandomness } @@ -144,7 +144,7 @@ func (v determinsiticBRSAVerifier) Blind(random io.Reader, message []byte) ([]by } // FixedBlind runs the Blind function with fixed blind and salt inputs. -func (v determinsiticBRSAVerifier) FixedBlind(message, blind, salt []byte) ([]byte, VerifierState, error) { +func (v deterministicBRSAVerifier) FixedBlind(message, blind, salt []byte) ([]byte, VerifierState, error) { if blind == nil { return nil, VerifierState{}, common.ErrInvalidRandomness } @@ -162,7 +162,7 @@ func (v determinsiticBRSAVerifier) FixedBlind(message, blind, salt []byte) ([]by } // Verify verifies the input (message, signature) pair and produces an error upon failure. -func (v determinsiticBRSAVerifier) Verify(message, signature []byte) error { +func (v deterministicBRSAVerifier) Verify(message, signature []byte) error { return common.VerifyMessageSignature(message, signature, 0, keys.NewBigPublicKey(v.pk), v.cryptoHash) } From f231c13d32533ff42dcbeaa2fb3beadc7ab61ab0 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:39:56 -0400 Subject: [PATCH 23/47] spelling: deterministically Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- hpke/hybridkem.go | 2 +- hpke/shortkem.go | 2 +- hpke/xkem.go | 2 +- kem/kem.go | 2 +- oprf/oprf.go | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hpke/hybridkem.go b/hpke/hybridkem.go index 2abffefd7..74e1ea6f1 100644 --- a/hpke/hybridkem.go +++ b/hpke/hybridkem.go @@ -153,7 +153,7 @@ func (k *hybridKEMPubKey) Equal(pk kem.PublicKey) bool { k.pubB.Equal(k1.pubB) } -// Deterministicallly derives a keypair from a seed. If you're unsure, +// Deterministically derives a keypair from a seed. If you're unsure, // you're better off using GenerateKey(). // // Panics if seed is not of length SeedSize(). diff --git a/hpke/shortkem.go b/hpke/shortkem.go index ca0b88439..e5c55e991 100644 --- a/hpke/shortkem.go +++ b/hpke/shortkem.go @@ -37,7 +37,7 @@ func (s shortKEM) calcDH(dh []byte, sk kem.PrivateKey, pk kem.PublicKey) error { return nil } -// Deterministicallly derives a keypair from a seed. If you're unsure, +// Deterministically derives a keypair from a seed. If you're unsure, // you're better off using GenerateKey(). // // Panics if seed is not of length SeedSize(). diff --git a/hpke/xkem.go b/hpke/xkem.go index 58ca2bee7..f11ab6b37 100644 --- a/hpke/xkem.go +++ b/hpke/xkem.go @@ -48,7 +48,7 @@ func (x xKEM) calcDH(dh []byte, sk kem.PrivateKey, pk kem.PublicKey) error { return nil } -// Deterministicallly derives a keypair from a seed. If you're unsure, +// Deterministically derives a keypair from a seed. If you're unsure, // you're better off using GenerateKey(). // // Panics if seed is not of length SeedSize(). diff --git a/kem/kem.go b/kem/kem.go index ca550c657..6ab0aa3ba 100644 --- a/kem/kem.go +++ b/kem/kem.go @@ -63,7 +63,7 @@ type Scheme interface { // Size of packed public keys. PublicKeySize() int - // DeriveKeyPair deterministicallly derives a pair of keys from a seed. + // DeriveKeyPair deterministically derives a pair of keys from a seed. // Panics if the length of seed is not equal to the value returned by // SeedSize. DeriveKeyPair(seed []byte) (PublicKey, PrivateKey) diff --git a/oprf/oprf.go b/oprf/oprf.go index eb562a018..febe5b1e1 100644 --- a/oprf/oprf.go +++ b/oprf/oprf.go @@ -265,7 +265,7 @@ type FinalizeData struct { evalReq *EvaluationRequest } -// CopyBlinds copies the serialized blinds to use when determinstically +// CopyBlinds copies the serialized blinds to use when deterministically // invoking DeterministicBlind. func (f FinalizeData) CopyBlinds() []Blind { out := make([]Blind, len(f.blinds)) From 67f1f420db9586f5428a6418231d426695f74de2 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:40:28 -0400 Subject: [PATCH 24/47] spelling: divisible Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- pke/kyber/internal/common/field.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pke/kyber/internal/common/field.go b/pke/kyber/internal/common/field.go index 33744dff7..31e93ed52 100644 --- a/pke/kyber/internal/common/field.go +++ b/pke/kyber/internal/common/field.go @@ -17,7 +17,7 @@ func montReduce(x int32) int16 { // we have int32(int64(a)*int64(b)) = int32(a*b) and so the result is ok. m := int16(x * 62209) - // Note that x - m q is divisable by R; indeed modulo R we have + // Note that x - m q is divisible by R; indeed modulo R we have // // x - m q ≡ x - x q' q ≡ x - x q⁻¹ q ≡ x - x = 0. // From 8e5b305757755c41871bf701db8fae25a9fed1e4 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:41:03 -0400 Subject: [PATCH 25/47] spelling: element Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- group/group.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/group/group.go b/group/group.go index 5ef5e51f8..9644d8c4d 100644 --- a/group/group.go +++ b/group/group.go @@ -88,7 +88,7 @@ type Element interface { // BinaryUnmarshaler recovers an element from a byte representation // produced either by encoding.BinaryMarshaler or MarshalBinaryCompress. encoding.BinaryUnmarshaler - // MarshalBinaryCompress returns a byte representation of an elment in a + // MarshalBinaryCompress returns a byte representation of an element in a // compact form whenever the group supports it; otherwise, returns the // same byte representation produced by encoding.BinaryMarshaler. MarshalBinaryCompress() ([]byte, error) From a00bc1af8997c76b2688c47f07ef2826c7adfd87 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:41:14 -0400 Subject: [PATCH 26/47] spelling: encryption Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- pke/kyber/kyber.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pke/kyber/kyber.go b/pke/kyber/kyber.go index e3f5041d8..1fb9a0c47 100644 --- a/pke/kyber/kyber.go +++ b/pke/kyber/kyber.go @@ -1,6 +1,6 @@ //go:generate go run gen.go -// Package kyber implements the CRYSTALS-Kyber.CPAPKE public key encrpyption +// Package kyber implements the CRYSTALS-Kyber.CPAPKE public key encryption // as submitted to round 3 of the NIST PQC competition and described in // // https://pq-crystals.org/kyber/data/kyber-specification-round3.pdf From 16268dcabb812c85312fb1dba9b3185478812fd6 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:41:35 -0400 Subject: [PATCH 27/47] spelling: exponentiation Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- abe/cpabe/tkn20/internal/tkn/matrixGT_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abe/cpabe/tkn20/internal/tkn/matrixGT_test.go b/abe/cpabe/tkn20/internal/tkn/matrixGT_test.go index d290c8219..4fd609397 100644 --- a/abe/cpabe/tkn20/internal/tkn/matrixGT_test.go +++ b/abe/cpabe/tkn20/internal/tkn/matrixGT_test.go @@ -157,7 +157,7 @@ func TestExpGTLinearity(t *testing.T) { absum.add(aexp, bexp) abexp.exp(ab) if !abexp.Equal(absum) { - t.Fatal("linearity of exponentation broken") + t.Fatal("linearity of exponentiation broken") } } From 20d4c2d675a4bf2b0c95059a12cdbf4ce40372cc Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:42:25 -0400 Subject: [PATCH 28/47] spelling: isogenous Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- dh/sidh/internal/p434/core.go | 4 ++-- dh/sidh/internal/p503/core.go | 4 ++-- dh/sidh/internal/p751/core.go | 4 ++-- dh/sidh/internal/templates/core.gotemp | 4 ++-- ecc/goldilocks/twist.go | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/dh/sidh/internal/p434/core.go b/dh/sidh/internal/p434/core.go index 78022b6c3..736d4c6f4 100644 --- a/dh/sidh/internal/p434/core.go +++ b/dh/sidh/internal/p434/core.go @@ -252,7 +252,7 @@ func DeriveSecretA(ss, prv []byte, pub3Pt *[3]Fp2) { // Traverse isogeny tree traverseTreeSharedKeyA(&cparam, &xR) - // Calculate j-invariant on isogeneus curve + // Calculate j-invariant on isogenous curve c := phi.GenerateCurve(&xR) RecoverCurveCoefficients4(&cparam, &c) Jinvariant(&cparam, &jInv) @@ -290,7 +290,7 @@ func DeriveSecretB(ss, prv []byte, pub3Pt *[3]Fp2) { // Traverse isogeny tree traverseTreeSharedKeyB(&cparam, &xR) - // Calculate j-invariant on isogeneus curve + // Calculate j-invariant on isogenous curve c := phi.GenerateCurve(&xR) RecoverCurveCoefficients3(&cparam, &c) Jinvariant(&cparam, &jInv) diff --git a/dh/sidh/internal/p503/core.go b/dh/sidh/internal/p503/core.go index cda3e0b5f..178951e48 100644 --- a/dh/sidh/internal/p503/core.go +++ b/dh/sidh/internal/p503/core.go @@ -252,7 +252,7 @@ func DeriveSecretA(ss, prv []byte, pub3Pt *[3]Fp2) { // Traverse isogeny tree traverseTreeSharedKeyA(&cparam, &xR) - // Calculate j-invariant on isogeneus curve + // Calculate j-invariant on isogenous curve c := phi.GenerateCurve(&xR) RecoverCurveCoefficients4(&cparam, &c) Jinvariant(&cparam, &jInv) @@ -290,7 +290,7 @@ func DeriveSecretB(ss, prv []byte, pub3Pt *[3]Fp2) { // Traverse isogeny tree traverseTreeSharedKeyB(&cparam, &xR) - // Calculate j-invariant on isogeneus curve + // Calculate j-invariant on isogenous curve c := phi.GenerateCurve(&xR) RecoverCurveCoefficients3(&cparam, &c) Jinvariant(&cparam, &jInv) diff --git a/dh/sidh/internal/p751/core.go b/dh/sidh/internal/p751/core.go index a79ff035e..d0b9993e8 100644 --- a/dh/sidh/internal/p751/core.go +++ b/dh/sidh/internal/p751/core.go @@ -252,7 +252,7 @@ func DeriveSecretA(ss, prv []byte, pub3Pt *[3]Fp2) { // Traverse isogeny tree traverseTreeSharedKeyA(&cparam, &xR) - // Calculate j-invariant on isogeneus curve + // Calculate j-invariant on isogenous curve c := phi.GenerateCurve(&xR) RecoverCurveCoefficients4(&cparam, &c) Jinvariant(&cparam, &jInv) @@ -290,7 +290,7 @@ func DeriveSecretB(ss, prv []byte, pub3Pt *[3]Fp2) { // Traverse isogeny tree traverseTreeSharedKeyB(&cparam, &xR) - // Calculate j-invariant on isogeneus curve + // Calculate j-invariant on isogenous curve c := phi.GenerateCurve(&xR) RecoverCurveCoefficients3(&cparam, &c) Jinvariant(&cparam, &jInv) diff --git a/dh/sidh/internal/templates/core.gotemp b/dh/sidh/internal/templates/core.gotemp index b2d10ba64..2f4ace0ef 100644 --- a/dh/sidh/internal/templates/core.gotemp +++ b/dh/sidh/internal/templates/core.gotemp @@ -252,7 +252,7 @@ func DeriveSecretA(ss, prv []byte, pub3Pt *[3]Fp2) { // Traverse isogeny tree traverseTreeSharedKeyA(&cparam, &xR) - // Calculate j-invariant on isogeneus curve + // Calculate j-invariant on isogenous curve c := phi.GenerateCurve(&xR) RecoverCurveCoefficients4(&cparam, &c) Jinvariant(&cparam, &jInv) @@ -290,7 +290,7 @@ func DeriveSecretB(ss, prv []byte, pub3Pt *[3]Fp2) { // Traverse isogeny tree traverseTreeSharedKeyB(&cparam, &xR) - // Calculate j-invariant on isogeneus curve + // Calculate j-invariant on isogenous curve c := phi.GenerateCurve(&xR) RecoverCurveCoefficients3(&cparam, &c) Jinvariant(&cparam, &jInv) diff --git a/ecc/goldilocks/twist.go b/ecc/goldilocks/twist.go index 8cd4e333b..83d7cdadd 100644 --- a/ecc/goldilocks/twist.go +++ b/ecc/goldilocks/twist.go @@ -9,7 +9,7 @@ import ( fp "github.com/cloudflare/circl/math/fp448" ) -// twistCurve is -x^2+y^2=1-39082x^2y^2 and is 4-isogeneous to Goldilocks. +// twistCurve is -x^2+y^2=1-39082x^2y^2 and is 4-isogenous to Goldilocks. type twistCurve struct{} // Identity returns the identity point. From fb0a6861e1795ac61d54a7fe216c86f3c9f524a1 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:43:20 -0400 Subject: [PATCH 29/47] spelling: mapping Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- ecc/bls12381/g1Isog.go | 2 +- ecc/bls12381/g2Isog.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ecc/bls12381/g1Isog.go b/ecc/bls12381/g1Isog.go index 99752be8c..4db77e418 100644 --- a/ecc/bls12381/g1Isog.go +++ b/ecc/bls12381/g1Isog.go @@ -28,7 +28,7 @@ func (p *isogG1Point) IsOnCurve() bool { } // sswu implements the Simplified Shallue-van de Woestijne-Ulas method for -// maping a field element to a point on the isogenous curve. +// mapping a field element to a point on the isogenous curve. func (p *isogG1Point) sswu(u *ff.Fp) { // Method in Appendix-G.2.1 of // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11 diff --git a/ecc/bls12381/g2Isog.go b/ecc/bls12381/g2Isog.go index aac78e056..f819b11be 100644 --- a/ecc/bls12381/g2Isog.go +++ b/ecc/bls12381/g2Isog.go @@ -28,7 +28,7 @@ func (p *isogG2Point) IsOnCurve() bool { } // sswu implements the Simplified Shallue-van de Woestijne-Ulas method for -// maping a field element to a point on the isogenous curve. +// mapping a field element to a point on the isogenous curve. func (p *isogG2Point) sswu(u *ff.Fp2) { // Method in Appendix-G.2.3 of // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11 From f3b37b8b6a3e466d872853d5893b1a34c2867e2d Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:44:08 -0400 Subject: [PATCH 30/47] spelling: only Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- dh/csidh/curve.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dh/csidh/curve.go b/dh/csidh/curve.go index e68f4f066..aebf40e4e 100644 --- a/dh/csidh/curve.go +++ b/dh/csidh/curve.go @@ -24,7 +24,7 @@ func xAdd(PaQ, P, Q, PdQ *point) { } // xDbl implements point doubling on a Montgomery curve -// E(x): x^3 + A*x^2 + x by using x-coordinate onlyh arithmetic. +// E(x): x^3 + A*x^2 + x by using x-coordinate only arithmetic. // // x(Q) = [2]*x(P) // @@ -48,7 +48,7 @@ func xDbl(Q, P, A *point) { // xDblAdd implements combined doubling of point P // and addition of points P and Q on a Montgomery curve -// E(x): x^3 + A*x^2 + x by using x-coordinate onlyh arithmetic. +// E(x): x^3 + A*x^2 + x by using x-coordinate only arithmetic. // // x(PaP) = x(2*P) // x(PaQ) = x(P+Q) From 883c8090dbe038b0cc14e414943b52b0c1391aa6 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:43:58 -0400 Subject: [PATCH 31/47] spelling: opposite Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- pke/kyber/internal/common/ntt.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pke/kyber/internal/common/ntt.go b/pke/kyber/internal/common/ntt.go index c1abaf237..5e565b344 100644 --- a/pke/kyber/internal/common/ntt.go +++ b/pke/kyber/internal/common/ntt.go @@ -146,7 +146,7 @@ func (p *Poly) invNTTGeneric() { k := 127 // Index into Zetas r := -1 // Index into InvNTTReductions. - // We basically do the oppposite of NTT, but postpone dividing by 2 in the + // We basically do the opposite of NTT, but postpone dividing by 2 in the // inverse of the Cooley-Tukey butterfly and accumulate that into a big // division by 2⁷ at the end. See the comments in the NTT() function. From c2ce95dcab4102b354a0c4556c35bac83bfc36b6 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:44:24 -0400 Subject: [PATCH 32/47] spelling: permutation Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- pke/kyber/internal/common/asm/src.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pke/kyber/internal/common/asm/src.go b/pke/kyber/internal/common/asm/src.go index fd3a6dae9..418a7a38b 100644 --- a/pke/kyber/internal/common/asm/src.go +++ b/pke/kyber/internal/common/asm/src.go @@ -701,7 +701,7 @@ func nttAVX2() { // which pairs to flip. We try to keep the permutations as local // as possible: there is only mixing between xs[0], xs[1], xs[2] // and xs[3]. As an added benefit this ensures that the final - // complete permuation is convenient for multiplication. + // complete permutation is convenient for multiplication. VMOVDQU(Mem{Base: zetasPtr, Disp: 32 * (9 + offset*4)}, zs[0]) VMOVDQU(Mem{Base: zetasPtr, Disp: 32 * (9 + offset*4 + 1)}, zs[1]) From e84c34aeef2ba1beec275d796e1719d52c56d39b Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:44:48 -0400 Subject: [PATCH 33/47] spelling: recovered Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- abe/cpabe/tkn20/example_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abe/cpabe/tkn20/example_test.go b/abe/cpabe/tkn20/example_test.go index 068cff74b..38bc7e305 100644 --- a/abe/cpabe/tkn20/example_test.go +++ b/abe/cpabe/tkn20/example_test.go @@ -124,7 +124,7 @@ func Example() { log.Fatalf("decryption using right attrs should have succeeded, plaintext: %s", pt) } if !bytes.Equal(pt, []byte(msgStr)) { - log.Fatalf("recoverd plaintext: %s is not equal to original msg: %s", pt, msgStr) + log.Fatalf("recovered plaintext: %s is not equal to original msg: %s", pt, msgStr) } fmt.Println("Successfully recovered plaintext") // Output: (occupation:doctor and country:US) From b9e82f9de41d55842eeef2bef5359dd04dbefcaf Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:44:57 -0400 Subject: [PATCH 34/47] spelling: recovers Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- dh/sidh/internal/p434/curve.go | 2 +- dh/sidh/internal/p503/curve.go | 2 +- dh/sidh/internal/p751/curve.go | 2 +- dh/sidh/internal/templates/curve.gotemp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dh/sidh/internal/p434/curve.go b/dh/sidh/internal/p434/curve.go index 741717ef3..5b476c7c2 100644 --- a/dh/sidh/internal/p434/curve.go +++ b/dh/sidh/internal/p434/curve.go @@ -48,7 +48,7 @@ func Jinvariant(cparams *ProjectiveCurveParameters, j *Fp2) { } // Given affine points x(P), x(Q) and x(Q-P) in a extension field F_{p^2}, function -// recorvers projective coordinate A of a curve. This is Algorithm 10 from SIKE. +// recovers projective coordinate A of a curve. This is Algorithm 10 from SIKE. func RecoverCoordinateA(curve *ProjectiveCurveParameters, xp, xq, xr *Fp2) { var t0, t1 Fp2 diff --git a/dh/sidh/internal/p503/curve.go b/dh/sidh/internal/p503/curve.go index 4bce35f81..e4613eff0 100644 --- a/dh/sidh/internal/p503/curve.go +++ b/dh/sidh/internal/p503/curve.go @@ -48,7 +48,7 @@ func Jinvariant(cparams *ProjectiveCurveParameters, j *Fp2) { } // Given affine points x(P), x(Q) and x(Q-P) in a extension field F_{p^2}, function -// recorvers projective coordinate A of a curve. This is Algorithm 10 from SIKE. +// recovers projective coordinate A of a curve. This is Algorithm 10 from SIKE. func RecoverCoordinateA(curve *ProjectiveCurveParameters, xp, xq, xr *Fp2) { var t0, t1 Fp2 diff --git a/dh/sidh/internal/p751/curve.go b/dh/sidh/internal/p751/curve.go index 6ac2d2502..b9d766a98 100644 --- a/dh/sidh/internal/p751/curve.go +++ b/dh/sidh/internal/p751/curve.go @@ -48,7 +48,7 @@ func Jinvariant(cparams *ProjectiveCurveParameters, j *Fp2) { } // Given affine points x(P), x(Q) and x(Q-P) in a extension field F_{p^2}, function -// recorvers projective coordinate A of a curve. This is Algorithm 10 from SIKE. +// recovers projective coordinate A of a curve. This is Algorithm 10 from SIKE. func RecoverCoordinateA(curve *ProjectiveCurveParameters, xp, xq, xr *Fp2) { var t0, t1 Fp2 diff --git a/dh/sidh/internal/templates/curve.gotemp b/dh/sidh/internal/templates/curve.gotemp index a3e941dd1..48c4b5b9b 100644 --- a/dh/sidh/internal/templates/curve.gotemp +++ b/dh/sidh/internal/templates/curve.gotemp @@ -48,7 +48,7 @@ func Jinvariant(cparams *ProjectiveCurveParameters, j *Fp2) { } // Given affine points x(P), x(Q) and x(Q-P) in a extension field F_{p^2}, function -// recorvers projective coordinate A of a curve. This is Algorithm 10 from SIKE. +// recovers projective coordinate A of a curve. This is Algorithm 10 from SIKE. func RecoverCoordinateA(curve *ProjectiveCurveParameters, xp, xq, xr *Fp2) { var t0, t1 Fp2 From f22959ec58a8c3b4d4a4edabc0cb7dbabbe8a92b Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:45:06 -0400 Subject: [PATCH 35/47] spelling: representation Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- ecc/bls12381/ff/doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecc/bls12381/ff/doc.go b/ecc/bls12381/ff/doc.go index 05d70acab..83cbea439 100644 --- a/ecc/bls12381/ff/doc.go +++ b/ecc/bls12381/ff/doc.go @@ -19,7 +19,7 @@ // // # Fp4 // -// Fp4 is GF(p^4)=Fp2[t]/(t^2-(u+1)). We use the repesentation a[1]v+a[0]. +// Fp4 is GF(p^4)=Fp2[t]/(t^2-(u+1)). We use the representation a[1]v+a[0]. // There is no fixed external form. // // # Fp6 From b4d5ea8da52254033a5e98897cf6aa71f7d1d854 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:51:07 -0400 Subject: [PATCH 36/47] spelling: specialize Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- abe/cpabe/tkn20/internal/tkn/tk.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abe/cpabe/tkn20/internal/tkn/tk.go b/abe/cpabe/tkn20/internal/tkn/tk.go index 60df30ad3..3903a0968 100644 --- a/abe/cpabe/tkn20/internal/tkn/tk.go +++ b/abe/cpabe/tkn20/internal/tkn/tk.go @@ -352,7 +352,7 @@ func (hdr *ciphertextHeader) marshalBinary() ([]byte, error) { ret = appendLenPrefixed(ret, c1Bytes) // Now we need to indicate how long c2, c3, c3neg are. - // Each array will be the same size (or nil), so with more work we can specalize + // Each array will be the same size (or nil), so with more work we can specialize // but for now we will ignore that. c2Len := len(hdr.c2) From 82b749575db9953cc5d4073b704e078d75ba9e5b Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:33:59 -0400 Subject: [PATCH 37/47] spelling: the Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- sign/dilithium/mode2/internal/sample.go | 2 +- sign/dilithium/mode2aes/internal/sample.go | 2 +- sign/dilithium/mode3/internal/sample.go | 2 +- sign/dilithium/mode3aes/internal/sample.go | 2 +- sign/dilithium/mode5/internal/sample.go | 2 +- sign/dilithium/mode5aes/internal/sample.go | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sign/dilithium/mode2/internal/sample.go b/sign/dilithium/mode2/internal/sample.go index fa866293c..c47185ada 100644 --- a/sign/dilithium/mode2/internal/sample.go +++ b/sign/dilithium/mode2/internal/sample.go @@ -240,7 +240,7 @@ func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { } // For each i, sample ps[i] uniformly with τ non-zero coefficients in {q-1,1} -// using the the given seed and w1[i]. ps[i] may be nil and is ignored +// using the given seed and w1[i]. ps[i] may be nil and is ignored // in that case. ps[i] will be normalized. // // Can only be called when DeriveX4Available is true. diff --git a/sign/dilithium/mode2aes/internal/sample.go b/sign/dilithium/mode2aes/internal/sample.go index fa866293c..c47185ada 100644 --- a/sign/dilithium/mode2aes/internal/sample.go +++ b/sign/dilithium/mode2aes/internal/sample.go @@ -240,7 +240,7 @@ func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { } // For each i, sample ps[i] uniformly with τ non-zero coefficients in {q-1,1} -// using the the given seed and w1[i]. ps[i] may be nil and is ignored +// using the given seed and w1[i]. ps[i] may be nil and is ignored // in that case. ps[i] will be normalized. // // Can only be called when DeriveX4Available is true. diff --git a/sign/dilithium/mode3/internal/sample.go b/sign/dilithium/mode3/internal/sample.go index ccde1f2ed..256ec731f 100644 --- a/sign/dilithium/mode3/internal/sample.go +++ b/sign/dilithium/mode3/internal/sample.go @@ -238,7 +238,7 @@ func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { } // For each i, sample ps[i] uniformly with τ non-zero coefficients in {q-1,1} -// using the the given seed and w1[i]. ps[i] may be nil and is ignored +// using the given seed and w1[i]. ps[i] may be nil and is ignored // in that case. ps[i] will be normalized. // // Can only be called when DeriveX4Available is true. diff --git a/sign/dilithium/mode3aes/internal/sample.go b/sign/dilithium/mode3aes/internal/sample.go index fa866293c..c47185ada 100644 --- a/sign/dilithium/mode3aes/internal/sample.go +++ b/sign/dilithium/mode3aes/internal/sample.go @@ -240,7 +240,7 @@ func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { } // For each i, sample ps[i] uniformly with τ non-zero coefficients in {q-1,1} -// using the the given seed and w1[i]. ps[i] may be nil and is ignored +// using the given seed and w1[i]. ps[i] may be nil and is ignored // in that case. ps[i] will be normalized. // // Can only be called when DeriveX4Available is true. diff --git a/sign/dilithium/mode5/internal/sample.go b/sign/dilithium/mode5/internal/sample.go index fa866293c..c47185ada 100644 --- a/sign/dilithium/mode5/internal/sample.go +++ b/sign/dilithium/mode5/internal/sample.go @@ -240,7 +240,7 @@ func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { } // For each i, sample ps[i] uniformly with τ non-zero coefficients in {q-1,1} -// using the the given seed and w1[i]. ps[i] may be nil and is ignored +// using the given seed and w1[i]. ps[i] may be nil and is ignored // in that case. ps[i] will be normalized. // // Can only be called when DeriveX4Available is true. diff --git a/sign/dilithium/mode5aes/internal/sample.go b/sign/dilithium/mode5aes/internal/sample.go index fa866293c..c47185ada 100644 --- a/sign/dilithium/mode5aes/internal/sample.go +++ b/sign/dilithium/mode5aes/internal/sample.go @@ -240,7 +240,7 @@ func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { } // For each i, sample ps[i] uniformly with τ non-zero coefficients in {q-1,1} -// using the the given seed and w1[i]. ps[i] may be nil and is ignored +// using the given seed and w1[i]. ps[i] may be nil and is ignored // in that case. ps[i] will be normalized. // // Can only be called when DeriveX4Available is true. From 171c41832e7ec817b9b2873732db6da46bdb1139 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:52:42 -0400 Subject: [PATCH 38/47] spelling: threshold Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- tss/rsa/keyshare.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tss/rsa/keyshare.go b/tss/rsa/keyshare.go index db2f4536a..cdfdf8962 100644 --- a/tss/rsa/keyshare.go +++ b/tss/rsa/keyshare.go @@ -40,7 +40,7 @@ func (kshare *KeyShare) MarshalBinary() ([]byte, error) { } if kshare.Threshold > math.MaxUint16 { - return nil, fmt.Errorf("rsa_threshold: keyshare marshall: Threhsold is too big to fit in a uint16") + return nil, fmt.Errorf("rsa_threshold: keyshare marshall: Threshold is too big to fit in a uint16") } if kshare.Index > math.MaxUint16 { @@ -105,7 +105,7 @@ func (kshare *KeyShare) UnmarshalBinary(data []byte) error { // | Players: uint16 | Threshold: uint16 | Index: uint16 | siLen: uint16 | si: []byte | twoDeltaSiNil: bool | twoDeltaSiLen: uint16 | twoDeltaSi: []byte | // with all values in big-endian. if len(data) < 6 { - return fmt.Errorf("rsa_threshold: keyshare unmarshalKeyShareTest failed: data length was too short for reading Players, Threashold, Index") + return fmt.Errorf("rsa_threshold: keyshare unmarshalKeyShareTest failed: data length was too short for reading Players, Threshold, Index") } players := binary.BigEndian.Uint16(data[0:2]) From dad216659ee1c9969957557a713537ceb589fce5 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Tue, 5 Sep 2023 17:44:38 -0400 Subject: [PATCH 39/47] spelling: title Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- abe/cpabe/tkn20/example_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abe/cpabe/tkn20/example_test.go b/abe/cpabe/tkn20/example_test.go index 38bc7e305..1b263ff15 100644 --- a/abe/cpabe/tkn20/example_test.go +++ b/abe/cpabe/tkn20/example_test.go @@ -50,7 +50,7 @@ func checkPolicy(in map[string][]string) bool { func Example() { policyStr := `(occupation: doctor) and (country: US)` - invalidPolicyStr := `(ocupation: doctor) and (country: pacific)` + invalidPolicyStr := `(title: doctor) and (country: pacific)` msgStr := `must have the precious 🎃` wrongAttrsMap := map[string]string{"occupation": "doctor", "country": "croatia"} rightAttrsMap := map[string]string{"occupation": "doctor", "country": "US", "age": "16"} From c2076d67b2c717b1b1c6f3aa3b324bf93079b6fb Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:53:02 -0400 Subject: [PATCH 40/47] spelling: transposes Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- pke/kyber/kyber1024/internal/mat.go | 2 +- pke/kyber/kyber512/internal/mat.go | 2 +- pke/kyber/kyber768/internal/mat.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pke/kyber/kyber1024/internal/mat.go b/pke/kyber/kyber1024/internal/mat.go index e8a35affa..404aacfb0 100644 --- a/pke/kyber/kyber1024/internal/mat.go +++ b/pke/kyber/kyber1024/internal/mat.go @@ -73,7 +73,7 @@ func (m *Mat) Derive(seed *[32]byte, transpose bool) { } } -// Tranposes A in place. +// Transposes A in place. func (m *Mat) Transpose() { for i := 0; i < K-1; i++ { for j := i + 1; j < K; j++ { diff --git a/pke/kyber/kyber512/internal/mat.go b/pke/kyber/kyber512/internal/mat.go index 9871a7741..735ecf556 100644 --- a/pke/kyber/kyber512/internal/mat.go +++ b/pke/kyber/kyber512/internal/mat.go @@ -71,7 +71,7 @@ func (m *Mat) Derive(seed *[32]byte, transpose bool) { } } -// Tranposes A in place. +// Transposes A in place. func (m *Mat) Transpose() { for i := 0; i < K-1; i++ { for j := i + 1; j < K; j++ { diff --git a/pke/kyber/kyber768/internal/mat.go b/pke/kyber/kyber768/internal/mat.go index e8a35affa..404aacfb0 100644 --- a/pke/kyber/kyber768/internal/mat.go +++ b/pke/kyber/kyber768/internal/mat.go @@ -73,7 +73,7 @@ func (m *Mat) Derive(seed *[32]byte, transpose bool) { } } -// Tranposes A in place. +// Transposes A in place. func (m *Mat) Transpose() { for i := 0; i < K-1; i++ { for j := i + 1; j < K; j++ { From 44133f703215856ee0b8f243778f24b001ff6c95 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Sun, 3 Sep 2023 02:53:09 -0400 Subject: [PATCH 41/47] spelling: tripped Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- abe/cpabe/tkn20/tkn20_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abe/cpabe/tkn20/tkn20_test.go b/abe/cpabe/tkn20/tkn20_test.go index 3913e1aed..837324e6a 100644 --- a/abe/cpabe/tkn20/tkn20_test.go +++ b/abe/cpabe/tkn20/tkn20_test.go @@ -108,7 +108,7 @@ func TestEndToEndEncryption(t *testing.T) { t.Fatalf("extracted policy doesn't match original") } if sat != npol2.Satisfaction(attrs) { - t.Fatalf("round triped policy doesn't match original") + t.Fatalf("round tripped policy doesn't match original") } ctSat := attrs.CouldDecrypt(ct) pt, err := sk.Decrypt(ct) From ceb2d90c4922ec2e26be09a20f217ee57c8ba1c4 Mon Sep 17 00:00:00 2001 From: armfazh Date: Wed, 11 Oct 2023 13:58:45 -0700 Subject: [PATCH 42/47] Updating blindrsa to be compliant with RFC9474. --- blindsign/blindrsa/brsa.go | 51 +++++-- blindsign/blindrsa/brsa_test.go | 140 ++++++++++++++---- blindsign/blindrsa/testdata/test_vectors.json | 32 ---- .../testdata/test_vectors_rfc9474.json | 77 ++++++++++ 4 files changed, 220 insertions(+), 80 deletions(-) delete mode 100644 blindsign/blindrsa/testdata/test_vectors.json create mode 100644 blindsign/blindrsa/testdata/test_vectors_rfc9474.json diff --git a/blindsign/blindrsa/brsa.go b/blindsign/blindrsa/brsa.go index c303b484e..0a1042097 100644 --- a/blindsign/blindrsa/brsa.go +++ b/blindsign/blindrsa/brsa.go @@ -1,13 +1,28 @@ -package blindrsa - -// This package implements the blind RSA protocol based on the CFRG specification: -// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures +// Package blindrsa implements the RSA Blind Signature Protocol. +// +// The RSA Blind Signature protocol, also called RSABSSA +// (RSA Blind Signature with Appendix) is a two-party protocol +// between a Client and Server where they interact to compute +// +// sig = Sign(sk, input_msg), +// +// where `input_msg = Prepare(msg)` is a prepared version of a private +// message `msg` provided by the Client, and `sk` is the private signing +// key provided by the server. +// +// # Supported Variants // -// Blind RSA is an example of a blind signature protocol is a two-party protocol -// for computing a digital signature. One party (the server) holds the signing -// key, and the other (the client) holds the message input. Blindness -// ensures that the server does not learn anything about the client's -// input during the BlindSign step. +// This package is compliant with the [RFC-9474] document +// and supports the following variants: +// - [NewVerifier] implements RSABSSA-SHA384-PSS-Deterministic +// - [NewDeterministicVerifier] implements RSABSSA-SHA384-PSSZERO-Deterministic +// +// while these variants are not supported yet: +// - RSABSSA-SHA384-PSS-Randomized +// - RSABSSA-SHA384-PSSZERO-Randomized +// +// [RFC-9474]: https://www.rfc-editor.org/info/rfc9474 +package blindrsa import ( "crypto" @@ -48,7 +63,7 @@ type deterministicBRSAVerifier struct { } // Verifier is a type that implements the client side of the blind RSA -// protocol, described in https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures +// protocol, described in https://www.rfc-editor.org/rfc/rfc9474.html#name-rsabssa-variants type Verifier interface { // Blind initializes the blind RSA protocol using an input message and source of randomness. The // signature is deterministic. This function fails if randomness was not provided. @@ -66,7 +81,7 @@ type Verifier interface { // NewDeterministicVerifier creates a new DeterministicBRSAVerifier using the corresponding Signer parameters. // This corresponds to the RSABSSA-SHA384-PSSZERO-Deterministic variant. See the specification for more details: -// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures#name-rsabssa-variants +// https://www.rfc-editor.org/rfc/rfc9474.html#name-rsabssa-variants func NewDeterministicVerifier(pk *rsa.PublicKey, hash crypto.Hash) Verifier { h := common.ConvertHashFunction(hash) return deterministicBRSAVerifier{ @@ -83,7 +98,7 @@ func (v deterministicBRSAVerifier) Hash() hash.Hash { // NewVerifier creates a new BRSAVerifier using the corresponding Signer parameters. // This corresponds to the RSABSSA-SHA384-PSS-Deterministic variant. See the specification for more details: -// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures#name-rsabssa-variants +// https://www.rfc-editor.org/rfc/rfc9474.html#name-rsabssa-variants func NewVerifier(pk *rsa.PublicKey, hash crypto.Hash) Verifier { h := common.ConvertHashFunction(hash) return randomBRSAVerifier{ @@ -98,6 +113,10 @@ func (v randomBRSAVerifier) Hash() hash.Hash { return v.hash } +func prepareMsg(message, prefix []byte) []byte { + return append(append([]byte{}, prefix...), message...) +} + func fixedBlind(message, salt []byte, r, rInv *big.Int, pk *rsa.PublicKey, hash hash.Hash) ([]byte, VerifierState, error) { encodedMsg, err := common.EncodeMessageEMSAPSS(message, pk.N, hash, salt) if err != nil { @@ -129,7 +148,7 @@ func fixedBlind(message, salt []byte, r, rInv *big.Int, pk *rsa.PublicKey, hash // signature is deterministic. This function fails if randomness was not provided. // // See the specification for more details: -// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-02#section-5.1.1 +// https://www.rfc-editor.org/rfc/rfc9474.html#name-blind func (v deterministicBRSAVerifier) Blind(random io.Reader, message []byte) ([]byte, VerifierState, error) { if random == nil { return nil, VerifierState{}, common.ErrInvalidRandomness @@ -171,7 +190,7 @@ func (v deterministicBRSAVerifier) Verify(message, signature []byte) error { // hash function. This function fails if randomness was not provided. // // See the specification for more details: -// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-02#section-5.1.1 +// https://www.rfc-editor.org/rfc/rfc9474.html#name-blind func (v randomBRSAVerifier) Blind(random io.Reader, message []byte) ([]byte, VerifierState, error) { if random == nil { return nil, VerifierState{}, common.ErrInvalidRandomness @@ -237,7 +256,7 @@ type VerifierState struct { // Finalize computes and outputs the final signature, if it's valid. Otherwise, it returns an error. // // See the specification for more details: -// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-02#section-5.1.3 +// https://www.rfc-editor.org/rfc/rfc9474.html#name-finalize func (state VerifierState) Finalize(data []byte) ([]byte, error) { kLen := (state.pk.N.BitLen() + 7) / 8 if len(data) != kLen { @@ -291,7 +310,7 @@ func NewSigner(sk *rsa.PrivateKey) Signer { // message input, if it's of valid length, and returns an error should the function fail. // // See the specification for more details: -// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-02#section-5.1.2 +// https://www.rfc-editor.org/rfc/rfc9474.html#name-blindsign func (signer Signer) BlindSign(data []byte) ([]byte, error) { kLen := (signer.sk.N.BitLen() + 7) / 8 if len(data) != kLen { diff --git a/blindsign/blindrsa/brsa_test.go b/blindsign/blindrsa/brsa_test.go index ec002608e..ae4dba183 100644 --- a/blindsign/blindrsa/brsa_test.go +++ b/blindsign/blindrsa/brsa_test.go @@ -13,7 +13,10 @@ import ( "io" "math/big" "os" + "strings" "testing" + + "github.com/cloudflare/circl/internal/test" ) // 2048-bit RSA private key @@ -254,31 +257,39 @@ func TestFixedRandomSignVerify(t *testing.T) { } type rawTestVector struct { + Name string `json:"name"` P string `json:"p"` Q string `json:"q"` N string `json:"n"` E string `json:"e"` D string `json:"d"` Msg string `json:"msg"` + MsgPrefix string `json:"msg_prefix"` + InputMsg string `json:"input_msg"` Salt string `json:"salt"` + SaltLen string `json:"sLen"` + IsRandomized string `json:"is_randomized"` Inv string `json:"inv"` - EncodedMsg string `json:"encoded_msg"` - BlindedMessage string `json:"blinded_message"` + BlindedMessage string `json:"blinded_msg"` BlindSig string `json:"blind_sig"` Sig string `json:"sig"` } type testVector struct { t *testing.T + name string p *big.Int q *big.Int n *big.Int e int d *big.Int msg []byte + msgPrefix []byte + inputMsg []byte salt []byte + saltLen int + isRandomized bool blindInverse *big.Int - encodedMessage []byte blindedMessage []byte blindSig []byte sig []byte @@ -290,17 +301,14 @@ type testVectorList struct { } func mustUnhexBigInt(number string) *big.Int { - data, err := hex.DecodeString(number) - if err != nil { - panic(err) - } - + data := mustUnhex(number) value := new(big.Int) value.SetBytes(data) return value } func mustUnhex(value string) []byte { + value = strings.TrimPrefix(value, "0x") data, err := hex.DecodeString(value) if err != nil { panic(err) @@ -322,14 +330,18 @@ func (tv *testVector) UnmarshalJSON(data []byte) error { return err } + tv.name = raw.Name tv.p = mustUnhexBigInt(raw.P) tv.q = mustUnhexBigInt(raw.Q) tv.n = mustUnhexBigInt(raw.N) tv.e = mustUnhexInt(raw.E) tv.d = mustUnhexBigInt(raw.D) tv.msg = mustUnhex(raw.Msg) + tv.msgPrefix = mustUnhex(raw.MsgPrefix) + tv.inputMsg = mustUnhex(raw.InputMsg) tv.salt = mustUnhex(raw.Salt) - tv.encodedMessage = mustUnhex(raw.EncodedMsg) + tv.saltLen = mustUnhexInt(raw.SaltLen) + tv.isRandomized = mustUnhexInt(raw.IsRandomized) != 0 tv.blindedMessage = mustUnhex(raw.BlindedMessage) tv.blindInverse = mustUnhexBigInt(raw.Inv) tv.blindSig = mustUnhex(raw.BlindSig) @@ -356,16 +368,11 @@ func (tvl *testVectorList) UnmarshalJSON(data []byte) error { } func verifyTestVector(t *testing.T, vector testVector) { - key, err := loadPrivateKey() - if err != nil { - t.Fatal(err) - } - + key := new(rsa.PrivateKey) key.PublicKey.N = vector.n key.PublicKey.E = vector.e key.D = vector.d - key.Primes[0] = vector.p - key.Primes[1] = vector.q + key.Primes = []*big.Int{vector.p, vector.q} key.Precomputed.Dp = nil // Remove precomputed CRT values // Recompute the original blind @@ -376,34 +383,56 @@ func verifyTestVector(t *testing.T, vector testVector) { } signer := NewSigner(key) - verifier := NewVerifier(&key.PublicKey, crypto.SHA384) - blindedMsg, state, err := fixedBlind(vector.msg, vector.salt, r, rInv, &key.PublicKey, verifier.Hash()) - if err != nil { - t.Fatal(err) + var verifier Verifier + switch vector.name { + case "RSABSSA-SHA384-PSS-Deterministic": + verifier = NewVerifier(&key.PublicKey, crypto.SHA384) + case "RSABSSA-SHA384-PSSZERO-Deterministic": + verifier = NewDeterministicVerifier(&key.PublicKey, crypto.SHA384) + case "RSABSSA-SHA384-PSS-Randomized", "RSABSSA-SHA384-PSSZERO-Randomized": + t.Skipf("variant %v not supported yet", vector.name) + default: + t.Fatal("variant not supported") } - blindSig, err := signer.BlindSign(blindedMsg) - if err != nil { - t.Fatal(err) + inputMsg := prepareMsg(vector.msg, vector.msgPrefix) + got := hex.EncodeToString(inputMsg) + want := hex.EncodeToString(vector.inputMsg) + if got != want { + test.ReportError(t, got, want) } - sig, err := state.Finalize(blindSig) - if err != nil { - t.Fatal(err) + blindedMsg, state, err := fixedBlind(inputMsg, vector.salt, r, rInv, &key.PublicKey, verifier.Hash()) + test.CheckNoErr(t, err, "fixedBlind failed") + got = hex.EncodeToString(blindedMsg) + want = hex.EncodeToString(vector.blindedMessage) + if got != want { + test.ReportError(t, got, want) } - if !bytes.Equal(state.encodedMsg, vector.encodedMessage) { - t.Errorf("Encoded message mismatch: expected %x, got %x", state.encodedMsg, vector.encodedMessage) + blindSig, err := signer.BlindSign(blindedMsg) + test.CheckNoErr(t, err, "blindSign failed") + got = hex.EncodeToString(blindSig) + want = hex.EncodeToString(vector.blindSig) + if got != want { + test.ReportError(t, got, want) } - if !bytes.Equal(sig, vector.sig) { - t.Errorf("Signature mismatch: expected %x, got %x", sig, vector.sig) + sig, err := state.Finalize(blindSig) + test.CheckNoErr(t, err, "finalize failed") + got = hex.EncodeToString(sig) + want = hex.EncodeToString(vector.sig) + if got != want { + test.ReportError(t, got, want) } + + err = verifier.Verify(inputMsg, sig) + test.CheckNoErr(t, err, "verification failed") } func TestVectors(t *testing.T) { - data, err := os.ReadFile("testdata/test_vectors.json") + data, err := os.ReadFile("testdata/test_vectors_rfc9474.json") if err != nil { t.Fatal("Failed reading test vectors:", err) } @@ -415,7 +444,9 @@ func TestVectors(t *testing.T) { } for _, vector := range tvl.vectors { - verifyTestVector(t, vector) + t.Run(vector.name, func(tt *testing.T) { + verifyTestVector(tt, vector) + }) } } @@ -463,3 +494,48 @@ func BenchmarkBRSA(b *testing.B) { b.Fatal(err) } } + +func Example_blindrsa() { + // Setup (offline) + + // Server: generate an RSA keypair. + sk, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to generate RSA key: %v", err) + return + } + pk := &sk.PublicKey + server := NewSigner(sk) + + // Client: stores Server's public key. + verifier := NewVerifier(pk, crypto.SHA384) + + // Protocol (online) + + // Client blinds a message. + msg := []byte("alice and bob") + blindedMsg, state, err := verifier.Blind(rand.Reader, msg) + if err != nil { + fmt.Fprintf(os.Stderr, "client failed to generate blinded message: %v", err) + return + } + + // Server signs a blinded message, and produces a blinded signature. + blindedSignature, err := server.BlindSign(blindedMsg) + if err != nil { + fmt.Fprintf(os.Stderr, "server failed to sign: %v", err) + return + } + + // Client builds a signature from the previous state and the blinded signature. + signature, err := state.Finalize(blindedSignature) + if err != nil { + fmt.Fprintf(os.Stderr, "client failed to obtain signature: %v", err) + return + } + + // Client verifies the signature is valid. + ok := verifier.Verify(msg, signature) + fmt.Printf("Valid signature: %v", ok == nil) + // Output: Valid signature: true +} diff --git a/blindsign/blindrsa/testdata/test_vectors.json b/blindsign/blindrsa/testdata/test_vectors.json deleted file mode 100644 index bbc03bea7..000000000 --- a/blindsign/blindrsa/testdata/test_vectors.json +++ /dev/null @@ -1,32 +0,0 @@ - - -[ - { - "p": "e1f4d7a34802e27c7392a3cea32a262a34dc3691bd87f3f310dc75673488930559c120fd0410194fb8a0da55bd0b81227e843fdca6692ae80e5a5d414116d4803fca7d8c30eaaae57e44a1816ebb5c5b0606c536246c7f11985d731684150b63c9a3ad9e41b04c0b5b27cb188a692c84696b742a80d3cd00ab891f2457443dadfeba6d6daf108602be26d7071803c67105a5426838e6889d77e8474b29244cefaf418e381b312048b457d73419213063c60ee7b0d81820165864fef93523c9635c22210956e53a8d96322493ffc58d845368e2416e078e5bcb5d2fd68ae6acfa54f9627c42e84a9d3f2774017e32ebca06308a12ecc290c7cd1156dcccfb2311", - "q": "c601a9caea66dc3835827b539db9df6f6f5ae77244692780cd334a006ab353c806426b60718c05245650821d39445d3ab591ed10a7339f15d83fe13f6a3dfb20b9452c6a9b42eaa62a68c970df3cadb2139f804ad8223d56108dfde30ba7d367e9b0a7a80c4fdba2fd9dde6661fc73fc2947569d2029f2870fc02d8325acf28c9afa19ecf962daa7916e21afad09eb62fe9f1cf91b77dc879b7974b490d3ebd2e95426057f35d0a3c9f45f79ac727ab81a519a8b9285932d9b2e5ccd347e59f3f32ad9ca359115e7da008ab7406707bd0e8e185a5ed8758b5ba266e8828f8d863ae133846304a2936ad7bc7c9803879d2fc4a28e69291d73dbd799f8bc238385", - "n": "aec4d69addc70b990ea66a5e70603b6fee27aafebd08f2d94cbe1250c556e047a928d635c3f45ee9b66d1bc628a03bac9b7c3f416fe20dabea8f3d7b4bbf7f963be335d2328d67e6c13ee4a8f955e05a3283720d3e1f139c38e43e0338ad058a9495c53377fc35be64d208f89b4aa721bf7f7d3fef837be2a80e0f8adf0bcd1eec5bb040443a2b2792fdca522a7472aed74f31a1ebe1eebc1f408660a0543dfe2a850f106a617ec6685573702eaaa21a5640a5dcaf9b74e397fa3af18a2f1b7c03ba91a6336158de420d63188ee143866ee415735d155b7c2d854d795b7bc236cffd71542df34234221a0413e142d8c61355cc44d45bda94204974557ac2704cd8b593f035a5724b1adf442e78c542cd4414fce6f1298182fb6d8e53cef1adfd2e90e1e4deec52999bdc6c29144e8d52a125232c8c6d75c706ea3cc06841c7bda33568c63a6c03817f722b50fcf898237d788a4400869e44d90a3020923dc646388abcc914315215fcd1bae11b1c751fd52443aac8f601087d8d42737c18a3fa11ecd4131ecae017ae0a14acfc4ef85b83c19fed33cfd1cd629da2c4c09e222b398e18d822f77bb378dea3cb360b605e5aa58b20edc29d000a66bd177c682a17e7eb12a63ef7c2e4183e0d898f3d6bf567ba8ae84f84f1d23bf8b8e261c3729e2fa6d07b832e07cddd1d14f55325c6f924267957121902dc19b3b32948bdead5", - "e": "010001", - "d": "0d43242aefe1fb2c13fbc66e20b678c4336d20b1808c558b6e62ad16a287077180b177e1f01b12f9c6cd6c52630257ccef26a45135a990928773f3bd2fc01a313f1dac97a51cec71cb1fd7efc7adffdeb05f1fb04812c924ed7f4a8269925dad88bd7dcfbc4ef01020ebfc60cb3e04c54f981fdbd273e69a8a58b8ceb7c2d83fbcbd6f784d052201b88a9848186f2a45c0d2826870733e6fd9aa46983e0a6e82e35ca20a439c5ee7b502a9062e1066493bdadf8b49eb30d9558ed85abc7afb29b3c9bc644199654a4676681af4babcea4e6f71fe4565c9c1b85d9985b84ec1abf1a820a9bbebee0df1398aae2c85ab580a9f13e7743afd3108eb32100b870648fa6bc17e8abac4d3c99246b1f0ea9f7f93a5dd5458c56d9f3f81ff2216b3c3680a13591673c43194d8e6fc93fc1e37ce2986bd628ac48088bc723d8fbe293861ca7a9f4a73e9fa63b1b6d0074f5dea2a624c5249ff3ad811b6255b299d6bc5451ba7477f19c5a0db690c3e6476398b1483d10314afd38bbaf6e2fbdbcd62c3ca9797a420ca6034ec0a83360a3ee2adf4b9d4ba29731d131b099a38d6a23cc463db754603211260e99d19affc902c915d7854554aabf608e3ac52c19b8aa26ae042249b17b2d29669b5c859103ee53ef9bdc73ba3c6b537d5c34b6d8f034671d7f3a8a6966cc4543df223565343154140fd7391c7e7be03e241f4ecfeb877a051", - "msg": "8f3dc6fb8c4a02f4d6352edf0907822c1210a9b32f9bdda4c45a698c80023aa6b59f8cfec5fdbb36331372ebefedae7d", - "salt": "051722b35f458781397c3a671a7d3bd3096503940e4c4f1aaa269d60300ce449555cd7340100df9d46944c5356825abf", - "inv": "80682c48982407b489d53d1261b19ec8627d02b8cda5336750b8cee332ae260de57b02d72609c1e0e9f28e2040fc65b6f02d56dbd6aa9af8fde656f70495dfb723ba01173d4707a12fddac628ca29f3e32340bd8f7ddb557cf819f6b01e445ad96f874ba235584ee71f6581f62d4f43bf03f910f6510deb85e8ef06c7f09d9794a008be7ff2529f0ebb69decef646387dc767b74939265fec0223aa6d84d2a8a1cc912d5ca25b4e144ab8f6ba054b54910176d5737a2cff011da431bd5f2a0d2d66b9e70b39f4b050e45c0d9c16f02deda9ddf2d00f3e4b01037d7029cd49c2d46a8e1fc2c0c17520af1f4b5e25ba396afc4cd60c494a4c426448b35b49635b337cfb08e7c22a39b256dd032c00adddafb51a627f99a0e1704170ac1f1912e49d9db10ec04c19c58f420212973e0cb329524223a6aa56c7937c5dffdb5d966b6cd4cbc26f3201dd25c80960a1a111b32947bb78973d269fac7f5186530930ed19f68507540eed9e1bab8b00f00d8ca09b3f099aae46180e04e3584bd7ca054df18a1504b89d1d1675d0966c4ae1407be325cdf623cf13ff13e4a28b594d59e3eadbadf6136eee7a59d6a444c9eb4e2198e8a974f27a39eb63af2c9af3870488b8adaad444674f512133ad80b9220e09158521614f1faadfe8505ef57b7df6813048603f0dd04f4280177a11380fbfc861dbcbd7418d62155248dad5fdec0991f", - "encoded_msg": "6e0c464d9c2f9fbc147b43570fc4f238e0d0b38870b3addcf7a4217df912ccef17a7f629aa850f63a063925f312d61d6437be954b45025e8282f9c0b1131bc8ff19a8a928d859b37113db1064f92a27f64761c181c1e1f9b251ae5a2f8a4047573b67a270584e089beadcb13e7c82337797119712e9b849ff56e04385d144d3ca9d8d92bf78adb20b5bbeb3685f17038ec6afade3ef354429c51c687b45a7018ee3a6966b3af15c9ba8f40e6461ba0a17ef5a799672ad882bab02b518f9da7c1a962945c2e9b0f02f29b31b9cdf3e633f9d9d2a22e96e1de28e25241ca7dd04147112f578973403e0f4fd80865965475d22294f065e17a1c4a201de93bd14223e6b1b999fd548f2f759f52db71964528b6f15b9c2d7811f2a0a35d534b8216301c47f4f04f412cae142b48c4cdff78bc54df690fd43142d750c671dd8e2e938e6a440b2f825b6dbb3e19f1d7a3c0150428a47948037c322365b7fe6fe57ac88d8f80889e9ff38177bad8c8d8d98db42908b389cb59692a58ce275aa15acb032ca951b3e0a3404b7f33f655b7c7d83a2f8d1b6bbff49d5fcedf2e030e80881aa436db27a5c0dea13f32e7d460dbf01240c2320c2bb5b3225b17145c72d61d47c8f84d1e19417ebd8ce3638a82d395cc6f7050b6209d9283dc7b93fecc04f3f9e7f566829ac41568ef799480c733c09759aa9734e2013d7640dc6151018ea902bc", - "blinded_msg": "10c166c6a711e81c46f45b18e5873cc4f494f003180dd7f115585d871a28930259654fe28a54dab319cc5011204c8373b50a57b0fdc7a678bd74c523259dfe4fd5ea9f52f170e19dfa332930ad1609fc8a00902d725cfe50685c95e5b2968c9a2828a21207fcf393d15f849769e2af34ac4259d91dfd98c3a707c509e1af55647efaa31290ddf48e0133b798562af5eabd327270ac2fb6c594734ce339a14ea4fe1b9a2f81c0bc230ca523bda17ff42a377266bc2778a274c0ae5ec5a8cbbe364fcf0d2403f7ee178d77ff28b67a20c7ceec009182dbcaa9bc99b51ebbf13b7d542be337172c6474f2cd3561219fe0dfa3fb207cff89632091ab841cf38d8aa88af6891539f263adb8eac6402c41b6ebd72984e43666e537f5f5fe27b2b5aa114957e9a580730308a5f5a9c63a1eb599f093ab401d0c6003a451931b6d124180305705845060ebba6b0036154fcef3e5e9f9e4b87e8f084542fd1dd67e7782a5585150181c01eb6d90cb95883837384a5b91dbb606f266059ecc51b5acbaa280e45cfd2eec8cc1cdb1b7211c8e14805ba683f9b78824b2eb005bc8a7d7179a36c152cb87c8219e5569bba911bb32a1b923ca83de0e03fb10fba75d85c55907dda5a2606bf918b056c3808ba496a4d95532212040a5f44f37e1097f26dc27b98a51837daa78f23e532156296b64352669c94a8a855acf30533d8e0594ace7c442", - "blind_sig": "364f6a40dbfbc3bbb257943337eeff791a0f290898a6791283bba581d9eac90a6376a837241f5f73a78a5c6746e1306ba3adab6067c32ff69115734ce014d354e2f259d4cbfb890244fd451a497fe6ecf9aa90d19a2d441162f7eaa7ce3fc4e89fd4e76b7ae585be2a2c0fd6fb246b8ac8d58bcb585634e30c9168a434786fe5e0b74bfe8187b47ac091aa571ffea0a864cb906d0e28c77a00e8cd8f6aba4317a8cc7bf32ce566bd1ef80c64de041728abe087bee6cadd0b7062bde5ceef308a23bd1ccc154fd0c3a26110df6193464fc0d24ee189aea8979d722170ba945fdcce9b1b4b63349980f3a92dc2e5418c54d38a862916926b3f9ca270a8cf40dfb9772bfbdd9a3e0e0892369c18249211ba857f35963d0e05d8da98f1aa0c6bba58f47487b8f663e395091275f82941830b050b260e4767ce2fa903e75ff8970c98bfb3a08d6db91ab1746c86420ee2e909bf681cac173697135983c3594b2def673736220452fde4ddec867d40ff42dd3da36c84e3e52508b891a00f50b4f62d112edb3b6b6cc3dbd546ba10f36b03f06c0d82aeec3b25e127af545fac28e1613a0517a6095ad18a98ab79f68801e05c175e15bae21f821e80c80ab4fdec6fb34ca315e194502b8f3dcf7892b511aee45060e3994cd15e003861bc7220a2babd7b40eda03382548a34a7110f9b1779bf3ef6011361611e6bc5c0dc851e1509de1a", - "sig": "6fef8bf9bc182cd8cf7ce45c7dcf0e6f3e518ae48f06f3c670c649ac737a8b8119a34d51641785be151a697ed7825fdfece82865123445eab03eb4bb91cecf4d6951738495f8481151b62de869658573df4e50a95c17c31b52e154ae26a04067d5ecdc1592c287550bb982a5bb9c30fd53a768cee6baabb3d483e9f1e2da954c7f4cf492fe3944d2fe456c1ecaf0840369e33fb4010e6b44bb1d721840513524d8e9a3519f40d1b81ae34fb7a31ee6b7ed641cb16c2ac999004c2191de0201457523f5a4700dd649267d9286f5c1d193f1454c9f868a57816bf5ff76c838a2eeb616a3fc9976f65d4371deecfbab29362caebdff69c635fe5a2113da4d4d8c24f0b16a0584fa05e80e607c5d9a2f765f1f069f8d4da21f27c2a3b5c984b4ab24899bef46c6d9323df4862fe51ce300fca40fb539c3bb7fe2dcc9409e425f2d3b95e70e9c49c5feb6ecc9d43442c33d50003ee936845892fb8be475647da9a080f5bc7f8a716590b3745c2209fe05b17992830ce15f32c7b22cde755c8a2fe50bd814a0434130b807dc1b7218d4e85342d70695a5d7f29306f25623ad1e8aa08ef71b54b8ee447b5f64e73d09bdd6c3b7ca224058d7c67cc7551e9241688ada12d859cb7646fbd3ed8b34312f3b49d69802f0eaa11bc4211c2f7a29cd5c01ed01a39001c5856fab36228f5ee2f2e1110811872fe7c865c42ed59029c706195d52" - }, - { - "p": "ca9d82e9059fa3b145da850e0c451ff31093d819644ba29a3409393de2adfa1bcd65e8669a5c5140142c1404204edbc380d4e7a5c866c06bb2427c76b9e3d16bbfc1b1668dec219b8c59fee90b7baf557fc2feb13f2f4b30d8606d20b9928f4f588a3b34baa659b3bd1dd590c83e90e6251b5239fbbb73b12e90534a375e3f71", - "q": "c075694f69db6a07456e19eeace01b430f2d6cc6cd5495d569e242b6f5e8ded7df27e6aeea4db4e307554fb519b68279a58d9e2d25cee4b37668554eec2f2feb79246955a07bd526f02a6afedc7a3aff2b8953287fef2c4a02207ccb9f14e4612e9af3447dd3401728a8957871b759b6bbf22aa0e8271b82f32dd5a2d2550197", - "n": "98530f850dcc894d84ecfce9dec3a475bf30ec3ce4606f677ac4a6ef63f763ff64a162ef1c991d8094b5652d0d78c126b3e97d1d77eba2f833b5be9a124e003065ec2a3ea4fbc31bc283de1c7cd8a971eb57aa7284b082562ccde572b73702068a6143e6dabf886538ff419874c300a85f3d9d50f0731fc6b9c92a121fefb7911f5ea92d25b17a4f3b2883eff34a221b5c28c488e35067a8460d8fab1c405704ebfa1ca165d69cd4e425995a03a447f6cbba5d20d459707ab4a2c537a5dbd02801d7b19a03aaa9aec21d1c363996c6b9fee2cab370d501c9b67e7dc4a20eb0cdc3b24be242093b5a66119b96da0fb0ec0b1b0da0bd0b92236ece47d5c95bdca7", - "e": "010001", - "d": "6b15d18e4f8220709fe75f7226ca517ef9b7320d28dc66d54fa89a5727670f24c7a0f1857a0c6682338946a4a298e6e90788390e137553afbbe2a4297a7edd8128d61b68c8e1b96b7596f0fa0406e9308e2ba64735e344edc237c97b993411b7796721ae54d05bda1574d5af913e59e30479b373e86676cb6566f7ada0480d3ae21d50ac94c0b41c476e566d6bcdef88eeab3042ef1016527558e794b6029cff1120596fe2104fac928a66ad2fb1094d1ae1231abf95206cae7cd4e7aad388199d7ac1fe17e3f917436232cffe70e12056e02cfb9604e73cc34984bb83f7112ed197bf3a4d9f6d0c0e3c4dd8f2d9cbe17185f1e63561b08f7d14bd36112f3ea1", - "msg": "5465737420766563746f7220776974682064657465726d696e69737469632070616464696e67", - "salt": "", - "inv": "6e69972553327ee6240ce0de7146aea2243927cf9f7f52c0103367df79e3bafebfa61c2ffdc41ea397a38523654a1a806f4eebcd5fe9a2592a463f1faa26c3601f83f29141eda488f14f7c0aa82faa025e37adbe77e02e575f72f7b9d095882923476f2328dfaeb23b607d2f706c6c8ef6c2aee50ddb14e6d27e043e7dec8e5dede6844aa80b2206b6019350d37925bb8819653aa7a13bfb9cc3c95b53378f278903b5c06a10c0b3ce0aa028e9600f7b2733f0278565f9b88e9d92e039db78300170d7bbd32ce2b89ad8944167839880e3a2aeba05bf00edc8032a63e6279bf42a131ccc9bb95b8693764b27665274fb673bdfb7d69b7957ee8b64a99efbeed9", - "encoded_msg": "4021ac68705782fb7587bf24ac0528853025aa4a998db7b1a503afb5b266cbd1876710a2b0aa6e37b70fca538d42285beddd61d965c02b2162c86445873bdaf687a29bf6b2ab10fa22013cae53ff1c78969ef6c3eb069bfef339a5df788044d159678e571e50fc3fa40a30fe183348453542f258c663dc9c4b372895120ad12ff8b8ec1d37d766b2604fbf50bf9d84432a59593d21d7f379d6bf9198ea2fa90ee5abadb27eada5d6f40a2ec45aa4bb8710042beab5c6afb4381fc57012e61b3a815800e53e69fe2fdccb3b4ee51968c1ef6281d7e8fe08c4337bad73d99e947df834e5402378a66142bf032dfade7e6e2d43ae90b145055861e06eff189b63bc", - "blinded_msg": "5a631b41e7759a634cef04359436e358143ee2892fbebd072d1e5cc45475ff55b6b492e13c59979f4b968994ddca3cc068084d3b176a6132039c584707acbb9862c009fa5b63cfb7b6f6d577825c1e81ad11059cb87a524083230f906ea0a4d9db3434d49cf9f0ea52b2425db4d319f51540e5de6cfb30b86d5e5d810a284f3478f6259f054407c854303ec23c2e0989dd57aa002e56ab6287594c25154a1646060cb4f6479b07f627991f7089ac0491d5841d6461166b324b3d448b2a8071de68505503feadf7d8182d18d8b0d3b91d77b627a5ffae68f913efbbb2fc082437f845880f94f07d873bc0c0688f60033235bcc1701dcba83dca944b05227884e3", - "blind_sig": "817596a0b568088b60c29482c0178d34e0d54dc34a9375152701e4e6d5ef76c92f4281a377d8b2f438f6af4ef9c26dd38ad2cc932f90fe45d4c0a1ba10e695a1c8e797aa5023f84385904e5f378df5677b8eb7312f835f9e3a097b1b7e55fece0d00ec3f52ba26b39c91322b6404eef4e567d909195bfc0f72690805ea3f71736d7eb51e84556c5241786f5f37bf9d2a0305bf36454d9ab8b5a9f6fe03fd4ab472b5379d7e8ab92e803c7c15bf3d0234653e1f6d80d23c7f127bed7fba3d297b62fee51b8e71b04d402cf291ac87460011fd222cfd27b5669d79d1e0dcc8d911c2dc6d0edcd205a91278cc97019cfc709ce8a50297409e66f27b1299e386a6cd", - "sig": "848fc8a032ea073280a7d9146ae55bb0199cd1941c10a03cce1dc38579c4e77e87f259e250b16a9912ce2c085cb9489846f803fd6ed09bf8605c4aa8b0ebf2c938093e53ad025a48b97f7975255805118c33fa0f73ec204b9723acefacd8031ab3d9f7ebeaf996eee3678c788cea96932dd723b236355c0e6864fad2fc87b00e4eda476e90f000936b0d9fa65bf1112fc296e8aa5bb05ca7cb32dec01407e3d3ed94c1ebb0dc430ea59588ccc0995a6e2f1423dbe06c6f27650b23b12eb343b9e461ba532825e5e26572fbe723b69753c178361e7a834a566ce950df55ff97d314b384b3fa8c0098d560d4c6ba519a9b6040f908adf34f6b2d5d30c265cd0fb1" - } -] \ No newline at end of file diff --git a/blindsign/blindrsa/testdata/test_vectors_rfc9474.json b/blindsign/blindrsa/testdata/test_vectors_rfc9474.json new file mode 100644 index 000000000..bbde82efa --- /dev/null +++ b/blindsign/blindrsa/testdata/test_vectors_rfc9474.json @@ -0,0 +1,77 @@ +[ + { + "name": "RSABSSA-SHA384-PSS-Randomized", + "p": "0xe1f4d7a34802e27c7392a3cea32a262a34dc3691bd87f3f310dc75673488930559c120fd0410194fb8a0da55bd0b81227e843fdca6692ae80e5a5d414116d4803fca7d8c30eaaae57e44a1816ebb5c5b0606c536246c7f11985d731684150b63c9a3ad9e41b04c0b5b27cb188a692c84696b742a80d3cd00ab891f2457443dadfeba6d6daf108602be26d7071803c67105a5426838e6889d77e8474b29244cefaf418e381b312048b457d73419213063c60ee7b0d81820165864fef93523c9635c22210956e53a8d96322493ffc58d845368e2416e078e5bcb5d2fd68ae6acfa54f9627c42e84a9d3f2774017e32ebca06308a12ecc290c7cd1156dcccfb2311", + "q": "0xc601a9caea66dc3835827b539db9df6f6f5ae77244692780cd334a006ab353c806426b60718c05245650821d39445d3ab591ed10a7339f15d83fe13f6a3dfb20b9452c6a9b42eaa62a68c970df3cadb2139f804ad8223d56108dfde30ba7d367e9b0a7a80c4fdba2fd9dde6661fc73fc2947569d2029f2870fc02d8325acf28c9afa19ecf962daa7916e21afad09eb62fe9f1cf91b77dc879b7974b490d3ebd2e95426057f35d0a3c9f45f79ac727ab81a519a8b9285932d9b2e5ccd347e59f3f32ad9ca359115e7da008ab7406707bd0e8e185a5ed8758b5ba266e8828f8d863ae133846304a2936ad7bc7c9803879d2fc4a28e69291d73dbd799f8bc238385", + "n": "0xaec4d69addc70b990ea66a5e70603b6fee27aafebd08f2d94cbe1250c556e047a928d635c3f45ee9b66d1bc628a03bac9b7c3f416fe20dabea8f3d7b4bbf7f963be335d2328d67e6c13ee4a8f955e05a3283720d3e1f139c38e43e0338ad058a9495c53377fc35be64d208f89b4aa721bf7f7d3fef837be2a80e0f8adf0bcd1eec5bb040443a2b2792fdca522a7472aed74f31a1ebe1eebc1f408660a0543dfe2a850f106a617ec6685573702eaaa21a5640a5dcaf9b74e397fa3af18a2f1b7c03ba91a6336158de420d63188ee143866ee415735d155b7c2d854d795b7bc236cffd71542df34234221a0413e142d8c61355cc44d45bda94204974557ac2704cd8b593f035a5724b1adf442e78c542cd4414fce6f1298182fb6d8e53cef1adfd2e90e1e4deec52999bdc6c29144e8d52a125232c8c6d75c706ea3cc06841c7bda33568c63a6c03817f722b50fcf898237d788a4400869e44d90a3020923dc646388abcc914315215fcd1bae11b1c751fd52443aac8f601087d8d42737c18a3fa11ecd4131ecae017ae0a14acfc4ef85b83c19fed33cfd1cd629da2c4c09e222b398e18d822f77bb378dea3cb360b605e5aa58b20edc29d000a66bd177c682a17e7eb12a63ef7c2e4183e0d898f3d6bf567ba8ae84f84f1d23bf8b8e261c3729e2fa6d07b832e07cddd1d14f55325c6f924267957121902dc19b3b32948bdead5", + "e": "0x010001", + "d": "0x0d43242aefe1fb2c13fbc66e20b678c4336d20b1808c558b6e62ad16a287077180b177e1f01b12f9c6cd6c52630257ccef26a45135a990928773f3bd2fc01a313f1dac97a51cec71cb1fd7efc7adffdeb05f1fb04812c924ed7f4a8269925dad88bd7dcfbc4ef01020ebfc60cb3e04c54f981fdbd273e69a8a58b8ceb7c2d83fbcbd6f784d052201b88a9848186f2a45c0d2826870733e6fd9aa46983e0a6e82e35ca20a439c5ee7b502a9062e1066493bdadf8b49eb30d9558ed85abc7afb29b3c9bc644199654a4676681af4babcea4e6f71fe4565c9c1b85d9985b84ec1abf1a820a9bbebee0df1398aae2c85ab580a9f13e7743afd3108eb32100b870648fa6bc17e8abac4d3c99246b1f0ea9f7f93a5dd5458c56d9f3f81ff2216b3c3680a13591673c43194d8e6fc93fc1e37ce2986bd628ac48088bc723d8fbe293861ca7a9f4a73e9fa63b1b6d0074f5dea2a624c5249ff3ad811b6255b299d6bc5451ba7477f19c5a0db690c3e6476398b1483d10314afd38bbaf6e2fbdbcd62c3ca9797a420ca6034ec0a83360a3ee2adf4b9d4ba29731d131b099a38d6a23cc463db754603211260e99d19affc902c915d7854554aabf608e3ac52c19b8aa26ae042249b17b2d29669b5c859103ee53ef9bdc73ba3c6b537d5c34b6d8f034671d7f3a8a6966cc4543df223565343154140fd7391c7e7be03e241f4ecfeb877a051", + "msg": "8f3dc6fb8c4a02f4d6352edf0907822c1210a9b32f9bdda4c45a698c80023aa6b59f8cfec5fdbb36331372ebefedae7d", + "msg_prefix": "8417e699b219d583fb6216ae0c53ca0e9723442d02f1d1a34295527e7d929e8b", + "input_msg": "8417e699b219d583fb6216ae0c53ca0e9723442d02f1d1a34295527e7d929e8b8f3dc6fb8c4a02f4d6352edf0907822c1210a9b32f9bdda4c45a698c80023aa6b59f8cfec5fdbb36331372ebefedae7d", + "sLen": "0x30", + "salt": "051722b35f458781397c3a671a7d3bd3096503940e4c4f1aaa269d60300ce449555cd7340100df9d46944c5356825abf", + "is_randomized": "0x01", + "inv": "0x80682c48982407b489d53d1261b19ec8627d02b8cda5336750b8cee332ae260de57b02d72609c1e0e9f28e2040fc65b6f02d56dbd6aa9af8fde656f70495dfb723ba01173d4707a12fddac628ca29f3e32340bd8f7ddb557cf819f6b01e445ad96f874ba235584ee71f6581f62d4f43bf03f910f6510deb85e8ef06c7f09d9794a008be7ff2529f0ebb69decef646387dc767b74939265fec0223aa6d84d2a8a1cc912d5ca25b4e144ab8f6ba054b54910176d5737a2cff011da431bd5f2a0d2d66b9e70b39f4b050e45c0d9c16f02deda9ddf2d00f3e4b01037d7029cd49c2d46a8e1fc2c0c17520af1f4b5e25ba396afc4cd60c494a4c426448b35b49635b337cfb08e7c22a39b256dd032c00adddafb51a627f99a0e1704170ac1f1912e49d9db10ec04c19c58f420212973e0cb329524223a6aa56c7937c5dffdb5d966b6cd4cbc26f3201dd25c80960a1a111b32947bb78973d269fac7f5186530930ed19f68507540eed9e1bab8b00f00d8ca09b3f099aae46180e04e3584bd7ca054df18a1504b89d1d1675d0966c4ae1407be325cdf623cf13ff13e4a28b594d59e3eadbadf6136eee7a59d6a444c9eb4e2198e8a974f27a39eb63af2c9af3870488b8adaad444674f512133ad80b9220e09158521614f1faadfe8505ef57b7df6813048603f0dd04f4280177a11380fbfc861dbcbd7418d62155248dad5fdec0991f", + "blinded_msg": "aa3ee045138d874669685ffaef962c7694a9450aa9b4fd6465db9b3b75a522bb921c4c0fdcdfae9667593255099cff51f5d3fd65e8ffb9d3b3036252a6b51b6edfb3f40382b2bbf34c0055e4cbcc422850e586d84f190cd449af11dc65545f5fe26fd89796eb87da4bda0c545f397cddfeeb56f06e28135ec74fd477949e7677f6f36cfae8fd5c1c5898b03b9c244cf6d1a4fb7ad1cb43aff5e80cb462fac541e72f67f0a50f1843d1759edfaae92d1a916d3f0efaf4d650db416c3bf8abdb5414a78cebc97de676723cb119e77aea489f2bbf530c440ebc5a75dccd3ebf5a412a5f346badd61bee588e5917bdcce9dc33c882e39826951b0b8276c6203971947072b726e935816056ff5cb11a71ca2946478584126bb877acdf87255f26e6cca4e0878801307485d3b7bb89b289551a8b65a7a6b93db010423d1406e149c87731910306e5e410b41d4da3234624e74f92845183e323cf7eb244f212a695f8856c675fbc3a021ce649e22c6f0d053a9d238841cf3afdc2739f99672a419ae13c17f1f8a3bc302ec2e7b98e8c353898b7150ad8877ec841ea6e4b288064c254fefd0d049c3ad196bf7ffa535e74585d0120ce728036ed500942fbd5e6332c298f1ffebe9ff60c1e117b274cf0cb9d70c36ee4891528996ec1ed0b178e9f3c0c0e6120885f39e8ccaadbb20f3196378c07b1ff22d10049d3039a7a92fe7efdd95d", + "blind_sig": "3f4a79eacd4445fca628a310d41e12fcd813c4d43aa4ef2b81226953248d6d00adfee6b79cb88bfa1f99270369fd063c023e5ed546719b0b2d143dd1bca46b0e0e615fe5c63d95c5a6b873b8b50bc52487354e69c3dfbf416e7aca18d5842c89b676efdd38087008fa5a810161fcdec26f20ccf2f1e6ab0f9d2bb93e051cb9e86a9b28c5bb62fd5f5391379f887c0f706a08bcc3b9e7506aaf02485d688198f5e22eefdf837b2dd919320b17482c5cc54271b4ccb41d267629b3f844fd63750b01f5276c79e33718bb561a152acb2eb36d8be75bce05c9d1b94eb609106f38226fb2e0f5cd5c5c39c59dda166862de498b8d92f6bcb41af433d65a2ac23da87f39764cb64e79e74a8f4ce4dd567480d967cefac46b6e9c06434c3715635834357edd2ce6f105eea854ac126ccfa3de2aac5607565a4e5efaac5eed491c335f6fc97e6eb7e9cea3e12de38dfb315220c0a3f84536abb2fdd722813e083feda010391ac3d8fd1cd9212b5d94e634e69ebcc800c4d5c4c1091c64afc37acf563c7fc0a6e4c082bc55544f50a7971f3fb97d5853d72c3af34ffd5ce123998be5360d1059820c66a81e1ee6d9c1803b5b62af6bc877526df255b6d1d835d8c840bebbcd6cc0ee910f17da37caf8488afbc08397a1941fcc79e76a5888a95b3d5405e13f737bea5c78d716a48eb9dc0aec8de39c4b45c6914ad4a8185969f70b1adf46", + "sig": "191e941c57510e22d29afad257de5ca436d2316221fe870c7cb75205a6c071c2735aed0bc24c37f3d5bd960ab97a829a508f966bbaed7a82645e65eadaf24ab5e6d9421392c5b15b7f9b640d34fec512846a3100b80f75ef51064602118c1a77d28d938f6efc22041d60159a518d3de7c4d840c9c68109672d743d299d8d2577ef60c19ab463c716b3fa75fa56f5735349d414a44df12bf0dd44aa3e10822a651ed4cb0eb6f47c9bd0ef14a034a7ac2451e30434d513eb22e68b7587a8de9b4e63a059d05c8b22c7c51e2cfee2d8bef511412e93c859a13726d87c57d1bc4c2e68ab121562f839c3a3d233e87ed63c69b7e57525367753fbebcc2a9805a2802659f5888b2c69115bf865559f10d906c09d048a0d71bfee4b33857393ec2b69e451433496d02c9a7910abb954317720bbde9e69108eafc3e90bad3d5ca4066d7b1e49013fa04e948104a1dd82b12509ecb146e948c54bd8bfb5e6d18127cd1f7a93c3cf9f2d869d5a78878c03fe808a0d799e910be6f26d18db61c485b303631d3568368fc41986d08a95ea6ac0592240c19d7b22416b9c82ae6241e211dd5610d0baaa9823158f9c32b66318f5529491b7eeadcaa71898a63bac9d95f4aa548d5e97568d744fc429104e32edd9c87519892a198a30d333d427739ffb9607b092e910ae37771abf2adb9f63bc058bf58062ad456cb934679795bbdfcdfad5e0f2" + }, + { + "name": "RSABSSA-SHA384-PSSZERO-Randomized", + "p": "0xe1f4d7a34802e27c7392a3cea32a262a34dc3691bd87f3f310dc75673488930559c120fd0410194fb8a0da55bd0b81227e843fdca6692ae80e5a5d414116d4803fca7d8c30eaaae57e44a1816ebb5c5b0606c536246c7f11985d731684150b63c9a3ad9e41b04c0b5b27cb188a692c84696b742a80d3cd00ab891f2457443dadfeba6d6daf108602be26d7071803c67105a5426838e6889d77e8474b29244cefaf418e381b312048b457d73419213063c60ee7b0d81820165864fef93523c9635c22210956e53a8d96322493ffc58d845368e2416e078e5bcb5d2fd68ae6acfa54f9627c42e84a9d3f2774017e32ebca06308a12ecc290c7cd1156dcccfb2311", + "q": "0xc601a9caea66dc3835827b539db9df6f6f5ae77244692780cd334a006ab353c806426b60718c05245650821d39445d3ab591ed10a7339f15d83fe13f6a3dfb20b9452c6a9b42eaa62a68c970df3cadb2139f804ad8223d56108dfde30ba7d367e9b0a7a80c4fdba2fd9dde6661fc73fc2947569d2029f2870fc02d8325acf28c9afa19ecf962daa7916e21afad09eb62fe9f1cf91b77dc879b7974b490d3ebd2e95426057f35d0a3c9f45f79ac727ab81a519a8b9285932d9b2e5ccd347e59f3f32ad9ca359115e7da008ab7406707bd0e8e185a5ed8758b5ba266e8828f8d863ae133846304a2936ad7bc7c9803879d2fc4a28e69291d73dbd799f8bc238385", + "n": "0xaec4d69addc70b990ea66a5e70603b6fee27aafebd08f2d94cbe1250c556e047a928d635c3f45ee9b66d1bc628a03bac9b7c3f416fe20dabea8f3d7b4bbf7f963be335d2328d67e6c13ee4a8f955e05a3283720d3e1f139c38e43e0338ad058a9495c53377fc35be64d208f89b4aa721bf7f7d3fef837be2a80e0f8adf0bcd1eec5bb040443a2b2792fdca522a7472aed74f31a1ebe1eebc1f408660a0543dfe2a850f106a617ec6685573702eaaa21a5640a5dcaf9b74e397fa3af18a2f1b7c03ba91a6336158de420d63188ee143866ee415735d155b7c2d854d795b7bc236cffd71542df34234221a0413e142d8c61355cc44d45bda94204974557ac2704cd8b593f035a5724b1adf442e78c542cd4414fce6f1298182fb6d8e53cef1adfd2e90e1e4deec52999bdc6c29144e8d52a125232c8c6d75c706ea3cc06841c7bda33568c63a6c03817f722b50fcf898237d788a4400869e44d90a3020923dc646388abcc914315215fcd1bae11b1c751fd52443aac8f601087d8d42737c18a3fa11ecd4131ecae017ae0a14acfc4ef85b83c19fed33cfd1cd629da2c4c09e222b398e18d822f77bb378dea3cb360b605e5aa58b20edc29d000a66bd177c682a17e7eb12a63ef7c2e4183e0d898f3d6bf567ba8ae84f84f1d23bf8b8e261c3729e2fa6d07b832e07cddd1d14f55325c6f924267957121902dc19b3b32948bdead5", + "e": "0x010001", + "d": "0x0d43242aefe1fb2c13fbc66e20b678c4336d20b1808c558b6e62ad16a287077180b177e1f01b12f9c6cd6c52630257ccef26a45135a990928773f3bd2fc01a313f1dac97a51cec71cb1fd7efc7adffdeb05f1fb04812c924ed7f4a8269925dad88bd7dcfbc4ef01020ebfc60cb3e04c54f981fdbd273e69a8a58b8ceb7c2d83fbcbd6f784d052201b88a9848186f2a45c0d2826870733e6fd9aa46983e0a6e82e35ca20a439c5ee7b502a9062e1066493bdadf8b49eb30d9558ed85abc7afb29b3c9bc644199654a4676681af4babcea4e6f71fe4565c9c1b85d9985b84ec1abf1a820a9bbebee0df1398aae2c85ab580a9f13e7743afd3108eb32100b870648fa6bc17e8abac4d3c99246b1f0ea9f7f93a5dd5458c56d9f3f81ff2216b3c3680a13591673c43194d8e6fc93fc1e37ce2986bd628ac48088bc723d8fbe293861ca7a9f4a73e9fa63b1b6d0074f5dea2a624c5249ff3ad811b6255b299d6bc5451ba7477f19c5a0db690c3e6476398b1483d10314afd38bbaf6e2fbdbcd62c3ca9797a420ca6034ec0a83360a3ee2adf4b9d4ba29731d131b099a38d6a23cc463db754603211260e99d19affc902c915d7854554aabf608e3ac52c19b8aa26ae042249b17b2d29669b5c859103ee53ef9bdc73ba3c6b537d5c34b6d8f034671d7f3a8a6966cc4543df223565343154140fd7391c7e7be03e241f4ecfeb877a051", + "msg": "8f3dc6fb8c4a02f4d6352edf0907822c1210a9b32f9bdda4c45a698c80023aa6b59f8cfec5fdbb36331372ebefedae7d", + "msg_prefix": "84ea86c8cf3beedfed73beceabd792027c609d1100bf041fdd60d826a718130d", + "input_msg": "84ea86c8cf3beedfed73beceabd792027c609d1100bf041fdd60d826a718130d8f3dc6fb8c4a02f4d6352edf0907822c1210a9b32f9bdda4c45a698c80023aa6b59f8cfec5fdbb36331372ebefedae7d", + "sLen": "0x00", + "salt": "", + "encoded_msg": "37f4ea66054b3570f2c46f43125a8df8d751a81db1003edcc70e9888cb3d0fa71bb7634437a779c1bf9e84e88b3479894490ee41cd69fc8e911478326fe8460d1699f96abedde22ba0ba25a02f78bae77eb039decd41e6cd40fecc28f301c94d5644eb3e55b316569e2bec3ccf8e33b06eb6defca5fe672613d33ea60f84daa560ded4c1c5e65613fb19e090d0fc96a1394e29dfad6a7644362bf30bdc90c7ca0a065190f5a099b5c33ae787b872518a724d9aa139229656eb21053bbe86c38f6d03b4c6fa37a900935d9b8d19e0c394be4af6af028680996e3fd533b6698ce9e2ed6a9f96d4d3a682027ae5240040e55d75017dc303b7142c1f7e17b79778a94431398d21dc0cc7ae454cc0d6cf4db4d588d3fd15fd7f71576052fd2a52d688f99790dfb13808ecb24b6b9e9a43a8c0105670ec3ad8d6318a9c6a9cef9eb99b36d74b8e83dbacf6e8100e135b609850b34a4b01091b263678d7cd9905af2ffda801a2888d863a25211903b43cb5e59f5dba6bc18713ce4f028f1774c593664912f1d181d4544a13a1da354332d8595f59cf5af260a8aaf21a6bc948b5d5d4a520c1f72c216259dc12a33c2a3bd4d32ff2bf3de2ffe76e51f8af030b40fadc5899e740da20be1dd5a50f701292ceaee51fa35d9a047f3efc6543dc583fb3f23abeade39c2a5b5b352de26d7a11267435be7bffa8f2292e139fad923dbaf863bc", + "is_randomized": "0x01", + "inv": "0x80682c48982407b489d53d1261b19ec8627d02b8cda5336750b8cee332ae260de57b02d72609c1e0e9f28e2040fc65b6f02d56dbd6aa9af8fde656f70495dfb723ba01173d4707a12fddac628ca29f3e32340bd8f7ddb557cf819f6b01e445ad96f874ba235584ee71f6581f62d4f43bf03f910f6510deb85e8ef06c7f09d9794a008be7ff2529f0ebb69decef646387dc767b74939265fec0223aa6d84d2a8a1cc912d5ca25b4e144ab8f6ba054b54910176d5737a2cff011da431bd5f2a0d2d66b9e70b39f4b050e45c0d9c16f02deda9ddf2d00f3e4b01037d7029cd49c2d46a8e1fc2c0c17520af1f4b5e25ba396afc4cd60c494a4c426448b35b49635b337cfb08e7c22a39b256dd032c00adddafb51a627f99a0e1704170ac1f1912e49d9db10ec04c19c58f420212973e0cb329524223a6aa56c7937c5dffdb5d966b6cd4cbc26f3201dd25c80960a1a111b32947bb78973d269fac7f5186530930ed19f68507540eed9e1bab8b00f00d8ca09b3f099aae46180e04e3584bd7ca054df18a1504b89d1d1675d0966c4ae1407be325cdf623cf13ff13e4a28b594d59e3eadbadf6136eee7a59d6a444c9eb4e2198e8a974f27a39eb63af2c9af3870488b8adaad444674f512133ad80b9220e09158521614f1faadfe8505ef57b7df6813048603f0dd04f4280177a11380fbfc861dbcbd7418d62155248dad5fdec0991f", + "blinded_msg": "4c1b82d9b97b968b2ce0754e326abd49e3d723ed937d84bead34b6a834483b43d510bf62ca47683ed366d94d3d357b270a85cf2cc2ddd171141b45d7549d5373cf67d14f6f462c14ebded906793144faba37f129c0f3172854ec0f854e555552eec5a30c87788f1039814594f04348709e26a883be82affff207b1886b75c037f43f847f45d89bcbf210c22ffcdf8118ce8a526b3723e6209c26319f8f5d2adcf0b637031c9fdf53470a915c587e30287ba88ed4f1cd5e93cf3d4990acf31fffdbfddec80ae0b728d5b4c612a396fd81acaa65566a4dc1c24624f44fd10cdba05f3d0bed2e69bb0d13d41a9f1b4e67aa566520778733ced5e6260f4d1982f63bb835442acffe3cb87f5f8ec6bb84226e0eab787159d08e57604b13557ceea97f2c4ad0631accf898f302df86f0b64354ec0b3bdf1b4e2a4deb4d38f655ea8d80de4cc19aa06ffcd56e348faf894c8774c53235ddcc152d80cf66b417eee4d182781bab8c979937a3c7502d8f39c57c4f09884de5a7247f2539910a96e4b15f9a3df88edc21a13030af357467a99dca50dba4afe4a6185a240ac8f1d8aab2e83443025f94e1af930f56f78661369cc6790701f31b83aec40f96a72c7f7ba13b4ebdd8e24e7351f4ffba0a7c072cb28f13aff06cd02368491044fcc536213b2e3b1cf6ca81cf2097b7b19d2b36bd246f390f53768f1c2e56113ea91b33c7cfa647", + "blind_sig": "4894f64d7214c216282d9842cbf7e7cccd9c0dcb1f4294a6bdeccd4c4c2446160d7cac7892f01b70dfa69f533891d2fbb447f7cf7541d1b504a2d46fc1bb6de26b345972aada8ebce280b906f3a10a13208f77ef896fbe6bc4504327fd4c5c8f03211d45ae9672e9f4be0f4900762ba2a7177a58b90d6dd1263faf2b7a5f15d50a7b00e733742c1b6a1ea4eb5fbfb407abf14496ab26b50cf1a5a56dea616b7a6a5595777400571a751c682b9fdd6badb3f72292f314f4ba2ba0f394f91676a4bb12e60ea08c977f7082be6357c1ca82fe3301fe5fb4128609bee2410db0481aea3a5737fb0bce9381272c2202644f662e99f64bf1190d66e230cc0371ec33fe32fe725dfd872041914d39462a909414a780c9aab394af443199eba56c83986d22d57d4421b41ff8e5bec537d271223adb34d26c64989048a88d8f352a06a7cc153e216a6bed9548bb38d2a1600b2f3403289df6df74aec525ef9e413b7140a7c1a914dedd74a336f1beed39a8e5e2cef76cac094df0dbb3fa55d4b7ee781c74bed3bd8bc7aa6ef3f1dbfa4674945720ec93dafa6d0650229ab75e3fae687327fac081cf4bb376e02a2b73314c54c12f88572c28980f13aba5731bc5a3a60575ea116c8ea2fe5009168deb1255026c9310783ff7f644255d3e1691e194db1babd7780b9a5dc0cb3de2b700d12f49cbe4db51ca2f3c8a58b09e854cc71e8070ab", + "sig": "195363ba25e4bf763f6538c86865785f93f4ea6092da3ad200d41b99eb0eb0869fa792df619fd8fa5923d5d03d5882faae6d25054118deef5e4a6a252dd5afb0dac262b74c391090b1575fbafd959d26bc294f47fb45a2c1c209932c4f94b24394eded91fbdd015e1a85dde63c9e77a0283f812cad1192d86432c51331e46fd4f3771bbafb929f847a19cb05e5f79b6b519d67e8f005951e53656be97cb612d2f506618b366403b34648451d6fbc7318c2f3f583cc6fa17bf2108398f9284e0602187904406a9322f1e7b8016ca9ad11b835756df862c465c420535e25faa48bf341f7ee8192be47fa875791f32f56d5e631d237060688f052426dee5b0b2b74ca5f830e82a453379eedb541fa4fcdaa19dae6509401e3cdd4c40f5c9243db3f6d7115c4e8cd6db8290723ab01d9d0d7e355a97a01547800e43f11736668c3f8908848d759c33a67a2f506abc3f6871cbe625b1bc71eb06d785a59501396712c581a60d6ccc450d2f4eb4cf08ae0dbfa45c2860425be90cc4cd4c989495bbd2963e19c59ae5d90d1ca884e80d654b5f2cd6a80c3588b514ee91c802736f594c340397b316a97e9c70b0609955b6c3ee06f4760d9377f0797a0411a244db395bb8b711ef79fbcb5589226174029be79a72dcd6f4ca566b7b1b9a27e43b5c02a9a579d60bdda183398d66d76e0e8eceb1af2f27633589d043bcdc041683b31f7f1" + }, + { + "name": "RSABSSA-SHA384-PSS-Deterministic", + "p": "0xe1f4d7a34802e27c7392a3cea32a262a34dc3691bd87f3f310dc75673488930559c120fd0410194fb8a0da55bd0b81227e843fdca6692ae80e5a5d414116d4803fca7d8c30eaaae57e44a1816ebb5c5b0606c536246c7f11985d731684150b63c9a3ad9e41b04c0b5b27cb188a692c84696b742a80d3cd00ab891f2457443dadfeba6d6daf108602be26d7071803c67105a5426838e6889d77e8474b29244cefaf418e381b312048b457d73419213063c60ee7b0d81820165864fef93523c9635c22210956e53a8d96322493ffc58d845368e2416e078e5bcb5d2fd68ae6acfa54f9627c42e84a9d3f2774017e32ebca06308a12ecc290c7cd1156dcccfb2311", + "q": "0xc601a9caea66dc3835827b539db9df6f6f5ae77244692780cd334a006ab353c806426b60718c05245650821d39445d3ab591ed10a7339f15d83fe13f6a3dfb20b9452c6a9b42eaa62a68c970df3cadb2139f804ad8223d56108dfde30ba7d367e9b0a7a80c4fdba2fd9dde6661fc73fc2947569d2029f2870fc02d8325acf28c9afa19ecf962daa7916e21afad09eb62fe9f1cf91b77dc879b7974b490d3ebd2e95426057f35d0a3c9f45f79ac727ab81a519a8b9285932d9b2e5ccd347e59f3f32ad9ca359115e7da008ab7406707bd0e8e185a5ed8758b5ba266e8828f8d863ae133846304a2936ad7bc7c9803879d2fc4a28e69291d73dbd799f8bc238385", + "n": "0xaec4d69addc70b990ea66a5e70603b6fee27aafebd08f2d94cbe1250c556e047a928d635c3f45ee9b66d1bc628a03bac9b7c3f416fe20dabea8f3d7b4bbf7f963be335d2328d67e6c13ee4a8f955e05a3283720d3e1f139c38e43e0338ad058a9495c53377fc35be64d208f89b4aa721bf7f7d3fef837be2a80e0f8adf0bcd1eec5bb040443a2b2792fdca522a7472aed74f31a1ebe1eebc1f408660a0543dfe2a850f106a617ec6685573702eaaa21a5640a5dcaf9b74e397fa3af18a2f1b7c03ba91a6336158de420d63188ee143866ee415735d155b7c2d854d795b7bc236cffd71542df34234221a0413e142d8c61355cc44d45bda94204974557ac2704cd8b593f035a5724b1adf442e78c542cd4414fce6f1298182fb6d8e53cef1adfd2e90e1e4deec52999bdc6c29144e8d52a125232c8c6d75c706ea3cc06841c7bda33568c63a6c03817f722b50fcf898237d788a4400869e44d90a3020923dc646388abcc914315215fcd1bae11b1c751fd52443aac8f601087d8d42737c18a3fa11ecd4131ecae017ae0a14acfc4ef85b83c19fed33cfd1cd629da2c4c09e222b398e18d822f77bb378dea3cb360b605e5aa58b20edc29d000a66bd177c682a17e7eb12a63ef7c2e4183e0d898f3d6bf567ba8ae84f84f1d23bf8b8e261c3729e2fa6d07b832e07cddd1d14f55325c6f924267957121902dc19b3b32948bdead5", + "e": "0x010001", + "d": "0x0d43242aefe1fb2c13fbc66e20b678c4336d20b1808c558b6e62ad16a287077180b177e1f01b12f9c6cd6c52630257ccef26a45135a990928773f3bd2fc01a313f1dac97a51cec71cb1fd7efc7adffdeb05f1fb04812c924ed7f4a8269925dad88bd7dcfbc4ef01020ebfc60cb3e04c54f981fdbd273e69a8a58b8ceb7c2d83fbcbd6f784d052201b88a9848186f2a45c0d2826870733e6fd9aa46983e0a6e82e35ca20a439c5ee7b502a9062e1066493bdadf8b49eb30d9558ed85abc7afb29b3c9bc644199654a4676681af4babcea4e6f71fe4565c9c1b85d9985b84ec1abf1a820a9bbebee0df1398aae2c85ab580a9f13e7743afd3108eb32100b870648fa6bc17e8abac4d3c99246b1f0ea9f7f93a5dd5458c56d9f3f81ff2216b3c3680a13591673c43194d8e6fc93fc1e37ce2986bd628ac48088bc723d8fbe293861ca7a9f4a73e9fa63b1b6d0074f5dea2a624c5249ff3ad811b6255b299d6bc5451ba7477f19c5a0db690c3e6476398b1483d10314afd38bbaf6e2fbdbcd62c3ca9797a420ca6034ec0a83360a3ee2adf4b9d4ba29731d131b099a38d6a23cc463db754603211260e99d19affc902c915d7854554aabf608e3ac52c19b8aa26ae042249b17b2d29669b5c859103ee53ef9bdc73ba3c6b537d5c34b6d8f034671d7f3a8a6966cc4543df223565343154140fd7391c7e7be03e241f4ecfeb877a051", + "msg": "8f3dc6fb8c4a02f4d6352edf0907822c1210a9b32f9bdda4c45a698c80023aa6b59f8cfec5fdbb36331372ebefedae7d", + "msg_prefix": "", + "input_msg": "8f3dc6fb8c4a02f4d6352edf0907822c1210a9b32f9bdda4c45a698c80023aa6b59f8cfec5fdbb36331372ebefedae7d", + "sLen": "0x30", + "salt": "051722b35f458781397c3a671a7d3bd3096503940e4c4f1aaa269d60300ce449555cd7340100df9d46944c5356825abf", + "encoded_msg": "6e0c464d9c2f9fbc147b43570fc4f238e0d0b38870b3addcf7a4217df912ccef17a7f629aa850f63a063925f312d61d6437be954b45025e8282f9c0b1131bc8ff19a8a928d859b37113db1064f92a27f64761c181c1e1f9b251ae5a2f8a4047573b67a270584e089beadcb13e7c82337797119712e9b849ff56e04385d144d3ca9d8d92bf78adb20b5bbeb3685f17038ec6afade3ef354429c51c687b45a7018ee3a6966b3af15c9ba8f40e6461ba0a17ef5a799672ad882bab02b518f9da7c1a962945c2e9b0f02f29b31b9cdf3e633f9d9d2a22e96e1de28e25241ca7dd04147112f578973403e0f4fd80865965475d22294f065e17a1c4a201de93bd14223e6b1b999fd548f2f759f52db71964528b6f15b9c2d7811f2a0a35d534b8216301c47f4f04f412cae142b48c4cdff78bc54df690fd43142d750c671dd8e2e938e6a440b2f825b6dbb3e19f1d7a3c0150428a47948037c322365b7fe6fe57ac88d8f80889e9ff38177bad8c8d8d98db42908b389cb59692a58ce275aa15acb032ca951b3e0a3404b7f33f655b7c7d83a2f8d1b6bbff49d5fcedf2e030e80881aa436db27a5c0dea13f32e7d460dbf01240c2320c2bb5b3225b17145c72d61d47c8f84d1e19417ebd8ce3638a82d395cc6f7050b6209d9283dc7b93fecc04f3f9e7f566829ac41568ef799480c733c09759aa9734e2013d7640dc6151018ea902bc", + "is_randomized": "0x00", + "inv": "0x80682c48982407b489d53d1261b19ec8627d02b8cda5336750b8cee332ae260de57b02d72609c1e0e9f28e2040fc65b6f02d56dbd6aa9af8fde656f70495dfb723ba01173d4707a12fddac628ca29f3e32340bd8f7ddb557cf819f6b01e445ad96f874ba235584ee71f6581f62d4f43bf03f910f6510deb85e8ef06c7f09d9794a008be7ff2529f0ebb69decef646387dc767b74939265fec0223aa6d84d2a8a1cc912d5ca25b4e144ab8f6ba054b54910176d5737a2cff011da431bd5f2a0d2d66b9e70b39f4b050e45c0d9c16f02deda9ddf2d00f3e4b01037d7029cd49c2d46a8e1fc2c0c17520af1f4b5e25ba396afc4cd60c494a4c426448b35b49635b337cfb08e7c22a39b256dd032c00adddafb51a627f99a0e1704170ac1f1912e49d9db10ec04c19c58f420212973e0cb329524223a6aa56c7937c5dffdb5d966b6cd4cbc26f3201dd25c80960a1a111b32947bb78973d269fac7f5186530930ed19f68507540eed9e1bab8b00f00d8ca09b3f099aae46180e04e3584bd7ca054df18a1504b89d1d1675d0966c4ae1407be325cdf623cf13ff13e4a28b594d59e3eadbadf6136eee7a59d6a444c9eb4e2198e8a974f27a39eb63af2c9af3870488b8adaad444674f512133ad80b9220e09158521614f1faadfe8505ef57b7df6813048603f0dd04f4280177a11380fbfc861dbcbd7418d62155248dad5fdec0991f", + "blinded_msg": "10c166c6a711e81c46f45b18e5873cc4f494f003180dd7f115585d871a28930259654fe28a54dab319cc5011204c8373b50a57b0fdc7a678bd74c523259dfe4fd5ea9f52f170e19dfa332930ad1609fc8a00902d725cfe50685c95e5b2968c9a2828a21207fcf393d15f849769e2af34ac4259d91dfd98c3a707c509e1af55647efaa31290ddf48e0133b798562af5eabd327270ac2fb6c594734ce339a14ea4fe1b9a2f81c0bc230ca523bda17ff42a377266bc2778a274c0ae5ec5a8cbbe364fcf0d2403f7ee178d77ff28b67a20c7ceec009182dbcaa9bc99b51ebbf13b7d542be337172c6474f2cd3561219fe0dfa3fb207cff89632091ab841cf38d8aa88af6891539f263adb8eac6402c41b6ebd72984e43666e537f5f5fe27b2b5aa114957e9a580730308a5f5a9c63a1eb599f093ab401d0c6003a451931b6d124180305705845060ebba6b0036154fcef3e5e9f9e4b87e8f084542fd1dd67e7782a5585150181c01eb6d90cb95883837384a5b91dbb606f266059ecc51b5acbaa280e45cfd2eec8cc1cdb1b7211c8e14805ba683f9b78824b2eb005bc8a7d7179a36c152cb87c8219e5569bba911bb32a1b923ca83de0e03fb10fba75d85c55907dda5a2606bf918b056c3808ba496a4d95532212040a5f44f37e1097f26dc27b98a51837daa78f23e532156296b64352669c94a8a855acf30533d8e0594ace7c442", + "blind_sig": "364f6a40dbfbc3bbb257943337eeff791a0f290898a6791283bba581d9eac90a6376a837241f5f73a78a5c6746e1306ba3adab6067c32ff69115734ce014d354e2f259d4cbfb890244fd451a497fe6ecf9aa90d19a2d441162f7eaa7ce3fc4e89fd4e76b7ae585be2a2c0fd6fb246b8ac8d58bcb585634e30c9168a434786fe5e0b74bfe8187b47ac091aa571ffea0a864cb906d0e28c77a00e8cd8f6aba4317a8cc7bf32ce566bd1ef80c64de041728abe087bee6cadd0b7062bde5ceef308a23bd1ccc154fd0c3a26110df6193464fc0d24ee189aea8979d722170ba945fdcce9b1b4b63349980f3a92dc2e5418c54d38a862916926b3f9ca270a8cf40dfb9772bfbdd9a3e0e0892369c18249211ba857f35963d0e05d8da98f1aa0c6bba58f47487b8f663e395091275f82941830b050b260e4767ce2fa903e75ff8970c98bfb3a08d6db91ab1746c86420ee2e909bf681cac173697135983c3594b2def673736220452fde4ddec867d40ff42dd3da36c84e3e52508b891a00f50b4f62d112edb3b6b6cc3dbd546ba10f36b03f06c0d82aeec3b25e127af545fac28e1613a0517a6095ad18a98ab79f68801e05c175e15bae21f821e80c80ab4fdec6fb34ca315e194502b8f3dcf7892b511aee45060e3994cd15e003861bc7220a2babd7b40eda03382548a34a7110f9b1779bf3ef6011361611e6bc5c0dc851e1509de1a", + "sig": "6fef8bf9bc182cd8cf7ce45c7dcf0e6f3e518ae48f06f3c670c649ac737a8b8119a34d51641785be151a697ed7825fdfece82865123445eab03eb4bb91cecf4d6951738495f8481151b62de869658573df4e50a95c17c31b52e154ae26a04067d5ecdc1592c287550bb982a5bb9c30fd53a768cee6baabb3d483e9f1e2da954c7f4cf492fe3944d2fe456c1ecaf0840369e33fb4010e6b44bb1d721840513524d8e9a3519f40d1b81ae34fb7a31ee6b7ed641cb16c2ac999004c2191de0201457523f5a4700dd649267d9286f5c1d193f1454c9f868a57816bf5ff76c838a2eeb616a3fc9976f65d4371deecfbab29362caebdff69c635fe5a2113da4d4d8c24f0b16a0584fa05e80e607c5d9a2f765f1f069f8d4da21f27c2a3b5c984b4ab24899bef46c6d9323df4862fe51ce300fca40fb539c3bb7fe2dcc9409e425f2d3b95e70e9c49c5feb6ecc9d43442c33d50003ee936845892fb8be475647da9a080f5bc7f8a716590b3745c2209fe05b17992830ce15f32c7b22cde755c8a2fe50bd814a0434130b807dc1b7218d4e85342d70695a5d7f29306f25623ad1e8aa08ef71b54b8ee447b5f64e73d09bdd6c3b7ca224058d7c67cc7551e9241688ada12d859cb7646fbd3ed8b34312f3b49d69802f0eaa11bc4211c2f7a29cd5c01ed01a39001c5856fab36228f5ee2f2e1110811872fe7c865c42ed59029c706195d52" + }, + { + "name": "RSABSSA-SHA384-PSSZERO-Deterministic", + "p": "0xe1f4d7a34802e27c7392a3cea32a262a34dc3691bd87f3f310dc75673488930559c120fd0410194fb8a0da55bd0b81227e843fdca6692ae80e5a5d414116d4803fca7d8c30eaaae57e44a1816ebb5c5b0606c536246c7f11985d731684150b63c9a3ad9e41b04c0b5b27cb188a692c84696b742a80d3cd00ab891f2457443dadfeba6d6daf108602be26d7071803c67105a5426838e6889d77e8474b29244cefaf418e381b312048b457d73419213063c60ee7b0d81820165864fef93523c9635c22210956e53a8d96322493ffc58d845368e2416e078e5bcb5d2fd68ae6acfa54f9627c42e84a9d3f2774017e32ebca06308a12ecc290c7cd1156dcccfb2311", + "q": "0xc601a9caea66dc3835827b539db9df6f6f5ae77244692780cd334a006ab353c806426b60718c05245650821d39445d3ab591ed10a7339f15d83fe13f6a3dfb20b9452c6a9b42eaa62a68c970df3cadb2139f804ad8223d56108dfde30ba7d367e9b0a7a80c4fdba2fd9dde6661fc73fc2947569d2029f2870fc02d8325acf28c9afa19ecf962daa7916e21afad09eb62fe9f1cf91b77dc879b7974b490d3ebd2e95426057f35d0a3c9f45f79ac727ab81a519a8b9285932d9b2e5ccd347e59f3f32ad9ca359115e7da008ab7406707bd0e8e185a5ed8758b5ba266e8828f8d863ae133846304a2936ad7bc7c9803879d2fc4a28e69291d73dbd799f8bc238385", + "n": "0xaec4d69addc70b990ea66a5e70603b6fee27aafebd08f2d94cbe1250c556e047a928d635c3f45ee9b66d1bc628a03bac9b7c3f416fe20dabea8f3d7b4bbf7f963be335d2328d67e6c13ee4a8f955e05a3283720d3e1f139c38e43e0338ad058a9495c53377fc35be64d208f89b4aa721bf7f7d3fef837be2a80e0f8adf0bcd1eec5bb040443a2b2792fdca522a7472aed74f31a1ebe1eebc1f408660a0543dfe2a850f106a617ec6685573702eaaa21a5640a5dcaf9b74e397fa3af18a2f1b7c03ba91a6336158de420d63188ee143866ee415735d155b7c2d854d795b7bc236cffd71542df34234221a0413e142d8c61355cc44d45bda94204974557ac2704cd8b593f035a5724b1adf442e78c542cd4414fce6f1298182fb6d8e53cef1adfd2e90e1e4deec52999bdc6c29144e8d52a125232c8c6d75c706ea3cc06841c7bda33568c63a6c03817f722b50fcf898237d788a4400869e44d90a3020923dc646388abcc914315215fcd1bae11b1c751fd52443aac8f601087d8d42737c18a3fa11ecd4131ecae017ae0a14acfc4ef85b83c19fed33cfd1cd629da2c4c09e222b398e18d822f77bb378dea3cb360b605e5aa58b20edc29d000a66bd177c682a17e7eb12a63ef7c2e4183e0d898f3d6bf567ba8ae84f84f1d23bf8b8e261c3729e2fa6d07b832e07cddd1d14f55325c6f924267957121902dc19b3b32948bdead5", + "e": "0x010001", + "d": "0x0d43242aefe1fb2c13fbc66e20b678c4336d20b1808c558b6e62ad16a287077180b177e1f01b12f9c6cd6c52630257ccef26a45135a990928773f3bd2fc01a313f1dac97a51cec71cb1fd7efc7adffdeb05f1fb04812c924ed7f4a8269925dad88bd7dcfbc4ef01020ebfc60cb3e04c54f981fdbd273e69a8a58b8ceb7c2d83fbcbd6f784d052201b88a9848186f2a45c0d2826870733e6fd9aa46983e0a6e82e35ca20a439c5ee7b502a9062e1066493bdadf8b49eb30d9558ed85abc7afb29b3c9bc644199654a4676681af4babcea4e6f71fe4565c9c1b85d9985b84ec1abf1a820a9bbebee0df1398aae2c85ab580a9f13e7743afd3108eb32100b870648fa6bc17e8abac4d3c99246b1f0ea9f7f93a5dd5458c56d9f3f81ff2216b3c3680a13591673c43194d8e6fc93fc1e37ce2986bd628ac48088bc723d8fbe293861ca7a9f4a73e9fa63b1b6d0074f5dea2a624c5249ff3ad811b6255b299d6bc5451ba7477f19c5a0db690c3e6476398b1483d10314afd38bbaf6e2fbdbcd62c3ca9797a420ca6034ec0a83360a3ee2adf4b9d4ba29731d131b099a38d6a23cc463db754603211260e99d19affc902c915d7854554aabf608e3ac52c19b8aa26ae042249b17b2d29669b5c859103ee53ef9bdc73ba3c6b537d5c34b6d8f034671d7f3a8a6966cc4543df223565343154140fd7391c7e7be03e241f4ecfeb877a051", + "msg": "8f3dc6fb8c4a02f4d6352edf0907822c1210a9b32f9bdda4c45a698c80023aa6b59f8cfec5fdbb36331372ebefedae7d", + "msg_prefix": "", + "input_msg": "8f3dc6fb8c4a02f4d6352edf0907822c1210a9b32f9bdda4c45a698c80023aa6b59f8cfec5fdbb36331372ebefedae7d", + "sLen": "0x00", + "salt": "", + "encoded_msg": "159499b90471b496c2639ec482e99feaba525c0420c565d17dc60c1bb1f47703f04436cceaa8f69811e1bf8546fa971226c9e71421b32b571ed5ea0e032269d4219b4404316eb17a58f277634aeed394b7f3888153b5bb163e40807e605dafdd1789dd473b0846bdcb6524417bc3a35366fab4261708c0e4b4beba07a1a64bbccb4b1ac215d1350a50a501e8e96612028b535ad731abf1f117ee07d07a4de9cef3d70f5845ba84c29d5d92c6e66a1f9489a5f527b846825360fd6e90f40ed041c682e489f3acde984a3ea580181418c1d15017af2657bc4b70485cdc0f1ebc3693e0d70a5d01f37ff640993fa071274fb9ee44e0c24dcb58ffa21a9a6540d87f24379beaafcc3b4bd42c45ec6820e03738ce98bea11c71685f31db63429fab8658bdb816f1ecccb1888f2402de0bd2f0f9646decdcad4c11b41428eec1ed25f2a86d43bb04f95726bfbd98ea34ca091b7adbabd0e28f17fa0345b89542d23c3530554987508a23641bd4f9e52962b0bee3ac9ffe005322d26a39941c5847774300411c69635f96903e8d593530908bd92a4fa6a2d52f88073a647a4b3894b7e4ebb80699e60227397bfa93f41b1c97e107b632f68e70409372ead2f072c11cf99be4486fcbf763dde28ee156db26cd358a69fcb79644f1f2fcc166f41a4c80f5851ee08be051f14b601418d6e56e61733b9b210c6bef17edac121a754d19b9bc", + "is_randomized": "0x00", + "inv": "0x55f2053e9a4309ac61ac4da7f3a314e626f362e95f30337962d12f08b343165c8dea34d7812dc2dcb227cfa8de49bca57880ac55f6d77b37ed83a32eb33656ddf0cde29761aef9f86bd758280b3403a63b466831cba4c97e17e9a11e4139f9d84e5912b017eafbafdbb3ae59a1424feae6914eb1bf20922c6db5da8a538752b3b662ae15cae7beac9a0362b8836001c57b0c5167dceb9a66e6ab6a90e9898646b4274c3662e4316926c4da7caf5aeff611934b70581280ec68fb2ce04c5681ef95b086b7289afae8ecd669325659791853a9f4c0b784f6f60b212c3b39754d5539e3671d7930d1272e82b3853b6583a83d9ff70c00ce1938c05eccee531cb075564059b2749e84b45dff7d179c69c86c5d1870aeffd6281d099838a3a988ff9e2684f6cc896b5326275309187d9e3558163131e4d247c2ec8317a2c09f8079d32db8241c869bc5f773722ed8e68bfa5c518d20b955abf02103fce1a025149b14670fdfc8a3f0089516db047f86b9be626ff44989d6fcc162c9570da5b862b47304eca2aceba4dedd6a672458aae779004fe116009600a6a52eb6161a3d09fda09963b56f2870a150df7183bfa03ce735513e637631fb4f980657a8cdb953b2156594607f8ebf7de6999626197072afd7ff60a5d2f782dabe026e0f298df141b8a276aaf7202d959088d7721786b04c79e45c807eb46fcf3a94031ef351aff644", + "blinded_msg": "0c86f078fe8fd2ea6b4e120d3fef7555701a7c6b7bd5606a7fb2ef2769d119f2639477a7904984d67f0ecf419059aac58041977871d8da253a1aee14cde49cfb919f502f4d79d56d473a95f450982ad83398c1f3dd3a3342a18df9e81447998eae6c7f9de94148a30de0846fc2402b17b2dfe233c450ba41f141ec14b27bf4e7d79a5c0fa23ad64c2d2fa33691a3048d835f7e477ecba458e4d58f8dbbcfec2a484e1442ab4b266cfc610fec95f6258ef137590254931dea30f58e96a64cef7aca013cb037259d4dec8a2298d3e2ce96c75a10f39dcdfe7e90eba200c73fc3f5fbbdc4d50d33990559504d0ddb4fe50407fc21321128f72866c780d1412f20d4788ad0ebc2077dca4ae87108e416c3510609867196f4fbb69ff6c3a4c0249e3d6bcf157636666a0e17d8dba9034d9875e40bbff075b0a936acd75baf15179042959d6b27f8e233b60db93a2abce81f47e259f76b5a68d58c21fd8ccd7e102fc9292ec5a1bad8618a94f09ca6a58b1c5c7062fb17bd62035d898b76ead5f52a9869d5b6fbbbf5cd07bc3c35adbff4f03949fe32b455cd5b3de07859d65045b72fb1f4a0ab5c80a27a60b57ebd9e0b173778d3be592e74cdc6a9ffa147cbb021a87b9a525bc9135114d4daacf0b111773551474ea98493ed8562dac1c9e6398ada60573ff550a01aa4468fd493fb69b3a98ab3790fc7f71ef5dfa3f1979ebe35af", + "blind_sig": "5ca77254ce107e6e6eedcf8ca03e08d4e92eeb0f4f08b2a2e7fb69da2f5db95f2167ce58a861e45a5cac1bf7d3df3edd64a2802bb5c16ceb62b2f5a0355c0d0f6d8270b658fa26e86afc18a88e91b0ec07e813d50ed4fb20376bf8470179a3a97d5a29f9f9fe931d6bff233c45d62cd91cdb9a692cda309fad962fd9f7f19f89cc48bc75f9b521aeca21921330c7e91ff7ff2af6e62fe3112f7ec675e866c5961556a1796f2fd4707dd9fcde702caf003b5acfde1cd97bc5d2a63d126ac0587bf8ed6a3064d20dbdef9e207423e678f36e516e4c2696cc74f0a74be4c3ddaaf6cdbc95c9d58d930f0f4e00dfa2bf5d0a333964ec03226073030b9b78210d3160ec2722abf3c01efa1636a28c6c5ac9d14913537322ee42d26ab26518ec2af03202ea0e190a4790b7a8951be98313000c62d1fe0ea05647c451348f97ef5ced6c6e83303aececcc508fcc8f18f7751e050f9f7a562f45b0d03159486d067ab4b3df1b0f270d009436f0305640929a2b61cfeef24a2e39a9a622c9d9d9e2c99245ea415243f472b226e068ebba7624ccf012b86b21d80cb2e3b718224b2f7b638a16b7665a1a493b014dd3d0f7b97ca290665b1f0972bc4a7d4051e843182771b6258d9d63f919fde109f8487f443ea54518c053acfbf7c0cfe60435b6966d42c034cf6ad3be2281fa2bf1a90f1d2cba55643e9ae37065a7534f53402e6f4c2a3a", + "sig": "4454b6983ff01cb28545329f394936efa42ed231e15efbc025fdaca00277acf0c8e00e3d8b0ecebd35b057b8ebfc14e1a7097368a4abd20b555894ccef3d1b9528c6bcbda6b95376bef230d0f1feff0c1064c62c60a7ae7431d1fdfa43a81eed9235e363e1ffa0b2797aba6aad6082fcd285e14fc8b71de6b9c87cb4059c7dc1e96ae1e63795a1e9af86b9073d1d848aef3eca8a03421bcd116572456b53bcfd4dabb0a9691f1fabda3ed0ce357aee2cfee5b1a0eb226f69716d4e011d96eede5e38a9acb531a64336a0d5b0bae3ab085b658692579a376740ff6ce69e89b06f360520b864e33d82d029c808248a19e18e31f0ecd16fac5cd4870f8d3ebc1c32c718124152dc905672ab0b7af48bf7d1ac1ff7b9c742549c91275ab105458ae37621757add83482bbcf779e777bbd61126e93686635d4766aedf5103cf7978f3856ccac9e28d21a850dbb03c811128616d315d717be1c2b6254f8509acae862042c034530329ce15ca2e2f6b1f5fd59272746e3918c748c0eb810bf76884fa10fcf749326bbfaa5ba285a0186a22e4f628dbf178d3bb5dc7e165ca73f6a55ecc14c4f5a26c4693ce5da032264cbec319b12ddb9787d0efa4fcf1e5ccee35ad85ecd453182df9ed735893f830b570faae8be0f6fe2e571a4e0d927cba4debd368d3b4fca33ec6251897a137cf75474a32ac8256df5e5ffa518b88b43fb6f63a24" + } +] \ No newline at end of file From e728d0d84e7e7cd9027050a62aa14adb8dec147c Mon Sep 17 00:00:00 2001 From: Armando Faz Date: Thu, 26 Oct 2023 09:43:06 -0700 Subject: [PATCH 43/47] Apply thibmeu code review suggestions Co-authored-by: Thibault --- blindsign/blindrsa/brsa.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/blindsign/blindrsa/brsa.go b/blindsign/blindrsa/brsa.go index 0a1042097..5268cb905 100644 --- a/blindsign/blindrsa/brsa.go +++ b/blindsign/blindrsa/brsa.go @@ -1,6 +1,6 @@ -// Package blindrsa implements the RSA Blind Signature Protocol. +// Package blindrsa implements the RSA Blind Signature Protocol as defined in [RFC9474]. // -// The RSA Blind Signature protocol, also called RSABSSA +// The RSA Blind Signature protocol, and its variant RSABSSA // (RSA Blind Signature with Appendix) is a two-party protocol // between a Client and Server where they interact to compute // @@ -114,7 +114,7 @@ func (v randomBRSAVerifier) Hash() hash.Hash { } func prepareMsg(message, prefix []byte) []byte { - return append(append([]byte{}, prefix...), message...) + return append(prefix, message...) } func fixedBlind(message, salt []byte, r, rInv *big.Int, pk *rsa.PublicKey, hash hash.Hash) ([]byte, VerifierState, error) { From 99f0f715ca5fbec868f5a0db1df2be6dcd28dbaa Mon Sep 17 00:00:00 2001 From: armfazh Date: Fri, 27 Oct 2023 14:38:22 -0700 Subject: [PATCH 44/47] Releasing CIRCL v1.3.6 --- CITATION.cff | 4 +- README.md | 140 +++++++++++++++++++++++++++++++++++---------------- 2 files changed, 99 insertions(+), 45 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index 4080d3a99..35616cbbe 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,6 +1,6 @@ --- cff-version: 1.2.0 -version: 1.3.3 +version: 1.3.6 title: "Introducing CIRCL: An Advanced Cryptographic Library" license: BSD-3-Clause abstract: > @@ -25,6 +25,6 @@ keywords: - golang repository-code: "https://github.com/cloudflare/circl/" type: software -message: "Available at https://github.com/cloudflare/circl. v1.3.3 Accessed May, 2023." +message: "Available at https://github.com/cloudflare/circl. v1.3.6 Accessed Oct, 2023." contact: - name: "Cloudflare, Inc." diff --git a/README.md b/README.md index 502263fbe..4d8c9984b 100644 --- a/README.md +++ b/README.md @@ -25,60 +25,114 @@ You can get CIRCL by fetching: go get -u github.com/cloudflare/circl ``` +Alternatively, look at the [Cloudflare Go](https://github.com/cloudflare/go/tree/cf) fork to see how to integrate CIRCL natively in Go. + ## List of Algorithms -#### Diffie-Hellman Protocol -- [X25519](https://datatracker.ietf.org/doc/html/rfc7748/) -- [X448](https://datatracker.ietf.org/doc/html/rfc7748/) -- [Curve4Q](https://datatracker.ietf.org/doc/draft-ladd-cfrg-4q/) +[RFC-7748]: https://doi.org/10.17487/RFC7748 +[RFC-8032]: https://doi.org/10.17487/RFC8032 +[RFC-8235]: https://doi.org/10.17487/RFC8235 +[RFC-9180]: https://doi.org/10.17487/RFC9180 +[RFC-9380]: https://doi.org/10.17487/RFC9380 +[RFC-9474]: https://doi.org/10.17487/RFC9474 +[RFC-9496]: https://doi.org/10.17487/RFC9496 +[RFC-9497]: https://doi.org/10.17487/RFC9497 +[FIPS 202]: https://doi.org/10.6028/NIST.FIPS.202 +[FIPS 186-5]: https://doi.org/10.6028/NIST.FIPS.186-5 +[BLS12-381]: https://electriccoin.co/blog/new-snark-curve/ +[ia.cr/2015/267]: https://ia.cr/2015/267 +[ia.cr/2019/966]: https://ia.cr/2019/966 -#### Digital Signature Schemes -- [Ed25519](https://datatracker.ietf.org/doc/rfc8032/) -- [Ed448](https://datatracker.ietf.org/doc/rfc8032/) +### Elliptic Curve Cryptography -#### Groups based on Elliptic Curves - - P-256, P-384, P-521, [FIPS 186-4](https://doi.org/10.6028/NIST.FIPS.186-4) - - [Ristretto](https://datatracker.ietf.org/doc/draft-irtf-cfrg-ristretto255-decaf448/01/) - - [Hash to Curve](https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/) +| Diffie-Hellman Protocol | +|:---:| -#### High-Level Protocols - - [HPKE](https://datatracker.ietf.org/doc/draft-irtf-cfrg-hpke/): Hybrid Public-Key Encryption - - [VOPRF](https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/): Verifiable Oblivious Pseudorandom function: OPRF, VOPRF and POPRF modes. - - [BlindRSA](https://datatracker.ietf.org/doc/draft-irtf-cfrg-rsa-blind-signatures/): Blind RSA signatures. - - [CPABE](./abe/cpabe): Ciphertext-policy Attribute-based Encryption. +- [X25519](./dh/x25519) and [X448](./dh/x448) functions. ([RFC-7748]) +- [Curve4Q](./dh/curve4q) function based on FourQ curve. ([draft-ladd-cfrg-4q](https://datatracker.ietf.org/doc/draft-ladd-cfrg-4q/)) -#### Post-Quantum Key Encapsulation Methods - - [CSIDH](https://csidh.isogeny.org/): Post-Quantum Commutative Group Action - - [Kyber](https://pq-crystals.org/kyber/) KEM: modes 512, 768, 1024 - - [FrodoKEM](https://frodokem.org/) KEM: modes 640-SHAKE - - (**insecure, deprecated**) [SIDH/SIKE](https://sike.org/): Supersingular Key Encapsulation with primes p434, p503, p751 +| Digital Signature Schemes | +|:---:| -#### Post-Quantum Public-Key Encryption - - [Kyber](https://pq-crystals.org/kyber/) PKE: modes 512, 768, 1024 +- [Ed25519](./sign/ed25519) and [Ed448](./sign/ed448) signatures. ([RFC-8032]) -#### Post-Quantum Digital Signature Schemes - - [Dilithium](https://pq-crystals.org/dilithium/): modes 2, 3, 5 +| Prime Groups | +|:---:| -#### Field Arithmetic - - Fp25519, Fp448, Fp381 + - [P-256, P-384, P-521](./group). ([FIPS 186-5]) + - [Ristretto](./group) group. ([RFC-9496]) + - [Bilinear pairings](./ecc/bls12381): with the [BLS12-381] curve, and hash to G1 and G2. + - [Hash to curve](./group), hash to field, XMD and XOF [expanders](./expander). ([RFC-9380]) + +| High-Level Protocols | +|:---:| + + - [HPKE](./hpke): Hybrid Public-Key Encryption ([RFC-9180]) + - [VOPRF](./oprf): Verifiable Oblivious Pseudorandom functions. ([RFC-9497]) + - [RSA Blind Signatures](./blindsign/blindrsa). ([RFC-9474]) + - [Partilly-blind](./blindsign/blindrsa/partiallyblindrsa/) Signatures. ([draft-cfrg-partially-blind-rsa](https://datatracker.ietf.org/doc/draft-amjad-cfrg-partially-blind-rsa/)) + - [CPABE](./abe/cpabe): Ciphertext-Policy Attribute-Based Encryption. ([ia.cr/2019/966]) + - [OT](./ot/simot): Simplest Oblivious Transfer ([ia.cr/2015/267]). + - [Threshold RSA](./tss/rsa) Signatures ([Shoup Eurocrypt 2000](https://www.iacr.org/archive/eurocrypt2000/1807/18070209-new.pdf)). + +### Post-Quantum Cryptography + +| KEM: Key Encapsulation Methods | +|:---:| + + - [CSIDH](./dh/csidh): Post-Quantum Commutative Group Action ([CSIDH](https://csidh.isogeny.org/)). + - [Kyber KEM](./kem/kyber): modes 512, 768, 1024 ([KYBER](https://pq-crystals.org/kyber/)). + - [FrodoKEM](./kem/frodo): modes 640-SHAKE. ([FrodoKEM](https://frodokem.org/)) + - (**insecure, deprecated**) ~~[SIDH/SIKE](./kem/sike)~~: Supersingular Key Encapsulation with primes p434, p503, p751 ([SIKE](https://sike.org/)). + +| Digital Signature Schemes | +|:---:| + + - [Dilithium](./sign/dilithium): modes 2, 3, 5 ([Dilithium](https://pq-crystals.org/dilithium/)). + +### Zero-knowledge Proofs + + - [Schnorr](./zk/dl): Prove knowledge of the Discrete Logarithm. ([RFC-8235]) + - [DLEQ](./zk/dleq): Prove knowledge of the Discrete Logarithm Equality. ([RFC-9497]) -#### Elliptic Curves - - P-384 Curve - - [FourQ](https://eprint.iacr.org/2015/565) - - [Goldilocks](https://eprint.iacr.org/2015/625) - - [BLS12-381](https://electriccoin.co/blog/new-snark-curve/): Bilinear pairings, hash to G1 and G2. -#### Parallel SIMD - - [Keccak](https://keccak.team/keccak_specs_summary.html) f1600 Permutation +### Symmetric Cryptography -#### XOF: eXtendable Output Functions - - [FIPS 202](https://doi.org/10.6028/NIST.FIPS.202): SHAKE128 and SHAKE256 - - [BLAKE2X](https://www.blake2.net/blake2x.pdf): BLAKE2XB and BLAKE2XS - - [KangarooTwelve](https://keccak.team/kangarootwelve.html): KangarooTwelve +| XOF: eXtendable Output Functions | +|:---:| -#### Zero-knowledge Proofs - - [Schnorr](./zk/dl): Prove knowledge of the Discrete Logarithm. - - [DLEQ](./zk/dleq): Prove knowledge of the Discrete Logarithm Equality. + - [SHAKE128 and SHAKE256](./xof) ([FIPS 202]). + - [BLAKE2X](./xof): BLAKE2XB and BLAKE2XS ([Blake2x](https://www.blake2.net/blake2x.pdf)) + - [KangarooTwelve](./xof/k12): fast hashing based on Keccak-p. ([KangarooTwelve](https://keccak.team/kangarootwelve.html)). + - SIMD [Keccak](https://keccak.team/keccak_specs_summary.html) f1600 Permutation. + +| LWC: Lightweight Cryptography | +|:---:| + +- [Ascon v1.2](./cipher/ascon): Family of AEAD block ciphers ([ASCON](https://ascon.iaik.tugraz.at/index.html)) + +### Misc + +| Integers | +|:---:| + +- Safe primes generation. +- Integer encoding: wNAF, regular signed digit, mLSBSet representations. + +| Finite Fields | +|:---:| + + - Fp25519, Fp448, Fp511, Fp434, Fp503, Fp751. + - Fp381, and its quadratic, sextic and twelveth extensions. + - Polynomials in monomial and Lagrange basis. + +| Elliptic Curves | +|:---:| + + - P-384 Curve + - [FourQ](https://eprint.iacr.org/2015/565) + - [Goldilocks](https://eprint.iacr.org/2015/625) + - [BLS12-381](https://electriccoin.co/blog/new-snark-curve/) ## Testing and Benchmarking @@ -105,7 +159,7 @@ APA Style ``` Faz-Hernández, A. and Kwiatkowski, K. (2019). Introducing CIRCL: An Advanced Cryptographic Library. Cloudflare. Available at -https://github.com/cloudflare/circl. v1.3.3 Accessed May, 2023. +https://github.com/cloudflare/circl. v1.3.6 Accessed Oct, 2023. ``` Bibtex Source @@ -120,7 +174,7 @@ Bibtex Source of this library is to be used as a tool for experimental deployment of cryptographic algorithms targeting Post-Quantum (PQ) and Elliptic Curve Cryptography (ECC).}}, - note = {Available at \url{https://github.com/cloudflare/circl}. v1.3.3 Accessed May, 2023}, + note = {Available at \url{https://github.com/cloudflare/circl}. v1.3.6 Accessed Oct, 2023}, month = jun, year = {2019} } From 899732a43256a5d6fb779917f597b32939ca4ba4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 00:08:14 +0000 Subject: [PATCH 45/47] build(deps): bump golang.org/x/crypto Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.3.1-0.20221117191849-2c476679df9a to 0.17.0. - [Commits](https://github.com/golang/crypto/commits/v0.17.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 3c9038c26..b172460a3 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,6 @@ go 1.19 require ( github.com/bwesterb/go-ristretto v1.2.3 - golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a - golang.org/x/sys v0.3.0 + golang.org/x/crypto v0.17.0 + golang.org/x/sys v0.15.0 ) diff --git a/go.sum b/go.sum index e48cb252d..a328e6986 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,6 @@ github.com/bwesterb/go-ristretto v1.2.3 h1:1w53tCkGhCQ5djbat3+MH0BAQ5Kfgbt56UZQ/JMzngw= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= -golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a h1:diz9pEYuTIuLMJLs3rGDkeaTsNyRs6duYdFyPAxzE/U= -golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= From 75ef91e8a2f438e6ce2b6e620d236add8be1887d Mon Sep 17 00:00:00 2001 From: Bas Westerbaan Date: Sat, 30 Dec 2023 13:47:10 +0100 Subject: [PATCH 46/47] kyber: remove division by q in ciphertext compression On some platforms, division by q leaks some information on the ciphertext by its timing. If a keypair is reused, and an attacker has access to a decapsulation oracle, this reveals information on the private key. This is known as "kyberslash2". Note that this does not affect to the typical ephemeral usage in TLS. --- pke/kyber/internal/common/poly.go | 28 ++++--- pke/kyber/internal/common/poly_test.go | 105 +++++++++++++++++++++++++ 2 files changed, 123 insertions(+), 10 deletions(-) diff --git a/pke/kyber/internal/common/poly.go b/pke/kyber/internal/common/poly.go index d72f35d36..f580e9150 100644 --- a/pke/kyber/internal/common/poly.go +++ b/pke/kyber/internal/common/poly.go @@ -166,7 +166,7 @@ func (p *Poly) CompressMessageTo(m []byte) { // Set p to Decompress_q(m, 1). // -// Assumes d is in {3, 4, 5, 10, 11}. p will be normalized. +// Assumes d is in {4, 5, 10, 11}. p will be normalized. func (p *Poly) Decompress(m []byte, d int) { // Decompress_q(x, d) = ⌈(q/2ᵈ)x⌋ // = ⌊(q/2ᵈ)x+½⌋ @@ -244,20 +244,28 @@ func (p *Poly) Decompress(m []byte, d int) { // Writes Compress_q(p, d) to m. // -// Assumes p is normalized and d is in {3, 4, 5, 10, 11}. +// Assumes p is normalized and d is in {4, 5, 10, 11}. func (p *Poly) CompressTo(m []byte, d int) { // Compress_q(x, d) = ⌈(2ᵈ/q)x⌋ mod⁺ 2ᵈ // = ⌊(2ᵈ/q)x+½⌋ mod⁺ 2ᵈ // = ⌊((x << d) + q/2) / q⌋ mod⁺ 2ᵈ // = DIV((x << d) + q/2, q) & ((1<>e, where a/(2^e) ≈ 1/q. + // For d in {10,11} we use 20,642,679/2^36, which computes division by x/q + // correctly for 0 ≤ x < 41,522,616, which fits (q << 11) + q/2 comfortably. + // For d in {4,5} we use 315/2^20, which doesn't compute division by x/q + // correctly for all inputs, but it's close enough that the end result + // of the compression is correct. The advantage is that we do not need + // to use a 64-bit intermediate value. switch d { case 4: var t [8]uint16 idx := 0 for i := 0; i < N/8; i++ { for j := 0; j < 8; j++ { - t[j] = uint16(((uint32(p[8*i+j])<<4)+uint32(Q)/2)/ - uint32(Q)) & ((1 << 4) - 1) + t[j] = uint16((((uint32(p[8*i+j])<<4)+uint32(Q)/2)*315)>> + 20) & ((1 << 4) - 1) } m[idx] = byte(t[0]) | byte(t[1]<<4) m[idx+1] = byte(t[2]) | byte(t[3]<<4) @@ -271,8 +279,8 @@ func (p *Poly) CompressTo(m []byte, d int) { idx := 0 for i := 0; i < N/8; i++ { for j := 0; j < 8; j++ { - t[j] = uint16(((uint32(p[8*i+j])<<5)+uint32(Q)/2)/ - uint32(Q)) & ((1 << 5) - 1) + t[j] = uint16((((uint32(p[8*i+j])<<5)+uint32(Q)/2)*315)>> + 20) & ((1 << 5) - 1) } m[idx] = byte(t[0]) | byte(t[1]<<5) m[idx+1] = byte(t[1]>>3) | byte(t[2]<<2) | byte(t[3]<<7) @@ -287,8 +295,8 @@ func (p *Poly) CompressTo(m []byte, d int) { idx := 0 for i := 0; i < N/4; i++ { for j := 0; j < 4; j++ { - t[j] = uint16(((uint32(p[4*i+j])<<10)+uint32(Q)/2)/ - uint32(Q)) & ((1 << 10) - 1) + t[j] = uint16((uint64((uint32(p[4*i+j])<<10)+uint32(Q)/2)* + 20642679)>>36) & ((1 << 10) - 1) } m[idx] = byte(t[0]) m[idx+1] = byte(t[0]>>8) | byte(t[1]<<2) @@ -302,8 +310,8 @@ func (p *Poly) CompressTo(m []byte, d int) { idx := 0 for i := 0; i < N/8; i++ { for j := 0; j < 8; j++ { - t[j] = uint16(((uint32(p[8*i+j])<<11)+uint32(Q)/2)/ - uint32(Q)) & ((1 << 11) - 1) + t[j] = uint16((uint64((uint32(p[8*i+j])<<11)+uint32(Q)/2)* + 20642679)>>36) & ((1 << 11) - 1) } m[idx] = byte(t[0]) m[idx+1] = byte(t[0]>>8) | byte(t[1]<<3) diff --git a/pke/kyber/internal/common/poly_test.go b/pke/kyber/internal/common/poly_test.go index fcce5fa78..350bef961 100644 --- a/pke/kyber/internal/common/poly_test.go +++ b/pke/kyber/internal/common/poly_test.go @@ -1,6 +1,7 @@ package common import ( + "bytes" "crypto/rand" "fmt" "testing" @@ -273,3 +274,107 @@ func TestNormalizeAgainstGeneric(t *testing.T) { } } } + +func (p *Poly) OldCompressTo(m []byte, d int) { + switch d { + case 4: + var t [8]uint16 + idx := 0 + for i := 0; i < N/8; i++ { + for j := 0; j < 8; j++ { + t[j] = uint16(((uint32(p[8*i+j])<<4)+uint32(Q)/2)/ + uint32(Q)) & ((1 << 4) - 1) + } + m[idx] = byte(t[0]) | byte(t[1]<<4) + m[idx+1] = byte(t[2]) | byte(t[3]<<4) + m[idx+2] = byte(t[4]) | byte(t[5]<<4) + m[idx+3] = byte(t[6]) | byte(t[7]<<4) + idx += 4 + } + + case 5: + var t [8]uint16 + idx := 0 + for i := 0; i < N/8; i++ { + for j := 0; j < 8; j++ { + t[j] = uint16(((uint32(p[8*i+j])<<5)+uint32(Q)/2)/ + uint32(Q)) & ((1 << 5) - 1) + } + m[idx] = byte(t[0]) | byte(t[1]<<5) + m[idx+1] = byte(t[1]>>3) | byte(t[2]<<2) | byte(t[3]<<7) + m[idx+2] = byte(t[3]>>1) | byte(t[4]<<4) + m[idx+3] = byte(t[4]>>4) | byte(t[5]<<1) | byte(t[6]<<6) + m[idx+4] = byte(t[6]>>2) | byte(t[7]<<3) + idx += 5 + } + + case 10: + var t [4]uint16 + idx := 0 + for i := 0; i < N/4; i++ { + for j := 0; j < 4; j++ { + t[j] = uint16(((uint32(p[4*i+j])<<10)+uint32(Q)/2)/ + uint32(Q)) & ((1 << 10) - 1) + } + m[idx] = byte(t[0]) + m[idx+1] = byte(t[0]>>8) | byte(t[1]<<2) + m[idx+2] = byte(t[1]>>6) | byte(t[2]<<4) + m[idx+3] = byte(t[2]>>4) | byte(t[3]<<6) + m[idx+4] = byte(t[3] >> 2) + idx += 5 + } + case 11: + var t [8]uint16 + idx := 0 + for i := 0; i < N/8; i++ { + for j := 0; j < 8; j++ { + t[j] = uint16(((uint32(p[8*i+j])<<11)+uint32(Q)/2)/ + uint32(Q)) & ((1 << 11) - 1) + } + m[idx] = byte(t[0]) + m[idx+1] = byte(t[0]>>8) | byte(t[1]<<3) + m[idx+2] = byte(t[1]>>5) | byte(t[2]<<6) + m[idx+3] = byte(t[2] >> 2) + m[idx+4] = byte(t[2]>>10) | byte(t[3]<<1) + m[idx+5] = byte(t[3]>>7) | byte(t[4]<<4) + m[idx+6] = byte(t[4]>>4) | byte(t[5]<<7) + m[idx+7] = byte(t[5] >> 1) + m[idx+8] = byte(t[5]>>9) | byte(t[6]<<2) + m[idx+9] = byte(t[6]>>6) | byte(t[7]<<5) + m[idx+10] = byte(t[7] >> 3) + idx += 11 + } + default: + panic("unsupported d") + } +} + +func TestCompressFullInputFirstCoeff(t *testing.T) { + for _, d := range []int{4, 5, 10, 11} { + d := d + t.Run(fmt.Sprintf("d=%d", d), func(t *testing.T) { + var p, q Poly + bound := (Q + (1 << uint(d))) >> uint(d+1) + buf := make([]byte, (N*d-1)/8+1) + buf2 := make([]byte, len(buf)) + for i := int16(0); i < Q; i++ { + p[0] = i + p.CompressTo(buf, d) + p.OldCompressTo(buf2, d) + if !bytes.Equal(buf, buf2) { + t.Fatalf("%d", i) + } + q.Decompress(buf, d) + diff := sModQ(p[0] - q[0]) + if diff < 0 { + diff = -diff + } + if diff > bound { + t.Logf("%v\n", buf) + t.Fatalf("|%d - %d mod^± q| = %d > %d", + p[0], q[0], diff, bound) + } + } + }) + } +} From c48866b3068dfa83721c021dec03c777ba91abab Mon Sep 17 00:00:00 2001 From: armfazh Date: Sun, 31 Dec 2023 21:20:43 -0800 Subject: [PATCH 47/47] Releasing CIRCL v1.3.7 --- CITATION.cff | 4 ++-- README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index 35616cbbe..53c96566b 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,6 +1,6 @@ --- cff-version: 1.2.0 -version: 1.3.6 +version: 1.3.7 title: "Introducing CIRCL: An Advanced Cryptographic Library" license: BSD-3-Clause abstract: > @@ -25,6 +25,6 @@ keywords: - golang repository-code: "https://github.com/cloudflare/circl/" type: software -message: "Available at https://github.com/cloudflare/circl. v1.3.6 Accessed Oct, 2023." +message: "Available at https://github.com/cloudflare/circl. v1.3.7 Accessed Dec, 2023." contact: - name: "Cloudflare, Inc." diff --git a/README.md b/README.md index 4d8c9984b..1f24168ad 100644 --- a/README.md +++ b/README.md @@ -159,7 +159,7 @@ APA Style ``` Faz-Hernández, A. and Kwiatkowski, K. (2019). Introducing CIRCL: An Advanced Cryptographic Library. Cloudflare. Available at -https://github.com/cloudflare/circl. v1.3.6 Accessed Oct, 2023. +https://github.com/cloudflare/circl. v1.3.7 Accessed Dec, 2023. ``` Bibtex Source @@ -174,7 +174,7 @@ Bibtex Source of this library is to be used as a tool for experimental deployment of cryptographic algorithms targeting Post-Quantum (PQ) and Elliptic Curve Cryptography (ECC).}}, - note = {Available at \url{https://github.com/cloudflare/circl}. v1.3.6 Accessed Oct, 2023}, + note = {Available at \url{https://github.com/cloudflare/circl}. v1.3.7 Accessed Dec, 2023}, month = jun, year = {2019} }