mirror of
https://github.com/owncloud/ocis
synced 2026-04-25 17:25:21 +02:00
* chore(deps): bump @testing-library/jest-dom in /services/idp
Bumps [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) from 6.6.4 to 6.9.1.
- [Release notes](https://github.com/testing-library/jest-dom/releases)
- [Changelog](https://github.com/testing-library/jest-dom/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/jest-dom/compare/v6.6.4...v6.9.1)
---
updated-dependencies:
- dependency-name: "@testing-library/jest-dom"
dependency-version: 6.9.1
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
* chore(deps): bump filippo.io/edwards25519 from 1.1.0 to 1.1.1
Bumps [filippo.io/edwards25519](https://github.com/FiloSottile/edwards25519) from 1.1.0 to 1.1.1.
- [Commits](https://github.com/FiloSottile/edwards25519/compare/v1.1.0...v1.1.1)
---
updated-dependencies:
- dependency-name: filippo.io/edwards25519
dependency-version: 1.1.1
dependency-type: indirect
...
Signed-off-by: dependabot[bot] <support@github.com>
* Merge branch 'master' into dependabot/go_modules/github.com/russellhaering/goxmldsig-1.6.0
* build(deps): bump alpine from 3.23.3 to 3.23.4
Bumps alpine from 3.23.3 to 3.23.4.
---
updated-dependencies:
- dependency-name: alpine
dependency-version: 3.23.4
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot] <support@github.com>
* build(deps): bump arm64v8/alpine from 3.23.3 to 3.23.4 in /ocis/docker
Bumps arm64v8/alpine from 3.23.3 to 3.23.4.
---
updated-dependencies:
- dependency-name: arm64v8/alpine
dependency-version: 3.23.4
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot] <support@github.com>
* build(deps): bump actions/cache from 5.0.4 to 5.0.5
Bumps [actions/cache](https://github.com/actions/cache) from 5.0.4 to 5.0.5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](668228422a...27d5ce7f10)
---
updated-dependencies:
- dependency-name: actions/cache
dependency-version: 5.0.5
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot] <support@github.com>
* build(deps): bump github.com/go-acme/lego/v4 from 4.25.2 to 4.34.0
Bumps [github.com/go-acme/lego/v4](https://github.com/go-acme/lego) from 4.25.2 to 4.34.0.
- [Release notes](https://github.com/go-acme/lego/releases)
- [Changelog](https://github.com/go-acme/lego/blob/master/CHANGELOG.md)
- [Commits](https://github.com/go-acme/lego/compare/v4.25.2...v4.34.0)
---
updated-dependencies:
- dependency-name: github.com/go-acme/lego/v4
dependency-version: 4.34.0
dependency-type: indirect
...
Signed-off-by: dependabot[bot] <support@github.com>
* build(deps): bump github.com/go-git/go-git/v5 from 5.17.1 to 5.18.0
Bumps [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) from 5.17.1 to 5.18.0.
- [Release notes](https://github.com/go-git/go-git/releases)
- [Commits](https://github.com/go-git/go-git/compare/v5.17.1...v5.18.0)
---
updated-dependencies:
- dependency-name: github.com/go-git/go-git/v5
dependency-version: 5.18.0
dependency-type: indirect
...
Signed-off-by: dependabot[bot] <support@github.com>
* chore: regenerate pnpm-lock.yaml
* fix(ci): replace nc-based fakeoffice with Python HTTP server
BusyBox nc -k restarts between connections leaving a gap where the
collaboration service gets ECONNRESET at startup, so healthz never
binds and the 300s wait times out. Python HTTPServer is gap-free.
---------
Signed-off-by: dependabot[bot] <support@github.com>
351 lines
10 KiB
Go
351 lines
10 KiB
Go
// Copyright (c) 2021 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package edwards25519
|
|
|
|
// This file contains additional functionality that is not included in the
|
|
// upstream crypto/internal/edwards25519 package.
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"filippo.io/edwards25519/field"
|
|
)
|
|
|
|
// ExtendedCoordinates returns v in extended coordinates (X:Y:Z:T) where
|
|
// x = X/Z, y = Y/Z, and xy = T/Z as in https://eprint.iacr.org/2008/522.
|
|
func (v *Point) ExtendedCoordinates() (X, Y, Z, T *field.Element) {
|
|
// This function is outlined to make the allocations inline in the caller
|
|
// rather than happen on the heap. Don't change the style without making
|
|
// sure it doesn't increase the inliner cost.
|
|
var e [4]field.Element
|
|
X, Y, Z, T = v.extendedCoordinates(&e)
|
|
return
|
|
}
|
|
|
|
func (v *Point) extendedCoordinates(e *[4]field.Element) (X, Y, Z, T *field.Element) {
|
|
checkInitialized(v)
|
|
X = e[0].Set(&v.x)
|
|
Y = e[1].Set(&v.y)
|
|
Z = e[2].Set(&v.z)
|
|
T = e[3].Set(&v.t)
|
|
return
|
|
}
|
|
|
|
// SetExtendedCoordinates sets v = (X:Y:Z:T) in extended coordinates where
|
|
// x = X/Z, y = Y/Z, and xy = T/Z as in https://eprint.iacr.org/2008/522.
|
|
//
|
|
// If the coordinates are invalid or don't represent a valid point on the curve,
|
|
// SetExtendedCoordinates returns nil and an error and the receiver is
|
|
// unchanged. Otherwise, SetExtendedCoordinates returns v.
|
|
func (v *Point) SetExtendedCoordinates(X, Y, Z, T *field.Element) (*Point, error) {
|
|
if !isOnCurve(X, Y, Z, T) {
|
|
return nil, errors.New("edwards25519: invalid point coordinates")
|
|
}
|
|
v.x.Set(X)
|
|
v.y.Set(Y)
|
|
v.z.Set(Z)
|
|
v.t.Set(T)
|
|
return v, nil
|
|
}
|
|
|
|
func isOnCurve(X, Y, Z, T *field.Element) bool {
|
|
var lhs, rhs field.Element
|
|
XX := new(field.Element).Square(X)
|
|
YY := new(field.Element).Square(Y)
|
|
ZZ := new(field.Element).Square(Z)
|
|
TT := new(field.Element).Square(T)
|
|
// -x² + y² = 1 + dx²y²
|
|
// -(X/Z)² + (Y/Z)² = 1 + d(T/Z)²
|
|
// -X² + Y² = Z² + dT²
|
|
lhs.Subtract(YY, XX)
|
|
rhs.Multiply(d, TT).Add(&rhs, ZZ)
|
|
if lhs.Equal(&rhs) != 1 {
|
|
return false
|
|
}
|
|
// xy = T/Z
|
|
// XY/Z² = T/Z
|
|
// XY = TZ
|
|
lhs.Multiply(X, Y)
|
|
rhs.Multiply(T, Z)
|
|
return lhs.Equal(&rhs) == 1
|
|
}
|
|
|
|
// BytesMontgomery converts v to a point on the birationally-equivalent
|
|
// Curve25519 Montgomery curve, and returns its canonical 32 bytes encoding
|
|
// according to RFC 7748.
|
|
//
|
|
// Note that BytesMontgomery only encodes the u-coordinate, so v and -v encode
|
|
// to the same value. If v is the identity point, BytesMontgomery returns 32
|
|
// zero bytes, analogously to the X25519 function.
|
|
//
|
|
// The lack of an inverse operation (such as SetMontgomeryBytes) is deliberate:
|
|
// while every valid edwards25519 point has a unique u-coordinate Montgomery
|
|
// encoding, X25519 accepts inputs on the quadratic twist, which don't correspond
|
|
// to any edwards25519 point, and every other X25519 input corresponds to two
|
|
// edwards25519 points.
|
|
func (v *Point) BytesMontgomery() []byte {
|
|
// This function is outlined to make the allocations inline in the caller
|
|
// rather than happen on the heap.
|
|
var buf [32]byte
|
|
return v.bytesMontgomery(&buf)
|
|
}
|
|
|
|
func (v *Point) bytesMontgomery(buf *[32]byte) []byte {
|
|
checkInitialized(v)
|
|
|
|
// RFC 7748, Section 4.1 provides the bilinear map to calculate the
|
|
// Montgomery u-coordinate
|
|
//
|
|
// u = (1 + y) / (1 - y)
|
|
//
|
|
// where y = Y / Z.
|
|
|
|
var y, recip, u field.Element
|
|
|
|
y.Multiply(&v.y, y.Invert(&v.z)) // y = Y / Z
|
|
recip.Invert(recip.Subtract(feOne, &y)) // r = 1/(1 - y)
|
|
u.Multiply(u.Add(feOne, &y), &recip) // u = (1 + y)*r
|
|
|
|
return copyFieldElement(buf, &u)
|
|
}
|
|
|
|
// MultByCofactor sets v = 8 * p, and returns v.
|
|
func (v *Point) MultByCofactor(p *Point) *Point {
|
|
checkInitialized(p)
|
|
result := projP1xP1{}
|
|
pp := (&projP2{}).FromP3(p)
|
|
result.Double(pp)
|
|
pp.FromP1xP1(&result)
|
|
result.Double(pp)
|
|
pp.FromP1xP1(&result)
|
|
result.Double(pp)
|
|
return v.fromP1xP1(&result)
|
|
}
|
|
|
|
// Given k > 0, set s = s**(2*i).
|
|
func (s *Scalar) pow2k(k int) {
|
|
for i := 0; i < k; i++ {
|
|
s.Multiply(s, s)
|
|
}
|
|
}
|
|
|
|
// Invert sets s to the inverse of a nonzero scalar v, and returns s.
|
|
//
|
|
// If t is zero, Invert returns zero.
|
|
func (s *Scalar) Invert(t *Scalar) *Scalar {
|
|
// Uses a hardcoded sliding window of width 4.
|
|
var table [8]Scalar
|
|
var tt Scalar
|
|
tt.Multiply(t, t)
|
|
table[0] = *t
|
|
for i := 0; i < 7; i++ {
|
|
table[i+1].Multiply(&table[i], &tt)
|
|
}
|
|
// Now table = [t**1, t**3, t**5, t**7, t**9, t**11, t**13, t**15]
|
|
// so t**k = t[k/2] for odd k
|
|
|
|
// To compute the sliding window digits, use the following Sage script:
|
|
|
|
// sage: import itertools
|
|
// sage: def sliding_window(w,k):
|
|
// ....: digits = []
|
|
// ....: while k > 0:
|
|
// ....: if k % 2 == 1:
|
|
// ....: kmod = k % (2**w)
|
|
// ....: digits.append(kmod)
|
|
// ....: k = k - kmod
|
|
// ....: else:
|
|
// ....: digits.append(0)
|
|
// ....: k = k // 2
|
|
// ....: return digits
|
|
|
|
// Now we can compute s roughly as follows:
|
|
|
|
// sage: s = 1
|
|
// sage: for coeff in reversed(sliding_window(4,l-2)):
|
|
// ....: s = s*s
|
|
// ....: if coeff > 0 :
|
|
// ....: s = s*t**coeff
|
|
|
|
// This works on one bit at a time, with many runs of zeros.
|
|
// The digits can be collapsed into [(count, coeff)] as follows:
|
|
|
|
// sage: [(len(list(group)),d) for d,group in itertools.groupby(sliding_window(4,l-2))]
|
|
|
|
// Entries of the form (k, 0) turn into pow2k(k)
|
|
// Entries of the form (1, coeff) turn into a squaring and then a table lookup.
|
|
// We can fold the squaring into the previous pow2k(k) as pow2k(k+1).
|
|
|
|
*s = table[1/2]
|
|
s.pow2k(127 + 1)
|
|
s.Multiply(s, &table[1/2])
|
|
s.pow2k(4 + 1)
|
|
s.Multiply(s, &table[9/2])
|
|
s.pow2k(3 + 1)
|
|
s.Multiply(s, &table[11/2])
|
|
s.pow2k(3 + 1)
|
|
s.Multiply(s, &table[13/2])
|
|
s.pow2k(3 + 1)
|
|
s.Multiply(s, &table[15/2])
|
|
s.pow2k(4 + 1)
|
|
s.Multiply(s, &table[7/2])
|
|
s.pow2k(4 + 1)
|
|
s.Multiply(s, &table[15/2])
|
|
s.pow2k(3 + 1)
|
|
s.Multiply(s, &table[5/2])
|
|
s.pow2k(3 + 1)
|
|
s.Multiply(s, &table[1/2])
|
|
s.pow2k(4 + 1)
|
|
s.Multiply(s, &table[15/2])
|
|
s.pow2k(4 + 1)
|
|
s.Multiply(s, &table[15/2])
|
|
s.pow2k(4 + 1)
|
|
s.Multiply(s, &table[7/2])
|
|
s.pow2k(3 + 1)
|
|
s.Multiply(s, &table[3/2])
|
|
s.pow2k(4 + 1)
|
|
s.Multiply(s, &table[11/2])
|
|
s.pow2k(5 + 1)
|
|
s.Multiply(s, &table[11/2])
|
|
s.pow2k(9 + 1)
|
|
s.Multiply(s, &table[9/2])
|
|
s.pow2k(3 + 1)
|
|
s.Multiply(s, &table[3/2])
|
|
s.pow2k(4 + 1)
|
|
s.Multiply(s, &table[3/2])
|
|
s.pow2k(4 + 1)
|
|
s.Multiply(s, &table[3/2])
|
|
s.pow2k(4 + 1)
|
|
s.Multiply(s, &table[9/2])
|
|
s.pow2k(3 + 1)
|
|
s.Multiply(s, &table[7/2])
|
|
s.pow2k(3 + 1)
|
|
s.Multiply(s, &table[3/2])
|
|
s.pow2k(3 + 1)
|
|
s.Multiply(s, &table[13/2])
|
|
s.pow2k(3 + 1)
|
|
s.Multiply(s, &table[7/2])
|
|
s.pow2k(4 + 1)
|
|
s.Multiply(s, &table[9/2])
|
|
s.pow2k(3 + 1)
|
|
s.Multiply(s, &table[15/2])
|
|
s.pow2k(4 + 1)
|
|
s.Multiply(s, &table[11/2])
|
|
|
|
return s
|
|
}
|
|
|
|
// MultiScalarMult sets v = sum(scalars[i] * points[i]), and returns v.
|
|
//
|
|
// Execution time depends only on the lengths of the two slices, which must match.
|
|
func (v *Point) MultiScalarMult(scalars []*Scalar, points []*Point) *Point {
|
|
if len(scalars) != len(points) {
|
|
panic("edwards25519: called MultiScalarMult with different size inputs")
|
|
}
|
|
checkInitialized(points...)
|
|
|
|
// Proceed as in the single-base case, but share doublings
|
|
// between each point in the multiscalar equation.
|
|
|
|
// Build lookup tables for each point
|
|
tables := make([]projLookupTable, len(points))
|
|
for i := range tables {
|
|
tables[i].FromP3(points[i])
|
|
}
|
|
// Compute signed radix-16 digits for each scalar
|
|
digits := make([][64]int8, len(scalars))
|
|
for i := range digits {
|
|
digits[i] = scalars[i].signedRadix16()
|
|
}
|
|
|
|
// Unwrap first loop iteration to save computing 16*identity
|
|
multiple := &projCached{}
|
|
tmp1 := &projP1xP1{}
|
|
tmp2 := &projP2{}
|
|
// Lookup-and-add the appropriate multiple of each input point
|
|
v.Set(NewIdentityPoint())
|
|
for j := range tables {
|
|
tables[j].SelectInto(multiple, digits[j][63])
|
|
tmp1.Add(v, multiple) // tmp1 = v + x_(j,63)*Q in P1xP1 coords
|
|
v.fromP1xP1(tmp1) // update v
|
|
}
|
|
tmp2.FromP3(v) // set up tmp2 = v in P2 coords for next iteration
|
|
for i := 62; i >= 0; i-- {
|
|
tmp1.Double(tmp2) // tmp1 = 2*(prev) in P1xP1 coords
|
|
tmp2.FromP1xP1(tmp1) // tmp2 = 2*(prev) in P2 coords
|
|
tmp1.Double(tmp2) // tmp1 = 4*(prev) in P1xP1 coords
|
|
tmp2.FromP1xP1(tmp1) // tmp2 = 4*(prev) in P2 coords
|
|
tmp1.Double(tmp2) // tmp1 = 8*(prev) in P1xP1 coords
|
|
tmp2.FromP1xP1(tmp1) // tmp2 = 8*(prev) in P2 coords
|
|
tmp1.Double(tmp2) // tmp1 = 16*(prev) in P1xP1 coords
|
|
v.fromP1xP1(tmp1) // v = 16*(prev) in P3 coords
|
|
// Lookup-and-add the appropriate multiple of each input point
|
|
for j := range tables {
|
|
tables[j].SelectInto(multiple, digits[j][i])
|
|
tmp1.Add(v, multiple) // tmp1 = v + x_(j,i)*Q in P1xP1 coords
|
|
v.fromP1xP1(tmp1) // update v
|
|
}
|
|
tmp2.FromP3(v) // set up tmp2 = v in P2 coords for next iteration
|
|
}
|
|
return v
|
|
}
|
|
|
|
// VarTimeMultiScalarMult sets v = sum(scalars[i] * points[i]), and returns v.
|
|
//
|
|
// Execution time depends on the inputs.
|
|
func (v *Point) VarTimeMultiScalarMult(scalars []*Scalar, points []*Point) *Point {
|
|
if len(scalars) != len(points) {
|
|
panic("edwards25519: called VarTimeMultiScalarMult with different size inputs")
|
|
}
|
|
checkInitialized(points...)
|
|
|
|
// Generalize double-base NAF computation to arbitrary sizes.
|
|
// Here all the points are dynamic, so we only use the smaller
|
|
// tables.
|
|
|
|
// Build lookup tables for each point
|
|
tables := make([]nafLookupTable5, len(points))
|
|
for i := range tables {
|
|
tables[i].FromP3(points[i])
|
|
}
|
|
// Compute a NAF for each scalar
|
|
nafs := make([][256]int8, len(scalars))
|
|
for i := range nafs {
|
|
nafs[i] = scalars[i].nonAdjacentForm(5)
|
|
}
|
|
|
|
multiple := &projCached{}
|
|
tmp1 := &projP1xP1{}
|
|
tmp2 := &projP2{}
|
|
tmp2.Zero()
|
|
|
|
// Move from high to low bits, doubling the accumulator
|
|
// at each iteration and checking whether there is a nonzero
|
|
// coefficient to look up a multiple of.
|
|
//
|
|
// Skip trying to find the first nonzero coefficent, because
|
|
// searching might be more work than a few extra doublings.
|
|
for i := 255; i >= 0; i-- {
|
|
tmp1.Double(tmp2)
|
|
|
|
for j := range nafs {
|
|
if nafs[j][i] > 0 {
|
|
v.fromP1xP1(tmp1)
|
|
tables[j].SelectInto(multiple, nafs[j][i])
|
|
tmp1.Add(v, multiple)
|
|
} else if nafs[j][i] < 0 {
|
|
v.fromP1xP1(tmp1)
|
|
tables[j].SelectInto(multiple, -nafs[j][i])
|
|
tmp1.Sub(v, multiple)
|
|
}
|
|
}
|
|
|
|
tmp2.FromP1xP1(tmp1)
|
|
}
|
|
|
|
v.fromP2(tmp2)
|
|
return v
|
|
}
|