Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: cloudflare/circl
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.3.6
Choose a base ref
...
head repository: cloudflare/circl
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v1.3.7
Choose a head ref
  • 3 commits
  • 6 files changed
  • 3 contributors

Commits on Dec 19, 2023

  1. 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] <support@github.com>
    dependabot[bot] authored and armfazh committed Dec 19, 2023
    Copy the full SHA
    899732a View commit details

Commits on Jan 1, 2024

  1. 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.
    bwesterb authored and armfazh committed Jan 1, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    75ef91e View commit details
  2. Releasing CIRCL v1.3.7

    armfazh committed Jan 1, 2024
    Copy the full SHA
    c48866b View commit details
Showing with 133 additions and 20 deletions.
  1. +2 −2 CITATION.cff
  2. +2 −2 README.md
  3. +2 −2 go.mod
  4. +4 −4 go.sum
  5. +18 −10 pke/kyber/internal/common/poly.go
  6. +105 −0 pke/kyber/internal/common/poly_test.go
4 changes: 2 additions & 2 deletions CITATION.cff
Original file line number Diff line number Diff line change
@@ -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."
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -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}
}
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -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
)
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -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=
28 changes: 18 additions & 10 deletions pke/kyber/internal/common/poly.go
Original file line number Diff line number Diff line change
@@ -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<<d) - 1)
//
// We approximate DIV(x, q) by computing (x*a)>>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)
105 changes: 105 additions & 0 deletions pke/kyber/internal/common/poly_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
})
}
}