mirror of
https://github.com/onsonr/sonr.git
synced 2025-03-10 13:07:09 +00:00
(no commit message provided)
This commit is contained in:
parent
5fd43dfd6b
commit
2f976209db
@ -1,15 +0,0 @@
|
||||
FROM jetpackio/devbox:latest
|
||||
|
||||
# Installing your devbox project
|
||||
WORKDIR /code
|
||||
USER root:root
|
||||
RUN mkdir -p /code && chown ${DEVBOX_USER}:${DEVBOX_USER} /code
|
||||
USER ${DEVBOX_USER}:${DEVBOX_USER}
|
||||
COPY --chown=${DEVBOX_USER}:${DEVBOX_USER} devbox.json devbox.json
|
||||
COPY --chown=${DEVBOX_USER}:${DEVBOX_USER} devbox.lock devbox.lock
|
||||
|
||||
|
||||
|
||||
RUN devbox run -- echo "Installed Packages."
|
||||
|
||||
RUN devbox shellenv --init-hook >> ~/.profile
|
@ -1,16 +0,0 @@
|
||||
{
|
||||
"name": "Devbox Remote Container",
|
||||
"build": {
|
||||
"dockerfile": "./Dockerfile",
|
||||
"context": ".."
|
||||
},
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"settings": {},
|
||||
"extensions": [
|
||||
"jetpack-io.devbox"
|
||||
]
|
||||
}
|
||||
},
|
||||
"remoteUser": "devbox"
|
||||
}
|
@ -104,9 +104,9 @@ func (x *fastReflection_Module) Has(fd protoreflect.FieldDescriptor) bool {
|
||||
switch fd.FullName() {
|
||||
default:
|
||||
if fd.IsExtension() {
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: didao.sonr.did.module.v1.Module"))
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: onsonr.hway.did.module.v1.Module"))
|
||||
}
|
||||
panic(fmt.Errorf("message didao.sonr.did.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
panic(fmt.Errorf("message onsonr.hway.did.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,9 +120,9 @@ func (x *fastReflection_Module) Clear(fd protoreflect.FieldDescriptor) {
|
||||
switch fd.FullName() {
|
||||
default:
|
||||
if fd.IsExtension() {
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: didao.sonr.did.module.v1.Module"))
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: onsonr.hway.did.module.v1.Module"))
|
||||
}
|
||||
panic(fmt.Errorf("message didao.sonr.did.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
panic(fmt.Errorf("message onsonr.hway.did.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,9 +136,9 @@ func (x *fastReflection_Module) Get(descriptor protoreflect.FieldDescriptor) pro
|
||||
switch descriptor.FullName() {
|
||||
default:
|
||||
if descriptor.IsExtension() {
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: didao.sonr.did.module.v1.Module"))
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: onsonr.hway.did.module.v1.Module"))
|
||||
}
|
||||
panic(fmt.Errorf("message didao.sonr.did.module.v1.Module does not contain field %s", descriptor.FullName()))
|
||||
panic(fmt.Errorf("message onsonr.hway.did.module.v1.Module does not contain field %s", descriptor.FullName()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,9 +156,9 @@ func (x *fastReflection_Module) Set(fd protoreflect.FieldDescriptor, value proto
|
||||
switch fd.FullName() {
|
||||
default:
|
||||
if fd.IsExtension() {
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: didao.sonr.did.module.v1.Module"))
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: onsonr.hway.did.module.v1.Module"))
|
||||
}
|
||||
panic(fmt.Errorf("message didao.sonr.did.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
panic(fmt.Errorf("message onsonr.hway.did.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,9 +176,9 @@ func (x *fastReflection_Module) Mutable(fd protoreflect.FieldDescriptor) protore
|
||||
switch fd.FullName() {
|
||||
default:
|
||||
if fd.IsExtension() {
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: didao.sonr.did.module.v1.Module"))
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: onsonr.hway.did.module.v1.Module"))
|
||||
}
|
||||
panic(fmt.Errorf("message didao.sonr.did.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
panic(fmt.Errorf("message onsonr.hway.did.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,9 +189,9 @@ func (x *fastReflection_Module) NewField(fd protoreflect.FieldDescriptor) protor
|
||||
switch fd.FullName() {
|
||||
default:
|
||||
if fd.IsExtension() {
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: didao.sonr.did.module.v1.Module"))
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: onsonr.hway.did.module.v1.Module"))
|
||||
}
|
||||
panic(fmt.Errorf("message didao.sonr.did.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
panic(fmt.Errorf("message onsonr.hway.did.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,7 +201,7 @@ func (x *fastReflection_Module) NewField(fd protoreflect.FieldDescriptor) protor
|
||||
func (x *fastReflection_Module) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor {
|
||||
switch d.FullName() {
|
||||
default:
|
||||
panic(fmt.Errorf("%s is not a oneof field in didao.sonr.did.module.v1.Module", d.FullName()))
|
||||
panic(fmt.Errorf("%s is not a oneof field in onsonr.hway.did.module.v1.Module", d.FullName()))
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
@ -414,28 +414,29 @@ var File_did_module_v1_module_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_did_module_v1_module_proto_rawDesc = []byte{
|
||||
0x0a, 0x1a, 0x64, 0x69, 0x64, 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f,
|
||||
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x18, 0x64, 0x69,
|
||||
0x64, 0x61, 0x6f, 0x2e, 0x73, 0x6f, 0x6e, 0x72, 0x2e, 0x64, 0x69, 0x64, 0x2e, 0x6d, 0x6f, 0x64,
|
||||
0x75, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x20, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x61,
|
||||
0x70, 0x70, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x6d, 0x6f, 0x64, 0x75,
|
||||
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x28, 0x0a, 0x06, 0x4d, 0x6f, 0x64, 0x75,
|
||||
0x6c, 0x65, 0x3a, 0x1e, 0xba, 0xc0, 0x96, 0xda, 0x01, 0x18, 0x0a, 0x16, 0x67, 0x69, 0x74, 0x68,
|
||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x69, 0x2d, 0x64, 0x61, 0x6f, 0x2f, 0x73, 0x6f,
|
||||
0x6e, 0x72, 0x42, 0xe3, 0x01, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x69, 0x64, 0x61, 0x6f,
|
||||
0x2e, 0x73, 0x6f, 0x6e, 0x72, 0x2e, 0x64, 0x69, 0x64, 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
|
||||
0x2e, 0x76, 0x31, 0x42, 0x0b, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x50, 0x01, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64,
|
||||
0x69, 0x2d, 0x64, 0x61, 0x6f, 0x2f, 0x73, 0x6f, 0x6e, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64,
|
||||
0x69, 0x64, 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x6d, 0x6f, 0x64,
|
||||
0x75, 0x6c, 0x65, 0x76, 0x31, 0xa2, 0x02, 0x04, 0x44, 0x53, 0x44, 0x4d, 0xaa, 0x02, 0x18, 0x44,
|
||||
0x69, 0x64, 0x61, 0x6f, 0x2e, 0x53, 0x6f, 0x6e, 0x72, 0x2e, 0x44, 0x69, 0x64, 0x2e, 0x4d, 0x6f,
|
||||
0x64, 0x75, 0x6c, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x18, 0x44, 0x69, 0x64, 0x61, 0x6f, 0x5c,
|
||||
0x53, 0x6f, 0x6e, 0x72, 0x5c, 0x44, 0x69, 0x64, 0x5c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5c,
|
||||
0x56, 0x31, 0xe2, 0x02, 0x24, 0x44, 0x69, 0x64, 0x61, 0x6f, 0x5c, 0x53, 0x6f, 0x6e, 0x72, 0x5c,
|
||||
0x44, 0x69, 0x64, 0x5c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50,
|
||||
0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1c, 0x44, 0x69, 0x64, 0x61,
|
||||
0x6f, 0x3a, 0x3a, 0x53, 0x6f, 0x6e, 0x72, 0x3a, 0x3a, 0x44, 0x69, 0x64, 0x3a, 0x3a, 0x4d, 0x6f,
|
||||
0x64, 0x75, 0x6c, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x6f, 0x6e,
|
||||
0x73, 0x6f, 0x6e, 0x72, 0x2e, 0x68, 0x77, 0x61, 0x79, 0x2e, 0x64, 0x69, 0x64, 0x2e, 0x6d, 0x6f,
|
||||
0x64, 0x75, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x20, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f,
|
||||
0x61, 0x70, 0x70, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x6d, 0x6f, 0x64,
|
||||
0x75, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x28, 0x0a, 0x06, 0x4d, 0x6f, 0x64,
|
||||
0x75, 0x6c, 0x65, 0x3a, 0x1e, 0xba, 0xc0, 0x96, 0xda, 0x01, 0x18, 0x0a, 0x16, 0x67, 0x69, 0x74,
|
||||
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x6e, 0x73, 0x6f, 0x6e, 0x72, 0x2f, 0x68,
|
||||
0x77, 0x61, 0x79, 0x42, 0xe8, 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x6f, 0x6e, 0x73, 0x6f,
|
||||
0x6e, 0x72, 0x2e, 0x68, 0x77, 0x61, 0x79, 0x2e, 0x64, 0x69, 0x64, 0x2e, 0x6d, 0x6f, 0x64, 0x75,
|
||||
0x6c, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0b, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x50, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x2f, 0x6f, 0x6e, 0x73, 0x6f, 0x6e, 0x72, 0x2f, 0x68, 0x77, 0x61, 0x79, 0x2f, 0x61, 0x70, 0x69,
|
||||
0x2f, 0x64, 0x69, 0x64, 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x6d,
|
||||
0x6f, 0x64, 0x75, 0x6c, 0x65, 0x76, 0x31, 0xa2, 0x02, 0x04, 0x4f, 0x48, 0x44, 0x4d, 0xaa, 0x02,
|
||||
0x19, 0x4f, 0x6e, 0x73, 0x6f, 0x6e, 0x72, 0x2e, 0x48, 0x77, 0x61, 0x79, 0x2e, 0x44, 0x69, 0x64,
|
||||
0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x19, 0x4f, 0x6e, 0x73,
|
||||
0x6f, 0x6e, 0x72, 0x5c, 0x48, 0x77, 0x61, 0x79, 0x5c, 0x44, 0x69, 0x64, 0x5c, 0x4d, 0x6f, 0x64,
|
||||
0x75, 0x6c, 0x65, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x25, 0x4f, 0x6e, 0x73, 0x6f, 0x6e, 0x72, 0x5c,
|
||||
0x48, 0x77, 0x61, 0x79, 0x5c, 0x44, 0x69, 0x64, 0x5c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5c,
|
||||
0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02,
|
||||
0x1d, 0x4f, 0x6e, 0x73, 0x6f, 0x6e, 0x72, 0x3a, 0x3a, 0x48, 0x77, 0x61, 0x79, 0x3a, 0x3a, 0x44,
|
||||
0x69, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@ -452,7 +453,7 @@ func file_did_module_v1_module_proto_rawDescGZIP() []byte {
|
||||
|
||||
var file_did_module_v1_module_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_did_module_v1_module_proto_goTypes = []interface{}{
|
||||
(*Module)(nil), // 0: didao.sonr.did.module.v1.Module
|
||||
(*Module)(nil), // 0: onsonr.hway.did.module.v1.Module
|
||||
}
|
||||
var file_did_module_v1_module_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
|
@ -2454,8 +2454,8 @@ var file_did_v1_account_proto_rawDesc = []byte{
|
||||
0x79, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x7c, 0x0a, 0x0a,
|
||||
0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x69, 0x64, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x41, 0x63, 0x63, 0x6f,
|
||||
0x75, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68,
|
||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x69, 0x2d, 0x64, 0x61, 0x6f, 0x2f, 0x73, 0x6f,
|
||||
0x6e, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x69, 0x64, 0x2f, 0x76, 0x31, 0x3b, 0x64, 0x69,
|
||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x6e, 0x73, 0x6f, 0x6e, 0x72, 0x2f, 0x68, 0x77,
|
||||
0x61, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x69, 0x64, 0x2f, 0x76, 0x31, 0x3b, 0x64, 0x69,
|
||||
0x64, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x44, 0x58, 0x58, 0xaa, 0x02, 0x06, 0x44, 0x69, 0x64, 0x2e,
|
||||
0x56, 0x31, 0xca, 0x02, 0x06, 0x44, 0x69, 0x64, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x12, 0x44, 0x69,
|
||||
0x64, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
|
||||
|
@ -1892,7 +1892,7 @@ var file_did_v1_genesis_proto_rawDesc = []byte{
|
||||
0x66, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x7c, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x69, 0x64,
|
||||
0x2e, 0x76, 0x31, 0x42, 0x0c, 0x47, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x50, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x50, 0x01, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
||||
0x64, 0x69, 0x2d, 0x64, 0x61, 0x6f, 0x2f, 0x73, 0x6f, 0x6e, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f,
|
||||
0x6f, 0x6e, 0x73, 0x6f, 0x6e, 0x72, 0x2f, 0x68, 0x77, 0x61, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f,
|
||||
0x64, 0x69, 0x64, 0x2f, 0x76, 0x31, 0x3b, 0x64, 0x69, 0x64, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x44,
|
||||
0x58, 0x58, 0xaa, 0x02, 0x06, 0x44, 0x69, 0x64, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x06, 0x44, 0x69,
|
||||
0x64, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x12, 0x44, 0x69, 0x64, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50,
|
||||
|
@ -4819,7 +4819,7 @@ var file_did_v1_query_proto_rawDesc = []byte{
|
||||
0x6c, 0x65, 0x7d, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x7a, 0x0a, 0x0a, 0x63,
|
||||
0x6f, 0x6d, 0x2e, 0x64, 0x69, 0x64, 0x2e, 0x76, 0x31, 0x42, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79,
|
||||
0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x69, 0x2d, 0x64, 0x61, 0x6f, 0x2f, 0x73, 0x6f, 0x6e, 0x72, 0x2f,
|
||||
0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x6e, 0x73, 0x6f, 0x6e, 0x72, 0x2f, 0x68, 0x77, 0x61, 0x79, 0x2f,
|
||||
0x61, 0x70, 0x69, 0x2f, 0x64, 0x69, 0x64, 0x2f, 0x76, 0x31, 0x3b, 0x64, 0x69, 0x64, 0x76, 0x31,
|
||||
0xa2, 0x02, 0x03, 0x44, 0x58, 0x58, 0xaa, 0x02, 0x06, 0x44, 0x69, 0x64, 0x2e, 0x56, 0x31, 0xca,
|
||||
0x02, 0x06, 0x44, 0x69, 0x64, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x12, 0x44, 0x69, 0x64, 0x5c, 0x56,
|
||||
|
@ -3167,8 +3167,8 @@ var file_did_v1_state_proto_rawDesc = []byte{
|
||||
0x69, 0x64, 0x3a, 0x0e, 0xf2, 0x9e, 0xd3, 0x8e, 0x03, 0x08, 0x0a, 0x04, 0x0a, 0x02, 0x69, 0x64,
|
||||
0x18, 0x04, 0x42, 0x7a, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x69, 0x64, 0x2e, 0x76, 0x31,
|
||||
0x42, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x27,
|
||||
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x69, 0x2d, 0x64, 0x61,
|
||||
0x6f, 0x2f, 0x73, 0x6f, 0x6e, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x69, 0x64, 0x2f, 0x76,
|
||||
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x6e, 0x73, 0x6f, 0x6e,
|
||||
0x72, 0x2f, 0x68, 0x77, 0x61, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x69, 0x64, 0x2f, 0x76,
|
||||
0x31, 0x3b, 0x64, 0x69, 0x64, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x44, 0x58, 0x58, 0xaa, 0x02, 0x06,
|
||||
0x44, 0x69, 0x64, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x06, 0x44, 0x69, 0x64, 0x5c, 0x56, 0x31, 0xe2,
|
||||
0x02, 0x12, 0x44, 0x69, 0x64, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61,
|
||||
|
@ -3411,8 +3411,8 @@ var file_did_v1_tx_proto_rawDesc = []byte{
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x1a, 0x05, 0x80, 0xe7, 0xb0, 0x2a, 0x01, 0x42, 0x77, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x64,
|
||||
0x69, 0x64, 0x2e, 0x76, 0x31, 0x42, 0x07, 0x54, 0x78, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01,
|
||||
0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x69, 0x2d,
|
||||
0x64, 0x61, 0x6f, 0x2f, 0x73, 0x6f, 0x6e, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x69, 0x64,
|
||||
0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x6e, 0x73,
|
||||
0x6f, 0x6e, 0x72, 0x2f, 0x68, 0x77, 0x61, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x69, 0x64,
|
||||
0x2f, 0x76, 0x31, 0x3b, 0x64, 0x69, 0x64, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x44, 0x58, 0x58, 0xaa,
|
||||
0x02, 0x06, 0x44, 0x69, 0x64, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x06, 0x44, 0x69, 0x64, 0x5c, 0x56,
|
||||
0x31, 0xe2, 0x02, 0x12, 0x44, 0x69, 0x64, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65,
|
||||
|
@ -104,9 +104,9 @@ func (x *fastReflection_Module) Has(fd protoreflect.FieldDescriptor) bool {
|
||||
switch fd.FullName() {
|
||||
default:
|
||||
if fd.IsExtension() {
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: didao.sonr.oracle.module.v1.Module"))
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: onsonr.hway.oracle.module.v1.Module"))
|
||||
}
|
||||
panic(fmt.Errorf("message didao.sonr.oracle.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
panic(fmt.Errorf("message onsonr.hway.oracle.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,9 +120,9 @@ func (x *fastReflection_Module) Clear(fd protoreflect.FieldDescriptor) {
|
||||
switch fd.FullName() {
|
||||
default:
|
||||
if fd.IsExtension() {
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: didao.sonr.oracle.module.v1.Module"))
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: onsonr.hway.oracle.module.v1.Module"))
|
||||
}
|
||||
panic(fmt.Errorf("message didao.sonr.oracle.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
panic(fmt.Errorf("message onsonr.hway.oracle.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,9 +136,9 @@ func (x *fastReflection_Module) Get(descriptor protoreflect.FieldDescriptor) pro
|
||||
switch descriptor.FullName() {
|
||||
default:
|
||||
if descriptor.IsExtension() {
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: didao.sonr.oracle.module.v1.Module"))
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: onsonr.hway.oracle.module.v1.Module"))
|
||||
}
|
||||
panic(fmt.Errorf("message didao.sonr.oracle.module.v1.Module does not contain field %s", descriptor.FullName()))
|
||||
panic(fmt.Errorf("message onsonr.hway.oracle.module.v1.Module does not contain field %s", descriptor.FullName()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,9 +156,9 @@ func (x *fastReflection_Module) Set(fd protoreflect.FieldDescriptor, value proto
|
||||
switch fd.FullName() {
|
||||
default:
|
||||
if fd.IsExtension() {
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: didao.sonr.oracle.module.v1.Module"))
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: onsonr.hway.oracle.module.v1.Module"))
|
||||
}
|
||||
panic(fmt.Errorf("message didao.sonr.oracle.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
panic(fmt.Errorf("message onsonr.hway.oracle.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,9 +176,9 @@ func (x *fastReflection_Module) Mutable(fd protoreflect.FieldDescriptor) protore
|
||||
switch fd.FullName() {
|
||||
default:
|
||||
if fd.IsExtension() {
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: didao.sonr.oracle.module.v1.Module"))
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: onsonr.hway.oracle.module.v1.Module"))
|
||||
}
|
||||
panic(fmt.Errorf("message didao.sonr.oracle.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
panic(fmt.Errorf("message onsonr.hway.oracle.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,9 +189,9 @@ func (x *fastReflection_Module) NewField(fd protoreflect.FieldDescriptor) protor
|
||||
switch fd.FullName() {
|
||||
default:
|
||||
if fd.IsExtension() {
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: didao.sonr.oracle.module.v1.Module"))
|
||||
panic(fmt.Errorf("proto3 declared messages do not support extensions: onsonr.hway.oracle.module.v1.Module"))
|
||||
}
|
||||
panic(fmt.Errorf("message didao.sonr.oracle.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
panic(fmt.Errorf("message onsonr.hway.oracle.module.v1.Module does not contain field %s", fd.FullName()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,7 +201,7 @@ func (x *fastReflection_Module) NewField(fd protoreflect.FieldDescriptor) protor
|
||||
func (x *fastReflection_Module) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor {
|
||||
switch d.FullName() {
|
||||
default:
|
||||
panic(fmt.Errorf("%s is not a oneof field in didao.sonr.oracle.module.v1.Module", d.FullName()))
|
||||
panic(fmt.Errorf("%s is not a oneof field in onsonr.hway.oracle.module.v1.Module", d.FullName()))
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
@ -415,29 +415,29 @@ var File_oracle_module_v1_module_proto protoreflect.FileDescriptor
|
||||
var file_oracle_module_v1_module_proto_rawDesc = []byte{
|
||||
0x0a, 0x1d, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2f,
|
||||
0x76, 0x31, 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
|
||||
0x1b, 0x64, 0x69, 0x64, 0x61, 0x6f, 0x2e, 0x73, 0x6f, 0x6e, 0x72, 0x2e, 0x6f, 0x72, 0x61, 0x63,
|
||||
0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x20, 0x63, 0x6f,
|
||||
0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61,
|
||||
0x31, 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x28,
|
||||
0x0a, 0x06, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x3a, 0x1e, 0xba, 0xc0, 0x96, 0xda, 0x01, 0x18,
|
||||
0x0a, 0x16, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x69, 0x2d,
|
||||
0x64, 0x61, 0x6f, 0x2f, 0x73, 0x6f, 0x6e, 0x72, 0x42, 0xf5, 0x01, 0x0a, 0x1f, 0x63, 0x6f, 0x6d,
|
||||
0x2e, 0x64, 0x69, 0x64, 0x61, 0x6f, 0x2e, 0x73, 0x6f, 0x6e, 0x72, 0x2e, 0x6f, 0x72, 0x61, 0x63,
|
||||
0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0b, 0x4d, 0x6f,
|
||||
0x64, 0x75, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x34, 0x67, 0x69, 0x74,
|
||||
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x69, 0x2d, 0x64, 0x61, 0x6f, 0x2f, 0x73,
|
||||
0x6f, 0x6e, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x2f, 0x6d,
|
||||
0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x76,
|
||||
0x31, 0xa2, 0x02, 0x04, 0x44, 0x53, 0x4f, 0x4d, 0xaa, 0x02, 0x1b, 0x44, 0x69, 0x64, 0x61, 0x6f,
|
||||
0x2e, 0x53, 0x6f, 0x6e, 0x72, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x2e, 0x4d, 0x6f, 0x64,
|
||||
0x75, 0x6c, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x1b, 0x44, 0x69, 0x64, 0x61, 0x6f, 0x5c, 0x53,
|
||||
0x6f, 0x6e, 0x72, 0x5c, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5c, 0x4d, 0x6f, 0x64, 0x75, 0x6c,
|
||||
0x65, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x27, 0x44, 0x69, 0x64, 0x61, 0x6f, 0x5c, 0x53, 0x6f, 0x6e,
|
||||
0x72, 0x5c, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5c,
|
||||
0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02,
|
||||
0x1f, 0x44, 0x69, 0x64, 0x61, 0x6f, 0x3a, 0x3a, 0x53, 0x6f, 0x6e, 0x72, 0x3a, 0x3a, 0x4f, 0x72,
|
||||
0x61, 0x63, 0x6c, 0x65, 0x3a, 0x3a, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x3a, 0x3a, 0x56, 0x31,
|
||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x1c, 0x6f, 0x6e, 0x73, 0x6f, 0x6e, 0x72, 0x2e, 0x68, 0x77, 0x61, 0x79, 0x2e, 0x6f, 0x72, 0x61,
|
||||
0x63, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x20, 0x63,
|
||||
0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68,
|
||||
0x61, 0x31, 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
|
||||
0x28, 0x0a, 0x06, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x3a, 0x1e, 0xba, 0xc0, 0x96, 0xda, 0x01,
|
||||
0x18, 0x0a, 0x16, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x6e,
|
||||
0x73, 0x6f, 0x6e, 0x72, 0x2f, 0x68, 0x77, 0x61, 0x79, 0x42, 0xfa, 0x01, 0x0a, 0x20, 0x63, 0x6f,
|
||||
0x6d, 0x2e, 0x6f, 0x6e, 0x73, 0x6f, 0x6e, 0x72, 0x2e, 0x68, 0x77, 0x61, 0x79, 0x2e, 0x6f, 0x72,
|
||||
0x61, 0x63, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0b,
|
||||
0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x34, 0x67,
|
||||
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x6e, 0x73, 0x6f, 0x6e, 0x72,
|
||||
0x2f, 0x68, 0x77, 0x61, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65,
|
||||
0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x6d, 0x6f, 0x64, 0x75, 0x6c,
|
||||
0x65, 0x76, 0x31, 0xa2, 0x02, 0x04, 0x4f, 0x48, 0x4f, 0x4d, 0xaa, 0x02, 0x1c, 0x4f, 0x6e, 0x73,
|
||||
0x6f, 0x6e, 0x72, 0x2e, 0x48, 0x77, 0x61, 0x79, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x2e,
|
||||
0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x1c, 0x4f, 0x6e, 0x73, 0x6f,
|
||||
0x6e, 0x72, 0x5c, 0x48, 0x77, 0x61, 0x79, 0x5c, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5c, 0x4d,
|
||||
0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x28, 0x4f, 0x6e, 0x73, 0x6f, 0x6e,
|
||||
0x72, 0x5c, 0x48, 0x77, 0x61, 0x79, 0x5c, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5c, 0x4d, 0x6f,
|
||||
0x64, 0x75, 0x6c, 0x65, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64,
|
||||
0x61, 0x74, 0x61, 0xea, 0x02, 0x20, 0x4f, 0x6e, 0x73, 0x6f, 0x6e, 0x72, 0x3a, 0x3a, 0x48, 0x77,
|
||||
0x61, 0x79, 0x3a, 0x3a, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x3a, 0x3a, 0x4d, 0x6f, 0x64, 0x75,
|
||||
0x6c, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@ -454,7 +454,7 @@ func file_oracle_module_v1_module_proto_rawDescGZIP() []byte {
|
||||
|
||||
var file_oracle_module_v1_module_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_oracle_module_v1_module_proto_goTypes = []interface{}{
|
||||
(*Module)(nil), // 0: didao.sonr.oracle.module.v1.Module
|
||||
(*Module)(nil), // 0: onsonr.hway.oracle.module.v1.Module
|
||||
}
|
||||
var file_oracle_module_v1_module_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
|
@ -419,8 +419,8 @@ var file_oracle_v1_genesis_proto_rawDesc = []byte{
|
||||
0x6e, 0x65, 0x73, 0x69, 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, 0x42, 0x91, 0x01, 0x0a, 0x0d, 0x63,
|
||||
0x6f, 0x6d, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x47, 0x65,
|
||||
0x6e, 0x65, 0x73, 0x69, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2d, 0x67, 0x69,
|
||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x69, 0x2d, 0x64, 0x61, 0x6f, 0x2f,
|
||||
0x73, 0x6f, 0x6e, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x2f,
|
||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x6e, 0x73, 0x6f, 0x6e, 0x72, 0x2f,
|
||||
0x68, 0x77, 0x61, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x2f,
|
||||
0x76, 0x31, 0x3b, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x4f, 0x58,
|
||||
0x58, 0xaa, 0x02, 0x09, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x09,
|
||||
0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x15, 0x4f, 0x72, 0x61, 0x63,
|
||||
|
@ -30,7 +30,7 @@ var file_oracle_v1_query_proto_rawDesc = []byte{
|
||||
0x67, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x8f, 0x01, 0x0a, 0x0d, 0x63, 0x6f, 0x6d,
|
||||
0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0a, 0x51, 0x75, 0x65, 0x72,
|
||||
0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x69, 0x2d, 0x64, 0x61, 0x6f, 0x2f, 0x73, 0x6f, 0x6e, 0x72,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x6e, 0x73, 0x6f, 0x6e, 0x72, 0x2f, 0x68, 0x77, 0x61, 0x79,
|
||||
0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x6f,
|
||||
0x72, 0x61, 0x63, 0x6c, 0x65, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x4f, 0x58, 0x58, 0xaa, 0x02, 0x09,
|
||||
0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x09, 0x4f, 0x72, 0x61, 0x63,
|
||||
|
@ -29,8 +29,8 @@ var file_oracle_v1_tx_proto_rawDesc = []byte{
|
||||
0x14, 0x67, 0x6f, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x8c, 0x01, 0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x2e, 0x6f, 0x72,
|
||||
0x61, 0x63, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x07, 0x54, 0x78, 0x50, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x50, 0x01, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64,
|
||||
0x69, 0x2d, 0x64, 0x61, 0x6f, 0x2f, 0x73, 0x6f, 0x6e, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6f,
|
||||
0x50, 0x01, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f,
|
||||
0x6e, 0x73, 0x6f, 0x6e, 0x72, 0x2f, 0x68, 0x77, 0x61, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6f,
|
||||
0x72, 0x61, 0x63, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x76,
|
||||
0x31, 0xa2, 0x02, 0x03, 0x4f, 0x58, 0x58, 0xaa, 0x02, 0x09, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65,
|
||||
0x2e, 0x56, 0x31, 0xca, 0x02, 0x09, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5c, 0x56, 0x31, 0xe2,
|
||||
|
@ -1,24 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/onsonr/hway/pkg/vault"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if err := serveCmd().Execute(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func serveCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "vltd",
|
||||
Aliases: []string{"vault"},
|
||||
Short: "run the vault rest api and htmx frontend",
|
||||
DisableFlagParsing: false,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
vault.Serve(cmd.Context())
|
||||
},
|
||||
}
|
||||
}
|
@ -1,171 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
// Package accumulator implements the cryptographic accumulator as described in https://eprint.iacr.org/2020/777.pdf
|
||||
// It also implements the zero knowledge proof of knowledge protocol
|
||||
// described in section 7 of the paper.
|
||||
// Note: the paper only describes for non-membership witness case, but we don't
|
||||
// use non-membership witness. We only implement the membership witness case.
|
||||
package accumulator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.sr.ht/~sircmpwn/go-bare"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
type structMarshal struct {
|
||||
Curve string `bare:"curve"`
|
||||
Value []byte `bare:"value"`
|
||||
}
|
||||
|
||||
type Element curves.Scalar
|
||||
|
||||
// Coefficient is a point
|
||||
type Coefficient curves.Point
|
||||
|
||||
// Accumulator is a point
|
||||
type Accumulator struct {
|
||||
value curves.Point
|
||||
}
|
||||
|
||||
// New creates a new accumulator.
|
||||
func (acc *Accumulator) New(curve *curves.PairingCurve) (*Accumulator, error) {
|
||||
// If we need to support non-membership witness, we need to implement Accumulator Initialization
|
||||
// as described in section 6 of <https://eprint.iacr.org/2020/777.pdf>
|
||||
// for now we don't need non-membership witness
|
||||
|
||||
// i.e., it computes V0 = prod(y + α) * P, y ∈ Y_V0, P is a generator of G1. Since we do not use non-membership witness
|
||||
// we just set the initial accumulator a G1 generator.
|
||||
acc.value = curve.Scalar.Point().Generator()
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
// WithElements initializes a new accumulator prefilled with entries
|
||||
// Each member is assumed to be hashed
|
||||
// V = prod(y + α) * V0, for all y∈ Y_V
|
||||
func (acc *Accumulator) WithElements(curve *curves.PairingCurve, key *SecretKey, m []Element) (*Accumulator, error) {
|
||||
_, err := acc.New(curve)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
y, err := key.BatchAdditions(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
acc.value = acc.value.Mul(y)
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
// AddElements accumulates a set of elements into the accumulator.
|
||||
func (acc *Accumulator) AddElements(key *SecretKey, m []Element) (*Accumulator, error) {
|
||||
if acc.value == nil || key.value == nil {
|
||||
return nil, fmt.Errorf("accumulator and secret key should not be nil")
|
||||
}
|
||||
y, err := key.BatchAdditions(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
acc.value = acc.value.Mul(y)
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
// Add accumulates a single element into the accumulator
|
||||
// V' = (y + alpha) * V
|
||||
func (acc *Accumulator) Add(key *SecretKey, e Element) (*Accumulator, error) {
|
||||
if acc.value == nil || acc.value.IsIdentity() || key.value == nil || e == nil {
|
||||
return nil, fmt.Errorf("accumulator, secret key and element should not be nil")
|
||||
}
|
||||
y := e.Add(key.value) // y + alpha
|
||||
acc.value = acc.value.Mul(y)
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
// Remove removes a single element from accumulator if it exists
|
||||
// V' = 1/(y+alpha) * V
|
||||
func (acc *Accumulator) Remove(key *SecretKey, e Element) (*Accumulator, error) {
|
||||
if acc.value == nil || acc.value.IsIdentity() || key.value == nil || e == nil {
|
||||
return nil, fmt.Errorf("accumulator, secret key and element should not be nil")
|
||||
}
|
||||
y := e.Add(key.value) // y + alpha
|
||||
y, err := y.Invert() // 1/(y+alpha)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
acc.value = acc.value.Mul(y)
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
// Update performs a batch addition and deletion as described on page 7, section 3 in
|
||||
// https://eprint.iacr.org/2020/777.pdf
|
||||
func (acc *Accumulator) Update(key *SecretKey, additions []Element, deletions []Element) (*Accumulator, []Coefficient, error) {
|
||||
if acc.value == nil || acc.value.IsIdentity() || key.value == nil {
|
||||
return nil, nil, fmt.Errorf("accumulator and secret key should not be nil")
|
||||
}
|
||||
|
||||
// Compute dA(-alpha) = prod(y + alpha), y in the set of A ⊆ ACC-Y_V
|
||||
a, err := key.BatchAdditions(additions)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Compute dD(-alpha) = 1/prod(y + alpha), y in the set of D ⊆ Y_V
|
||||
d, err := key.BatchDeletions(deletions)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// dA(-alpha)/dD(-alpha)
|
||||
div := a.Mul(d)
|
||||
newAcc := acc.value.Mul(div)
|
||||
|
||||
// build an array of coefficients
|
||||
elements, err := key.CreateCoefficients(additions, deletions)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
coefficients := make([]Coefficient, len(elements))
|
||||
for i := 0; i < len(elements); i++ {
|
||||
coefficients[i] = acc.value.Mul(elements[i])
|
||||
}
|
||||
acc.value = newAcc
|
||||
return acc, coefficients, nil
|
||||
}
|
||||
|
||||
// MarshalBinary converts Accumulator to bytes
|
||||
func (acc Accumulator) MarshalBinary() ([]byte, error) {
|
||||
if acc.value == nil {
|
||||
return nil, fmt.Errorf("accumulator cannot be nil")
|
||||
}
|
||||
tv := &structMarshal{
|
||||
Value: acc.value.ToAffineCompressed(),
|
||||
Curve: acc.value.CurveName(),
|
||||
}
|
||||
return bare.Marshal(tv)
|
||||
}
|
||||
|
||||
// UnmarshalBinary sets Accumulator from bytes
|
||||
func (acc *Accumulator) UnmarshalBinary(data []byte) error {
|
||||
tv := new(structMarshal)
|
||||
err := bare.Unmarshal(data, tv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
curve := curves.GetCurveByName(tv.Curve)
|
||||
if curve == nil {
|
||||
return fmt.Errorf("invalid curve")
|
||||
}
|
||||
|
||||
value, err := curve.NewIdentityPoint().FromAffineCompressed(tv.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
acc.value = value
|
||||
return nil
|
||||
}
|
@ -1,188 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package accumulator
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
func TestNewAccumulator100(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
var seed [32]byte
|
||||
key, err := new(SecretKey).New(curve, seed[:])
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, key)
|
||||
acc, err := new(Accumulator).New(curve)
|
||||
require.NoError(t, err)
|
||||
accBz, err := acc.MarshalBinary()
|
||||
require.NoError(t, err)
|
||||
fmt.Println(accBz)
|
||||
fmt.Println(len(accBz))
|
||||
fmt.Println(hex.EncodeToString(accBz))
|
||||
fmt.Println(len(hex.EncodeToString(accBz)))
|
||||
require.Equal(t, 60, len(accBz), "Marshalled accumulator should be 60 bytes")
|
||||
require.Equal(t, 120, len(hex.EncodeToString(accBz)), "Hex-encoded accumulator should be 120 characters")
|
||||
require.NotNil(t, acc)
|
||||
require.Equal(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
|
||||
}
|
||||
|
||||
func TestNewAccumulator10K(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
var seed [32]byte
|
||||
key, err := new(SecretKey).New(curve, seed[:])
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, key)
|
||||
acc, err := new(Accumulator).New(curve)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, acc)
|
||||
require.Equal(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
|
||||
}
|
||||
|
||||
func TestNewAccumulator10M(t *testing.T) {
|
||||
// Initiating 10M values takes time
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
var seed [32]byte
|
||||
key, err := new(SecretKey).New(curve, seed[:])
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, key)
|
||||
acc, err := new(Accumulator).New(curve)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, acc)
|
||||
require.Equal(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
|
||||
}
|
||||
|
||||
func TestWithElements(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
var seed [32]byte
|
||||
key, _ := new(SecretKey).New(curve, seed[:])
|
||||
element1 := curve.Scalar.Hash([]byte("value1"))
|
||||
element2 := curve.Scalar.Hash([]byte("value2"))
|
||||
elements := []Element{element1, element2}
|
||||
newAcc, err := new(Accumulator).WithElements(curve, key, elements)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, newAcc)
|
||||
require.NotEqual(t, newAcc.value.ToAffineCompressed(), curve.PointG1.Identity().ToAffineCompressed())
|
||||
require.NotEqual(t, newAcc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
|
||||
|
||||
_, _ = newAcc.Remove(key, element1)
|
||||
_, _ = newAcc.Remove(key, element2)
|
||||
require.Equal(t, newAcc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
|
||||
}
|
||||
|
||||
func TestAdd(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
var seed [32]byte
|
||||
key, err := new(SecretKey).New(curve, seed[:])
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, key)
|
||||
acc := &Accumulator{curve.PointG1.Generator()}
|
||||
_, _ = acc.New(curve)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, acc)
|
||||
|
||||
element := curve.Scalar.Hash([]byte("value1"))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, element)
|
||||
_, _ = acc.Add(key, element)
|
||||
require.NotEqual(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
|
||||
}
|
||||
|
||||
func TestRemove(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
var seed [32]byte
|
||||
key, err := new(SecretKey).New(curve, seed[:])
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, key)
|
||||
acc, err := new(Accumulator).New(curve)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, acc)
|
||||
require.Equal(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
|
||||
|
||||
element := curve.Scalar.Hash([]byte("value1"))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, element)
|
||||
|
||||
// add element
|
||||
_, _ = acc.Add(key, element)
|
||||
require.NotEqual(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
|
||||
|
||||
// remove element
|
||||
acc, err = acc.Remove(key, element)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
|
||||
}
|
||||
|
||||
func TestAddElements(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
var seed [32]byte
|
||||
key, err := new(SecretKey).New(curve, seed[:])
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, key)
|
||||
acc := &Accumulator{curve.PointG1.Generator()}
|
||||
_, _ = acc.New(curve)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, acc)
|
||||
require.Equal(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
|
||||
|
||||
element1 := curve.Scalar.Hash([]byte("value1"))
|
||||
element2 := curve.Scalar.Hash([]byte("value2"))
|
||||
element3 := curve.Scalar.Hash([]byte("value3"))
|
||||
elements := []Element{element1, element2, element3}
|
||||
|
||||
acc, err = acc.AddElements(key, elements)
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
|
||||
}
|
||||
|
||||
func TestAccumulatorMarshal(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
point := curve.PointG1.Generator().Mul(curve.Scalar.New(2))
|
||||
data, err := Accumulator{point}.MarshalBinary()
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, data)
|
||||
// element cannot be empty
|
||||
_, err = Accumulator{}.MarshalBinary()
|
||||
require.Error(t, err)
|
||||
|
||||
e := &Accumulator{curve.PointG1.Generator()}
|
||||
_ = e.UnmarshalBinary(data)
|
||||
require.True(t, e.value.Equal(point))
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
var seed [32]byte
|
||||
key, err := new(SecretKey).New(curve, seed[:])
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, key)
|
||||
acc, err := new(Accumulator).New(curve)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, acc)
|
||||
require.Equal(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
|
||||
|
||||
element1 := curve.Scalar.Hash([]byte("value1"))
|
||||
element2 := curve.Scalar.Hash([]byte("value2"))
|
||||
element3 := curve.Scalar.Hash([]byte("value3"))
|
||||
elements := []Element{element1, element2, element3}
|
||||
|
||||
acc, _, err = acc.Update(key, elements, nil)
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
|
||||
|
||||
acc, _, err = acc.Update(key, nil, elements)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
|
||||
}
|
@ -1,244 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package accumulator
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.sr.ht/~sircmpwn/go-bare"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
// SecretKey is the secret alpha only held by the accumulator manager.
|
||||
type SecretKey struct {
|
||||
value curves.Scalar
|
||||
}
|
||||
|
||||
// New creates a new secret key from the seed.
|
||||
func (sk *SecretKey) New(curve *curves.PairingCurve, seed []byte) (*SecretKey, error) {
|
||||
sk.value = curve.Scalar.Hash(seed)
|
||||
return sk, nil
|
||||
}
|
||||
|
||||
// GetPublicKey creates a public key from SecretKey sk
|
||||
func (sk SecretKey) GetPublicKey(curve *curves.PairingCurve) (*PublicKey, error) {
|
||||
if sk.value == nil || curve == nil {
|
||||
return nil, fmt.Errorf("curve and sk value cannot be nil")
|
||||
}
|
||||
value := curve.Scalar.Point().(curves.PairingPoint).OtherGroup().Generator().Mul(sk.value)
|
||||
return &PublicKey{value.(curves.PairingPoint)}, nil
|
||||
}
|
||||
|
||||
// MarshalBinary converts SecretKey to bytes
|
||||
func (sk SecretKey) MarshalBinary() ([]byte, error) {
|
||||
if sk.value == nil {
|
||||
return nil, fmt.Errorf("sk cannot be empty")
|
||||
}
|
||||
tv := &structMarshal{
|
||||
Value: sk.value.Bytes(),
|
||||
Curve: sk.value.Point().CurveName(),
|
||||
}
|
||||
return bare.Marshal(tv)
|
||||
}
|
||||
|
||||
// UnmarshalBinary sets SecretKey from bytes
|
||||
func (sk *SecretKey) UnmarshalBinary(data []byte) error {
|
||||
tv := new(structMarshal)
|
||||
err := bare.Unmarshal(data, tv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
curve := curves.GetCurveByName(tv.Curve)
|
||||
if curve == nil {
|
||||
return fmt.Errorf("invalid curve")
|
||||
}
|
||||
|
||||
value, err := curve.NewScalar().SetBytes(tv.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sk.value = value
|
||||
return nil
|
||||
}
|
||||
|
||||
// BatchAdditions computes product(y + sk) for y in additions and output the product
|
||||
func (sk SecretKey) BatchAdditions(additions []Element) (Element, error) {
|
||||
if sk.value == nil {
|
||||
return nil, fmt.Errorf("secret key cannot be empty")
|
||||
}
|
||||
mul := sk.value.One()
|
||||
for i := 0; i < len(additions); i++ {
|
||||
if additions[i] == nil {
|
||||
return nil, fmt.Errorf("some element in additions is nil")
|
||||
}
|
||||
// y + alpha
|
||||
temp := additions[i].Add(sk.value)
|
||||
// prod(y + alpha)
|
||||
mul = mul.Mul(temp)
|
||||
}
|
||||
return mul, nil
|
||||
}
|
||||
|
||||
// BatchDeletions computes 1/product(y + sk) for y in deletions and output it
|
||||
func (sk SecretKey) BatchDeletions(deletions []Element) (Element, error) {
|
||||
v, err := sk.BatchAdditions(deletions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
y, err := v.Invert()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return y, nil
|
||||
}
|
||||
|
||||
// CreateCoefficients creates the Batch Polynomial coefficients
|
||||
// See page 7 of https://eprint.iacr.org/2020/777.pdf
|
||||
func (sk SecretKey) CreateCoefficients(additions []Element, deletions []Element) ([]Element, error) {
|
||||
if sk.value == nil {
|
||||
return nil, fmt.Errorf("secret key should not be nil")
|
||||
}
|
||||
|
||||
// vD(x) = ∑^{m}_{s=1}{ ∏ 1..s {yD_i + alpha}^-1 ∏ 1 ..s-1 {yD_j - x}
|
||||
one := sk.value.One()
|
||||
m1 := one.Neg() // m1 is -1
|
||||
vD := make(polynomial, 0, len(deletions))
|
||||
for s := 0; s < len(deletions); s++ {
|
||||
// ∏ 1..s (yD_i + alpha)^-1
|
||||
c, err := sk.BatchDeletions(deletions[0 : s+1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error in sk batchDeletions")
|
||||
}
|
||||
poly := make(polynomial, 1, s+2)
|
||||
poly[0] = one
|
||||
|
||||
// ∏ 1..(s-1) (yD_j - x)
|
||||
for j := 0; j < s; j++ {
|
||||
t := make(polynomial, 2)
|
||||
// yD_j
|
||||
t[0] = deletions[j]
|
||||
// -x
|
||||
t[1] = m1
|
||||
|
||||
// polynomial multiplication (yD_1-x) * (yD_2 - x) ...
|
||||
poly, err = poly.Mul(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
poly, err = poly.MulScalar(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vD, err = vD.Add(poly)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// vD(x) * ∏ 1..n (yA_i + alpha)
|
||||
bAdd, err := sk.BatchAdditions(additions)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error in sk batchAdditions")
|
||||
}
|
||||
vD, err = vD.MulScalar(bAdd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// vA(x) = ∑^n_{s=1}{ ∏ 1..s-1 {yA_i + alpha} ∏ s+1..n {yA_j - x} }
|
||||
vA := make(polynomial, 0, len(additions))
|
||||
for s := 0; s < len(additions); s++ {
|
||||
// ∏ 1..s-1 {yA_i + alpha}
|
||||
var c Element
|
||||
if s == 0 {
|
||||
c = one
|
||||
} else {
|
||||
c, err = sk.BatchAdditions(additions[0:s])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
poly := make(polynomial, 1, s+2)
|
||||
poly[0] = one
|
||||
|
||||
// ∏ s+1..n {yA_j - x}
|
||||
for j := s + 1; j < len(additions); j++ {
|
||||
t := make(polynomial, 2)
|
||||
t[0] = additions[j]
|
||||
t[1] = m1
|
||||
|
||||
// polynomial multiplication (yA_1-x) * (yA_2 - x) ...
|
||||
poly, err = poly.Mul(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
poly, err = poly.MulScalar(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vA, err = vA.Add(poly)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// vA - vD
|
||||
vA, err = vA.Sub(vD)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]Element, len(vA))
|
||||
for i := 0; i < len(vA); i++ {
|
||||
result[i] = vA[i]
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// PublicKey is the public key of accumulator, it should be sk * generator of G2
|
||||
type PublicKey struct {
|
||||
value curves.PairingPoint
|
||||
}
|
||||
|
||||
// MarshalBinary converts PublicKey to bytes
|
||||
func (pk PublicKey) MarshalBinary() ([]byte, error) {
|
||||
if pk.value == nil {
|
||||
return nil, fmt.Errorf("public key cannot be nil")
|
||||
}
|
||||
tv := &structMarshal{
|
||||
Value: pk.value.ToAffineCompressed(),
|
||||
Curve: pk.value.CurveName(),
|
||||
}
|
||||
return bare.Marshal(tv)
|
||||
}
|
||||
|
||||
// UnmarshalBinary sets PublicKey from bytes
|
||||
func (pk *PublicKey) UnmarshalBinary(data []byte) error {
|
||||
tv := new(structMarshal)
|
||||
err := bare.Unmarshal(data, tv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
curve := curves.GetPairingCurveByName(tv.Curve)
|
||||
if curve == nil {
|
||||
return fmt.Errorf("invalid curve")
|
||||
}
|
||||
|
||||
value, err := curve.NewScalar().Point().FromAffineCompressed(tv.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var ok bool
|
||||
pk.value, ok = value.(curves.PairingPoint)
|
||||
if !ok {
|
||||
return errors.New("can't convert to PairingPoint")
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package accumulator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
func TestSecretKeyMarshal(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
data, err := SecretKey{curve.Scalar.One()}.MarshalBinary()
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, data)
|
||||
e := &SecretKey{curve.Scalar.New(2)}
|
||||
err = e.UnmarshalBinary(data)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, e.value.Bytes(), curve.Scalar.One().Bytes())
|
||||
|
||||
// element cannot be empty
|
||||
_, err = SecretKey{}.MarshalBinary()
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestPublicKeyMarshal(t *testing.T) {
|
||||
// Actually test both toBytes() and from()
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
sk := &SecretKey{curve.Scalar.New(3)}
|
||||
pk, _ := sk.GetPublicKey(curve)
|
||||
pkBytes, err := pk.MarshalBinary()
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, pkBytes)
|
||||
|
||||
pk2 := &PublicKey{}
|
||||
err = pk2.UnmarshalBinary(pkBytes)
|
||||
require.NoError(t, err)
|
||||
require.True(t, pk.value.Equal(pk2.value))
|
||||
}
|
||||
|
||||
func TestBatch(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
var seed [32]byte
|
||||
sk, _ := new(SecretKey).New(curve, seed[:])
|
||||
element1 := curve.Scalar.Hash([]byte("value1"))
|
||||
element2 := curve.Scalar.Hash([]byte("value2"))
|
||||
elements := []Element{element1, element2}
|
||||
|
||||
add, err := sk.BatchAdditions(elements)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, add)
|
||||
|
||||
del, err := sk.BatchDeletions(elements)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, del)
|
||||
|
||||
result := add.Mul(del)
|
||||
require.Equal(t, result, curve.Scalar.One())
|
||||
|
||||
g1 := curve.PointG1.Generator()
|
||||
acc := g1.Mul(add)
|
||||
require.NotEqual(t, acc, g1)
|
||||
acc = acc.Mul(del)
|
||||
require.Equal(t, acc.ToAffineCompressed(), g1.ToAffineCompressed())
|
||||
|
||||
acc2 := g1.Mul(result)
|
||||
require.True(t, acc2.Equal(g1))
|
||||
}
|
||||
|
||||
func TestCoefficient(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
sk, _ := new(SecretKey).New(curve, []byte("1234567890"))
|
||||
element1 := curve.Scalar.Hash([]byte("value1"))
|
||||
element2 := curve.Scalar.Hash([]byte("value2"))
|
||||
element3 := curve.Scalar.Hash([]byte("value3"))
|
||||
element4 := curve.Scalar.Hash([]byte("value4"))
|
||||
element5 := curve.Scalar.Hash([]byte("value5"))
|
||||
elements := []Element{element1, element2, element3, element4, element5}
|
||||
coefficients, err := sk.CreateCoefficients(elements[0:2], elements[2:5])
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(coefficients), 3)
|
||||
}
|
@ -1,204 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package accumulator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
// dad constructs two polynomials - dA(x) and dD(x)
|
||||
// dA(y) = prod(y_A,t - y), t = 1...n
|
||||
// dD(y) = prod(y_D,t - y), t = 1...n
|
||||
func dad(values []Element, y Element) (Element, error) {
|
||||
if values == nil || y == nil {
|
||||
return nil, fmt.Errorf("curve, values or y should not be nil")
|
||||
}
|
||||
|
||||
for _, value := range values {
|
||||
if value == nil {
|
||||
return nil, fmt.Errorf("some element is nil")
|
||||
}
|
||||
}
|
||||
|
||||
result := y.One()
|
||||
if len(values) == 1 {
|
||||
a := values[0]
|
||||
result = a.Sub(y)
|
||||
} else {
|
||||
for i := 0; i < len(values); i++ {
|
||||
temp := values[i].Sub(y)
|
||||
result = result.Mul(temp)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type polynomialPoint []curves.Point
|
||||
|
||||
// evaluate evaluates a PolynomialG1 on input x.
|
||||
func (p polynomialPoint) evaluate(x curves.Scalar) (curves.Point, error) {
|
||||
if p == nil {
|
||||
return nil, fmt.Errorf("p cannot be empty")
|
||||
}
|
||||
for i := 0; i < len(p); i++ {
|
||||
if p[i] == nil {
|
||||
return nil, fmt.Errorf("some coefficient in p is nil")
|
||||
}
|
||||
}
|
||||
|
||||
pp := x
|
||||
res := p[0]
|
||||
for i := 1; i < len(p); i++ {
|
||||
r := p[i].Mul(pp)
|
||||
res = res.Add(r)
|
||||
pp = pp.Mul(x)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Add adds two PolynomialG1
|
||||
func (p polynomialPoint) Add(rhs polynomialPoint) (polynomialPoint, error) {
|
||||
maxLen := int(math.Max(float64(len(p)), float64(len(rhs))))
|
||||
|
||||
result := make(polynomialPoint, maxLen)
|
||||
|
||||
for i, c := range p {
|
||||
if c == nil {
|
||||
return nil, fmt.Errorf("invalid coefficient at %d", i)
|
||||
}
|
||||
result[i] = c.Add(c.Identity())
|
||||
}
|
||||
|
||||
for i, c := range rhs {
|
||||
if c == nil {
|
||||
return nil, fmt.Errorf("invalid coefficient at %d", i)
|
||||
}
|
||||
if result[i] == nil {
|
||||
result[i] = c.Add(c.Identity())
|
||||
} else {
|
||||
result[i] = result[i].Add(c)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Mul for PolynomialG1 computes rhs * p, p is a polynomial, rhs is a value
|
||||
func (p polynomialPoint) Mul(rhs curves.Scalar) (polynomialPoint, error) {
|
||||
result := make(polynomialPoint, len(p))
|
||||
|
||||
for i, c := range p {
|
||||
if c == nil {
|
||||
return nil, fmt.Errorf("invalid coefficient at %d", i)
|
||||
}
|
||||
result[i] = c.Mul(rhs)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type polynomial []curves.Scalar
|
||||
|
||||
// Add adds two polynomials
|
||||
func (p polynomial) Add(rhs polynomial) (polynomial, error) {
|
||||
maxLen := int(math.Max(float64(len(p)), float64(len(rhs))))
|
||||
result := make([]curves.Scalar, maxLen)
|
||||
|
||||
for i, c := range p {
|
||||
if c == nil {
|
||||
return nil, fmt.Errorf("invalid coefficient at %d", i)
|
||||
}
|
||||
result[i] = c.Clone()
|
||||
}
|
||||
|
||||
for i, c := range rhs {
|
||||
if c == nil {
|
||||
return nil, fmt.Errorf("invalid coefficient at %d", i)
|
||||
}
|
||||
if result[i] == nil {
|
||||
result[i] = c.Clone()
|
||||
} else {
|
||||
result[i] = result[i].Add(c)
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Sub computes p-rhs and returns
|
||||
func (p polynomial) Sub(rhs polynomial) (polynomial, error) {
|
||||
maxLen := int(math.Max(float64(len(p)), float64(len(rhs))))
|
||||
result := make([]curves.Scalar, maxLen)
|
||||
|
||||
for i, c := range p {
|
||||
if c == nil {
|
||||
return nil, fmt.Errorf("invalid coefficient at %d", i)
|
||||
}
|
||||
result[i] = c.Clone()
|
||||
}
|
||||
|
||||
for i, c := range rhs {
|
||||
if c == nil {
|
||||
return nil, fmt.Errorf("invalid coefficient at %d", i)
|
||||
}
|
||||
if result[i] == nil {
|
||||
result[i] = c.Neg()
|
||||
} else {
|
||||
result[i] = result[i].Sub(c)
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Mul multiplies two polynomials - p * rhs
|
||||
func (p polynomial) Mul(rhs polynomial) (polynomial, error) {
|
||||
// Check for each coefficient that should not be nil
|
||||
for i, c := range p {
|
||||
if c == nil {
|
||||
return nil, fmt.Errorf("coefficient in p at %d is nil", i)
|
||||
}
|
||||
}
|
||||
|
||||
for i, c := range rhs {
|
||||
if c == nil {
|
||||
return nil, fmt.Errorf("coefficient in rhs at %d is nil", i)
|
||||
}
|
||||
}
|
||||
|
||||
m := len(p)
|
||||
n := len(rhs)
|
||||
|
||||
// Initialize the product polynomial
|
||||
prod := make(polynomial, m+n-1)
|
||||
for i := 0; i < len(prod); i++ {
|
||||
prod[i] = p[0].Zero()
|
||||
}
|
||||
|
||||
// Multiply two polynomials term by term
|
||||
for i, cp := range p {
|
||||
for j, cr := range rhs {
|
||||
temp := cp.Mul(cr)
|
||||
prod[i+j] = prod[i+j].Add(temp)
|
||||
}
|
||||
}
|
||||
return prod, nil
|
||||
}
|
||||
|
||||
// MulScalar computes p * rhs, where rhs is a scalar value
|
||||
func (p polynomial) MulScalar(rhs curves.Scalar) (polynomial, error) {
|
||||
result := make(polynomial, len(p))
|
||||
for i, c := range p {
|
||||
if c == nil {
|
||||
return nil, fmt.Errorf("coefficient at %d is nil", i)
|
||||
}
|
||||
result[i] = c.Mul(rhs)
|
||||
}
|
||||
return result, nil
|
||||
}
|
@ -1,404 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package accumulator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
func TestEvaluatePolyG1(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
poly := polynomialPoint{
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(3)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(2)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
|
||||
}
|
||||
output1, err := poly.evaluate(curve.Scalar.New(1))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, output1)
|
||||
result1 := curve.PointG1.Generator().Mul(curve.Scalar.New(6))
|
||||
require.Equal(t, output1.ToAffineCompressed(), result1.ToAffineCompressed())
|
||||
|
||||
output2, err := poly.evaluate(curve.Scalar.New(2))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, output2)
|
||||
result2 := curve.PointG1.Generator().Mul(curve.Scalar.New(11))
|
||||
require.Equal(t, output2.ToAffineCompressed(), result2.ToAffineCompressed())
|
||||
}
|
||||
|
||||
func TestEvaluatePolyG1Error(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
poly := polynomialPoint{
|
||||
nil,
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(2)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
|
||||
}
|
||||
_, err := poly.evaluate(curve.Scalar.New(1))
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestAddAssignPolyG1(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
// Test polynomial with equal length
|
||||
poly1 := polynomialPoint{
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(3)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(2)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
|
||||
}
|
||||
poly2 := polynomialPoint{
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(2)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(3)),
|
||||
}
|
||||
|
||||
output, err := poly1.Add(poly2)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, output)
|
||||
result := polynomialPoint{
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(4)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(4)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(4)),
|
||||
}
|
||||
for i := 0; i < len(output); i++ {
|
||||
require.Equal(t, output[i].ToAffineCompressed(), result[i].ToAffineCompressed())
|
||||
}
|
||||
|
||||
// Test polynomials with unequal length
|
||||
poly3 := polynomialPoint{
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(2)),
|
||||
}
|
||||
output2, err := poly1.Add(poly3)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, output2)
|
||||
result2 := polynomialPoint{
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(4)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(4)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
|
||||
}
|
||||
require.Equal(t, len(output2), len(result2))
|
||||
for i := 0; i < len(output2); i++ {
|
||||
require.Equal(t, output2[i].ToAffineCompressed(), result2[i].ToAffineCompressed())
|
||||
}
|
||||
|
||||
// Test polynomial with Capacity
|
||||
poly4 := make(polynomialPoint, 0, 3)
|
||||
poly5, err := poly4.Add(poly1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(poly5), len(poly1))
|
||||
for i := 0; i < len(poly5); i++ {
|
||||
require.Equal(t, poly5[i].ToAffineCompressed(), poly1[i].ToAffineCompressed())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddAssignPolyG1Error(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
poly1 := polynomialPoint{
|
||||
nil,
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(2)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
|
||||
}
|
||||
poly2 := polynomialPoint{
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(2)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(3)),
|
||||
}
|
||||
output, err := poly1.Add(poly2)
|
||||
require.Error(t, err)
|
||||
require.Nil(t, output)
|
||||
}
|
||||
|
||||
func TestMulAssignPolyG1(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
poly := polynomialPoint{
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(3)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(2)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
|
||||
}
|
||||
rhs := curve.Scalar.New(3)
|
||||
output, err := poly.Mul(rhs)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, output)
|
||||
poly2 := polynomialPoint{
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(9)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(6)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(3)),
|
||||
}
|
||||
for i := 0; i < len(poly2); i++ {
|
||||
require.Equal(t, output[i].ToAffineCompressed(), poly2[i].ToAffineCompressed())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMulAssignPolyG1Error(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
poly := polynomialPoint{
|
||||
nil,
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(2)),
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
|
||||
}
|
||||
rhs := curve.Scalar.New(3)
|
||||
output, err := poly.Mul(rhs)
|
||||
require.Error(t, err)
|
||||
require.Nil(t, output)
|
||||
}
|
||||
|
||||
func TestPushPoly(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
poly := polynomial{
|
||||
curve.Scalar.New(3),
|
||||
curve.Scalar.New(2),
|
||||
curve.Scalar.New(1),
|
||||
}
|
||||
scalar := curve.Scalar.New(4)
|
||||
result := append(poly, scalar)
|
||||
require.Equal(t, result[3], scalar)
|
||||
|
||||
// Push one more
|
||||
scalar2 := curve.Scalar.New(5)
|
||||
result2 := append(result, scalar2)
|
||||
require.Equal(t, result2[4], scalar2)
|
||||
|
||||
// Push to a new polynomial
|
||||
newPoly := polynomial{}
|
||||
newPoly = append(newPoly, scalar)
|
||||
require.Equal(t, newPoly[0], scalar)
|
||||
newPoly = append(newPoly, scalar2)
|
||||
require.Equal(t, newPoly[1], scalar2)
|
||||
}
|
||||
|
||||
func TestAddAssignPoly(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
// Test polynomial with equal length
|
||||
poly1 := polynomial{
|
||||
curve.Scalar.New(3),
|
||||
curve.Scalar.New(2),
|
||||
curve.Scalar.New(1),
|
||||
}
|
||||
poly2 := polynomial{
|
||||
curve.Scalar.New(1),
|
||||
curve.Scalar.New(2),
|
||||
curve.Scalar.New(3),
|
||||
}
|
||||
|
||||
output, err := poly1.Add(poly2)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, output)
|
||||
result := []curves.Scalar{
|
||||
curve.Scalar.New(4),
|
||||
curve.Scalar.New(4),
|
||||
curve.Scalar.New(4),
|
||||
}
|
||||
for i := 0; i < len(output); i++ {
|
||||
require.Equal(t, output[i], result[i])
|
||||
}
|
||||
|
||||
// Test polynomials with unequal length
|
||||
poly3 := polynomial{
|
||||
curve.Scalar.New(1),
|
||||
curve.Scalar.New(2),
|
||||
}
|
||||
output2, err := poly1.Add(poly3)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, output2)
|
||||
result2 := []curves.Scalar{
|
||||
curve.Scalar.New(4),
|
||||
curve.Scalar.New(4),
|
||||
curve.Scalar.New(1),
|
||||
}
|
||||
require.Equal(t, len(output2), len(result2))
|
||||
for i := 0; i < len(output2); i++ {
|
||||
require.Equal(t, output2[i], result2[i])
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddAssignPolyError(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
// Test polynomial with equal length
|
||||
poly1 := polynomial{
|
||||
nil,
|
||||
curve.Scalar.New(2),
|
||||
curve.Scalar.New(1),
|
||||
}
|
||||
poly2 := polynomial{
|
||||
curve.Scalar.New(1),
|
||||
curve.Scalar.New(2),
|
||||
curve.Scalar.New(3),
|
||||
}
|
||||
|
||||
output, err := poly1.Add(poly2)
|
||||
require.Error(t, err)
|
||||
require.Nil(t, output)
|
||||
}
|
||||
|
||||
func TestSubAssignPoly(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
// Test polynomial with equal length
|
||||
poly1 := polynomial{
|
||||
curve.Scalar.New(3),
|
||||
curve.Scalar.New(2),
|
||||
curve.Scalar.New(1),
|
||||
}
|
||||
poly2 := polynomial{
|
||||
curve.Scalar.New(1),
|
||||
curve.Scalar.New(2),
|
||||
curve.Scalar.New(3),
|
||||
}
|
||||
|
||||
output, err := poly1.Sub(poly2)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, output)
|
||||
result := []curves.Scalar{
|
||||
curve.Scalar.New(2),
|
||||
curve.Scalar.New(0),
|
||||
curve.Scalar.New(-2),
|
||||
}
|
||||
for i := 0; i < len(output); i++ {
|
||||
require.Equal(t, output[i].Bytes(), result[i].Bytes())
|
||||
}
|
||||
|
||||
// Test polynomials with unequal length
|
||||
poly3 := polynomial{
|
||||
curve.Scalar.New(1),
|
||||
curve.Scalar.New(2),
|
||||
curve.Scalar.New(3),
|
||||
curve.Scalar.New(4),
|
||||
}
|
||||
output2, err := poly1.Sub(poly3)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, output2)
|
||||
result2 := []curves.Scalar{
|
||||
curve.Scalar.New(2),
|
||||
curve.Scalar.New(0),
|
||||
curve.Scalar.New(-2),
|
||||
curve.Scalar.New(-4),
|
||||
}
|
||||
require.Equal(t, len(output2), len(result2))
|
||||
for i := 0; i < len(output2); i++ {
|
||||
require.Equal(t, output2[i].Bytes(), result2[i].Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubAssignPolyError(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
poly1 := polynomial{
|
||||
nil,
|
||||
curve.Scalar.New(2),
|
||||
curve.Scalar.New(1),
|
||||
}
|
||||
poly2 := polynomial{
|
||||
curve.Scalar.New(1),
|
||||
curve.Scalar.New(2),
|
||||
curve.Scalar.New(3),
|
||||
}
|
||||
|
||||
output, err := poly1.Sub(poly2)
|
||||
require.Error(t, err)
|
||||
require.Nil(t, output)
|
||||
}
|
||||
|
||||
func TestMulAssignPoly(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
// Test polynomial with equal length
|
||||
poly1 := polynomial{
|
||||
curve.Scalar.New(3),
|
||||
curve.Scalar.New(2),
|
||||
curve.Scalar.New(1),
|
||||
}
|
||||
poly2 := polynomial{
|
||||
curve.Scalar.New(1),
|
||||
curve.Scalar.New(2),
|
||||
curve.Scalar.New(3),
|
||||
}
|
||||
|
||||
output, err := poly1.Mul(poly2)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, output)
|
||||
result := []curves.Scalar{
|
||||
curve.Scalar.New(3),
|
||||
curve.Scalar.New(8),
|
||||
curve.Scalar.New(14),
|
||||
curve.Scalar.New(8),
|
||||
curve.Scalar.New(3),
|
||||
}
|
||||
for i := 0; i < len(result); i++ {
|
||||
require.Equal(t, output[i].Bytes(), result[i].Bytes())
|
||||
}
|
||||
|
||||
// Test polynomials with unequal length
|
||||
poly3 := polynomial{
|
||||
curve.Scalar.New(1),
|
||||
curve.Scalar.New(2),
|
||||
}
|
||||
output2, err := poly1.Mul(poly3)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, output2)
|
||||
result2 := []curves.Scalar{
|
||||
curve.Scalar.New(3),
|
||||
curve.Scalar.New(8),
|
||||
curve.Scalar.New(5),
|
||||
curve.Scalar.New(2),
|
||||
}
|
||||
require.Equal(t, len(output2), 4)
|
||||
for i := 0; i < len(output2); i++ {
|
||||
require.Equal(t, output2[i].Bytes(), result2[i].Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMulAssignPolyError(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
poly1 := polynomial{
|
||||
nil,
|
||||
curve.Scalar.New(2),
|
||||
curve.Scalar.New(1),
|
||||
}
|
||||
poly2 := polynomial{
|
||||
curve.Scalar.New(1),
|
||||
curve.Scalar.New(2),
|
||||
curve.Scalar.New(3),
|
||||
}
|
||||
output, err := poly1.Mul(poly2)
|
||||
require.Error(t, err)
|
||||
require.Nil(t, output)
|
||||
}
|
||||
|
||||
func TestMulValueAssignPoly(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
poly := polynomial{
|
||||
curve.Scalar.New(3),
|
||||
curve.Scalar.New(2),
|
||||
curve.Scalar.New(1),
|
||||
}
|
||||
rhs := curve.Scalar.New(3)
|
||||
output, err := poly.MulScalar(rhs)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, output)
|
||||
coefficients2 := []curves.Scalar{
|
||||
curve.Scalar.New(9),
|
||||
curve.Scalar.New(6),
|
||||
curve.Scalar.New(3),
|
||||
}
|
||||
for i := 0; i < len(coefficients2); i++ {
|
||||
require.Equal(t, output[i].Bytes(), coefficients2[i].Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMulValueAssignPolyError(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
poly := polynomial{
|
||||
nil,
|
||||
curve.Scalar.New(2),
|
||||
curve.Scalar.New(1),
|
||||
}
|
||||
rhs := curve.Scalar.New(3)
|
||||
output, err := poly.MulScalar(rhs)
|
||||
require.Error(t, err)
|
||||
require.Nil(t, output)
|
||||
}
|
@ -1,518 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package accumulator
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
crand "crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.sr.ht/~sircmpwn/go-bare"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
type proofParamsMarshal struct {
|
||||
X []byte `bare:"x"`
|
||||
Y []byte `bare:"y"`
|
||||
Z []byte `bare:"z"`
|
||||
Curve string `bare:"curve"`
|
||||
}
|
||||
|
||||
// ProofParams contains four distinct public generators of G1 - X, Y, Z
|
||||
type ProofParams struct {
|
||||
x, y, z curves.Point
|
||||
}
|
||||
|
||||
// New samples X, Y, Z, K
|
||||
func (p *ProofParams) New(curve *curves.PairingCurve, pk *PublicKey, entropy []byte) (*ProofParams, error) {
|
||||
pkBytes, err := pk.MarshalBinary()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
prefix := bytes.Repeat([]byte{0xFF}, 32)
|
||||
data := append(prefix, entropy...)
|
||||
data = append(data, pkBytes...)
|
||||
p.z = curve.Scalar.Point().Hash(data)
|
||||
|
||||
data[0] = 0xFE
|
||||
p.y = curve.Scalar.Point().Hash(data)
|
||||
|
||||
data[0] = 0xFD
|
||||
p.x = curve.Scalar.Point().Hash(data)
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// MarshalBinary converts ProofParams to bytes
|
||||
func (p *ProofParams) MarshalBinary() ([]byte, error) {
|
||||
if p.x == nil || p.y == nil || p.z == nil {
|
||||
return nil, fmt.Errorf("some value x, y, or z is nil")
|
||||
}
|
||||
tv := &proofParamsMarshal{
|
||||
X: p.x.ToAffineCompressed(),
|
||||
Y: p.y.ToAffineCompressed(),
|
||||
Z: p.z.ToAffineCompressed(),
|
||||
Curve: p.x.CurveName(),
|
||||
}
|
||||
return bare.Marshal(tv)
|
||||
}
|
||||
|
||||
// UnmarshalBinary converts bytes to ProofParams
|
||||
func (p *ProofParams) UnmarshalBinary(data []byte) error {
|
||||
if data == nil {
|
||||
return fmt.Errorf("expected non-zero byte sequence")
|
||||
}
|
||||
tv := new(proofParamsMarshal)
|
||||
err := bare.Unmarshal(data, tv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
curve := curves.GetCurveByName(tv.Curve)
|
||||
if curve == nil {
|
||||
return fmt.Errorf("invalid curve")
|
||||
}
|
||||
x, err := curve.NewIdentityPoint().FromAffineCompressed(tv.X)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
y, err := curve.NewIdentityPoint().FromAffineCompressed(tv.Y)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
z, err := curve.NewIdentityPoint().FromAffineCompressed(tv.Z)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.x = x
|
||||
p.y = y
|
||||
p.z = z
|
||||
return nil
|
||||
}
|
||||
|
||||
// MembershipProofCommitting contains value computed in Proof of knowledge and
|
||||
// Blinding phases as described in section 7 of https://eprint.iacr.org/2020/777.pdf
|
||||
type MembershipProofCommitting struct {
|
||||
eC curves.Point
|
||||
tSigma curves.Point
|
||||
tRho curves.Point
|
||||
deltaSigma curves.Scalar
|
||||
deltaRho curves.Scalar
|
||||
blindingFactor curves.Scalar
|
||||
rSigma curves.Scalar
|
||||
rRho curves.Scalar
|
||||
rDeltaSigma curves.Scalar
|
||||
rDeltaRho curves.Scalar
|
||||
sigma curves.Scalar
|
||||
rho curves.Scalar
|
||||
capRSigma curves.Point
|
||||
capRRho curves.Point
|
||||
capRDeltaSigma curves.Point
|
||||
capRDeltaRho curves.Point
|
||||
capRE curves.Scalar
|
||||
accumulator curves.Point
|
||||
witnessValue curves.Scalar
|
||||
xG1 curves.Point
|
||||
yG1 curves.Point
|
||||
zG1 curves.Point
|
||||
}
|
||||
|
||||
// New initiates values of MembershipProofCommitting
|
||||
func (mpc *MembershipProofCommitting) New(
|
||||
witness *MembershipWitness,
|
||||
acc *Accumulator,
|
||||
pp *ProofParams,
|
||||
pk *PublicKey,
|
||||
) (*MembershipProofCommitting, error) {
|
||||
// Randomly select σ, ρ
|
||||
sigma := witness.y.Random(crand.Reader)
|
||||
rho := witness.y.Random(crand.Reader)
|
||||
|
||||
// E_C = C + (σ + ρ)Z
|
||||
t := sigma
|
||||
t = t.Add(rho)
|
||||
eC := pp.z
|
||||
eC = eC.Mul(t)
|
||||
eC = eC.Add(witness.c)
|
||||
|
||||
// T_σ = σX
|
||||
tSigma := pp.x
|
||||
tSigma = tSigma.Mul(sigma)
|
||||
|
||||
// T_ρ = ρY
|
||||
tRho := pp.y
|
||||
tRho = tRho.Mul(rho)
|
||||
|
||||
// δ_σ = yσ
|
||||
deltaSigma := witness.y
|
||||
deltaSigma = deltaSigma.Mul(sigma)
|
||||
|
||||
// δ_ρ = yρ
|
||||
deltaRho := witness.y
|
||||
deltaRho = deltaRho.Mul(rho)
|
||||
|
||||
// Randomly pick r_σ,r_ρ,r_δσ,r_δρ
|
||||
rY := witness.y.Random(crand.Reader)
|
||||
rSigma := witness.y.Random(crand.Reader)
|
||||
rRho := witness.y.Random(crand.Reader)
|
||||
rDeltaSigma := witness.y.Random(crand.Reader)
|
||||
rDeltaRho := witness.y.Random(crand.Reader)
|
||||
|
||||
// R_σ = r_σ X
|
||||
capRSigma := pp.x
|
||||
capRSigma = capRSigma.Mul(rSigma)
|
||||
|
||||
// R_ρ = ρY
|
||||
capRRho := pp.y
|
||||
capRRho = capRRho.Mul(rRho)
|
||||
|
||||
// R_δσ = r_y T_σ - r_δσ X
|
||||
negX := pp.x
|
||||
negX = negX.Neg()
|
||||
capRDeltaSigma := tSigma.Mul(rY)
|
||||
capRDeltaSigma = capRDeltaSigma.Add(negX.Mul(rDeltaSigma))
|
||||
|
||||
// R_δρ = r_y T_ρ - r_δρ Y
|
||||
negY := pp.y
|
||||
negY = negY.Neg()
|
||||
capRDeltaRho := tRho.Mul(rY)
|
||||
capRDeltaRho = capRDeltaRho.Add(negY.Mul(rDeltaRho))
|
||||
|
||||
// P~
|
||||
g2 := pk.value.Generator()
|
||||
|
||||
// -r_δσ - r_δρ
|
||||
exp := rDeltaSigma
|
||||
exp = exp.Add(rDeltaRho)
|
||||
exp = exp.Neg()
|
||||
|
||||
// -r_σ - r_ρ
|
||||
exp2 := rSigma
|
||||
exp2 = exp2.Add(rRho)
|
||||
exp2 = exp2.Neg()
|
||||
|
||||
// rY * eC
|
||||
rYeC := eC.Mul(rY)
|
||||
|
||||
// (-r_δσ - r_δρ)*Z
|
||||
expZ := pp.z.Mul(exp)
|
||||
|
||||
// (-r_σ - r_ρ)*Z
|
||||
exp2Z := pp.z.Mul(exp2)
|
||||
|
||||
// Prepare
|
||||
rYeCPrep, ok := rYeC.(curves.PairingPoint)
|
||||
if !ok {
|
||||
return nil, errors.New("incorrect type conversion")
|
||||
}
|
||||
g2Prep, ok := g2.(curves.PairingPoint)
|
||||
if !ok {
|
||||
return nil, errors.New("incorrect type conversion")
|
||||
}
|
||||
expZPrep, ok := expZ.(curves.PairingPoint)
|
||||
if !ok {
|
||||
return nil, errors.New("incorrect type conversion")
|
||||
}
|
||||
exp2ZPrep, ok := exp2Z.(curves.PairingPoint)
|
||||
if !ok {
|
||||
return nil, errors.New("incorrect type conversion")
|
||||
}
|
||||
pkPrep := pk.value
|
||||
|
||||
// Pairing
|
||||
capRE := g2Prep.MultiPairing(rYeCPrep, g2Prep, expZPrep, g2Prep, exp2ZPrep, pkPrep)
|
||||
|
||||
return &MembershipProofCommitting{
|
||||
eC,
|
||||
tSigma,
|
||||
tRho,
|
||||
deltaSigma,
|
||||
deltaRho,
|
||||
rY,
|
||||
rSigma,
|
||||
rRho,
|
||||
rDeltaSigma,
|
||||
rDeltaRho,
|
||||
sigma,
|
||||
rho,
|
||||
capRSigma,
|
||||
capRRho,
|
||||
capRDeltaSigma,
|
||||
capRDeltaRho,
|
||||
capRE,
|
||||
acc.value,
|
||||
witness.y,
|
||||
pp.x,
|
||||
pp.y,
|
||||
pp.z,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetChallenge returns bytes that need to be hashed for generating challenge.
|
||||
// V || Ec || T_sigma || T_rho || R_E || R_sigma || R_rho || R_delta_sigma || R_delta_rho
|
||||
func (mpc MembershipProofCommitting) GetChallengeBytes() []byte {
|
||||
res := mpc.accumulator.ToAffineCompressed()
|
||||
res = append(res, mpc.eC.ToAffineCompressed()...)
|
||||
res = append(res, mpc.tSigma.ToAffineCompressed()...)
|
||||
res = append(res, mpc.tRho.ToAffineCompressed()...)
|
||||
res = append(res, mpc.capRE.Bytes()...)
|
||||
res = append(res, mpc.capRSigma.ToAffineCompressed()...)
|
||||
res = append(res, mpc.capRRho.ToAffineCompressed()...)
|
||||
res = append(res, mpc.capRDeltaSigma.ToAffineCompressed()...)
|
||||
res = append(res, mpc.capRDeltaRho.ToAffineCompressed()...)
|
||||
return res
|
||||
}
|
||||
|
||||
// GenProof computes the s values for Fiat-Shamir and return the actual
|
||||
// proof to be sent to the verifier given the challenge c.
|
||||
func (mpc *MembershipProofCommitting) GenProof(c curves.Scalar) *MembershipProof {
|
||||
// s_y = r_y + c*y
|
||||
sY := schnorr(mpc.blindingFactor, mpc.witnessValue, c)
|
||||
// s_σ = r_σ + c*σ
|
||||
sSigma := schnorr(mpc.rSigma, mpc.sigma, c)
|
||||
// s_ρ = r_ρ + c*ρ
|
||||
sRho := schnorr(mpc.rRho, mpc.rho, c)
|
||||
// s_δσ = rδσ + c*δ_σ
|
||||
sDeltaSigma := schnorr(mpc.rDeltaSigma, mpc.deltaSigma, c)
|
||||
// s_δρ = rδρ + c*δ_ρ
|
||||
sDeltaRho := schnorr(mpc.rDeltaRho, mpc.deltaRho, c)
|
||||
|
||||
return &MembershipProof{
|
||||
mpc.eC,
|
||||
mpc.tSigma,
|
||||
mpc.tRho,
|
||||
sSigma,
|
||||
sRho,
|
||||
sDeltaSigma,
|
||||
sDeltaRho,
|
||||
sY,
|
||||
}
|
||||
}
|
||||
|
||||
func schnorr(r, v, challenge curves.Scalar) curves.Scalar {
|
||||
res := v
|
||||
res = res.Mul(challenge)
|
||||
res = res.Add(r)
|
||||
return res
|
||||
}
|
||||
|
||||
type membershipProofMarshal struct {
|
||||
EC []byte `bare:"e_c"`
|
||||
TSigma []byte `bare:"t_sigma"`
|
||||
TRho []byte `bare:"t_rho"`
|
||||
SSigma []byte `bare:"s_sigma"`
|
||||
SRho []byte `bare:"s_rho"`
|
||||
SDeltaSigma []byte `bare:"s_delta_sigma"`
|
||||
SDeltaRho []byte `bare:"s_delta_rho"`
|
||||
SY []byte `bare:"s_y"`
|
||||
Curve string `bare:"curve"`
|
||||
}
|
||||
|
||||
// MembershipProof contains values in the proof to be verified
|
||||
type MembershipProof struct {
|
||||
eC curves.Point
|
||||
tSigma curves.Point
|
||||
tRho curves.Point
|
||||
sSigma curves.Scalar
|
||||
sRho curves.Scalar
|
||||
sDeltaSigma curves.Scalar
|
||||
sDeltaRho curves.Scalar
|
||||
sY curves.Scalar
|
||||
}
|
||||
|
||||
// Finalize computes values in the proof to be verified.
|
||||
func (mp *MembershipProof) Finalize(acc *Accumulator, pp *ProofParams, pk *PublicKey, challenge curves.Scalar) (*MembershipProofFinal, error) {
|
||||
// R_σ = s_δ X + c T_σ
|
||||
negTSigma := mp.tSigma
|
||||
negTSigma = negTSigma.Neg()
|
||||
capRSigma := pp.x.Mul(mp.sSigma)
|
||||
capRSigma = capRSigma.Add(negTSigma.Mul(challenge))
|
||||
|
||||
// R_ρ = s_ρ Y + c T_ρ
|
||||
negTRho := mp.tRho
|
||||
negTRho = negTRho.Neg()
|
||||
capRRho := pp.y.Mul(mp.sRho)
|
||||
capRRho = capRRho.Add(negTRho.Mul(challenge))
|
||||
|
||||
// R_δσ = s_y T_σ - s_δσ X
|
||||
negX := pp.x
|
||||
negX = negX.Neg()
|
||||
capRDeltaSigma := mp.tSigma.Mul(mp.sY)
|
||||
capRDeltaSigma = capRDeltaSigma.Add(negX.Mul(mp.sDeltaSigma))
|
||||
|
||||
// R_δρ = s_y T_ρ - s_δρ Y
|
||||
negY := pp.y
|
||||
negY = negY.Neg()
|
||||
capRDeltaRho := mp.tRho.Mul(mp.sY)
|
||||
capRDeltaRho = capRDeltaRho.Add(negY.Mul(mp.sDeltaRho))
|
||||
|
||||
// tildeP
|
||||
g2 := pk.value.Generator()
|
||||
|
||||
// Compute capRE, the pairing
|
||||
// E_c * s_y
|
||||
eCsY := mp.eC.Mul(mp.sY)
|
||||
|
||||
// (-s_delta_sigma - s_delta_rho) * Z
|
||||
exp := mp.sDeltaSigma
|
||||
exp = exp.Add(mp.sDeltaRho)
|
||||
exp = exp.Neg()
|
||||
expZ := pp.z.Mul(exp)
|
||||
|
||||
// (-c) * V
|
||||
exp = challenge.Neg()
|
||||
expV := acc.value.Mul(exp)
|
||||
|
||||
// E_c * s_y + (-s_delta_sigma - s_delta_rho) * Z + (-c) * V
|
||||
lhs := eCsY.Add(expZ).Add(expV)
|
||||
|
||||
// (-s_sigma - s_rho) * Z
|
||||
exp = mp.sSigma
|
||||
exp = exp.Add(mp.sRho)
|
||||
exp = exp.Neg()
|
||||
expZ2 := pp.z.Mul(exp)
|
||||
|
||||
// E_c * c
|
||||
cEc := mp.eC.Mul(challenge)
|
||||
|
||||
// (-s_sigma - s_rho) * Z + E_c * c
|
||||
rhs := cEc.Add(expZ2)
|
||||
|
||||
// Prepare
|
||||
lhsPrep, ok := lhs.(curves.PairingPoint)
|
||||
if !ok {
|
||||
return nil, errors.New("incorrect type conversion")
|
||||
}
|
||||
g2Prep, ok := g2.(curves.PairingPoint)
|
||||
if !ok {
|
||||
return nil, errors.New("incorrect type conversion")
|
||||
}
|
||||
rhsPrep, ok := rhs.(curves.PairingPoint)
|
||||
if !ok {
|
||||
return nil, errors.New("incorrect type conversion")
|
||||
}
|
||||
pkPrep := pk.value
|
||||
|
||||
// capRE
|
||||
capRE := g2Prep.MultiPairing(lhsPrep, g2Prep, rhsPrep, pkPrep)
|
||||
|
||||
return &MembershipProofFinal{
|
||||
acc.value,
|
||||
mp.eC,
|
||||
mp.tSigma,
|
||||
mp.tRho,
|
||||
capRE,
|
||||
capRSigma,
|
||||
capRRho,
|
||||
capRDeltaSigma,
|
||||
capRDeltaRho,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// MarshalBinary converts MembershipProof to bytes
|
||||
func (mp MembershipProof) MarshalBinary() ([]byte, error) {
|
||||
tv := &membershipProofMarshal{
|
||||
EC: mp.eC.ToAffineCompressed(),
|
||||
TSigma: mp.tSigma.ToAffineCompressed(),
|
||||
TRho: mp.tRho.ToAffineCompressed(),
|
||||
SSigma: mp.sSigma.Bytes(),
|
||||
SRho: mp.sRho.Bytes(),
|
||||
SDeltaSigma: mp.sDeltaSigma.Bytes(),
|
||||
SDeltaRho: mp.sDeltaRho.Bytes(),
|
||||
SY: mp.sY.Bytes(),
|
||||
Curve: mp.eC.CurveName(),
|
||||
}
|
||||
return bare.Marshal(tv)
|
||||
}
|
||||
|
||||
// UnmarshalBinary converts bytes to MembershipProof
|
||||
func (mp *MembershipProof) UnmarshalBinary(data []byte) error {
|
||||
if data == nil {
|
||||
return fmt.Errorf("expected non-zero byte sequence")
|
||||
}
|
||||
tv := new(membershipProofMarshal)
|
||||
err := bare.Unmarshal(data, tv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
curve := curves.GetCurveByName(tv.Curve)
|
||||
if curve == nil {
|
||||
return fmt.Errorf("invalid curve")
|
||||
}
|
||||
eC, err := curve.NewIdentityPoint().FromAffineCompressed(tv.EC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tSigma, err := curve.NewIdentityPoint().FromAffineCompressed(tv.TSigma)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tRho, err := curve.NewIdentityPoint().FromAffineCompressed(tv.TRho)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sSigma, err := curve.NewScalar().SetBytes(tv.SSigma)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sRho, err := curve.NewScalar().SetBytes(tv.SRho)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sDeltaSigma, err := curve.NewScalar().SetBytes(tv.SDeltaSigma)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sDeltaRho, err := curve.NewScalar().SetBytes(tv.SDeltaRho)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sY, err := curve.NewScalar().SetBytes(tv.SY)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mp.eC = eC
|
||||
mp.tSigma = tSigma
|
||||
mp.tRho = tRho
|
||||
mp.sSigma = sSigma
|
||||
mp.sRho = sRho
|
||||
mp.sDeltaSigma = sDeltaSigma
|
||||
mp.sDeltaRho = sDeltaRho
|
||||
mp.sY = sY
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MembershipProofFinal contains values that are input to Fiat-Shamir Heuristic
|
||||
type MembershipProofFinal struct {
|
||||
accumulator curves.Point
|
||||
eC curves.Point
|
||||
tSigma curves.Point
|
||||
tRho curves.Point
|
||||
capRE curves.Scalar
|
||||
capRSigma curves.Point
|
||||
capRRho curves.Point
|
||||
capRDeltaSigma curves.Point
|
||||
capRDeltaRho curves.Point
|
||||
}
|
||||
|
||||
// GetChallenge computes Fiat-Shamir Heuristic taking input values of MembershipProofFinal
|
||||
func (m MembershipProofFinal) GetChallenge(curve *curves.PairingCurve) curves.Scalar {
|
||||
res := m.accumulator.ToAffineCompressed()
|
||||
res = append(res, m.eC.ToAffineCompressed()...)
|
||||
res = append(res, m.tSigma.ToAffineCompressed()...)
|
||||
res = append(res, m.tRho.ToAffineCompressed()...)
|
||||
res = append(res, m.capRE.Bytes()...)
|
||||
res = append(res, m.capRSigma.ToAffineCompressed()...)
|
||||
res = append(res, m.capRRho.ToAffineCompressed()...)
|
||||
res = append(res, m.capRDeltaSigma.ToAffineCompressed()...)
|
||||
res = append(res, m.capRDeltaRho.ToAffineCompressed()...)
|
||||
challenge := curve.Scalar.Hash(res)
|
||||
return challenge
|
||||
}
|
@ -1,182 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package accumulator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
func TestProofParamsMarshal(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
sk, _ := new(SecretKey).New(curve, []byte("1234567890"))
|
||||
pk, _ := sk.GetPublicKey(curve)
|
||||
|
||||
params, err := new(ProofParams).New(curve, pk, []byte("entropy"))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, params.x)
|
||||
require.NotNil(t, params.y)
|
||||
require.NotNil(t, params.z)
|
||||
|
||||
bytes, err := params.MarshalBinary()
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, bytes)
|
||||
|
||||
params2 := &ProofParams{
|
||||
curve.PointG1.Generator(),
|
||||
curve.PointG1.Generator(),
|
||||
curve.PointG1.Generator(),
|
||||
}
|
||||
err = params2.UnmarshalBinary(bytes)
|
||||
require.NoError(t, err)
|
||||
require.True(t, params.x.Equal(params2.x))
|
||||
require.True(t, params.y.Equal(params2.y))
|
||||
require.True(t, params.z.Equal(params2.z))
|
||||
}
|
||||
|
||||
func TestMembershipProof(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
sk, _ := new(SecretKey).New(curve, []byte("1234567890"))
|
||||
pk, _ := sk.GetPublicKey(curve)
|
||||
|
||||
element1 := curve.Scalar.Hash([]byte("3"))
|
||||
element2 := curve.Scalar.Hash([]byte("4"))
|
||||
element3 := curve.Scalar.Hash([]byte("5"))
|
||||
element4 := curve.Scalar.Hash([]byte("6"))
|
||||
element5 := curve.Scalar.Hash([]byte("7"))
|
||||
element6 := curve.Scalar.Hash([]byte("8"))
|
||||
element7 := curve.Scalar.Hash([]byte("9"))
|
||||
elements := []Element{element1, element2, element3, element4, element5, element6, element7}
|
||||
|
||||
// Initiate a new accumulator
|
||||
acc, err := new(Accumulator).WithElements(curve, sk, elements)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, acc.value)
|
||||
|
||||
// Initiate a new membership witness for value elements[3]
|
||||
wit, err := new(MembershipWitness).New(elements[3], acc, sk)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, wit.y, elements[3])
|
||||
|
||||
// Create proof parameters, which contains randomly sampled G1 points X, Y, Z, K
|
||||
params, err := new(ProofParams).New(curve, pk, []byte("entropy"))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, params.x)
|
||||
require.NotNil(t, params.y)
|
||||
require.NotNil(t, params.z)
|
||||
|
||||
mpc, err := new(MembershipProofCommitting).New(wit, acc, params, pk)
|
||||
require.NoError(t, err)
|
||||
testMPC(t, mpc)
|
||||
|
||||
challenge := curve.Scalar.Hash(mpc.GetChallengeBytes())
|
||||
require.NotNil(t, challenge)
|
||||
|
||||
proof := mpc.GenProof(challenge)
|
||||
require.NotNil(t, proof)
|
||||
testProof(t, proof)
|
||||
|
||||
finalProof, err := proof.Finalize(acc, params, pk, challenge)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, finalProof)
|
||||
testFinalProof(t, finalProof)
|
||||
|
||||
challenge2 := finalProof.GetChallenge(curve)
|
||||
require.Equal(t, challenge, challenge2)
|
||||
|
||||
// Check we can still have a valid proof even if accumulator and witness are updated
|
||||
data1 := curve.Scalar.Hash([]byte("1"))
|
||||
data2 := curve.Scalar.Hash([]byte("2"))
|
||||
data3 := curve.Scalar.Hash([]byte("3"))
|
||||
data4 := curve.Scalar.Hash([]byte("4"))
|
||||
data5 := curve.Scalar.Hash([]byte("5"))
|
||||
data := []Element{data1, data2, data3, data4, data5}
|
||||
additions := data[0:2]
|
||||
deletions := data[2:5]
|
||||
_, coefficients, err := acc.Update(sk, additions, deletions)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, coefficients)
|
||||
|
||||
_, err = wit.BatchUpdate(additions, deletions, coefficients)
|
||||
require.NoError(t, err)
|
||||
|
||||
newParams, err := new(ProofParams).New(curve, pk, []byte("entropy"))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, newParams.x)
|
||||
require.NotNil(t, newParams.y)
|
||||
require.NotNil(t, newParams.z)
|
||||
|
||||
newMPC, err := new(MembershipProofCommitting).New(wit, acc, newParams, pk)
|
||||
require.NoError(t, err)
|
||||
testMPC(t, newMPC)
|
||||
|
||||
challenge3 := curve.Scalar.Hash(newMPC.GetChallengeBytes())
|
||||
require.NotNil(t, challenge3)
|
||||
|
||||
newProof := newMPC.GenProof(challenge3)
|
||||
require.NotNil(t, newProof)
|
||||
testProof(t, newProof)
|
||||
|
||||
newFinalProof, err := newProof.Finalize(acc, newParams, pk, challenge3)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, newFinalProof)
|
||||
testFinalProof(t, newFinalProof)
|
||||
|
||||
challenge4 := newFinalProof.GetChallenge(curve)
|
||||
require.Equal(t, challenge3, challenge4)
|
||||
}
|
||||
|
||||
func testMPC(t *testing.T, mpc *MembershipProofCommitting) {
|
||||
require.NotNil(t, mpc.eC)
|
||||
require.NotNil(t, mpc.tSigma)
|
||||
require.NotNil(t, mpc.tRho)
|
||||
require.NotNil(t, mpc.deltaSigma)
|
||||
require.NotNil(t, mpc.deltaRho)
|
||||
require.NotNil(t, mpc.blindingFactor)
|
||||
require.NotNil(t, mpc.rSigma)
|
||||
require.NotNil(t, mpc.rRho)
|
||||
require.NotNil(t, mpc.rDeltaSigma)
|
||||
require.NotNil(t, mpc.rDeltaRho)
|
||||
require.NotNil(t, mpc.sigma)
|
||||
require.NotNil(t, mpc.rho)
|
||||
require.NotNil(t, mpc.capRSigma)
|
||||
require.NotNil(t, mpc.capRRho)
|
||||
require.NotNil(t, mpc.capRDeltaSigma)
|
||||
require.NotNil(t, mpc.capRDeltaRho)
|
||||
require.NotNil(t, mpc.capRE)
|
||||
require.NotNil(t, mpc.accumulator)
|
||||
require.NotNil(t, mpc.witnessValue)
|
||||
require.NotNil(t, mpc.xG1)
|
||||
require.NotNil(t, mpc.yG1)
|
||||
require.NotNil(t, mpc.zG1)
|
||||
}
|
||||
|
||||
func testProof(t *testing.T, proof *MembershipProof) {
|
||||
require.NotNil(t, proof.eC)
|
||||
require.NotNil(t, proof.tSigma)
|
||||
require.NotNil(t, proof.tRho)
|
||||
require.NotNil(t, proof.sSigma)
|
||||
require.NotNil(t, proof.sRho)
|
||||
require.NotNil(t, proof.sDeltaSigma)
|
||||
require.NotNil(t, proof.sDeltaRho)
|
||||
require.NotNil(t, proof.sY)
|
||||
}
|
||||
|
||||
func testFinalProof(t *testing.T, finalProof *MembershipProofFinal) {
|
||||
require.NotNil(t, finalProof.accumulator)
|
||||
require.NotNil(t, finalProof.eC)
|
||||
require.NotNil(t, finalProof.tSigma)
|
||||
require.NotNil(t, finalProof.tRho)
|
||||
require.NotNil(t, finalProof.capRE)
|
||||
require.NotNil(t, finalProof.capRSigma)
|
||||
require.NotNil(t, finalProof.capRRho)
|
||||
require.NotNil(t, finalProof.capRDeltaSigma)
|
||||
require.NotNil(t, finalProof.capRDeltaRho)
|
||||
}
|
@ -1,375 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package accumulator
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.sr.ht/~sircmpwn/go-bare"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
// MembershipWitness contains the witness c and the value y respect to the accumulator state.
|
||||
type MembershipWitness struct {
|
||||
c curves.Point
|
||||
y curves.Scalar
|
||||
}
|
||||
|
||||
// New creates a new membership witness
|
||||
func (mw *MembershipWitness) New(y Element, acc *Accumulator, sk *SecretKey) (*MembershipWitness, error) {
|
||||
if acc.value == nil || acc.value.IsIdentity() {
|
||||
return nil, fmt.Errorf("value of accumulator should not be nil")
|
||||
}
|
||||
if sk.value == nil || sk.value.IsZero() {
|
||||
return nil, fmt.Errorf("secret key should not be nil")
|
||||
}
|
||||
if y == nil || y.IsZero() {
|
||||
return nil, fmt.Errorf("y should not be nil")
|
||||
}
|
||||
newAcc := &Accumulator{acc.value}
|
||||
_, err := newAcc.Remove(sk, y)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mw.c = newAcc.value
|
||||
mw.y = y.Add(y.Zero())
|
||||
return mw, nil
|
||||
}
|
||||
|
||||
// Verify the MembershipWitness mw is a valid witness as per section 4 in
|
||||
// <https://eprint.iacr.org/2020/777>
|
||||
func (mw MembershipWitness) Verify(pk *PublicKey, acc *Accumulator) error {
|
||||
if mw.c == nil || mw.y == nil || mw.c.IsIdentity() || mw.y.IsZero() {
|
||||
return fmt.Errorf("c and y should not be nil")
|
||||
}
|
||||
|
||||
if pk.value == nil || pk.value.IsIdentity() {
|
||||
return fmt.Errorf("invalid public key")
|
||||
}
|
||||
if acc.value == nil || acc.value.IsIdentity() {
|
||||
return fmt.Errorf("accumulator value should not be nil")
|
||||
}
|
||||
|
||||
// Set -tildeP
|
||||
g2, ok := pk.value.Generator().(curves.PairingPoint)
|
||||
if !ok {
|
||||
return errors.New("incorrect type conversion")
|
||||
}
|
||||
|
||||
// y*tildeP + tildeQ, tildeP is a G2 generator.
|
||||
p, ok := g2.Mul(mw.y).Add(pk.value).(curves.PairingPoint)
|
||||
if !ok {
|
||||
return errors.New("incorrect type conversion")
|
||||
}
|
||||
|
||||
// Prepare
|
||||
witness, ok := mw.c.(curves.PairingPoint)
|
||||
if !ok {
|
||||
return errors.New("incorrect type conversion")
|
||||
}
|
||||
v, ok := acc.value.Neg().(curves.PairingPoint)
|
||||
if !ok {
|
||||
return errors.New("incorrect type conversion")
|
||||
}
|
||||
|
||||
// Check e(witness, y*tildeP + tildeQ) * e(-acc, tildeP) == Identity
|
||||
result := p.MultiPairing(witness, p, v, g2)
|
||||
if !result.IsOne() {
|
||||
return fmt.Errorf("invalid result")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyDelta returns C' = dA(y)/dD(y)*C + 1/dD(y) * <Gamma_y, Omega>
|
||||
// according to the witness update protocol described in section 4 of
|
||||
// https://eprint.iacr.org/2020/777.pdf
|
||||
func (mw *MembershipWitness) ApplyDelta(delta *Delta) (*MembershipWitness, error) {
|
||||
if mw.c == nil || mw.y == nil || delta == nil {
|
||||
return nil, fmt.Errorf("y, c or delta should not be nil")
|
||||
}
|
||||
|
||||
// C' = dA(y)/dD(y)*C + 1/dD(y) * <Gamma_y, Omega>
|
||||
mw.c = mw.c.Mul(delta.d).Add(delta.p)
|
||||
return mw, nil
|
||||
}
|
||||
|
||||
// BatchUpdate performs batch update as described in section 4
|
||||
func (mw *MembershipWitness) BatchUpdate(additions []Element, deletions []Element, coefficients []Coefficient) (*MembershipWitness, error) {
|
||||
delta, err := evaluateDelta(mw.y, additions, deletions, coefficients)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mw, err = mw.ApplyDelta(delta)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("applyDelta fails")
|
||||
}
|
||||
return mw, nil
|
||||
}
|
||||
|
||||
// MultiBatchUpdate performs multi-batch update using epoch as described in section 4.2
|
||||
func (mw *MembershipWitness) MultiBatchUpdate(A [][]Element, D [][]Element, C [][]Coefficient) (*MembershipWitness, error) {
|
||||
delta, err := evaluateDeltas(mw.y, A, D, C)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("evaluateDeltas fails")
|
||||
}
|
||||
mw, err = mw.ApplyDelta(delta)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mw, nil
|
||||
}
|
||||
|
||||
// MarshalBinary converts a membership witness to bytes
|
||||
func (mw MembershipWitness) MarshalBinary() ([]byte, error) {
|
||||
if mw.c == nil || mw.y == nil {
|
||||
return nil, fmt.Errorf("c and y value should not be nil")
|
||||
}
|
||||
|
||||
result := append(mw.c.ToAffineCompressed(), mw.y.Bytes()...)
|
||||
tv := &structMarshal{
|
||||
Value: result,
|
||||
Curve: mw.c.CurveName(),
|
||||
}
|
||||
return bare.Marshal(tv)
|
||||
}
|
||||
|
||||
// UnmarshalBinary converts bytes into MembershipWitness
|
||||
func (mw *MembershipWitness) UnmarshalBinary(data []byte) error {
|
||||
if data == nil {
|
||||
return fmt.Errorf("input data should not be nil")
|
||||
}
|
||||
tv := new(structMarshal)
|
||||
err := bare.Unmarshal(data, tv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
curve := curves.GetCurveByName(tv.Curve)
|
||||
if curve == nil {
|
||||
return fmt.Errorf("invalid curve")
|
||||
}
|
||||
|
||||
ptLength := len(curve.Point.ToAffineCompressed())
|
||||
scLength := len(curve.Scalar.Bytes())
|
||||
expectedLength := ptLength + scLength
|
||||
if len(tv.Value) != expectedLength {
|
||||
return fmt.Errorf("invalid byte sequence")
|
||||
}
|
||||
cValue, err := curve.Point.FromAffineCompressed(tv.Value[:ptLength])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
yValue, err := curve.Scalar.SetBytes(tv.Value[ptLength:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mw.c = cValue
|
||||
mw.y = yValue
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delta contains values d and p, where d should be the division dA(y)/dD(y) on some value y
|
||||
// p should be equal to 1/dD * <Gamma_y, Omega>
|
||||
type Delta struct {
|
||||
d curves.Scalar
|
||||
p curves.Point
|
||||
}
|
||||
|
||||
// MarshalBinary converts Delta into bytes
|
||||
func (d *Delta) MarshalBinary() ([]byte, error) {
|
||||
if d.d == nil || d.p == nil {
|
||||
return nil, fmt.Errorf("d and p should not be nil")
|
||||
}
|
||||
var result []byte
|
||||
result = append(result, d.p.ToAffineCompressed()...)
|
||||
result = append(result, d.d.Bytes()...)
|
||||
tv := &structMarshal{
|
||||
Value: result,
|
||||
Curve: d.p.CurveName(),
|
||||
}
|
||||
return bare.Marshal(tv)
|
||||
}
|
||||
|
||||
// UnmarshalBinary converts data into Delta
|
||||
func (d *Delta) UnmarshalBinary(data []byte) error {
|
||||
if data == nil {
|
||||
return fmt.Errorf("expected non-zero byte sequence")
|
||||
}
|
||||
|
||||
tv := new(structMarshal)
|
||||
err := bare.Unmarshal(data, tv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
curve := curves.GetCurveByName(tv.Curve)
|
||||
if curve == nil {
|
||||
return fmt.Errorf("invalid curve")
|
||||
}
|
||||
|
||||
ptLength := len(curve.Point.ToAffineCompressed())
|
||||
scLength := len(curve.Scalar.Bytes())
|
||||
expectedLength := ptLength + scLength
|
||||
if len(tv.Value) != expectedLength {
|
||||
return fmt.Errorf("invalid byte sequence")
|
||||
}
|
||||
pValue, err := curve.NewIdentityPoint().FromAffineCompressed(tv.Value[:ptLength])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dValue, err := curve.NewScalar().SetBytes(tv.Value[ptLength:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.d = dValue
|
||||
d.p = pValue
|
||||
return nil
|
||||
}
|
||||
|
||||
// evaluateDeltas compute values used for membership witness batch update with epoch
|
||||
// as described in section 4.2, page 11 of https://eprint.iacr.org/2020/777.pdf
|
||||
func evaluateDeltas(y Element, A [][]Element, D [][]Element, C [][]Coefficient) (*Delta, error) {
|
||||
if len(A) != len(D) || len(A) != len(C) {
|
||||
return nil, fmt.Errorf("a, d, c should have same length")
|
||||
}
|
||||
|
||||
one := y.One()
|
||||
size := len(A)
|
||||
|
||||
// dA(x) = ∏ 1..n (yA_i - x)
|
||||
aa := make([]curves.Scalar, 0)
|
||||
// dD(x) = ∏ 1..m (yD_i - x)
|
||||
dd := make([]curves.Scalar, 0)
|
||||
|
||||
a := one
|
||||
d := one
|
||||
|
||||
// dA_{a->b}(y) = ∏ a..b dAs(y)
|
||||
// dD_{a->b}(y) = ∏ a..b dDs(y)
|
||||
for i := 0; i < size; i++ {
|
||||
adds := A[i]
|
||||
dels := D[i]
|
||||
|
||||
// ta = dAs(y)
|
||||
ta, err := dad(adds, y)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dad on additions fails")
|
||||
}
|
||||
// td = dDs(y)
|
||||
td, err := dad(dels, y)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dad on deletions fails")
|
||||
}
|
||||
// ∏ a..b dAs(y)
|
||||
a = a.Mul(ta)
|
||||
// ∏ a..b dDs(y)
|
||||
d = d.Mul(td)
|
||||
|
||||
aa = append(aa, ta)
|
||||
dd = append(dd, td)
|
||||
}
|
||||
|
||||
// If this fails, then this value was removed.
|
||||
d, err := d.Invert()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("no inverse exists")
|
||||
}
|
||||
|
||||
// <Gamma_y, Omega>
|
||||
p := make(polynomialPoint, 0, size)
|
||||
|
||||
// Ωi->j+1 = ∑ 1..t (dAt * dDt-1) · Ω
|
||||
for i := 0; i < size; i++ {
|
||||
// t = i+1
|
||||
// ∏^(t-1)_(h=i+1)
|
||||
ddh := one
|
||||
|
||||
// dDi→t−1 (y)
|
||||
for h := 0; h < i; h++ {
|
||||
ddh = ddh.Mul(dd[h])
|
||||
}
|
||||
|
||||
// ∏^(j+1)_(k=t+1)
|
||||
dak := one
|
||||
// dAt->j(y)
|
||||
for k := i + 1; k < size; k++ {
|
||||
dak = dak.Mul(aa[k])
|
||||
}
|
||||
|
||||
// dDi->t-1(y) * dAt->j(y)
|
||||
dak = dak.Mul(ddh)
|
||||
pp := make(polynomialPoint, len(C[i]))
|
||||
for j := 0; j < len(pp); j++ {
|
||||
pp[j] = C[i][j]
|
||||
}
|
||||
|
||||
// dDi->t-1(y) * dAt->j(y) · Ω
|
||||
pp, err := pp.Mul(dak)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pp.Mul fails")
|
||||
}
|
||||
|
||||
p, err = p.Add(pp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pp.Add fails")
|
||||
}
|
||||
}
|
||||
// dAi->j(y)/dDi->j(y)
|
||||
a = a.Mul(d)
|
||||
|
||||
// Ωi->j(y)
|
||||
v, err := p.evaluate(y)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("p.evaluate fails")
|
||||
}
|
||||
|
||||
// (1/dDi->j(y)) * Ωi->j(y)
|
||||
v = v.Mul(d)
|
||||
|
||||
// return
|
||||
return &Delta{d: a, p: v}, nil
|
||||
}
|
||||
|
||||
// evaluateDelta computes values used for membership witness batch update
|
||||
// as described in section 4.1 of https://eprint.iacr.org/2020/777.pdf
|
||||
func evaluateDelta(y Element, additions []Element, deletions []Element, coefficients []Coefficient) (*Delta, error) {
|
||||
// dD(y) = ∏ 1..m (yD_i - y), d = 1/dD(y)
|
||||
var err error
|
||||
d, err := dad(deletions, y)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dad fails on deletions")
|
||||
}
|
||||
d, err = d.Invert()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("no inverse exists")
|
||||
}
|
||||
|
||||
// dA(y) = ∏ 1..n (yA_i - y)
|
||||
a, err := dad(additions, y)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dad fails on additions")
|
||||
}
|
||||
// dA(y)/dD(y)
|
||||
a = a.Mul(d)
|
||||
|
||||
// Create a PolynomialG1 from coefficients
|
||||
p := make(polynomialPoint, len(coefficients))
|
||||
for i := 0; i < len(coefficients); i++ {
|
||||
p[i] = coefficients[i]
|
||||
}
|
||||
|
||||
// <Gamma_y, Omega>
|
||||
v, err := p.evaluate(y)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("p.evaluate fails")
|
||||
}
|
||||
// 1/dD * <Gamma_y, Omega>
|
||||
v = v.Mul(d)
|
||||
|
||||
return &Delta{d: a, p: v}, nil
|
||||
}
|
@ -1,229 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package accumulator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
func Test_Membership_Witness_New(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
var seed [32]byte
|
||||
key, _ := new(SecretKey).New(curve, seed[:])
|
||||
acc, _ := new(Accumulator).New(curve)
|
||||
e := curve.Scalar.New(2)
|
||||
mw, err := new(MembershipWitness).New(e, acc, key)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, mw.c)
|
||||
require.NotNil(t, mw.y)
|
||||
}
|
||||
|
||||
func Test_Membership_Witness_Marshal(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
mw := &MembershipWitness{
|
||||
curve.PointG1.Generator().Mul(curve.Scalar.New(10)),
|
||||
curve.Scalar.New(15),
|
||||
}
|
||||
data, err := mw.MarshalBinary()
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, data)
|
||||
newMW := &MembershipWitness{}
|
||||
err = newMW.UnmarshalBinary(data)
|
||||
require.NoError(t, err)
|
||||
require.True(t, mw.c.Equal(newMW.c))
|
||||
require.Equal(t, 0, mw.y.Cmp(newMW.y))
|
||||
}
|
||||
|
||||
func Test_Membership(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
sk, _ := new(SecretKey).New(curve, []byte("1234567890"))
|
||||
pk, _ := sk.GetPublicKey(curve)
|
||||
|
||||
element1 := curve.Scalar.Hash([]byte("3"))
|
||||
element2 := curve.Scalar.Hash([]byte("4"))
|
||||
element3 := curve.Scalar.Hash([]byte("5"))
|
||||
element4 := curve.Scalar.Hash([]byte("6"))
|
||||
element5 := curve.Scalar.Hash([]byte("7"))
|
||||
element6 := curve.Scalar.Hash([]byte("8"))
|
||||
element7 := curve.Scalar.Hash([]byte("9"))
|
||||
elements := []Element{element1, element2, element3, element4, element5, element6, element7}
|
||||
|
||||
// nm_witness_max works as well if set to value larger than 0 for this test.x
|
||||
acc, err := new(Accumulator).WithElements(curve, sk, elements)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, acc.value)
|
||||
require.False(t, acc.value.IsIdentity())
|
||||
require.True(t, acc.value.IsOnCurve())
|
||||
require.NotEqual(t, acc.value, curve.NewG1GeneratorPoint())
|
||||
|
||||
wit, err := new(MembershipWitness).New(elements[3], acc, sk)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, wit.y, elements[3])
|
||||
|
||||
err = wit.Verify(pk, acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test wrong cases, forge a wrong witness
|
||||
wrongWit := MembershipWitness{
|
||||
curve.PointG1.Identity(),
|
||||
curve.Scalar.One(),
|
||||
}
|
||||
err = wrongWit.Verify(pk, acc)
|
||||
require.Error(t, err)
|
||||
|
||||
// Test wrong cases, forge a wrong accumulator
|
||||
wrongAcc := &Accumulator{
|
||||
curve.PointG1.Generator(),
|
||||
}
|
||||
err = wit.Verify(pk, wrongAcc)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func Test_Membership_Batch_Update(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
sk, _ := new(SecretKey).New(curve, []byte("1234567890"))
|
||||
pk, _ := sk.GetPublicKey(curve)
|
||||
|
||||
element1 := curve.Scalar.Hash([]byte("3"))
|
||||
element2 := curve.Scalar.Hash([]byte("4"))
|
||||
element3 := curve.Scalar.Hash([]byte("5"))
|
||||
element4 := curve.Scalar.Hash([]byte("6"))
|
||||
element5 := curve.Scalar.Hash([]byte("7"))
|
||||
element6 := curve.Scalar.Hash([]byte("8"))
|
||||
element7 := curve.Scalar.Hash([]byte("9"))
|
||||
elements := []Element{element1, element2, element3, element4, element5, element6, element7}
|
||||
|
||||
// nm_witness_max works as well if set to value larger than 0 for this test.
|
||||
acc, err := new(Accumulator).WithElements(curve, sk, elements)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, acc.value)
|
||||
|
||||
wit, err := new(MembershipWitness).New(elements[3], acc, sk)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, wit.y, elements[3])
|
||||
|
||||
err = wit.Verify(pk, acc)
|
||||
require.Nil(t, err)
|
||||
|
||||
data1 := curve.Scalar.Hash([]byte("1"))
|
||||
data2 := curve.Scalar.Hash([]byte("2"))
|
||||
data3 := curve.Scalar.Hash([]byte("3"))
|
||||
data4 := curve.Scalar.Hash([]byte("4"))
|
||||
data5 := curve.Scalar.Hash([]byte("5"))
|
||||
data := []Element{data1, data2, data3, data4, data5}
|
||||
additions := data[0:2]
|
||||
deletions := data[2:5]
|
||||
_, coefficients, err := acc.Update(sk, additions, deletions)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, coefficients)
|
||||
|
||||
_, err = wit.BatchUpdate(additions, deletions, coefficients)
|
||||
require.NoError(t, err)
|
||||
err = wit.Verify(pk, acc)
|
||||
require.Nil(t, err)
|
||||
}
|
||||
|
||||
func Test_Membership_Multi_Batch_Update(t *testing.T) {
|
||||
curve := curves.BLS12381(&curves.PointBls12381G1{})
|
||||
sk, _ := new(SecretKey).New(curve, []byte("1234567890"))
|
||||
pk, _ := sk.GetPublicKey(curve)
|
||||
|
||||
element1 := curve.Scalar.Hash([]byte("3"))
|
||||
element2 := curve.Scalar.Hash([]byte("4"))
|
||||
element3 := curve.Scalar.Hash([]byte("5"))
|
||||
element4 := curve.Scalar.Hash([]byte("6"))
|
||||
element5 := curve.Scalar.Hash([]byte("7"))
|
||||
element6 := curve.Scalar.Hash([]byte("8"))
|
||||
element7 := curve.Scalar.Hash([]byte("9"))
|
||||
element8 := curve.Scalar.Hash([]byte("10"))
|
||||
element9 := curve.Scalar.Hash([]byte("11"))
|
||||
element10 := curve.Scalar.Hash([]byte("12"))
|
||||
element11 := curve.Scalar.Hash([]byte("13"))
|
||||
element12 := curve.Scalar.Hash([]byte("14"))
|
||||
element13 := curve.Scalar.Hash([]byte("15"))
|
||||
element14 := curve.Scalar.Hash([]byte("16"))
|
||||
element15 := curve.Scalar.Hash([]byte("17"))
|
||||
element16 := curve.Scalar.Hash([]byte("18"))
|
||||
element17 := curve.Scalar.Hash([]byte("19"))
|
||||
element18 := curve.Scalar.Hash([]byte("20"))
|
||||
elements := []Element{
|
||||
element1,
|
||||
element2,
|
||||
element3,
|
||||
element4,
|
||||
element5,
|
||||
element6,
|
||||
element7,
|
||||
element8,
|
||||
element9,
|
||||
element10,
|
||||
element11,
|
||||
element12,
|
||||
element13,
|
||||
element14,
|
||||
element15,
|
||||
element16,
|
||||
element17,
|
||||
element18,
|
||||
}
|
||||
acc, err := new(Accumulator).WithElements(curve, sk, elements)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, acc.value)
|
||||
|
||||
wit, err := new(MembershipWitness).New(elements[3], acc, sk)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = wit.Verify(pk, acc)
|
||||
require.Nil(t, err)
|
||||
|
||||
data1 := curve.Scalar.Hash([]byte("1"))
|
||||
data2 := curve.Scalar.Hash([]byte("2"))
|
||||
data3 := curve.Scalar.Hash([]byte("3"))
|
||||
data4 := curve.Scalar.Hash([]byte("4"))
|
||||
data5 := curve.Scalar.Hash([]byte("5"))
|
||||
data := []Element{data1, data2, data3, data4, data5}
|
||||
adds1 := data[0:2]
|
||||
dels1 := data[2:5]
|
||||
_, coeffs1, err := acc.Update(sk, adds1, dels1)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, coeffs1)
|
||||
|
||||
dels2 := elements[8:10]
|
||||
_, coeffs2, err := acc.Update(sk, []Element{}, dels2)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, coeffs2)
|
||||
|
||||
dels3 := elements[11:14]
|
||||
_, coeffs3, err := acc.Update(sk, []Element{}, dels3)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, coeffs3)
|
||||
|
||||
a := make([][]Element, 3)
|
||||
a[0] = adds1
|
||||
a[1] = []Element{}
|
||||
a[2] = []Element{}
|
||||
|
||||
d := make([][]Element, 3)
|
||||
d[0] = dels1
|
||||
d[1] = dels2
|
||||
d[2] = dels3
|
||||
|
||||
c := make([][]Coefficient, 3)
|
||||
c[0] = coeffs1
|
||||
c[1] = coeffs2
|
||||
c[2] = coeffs3
|
||||
|
||||
_, err = wit.MultiBatchUpdate(a, d, c)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = wit.Verify(pk, acc)
|
||||
require.Nil(t, err)
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
package bip32
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha512"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
)
|
||||
|
||||
// ComputePublicKey computes the public key of a child key given the extended public key, chain code, and index.
|
||||
func ComputePublicKey(extPubKey []byte, chainCode uint32, index int) ([]byte, error) {
|
||||
// Check if the index is a hardened child key
|
||||
if chainCode&0x80000000 != 0 && index < 0 {
|
||||
return nil, errors.New("invalid index")
|
||||
}
|
||||
|
||||
// Serialize the public key
|
||||
pubKey, err := btcec.ParsePubKey(extPubKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pubKeyBytes := pubKey.SerializeCompressed()
|
||||
|
||||
// Serialize the index
|
||||
indexBytes := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(indexBytes, uint32(index))
|
||||
|
||||
// Compute the HMAC-SHA512
|
||||
mac := hmac.New(sha512.New, []byte{byte(chainCode)})
|
||||
mac.Write(pubKeyBytes)
|
||||
mac.Write(indexBytes)
|
||||
I := mac.Sum(nil)
|
||||
|
||||
// Split I into two 32-byte sequences
|
||||
IL := I[:32]
|
||||
|
||||
// Convert IL to a big integer
|
||||
ilNum := new(big.Int).SetBytes(IL)
|
||||
|
||||
// Check if parse256(IL) >= n
|
||||
curve := btcec.S256()
|
||||
if ilNum.Cmp(curve.N) >= 0 {
|
||||
return nil, errors.New("invalid child key")
|
||||
}
|
||||
|
||||
// Compute the child public key
|
||||
ilx, ily := curve.ScalarBaseMult(IL)
|
||||
childX, childY := curve.Add(ilx, ily, pubKey.X(), pubKey.Y())
|
||||
lx := newBigIntFieldVal(childX)
|
||||
ly := newBigIntFieldVal(childY)
|
||||
|
||||
// Create the child public key
|
||||
childPubKey := btcec.NewPublicKey(lx, ly)
|
||||
childPubKeyBytes := childPubKey.SerializeCompressed()
|
||||
return childPubKeyBytes, nil
|
||||
}
|
||||
|
||||
// newBigIntFieldVal creates a new field value from a big integer.
|
||||
func newBigIntFieldVal(val *big.Int) *btcec.FieldVal {
|
||||
lx := new(btcec.FieldVal)
|
||||
lx.SetByteSlice(val.Bytes())
|
||||
return lx
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package bulletproof
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/crypto/sha3"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
// generators contains a list of points to be used as generators for bulletproofs.
|
||||
type generators []curves.Point
|
||||
|
||||
// ippGenerators holds generators necessary for an Inner Product Proof
|
||||
// It includes a single u generator, and a list of generators divided in half to G and H
|
||||
// See lines 10 on pg 16 of https://eprint.iacr.org/2017/1066.pdf
|
||||
type ippGenerators struct {
|
||||
G generators
|
||||
H generators
|
||||
}
|
||||
|
||||
// getGeneratorPoints generates generators using HashToCurve with Shake256(domain) as input
|
||||
// lenVector is the length of the scalars used for the Inner Product Proof
|
||||
// getGeneratorPoints will return 2*lenVector + 1 total points, split between a single u generator
|
||||
// and G and H lists of vectors per the IPP specification
|
||||
// See lines 10 on pg 16 of https://eprint.iacr.org/2017/1066.pdf
|
||||
func getGeneratorPoints(lenVector int, domain []byte, curve curves.Curve) (*ippGenerators, error) {
|
||||
shake := sha3.NewShake256()
|
||||
_, err := shake.Write(domain)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getGeneratorPoints shake.Write")
|
||||
}
|
||||
numPoints := lenVector * 2
|
||||
points := make([]curves.Point, numPoints)
|
||||
for i := 0; i < numPoints; i++ {
|
||||
bytes := [64]byte{}
|
||||
_, err := shake.Read(bytes[:])
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getGeneratorPoints shake.Read")
|
||||
}
|
||||
nextPoint := curve.Point.Hash(bytes[:])
|
||||
points[i] = nextPoint
|
||||
}
|
||||
// Get G and H by splitting points in half
|
||||
G, H, err := splitPointVector(points)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getGeneratorPoints splitPointVector")
|
||||
}
|
||||
out := ippGenerators{G: G, H: H}
|
||||
|
||||
return &out, nil
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
package bulletproof
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/crypto/sha3"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
func TestGeneratorsHappyPath(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
gs, err := getGeneratorPoints(10, []byte("test"), *curve)
|
||||
gsConcatenated := concatIPPGenerators(*gs)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, gs.G, 10)
|
||||
require.Len(t, gs.H, 10)
|
||||
require.True(t, noDuplicates(gsConcatenated))
|
||||
}
|
||||
|
||||
func TestGeneratorsUniquePerDomain(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
gs1, err := getGeneratorPoints(10, []byte("test"), *curve)
|
||||
gs1Concatenated := concatIPPGenerators(*gs1)
|
||||
require.NoError(t, err)
|
||||
gs2, err := getGeneratorPoints(10, []byte("test2"), *curve)
|
||||
gs2Concatenated := concatIPPGenerators(*gs2)
|
||||
require.NoError(t, err)
|
||||
require.True(t, areDisjoint(gs1Concatenated, gs2Concatenated))
|
||||
}
|
||||
|
||||
func noDuplicates(gs generators) bool {
|
||||
seen := map[[32]byte]bool{}
|
||||
for _, G := range gs {
|
||||
value := sha3.Sum256(G.ToAffineCompressed())
|
||||
if seen[value] {
|
||||
return false
|
||||
}
|
||||
seen[value] = true
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func areDisjoint(gs1, gs2 generators) bool {
|
||||
for _, g1 := range gs1 {
|
||||
for _, g2 := range gs2 {
|
||||
if g1.Equal(g2) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func concatIPPGenerators(ippGens ippGenerators) generators {
|
||||
var out generators
|
||||
out = append(out, ippGens.G...)
|
||||
out = append(out, ippGens.H...)
|
||||
return out
|
||||
}
|
@ -1,181 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package bulletproof
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
// innerProduct takes two lists of scalars (a, b) and performs the dot product returning a single scalar.
|
||||
func innerProduct(a, b []curves.Scalar) (curves.Scalar, error) {
|
||||
if len(a) != len(b) {
|
||||
return nil, errors.New("length of scalar vectors must be the same")
|
||||
}
|
||||
if len(a) < 1 {
|
||||
return nil, errors.New("length of vectors must be at least one")
|
||||
}
|
||||
// Get a new scalar of value zero of the same curve as input arguments
|
||||
innerProduct := a[0].Zero()
|
||||
for i, aElem := range a {
|
||||
bElem := b[i]
|
||||
// innerProduct = aElem*bElem + innerProduct
|
||||
innerProduct = aElem.MulAdd(bElem, innerProduct)
|
||||
}
|
||||
|
||||
return innerProduct, nil
|
||||
}
|
||||
|
||||
// splitPointVector takes a vector of points, splits it in half returning each half.
|
||||
func splitPointVector(points []curves.Point) ([]curves.Point, []curves.Point, error) {
|
||||
if len(points) < 1 {
|
||||
return nil, nil, errors.New("length of points must be at least one")
|
||||
}
|
||||
if len(points)&0x01 != 0 {
|
||||
return nil, nil, errors.New("length of points must be even")
|
||||
}
|
||||
nPrime := len(points) >> 1
|
||||
firstHalf := points[:nPrime]
|
||||
secondHalf := points[nPrime:]
|
||||
return firstHalf, secondHalf, nil
|
||||
}
|
||||
|
||||
// splitScalarVector takes a vector of scalars, splits it in half returning each half.
|
||||
func splitScalarVector(scalars []curves.Scalar) ([]curves.Scalar, []curves.Scalar, error) {
|
||||
if len(scalars) < 1 {
|
||||
return nil, nil, errors.New("length of scalars must be at least one")
|
||||
}
|
||||
if len(scalars)&0x01 != 0 {
|
||||
return nil, nil, errors.New("length of scalars must be even")
|
||||
}
|
||||
nPrime := len(scalars) >> 1
|
||||
firstHalf := scalars[:nPrime]
|
||||
secondHalf := scalars[nPrime:]
|
||||
return firstHalf, secondHalf, nil
|
||||
}
|
||||
|
||||
// multiplyScalarToPointVector takes a single scalar and a list of points, multiplies each point by scalar.
|
||||
func multiplyScalarToPointVector(x curves.Scalar, g []curves.Point) []curves.Point {
|
||||
products := make([]curves.Point, len(g))
|
||||
for i, gElem := range g {
|
||||
product := gElem.Mul(x)
|
||||
products[i] = product
|
||||
}
|
||||
|
||||
return products
|
||||
}
|
||||
|
||||
// multiplyScalarToScalarVector takes a single scalar (x) and a list of scalars (a), multiplies each scalar in the vector by the scalar.
|
||||
func multiplyScalarToScalarVector(x curves.Scalar, a []curves.Scalar) []curves.Scalar {
|
||||
products := make([]curves.Scalar, len(a))
|
||||
for i, aElem := range a {
|
||||
product := aElem.Mul(x)
|
||||
products[i] = product
|
||||
}
|
||||
|
||||
return products
|
||||
}
|
||||
|
||||
// multiplyPairwisePointVectors takes two lists of points (g, h) and performs a pairwise multiplication returning a list of points.
|
||||
func multiplyPairwisePointVectors(g, h []curves.Point) ([]curves.Point, error) {
|
||||
if len(g) != len(h) {
|
||||
return nil, errors.New("length of point vectors must be the same")
|
||||
}
|
||||
product := make([]curves.Point, len(g))
|
||||
for i, gElem := range g {
|
||||
product[i] = gElem.Add(h[i])
|
||||
}
|
||||
|
||||
return product, nil
|
||||
}
|
||||
|
||||
// multiplyPairwiseScalarVectors takes two lists of points (a, b) and performs a pairwise multiplication returning a list of scalars.
|
||||
func multiplyPairwiseScalarVectors(a, b []curves.Scalar) ([]curves.Scalar, error) {
|
||||
if len(a) != len(b) {
|
||||
return nil, errors.New("length of point vectors must be the same")
|
||||
}
|
||||
product := make([]curves.Scalar, len(a))
|
||||
for i, aElem := range a {
|
||||
product[i] = aElem.Mul(b[i])
|
||||
}
|
||||
|
||||
return product, nil
|
||||
}
|
||||
|
||||
// addPairwiseScalarVectors takes two lists of scalars (a, b) and performs a pairwise addition returning a list of scalars.
|
||||
func addPairwiseScalarVectors(a, b []curves.Scalar) ([]curves.Scalar, error) {
|
||||
if len(a) != len(b) {
|
||||
return nil, errors.New("length of scalar vectors must be the same")
|
||||
}
|
||||
sum := make([]curves.Scalar, len(a))
|
||||
for i, aElem := range a {
|
||||
sum[i] = aElem.Add(b[i])
|
||||
}
|
||||
|
||||
return sum, nil
|
||||
}
|
||||
|
||||
// subtractPairwiseScalarVectors takes two lists of scalars (a, b) and performs a pairwise subtraction returning a list of scalars.
|
||||
func subtractPairwiseScalarVectors(a, b []curves.Scalar) ([]curves.Scalar, error) {
|
||||
if len(a) != len(b) {
|
||||
return nil, errors.New("length of scalar vectors must be the same")
|
||||
}
|
||||
diff := make([]curves.Scalar, len(a))
|
||||
for i, aElem := range a {
|
||||
diff[i] = aElem.Sub(b[i])
|
||||
}
|
||||
return diff, nil
|
||||
}
|
||||
|
||||
// invertScalars takes a list of scalars then returns a list with each element inverted.
|
||||
func invertScalars(xs []curves.Scalar) ([]curves.Scalar, error) {
|
||||
xinvs := make([]curves.Scalar, len(xs))
|
||||
for i, x := range xs {
|
||||
xinv, err := x.Invert()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "bulletproof helpers invertx")
|
||||
}
|
||||
xinvs[i] = xinv
|
||||
}
|
||||
|
||||
return xinvs, nil
|
||||
}
|
||||
|
||||
// isPowerOfTwo returns whether a number i is a power of two or not.
|
||||
func isPowerOfTwo(i int) bool {
|
||||
return i&(i-1) == 0
|
||||
}
|
||||
|
||||
// get2nVector returns a scalar vector 2^n such that [1, 2, 4, ... 2^(n-1)]
|
||||
// See k^n and 2^n definitions on pg 12 of https://eprint.iacr.org/2017/1066.pdf
|
||||
func get2nVector(length int, curve curves.Curve) []curves.Scalar {
|
||||
vector2n := make([]curves.Scalar, length)
|
||||
vector2n[0] = curve.Scalar.One()
|
||||
for i := 1; i < length; i++ {
|
||||
vector2n[i] = vector2n[i-1].Double()
|
||||
}
|
||||
return vector2n
|
||||
}
|
||||
|
||||
func get1nVector(length int, curve curves.Curve) []curves.Scalar {
|
||||
vector1n := make([]curves.Scalar, length)
|
||||
for i := 0; i < length; i++ {
|
||||
vector1n[i] = curve.Scalar.One()
|
||||
}
|
||||
return vector1n
|
||||
}
|
||||
|
||||
func getknVector(k curves.Scalar, length int, curve curves.Curve) []curves.Scalar {
|
||||
vectorkn := make([]curves.Scalar, length)
|
||||
vectorkn[0] = curve.Scalar.One()
|
||||
vectorkn[1] = k
|
||||
for i := 2; i < length; i++ {
|
||||
vectorkn[i] = vectorkn[i-1].Mul(k)
|
||||
}
|
||||
return vectorkn
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
package bulletproof
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
func TestInnerProductHappyPath(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
a := randScalarVec(3, *curve)
|
||||
b := randScalarVec(3, *curve)
|
||||
_, err := innerProduct(a, b)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestInnerProductMismatchedLengths(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
a := randScalarVec(3, *curve)
|
||||
b := randScalarVec(4, *curve)
|
||||
_, err := innerProduct(a, b)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestInnerProductEmptyVector(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
a := randScalarVec(0, *curve)
|
||||
b := randScalarVec(0, *curve)
|
||||
_, err := innerProduct(a, b)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestInnerProductOut(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
a := randScalarVec(2, *curve)
|
||||
b := randScalarVec(2, *curve)
|
||||
c, err := innerProduct(a, b)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Calculate manually a0*b0 + a1*b1
|
||||
cPrime := a[0].Mul(b[0]).Add(a[1].Mul(b[1]))
|
||||
require.Equal(t, c, cPrime)
|
||||
}
|
||||
|
||||
func TestSplitListofPointsHappyPath(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
points := randPointVec(10, *curve)
|
||||
firstHalf, secondHalf, err := splitPointVector(points)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, firstHalf, 5)
|
||||
require.Len(t, secondHalf, 5)
|
||||
}
|
||||
|
||||
func TestSplitListofPointsOddLength(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
points := randPointVec(11, *curve)
|
||||
_, _, err := splitPointVector(points)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestSplitListofPointsZeroLength(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
points := randPointVec(0, *curve)
|
||||
_, _, err := splitPointVector(points)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func randScalarVec(length int, curve curves.Curve) []curves.Scalar {
|
||||
out := make([]curves.Scalar, length)
|
||||
for i := 0; i < length; i++ {
|
||||
out[i] = curve.Scalar.Random(crand.Reader)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func randPointVec(length int, curve curves.Curve) []curves.Point {
|
||||
out := make([]curves.Point, length)
|
||||
for i := 0; i < length; i++ {
|
||||
out[i] = curve.Point.Random(crand.Reader)
|
||||
}
|
||||
return out
|
||||
}
|
@ -1,396 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
// Package bulletproof implements the zero knowledge protocol bulletproofs as defined in https://eprint.iacr.org/2017/1066.pdf
|
||||
package bulletproof
|
||||
|
||||
import (
|
||||
"github.com/gtank/merlin"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
// InnerProductProver is the struct used to create InnerProductProofs
|
||||
// It specifies which curve to use and holds precomputed generators
|
||||
// See NewInnerProductProver() for prover initialization.
|
||||
type InnerProductProver struct {
|
||||
curve curves.Curve
|
||||
generators ippGenerators
|
||||
}
|
||||
|
||||
// InnerProductProof contains necessary output for the inner product proof
|
||||
// a and b are the final input vectors of scalars, they should be of length 1
|
||||
// Ls and Rs are calculated per recursion of the IPP and are necessary for verification
|
||||
// See section 3.1 on pg 15 of https://eprint.iacr.org/2017/1066.pdf
|
||||
type InnerProductProof struct {
|
||||
a, b curves.Scalar
|
||||
capLs, capRs []curves.Point
|
||||
curve *curves.Curve
|
||||
}
|
||||
|
||||
// ippRecursion is the same as IPP but tracks recursive a', b', g', h' and Ls and Rs
|
||||
// It should only be used internally by InnerProductProver.Prove()
|
||||
// See L35 on pg 16 of https://eprint.iacr.org/2017/1066.pdf
|
||||
type ippRecursion struct {
|
||||
a, b []curves.Scalar
|
||||
c curves.Scalar
|
||||
capLs, capRs []curves.Point
|
||||
g, h []curves.Point
|
||||
u, capP curves.Point
|
||||
transcript *merlin.Transcript
|
||||
}
|
||||
|
||||
// NewInnerProductProver initializes a new prover
|
||||
// It uses the specified domain to generate generators for vectors of at most maxVectorLength
|
||||
// A prover can be used to construct inner product proofs for vectors of length less than or equal to maxVectorLength
|
||||
// A prover is defined by an explicit curve.
|
||||
func NewInnerProductProver(maxVectorLength int, domain []byte, curve curves.Curve) (*InnerProductProver, error) {
|
||||
generators, err := getGeneratorPoints(maxVectorLength, domain, curve)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ipp getGenerators")
|
||||
}
|
||||
return &InnerProductProver{curve: curve, generators: *generators}, nil
|
||||
}
|
||||
|
||||
// NewInnerProductProof initializes a new InnerProductProof for a specified curve
|
||||
// This should be used in tandem with UnmarshalBinary() to convert a marshaled proof into the struct.
|
||||
func NewInnerProductProof(curve *curves.Curve) *InnerProductProof {
|
||||
var capLs, capRs []curves.Point
|
||||
newProof := InnerProductProof{
|
||||
a: curve.NewScalar(),
|
||||
b: curve.NewScalar(),
|
||||
capLs: capLs,
|
||||
capRs: capRs,
|
||||
curve: curve,
|
||||
}
|
||||
return &newProof
|
||||
}
|
||||
|
||||
// rangeToIPP takes the output of a range proof and converts it into an inner product proof
|
||||
// See section 4.2 on pg 20
|
||||
// The conversion specifies generators to use (g and hPrime), as well as the two vectors l, r of which the inner product is tHat
|
||||
// Additionally, note that the P used for the IPP is in fact P*h^-mu from the range proof.
|
||||
func (prover *InnerProductProver) rangeToIPP(proofG, proofH []curves.Point, l, r []curves.Scalar, tHat curves.Scalar, capPhmuinv, u curves.Point, transcript *merlin.Transcript) (*InnerProductProof, error) {
|
||||
// Note that P as a witness is only g^l * h^r
|
||||
// P needs to be in the form of g^l * h^r * u^<l,r>
|
||||
// Calculate the final P including the u^<l,r> term
|
||||
utHat := u.Mul(tHat)
|
||||
capP := capPhmuinv.Add(utHat)
|
||||
|
||||
// Use params to prove inner product
|
||||
recursionParams := &ippRecursion{
|
||||
a: l,
|
||||
b: r,
|
||||
capLs: []curves.Point{},
|
||||
capRs: []curves.Point{},
|
||||
c: tHat,
|
||||
g: proofG,
|
||||
h: proofH,
|
||||
capP: capP,
|
||||
u: u,
|
||||
transcript: transcript,
|
||||
}
|
||||
|
||||
return prover.proveRecursive(recursionParams)
|
||||
}
|
||||
|
||||
// getP returns the initial P value given two scalars a,b and point u
|
||||
// This method should only be used for testing
|
||||
// See (3) on page 13 of https://eprint.iacr.org/2017/1066.pdf
|
||||
func (prover *InnerProductProver) getP(a, b []curves.Scalar, u curves.Point) (curves.Point, error) {
|
||||
// Vectors must have length power of two
|
||||
if !isPowerOfTwo(len(a)) {
|
||||
return nil, errors.New("ipp vector length must be power of two")
|
||||
}
|
||||
// Generator vectors must be same length
|
||||
if len(prover.generators.G) != len(prover.generators.H) {
|
||||
return nil, errors.New("ipp generator lengths of g and h must be equal")
|
||||
}
|
||||
// Inner product requires len(a) == len(b) else error is returned
|
||||
c, err := innerProduct(a, b)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ipp getInnerProduct")
|
||||
}
|
||||
|
||||
// In case where len(a) is less than number of generators precomputed by prover, trim to length
|
||||
proofG := prover.generators.G[0:len(a)]
|
||||
proofH := prover.generators.H[0:len(b)]
|
||||
|
||||
// initial P = g^a * h^b * u^(a dot b) (See (3) on page 13 of https://eprint.iacr.org/2017/1066.pdf)
|
||||
ga := prover.curve.NewGeneratorPoint().SumOfProducts(proofG, a)
|
||||
hb := prover.curve.NewGeneratorPoint().SumOfProducts(proofH, b)
|
||||
uadotb := u.Mul(c)
|
||||
capP := ga.Add(hb).Add(uadotb)
|
||||
|
||||
return capP, nil
|
||||
}
|
||||
|
||||
// Prove executes the prover protocol on pg 16 of https://eprint.iacr.org/2017/1066.pdf
|
||||
// It generates an inner product proof for vectors a and b, using u to blind the inner product in P
|
||||
// A transcript is used for the Fiat Shamir heuristic.
|
||||
func (prover *InnerProductProver) Prove(a, b []curves.Scalar, u curves.Point, transcript *merlin.Transcript) (*InnerProductProof, error) {
|
||||
// Vectors must have length power of two
|
||||
if !isPowerOfTwo(len(a)) {
|
||||
return nil, errors.New("ipp vector length must be power of two")
|
||||
}
|
||||
// Generator vectors must be same length
|
||||
if len(prover.generators.G) != len(prover.generators.H) {
|
||||
return nil, errors.New("ipp generator lengths of g and h must be equal")
|
||||
}
|
||||
// Inner product requires len(a) == len(b) else error is returned
|
||||
c, err := innerProduct(a, b)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ipp getInnerProduct")
|
||||
}
|
||||
|
||||
// Length of vectors must be less than the number of generators generated
|
||||
if len(a) > len(prover.generators.G) {
|
||||
return nil, errors.New("ipp vector length must be less than maxVectorLength")
|
||||
}
|
||||
// In case where len(a) is less than number of generators precomputed by prover, trim to length
|
||||
proofG := prover.generators.G[0:len(a)]
|
||||
proofH := prover.generators.H[0:len(b)]
|
||||
|
||||
// initial P = g^a * h^b * u^(a dot b) (See (3) on page 13 of https://eprint.iacr.org/2017/1066.pdf)
|
||||
ga := prover.curve.NewGeneratorPoint().SumOfProducts(proofG, a)
|
||||
hb := prover.curve.NewGeneratorPoint().SumOfProducts(proofH, b)
|
||||
uadotb := u.Mul(c)
|
||||
capP := ga.Add(hb).Add(uadotb)
|
||||
|
||||
recursionParams := &ippRecursion{
|
||||
a: a,
|
||||
b: b,
|
||||
capLs: []curves.Point{},
|
||||
capRs: []curves.Point{},
|
||||
c: c,
|
||||
g: proofG,
|
||||
h: proofH,
|
||||
capP: capP,
|
||||
u: u,
|
||||
transcript: transcript,
|
||||
}
|
||||
return prover.proveRecursive(recursionParams)
|
||||
}
|
||||
|
||||
// proveRecursive executes the recursion on pg 16 of https://eprint.iacr.org/2017/1066.pdf
|
||||
func (prover *InnerProductProver) proveRecursive(recursionParams *ippRecursion) (*InnerProductProof, error) {
|
||||
// length checks
|
||||
if len(recursionParams.a) != len(recursionParams.b) {
|
||||
return nil, errors.New("ipp proveRecursive a and b different lengths")
|
||||
}
|
||||
if len(recursionParams.g) != len(recursionParams.h) {
|
||||
return nil, errors.New("ipp proveRecursive g and h different lengths")
|
||||
}
|
||||
if len(recursionParams.a) != len(recursionParams.g) {
|
||||
return nil, errors.New("ipp proveRecursive scalar and point vectors different lengths")
|
||||
}
|
||||
// Base case (L14, pg16 of https://eprint.iacr.org/2017/1066.pdf)
|
||||
if len(recursionParams.a) == 1 {
|
||||
proof := &InnerProductProof{
|
||||
a: recursionParams.a[0],
|
||||
b: recursionParams.b[0],
|
||||
capLs: recursionParams.capLs,
|
||||
capRs: recursionParams.capRs,
|
||||
curve: &prover.curve,
|
||||
}
|
||||
return proof, nil
|
||||
}
|
||||
|
||||
// Split current state into low (first half) vs high (second half) vectors
|
||||
aLo, aHi, err := splitScalarVector(recursionParams.a)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "recursionParams splitScalarVector")
|
||||
}
|
||||
bLo, bHi, err := splitScalarVector(recursionParams.b)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "recursionParams splitScalarVector")
|
||||
}
|
||||
gLo, gHi, err := splitPointVector(recursionParams.g)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "recursionParams splitPointVector")
|
||||
}
|
||||
hLo, hHi, err := splitPointVector(recursionParams.h)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "recursionParams splitPointVector")
|
||||
}
|
||||
|
||||
// c_l, c_r (L21,22, pg16 of https://eprint.iacr.org/2017/1066.pdf)
|
||||
cL, err := innerProduct(aLo, bHi)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "recursionParams innerProduct")
|
||||
}
|
||||
|
||||
cR, err := innerProduct(aHi, bLo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "recursionParams innerProduct")
|
||||
}
|
||||
|
||||
// L, R (L23,24, pg16 of https://eprint.iacr.org/2017/1066.pdf)
|
||||
lga := prover.curve.Point.SumOfProducts(gHi, aLo)
|
||||
lhb := prover.curve.Point.SumOfProducts(hLo, bHi)
|
||||
ucL := recursionParams.u.Mul(cL)
|
||||
capL := lga.Add(lhb).Add(ucL)
|
||||
|
||||
rga := prover.curve.Point.SumOfProducts(gLo, aHi)
|
||||
rhb := prover.curve.Point.SumOfProducts(hHi, bLo)
|
||||
ucR := recursionParams.u.Mul(cR)
|
||||
capR := rga.Add(rhb).Add(ucR)
|
||||
|
||||
// Add L,R for verifier to use to calculate final g, h
|
||||
newL := recursionParams.capLs
|
||||
newL = append(newL, capL)
|
||||
newR := recursionParams.capRs
|
||||
newR = append(newR, capR)
|
||||
|
||||
// Get x from L, R for non-interactive (See section 4.4 pg22 of https://eprint.iacr.org/2017/1066.pdf)
|
||||
// Note this replaces the interactive model, i.e. L36-28 of pg16 of https://eprint.iacr.org/2017/1066.pdf
|
||||
x, err := prover.calcx(capL, capR, recursionParams.transcript)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "recursionParams calcx")
|
||||
}
|
||||
|
||||
// Calculate recursive inputs
|
||||
xInv, err := x.Invert()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "recursionParams x.Invert")
|
||||
}
|
||||
|
||||
// g', h' (L29,30, pg16 of https://eprint.iacr.org/2017/1066.pdf)
|
||||
gLoxInverse := multiplyScalarToPointVector(xInv, gLo)
|
||||
gHix := multiplyScalarToPointVector(x, gHi)
|
||||
gPrime, err := multiplyPairwisePointVectors(gLoxInverse, gHix)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "recursionParams multiplyPairwisePointVectors")
|
||||
}
|
||||
|
||||
hLox := multiplyScalarToPointVector(x, hLo)
|
||||
hHixInv := multiplyScalarToPointVector(xInv, hHi)
|
||||
hPrime, err := multiplyPairwisePointVectors(hLox, hHixInv)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "recursionParams multiplyPairwisePointVectors")
|
||||
}
|
||||
|
||||
// P' (L31, pg16 of https://eprint.iacr.org/2017/1066.pdf)
|
||||
xSquare := x.Square()
|
||||
xInvSquare := xInv.Square()
|
||||
LxSquare := capL.Mul(xSquare)
|
||||
RxInvSquare := capR.Mul(xInvSquare)
|
||||
PPrime := LxSquare.Add(recursionParams.capP).Add(RxInvSquare)
|
||||
|
||||
// a', b' (L33, 34, pg16 of https://eprint.iacr.org/2017/1066.pdf)
|
||||
aLox := multiplyScalarToScalarVector(x, aLo)
|
||||
aHixIn := multiplyScalarToScalarVector(xInv, aHi)
|
||||
aPrime, err := addPairwiseScalarVectors(aLox, aHixIn)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "recursionParams addPairwiseScalarVectors")
|
||||
}
|
||||
|
||||
bLoxInv := multiplyScalarToScalarVector(xInv, bLo)
|
||||
bHix := multiplyScalarToScalarVector(x, bHi)
|
||||
bPrime, err := addPairwiseScalarVectors(bLoxInv, bHix)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "recursionParams addPairwiseScalarVectors")
|
||||
}
|
||||
|
||||
// c'
|
||||
cPrime, err := innerProduct(aPrime, bPrime)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "recursionParams innerProduct")
|
||||
}
|
||||
|
||||
// Make recursive call (L35, pg16 of https://eprint.iacr.org/2017/1066.pdf)
|
||||
recursiveIPP := &ippRecursion{
|
||||
a: aPrime,
|
||||
b: bPrime,
|
||||
capLs: newL,
|
||||
capRs: newR,
|
||||
c: cPrime,
|
||||
g: gPrime,
|
||||
h: hPrime,
|
||||
capP: PPrime,
|
||||
u: recursionParams.u,
|
||||
transcript: recursionParams.transcript,
|
||||
}
|
||||
|
||||
out, err := prover.proveRecursive(recursiveIPP)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "recursionParams proveRecursive")
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// calcx uses a merlin transcript for Fiat Shamir
|
||||
// For each recursion, it takes the current state of the transcript and appends the newly calculated L and R values
|
||||
// A new scalar is then read from the transcript
|
||||
// See section 4.4 pg22 of https://eprint.iacr.org/2017/1066.pdf
|
||||
func (prover *InnerProductProver) calcx(capL, capR curves.Point, transcript *merlin.Transcript) (curves.Scalar, error) {
|
||||
// Add the newest capL and capR values to transcript
|
||||
transcript.AppendMessage([]byte("addRecursiveL"), capL.ToAffineUncompressed())
|
||||
transcript.AppendMessage([]byte("addRecursiveR"), capR.ToAffineUncompressed())
|
||||
// Read 64 bytes from, set to scalar
|
||||
outBytes := transcript.ExtractBytes([]byte("getx"), 64)
|
||||
x, err := prover.curve.NewScalar().SetBytesWide(outBytes)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "calcx NewScalar SetBytesWide")
|
||||
}
|
||||
|
||||
return x, nil
|
||||
}
|
||||
|
||||
// MarshalBinary takes an inner product proof and marshals into bytes.
|
||||
func (proof *InnerProductProof) MarshalBinary() []byte {
|
||||
var out []byte
|
||||
out = append(out, proof.a.Bytes()...)
|
||||
out = append(out, proof.b.Bytes()...)
|
||||
for i, capLElem := range proof.capLs {
|
||||
capRElem := proof.capRs[i]
|
||||
out = append(out, capLElem.ToAffineCompressed()...)
|
||||
out = append(out, capRElem.ToAffineCompressed()...)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// UnmarshalBinary takes bytes of a marshaled proof and writes them into an inner product proof
|
||||
// The inner product proof used should be from the output of NewInnerProductProof().
|
||||
func (proof *InnerProductProof) UnmarshalBinary(data []byte) error {
|
||||
scalarLen := len(proof.curve.NewScalar().Bytes())
|
||||
pointLen := len(proof.curve.NewGeneratorPoint().ToAffineCompressed())
|
||||
ptr := 0
|
||||
// Get scalars
|
||||
a, err := proof.curve.NewScalar().SetBytes(data[ptr : ptr+scalarLen])
|
||||
if err != nil {
|
||||
return errors.New("innerProductProof UnmarshalBinary SetBytes")
|
||||
}
|
||||
proof.a = a
|
||||
ptr += scalarLen
|
||||
b, err := proof.curve.NewScalar().SetBytes(data[ptr : ptr+scalarLen])
|
||||
if err != nil {
|
||||
return errors.New("innerProductProof UnmarshalBinary SetBytes")
|
||||
}
|
||||
proof.b = b
|
||||
ptr += scalarLen
|
||||
// Get points
|
||||
var capLs, capRs []curves.Point //nolint:prealloc // pointer arithmetic makes it too unreadable.
|
||||
for ptr < len(data) {
|
||||
capLElem, err := proof.curve.Point.FromAffineCompressed(data[ptr : ptr+pointLen])
|
||||
if err != nil {
|
||||
return errors.New("innerProductProof UnmarshalBinary FromAffineCompressed")
|
||||
}
|
||||
capLs = append(capLs, capLElem)
|
||||
ptr += pointLen
|
||||
capRElem, err := proof.curve.Point.FromAffineCompressed(data[ptr : ptr+pointLen])
|
||||
if err != nil {
|
||||
return errors.New("innerProductProof UnmarshalBinary FromAffineCompressed")
|
||||
}
|
||||
capRs = append(capRs, capRElem)
|
||||
ptr += pointLen
|
||||
}
|
||||
proof.capLs = capLs
|
||||
proof.capRs = capRs
|
||||
|
||||
return nil
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
package bulletproof
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/gtank/merlin"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
func TestIPPHappyPath(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
prover, err := NewInnerProductProver(8, []byte("test"), *curve)
|
||||
require.NoError(t, err)
|
||||
a := randScalarVec(8, *curve)
|
||||
b := randScalarVec(8, *curve)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
transcript := merlin.NewTranscript("test")
|
||||
proof, err := prover.Prove(a, b, u, transcript)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 3, len(proof.capLs))
|
||||
require.Equal(t, 3, len(proof.capRs))
|
||||
}
|
||||
|
||||
func TestIPPMismatchedVectors(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
prover, err := NewInnerProductProver(8, []byte("test"), *curve)
|
||||
require.NoError(t, err)
|
||||
a := randScalarVec(4, *curve)
|
||||
b := randScalarVec(8, *curve)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
transcript := merlin.NewTranscript("test")
|
||||
_, err = prover.Prove(a, b, u, transcript)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestIPPNonPowerOfTwoLengthVectors(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
prover, err := NewInnerProductProver(8, []byte("test"), *curve)
|
||||
require.NoError(t, err)
|
||||
a := randScalarVec(3, *curve)
|
||||
b := randScalarVec(3, *curve)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
transcript := merlin.NewTranscript("test")
|
||||
_, err = prover.Prove(a, b, u, transcript)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestIPPZeroLengthVectors(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
prover, err := NewInnerProductProver(8, []byte("test"), *curve)
|
||||
require.NoError(t, err)
|
||||
a := randScalarVec(0, *curve)
|
||||
b := randScalarVec(0, *curve)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
transcript := merlin.NewTranscript("test")
|
||||
_, err = prover.Prove(a, b, u, transcript)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestIPPGreaterThanMaxLengthVectors(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
prover, err := NewInnerProductProver(8, []byte("test"), *curve)
|
||||
require.NoError(t, err)
|
||||
a := randScalarVec(16, *curve)
|
||||
b := randScalarVec(16, *curve)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
transcript := merlin.NewTranscript("test")
|
||||
_, err = prover.Prove(a, b, u, transcript)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestIPPMarshal(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
prover, err := NewInnerProductProver(8, []byte("test"), *curve)
|
||||
require.NoError(t, err)
|
||||
a := randScalarVec(8, *curve)
|
||||
b := randScalarVec(8, *curve)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
transcript := merlin.NewTranscript("test")
|
||||
proof, err := prover.Prove(a, b, u, transcript)
|
||||
require.NoError(t, err)
|
||||
|
||||
proofMarshaled := proof.MarshalBinary()
|
||||
proofPrime := NewInnerProductProof(curve)
|
||||
err = proofPrime.UnmarshalBinary(proofMarshaled)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, proof.a.Cmp(proofPrime.a))
|
||||
require.Zero(t, proof.b.Cmp(proofPrime.b))
|
||||
for i, proofCapLElem := range proof.capLs {
|
||||
proofPrimeCapLElem := proofPrime.capLs[i]
|
||||
require.True(t, proofCapLElem.Equal(proofPrimeCapLElem))
|
||||
proofCapRElem := proof.capRs[i]
|
||||
proofPrimeCapRElem := proofPrime.capRs[i]
|
||||
require.True(t, proofCapRElem.Equal(proofPrimeCapRElem))
|
||||
}
|
||||
}
|
@ -1,209 +0,0 @@
|
||||
package bulletproof
|
||||
|
||||
import (
|
||||
"github.com/gtank/merlin"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
// InnerProductVerifier is the struct used to verify inner product proofs
|
||||
// It specifies which curve to use and holds precomputed generators
|
||||
// See NewInnerProductProver() for prover initialization.
|
||||
type InnerProductVerifier struct {
|
||||
curve curves.Curve
|
||||
generators ippGenerators
|
||||
}
|
||||
|
||||
// NewInnerProductVerifier initializes a new verifier
|
||||
// It uses the specified domain to generate generators for vectors of at most maxVectorLength
|
||||
// A verifier can be used to verify inner product proofs for vectors of length less than or equal to maxVectorLength
|
||||
// A verifier is defined by an explicit curve.
|
||||
func NewInnerProductVerifier(maxVectorLength int, domain []byte, curve curves.Curve) (*InnerProductVerifier, error) {
|
||||
generators, err := getGeneratorPoints(maxVectorLength, domain, curve)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ipp getGenerators")
|
||||
}
|
||||
return &InnerProductVerifier{curve: curve, generators: *generators}, nil
|
||||
}
|
||||
|
||||
// Verify verifies the given proof inputs
|
||||
// It implements the final comparison of section 3.1 on pg17 of https://eprint.iacr.org/2017/1066.pdf
|
||||
func (verifier *InnerProductVerifier) Verify(capP, u curves.Point, proof *InnerProductProof, transcript *merlin.Transcript) (bool, error) {
|
||||
if len(proof.capLs) != len(proof.capRs) {
|
||||
return false, errors.New("ipp capLs and capRs must be same length")
|
||||
}
|
||||
// Generator vectors must be same length
|
||||
if len(verifier.generators.G) != len(verifier.generators.H) {
|
||||
return false, errors.New("ipp generator lengths of g and h must be equal")
|
||||
}
|
||||
|
||||
// Get generators for each elem in a, b and one more for u
|
||||
// len(Ls) = log n, therefore can just exponentiate
|
||||
n := 1 << len(proof.capLs)
|
||||
|
||||
// Length of vectors must be less than the number of generators generated
|
||||
if n > len(verifier.generators.G) {
|
||||
return false, errors.New("ipp vector length must be less than maxVectorLength")
|
||||
}
|
||||
// In case where len(a) is less than number of generators precomputed by prover, trim to length
|
||||
proofG := verifier.generators.G[0:n]
|
||||
proofH := verifier.generators.H[0:n]
|
||||
|
||||
xs, err := getxs(transcript, proof.capLs, proof.capRs, verifier.curve)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "verifier getxs")
|
||||
}
|
||||
s, err := verifier.getsNew(xs, n)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "verifier getss")
|
||||
}
|
||||
lhs, err := verifier.getLHS(u, proof, proofG, proofH, s)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "verify getLHS")
|
||||
}
|
||||
rhs, err := verifier.getRHS(capP, proof, xs)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "verify getRHS")
|
||||
}
|
||||
return lhs.Equal(rhs), nil
|
||||
}
|
||||
|
||||
// Verify verifies the given proof inputs
|
||||
// It implements the final comparison of section 3.1 on pg17 of https://eprint.iacr.org/2017/1066.pdf
|
||||
func (verifier *InnerProductVerifier) VerifyFromRangeProof(proofG, proofH []curves.Point, capPhmuinv, u curves.Point, tHat curves.Scalar, proof *InnerProductProof, transcript *merlin.Transcript) (bool, error) {
|
||||
// Get generators for each elem in a, b and one more for u
|
||||
// len(Ls) = log n, therefore can just exponentiate
|
||||
n := 1 << len(proof.capLs)
|
||||
|
||||
xs, err := getxs(transcript, proof.capLs, proof.capRs, verifier.curve)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "verifier getxs")
|
||||
}
|
||||
s, err := verifier.gets(xs, n)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "verifier getss")
|
||||
}
|
||||
lhs, err := verifier.getLHS(u, proof, proofG, proofH, s)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "verify getLHS")
|
||||
}
|
||||
utHat := u.Mul(tHat)
|
||||
capP := capPhmuinv.Add(utHat)
|
||||
rhs, err := verifier.getRHS(capP, proof, xs)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "verify getRHS")
|
||||
}
|
||||
return lhs.Equal(rhs), nil
|
||||
}
|
||||
|
||||
// getRHS gets the right hand side of the final comparison of section 3.1 on pg17.
|
||||
func (*InnerProductVerifier) getRHS(capP curves.Point, proof *InnerProductProof, xs []curves.Scalar) (curves.Point, error) {
|
||||
product := capP
|
||||
for j, Lj := range proof.capLs {
|
||||
Rj := proof.capRs[j]
|
||||
xj := xs[j]
|
||||
xjSquare := xj.Square()
|
||||
xjSquareInv, err := xjSquare.Invert()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "verify invert")
|
||||
}
|
||||
LjxjSquare := Lj.Mul(xjSquare)
|
||||
RjxjSquareInv := Rj.Mul(xjSquareInv)
|
||||
product = product.Add(LjxjSquare).Add(RjxjSquareInv)
|
||||
}
|
||||
return product, nil
|
||||
}
|
||||
|
||||
// getLHS gets the left hand side of the final comparison of section 3.1 on pg17.
|
||||
func (verifier *InnerProductVerifier) getLHS(u curves.Point, proof *InnerProductProof, g, h []curves.Point, s []curves.Scalar) (curves.Point, error) {
|
||||
sInv, err := invertScalars(s)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "verify invertScalars")
|
||||
}
|
||||
// g^(a*s)
|
||||
as := multiplyScalarToScalarVector(proof.a, s)
|
||||
gas := verifier.curve.Point.SumOfProducts(g, as)
|
||||
// h^(b*s^-1)
|
||||
bsInv := multiplyScalarToScalarVector(proof.b, sInv)
|
||||
hbsInv := verifier.curve.Point.SumOfProducts(h, bsInv)
|
||||
// u^a*b
|
||||
ab := proof.a.Mul(proof.b)
|
||||
uab := u.Mul(ab)
|
||||
// g^(a*s) * h^(b*s^-1) * u^a*b
|
||||
out := gas.Add(hbsInv).Add(uab)
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// getxs calculates the x values from Ls and Rs
|
||||
// Note that each x is read from the transcript, then the L and R at a certain index are written to the transcript
|
||||
// This mirrors the reading of xs and writing of Ls and Rs in the prover.
|
||||
func getxs(transcript *merlin.Transcript, capLs, capRs []curves.Point, curve curves.Curve) ([]curves.Scalar, error) {
|
||||
xs := make([]curves.Scalar, len(capLs))
|
||||
for i, capLi := range capLs {
|
||||
capRi := capRs[i]
|
||||
// Add the newest L and R values to transcript
|
||||
transcript.AppendMessage([]byte("addRecursiveL"), capLi.ToAffineUncompressed())
|
||||
transcript.AppendMessage([]byte("addRecursiveR"), capRi.ToAffineUncompressed())
|
||||
// Read 64 bytes from, set to scalar
|
||||
outBytes := transcript.ExtractBytes([]byte("getx"), 64)
|
||||
x, err := curve.NewScalar().SetBytesWide(outBytes)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "calcx NewScalar SetBytesWide")
|
||||
}
|
||||
xs[i] = x
|
||||
}
|
||||
|
||||
return xs, nil
|
||||
}
|
||||
|
||||
// gets calculates the vector s of values used for verification
|
||||
// See the second expression of section 3.1 on pg15
|
||||
// nolint
|
||||
func (verifier *InnerProductVerifier) gets(xs []curves.Scalar, n int) ([]curves.Scalar, error) {
|
||||
ss := make([]curves.Scalar, n)
|
||||
for i := 0; i < n; i++ {
|
||||
si := verifier.curve.Scalar.One()
|
||||
for j, xj := range xs {
|
||||
if i>>(len(xs)-j-1)&0x01 == 1 {
|
||||
si = si.Mul(xj)
|
||||
} else {
|
||||
xjInverse, err := xj.Invert()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getss invert")
|
||||
}
|
||||
si = si.Mul(xjInverse)
|
||||
}
|
||||
}
|
||||
ss[i] = si
|
||||
}
|
||||
|
||||
return ss, nil
|
||||
}
|
||||
|
||||
// getsNew calculates the vector s of values used for verification
|
||||
// It provides analogous functionality as gets(), but uses a O(n) algorithm vs O(nlogn)
|
||||
// The algorithm inverts all xs, then begins multiplying the inversion by the square of x elements to
|
||||
// calculate all s values thus minimizing necessary inversions/ computation.
|
||||
func (verifier *InnerProductVerifier) getsNew(xs []curves.Scalar, n int) ([]curves.Scalar, error) {
|
||||
var err error
|
||||
ss := make([]curves.Scalar, n)
|
||||
// First element is all xs inverted mul'd
|
||||
ss[0] = verifier.curve.Scalar.One()
|
||||
for _, xj := range xs {
|
||||
ss[0] = ss[0].Mul(xj)
|
||||
}
|
||||
ss[0], err = ss[0].Invert()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ipp gets inv ss0")
|
||||
}
|
||||
for j, xj := range xs {
|
||||
xjSquared := xj.Square()
|
||||
for i := 0; i < n; i += 1 << (len(xs) - j) {
|
||||
ss[i+1<<(len(xs)-j-1)] = ss[i].Mul(xjSquared)
|
||||
}
|
||||
}
|
||||
|
||||
return ss, nil
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
package bulletproof
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/gtank/merlin"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
func TestIPPVerifyHappyPath(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
vecLength := 256
|
||||
prover, err := NewInnerProductProver(vecLength, []byte("test"), *curve)
|
||||
require.NoError(t, err)
|
||||
a := randScalarVec(vecLength, *curve)
|
||||
b := randScalarVec(vecLength, *curve)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
transcriptProver := merlin.NewTranscript("test")
|
||||
proof, err := prover.Prove(a, b, u, transcriptProver)
|
||||
require.NoError(t, err)
|
||||
|
||||
verifier, err := NewInnerProductVerifier(vecLength, []byte("test"), *curve)
|
||||
require.NoError(t, err)
|
||||
capP, err := prover.getP(a, b, u)
|
||||
require.NoError(t, err)
|
||||
transcriptVerifier := merlin.NewTranscript("test")
|
||||
verified, err := verifier.Verify(capP, u, proof, transcriptVerifier)
|
||||
require.NoError(t, err)
|
||||
require.True(t, verified)
|
||||
}
|
||||
|
||||
func BenchmarkIPPVerification(bench *testing.B) {
|
||||
curve := curves.ED25519()
|
||||
vecLength := 1024
|
||||
prover, _ := NewInnerProductProver(vecLength, []byte("test"), *curve)
|
||||
a := randScalarVec(vecLength, *curve)
|
||||
b := randScalarVec(vecLength, *curve)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
transcriptProver := merlin.NewTranscript("test")
|
||||
proof, _ := prover.Prove(a, b, u, transcriptProver)
|
||||
|
||||
verifier, _ := NewInnerProductVerifier(vecLength, []byte("test"), *curve)
|
||||
capP, _ := prover.getP(a, b, u)
|
||||
transcriptVerifier := merlin.NewTranscript("test")
|
||||
verified, _ := verifier.Verify(capP, u, proof, transcriptVerifier)
|
||||
require.True(bench, verified)
|
||||
}
|
||||
|
||||
func TestIPPVerifyInvalidProof(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
vecLength := 64
|
||||
prover, err := NewInnerProductProver(vecLength, []byte("test"), *curve)
|
||||
require.NoError(t, err)
|
||||
|
||||
a := randScalarVec(vecLength, *curve)
|
||||
b := randScalarVec(vecLength, *curve)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
|
||||
aPrime := randScalarVec(64, *curve)
|
||||
bPrime := randScalarVec(64, *curve)
|
||||
uPrime := curve.Point.Random(crand.Reader)
|
||||
transcriptProver := merlin.NewTranscript("test")
|
||||
|
||||
proofPrime, err := prover.Prove(aPrime, bPrime, uPrime, transcriptProver)
|
||||
require.NoError(t, err)
|
||||
|
||||
verifier, err := NewInnerProductVerifier(vecLength, []byte("test"), *curve)
|
||||
require.NoError(t, err)
|
||||
capP, err := prover.getP(a, b, u)
|
||||
require.NoError(t, err)
|
||||
transcriptVerifier := merlin.NewTranscript("test")
|
||||
// Check for different capP, u from proof
|
||||
verified, err := verifier.Verify(capP, u, proofPrime, transcriptVerifier)
|
||||
require.NoError(t, err)
|
||||
require.False(t, verified)
|
||||
}
|
@ -1,348 +0,0 @@
|
||||
package bulletproof
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
|
||||
"github.com/gtank/merlin"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
// BatchProve proves that a list of scalars v are in the range n.
|
||||
// It implements the aggregating logarithmic proofs defined on pg21.
|
||||
// Instead of taking a single value and a single blinding factor, BatchProve takes in a list of values and list of
|
||||
// blinding factors.
|
||||
func (prover *RangeProver) BatchProve(v, gamma []curves.Scalar, n int, proofGenerators RangeProofGenerators, transcript *merlin.Transcript) (*RangeProof, error) {
|
||||
// Define nm as the total bits required for secrets, calculated as number of secrets * n
|
||||
m := len(v)
|
||||
nm := n * m
|
||||
// nm must be less than or equal to the number of generators generated
|
||||
if nm > len(prover.generators.G) {
|
||||
return nil, errors.New("ipp vector length must be less than or equal to maxVectorLength")
|
||||
}
|
||||
|
||||
// In case where nm is less than number of generators precomputed by prover, trim to length
|
||||
proofG := prover.generators.G[0:nm]
|
||||
proofH := prover.generators.H[0:nm]
|
||||
|
||||
// Check that each elem in v is in range [0, 2^n]
|
||||
for _, vi := range v {
|
||||
checkedRange := checkRange(vi, n)
|
||||
if checkedRange != nil {
|
||||
return nil, checkedRange
|
||||
}
|
||||
}
|
||||
|
||||
// L40 on pg19
|
||||
aL, err := getaLBatched(v, n, prover.curve)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
onenm := get1nVector(nm, prover.curve)
|
||||
// L41 on pg19
|
||||
aR, err := subtractPairwiseScalarVectors(aL, onenm)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
alpha := prover.curve.Scalar.Random(crand.Reader)
|
||||
// Calc A (L44, pg19)
|
||||
halpha := proofGenerators.h.Mul(alpha)
|
||||
gaL := prover.curve.Point.SumOfProducts(proofG, aL)
|
||||
haR := prover.curve.Point.SumOfProducts(proofH, aR)
|
||||
capA := halpha.Add(gaL).Add(haR)
|
||||
|
||||
// L45, 46, pg19
|
||||
sL := getBlindingVector(nm, prover.curve)
|
||||
sR := getBlindingVector(nm, prover.curve)
|
||||
rho := prover.curve.Scalar.Random(crand.Reader)
|
||||
|
||||
// Calc S (L47, pg19)
|
||||
hrho := proofGenerators.h.Mul(rho)
|
||||
gsL := prover.curve.Point.SumOfProducts(proofG, sL)
|
||||
hsR := prover.curve.Point.SumOfProducts(proofH, sR)
|
||||
capS := hrho.Add(gsL).Add(hsR)
|
||||
|
||||
// Fiat Shamir for y,z (L49, pg19)
|
||||
capV := getcapVBatched(v, gamma, proofGenerators.g, proofGenerators.h)
|
||||
y, z, err := calcyzBatched(capV, capA, capS, transcript, prover.curve)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
// Calc t_1, t_2
|
||||
// See the l(X), r(X), equations on pg 21
|
||||
// Use l(X)'s and r(X)'s constant and linear terms to derive t_1 and t_2
|
||||
// (a_l - z*1^n)
|
||||
zonenm := multiplyScalarToScalarVector(z, onenm)
|
||||
constantTerml, err := subtractPairwiseScalarVectors(aL, zonenm)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
linearTerml := sL
|
||||
|
||||
// zSum term, see equation 71 on pg21
|
||||
zSum := getSumTermrXBatched(z, n, len(v), prover.curve)
|
||||
// a_r + z*1^nm
|
||||
aRPluszonenm, err := addPairwiseScalarVectors(aR, zonenm)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
ynm := getknVector(y, nm, prover.curve)
|
||||
hadamard, err := multiplyPairwiseScalarVectors(ynm, aRPluszonenm)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
constantTermr, err := addPairwiseScalarVectors(hadamard, zSum)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
linearTermr, err := multiplyPairwiseScalarVectors(ynm, sR)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
// t_1 (as the linear coefficient) is the sum of the dot products of l(X)'s linear term dot r(X)'s constant term
|
||||
// and r(X)'s linear term dot l(X)'s constant term
|
||||
t1FirstTerm, err := innerProduct(linearTerml, constantTermr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
t1SecondTerm, err := innerProduct(linearTermr, constantTerml)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
t1 := t1FirstTerm.Add(t1SecondTerm)
|
||||
|
||||
// t_2 (as the quadratic coefficient) is the dot product of l(X)'s and r(X)'s linear terms
|
||||
t2, err := innerProduct(linearTerml, linearTermr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
// L52, pg20
|
||||
tau1 := prover.curve.Scalar.Random(crand.Reader)
|
||||
tau2 := prover.curve.Scalar.Random(crand.Reader)
|
||||
|
||||
// T_1, T_2 (L53, pg20)
|
||||
capT1 := proofGenerators.g.Mul(t1).Add(proofGenerators.h.Mul(tau1))
|
||||
capT2 := proofGenerators.g.Mul(t2).Add(proofGenerators.h.Mul(tau2))
|
||||
|
||||
// Fiat shamir for x (L55, pg20)
|
||||
x, err := calcx(capT1, capT2, transcript, prover.curve)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
// Calc l
|
||||
// Instead of using the expression in the line, evaluate l() at x
|
||||
sLx := multiplyScalarToScalarVector(x, linearTerml)
|
||||
l, err := addPairwiseScalarVectors(constantTerml, sLx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
// Calc r
|
||||
// Instead of using the expression in the line, evaluate r() at x
|
||||
ynsRx := multiplyScalarToScalarVector(x, linearTermr)
|
||||
r, err := addPairwiseScalarVectors(constantTermr, ynsRx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
// Calc t hat
|
||||
// For efficiency, instead of calculating the dot product, evaluate t() at x
|
||||
zm := getknVector(z, m, prover.curve)
|
||||
zsquarezm := multiplyScalarToScalarVector(z.Square(), zm)
|
||||
sumv := prover.curve.Scalar.Zero()
|
||||
for i := 0; i < m; i++ {
|
||||
elem := zsquarezm[i].Mul(v[i])
|
||||
sumv = sumv.Add(elem)
|
||||
}
|
||||
|
||||
deltayzBatched, err := deltayzBatched(y, z, n, m, prover.curve)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
t0 := sumv.Add(deltayzBatched)
|
||||
tLinear := t1.Mul(x)
|
||||
tQuadratic := t2.Mul(x.Square())
|
||||
tHat := t0.Add(tLinear).Add(tQuadratic)
|
||||
|
||||
// Calc tau_x (L61, pg20)
|
||||
tau2xsquare := tau2.Mul(x.Square())
|
||||
tau1x := tau1.Mul(x)
|
||||
zsum := prover.curve.Scalar.Zero()
|
||||
zExp := z.Clone()
|
||||
for j := 1; j < m+1; j++ {
|
||||
zExp = zExp.Mul(z)
|
||||
zsum = zsum.Add(zExp.Mul(gamma[j-1]))
|
||||
}
|
||||
taux := tau2xsquare.Add(tau1x).Add(zsum)
|
||||
|
||||
// Calc mu (L62, pg20)
|
||||
mu := alpha.Add(rho.Mul(x))
|
||||
|
||||
// Calc IPP (See section 4.2)
|
||||
hPrime, err := gethPrime(proofH, y, prover.curve)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
// P is redefined in batched case, see bottom equation on pg21.
|
||||
capPhmu := getPhmuBatched(proofG, hPrime, proofGenerators.h, capA, capS, x, y, z, mu, n, m, prover.curve)
|
||||
|
||||
wBytes := transcript.ExtractBytes([]byte("getw"), 64)
|
||||
w, err := prover.curve.NewScalar().SetBytesWide(wBytes)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
ipp, err := prover.ippProver.rangeToIPP(proofG, hPrime, l, r, tHat, capPhmu, proofGenerators.u.Mul(w), transcript)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
out := &RangeProof{
|
||||
capA: capA,
|
||||
capS: capS,
|
||||
capT1: capT1,
|
||||
capT2: capT2,
|
||||
taux: taux,
|
||||
mu: mu,
|
||||
tHat: tHat,
|
||||
ipp: ipp,
|
||||
curve: &prover.curve,
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// See final term of L71 on pg 21
|
||||
// Sigma_{j=1}^{m} z^{1+j} * (0^{(j-1)*n} || 2^{n} || 0^{(m-j)*n}).
|
||||
func getSumTermrXBatched(z curves.Scalar, n, m int, curve curves.Curve) []curves.Scalar {
|
||||
twoN := get2nVector(n, curve)
|
||||
var out []curves.Scalar
|
||||
// The final power should be one more than m
|
||||
zExp := z.Clone()
|
||||
for j := 0; j < m; j++ {
|
||||
zExp = zExp.Mul(z)
|
||||
elem := multiplyScalarToScalarVector(zExp, twoN)
|
||||
out = append(out, elem...)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func getcapVBatched(v, gamma []curves.Scalar, g, h curves.Point) []curves.Point {
|
||||
out := make([]curves.Point, len(v))
|
||||
for i, vi := range v {
|
||||
out[i] = getcapV(vi, gamma[i], g, h)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func getaLBatched(v []curves.Scalar, n int, curve curves.Curve) ([]curves.Scalar, error) {
|
||||
var aL []curves.Scalar
|
||||
for _, vi := range v {
|
||||
aLi, err := getaL(vi, n, curve)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aL = append(aL, aLi...)
|
||||
}
|
||||
return aL, nil
|
||||
}
|
||||
|
||||
func calcyzBatched(capV []curves.Point, capA, capS curves.Point, transcript *merlin.Transcript, curve curves.Curve) (curves.Scalar, curves.Scalar, error) {
|
||||
// Add the A,S values to transcript
|
||||
for _, capVi := range capV {
|
||||
transcript.AppendMessage([]byte("addV"), capVi.ToAffineUncompressed())
|
||||
}
|
||||
transcript.AppendMessage([]byte("addcapA"), capA.ToAffineUncompressed())
|
||||
transcript.AppendMessage([]byte("addcapS"), capS.ToAffineUncompressed())
|
||||
// Read 64 bytes twice from, set to scalar for y and z
|
||||
yBytes := transcript.ExtractBytes([]byte("gety"), 64)
|
||||
y, err := curve.NewScalar().SetBytesWide(yBytes)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "calcyz NewScalar SetBytesWide")
|
||||
}
|
||||
zBytes := transcript.ExtractBytes([]byte("getz"), 64)
|
||||
z, err := curve.NewScalar().SetBytesWide(zBytes)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "calcyz NewScalar SetBytesWide")
|
||||
}
|
||||
|
||||
return y, z, nil
|
||||
}
|
||||
|
||||
func deltayzBatched(y, z curves.Scalar, n, m int, curve curves.Curve) (curves.Scalar, error) {
|
||||
// z - z^2
|
||||
zMinuszsquare := z.Sub(z.Square())
|
||||
// 1^(n*m)
|
||||
onenm := get1nVector(n*m, curve)
|
||||
// <1^nm, y^nm>
|
||||
onenmdotynm, err := innerProduct(onenm, getknVector(y, n*m, curve))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "deltayz")
|
||||
}
|
||||
// (z - z^2)*<1^n, y^n>
|
||||
termFirst := zMinuszsquare.Mul(onenmdotynm)
|
||||
|
||||
// <1^n, 2^n>
|
||||
onendottwon, err := innerProduct(get1nVector(n, curve), get2nVector(n, curve))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "deltayz")
|
||||
}
|
||||
|
||||
termSecond := curve.Scalar.Zero()
|
||||
zExp := z.Square()
|
||||
for j := 1; j < m+1; j++ {
|
||||
zExp = zExp.Mul(z)
|
||||
elem := zExp.Mul(onendottwon)
|
||||
termSecond = termSecond.Add(elem)
|
||||
}
|
||||
|
||||
// (z - z^2)*<1^n, y^n> - z^3*<1^n, 2^n>
|
||||
out := termFirst.Sub(termSecond)
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Bottom equation on pg21.
|
||||
func getPhmuBatched(proofG, proofHPrime []curves.Point, h, capA, capS curves.Point, x, y, z, mu curves.Scalar, n, m int, curve curves.Curve) curves.Point {
|
||||
twoN := get2nVector(n, curve)
|
||||
// h'^(z*y^n + z^2*2^n)
|
||||
lastElem := curve.NewIdentityPoint()
|
||||
zExp := z.Clone()
|
||||
for j := 1; j < m+1; j++ {
|
||||
// Get subvector of h
|
||||
hSubvector := proofHPrime[(j-1)*n : j*n]
|
||||
// z^(j+1)
|
||||
zExp = zExp.Mul(z)
|
||||
exp := multiplyScalarToScalarVector(zExp, twoN)
|
||||
// Final elem
|
||||
elem := curve.Point.SumOfProducts(hSubvector, exp)
|
||||
lastElem = lastElem.Add(elem)
|
||||
}
|
||||
|
||||
zynm := multiplyScalarToScalarVector(z, getknVector(y, n*m, curve))
|
||||
hPrimezynm := curve.Point.SumOfProducts(proofHPrime, zynm)
|
||||
lastElem = lastElem.Add(hPrimezynm)
|
||||
|
||||
// S^x
|
||||
capSx := capS.Mul(x)
|
||||
|
||||
// g^-z --> -z*<1,g>
|
||||
onenm := get1nVector(n*m, curve)
|
||||
zNeg := z.Neg()
|
||||
zinvonen := multiplyScalarToScalarVector(zNeg, onenm)
|
||||
zgdotonen := curve.Point.SumOfProducts(proofG, zinvonen)
|
||||
|
||||
// L66 on pg20
|
||||
P := capA.Add(capSx).Add(zgdotonen).Add(lastElem)
|
||||
hmu := h.Mul(mu)
|
||||
Phmu := P.Sub(hmu)
|
||||
|
||||
return Phmu
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
package bulletproof
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/gtank/merlin"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
func TestRangeBatchProverHappyPath(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
n := 256
|
||||
prover, err := NewRangeProver(n*4, []byte("rangeDomain"), []byte("ippDomain"), *curve)
|
||||
require.NoError(t, err)
|
||||
v1 := curve.Scalar.Random(crand.Reader)
|
||||
v2 := curve.Scalar.Random(crand.Reader)
|
||||
v3 := curve.Scalar.Random(crand.Reader)
|
||||
v4 := curve.Scalar.Random(crand.Reader)
|
||||
v := []curves.Scalar{v1, v2, v3, v4}
|
||||
|
||||
gamma1 := curve.Scalar.Random(crand.Reader)
|
||||
gamma2 := curve.Scalar.Random(crand.Reader)
|
||||
gamma3 := curve.Scalar.Random(crand.Reader)
|
||||
gamma4 := curve.Scalar.Random(crand.Reader)
|
||||
gamma := []curves.Scalar{gamma1, gamma2, gamma3, gamma4}
|
||||
g := curve.Point.Random(crand.Reader)
|
||||
h := curve.Point.Random(crand.Reader)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
proofGenerators := RangeProofGenerators{
|
||||
g: g,
|
||||
h: h,
|
||||
u: u,
|
||||
}
|
||||
transcript := merlin.NewTranscript("test")
|
||||
proof, err := prover.BatchProve(v, gamma, n, proofGenerators, transcript)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, proof)
|
||||
require.Equal(t, 10, len(proof.ipp.capLs))
|
||||
require.Equal(t, 10, len(proof.ipp.capRs))
|
||||
}
|
||||
|
||||
func TestGetaLBatched(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
v1 := curve.Scalar.Random(crand.Reader)
|
||||
v2 := curve.Scalar.Random(crand.Reader)
|
||||
v3 := curve.Scalar.Random(crand.Reader)
|
||||
v4 := curve.Scalar.Random(crand.Reader)
|
||||
v := []curves.Scalar{v1, v2, v3, v4}
|
||||
aL, err := getaLBatched(v, 256, *curve)
|
||||
require.NoError(t, err)
|
||||
twoN := get2nVector(256, *curve)
|
||||
for i := 1; i < len(v)+1; i++ {
|
||||
vec := aL[(i-1)*256 : i*256]
|
||||
product, err := innerProduct(vec, twoN)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, product.Cmp(v[i-1]))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRangeBatchProverMarshal(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
n := 256
|
||||
prover, err := NewRangeProver(n*4, []byte("rangeDomain"), []byte("ippDomain"), *curve)
|
||||
require.NoError(t, err)
|
||||
v1 := curve.Scalar.Random(crand.Reader)
|
||||
v2 := curve.Scalar.Random(crand.Reader)
|
||||
v3 := curve.Scalar.Random(crand.Reader)
|
||||
v4 := curve.Scalar.Random(crand.Reader)
|
||||
v := []curves.Scalar{v1, v2, v3, v4}
|
||||
|
||||
gamma1 := curve.Scalar.Random(crand.Reader)
|
||||
gamma2 := curve.Scalar.Random(crand.Reader)
|
||||
gamma3 := curve.Scalar.Random(crand.Reader)
|
||||
gamma4 := curve.Scalar.Random(crand.Reader)
|
||||
gamma := []curves.Scalar{gamma1, gamma2, gamma3, gamma4}
|
||||
g := curve.Point.Random(crand.Reader)
|
||||
h := curve.Point.Random(crand.Reader)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
proofGenerators := RangeProofGenerators{
|
||||
g: g,
|
||||
h: h,
|
||||
u: u,
|
||||
}
|
||||
transcript := merlin.NewTranscript("test")
|
||||
proof, err := prover.BatchProve(v, gamma, n, proofGenerators, transcript)
|
||||
require.NoError(t, err)
|
||||
|
||||
proofMarshaled := proof.MarshalBinary()
|
||||
proofPrime := NewRangeProof(curve)
|
||||
err = proofPrime.UnmarshalBinary(proofMarshaled)
|
||||
require.NoError(t, err)
|
||||
require.True(t, proof.capA.Equal(proofPrime.capA))
|
||||
require.True(t, proof.capS.Equal(proofPrime.capS))
|
||||
require.True(t, proof.capT1.Equal(proofPrime.capT1))
|
||||
require.True(t, proof.capT2.Equal(proofPrime.capT2))
|
||||
require.Zero(t, proof.taux.Cmp(proofPrime.taux))
|
||||
require.Zero(t, proof.mu.Cmp(proofPrime.mu))
|
||||
require.Zero(t, proof.tHat.Cmp(proofPrime.tHat))
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
package bulletproof
|
||||
|
||||
import (
|
||||
"github.com/gtank/merlin"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
// VerifyBatched verifies a given batched range proof.
|
||||
// It takes in a list of commitments to the secret values as capV instead of a single commitment to a single point
|
||||
// when compared to the unbatched single range proof case.
|
||||
func (verifier *RangeVerifier) VerifyBatched(proof *RangeProof, capV []curves.Point, proofGenerators RangeProofGenerators, n int, transcript *merlin.Transcript) (bool, error) {
|
||||
// Define nm as the total bits required for secrets, calculated as number of secrets * n
|
||||
m := len(capV)
|
||||
nm := n * m
|
||||
// nm must be less than the number of generators generated
|
||||
if nm > len(verifier.generators.G) {
|
||||
return false, errors.New("ipp vector length must be less than maxVectorLength")
|
||||
}
|
||||
|
||||
// In case where len(a) is less than number of generators precomputed by prover, trim to length
|
||||
proofG := verifier.generators.G[0:nm]
|
||||
proofH := verifier.generators.H[0:nm]
|
||||
|
||||
// Calc y,z,x from Fiat Shamir heuristic
|
||||
y, z, err := calcyzBatched(capV, proof.capA, proof.capS, transcript, verifier.curve)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "rangeproof verify")
|
||||
}
|
||||
|
||||
x, err := calcx(proof.capT1, proof.capT2, transcript, verifier.curve)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "rangeproof verify")
|
||||
}
|
||||
|
||||
wBytes := transcript.ExtractBytes([]byte("getw"), 64)
|
||||
w, err := verifier.curve.NewScalar().SetBytesWide(wBytes)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
// Calc delta(y,z), redefined for batched case on pg21
|
||||
deltayzBatched, err := deltayzBatched(y, z, n, m, verifier.curve)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "rangeproof verify")
|
||||
}
|
||||
|
||||
// Check tHat: L65, pg20
|
||||
// See equation 72 on pg21
|
||||
tHatIsValid := verifier.checktHatBatched(proof, capV, proofGenerators.g, proofGenerators.h, deltayzBatched, x, z, m)
|
||||
if !tHatIsValid {
|
||||
return false, errors.New("rangeproof verify tHat is invalid")
|
||||
}
|
||||
|
||||
// Verify IPP
|
||||
hPrime, err := gethPrime(proofH, y, verifier.curve)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "rangeproof verify")
|
||||
}
|
||||
|
||||
capPhmu := getPhmuBatched(proofG, hPrime, proofGenerators.h, proof.capA, proof.capS, x, y, z, proof.mu, n, m, verifier.curve)
|
||||
|
||||
ippVerified, err := verifier.ippVerifier.VerifyFromRangeProof(proofG, hPrime, capPhmu, proofGenerators.u.Mul(w), proof.tHat, proof.ipp, transcript)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "rangeproof verify")
|
||||
}
|
||||
|
||||
return ippVerified, nil
|
||||
}
|
||||
|
||||
// L65, pg20.
|
||||
func (verifier *RangeVerifier) checktHatBatched(proof *RangeProof, capV []curves.Point, g, h curves.Point, deltayz, x, z curves.Scalar, m int) bool {
|
||||
// g^tHat * h^tau_x
|
||||
gtHat := g.Mul(proof.tHat)
|
||||
htaux := h.Mul(proof.taux)
|
||||
lhs := gtHat.Add(htaux)
|
||||
|
||||
// V^z^2 * g^delta(y,z) * Tau_1^x * Tau_2^x^2
|
||||
// g^delta(y,z) * V^(z^2*z^m) * Tau_1^x * Tau_2^x^2
|
||||
zm := getknVector(z, m, verifier.curve)
|
||||
zsquarezm := multiplyScalarToScalarVector(z.Square(), zm)
|
||||
capVzsquaretwom := verifier.curve.Point.SumOfProducts(capV, zsquarezm)
|
||||
gdeltayz := g.Mul(deltayz)
|
||||
capTau1x := proof.capT1.Mul(x)
|
||||
capTau2xsquare := proof.capT2.Mul(x.Square())
|
||||
rhs := capVzsquaretwom.Add(gdeltayz).Add(capTau1x).Add(capTau2xsquare)
|
||||
|
||||
// Compare lhs =? rhs
|
||||
return lhs.Equal(rhs)
|
||||
}
|
@ -1,148 +0,0 @@
|
||||
package bulletproof
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/gtank/merlin"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
func TestRangeBatchVerifyHappyPath(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
n := 256
|
||||
prover, err := NewRangeProver(n*4, []byte("rangeDomain"), []byte("ippDomain"), *curve)
|
||||
require.NoError(t, err)
|
||||
v1 := curve.Scalar.Random(crand.Reader)
|
||||
v2 := curve.Scalar.Random(crand.Reader)
|
||||
v3 := curve.Scalar.Random(crand.Reader)
|
||||
v4 := curve.Scalar.Random(crand.Reader)
|
||||
v := []curves.Scalar{v1, v2, v3, v4}
|
||||
gamma1 := curve.Scalar.Random(crand.Reader)
|
||||
gamma2 := curve.Scalar.Random(crand.Reader)
|
||||
gamma3 := curve.Scalar.Random(crand.Reader)
|
||||
gamma4 := curve.Scalar.Random(crand.Reader)
|
||||
gamma := []curves.Scalar{gamma1, gamma2, gamma3, gamma4}
|
||||
g := curve.Point.Random(crand.Reader)
|
||||
h := curve.Point.Random(crand.Reader)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
proofGenerators := RangeProofGenerators{
|
||||
g: g,
|
||||
h: h,
|
||||
u: u,
|
||||
}
|
||||
transcript := merlin.NewTranscript("test")
|
||||
proof, err := prover.BatchProve(v, gamma, n, proofGenerators, transcript)
|
||||
require.NoError(t, err)
|
||||
|
||||
verifier, err := NewRangeVerifier(n*4, []byte("rangeDomain"), []byte("ippDomain"), *curve)
|
||||
require.NoError(t, err)
|
||||
transcriptVerifier := merlin.NewTranscript("test")
|
||||
capV := getcapVBatched(v, gamma, g, h)
|
||||
verified, err := verifier.VerifyBatched(proof, capV, proofGenerators, n, transcriptVerifier)
|
||||
require.NoError(t, err)
|
||||
require.True(t, verified)
|
||||
}
|
||||
|
||||
func TestRangeBatchVerifyNotInRange(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
n := 2
|
||||
prover, err := NewRangeProver(n*4, []byte("rangeDomain"), []byte("ippDomain"), *curve)
|
||||
require.NoError(t, err)
|
||||
v1 := curve.Scalar.One()
|
||||
v2 := curve.Scalar.Random(crand.Reader)
|
||||
v3 := curve.Scalar.Random(crand.Reader)
|
||||
v4 := curve.Scalar.Random(crand.Reader)
|
||||
v := []curves.Scalar{v1, v2, v3, v4}
|
||||
gamma1 := curve.Scalar.Random(crand.Reader)
|
||||
gamma2 := curve.Scalar.Random(crand.Reader)
|
||||
gamma3 := curve.Scalar.Random(crand.Reader)
|
||||
gamma4 := curve.Scalar.Random(crand.Reader)
|
||||
gamma := []curves.Scalar{gamma1, gamma2, gamma3, gamma4}
|
||||
g := curve.Point.Random(crand.Reader)
|
||||
h := curve.Point.Random(crand.Reader)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
proofGenerators := RangeProofGenerators{
|
||||
g: g,
|
||||
h: h,
|
||||
u: u,
|
||||
}
|
||||
transcript := merlin.NewTranscript("test")
|
||||
_, err = prover.BatchProve(v, gamma, n, proofGenerators, transcript)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestRangeBatchVerifyNonRandom(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
n := 2
|
||||
prover, err := NewRangeProver(n*4, []byte("rangeDomain"), []byte("ippDomain"), *curve)
|
||||
require.NoError(t, err)
|
||||
v1 := curve.Scalar.One()
|
||||
v2 := curve.Scalar.One()
|
||||
v3 := curve.Scalar.One()
|
||||
v4 := curve.Scalar.One()
|
||||
v := []curves.Scalar{v1, v2, v3, v4}
|
||||
gamma1 := curve.Scalar.Random(crand.Reader)
|
||||
gamma2 := curve.Scalar.Random(crand.Reader)
|
||||
gamma3 := curve.Scalar.Random(crand.Reader)
|
||||
gamma4 := curve.Scalar.Random(crand.Reader)
|
||||
gamma := []curves.Scalar{gamma1, gamma2, gamma3, gamma4}
|
||||
g := curve.Point.Random(crand.Reader)
|
||||
h := curve.Point.Random(crand.Reader)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
proofGenerators := RangeProofGenerators{
|
||||
g: g,
|
||||
h: h,
|
||||
u: u,
|
||||
}
|
||||
transcript := merlin.NewTranscript("test")
|
||||
proof, err := prover.BatchProve(v, gamma, n, proofGenerators, transcript)
|
||||
require.NoError(t, err)
|
||||
|
||||
verifier, err := NewRangeVerifier(n*4, []byte("rangeDomain"), []byte("ippDomain"), *curve)
|
||||
require.NoError(t, err)
|
||||
transcriptVerifier := merlin.NewTranscript("test")
|
||||
capV := getcapVBatched(v, gamma, g, h)
|
||||
verified, err := verifier.VerifyBatched(proof, capV, proofGenerators, n, transcriptVerifier)
|
||||
require.NoError(t, err)
|
||||
require.True(t, verified)
|
||||
}
|
||||
|
||||
func TestRangeBatchVerifyInvalid(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
n := 2
|
||||
prover, err := NewRangeProver(n*4, []byte("rangeDomain"), []byte("ippDomain"), *curve)
|
||||
require.NoError(t, err)
|
||||
v1 := curve.Scalar.One()
|
||||
v2 := curve.Scalar.One()
|
||||
v3 := curve.Scalar.One()
|
||||
v4 := curve.Scalar.One()
|
||||
v := []curves.Scalar{v1, v2, v3, v4}
|
||||
gamma1 := curve.Scalar.Random(crand.Reader)
|
||||
gamma2 := curve.Scalar.Random(crand.Reader)
|
||||
gamma3 := curve.Scalar.Random(crand.Reader)
|
||||
gamma4 := curve.Scalar.Random(crand.Reader)
|
||||
gamma := []curves.Scalar{gamma1, gamma2, gamma3, gamma4}
|
||||
g := curve.Point.Random(crand.Reader)
|
||||
h := curve.Point.Random(crand.Reader)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
proofGenerators := RangeProofGenerators{
|
||||
g: g,
|
||||
h: h,
|
||||
u: u,
|
||||
}
|
||||
transcript := merlin.NewTranscript("test")
|
||||
proof, err := prover.BatchProve(v, gamma, n, proofGenerators, transcript)
|
||||
require.NoError(t, err)
|
||||
|
||||
verifier, err := NewRangeVerifier(n*4, []byte("rangeDomain"), []byte("ippDomain"), *curve)
|
||||
require.NoError(t, err)
|
||||
transcriptVerifier := merlin.NewTranscript("test")
|
||||
capV := getcapVBatched(v, gamma, g, h)
|
||||
capV[0] = curve.Point.Random(crand.Reader)
|
||||
verified, err := verifier.VerifyBatched(proof, capV, proofGenerators, n, transcriptVerifier)
|
||||
require.Error(t, err)
|
||||
require.False(t, verified)
|
||||
}
|
@ -1,476 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
// Package bulletproof implements the zero knowledge protocol bulletproofs as defined in https://eprint.iacr.org/2017/1066.pdf
|
||||
package bulletproof
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"math/big"
|
||||
|
||||
"github.com/gtank/merlin"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
// RangeProver is the struct used to create RangeProofs
|
||||
// It specifies which curve to use and holds precomputed generators
|
||||
// See NewRangeProver() for prover initialization.
|
||||
type RangeProver struct {
|
||||
curve curves.Curve
|
||||
generators *ippGenerators
|
||||
ippProver *InnerProductProver
|
||||
}
|
||||
|
||||
// RangeProof is the struct used to hold a range proof
|
||||
// capA is a commitment to a_L and a_R using randomness alpha
|
||||
// capS is a commitment to s_L and s_R using randomness rho
|
||||
// capTau1,2 are commitments to t1,t2 respectively using randomness tau_1,2
|
||||
// tHat represents t(X) as defined on page 19
|
||||
// taux is the blinding factor for tHat
|
||||
// ipp is the inner product proof used for compacting the transfer of l,r (See 4.2 on pg20).
|
||||
type RangeProof struct {
|
||||
capA, capS, capT1, capT2 curves.Point
|
||||
taux, mu, tHat curves.Scalar
|
||||
ipp *InnerProductProof
|
||||
curve *curves.Curve
|
||||
}
|
||||
|
||||
type RangeProofGenerators struct {
|
||||
g, h, u curves.Point
|
||||
}
|
||||
|
||||
// NewRangeProver initializes a new prover
|
||||
// It uses the specified domain to generate generators for vectors of at most maxVectorLength
|
||||
// A prover can be used to construct range proofs for vectors of length less than or equal to maxVectorLength
|
||||
// A prover is defined by an explicit curve.
|
||||
func NewRangeProver(maxVectorLength int, rangeDomain, ippDomain []byte, curve curves.Curve) (*RangeProver, error) {
|
||||
generators, err := getGeneratorPoints(maxVectorLength, rangeDomain, curve)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "range NewRangeProver")
|
||||
}
|
||||
ippProver, err := NewInnerProductProver(maxVectorLength, ippDomain, curve)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "range NewRangeProver")
|
||||
}
|
||||
return &RangeProver{curve: curve, generators: generators, ippProver: ippProver}, nil
|
||||
}
|
||||
|
||||
// NewRangeProof initializes a new RangeProof for a specified curve
|
||||
// This should be used in tandem with UnmarshalBinary() to convert a marshaled proof into the struct.
|
||||
func NewRangeProof(curve *curves.Curve) *RangeProof {
|
||||
out := RangeProof{
|
||||
capA: nil,
|
||||
capS: nil,
|
||||
capT1: nil,
|
||||
capT2: nil,
|
||||
taux: nil,
|
||||
mu: nil,
|
||||
tHat: nil,
|
||||
ipp: NewInnerProductProof(curve),
|
||||
curve: curve,
|
||||
}
|
||||
|
||||
return &out
|
||||
}
|
||||
|
||||
// Prove uses the range prover to prove that some value v is within the range [0, 2^n]
|
||||
// It implements the protocol defined on pgs 19,20 in https://eprint.iacr.org/2017/1066.pdf
|
||||
// v is the value of which to prove the range
|
||||
// n is the power that specifies the upper bound of the range, ie. 2^n
|
||||
// gamma is a scalar used for as a blinding factor
|
||||
// g, h, u are unique points used as generators for the blinding factor
|
||||
// transcript is a merlin transcript to be used for the fiat shamir heuristic.
|
||||
func (prover *RangeProver) Prove(v, gamma curves.Scalar, n int, proofGenerators RangeProofGenerators, transcript *merlin.Transcript) (*RangeProof, error) {
|
||||
// n must be less than or equal to the number of generators generated
|
||||
if n > len(prover.generators.G) {
|
||||
return nil, errors.New("ipp vector length must be less than or equal to maxVectorLength")
|
||||
}
|
||||
// In case where len(a) is less than number of generators precomputed by prover, trim to length
|
||||
proofG := prover.generators.G[0:n]
|
||||
proofH := prover.generators.H[0:n]
|
||||
|
||||
// Check that v is in range [0, 2^n]
|
||||
if bigZero := big.NewInt(0); v.BigInt().Cmp(bigZero) == -1 {
|
||||
return nil, errors.New("v is less than 0")
|
||||
}
|
||||
|
||||
bigTwo := big.NewInt(2)
|
||||
if n < 0 {
|
||||
return nil, errors.New("n cannot be less than 0")
|
||||
}
|
||||
bigN := big.NewInt(int64(n))
|
||||
var bigTwoToN big.Int
|
||||
bigTwoToN.Exp(bigTwo, bigN, nil)
|
||||
if v.BigInt().Cmp(&bigTwoToN) == 1 {
|
||||
return nil, errors.New("v is greater than 2^n")
|
||||
}
|
||||
|
||||
// L40 on pg19
|
||||
aL, err := getaL(v, n, prover.curve)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
onen := get1nVector(n, prover.curve)
|
||||
// L41 on pg19
|
||||
aR, err := subtractPairwiseScalarVectors(aL, onen)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
alpha := prover.curve.Scalar.Random(crand.Reader)
|
||||
// Calc A (L44, pg19)
|
||||
halpha := proofGenerators.h.Mul(alpha)
|
||||
gaL := prover.curve.Point.SumOfProducts(proofG, aL)
|
||||
haR := prover.curve.Point.SumOfProducts(proofH, aR)
|
||||
capA := halpha.Add(gaL).Add(haR)
|
||||
|
||||
// L45, 46, pg19
|
||||
sL := getBlindingVector(n, prover.curve)
|
||||
sR := getBlindingVector(n, prover.curve)
|
||||
rho := prover.curve.Scalar.Random(crand.Reader)
|
||||
|
||||
// Calc S (L47, pg19)
|
||||
hrho := proofGenerators.h.Mul(rho)
|
||||
gsL := prover.curve.Point.SumOfProducts(proofG, sL)
|
||||
hsR := prover.curve.Point.SumOfProducts(proofH, sR)
|
||||
capS := hrho.Add(gsL).Add(hsR)
|
||||
|
||||
// Fiat Shamir for y,z (L49, pg19)
|
||||
capV := getcapV(v, gamma, proofGenerators.g, proofGenerators.h)
|
||||
y, z, err := calcyz(capV, capA, capS, transcript, prover.curve)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
// Calc t_1, t_2
|
||||
// See the l(X), r(X), t(X) equations on pg 19
|
||||
// Use l(X)'s and r(X)'s constant and linear terms to derive t_1 and t_2
|
||||
// (a_l - z*1^n)
|
||||
zonen := multiplyScalarToScalarVector(z, onen)
|
||||
constantTerml, err := subtractPairwiseScalarVectors(aL, zonen)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
linearTerml := sL
|
||||
|
||||
// z^2 * 2^N
|
||||
twoN := get2nVector(n, prover.curve)
|
||||
zSquareTwon := multiplyScalarToScalarVector(z.Square(), twoN)
|
||||
// a_r + z*1^n
|
||||
aRPluszonen, err := addPairwiseScalarVectors(aR, zonen)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
yn := getknVector(y, n, prover.curve)
|
||||
hadamard, err := multiplyPairwiseScalarVectors(yn, aRPluszonen)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
constantTermr, err := addPairwiseScalarVectors(hadamard, zSquareTwon)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
linearTermr, err := multiplyPairwiseScalarVectors(yn, sR)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
// t_1 (as the linear coefficient) is the sum of the dot products of l(X)'s linear term dot r(X)'s constant term
|
||||
// and r(X)'s linear term dot l(X)'s constant term
|
||||
t1FirstTerm, err := innerProduct(linearTerml, constantTermr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
t1SecondTerm, err := innerProduct(linearTermr, constantTerml)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
t1 := t1FirstTerm.Add(t1SecondTerm)
|
||||
|
||||
// t_2 (as the quadratic coefficient) is the dot product of l(X)'s and r(X)'s linear terms
|
||||
t2, err := innerProduct(linearTerml, linearTermr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
// L52, pg20
|
||||
tau1 := prover.curve.Scalar.Random(crand.Reader)
|
||||
tau2 := prover.curve.Scalar.Random(crand.Reader)
|
||||
|
||||
// T_1, T_2 (L53, pg20)
|
||||
capT1 := proofGenerators.g.Mul(t1).Add(proofGenerators.h.Mul(tau1))
|
||||
capT2 := proofGenerators.g.Mul(t2).Add(proofGenerators.h.Mul(tau2))
|
||||
|
||||
// Fiat shamir for x (L55, pg20)
|
||||
x, err := calcx(capT1, capT2, transcript, prover.curve)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
// Calc l (L58, pg20)
|
||||
// Instead of using the expression in the line, evaluate l() at x
|
||||
sLx := multiplyScalarToScalarVector(x, linearTerml)
|
||||
l, err := addPairwiseScalarVectors(constantTerml, sLx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
// Calc r (L59, pg20)
|
||||
// Instead of using the expression in the line, evaluate r() at x
|
||||
ynsRx := multiplyScalarToScalarVector(x, linearTermr)
|
||||
r, err := addPairwiseScalarVectors(constantTermr, ynsRx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
// Calc t hat (L60, pg20)
|
||||
// For efficiency, instead of calculating the dot product, evaluate t() at x
|
||||
deltayz, err := deltayz(y, z, n, prover.curve)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
t0 := v.Mul(z.Square()).Add(deltayz)
|
||||
tLinear := t1.Mul(x)
|
||||
tQuadratic := t2.Mul(x.Square())
|
||||
tHat := t0.Add(tLinear).Add(tQuadratic)
|
||||
|
||||
// Calc tau_x (L61, pg20)
|
||||
tau2xsquare := tau2.Mul(x.Square())
|
||||
tau1x := tau1.Mul(x)
|
||||
zsquaregamma := z.Square().Mul(gamma)
|
||||
taux := tau2xsquare.Add(tau1x).Add(zsquaregamma)
|
||||
|
||||
// Calc mu (L62, pg20)
|
||||
mu := alpha.Add(rho.Mul(x))
|
||||
|
||||
// Calc IPP (See section 4.2)
|
||||
hPrime, err := gethPrime(proofH, y, prover.curve)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
capPhmu, err := getPhmu(proofG, hPrime, proofGenerators.h, capA, capS, x, y, z, mu, n, prover.curve)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
wBytes := transcript.ExtractBytes([]byte("getw"), 64)
|
||||
w, err := prover.curve.NewScalar().SetBytesWide(wBytes)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
ipp, err := prover.ippProver.rangeToIPP(proofG, hPrime, l, r, tHat, capPhmu, proofGenerators.u.Mul(w), transcript)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
out := &RangeProof{
|
||||
capA: capA,
|
||||
capS: capS,
|
||||
capT1: capT1,
|
||||
capT2: capT2,
|
||||
taux: taux,
|
||||
mu: mu,
|
||||
tHat: tHat,
|
||||
ipp: ipp,
|
||||
curve: &prover.curve,
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// MarshalBinary takes a range proof and marshals into bytes.
|
||||
func (proof *RangeProof) MarshalBinary() []byte {
|
||||
var out []byte
|
||||
out = append(out, proof.capA.ToAffineCompressed()...)
|
||||
out = append(out, proof.capS.ToAffineCompressed()...)
|
||||
out = append(out, proof.capT1.ToAffineCompressed()...)
|
||||
out = append(out, proof.capT2.ToAffineCompressed()...)
|
||||
out = append(out, proof.taux.Bytes()...)
|
||||
out = append(out, proof.mu.Bytes()...)
|
||||
out = append(out, proof.tHat.Bytes()...)
|
||||
out = append(out, proof.ipp.MarshalBinary()...)
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// UnmarshalBinary takes bytes of a marshaled proof and writes them into a range proof
|
||||
// The range proof used should be from the output of NewRangeProof().
|
||||
func (proof *RangeProof) UnmarshalBinary(data []byte) error {
|
||||
scalarLen := len(proof.curve.NewScalar().Bytes())
|
||||
pointLen := len(proof.curve.NewGeneratorPoint().ToAffineCompressed())
|
||||
ptr := 0
|
||||
// Get points
|
||||
capA, err := proof.curve.Point.FromAffineCompressed(data[ptr : ptr+pointLen])
|
||||
if err != nil {
|
||||
return errors.New("rangeProof UnmarshalBinary FromAffineCompressed")
|
||||
}
|
||||
proof.capA = capA
|
||||
ptr += pointLen
|
||||
capS, err := proof.curve.Point.FromAffineCompressed(data[ptr : ptr+pointLen])
|
||||
if err != nil {
|
||||
return errors.New("rangeProof UnmarshalBinary FromAffineCompressed")
|
||||
}
|
||||
proof.capS = capS
|
||||
ptr += pointLen
|
||||
capT1, err := proof.curve.Point.FromAffineCompressed(data[ptr : ptr+pointLen])
|
||||
if err != nil {
|
||||
return errors.New("rangeProof UnmarshalBinary FromAffineCompressed")
|
||||
}
|
||||
proof.capT1 = capT1
|
||||
ptr += pointLen
|
||||
capT2, err := proof.curve.Point.FromAffineCompressed(data[ptr : ptr+pointLen])
|
||||
if err != nil {
|
||||
return errors.New("rangeProof UnmarshalBinary FromAffineCompressed")
|
||||
}
|
||||
proof.capT2 = capT2
|
||||
ptr += pointLen
|
||||
|
||||
// Get scalars
|
||||
taux, err := proof.curve.NewScalar().SetBytes(data[ptr : ptr+scalarLen])
|
||||
if err != nil {
|
||||
return errors.New("rangeProof UnmarshalBinary SetBytes")
|
||||
}
|
||||
proof.taux = taux
|
||||
ptr += scalarLen
|
||||
mu, err := proof.curve.NewScalar().SetBytes(data[ptr : ptr+scalarLen])
|
||||
if err != nil {
|
||||
return errors.New("rangeProof UnmarshalBinary SetBytes")
|
||||
}
|
||||
proof.mu = mu
|
||||
ptr += scalarLen
|
||||
tHat, err := proof.curve.NewScalar().SetBytes(data[ptr : ptr+scalarLen])
|
||||
if err != nil {
|
||||
return errors.New("rangeProof UnmarshalBinary SetBytes")
|
||||
}
|
||||
proof.tHat = tHat
|
||||
ptr += scalarLen
|
||||
|
||||
// Get IPP
|
||||
err = proof.ipp.UnmarshalBinary(data[ptr:])
|
||||
if err != nil {
|
||||
return errors.New("rangeProof UnmarshalBinary")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkRange validates whether some scalar v is within the range [0, 2^n - 1]
|
||||
// It will return an error if v is less than 0 or greater than 2^n - 1
|
||||
// Otherwise it will return nil.
|
||||
func checkRange(v curves.Scalar, n int) error {
|
||||
bigOne := big.NewInt(1)
|
||||
if n < 0 {
|
||||
return errors.New("n cannot be less than 0")
|
||||
}
|
||||
var bigTwoToN big.Int
|
||||
bigTwoToN.Lsh(bigOne, uint(n))
|
||||
if v.BigInt().Cmp(&bigTwoToN) == 1 {
|
||||
return errors.New("v is greater than 2^n")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getBlindingVector returns a vector of scalars used as blinding factors for commitments.
|
||||
func getBlindingVector(length int, curve curves.Curve) []curves.Scalar {
|
||||
vec := make([]curves.Scalar, length)
|
||||
for i := 0; i < length; i++ {
|
||||
vec[i] = curve.Scalar.Random(crand.Reader)
|
||||
}
|
||||
return vec
|
||||
}
|
||||
|
||||
// getcapV returns a commitment to v using blinding factor gamma.
|
||||
func getcapV(v, gamma curves.Scalar, g, h curves.Point) curves.Point {
|
||||
return h.Mul(gamma).Add(g.Mul(v))
|
||||
}
|
||||
|
||||
// getaL obtains the bit vector representation of v
|
||||
// See the a_L definition towards the bottom of pg 17 of https://eprint.iacr.org/2017/1066.pdf
|
||||
func getaL(v curves.Scalar, n int, curve curves.Curve) ([]curves.Scalar, error) {
|
||||
var err error
|
||||
|
||||
vBytes := v.Bytes()
|
||||
zero := curve.Scalar.Zero()
|
||||
one := curve.Scalar.One()
|
||||
aL := make([]curves.Scalar, n)
|
||||
for j := 0; j < len(aL); j++ {
|
||||
aL[j] = zero
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
ithBit := vBytes[i>>3] >> (i & 0x07) & 0x01
|
||||
aL[i], err = cmoveScalar(zero, one, int(ithBit), curve)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getaL")
|
||||
}
|
||||
}
|
||||
|
||||
return aL, nil
|
||||
}
|
||||
|
||||
// cmoveScalar provides a constant time operation that returns x if which is 0 and returns y if which is 1.
|
||||
func cmoveScalar(x, y curves.Scalar, which int, curve curves.Curve) (curves.Scalar, error) {
|
||||
if which != 0 && which != 1 {
|
||||
return nil, errors.New("cmoveScalar which must be 0 or 1")
|
||||
}
|
||||
mask := -byte(which)
|
||||
xBytes := x.Bytes()
|
||||
yBytes := y.Bytes()
|
||||
for i, xByte := range xBytes {
|
||||
xBytes[i] ^= (xByte ^ yBytes[i]) & mask
|
||||
}
|
||||
out, err := curve.NewScalar().SetBytes(xBytes)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cmoveScalar SetBytes")
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// calcyz uses a merlin transcript for Fiat Shamir
|
||||
// It takes the current state of the transcript and appends the newly calculated capA and capS values
|
||||
// Two new scalars are then read from the transcript
|
||||
// See section 4.4 pg22 of https://eprint.iacr.org/2017/1066.pdf
|
||||
func calcyz(capV, capA, capS curves.Point, transcript *merlin.Transcript, curve curves.Curve) (curves.Scalar, curves.Scalar, error) {
|
||||
// Add the A,S values to transcript
|
||||
transcript.AppendMessage([]byte("addV"), capV.ToAffineUncompressed())
|
||||
transcript.AppendMessage([]byte("addcapA"), capA.ToAffineUncompressed())
|
||||
transcript.AppendMessage([]byte("addcapS"), capS.ToAffineUncompressed())
|
||||
// Read 64 bytes twice from, set to scalar for y and z
|
||||
yBytes := transcript.ExtractBytes([]byte("gety"), 64)
|
||||
y, err := curve.NewScalar().SetBytesWide(yBytes)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "calcyz NewScalar SetBytesWide")
|
||||
}
|
||||
zBytes := transcript.ExtractBytes([]byte("getz"), 64)
|
||||
z, err := curve.NewScalar().SetBytesWide(zBytes)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "calcyz NewScalar SetBytesWide")
|
||||
}
|
||||
|
||||
return y, z, nil
|
||||
}
|
||||
|
||||
// calcx uses a merlin transcript for Fiat Shamir
|
||||
// It takes the current state of the transcript and appends the newly calculated capT1 and capT2 values
|
||||
// A new scalar is then read from the transcript
|
||||
// See section 4.4 pg22 of https://eprint.iacr.org/2017/1066.pdf
|
||||
func calcx(capT1, capT2 curves.Point, transcript *merlin.Transcript, curve curves.Curve) (curves.Scalar, error) {
|
||||
// Add the Tau1,2 values to transcript
|
||||
transcript.AppendMessage([]byte("addcapT1"), capT1.ToAffineUncompressed())
|
||||
transcript.AppendMessage([]byte("addcapT2"), capT2.ToAffineUncompressed())
|
||||
// Read 64 bytes from, set to scalar
|
||||
outBytes := transcript.ExtractBytes([]byte("getx"), 64)
|
||||
x, err := curve.NewScalar().SetBytesWide(outBytes)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "calcx NewScalar SetBytesWide")
|
||||
}
|
||||
|
||||
return x, nil
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
package bulletproof
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/gtank/merlin"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
func TestRangeProverHappyPath(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
n := 256
|
||||
prover, err := NewRangeProver(n, []byte("rangeDomain"), []byte("ippDomain"), *curve)
|
||||
require.NoError(t, err)
|
||||
v := curve.Scalar.Random(crand.Reader)
|
||||
gamma := curve.Scalar.Random(crand.Reader)
|
||||
g := curve.Point.Random(crand.Reader)
|
||||
h := curve.Point.Random(crand.Reader)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
proofGenerators := RangeProofGenerators{
|
||||
g: g,
|
||||
h: h,
|
||||
u: u,
|
||||
}
|
||||
transcript := merlin.NewTranscript("test")
|
||||
proof, err := prover.Prove(v, gamma, n, proofGenerators, transcript)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, proof)
|
||||
require.Equal(t, 8, len(proof.ipp.capLs))
|
||||
require.Equal(t, 8, len(proof.ipp.capRs))
|
||||
}
|
||||
|
||||
func TestGetaL(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
v := curve.Scalar.Random(crand.Reader)
|
||||
aL, err := getaL(v, 256, *curve)
|
||||
require.NoError(t, err)
|
||||
twoN := get2nVector(256, *curve)
|
||||
product, err := innerProduct(aL, twoN)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, product.Cmp(v))
|
||||
}
|
||||
|
||||
func TestCmove(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
two := curve.Scalar.One().Double()
|
||||
four := two.Double()
|
||||
out, err := cmoveScalar(two, four, 1, *curve)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, out.Cmp(four))
|
||||
}
|
||||
|
||||
func TestRangeProverMarshal(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
n := 256
|
||||
prover, err := NewRangeProver(n, []byte("rangeDomain"), []byte("ippDomain"), *curve)
|
||||
require.NoError(t, err)
|
||||
v := curve.Scalar.Random(crand.Reader)
|
||||
gamma := curve.Scalar.Random(crand.Reader)
|
||||
g := curve.Point.Random(crand.Reader)
|
||||
h := curve.Point.Random(crand.Reader)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
proofGenerators := RangeProofGenerators{
|
||||
g: g,
|
||||
h: h,
|
||||
u: u,
|
||||
}
|
||||
transcript := merlin.NewTranscript("test")
|
||||
proof, err := prover.Prove(v, gamma, n, proofGenerators, transcript)
|
||||
require.NoError(t, err)
|
||||
|
||||
proofMarshaled := proof.MarshalBinary()
|
||||
proofPrime := NewRangeProof(curve)
|
||||
err = proofPrime.UnmarshalBinary(proofMarshaled)
|
||||
require.NoError(t, err)
|
||||
require.True(t, proof.capA.Equal(proofPrime.capA))
|
||||
require.True(t, proof.capS.Equal(proofPrime.capS))
|
||||
require.True(t, proof.capT1.Equal(proofPrime.capT1))
|
||||
require.True(t, proof.capT2.Equal(proofPrime.capT2))
|
||||
require.Zero(t, proof.taux.Cmp(proofPrime.taux))
|
||||
require.Zero(t, proof.mu.Cmp(proofPrime.mu))
|
||||
require.Zero(t, proof.tHat.Cmp(proofPrime.tHat))
|
||||
}
|
@ -1,187 +0,0 @@
|
||||
package bulletproof
|
||||
|
||||
import (
|
||||
"github.com/gtank/merlin"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
// RangeVerifier is the struct used to verify RangeProofs
|
||||
// It specifies which curve to use and holds precomputed generators
|
||||
// See NewRangeVerifier() for verifier initialization.
|
||||
type RangeVerifier struct {
|
||||
curve curves.Curve
|
||||
generators *ippGenerators
|
||||
ippVerifier *InnerProductVerifier
|
||||
}
|
||||
|
||||
// NewRangeVerifier initializes a new verifier
|
||||
// It uses the specified domain to generate generators for vectors of at most maxVectorLength
|
||||
// A verifier can be used to verify range proofs for vectors of length less than or equal to maxVectorLength
|
||||
// A verifier is defined by an explicit curve.
|
||||
func NewRangeVerifier(maxVectorLength int, rangeDomain, ippDomain []byte, curve curves.Curve) (*RangeVerifier, error) {
|
||||
generators, err := getGeneratorPoints(maxVectorLength, rangeDomain, curve)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "range NewRangeProver")
|
||||
}
|
||||
ippVerifier, err := NewInnerProductVerifier(maxVectorLength, ippDomain, curve)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "range NewRangeProver")
|
||||
}
|
||||
return &RangeVerifier{curve: curve, generators: generators, ippVerifier: ippVerifier}, nil
|
||||
}
|
||||
|
||||
// Verify verifies the given range proof inputs
|
||||
// It implements the checking of L65 on pg 20
|
||||
// It also verifies the dot product of <l,r> using the inner product proof\
|
||||
// capV is a commitment to v using blinding factor gamma
|
||||
// n is the power that specifies the upper bound of the range, ie. 2^n
|
||||
// g, h, u are unique points used as generators for the blinding factor
|
||||
// transcript is a merlin transcript to be used for the fiat shamir heuristic.
|
||||
func (verifier *RangeVerifier) Verify(proof *RangeProof, capV curves.Point, proofGenerators RangeProofGenerators, n int, transcript *merlin.Transcript) (bool, error) {
|
||||
// Length of vectors must be less than the number of generators generated
|
||||
if n > len(verifier.generators.G) {
|
||||
return false, errors.New("ipp vector length must be less than maxVectorLength")
|
||||
}
|
||||
// In case where len(a) is less than number of generators precomputed by prover, trim to length
|
||||
proofG := verifier.generators.G[0:n]
|
||||
proofH := verifier.generators.H[0:n]
|
||||
|
||||
// Calc y,z,x from Fiat Shamir heuristic
|
||||
y, z, err := calcyz(capV, proof.capA, proof.capS, transcript, verifier.curve)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "rangeproof verify")
|
||||
}
|
||||
|
||||
x, err := calcx(proof.capT1, proof.capT2, transcript, verifier.curve)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "rangeproof verify")
|
||||
}
|
||||
|
||||
wBytes := transcript.ExtractBytes([]byte("getw"), 64)
|
||||
w, err := verifier.curve.NewScalar().SetBytesWide(wBytes)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "rangeproof prove")
|
||||
}
|
||||
|
||||
// Calc delta(y,z)
|
||||
deltayz, err := deltayz(y, z, n, verifier.curve)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "rangeproof verify")
|
||||
}
|
||||
|
||||
// Check tHat: L65, pg20
|
||||
tHatIsValid := verifier.checktHat(proof, capV, proofGenerators.g, proofGenerators.h, deltayz, x, z)
|
||||
if !tHatIsValid {
|
||||
return false, errors.New("rangeproof verify tHat is invalid")
|
||||
}
|
||||
|
||||
// Verify IPP
|
||||
hPrime, err := gethPrime(proofH, y, verifier.curve)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "rangeproof verify")
|
||||
}
|
||||
|
||||
capPhmu, err := getPhmu(proofG, hPrime, proofGenerators.h, proof.capA, proof.capS, x, y, z, proof.mu, n, verifier.curve)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "rangeproof verify")
|
||||
}
|
||||
|
||||
ippVerified, err := verifier.ippVerifier.VerifyFromRangeProof(proofG, hPrime, capPhmu, proofGenerators.u.Mul(w), proof.tHat, proof.ipp, transcript)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "rangeproof verify")
|
||||
}
|
||||
|
||||
return ippVerified, nil
|
||||
}
|
||||
|
||||
// L65, pg20.
|
||||
func (*RangeVerifier) checktHat(proof *RangeProof, capV, g, h curves.Point, deltayz, x, z curves.Scalar) bool {
|
||||
// g^tHat * h^tau_x
|
||||
gtHat := g.Mul(proof.tHat)
|
||||
htaux := h.Mul(proof.taux)
|
||||
lhs := gtHat.Add(htaux)
|
||||
|
||||
// V^z^2 * g^delta(y,z) * Tau_1^x * Tau_2^x^2
|
||||
capVzsquare := capV.Mul(z.Square())
|
||||
gdeltayz := g.Mul(deltayz)
|
||||
capTau1x := proof.capT1.Mul(x)
|
||||
capTau2xsquare := proof.capT2.Mul(x.Square())
|
||||
rhs := capVzsquare.Add(gdeltayz).Add(capTau1x).Add(capTau2xsquare)
|
||||
|
||||
// Compare lhs =? rhs
|
||||
return lhs.Equal(rhs)
|
||||
}
|
||||
|
||||
// gethPrime calculates new h prime generators as defined in L64 on pg20.
|
||||
func gethPrime(h []curves.Point, y curves.Scalar, curve curves.Curve) ([]curves.Point, error) {
|
||||
hPrime := make([]curves.Point, len(h))
|
||||
yInv, err := y.Invert()
|
||||
yInvn := getknVector(yInv, len(h), curve)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "gethPrime")
|
||||
}
|
||||
for i, hElem := range h {
|
||||
hPrime[i] = hElem.Mul(yInvn[i])
|
||||
}
|
||||
return hPrime, nil
|
||||
}
|
||||
|
||||
// Obtain P used for IPP verification
|
||||
// See L67 on pg20
|
||||
// Note P on L66 includes blinding factor hmu, this method removes that factor.
|
||||
func getPhmu(proofG, proofHPrime []curves.Point, h, capA, capS curves.Point, x, y, z, mu curves.Scalar, n int, curve curves.Curve) (curves.Point, error) {
|
||||
// h'^(z*y^n + z^2*2^n)
|
||||
zyn := multiplyScalarToScalarVector(z, getknVector(y, n, curve))
|
||||
zsquaretwon := multiplyScalarToScalarVector(z.Square(), get2nVector(n, curve))
|
||||
elemLastExponent, err := addPairwiseScalarVectors(zyn, zsquaretwon)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getPhmu")
|
||||
}
|
||||
lastElem := curve.Point.SumOfProducts(proofHPrime, elemLastExponent)
|
||||
|
||||
// S^x
|
||||
capSx := capS.Mul(x)
|
||||
|
||||
// g^-z --> -z*<1,g>
|
||||
onen := get1nVector(n, curve)
|
||||
zNeg := z.Neg()
|
||||
zinvonen := multiplyScalarToScalarVector(zNeg, onen)
|
||||
zgdotonen := curve.Point.SumOfProducts(proofG, zinvonen)
|
||||
|
||||
// L66 on pg20
|
||||
P := capA.Add(capSx).Add(zgdotonen).Add(lastElem)
|
||||
hmu := h.Mul(mu)
|
||||
Phmu := P.Sub(hmu)
|
||||
|
||||
return Phmu, nil
|
||||
}
|
||||
|
||||
// Delta function for delta(y,z), See (39) on pg18.
|
||||
func deltayz(y, z curves.Scalar, n int, curve curves.Curve) (curves.Scalar, error) {
|
||||
// z - z^2
|
||||
zMinuszsquare := z.Sub(z.Square())
|
||||
// 1^n
|
||||
onen := get1nVector(n, curve)
|
||||
// <1^n, y^n>
|
||||
onendotyn, err := innerProduct(onen, getknVector(y, n, curve))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "deltayz")
|
||||
}
|
||||
// (z - z^2)*<1^n, y^n>
|
||||
termFirst := zMinuszsquare.Mul(onendotyn)
|
||||
|
||||
// <1^n, 2^n>
|
||||
onendottwon, err := innerProduct(onen, get2nVector(n, curve))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "deltayz")
|
||||
}
|
||||
// z^3*<1^n, 2^n>
|
||||
termSecond := z.Cube().Mul(onendottwon)
|
||||
|
||||
// (z - z^2)*<1^n, y^n> - z^3*<1^n, 2^n>
|
||||
out := termFirst.Sub(termSecond)
|
||||
|
||||
return out, nil
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
package bulletproof
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/gtank/merlin"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
)
|
||||
|
||||
func TestRangeVerifyHappyPath(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
n := 256
|
||||
prover, err := NewRangeProver(n, []byte("rangeDomain"), []byte("ippDomain"), *curve)
|
||||
require.NoError(t, err)
|
||||
v := curve.Scalar.Random(crand.Reader)
|
||||
gamma := curve.Scalar.Random(crand.Reader)
|
||||
g := curve.Point.Random(crand.Reader)
|
||||
h := curve.Point.Random(crand.Reader)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
proofGenerators := RangeProofGenerators{
|
||||
g: g,
|
||||
h: h,
|
||||
u: u,
|
||||
}
|
||||
transcript := merlin.NewTranscript("test")
|
||||
proof, err := prover.Prove(v, gamma, n, proofGenerators, transcript)
|
||||
require.NoError(t, err)
|
||||
|
||||
verifier, err := NewRangeVerifier(n, []byte("rangeDomain"), []byte("ippDomain"), *curve)
|
||||
require.NoError(t, err)
|
||||
transcriptVerifier := merlin.NewTranscript("test")
|
||||
capV := getcapV(v, gamma, g, h)
|
||||
verified, err := verifier.Verify(proof, capV, proofGenerators, n, transcriptVerifier)
|
||||
require.NoError(t, err)
|
||||
require.True(t, verified)
|
||||
}
|
||||
|
||||
func TestRangeVerifyNotInRange(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
n := 2
|
||||
prover, err := NewRangeProver(n, []byte("rangeDomain"), []byte("ippDomain"), *curve)
|
||||
require.NoError(t, err)
|
||||
v := curve.Scalar.Random(crand.Reader)
|
||||
gamma := curve.Scalar.Random(crand.Reader)
|
||||
g := curve.Point.Random(crand.Reader)
|
||||
h := curve.Point.Random(crand.Reader)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
proofGenerators := RangeProofGenerators{
|
||||
g: g,
|
||||
h: h,
|
||||
u: u,
|
||||
}
|
||||
transcript := merlin.NewTranscript("test")
|
||||
_, err = prover.Prove(v, gamma, n, proofGenerators, transcript)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestRangeVerifyNonRandom(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
n := 2
|
||||
prover, err := NewRangeProver(n, []byte("rangeDomain"), []byte("ippDomain"), *curve)
|
||||
require.NoError(t, err)
|
||||
v := curve.Scalar.One()
|
||||
gamma := curve.Scalar.Random(crand.Reader)
|
||||
g := curve.Point.Random(crand.Reader)
|
||||
h := curve.Point.Random(crand.Reader)
|
||||
u := curve.Point.Random(crand.Reader)
|
||||
proofGenerators := RangeProofGenerators{
|
||||
g: g,
|
||||
h: h,
|
||||
u: u,
|
||||
}
|
||||
transcript := merlin.NewTranscript("test")
|
||||
proof, err := prover.Prove(v, gamma, n, proofGenerators, transcript)
|
||||
require.NoError(t, err)
|
||||
|
||||
verifier, err := NewRangeVerifier(n, []byte("rangeDomain"), []byte("ippDomain"), *curve)
|
||||
require.NoError(t, err)
|
||||
transcriptVerifier := merlin.NewTranscript("test")
|
||||
capV := getcapV(v, gamma, g, h)
|
||||
verified, err := verifier.Verify(proof, capV, proofGenerators, n, transcriptVerifier)
|
||||
require.NoError(t, err)
|
||||
require.True(t, verified)
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
---
|
||||
aliases: [README]
|
||||
tags: []
|
||||
title: README
|
||||
linter-yaml-title-alias: README
|
||||
date created: Wednesday, April 17th 2024, 4:11:40 pm
|
||||
date modified: Thursday, April 18th 2024, 8:19:25 am
|
||||
---
|
||||
|
||||
## Core Package
|
||||
|
||||
The core package contains a set of primitives, including but not limited to various
|
||||
elliptic curves, hashes, and commitment schemes. These primitives are used internally
|
||||
and can also be used independently on their own externally.
|
@ -1,115 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
crand "crypto/rand"
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// Size of random values and hash outputs are determined by our hash function
|
||||
const Size = sha256.Size
|
||||
|
||||
type (
|
||||
// Commitment to a given message which can be later revealed.
|
||||
// This is sent to and held by a verifier until the corresponding
|
||||
// witness is provided.
|
||||
Commitment []byte
|
||||
|
||||
// Witness is sent to and opened by the verifier. This proves that
|
||||
// committed message hasn't been altered by later information.
|
||||
Witness struct {
|
||||
Msg []byte
|
||||
r [Size]byte
|
||||
}
|
||||
|
||||
// witnessJSON is used for un/marshaling.
|
||||
witnessJSON struct {
|
||||
Msg []byte
|
||||
R [Size]byte
|
||||
}
|
||||
)
|
||||
|
||||
// MarshalJSON encodes Witness in JSON
|
||||
func (w Witness) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(witnessJSON{w.Msg, w.r})
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes JSON into a Witness struct
|
||||
func (w *Witness) UnmarshalJSON(data []byte) error {
|
||||
witness := &witnessJSON{}
|
||||
err := json.Unmarshal(data, witness)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.Msg = witness.Msg
|
||||
w.r = witness.R
|
||||
return nil
|
||||
}
|
||||
|
||||
// Commit to a given message. Uses SHA256 as the hash function.
|
||||
func Commit(msg []byte) (Commitment, *Witness, error) {
|
||||
// Initialize our decommitment
|
||||
d := Witness{msg, [Size]byte{}}
|
||||
|
||||
// Generate a random nonce of the required length
|
||||
n, err := crand.Read(d.r[:])
|
||||
// Ensure no errors retrieving nonce
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Ensure we read all the bytes expected
|
||||
if n != Size {
|
||||
return nil, nil, fmt.Errorf("failed to read %v bytes from crypto/rand: received %v bytes", Size, n)
|
||||
}
|
||||
// Compute the commitment: HMAC(Sha2, msg, key)
|
||||
c, err := ComputeHMAC(sha256.New, msg, d.r[:])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return c, &d, nil
|
||||
}
|
||||
|
||||
// Open a commitment and return true if the commitment/decommitment pair are valid.
|
||||
// reference: spec.§2.4: Commitment Scheme
|
||||
func Open(c Commitment, d Witness) (bool, error) {
|
||||
// Ensure commitment is well-formed.
|
||||
if len(c) != Size {
|
||||
return false, fmt.Errorf("invalid commitment, wrong length. %v != %v", len(c), Size)
|
||||
}
|
||||
|
||||
// Re-compute the commitment: HMAC(Sha2, msg, key)
|
||||
cʹ, err := ComputeHMAC(sha256.New, d.Msg, d.r[:])
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return subtle.ConstantTimeCompare(cʹ, c) == 1, nil
|
||||
}
|
||||
|
||||
// ComputeHMAC computes HMAC(hash_fn, msg, key)
|
||||
// Takes in a hash function to use for HMAC
|
||||
func ComputeHMAC(f func() hash.Hash, msg []byte, k []byte) ([]byte, error) {
|
||||
if f == nil {
|
||||
return nil, fmt.Errorf("hash function cannot be nil")
|
||||
}
|
||||
|
||||
mac := hmac.New(f, k)
|
||||
w, err := mac.Write(msg)
|
||||
|
||||
if w != len(msg) {
|
||||
return nil, fmt.Errorf("bytes written to hash doesn't match expected: %v != %v", w, len(msg))
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mac.Sum(nil), nil
|
||||
}
|
@ -1,374 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// An entry into our test table
|
||||
type entry struct {
|
||||
// Input
|
||||
msg []byte
|
||||
|
||||
// Result (actual, not expected)
|
||||
commit Commitment
|
||||
decommit *Witness
|
||||
err error
|
||||
}
|
||||
|
||||
// Test inputs and placeholders for results that will be filled in
|
||||
// during init()
|
||||
var testResults = []entry{
|
||||
{[]byte("This is a test message"), nil, nil, nil},
|
||||
{[]byte("short msg"), nil, nil, nil},
|
||||
{[]byte("This input field is intentionally longer than the SHA256 block size to ensure that the entire message is processed"),
|
||||
nil, nil, nil},
|
||||
{[]byte{0xFB, 0x1A, 0x18, 0x47, 0x39, 0x3C, 0x9F, 0x45, 0x5F, 0x29, 0x4C, 0x51, 0x42, 0x30, 0xA6, 0xB9},
|
||||
nil, nil, nil},
|
||||
// msg = \epsilon (empty string)
|
||||
{[]byte{}, nil, nil, nil},
|
||||
// msg == nil
|
||||
{nil, nil, nil, nil},
|
||||
}
|
||||
|
||||
// Run our inputs through commit and record the outputs
|
||||
func init() {
|
||||
for i := range testResults {
|
||||
entry := &testResults[i]
|
||||
entry.commit, entry.decommit, entry.err = Commit(entry.msg)
|
||||
}
|
||||
}
|
||||
|
||||
// Computing commitments should never produce errors
|
||||
func TestCommitWithoutErrors(t *testing.T) {
|
||||
for _, entry := range testResults {
|
||||
if entry.err != nil {
|
||||
t.Errorf("received Commit(%v): %v", entry.msg, entry.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Commitments should be 256b == 64B in length
|
||||
func TestCommitmentsAreExpectedLength(t *testing.T) {
|
||||
const expLen = 256 / 8
|
||||
for _, entry := range testResults {
|
||||
if len(entry.commit) != expLen {
|
||||
t.Errorf("commitment is not expected length: %v != %v", len(entry.commit), expLen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Decommit cannot be nil
|
||||
func TestCommmitProducesDecommit(t *testing.T) {
|
||||
for _, entry := range testResults {
|
||||
if entry.decommit == nil {
|
||||
t.Errorf("decommit cannot be nil: Commit(%v)", entry.msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Decommit value should contain the same message
|
||||
func TestCommmitProducesDecommitWithSameMessage(t *testing.T) {
|
||||
for _, entry := range testResults {
|
||||
if !bytes.Equal(entry.msg, entry.decommit.Msg) {
|
||||
t.Errorf("decommit.msg != msg: %v != %v", entry.msg, entry.decommit.Msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Commitments should be unique
|
||||
func TestCommmitProducesDistinctCommitments(t *testing.T) {
|
||||
seen := make(map[[Size]byte]bool)
|
||||
|
||||
// Check the pre-computed commitments for uniquness
|
||||
for _, entry := range testResults {
|
||||
|
||||
// Slices cannot be used as hash keys, so we need to copy into
|
||||
// an array. Oh, go-lang.
|
||||
var cee [Size]byte
|
||||
copy(cee[:], entry.commit)
|
||||
|
||||
// Ensure each commit is unique
|
||||
if seen[cee] {
|
||||
t.Errorf("duplicate commit found: %v", cee)
|
||||
}
|
||||
seen[cee] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Commitments should be unique even for the same message since the nonce is
|
||||
// randomly selected
|
||||
func TestCommmitDistinctCommitments(t *testing.T) {
|
||||
seen := make(map[[Size]byte]bool)
|
||||
msg := []byte("black lives matter")
|
||||
const iterations = 1000
|
||||
|
||||
// Check the pre-computed commitments for uniquness
|
||||
for i := 0; i < iterations; i++ {
|
||||
// Compute a commitment
|
||||
c, _, err := Commit(msg)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// Slices cannot be used as hash keys, so copy into an array
|
||||
var cee [Size]byte
|
||||
copy(cee[:], []byte(c))
|
||||
|
||||
// Ensure each commit is unique
|
||||
if seen[cee] {
|
||||
t.Errorf("duplicate commit found: %v", cee)
|
||||
}
|
||||
seen[cee] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Nonces must be 256b = 64B
|
||||
func TestCommmitNonceIsExpectedLength(t *testing.T) {
|
||||
const expLen = 256 / 8
|
||||
|
||||
// Check the pre-computed nonces
|
||||
for _, entry := range testResults {
|
||||
if len(entry.decommit.r) != expLen {
|
||||
t.Errorf("nonce is not expected length: %v != %v", len(entry.decommit.r), expLen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Randomly selected nonces will be unique with overwhelming probability
|
||||
func TestCommmitProducesDistinctNonces(t *testing.T) {
|
||||
seen := make(map[[Size]byte]bool)
|
||||
msg := []byte("black lives matter")
|
||||
const iterations = 1000
|
||||
|
||||
// Check the pre-computed commitments for uniquness
|
||||
for i := 0; i < iterations; i++ {
|
||||
// Compute a commitment
|
||||
_, dee, err := Commit(msg)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// Ensure each nonce is unique
|
||||
if seen[dee.r] {
|
||||
t.Errorf("duplicate nonce found: %v", dee.r)
|
||||
}
|
||||
seen[dee.r] = true
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenOnValidCommitments(t *testing.T) {
|
||||
for _, entry := range testResults {
|
||||
|
||||
// Open each commitment
|
||||
ok, err := Open(entry.commit, *entry.decommit)
|
||||
|
||||
// There should be no error
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// The commitments should verify
|
||||
if !ok {
|
||||
t.Errorf("commitment failed to open: %v", entry.msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenOnModifiedNonce(t *testing.T) {
|
||||
for _, entry := range testResults {
|
||||
dʹ := copyWitness(entry.decommit)
|
||||
|
||||
// Modify the nonce
|
||||
dʹ.r[0] ^= 0x40
|
||||
|
||||
// Open and check for failure
|
||||
ok, err := Open(entry.commit, *dʹ)
|
||||
assertFailedOpen(t, ok, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenOnZeroPrefixNonce(t *testing.T) {
|
||||
for _, entry := range testResults {
|
||||
dʹ := copyWitness(entry.decommit)
|
||||
|
||||
// Modify the nonce
|
||||
dʹ.r[0] = 0x00
|
||||
dʹ.r[1] = 0x00
|
||||
dʹ.r[2] = 0x00
|
||||
dʹ.r[3] = 0x00
|
||||
dʹ.r[4] = 0x00
|
||||
dʹ.r[5] = 0x00
|
||||
dʹ.r[6] = 0x00
|
||||
dʹ.r[7] = 0x00
|
||||
dʹ.r[8] = 0x00
|
||||
dʹ.r[9] = 0x00
|
||||
dʹ.r[10] = 0x00
|
||||
|
||||
// Open and check for failure
|
||||
ok, err := Open(entry.commit, *dʹ)
|
||||
assertFailedOpen(t, ok, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Makes a deep copy of a Witness
|
||||
func copyWitness(d *Witness) *Witness {
|
||||
msg := make([]byte, len(d.Msg))
|
||||
var r [Size]byte
|
||||
|
||||
copy(msg, d.Msg)
|
||||
copy(r[:], d.r[:])
|
||||
return &Witness{msg, r}
|
||||
}
|
||||
|
||||
// Asserts that err != nil, and ok == false.
|
||||
func assertFailedOpen(t *testing.T, ok bool, err error) {
|
||||
// There should be no error
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// But the commitments should fail
|
||||
if ok {
|
||||
t.Error("commitment was verified but was expected to fail")
|
||||
}
|
||||
}
|
||||
|
||||
// An unrelated message should fail on open
|
||||
func TestOpenOnNewMessage(t *testing.T) {
|
||||
for _, entry := range testResults {
|
||||
dʹ := copyWitness(entry.decommit)
|
||||
|
||||
// Use a distinct message
|
||||
dʹ.Msg = []byte("no one expects the spanish inquisition")
|
||||
|
||||
// Open and check for failure
|
||||
ok, err := Open(entry.commit, *dʹ)
|
||||
assertFailedOpen(t, ok, err)
|
||||
}
|
||||
}
|
||||
|
||||
// An appended message should fail on open
|
||||
func TestOpenOnAppendedMessage(t *testing.T) {
|
||||
for _, entry := range testResults {
|
||||
dʹ := copyWitness(entry.decommit)
|
||||
|
||||
// Modify the message
|
||||
dʹ.Msg = []byte("no one expects the spanish inquisition")
|
||||
|
||||
// Open and check for failure
|
||||
ok, err := Open(entry.commit, *dʹ)
|
||||
assertFailedOpen(t, ok, err)
|
||||
}
|
||||
}
|
||||
|
||||
// A modified message should fail on open
|
||||
func TestOpenOnModifiedMessage(t *testing.T) {
|
||||
for _, entry := range testResults {
|
||||
// Skip the empty string message for this test case
|
||||
if len(entry.msg) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Modify the message _in situ_
|
||||
dʹ := copyWitness(entry.decommit)
|
||||
dʹ.Msg[1] ^= 0x99
|
||||
|
||||
// Open and check for failure
|
||||
ok, err := Open(entry.commit, *dʹ)
|
||||
assertFailedOpen(t, ok, err)
|
||||
}
|
||||
}
|
||||
|
||||
// A modified commitment should fail on open
|
||||
func TestOpenOnModifiedCommitment(t *testing.T) {
|
||||
for _, entry := range testResults {
|
||||
// Copy and then modify the commitment
|
||||
cʹ := make([]byte, Size)
|
||||
copy(cʹ[:], entry.commit)
|
||||
cʹ[6] ^= 0x33
|
||||
|
||||
// Open and check for failure
|
||||
ok, err := Open(cʹ, *entry.decommit)
|
||||
assertFailedOpen(t, ok, err)
|
||||
}
|
||||
}
|
||||
|
||||
// An empty decommit should fail to open
|
||||
func TestOpenOnDefaultDecommitObject(t *testing.T) {
|
||||
for _, entry := range testResults {
|
||||
// Open and check for failure
|
||||
ok, err := Open(entry.commit, Witness{})
|
||||
assertFailedOpen(t, ok, err)
|
||||
}
|
||||
}
|
||||
|
||||
// A nil commit should return an error
|
||||
func TestOpenOnNilCommitment(t *testing.T) {
|
||||
_, err := Open(nil, Witness{})
|
||||
assertError(t, err)
|
||||
}
|
||||
|
||||
// Verifies that err != nil
|
||||
func assertError(t *testing.T, err error) {
|
||||
if err == nil {
|
||||
t.Error("expected an error but received nil")
|
||||
}
|
||||
}
|
||||
|
||||
// Ill-formed commitment should produce an error
|
||||
func TestOpenOnLongCommitment(t *testing.T) {
|
||||
tooLong := make([]byte, Size+1)
|
||||
_, err := Open(tooLong, Witness{})
|
||||
assertError(t, err)
|
||||
}
|
||||
|
||||
// Ill-formed commitment should produce an error
|
||||
func TestOpenOnShortCommitment(t *testing.T) {
|
||||
tooShort := make([]byte, Size-1)
|
||||
_, err := Open(tooShort, Witness{})
|
||||
assertError(t, err)
|
||||
}
|
||||
|
||||
// Tests that marshal-unmarshal is the identity function
|
||||
func TestWitnessMarshalRoundTrip(t *testing.T) {
|
||||
expected := &Witness{
|
||||
[]byte("I'm the dude. So that's what you call me"),
|
||||
[Size]byte{0xAC},
|
||||
}
|
||||
|
||||
// Marhal and test
|
||||
jsonBytes, err := json.Marshal(expected)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, jsonBytes)
|
||||
|
||||
// Unmarshal and test
|
||||
actual := &Witness{}
|
||||
require.NoError(t, json.Unmarshal(jsonBytes, actual))
|
||||
require.Equal(t, expected.Msg, actual.Msg)
|
||||
require.Equal(t, expected.r, actual.r)
|
||||
}
|
||||
|
||||
// Tests that marshal-unmarshal is the identity function
|
||||
func TestCommitmentMarshalRoundTrip(t *testing.T) {
|
||||
expected := Commitment([]byte("That or uh his-dudeness or duder or el duderino."))
|
||||
|
||||
// Marhal and test
|
||||
jsonBytes, err := json.Marshal(expected)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, jsonBytes)
|
||||
|
||||
// Unmarshal and test
|
||||
actual := Commitment{}
|
||||
require.NoError(t, json.Unmarshal(jsonBytes, &actual))
|
||||
require.Equal(t, []byte(expected), []byte(actual))
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,863 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package curves
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"math/big"
|
||||
"sync"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native/bls12381"
|
||||
)
|
||||
|
||||
var (
|
||||
k256Initonce sync.Once
|
||||
k256 Curve
|
||||
|
||||
bls12381g1Initonce sync.Once
|
||||
bls12381g1 Curve
|
||||
|
||||
bls12381g2Initonce sync.Once
|
||||
bls12381g2 Curve
|
||||
|
||||
bls12377g1Initonce sync.Once
|
||||
bls12377g1 Curve
|
||||
|
||||
bls12377g2Initonce sync.Once
|
||||
bls12377g2 Curve
|
||||
|
||||
p256Initonce sync.Once
|
||||
p256 Curve
|
||||
|
||||
ed25519Initonce sync.Once
|
||||
ed25519 Curve
|
||||
|
||||
pallasInitonce sync.Once
|
||||
pallas Curve
|
||||
)
|
||||
|
||||
const (
|
||||
K256Name = "secp256k1"
|
||||
BLS12381G1Name = "BLS12381G1"
|
||||
BLS12381G2Name = "BLS12381G2"
|
||||
BLS12831Name = "BLS12831"
|
||||
P256Name = "P-256"
|
||||
ED25519Name = "ed25519"
|
||||
PallasName = "pallas"
|
||||
BLS12377G1Name = "BLS12377G1"
|
||||
BLS12377G2Name = "BLS12377G2"
|
||||
BLS12377Name = "BLS12377"
|
||||
)
|
||||
|
||||
const scalarBytes = 32
|
||||
|
||||
// Scalar represents an element of the scalar field \mathbb{F}_q
|
||||
// of the elliptic curve construction.
|
||||
type Scalar interface {
|
||||
// Random returns a random scalar using the provided reader
|
||||
// to retrieve bytes
|
||||
Random(reader io.Reader) Scalar
|
||||
// Hash the specific bytes in a manner to yield a
|
||||
// uniformly distributed scalar
|
||||
Hash(bytes []byte) Scalar
|
||||
// Zero returns the additive identity element
|
||||
Zero() Scalar
|
||||
// One returns the multiplicative identity element
|
||||
One() Scalar
|
||||
// IsZero returns true if this element is the additive identity element
|
||||
IsZero() bool
|
||||
// IsOne returns true if this element is the multiplicative identity element
|
||||
IsOne() bool
|
||||
// IsOdd returns true if this element is odd
|
||||
IsOdd() bool
|
||||
// IsEven returns true if this element is even
|
||||
IsEven() bool
|
||||
// New returns an element with the value equal to `value`
|
||||
New(value int) Scalar
|
||||
// Cmp returns
|
||||
// -2 if this element is in a different field than rhs
|
||||
// -1 if this element is less than rhs
|
||||
// 0 if this element is equal to rhs
|
||||
// 1 if this element is greater than rhs
|
||||
Cmp(rhs Scalar) int
|
||||
// Square returns element*element
|
||||
Square() Scalar
|
||||
// Double returns element+element
|
||||
Double() Scalar
|
||||
// Invert returns element^-1 mod p
|
||||
Invert() (Scalar, error)
|
||||
// Sqrt computes the square root of this element if it exists.
|
||||
Sqrt() (Scalar, error)
|
||||
// Cube returns element*element*element
|
||||
Cube() Scalar
|
||||
// Add returns element+rhs
|
||||
Add(rhs Scalar) Scalar
|
||||
// Sub returns element-rhs
|
||||
Sub(rhs Scalar) Scalar
|
||||
// Mul returns element*rhs
|
||||
Mul(rhs Scalar) Scalar
|
||||
// MulAdd returns element * y + z mod p
|
||||
MulAdd(y, z Scalar) Scalar
|
||||
// Div returns element*rhs^-1 mod p
|
||||
Div(rhs Scalar) Scalar
|
||||
// Neg returns -element mod p
|
||||
Neg() Scalar
|
||||
// SetBigInt returns this element set to the value of v
|
||||
SetBigInt(v *big.Int) (Scalar, error)
|
||||
// BigInt returns this element as a big integer
|
||||
BigInt() *big.Int
|
||||
// Point returns the associated point for this scalar
|
||||
Point() Point
|
||||
// Bytes returns the canonical byte representation of this scalar
|
||||
Bytes() []byte
|
||||
// SetBytes creates a scalar from the canonical representation expecting the exact number of bytes needed to represent the scalar
|
||||
SetBytes(bytes []byte) (Scalar, error)
|
||||
// SetBytesWide creates a scalar expecting double the exact number of bytes needed to represent the scalar which is reduced by the modulus
|
||||
SetBytesWide(bytes []byte) (Scalar, error)
|
||||
// Clone returns a cloned Scalar of this value
|
||||
Clone() Scalar
|
||||
}
|
||||
|
||||
type PairingScalar interface {
|
||||
Scalar
|
||||
SetPoint(p Point) PairingScalar
|
||||
}
|
||||
|
||||
func unmarshalScalar(input []byte) (*Curve, []byte, error) {
|
||||
sep := byte(':')
|
||||
i := 0
|
||||
for ; i < len(input); i++ {
|
||||
if input[i] == sep {
|
||||
break
|
||||
}
|
||||
}
|
||||
name := string(input[:i])
|
||||
curve := GetCurveByName(name)
|
||||
if curve == nil {
|
||||
return nil, nil, fmt.Errorf("unrecognized curve")
|
||||
}
|
||||
return curve, input[i+1:], nil
|
||||
}
|
||||
|
||||
func scalarMarshalBinary(scalar Scalar) ([]byte, error) {
|
||||
// All scalars are 32 bytes long
|
||||
// The last 32 bytes are the actual value
|
||||
// The first remaining bytes are the curve name
|
||||
// separated by a colon
|
||||
name := []byte(scalar.Point().CurveName())
|
||||
output := make([]byte, len(name)+1+scalarBytes)
|
||||
copy(output[:len(name)], name)
|
||||
output[len(name)] = byte(':')
|
||||
copy(output[len(name)+1:], scalar.Bytes())
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func scalarUnmarshalBinary(input []byte) (Scalar, error) {
|
||||
// All scalars are 32 bytes long
|
||||
// The first 32 bytes are the actual value
|
||||
// The remaining bytes are the curve name
|
||||
if len(input) < scalarBytes+1+len(P256Name) {
|
||||
return nil, fmt.Errorf("invalid byte sequence")
|
||||
}
|
||||
sc, data, err := unmarshalScalar(input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sc.Scalar.SetBytes(data)
|
||||
}
|
||||
|
||||
func scalarMarshalText(scalar Scalar) ([]byte, error) {
|
||||
// All scalars are 32 bytes long
|
||||
// For text encoding we put the curve name first for readability
|
||||
// separated by a colon, then the hex encoding of the scalar
|
||||
// which avoids the base64 weakness with strict mode or not
|
||||
name := []byte(scalar.Point().CurveName())
|
||||
output := make([]byte, len(name)+1+scalarBytes*2)
|
||||
copy(output[:len(name)], name)
|
||||
output[len(name)] = byte(':')
|
||||
_ = hex.Encode(output[len(name)+1:], scalar.Bytes())
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func scalarUnmarshalText(input []byte) (Scalar, error) {
|
||||
if len(input) < scalarBytes*2+len(P256Name)+1 {
|
||||
return nil, fmt.Errorf("invalid byte sequence")
|
||||
}
|
||||
curve, data, err := unmarshalScalar(input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var t [scalarBytes]byte
|
||||
_, err = hex.Decode(t[:], data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return curve.Scalar.SetBytes(t[:])
|
||||
}
|
||||
|
||||
func scalarMarshalJson(scalar Scalar) ([]byte, error) {
|
||||
m := make(map[string]string, 2)
|
||||
m["type"] = scalar.Point().CurveName()
|
||||
m["value"] = hex.EncodeToString(scalar.Bytes())
|
||||
return json.Marshal(m)
|
||||
}
|
||||
|
||||
func scalarUnmarshalJson(input []byte) (Scalar, error) {
|
||||
var m map[string]string
|
||||
|
||||
err := json.Unmarshal(input, &m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
curve := GetCurveByName(m["type"])
|
||||
if curve == nil {
|
||||
return nil, fmt.Errorf("invalid type")
|
||||
}
|
||||
s, err := hex.DecodeString(m["value"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
S, err := curve.Scalar.SetBytes(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return S, nil
|
||||
}
|
||||
|
||||
// Point represents an elliptic curve point
|
||||
type Point interface {
|
||||
Random(reader io.Reader) Point
|
||||
Hash(bytes []byte) Point
|
||||
Identity() Point
|
||||
Generator() Point
|
||||
IsIdentity() bool
|
||||
IsNegative() bool
|
||||
IsOnCurve() bool
|
||||
Double() Point
|
||||
Scalar() Scalar
|
||||
Neg() Point
|
||||
Add(rhs Point) Point
|
||||
Sub(rhs Point) Point
|
||||
Mul(rhs Scalar) Point
|
||||
Equal(rhs Point) bool
|
||||
Set(x, y *big.Int) (Point, error)
|
||||
ToAffineCompressed() []byte
|
||||
ToAffineUncompressed() []byte
|
||||
FromAffineCompressed(bytes []byte) (Point, error)
|
||||
FromAffineUncompressed(bytes []byte) (Point, error)
|
||||
CurveName() string
|
||||
SumOfProducts(points []Point, scalars []Scalar) Point
|
||||
}
|
||||
|
||||
type PairingPoint interface {
|
||||
Point
|
||||
OtherGroup() PairingPoint
|
||||
Pairing(rhs PairingPoint) Scalar
|
||||
MultiPairing(...PairingPoint) Scalar
|
||||
}
|
||||
|
||||
func pointMarshalBinary(point Point) ([]byte, error) {
|
||||
// Always stores points in compressed form
|
||||
// The first bytes are the curve name
|
||||
// separated by a colon followed by the compressed point
|
||||
// bytes
|
||||
t := point.ToAffineCompressed()
|
||||
name := []byte(point.CurveName())
|
||||
output := make([]byte, len(name)+1+len(t))
|
||||
copy(output[:len(name)], name)
|
||||
output[len(name)] = byte(':')
|
||||
copy(output[len(output)-len(t):], t)
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func pointUnmarshalBinary(input []byte) (Point, error) {
|
||||
if len(input) < scalarBytes+1+len(P256Name) {
|
||||
return nil, fmt.Errorf("invalid byte sequence")
|
||||
}
|
||||
sep := byte(':')
|
||||
i := 0
|
||||
for ; i < len(input); i++ {
|
||||
if input[i] == sep {
|
||||
break
|
||||
}
|
||||
}
|
||||
name := string(input[:i])
|
||||
curve := GetCurveByName(name)
|
||||
if curve == nil {
|
||||
return nil, fmt.Errorf("unrecognized curve")
|
||||
}
|
||||
return curve.Point.FromAffineCompressed(input[i+1:])
|
||||
}
|
||||
|
||||
func pointMarshalText(point Point) ([]byte, error) {
|
||||
// Always stores points in compressed form
|
||||
// The first bytes are the curve name
|
||||
// separated by a colon followed by the compressed point
|
||||
// bytes
|
||||
t := point.ToAffineCompressed()
|
||||
name := []byte(point.CurveName())
|
||||
output := make([]byte, len(name)+1+len(t)*2)
|
||||
copy(output[:len(name)], name)
|
||||
output[len(name)] = byte(':')
|
||||
hex.Encode(output[len(output)-len(t)*2:], t)
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func pointUnmarshalText(input []byte) (Point, error) {
|
||||
if len(input) < scalarBytes*2+1+len(P256Name) {
|
||||
return nil, fmt.Errorf("invalid byte sequence")
|
||||
}
|
||||
sep := byte(':')
|
||||
i := 0
|
||||
for ; i < len(input); i++ {
|
||||
if input[i] == sep {
|
||||
break
|
||||
}
|
||||
}
|
||||
name := string(input[:i])
|
||||
curve := GetCurveByName(name)
|
||||
if curve == nil {
|
||||
return nil, fmt.Errorf("unrecognized curve")
|
||||
}
|
||||
buffer := make([]byte, (len(input)-i)/2)
|
||||
_, err := hex.Decode(buffer, input[i+1:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return curve.Point.FromAffineCompressed(buffer)
|
||||
}
|
||||
|
||||
func pointMarshalJson(point Point) ([]byte, error) {
|
||||
m := make(map[string]string, 2)
|
||||
m["type"] = point.CurveName()
|
||||
m["value"] = hex.EncodeToString(point.ToAffineCompressed())
|
||||
return json.Marshal(m)
|
||||
}
|
||||
|
||||
func pointUnmarshalJson(input []byte) (Point, error) {
|
||||
var m map[string]string
|
||||
|
||||
err := json.Unmarshal(input, &m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
curve := GetCurveByName(m["type"])
|
||||
if curve == nil {
|
||||
return nil, fmt.Errorf("invalid type")
|
||||
}
|
||||
p, err := hex.DecodeString(m["value"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
P, err := curve.Point.FromAffineCompressed(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return P, nil
|
||||
}
|
||||
|
||||
// Curve represents a named elliptic curve with a scalar field and point group
|
||||
type Curve struct {
|
||||
Scalar Scalar
|
||||
Point Point
|
||||
Name string
|
||||
}
|
||||
|
||||
func (c Curve) ScalarBaseMult(sc Scalar) Point {
|
||||
return c.Point.Generator().Mul(sc)
|
||||
}
|
||||
|
||||
func (c Curve) NewGeneratorPoint() Point {
|
||||
return c.Point.Generator()
|
||||
}
|
||||
|
||||
func (c Curve) NewIdentityPoint() Point {
|
||||
return c.Point.Identity()
|
||||
}
|
||||
|
||||
func (c Curve) NewScalar() Scalar {
|
||||
return c.Scalar.Zero()
|
||||
}
|
||||
|
||||
// ToEllipticCurve returns the equivalent of this curve as the go interface `elliptic.Curve`
|
||||
func (c Curve) ToEllipticCurve() (elliptic.Curve, error) {
|
||||
err := fmt.Errorf("can't convert %s", c.Name)
|
||||
switch c.Name {
|
||||
case K256Name:
|
||||
return K256Curve(), nil
|
||||
case BLS12381G1Name:
|
||||
return nil, err
|
||||
case BLS12381G2Name:
|
||||
return nil, err
|
||||
case BLS12831Name:
|
||||
return nil, err
|
||||
case P256Name:
|
||||
return NistP256Curve(), nil
|
||||
case ED25519Name:
|
||||
return nil, err
|
||||
case PallasName:
|
||||
return nil, err
|
||||
case BLS12377G1Name:
|
||||
return nil, err
|
||||
case BLS12377G2Name:
|
||||
return nil, err
|
||||
case BLS12377Name:
|
||||
return nil, err
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// PairingCurve represents a named elliptic curve
|
||||
// that supports pairings
|
||||
type PairingCurve struct {
|
||||
Scalar PairingScalar
|
||||
PointG1 PairingPoint
|
||||
PointG2 PairingPoint
|
||||
GT Scalar
|
||||
Name string
|
||||
}
|
||||
|
||||
func (c PairingCurve) ScalarG1BaseMult(sc Scalar) PairingPoint {
|
||||
return c.PointG1.Generator().Mul(sc).(PairingPoint)
|
||||
}
|
||||
|
||||
func (c PairingCurve) ScalarG2BaseMult(sc Scalar) PairingPoint {
|
||||
return c.PointG2.Generator().Mul(sc).(PairingPoint)
|
||||
}
|
||||
|
||||
func (c PairingCurve) NewG1GeneratorPoint() PairingPoint {
|
||||
return c.PointG1.Generator().(PairingPoint)
|
||||
}
|
||||
|
||||
func (c PairingCurve) NewG2GeneratorPoint() PairingPoint {
|
||||
return c.PointG2.Generator().(PairingPoint)
|
||||
}
|
||||
|
||||
func (c PairingCurve) NewG1IdentityPoint() PairingPoint {
|
||||
return c.PointG1.Identity().(PairingPoint)
|
||||
}
|
||||
|
||||
func (c PairingCurve) NewG2IdentityPoint() PairingPoint {
|
||||
return c.PointG2.Identity().(PairingPoint)
|
||||
}
|
||||
|
||||
func (c PairingCurve) NewScalar() PairingScalar {
|
||||
return c.Scalar.Zero().(PairingScalar)
|
||||
}
|
||||
|
||||
// GetCurveByName returns the correct `Curve` given the name
|
||||
func GetCurveByName(name string) *Curve {
|
||||
switch name {
|
||||
case K256Name:
|
||||
return K256()
|
||||
case BLS12381G1Name:
|
||||
return BLS12381G1()
|
||||
case BLS12381G2Name:
|
||||
return BLS12381G2()
|
||||
case BLS12831Name:
|
||||
return BLS12381G1()
|
||||
case P256Name:
|
||||
return P256()
|
||||
case ED25519Name:
|
||||
return ED25519()
|
||||
case PallasName:
|
||||
return PALLAS()
|
||||
case BLS12377G1Name:
|
||||
return BLS12377G1()
|
||||
case BLS12377G2Name:
|
||||
return BLS12377G2()
|
||||
case BLS12377Name:
|
||||
return BLS12377G1()
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetPairingCurveByName(name string) *PairingCurve {
|
||||
switch name {
|
||||
case BLS12381G1Name:
|
||||
return BLS12381(BLS12381G1().NewIdentityPoint())
|
||||
case BLS12381G2Name:
|
||||
return BLS12381(BLS12381G2().NewIdentityPoint())
|
||||
case BLS12831Name:
|
||||
return BLS12381(BLS12381G1().NewIdentityPoint())
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// BLS12381G1 returns the BLS12-381 curve with points in G1
|
||||
func BLS12381G1() *Curve {
|
||||
bls12381g1Initonce.Do(bls12381g1Init)
|
||||
return &bls12381g1
|
||||
}
|
||||
|
||||
func bls12381g1Init() {
|
||||
bls12381g1 = Curve{
|
||||
Scalar: &ScalarBls12381{
|
||||
Value: bls12381.Bls12381FqNew(),
|
||||
point: new(PointBls12381G1),
|
||||
},
|
||||
Point: new(PointBls12381G1).Identity(),
|
||||
Name: BLS12381G1Name,
|
||||
}
|
||||
}
|
||||
|
||||
// BLS12381G2 returns the BLS12-381 curve with points in G2
|
||||
func BLS12381G2() *Curve {
|
||||
bls12381g2Initonce.Do(bls12381g2Init)
|
||||
return &bls12381g2
|
||||
}
|
||||
|
||||
func bls12381g2Init() {
|
||||
bls12381g2 = Curve{
|
||||
Scalar: &ScalarBls12381{
|
||||
Value: bls12381.Bls12381FqNew(),
|
||||
point: new(PointBls12381G2),
|
||||
},
|
||||
Point: new(PointBls12381G2).Identity(),
|
||||
Name: BLS12381G2Name,
|
||||
}
|
||||
}
|
||||
|
||||
func BLS12381(preferredPoint Point) *PairingCurve {
|
||||
return &PairingCurve{
|
||||
Scalar: &ScalarBls12381{
|
||||
Value: bls12381.Bls12381FqNew(),
|
||||
point: preferredPoint,
|
||||
},
|
||||
PointG1: &PointBls12381G1{
|
||||
Value: new(bls12381.G1).Identity(),
|
||||
},
|
||||
PointG2: &PointBls12381G2{
|
||||
Value: new(bls12381.G2).Identity(),
|
||||
},
|
||||
GT: &ScalarBls12381Gt{
|
||||
Value: new(bls12381.Gt).SetOne(),
|
||||
},
|
||||
Name: BLS12831Name,
|
||||
}
|
||||
}
|
||||
|
||||
// BLS12377G1 returns the BLS12-377 curve with points in G1
|
||||
func BLS12377G1() *Curve {
|
||||
bls12377g1Initonce.Do(bls12377g1Init)
|
||||
return &bls12377g1
|
||||
}
|
||||
|
||||
func bls12377g1Init() {
|
||||
bls12377g1 = Curve{
|
||||
Scalar: &ScalarBls12377{
|
||||
value: new(big.Int),
|
||||
point: new(PointBls12377G1),
|
||||
},
|
||||
Point: new(PointBls12377G1).Identity(),
|
||||
Name: BLS12377G1Name,
|
||||
}
|
||||
}
|
||||
|
||||
// BLS12377G2 returns the BLS12-377 curve with points in G2
|
||||
func BLS12377G2() *Curve {
|
||||
bls12377g2Initonce.Do(bls12377g2Init)
|
||||
return &bls12377g2
|
||||
}
|
||||
|
||||
func bls12377g2Init() {
|
||||
bls12377g2 = Curve{
|
||||
Scalar: &ScalarBls12377{
|
||||
value: new(big.Int),
|
||||
point: new(PointBls12377G2),
|
||||
},
|
||||
Point: new(PointBls12377G2).Identity(),
|
||||
Name: BLS12377G2Name,
|
||||
}
|
||||
}
|
||||
|
||||
// K256 returns the secp256k1 curve
|
||||
func K256() *Curve {
|
||||
k256Initonce.Do(k256Init)
|
||||
return &k256
|
||||
}
|
||||
|
||||
func k256Init() {
|
||||
k256 = Curve{
|
||||
Scalar: new(ScalarK256).Zero(),
|
||||
Point: new(PointK256).Identity(),
|
||||
Name: K256Name,
|
||||
}
|
||||
}
|
||||
|
||||
func P256() *Curve {
|
||||
p256Initonce.Do(p256Init)
|
||||
return &p256
|
||||
}
|
||||
|
||||
func p256Init() {
|
||||
p256 = Curve{
|
||||
Scalar: new(ScalarP256).Zero(),
|
||||
Point: new(PointP256).Identity(),
|
||||
Name: P256Name,
|
||||
}
|
||||
}
|
||||
|
||||
func ED25519() *Curve {
|
||||
ed25519Initonce.Do(ed25519Init)
|
||||
return &ed25519
|
||||
}
|
||||
|
||||
func ed25519Init() {
|
||||
ed25519 = Curve{
|
||||
Scalar: new(ScalarEd25519).Zero(),
|
||||
Point: new(PointEd25519).Identity(),
|
||||
Name: ED25519Name,
|
||||
}
|
||||
}
|
||||
|
||||
func PALLAS() *Curve {
|
||||
pallasInitonce.Do(pallasInit)
|
||||
return &pallas
|
||||
}
|
||||
|
||||
func pallasInit() {
|
||||
pallas = Curve{
|
||||
Scalar: new(ScalarPallas).Zero(),
|
||||
Point: new(PointPallas).Identity(),
|
||||
Name: PallasName,
|
||||
}
|
||||
}
|
||||
|
||||
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-11#appendix-G.2.1
|
||||
func osswu3mod4(u *big.Int, p *sswuParams) (x, y *big.Int) {
|
||||
params := p.Params
|
||||
field := NewField(p.Params.P)
|
||||
|
||||
tv1 := field.NewElement(u)
|
||||
tv1 = tv1.Mul(tv1) // tv1 = u^2
|
||||
tv3 := field.NewElement(p.Z).Mul(tv1) // tv3 = Z * tv1
|
||||
tv2 := tv3.Mul(tv3) // tv2 = tv3^2
|
||||
xd := tv2.Add(tv3) // xd = tv2 + tv3
|
||||
x1n := xd.Add(field.One()) // x1n = (xd + 1)
|
||||
x1n = x1n.Mul(field.NewElement(p.B)) // x1n * B
|
||||
aNeg := field.NewElement(p.A).Neg()
|
||||
xd = xd.Mul(aNeg) // xd = -A * xd
|
||||
|
||||
if xd.Value.Cmp(big.NewInt(0)) == 0 {
|
||||
xd = field.NewElement(p.Z).Mul(field.NewElement(p.A)) // xd = Z * A
|
||||
}
|
||||
|
||||
tv2 = xd.Mul(xd) // tv2 = xd^2
|
||||
gxd := tv2.Mul(xd) // gxd = tv2 * xd
|
||||
tv2 = tv2.Mul(field.NewElement(p.A)) // tv2 = A * tv2
|
||||
|
||||
gx1 := x1n.Mul(x1n) // gx1 = x1n^2
|
||||
gx1 = gx1.Add(tv2) // gx1 = gx1 + tv2
|
||||
gx1 = gx1.Mul(x1n) // gx1 = gx1 * x1n
|
||||
tv2 = gxd.Mul(field.NewElement(p.B)) // tv2 = B * gxd
|
||||
gx1 = gx1.Add(tv2) // gx1 = gx1 + tv2
|
||||
|
||||
tv4 := gxd.Mul(gxd) // tv4 = gxd^2
|
||||
tv2 = gx1.Mul(gxd) // tv2 = gx1 * gxd
|
||||
tv4 = tv4.Mul(tv2) // tv4 = tv4 * tv2
|
||||
|
||||
y1 := tv4.Pow(field.NewElement(p.C1))
|
||||
y1 = y1.Mul(tv2) // y1 = y1 * tv2
|
||||
x2n := tv3.Mul(x1n) // x2n = tv3 * x1n
|
||||
|
||||
y2 := y1.Mul(field.NewElement(p.C2)) // y2 = y1 * c2
|
||||
y2 = y2.Mul(tv1) // y2 = y2 * tv1
|
||||
y2 = y2.Mul(field.NewElement(u)) // y2 = y2 * u
|
||||
|
||||
tv2 = y1.Mul(y1) // tv2 = y1^2
|
||||
|
||||
tv2 = tv2.Mul(gxd) // tv2 = tv2 * gxd
|
||||
|
||||
e2 := tv2.Value.Cmp(gx1.Value) == 0
|
||||
|
||||
// If e2, x = x1, else x = x2
|
||||
if e2 {
|
||||
x = x1n.Value
|
||||
} else {
|
||||
x = x2n.Value
|
||||
}
|
||||
// xn / xd
|
||||
x.Mul(x, new(big.Int).ModInverse(xd.Value, params.P))
|
||||
x.Mod(x, params.P)
|
||||
|
||||
// If e2, y = y1, else y = y2
|
||||
if e2 {
|
||||
y = y1.Value
|
||||
} else {
|
||||
y = y2.Value
|
||||
}
|
||||
|
||||
uBytes := u.Bytes()
|
||||
yBytes := y.Bytes()
|
||||
|
||||
usign := uBytes[len(uBytes)-1] & 1
|
||||
ysign := yBytes[len(yBytes)-1] & 1
|
||||
|
||||
// Fix sign of y
|
||||
if usign != ysign {
|
||||
y.Neg(y)
|
||||
y.Mod(y, params.P)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func expandMsgXmd(h hash.Hash, msg, domain []byte, outLen int) ([]byte, error) {
|
||||
domainLen := uint8(len(domain))
|
||||
if domainLen > 255 {
|
||||
return nil, fmt.Errorf("invalid domain length")
|
||||
}
|
||||
// DST_prime = DST || I2OSP(len(DST), 1)
|
||||
// b_0 = H(Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime)
|
||||
_, _ = h.Write(make([]byte, h.BlockSize()))
|
||||
_, _ = h.Write(msg)
|
||||
_, _ = h.Write([]byte{uint8(outLen >> 8), uint8(outLen)})
|
||||
_, _ = h.Write([]byte{0})
|
||||
_, _ = h.Write(domain)
|
||||
_, _ = h.Write([]byte{domainLen})
|
||||
b0 := h.Sum(nil)
|
||||
|
||||
// b_1 = H(b_0 || I2OSP(1, 1) || DST_prime)
|
||||
h.Reset()
|
||||
_, _ = h.Write(b0)
|
||||
_, _ = h.Write([]byte{1})
|
||||
_, _ = h.Write(domain)
|
||||
_, _ = h.Write([]byte{domainLen})
|
||||
b1 := h.Sum(nil)
|
||||
|
||||
// b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime)
|
||||
ell := (outLen + h.Size() - 1) / h.Size()
|
||||
bi := b1
|
||||
out := make([]byte, outLen)
|
||||
for i := 1; i < ell; i++ {
|
||||
h.Reset()
|
||||
// b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime)
|
||||
tmp := make([]byte, h.Size())
|
||||
for j := 0; j < h.Size(); j++ {
|
||||
tmp[j] = b0[j] ^ bi[j]
|
||||
}
|
||||
_, _ = h.Write(tmp)
|
||||
_, _ = h.Write([]byte{1 + uint8(i)})
|
||||
_, _ = h.Write(domain)
|
||||
_, _ = h.Write([]byte{domainLen})
|
||||
|
||||
// b_1 || ... || b_(ell - 1)
|
||||
copy(out[(i-1)*h.Size():i*h.Size()], bi[:])
|
||||
bi = h.Sum(nil)
|
||||
}
|
||||
// b_ell
|
||||
copy(out[(ell-1)*h.Size():], bi[:])
|
||||
return out[:outLen], nil
|
||||
}
|
||||
|
||||
func bhex(s string) *big.Int {
|
||||
r, _ := new(big.Int).SetString(s, 16)
|
||||
return r
|
||||
}
|
||||
|
||||
type sswuParams struct {
|
||||
Params *elliptic.CurveParams
|
||||
C1, C2, A, B, Z *big.Int
|
||||
}
|
||||
|
||||
// sumOfProductsPippenger implements a version of Pippenger's algorithm.
|
||||
//
|
||||
// The algorithm works as follows:
|
||||
//
|
||||
// Let `n` be a number of point-scalar pairs.
|
||||
// Let `w` be a window of bits (6..8, chosen based on `n`, see cost factor).
|
||||
//
|
||||
// 1. Prepare `2^(w-1) - 1` buckets with indices `[1..2^(w-1))` initialized with identity points.
|
||||
// Bucket 0 is not needed as it would contain points multiplied by 0.
|
||||
// 2. Convert scalars to a radix-`2^w` representation with signed digits in `[-2^w/2, 2^w/2]`.
|
||||
// Note: only the last digit may equal `2^w/2`.
|
||||
// 3. Starting with the last window, for each point `i=[0..n)` add it to a a bucket indexed by
|
||||
// the point's scalar's value in the window.
|
||||
// 4. Once all points in a window are sorted into buckets, add buckets by multiplying each
|
||||
// by their index. Efficient way of doing it is to start with the last bucket and compute two sums:
|
||||
// intermediate sum from the last to the first, and the full sum made of all intermediate sums.
|
||||
// 5. Shift the resulting sum of buckets by `w` bits by using `w` doublings.
|
||||
// 6. Add to the return value.
|
||||
// 7. Repeat the loop.
|
||||
//
|
||||
// Approximate cost w/o wNAF optimizations (A = addition, D = doubling):
|
||||
//
|
||||
// ```ascii
|
||||
// cost = (n*A + 2*(2^w/2)*A + w*D + A)*256/w
|
||||
//
|
||||
// | | | | |
|
||||
// | | | | looping over 256/w windows
|
||||
// | | | adding to the result
|
||||
// sorting points | shifting the sum by w bits (to the next window, starting from last window)
|
||||
// one by one |
|
||||
// into buckets adding/subtracting all buckets
|
||||
// multiplied by their indexes
|
||||
// using a sum of intermediate sums
|
||||
//
|
||||
// ```
|
||||
//
|
||||
// For large `n`, dominant factor is (n*256/w) additions.
|
||||
// However, if `w` is too big and `n` is not too big, then `(2^w/2)*A` could dominate.
|
||||
// Therefore, the optimal choice of `w` grows slowly as `n` grows.
|
||||
//
|
||||
// # For constant time we use a fixed window of 6
|
||||
//
|
||||
// This algorithm is adapted from section 4 of <https://eprint.iacr.org/2012/549.pdf>.
|
||||
// and https://cacr.uwaterloo.ca/techreports/2010/cacr2010-26.pdf
|
||||
func sumOfProductsPippenger(points []Point, scalars []*big.Int) Point {
|
||||
if len(points) != len(scalars) {
|
||||
return nil
|
||||
}
|
||||
|
||||
const w = 6
|
||||
|
||||
bucketSize := (1 << w) - 1
|
||||
windows := make([]Point, 255/w+1)
|
||||
for i := range windows {
|
||||
windows[i] = points[0].Identity()
|
||||
}
|
||||
bucket := make([]Point, bucketSize)
|
||||
|
||||
for j := 0; j < len(windows); j++ {
|
||||
for i := 0; i < bucketSize; i++ {
|
||||
bucket[i] = points[0].Identity()
|
||||
}
|
||||
|
||||
for i := 0; i < len(scalars); i++ {
|
||||
index := bucketSize & int(new(big.Int).Rsh(scalars[i], uint(w*j)).Int64())
|
||||
if index != 0 {
|
||||
bucket[index-1] = bucket[index-1].Add(points[i])
|
||||
}
|
||||
}
|
||||
|
||||
acc, sum := windows[j].Identity(), windows[j].Identity()
|
||||
|
||||
for i := bucketSize - 1; i >= 0; i-- {
|
||||
sum = sum.Add(bucket[i])
|
||||
acc = acc.Add(sum)
|
||||
}
|
||||
windows[j] = acc
|
||||
}
|
||||
|
||||
acc := windows[0].Identity()
|
||||
for i := len(windows) - 1; i >= 0; i-- {
|
||||
for j := 0; j < w; j++ {
|
||||
acc = acc.Double()
|
||||
}
|
||||
acc = acc.Add(windows[i])
|
||||
}
|
||||
return acc
|
||||
}
|
@ -1,256 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package curves
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core"
|
||||
"github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
var curveNameToId = map[string]byte{
|
||||
"secp256k1": 0,
|
||||
"P-224": 1,
|
||||
"P-256": 2,
|
||||
"P-384": 3,
|
||||
"P-521": 4,
|
||||
}
|
||||
|
||||
var curveIdToName = map[byte]func() elliptic.Curve{
|
||||
0: func() elliptic.Curve { return btcec.S256() },
|
||||
1: elliptic.P224,
|
||||
2: elliptic.P256,
|
||||
3: elliptic.P384,
|
||||
4: elliptic.P521,
|
||||
}
|
||||
|
||||
var curveMapper = map[string]func() elliptic.Curve{
|
||||
"secp256k1": func() elliptic.Curve { return btcec.S256() },
|
||||
"P-224": elliptic.P224,
|
||||
"P-256": elliptic.P256,
|
||||
"P-384": elliptic.P384,
|
||||
"P-521": elliptic.P521,
|
||||
}
|
||||
|
||||
// EcPoint represents an elliptic curve Point
|
||||
type EcPoint struct {
|
||||
Curve elliptic.Curve
|
||||
X, Y *big.Int
|
||||
}
|
||||
|
||||
// EcPointJson encapsulates the data that is serialized to JSON
|
||||
// used internally and not for external use. Public so other pieces
|
||||
// can use for serialization
|
||||
type EcPointJson struct {
|
||||
CurveName string
|
||||
X, Y *big.Int
|
||||
}
|
||||
|
||||
// MarshalJSON serializes
|
||||
func (a EcPoint) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(EcPointJson{
|
||||
CurveName: a.Curve.Params().Name,
|
||||
X: a.X,
|
||||
Y: a.Y,
|
||||
})
|
||||
}
|
||||
|
||||
func (a *EcPoint) UnmarshalJSON(bytes []byte) error {
|
||||
data := new(EcPointJson)
|
||||
err := json.Unmarshal(bytes, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if mapper, ok := curveMapper[data.CurveName]; ok {
|
||||
a.Curve = mapper()
|
||||
a.X = data.X
|
||||
a.Y = data.Y
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown curve deserialized")
|
||||
}
|
||||
|
||||
func (a *EcPoint) MarshalBinary() ([]byte, error) {
|
||||
result := [65]byte{}
|
||||
if code, ok := curveNameToId[a.Curve.Params().Name]; ok {
|
||||
result[0] = code
|
||||
a.X.FillBytes(result[1:33])
|
||||
a.Y.FillBytes(result[33:65])
|
||||
return result[:], nil
|
||||
}
|
||||
return nil, fmt.Errorf("unknown curve serialized")
|
||||
}
|
||||
|
||||
func (a *EcPoint) UnmarshalBinary(data []byte) error {
|
||||
if mapper, ok := curveIdToName[data[0]]; ok {
|
||||
a.Curve = mapper()
|
||||
a.X = new(big.Int).SetBytes(data[1:33])
|
||||
a.Y = new(big.Int).SetBytes(data[33:65])
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown curve deserialized")
|
||||
}
|
||||
|
||||
func (a EcPoint) IsValid() bool {
|
||||
return a.IsOnCurve() || a.IsIdentity()
|
||||
}
|
||||
|
||||
func (a EcPoint) IsOnCurve() bool {
|
||||
return a.Curve.IsOnCurve(a.X, a.Y)
|
||||
}
|
||||
|
||||
// IsIdentity returns true if this Point is the Point at infinity
|
||||
func (a EcPoint) IsIdentity() bool {
|
||||
x := core.ConstantTimeEqByte(a.X, core.Zero)
|
||||
y := core.ConstantTimeEqByte(a.Y, core.Zero)
|
||||
return (x & y) == 1
|
||||
}
|
||||
|
||||
// Equals return true if a + b have the same x,y coordinates
|
||||
func (a EcPoint) Equals(b *EcPoint) bool {
|
||||
if !sameCurve(&a, b) {
|
||||
return false
|
||||
}
|
||||
// Next, compare coords to determine equality
|
||||
x := core.ConstantTimeEqByte(a.X, b.X)
|
||||
y := core.ConstantTimeEqByte(a.Y, b.Y)
|
||||
return (x & y) == 1
|
||||
}
|
||||
|
||||
// IsBasePoint returns true if this Point is curve's base Point
|
||||
func (a EcPoint) IsBasePoint() bool {
|
||||
p := a.Curve.Params()
|
||||
x := core.ConstantTimeEqByte(a.X, p.Gx)
|
||||
y := core.ConstantTimeEqByte(a.Y, p.Gy)
|
||||
return (x & y) == 1
|
||||
}
|
||||
|
||||
// Normalizes the Scalar to a positive element smaller than the base Point order.
|
||||
func reduceModN(curve elliptic.Curve, k *big.Int) *big.Int {
|
||||
return new(big.Int).Mod(k, curve.Params().N)
|
||||
}
|
||||
|
||||
// Add performs elliptic curve addition on two points
|
||||
func (a *EcPoint) Add(b *EcPoint) (*EcPoint, error) {
|
||||
// Validate parameters
|
||||
if a == nil || b == nil {
|
||||
return nil, internal.ErrNilArguments
|
||||
}
|
||||
// Only add points from the same curve
|
||||
if !sameCurve(a, b) {
|
||||
return nil, internal.ErrPointsDistinctCurves
|
||||
}
|
||||
p := &EcPoint{Curve: a.Curve}
|
||||
p.X, p.Y = a.Curve.Add(a.X, a.Y, b.X, b.Y)
|
||||
if !p.IsValid() {
|
||||
return nil, internal.ErrNotOnCurve
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Neg returns the negation of a Weierstrass Point.
|
||||
func (a *EcPoint) Neg() (*EcPoint, error) {
|
||||
// Validate parameters
|
||||
if a == nil {
|
||||
return nil, internal.ErrNilArguments
|
||||
}
|
||||
// Only add points from the same curve
|
||||
p := &EcPoint{Curve: a.Curve, X: a.X, Y: new(big.Int).Sub(a.Curve.Params().P, a.Y)}
|
||||
if !p.IsValid() {
|
||||
return nil, internal.ErrNotOnCurve
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// ScalarMult multiplies this Point by a Scalar
|
||||
func (a *EcPoint) ScalarMult(k *big.Int) (*EcPoint, error) {
|
||||
if a == nil || k == nil {
|
||||
return nil, fmt.Errorf("cannot multiply nil Point or element")
|
||||
}
|
||||
n := reduceModN(a.Curve, k)
|
||||
p := new(EcPoint)
|
||||
p.Curve = a.Curve
|
||||
p.X, p.Y = a.Curve.ScalarMult(a.X, a.Y, n.Bytes())
|
||||
if !p.IsValid() {
|
||||
return nil, fmt.Errorf("result not on the curve")
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// NewScalarBaseMult creates a Point from the base Point multiplied by a field element
|
||||
func NewScalarBaseMult(curve elliptic.Curve, k *big.Int) (*EcPoint, error) {
|
||||
if curve == nil || k == nil {
|
||||
return nil, fmt.Errorf("nil parameters are not supported")
|
||||
}
|
||||
n := reduceModN(curve, k)
|
||||
p := new(EcPoint)
|
||||
p.Curve = curve
|
||||
p.X, p.Y = curve.ScalarBaseMult(n.Bytes())
|
||||
if !p.IsValid() {
|
||||
return nil, fmt.Errorf("result not on the curve")
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Bytes returns the bytes represented by this Point with x || y
|
||||
func (a EcPoint) Bytes() []byte {
|
||||
fieldSize := internal.CalcFieldSize(a.Curve)
|
||||
out := make([]byte, fieldSize*2)
|
||||
|
||||
a.X.FillBytes(out[0:fieldSize])
|
||||
a.Y.FillBytes(out[fieldSize : fieldSize*2])
|
||||
return out
|
||||
}
|
||||
|
||||
// PointFromBytesUncompressed outputs uncompressed X || Y similar to
|
||||
// https://www.secg.org/sec1-v1.99.dif.pdf section 2.2 and 2.3
|
||||
func PointFromBytesUncompressed(curve elliptic.Curve, b []byte) (*EcPoint, error) {
|
||||
fieldSize := internal.CalcFieldSize(curve)
|
||||
if len(b) != fieldSize*2 {
|
||||
return nil, fmt.Errorf("invalid number of bytes")
|
||||
}
|
||||
p := &EcPoint{
|
||||
Curve: curve,
|
||||
X: new(big.Int).SetBytes(b[:fieldSize]),
|
||||
Y: new(big.Int).SetBytes(b[fieldSize:]),
|
||||
}
|
||||
if !p.IsValid() {
|
||||
return nil, fmt.Errorf("invalid Point")
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// sameCurve determines if points a,b appear to be from the same curve
|
||||
func sameCurve(a, b *EcPoint) bool {
|
||||
// Handle identical pointers and double-nil
|
||||
if a == b {
|
||||
return true
|
||||
}
|
||||
|
||||
// Handle one nil pointer
|
||||
if a == nil || b == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
aParams := a.Curve.Params()
|
||||
bParams := b.Curve.Params()
|
||||
|
||||
// Use curve order and name
|
||||
return aParams.P == bParams.P &&
|
||||
aParams.N == bParams.N &&
|
||||
aParams.B == bParams.B &&
|
||||
aParams.BitSize == bParams.BitSize &&
|
||||
aParams.Gx == bParams.Gx &&
|
||||
aParams.Gy == bParams.Gy &&
|
||||
aParams.Name == bParams.Name
|
||||
}
|
@ -1,369 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package curves
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/elliptic"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core"
|
||||
tt "github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
func TestIsIdentity(t *testing.T) {
|
||||
// Should be Point at infinity
|
||||
identity := &EcPoint{btcec.S256(), core.Zero, core.Zero}
|
||||
require.True(t, identity.IsIdentity())
|
||||
}
|
||||
|
||||
func TestNewScalarBaseMultZero(t *testing.T) {
|
||||
// Should be Point at infinity
|
||||
curve := btcec.S256()
|
||||
num := big.NewInt(0)
|
||||
p, err := NewScalarBaseMult(curve, num)
|
||||
if err != nil {
|
||||
t.Errorf("NewScalarBaseMult failed: %v", err)
|
||||
}
|
||||
if p == nil {
|
||||
t.Errorf("NewScalarBaseMult failed when it should've succeeded.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewScalarBaseMultOne(t *testing.T) {
|
||||
// Should be base Point
|
||||
curve := btcec.S256()
|
||||
num := big.NewInt(1)
|
||||
p, err := NewScalarBaseMult(curve, num)
|
||||
if err != nil {
|
||||
t.Errorf("NewScalarBaseMult failed: %v", err)
|
||||
}
|
||||
if p == nil {
|
||||
t.Errorf("NewScalarBaseMult failed when it should've succeeded.")
|
||||
t.FailNow()
|
||||
}
|
||||
if !bytes.Equal(p.Bytes(), append(curve.Gx.Bytes(), curve.Gy.Bytes()...)) {
|
||||
t.Errorf("NewScalarBaseMult should've returned the base Point.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewScalarBaseMultNeg(t *testing.T) {
|
||||
curve := btcec.S256()
|
||||
num := big.NewInt(-1)
|
||||
p, err := NewScalarBaseMult(curve, num)
|
||||
if err != nil {
|
||||
t.Errorf("NewScalarBaseMult failed: %v", err)
|
||||
}
|
||||
if p == nil {
|
||||
t.Errorf("NewScalarBaseMult failed when it should've succeeded.")
|
||||
t.FailNow()
|
||||
}
|
||||
num.Mod(num, curve.N)
|
||||
|
||||
e, err := NewScalarBaseMult(curve, num)
|
||||
if err != nil {
|
||||
t.Errorf("NewScalarBaseMult failed: %v", err)
|
||||
}
|
||||
if e == nil {
|
||||
t.Errorf("NewScalarBaseMult failed when it should've succeeded.")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if !bytes.Equal(p.Bytes(), e.Bytes()) {
|
||||
t.Errorf("NewScalarBaseMult should've returned the %v, found: %v", e, p)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScalarMultZero(t *testing.T) {
|
||||
// Should be Point at infinity
|
||||
curve := btcec.S256()
|
||||
p := &EcPoint{
|
||||
Curve: curve,
|
||||
X: curve.Gx,
|
||||
Y: curve.Gy,
|
||||
}
|
||||
num := big.NewInt(0)
|
||||
q, err := p.ScalarMult(num)
|
||||
if err != nil {
|
||||
t.Errorf("ScalarMult failed: %v", err)
|
||||
}
|
||||
if q == nil {
|
||||
t.Errorf("ScalarMult failed when it should've succeeded.")
|
||||
t.FailNow()
|
||||
}
|
||||
if !q.IsIdentity() {
|
||||
t.Errorf("ScalarMult should've returned the identity Point.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestScalarMultOne(t *testing.T) {
|
||||
// Should be base Point
|
||||
curve := btcec.S256()
|
||||
p := &EcPoint{
|
||||
Curve: curve,
|
||||
X: curve.Gx,
|
||||
Y: curve.Gy,
|
||||
}
|
||||
num := big.NewInt(1)
|
||||
q, err := p.ScalarMult(num)
|
||||
if err != nil {
|
||||
t.Errorf("ScalarMult failed: %v", err)
|
||||
}
|
||||
if q == nil {
|
||||
t.Errorf("ScalarMult failed when it should've succeeded.")
|
||||
t.FailNow()
|
||||
}
|
||||
if !bytes.Equal(q.Bytes(), append(curve.Gx.Bytes(), curve.Gy.Bytes()...)) {
|
||||
t.Errorf("ScalarMult should've returned the base Point.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestScalarMultNeg(t *testing.T) {
|
||||
curve := btcec.S256()
|
||||
p := &EcPoint{
|
||||
Curve: curve,
|
||||
X: curve.Gx,
|
||||
Y: curve.Gy,
|
||||
}
|
||||
num := big.NewInt(-1)
|
||||
q, err := p.ScalarMult(num)
|
||||
if err != nil {
|
||||
t.Errorf("ScalarMult failed: %v", err)
|
||||
}
|
||||
if q == nil {
|
||||
t.Errorf("ScalarMult failed when it should've succeeded.")
|
||||
}
|
||||
num.Mod(num, curve.N)
|
||||
|
||||
e, err := p.ScalarMult(num)
|
||||
if err != nil {
|
||||
t.Errorf("ScalarMult failed: %v", err)
|
||||
}
|
||||
if e == nil {
|
||||
t.Errorf("ScalarMult failed when it should've succeeded.")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if !bytes.Equal(q.Bytes(), e.Bytes()) {
|
||||
t.Errorf("ScalarMult should've returned the %v, found: %v", e, p)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEcPointAddSimple(t *testing.T) {
|
||||
curve := btcec.S256()
|
||||
num := big.NewInt(1)
|
||||
p1, _ := NewScalarBaseMult(curve, num)
|
||||
|
||||
p2, _ := NewScalarBaseMult(curve, num)
|
||||
p3, err := p1.Add(p2)
|
||||
if err != nil {
|
||||
t.Errorf("EcPoint.Add failed: %v", err)
|
||||
}
|
||||
num = big.NewInt(2)
|
||||
|
||||
ep, _ := NewScalarBaseMult(curve, num)
|
||||
|
||||
if !bytes.Equal(ep.Bytes(), p3.Bytes()) {
|
||||
t.Errorf("EcPoint.Add failed: should equal %v, found: %v", ep, p3)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEcPointAddCommunicative(t *testing.T) {
|
||||
curve := btcec.S256()
|
||||
a, _ := core.Rand(curve.Params().N)
|
||||
b, _ := core.Rand(curve.Params().N)
|
||||
|
||||
p1, _ := NewScalarBaseMult(curve, a)
|
||||
p2, _ := NewScalarBaseMult(curve, b)
|
||||
p3, err := p1.Add(p2)
|
||||
if err != nil {
|
||||
t.Errorf("EcPoint.Add failed: %v", err)
|
||||
}
|
||||
p4, err := p2.Add(p1)
|
||||
if err != nil {
|
||||
t.Errorf("EcPoint.Add failed: %v", err)
|
||||
}
|
||||
if !bytes.Equal(p3.Bytes(), p4.Bytes()) {
|
||||
t.Errorf("EcPoint.Add Communicative not valid")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEcPointAddNeg(t *testing.T) {
|
||||
curve := btcec.S256()
|
||||
num := big.NewInt(-1)
|
||||
|
||||
p1, _ := NewScalarBaseMult(curve, num)
|
||||
num.Abs(num)
|
||||
|
||||
p2, _ := NewScalarBaseMult(curve, num)
|
||||
|
||||
p3, err := p1.Add(p2)
|
||||
if err != nil {
|
||||
t.Errorf("EcPoint.Add failed: %v", err)
|
||||
}
|
||||
zero := make([]byte, 64)
|
||||
if !bytes.Equal(zero, p3.Bytes()) {
|
||||
t.Errorf("Expected value to be zero, found: %v", p3)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEcPointBytes(t *testing.T) {
|
||||
curve := btcec.S256()
|
||||
|
||||
point, err := NewScalarBaseMult(curve, big.NewInt(2))
|
||||
require.NoError(t, err)
|
||||
data := point.Bytes()
|
||||
point2, err := PointFromBytesUncompressed(curve, data)
|
||||
require.NoError(t, err)
|
||||
if point.X.Cmp(point2.X) != 0 && point.Y.Cmp(point2.Y) != 0 {
|
||||
t.Errorf("Points are not equal. Expected %v, found %v", point, point2)
|
||||
}
|
||||
|
||||
curve2 := elliptic.P224()
|
||||
p2, err := NewScalarBaseMult(curve2, big.NewInt(2))
|
||||
require.NoError(t, err)
|
||||
dta := p2.Bytes()
|
||||
point3, err := PointFromBytesUncompressed(curve2, dta)
|
||||
require.NoError(t, err)
|
||||
if p2.X.Cmp(point3.X) != 0 && p2.Y.Cmp(point3.Y) != 0 {
|
||||
t.Errorf("Points are not equal. Expected %v, found %v", p2, point3)
|
||||
}
|
||||
|
||||
curve3 := elliptic.P521()
|
||||
p3, err := NewScalarBaseMult(curve3, big.NewInt(2))
|
||||
require.NoError(t, err)
|
||||
data = p3.Bytes()
|
||||
point4, err := PointFromBytesUncompressed(curve3, data)
|
||||
require.NoError(t, err)
|
||||
if p3.X.Cmp(point4.X) != 0 && p3.Y.Cmp(point4.Y) != 0 {
|
||||
t.Errorf("Points are not equal. Expected %v, found %v", p3, point4)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEcPointBytesDifferentCurves(t *testing.T) {
|
||||
k256 := btcec.S256()
|
||||
p224 := elliptic.P224()
|
||||
p256 := elliptic.P256()
|
||||
|
||||
kp, err := NewScalarBaseMult(k256, big.NewInt(1))
|
||||
require.NoError(t, err)
|
||||
data := kp.Bytes()
|
||||
_, err = PointFromBytesUncompressed(p224, data)
|
||||
require.Error(t, err)
|
||||
_, err = PointFromBytesUncompressed(p256, data)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestEcPointBytesInvalidNumberBytes(t *testing.T) {
|
||||
curve := btcec.S256()
|
||||
|
||||
for i := 1; i < 64; i++ {
|
||||
data := make([]byte, i)
|
||||
_, err := PointFromBytesUncompressed(curve, data)
|
||||
require.Error(t, err)
|
||||
}
|
||||
for i := 65; i < 128; i++ {
|
||||
data := make([]byte, i)
|
||||
_, err := PointFromBytesUncompressed(curve, data)
|
||||
require.Error(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEcPointMultRandom(t *testing.T) {
|
||||
curve := btcec.S256()
|
||||
r, err := core.Rand(curve.N)
|
||||
require.NoError(t, err)
|
||||
pt, err := NewScalarBaseMult(curve, r)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, pt)
|
||||
data := pt.Bytes()
|
||||
pt2, err := PointFromBytesUncompressed(curve, data)
|
||||
require.NoError(t, err)
|
||||
if pt.X.Cmp(pt2.X) != 0 || pt.Y.Cmp(pt2.Y) != 0 {
|
||||
t.Errorf("Points are not equal. Expected: %v, found: %v", pt, pt2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsBasePoint(t *testing.T) {
|
||||
k256 := btcec.S256()
|
||||
p224 := elliptic.P224()
|
||||
p256 := elliptic.P256()
|
||||
|
||||
notG_p224, err := NewScalarBaseMult(p224, tt.B10("9876453120"))
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
curve elliptic.Curve
|
||||
x, y *big.Int
|
||||
expected bool
|
||||
}{
|
||||
{"k256-positive", k256, k256.Gx, k256.Gy, true},
|
||||
{"p224-positive", p224, p224.Params().Gx, p224.Params().Gy, true},
|
||||
{"p256-positive", p256, p256.Params().Gx, p256.Params().Gy, true},
|
||||
|
||||
{"p224-negative", p224, notG_p224.X, notG_p224.Y, false},
|
||||
{"p256-negative-wrong-curve", p256, notG_p224.X, notG_p224.Y, false},
|
||||
{"k256-negative-doubleGx", k256, k256.Gx, k256.Gx, false},
|
||||
{"k256-negative-doubleGy", k256, k256.Gy, k256.Gy, false},
|
||||
{"k256-negative-xy-swap", k256, k256.Gy, k256.Gx, false},
|
||||
{"k256-negative-oh-oh", k256, core.Zero, core.Zero, false},
|
||||
}
|
||||
// Run all the tests!
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual := EcPoint{test.curve, test.x, test.y}.IsBasePoint()
|
||||
require.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEquals(t *testing.T) {
|
||||
k256 := btcec.S256()
|
||||
p224 := elliptic.P224()
|
||||
p256 := elliptic.P256()
|
||||
P_p224, _ := NewScalarBaseMult(p224, tt.B10("9876453120"))
|
||||
P1_p224, _ := NewScalarBaseMult(p224, tt.B10("9876453120"))
|
||||
|
||||
P_k256 := &EcPoint{k256, P_p224.X, P_p224.Y}
|
||||
|
||||
id_p224 := &EcPoint{p224, core.Zero, core.Zero}
|
||||
id_k256 := &EcPoint{k256, core.Zero, core.Zero}
|
||||
id_p256 := &EcPoint{p256, core.Zero, core.Zero}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
x, y *EcPoint
|
||||
expected bool
|
||||
}{
|
||||
{"p224 same pointer", P_p224, P_p224, true},
|
||||
{"p224 same Point", P_p224, P1_p224, true},
|
||||
{"p224 identity", id_p224, id_p224, true},
|
||||
{"p256 identity", id_p256, id_p256, true},
|
||||
{"k256 identity", id_k256, id_k256, true},
|
||||
|
||||
{"negative-same x different y", P_p224, &EcPoint{p224, P_p224.X, core.One}, false},
|
||||
{"negative-same y different x", P_p224, &EcPoint{p224, core.Two, P_k256.Y}, false},
|
||||
|
||||
{"negative-wrong curve", P_p224, P_k256, false},
|
||||
{"negative-wrong curve reversed", P_k256, P_p224, false},
|
||||
{"Point is not the identity", P_p224, id_p224, false},
|
||||
{"negative nil", P1_p224, nil, false},
|
||||
{"identities on wrong curve", id_p256, id_k256, false},
|
||||
}
|
||||
// Run all the tests!
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual := test.x.Equals(test.y)
|
||||
require.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
@ -1,351 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package curves
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
crand "crypto/rand"
|
||||
"crypto/sha512"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"filippo.io/edwards25519"
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/bwesterb/go-ristretto"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core"
|
||||
"github.com/onsonr/hway/crypto/core/curves/native/bls12381"
|
||||
"github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
type EcScalar interface {
|
||||
Add(x, y *big.Int) *big.Int
|
||||
Sub(x, y *big.Int) *big.Int
|
||||
Neg(x *big.Int) *big.Int
|
||||
Mul(x, y *big.Int) *big.Int
|
||||
Hash(input []byte) *big.Int
|
||||
Div(x, y *big.Int) *big.Int
|
||||
Random() (*big.Int, error)
|
||||
IsValid(x *big.Int) bool
|
||||
Bytes(x *big.Int) []byte // fixed-length byte array
|
||||
}
|
||||
|
||||
type K256Scalar struct{}
|
||||
|
||||
// Static interface assertion
|
||||
var _ EcScalar = (*K256Scalar)(nil)
|
||||
|
||||
// warning: the Euclidean alg which Mod uses is not constant-time.
|
||||
|
||||
func NewK256Scalar() *K256Scalar {
|
||||
return &K256Scalar{}
|
||||
}
|
||||
|
||||
func (k K256Scalar) Add(x, y *big.Int) *big.Int {
|
||||
v := new(big.Int).Add(x, y)
|
||||
v.Mod(v, btcec.S256().N)
|
||||
return v
|
||||
}
|
||||
|
||||
func (k K256Scalar) Sub(x, y *big.Int) *big.Int {
|
||||
v := new(big.Int).Sub(x, y)
|
||||
v.Mod(v, btcec.S256().N)
|
||||
return v
|
||||
}
|
||||
|
||||
func (k K256Scalar) Neg(x *big.Int) *big.Int {
|
||||
v := new(big.Int).Sub(btcec.S256().N, x)
|
||||
v.Mod(v, btcec.S256().N)
|
||||
return v
|
||||
}
|
||||
|
||||
func (k K256Scalar) Mul(x, y *big.Int) *big.Int {
|
||||
v := new(big.Int).Mul(x, y)
|
||||
v.Mod(v, btcec.S256().N)
|
||||
return v
|
||||
}
|
||||
|
||||
func (k K256Scalar) Div(x, y *big.Int) *big.Int {
|
||||
t := new(big.Int).ModInverse(y, btcec.S256().N)
|
||||
return k.Mul(x, t)
|
||||
}
|
||||
|
||||
func (k K256Scalar) Hash(input []byte) *big.Int {
|
||||
return new(ScalarK256).Hash(input).BigInt()
|
||||
}
|
||||
|
||||
func (k K256Scalar) Random() (*big.Int, error) {
|
||||
b := make([]byte, 48)
|
||||
n, err := crand.Read(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n != 48 {
|
||||
return nil, fmt.Errorf("insufficient bytes read")
|
||||
}
|
||||
v := new(big.Int).SetBytes(b)
|
||||
v.Mod(v, btcec.S256().N)
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (k K256Scalar) IsValid(x *big.Int) bool {
|
||||
return core.In(x, btcec.S256().N) == nil
|
||||
}
|
||||
|
||||
func (k K256Scalar) Bytes(x *big.Int) []byte {
|
||||
bytes := make([]byte, 32)
|
||||
x.FillBytes(bytes) // big-endian; will left-pad.
|
||||
return bytes
|
||||
}
|
||||
|
||||
type P256Scalar struct{}
|
||||
|
||||
// Static interface assertion
|
||||
var _ EcScalar = (*P256Scalar)(nil)
|
||||
|
||||
func NewP256Scalar() *P256Scalar {
|
||||
return &P256Scalar{}
|
||||
}
|
||||
|
||||
func (k P256Scalar) Add(x, y *big.Int) *big.Int {
|
||||
v := new(big.Int).Add(x, y)
|
||||
v.Mod(v, elliptic.P256().Params().N)
|
||||
return v
|
||||
}
|
||||
|
||||
func (k P256Scalar) Sub(x, y *big.Int) *big.Int {
|
||||
v := new(big.Int).Sub(x, y)
|
||||
v.Mod(v, elliptic.P256().Params().N)
|
||||
return v
|
||||
}
|
||||
|
||||
func (k P256Scalar) Neg(x *big.Int) *big.Int {
|
||||
v := new(big.Int).Sub(elliptic.P256().Params().N, x)
|
||||
v.Mod(v, elliptic.P256().Params().N)
|
||||
return v
|
||||
}
|
||||
|
||||
func (k P256Scalar) Mul(x, y *big.Int) *big.Int {
|
||||
v := new(big.Int).Mul(x, y)
|
||||
v.Mod(v, elliptic.P256().Params().N)
|
||||
return v
|
||||
}
|
||||
|
||||
func (k P256Scalar) Div(x, y *big.Int) *big.Int {
|
||||
t := new(big.Int).ModInverse(y, elliptic.P256().Params().N)
|
||||
return k.Mul(x, t)
|
||||
}
|
||||
|
||||
func (k P256Scalar) Hash(input []byte) *big.Int {
|
||||
return new(ScalarP256).Hash(input).BigInt()
|
||||
}
|
||||
|
||||
func (k P256Scalar) Random() (*big.Int, error) {
|
||||
b := make([]byte, 48)
|
||||
n, err := crand.Read(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n != 48 {
|
||||
return nil, fmt.Errorf("insufficient bytes read")
|
||||
}
|
||||
v := new(big.Int).SetBytes(b)
|
||||
v.Mod(v, elliptic.P256().Params().N)
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (k P256Scalar) IsValid(x *big.Int) bool {
|
||||
return core.In(x, elliptic.P256().Params().N) == nil
|
||||
}
|
||||
|
||||
func (k P256Scalar) Bytes(x *big.Int) []byte {
|
||||
bytes := make([]byte, 32)
|
||||
x.FillBytes(bytes) // big-endian; will left-pad.
|
||||
return bytes
|
||||
}
|
||||
|
||||
type Bls12381Scalar struct{}
|
||||
|
||||
// Static interface assertion
|
||||
var _ EcScalar = (*Bls12381Scalar)(nil)
|
||||
|
||||
func NewBls12381Scalar() *Bls12381Scalar {
|
||||
return &Bls12381Scalar{}
|
||||
}
|
||||
|
||||
func (k Bls12381Scalar) Add(x, y *big.Int) *big.Int {
|
||||
a := bls12381.Bls12381FqNew().SetBigInt(x)
|
||||
b := bls12381.Bls12381FqNew().SetBigInt(y)
|
||||
return a.Add(a, b).BigInt()
|
||||
}
|
||||
|
||||
func (k Bls12381Scalar) Sub(x, y *big.Int) *big.Int {
|
||||
a := bls12381.Bls12381FqNew().SetBigInt(x)
|
||||
b := bls12381.Bls12381FqNew().SetBigInt(y)
|
||||
return a.Sub(a, b).BigInt()
|
||||
}
|
||||
|
||||
func (k Bls12381Scalar) Neg(x *big.Int) *big.Int {
|
||||
a := bls12381.Bls12381FqNew().SetBigInt(x)
|
||||
return a.Neg(a).BigInt()
|
||||
}
|
||||
|
||||
func (k Bls12381Scalar) Mul(x, y *big.Int) *big.Int {
|
||||
a := bls12381.Bls12381FqNew().SetBigInt(x)
|
||||
b := bls12381.Bls12381FqNew().SetBigInt(y)
|
||||
return a.Mul(a, b).BigInt()
|
||||
}
|
||||
|
||||
func (k Bls12381Scalar) Div(x, y *big.Int) *big.Int {
|
||||
c := bls12381.Bls12381FqNew()
|
||||
a := bls12381.Bls12381FqNew().SetBigInt(x)
|
||||
b := bls12381.Bls12381FqNew().SetBigInt(y)
|
||||
_, wasInverted := c.Invert(b)
|
||||
c.Mul(a, c)
|
||||
tt := map[bool]int{false: 0, true: 1}
|
||||
return a.CMove(a, c, tt[wasInverted]).BigInt()
|
||||
}
|
||||
|
||||
func (k Bls12381Scalar) Hash(input []byte) *big.Int {
|
||||
return new(ScalarBls12381).Hash(input).BigInt()
|
||||
}
|
||||
|
||||
func (k Bls12381Scalar) Random() (*big.Int, error) {
|
||||
a := BLS12381G1().NewScalar().Random(crand.Reader)
|
||||
if a == nil {
|
||||
return nil, fmt.Errorf("invalid random value")
|
||||
}
|
||||
return a.BigInt(), nil
|
||||
}
|
||||
|
||||
func (k Bls12381Scalar) Bytes(x *big.Int) []byte {
|
||||
bytes := make([]byte, 32)
|
||||
x.FillBytes(bytes) // big-endian; will left-pad.
|
||||
return bytes
|
||||
}
|
||||
|
||||
func (k Bls12381Scalar) IsValid(x *big.Int) bool {
|
||||
a := bls12381.Bls12381FqNew().SetBigInt(x)
|
||||
return a.BigInt().Cmp(x) == 0
|
||||
}
|
||||
|
||||
// taken from https://datatracker.ietf.org/doc/html/rfc8032
|
||||
var ed25519N, _ = new(big.Int).SetString("1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED", 16)
|
||||
|
||||
type Ed25519Scalar struct{}
|
||||
|
||||
// Static interface assertion
|
||||
var _ EcScalar = (*Ed25519Scalar)(nil)
|
||||
|
||||
func NewEd25519Scalar() *Ed25519Scalar {
|
||||
return &Ed25519Scalar{}
|
||||
}
|
||||
|
||||
func (k Ed25519Scalar) Add(x, y *big.Int) *big.Int {
|
||||
a, err := internal.BigInt2Ed25519Scalar(x)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
b, err := internal.BigInt2Ed25519Scalar(y)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
a.Add(a, b)
|
||||
return new(big.Int).SetBytes(internal.ReverseScalarBytes(a.Bytes()))
|
||||
}
|
||||
|
||||
func (k Ed25519Scalar) Sub(x, y *big.Int) *big.Int {
|
||||
a, err := internal.BigInt2Ed25519Scalar(x)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
b, err := internal.BigInt2Ed25519Scalar(y)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
a.Subtract(a, b)
|
||||
return new(big.Int).SetBytes(internal.ReverseScalarBytes(a.Bytes()))
|
||||
}
|
||||
|
||||
func (k Ed25519Scalar) Neg(x *big.Int) *big.Int {
|
||||
a, err := internal.BigInt2Ed25519Scalar(x)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
a.Negate(a)
|
||||
return new(big.Int).SetBytes(internal.ReverseScalarBytes(a.Bytes()))
|
||||
}
|
||||
|
||||
func (k Ed25519Scalar) Mul(x, y *big.Int) *big.Int {
|
||||
a, err := internal.BigInt2Ed25519Scalar(x)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
b, err := internal.BigInt2Ed25519Scalar(y)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
a.Multiply(a, b)
|
||||
return new(big.Int).SetBytes(internal.ReverseScalarBytes(a.Bytes()))
|
||||
}
|
||||
|
||||
func (k Ed25519Scalar) Div(x, y *big.Int) *big.Int {
|
||||
b, err := internal.BigInt2Ed25519Scalar(y)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
b.Invert(b)
|
||||
a, err := internal.BigInt2Ed25519Scalar(x)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
a.Multiply(a, b)
|
||||
return new(big.Int).SetBytes(internal.ReverseScalarBytes(a.Bytes()))
|
||||
}
|
||||
|
||||
func (k Ed25519Scalar) Hash(input []byte) *big.Int {
|
||||
v := new(ristretto.Scalar).Derive(input)
|
||||
var data [32]byte
|
||||
v.BytesInto(&data)
|
||||
return new(big.Int).SetBytes(internal.ReverseScalarBytes(data[:]))
|
||||
}
|
||||
|
||||
func (k Ed25519Scalar) Bytes(x *big.Int) []byte {
|
||||
a, err := internal.BigInt2Ed25519Scalar(x)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return internal.ReverseScalarBytes(a.Bytes())
|
||||
}
|
||||
|
||||
func (k Ed25519Scalar) Random() (*big.Int, error) {
|
||||
return k.RandomWithReader(crand.Reader)
|
||||
}
|
||||
|
||||
func (k Ed25519Scalar) RandomWithReader(r io.Reader) (*big.Int, error) {
|
||||
b := make([]byte, 64)
|
||||
n, err := r.Read(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n != 64 {
|
||||
return nil, fmt.Errorf("insufficient bytes read")
|
||||
}
|
||||
digest := sha512.Sum512(b)
|
||||
var hBytes [32]byte
|
||||
copy(hBytes[:], digest[:])
|
||||
s, err := edwards25519.NewScalar().SetBytesWithClamping(hBytes[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return new(big.Int).SetBytes(internal.ReverseScalarBytes(s.Bytes())), nil
|
||||
}
|
||||
|
||||
func (k Ed25519Scalar) IsValid(x *big.Int) bool {
|
||||
return x.Cmp(ed25519N) == -1
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package curves
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// EcdsaVerify runs a curve- or algorithm-specific ECDSA verification function on input
|
||||
// an ECDSA public (verification) key, a message digest, and an ECDSA signature.
|
||||
// It must return true if all the parameters are sane and the ECDSA signature is valid,
|
||||
// and false otherwise
|
||||
type EcdsaVerify func(pubKey *EcPoint, hash []byte, signature *EcdsaSignature) bool
|
||||
|
||||
// EcdsaSignature represents a (composite) digital signature
|
||||
type EcdsaSignature struct {
|
||||
V int
|
||||
R, S *big.Int
|
||||
}
|
||||
|
||||
// Static type assertion
|
||||
var _ EcdsaVerify = VerifyEcdsa
|
||||
|
||||
// Verifies ECDSA signature using core types.
|
||||
func VerifyEcdsa(pk *EcPoint, hash []byte, sig *EcdsaSignature) bool {
|
||||
return ecdsa.Verify(
|
||||
&ecdsa.PublicKey{
|
||||
Curve: pk.Curve,
|
||||
X: pk.X,
|
||||
Y: pk.Y,
|
||||
},
|
||||
hash, sig.R, sig.S)
|
||||
}
|
@ -1,788 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package curves
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha512"
|
||||
"crypto/subtle"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"filippo.io/edwards25519"
|
||||
"filippo.io/edwards25519/field"
|
||||
"github.com/bwesterb/go-ristretto"
|
||||
ed "github.com/bwesterb/go-ristretto/edwards25519"
|
||||
|
||||
"github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
type ScalarEd25519 struct {
|
||||
value *edwards25519.Scalar
|
||||
}
|
||||
|
||||
type PointEd25519 struct {
|
||||
value *edwards25519.Point
|
||||
}
|
||||
|
||||
var scOne, _ = edwards25519.NewScalar().SetCanonicalBytes([]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
|
||||
|
||||
func (s *ScalarEd25519) Random(reader io.Reader) Scalar {
|
||||
if reader == nil {
|
||||
return nil
|
||||
}
|
||||
var seed [64]byte
|
||||
_, _ = reader.Read(seed[:])
|
||||
return s.Hash(seed[:])
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) Hash(bytes []byte) Scalar {
|
||||
v := new(ristretto.Scalar).Derive(bytes)
|
||||
var data [32]byte
|
||||
v.BytesInto(&data)
|
||||
value, err := edwards25519.NewScalar().SetCanonicalBytes(data[:])
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &ScalarEd25519{value}
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) Zero() Scalar {
|
||||
return &ScalarEd25519{
|
||||
value: edwards25519.NewScalar(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) One() Scalar {
|
||||
return &ScalarEd25519{
|
||||
value: edwards25519.NewScalar().Set(scOne),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) IsZero() bool {
|
||||
i := byte(0)
|
||||
for _, b := range s.value.Bytes() {
|
||||
i |= b
|
||||
}
|
||||
return i == 0
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) IsOne() bool {
|
||||
data := s.value.Bytes()
|
||||
i := byte(0)
|
||||
for j := 1; j < len(data); j++ {
|
||||
i |= data[j]
|
||||
}
|
||||
return i == 0 && data[0] == 1
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) IsOdd() bool {
|
||||
return s.value.Bytes()[0]&1 == 1
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) IsEven() bool {
|
||||
return s.value.Bytes()[0]&1 == 0
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) New(input int) Scalar {
|
||||
var data [64]byte
|
||||
i := input
|
||||
if input < 0 {
|
||||
i = -input
|
||||
}
|
||||
data[0] = byte(i)
|
||||
data[1] = byte(i >> 8)
|
||||
data[2] = byte(i >> 16)
|
||||
data[3] = byte(i >> 24)
|
||||
value, err := edwards25519.NewScalar().SetUniformBytes(data[:])
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if input < 0 {
|
||||
value.Negate(value)
|
||||
}
|
||||
|
||||
return &ScalarEd25519{
|
||||
value,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) Cmp(rhs Scalar) int {
|
||||
r := s.Sub(rhs)
|
||||
if r != nil && r.IsZero() {
|
||||
return 0
|
||||
} else {
|
||||
return -2
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) Square() Scalar {
|
||||
value := edwards25519.NewScalar().Multiply(s.value, s.value)
|
||||
return &ScalarEd25519{value}
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) Double() Scalar {
|
||||
return &ScalarEd25519{
|
||||
value: edwards25519.NewScalar().Add(s.value, s.value),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) Invert() (Scalar, error) {
|
||||
return &ScalarEd25519{
|
||||
value: edwards25519.NewScalar().Invert(s.value),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) Sqrt() (Scalar, error) {
|
||||
bi25519, _ := new(big.Int).SetString("1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED", 16)
|
||||
x := s.BigInt()
|
||||
x.ModSqrt(x, bi25519)
|
||||
return s.SetBigInt(x)
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) Cube() Scalar {
|
||||
value := edwards25519.NewScalar().Multiply(s.value, s.value)
|
||||
value.Multiply(value, s.value)
|
||||
return &ScalarEd25519{value}
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) Add(rhs Scalar) Scalar {
|
||||
r, ok := rhs.(*ScalarEd25519)
|
||||
if ok {
|
||||
return &ScalarEd25519{
|
||||
value: edwards25519.NewScalar().Add(s.value, r.value),
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) Sub(rhs Scalar) Scalar {
|
||||
r, ok := rhs.(*ScalarEd25519)
|
||||
if ok {
|
||||
return &ScalarEd25519{
|
||||
value: edwards25519.NewScalar().Subtract(s.value, r.value),
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) Mul(rhs Scalar) Scalar {
|
||||
r, ok := rhs.(*ScalarEd25519)
|
||||
if ok {
|
||||
return &ScalarEd25519{
|
||||
value: edwards25519.NewScalar().Multiply(s.value, r.value),
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) MulAdd(y, z Scalar) Scalar {
|
||||
yy, ok := y.(*ScalarEd25519)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
zz, ok := z.(*ScalarEd25519)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return &ScalarEd25519{value: edwards25519.NewScalar().MultiplyAdd(s.value, yy.value, zz.value)}
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) Div(rhs Scalar) Scalar {
|
||||
r, ok := rhs.(*ScalarEd25519)
|
||||
if ok {
|
||||
value := edwards25519.NewScalar().Invert(r.value)
|
||||
value.Multiply(value, s.value)
|
||||
return &ScalarEd25519{value}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) Neg() Scalar {
|
||||
return &ScalarEd25519{
|
||||
value: edwards25519.NewScalar().Negate(s.value),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) SetBigInt(x *big.Int) (Scalar, error) {
|
||||
if x == nil {
|
||||
return nil, fmt.Errorf("invalid value")
|
||||
}
|
||||
|
||||
bi25519, _ := new(big.Int).SetString("1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED", 16)
|
||||
var v big.Int
|
||||
buf := v.Mod(x, bi25519).Bytes()
|
||||
var rBuf [32]byte
|
||||
for i := 0; i < len(buf) && i < 32; i++ {
|
||||
rBuf[i] = buf[len(buf)-i-1]
|
||||
}
|
||||
value, err := edwards25519.NewScalar().SetCanonicalBytes(rBuf[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ScalarEd25519{value}, nil
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) BigInt() *big.Int {
|
||||
var ret big.Int
|
||||
buf := internal.ReverseScalarBytes(s.value.Bytes())
|
||||
return ret.SetBytes(buf)
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) Bytes() []byte {
|
||||
return s.value.Bytes()
|
||||
}
|
||||
|
||||
// SetBytes takes input a 32-byte long array and returns a ed25519 scalar.
|
||||
// The input must be 32-byte long and must be a reduced bytes.
|
||||
func (s *ScalarEd25519) SetBytes(input []byte) (Scalar, error) {
|
||||
if len(input) != 32 {
|
||||
return nil, fmt.Errorf("invalid byte sequence")
|
||||
}
|
||||
value, err := edwards25519.NewScalar().SetCanonicalBytes(input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ScalarEd25519{value}, nil
|
||||
}
|
||||
|
||||
// SetBytesWide takes input a 64-byte long byte array, reduce it and return an ed25519 scalar.
|
||||
// It uses SetUniformBytes of fillipo.io/edwards25519 - https://github.com/FiloSottile/edwards25519/blob/v1.0.0-rc.1/scalar.go#L85
|
||||
// If bytes is not of the right length, it returns nil and an error
|
||||
func (s *ScalarEd25519) SetBytesWide(bytes []byte) (Scalar, error) {
|
||||
value, err := edwards25519.NewScalar().SetUniformBytes(bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ScalarEd25519{value}, nil
|
||||
}
|
||||
|
||||
// SetBytesClamping uses SetBytesWithClamping of fillipo.io/edwards25519- https://github.com/FiloSottile/edwards25519/blob/v1.0.0-rc.1/scalar.go#L135
|
||||
// which applies the buffer pruning described in RFC 8032, Section 5.1.5 (also known as clamping)
|
||||
// and sets bytes to the result. The input must be 32-byte long, and it is not modified.
|
||||
// If bytes is not of the right length, SetBytesWithClamping returns nil and an error, and the receiver is unchanged.
|
||||
func (s *ScalarEd25519) SetBytesClamping(bytes []byte) (Scalar, error) {
|
||||
value, err := edwards25519.NewScalar().SetBytesWithClamping(bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ScalarEd25519{value}, nil
|
||||
}
|
||||
|
||||
// SetBytesCanonical uses SetCanonicalBytes of fillipo.io/edwards25519.
|
||||
// https://github.com/FiloSottile/edwards25519/blob/v1.0.0-rc.1/scalar.go#L98
|
||||
// This function takes an input x and sets s = x, where x is a 32-byte little-endian
|
||||
// encoding of s, then it returns the corresponding ed25519 scalar. If the input is
|
||||
// not a canonical encoding of s, it returns nil and an error.
|
||||
func (s *ScalarEd25519) SetBytesCanonical(bytes []byte) (Scalar, error) {
|
||||
return s.SetBytes(bytes)
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) Point() Point {
|
||||
return new(PointEd25519).Identity()
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) Clone() Scalar {
|
||||
return &ScalarEd25519{
|
||||
value: edwards25519.NewScalar().Set(s.value),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) MarshalBinary() ([]byte, error) {
|
||||
return scalarMarshalBinary(s)
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) UnmarshalBinary(input []byte) error {
|
||||
sc, err := scalarUnmarshalBinary(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ss, ok := sc.(*ScalarEd25519)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid scalar")
|
||||
}
|
||||
s.value = ss.value
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) MarshalText() ([]byte, error) {
|
||||
return scalarMarshalText(s)
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) UnmarshalText(input []byte) error {
|
||||
sc, err := scalarUnmarshalText(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ss, ok := sc.(*ScalarEd25519)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid scalar")
|
||||
}
|
||||
s.value = ss.value
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) GetEdwardsScalar() *edwards25519.Scalar {
|
||||
return edwards25519.NewScalar().Set(s.value)
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) SetEdwardsScalar(sc *edwards25519.Scalar) *ScalarEd25519 {
|
||||
return &ScalarEd25519{value: edwards25519.NewScalar().Set(sc)}
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) MarshalJSON() ([]byte, error) {
|
||||
return scalarMarshalJson(s)
|
||||
}
|
||||
|
||||
func (s *ScalarEd25519) UnmarshalJSON(input []byte) error {
|
||||
sc, err := scalarUnmarshalJson(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
S, ok := sc.(*ScalarEd25519)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid type")
|
||||
}
|
||||
s.value = S.value
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PointEd25519) Random(reader io.Reader) Point {
|
||||
var seed [64]byte
|
||||
_, _ = reader.Read(seed[:])
|
||||
return p.Hash(seed[:])
|
||||
}
|
||||
|
||||
func (p *PointEd25519) Hash(bytes []byte) Point {
|
||||
/// Perform hashing to the group using the Elligator2 map
|
||||
///
|
||||
/// See https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-11#section-6.7.1
|
||||
h := sha512.Sum512(bytes)
|
||||
var res [32]byte
|
||||
copy(res[:], h[:32])
|
||||
signBit := (res[31] & 0x80) >> 7
|
||||
|
||||
fe := new(ed.FieldElement).SetBytes(&res).BytesInto(&res)
|
||||
m1 := elligatorEncode(fe)
|
||||
|
||||
return toEdwards(m1, signBit)
|
||||
}
|
||||
|
||||
func (p *PointEd25519) Identity() Point {
|
||||
return &PointEd25519{
|
||||
value: edwards25519.NewIdentityPoint(),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PointEd25519) Generator() Point {
|
||||
return &PointEd25519{
|
||||
value: edwards25519.NewGeneratorPoint(),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PointEd25519) IsIdentity() bool {
|
||||
return p.Equal(p.Identity())
|
||||
}
|
||||
|
||||
func (p *PointEd25519) IsNegative() bool {
|
||||
// Negative points don't really exist in ed25519
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *PointEd25519) IsOnCurve() bool {
|
||||
_, err := edwards25519.NewIdentityPoint().SetBytes(p.ToAffineCompressed())
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (p *PointEd25519) Double() Point {
|
||||
return &PointEd25519{value: edwards25519.NewIdentityPoint().Add(p.value, p.value)}
|
||||
}
|
||||
|
||||
func (p *PointEd25519) Scalar() Scalar {
|
||||
return new(ScalarEd25519).Zero()
|
||||
}
|
||||
|
||||
func (p *PointEd25519) Neg() Point {
|
||||
return &PointEd25519{value: edwards25519.NewIdentityPoint().Negate(p.value)}
|
||||
}
|
||||
|
||||
func (p *PointEd25519) Add(rhs Point) Point {
|
||||
if rhs == nil {
|
||||
return nil
|
||||
}
|
||||
r, ok := rhs.(*PointEd25519)
|
||||
if ok {
|
||||
return &PointEd25519{value: edwards25519.NewIdentityPoint().Add(p.value, r.value)}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PointEd25519) Sub(rhs Point) Point {
|
||||
if rhs == nil {
|
||||
return nil
|
||||
}
|
||||
r, ok := rhs.(*PointEd25519)
|
||||
if ok {
|
||||
rTmp := edwards25519.NewIdentityPoint().Negate(r.value)
|
||||
return &PointEd25519{value: edwards25519.NewIdentityPoint().Add(p.value, rTmp)}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PointEd25519) Mul(rhs Scalar) Point {
|
||||
if rhs == nil {
|
||||
return nil
|
||||
}
|
||||
r, ok := rhs.(*ScalarEd25519)
|
||||
if ok {
|
||||
value := edwards25519.NewIdentityPoint().ScalarMult(r.value, p.value)
|
||||
return &PointEd25519{value}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// MangleScalarBitsAndMulByBasepointToProducePublicKey
|
||||
// is a function for mangling the bits of a (formerly
|
||||
// mathematically well-defined) "scalar" and multiplying it to produce a
|
||||
// public key.
|
||||
func (p *PointEd25519) MangleScalarBitsAndMulByBasepointToProducePublicKey(rhs *ScalarEd25519) *PointEd25519 {
|
||||
data := rhs.value.Bytes()
|
||||
s, err := edwards25519.NewScalar().SetBytesWithClamping(data[:])
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
value := edwards25519.NewIdentityPoint().ScalarBaseMult(s)
|
||||
return &PointEd25519{value}
|
||||
}
|
||||
|
||||
func (p *PointEd25519) Equal(rhs Point) bool {
|
||||
r, ok := rhs.(*PointEd25519)
|
||||
if ok {
|
||||
// We would like to check that the point (X/Z, Y/Z) is equal to
|
||||
// the point (X'/Z', Y'/Z') without converting into affine
|
||||
// coordinates (x, y) and (x', y'), which requires two inversions.
|
||||
// We have that X = xZ and X' = x'Z'. Thus, x = x' is equivalent to
|
||||
// (xZ)Z' = (x'Z')Z, and similarly for the y-coordinate.
|
||||
return p.value.Equal(r.value) == 1
|
||||
//lhs1 := new(ed.FieldElement).Mul(&p.value.X, &r.value.Z)
|
||||
//rhs1 := new(ed.FieldElement).Mul(&r.value.X, &p.value.Z)
|
||||
//lhs2 := new(ed.FieldElement).Mul(&p.value.Y, &r.value.Z)
|
||||
//rhs2 := new(ed.FieldElement).Mul(&r.value.Y, &p.value.Z)
|
||||
//
|
||||
//return lhs1.Equals(rhs1) && lhs2.Equals(rhs2)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PointEd25519) Set(x, y *big.Int) (Point, error) {
|
||||
// check is identity
|
||||
xx := subtle.ConstantTimeCompare(x.Bytes(), []byte{})
|
||||
yy := subtle.ConstantTimeCompare(y.Bytes(), []byte{})
|
||||
if (xx | yy) == 1 {
|
||||
return p.Identity(), nil
|
||||
}
|
||||
xElem := new(ed.FieldElement).SetBigInt(x)
|
||||
yElem := new(ed.FieldElement).SetBigInt(y)
|
||||
|
||||
var data [32]byte
|
||||
var affine [64]byte
|
||||
xElem.BytesInto(&data)
|
||||
copy(affine[:32], data[:])
|
||||
yElem.BytesInto(&data)
|
||||
copy(affine[32:], data[:])
|
||||
return p.FromAffineUncompressed(affine[:])
|
||||
}
|
||||
|
||||
// sqrtRatio sets r to the non-negative square root of the ratio of u and v.
|
||||
//
|
||||
// If u/v is square, sqrtRatio returns r and 1. If u/v is not square, SqrtRatio
|
||||
// sets r according to Section 4.3 of draft-irtf-cfrg-ristretto255-decaf448-00,
|
||||
// and returns r and 0.
|
||||
func sqrtRatio(u, v *ed.FieldElement) (r *ed.FieldElement, wasSquare bool) {
|
||||
sqrtM1 := ed.FieldElement{
|
||||
533094393274173, 2016890930128738, 18285341111199,
|
||||
134597186663265, 1486323764102114,
|
||||
}
|
||||
a := new(ed.FieldElement)
|
||||
b := new(ed.FieldElement)
|
||||
r = new(ed.FieldElement)
|
||||
|
||||
// r = (u * v3) * (u * v7)^((p-5)/8)
|
||||
v2 := a.Square(v)
|
||||
uv3 := b.Mul(u, b.Mul(v2, v))
|
||||
uv7 := a.Mul(uv3, a.Square(v2))
|
||||
r.Mul(uv3, r.Exp22523(uv7))
|
||||
|
||||
check := a.Mul(v, a.Square(r)) // check = v * r^2
|
||||
|
||||
uNeg := b.Neg(u)
|
||||
correctSignSqrt := check.Equals(u)
|
||||
flippedSignSqrt := check.Equals(uNeg)
|
||||
flippedSignSqrtI := check.Equals(uNeg.Mul(uNeg, &sqrtM1))
|
||||
|
||||
rPrime := b.Mul(r, &sqrtM1) // r_prime = SQRT_M1 * r
|
||||
// r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r)
|
||||
cselect(r, rPrime, r, flippedSignSqrt || flippedSignSqrtI)
|
||||
|
||||
r.Abs(r) // Choose the nonnegative square root.
|
||||
return r, correctSignSqrt || flippedSignSqrt
|
||||
}
|
||||
|
||||
// cselect sets v to a if cond == 1, and to b if cond == 0.
|
||||
func cselect(v, a, b *ed.FieldElement, cond bool) *ed.FieldElement {
|
||||
const mask64Bits uint64 = (1 << 64) - 1
|
||||
|
||||
m := uint64(0)
|
||||
if cond {
|
||||
m = mask64Bits
|
||||
}
|
||||
|
||||
v[0] = (m & a[0]) | (^m & b[0])
|
||||
v[1] = (m & a[1]) | (^m & b[1])
|
||||
v[2] = (m & a[2]) | (^m & b[2])
|
||||
v[3] = (m & a[3]) | (^m & b[3])
|
||||
v[4] = (m & a[4]) | (^m & b[4])
|
||||
return v
|
||||
}
|
||||
|
||||
func (p *PointEd25519) ToAffineCompressed() []byte {
|
||||
return p.value.Bytes()
|
||||
}
|
||||
|
||||
func (p *PointEd25519) ToAffineUncompressed() []byte {
|
||||
x, y, z, _ := p.value.ExtendedCoordinates()
|
||||
recip := new(field.Element).Invert(z)
|
||||
x.Multiply(x, recip)
|
||||
y.Multiply(y, recip)
|
||||
var out [64]byte
|
||||
copy(out[:32], x.Bytes())
|
||||
copy(out[32:], y.Bytes())
|
||||
return out[:]
|
||||
}
|
||||
|
||||
func (p *PointEd25519) FromAffineCompressed(inBytes []byte) (Point, error) {
|
||||
pt, err := edwards25519.NewIdentityPoint().SetBytes(inBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &PointEd25519{value: pt}, nil
|
||||
}
|
||||
|
||||
func (p *PointEd25519) FromAffineUncompressed(inBytes []byte) (Point, error) {
|
||||
if len(inBytes) != 64 {
|
||||
return nil, fmt.Errorf("invalid byte sequence")
|
||||
}
|
||||
if bytes.Equal(inBytes, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) {
|
||||
return &PointEd25519{value: edwards25519.NewIdentityPoint()}, nil
|
||||
}
|
||||
x, err := new(field.Element).SetBytes(inBytes[:32])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
y, err := new(field.Element).SetBytes(inBytes[32:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
z := new(field.Element).One()
|
||||
t := new(field.Element).Multiply(x, y)
|
||||
value, err := edwards25519.NewIdentityPoint().SetExtendedCoordinates(x, y, z, t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &PointEd25519{value}, nil
|
||||
}
|
||||
|
||||
func (p *PointEd25519) CurveName() string {
|
||||
return ED25519Name
|
||||
}
|
||||
|
||||
func (p *PointEd25519) SumOfProducts(points []Point, scalars []Scalar) Point {
|
||||
nScalars := make([]*edwards25519.Scalar, len(scalars))
|
||||
nPoints := make([]*edwards25519.Point, len(points))
|
||||
for i, sc := range scalars {
|
||||
s, err := edwards25519.NewScalar().SetCanonicalBytes(sc.Bytes())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
nScalars[i] = s
|
||||
}
|
||||
for i, pt := range points {
|
||||
pp, ok := pt.(*PointEd25519)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
nPoints[i] = pp.value
|
||||
}
|
||||
pt := edwards25519.NewIdentityPoint().MultiScalarMult(nScalars, nPoints)
|
||||
return &PointEd25519{value: pt}
|
||||
}
|
||||
|
||||
func (p *PointEd25519) VarTimeDoubleScalarBaseMult(a Scalar, A Point, b Scalar) Point {
|
||||
AA, ok := A.(*PointEd25519)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
aa, ok := a.(*ScalarEd25519)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
bb, ok := b.(*ScalarEd25519)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
value := edwards25519.NewIdentityPoint().VarTimeDoubleScalarBaseMult(aa.value, AA.value, bb.value)
|
||||
return &PointEd25519{value}
|
||||
}
|
||||
|
||||
func (p *PointEd25519) MarshalBinary() ([]byte, error) {
|
||||
return pointMarshalBinary(p)
|
||||
}
|
||||
|
||||
func (p *PointEd25519) UnmarshalBinary(input []byte) error {
|
||||
pt, err := pointUnmarshalBinary(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ppt, ok := pt.(*PointEd25519)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid point")
|
||||
}
|
||||
p.value = ppt.value
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PointEd25519) MarshalText() ([]byte, error) {
|
||||
return pointMarshalText(p)
|
||||
}
|
||||
|
||||
func (p *PointEd25519) UnmarshalText(input []byte) error {
|
||||
pt, err := pointUnmarshalText(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ppt, ok := pt.(*PointEd25519)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid point")
|
||||
}
|
||||
p.value = ppt.value
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PointEd25519) MarshalJSON() ([]byte, error) {
|
||||
return pointMarshalJson(p)
|
||||
}
|
||||
|
||||
func (p *PointEd25519) UnmarshalJSON(input []byte) error {
|
||||
pt, err := pointUnmarshalJson(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
P, ok := pt.(*PointEd25519)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid type")
|
||||
}
|
||||
p.value = P.value
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PointEd25519) GetEdwardsPoint() *edwards25519.Point {
|
||||
return edwards25519.NewIdentityPoint().Set(p.value)
|
||||
}
|
||||
|
||||
func (p *PointEd25519) SetEdwardsPoint(pt *edwards25519.Point) *PointEd25519 {
|
||||
return &PointEd25519{value: edwards25519.NewIdentityPoint().Set(pt)}
|
||||
}
|
||||
|
||||
// Attempt to convert to an `EdwardsPoint`, using the supplied
|
||||
// choice of sign for the `EdwardsPoint`.
|
||||
// - `sign`: a `u8` donating the desired sign of the resulting
|
||||
// `EdwardsPoint`. `0` denotes positive and `1` negative.
|
||||
func toEdwards(u *ed.FieldElement, sign byte) *PointEd25519 {
|
||||
one := new(ed.FieldElement).SetOne()
|
||||
// To decompress the Montgomery u coordinate to an
|
||||
// `EdwardsPoint`, we apply the birational map to obtain the
|
||||
// Edwards y coordinate, then do Edwards decompression.
|
||||
//
|
||||
// The birational map is y = (u-1)/(u+1).
|
||||
//
|
||||
// The exceptional points are the zeros of the denominator,
|
||||
// i.e., u = -1.
|
||||
//
|
||||
// But when u = -1, v^2 = u*(u^2+486662*u+1) = 486660.
|
||||
//
|
||||
// Since this is nonsquare mod p, u = -1 corresponds to a point
|
||||
// on the twist, not the curve, so we can reject it early.
|
||||
if u.Equals(new(ed.FieldElement).Neg(one)) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// y = (u-1)/(u+1)
|
||||
yLhs := new(ed.FieldElement).Sub(u, one)
|
||||
yRhs := new(ed.FieldElement).Add(u, one)
|
||||
yInv := new(ed.FieldElement).Inverse(yRhs)
|
||||
y := new(ed.FieldElement).Mul(yLhs, yInv)
|
||||
yBytes := y.Bytes()
|
||||
yBytes[31] ^= sign << 7
|
||||
|
||||
pt, err := edwards25519.NewIdentityPoint().SetBytes(yBytes[:])
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
pt.MultByCofactor(pt)
|
||||
return &PointEd25519{value: pt}
|
||||
}
|
||||
|
||||
// Perform the Elligator2 mapping to a Montgomery point encoded as a 32 byte value
|
||||
//
|
||||
// See <https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-11#section-6.7.1>
|
||||
func elligatorEncode(r0 *ed.FieldElement) *ed.FieldElement {
|
||||
montgomeryA := &ed.FieldElement{
|
||||
486662, 0, 0, 0, 0,
|
||||
}
|
||||
// montgomeryANeg is equal to -486662.
|
||||
montgomeryANeg := &ed.FieldElement{
|
||||
2251799813198567,
|
||||
2251799813685247,
|
||||
2251799813685247,
|
||||
2251799813685247,
|
||||
2251799813685247,
|
||||
}
|
||||
t := new(ed.FieldElement)
|
||||
one := new(ed.FieldElement).SetOne()
|
||||
// 2r^2
|
||||
d1 := new(ed.FieldElement).Add(one, t.DoubledSquare(r0))
|
||||
// A/(1+2r^2)
|
||||
d := new(ed.FieldElement).Mul(montgomeryANeg, t.Inverse(d1))
|
||||
dsq := new(ed.FieldElement).Square(d)
|
||||
au := new(ed.FieldElement).Mul(montgomeryA, d)
|
||||
|
||||
inner := new(ed.FieldElement).Add(dsq, au)
|
||||
inner.Add(inner, one)
|
||||
|
||||
// d^3 + Ad^2 + d
|
||||
eps := new(ed.FieldElement).Mul(d, inner)
|
||||
_, wasSquare := sqrtRatio(eps, one)
|
||||
|
||||
zero := new(ed.FieldElement).SetZero()
|
||||
aTemp := new(ed.FieldElement).SetZero()
|
||||
// 0 or A if non-square
|
||||
cselect(aTemp, zero, montgomeryA, wasSquare)
|
||||
// d, or d+A if non-square
|
||||
u := new(ed.FieldElement).Add(d, aTemp)
|
||||
// d or -d-A if non-square
|
||||
cselect(u, u, new(ed.FieldElement).Neg(u), wasSquare)
|
||||
return u
|
||||
}
|
@ -1,403 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package curves
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
ed "filippo.io/edwards25519"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
func TestScalarEd25519Random(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
sc := ed25519.Scalar.Random(testRng())
|
||||
s, ok := sc.(*ScalarEd25519)
|
||||
require.True(t, ok)
|
||||
expected := toRSc("feaa6a9d6dda758da6145f7d411a3af9f8a120698e0093faa97085b384c3f00e")
|
||||
require.Equal(t, s.value.Equal(expected), 1)
|
||||
// Try 10 random values
|
||||
for i := 0; i < 10; i++ {
|
||||
sc := ed25519.Scalar.Random(crand.Reader)
|
||||
_, ok := sc.(*ScalarEd25519)
|
||||
require.True(t, ok)
|
||||
require.True(t, !sc.IsZero())
|
||||
}
|
||||
}
|
||||
|
||||
func TestScalarEd25519Hash(t *testing.T) {
|
||||
var b [32]byte
|
||||
ed25519 := ED25519()
|
||||
sc := ed25519.Scalar.Hash(b[:])
|
||||
s, ok := sc.(*ScalarEd25519)
|
||||
require.True(t, ok)
|
||||
expected := toRSc("9d574494a02d72f5ff311cf0fb844d0fdd6103b17255274e029bdeed7207d409")
|
||||
require.Equal(t, s.value.Equal(expected), 1)
|
||||
}
|
||||
|
||||
func TestScalarEd25519Zero(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
sc := ed25519.Scalar.Zero()
|
||||
require.True(t, sc.IsZero())
|
||||
require.True(t, sc.IsEven())
|
||||
}
|
||||
|
||||
func TestScalarEd25519One(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
sc := ed25519.Scalar.One()
|
||||
require.True(t, sc.IsOne())
|
||||
require.True(t, sc.IsOdd())
|
||||
}
|
||||
|
||||
func TestScalarEd25519New(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
three := ed25519.Scalar.New(3)
|
||||
require.True(t, three.IsOdd())
|
||||
four := ed25519.Scalar.New(4)
|
||||
require.True(t, four.IsEven())
|
||||
neg1 := ed25519.Scalar.New(-1)
|
||||
require.True(t, neg1.IsEven())
|
||||
neg2 := ed25519.Scalar.New(-2)
|
||||
require.True(t, neg2.IsOdd())
|
||||
}
|
||||
|
||||
func TestScalarEd25519Square(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
three := ed25519.Scalar.New(3)
|
||||
nine := ed25519.Scalar.New(9)
|
||||
require.Equal(t, three.Square().Cmp(nine), 0)
|
||||
}
|
||||
|
||||
func TestScalarEd25519Cube(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
three := ed25519.Scalar.New(3)
|
||||
twentySeven := ed25519.Scalar.New(27)
|
||||
require.Equal(t, three.Cube().Cmp(twentySeven), 0)
|
||||
}
|
||||
|
||||
func TestScalarEd25519Double(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
three := ed25519.Scalar.New(3)
|
||||
six := ed25519.Scalar.New(6)
|
||||
require.Equal(t, three.Double().Cmp(six), 0)
|
||||
}
|
||||
|
||||
func TestScalarEd25519Neg(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
one := ed25519.Scalar.One()
|
||||
neg1 := ed25519.Scalar.New(-1)
|
||||
require.Equal(t, one.Neg().Cmp(neg1), 0)
|
||||
lotsOfThrees := ed25519.Scalar.New(333333)
|
||||
expected := ed25519.Scalar.New(-333333)
|
||||
require.Equal(t, lotsOfThrees.Neg().Cmp(expected), 0)
|
||||
}
|
||||
|
||||
func TestScalarEd25519Invert(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
nine := ed25519.Scalar.New(9)
|
||||
actual, _ := nine.Invert()
|
||||
sa, _ := actual.(*ScalarEd25519)
|
||||
expected := toRSc("c3d9c4db0516043013b1e1ce8637dc92e3388ee3388ee3388ee3388ee3388e03")
|
||||
require.Equal(t, sa.value.Equal(expected), 1)
|
||||
}
|
||||
|
||||
func TestScalarEd25519Sqrt(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
nine := ed25519.Scalar.New(9)
|
||||
actual, err := nine.Sqrt()
|
||||
sa, _ := actual.(*ScalarEd25519)
|
||||
expected := toRSc("03")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sa.value.Equal(expected), 1)
|
||||
}
|
||||
|
||||
func TestScalarEd25519Add(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
nine := ed25519.Scalar.New(9)
|
||||
six := ed25519.Scalar.New(6)
|
||||
fifteen := nine.Add(six)
|
||||
require.NotNil(t, fifteen)
|
||||
expected := ed25519.Scalar.New(15)
|
||||
require.Equal(t, expected.Cmp(fifteen), 0)
|
||||
|
||||
upper := ed25519.Scalar.New(-3)
|
||||
actual := upper.Add(nine)
|
||||
require.NotNil(t, actual)
|
||||
require.Equal(t, actual.Cmp(six), 0)
|
||||
}
|
||||
|
||||
func TestScalarEd25519Sub(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
nine := ed25519.Scalar.New(9)
|
||||
six := ed25519.Scalar.New(6)
|
||||
expected := ed25519.Scalar.New(-3)
|
||||
|
||||
actual := six.Sub(nine)
|
||||
require.Equal(t, expected.Cmp(actual), 0)
|
||||
|
||||
actual = nine.Sub(six)
|
||||
require.Equal(t, actual.Cmp(ed25519.Scalar.New(3)), 0)
|
||||
}
|
||||
|
||||
func TestScalarEd25519Mul(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
nine := ed25519.Scalar.New(9)
|
||||
six := ed25519.Scalar.New(6)
|
||||
actual := nine.Mul(six)
|
||||
require.Equal(t, actual.Cmp(ed25519.Scalar.New(54)), 0)
|
||||
|
||||
upper := ed25519.Scalar.New(-1)
|
||||
require.Equal(t, upper.Mul(upper).Cmp(ed25519.Scalar.New(1)), 0)
|
||||
}
|
||||
|
||||
func TestScalarEd25519Div(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
nine := ed25519.Scalar.New(9)
|
||||
actual := nine.Div(nine)
|
||||
require.Equal(t, actual.Cmp(ed25519.Scalar.New(1)), 0)
|
||||
require.Equal(t, ed25519.Scalar.New(54).Div(nine).Cmp(ed25519.Scalar.New(6)), 0)
|
||||
}
|
||||
|
||||
func TestScalarEd25519Serialize(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
sc := ed25519.Scalar.New(255)
|
||||
sequence := sc.Bytes()
|
||||
require.Equal(t, len(sequence), 32)
|
||||
require.Equal(t, sequence, []byte{0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0})
|
||||
ret, err := ed25519.Scalar.SetBytes(sequence)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ret.Cmp(sc), 0)
|
||||
|
||||
// Try 10 random values
|
||||
for i := 0; i < 10; i++ {
|
||||
sc = ed25519.Scalar.Random(crand.Reader)
|
||||
sequence = sc.Bytes()
|
||||
require.Equal(t, len(sequence), 32)
|
||||
ret, err = ed25519.Scalar.SetBytes(sequence)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ret.Cmp(sc), 0)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScalarEd25519Nil(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
one := ed25519.Scalar.New(1)
|
||||
require.Nil(t, one.Add(nil))
|
||||
require.Nil(t, one.Sub(nil))
|
||||
require.Nil(t, one.Mul(nil))
|
||||
require.Nil(t, one.Div(nil))
|
||||
require.Nil(t, ed25519.Scalar.Random(nil))
|
||||
require.Equal(t, one.Cmp(nil), -2)
|
||||
_, err := ed25519.Scalar.SetBigInt(nil)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestPointEd25519Random(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
sc := ed25519.Point.Random(testRng())
|
||||
s, ok := sc.(*PointEd25519)
|
||||
require.True(t, ok)
|
||||
expected := toRPt("6011540c6231421a70ced5f577432531f198d318facfaad6e52cc42fba6e6fc5")
|
||||
require.True(t, s.Equal(&PointEd25519{expected}))
|
||||
// Try 25 random values
|
||||
for i := 0; i < 25; i++ {
|
||||
sc := ed25519.Point.Random(crand.Reader)
|
||||
_, ok := sc.(*PointEd25519)
|
||||
require.True(t, ok)
|
||||
require.True(t, !sc.IsIdentity())
|
||||
pBytes := sc.ToAffineCompressed()
|
||||
_, err := ed.NewIdentityPoint().SetBytes(pBytes)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPointEd25519Hash(t *testing.T) {
|
||||
var b [32]byte
|
||||
ed25519 := ED25519()
|
||||
sc := ed25519.Point.Hash(b[:])
|
||||
s, ok := sc.(*PointEd25519)
|
||||
require.True(t, ok)
|
||||
expected := toRPt("b4d75c3bb03ca644ab6c6d2a955c911003d8cfa719415de93a6b85eeb0c8dd97")
|
||||
require.True(t, s.Equal(&PointEd25519{expected}))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
_, _ = crand.Read(b[:])
|
||||
sc = ed25519.Point.Hash(b[:])
|
||||
require.NotNil(t, sc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPointEd25519Identity(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
sc := ed25519.Point.Identity()
|
||||
require.True(t, sc.IsIdentity())
|
||||
require.Equal(t, sc.ToAffineCompressed(), []byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
|
||||
}
|
||||
|
||||
func TestPointEd25519Generator(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
sc := ed25519.Point.Generator()
|
||||
s, ok := sc.(*PointEd25519)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, s.ToAffineCompressed(), []byte{0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66})
|
||||
}
|
||||
|
||||
func TestPointEd25519Set(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
iden, err := ed25519.Point.Set(big.NewInt(0), big.NewInt(0))
|
||||
require.NoError(t, err)
|
||||
require.True(t, iden.IsIdentity())
|
||||
xBytes, _ := hex.DecodeString("1ad5258f602d56c9b2a7259560c72c695cdcd6fd31e2a4c0fe536ecdd3366921")
|
||||
yBytes, _ := hex.DecodeString("5866666666666666666666666666666666666666666666666666666666666666")
|
||||
x := new(big.Int).SetBytes(internal.ReverseScalarBytes(xBytes))
|
||||
y := new(big.Int).SetBytes(internal.ReverseScalarBytes(yBytes))
|
||||
newPoint, err := ed25519.Point.Set(x, y)
|
||||
require.NoError(t, err)
|
||||
require.NotEqualf(t, iden, newPoint, "after setting valid x and y, the point should NOT be identity point")
|
||||
|
||||
emptyX := new(big.Int).SetBytes(internal.ReverseScalarBytes([]byte{}))
|
||||
identityPoint, err := ed25519.Point.Set(emptyX, y)
|
||||
require.NoError(t, err)
|
||||
require.Equalf(t, iden, identityPoint, "When x is empty, the point will be identity")
|
||||
}
|
||||
|
||||
func TestPointEd25519Double(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
g := ed25519.Point.Generator()
|
||||
g2 := g.Double()
|
||||
require.True(t, g2.Equal(g.Mul(ed25519.Scalar.New(2))))
|
||||
i := ed25519.Point.Identity()
|
||||
require.True(t, i.Double().Equal(i))
|
||||
}
|
||||
|
||||
func TestPointEd25519Neg(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
g := ed25519.Point.Generator().Neg()
|
||||
require.True(t, g.Neg().Equal(ed25519.Point.Generator()))
|
||||
require.True(t, ed25519.Point.Identity().Neg().Equal(ed25519.Point.Identity()))
|
||||
}
|
||||
|
||||
func TestPointEd25519Add(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
pt := ed25519.Point.Generator()
|
||||
require.True(t, pt.Add(pt).Equal(pt.Double()))
|
||||
require.True(t, pt.Mul(ed25519.Scalar.New(3)).Equal(pt.Add(pt).Add(pt)))
|
||||
}
|
||||
|
||||
func TestPointEd25519Sub(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
g := ed25519.Point.Generator()
|
||||
pt := ed25519.Point.Generator().Mul(ed25519.Scalar.New(4))
|
||||
require.True(t, pt.Sub(g).Sub(g).Sub(g).Equal(g))
|
||||
require.True(t, pt.Sub(g).Sub(g).Sub(g).Sub(g).IsIdentity())
|
||||
}
|
||||
|
||||
func TestPointEd25519Mul(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
g := ed25519.Point.Generator()
|
||||
pt := ed25519.Point.Generator().Mul(ed25519.Scalar.New(4))
|
||||
require.True(t, g.Double().Double().Equal(pt))
|
||||
}
|
||||
|
||||
func TestPointEd25519Serialize(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
ss := ed25519.Scalar.Random(testRng())
|
||||
g := ed25519.Point.Generator()
|
||||
|
||||
ppt := g.Mul(ss)
|
||||
expectedC := []byte{0x7f, 0x5b, 0xa, 0xd9, 0xb8, 0xce, 0xb7, 0x7, 0x4c, 0x10, 0xc8, 0xb4, 0x27, 0xe8, 0xd2, 0x28, 0x50, 0x42, 0x6c, 0x0, 0x8a, 0x3, 0x72, 0x2b, 0x7c, 0x3c, 0x37, 0x6f, 0xf8, 0x8f, 0x42, 0x5d}
|
||||
expectedU := []byte{0x70, 0xad, 0x4, 0xa1, 0x6, 0x8, 0x9f, 0x47, 0xe1, 0xe8, 0x9b, 0x9c, 0x81, 0x5a, 0xfb, 0xb9, 0x85, 0x6a, 0x2c, 0xa, 0xbc, 0xff, 0xe, 0xc6, 0xa0, 0xb0, 0xac, 0x75, 0xc, 0xd8, 0x59, 0x53, 0x7f, 0x5b, 0xa, 0xd9, 0xb8, 0xce, 0xb7, 0x7, 0x4c, 0x10, 0xc8, 0xb4, 0x27, 0xe8, 0xd2, 0x28, 0x50, 0x42, 0x6c, 0x0, 0x8a, 0x3, 0x72, 0x2b, 0x7c, 0x3c, 0x37, 0x6f, 0xf8, 0x8f, 0x42, 0x5d}
|
||||
require.Equal(t, ppt.ToAffineCompressed(), expectedC)
|
||||
require.Equal(t, ppt.ToAffineUncompressed(), expectedU)
|
||||
retP, err := ppt.FromAffineCompressed(ppt.ToAffineCompressed())
|
||||
require.NoError(t, err)
|
||||
require.True(t, ppt.Equal(retP))
|
||||
retP, err = ppt.FromAffineUncompressed(ppt.ToAffineUncompressed())
|
||||
require.NoError(t, err)
|
||||
require.True(t, ppt.Equal(retP))
|
||||
|
||||
// smoke test
|
||||
for i := 0; i < 25; i++ {
|
||||
s := ed25519.Scalar.Random(crand.Reader)
|
||||
pt := g.Mul(s)
|
||||
cmprs := pt.ToAffineCompressed()
|
||||
require.Equal(t, len(cmprs), 32)
|
||||
retC, err := pt.FromAffineCompressed(cmprs)
|
||||
require.NoError(t, err)
|
||||
require.True(t, pt.Equal(retC))
|
||||
|
||||
un := pt.ToAffineUncompressed()
|
||||
require.Equal(t, len(un), 64)
|
||||
retU, err := pt.FromAffineUncompressed(un)
|
||||
require.NoError(t, err)
|
||||
require.True(t, pt.Equal(retU))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPointEd25519Nil(t *testing.T) {
|
||||
ed25519 := ED25519()
|
||||
one := ed25519.Point.Generator()
|
||||
require.Nil(t, one.Add(nil))
|
||||
require.Nil(t, one.Sub(nil))
|
||||
require.Nil(t, one.Mul(nil))
|
||||
require.Nil(t, ed25519.Scalar.Random(nil))
|
||||
require.False(t, one.Equal(nil))
|
||||
_, err := ed25519.Scalar.SetBigInt(nil)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestPointEd25519SumOfProducts(t *testing.T) {
|
||||
lhs := new(PointEd25519).Generator().Mul(new(ScalarEd25519).New(50))
|
||||
points := make([]Point, 5)
|
||||
for i := range points {
|
||||
points[i] = new(PointEd25519).Generator()
|
||||
}
|
||||
scalars := []Scalar{
|
||||
new(ScalarEd25519).New(8),
|
||||
new(ScalarEd25519).New(9),
|
||||
new(ScalarEd25519).New(10),
|
||||
new(ScalarEd25519).New(11),
|
||||
new(ScalarEd25519).New(12),
|
||||
}
|
||||
rhs := lhs.SumOfProducts(points, scalars)
|
||||
require.NotNil(t, rhs)
|
||||
require.True(t, lhs.Equal(rhs))
|
||||
}
|
||||
|
||||
func TestPointEd25519VarTimeDoubleScalarBaseMult(t *testing.T) {
|
||||
curve := ED25519()
|
||||
h := curve.Point.Hash([]byte("TestPointEd25519VarTimeDoubleScalarBaseMult"))
|
||||
a := curve.Scalar.New(23)
|
||||
b := curve.Scalar.New(77)
|
||||
H, ok := h.(*PointEd25519)
|
||||
require.True(t, ok)
|
||||
rhs := H.VarTimeDoubleScalarBaseMult(a, H, b)
|
||||
lhs := h.Mul(a).Add(curve.Point.Generator().Mul(b))
|
||||
require.True(t, lhs.Equal(rhs))
|
||||
}
|
||||
|
||||
func toRSc(hx string) *ed.Scalar {
|
||||
e, _ := hex.DecodeString(hx)
|
||||
var data [32]byte
|
||||
copy(data[:], e)
|
||||
value, _ := new(ed.Scalar).SetCanonicalBytes(data[:])
|
||||
return value
|
||||
}
|
||||
|
||||
func toRPt(hx string) *ed.Point {
|
||||
e, _ := hex.DecodeString(hx)
|
||||
var data [32]byte
|
||||
copy(data[:], e)
|
||||
pt, _ := new(PointEd25519).FromAffineCompressed(data[:])
|
||||
return pt.(*PointEd25519).value
|
||||
}
|
@ -1,280 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
// Package curves: Field implementation IS NOT constant time as it leverages math/big for big number operations.
|
||||
package curves
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var ed25519SubGroupOrderOnce sync.Once
|
||||
var ed25519SubGroupOrder *big.Int
|
||||
|
||||
// Field is a finite field.
|
||||
type Field struct {
|
||||
*big.Int
|
||||
}
|
||||
|
||||
// Element is a group element within a finite field.
|
||||
type Element struct {
|
||||
Modulus *Field `json:"modulus"`
|
||||
Value *big.Int `json:"value"`
|
||||
}
|
||||
|
||||
// ElementJSON is used in JSON<>Element conversions.
|
||||
// For years, big.Int hasn't properly supported JSON unmarshaling
|
||||
// https://github.com/golang/go/issues/28154
|
||||
type ElementJSON struct {
|
||||
Modulus string `json:"modulus"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// Marshal Element to JSON
|
||||
func (x *Element) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(ElementJSON{
|
||||
Modulus: x.Modulus.String(),
|
||||
Value: x.Value.String(),
|
||||
})
|
||||
}
|
||||
|
||||
func (x *Element) UnmarshalJSON(bytes []byte) error {
|
||||
var e ElementJSON
|
||||
err := json.Unmarshal(bytes, &e)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Convert the strings to big.Ints
|
||||
modulus, ok := new(big.Int).SetString(e.Modulus, 10)
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to unmarshal modulus string '%v' to big.Int", e.Modulus)
|
||||
}
|
||||
x.Modulus = &Field{modulus}
|
||||
x.Value, ok = new(big.Int).SetString(e.Value, 10)
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to unmarshal value string '%v' to big.Int", e.Value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// The probability of returning true for a randomly chosen
|
||||
// non-prime is at most ¼ⁿ. 64 is a widely used standard
|
||||
// that is more than sufficient.
|
||||
const millerRabinRounds = 64
|
||||
|
||||
// New is a constructor for a Field.
|
||||
func NewField(modulus *big.Int) *Field {
|
||||
// For our purposes we never expect to be dealing with a non-prime field. This provides some protection against
|
||||
// accidentally doing that.
|
||||
if !modulus.ProbablyPrime(millerRabinRounds) {
|
||||
panic(fmt.Sprintf("modulus: %x is not a prime", modulus))
|
||||
}
|
||||
|
||||
return &Field{modulus}
|
||||
}
|
||||
|
||||
func newElement(field *Field, value *big.Int) *Element {
|
||||
if !field.IsValid(value) {
|
||||
panic(fmt.Sprintf("value: %x is not within field: %x", value, field))
|
||||
}
|
||||
|
||||
return &Element{field, value}
|
||||
}
|
||||
|
||||
// IsValid returns whether or not the value is within [0, modulus)
|
||||
func (f Field) IsValid(value *big.Int) bool {
|
||||
// value < modulus && value >= 0
|
||||
return value.Cmp(f.Int) < 0 && value.Sign() >= 0
|
||||
}
|
||||
|
||||
func (f Field) NewElement(value *big.Int) *Element {
|
||||
return newElement(&f, value)
|
||||
}
|
||||
|
||||
func (f Field) Zero() *Element {
|
||||
return newElement(&f, big.NewInt(0))
|
||||
}
|
||||
|
||||
func (f Field) One() *Element {
|
||||
return newElement(&f, big.NewInt(1))
|
||||
}
|
||||
|
||||
func (f Field) RandomElement(r io.Reader) (*Element, error) {
|
||||
if r == nil {
|
||||
r = rand.Reader
|
||||
}
|
||||
var randInt *big.Int
|
||||
var err error
|
||||
// Ed25519 needs to do special handling
|
||||
// in case the value is used in
|
||||
// Scalar multiplications with points
|
||||
if f.Int.Cmp(Ed25519Order()) == 0 {
|
||||
scalar := NewEd25519Scalar()
|
||||
randInt, err = scalar.RandomWithReader(r)
|
||||
} else {
|
||||
// Read a random integer within the field. This is defined as [0, max) so we don't need to
|
||||
// explicitly check it is within the field. If it is not, NewElement will panic anyways.
|
||||
randInt, err = rand.Int(r, f.Int)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newElement(&f, randInt), nil
|
||||
}
|
||||
|
||||
// ElementFromBytes initializes a new field element from big-endian bytes
|
||||
func (f Field) ElementFromBytes(bytes []byte) *Element {
|
||||
return newElement(&f, new(big.Int).SetBytes(bytes))
|
||||
}
|
||||
|
||||
// ReducedElementFromBytes initializes a new field element from big-endian bytes and reduces it by
|
||||
// the modulus of the field.
|
||||
//
|
||||
// WARNING: If this is used with cryptographic constructions which rely on a uniform distribution of
|
||||
// values, this may introduce a bias to the value of the returned field element. This happens when
|
||||
// the integer range of the provided bytes is not an integer multiple of the field order.
|
||||
//
|
||||
// Assume we are working in field which a modulus of 3 and the range of the uniform random bytes we
|
||||
// provide as input is 5. Thus, the set of field elements is {0, 1, 2} and the set of integer values
|
||||
// for the input bytes is: {0, 1, 2, 3, 4}. What is the distribution of the output values produced
|
||||
// by this function?
|
||||
//
|
||||
// ReducedElementFromBytes(0) => 0
|
||||
// ReducedElementFromBytes(1) => 1
|
||||
// ReducedElementFromBytes(2) => 2
|
||||
// ReducedElementFromBytes(3) => 0
|
||||
// ReducedElementFromBytes(4) => 1
|
||||
//
|
||||
// For a value space V and random value v, a uniform distribution is defined as P[V = v] = 1/|V|
|
||||
// where |V| is to the order of the field. Using the results from above, we see that P[v = 0] = 2/5,
|
||||
// P[v = 1] = 2/5, and P[v = 2] = 1/5. For a uniform distribution we would expect these to each be
|
||||
// equal to 1/3. As they do not, this does not return uniform output for that example.
|
||||
//
|
||||
// To see why this is okay if the range is a multiple of the field order, change the input range to
|
||||
// 6 and notice that now each output has a probability of 2/6 = 1/3, and the output is uniform.
|
||||
func (f Field) ReducedElementFromBytes(bytes []byte) *Element {
|
||||
value := new(big.Int).SetBytes(bytes)
|
||||
value.Mod(value, f.Int)
|
||||
return newElement(&f, value)
|
||||
}
|
||||
|
||||
func (x Element) Field() *Field {
|
||||
return x.Modulus
|
||||
}
|
||||
|
||||
// Add returns the sum x+y
|
||||
func (x Element) Add(y *Element) *Element {
|
||||
x.validateFields(y)
|
||||
|
||||
sum := new(big.Int).Add(x.Value, y.Value)
|
||||
sum.Mod(sum, x.Modulus.Int)
|
||||
return newElement(x.Modulus, sum)
|
||||
}
|
||||
|
||||
// Sub returns the difference x-y
|
||||
func (x Element) Sub(y *Element) *Element {
|
||||
x.validateFields(y)
|
||||
|
||||
difference := new(big.Int).Sub(x.Value, y.Value)
|
||||
difference.Mod(difference, x.Modulus.Int)
|
||||
return newElement(x.Modulus, difference)
|
||||
}
|
||||
|
||||
// Neg returns the field negation
|
||||
func (x Element) Neg() *Element {
|
||||
z := new(big.Int).Neg(x.Value)
|
||||
z.Mod(z, x.Modulus.Int)
|
||||
return newElement(x.Modulus, z)
|
||||
}
|
||||
|
||||
// Mul returns the product x*y
|
||||
func (x Element) Mul(y *Element) *Element {
|
||||
x.validateFields(y)
|
||||
|
||||
product := new(big.Int).Mul(x.Value, y.Value)
|
||||
product.Mod(product, x.Modulus.Int)
|
||||
return newElement(x.Modulus, product)
|
||||
}
|
||||
|
||||
// Div returns the quotient x/y
|
||||
func (x Element) Div(y *Element) *Element {
|
||||
x.validateFields(y)
|
||||
|
||||
yInv := new(big.Int).ModInverse(y.Value, x.Modulus.Int)
|
||||
quotient := new(big.Int).Mul(x.Value, yInv)
|
||||
quotient.Mod(quotient, x.Modulus.Int)
|
||||
return newElement(x.Modulus, quotient)
|
||||
}
|
||||
|
||||
// Pow computes x^y reduced by the modulus
|
||||
func (x Element) Pow(y *Element) *Element {
|
||||
x.validateFields(y)
|
||||
|
||||
return newElement(x.Modulus, new(big.Int).Exp(x.Value, y.Value, x.Modulus.Int))
|
||||
}
|
||||
|
||||
func (x Element) Invert() *Element {
|
||||
return newElement(x.Modulus, new(big.Int).ModInverse(x.Value, x.Modulus.Int))
|
||||
}
|
||||
|
||||
func (x Element) Sqrt() *Element {
|
||||
return newElement(x.Modulus, new(big.Int).ModSqrt(x.Value, x.Modulus.Int))
|
||||
}
|
||||
|
||||
// BigInt returns value as a big.Int
|
||||
func (x Element) BigInt() *big.Int {
|
||||
return x.Value
|
||||
}
|
||||
|
||||
// Bytes returns the value as bytes
|
||||
func (x Element) Bytes() []byte {
|
||||
return x.BigInt().Bytes()
|
||||
}
|
||||
|
||||
// IsEqual returns x == y
|
||||
func (x Element) IsEqual(y *Element) bool {
|
||||
if !x.isEqualFields(y) {
|
||||
return false
|
||||
}
|
||||
|
||||
return x.Value.Cmp(y.Value) == 0
|
||||
}
|
||||
|
||||
// Clone returns a new copy of the element
|
||||
func (x Element) Clone() *Element {
|
||||
return x.Modulus.ElementFromBytes(x.Bytes())
|
||||
}
|
||||
|
||||
func (x Element) isEqualFields(y *Element) bool {
|
||||
return x.Modulus.Int.Cmp(y.Modulus.Int) == 0
|
||||
}
|
||||
|
||||
func (x Element) validateFields(y *Element) {
|
||||
if !x.isEqualFields(y) {
|
||||
panic("fields must match for valid binary operation")
|
||||
}
|
||||
}
|
||||
|
||||
// SubgroupOrder returns the order of the Ed25519 base Point.
|
||||
func Ed25519Order() *big.Int {
|
||||
ed25519SubGroupOrderOnce.Do(func() {
|
||||
order, ok := new(big.Int).SetString(
|
||||
"1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED",
|
||||
16,
|
||||
)
|
||||
if !ok {
|
||||
panic("invalid hex string provided. This should never happen as it is constant.")
|
||||
}
|
||||
ed25519SubGroupOrder = order
|
||||
})
|
||||
|
||||
return ed25519SubGroupOrder
|
||||
}
|
@ -1,301 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package curves
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
one = big.NewInt(1)
|
||||
modulus, modulusOk = new(big.Int).SetString(
|
||||
"1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED",
|
||||
16,
|
||||
)
|
||||
oneBelowModulus = zero().Sub(modulus, one)
|
||||
oneAboveModulus = zero().Add(modulus, one)
|
||||
field25519 = NewField(modulus)
|
||||
)
|
||||
|
||||
type buggedReader struct{}
|
||||
|
||||
func (r buggedReader) Read(p []byte) (n int, err error) {
|
||||
return 0, errors.New("EOF")
|
||||
}
|
||||
|
||||
func zero() *big.Int {
|
||||
return new(big.Int)
|
||||
}
|
||||
|
||||
func assertElementZero(t *testing.T, e *Element) {
|
||||
require.Equal(t, zero().Bytes(), e.Bytes())
|
||||
}
|
||||
|
||||
type binaryOperation func(*Element) *Element
|
||||
|
||||
func assertUnequalFieldsPanic(t *testing.T, b binaryOperation) {
|
||||
altField := NewField(big.NewInt(23))
|
||||
altElement := altField.NewElement(one)
|
||||
|
||||
require.PanicsWithValue(
|
||||
t,
|
||||
"fields must match for valid binary operation",
|
||||
func() { b(altElement) },
|
||||
)
|
||||
}
|
||||
|
||||
func TestFieldModulus(t *testing.T) {
|
||||
require.True(t, modulusOk)
|
||||
}
|
||||
|
||||
func TestNewField(t *testing.T) {
|
||||
require.PanicsWithValue(
|
||||
t,
|
||||
fmt.Sprintf("modulus: %x is not a prime", oneBelowModulus),
|
||||
func() { NewField(oneBelowModulus) },
|
||||
)
|
||||
require.NotPanics(
|
||||
t,
|
||||
func() { NewField(modulus) },
|
||||
)
|
||||
}
|
||||
|
||||
func TestNewElement(t *testing.T) {
|
||||
require.PanicsWithValue(
|
||||
t,
|
||||
fmt.Sprintf("value: %x is not within field: %x", modulus, field25519.Int),
|
||||
func() { newElement(field25519, modulus) },
|
||||
)
|
||||
require.NotPanics(
|
||||
t,
|
||||
func() { newElement(field25519, oneBelowModulus) },
|
||||
)
|
||||
}
|
||||
|
||||
func TestElementIsValid(t *testing.T) {
|
||||
require.False(t, field25519.IsValid(zero().Neg(one)))
|
||||
require.False(t, field25519.IsValid(modulus))
|
||||
require.False(t, field25519.IsValid(oneAboveModulus))
|
||||
require.True(t, field25519.IsValid(oneBelowModulus))
|
||||
}
|
||||
|
||||
func TestFieldNewElement(t *testing.T) {
|
||||
element := field25519.NewElement(oneBelowModulus)
|
||||
|
||||
require.Equal(t, oneBelowModulus, element.Value)
|
||||
require.Equal(t, field25519, element.Field())
|
||||
}
|
||||
|
||||
func TestZeroElement(t *testing.T) {
|
||||
require.Equal(t, zero(), field25519.Zero().Value)
|
||||
require.Equal(t, field25519, field25519.Zero().Field())
|
||||
}
|
||||
|
||||
func TestOneElement(t *testing.T) {
|
||||
require.Equal(t, field25519.One().Value, one)
|
||||
require.Equal(t, field25519.One().Field(), field25519)
|
||||
}
|
||||
|
||||
func TestRandomElement(t *testing.T) {
|
||||
randomElement1, err := field25519.RandomElement(nil)
|
||||
require.NoError(t, err)
|
||||
randomElement2, err := field25519.RandomElement(nil)
|
||||
require.NoError(t, err)
|
||||
randomElement3, err := field25519.RandomElement(new(buggedReader))
|
||||
require.Error(t, err)
|
||||
|
||||
require.Equal(t, field25519, randomElement1.Field())
|
||||
require.Equal(t, field25519, randomElement2.Field())
|
||||
require.NotEqual(t, randomElement1.Value, randomElement2.Value)
|
||||
require.Nil(t, randomElement3)
|
||||
}
|
||||
|
||||
func TestElementFromBytes(t *testing.T) {
|
||||
element := field25519.ElementFromBytes(oneBelowModulus.Bytes())
|
||||
|
||||
require.Equal(t, field25519, element.Field())
|
||||
require.Equal(t, oneBelowModulus, element.Value)
|
||||
}
|
||||
|
||||
func TestReducedElementFromBytes(t *testing.T) {
|
||||
element := field25519.ReducedElementFromBytes(oneBelowModulus.Bytes())
|
||||
|
||||
require.Equal(t, field25519, element.Field())
|
||||
require.Equal(t, oneBelowModulus, element.Value)
|
||||
|
||||
element = field25519.ReducedElementFromBytes(oneAboveModulus.Bytes())
|
||||
|
||||
require.Equal(t, field25519, element.Field())
|
||||
require.Equal(t, one, element.Value)
|
||||
}
|
||||
|
||||
func TestAddElement(t *testing.T) {
|
||||
element1 := field25519.NewElement(one)
|
||||
element2 := field25519.NewElement(big.NewInt(2))
|
||||
element3 := field25519.NewElement(oneBelowModulus)
|
||||
element4 := &Element{field25519, modulus}
|
||||
|
||||
require.Equal(t, element2, element1.Add(element1))
|
||||
require.Equal(t, big.NewInt(3), element1.Add(element2).Value)
|
||||
require.Equal(t, big.NewInt(3), element2.Add(element1).Value)
|
||||
require.Equal(t, one, element1.Add(element4).Value)
|
||||
require.Equal(t, one, element3.Add(element2).Value)
|
||||
assertElementZero(t, element1.Add(element3))
|
||||
assertUnequalFieldsPanic(t, element1.Add)
|
||||
}
|
||||
|
||||
func TestSubElement(t *testing.T) {
|
||||
element1 := field25519.NewElement(one)
|
||||
element2 := field25519.NewElement(big.NewInt(2))
|
||||
element3 := field25519.NewElement(oneBelowModulus)
|
||||
element4 := &Element{field25519, modulus}
|
||||
|
||||
assertElementZero(t, element1.Sub(element1))
|
||||
require.Equal(t, element3, element1.Sub(element2))
|
||||
require.Equal(t, element1, element2.Sub(element1))
|
||||
require.Equal(t, element1, element1.Sub(element4))
|
||||
require.Equal(t, element3, element4.Sub(element1))
|
||||
require.Equal(t, element1, element4.Sub(element3))
|
||||
require.Equal(t, element3, element3.Sub(element4))
|
||||
assertUnequalFieldsPanic(t, element1.Sub)
|
||||
}
|
||||
|
||||
func TestMulElement(t *testing.T) {
|
||||
element1 := field25519.NewElement(one)
|
||||
element2 := field25519.NewElement(big.NewInt(2))
|
||||
element3 := field25519.NewElement(oneBelowModulus)
|
||||
element4 := field25519.NewElement(zero())
|
||||
expectedProduct, ok := new(big.Int).SetString(
|
||||
"1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3eb",
|
||||
16,
|
||||
)
|
||||
require.True(t, ok)
|
||||
|
||||
assertElementZero(t, element1.Mul(element4))
|
||||
assertElementZero(t, element4.Mul(element1))
|
||||
require.Equal(t, element3, element1.Mul(element3))
|
||||
require.Equal(t, element3, element3.Mul(element1))
|
||||
require.Equal(t, expectedProduct, element3.Mul(element2).Value)
|
||||
require.Equal(t, expectedProduct, element2.Mul(element3).Value)
|
||||
assertUnequalFieldsPanic(t, element1.Mul)
|
||||
}
|
||||
|
||||
func TestDivElement(t *testing.T) {
|
||||
element1 := field25519.NewElement(one)
|
||||
element2 := field25519.NewElement(big.NewInt(2))
|
||||
element3 := field25519.NewElement(oneBelowModulus)
|
||||
element4 := field25519.NewElement(zero())
|
||||
expectedQuotient1, ok := new(big.Int).SetString(
|
||||
"80000000000000000000000000000000a6f7cef517bce6b2c09318d2e7ae9f6",
|
||||
16,
|
||||
)
|
||||
require.True(t, ok)
|
||||
expectedQuotient2, ok := new(big.Int).SetString(
|
||||
"1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3eb",
|
||||
16,
|
||||
)
|
||||
require.True(t, ok)
|
||||
|
||||
assertElementZero(t, element4.Div(element3))
|
||||
require.Equal(t, element3, element3.Div(element1))
|
||||
require.Equal(t, expectedQuotient1, element3.Div(element2).Value)
|
||||
require.Equal(t, expectedQuotient2, element2.Div(element3).Value)
|
||||
require.Panics(t, func() { element3.Div(element4) })
|
||||
assertUnequalFieldsPanic(t, element1.Div)
|
||||
}
|
||||
|
||||
func TestIsEqualElement(t *testing.T) {
|
||||
element1 := field25519.NewElement(oneBelowModulus)
|
||||
element2 := field25519.NewElement(big.NewInt(23))
|
||||
element3 := field25519.NewElement(oneBelowModulus)
|
||||
altField := NewField(big.NewInt(23))
|
||||
altElement1 := altField.NewElement(one)
|
||||
|
||||
require.False(t, element1.IsEqual(element2))
|
||||
require.True(t, element1.IsEqual(element3))
|
||||
require.True(t, element1.IsEqual(element1))
|
||||
require.False(t, element1.IsEqual(altElement1))
|
||||
}
|
||||
|
||||
func TestBigIntElement(t *testing.T) {
|
||||
element := field25519.NewElement(oneBelowModulus)
|
||||
|
||||
require.Equal(t, oneBelowModulus, element.BigInt())
|
||||
}
|
||||
|
||||
func TestBytesElement(t *testing.T) {
|
||||
element := field25519.NewElement(oneBelowModulus)
|
||||
|
||||
require.Equal(
|
||||
t,
|
||||
[]byte{
|
||||
0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0xde, 0xf9, 0xde, 0xa2,
|
||||
0xf7, 0x9c, 0xd6, 0x58, 0x12, 0x63, 0x1a, 0x5c, 0xf5,
|
||||
0xd3, 0xec,
|
||||
},
|
||||
element.Bytes(),
|
||||
)
|
||||
}
|
||||
|
||||
func TestCloneElement(t *testing.T) {
|
||||
element := field25519.NewElement(oneBelowModulus)
|
||||
clone := element.Clone()
|
||||
|
||||
require.Equal(t, clone, element)
|
||||
|
||||
clone.Value.Add(one, one)
|
||||
|
||||
require.NotEqual(t, clone, element)
|
||||
}
|
||||
|
||||
// Tests un/marshaling Element
|
||||
func TestElementMarshalJsonRoundTrip(t *testing.T) {
|
||||
reallyBigInt1, ok := new(big.Int).SetString("12365234878725472538962348629568356835892346729834725643857832", 10)
|
||||
require.True(t, ok)
|
||||
|
||||
reallyBigInt2, ok := new(big.Int).SetString("123652348787DEF9DEA2F79CD65812631A5CF5D3ED46729834725643857832", 16)
|
||||
require.True(t, ok)
|
||||
|
||||
ins := []*Element{
|
||||
newElement(field25519, big.NewInt(300)),
|
||||
newElement(field25519, big.NewInt(300000)),
|
||||
newElement(field25519, big.NewInt(12812798)),
|
||||
newElement(field25519, big.NewInt(17)),
|
||||
newElement(field25519, big.NewInt(5066680)),
|
||||
newElement(field25519, big.NewInt(3005)),
|
||||
newElement(field25519, big.NewInt(317)),
|
||||
newElement(field25519, big.NewInt(323)),
|
||||
newElement(field25519, reallyBigInt1),
|
||||
newElement(field25519, reallyBigInt2),
|
||||
newElement(field25519, oneBelowModulus),
|
||||
}
|
||||
|
||||
// Run all the tests!
|
||||
for _, in := range ins {
|
||||
bytes, err := json.Marshal(in)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, bytes)
|
||||
|
||||
// Unmarshal and test
|
||||
out := &Element{}
|
||||
err = json.Unmarshal(bytes, &out)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, out)
|
||||
require.NotNil(t, out.Modulus)
|
||||
require.NotNil(t, out.Value)
|
||||
|
||||
require.Equal(t, in.Modulus.Bytes(), out.Modulus.Bytes())
|
||||
require.Equal(t, in.Value.Bytes(), out.Value.Bytes())
|
||||
}
|
||||
}
|
@ -1,446 +0,0 @@
|
||||
package curves
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"crypto/sha256"
|
||||
"io"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
|
||||
mod "github.com/onsonr/hway/crypto/core"
|
||||
"github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
func BenchmarkK256(b *testing.B) {
|
||||
// 1000 points
|
||||
b.Run("1000 point add - btcec", func(b *testing.B) {
|
||||
b.StopTimer()
|
||||
points := make([]*BenchPoint, 1000)
|
||||
for i := range points {
|
||||
points[i] = points[i].Random(crand.Reader).(*BenchPoint)
|
||||
}
|
||||
acc := new(BenchPoint).Identity()
|
||||
b.StartTimer()
|
||||
for _, pt := range points {
|
||||
acc = acc.Add(pt)
|
||||
}
|
||||
})
|
||||
b.Run("1000 point add - ct k256", func(b *testing.B) {
|
||||
b.StopTimer()
|
||||
curve := K256()
|
||||
points := make([]*PointK256, 1000)
|
||||
for i := range points {
|
||||
points[i] = curve.NewIdentityPoint().Random(crand.Reader).(*PointK256)
|
||||
}
|
||||
acc := curve.NewIdentityPoint()
|
||||
b.StartTimer()
|
||||
for _, pt := range points {
|
||||
acc = acc.Add(pt)
|
||||
}
|
||||
})
|
||||
b.Run("1000 point double - btcec", func(b *testing.B) {
|
||||
b.StopTimer()
|
||||
acc := new(BenchPoint).Generator()
|
||||
b.StartTimer()
|
||||
for i := 0; i < 1000; i++ {
|
||||
acc = acc.Double()
|
||||
}
|
||||
})
|
||||
b.Run("1000 point double - ct k256", func(b *testing.B) {
|
||||
b.StopTimer()
|
||||
acc := new(PointK256).Generator()
|
||||
b.StartTimer()
|
||||
for i := 0; i < 1000; i++ {
|
||||
acc = acc.Double()
|
||||
}
|
||||
})
|
||||
b.Run("1000 point multiply - btcec", func(b *testing.B) {
|
||||
b.StopTimer()
|
||||
scalars := make([]*BenchScalar, 1000)
|
||||
for i := range scalars {
|
||||
s := new(BenchScalar).Random(crand.Reader)
|
||||
scalars[i] = s.(*BenchScalar)
|
||||
}
|
||||
acc := new(BenchPoint).Generator().Mul(new(BenchScalar).New(2))
|
||||
b.StartTimer()
|
||||
for _, sc := range scalars {
|
||||
acc = acc.Mul(sc)
|
||||
}
|
||||
})
|
||||
b.Run("1000 point multiply - ct k256", func(b *testing.B) {
|
||||
b.StopTimer()
|
||||
scalars := make([]*ScalarK256, 1000)
|
||||
for i := range scalars {
|
||||
s := new(ScalarK256).Random(crand.Reader)
|
||||
scalars[i] = s.(*ScalarK256)
|
||||
}
|
||||
acc := new(PointK256).Generator()
|
||||
b.StartTimer()
|
||||
for _, sc := range scalars {
|
||||
acc = acc.Mul(sc)
|
||||
}
|
||||
})
|
||||
b.Run("1000 scalar invert - btcec", func(b *testing.B) {
|
||||
b.StopTimer()
|
||||
scalars := make([]*BenchScalar, 1000)
|
||||
for i := range scalars {
|
||||
s := new(BenchScalar).Random(crand.Reader)
|
||||
scalars[i] = s.(*BenchScalar)
|
||||
}
|
||||
b.StartTimer()
|
||||
for _, sc := range scalars {
|
||||
_, _ = sc.Invert()
|
||||
}
|
||||
})
|
||||
b.Run("1000 scalar invert - ct k256", func(b *testing.B) {
|
||||
b.StopTimer()
|
||||
scalars := make([]*ScalarK256, 1000)
|
||||
for i := range scalars {
|
||||
s := new(ScalarK256).Random(crand.Reader)
|
||||
scalars[i] = s.(*ScalarK256)
|
||||
}
|
||||
b.StartTimer()
|
||||
for _, sc := range scalars {
|
||||
_, _ = sc.Invert()
|
||||
}
|
||||
})
|
||||
b.Run("1000 scalar sqrt - btcec", func(b *testing.B) {
|
||||
b.StopTimer()
|
||||
scalars := make([]*BenchScalar, 1000)
|
||||
for i := range scalars {
|
||||
s := new(BenchScalar).Random(crand.Reader)
|
||||
scalars[i] = s.(*BenchScalar)
|
||||
}
|
||||
b.StartTimer()
|
||||
for _, sc := range scalars {
|
||||
_, _ = sc.Sqrt()
|
||||
}
|
||||
})
|
||||
b.Run("1000 scalar sqrt - ct k256", func(b *testing.B) {
|
||||
b.StopTimer()
|
||||
scalars := make([]*ScalarK256, 1000)
|
||||
for i := range scalars {
|
||||
s := new(ScalarK256).Random(crand.Reader)
|
||||
scalars[i] = s.(*ScalarK256)
|
||||
}
|
||||
b.StartTimer()
|
||||
for _, sc := range scalars {
|
||||
_, _ = sc.Sqrt()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type BenchScalar struct {
|
||||
value *big.Int
|
||||
}
|
||||
|
||||
func (s *BenchScalar) Random(reader io.Reader) Scalar {
|
||||
var v [32]byte
|
||||
_, _ = reader.Read(v[:])
|
||||
value := new(big.Int).SetBytes(v[:])
|
||||
return &BenchScalar{
|
||||
value: value.Mod(value, btcec.S256().N),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BenchScalar) Hash(bytes []byte) Scalar {
|
||||
h := sha256.Sum256(bytes)
|
||||
value := new(big.Int).SetBytes(h[:])
|
||||
return &BenchScalar{
|
||||
value: value.Mod(value, btcec.S256().N),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BenchScalar) Zero() Scalar {
|
||||
return &BenchScalar{
|
||||
value: big.NewInt(0),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BenchScalar) One() Scalar {
|
||||
return &BenchScalar{
|
||||
value: big.NewInt(1),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BenchScalar) IsZero() bool {
|
||||
return s.value.Cmp(big.NewInt(0)) == 0
|
||||
}
|
||||
|
||||
func (s *BenchScalar) IsOne() bool {
|
||||
return s.value.Cmp(big.NewInt(1)) == 0
|
||||
}
|
||||
|
||||
func (s *BenchScalar) IsOdd() bool {
|
||||
return s.value.Bit(0) == 1
|
||||
}
|
||||
|
||||
func (s *BenchScalar) IsEven() bool {
|
||||
return s.value.Bit(0) == 0
|
||||
}
|
||||
|
||||
func (s *BenchScalar) New(value int) Scalar {
|
||||
v := big.NewInt(int64(value))
|
||||
return &BenchScalar{
|
||||
value: v.Mod(v, btcec.S256().N),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BenchScalar) Cmp(rhs Scalar) int {
|
||||
r := rhs.(*BenchScalar)
|
||||
return s.value.Cmp(r.value)
|
||||
}
|
||||
|
||||
func (s *BenchScalar) Square() Scalar {
|
||||
v := new(big.Int).Mul(s.value, s.value)
|
||||
return &BenchScalar{
|
||||
value: v.Mod(v, btcec.S256().N),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BenchScalar) Double() Scalar {
|
||||
v := new(big.Int).Add(s.value, s.value)
|
||||
return &BenchScalar{
|
||||
value: v.Mod(v, btcec.S256().N),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BenchScalar) Invert() (Scalar, error) {
|
||||
return &BenchScalar{
|
||||
value: new(big.Int).ModInverse(s.value, btcec.S256().N),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *BenchScalar) Sqrt() (Scalar, error) {
|
||||
return &BenchScalar{
|
||||
value: new(big.Int).ModSqrt(s.value, btcec.S256().N),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *BenchScalar) Cube() Scalar {
|
||||
v := new(big.Int).Mul(s.value, s.value)
|
||||
v.Mul(v, s.value)
|
||||
return &BenchScalar{
|
||||
value: v.Mod(v, btcec.S256().N),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BenchScalar) Add(rhs Scalar) Scalar {
|
||||
r := rhs.(*BenchScalar)
|
||||
v := new(big.Int).Add(s.value, r.value)
|
||||
return &BenchScalar{
|
||||
value: v.Mod(v, btcec.S256().N),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BenchScalar) Sub(rhs Scalar) Scalar {
|
||||
r := rhs.(*BenchScalar)
|
||||
v := new(big.Int).Sub(s.value, r.value)
|
||||
return &BenchScalar{
|
||||
value: v.Mod(v, btcec.S256().N),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BenchScalar) Mul(rhs Scalar) Scalar {
|
||||
r := rhs.(*BenchScalar)
|
||||
v := new(big.Int).Mul(s.value, r.value)
|
||||
return &BenchScalar{
|
||||
value: v.Mod(v, btcec.S256().N),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BenchScalar) MulAdd(y, z Scalar) Scalar {
|
||||
yy := y.(*BenchScalar)
|
||||
zz := z.(*BenchScalar)
|
||||
v := new(big.Int).Mul(s.value, yy.value)
|
||||
v.Add(v, zz.value)
|
||||
return &BenchScalar{
|
||||
value: v.Mod(v, btcec.S256().N),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BenchScalar) Div(rhs Scalar) Scalar {
|
||||
r := rhs.(*BenchScalar)
|
||||
v := new(big.Int).ModInverse(r.value, btcec.S256().N)
|
||||
v.Mul(v, s.value)
|
||||
return &BenchScalar{
|
||||
value: v.Mod(v, btcec.S256().N),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BenchScalar) Neg() Scalar {
|
||||
v, _ := mod.Neg(s.value, btcec.S256().N)
|
||||
return &BenchScalar{
|
||||
value: v,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BenchScalar) SetBigInt(v *big.Int) (Scalar, error) {
|
||||
return &BenchScalar{
|
||||
value: new(big.Int).Set(v),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *BenchScalar) BigInt() *big.Int {
|
||||
return new(big.Int).Set(s.value)
|
||||
}
|
||||
|
||||
func (s *BenchScalar) Point() Point {
|
||||
return (&BenchPoint{}).Identity()
|
||||
}
|
||||
|
||||
func (s *BenchScalar) Bytes() []byte {
|
||||
return internal.ReverseScalarBytes(s.value.Bytes())
|
||||
}
|
||||
|
||||
func (s *BenchScalar) SetBytes(bytes []byte) (Scalar, error) {
|
||||
value := new(big.Int).SetBytes(internal.ReverseScalarBytes(bytes))
|
||||
value.Mod(value, btcec.S256().N)
|
||||
return &BenchScalar{
|
||||
value,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *BenchScalar) SetBytesWide(bytes []byte) (Scalar, error) {
|
||||
value := new(big.Int).SetBytes(internal.ReverseScalarBytes(bytes))
|
||||
value.Mod(value, btcec.S256().N)
|
||||
return &BenchScalar{
|
||||
value,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *BenchScalar) Clone() Scalar {
|
||||
return &BenchScalar{
|
||||
value: new(big.Int).Set(s.value),
|
||||
}
|
||||
}
|
||||
|
||||
type BenchPoint struct {
|
||||
x, y *big.Int
|
||||
}
|
||||
|
||||
func (p *BenchPoint) Random(reader io.Reader) Point {
|
||||
var k [32]byte
|
||||
curve := btcec.S256()
|
||||
_, _ = reader.Read(k[:])
|
||||
x, y := curve.ScalarBaseMult(k[:])
|
||||
for !curve.IsOnCurve(x, y) {
|
||||
_, _ = reader.Read(k[:])
|
||||
x, y = curve.ScalarBaseMult(k[:])
|
||||
}
|
||||
return &BenchPoint{x, y}
|
||||
}
|
||||
|
||||
func (p *BenchPoint) Hash(bytes []byte) Point {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *BenchPoint) Identity() Point {
|
||||
return &BenchPoint{x: big.NewInt(0), y: big.NewInt(0)}
|
||||
}
|
||||
|
||||
func (p *BenchPoint) Generator() Point {
|
||||
return &BenchPoint{
|
||||
x: new(big.Int).Set(btcec.S256().Gx),
|
||||
y: new(big.Int).Set(btcec.S256().Gy),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *BenchPoint) IsIdentity() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *BenchPoint) IsNegative() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *BenchPoint) IsOnCurve() bool {
|
||||
return btcec.S256().IsOnCurve(p.x, p.y)
|
||||
}
|
||||
|
||||
func (p *BenchPoint) Double() Point {
|
||||
x, y := btcec.S256().Double(p.x, p.y)
|
||||
return &BenchPoint{
|
||||
x, y,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *BenchPoint) Scalar() Scalar {
|
||||
return &BenchScalar{value: big.NewInt(0)}
|
||||
}
|
||||
|
||||
func (p *BenchPoint) Neg() Point {
|
||||
y, _ := mod.Neg(p.y, btcec.S256().P)
|
||||
return &BenchPoint{
|
||||
x: new(big.Int).Set(p.x), y: y,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *BenchPoint) Add(rhs Point) Point {
|
||||
r := rhs.(*BenchPoint)
|
||||
x, y := btcec.S256().Add(p.x, p.y, r.x, r.y)
|
||||
return &BenchPoint{
|
||||
x, y,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *BenchPoint) Sub(rhs Point) Point {
|
||||
t := rhs.Neg().(*BenchPoint)
|
||||
return t.Add(p)
|
||||
}
|
||||
|
||||
func (p *BenchPoint) Mul(rhs Scalar) Point {
|
||||
k := rhs.Bytes()
|
||||
x, y := btcec.S256().ScalarMult(p.x, p.y, k)
|
||||
return &BenchPoint{
|
||||
x, y,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *BenchPoint) Equal(rhs Point) bool {
|
||||
r := rhs.(*BenchPoint)
|
||||
return p.x.Cmp(r.x) == 0 && p.y.Cmp(r.y) == 0
|
||||
}
|
||||
|
||||
func (p *BenchPoint) Set(x, y *big.Int) (Point, error) {
|
||||
return &BenchPoint{
|
||||
x, y,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *BenchPoint) ToAffineCompressed() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *BenchPoint) ToAffineUncompressed() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *BenchPoint) FromAffineCompressed(bytes []byte) (Point, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (p *BenchPoint) FromAffineUncompressed(bytes []byte) (Point, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (p *BenchPoint) CurveName() string {
|
||||
return btcec.S256().Name
|
||||
}
|
||||
|
||||
func (p *BenchPoint) SumOfProducts(points []Point, scalars []Scalar) Point {
|
||||
biScalars := make([]*big.Int, len(scalars))
|
||||
for i := 0; i < len(scalars); i++ {
|
||||
biScalars[i] = scalars[i].BigInt()
|
||||
}
|
||||
return sumOfProductsPippenger(points, biScalars)
|
||||
}
|
||||
|
||||
//func rhsK256(x *big.Int) *big.Int {
|
||||
// // y^2 = x^3 + B
|
||||
// x3, _ := mod.Exp(x, big.NewInt(3), btcec.S256().P)
|
||||
// x3.Add(x3, btcec.S256().B)
|
||||
// return x3.ModSqrt(x3, btcec.S256().P)
|
||||
//}
|
@ -1,670 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package curves
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"sync"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
secp256k1 "github.com/onsonr/hway/crypto/core/curves/native/k256"
|
||||
"github.com/onsonr/hway/crypto/core/curves/native/k256/fp"
|
||||
"github.com/onsonr/hway/crypto/core/curves/native/k256/fq"
|
||||
"github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
var (
|
||||
oldK256Initonce sync.Once
|
||||
oldK256 Koblitz256
|
||||
)
|
||||
|
||||
type Koblitz256 struct {
|
||||
*elliptic.CurveParams
|
||||
}
|
||||
|
||||
func oldK256InitAll() {
|
||||
curve := btcec.S256()
|
||||
oldK256.CurveParams = new(elliptic.CurveParams)
|
||||
oldK256.P = curve.P
|
||||
oldK256.N = curve.N
|
||||
oldK256.Gx = curve.Gx
|
||||
oldK256.Gy = curve.Gy
|
||||
oldK256.B = curve.B
|
||||
oldK256.BitSize = curve.BitSize
|
||||
oldK256.Name = K256Name
|
||||
}
|
||||
|
||||
func K256Curve() *Koblitz256 {
|
||||
oldK256Initonce.Do(oldK256InitAll)
|
||||
return &oldK256
|
||||
}
|
||||
|
||||
func (curve *Koblitz256) Params() *elliptic.CurveParams {
|
||||
return curve.CurveParams
|
||||
}
|
||||
|
||||
func (curve *Koblitz256) IsOnCurve(x, y *big.Int) bool {
|
||||
_, err := secp256k1.K256PointNew().SetBigInt(x, y)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (curve *Koblitz256) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
|
||||
p1, err := secp256k1.K256PointNew().SetBigInt(x1, y1)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
p2, err := secp256k1.K256PointNew().SetBigInt(x2, y2)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
return p1.Add(p1, p2).BigInt()
|
||||
}
|
||||
|
||||
func (curve *Koblitz256) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
|
||||
p1, err := secp256k1.K256PointNew().SetBigInt(x1, y1)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
return p1.Double(p1).BigInt()
|
||||
}
|
||||
|
||||
func (curve *Koblitz256) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
|
||||
p1, err := secp256k1.K256PointNew().SetBigInt(Bx, By)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
var bytes [32]byte
|
||||
copy(bytes[:], internal.ReverseScalarBytes(k))
|
||||
s, err := fq.K256FqNew().SetBytes(&bytes)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
return p1.Mul(p1, s).BigInt()
|
||||
}
|
||||
|
||||
func (curve *Koblitz256) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
|
||||
var bytes [32]byte
|
||||
copy(bytes[:], internal.ReverseScalarBytes(k))
|
||||
s, err := fq.K256FqNew().SetBytes(&bytes)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
p1 := secp256k1.K256PointNew().Generator()
|
||||
return p1.Mul(p1, s).BigInt()
|
||||
}
|
||||
|
||||
type ScalarK256 struct {
|
||||
value *native.Field
|
||||
}
|
||||
|
||||
type PointK256 struct {
|
||||
value *native.EllipticPoint
|
||||
}
|
||||
|
||||
func (s *ScalarK256) Random(reader io.Reader) Scalar {
|
||||
if reader == nil {
|
||||
return nil
|
||||
}
|
||||
var seed [64]byte
|
||||
_, _ = reader.Read(seed[:])
|
||||
return s.Hash(seed[:])
|
||||
}
|
||||
|
||||
func (s *ScalarK256) Hash(bytes []byte) Scalar {
|
||||
dst := []byte("secp256k1_XMD:SHA-256_SSWU_RO_")
|
||||
xmd := native.ExpandMsgXmd(native.EllipticPointHasherSha256(), bytes, dst, 48)
|
||||
var t [64]byte
|
||||
copy(t[:48], internal.ReverseScalarBytes(xmd))
|
||||
|
||||
return &ScalarK256{
|
||||
value: fq.K256FqNew().SetBytesWide(&t),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarK256) Zero() Scalar {
|
||||
return &ScalarK256{
|
||||
value: fq.K256FqNew().SetZero(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarK256) One() Scalar {
|
||||
return &ScalarK256{
|
||||
value: fq.K256FqNew().SetOne(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarK256) IsZero() bool {
|
||||
return s.value.IsZero() == 1
|
||||
}
|
||||
|
||||
func (s *ScalarK256) IsOne() bool {
|
||||
return s.value.IsOne() == 1
|
||||
}
|
||||
|
||||
func (s *ScalarK256) IsOdd() bool {
|
||||
return s.value.Bytes()[0]&1 == 1
|
||||
}
|
||||
|
||||
func (s *ScalarK256) IsEven() bool {
|
||||
return s.value.Bytes()[0]&1 == 0
|
||||
}
|
||||
|
||||
func (s *ScalarK256) New(value int) Scalar {
|
||||
t := fq.K256FqNew()
|
||||
v := big.NewInt(int64(value))
|
||||
if value < 0 {
|
||||
v.Mod(v, t.Params.BiModulus)
|
||||
}
|
||||
return &ScalarK256{
|
||||
value: t.SetBigInt(v),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarK256) Cmp(rhs Scalar) int {
|
||||
r, ok := rhs.(*ScalarK256)
|
||||
if ok {
|
||||
return s.value.Cmp(r.value)
|
||||
} else {
|
||||
return -2
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarK256) Square() Scalar {
|
||||
return &ScalarK256{
|
||||
value: fq.K256FqNew().Square(s.value),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarK256) Double() Scalar {
|
||||
return &ScalarK256{
|
||||
value: fq.K256FqNew().Double(s.value),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarK256) Invert() (Scalar, error) {
|
||||
value, wasInverted := fq.K256FqNew().Invert(s.value)
|
||||
if !wasInverted {
|
||||
return nil, fmt.Errorf("inverse doesn't exist")
|
||||
}
|
||||
return &ScalarK256{
|
||||
value,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *ScalarK256) Sqrt() (Scalar, error) {
|
||||
value, wasSquare := fq.K256FqNew().Sqrt(s.value)
|
||||
if !wasSquare {
|
||||
return nil, fmt.Errorf("not a square")
|
||||
}
|
||||
return &ScalarK256{
|
||||
value,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *ScalarK256) Cube() Scalar {
|
||||
value := fq.K256FqNew().Mul(s.value, s.value)
|
||||
value.Mul(value, s.value)
|
||||
return &ScalarK256{
|
||||
value,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarK256) Add(rhs Scalar) Scalar {
|
||||
r, ok := rhs.(*ScalarK256)
|
||||
if ok {
|
||||
return &ScalarK256{
|
||||
value: fq.K256FqNew().Add(s.value, r.value),
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarK256) Sub(rhs Scalar) Scalar {
|
||||
r, ok := rhs.(*ScalarK256)
|
||||
if ok {
|
||||
return &ScalarK256{
|
||||
value: fq.K256FqNew().Sub(s.value, r.value),
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarK256) Mul(rhs Scalar) Scalar {
|
||||
r, ok := rhs.(*ScalarK256)
|
||||
if ok {
|
||||
return &ScalarK256{
|
||||
value: fq.K256FqNew().Mul(s.value, r.value),
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarK256) MulAdd(y, z Scalar) Scalar {
|
||||
return s.Mul(y).Add(z)
|
||||
}
|
||||
|
||||
func (s *ScalarK256) Div(rhs Scalar) Scalar {
|
||||
r, ok := rhs.(*ScalarK256)
|
||||
if ok {
|
||||
v, wasInverted := fq.K256FqNew().Invert(r.value)
|
||||
if !wasInverted {
|
||||
return nil
|
||||
}
|
||||
v.Mul(v, s.value)
|
||||
return &ScalarK256{value: v}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarK256) Neg() Scalar {
|
||||
return &ScalarK256{
|
||||
value: fq.K256FqNew().Neg(s.value),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarK256) SetBigInt(v *big.Int) (Scalar, error) {
|
||||
if v == nil {
|
||||
return nil, fmt.Errorf("'v' cannot be nil")
|
||||
}
|
||||
value := fq.K256FqNew().SetBigInt(v)
|
||||
return &ScalarK256{
|
||||
value,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *ScalarK256) BigInt() *big.Int {
|
||||
return s.value.BigInt()
|
||||
}
|
||||
|
||||
func (s *ScalarK256) Bytes() []byte {
|
||||
t := s.value.Bytes()
|
||||
return internal.ReverseScalarBytes(t[:])
|
||||
}
|
||||
|
||||
func (s *ScalarK256) SetBytes(bytes []byte) (Scalar, error) {
|
||||
if len(bytes) != 32 {
|
||||
return nil, fmt.Errorf("invalid length")
|
||||
}
|
||||
var seq [32]byte
|
||||
copy(seq[:], internal.ReverseScalarBytes(bytes))
|
||||
value, err := fq.K256FqNew().SetBytes(&seq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ScalarK256{
|
||||
value,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *ScalarK256) SetBytesWide(bytes []byte) (Scalar, error) {
|
||||
if len(bytes) != 64 {
|
||||
return nil, fmt.Errorf("invalid length")
|
||||
}
|
||||
var seq [64]byte
|
||||
copy(seq[:], bytes)
|
||||
return &ScalarK256{
|
||||
value: fq.K256FqNew().SetBytesWide(&seq),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *ScalarK256) Point() Point {
|
||||
return new(PointK256).Identity()
|
||||
}
|
||||
|
||||
func (s *ScalarK256) Clone() Scalar {
|
||||
return &ScalarK256{
|
||||
value: fq.K256FqNew().Set(s.value),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScalarK256) MarshalBinary() ([]byte, error) {
|
||||
return scalarMarshalBinary(s)
|
||||
}
|
||||
|
||||
func (s *ScalarK256) UnmarshalBinary(input []byte) error {
|
||||
sc, err := scalarUnmarshalBinary(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ss, ok := sc.(*ScalarK256)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid scalar")
|
||||
}
|
||||
s.value = ss.value
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ScalarK256) MarshalText() ([]byte, error) {
|
||||
return scalarMarshalText(s)
|
||||
}
|
||||
|
||||
func (s *ScalarK256) UnmarshalText(input []byte) error {
|
||||
sc, err := scalarUnmarshalText(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ss, ok := sc.(*ScalarK256)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid scalar")
|
||||
}
|
||||
s.value = ss.value
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ScalarK256) MarshalJSON() ([]byte, error) {
|
||||
return scalarMarshalJson(s)
|
||||
}
|
||||
|
||||
func (s *ScalarK256) UnmarshalJSON(input []byte) error {
|
||||
sc, err := scalarUnmarshalJson(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
S, ok := sc.(*ScalarK256)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid type")
|
||||
}
|
||||
s.value = S.value
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PointK256) Random(reader io.Reader) Point {
|
||||
var seed [64]byte
|
||||
_, _ = reader.Read(seed[:])
|
||||
return p.Hash(seed[:])
|
||||
}
|
||||
|
||||
func (p *PointK256) Hash(bytes []byte) Point {
|
||||
value, err := secp256k1.K256PointNew().Hash(bytes, native.EllipticPointHasherSha256())
|
||||
// TODO: change hash to return an error also
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &PointK256{value}
|
||||
}
|
||||
|
||||
func (p *PointK256) Identity() Point {
|
||||
return &PointK256{
|
||||
value: secp256k1.K256PointNew().Identity(),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PointK256) Generator() Point {
|
||||
return &PointK256{
|
||||
value: secp256k1.K256PointNew().Generator(),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PointK256) IsIdentity() bool {
|
||||
return p.value.IsIdentity()
|
||||
}
|
||||
|
||||
func (p *PointK256) IsNegative() bool {
|
||||
return p.value.GetY().Value[0]&1 == 1
|
||||
}
|
||||
|
||||
func (p *PointK256) IsOnCurve() bool {
|
||||
return p.value.IsOnCurve()
|
||||
}
|
||||
|
||||
func (p *PointK256) Double() Point {
|
||||
value := secp256k1.K256PointNew().Double(p.value)
|
||||
return &PointK256{value}
|
||||
}
|
||||
|
||||
func (p *PointK256) Scalar() Scalar {
|
||||
return new(ScalarK256).Zero()
|
||||
}
|
||||
|
||||
func (p *PointK256) Neg() Point {
|
||||
value := secp256k1.K256PointNew().Neg(p.value)
|
||||
return &PointK256{value}
|
||||
}
|
||||
|
||||
func (p *PointK256) Add(rhs Point) Point {
|
||||
if rhs == nil {
|
||||
return nil
|
||||
}
|
||||
r, ok := rhs.(*PointK256)
|
||||
if ok {
|
||||
value := secp256k1.K256PointNew().Add(p.value, r.value)
|
||||
return &PointK256{value}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PointK256) Sub(rhs Point) Point {
|
||||
if rhs == nil {
|
||||
return nil
|
||||
}
|
||||
r, ok := rhs.(*PointK256)
|
||||
if ok {
|
||||
value := secp256k1.K256PointNew().Sub(p.value, r.value)
|
||||
return &PointK256{value}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PointK256) Mul(rhs Scalar) Point {
|
||||
if rhs == nil {
|
||||
return nil
|
||||
}
|
||||
r, ok := rhs.(*ScalarK256)
|
||||
if ok {
|
||||
value := secp256k1.K256PointNew().Mul(p.value, r.value)
|
||||
return &PointK256{value}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PointK256) Equal(rhs Point) bool {
|
||||
r, ok := rhs.(*PointK256)
|
||||
if ok {
|
||||
return p.value.Equal(r.value) == 1
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PointK256) Set(x, y *big.Int) (Point, error) {
|
||||
value, err := secp256k1.K256PointNew().SetBigInt(x, y)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &PointK256{value}, nil
|
||||
}
|
||||
|
||||
func (p *PointK256) ToAffineCompressed() []byte {
|
||||
var x [33]byte
|
||||
x[0] = byte(2)
|
||||
|
||||
t := secp256k1.K256PointNew().ToAffine(p.value)
|
||||
|
||||
x[0] |= t.Y.Bytes()[0] & 1
|
||||
|
||||
xBytes := t.X.Bytes()
|
||||
copy(x[1:], internal.ReverseScalarBytes(xBytes[:]))
|
||||
return x[:]
|
||||
}
|
||||
|
||||
func (p *PointK256) ToAffineUncompressed() []byte {
|
||||
var out [65]byte
|
||||
out[0] = byte(4)
|
||||
t := secp256k1.K256PointNew().ToAffine(p.value)
|
||||
arr := t.X.Bytes()
|
||||
copy(out[1:33], internal.ReverseScalarBytes(arr[:]))
|
||||
arr = t.Y.Bytes()
|
||||
copy(out[33:], internal.ReverseScalarBytes(arr[:]))
|
||||
return out[:]
|
||||
}
|
||||
|
||||
func (p *PointK256) FromAffineCompressed(bytes []byte) (Point, error) {
|
||||
var raw [native.FieldBytes]byte
|
||||
if len(bytes) != 33 {
|
||||
return nil, fmt.Errorf("invalid byte sequence")
|
||||
}
|
||||
sign := int(bytes[0])
|
||||
if sign != 2 && sign != 3 {
|
||||
return nil, fmt.Errorf("invalid sign byte")
|
||||
}
|
||||
sign &= 0x1
|
||||
|
||||
copy(raw[:], internal.ReverseScalarBytes(bytes[1:]))
|
||||
x, err := fp.K256FpNew().SetBytes(&raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
value := secp256k1.K256PointNew().Identity()
|
||||
rhs := fp.K256FpNew()
|
||||
p.value.Arithmetic.RhsEq(rhs, x)
|
||||
// test that rhs is quadratic residue
|
||||
// if not, then this Point is at infinity
|
||||
y, wasQr := fp.K256FpNew().Sqrt(rhs)
|
||||
if wasQr {
|
||||
// fix the sign
|
||||
sigY := int(y.Bytes()[0] & 1)
|
||||
if sigY != sign {
|
||||
y.Neg(y)
|
||||
}
|
||||
value.X = x
|
||||
value.Y = y
|
||||
value.Z.SetOne()
|
||||
}
|
||||
return &PointK256{value}, nil
|
||||
}
|
||||
|
||||
func (p *PointK256) FromAffineUncompressed(bytes []byte) (Point, error) {
|
||||
var arr [native.FieldBytes]byte
|
||||
if len(bytes) != 65 {
|
||||
return nil, fmt.Errorf("invalid byte sequence")
|
||||
}
|
||||
if bytes[0] != 4 {
|
||||
return nil, fmt.Errorf("invalid sign byte")
|
||||
}
|
||||
|
||||
copy(arr[:], internal.ReverseScalarBytes(bytes[1:33]))
|
||||
x, err := fp.K256FpNew().SetBytes(&arr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copy(arr[:], internal.ReverseScalarBytes(bytes[33:]))
|
||||
y, err := fp.K256FpNew().SetBytes(&arr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
value := secp256k1.K256PointNew()
|
||||
value.X = x
|
||||
value.Y = y
|
||||
value.Z.SetOne()
|
||||
return &PointK256{value}, nil
|
||||
}
|
||||
|
||||
func (p *PointK256) CurveName() string {
|
||||
return p.value.Params.Name
|
||||
}
|
||||
|
||||
func (p *PointK256) SumOfProducts(points []Point, scalars []Scalar) Point {
|
||||
nPoints := make([]*native.EllipticPoint, len(points))
|
||||
nScalars := make([]*native.Field, len(scalars))
|
||||
for i, pt := range points {
|
||||
ptv, ok := pt.(*PointK256)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
nPoints[i] = ptv.value
|
||||
}
|
||||
for i, sc := range scalars {
|
||||
s, ok := sc.(*ScalarK256)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
nScalars[i] = s.value
|
||||
}
|
||||
value := secp256k1.K256PointNew()
|
||||
_, err := value.SumOfProducts(nPoints, nScalars)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &PointK256{value}
|
||||
}
|
||||
|
||||
func (p *PointK256) X() *native.Field {
|
||||
return p.value.GetX()
|
||||
}
|
||||
|
||||
func (p *PointK256) Y() *native.Field {
|
||||
return p.value.GetY()
|
||||
}
|
||||
|
||||
func (p *PointK256) Params() *elliptic.CurveParams {
|
||||
return K256Curve().Params()
|
||||
}
|
||||
|
||||
func (p *PointK256) MarshalBinary() ([]byte, error) {
|
||||
return pointMarshalBinary(p)
|
||||
}
|
||||
|
||||
func (p *PointK256) UnmarshalBinary(input []byte) error {
|
||||
pt, err := pointUnmarshalBinary(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ppt, ok := pt.(*PointK256)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid point")
|
||||
}
|
||||
p.value = ppt.value
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PointK256) MarshalText() ([]byte, error) {
|
||||
return pointMarshalText(p)
|
||||
}
|
||||
|
||||
func (p *PointK256) UnmarshalText(input []byte) error {
|
||||
pt, err := pointUnmarshalText(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ppt, ok := pt.(*PointK256)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid point")
|
||||
}
|
||||
p.value = ppt.value
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PointK256) MarshalJSON() ([]byte, error) {
|
||||
return pointMarshalJson(p)
|
||||
}
|
||||
|
||||
func (p *PointK256) UnmarshalJSON(input []byte) error {
|
||||
pt, err := pointUnmarshalJson(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
P, ok := pt.(*PointK256)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid type")
|
||||
}
|
||||
p.value = P.value
|
||||
return nil
|
||||
}
|
@ -1,421 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package curves
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"math/big"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type mockReader struct {
|
||||
index int
|
||||
seed []byte
|
||||
}
|
||||
|
||||
var mockRngInitonce sync.Once
|
||||
var mockRng mockReader
|
||||
|
||||
func newMockReader() {
|
||||
mockRng.index = 0
|
||||
mockRng.seed = make([]byte, 32)
|
||||
for i := range mockRng.seed {
|
||||
mockRng.seed[i] = 1
|
||||
}
|
||||
}
|
||||
|
||||
func testRng() *mockReader {
|
||||
mockRngInitonce.Do(newMockReader)
|
||||
return &mockRng
|
||||
}
|
||||
|
||||
func (m *mockReader) Read(p []byte) (n int, err error) {
|
||||
limit := len(m.seed)
|
||||
for i := range p {
|
||||
p[i] = m.seed[m.index]
|
||||
m.index += 1
|
||||
m.index %= limit
|
||||
}
|
||||
n = len(p)
|
||||
err = nil
|
||||
return
|
||||
}
|
||||
|
||||
func TestScalarK256Random(t *testing.T) {
|
||||
curve := K256()
|
||||
sc := curve.Scalar.Random(testRng())
|
||||
s, ok := sc.(*ScalarK256)
|
||||
require.True(t, ok)
|
||||
expected, _ := new(big.Int).SetString("2f71aaec5e14d747c72e46cdcaffffe6f542f38b3f0925469ceb24ac1c65885d", 16)
|
||||
require.Equal(t, s.value.BigInt(), expected)
|
||||
// Try 10 random values
|
||||
for i := 0; i < 10; i++ {
|
||||
sc := curve.Scalar.Random(crand.Reader)
|
||||
_, ok := sc.(*ScalarK256)
|
||||
require.True(t, ok)
|
||||
require.True(t, !sc.IsZero())
|
||||
}
|
||||
}
|
||||
|
||||
func TestScalarK256Hash(t *testing.T) {
|
||||
var b [32]byte
|
||||
k256 := K256()
|
||||
sc := k256.Scalar.Hash(b[:])
|
||||
s, ok := sc.(*ScalarK256)
|
||||
require.True(t, ok)
|
||||
expected, _ := new(big.Int).SetString("e5cb3500b809a8202de0834a805068bc21bde09bd6367815e7523a37adf8f52e", 16)
|
||||
require.Equal(t, s.value.BigInt(), expected)
|
||||
}
|
||||
|
||||
func TestScalarK256Zero(t *testing.T) {
|
||||
k256 := K256()
|
||||
sc := k256.Scalar.Zero()
|
||||
require.True(t, sc.IsZero())
|
||||
require.True(t, sc.IsEven())
|
||||
}
|
||||
|
||||
func TestScalarK256One(t *testing.T) {
|
||||
k256 := K256()
|
||||
sc := k256.Scalar.One()
|
||||
require.True(t, sc.IsOne())
|
||||
require.True(t, sc.IsOdd())
|
||||
}
|
||||
|
||||
func TestScalarK256New(t *testing.T) {
|
||||
k256 := K256()
|
||||
three := k256.Scalar.New(3)
|
||||
require.True(t, three.IsOdd())
|
||||
four := k256.Scalar.New(4)
|
||||
require.True(t, four.IsEven())
|
||||
neg1 := k256.Scalar.New(-1)
|
||||
require.True(t, neg1.IsEven())
|
||||
neg2 := k256.Scalar.New(-2)
|
||||
require.True(t, neg2.IsOdd())
|
||||
}
|
||||
|
||||
func TestScalarK256Square(t *testing.T) {
|
||||
k256 := K256()
|
||||
three := k256.Scalar.New(3)
|
||||
nine := k256.Scalar.New(9)
|
||||
require.Equal(t, three.Square().Cmp(nine), 0)
|
||||
}
|
||||
|
||||
func TestScalarK256Cube(t *testing.T) {
|
||||
k256 := K256()
|
||||
three := k256.Scalar.New(3)
|
||||
twentySeven := k256.Scalar.New(27)
|
||||
require.Equal(t, three.Cube().Cmp(twentySeven), 0)
|
||||
}
|
||||
|
||||
func TestScalarK256Double(t *testing.T) {
|
||||
k256 := K256()
|
||||
three := k256.Scalar.New(3)
|
||||
six := k256.Scalar.New(6)
|
||||
require.Equal(t, three.Double().Cmp(six), 0)
|
||||
}
|
||||
|
||||
func TestScalarK256Neg(t *testing.T) {
|
||||
k256 := K256()
|
||||
one := k256.Scalar.One()
|
||||
neg1 := k256.Scalar.New(-1)
|
||||
require.Equal(t, one.Neg().Cmp(neg1), 0)
|
||||
lotsOfThrees := k256.Scalar.New(333333)
|
||||
expected := k256.Scalar.New(-333333)
|
||||
require.Equal(t, lotsOfThrees.Neg().Cmp(expected), 0)
|
||||
}
|
||||
|
||||
func TestScalarK256Invert(t *testing.T) {
|
||||
k256 := K256()
|
||||
nine := k256.Scalar.New(9)
|
||||
actual, _ := nine.Invert()
|
||||
sa, _ := actual.(*ScalarK256)
|
||||
bn, _ := new(big.Int).SetString("8e38e38e38e38e38e38e38e38e38e38d842841d57dd303af6a9150f8e5737996", 16)
|
||||
expected, err := k256.Scalar.SetBigInt(bn)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sa.Cmp(expected), 0)
|
||||
}
|
||||
|
||||
func TestScalarK256Sqrt(t *testing.T) {
|
||||
k256 := K256()
|
||||
nine := k256.Scalar.New(9)
|
||||
actual, err := nine.Sqrt()
|
||||
sa, _ := actual.(*ScalarK256)
|
||||
expected := k256.Scalar.New(3)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sa.Cmp(expected), 0)
|
||||
}
|
||||
|
||||
func TestScalarK256Add(t *testing.T) {
|
||||
k256 := K256()
|
||||
nine := k256.Scalar.New(9)
|
||||
six := k256.Scalar.New(6)
|
||||
fifteen := nine.Add(six)
|
||||
require.NotNil(t, fifteen)
|
||||
expected := k256.Scalar.New(15)
|
||||
require.Equal(t, expected.Cmp(fifteen), 0)
|
||||
n := new(big.Int).Set(btcec.S256().N)
|
||||
n.Sub(n, big.NewInt(3))
|
||||
|
||||
upper, err := k256.Scalar.SetBigInt(n)
|
||||
require.NoError(t, err)
|
||||
actual := upper.Add(nine)
|
||||
require.NotNil(t, actual)
|
||||
require.Equal(t, actual.Cmp(six), 0)
|
||||
}
|
||||
|
||||
func TestScalarK256Sub(t *testing.T) {
|
||||
k256 := K256()
|
||||
nine := k256.Scalar.New(9)
|
||||
six := k256.Scalar.New(6)
|
||||
n := new(big.Int).Set(btcec.S256().N)
|
||||
n.Sub(n, big.NewInt(3))
|
||||
|
||||
expected, err := k256.Scalar.SetBigInt(n)
|
||||
require.NoError(t, err)
|
||||
actual := six.Sub(nine)
|
||||
require.Equal(t, expected.Cmp(actual), 0)
|
||||
|
||||
actual = nine.Sub(six)
|
||||
require.Equal(t, actual.Cmp(k256.Scalar.New(3)), 0)
|
||||
}
|
||||
|
||||
func TestScalarK256Mul(t *testing.T) {
|
||||
k256 := K256()
|
||||
nine := k256.Scalar.New(9)
|
||||
six := k256.Scalar.New(6)
|
||||
actual := nine.Mul(six)
|
||||
require.Equal(t, actual.Cmp(k256.Scalar.New(54)), 0)
|
||||
n := new(big.Int).Set(btcec.S256().N)
|
||||
n.Sub(n, big.NewInt(1))
|
||||
upper, err := k256.Scalar.SetBigInt(n)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, upper.Mul(upper).Cmp(k256.Scalar.New(1)), 0)
|
||||
}
|
||||
|
||||
func TestScalarK256Div(t *testing.T) {
|
||||
k256 := K256()
|
||||
nine := k256.Scalar.New(9)
|
||||
actual := nine.Div(nine)
|
||||
require.Equal(t, actual.Cmp(k256.Scalar.New(1)), 0)
|
||||
require.Equal(t, k256.Scalar.New(54).Div(nine).Cmp(k256.Scalar.New(6)), 0)
|
||||
}
|
||||
|
||||
func TestScalarK256Serialize(t *testing.T) {
|
||||
k256 := K256()
|
||||
sc := k256.Scalar.New(255)
|
||||
sequence := sc.Bytes()
|
||||
require.Equal(t, len(sequence), 32)
|
||||
require.Equal(t, sequence, []byte{0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff})
|
||||
ret, err := k256.Scalar.SetBytes(sequence)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ret.Cmp(sc), 0)
|
||||
|
||||
// Try 10 random values
|
||||
for i := 0; i < 10; i++ {
|
||||
sc = k256.Scalar.Random(crand.Reader)
|
||||
sequence = sc.Bytes()
|
||||
require.Equal(t, len(sequence), 32)
|
||||
ret, err = k256.Scalar.SetBytes(sequence)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ret.Cmp(sc), 0)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScalarK256Nil(t *testing.T) {
|
||||
k256 := K256()
|
||||
one := k256.Scalar.New(1)
|
||||
require.Nil(t, one.Add(nil))
|
||||
require.Nil(t, one.Sub(nil))
|
||||
require.Nil(t, one.Mul(nil))
|
||||
require.Nil(t, one.Div(nil))
|
||||
require.Nil(t, k256.Scalar.Random(nil))
|
||||
require.Equal(t, one.Cmp(nil), -2)
|
||||
_, err := k256.Scalar.SetBigInt(nil)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestPointK256Random(t *testing.T) {
|
||||
curve := K256()
|
||||
sc := curve.Point.Random(testRng())
|
||||
s, ok := sc.(*PointK256)
|
||||
require.True(t, ok)
|
||||
expectedX, _ := new(big.Int).SetString("c6e18a1d7cf834462675b31581639a18e14fd0f73f8dfd5fe2993f88f6fbe008", 16)
|
||||
expectedY, _ := new(big.Int).SetString("b65fab3243c5d07cef005d7fb335ebe8019efd954e95e68c86ef9b3bd7bccd36", 16)
|
||||
require.Equal(t, s.X().BigInt(), expectedX)
|
||||
require.Equal(t, s.Y().BigInt(), expectedY)
|
||||
// Try 10 random values
|
||||
for i := 0; i < 10; i++ {
|
||||
sc := curve.Point.Random(crand.Reader)
|
||||
_, ok := sc.(*PointK256)
|
||||
require.True(t, ok)
|
||||
require.True(t, !sc.IsIdentity())
|
||||
}
|
||||
}
|
||||
|
||||
func TestPointK256Hash(t *testing.T) {
|
||||
var b [32]byte
|
||||
curve := K256()
|
||||
sc := curve.Point.Hash(b[:])
|
||||
s, ok := sc.(*PointK256)
|
||||
require.True(t, ok)
|
||||
expectedX, _ := new(big.Int).SetString("95d0ad42f68ddb5a808469dd75fa866890dcc7d039844e0e2d58a6d25bd9a66b", 16)
|
||||
expectedY, _ := new(big.Int).SetString("f37c564d05168dab4413caacdb8e3426143fc5fb24a470ccd8a51856c11d163c", 16)
|
||||
require.Equal(t, s.X().BigInt(), expectedX)
|
||||
require.Equal(t, s.Y().BigInt(), expectedY)
|
||||
}
|
||||
|
||||
func TestPointK256Identity(t *testing.T) {
|
||||
k256 := K256()
|
||||
sc := k256.Point.Identity()
|
||||
require.True(t, sc.IsIdentity())
|
||||
require.Equal(t, sc.ToAffineCompressed(), []byte{2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
|
||||
}
|
||||
|
||||
func TestPointK256Generator(t *testing.T) {
|
||||
curve := K256()
|
||||
sc := curve.Point.Generator()
|
||||
s, ok := sc.(*PointK256)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, s.X().BigInt().Cmp(btcec.S256().Gx), 0)
|
||||
require.Equal(t, s.Y().BigInt().Cmp(btcec.S256().Gy), 0)
|
||||
}
|
||||
|
||||
func TestPointK256Set(t *testing.T) {
|
||||
k256 := K256()
|
||||
iden, err := k256.Point.Set(big.NewInt(0), big.NewInt(0))
|
||||
require.NoError(t, err)
|
||||
require.True(t, iden.IsIdentity())
|
||||
_, err = k256.Point.Set(btcec.S256().Gx, btcec.S256().Gy)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestPointK256Double(t *testing.T) {
|
||||
curve := K256()
|
||||
g := curve.Point.Generator()
|
||||
g2 := g.Double()
|
||||
require.True(t, g2.Equal(g.Mul(curve.Scalar.New(2))))
|
||||
i := curve.Point.Identity()
|
||||
require.True(t, i.Double().Equal(i))
|
||||
gg := curve.Point.Generator().Add(curve.Point.Generator())
|
||||
require.True(t, g2.Equal(gg))
|
||||
}
|
||||
|
||||
func TestPointK256Neg(t *testing.T) {
|
||||
k256 := K256()
|
||||
g := k256.Point.Generator().Neg()
|
||||
require.True(t, g.Neg().Equal(k256.Point.Generator()))
|
||||
require.True(t, k256.Point.Identity().Neg().Equal(k256.Point.Identity()))
|
||||
}
|
||||
|
||||
func TestPointK256Add(t *testing.T) {
|
||||
curve := K256()
|
||||
pt := curve.Point.Generator().(*PointK256)
|
||||
pt1 := pt.Add(pt).(*PointK256)
|
||||
pt2 := pt.Double().(*PointK256)
|
||||
pt3 := pt.Mul(curve.Scalar.New(2)).(*PointK256)
|
||||
|
||||
require.True(t, pt1.Equal(pt2))
|
||||
require.True(t, pt1.Equal(pt3))
|
||||
require.True(t, pt.Add(pt).Equal(pt.Double()))
|
||||
require.True(t, pt.Mul(curve.Scalar.New(3)).Equal(pt.Add(pt).Add(pt)))
|
||||
}
|
||||
|
||||
func TestPointK256Sub(t *testing.T) {
|
||||
curve := K256()
|
||||
g := curve.Point.Generator()
|
||||
pt := curve.Point.Generator().Mul(curve.Scalar.New(4))
|
||||
|
||||
require.True(t, pt.Sub(g).Sub(g).Sub(g).Equal(g))
|
||||
require.True(t, pt.Sub(g).Sub(g).Sub(g).Sub(g).IsIdentity())
|
||||
}
|
||||
|
||||
func TestPointK256Mul(t *testing.T) {
|
||||
curve := K256()
|
||||
g := curve.Point.Generator()
|
||||
pt := curve.Point.Generator().Mul(curve.Scalar.New(4))
|
||||
require.True(t, g.Double().Double().Equal(pt))
|
||||
}
|
||||
|
||||
func TestPointK256Serialize(t *testing.T) {
|
||||
curve := K256()
|
||||
ss := curve.Scalar.Random(testRng())
|
||||
|
||||
g := curve.Point.Generator()
|
||||
ppt := g.Mul(ss).(*PointK256)
|
||||
|
||||
require.Equal(t, ppt.ToAffineCompressed(), []byte{0x2, 0x1b, 0xa7, 0x7e, 0x98, 0xd6, 0xd8, 0x49, 0x45, 0xa4, 0x75, 0xd8, 0x6, 0xc0, 0x94, 0x5b, 0x8c, 0xf0, 0x5b, 0x8a, 0xb2, 0x76, 0xbb, 0x9f, 0x6e, 0x52, 0x9a, 0x11, 0x9c, 0x79, 0xdd, 0xf6, 0x5a})
|
||||
require.Equal(t, ppt.ToAffineUncompressed(), []byte{0x4, 0x1b, 0xa7, 0x7e, 0x98, 0xd6, 0xd8, 0x49, 0x45, 0xa4, 0x75, 0xd8, 0x6, 0xc0, 0x94, 0x5b, 0x8c, 0xf0, 0x5b, 0x8a, 0xb2, 0x76, 0xbb, 0x9f, 0x6e, 0x52, 0x9a, 0x11, 0x9c, 0x79, 0xdd, 0xf6, 0x5a, 0xb2, 0x96, 0x7c, 0x59, 0x4, 0xeb, 0x9a, 0xaa, 0xa9, 0x1d, 0x4d, 0xd0, 0x2d, 0xc6, 0x37, 0xee, 0x4a, 0x95, 0x51, 0x60, 0xab, 0xab, 0xf7, 0xdb, 0x30, 0x7d, 0x7d, 0x0, 0x68, 0x6c, 0xcf, 0xf6})
|
||||
retP, err := ppt.FromAffineCompressed(ppt.ToAffineCompressed())
|
||||
require.NoError(t, err)
|
||||
require.True(t, ppt.Equal(retP))
|
||||
retP, err = ppt.FromAffineUncompressed(ppt.ToAffineUncompressed())
|
||||
require.NoError(t, err)
|
||||
require.True(t, ppt.Equal(retP))
|
||||
|
||||
// smoke test
|
||||
for i := 0; i < 25; i++ {
|
||||
s := curve.Scalar.Random(crand.Reader)
|
||||
pt := g.Mul(s)
|
||||
cmprs := pt.ToAffineCompressed()
|
||||
require.Equal(t, len(cmprs), 33)
|
||||
retC, err := pt.FromAffineCompressed(cmprs)
|
||||
require.NoError(t, err)
|
||||
require.True(t, pt.Equal(retC))
|
||||
|
||||
un := pt.ToAffineUncompressed()
|
||||
require.Equal(t, len(un), 65)
|
||||
retU, err := pt.FromAffineUncompressed(un)
|
||||
require.NoError(t, err)
|
||||
require.True(t, pt.Equal(retU))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPointK256Nil(t *testing.T) {
|
||||
k256 := K256()
|
||||
one := k256.Point.Generator()
|
||||
require.Nil(t, one.Add(nil))
|
||||
require.Nil(t, one.Sub(nil))
|
||||
require.Nil(t, one.Mul(nil))
|
||||
require.Nil(t, k256.Scalar.Random(nil))
|
||||
require.False(t, one.Equal(nil))
|
||||
_, err := k256.Scalar.SetBigInt(nil)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestPointK256SumOfProducts(t *testing.T) {
|
||||
lhs := new(PointK256).Generator().Mul(new(ScalarK256).New(50))
|
||||
points := make([]Point, 5)
|
||||
for i := range points {
|
||||
points[i] = new(PointK256).Generator()
|
||||
}
|
||||
scalars := []Scalar{
|
||||
new(ScalarK256).New(8),
|
||||
new(ScalarK256).New(9),
|
||||
new(ScalarK256).New(10),
|
||||
new(ScalarK256).New(11),
|
||||
new(ScalarK256).New(12),
|
||||
}
|
||||
rhs := lhs.SumOfProducts(points, scalars)
|
||||
require.NotNil(t, rhs)
|
||||
require.True(t, lhs.Equal(rhs))
|
||||
|
||||
for j := 0; j < 25; j++ {
|
||||
lhs = lhs.Identity()
|
||||
for i := range points {
|
||||
points[i] = new(PointK256).Random(crand.Reader)
|
||||
scalars[i] = new(ScalarK256).Random(crand.Reader)
|
||||
lhs = lhs.Add(points[i].Mul(scalars[i]))
|
||||
}
|
||||
rhs = lhs.SumOfProducts(points, scalars)
|
||||
require.NotNil(t, rhs)
|
||||
require.True(t, lhs.Equal(rhs))
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
package bls12381
|
||||
|
||||
import (
|
||||
"math/bits"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
)
|
||||
|
||||
var fqModulusBytes = [native.FieldBytes]byte{0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x5b, 0xfe, 0xff, 0x02, 0xa4, 0xbd, 0x53, 0x05, 0xd8, 0xa1, 0x09, 0x08, 0xd8, 0x39, 0x33, 0x48, 0x7d, 0x9d, 0x29, 0x53, 0xa7, 0xed, 0x73}
|
||||
|
||||
const (
|
||||
// The BLS parameter x for BLS12-381 is -0xd201000000010000
|
||||
paramX = uint64(0xd201000000010000)
|
||||
Limbs = 6
|
||||
FieldBytes = 48
|
||||
WideFieldBytes = 96
|
||||
DoubleWideFieldBytes = 192
|
||||
)
|
||||
|
||||
// mac Multiply and Accumulate - compute a + (b * c) + d, return the result and new carry
|
||||
func mac(a, b, c, d uint64) (uint64, uint64) {
|
||||
hi, lo := bits.Mul64(b, c)
|
||||
carry2, carry := bits.Add64(a, d, 0)
|
||||
hi, _ = bits.Add64(hi, 0, carry)
|
||||
lo, carry = bits.Add64(lo, carry2, 0)
|
||||
hi, _ = bits.Add64(hi, 0, carry)
|
||||
|
||||
return lo, hi
|
||||
}
|
||||
|
||||
// adc Add w/Carry
|
||||
func adc(x, y, carry uint64) (uint64, uint64) {
|
||||
sum := x + y + carry
|
||||
// The sum will overflow if both top bits are set (x & y) or if one of them
|
||||
// is (x | y), and a carry from the lower place happened. If such a carry
|
||||
// happens, the top bit will be 1 + 0 + 1 = 0 (&^ sum).
|
||||
carryOut := ((x & y) | ((x | y) &^ sum)) >> 63
|
||||
carryOut |= ((x & carry) | ((x | carry) &^ sum)) >> 63
|
||||
carryOut |= ((y & carry) | ((y | carry) &^ sum)) >> 63
|
||||
return sum, carryOut
|
||||
}
|
||||
|
||||
// sbb Subtract with borrow
|
||||
func sbb(x, y, borrow uint64) (uint64, uint64) {
|
||||
diff := x - (y + borrow)
|
||||
borrowOut := ((^x & y) | (^(x ^ y) & diff)) >> 63
|
||||
return diff, borrowOut
|
||||
}
|
@ -1,697 +0,0 @@
|
||||
package bls12381
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
"github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
// fp field element mod p
|
||||
type fp [Limbs]uint64
|
||||
|
||||
var (
|
||||
modulus = fp{
|
||||
0xb9feffffffffaaab,
|
||||
0x1eabfffeb153ffff,
|
||||
0x6730d2a0f6b0f624,
|
||||
0x64774b84f38512bf,
|
||||
0x4b1ba7b6434bacd7,
|
||||
0x1a0111ea397fe69a,
|
||||
}
|
||||
halfModulus = fp{
|
||||
0xdcff_7fff_ffff_d556,
|
||||
0x0f55_ffff_58a9_ffff,
|
||||
0xb398_6950_7b58_7b12,
|
||||
0xb23b_a5c2_79c2_895f,
|
||||
0x258d_d3db_21a5_d66b,
|
||||
0x0d00_88f5_1cbf_f34d,
|
||||
}
|
||||
// 2^256 mod p
|
||||
r = fp{
|
||||
0x760900000002fffd,
|
||||
0xebf4000bc40c0002,
|
||||
0x5f48985753c758ba,
|
||||
0x77ce585370525745,
|
||||
0x5c071a97a256ec6d,
|
||||
0x15f65ec3fa80e493,
|
||||
}
|
||||
// 2^512 mod p
|
||||
r2 = fp{
|
||||
0xf4df1f341c341746,
|
||||
0x0a76e6a609d104f1,
|
||||
0x8de5476c4c95b6d5,
|
||||
0x67eb88a9939d83c0,
|
||||
0x9a793e85b519952d,
|
||||
0x11988fe592cae3aa,
|
||||
}
|
||||
// 2^768 mod p
|
||||
r3 = fp{
|
||||
0xed48ac6bd94ca1e0,
|
||||
0x315f831e03a7adf8,
|
||||
0x9a53352a615e29dd,
|
||||
0x34c04e5e921e1761,
|
||||
0x2512d43565724728,
|
||||
0x0aa6346091755d4d,
|
||||
}
|
||||
biModulus = new(big.Int).SetBytes([]byte{
|
||||
0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a, 0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b, 0xac, 0xd7, 0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0, 0xf6, 0xb0, 0xf6, 0x24, 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xab,
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
// inv = -(p^{-1} mod 2^64) mod 2^64
|
||||
const (
|
||||
inv = 0x89f3_fffc_fffc_fffd
|
||||
hashBytes = 64
|
||||
)
|
||||
|
||||
// IsZero returns 1 if fp == 0, 0 otherwise
|
||||
func (f *fp) IsZero() int {
|
||||
t := f[0]
|
||||
t |= f[1]
|
||||
t |= f[2]
|
||||
t |= f[3]
|
||||
t |= f[4]
|
||||
t |= f[5]
|
||||
return int(((int64(t) | int64(-t)) >> 63) + 1)
|
||||
}
|
||||
|
||||
// IsNonZero returns 1 if fp != 0, 0 otherwise
|
||||
func (f *fp) IsNonZero() int {
|
||||
t := f[0]
|
||||
t |= f[1]
|
||||
t |= f[2]
|
||||
t |= f[3]
|
||||
t |= f[4]
|
||||
t |= f[5]
|
||||
return int(-((int64(t) | int64(-t)) >> 63))
|
||||
}
|
||||
|
||||
// IsOne returns 1 if fp == 1, 0 otherwise
|
||||
func (f *fp) IsOne() int {
|
||||
return f.Equal(&r)
|
||||
}
|
||||
|
||||
// Cmp returns -1 if f < rhs
|
||||
// 0 if f == rhs
|
||||
// 1 if f > rhs
|
||||
func (f *fp) Cmp(rhs *fp) int {
|
||||
gt := uint64(0)
|
||||
lt := uint64(0)
|
||||
for i := 5; i >= 0; i-- {
|
||||
// convert to two 64-bit numbers where
|
||||
// the leading bits are zeros and hold no meaning
|
||||
// so rhs - f actually means gt
|
||||
// and f - rhs actually means lt.
|
||||
rhsH := rhs[i] >> 32
|
||||
rhsL := rhs[i] & 0xffffffff
|
||||
lhsH := f[i] >> 32
|
||||
lhsL := f[i] & 0xffffffff
|
||||
|
||||
// Check the leading bit
|
||||
// if negative then f > rhs
|
||||
// if positive then f < rhs
|
||||
gt |= (rhsH - lhsH) >> 32 & 1 &^ lt
|
||||
lt |= (lhsH - rhsH) >> 32 & 1 &^ gt
|
||||
gt |= (rhsL - lhsL) >> 32 & 1 &^ lt
|
||||
lt |= (lhsL - rhsL) >> 32 & 1 &^ gt
|
||||
}
|
||||
// Make the result -1 for <, 0 for =, 1 for >
|
||||
return int(gt) - int(lt)
|
||||
}
|
||||
|
||||
// Equal returns 1 if fp == rhs, 0 otherwise
|
||||
func (f *fp) Equal(rhs *fp) int {
|
||||
t := f[0] ^ rhs[0]
|
||||
t |= f[1] ^ rhs[1]
|
||||
t |= f[2] ^ rhs[2]
|
||||
t |= f[3] ^ rhs[3]
|
||||
t |= f[4] ^ rhs[4]
|
||||
t |= f[5] ^ rhs[5]
|
||||
return int(((int64(t) | int64(-t)) >> 63) + 1)
|
||||
}
|
||||
|
||||
// LexicographicallyLargest returns 1 if
|
||||
// this element is strictly lexicographically larger than its negation
|
||||
// 0 otherwise
|
||||
func (f *fp) LexicographicallyLargest() int {
|
||||
var ff fp
|
||||
ff.fromMontgomery(f)
|
||||
|
||||
_, borrow := sbb(ff[0], halfModulus[0], 0)
|
||||
_, borrow = sbb(ff[1], halfModulus[1], borrow)
|
||||
_, borrow = sbb(ff[2], halfModulus[2], borrow)
|
||||
_, borrow = sbb(ff[3], halfModulus[3], borrow)
|
||||
_, borrow = sbb(ff[4], halfModulus[4], borrow)
|
||||
_, borrow = sbb(ff[5], halfModulus[5], borrow)
|
||||
|
||||
return (int(borrow) - 1) & 1
|
||||
}
|
||||
|
||||
// Sgn0 returns the lowest bit value
|
||||
func (f *fp) Sgn0() int {
|
||||
t := new(fp).fromMontgomery(f)
|
||||
return int(t[0] & 1)
|
||||
}
|
||||
|
||||
// SetOne fp = r
|
||||
func (f *fp) SetOne() *fp {
|
||||
f[0] = r[0]
|
||||
f[1] = r[1]
|
||||
f[2] = r[2]
|
||||
f[3] = r[3]
|
||||
f[4] = r[4]
|
||||
f[5] = r[5]
|
||||
return f
|
||||
}
|
||||
|
||||
// SetZero fp = 0
|
||||
func (f *fp) SetZero() *fp {
|
||||
f[0] = 0
|
||||
f[1] = 0
|
||||
f[2] = 0
|
||||
f[3] = 0
|
||||
f[4] = 0
|
||||
f[5] = 0
|
||||
return f
|
||||
}
|
||||
|
||||
// SetUint64 fp = rhs
|
||||
func (f *fp) SetUint64(rhs uint64) *fp {
|
||||
f[0] = rhs
|
||||
f[1] = 0
|
||||
f[2] = 0
|
||||
f[3] = 0
|
||||
f[4] = 0
|
||||
f[5] = 0
|
||||
return f.toMontgomery(f)
|
||||
}
|
||||
|
||||
// Random generates a random field element
|
||||
func (f *fp) Random(reader io.Reader) (*fp, error) {
|
||||
var t [WideFieldBytes]byte
|
||||
n, err := reader.Read(t[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n != WideFieldBytes {
|
||||
return nil, fmt.Errorf("can only read %d when %d are needed", n, WideFieldBytes)
|
||||
}
|
||||
return f.Hash(t[:]), nil
|
||||
}
|
||||
|
||||
// Hash converts the byte sequence into a field element
|
||||
func (f *fp) Hash(input []byte) *fp {
|
||||
dst := []byte("BLS12381_XMD:SHA-256_SSWU_RO_")
|
||||
xmd := native.ExpandMsgXmd(native.EllipticPointHasherSha256(), input, dst, hashBytes)
|
||||
var t [WideFieldBytes]byte
|
||||
copy(t[:hashBytes], internal.ReverseScalarBytes(xmd))
|
||||
return f.SetBytesWide(&t)
|
||||
}
|
||||
|
||||
// toMontgomery converts this field to montgomery form
|
||||
func (f *fp) toMontgomery(a *fp) *fp {
|
||||
// arg.R^0 * R^2 / R = arg.R
|
||||
return f.Mul(a, &r2)
|
||||
}
|
||||
|
||||
// fromMontgomery converts this field from montgomery form
|
||||
func (f *fp) fromMontgomery(a *fp) *fp {
|
||||
// Mul by 1 is division by 2^256 mod q
|
||||
// out.Mul(arg, &[native.FieldLimbs]uint64{1, 0, 0, 0})
|
||||
return f.montReduce(&[Limbs * 2]uint64{a[0], a[1], a[2], a[3], a[4], a[5], 0, 0, 0, 0, 0, 0})
|
||||
}
|
||||
|
||||
// Neg performs modular negation
|
||||
func (f *fp) Neg(a *fp) *fp {
|
||||
// Subtract `arg` from `modulus`. Ignore final borrow
|
||||
// since it can't underflow.
|
||||
var t [Limbs]uint64
|
||||
var borrow uint64
|
||||
t[0], borrow = sbb(modulus[0], a[0], 0)
|
||||
t[1], borrow = sbb(modulus[1], a[1], borrow)
|
||||
t[2], borrow = sbb(modulus[2], a[2], borrow)
|
||||
t[3], borrow = sbb(modulus[3], a[3], borrow)
|
||||
t[4], borrow = sbb(modulus[4], a[4], borrow)
|
||||
t[5], _ = sbb(modulus[5], a[5], borrow)
|
||||
|
||||
// t could be `modulus` if `arg`=0. Set mask=0 if self=0
|
||||
// and 0xff..ff if `arg`!=0
|
||||
mask := a[0] | a[1] | a[2] | a[3] | a[4] | a[5]
|
||||
mask = -((mask | -mask) >> 63)
|
||||
f[0] = t[0] & mask
|
||||
f[1] = t[1] & mask
|
||||
f[2] = t[2] & mask
|
||||
f[3] = t[3] & mask
|
||||
f[4] = t[4] & mask
|
||||
f[5] = t[5] & mask
|
||||
return f
|
||||
}
|
||||
|
||||
// Square performs modular square
|
||||
func (f *fp) Square(a *fp) *fp {
|
||||
var r [2 * Limbs]uint64
|
||||
var carry uint64
|
||||
|
||||
r[1], carry = mac(0, a[0], a[1], 0)
|
||||
r[2], carry = mac(0, a[0], a[2], carry)
|
||||
r[3], carry = mac(0, a[0], a[3], carry)
|
||||
r[4], carry = mac(0, a[0], a[4], carry)
|
||||
r[5], r[6] = mac(0, a[0], a[5], carry)
|
||||
|
||||
r[3], carry = mac(r[3], a[1], a[2], 0)
|
||||
r[4], carry = mac(r[4], a[1], a[3], carry)
|
||||
r[5], carry = mac(r[5], a[1], a[4], carry)
|
||||
r[6], r[7] = mac(r[6], a[1], a[5], carry)
|
||||
|
||||
r[5], carry = mac(r[5], a[2], a[3], 0)
|
||||
r[6], carry = mac(r[6], a[2], a[4], carry)
|
||||
r[7], r[8] = mac(r[7], a[2], a[5], carry)
|
||||
|
||||
r[7], carry = mac(r[7], a[3], a[4], 0)
|
||||
r[8], r[9] = mac(r[8], a[3], a[5], carry)
|
||||
|
||||
r[9], r[10] = mac(r[9], a[4], a[5], 0)
|
||||
|
||||
r[11] = r[10] >> 63
|
||||
r[10] = (r[10] << 1) | r[9]>>63
|
||||
r[9] = (r[9] << 1) | r[8]>>63
|
||||
r[8] = (r[8] << 1) | r[7]>>63
|
||||
r[7] = (r[7] << 1) | r[6]>>63
|
||||
r[6] = (r[6] << 1) | r[5]>>63
|
||||
r[5] = (r[5] << 1) | r[4]>>63
|
||||
r[4] = (r[4] << 1) | r[3]>>63
|
||||
r[3] = (r[3] << 1) | r[2]>>63
|
||||
r[2] = (r[2] << 1) | r[1]>>63
|
||||
r[1] = r[1] << 1
|
||||
|
||||
r[0], carry = mac(0, a[0], a[0], 0)
|
||||
r[1], carry = adc(0, r[1], carry)
|
||||
r[2], carry = mac(r[2], a[1], a[1], carry)
|
||||
r[3], carry = adc(0, r[3], carry)
|
||||
r[4], carry = mac(r[4], a[2], a[2], carry)
|
||||
r[5], carry = adc(0, r[5], carry)
|
||||
r[6], carry = mac(r[6], a[3], a[3], carry)
|
||||
r[7], carry = adc(0, r[7], carry)
|
||||
r[8], carry = mac(r[8], a[4], a[4], carry)
|
||||
r[9], carry = adc(0, r[9], carry)
|
||||
r[10], carry = mac(r[10], a[5], a[5], carry)
|
||||
r[11], _ = adc(0, r[11], carry)
|
||||
|
||||
return f.montReduce(&r)
|
||||
}
|
||||
|
||||
// Double this element
|
||||
func (f *fp) Double(a *fp) *fp {
|
||||
return f.Add(a, a)
|
||||
}
|
||||
|
||||
// Mul performs modular multiplication
|
||||
func (f *fp) Mul(arg1, arg2 *fp) *fp {
|
||||
// Schoolbook multiplication
|
||||
var r [2 * Limbs]uint64
|
||||
var carry uint64
|
||||
|
||||
r[0], carry = mac(0, arg1[0], arg2[0], 0)
|
||||
r[1], carry = mac(0, arg1[0], arg2[1], carry)
|
||||
r[2], carry = mac(0, arg1[0], arg2[2], carry)
|
||||
r[3], carry = mac(0, arg1[0], arg2[3], carry)
|
||||
r[4], carry = mac(0, arg1[0], arg2[4], carry)
|
||||
r[5], r[6] = mac(0, arg1[0], arg2[5], carry)
|
||||
|
||||
r[1], carry = mac(r[1], arg1[1], arg2[0], 0)
|
||||
r[2], carry = mac(r[2], arg1[1], arg2[1], carry)
|
||||
r[3], carry = mac(r[3], arg1[1], arg2[2], carry)
|
||||
r[4], carry = mac(r[4], arg1[1], arg2[3], carry)
|
||||
r[5], carry = mac(r[5], arg1[1], arg2[4], carry)
|
||||
r[6], r[7] = mac(r[6], arg1[1], arg2[5], carry)
|
||||
|
||||
r[2], carry = mac(r[2], arg1[2], arg2[0], 0)
|
||||
r[3], carry = mac(r[3], arg1[2], arg2[1], carry)
|
||||
r[4], carry = mac(r[4], arg1[2], arg2[2], carry)
|
||||
r[5], carry = mac(r[5], arg1[2], arg2[3], carry)
|
||||
r[6], carry = mac(r[6], arg1[2], arg2[4], carry)
|
||||
r[7], r[8] = mac(r[7], arg1[2], arg2[5], carry)
|
||||
|
||||
r[3], carry = mac(r[3], arg1[3], arg2[0], 0)
|
||||
r[4], carry = mac(r[4], arg1[3], arg2[1], carry)
|
||||
r[5], carry = mac(r[5], arg1[3], arg2[2], carry)
|
||||
r[6], carry = mac(r[6], arg1[3], arg2[3], carry)
|
||||
r[7], carry = mac(r[7], arg1[3], arg2[4], carry)
|
||||
r[8], r[9] = mac(r[8], arg1[3], arg2[5], carry)
|
||||
|
||||
r[4], carry = mac(r[4], arg1[4], arg2[0], 0)
|
||||
r[5], carry = mac(r[5], arg1[4], arg2[1], carry)
|
||||
r[6], carry = mac(r[6], arg1[4], arg2[2], carry)
|
||||
r[7], carry = mac(r[7], arg1[4], arg2[3], carry)
|
||||
r[8], carry = mac(r[8], arg1[4], arg2[4], carry)
|
||||
r[9], r[10] = mac(r[9], arg1[4], arg2[5], carry)
|
||||
|
||||
r[5], carry = mac(r[5], arg1[5], arg2[0], 0)
|
||||
r[6], carry = mac(r[6], arg1[5], arg2[1], carry)
|
||||
r[7], carry = mac(r[7], arg1[5], arg2[2], carry)
|
||||
r[8], carry = mac(r[8], arg1[5], arg2[3], carry)
|
||||
r[9], carry = mac(r[9], arg1[5], arg2[4], carry)
|
||||
r[10], r[11] = mac(r[10], arg1[5], arg2[5], carry)
|
||||
|
||||
return f.montReduce(&r)
|
||||
}
|
||||
|
||||
// MulBy3b returns arg * 12 or 3 * b
|
||||
func (f *fp) MulBy3b(arg *fp) *fp {
|
||||
var a, t fp
|
||||
a.Double(arg) // 2
|
||||
t.Double(&a) // 4
|
||||
a.Double(&t) // 8
|
||||
a.Add(&a, &t) // 12
|
||||
return f.Set(&a)
|
||||
}
|
||||
|
||||
// Add performs modular addition
|
||||
func (f *fp) Add(arg1, arg2 *fp) *fp {
|
||||
var t fp
|
||||
var carry uint64
|
||||
|
||||
t[0], carry = adc(arg1[0], arg2[0], 0)
|
||||
t[1], carry = adc(arg1[1], arg2[1], carry)
|
||||
t[2], carry = adc(arg1[2], arg2[2], carry)
|
||||
t[3], carry = adc(arg1[3], arg2[3], carry)
|
||||
t[4], carry = adc(arg1[4], arg2[4], carry)
|
||||
t[5], _ = adc(arg1[5], arg2[5], carry)
|
||||
|
||||
// Subtract the modulus to ensure the value
|
||||
// is smaller.
|
||||
return f.Sub(&t, &modulus)
|
||||
}
|
||||
|
||||
// Sub performs modular subtraction
|
||||
func (f *fp) Sub(arg1, arg2 *fp) *fp {
|
||||
d0, borrow := sbb(arg1[0], arg2[0], 0)
|
||||
d1, borrow := sbb(arg1[1], arg2[1], borrow)
|
||||
d2, borrow := sbb(arg1[2], arg2[2], borrow)
|
||||
d3, borrow := sbb(arg1[3], arg2[3], borrow)
|
||||
d4, borrow := sbb(arg1[4], arg2[4], borrow)
|
||||
d5, borrow := sbb(arg1[5], arg2[5], borrow)
|
||||
|
||||
// If underflow occurred on the final limb, borrow 0xff...ff, otherwise
|
||||
// borrow = 0x00...00. Conditionally mask to add the modulus
|
||||
borrow = -borrow
|
||||
d0, carry := adc(d0, modulus[0]&borrow, 0)
|
||||
d1, carry = adc(d1, modulus[1]&borrow, carry)
|
||||
d2, carry = adc(d2, modulus[2]&borrow, carry)
|
||||
d3, carry = adc(d3, modulus[3]&borrow, carry)
|
||||
d4, carry = adc(d4, modulus[4]&borrow, carry)
|
||||
d5, _ = adc(d5, modulus[5]&borrow, carry)
|
||||
|
||||
f[0] = d0
|
||||
f[1] = d1
|
||||
f[2] = d2
|
||||
f[3] = d3
|
||||
f[4] = d4
|
||||
f[5] = d5
|
||||
return f
|
||||
}
|
||||
|
||||
// Sqrt performs modular square root
|
||||
func (f *fp) Sqrt(a *fp) (*fp, int) {
|
||||
// Shank's method, as p = 3 (mod 4). This means
|
||||
// exponentiate by (p+1)/4. This only works for elements
|
||||
// that are actually quadratic residue,
|
||||
// so check the result at the end.
|
||||
var c, z fp
|
||||
z.pow(a, &fp{
|
||||
0xee7fbfffffffeaab,
|
||||
0x07aaffffac54ffff,
|
||||
0xd9cc34a83dac3d89,
|
||||
0xd91dd2e13ce144af,
|
||||
0x92c6e9ed90d2eb35,
|
||||
0x0680447a8e5ff9a6,
|
||||
})
|
||||
|
||||
c.Square(&z)
|
||||
wasSquare := c.Equal(a)
|
||||
f.CMove(f, &z, wasSquare)
|
||||
return f, wasSquare
|
||||
}
|
||||
|
||||
// Invert performs modular inverse
|
||||
func (f *fp) Invert(a *fp) (*fp, int) {
|
||||
// Exponentiate by p - 2
|
||||
t := &fp{}
|
||||
t.pow(a, &fp{
|
||||
0xb9feffffffffaaa9,
|
||||
0x1eabfffeb153ffff,
|
||||
0x6730d2a0f6b0f624,
|
||||
0x64774b84f38512bf,
|
||||
0x4b1ba7b6434bacd7,
|
||||
0x1a0111ea397fe69a,
|
||||
})
|
||||
wasInverted := a.IsNonZero()
|
||||
f.CMove(a, t, wasInverted)
|
||||
return f, wasInverted
|
||||
}
|
||||
|
||||
// SetBytes converts a little endian byte array into a field element
|
||||
// return 0 if the bytes are not in the field, 1 if they are
|
||||
func (f *fp) SetBytes(arg *[FieldBytes]byte) (*fp, int) {
|
||||
var borrow uint64
|
||||
t := &fp{}
|
||||
|
||||
t[0] = binary.LittleEndian.Uint64(arg[:8])
|
||||
t[1] = binary.LittleEndian.Uint64(arg[8:16])
|
||||
t[2] = binary.LittleEndian.Uint64(arg[16:24])
|
||||
t[3] = binary.LittleEndian.Uint64(arg[24:32])
|
||||
t[4] = binary.LittleEndian.Uint64(arg[32:40])
|
||||
t[5] = binary.LittleEndian.Uint64(arg[40:])
|
||||
|
||||
// Try to subtract the modulus
|
||||
_, borrow = sbb(t[0], modulus[0], 0)
|
||||
_, borrow = sbb(t[1], modulus[1], borrow)
|
||||
_, borrow = sbb(t[2], modulus[2], borrow)
|
||||
_, borrow = sbb(t[3], modulus[3], borrow)
|
||||
_, borrow = sbb(t[4], modulus[4], borrow)
|
||||
_, borrow = sbb(t[5], modulus[5], borrow)
|
||||
|
||||
// If the element is smaller than modulus then the
|
||||
// subtraction will underflow, producing a borrow value
|
||||
// of 1. Otherwise, it'll be zero.
|
||||
mask := int(borrow)
|
||||
return f.CMove(f, t.toMontgomery(t), mask), mask
|
||||
}
|
||||
|
||||
// SetBytesWide takes 96 bytes as input and treats them as a 512-bit number.
|
||||
// Attributed to https://github.com/zcash/pasta_curves/blob/main/src/fields/Fp.rs#L255
|
||||
// We reduce an arbitrary 768-bit number by decomposing it into two 384-bit digits
|
||||
// with the higher bits multiplied by 2^384. Thus, we perform two reductions
|
||||
//
|
||||
// 1. the lower bits are multiplied by r^2, as normal
|
||||
// 2. the upper bits are multiplied by r^2 * 2^384 = r^3
|
||||
//
|
||||
// and computing their sum in the field. It remains to see that arbitrary 384-bit
|
||||
// numbers can be placed into Montgomery form safely using the reduction. The
|
||||
// reduction works so long as the product is less than r=2^384 multiplied by
|
||||
// the modulus. This holds because for any `c` smaller than the modulus, we have
|
||||
// that (2^384 - 1)*c is an acceptable product for the reduction. Therefore, the
|
||||
// reduction always works so long as `c` is in the field; in this case it is either the
|
||||
// constant `r2` or `r3`.
|
||||
func (f *fp) SetBytesWide(a *[WideFieldBytes]byte) *fp {
|
||||
d0 := &fp{
|
||||
binary.LittleEndian.Uint64(a[:8]),
|
||||
binary.LittleEndian.Uint64(a[8:16]),
|
||||
binary.LittleEndian.Uint64(a[16:24]),
|
||||
binary.LittleEndian.Uint64(a[24:32]),
|
||||
binary.LittleEndian.Uint64(a[32:40]),
|
||||
binary.LittleEndian.Uint64(a[40:48]),
|
||||
}
|
||||
d1 := &fp{
|
||||
binary.LittleEndian.Uint64(a[48:56]),
|
||||
binary.LittleEndian.Uint64(a[56:64]),
|
||||
binary.LittleEndian.Uint64(a[64:72]),
|
||||
binary.LittleEndian.Uint64(a[72:80]),
|
||||
binary.LittleEndian.Uint64(a[80:88]),
|
||||
binary.LittleEndian.Uint64(a[88:96]),
|
||||
}
|
||||
// d0*r2 + d1*r3
|
||||
d0.Mul(d0, &r2)
|
||||
d1.Mul(d1, &r3)
|
||||
return f.Add(d0, d1)
|
||||
}
|
||||
|
||||
// SetBigInt initializes an element from big.Int
|
||||
// The value is reduced by the modulus
|
||||
func (f *fp) SetBigInt(bi *big.Int) *fp {
|
||||
var buffer [FieldBytes]byte
|
||||
t := new(big.Int).Set(bi)
|
||||
t.Mod(t, biModulus)
|
||||
t.FillBytes(buffer[:])
|
||||
copy(buffer[:], internal.ReverseScalarBytes(buffer[:]))
|
||||
_, _ = f.SetBytes(&buffer)
|
||||
return f
|
||||
}
|
||||
|
||||
// Set copies a into fp
|
||||
func (f *fp) Set(a *fp) *fp {
|
||||
f[0] = a[0]
|
||||
f[1] = a[1]
|
||||
f[2] = a[2]
|
||||
f[3] = a[3]
|
||||
f[4] = a[4]
|
||||
f[5] = a[5]
|
||||
return f
|
||||
}
|
||||
|
||||
// SetLimbs converts an array into a field element
|
||||
// by converting to montgomery form
|
||||
func (f *fp) SetLimbs(a *[Limbs]uint64) *fp {
|
||||
return f.toMontgomery((*fp)(a))
|
||||
}
|
||||
|
||||
// SetRaw converts a raw array into a field element
|
||||
// Assumes input is already in montgomery form
|
||||
func (f *fp) SetRaw(a *[Limbs]uint64) *fp {
|
||||
f[0] = a[0]
|
||||
f[1] = a[1]
|
||||
f[2] = a[2]
|
||||
f[3] = a[3]
|
||||
f[4] = a[4]
|
||||
f[5] = a[5]
|
||||
return f
|
||||
}
|
||||
|
||||
// Bytes converts a field element to a little endian byte array
|
||||
func (f *fp) Bytes() [FieldBytes]byte {
|
||||
var out [FieldBytes]byte
|
||||
t := new(fp).fromMontgomery(f)
|
||||
binary.LittleEndian.PutUint64(out[:8], t[0])
|
||||
binary.LittleEndian.PutUint64(out[8:16], t[1])
|
||||
binary.LittleEndian.PutUint64(out[16:24], t[2])
|
||||
binary.LittleEndian.PutUint64(out[24:32], t[3])
|
||||
binary.LittleEndian.PutUint64(out[32:40], t[4])
|
||||
binary.LittleEndian.PutUint64(out[40:], t[5])
|
||||
return out
|
||||
}
|
||||
|
||||
// BigInt converts this element into the big.Int struct
|
||||
func (f *fp) BigInt() *big.Int {
|
||||
buffer := f.Bytes()
|
||||
return new(big.Int).SetBytes(internal.ReverseScalarBytes(buffer[:]))
|
||||
}
|
||||
|
||||
// Raw converts this element into the a [FieldLimbs]uint64
|
||||
func (f *fp) Raw() [Limbs]uint64 {
|
||||
t := new(fp).fromMontgomery(f)
|
||||
return *t
|
||||
}
|
||||
|
||||
// CMove performs conditional select.
|
||||
// selects arg1 if choice == 0 and arg2 if choice == 1
|
||||
func (f *fp) CMove(arg1, arg2 *fp, choice int) *fp {
|
||||
mask := uint64(-choice)
|
||||
f[0] = arg1[0] ^ ((arg1[0] ^ arg2[0]) & mask)
|
||||
f[1] = arg1[1] ^ ((arg1[1] ^ arg2[1]) & mask)
|
||||
f[2] = arg1[2] ^ ((arg1[2] ^ arg2[2]) & mask)
|
||||
f[3] = arg1[3] ^ ((arg1[3] ^ arg2[3]) & mask)
|
||||
f[4] = arg1[4] ^ ((arg1[4] ^ arg2[4]) & mask)
|
||||
f[5] = arg1[5] ^ ((arg1[5] ^ arg2[5]) & mask)
|
||||
return f
|
||||
}
|
||||
|
||||
// CNeg conditionally negates a if choice == 1
|
||||
func (f *fp) CNeg(a *fp, choice int) *fp {
|
||||
var t fp
|
||||
t.Neg(a)
|
||||
return f.CMove(f, &t, choice)
|
||||
}
|
||||
|
||||
// Exp raises base^exp.
|
||||
func (f *fp) Exp(base, exp *fp) *fp {
|
||||
e := (&fp{}).fromMontgomery(exp)
|
||||
return f.pow(base, e)
|
||||
}
|
||||
|
||||
func (f *fp) pow(base, e *fp) *fp {
|
||||
var tmp, res fp
|
||||
res.SetOne()
|
||||
|
||||
for i := len(e) - 1; i >= 0; i-- {
|
||||
for j := 63; j >= 0; j-- {
|
||||
res.Square(&res)
|
||||
tmp.Mul(&res, base)
|
||||
res.CMove(&res, &tmp, int(e[i]>>j)&1)
|
||||
}
|
||||
}
|
||||
f[0] = res[0]
|
||||
f[1] = res[1]
|
||||
f[2] = res[2]
|
||||
f[3] = res[3]
|
||||
f[4] = res[4]
|
||||
f[5] = res[5]
|
||||
return f
|
||||
}
|
||||
|
||||
// montReduce performs the montgomery reduction
|
||||
func (f *fp) montReduce(r *[2 * Limbs]uint64) *fp {
|
||||
// Taken from Algorithm 14.32 in Handbook of Applied Cryptography
|
||||
var r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, carry, k uint64
|
||||
var rr fp
|
||||
|
||||
k = r[0] * inv
|
||||
_, carry = mac(r[0], k, modulus[0], 0)
|
||||
r1, carry = mac(r[1], k, modulus[1], carry)
|
||||
r2, carry = mac(r[2], k, modulus[2], carry)
|
||||
r3, carry = mac(r[3], k, modulus[3], carry)
|
||||
r4, carry = mac(r[4], k, modulus[4], carry)
|
||||
r5, carry = mac(r[5], k, modulus[5], carry)
|
||||
r6, r7 = adc(r[6], 0, carry)
|
||||
|
||||
k = r1 * inv
|
||||
_, carry = mac(r1, k, modulus[0], 0)
|
||||
r2, carry = mac(r2, k, modulus[1], carry)
|
||||
r3, carry = mac(r3, k, modulus[2], carry)
|
||||
r4, carry = mac(r4, k, modulus[3], carry)
|
||||
r5, carry = mac(r5, k, modulus[4], carry)
|
||||
r6, carry = mac(r6, k, modulus[5], carry)
|
||||
r7, r8 = adc(r7, r[7], carry)
|
||||
|
||||
k = r2 * inv
|
||||
_, carry = mac(r2, k, modulus[0], 0)
|
||||
r3, carry = mac(r3, k, modulus[1], carry)
|
||||
r4, carry = mac(r4, k, modulus[2], carry)
|
||||
r5, carry = mac(r5, k, modulus[3], carry)
|
||||
r6, carry = mac(r6, k, modulus[4], carry)
|
||||
r7, carry = mac(r7, k, modulus[5], carry)
|
||||
r8, r9 = adc(r8, r[8], carry)
|
||||
|
||||
k = r3 * inv
|
||||
_, carry = mac(r3, k, modulus[0], 0)
|
||||
r4, carry = mac(r4, k, modulus[1], carry)
|
||||
r5, carry = mac(r5, k, modulus[2], carry)
|
||||
r6, carry = mac(r6, k, modulus[3], carry)
|
||||
r7, carry = mac(r7, k, modulus[4], carry)
|
||||
r8, carry = mac(r8, k, modulus[5], carry)
|
||||
r9, r10 = adc(r9, r[9], carry)
|
||||
|
||||
k = r4 * inv
|
||||
_, carry = mac(r4, k, modulus[0], 0)
|
||||
r5, carry = mac(r5, k, modulus[1], carry)
|
||||
r6, carry = mac(r6, k, modulus[2], carry)
|
||||
r7, carry = mac(r7, k, modulus[3], carry)
|
||||
r8, carry = mac(r8, k, modulus[4], carry)
|
||||
r9, carry = mac(r9, k, modulus[5], carry)
|
||||
r10, r11 = adc(r10, r[10], carry)
|
||||
|
||||
k = r5 * inv
|
||||
_, carry = mac(r5, k, modulus[0], 0)
|
||||
rr[0], carry = mac(r6, k, modulus[1], carry)
|
||||
rr[1], carry = mac(r7, k, modulus[2], carry)
|
||||
rr[2], carry = mac(r8, k, modulus[3], carry)
|
||||
rr[3], carry = mac(r9, k, modulus[4], carry)
|
||||
rr[4], carry = mac(r10, k, modulus[5], carry)
|
||||
rr[5], _ = adc(r11, r[11], carry)
|
||||
|
||||
return f.Sub(&rr, &modulus)
|
||||
}
|
@ -1,231 +0,0 @@
|
||||
package bls12381
|
||||
|
||||
import "io"
|
||||
|
||||
// fp12 represents an element a + b w of fp^12 = fp^6 / w^2 - v.
|
||||
type fp12 struct {
|
||||
A, B fp6
|
||||
}
|
||||
|
||||
// SetFp creates an element from a lower field
|
||||
func (f *fp12) SetFp(a *fp) *fp12 {
|
||||
f.A.SetFp(a)
|
||||
f.B.SetZero()
|
||||
return f
|
||||
}
|
||||
|
||||
// SetFp2 creates an element from a lower field
|
||||
func (f *fp12) SetFp2(a *fp2) *fp12 {
|
||||
f.A.SetFp2(a)
|
||||
f.B.SetZero()
|
||||
return f
|
||||
}
|
||||
|
||||
// SetFp6 creates an element from a lower field
|
||||
func (f *fp12) SetFp6(a *fp6) *fp12 {
|
||||
f.A.Set(a)
|
||||
f.B.SetZero()
|
||||
return f
|
||||
}
|
||||
|
||||
// Set copies the value `a`
|
||||
func (f *fp12) Set(a *fp12) *fp12 {
|
||||
f.A.Set(&a.A)
|
||||
f.B.Set(&a.B)
|
||||
return f
|
||||
}
|
||||
|
||||
// SetZero fp6 to zero
|
||||
func (f *fp12) SetZero() *fp12 {
|
||||
f.A.SetZero()
|
||||
f.B.SetZero()
|
||||
return f
|
||||
}
|
||||
|
||||
// SetOne fp6 to multiplicative identity element
|
||||
func (f *fp12) SetOne() *fp12 {
|
||||
f.A.SetOne()
|
||||
f.B.SetZero()
|
||||
return f
|
||||
}
|
||||
|
||||
// Random generates a random field element
|
||||
func (f *fp12) Random(reader io.Reader) (*fp12, error) {
|
||||
a, err := new(fp6).Random(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b, err := new(fp6).Random(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.A.Set(a)
|
||||
f.B.Set(b)
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// Square computes arg^2
|
||||
func (f *fp12) Square(arg *fp12) *fp12 {
|
||||
var ab, apb, aTick, bTick, t fp6
|
||||
|
||||
ab.Mul(&arg.A, &arg.B)
|
||||
apb.Add(&arg.A, &arg.B)
|
||||
|
||||
aTick.MulByNonResidue(&arg.B)
|
||||
aTick.Add(&aTick, &arg.A)
|
||||
aTick.Mul(&aTick, &apb)
|
||||
aTick.Sub(&aTick, &ab)
|
||||
t.MulByNonResidue(&ab)
|
||||
aTick.Sub(&aTick, &t)
|
||||
|
||||
bTick.Double(&ab)
|
||||
|
||||
f.A.Set(&aTick)
|
||||
f.B.Set(&bTick)
|
||||
return f
|
||||
}
|
||||
|
||||
// Invert computes this element's field inversion
|
||||
func (f *fp12) Invert(arg *fp12) (*fp12, int) {
|
||||
var a, b, t fp6
|
||||
a.Square(&arg.A)
|
||||
b.Square(&arg.B)
|
||||
b.MulByNonResidue(&b)
|
||||
a.Sub(&a, &b)
|
||||
_, wasInverted := t.Invert(&a)
|
||||
|
||||
a.Mul(&arg.A, &t)
|
||||
t.Neg(&t)
|
||||
b.Mul(&arg.B, &t)
|
||||
f.A.CMove(&f.A, &a, wasInverted)
|
||||
f.B.CMove(&f.B, &b, wasInverted)
|
||||
return f, wasInverted
|
||||
}
|
||||
|
||||
// Add computes arg1+arg2
|
||||
func (f *fp12) Add(arg1, arg2 *fp12) *fp12 {
|
||||
f.A.Add(&arg1.A, &arg2.A)
|
||||
f.B.Add(&arg1.B, &arg2.B)
|
||||
return f
|
||||
}
|
||||
|
||||
// Sub computes arg1-arg2
|
||||
func (f *fp12) Sub(arg1, arg2 *fp12) *fp12 {
|
||||
f.A.Sub(&arg1.A, &arg2.A)
|
||||
f.B.Sub(&arg1.B, &arg2.B)
|
||||
return f
|
||||
}
|
||||
|
||||
// Mul computes arg1*arg2
|
||||
func (f *fp12) Mul(arg1, arg2 *fp12) *fp12 {
|
||||
var aa, bb, a2b2, a, b fp6
|
||||
|
||||
aa.Mul(&arg1.A, &arg2.A)
|
||||
bb.Mul(&arg1.B, &arg2.B)
|
||||
a2b2.Add(&arg2.A, &arg2.B)
|
||||
b.Add(&arg1.A, &arg1.B)
|
||||
b.Mul(&b, &a2b2)
|
||||
b.Sub(&b, &aa)
|
||||
b.Sub(&b, &bb)
|
||||
a.MulByNonResidue(&bb)
|
||||
a.Add(&a, &aa)
|
||||
|
||||
f.A.Set(&a)
|
||||
f.B.Set(&b)
|
||||
return f
|
||||
}
|
||||
|
||||
// Neg computes the field negation
|
||||
func (f *fp12) Neg(arg *fp12) *fp12 {
|
||||
f.A.Neg(&arg.A)
|
||||
f.B.Neg(&arg.B)
|
||||
return f
|
||||
}
|
||||
|
||||
// MulByABD computes arg * a * b * c
|
||||
func (f *fp12) MulByABD(arg *fp12, a, b, d *fp2) *fp12 {
|
||||
var aa, bb, aTick, bTick fp6
|
||||
var bd fp2
|
||||
|
||||
aa.MulByAB(&arg.A, a, b)
|
||||
bb.MulByB(&arg.B, d)
|
||||
bd.Add(b, d)
|
||||
|
||||
bTick.Add(&arg.A, &arg.B)
|
||||
bTick.MulByAB(&bTick, a, &bd)
|
||||
bTick.Sub(&bTick, &aa)
|
||||
bTick.Sub(&bTick, &bb)
|
||||
|
||||
aTick.MulByNonResidue(&bb)
|
||||
aTick.Add(&aTick, &aa)
|
||||
|
||||
f.A.Set(&aTick)
|
||||
f.B.Set(&bTick)
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
// Conjugate computes the field conjugation
|
||||
func (f *fp12) Conjugate(arg *fp12) *fp12 {
|
||||
f.A.Set(&arg.A)
|
||||
f.B.Neg(&arg.B)
|
||||
return f
|
||||
}
|
||||
|
||||
// FrobeniusMap raises this element to p.
|
||||
func (f *fp12) FrobeniusMap(arg *fp12) *fp12 {
|
||||
var a, b, up1epm1div6 fp6
|
||||
|
||||
// (u + 1)^((p - 1) / 6)
|
||||
up1epm1div6.A = fp2{
|
||||
A: fp{
|
||||
0x07089552b319d465,
|
||||
0xc6695f92b50a8313,
|
||||
0x97e83cccd117228f,
|
||||
0xa35baecab2dc29ee,
|
||||
0x1ce393ea5daace4d,
|
||||
0x08f2220fb0fb66eb,
|
||||
},
|
||||
B: fp{
|
||||
0xb2f66aad4ce5d646,
|
||||
0x5842a06bfc497cec,
|
||||
0xcf4895d42599d394,
|
||||
0xc11b9cba40a8e8d0,
|
||||
0x2e3813cbe5a0de89,
|
||||
0x110eefda88847faf,
|
||||
},
|
||||
}
|
||||
|
||||
a.FrobeniusMap(&arg.A)
|
||||
b.FrobeniusMap(&arg.B)
|
||||
|
||||
// b' = b' * (u + 1)^((p - 1) / 6)
|
||||
b.Mul(&b, &up1epm1div6)
|
||||
|
||||
f.A.Set(&a)
|
||||
f.B.Set(&b)
|
||||
return f
|
||||
}
|
||||
|
||||
// Equal returns 1 if fp12 == rhs, 0 otherwise
|
||||
func (f *fp12) Equal(rhs *fp12) int {
|
||||
return f.A.Equal(&rhs.A) & f.B.Equal(&rhs.B)
|
||||
}
|
||||
|
||||
// IsZero returns 1 if fp6 == 0, 0 otherwise
|
||||
func (f *fp12) IsZero() int {
|
||||
return f.A.IsZero() & f.B.IsZero()
|
||||
}
|
||||
|
||||
// IsOne returns 1 if fp12 == 1, 0 otherwise
|
||||
func (f *fp12) IsOne() int {
|
||||
return f.A.IsOne() & f.B.IsZero()
|
||||
}
|
||||
|
||||
// CMove performs conditional select.
|
||||
// selects arg1 if choice == 0 and arg2 if choice == 1
|
||||
func (f *fp12) CMove(arg1, arg2 *fp12, choice int) *fp12 {
|
||||
f.A.CMove(&arg1.A, &arg2.A, choice)
|
||||
f.B.CMove(&arg1.B, &arg2.B, choice)
|
||||
return f
|
||||
}
|
@ -1,417 +0,0 @@
|
||||
package bls12381
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFp12Arithmetic(t *testing.T) {
|
||||
var aa, bb, cc, d, e, f fp12
|
||||
a := fp12{
|
||||
A: fp6{
|
||||
A: fp2{
|
||||
A: fp{
|
||||
0x47f9cb98b1b82d58,
|
||||
0x5fe911eba3aa1d9d,
|
||||
0x96bf1b5f4dd81db3,
|
||||
0x8100d27cc9259f5b,
|
||||
0xafa20b9674640eab,
|
||||
0x09bbcea7d8d9497d,
|
||||
},
|
||||
B: fp{
|
||||
0x0303cb98b1662daa,
|
||||
0xd93110aa0a621d5a,
|
||||
0xbfa9820c5be4a468,
|
||||
0x0ba3643ecb05a348,
|
||||
0xdc3534bb1f1c25a6,
|
||||
0x06c305bb19c0e1c1,
|
||||
},
|
||||
},
|
||||
B: fp2{
|
||||
A: fp{
|
||||
0x46f9cb98b162d858,
|
||||
0x0be9109cf7aa1d57,
|
||||
0xc791bc55fece41d2,
|
||||
0xf84c57704e385ec2,
|
||||
0xcb49c1d9c010e60f,
|
||||
0x0acdb8e158bfe3c8,
|
||||
},
|
||||
B: fp{
|
||||
0x8aefcb98b15f8306,
|
||||
0x3ea1108fe4f21d54,
|
||||
0xcf79f69fa1b7df3b,
|
||||
0xe4f54aa1d16b1a3c,
|
||||
0xba5e4ef86105a679,
|
||||
0x0ed86c0797bee5cf,
|
||||
},
|
||||
},
|
||||
C: fp2{
|
||||
A: fp{
|
||||
0xcee5cb98b15c2db4,
|
||||
0x71591082d23a1d51,
|
||||
0xd76230e944a17ca4,
|
||||
0xd19e3dd3549dd5b6,
|
||||
0xa972dc1701fa66e3,
|
||||
0x12e31f2dd6bde7d6,
|
||||
},
|
||||
B: fp{
|
||||
0xad2acb98b1732d9d,
|
||||
0x2cfd10dd06961d64,
|
||||
0x07396b86c6ef24e8,
|
||||
0xbd76e2fdb1bfc820,
|
||||
0x6afea7f6de94d0d5,
|
||||
0x10994b0c5744c040,
|
||||
},
|
||||
},
|
||||
},
|
||||
B: fp6{
|
||||
A: fp2{
|
||||
A: fp{
|
||||
0x47f9cb98b1b82d58,
|
||||
0x5fe911eba3aa1d9d,
|
||||
0x96bf1b5f4dd81db3,
|
||||
0x8100d27cc9259f5b,
|
||||
0xafa20b9674640eab,
|
||||
0x09bbcea7d8d9497d,
|
||||
},
|
||||
B: fp{
|
||||
0x0303cb98b1662daa,
|
||||
0xd93110aa0a621d5a,
|
||||
0xbfa9820c5be4a468,
|
||||
0x0ba3643ecb05a348,
|
||||
0xdc3534bb1f1c25a6,
|
||||
0x06c305bb19c0e1c1,
|
||||
},
|
||||
},
|
||||
B: fp2{
|
||||
A: fp{
|
||||
0x46f9cb98b162d858,
|
||||
0x0be9109cf7aa1d57,
|
||||
0xc791bc55fece41d2,
|
||||
0xf84c57704e385ec2,
|
||||
0xcb49c1d9c010e60f,
|
||||
0x0acdb8e158bfe3c8,
|
||||
},
|
||||
B: fp{
|
||||
0x8aefcb98b15f8306,
|
||||
0x3ea1108fe4f21d54,
|
||||
0xcf79f69fa1b7df3b,
|
||||
0xe4f54aa1d16b1a3c,
|
||||
0xba5e4ef86105a679,
|
||||
0x0ed86c0797bee5cf,
|
||||
},
|
||||
},
|
||||
C: fp2{
|
||||
A: fp{
|
||||
0xcee5cb98b15c2db4,
|
||||
0x71591082d23a1d51,
|
||||
0xd76230e944a17ca4,
|
||||
0xd19e3dd3549dd5b6,
|
||||
0xa972dc1701fa66e3,
|
||||
0x12e31f2dd6bde7d6,
|
||||
},
|
||||
B: fp{
|
||||
0xad2acb98b1732d9d,
|
||||
0x2cfd10dd06961d64,
|
||||
0x07396b86c6ef24e8,
|
||||
0xbd76e2fdb1bfc820,
|
||||
0x6afea7f6de94d0d5,
|
||||
0x10994b0c5744c040,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
b := fp12{
|
||||
A: fp6{
|
||||
A: fp2{
|
||||
A: fp{
|
||||
0x47f9_cb98_b1b8_2d58,
|
||||
0x5fe9_11eb_a3aa_1d9d,
|
||||
0x96bf_1b5f_4dd8_1db3,
|
||||
0x8100_d272_c925_9f5b,
|
||||
0xafa2_0b96_7464_0eab,
|
||||
0x09bb_cea7_d8d9_497d,
|
||||
},
|
||||
B: fp{
|
||||
0x0303_cb98_b166_2daa,
|
||||
0xd931_10aa_0a62_1d5a,
|
||||
0xbfa9_820c_5be4_a468,
|
||||
0x0ba3_643e_cb05_a348,
|
||||
0xdc35_34bb_1f1c_25a6,
|
||||
0x06c3_05bb_19c0_e1c1,
|
||||
},
|
||||
},
|
||||
B: fp2{
|
||||
A: fp{
|
||||
0x46f9_cb98_b162_d858,
|
||||
0x0be9_109c_f7aa_1d57,
|
||||
0xc791_bc55_fece_41d2,
|
||||
0xf84c_5770_4e38_5ec2,
|
||||
0xcb49_c1d9_c010_e60f,
|
||||
0x0acd_b8e1_58bf_e348,
|
||||
},
|
||||
B: fp{
|
||||
0x8aef_cb98_b15f_8306,
|
||||
0x3ea1_108f_e4f2_1d54,
|
||||
0xcf79_f69f_a1b7_df3b,
|
||||
0xe4f5_4aa1_d16b_1a3c,
|
||||
0xba5e_4ef8_6105_a679,
|
||||
0x0ed8_6c07_97be_e5cf,
|
||||
},
|
||||
},
|
||||
C: fp2{
|
||||
A: fp{
|
||||
0xcee5_cb98_b15c_2db4,
|
||||
0x7159_1082_d23a_1d51,
|
||||
0xd762_30e9_44a1_7ca4,
|
||||
0xd19e_3dd3_549d_d5b6,
|
||||
0xa972_dc17_01fa_66e3,
|
||||
0x12e3_1f2d_d6bd_e7d6,
|
||||
},
|
||||
B: fp{
|
||||
0xad2a_cb98_b173_2d9d,
|
||||
0x2cfd_10dd_0696_1d64,
|
||||
0x0739_6b86_c6ef_24e8,
|
||||
0xbd76_e2fd_b1bf_c820,
|
||||
0x6afe_a7f6_de94_d0d5,
|
||||
0x1099_4b0c_5744_c040,
|
||||
},
|
||||
},
|
||||
},
|
||||
B: fp6{
|
||||
A: fp2{
|
||||
A: fp{
|
||||
0x47f9_cb98_b1b8_2d58,
|
||||
0x5fe9_11eb_a3aa_1d9d,
|
||||
0x96bf_1b5f_4dd2_1db3,
|
||||
0x8100_d27c_c925_9f5b,
|
||||
0xafa2_0b96_7464_0eab,
|
||||
0x09bb_cea7_d8d9_497d,
|
||||
},
|
||||
B: fp{
|
||||
0x0303_cb98_b166_2daa,
|
||||
0xd931_10aa_0a62_1d5a,
|
||||
0xbfa9_820c_5be4_a468,
|
||||
0x0ba3_643e_cb05_a348,
|
||||
0xdc35_34bb_1f1c_25a6,
|
||||
0x06c3_05bb_19c0_e1c1,
|
||||
},
|
||||
},
|
||||
B: fp2{
|
||||
A: fp{
|
||||
0x46f9_cb98_b162_d858,
|
||||
0x0be9_109c_f7aa_1d57,
|
||||
0xc791_bc55_fece_41d2,
|
||||
0xf84c_5770_4e38_5ec2,
|
||||
0xcb49_c1d9_c010_e60f,
|
||||
0x0acd_b8e1_58bf_e3c8,
|
||||
},
|
||||
B: fp{
|
||||
0x8aef_cb98_b15f_8306,
|
||||
0x3ea1_108f_e4f2_1d54,
|
||||
0xcf79_f69f_a117_df3b,
|
||||
0xe4f5_4aa1_d16b_1a3c,
|
||||
0xba5e_4ef8_6105_a679,
|
||||
0x0ed8_6c07_97be_e5cf,
|
||||
},
|
||||
},
|
||||
C: fp2{
|
||||
A: fp{
|
||||
0xcee5_cb98_b15c_2db4,
|
||||
0x7159_1082_d23a_1d51,
|
||||
0xd762_30e9_44a1_7ca4,
|
||||
0xd19e_3dd3_549d_d5b6,
|
||||
0xa972_dc17_01fa_66e3,
|
||||
0x12e3_1f2d_d6bd_e7d6,
|
||||
},
|
||||
B: fp{
|
||||
0xad2a_cb98_b173_2d9d,
|
||||
0x2cfd_10dd_0696_1d64,
|
||||
0x0739_6b86_c6ef_24e8,
|
||||
0xbd76_e2fd_b1bf_c820,
|
||||
0x6afe_a7f6_de94_d0d5,
|
||||
0x1099_4b0c_5744_c040,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
c := fp12{
|
||||
A: fp6{
|
||||
A: fp2{
|
||||
A: fp{
|
||||
0x47f9_cb98_71b8_2d58,
|
||||
0x5fe9_11eb_a3aa_1d9d,
|
||||
0x96bf_1b5f_4dd8_1db3,
|
||||
0x8100_d27c_c925_9f5b,
|
||||
0xafa2_0b96_7464_0eab,
|
||||
0x09bb_cea7_d8d9_497d,
|
||||
},
|
||||
B: fp{
|
||||
0x0303_cb98_b166_2daa,
|
||||
0xd931_10aa_0a62_1d5a,
|
||||
0xbfa9_820c_5be4_a468,
|
||||
0x0ba3_643e_cb05_a348,
|
||||
0xdc35_34bb_1f1c_25a6,
|
||||
0x06c3_05bb_19c0_e1c1,
|
||||
},
|
||||
},
|
||||
B: fp2{
|
||||
A: fp{
|
||||
0x46f9_cb98_b162_d858,
|
||||
0x0be9_109c_f7aa_1d57,
|
||||
0x7791_bc55_fece_41d2,
|
||||
0xf84c_5770_4e38_5ec2,
|
||||
0xcb49_c1d9_c010_e60f,
|
||||
0x0acd_b8e1_58bf_e3c8,
|
||||
},
|
||||
B: fp{
|
||||
0x8aef_cb98_b15f_8306,
|
||||
0x3ea1_108f_e4f2_1d54,
|
||||
0xcf79_f69f_a1b7_df3b,
|
||||
0xe4f5_4aa1_d16b_133c,
|
||||
0xba5e_4ef8_6105_a679,
|
||||
0x0ed8_6c07_97be_e5cf,
|
||||
},
|
||||
},
|
||||
C: fp2{
|
||||
A: fp{
|
||||
0xcee5_cb98_b15c_2db4,
|
||||
0x7159_1082_d23a_1d51,
|
||||
0xd762_40e9_44a1_7ca4,
|
||||
0xd19e_3dd3_549d_d5b6,
|
||||
0xa972_dc17_01fa_66e3,
|
||||
0x12e3_1f2d_d6bd_e7d6,
|
||||
},
|
||||
B: fp{
|
||||
0xad2a_cb98_b173_2d9d,
|
||||
0x2cfd_10dd_0696_1d64,
|
||||
0x0739_6b86_c6ef_24e8,
|
||||
0xbd76_e2fd_b1bf_c820,
|
||||
0x6afe_a7f6_de94_d0d5,
|
||||
0x1099_4b0c_1744_c040,
|
||||
},
|
||||
},
|
||||
},
|
||||
B: fp6{
|
||||
A: fp2{
|
||||
A: fp{
|
||||
0x47f9_cb98_b1b8_2d58,
|
||||
0x5fe9_11eb_a3aa_1d9d,
|
||||
0x96bf_1b5f_4dd8_1db3,
|
||||
0x8100_d27c_c925_9f5b,
|
||||
0xafa2_0b96_7464_0eab,
|
||||
0x09bb_cea7_d8d9_497d,
|
||||
},
|
||||
B: fp{
|
||||
0x0303_cb98_b166_2daa,
|
||||
0xd931_10aa_0a62_1d5a,
|
||||
0xbfa9_820c_5be4_a468,
|
||||
0x0ba3_643e_cb05_a348,
|
||||
0xdc35_34bb_1f1c_25a6,
|
||||
0x06c3_05bb_19c0_e1c1,
|
||||
},
|
||||
},
|
||||
B: fp2{
|
||||
A: fp{
|
||||
0x46f9_cb98_b162_d858,
|
||||
0x0be9_109c_f7aa_1d57,
|
||||
0xc791_bc55_fece_41d2,
|
||||
0xf84c_5770_4e38_5ec2,
|
||||
0xcb49_c1d3_c010_e60f,
|
||||
0x0acd_b8e1_58bf_e3c8,
|
||||
},
|
||||
B: fp{
|
||||
0x8aef_cb98_b15f_8306,
|
||||
0x3ea1_108f_e4f2_1d54,
|
||||
0xcf79_f69f_a1b7_df3b,
|
||||
0xe4f5_4aa1_d16b_1a3c,
|
||||
0xba5e_4ef8_6105_a679,
|
||||
0x0ed8_6c07_97be_e5cf,
|
||||
},
|
||||
},
|
||||
C: fp2{
|
||||
A: fp{
|
||||
0xcee5_cb98_b15c_2db4,
|
||||
0x7159_1082_d23a_1d51,
|
||||
0xd762_30e9_44a1_7ca4,
|
||||
0xd19e_3dd3_549d_d5b6,
|
||||
0xa972_dc17_01fa_66e3,
|
||||
0x12e3_1f2d_d6bd_e7d6,
|
||||
},
|
||||
B: fp{
|
||||
0xad2a_cb98_b173_2d9d,
|
||||
0x2cfd_10dd_0696_1d64,
|
||||
0x0739_6b86_c6ef_24e8,
|
||||
0xbd76_e2fd_b1bf_c820,
|
||||
0x6afe_a7f6_de94_d0d5,
|
||||
0x1099_4b0c_5744_1040,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
aa.Square(&a)
|
||||
aa.Invert(&aa)
|
||||
aa.Square(&aa)
|
||||
aa.Add(&aa, &c)
|
||||
|
||||
bb.Square(&b)
|
||||
bb.Invert(&bb)
|
||||
bb.Square(&bb)
|
||||
bb.Add(&bb, &aa)
|
||||
|
||||
cc.Square(&c)
|
||||
cc.Invert(&cc)
|
||||
cc.Square(&cc)
|
||||
cc.Add(&cc, &bb)
|
||||
|
||||
d.Square(&aa)
|
||||
e.Mul(&aa, &aa)
|
||||
require.Equal(t, 1, e.Equal(&d))
|
||||
|
||||
d.Square(&bb)
|
||||
e.Mul(&bb, &bb)
|
||||
require.Equal(t, 1, e.Equal(&d))
|
||||
|
||||
d.Square(&cc)
|
||||
e.Mul(&cc, &cc)
|
||||
require.Equal(t, 1, e.Equal(&d))
|
||||
|
||||
d.Square(&cc)
|
||||
e.Add(&aa, &bb)
|
||||
d.Mul(&d, &e)
|
||||
|
||||
e.Mul(&cc, &cc)
|
||||
e.Mul(&e, &aa)
|
||||
f.Mul(&cc, &cc)
|
||||
f.Mul(&f, &bb)
|
||||
e.Add(&e, &f)
|
||||
|
||||
require.Equal(t, 1, e.Equal(&d))
|
||||
|
||||
d.Invert(&aa)
|
||||
e.Invert(&bb)
|
||||
f.Mul(&aa, &bb)
|
||||
f.Invert(&f)
|
||||
require.Equal(t, 1, f.Equal(e.Mul(&e, &d)))
|
||||
|
||||
require.Equal(t, 1, d.Mul(&d, &aa).IsOne())
|
||||
|
||||
require.Equal(t, 0, aa.Equal(d.FrobeniusMap(&aa)))
|
||||
d.FrobeniusMap(&aa).
|
||||
FrobeniusMap(&d).
|
||||
FrobeniusMap(&d).
|
||||
FrobeniusMap(&d).
|
||||
FrobeniusMap(&d).
|
||||
FrobeniusMap(&d).
|
||||
FrobeniusMap(&d).
|
||||
FrobeniusMap(&d).
|
||||
FrobeniusMap(&d).
|
||||
FrobeniusMap(&d).
|
||||
FrobeniusMap(&d).
|
||||
FrobeniusMap(&d)
|
||||
require.Equal(t, 1, aa.Equal(&d))
|
||||
}
|
@ -1,344 +0,0 @@
|
||||
package bls12381
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// fp2 is a point in p^2
|
||||
type fp2 struct {
|
||||
A, B fp
|
||||
}
|
||||
|
||||
// Set copies a into fp2
|
||||
func (f *fp2) Set(a *fp2) *fp2 {
|
||||
f.A.Set(&a.A)
|
||||
f.B.Set(&a.B)
|
||||
return f
|
||||
}
|
||||
|
||||
// SetZero fp2 = 0
|
||||
func (f *fp2) SetZero() *fp2 {
|
||||
f.A.SetZero()
|
||||
f.B.SetZero()
|
||||
return f
|
||||
}
|
||||
|
||||
// SetOne fp2 to the multiplicative identity element
|
||||
func (f *fp2) SetOne() *fp2 {
|
||||
f.A.SetOne()
|
||||
f.B.SetZero()
|
||||
return f
|
||||
}
|
||||
|
||||
// SetFp creates an element from a lower field
|
||||
func (f *fp2) SetFp(a *fp) *fp2 {
|
||||
f.A.Set(a)
|
||||
f.B.SetZero()
|
||||
return f
|
||||
}
|
||||
|
||||
// Random generates a random field element
|
||||
func (f *fp2) Random(reader io.Reader) (*fp2, error) {
|
||||
a, err := new(fp).Random(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b, err := new(fp).Random(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.A = *a
|
||||
f.B = *b
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// IsZero returns 1 if fp2 == 0, 0 otherwise
|
||||
func (f *fp2) IsZero() int {
|
||||
return f.A.IsZero() & f.B.IsZero()
|
||||
}
|
||||
|
||||
// IsOne returns 1 if fp2 == 1, 0 otherwise
|
||||
func (f *fp2) IsOne() int {
|
||||
return f.A.IsOne() & f.B.IsZero()
|
||||
}
|
||||
|
||||
// Equal returns 1 if f == rhs, 0 otherwise
|
||||
func (f *fp2) Equal(rhs *fp2) int {
|
||||
return f.A.Equal(&rhs.A) & f.B.Equal(&rhs.B)
|
||||
}
|
||||
|
||||
// LexicographicallyLargest returns 1 if
|
||||
// this element is strictly lexicographically larger than its negation
|
||||
// 0 otherwise
|
||||
func (f *fp2) LexicographicallyLargest() int {
|
||||
// If this element's B coefficient is lexicographically largest
|
||||
// then it is lexicographically largest. Otherwise, in the event
|
||||
// the B coefficient is zero and the A coefficient is
|
||||
// lexicographically largest, then this element is lexicographically
|
||||
// largest.
|
||||
|
||||
return f.B.LexicographicallyLargest() |
|
||||
f.B.IsZero()&f.A.LexicographicallyLargest()
|
||||
}
|
||||
|
||||
// Sgn0 returns the lowest bit value
|
||||
func (f *fp2) Sgn0() int {
|
||||
// if A = 0 return B.Sgn0 else A.Sgn0
|
||||
a := f.A.IsZero()
|
||||
t := f.B.Sgn0() & a
|
||||
a = -a + 1
|
||||
t |= f.A.Sgn0() & a
|
||||
return t
|
||||
}
|
||||
|
||||
// FrobeniusMap raises this element to p.
|
||||
func (f *fp2) FrobeniusMap(a *fp2) *fp2 {
|
||||
// This is always just a conjugation. If you're curious why, here's
|
||||
// an article about it: https://alicebob.cryptoland.net/the-frobenius-endomorphism-with-finite-fields/
|
||||
return f.Conjugate(a)
|
||||
}
|
||||
|
||||
// Conjugate computes the conjugation of this element
|
||||
func (f *fp2) Conjugate(a *fp2) *fp2 {
|
||||
f.A.Set(&a.A)
|
||||
f.B.Neg(&a.B)
|
||||
return f
|
||||
}
|
||||
|
||||
// MulByNonResidue computes the following:
|
||||
// multiply a + bu by u + 1, getting
|
||||
// au + a + bu^2 + bu
|
||||
// and because u^2 = -1, we get
|
||||
// (a - b) + (a + b)u
|
||||
func (f *fp2) MulByNonResidue(a *fp2) *fp2 {
|
||||
var aa, bb fp
|
||||
aa.Sub(&a.A, &a.B)
|
||||
bb.Add(&a.A, &a.B)
|
||||
f.A.Set(&aa)
|
||||
f.B.Set(&bb)
|
||||
return f
|
||||
}
|
||||
|
||||
// Square computes the square of this element
|
||||
func (f *fp2) Square(arg *fp2) *fp2 {
|
||||
var a, b, c fp
|
||||
|
||||
// Complex squaring:
|
||||
//
|
||||
// v0 = a * b
|
||||
// a' = (a + b) * (a + \beta*b) - v0 - \beta * v0
|
||||
// b' = 2 * v0
|
||||
//
|
||||
// In BLS12-381's F_{p^2}, our \beta is -1, so we
|
||||
// can modify this formula:
|
||||
//
|
||||
// a' = (a + b) * (a - b)
|
||||
// b' = 2 * a * b
|
||||
a.Add(&arg.A, &arg.B)
|
||||
b.Sub(&arg.A, &arg.B)
|
||||
c.Add(&arg.A, &arg.A)
|
||||
|
||||
f.A.Mul(&a, &b)
|
||||
f.B.Mul(&c, &arg.B)
|
||||
return f
|
||||
}
|
||||
|
||||
// Add performs field addition
|
||||
func (f *fp2) Add(arg1, arg2 *fp2) *fp2 {
|
||||
f.A.Add(&arg1.A, &arg2.A)
|
||||
f.B.Add(&arg1.B, &arg2.B)
|
||||
return f
|
||||
}
|
||||
|
||||
// Double doubles specified element
|
||||
func (f *fp2) Double(a *fp2) *fp2 {
|
||||
f.A.Double(&a.A)
|
||||
f.B.Double(&a.B)
|
||||
return f
|
||||
}
|
||||
|
||||
// Sub performs field subtraction
|
||||
func (f *fp2) Sub(arg1, arg2 *fp2) *fp2 {
|
||||
f.A.Sub(&arg1.A, &arg2.A)
|
||||
f.B.Sub(&arg1.B, &arg2.B)
|
||||
return f
|
||||
}
|
||||
|
||||
// Mul computes Karatsuba multiplication
|
||||
func (f *fp2) Mul(arg1, arg2 *fp2) *fp2 {
|
||||
var v0, v1, t, a, b fp
|
||||
|
||||
// Karatsuba multiplication:
|
||||
//
|
||||
// v0 = a0 * b0
|
||||
// v1 = a1 * b1
|
||||
// c0 = v0 + \beta * v1
|
||||
// c1 = (a0 + a1) * (b0 + b1) - v0 - v1
|
||||
//
|
||||
// In BLS12-381's F_{p^2}, our \beta is -1, so we
|
||||
// can modify this formula. (Also, since we always
|
||||
// subtract v1, we can compute v1 = -a1 * b1.)
|
||||
//
|
||||
// v0 = a0 * a1
|
||||
// v1 = (-b0) * b1
|
||||
// a' = v0 + v1
|
||||
// b' = (a0 + b0) * (a1 + b1) - v0 + v1
|
||||
v0.Mul(&arg1.A, &arg2.A)
|
||||
v1.Mul(new(fp).Neg(&arg1.B), &arg2.B)
|
||||
|
||||
a.Add(&v0, &v1)
|
||||
b.Add(&arg1.A, &arg1.B)
|
||||
t.Add(&arg2.A, &arg2.B)
|
||||
b.Mul(&b, &t)
|
||||
b.Sub(&b, &v0)
|
||||
b.Add(&b, &v1)
|
||||
f.A.Set(&a)
|
||||
f.B.Set(&b)
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *fp2) Mul0(arg1 *fp2, arg2 *fp) *fp2 {
|
||||
f.A.Mul(&arg1.A, arg2)
|
||||
f.B.Mul(&arg1.B, arg2)
|
||||
return f
|
||||
}
|
||||
|
||||
// MulBy3b returns arg * 12 or 3 * b
|
||||
func (f *fp2) MulBy3b(arg *fp2) *fp2 {
|
||||
return f.Mul(arg, &curveG23B)
|
||||
}
|
||||
|
||||
// Neg performs field negation
|
||||
func (f *fp2) Neg(a *fp2) *fp2 {
|
||||
f.A.Neg(&a.A)
|
||||
f.B.Neg(&a.B)
|
||||
return f
|
||||
}
|
||||
|
||||
// Sqrt performs field square root
|
||||
func (f *fp2) Sqrt(a *fp2) (*fp2, int) {
|
||||
// Algorithm 9, https://eprint.iacr.org/2012/685.pdf
|
||||
// with constant time modifications.
|
||||
var a1, alpha, x0, t, res, res2 fp2
|
||||
e1 := a.IsZero()
|
||||
// a1 = self^((p - 3) / 4)
|
||||
a1.pow(a, &[Limbs]uint64{
|
||||
0xee7fbfffffffeaaa,
|
||||
0x07aaffffac54ffff,
|
||||
0xd9cc34a83dac3d89,
|
||||
0xd91dd2e13ce144af,
|
||||
0x92c6e9ed90d2eb35,
|
||||
0x0680447a8e5ff9a6,
|
||||
})
|
||||
|
||||
// alpha = a1^2 * a = a^((p - 3) / 2 + 1) = a^((p - 1) / 2)
|
||||
alpha.Square(&a1)
|
||||
alpha.Mul(&alpha, a)
|
||||
|
||||
// x0 = self^((p + 1) / 4)
|
||||
x0.Mul(&a1, a)
|
||||
|
||||
// In the event that alpha = -1, the element is order p - 1. So
|
||||
// we're just trying to get the square of an element of the subfield
|
||||
// fp. This is given by x0 * u, since u = sqrt(-1). Since the element
|
||||
// x0 = a + bu has b = 0, the solution is therefore au.
|
||||
res2.A.Neg(&x0.B)
|
||||
res2.B.Set(&x0.A)
|
||||
// alpha == -1
|
||||
e2 := alpha.Equal(&fp2{
|
||||
A: fp{
|
||||
0x43f5fffffffcaaae,
|
||||
0x32b7fff2ed47fffd,
|
||||
0x07e83a49a2e99d69,
|
||||
0xeca8f3318332bb7a,
|
||||
0xef148d1ea0f4c069,
|
||||
0x040ab3263eff0206,
|
||||
},
|
||||
B: fp{},
|
||||
})
|
||||
|
||||
// Otherwise, the correct solution is (1 + alpha)^((p - 1) // 2) * x0
|
||||
t.SetOne()
|
||||
t.Add(&t, &alpha)
|
||||
t.pow(&t, &[Limbs]uint64{
|
||||
0xdcff7fffffffd555,
|
||||
0x0f55ffff58a9ffff,
|
||||
0xb39869507b587b12,
|
||||
0xb23ba5c279c2895f,
|
||||
0x258dd3db21a5d66b,
|
||||
0x0d0088f51cbff34d,
|
||||
})
|
||||
t.Mul(&t, &x0)
|
||||
// if a = 0, then its zero
|
||||
res.CMove(&res2, &res, e1)
|
||||
// if alpha = -1, its not (1 + alpha)^((p - 1) // 2) * x0
|
||||
// but au
|
||||
res.CMove(&t, &res, e2)
|
||||
|
||||
// is the result^2 = a
|
||||
t.Square(&res)
|
||||
e3 := t.Equal(a)
|
||||
f.CMove(f, &res, e3)
|
||||
return f, e3
|
||||
}
|
||||
|
||||
// Invert computes the multiplicative inverse of this field
|
||||
// element, returning the original value of fp2
|
||||
// in the case that this element is zero.
|
||||
func (f *fp2) Invert(arg *fp2) (*fp2, int) {
|
||||
// We wish to find the multiplicative inverse of a nonzero
|
||||
// element a + bu in fp2. We leverage an identity
|
||||
//
|
||||
// (a + bu)(a - bu) = a^2 + b^2
|
||||
//
|
||||
// which holds because u^2 = -1. This can be rewritten as
|
||||
//
|
||||
// (a + bu)(a - bu)/(a^2 + b^2) = 1
|
||||
//
|
||||
// because a^2 + b^2 = 0 has no nonzero solutions for (a, b).
|
||||
// This gives that (a - bu)/(a^2 + b^2) is the inverse
|
||||
// of (a + bu). Importantly, this can be computing using
|
||||
// only a single inversion in fp.
|
||||
var a, b, t fp
|
||||
a.Square(&arg.A)
|
||||
b.Square(&arg.B)
|
||||
a.Add(&a, &b)
|
||||
_, wasInverted := t.Invert(&a)
|
||||
// a * t
|
||||
a.Mul(&arg.A, &t)
|
||||
// b * -t
|
||||
b.Neg(&t)
|
||||
b.Mul(&b, &arg.B)
|
||||
f.A.CMove(&f.A, &a, wasInverted)
|
||||
f.B.CMove(&f.B, &b, wasInverted)
|
||||
return f, wasInverted
|
||||
}
|
||||
|
||||
// CMove performs conditional select.
|
||||
// selects arg1 if choice == 0 and arg2 if choice == 1
|
||||
func (f *fp2) CMove(arg1, arg2 *fp2, choice int) *fp2 {
|
||||
f.A.CMove(&arg1.A, &arg2.A, choice)
|
||||
f.B.CMove(&arg1.B, &arg2.B, choice)
|
||||
return f
|
||||
}
|
||||
|
||||
// CNeg conditionally negates a if choice == 1
|
||||
func (f *fp2) CNeg(a *fp2, choice int) *fp2 {
|
||||
var t fp2
|
||||
t.Neg(a)
|
||||
return f.CMove(f, &t, choice)
|
||||
}
|
||||
|
||||
func (f *fp2) pow(base *fp2, exp *[Limbs]uint64) *fp2 {
|
||||
res := (&fp2{}).SetOne()
|
||||
tmp := (&fp2{}).SetZero()
|
||||
|
||||
for i := len(exp) - 1; i >= 0; i-- {
|
||||
for j := 63; j >= 0; j-- {
|
||||
res.Square(res)
|
||||
tmp.Mul(res, base)
|
||||
res.CMove(res, tmp, int(exp[i]>>j)&1)
|
||||
}
|
||||
}
|
||||
return f.Set(res)
|
||||
}
|
@ -1,424 +0,0 @@
|
||||
package bls12381
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFp2Square(t *testing.T) {
|
||||
a := fp2{
|
||||
A: fp{
|
||||
0xc9a2183163ee70d4,
|
||||
0xbc3770a7196b5c91,
|
||||
0xa247f8c1304c5f44,
|
||||
0xb01fc2a3726c80b5,
|
||||
0xe1d293e5bbd919c9,
|
||||
0x04b78e80020ef2ca,
|
||||
},
|
||||
B: fp{
|
||||
0x952ea4460462618f,
|
||||
0x238d5eddf025c62f,
|
||||
0xf6c94b012ea92e72,
|
||||
0x03ce24eac1c93808,
|
||||
0x055950f945da483c,
|
||||
0x010a768d0df4eabc,
|
||||
},
|
||||
}
|
||||
b := fp2{
|
||||
A: fp{
|
||||
0xa1e09175a4d2c1fe,
|
||||
0x8b33acfc204eff12,
|
||||
0xe24415a11b456e42,
|
||||
0x61d996b1b6ee1936,
|
||||
0x1164dbe8667c853c,
|
||||
0x0788557acc7d9c79,
|
||||
},
|
||||
B: fp{
|
||||
0xda6a87cc6f48fa36,
|
||||
0x0fc7b488277c1903,
|
||||
0x9445ac4adc448187,
|
||||
0x02616d5bc9099209,
|
||||
0xdbed46772db58d48,
|
||||
0x11b94d5076c7b7b1,
|
||||
},
|
||||
}
|
||||
|
||||
require.Equal(t, &b, a.Square(&a))
|
||||
}
|
||||
|
||||
func TestFp2Mul(t *testing.T) {
|
||||
a := fp2{
|
||||
A: fp{
|
||||
0xc9a2183163ee70d4,
|
||||
0xbc3770a7196b5c91,
|
||||
0xa247f8c1304c5f44,
|
||||
0xb01fc2a3726c80b5,
|
||||
0xe1d293e5bbd919c9,
|
||||
0x04b78e80020ef2ca,
|
||||
},
|
||||
B: fp{
|
||||
0x952ea4460462618f,
|
||||
0x238d5eddf025c62f,
|
||||
0xf6c94b012ea92e72,
|
||||
0x03ce24eac1c93808,
|
||||
0x055950f945da483c,
|
||||
0x010a768d0df4eabc,
|
||||
},
|
||||
}
|
||||
b := fp2{
|
||||
A: fp{
|
||||
0xa1e09175a4d2c1fe,
|
||||
0x8b33acfc204eff12,
|
||||
0xe24415a11b456e42,
|
||||
0x61d996b1b6ee1936,
|
||||
0x1164dbe8667c853c,
|
||||
0x0788557acc7d9c79,
|
||||
},
|
||||
B: fp{
|
||||
0xda6a87cc6f48fa36,
|
||||
0x0fc7b488277c1903,
|
||||
0x9445ac4adc448187,
|
||||
0x02616d5bc9099209,
|
||||
0xdbed46772db58d48,
|
||||
0x11b94d5076c7b7b1,
|
||||
},
|
||||
}
|
||||
c := fp2{
|
||||
A: fp{
|
||||
0xf597483e27b4e0f7,
|
||||
0x610fbadf811dae5f,
|
||||
0x8432af917714327a,
|
||||
0x6a9a9603cf88f09e,
|
||||
0xf05a7bf8bad0eb01,
|
||||
0x09549131c003ffae,
|
||||
},
|
||||
B: fp{
|
||||
0x963b02d0f93d37cd,
|
||||
0xc95ce1cdb30a73d4,
|
||||
0x308725fa3126f9b8,
|
||||
0x56da3c167fab0d50,
|
||||
0x6b5086b5f4b6d6af,
|
||||
0x09c39f062f18e9f2,
|
||||
},
|
||||
}
|
||||
|
||||
require.Equal(t, 1, c.Equal(new(fp2).Mul(&a, &b)))
|
||||
}
|
||||
|
||||
func TestFp2Add(t *testing.T) {
|
||||
a := fp2{
|
||||
A: fp{
|
||||
0xc9a2183163ee70d4,
|
||||
0xbc3770a7196b5c91,
|
||||
0xa247f8c1304c5f44,
|
||||
0xb01fc2a3726c80b5,
|
||||
0xe1d293e5bbd919c9,
|
||||
0x04b78e80020ef2ca,
|
||||
},
|
||||
B: fp{
|
||||
0x952ea4460462618f,
|
||||
0x238d5eddf025c62f,
|
||||
0xf6c94b012ea92e72,
|
||||
0x03ce24eac1c93808,
|
||||
0x055950f945da483c,
|
||||
0x010a768d0df4eabc,
|
||||
},
|
||||
}
|
||||
b := fp2{
|
||||
A: fp{
|
||||
0xa1e09175a4d2c1fe,
|
||||
0x8b33acfc204eff12,
|
||||
0xe24415a11b456e42,
|
||||
0x61d996b1b6ee1936,
|
||||
0x1164dbe8667c853c,
|
||||
0x0788557acc7d9c79,
|
||||
},
|
||||
B: fp{
|
||||
0xda6a87cc6f48fa36,
|
||||
0x0fc7b488277c1903,
|
||||
0x9445ac4adc448187,
|
||||
0x02616d5bc9099209,
|
||||
0xdbed46772db58d48,
|
||||
0x11b94d5076c7b7b1,
|
||||
},
|
||||
}
|
||||
c := fp2{
|
||||
A: fp{
|
||||
0x6b82a9a708c132d2,
|
||||
0x476b1da339ba5ba4,
|
||||
0x848c0e624b91cd87,
|
||||
0x11f95955295a99ec,
|
||||
0xf3376fce22559f06,
|
||||
0x0c3fe3face8c8f43,
|
||||
},
|
||||
B: fp{
|
||||
0x6f992c1273ab5bc5,
|
||||
0x3355136617a1df33,
|
||||
0x8b0ef74c0aedaff9,
|
||||
0x062f92468ad2ca12,
|
||||
0xe1469770738fd584,
|
||||
0x12c3c3dd84bca26d,
|
||||
},
|
||||
}
|
||||
|
||||
require.Equal(t, 1, c.Equal(new(fp2).Add(&a, &b)))
|
||||
}
|
||||
|
||||
func TestFp2Sub(t *testing.T) {
|
||||
a := fp2{
|
||||
A: fp{
|
||||
0xc9a2183163ee70d4,
|
||||
0xbc3770a7196b5c91,
|
||||
0xa247f8c1304c5f44,
|
||||
0xb01fc2a3726c80b5,
|
||||
0xe1d293e5bbd919c9,
|
||||
0x04b78e80020ef2ca,
|
||||
},
|
||||
B: fp{
|
||||
0x952ea4460462618f,
|
||||
0x238d5eddf025c62f,
|
||||
0xf6c94b012ea92e72,
|
||||
0x03ce24eac1c93808,
|
||||
0x055950f945da483c,
|
||||
0x010a768d0df4eabc,
|
||||
},
|
||||
}
|
||||
b := fp2{
|
||||
A: fp{
|
||||
0xa1e09175a4d2c1fe,
|
||||
0x8b33acfc204eff12,
|
||||
0xe24415a11b456e42,
|
||||
0x61d996b1b6ee1936,
|
||||
0x1164dbe8667c853c,
|
||||
0x0788557acc7d9c79,
|
||||
},
|
||||
B: fp{
|
||||
0xda6a87cc6f48fa36,
|
||||
0x0fc7b488277c1903,
|
||||
0x9445ac4adc448187,
|
||||
0x02616d5bc9099209,
|
||||
0xdbed46772db58d48,
|
||||
0x11b94d5076c7b7b1,
|
||||
},
|
||||
}
|
||||
c := fp2{
|
||||
A: fp{
|
||||
0xe1c086bbbf1b5981,
|
||||
0x4fafc3a9aa705d7e,
|
||||
0x2734b5c10bb7e726,
|
||||
0xb2bd7776af037a3e,
|
||||
0x1b895fb398a84164,
|
||||
0x17304aef6f113cec,
|
||||
},
|
||||
B: fp{
|
||||
0x74c31c7995191204,
|
||||
0x3271aa5479fdad2b,
|
||||
0xc9b471574915a30f,
|
||||
0x65e40313ec44b8be,
|
||||
0x7487b2385b7067cb,
|
||||
0x09523b26d0ad19a4,
|
||||
},
|
||||
}
|
||||
|
||||
require.Equal(t, 1, c.Equal(new(fp2).Sub(&a, &b)))
|
||||
}
|
||||
|
||||
func TestFp2Neg(t *testing.T) {
|
||||
a := fp2{
|
||||
A: fp{
|
||||
0xc9a2183163ee70d4,
|
||||
0xbc3770a7196b5c91,
|
||||
0xa247f8c1304c5f44,
|
||||
0xb01fc2a3726c80b5,
|
||||
0xe1d293e5bbd919c9,
|
||||
0x04b78e80020ef2ca,
|
||||
},
|
||||
B: fp{
|
||||
0x952ea4460462618f,
|
||||
0x238d5eddf025c62f,
|
||||
0xf6c94b012ea92e72,
|
||||
0x03ce24eac1c93808,
|
||||
0x055950f945da483c,
|
||||
0x010a768d0df4eabc,
|
||||
},
|
||||
}
|
||||
b := fp2{
|
||||
A: fp{
|
||||
0xf05ce7ce9c1139d7,
|
||||
0x62748f5797e8a36d,
|
||||
0xc4e8d9dfc66496df,
|
||||
0xb45788e181189209,
|
||||
0x694913d08772930d,
|
||||
0x1549836a3770f3cf,
|
||||
},
|
||||
B: fp{
|
||||
0x24d05bb9fb9d491c,
|
||||
0xfb1ea120c12e39d0,
|
||||
0x7067879fc807c7b1,
|
||||
0x60a9269a31bbdab6,
|
||||
0x45c256bcfd71649b,
|
||||
0x18f69b5d2b8afbde,
|
||||
},
|
||||
}
|
||||
|
||||
require.Equal(t, 1, b.Equal(new(fp2).Neg(&a)))
|
||||
}
|
||||
|
||||
func TestFp2Sqrt(t *testing.T) {
|
||||
a := fp2{
|
||||
A: fp{
|
||||
0x2beed14627d7f9e9,
|
||||
0xb6614e06660e5dce,
|
||||
0x06c4cc7c2f91d42c,
|
||||
0x996d78474b7a63cc,
|
||||
0xebaebc4c820d574e,
|
||||
0x18865e12d93fd845,
|
||||
},
|
||||
B: fp{
|
||||
0x7d828664baf4f566,
|
||||
0xd17e663996ec7339,
|
||||
0x679ead55cb4078d0,
|
||||
0xfe3b2260e001ec28,
|
||||
0x305993d043d91b68,
|
||||
0x0626f03c0489b72d,
|
||||
},
|
||||
}
|
||||
|
||||
asq, wasSquare := (&fp2{}).Sqrt(&a)
|
||||
require.Equal(t, 1, wasSquare)
|
||||
require.Equal(t, 1, a.Equal(asq.Square(asq)))
|
||||
|
||||
b := fp2{
|
||||
A: fp{
|
||||
0x6631000000105545,
|
||||
0x211400400eec000d,
|
||||
0x3fa7af30c820e316,
|
||||
0xc52a8b8d6387695d,
|
||||
0x9fb4e61d1e83eac5,
|
||||
0x005cb922afe84dc7,
|
||||
},
|
||||
B: fp{},
|
||||
}
|
||||
bsq, wasSquare := (&fp2{}).Sqrt(&b)
|
||||
require.Equal(t, 1, wasSquare)
|
||||
require.Equal(t, 1, b.Equal(bsq.Square(bsq)))
|
||||
|
||||
c := fp2{
|
||||
A: fp{
|
||||
0x44f600000051ffae,
|
||||
0x86b8014199480043,
|
||||
0xd7159952f1f3794a,
|
||||
0x755d6e3dfe1ffc12,
|
||||
0xd36cd6db5547e905,
|
||||
0x02f8c8ecbf1867bb,
|
||||
},
|
||||
B: fp{},
|
||||
}
|
||||
csq, wasSquare := (&fp2{}).Sqrt(&c)
|
||||
require.Equal(t, 1, wasSquare)
|
||||
require.Equal(t, 1, c.Equal(csq.Square(csq)))
|
||||
|
||||
d := fp2{
|
||||
A: fp{
|
||||
0xc5fa1bc8fd00d7f6,
|
||||
0x3830ca454606003b,
|
||||
0x2b287f1104b102da,
|
||||
0xa7fb30f28230f23e,
|
||||
0x339cdb9ee953dbf0,
|
||||
0x0d78ec51d989fc57,
|
||||
},
|
||||
B: fp{
|
||||
0x27ec4898cf87f613,
|
||||
0x9de1394e1abb05a5,
|
||||
0x0947f85dc170fc14,
|
||||
0x586fbc696b6114b7,
|
||||
0x2b3475a4077d7169,
|
||||
0x13e1c895cc4b6c22,
|
||||
},
|
||||
}
|
||||
_, wasSquare = (&fp2{}).Sqrt(&d)
|
||||
require.Equal(t, 0, wasSquare)
|
||||
|
||||
_, wasSquare = (&fp2{}).Sqrt(&fp2{})
|
||||
require.Equal(t, 1, wasSquare)
|
||||
}
|
||||
|
||||
func TestFp2Invert(t *testing.T) {
|
||||
a := fp2{
|
||||
A: fp{
|
||||
0x1128ecad67549455,
|
||||
0x9e7a1cff3a4ea1a8,
|
||||
0xeb208d51e08bcf27,
|
||||
0xe98ad40811f5fc2b,
|
||||
0x736c3a59232d511d,
|
||||
0x10acd42d29cfcbb6,
|
||||
},
|
||||
B: fp{
|
||||
0xd328e37cc2f58d41,
|
||||
0x948df0858a605869,
|
||||
0x6032f9d56f93a573,
|
||||
0x2be483ef3fffdc87,
|
||||
0x30ef61f88f483c2a,
|
||||
0x1333f55a35725be0,
|
||||
},
|
||||
}
|
||||
|
||||
b := fp2{
|
||||
A: fp{
|
||||
0x0581a1333d4f48a6,
|
||||
0x58242f6ef0748500,
|
||||
0x0292c955349e6da5,
|
||||
0xba37721ddd95fcd0,
|
||||
0x70d167903aa5dfc5,
|
||||
0x11895e118b58a9d5,
|
||||
},
|
||||
B: fp{
|
||||
0x0eda09d2d7a85d17,
|
||||
0x8808e137a7d1a2cf,
|
||||
0x43ae2625c1ff21db,
|
||||
0xf85ac9fdf7a74c64,
|
||||
0x8fccdda5b8da9738,
|
||||
0x08e84f0cb32cd17d,
|
||||
},
|
||||
}
|
||||
|
||||
ainv, wasInverted := (&fp2{}).Invert(&a)
|
||||
require.Equal(t, 1, wasInverted)
|
||||
require.Equal(t, 1, b.Equal(ainv))
|
||||
|
||||
_, wasInverted = (&fp2{}).Invert(&fp2{})
|
||||
require.Equal(t, 0, wasInverted)
|
||||
}
|
||||
|
||||
func TestFp2LexicographicallyLargest(t *testing.T) {
|
||||
require.Equal(t, 0, new(fp2).SetZero().LexicographicallyLargest())
|
||||
require.Equal(t, 0, new(fp2).SetOne().LexicographicallyLargest())
|
||||
|
||||
a := fp2{
|
||||
A: fp{
|
||||
0x1128_ecad_6754_9455,
|
||||
0x9e7a_1cff_3a4e_a1a8,
|
||||
0xeb20_8d51_e08b_cf27,
|
||||
0xe98a_d408_11f5_fc2b,
|
||||
0x736c_3a59_232d_511d,
|
||||
0x10ac_d42d_29cf_cbb6,
|
||||
},
|
||||
B: fp{
|
||||
0xd328_e37c_c2f5_8d41,
|
||||
0x948d_f085_8a60_5869,
|
||||
0x6032_f9d5_6f93_a573,
|
||||
0x2be4_83ef_3fff_dc87,
|
||||
0x30ef_61f8_8f48_3c2a,
|
||||
0x1333_f55a_3572_5be0,
|
||||
},
|
||||
}
|
||||
|
||||
require.Equal(t, 1, a.LexicographicallyLargest())
|
||||
aNeg := new(fp2).Neg(&a)
|
||||
require.Equal(t, 0, aNeg.LexicographicallyLargest())
|
||||
a.B.SetZero()
|
||||
require.Equal(t, 0, a.LexicographicallyLargest())
|
||||
aNeg.B.SetZero()
|
||||
require.Equal(t, 1, aNeg.LexicographicallyLargest())
|
||||
}
|
@ -1,340 +0,0 @@
|
||||
package bls12381
|
||||
|
||||
import "io"
|
||||
|
||||
// fp6 represents an element
|
||||
// a + b v + c v^2 of fp^6 = fp^2 / v^3 - u - 1.
|
||||
type fp6 struct {
|
||||
A, B, C fp2
|
||||
}
|
||||
|
||||
// Set fp6 = a
|
||||
func (f *fp6) Set(a *fp6) *fp6 {
|
||||
f.A.Set(&a.A)
|
||||
f.B.Set(&a.B)
|
||||
f.C.Set(&a.C)
|
||||
return f
|
||||
}
|
||||
|
||||
// SetFp creates an element from a lower field
|
||||
func (f *fp6) SetFp(a *fp) *fp6 {
|
||||
f.A.SetFp(a)
|
||||
f.B.SetZero()
|
||||
f.C.SetZero()
|
||||
return f
|
||||
}
|
||||
|
||||
// SetFp2 creates an element from a lower field
|
||||
func (f *fp6) SetFp2(a *fp2) *fp6 {
|
||||
f.A.Set(a)
|
||||
f.B.SetZero()
|
||||
f.C.SetZero()
|
||||
return f
|
||||
}
|
||||
|
||||
// SetZero fp6 to zero
|
||||
func (f *fp6) SetZero() *fp6 {
|
||||
f.A.SetZero()
|
||||
f.B.SetZero()
|
||||
f.C.SetZero()
|
||||
return f
|
||||
}
|
||||
|
||||
// SetOne fp6 to multiplicative identity element
|
||||
func (f *fp6) SetOne() *fp6 {
|
||||
f.A.SetOne()
|
||||
f.B.SetZero()
|
||||
f.C.SetZero()
|
||||
return f
|
||||
}
|
||||
|
||||
// Random generates a random field element
|
||||
func (f *fp6) Random(reader io.Reader) (*fp6, error) {
|
||||
a, err := new(fp2).Random(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b, err := new(fp2).Random(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c, err := new(fp2).Random(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.A.Set(a)
|
||||
f.B.Set(b)
|
||||
f.C.Set(c)
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// Add computes arg1+arg2
|
||||
func (f *fp6) Add(arg1, arg2 *fp6) *fp6 {
|
||||
f.A.Add(&arg1.A, &arg2.A)
|
||||
f.B.Add(&arg1.B, &arg2.B)
|
||||
f.C.Add(&arg1.C, &arg2.C)
|
||||
return f
|
||||
}
|
||||
|
||||
// Double computes arg1+arg1
|
||||
func (f *fp6) Double(arg *fp6) *fp6 {
|
||||
return f.Add(arg, arg)
|
||||
}
|
||||
|
||||
// Sub computes arg1-arg2
|
||||
func (f *fp6) Sub(arg1, arg2 *fp6) *fp6 {
|
||||
f.A.Sub(&arg1.A, &arg2.A)
|
||||
f.B.Sub(&arg1.B, &arg2.B)
|
||||
f.C.Sub(&arg1.C, &arg2.C)
|
||||
return f
|
||||
}
|
||||
|
||||
// Mul computes arg1*arg2
|
||||
func (f *fp6) Mul(arg1, arg2 *fp6) *fp6 {
|
||||
var aa, bb, cc, s, t1, t2, t3 fp2
|
||||
|
||||
aa.Mul(&arg1.A, &arg2.A)
|
||||
bb.Mul(&arg1.B, &arg2.B)
|
||||
cc.Mul(&arg1.C, &arg2.C)
|
||||
|
||||
t1.Add(&arg2.B, &arg2.C)
|
||||
s.Add(&arg1.B, &arg1.C)
|
||||
t1.Mul(&t1, &s)
|
||||
t1.Sub(&t1, &bb)
|
||||
t1.Sub(&t1, &cc)
|
||||
t1.MulByNonResidue(&t1)
|
||||
t1.Add(&t1, &aa)
|
||||
|
||||
t3.Add(&arg2.A, &arg2.C)
|
||||
s.Add(&arg1.A, &arg1.C)
|
||||
t3.Mul(&t3, &s)
|
||||
t3.Sub(&t3, &aa)
|
||||
t3.Add(&t3, &bb)
|
||||
t3.Sub(&t3, &cc)
|
||||
|
||||
t2.Add(&arg2.A, &arg2.B)
|
||||
s.Add(&arg1.A, &arg1.B)
|
||||
t2.Mul(&t2, &s)
|
||||
t2.Sub(&t2, &aa)
|
||||
t2.Sub(&t2, &bb)
|
||||
cc.MulByNonResidue(&cc)
|
||||
t2.Add(&t2, &cc)
|
||||
|
||||
f.A.Set(&t1)
|
||||
f.B.Set(&t2)
|
||||
f.C.Set(&t3)
|
||||
return f
|
||||
}
|
||||
|
||||
// MulByB scales this field by a scalar in the B coefficient
|
||||
func (f *fp6) MulByB(arg *fp6, b *fp2) *fp6 {
|
||||
var bB, t1, t2 fp2
|
||||
bB.Mul(&arg.B, b)
|
||||
// (b + c) * arg2 - bB
|
||||
t1.Add(&arg.B, &arg.C)
|
||||
t1.Mul(&t1, b)
|
||||
t1.Sub(&t1, &bB)
|
||||
t1.MulByNonResidue(&t1)
|
||||
|
||||
t2.Add(&arg.A, &arg.B)
|
||||
t2.Mul(&t2, b)
|
||||
t2.Sub(&t2, &bB)
|
||||
|
||||
f.A.Set(&t1)
|
||||
f.B.Set(&t2)
|
||||
f.C.Set(&bB)
|
||||
return f
|
||||
}
|
||||
|
||||
// MulByAB scales this field by scalars in the A and B coefficients
|
||||
func (f *fp6) MulByAB(arg *fp6, a, b *fp2) *fp6 {
|
||||
var aA, bB, t1, t2, t3 fp2
|
||||
|
||||
aA.Mul(&arg.A, a)
|
||||
bB.Mul(&arg.B, b)
|
||||
|
||||
t1.Add(&arg.B, &arg.C)
|
||||
t1.Mul(&t1, b)
|
||||
t1.Sub(&t1, &bB)
|
||||
t1.MulByNonResidue(&t1)
|
||||
t1.Add(&t1, &aA)
|
||||
|
||||
t2.Add(a, b)
|
||||
t3.Add(&arg.A, &arg.B)
|
||||
t2.Mul(&t2, &t3)
|
||||
t2.Sub(&t2, &aA)
|
||||
t2.Sub(&t2, &bB)
|
||||
|
||||
t3.Add(&arg.A, &arg.C)
|
||||
t3.Mul(&t3, a)
|
||||
t3.Sub(&t3, &aA)
|
||||
t3.Add(&t3, &bB)
|
||||
|
||||
f.A.Set(&t1)
|
||||
f.B.Set(&t2)
|
||||
f.C.Set(&t3)
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
// MulByNonResidue multiplies by quadratic nonresidue v.
|
||||
func (f *fp6) MulByNonResidue(arg *fp6) *fp6 {
|
||||
// Given a + bv + cv^2, this produces
|
||||
// av + bv^2 + cv^3
|
||||
// but because v^3 = u + 1, we have
|
||||
// c(u + 1) + av + bv^2
|
||||
var a, b, c fp2
|
||||
a.MulByNonResidue(&arg.C)
|
||||
b.Set(&arg.A)
|
||||
c.Set(&arg.B)
|
||||
f.A.Set(&a)
|
||||
f.B.Set(&b)
|
||||
f.C.Set(&c)
|
||||
return f
|
||||
}
|
||||
|
||||
// FrobeniusMap raises this element to p.
|
||||
func (f *fp6) FrobeniusMap(arg *fp6) *fp6 {
|
||||
var a, b, c fp2
|
||||
pm1Div3 := fp2{
|
||||
A: fp{},
|
||||
B: fp{
|
||||
0xcd03c9e48671f071,
|
||||
0x5dab22461fcda5d2,
|
||||
0x587042afd3851b95,
|
||||
0x8eb60ebe01bacb9e,
|
||||
0x03f97d6e83d050d2,
|
||||
0x18f0206554638741,
|
||||
},
|
||||
}
|
||||
p2m2Div3 := fp2{
|
||||
A: fp{
|
||||
0x890dc9e4867545c3,
|
||||
0x2af322533285a5d5,
|
||||
0x50880866309b7e2c,
|
||||
0xa20d1b8c7e881024,
|
||||
0x14e4f04fe2db9068,
|
||||
0x14e56d3f1564853a,
|
||||
},
|
||||
B: fp{},
|
||||
}
|
||||
a.FrobeniusMap(&arg.A)
|
||||
b.FrobeniusMap(&arg.B)
|
||||
c.FrobeniusMap(&arg.C)
|
||||
|
||||
// b = b * (u + 1)^((p - 1) / 3)
|
||||
b.Mul(&b, &pm1Div3)
|
||||
|
||||
// c = c * (u + 1)^((2p - 2) / 3)
|
||||
c.Mul(&c, &p2m2Div3)
|
||||
|
||||
f.A.Set(&a)
|
||||
f.B.Set(&b)
|
||||
f.C.Set(&c)
|
||||
return f
|
||||
}
|
||||
|
||||
// Square computes fp6^2
|
||||
func (f *fp6) Square(arg *fp6) *fp6 {
|
||||
var s0, s1, s2, s3, s4, ab, bc fp2
|
||||
|
||||
s0.Square(&arg.A)
|
||||
ab.Mul(&arg.A, &arg.B)
|
||||
s1.Double(&ab)
|
||||
s2.Sub(&arg.A, &arg.B)
|
||||
s2.Add(&s2, &arg.C)
|
||||
s2.Square(&s2)
|
||||
bc.Mul(&arg.B, &arg.C)
|
||||
s3.Double(&bc)
|
||||
s4.Square(&arg.C)
|
||||
|
||||
f.A.MulByNonResidue(&s3)
|
||||
f.A.Add(&f.A, &s0)
|
||||
|
||||
f.B.MulByNonResidue(&s4)
|
||||
f.B.Add(&f.B, &s1)
|
||||
|
||||
// s1 + s2 + s3 - s0 - s4
|
||||
f.C.Add(&s1, &s2)
|
||||
f.C.Add(&f.C, &s3)
|
||||
f.C.Sub(&f.C, &s0)
|
||||
f.C.Sub(&f.C, &s4)
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
// Invert computes this element's field inversion
|
||||
func (f *fp6) Invert(arg *fp6) (*fp6, int) {
|
||||
var a, b, c, s, t fp2
|
||||
|
||||
// a' = a^2 - (b * c).mul_by_nonresidue()
|
||||
a.Mul(&arg.B, &arg.C)
|
||||
a.MulByNonResidue(&a)
|
||||
t.Square(&arg.A)
|
||||
a.Sub(&t, &a)
|
||||
|
||||
// b' = (c^2).mul_by_nonresidue() - (a * b)
|
||||
b.Square(&arg.C)
|
||||
b.MulByNonResidue(&b)
|
||||
t.Mul(&arg.A, &arg.B)
|
||||
b.Sub(&b, &t)
|
||||
|
||||
// c' = b^2 - (a * c)
|
||||
c.Square(&arg.B)
|
||||
t.Mul(&arg.A, &arg.C)
|
||||
c.Sub(&c, &t)
|
||||
|
||||
// t = ((b * c') + (c * b')).mul_by_nonresidue() + (a * a')
|
||||
s.Mul(&arg.B, &c)
|
||||
t.Mul(&arg.C, &b)
|
||||
s.Add(&s, &t)
|
||||
s.MulByNonResidue(&s)
|
||||
|
||||
t.Mul(&arg.A, &a)
|
||||
s.Add(&s, &t)
|
||||
|
||||
_, wasInverted := t.Invert(&s)
|
||||
|
||||
// newA = a' * t^-1
|
||||
s.Mul(&a, &t)
|
||||
f.A.CMove(&f.A, &s, wasInverted)
|
||||
// newB = b' * t^-1
|
||||
s.Mul(&b, &t)
|
||||
f.B.CMove(&f.B, &s, wasInverted)
|
||||
// newC = c' * t^-1
|
||||
s.Mul(&c, &t)
|
||||
f.C.CMove(&f.C, &s, wasInverted)
|
||||
return f, wasInverted
|
||||
}
|
||||
|
||||
// Neg computes the field negation
|
||||
func (f *fp6) Neg(arg *fp6) *fp6 {
|
||||
f.A.Neg(&arg.A)
|
||||
f.B.Neg(&arg.B)
|
||||
f.C.Neg(&arg.C)
|
||||
return f
|
||||
}
|
||||
|
||||
// IsZero returns 1 if fp6 == 0, 0 otherwise
|
||||
func (f *fp6) IsZero() int {
|
||||
return f.A.IsZero() & f.B.IsZero() & f.C.IsZero()
|
||||
}
|
||||
|
||||
// IsOne returns 1 if fp6 == 1, 0 otherwise
|
||||
func (f *fp6) IsOne() int {
|
||||
return f.A.IsOne() & f.B.IsZero() & f.B.IsZero()
|
||||
}
|
||||
|
||||
// Equal returns 1 if fp6 == rhs, 0 otherwise
|
||||
func (f *fp6) Equal(rhs *fp6) int {
|
||||
return f.A.Equal(&rhs.A) & f.B.Equal(&rhs.B) & f.C.Equal(&rhs.C)
|
||||
}
|
||||
|
||||
// CMove performs conditional select.
|
||||
// selects arg1 if choice == 0 and arg2 if choice == 1
|
||||
func (f *fp6) CMove(arg1, arg2 *fp6, choice int) *fp6 {
|
||||
f.A.CMove(&arg1.A, &arg2.A, choice)
|
||||
f.B.CMove(&arg1.B, &arg2.B, choice)
|
||||
f.C.CMove(&arg1.C, &arg2.C, choice)
|
||||
return f
|
||||
}
|
@ -1,217 +0,0 @@
|
||||
package bls12381
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFp6Arithmetic(t *testing.T) {
|
||||
a := fp6{
|
||||
A: fp2{
|
||||
A: fp{
|
||||
0x47f9cb98b1b82d58,
|
||||
0x5fe911eba3aa1d9d,
|
||||
0x96bf1b5f4dd81db3,
|
||||
0x8100d27cc9259f5b,
|
||||
0xafa20b9674640eab,
|
||||
0x09bbcea7d8d9497d,
|
||||
},
|
||||
B: fp{
|
||||
0x0303cb98b1662daa,
|
||||
0xd93110aa0a621d5a,
|
||||
0xbfa9820c5be4a468,
|
||||
0x0ba3643ecb05a348,
|
||||
0xdc3534bb1f1c25a6,
|
||||
0x06c305bb19c0e1c1,
|
||||
},
|
||||
},
|
||||
B: fp2{
|
||||
A: fp{
|
||||
0x46f9cb98b162d858,
|
||||
0x0be9109cf7aa1d57,
|
||||
0xc791bc55fece41d2,
|
||||
0xf84c57704e385ec2,
|
||||
0xcb49c1d9c010e60f,
|
||||
0x0acdb8e158bfe3c8,
|
||||
},
|
||||
B: fp{
|
||||
0x8aefcb98b15f8306,
|
||||
0x3ea1108fe4f21d54,
|
||||
0xcf79f69fa1b7df3b,
|
||||
0xe4f54aa1d16b1a3c,
|
||||
0xba5e4ef86105a679,
|
||||
0x0ed86c0797bee5cf,
|
||||
},
|
||||
},
|
||||
C: fp2{
|
||||
A: fp{
|
||||
0xcee5cb98b15c2db4,
|
||||
0x71591082d23a1d51,
|
||||
0xd76230e944a17ca4,
|
||||
0xd19e3dd3549dd5b6,
|
||||
0xa972dc1701fa66e3,
|
||||
0x12e31f2dd6bde7d6,
|
||||
},
|
||||
B: fp{
|
||||
0xad2acb98b1732d9d,
|
||||
0x2cfd10dd06961d64,
|
||||
0x07396b86c6ef24e8,
|
||||
0xbd76e2fdb1bfc820,
|
||||
0x6afea7f6de94d0d5,
|
||||
0x10994b0c5744c040,
|
||||
},
|
||||
},
|
||||
}
|
||||
b := fp6{
|
||||
A: fp2{
|
||||
A: fp{
|
||||
0xf120cb98b16fd84b,
|
||||
0x5fb510cff3de1d61,
|
||||
0x0f21a5d069d8c251,
|
||||
0xaa1fd62f34f2839a,
|
||||
0x5a1335157f89913f,
|
||||
0x14a3fe329643c247,
|
||||
},
|
||||
B: fp{
|
||||
0x3516cb98b16c82f9,
|
||||
0x926d10c2e1261d5f,
|
||||
0x1709e01a0cc25fba,
|
||||
0x96c8c960b8253f14,
|
||||
0x4927c234207e51a9,
|
||||
0x18aeb158d542c44e,
|
||||
},
|
||||
},
|
||||
B: fp2{
|
||||
A: fp{
|
||||
0xbf0dcb98b16982fc,
|
||||
0xa67910b71d1a1d5c,
|
||||
0xb7c147c2b8fb06ff,
|
||||
0x1efa710d47d2e7ce,
|
||||
0xed20a79c7e27653c,
|
||||
0x02b85294dac1dfba,
|
||||
},
|
||||
B: fp{
|
||||
0x9d52cb98b18082e5,
|
||||
0x621d111151761d6f,
|
||||
0xe79882603b48af43,
|
||||
0x0ad31637a4f4da37,
|
||||
0xaeac737c5ac1cf2e,
|
||||
0x006e7e735b48b824,
|
||||
},
|
||||
},
|
||||
C: fp2{
|
||||
A: fp{
|
||||
0xe148cb98b17d2d93,
|
||||
0x94d511043ebe1d6c,
|
||||
0xef80bca9de324cac,
|
||||
0xf77c0969282795b1,
|
||||
0x9dc1009afbb68f97,
|
||||
0x047931999a47ba2b,
|
||||
},
|
||||
B: fp{
|
||||
0x253ecb98b179d841,
|
||||
0xc78d10f72c061d6a,
|
||||
0xf768f6f3811bea15,
|
||||
0xe424fc9aab5a512b,
|
||||
0x8cd58db99cab5001,
|
||||
0x0883e4bfd946bc32,
|
||||
},
|
||||
},
|
||||
}
|
||||
c := fp6{
|
||||
A: fp2{
|
||||
A: fp{
|
||||
0x6934cb98b17682ef,
|
||||
0xfa4510ea194e1d67,
|
||||
0xff51313d2405877e,
|
||||
0xd0cdefcc2e8d0ca5,
|
||||
0x7bea1ad83da0106b,
|
||||
0x0c8e97e61845be39,
|
||||
},
|
||||
B: fp{
|
||||
0x4779cb98b18d82d8,
|
||||
0xb5e911444daa1d7a,
|
||||
0x2f286bdaa6532fc2,
|
||||
0xbca694f68baeff0f,
|
||||
0x3d75e6b81a3a7a5d,
|
||||
0x0a44c3c498cc96a3,
|
||||
},
|
||||
},
|
||||
B: fp2{
|
||||
A: fp{
|
||||
0x8b6fcb98b18a2d86,
|
||||
0xe8a111373af21d77,
|
||||
0x3710a624493ccd2b,
|
||||
0xa94f88280ee1ba89,
|
||||
0x2c8a73d6bb2f3ac7,
|
||||
0x0e4f76ead7cb98aa,
|
||||
},
|
||||
B: fp{
|
||||
0xcf65cb98b186d834,
|
||||
0x1b59112a283a1d74,
|
||||
0x3ef8e06dec266a95,
|
||||
0x95f87b5992147603,
|
||||
0x1b9f00f55c23fb31,
|
||||
0x125a2a1116ca9ab1,
|
||||
},
|
||||
},
|
||||
C: fp2{
|
||||
A: fp{
|
||||
0x135bcb98b18382e2,
|
||||
0x4e11111d15821d72,
|
||||
0x46e11ab78f1007fe,
|
||||
0x82a16e8b1547317d,
|
||||
0x0ab38e13fd18bb9b,
|
||||
0x1664dd3755c99cb8,
|
||||
},
|
||||
B: fp{
|
||||
0xce65cb98b1318334,
|
||||
0xc7590fdb7c3a1d2e,
|
||||
0x6fcb81649d1c8eb3,
|
||||
0x0d44004d1727356a,
|
||||
0x3746b738a7d0d296,
|
||||
0x136c144a96b134fc,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
d := new(fp6).Square(&a)
|
||||
e := new(fp6).Mul(&a, &a)
|
||||
require.Equal(t, 1, e.Equal(d))
|
||||
|
||||
d.Square(&b)
|
||||
e.Mul(&b, &b)
|
||||
require.Equal(t, 1, e.Equal(d))
|
||||
|
||||
d.Square(&c)
|
||||
e.Mul(&c, &c)
|
||||
require.Equal(t, 1, e.Equal(d))
|
||||
|
||||
// (a + b) * c^2
|
||||
d.Add(&a, &b)
|
||||
d.Mul(d, new(fp6).Square(&c))
|
||||
|
||||
e.Mul(&c, &c)
|
||||
e.Mul(e, &a)
|
||||
tt := new(fp6).Mul(&c, &c)
|
||||
tt.Mul(tt, &b)
|
||||
e.Add(e, tt)
|
||||
|
||||
require.Equal(t, 1, d.Equal(e))
|
||||
|
||||
_, wasInverted := d.Invert(&a)
|
||||
require.Equal(t, 1, wasInverted)
|
||||
_, wasInverted = e.Invert(&b)
|
||||
require.Equal(t, 1, wasInverted)
|
||||
|
||||
tt.Mul(&a, &b)
|
||||
_, wasInverted = tt.Invert(tt)
|
||||
require.Equal(t, 1, wasInverted)
|
||||
d.Mul(d, e)
|
||||
require.Equal(t, 1, tt.Equal(d))
|
||||
|
||||
_, _ = d.Invert(&a)
|
||||
e.SetOne()
|
||||
require.Equal(t, 1, e.Equal(d.Mul(d, &a)))
|
||||
}
|
@ -1,297 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package bls12381
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
func TestFpSetOne(t *testing.T) {
|
||||
var fp fp
|
||||
fp.SetOne()
|
||||
require.NotNil(t, fp)
|
||||
require.Equal(t, fp, r)
|
||||
}
|
||||
|
||||
func TestFpSetUint64(t *testing.T) {
|
||||
var act fp
|
||||
act.SetUint64(1 << 60)
|
||||
require.NotNil(t, act)
|
||||
// Remember it will be in montgomery form
|
||||
require.Equal(t, act[0], uint64(0xf6ea9fde37db5e8c))
|
||||
}
|
||||
|
||||
func TestFpAdd(t *testing.T) {
|
||||
var lhs, rhs, exp, res fp
|
||||
lhs.SetOne()
|
||||
rhs.SetOne()
|
||||
exp.SetUint64(2)
|
||||
res.Add(&lhs, &rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, 1, res.Equal(&exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint64() >> 2
|
||||
r := rand.Uint64() >> 2
|
||||
e := l + r
|
||||
lhs.SetUint64(l)
|
||||
rhs.SetUint64(r)
|
||||
exp.SetUint64(e)
|
||||
|
||||
res.Add(&lhs, &rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, exp, res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpSub(t *testing.T) {
|
||||
var lhs, rhs, exp, res fp
|
||||
lhs.SetOne()
|
||||
rhs.SetOne()
|
||||
exp.SetZero()
|
||||
res.Sub(&lhs, &rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, 1, res.Equal(&exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint64() >> 2
|
||||
r := rand.Uint64() >> 2
|
||||
if l < r {
|
||||
l, r = r, l
|
||||
}
|
||||
e := l - r
|
||||
lhs.SetUint64(l)
|
||||
rhs.SetUint64(r)
|
||||
exp.SetUint64(e)
|
||||
|
||||
res.Sub(&lhs, &rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, exp, res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpMul(t *testing.T) {
|
||||
var lhs, rhs, exp, res fp
|
||||
lhs.SetOne()
|
||||
rhs.SetOne()
|
||||
exp.SetOne()
|
||||
res.Mul(&lhs, &rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, 1, res.Equal(&exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint32()
|
||||
r := rand.Uint32()
|
||||
e := uint64(l) * uint64(r)
|
||||
lhs.SetUint64(uint64(l))
|
||||
rhs.SetUint64(uint64(r))
|
||||
exp.SetUint64(e)
|
||||
|
||||
res.Mul(&lhs, &rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, exp, res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpDouble(t *testing.T) {
|
||||
var a, e, res fp
|
||||
a.SetUint64(2)
|
||||
e.SetUint64(4)
|
||||
require.Equal(t, &e, res.Double(&a))
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
tv := rand.Uint32()
|
||||
ttv := uint64(tv) * 2
|
||||
a.SetUint64(uint64(tv))
|
||||
e.SetUint64(ttv)
|
||||
require.Equal(t, &e, res.Double(&a))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpSquare(t *testing.T) {
|
||||
var a, e, res fp
|
||||
a.SetUint64(4)
|
||||
e.SetUint64(16)
|
||||
require.Equal(t, 1, e.Equal(res.Square(&a)))
|
||||
|
||||
a.SetUint64(2854263694)
|
||||
e.SetUint64(8146821234886525636)
|
||||
require.Equal(t, 1, e.Equal(res.Square(&a)))
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
j := rand.Uint32()
|
||||
exp := uint64(j) * uint64(j)
|
||||
e.SetUint64(exp)
|
||||
a.SetUint64(uint64(j))
|
||||
require.Equal(t, 1, e.Equal(res.Square(&a)), "exp = %d, j = %d", exp, j)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpNeg(t *testing.T) {
|
||||
var g, a, e fp
|
||||
g.SetLimbs(&[Limbs]uint64{7, 0, 0, 0, 0, 0})
|
||||
a.SetOne()
|
||||
a.Neg(&a)
|
||||
e.SetRaw(&[Limbs]uint64{0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x07e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x040ab3263eff0206})
|
||||
require.Equal(t, 1, e.Equal(&a))
|
||||
a.Neg(&g)
|
||||
e.SetRaw(&[Limbs]uint64{0x21baffffffe90017, 0x445bffa5cba3ffed, 0xd028c5627db257bc, 0x14275ad5a2de0d96, 0x3e7434202365960e, 0x0249d4217f792796})
|
||||
require.Equal(t, e, a)
|
||||
}
|
||||
|
||||
func TestFpExp(t *testing.T) {
|
||||
var a, e, by fp
|
||||
e.SetUint64(8)
|
||||
a.SetUint64(2)
|
||||
by.SetUint64(3)
|
||||
require.Equal(t, &e, a.Exp(&a, &by))
|
||||
}
|
||||
|
||||
func TestFpSqrt(t *testing.T) {
|
||||
var t1, t2, t3 fp
|
||||
t1.SetUint64(2)
|
||||
t2.Neg(&t1)
|
||||
t3.Square(&t1)
|
||||
_, wasSquare := t3.Sqrt(&t3)
|
||||
|
||||
require.Equal(t, 1, wasSquare)
|
||||
require.Equal(t, 1, t1.Equal(&t3)|t2.Equal(&t3))
|
||||
t1.SetUint64(5)
|
||||
_, wasSquare = t1.Sqrt(&t1)
|
||||
require.Equal(t, 0, wasSquare)
|
||||
}
|
||||
|
||||
func TestFpInvert(t *testing.T) {
|
||||
var two, twoInv, a, lhs, rhs, rhsInv fp
|
||||
twoInv.SetRaw(&[Limbs]uint64{0x1804000000015554, 0x855000053ab00001, 0x633cb57c253c276f, 0x6e22d1ec31ebb502, 0xd3916126f2d14ca2, 0x17fbb8571a006596})
|
||||
two.SetUint64(2)
|
||||
_, inverted := a.Invert(&two)
|
||||
require.Equal(t, 1, inverted)
|
||||
require.Equal(t, &a, &twoInv)
|
||||
|
||||
lhs.SetUint64(9)
|
||||
rhs.SetUint64(3)
|
||||
_, inverted = rhsInv.Invert(&rhs)
|
||||
require.Equal(t, 1, inverted)
|
||||
require.Equal(t, &rhs, lhs.Mul(&lhs, &rhsInv))
|
||||
|
||||
rhs.SetZero()
|
||||
_, inverted = lhs.Invert(&rhs)
|
||||
require.Equal(t, 0, inverted)
|
||||
}
|
||||
|
||||
func TestFpCMove(t *testing.T) {
|
||||
var t1, t2, tt fp
|
||||
t1.SetUint64(5)
|
||||
t2.SetUint64(10)
|
||||
require.Equal(t, &t1, tt.CMove(&t1, &t2, 0))
|
||||
require.Equal(t, &t2, tt.CMove(&t1, &t2, 1))
|
||||
}
|
||||
|
||||
func TestFpBytes(t *testing.T) {
|
||||
var t1, t2 fp
|
||||
t1.SetUint64(99)
|
||||
seq := t1.Bytes()
|
||||
_, suc := t2.SetBytes(&seq)
|
||||
require.Equal(t, 1, suc)
|
||||
require.Equal(t, t1, t2)
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
t1.SetUint64(rand.Uint64())
|
||||
seq = t1.Bytes()
|
||||
_, suc = t2.SetBytes(&seq)
|
||||
require.Equal(t, 1, suc)
|
||||
require.Equal(t, t1, t2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpBigInt(t *testing.T) {
|
||||
var t1, t2, e fp
|
||||
t1.SetBigInt(big.NewInt(9999))
|
||||
t2.SetBigInt(t1.BigInt())
|
||||
require.Equal(t, t1, t2)
|
||||
|
||||
e.SetRaw(&[Limbs]uint64{0x922af810e5e35f31, 0x6bc75973ed382d59, 0xd4716c9d4d491d42, 0x69d98d1ebeeb3f6e, 0x7e425d7b46d4a82b, 0x12d04b0965870e92})
|
||||
b := new(big.Int).SetBytes([]byte{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9})
|
||||
t1.SetBigInt(b)
|
||||
require.Equal(t, e, t1)
|
||||
e.Neg(&e)
|
||||
b.Neg(b)
|
||||
t1.SetBigInt(b)
|
||||
require.Equal(t, e, t1)
|
||||
}
|
||||
|
||||
func TestFpSetBytesWideBigInt(t *testing.T) {
|
||||
var a fp
|
||||
var tv2 [96]byte
|
||||
for i := 0; i < 25; i++ {
|
||||
_, _ = crand.Read(tv2[:])
|
||||
e := new(big.Int).SetBytes(tv2[:])
|
||||
e.Mod(e, biModulus)
|
||||
|
||||
tv := internal.ReverseScalarBytes(tv2[:])
|
||||
copy(tv2[:], tv)
|
||||
a.SetBytesWide(&tv2)
|
||||
require.Equal(t, 0, e.Cmp(a.BigInt()))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpToMontgomery(t *testing.T) {
|
||||
var v fp
|
||||
v.SetUint64(2)
|
||||
require.Equal(t, fp{0x321300000006554f, 0xb93c0018d6c40005, 0x57605e0db0ddbb51, 0x8b256521ed1f9bcb, 0x6cf28d7901622c03, 0x11ebab9dbb81e28c}, v)
|
||||
}
|
||||
|
||||
func TestFpFromMontgomery(t *testing.T) {
|
||||
var v fp
|
||||
e := fp{2, 0, 0, 0, 0, 0}
|
||||
v.SetUint64(2)
|
||||
v.fromMontgomery(&v)
|
||||
require.Equal(t, e, v)
|
||||
}
|
||||
|
||||
func TestFpLexicographicallyLargest(t *testing.T) {
|
||||
require.Equal(t, 0, new(fp).SetZero().LexicographicallyLargest())
|
||||
require.Equal(t, 0, new(fp).SetOne().LexicographicallyLargest())
|
||||
require.Equal(t, 0, (&fp{
|
||||
0xa1fafffffffe5557,
|
||||
0x995bfff976a3fffe,
|
||||
0x03f41d24d174ceb4,
|
||||
0xf6547998c1995dbd,
|
||||
0x778a468f507a6034,
|
||||
0x020559931f7f8103,
|
||||
}).LexicographicallyLargest())
|
||||
require.Equal(t, 1, (&fp{
|
||||
0x1804000000015554,
|
||||
0x855000053ab00001,
|
||||
0x633cb57c253c276f,
|
||||
0x6e22d1ec31ebb502,
|
||||
0xd3916126f2d14ca2,
|
||||
0x17fbb8571a006596,
|
||||
}).LexicographicallyLargest())
|
||||
require.Equal(t, 1, (&fp{
|
||||
0x43f5fffffffcaaae,
|
||||
0x32b7fff2ed47fffd,
|
||||
0x07e83a49a2e99d69,
|
||||
0xeca8f3318332bb7a,
|
||||
0xef148d1ea0f4c069,
|
||||
0x040ab3263eff0206,
|
||||
}).LexicographicallyLargest())
|
||||
}
|
@ -1,416 +0,0 @@
|
||||
package bls12381
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"math/big"
|
||||
"sync"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
)
|
||||
|
||||
type Fq [native.FieldLimbs]uint64
|
||||
|
||||
var (
|
||||
bls12381FqInitonce sync.Once
|
||||
bls12381FqParams native.FieldParams
|
||||
)
|
||||
|
||||
// 2^S * t = MODULUS - 1 with t odd
|
||||
const fqS = 32
|
||||
|
||||
// qInv = -(q^{-1} mod 2^64) mod 2^64
|
||||
const qInv = 0xfffffffeffffffff
|
||||
|
||||
// fqGenerator = 7 (multiplicative fqGenerator of r-1 order, that is also quadratic nonresidue)
|
||||
var fqGenerator = [native.FieldLimbs]uint64{0x0000000efffffff1, 0x17e363d300189c0f, 0xff9c57876f8457b0, 0x351332208fc5a8c4}
|
||||
|
||||
// fqModulus
|
||||
var fqModulus = [native.FieldLimbs]uint64{0xffffffff00000001, 0x53bda402fffe5bfe, 0x3339d80809a1d805, 0x73eda753299d7d48}
|
||||
|
||||
func Bls12381FqNew() *native.Field {
|
||||
return &native.Field{
|
||||
Value: [native.FieldLimbs]uint64{},
|
||||
Params: getBls12381FqParams(),
|
||||
Arithmetic: bls12381FqArithmetic{},
|
||||
}
|
||||
}
|
||||
|
||||
func bls12381FqParamsInit() {
|
||||
bls12381FqParams = native.FieldParams{
|
||||
R: [native.FieldLimbs]uint64{0x00000001fffffffe, 0x5884b7fa00034802, 0x998c4fefecbc4ff5, 0x1824b159acc5056f},
|
||||
R2: [native.FieldLimbs]uint64{0xc999e990f3f29c6d, 0x2b6cedcb87925c23, 0x05d314967254398f, 0x0748d9d99f59ff11},
|
||||
R3: [native.FieldLimbs]uint64{0xc62c1807439b73af, 0x1b3e0d188cf06990, 0x73d13c71c7b5f418, 0x6e2a5bb9c8db33e9},
|
||||
Modulus: [native.FieldLimbs]uint64{0xffffffff00000001, 0x53bda402fffe5bfe, 0x3339d80809a1d805, 0x73eda753299d7d48},
|
||||
BiModulus: new(big.Int).SetBytes([]byte{
|
||||
0x73, 0xed, 0xa7, 0x53, 0x29, 0x9d, 0x7d, 0x48, 0x33, 0x39, 0xd8, 0x08, 0x09, 0xa1, 0xd8, 0x05, 0x53, 0xbd, 0xa4, 0x02, 0xff, 0xfe, 0x5b, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func getBls12381FqParams() *native.FieldParams {
|
||||
bls12381FqInitonce.Do(bls12381FqParamsInit)
|
||||
return &bls12381FqParams
|
||||
}
|
||||
|
||||
// bls12381FqArithmetic is a struct with all the methods needed for working
|
||||
// in mod q
|
||||
type bls12381FqArithmetic struct{}
|
||||
|
||||
// ToMontgomery converts this field to montgomery form
|
||||
func (f bls12381FqArithmetic) ToMontgomery(out, arg *[native.FieldLimbs]uint64) {
|
||||
// arg.R^0 * R^2 / R = arg.R
|
||||
f.Mul(out, arg, &getBls12381FqParams().R2)
|
||||
}
|
||||
|
||||
// FromMontgomery converts this field from montgomery form
|
||||
func (f bls12381FqArithmetic) FromMontgomery(out, arg *[native.FieldLimbs]uint64) {
|
||||
// Mul by 1 is division by 2^256 mod q
|
||||
// f.Mul(out, arg, &[native.FieldLimbs]uint64{1, 0, 0, 0})
|
||||
f.montReduce(out, &[native.FieldLimbs * 2]uint64{arg[0], arg[1], arg[2], arg[3], 0, 0, 0, 0})
|
||||
}
|
||||
|
||||
// Neg performs modular negation
|
||||
func (f bls12381FqArithmetic) Neg(out, arg *[native.FieldLimbs]uint64) {
|
||||
// Subtract `arg` from `fqModulus`. Ignore final borrow
|
||||
// since it can't underflow.
|
||||
var t [native.FieldLimbs]uint64
|
||||
var borrow uint64
|
||||
t[0], borrow = sbb(fqModulus[0], arg[0], 0)
|
||||
t[1], borrow = sbb(fqModulus[1], arg[1], borrow)
|
||||
t[2], borrow = sbb(fqModulus[2], arg[2], borrow)
|
||||
t[3], _ = sbb(fqModulus[3], arg[3], borrow)
|
||||
|
||||
// t could be `fqModulus` if `arg`=0. Set mask=0 if self=0
|
||||
// and 0xff..ff if `arg`!=0
|
||||
mask := t[0] | t[1] | t[2] | t[3]
|
||||
mask = -((mask | -mask) >> 63)
|
||||
out[0] = t[0] & mask
|
||||
out[1] = t[1] & mask
|
||||
out[2] = t[2] & mask
|
||||
out[3] = t[3] & mask
|
||||
}
|
||||
|
||||
// Square performs modular square
|
||||
func (f bls12381FqArithmetic) Square(out, arg *[native.FieldLimbs]uint64) {
|
||||
var r [2 * native.FieldLimbs]uint64
|
||||
var carry uint64
|
||||
|
||||
r[1], carry = mac(0, arg[0], arg[1], 0)
|
||||
r[2], carry = mac(0, arg[0], arg[2], carry)
|
||||
r[3], r[4] = mac(0, arg[0], arg[3], carry)
|
||||
|
||||
r[3], carry = mac(r[3], arg[1], arg[2], 0)
|
||||
r[4], r[5] = mac(r[4], arg[1], arg[3], carry)
|
||||
|
||||
r[5], r[6] = mac(r[5], arg[2], arg[3], 0)
|
||||
|
||||
r[7] = r[6] >> 63
|
||||
r[6] = (r[6] << 1) | r[5]>>63
|
||||
r[5] = (r[5] << 1) | r[4]>>63
|
||||
r[4] = (r[4] << 1) | r[3]>>63
|
||||
r[3] = (r[3] << 1) | r[2]>>63
|
||||
r[2] = (r[2] << 1) | r[1]>>63
|
||||
r[1] = r[1] << 1
|
||||
|
||||
r[0], carry = mac(0, arg[0], arg[0], 0)
|
||||
r[1], carry = adc(0, r[1], carry)
|
||||
r[2], carry = mac(r[2], arg[1], arg[1], carry)
|
||||
r[3], carry = adc(0, r[3], carry)
|
||||
r[4], carry = mac(r[4], arg[2], arg[2], carry)
|
||||
r[5], carry = adc(0, r[5], carry)
|
||||
r[6], carry = mac(r[6], arg[3], arg[3], carry)
|
||||
r[7], _ = adc(0, r[7], carry)
|
||||
|
||||
f.montReduce(out, &r)
|
||||
}
|
||||
|
||||
// Mul performs modular multiplication
|
||||
func (f bls12381FqArithmetic) Mul(out, arg1, arg2 *[native.FieldLimbs]uint64) {
|
||||
// Schoolbook multiplication
|
||||
var r [2 * native.FieldLimbs]uint64
|
||||
var carry uint64
|
||||
|
||||
r[0], carry = mac(0, arg1[0], arg2[0], 0)
|
||||
r[1], carry = mac(0, arg1[0], arg2[1], carry)
|
||||
r[2], carry = mac(0, arg1[0], arg2[2], carry)
|
||||
r[3], r[4] = mac(0, arg1[0], arg2[3], carry)
|
||||
|
||||
r[1], carry = mac(r[1], arg1[1], arg2[0], 0)
|
||||
r[2], carry = mac(r[2], arg1[1], arg2[1], carry)
|
||||
r[3], carry = mac(r[3], arg1[1], arg2[2], carry)
|
||||
r[4], r[5] = mac(r[4], arg1[1], arg2[3], carry)
|
||||
|
||||
r[2], carry = mac(r[2], arg1[2], arg2[0], 0)
|
||||
r[3], carry = mac(r[3], arg1[2], arg2[1], carry)
|
||||
r[4], carry = mac(r[4], arg1[2], arg2[2], carry)
|
||||
r[5], r[6] = mac(r[5], arg1[2], arg2[3], carry)
|
||||
|
||||
r[3], carry = mac(r[3], arg1[3], arg2[0], 0)
|
||||
r[4], carry = mac(r[4], arg1[3], arg2[1], carry)
|
||||
r[5], carry = mac(r[5], arg1[3], arg2[2], carry)
|
||||
r[6], r[7] = mac(r[6], arg1[3], arg2[3], carry)
|
||||
|
||||
f.montReduce(out, &r)
|
||||
}
|
||||
|
||||
// Add performs modular addition
|
||||
func (f bls12381FqArithmetic) Add(out, arg1, arg2 *[native.FieldLimbs]uint64) {
|
||||
var t [native.FieldLimbs]uint64
|
||||
var carry uint64
|
||||
|
||||
t[0], carry = adc(arg1[0], arg2[0], 0)
|
||||
t[1], carry = adc(arg1[1], arg2[1], carry)
|
||||
t[2], carry = adc(arg1[2], arg2[2], carry)
|
||||
t[3], _ = adc(arg1[3], arg2[3], carry)
|
||||
|
||||
// Subtract the fqModulus to ensure the value
|
||||
// is smaller.
|
||||
f.Sub(out, &t, &fqModulus)
|
||||
}
|
||||
|
||||
// Sub performs modular subtraction
|
||||
func (f bls12381FqArithmetic) Sub(out, arg1, arg2 *[native.FieldLimbs]uint64) {
|
||||
d0, borrow := sbb(arg1[0], arg2[0], 0)
|
||||
d1, borrow := sbb(arg1[1], arg2[1], borrow)
|
||||
d2, borrow := sbb(arg1[2], arg2[2], borrow)
|
||||
d3, borrow := sbb(arg1[3], arg2[3], borrow)
|
||||
|
||||
// If underflow occurred on the final limb, borrow 0xff...ff, otherwise
|
||||
// borrow = 0x00...00. Conditionally mask to add the fqModulus
|
||||
borrow = -borrow
|
||||
d0, carry := adc(d0, fqModulus[0]&borrow, 0)
|
||||
d1, carry = adc(d1, fqModulus[1]&borrow, carry)
|
||||
d2, carry = adc(d2, fqModulus[2]&borrow, carry)
|
||||
d3, _ = adc(d3, fqModulus[3]&borrow, carry)
|
||||
|
||||
out[0] = d0
|
||||
out[1] = d1
|
||||
out[2] = d2
|
||||
out[3] = d3
|
||||
}
|
||||
|
||||
// Sqrt performs modular square root
|
||||
func (f bls12381FqArithmetic) Sqrt(wasSquare *int, out, arg *[native.FieldLimbs]uint64) {
|
||||
// See sqrt_ts_ct at
|
||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-I.4
|
||||
// c1 := fqS
|
||||
// c2 := (q - 1) / (2^c1)
|
||||
c2 := [4]uint64{
|
||||
0xfffe5bfeffffffff,
|
||||
0x09a1d80553bda402,
|
||||
0x299d7d483339d808,
|
||||
0x0000000073eda753,
|
||||
}
|
||||
// c3 := (c2 - 1) / 2
|
||||
c3 := [native.FieldLimbs]uint64{
|
||||
0x7fff2dff7fffffff,
|
||||
0x04d0ec02a9ded201,
|
||||
0x94cebea4199cec04,
|
||||
0x0000000039f6d3a9,
|
||||
}
|
||||
// c4 := fqGenerator
|
||||
var c5 [native.FieldLimbs]uint64
|
||||
native.Pow(&c5, &fqGenerator, &c2, getBls12381FqParams(), f)
|
||||
// c5 := [native.FieldLimbs]uint64{0x1015708f7e368fe1, 0x31c6c5456ecc4511, 0x5281fe8998a19ea1, 0x0279089e10c63fe8}
|
||||
var z, t, b, c, tv [native.FieldLimbs]uint64
|
||||
|
||||
native.Pow(&z, arg, &c3, getBls12381FqParams(), f)
|
||||
f.Square(&t, &z)
|
||||
f.Mul(&t, &t, arg)
|
||||
f.Mul(&z, &z, arg)
|
||||
|
||||
copy(b[:], t[:])
|
||||
copy(c[:], c5[:])
|
||||
|
||||
for i := fqS; i >= 2; i-- {
|
||||
for j := 1; j <= i-2; j++ {
|
||||
f.Square(&b, &b)
|
||||
}
|
||||
// if b == 1 flag = 0 else flag = 1
|
||||
flag := -(&native.Field{
|
||||
Value: b,
|
||||
Params: getBls12381FqParams(),
|
||||
Arithmetic: f,
|
||||
}).IsOne() + 1
|
||||
f.Mul(&tv, &z, &c)
|
||||
f.Selectznz(&z, &z, &tv, flag)
|
||||
f.Square(&c, &c)
|
||||
f.Mul(&tv, &t, &c)
|
||||
f.Selectznz(&t, &t, &tv, flag)
|
||||
copy(b[:], t[:])
|
||||
}
|
||||
f.Square(&c, &z)
|
||||
*wasSquare = (&native.Field{
|
||||
Value: c,
|
||||
Params: getBls12381FqParams(),
|
||||
Arithmetic: f,
|
||||
}).Equal(&native.Field{
|
||||
Value: *arg,
|
||||
Params: getBls12381FqParams(),
|
||||
Arithmetic: f,
|
||||
})
|
||||
f.Selectznz(out, out, &z, *wasSquare)
|
||||
}
|
||||
|
||||
// Invert performs modular inverse
|
||||
func (f bls12381FqArithmetic) Invert(wasInverted *int, out, arg *[native.FieldLimbs]uint64) {
|
||||
// Using an addition chain from
|
||||
// https://github.com/kwantam/addchain
|
||||
var t0, t1, t2, t3, t4, t5, t6, t7, t8 [native.FieldLimbs]uint64
|
||||
var t9, t11, t12, t13, t14, t15, t16, t17 [native.FieldLimbs]uint64
|
||||
|
||||
f.Square(&t0, arg)
|
||||
f.Mul(&t1, &t0, arg)
|
||||
f.Square(&t16, &t0)
|
||||
f.Square(&t6, &t16)
|
||||
f.Mul(&t5, &t6, &t0)
|
||||
f.Mul(&t0, &t6, &t16)
|
||||
f.Mul(&t12, &t5, &t16)
|
||||
f.Square(&t2, &t6)
|
||||
f.Mul(&t7, &t5, &t6)
|
||||
f.Mul(&t15, &t0, &t5)
|
||||
f.Square(&t17, &t12)
|
||||
f.Mul(&t1, &t1, &t17)
|
||||
f.Mul(&t3, &t7, &t2)
|
||||
f.Mul(&t8, &t1, &t17)
|
||||
f.Mul(&t4, &t8, &t2)
|
||||
f.Mul(&t9, &t8, &t7)
|
||||
f.Mul(&t7, &t4, &t5)
|
||||
f.Mul(&t11, &t4, &t17)
|
||||
f.Mul(&t5, &t9, &t17)
|
||||
f.Mul(&t14, &t7, &t15)
|
||||
f.Mul(&t13, &t11, &t12)
|
||||
f.Mul(&t12, &t11, &t17)
|
||||
f.Mul(&t15, &t15, &t12)
|
||||
f.Mul(&t16, &t16, &t15)
|
||||
f.Mul(&t3, &t3, &t16)
|
||||
f.Mul(&t17, &t17, &t3)
|
||||
f.Mul(&t0, &t0, &t17)
|
||||
f.Mul(&t6, &t6, &t0)
|
||||
f.Mul(&t2, &t2, &t6)
|
||||
native.Pow2k(&t0, &t0, 8, f)
|
||||
f.Mul(&t0, &t0, &t17)
|
||||
native.Pow2k(&t0, &t0, 9, f)
|
||||
f.Mul(&t0, &t0, &t16)
|
||||
native.Pow2k(&t0, &t0, 9, f)
|
||||
f.Mul(&t0, &t0, &t15)
|
||||
native.Pow2k(&t0, &t0, 9, f)
|
||||
f.Mul(&t0, &t0, &t15)
|
||||
native.Pow2k(&t0, &t0, 7, f)
|
||||
f.Mul(&t0, &t0, &t14)
|
||||
native.Pow2k(&t0, &t0, 7, f)
|
||||
f.Mul(&t0, &t0, &t13)
|
||||
native.Pow2k(&t0, &t0, 10, f)
|
||||
f.Mul(&t0, &t0, &t12)
|
||||
native.Pow2k(&t0, &t0, 9, f)
|
||||
f.Mul(&t0, &t0, &t11)
|
||||
native.Pow2k(&t0, &t0, 8, f)
|
||||
f.Mul(&t0, &t0, &t8)
|
||||
native.Pow2k(&t0, &t0, 8, f)
|
||||
f.Mul(&t0, &t0, arg)
|
||||
native.Pow2k(&t0, &t0, 14, f)
|
||||
f.Mul(&t0, &t0, &t9)
|
||||
native.Pow2k(&t0, &t0, 10, f)
|
||||
f.Mul(&t0, &t0, &t8)
|
||||
native.Pow2k(&t0, &t0, 15, f)
|
||||
f.Mul(&t0, &t0, &t7)
|
||||
native.Pow2k(&t0, &t0, 10, f)
|
||||
f.Mul(&t0, &t0, &t6)
|
||||
native.Pow2k(&t0, &t0, 8, f)
|
||||
f.Mul(&t0, &t0, &t5)
|
||||
native.Pow2k(&t0, &t0, 16, f)
|
||||
f.Mul(&t0, &t0, &t3)
|
||||
native.Pow2k(&t0, &t0, 8, f)
|
||||
f.Mul(&t0, &t0, &t2)
|
||||
native.Pow2k(&t0, &t0, 7, f)
|
||||
f.Mul(&t0, &t0, &t4)
|
||||
native.Pow2k(&t0, &t0, 9, f)
|
||||
f.Mul(&t0, &t0, &t2)
|
||||
native.Pow2k(&t0, &t0, 8, f)
|
||||
f.Mul(&t0, &t0, &t3)
|
||||
native.Pow2k(&t0, &t0, 8, f)
|
||||
f.Mul(&t0, &t0, &t2)
|
||||
native.Pow2k(&t0, &t0, 8, f)
|
||||
f.Mul(&t0, &t0, &t2)
|
||||
native.Pow2k(&t0, &t0, 8, f)
|
||||
f.Mul(&t0, &t0, &t2)
|
||||
native.Pow2k(&t0, &t0, 8, f)
|
||||
f.Mul(&t0, &t0, &t3)
|
||||
native.Pow2k(&t0, &t0, 8, f)
|
||||
f.Mul(&t0, &t0, &t2)
|
||||
native.Pow2k(&t0, &t0, 8, f)
|
||||
f.Mul(&t0, &t0, &t2)
|
||||
native.Pow2k(&t0, &t0, 5, f)
|
||||
f.Mul(&t0, &t0, &t1)
|
||||
native.Pow2k(&t0, &t0, 5, f)
|
||||
f.Mul(&t0, &t0, &t1)
|
||||
|
||||
*wasInverted = (&native.Field{
|
||||
Value: *arg,
|
||||
Params: getBls12381FqParams(),
|
||||
Arithmetic: f,
|
||||
}).IsNonZero()
|
||||
f.Selectznz(out, out, &t0, *wasInverted)
|
||||
}
|
||||
|
||||
// FromBytes converts a little endian byte array into a field element
|
||||
func (f bls12381FqArithmetic) FromBytes(out *[native.FieldLimbs]uint64, arg *[native.FieldBytes]byte) {
|
||||
out[0] = binary.LittleEndian.Uint64(arg[:8])
|
||||
out[1] = binary.LittleEndian.Uint64(arg[8:16])
|
||||
out[2] = binary.LittleEndian.Uint64(arg[16:24])
|
||||
out[3] = binary.LittleEndian.Uint64(arg[24:])
|
||||
}
|
||||
|
||||
// ToBytes converts a field element to a little endian byte array
|
||||
func (f bls12381FqArithmetic) ToBytes(out *[native.FieldBytes]byte, arg *[native.FieldLimbs]uint64) {
|
||||
binary.LittleEndian.PutUint64(out[:8], arg[0])
|
||||
binary.LittleEndian.PutUint64(out[8:16], arg[1])
|
||||
binary.LittleEndian.PutUint64(out[16:24], arg[2])
|
||||
binary.LittleEndian.PutUint64(out[24:], arg[3])
|
||||
}
|
||||
|
||||
// Selectznz performs conditional select.
|
||||
// selects arg1 if choice == 0 and arg2 if choice == 1
|
||||
func (f bls12381FqArithmetic) Selectznz(out, arg1, arg2 *[native.FieldLimbs]uint64, choice int) {
|
||||
b := uint64(-choice)
|
||||
out[0] = arg1[0] ^ ((arg1[0] ^ arg2[0]) & b)
|
||||
out[1] = arg1[1] ^ ((arg1[1] ^ arg2[1]) & b)
|
||||
out[2] = arg1[2] ^ ((arg1[2] ^ arg2[2]) & b)
|
||||
out[3] = arg1[3] ^ ((arg1[3] ^ arg2[3]) & b)
|
||||
}
|
||||
|
||||
func (f bls12381FqArithmetic) montReduce(out *[native.FieldLimbs]uint64, r *[2 * native.FieldLimbs]uint64) {
|
||||
// Taken from Algorithm 14.32 in Handbook of Applied Cryptography
|
||||
var r1, r2, r3, r4, r5, r6, carry, carry2, k uint64
|
||||
var rr [native.FieldLimbs]uint64
|
||||
|
||||
k = r[0] * qInv
|
||||
_, carry = mac(r[0], k, fqModulus[0], 0)
|
||||
r1, carry = mac(r[1], k, fqModulus[1], carry)
|
||||
r2, carry = mac(r[2], k, fqModulus[2], carry)
|
||||
r3, carry = mac(r[3], k, fqModulus[3], carry)
|
||||
r4, carry2 = adc(r[4], 0, carry)
|
||||
|
||||
k = r1 * qInv
|
||||
_, carry = mac(r1, k, fqModulus[0], 0)
|
||||
r2, carry = mac(r2, k, fqModulus[1], carry)
|
||||
r3, carry = mac(r3, k, fqModulus[2], carry)
|
||||
r4, carry = mac(r4, k, fqModulus[3], carry)
|
||||
r5, carry2 = adc(r[5], carry2, carry)
|
||||
|
||||
k = r2 * qInv
|
||||
_, carry = mac(r2, k, fqModulus[0], 0)
|
||||
r3, carry = mac(r3, k, fqModulus[1], carry)
|
||||
r4, carry = mac(r4, k, fqModulus[2], carry)
|
||||
r5, carry = mac(r5, k, fqModulus[3], carry)
|
||||
r6, carry2 = adc(r[6], carry2, carry)
|
||||
|
||||
k = r3 * qInv
|
||||
_, carry = mac(r3, k, fqModulus[0], 0)
|
||||
rr[0], carry = mac(r4, k, fqModulus[1], carry)
|
||||
rr[1], carry = mac(r5, k, fqModulus[2], carry)
|
||||
rr[2], carry = mac(r6, k, fqModulus[3], carry)
|
||||
rr[3], _ = adc(r[7], carry2, carry)
|
||||
|
||||
f.Sub(out, &rr, &fqModulus)
|
||||
}
|
@ -1,342 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package bls12381
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
"github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
func TestFqSetOne(t *testing.T) {
|
||||
fq := Bls12381FqNew().SetOne()
|
||||
require.NotNil(t, fq)
|
||||
require.Equal(t, fq.Value, getBls12381FqParams().R)
|
||||
}
|
||||
|
||||
func TestFqSetUint64(t *testing.T) {
|
||||
act := Bls12381FqNew().SetUint64(1 << 60)
|
||||
require.NotNil(t, act)
|
||||
// Remember it will be in montgomery form
|
||||
require.Equal(t, act.Value[0], uint64(0xbc98da2820121c89))
|
||||
}
|
||||
|
||||
func TestFqAdd(t *testing.T) {
|
||||
lhs := Bls12381FqNew().SetOne()
|
||||
rhs := Bls12381FqNew().SetOne()
|
||||
exp := Bls12381FqNew().SetUint64(2)
|
||||
res := Bls12381FqNew().Add(lhs, rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, 1, res.Equal(exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint64() >> 2
|
||||
r := rand.Uint64() >> 2
|
||||
e := l + r
|
||||
lhs.SetUint64(l)
|
||||
rhs.SetUint64(r)
|
||||
exp.SetUint64(e)
|
||||
|
||||
a := Bls12381FqNew().Add(lhs, rhs)
|
||||
require.NotNil(t, a)
|
||||
require.Equal(t, exp, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqSub(t *testing.T) {
|
||||
lhs := Bls12381FqNew().SetOne()
|
||||
rhs := Bls12381FqNew().SetOne()
|
||||
exp := Bls12381FqNew().SetZero()
|
||||
res := Bls12381FqNew().Sub(lhs, rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, 1, res.Equal(exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint64() >> 2
|
||||
r := rand.Uint64() >> 2
|
||||
if l < r {
|
||||
l, r = r, l
|
||||
}
|
||||
e := l - r
|
||||
lhs.SetUint64(l)
|
||||
rhs.SetUint64(r)
|
||||
exp.SetUint64(e)
|
||||
|
||||
a := Bls12381FqNew().Sub(lhs, rhs)
|
||||
require.NotNil(t, a)
|
||||
require.Equal(t, exp, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqMul(t *testing.T) {
|
||||
lhs := Bls12381FqNew().SetOne()
|
||||
rhs := Bls12381FqNew().SetOne()
|
||||
exp := Bls12381FqNew().SetOne()
|
||||
res := Bls12381FqNew().Mul(lhs, rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, 1, res.Equal(exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint32()
|
||||
r := rand.Uint32()
|
||||
e := uint64(l) * uint64(r)
|
||||
lhs.SetUint64(uint64(l))
|
||||
rhs.SetUint64(uint64(r))
|
||||
exp.SetUint64(e)
|
||||
|
||||
a := Bls12381FqNew().Mul(lhs, rhs)
|
||||
require.NotNil(t, a)
|
||||
require.Equal(t, exp, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqDouble(t *testing.T) {
|
||||
a := Bls12381FqNew().SetUint64(2)
|
||||
e := Bls12381FqNew().SetUint64(4)
|
||||
require.Equal(t, e, Bls12381FqNew().Double(a))
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
tv := rand.Uint32()
|
||||
ttv := uint64(tv) * 2
|
||||
a = Bls12381FqNew().SetUint64(uint64(tv))
|
||||
e = Bls12381FqNew().SetUint64(ttv)
|
||||
require.Equal(t, e, Bls12381FqNew().Double(a))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqSquare(t *testing.T) {
|
||||
a := Bls12381FqNew().SetUint64(4)
|
||||
e := Bls12381FqNew().SetUint64(16)
|
||||
require.Equal(t, 1, e.Equal(a.Square(a)))
|
||||
|
||||
a.SetUint64(2854263694)
|
||||
e.SetUint64(8146821234886525636)
|
||||
require.Equal(t, 1, e.Equal(a.Square(a)))
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
j := rand.Uint32()
|
||||
exp := uint64(j) * uint64(j)
|
||||
e.SetUint64(exp)
|
||||
a.SetUint64(uint64(j))
|
||||
require.Equal(t, 1, e.Equal(a.Square(a)), "exp = %d, j = %d", exp, j)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqNeg(t *testing.T) {
|
||||
g := Bls12381FqNew().SetRaw(&fqGenerator)
|
||||
a := Bls12381FqNew().SetOne()
|
||||
a.Neg(a)
|
||||
e := Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{0xfffffffd00000003, 0xfb38ec08fffb13fc, 0x99ad88181ce5880f, 0x5bc8f5f97cd877d8})
|
||||
require.Equal(t, 1, e.Equal(a))
|
||||
a.Neg(g)
|
||||
e = Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{0xfffffff000000010, 0x3bda402fffe5bfef, 0x339d80809a1d8055, 0x3eda753299d7d483})
|
||||
require.Equal(t, e, a)
|
||||
}
|
||||
|
||||
func TestFqExp(t *testing.T) {
|
||||
e := Bls12381FqNew().SetUint64(8)
|
||||
a := Bls12381FqNew().SetUint64(2)
|
||||
by := Bls12381FqNew().SetUint64(3)
|
||||
require.Equal(t, e, a.Exp(a, by))
|
||||
}
|
||||
|
||||
func TestFqSqrt(t *testing.T) {
|
||||
t1 := Bls12381FqNew().SetUint64(2)
|
||||
t2 := Bls12381FqNew().Neg(t1)
|
||||
t3 := Bls12381FqNew().Square(t1)
|
||||
_, wasSquare := t3.Sqrt(t3)
|
||||
|
||||
require.True(t, wasSquare)
|
||||
require.Equal(t, 1, t1.Equal(t3)|t2.Equal(t3))
|
||||
t1.SetUint64(5)
|
||||
_, wasSquare = Bls12381FqNew().Sqrt(t1)
|
||||
require.False(t, wasSquare)
|
||||
}
|
||||
|
||||
func TestFqInvert(t *testing.T) {
|
||||
twoInv := Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{0xffffffff, 0xac425bfd0001a401, 0xccc627f7f65e27fa, 0xc1258acd66282b7})
|
||||
two := Bls12381FqNew().SetUint64(2)
|
||||
a, inverted := Bls12381FqNew().Invert(two)
|
||||
require.True(t, inverted)
|
||||
require.Equal(t, a, twoInv)
|
||||
|
||||
rootOfUnity := Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{0xb9b58d8c5f0e466a, 0x5b1b4c801819d7ec, 0x0af53ae352a31e64, 0x5bf3adda19e9b27b})
|
||||
rootOfUnityInv := Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{0x4256481adcf3219a, 0x45f37b7f96b6cad3, 0xf9c3f1d75f7a3b27, 0x2d2fc049658afd43})
|
||||
a, inverted = Bls12381FqNew().Invert(rootOfUnity)
|
||||
require.True(t, inverted)
|
||||
require.Equal(t, a, rootOfUnityInv)
|
||||
|
||||
lhs := Bls12381FqNew().SetUint64(9)
|
||||
rhs := Bls12381FqNew().SetUint64(3)
|
||||
rhsInv, inverted := Bls12381FqNew().Invert(rhs)
|
||||
require.True(t, inverted)
|
||||
require.Equal(t, rhs, Bls12381FqNew().Mul(lhs, rhsInv))
|
||||
|
||||
rhs.SetZero()
|
||||
_, inverted = Bls12381FqNew().Invert(rhs)
|
||||
require.False(t, inverted)
|
||||
}
|
||||
|
||||
func TestFqCMove(t *testing.T) {
|
||||
t1 := Bls12381FqNew().SetUint64(5)
|
||||
t2 := Bls12381FqNew().SetUint64(10)
|
||||
require.Equal(t, t1, Bls12381FqNew().CMove(t1, t2, 0))
|
||||
require.Equal(t, t2, Bls12381FqNew().CMove(t1, t2, 1))
|
||||
}
|
||||
|
||||
func TestFqBytes(t *testing.T) {
|
||||
t1 := Bls12381FqNew().SetUint64(99)
|
||||
seq := t1.Bytes()
|
||||
t2, err := Bls12381FqNew().SetBytes(&seq)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, t1, t2)
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
t1.SetUint64(rand.Uint64())
|
||||
seq = t1.Bytes()
|
||||
_, err = t2.SetBytes(&seq)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, t1, t2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqCmp(t *testing.T) {
|
||||
tests := []struct {
|
||||
a *native.Field
|
||||
b *native.Field
|
||||
e int
|
||||
}{
|
||||
{
|
||||
a: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{2731658267414164836, 14655288906067898431, 6537465423330262322, 8306191141697566219}),
|
||||
b: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{6472764012681988529, 10848812988401906064, 2961825807536828898, 4282183981941645679}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{8023004109510539223, 4652004072850285717, 1877219145646046927, 383214385093921911}),
|
||||
b: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{10099384440823804262, 16139476942229308465, 8636966320777393798, 5435928725024696785}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{3741840066202388211, 12165774400417314871, 16619312580230515379, 16195032234110087705}),
|
||||
b: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{3905865991286066744, 543690822309071825, 17963103015950210055, 3745476720756119742}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{16660853697936147788, 7799793619412111108, 13515141085171033220, 2641079731236069032}),
|
||||
b: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{17790588295388238399, 571847801379669440, 14537208974498222469, 12792570372087452754}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{3912839285384959186, 2701177075110484070, 6453856448115499033, 6475797457962597458}),
|
||||
b: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{1282566391665688512, 13503640416992806563, 2962240104675990153, 3374904770947067689}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{5716631803409360103, 7859567470082614154, 12747956220853330146, 18434584096087315020}),
|
||||
b: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{16317076441459028418, 12854146980376319601, 2258436689269031143, 9531877130792223752}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{17955191469941083403, 10350326247207200880, 17263512235150705075, 12700328451238078022}),
|
||||
b: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{6767595547459644695, 7146403825494928147, 12269344038346710612, 9122477829383225603}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{17099388671847024438, 6426264987820696548, 10641143464957227405, 7709745403700754098}),
|
||||
b: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{10799154372990268556, 17178492485719929374, 5705777922258988797, 8051037767683567782}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{4567139260680454325, 1629385880182139061, 16607020832317899145, 1261011562621553200}),
|
||||
b: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{13487234491304534488, 17872642955936089265, 17651026784972590233, 9468934643333871559}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{18071070103467571798, 11787850505799426140, 10631355976141928593, 4867785203635092610}),
|
||||
b: Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{12596443599426461624, 10176122686151524591, 17075755296887483439, 6726169532695070719}),
|
||||
e: -1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
require.Equal(t, test.e, test.a.Cmp(test.b))
|
||||
require.Equal(t, -test.e, test.b.Cmp(test.a))
|
||||
require.Equal(t, 0, test.a.Cmp(test.a))
|
||||
require.Equal(t, 0, test.b.Cmp(test.b))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqBigInt(t *testing.T) {
|
||||
t1 := Bls12381FqNew().SetBigInt(big.NewInt(9999))
|
||||
t2 := Bls12381FqNew().SetBigInt(t1.BigInt())
|
||||
require.Equal(t, t1, t2)
|
||||
|
||||
e := Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{0x673053fc60e06500, 0x86e6d480b4f76ada, 0x7fc68f9fefa23291, 0x3fb17f49bdda126d})
|
||||
b := new(big.Int).SetBytes([]byte{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9})
|
||||
t1.SetBigInt(b)
|
||||
require.Equal(t, e, t1)
|
||||
e.Neg(e)
|
||||
b.Neg(b)
|
||||
t1.SetBigInt(b)
|
||||
require.Equal(t, e, t1)
|
||||
}
|
||||
|
||||
func TestFqSetBytesWide(t *testing.T) {
|
||||
e := Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{0xc759fba87ff8c5a6, 0x9ef5194839e7df44, 0x21375d22b678bf0e, 0x38b105387033fd57})
|
||||
|
||||
a := Bls12381FqNew().SetBytesWide(&[64]byte{
|
||||
0x69, 0x23, 0x5a, 0x0b, 0xce, 0x0c, 0xa8, 0x64,
|
||||
0x3c, 0x78, 0xbc, 0x01, 0x05, 0xef, 0xf2, 0x84,
|
||||
0xde, 0xbb, 0x6b, 0xc8, 0x63, 0x5e, 0x6e, 0x69,
|
||||
0x62, 0xcc, 0xc6, 0x2d, 0xf5, 0x72, 0x40, 0x92,
|
||||
0x28, 0x11, 0xd6, 0xc8, 0x07, 0xa5, 0x88, 0x82,
|
||||
0xfe, 0xe3, 0x97, 0xf6, 0x1e, 0xfb, 0x2e, 0x3b,
|
||||
0x27, 0x5f, 0x85, 0x06, 0x8d, 0x99, 0xa4, 0x75,
|
||||
0xc0, 0x2c, 0x71, 0x69, 0x9e, 0x58, 0xea, 0x52,
|
||||
})
|
||||
require.Equal(t, e, a)
|
||||
}
|
||||
|
||||
func TestFqSetBytesWideBigInt(t *testing.T) {
|
||||
params := getBls12381FqParams()
|
||||
var tv2 [64]byte
|
||||
for i := 0; i < 25; i++ {
|
||||
_, _ = crand.Read(tv2[:])
|
||||
e := new(big.Int).SetBytes(tv2[:])
|
||||
e.Mod(e, params.BiModulus)
|
||||
|
||||
tv := internal.ReverseScalarBytes(tv2[:])
|
||||
copy(tv2[:], tv)
|
||||
a := Bls12381FqNew().SetBytesWide(&tv2)
|
||||
require.Equal(t, 0, e.Cmp(a.BigInt()))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqToMontgomery(t *testing.T) {
|
||||
v := Bls12381FqNew().SetUint64(2)
|
||||
require.Equal(t, [native.FieldLimbs]uint64{0x3fffffffc, 0xb1096ff400069004, 0x33189fdfd9789fea, 0x304962b3598a0adf}, v.Value)
|
||||
}
|
||||
|
||||
func TestFqFromMontgomery(t *testing.T) {
|
||||
e := [native.FieldLimbs]uint64{2, 0, 0, 0}
|
||||
a := [native.FieldLimbs]uint64{0, 0, 0, 0}
|
||||
v := Bls12381FqNew().SetUint64(2)
|
||||
v.Arithmetic.FromMontgomery(&a, &v.Value)
|
||||
require.Equal(t, e, a)
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,412 +0,0 @@
|
||||
package bls12381
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
)
|
||||
|
||||
func TestG1IsOnCurve(t *testing.T) {
|
||||
require.Equal(t, 1, new(G1).Identity().IsOnCurve())
|
||||
require.Equal(t, 1, new(G1).Generator().IsOnCurve())
|
||||
|
||||
z := fp{
|
||||
0xba7afa1f9a6fe250,
|
||||
0xfa0f5b595eafe731,
|
||||
0x3bdc477694c306e7,
|
||||
0x2149be4b3949fa24,
|
||||
0x64aa6e0649b2078c,
|
||||
0x12b108ac33643c3e,
|
||||
}
|
||||
|
||||
gen := new(G1).Generator()
|
||||
test := G1{
|
||||
x: *(gen.x.Mul(&gen.x, &z)),
|
||||
y: *(gen.y.Mul(&gen.y, &z)),
|
||||
z: z,
|
||||
}
|
||||
require.Equal(t, 1, test.IsOnCurve())
|
||||
test.x = z
|
||||
require.Equal(t, 0, test.IsOnCurve())
|
||||
}
|
||||
|
||||
func TestG1Equality(t *testing.T) {
|
||||
a := new(G1).Generator()
|
||||
b := new(G1).Identity()
|
||||
|
||||
require.Equal(t, 1, a.Equal(a))
|
||||
require.Equal(t, 1, b.Equal(b))
|
||||
require.Equal(t, 0, a.Equal(b))
|
||||
require.Equal(t, 0, b.Equal(a))
|
||||
|
||||
z := fp{
|
||||
0xba7afa1f9a6fe250,
|
||||
0xfa0f5b595eafe731,
|
||||
0x3bdc477694c306e7,
|
||||
0x2149be4b3949fa24,
|
||||
0x64aa6e0649b2078c,
|
||||
0x12b108ac33643c3e,
|
||||
}
|
||||
|
||||
c := G1{}
|
||||
c.x.Mul(&a.x, &z)
|
||||
c.y.Mul(&a.y, &z)
|
||||
c.z.Set(&z)
|
||||
|
||||
require.Equal(t, 1, c.IsOnCurve())
|
||||
|
||||
require.Equal(t, 1, a.Equal(&c))
|
||||
require.Equal(t, 0, b.Equal(&c))
|
||||
|
||||
c.y.Neg(&c.y)
|
||||
require.Equal(t, 1, c.IsOnCurve())
|
||||
|
||||
require.Equal(t, 0, a.Equal(&c))
|
||||
|
||||
c.y.Neg(&c.y)
|
||||
c.x.Set(&z)
|
||||
require.Equal(t, 0, c.IsOnCurve())
|
||||
}
|
||||
|
||||
func TestG1Double(t *testing.T) {
|
||||
t0 := new(G1).Identity()
|
||||
t0.Double(t0)
|
||||
require.Equal(t, 1, t0.IsIdentity())
|
||||
require.Equal(t, 1, t0.IsOnCurve())
|
||||
|
||||
t0.Double(t0.Generator())
|
||||
require.Equal(t, 0, t0.IsIdentity())
|
||||
require.Equal(t, 1, t0.IsOnCurve())
|
||||
e := G1{
|
||||
x: fp{
|
||||
0x53e978ce58a9ba3c,
|
||||
0x3ea0583c4f3d65f9,
|
||||
0x4d20bb47f0012960,
|
||||
0xa54c664ae5b2b5d9,
|
||||
0x26b552a39d7eb21f,
|
||||
0x0008895d26e68785,
|
||||
},
|
||||
y: fp{
|
||||
0x70110b3298293940,
|
||||
0xda33c5393f1f6afc,
|
||||
0xb86edfd16a5aa785,
|
||||
0xaec6d1c9e7b1c895,
|
||||
0x25cfc2b522d11720,
|
||||
0x06361c83f8d09b15,
|
||||
},
|
||||
z: r,
|
||||
}
|
||||
|
||||
require.Equal(t, 1, e.Equal(t0))
|
||||
}
|
||||
|
||||
func TestG1Add(t *testing.T) {
|
||||
g := new(G1).Generator()
|
||||
a := new(G1).Identity()
|
||||
b := new(G1).Identity()
|
||||
c := new(G1).Add(a, b)
|
||||
require.Equal(t, 1, c.IsIdentity())
|
||||
require.Equal(t, 1, c.IsOnCurve())
|
||||
|
||||
b.Generator()
|
||||
z := fp{
|
||||
0xba7afa1f9a6fe250,
|
||||
0xfa0f5b595eafe731,
|
||||
0x3bdc477694c306e7,
|
||||
0x2149be4b3949fa24,
|
||||
0x64aa6e0649b2078c,
|
||||
0x12b108ac33643c3e,
|
||||
}
|
||||
b.x.Mul(&b.x, &z)
|
||||
b.y.Mul(&b.y, &z)
|
||||
b.z.Set(&z)
|
||||
c.Add(a, b)
|
||||
require.Equal(t, 0, c.IsIdentity())
|
||||
require.Equal(t, 1, g.Equal(c))
|
||||
|
||||
a.Generator()
|
||||
a.Double(a)
|
||||
a.Double(a)
|
||||
b.Generator()
|
||||
b.Double(b)
|
||||
c.Add(a, b)
|
||||
d := new(G1).Generator()
|
||||
for i := 0; i < 5; i++ {
|
||||
d.Add(d, g)
|
||||
}
|
||||
require.Equal(t, 0, c.IsIdentity())
|
||||
require.Equal(t, 1, c.IsOnCurve())
|
||||
require.Equal(t, 0, d.IsIdentity())
|
||||
require.Equal(t, 1, d.IsOnCurve())
|
||||
require.Equal(t, 1, c.Equal(d))
|
||||
|
||||
beta := fp{
|
||||
0xcd03c9e48671f071,
|
||||
0x5dab22461fcda5d2,
|
||||
0x587042afd3851b95,
|
||||
0x8eb60ebe01bacb9e,
|
||||
0x03f97d6e83d050d2,
|
||||
0x18f0206554638741,
|
||||
}
|
||||
beta.Square(&beta)
|
||||
a.Generator()
|
||||
a.Double(a)
|
||||
a.Double(a)
|
||||
b.x.Mul(&a.x, &beta)
|
||||
b.y.Neg(&a.y)
|
||||
b.z.Set(&a.z)
|
||||
require.Equal(t, 1, a.IsOnCurve())
|
||||
require.Equal(t, 1, b.IsOnCurve())
|
||||
c.Add(a, b)
|
||||
d.x.Set(&fp{
|
||||
0x29e1e987ef68f2d0,
|
||||
0xc5f3ec531db03233,
|
||||
0xacd6c4b6ca19730f,
|
||||
0x18ad9e827bc2bab7,
|
||||
0x46e3b2c5785cc7a9,
|
||||
0x07e571d42d22ddd6,
|
||||
})
|
||||
d.y.Set(&fp{
|
||||
0x94d117a7e5a539e7,
|
||||
0x8e17ef673d4b5d22,
|
||||
0x9d746aaf508a33ea,
|
||||
0x8c6d883d2516c9a2,
|
||||
0x0bc3b8d5fb0447f7,
|
||||
0x07bfa4c7210f4f44,
|
||||
})
|
||||
d.z.SetOne()
|
||||
require.Equal(t, 1, c.Equal(d))
|
||||
}
|
||||
|
||||
func TestG1Sub(t *testing.T) {
|
||||
a := new(G1).Generator()
|
||||
b := new(G1).Generator()
|
||||
require.Equal(t, 1, a.Sub(a, b).IsIdentity())
|
||||
b.Double(b)
|
||||
a.Generator()
|
||||
require.Equal(t, 1, b.Sub(b, a).Equal(a))
|
||||
}
|
||||
|
||||
func TestG1Mul(t *testing.T) {
|
||||
g := new(G1).Generator()
|
||||
a := Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{
|
||||
0x2b568297a56da71c,
|
||||
0xd8c39ecb0ef375d1,
|
||||
0x435c38da67bfbf96,
|
||||
0x8088a05026b659b2,
|
||||
})
|
||||
b := Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{
|
||||
0x785fdd9b26ef8b85,
|
||||
0xc997f25837695c18,
|
||||
0x4c8dbc39e7b756c1,
|
||||
0x70d9b6cc6d87df20,
|
||||
})
|
||||
c := Bls12381FqNew().Mul(a, b)
|
||||
t1 := new(G1).Generator()
|
||||
t1.Mul(t1, a)
|
||||
t1.Mul(t1, b)
|
||||
require.Equal(t, 1, t1.Equal(g.Mul(g, c)))
|
||||
}
|
||||
|
||||
func TestG1Neg(t *testing.T) {
|
||||
a := new(G1).Generator()
|
||||
b := new(G1).Neg(a)
|
||||
require.Equal(t, 1, new(G1).Add(a, b).IsIdentity())
|
||||
require.Equal(t, 1, new(G1).Sub(a, b.Neg(b)).IsIdentity())
|
||||
a.Identity()
|
||||
require.Equal(t, 1, a.Neg(a).IsIdentity())
|
||||
}
|
||||
|
||||
func TestG1InCorrectSubgroup(t *testing.T) {
|
||||
// ZCash test vector
|
||||
a := G1{
|
||||
x: fp{
|
||||
0x0abaf895b97e43c8,
|
||||
0xba4c6432eb9b61b0,
|
||||
0x12506f52adfe307f,
|
||||
0x75028c3439336b72,
|
||||
0x84744f05b8e9bd71,
|
||||
0x113d554fb09554f7,
|
||||
},
|
||||
y: fp{
|
||||
0x73e90e88f5cf01c0,
|
||||
0x37007b65dd3197e2,
|
||||
0x5cf9a1992f0d7c78,
|
||||
0x4f83c10b9eb3330d,
|
||||
0xf6a63f6f07f60961,
|
||||
0x0c53b5b97e634df3,
|
||||
},
|
||||
z: *(new(fp).SetOne()),
|
||||
}
|
||||
require.Equal(t, 0, a.InCorrectSubgroup())
|
||||
|
||||
require.Equal(t, 1, new(G1).Identity().InCorrectSubgroup())
|
||||
require.Equal(t, 1, new(G1).Generator().InCorrectSubgroup())
|
||||
}
|
||||
|
||||
func TestG1MulByX(t *testing.T) {
|
||||
// multiplying by `x` a point in G1 is the same as multiplying by
|
||||
// the equivalent scalar.
|
||||
generator := new(G1).Generator()
|
||||
x := Bls12381FqNew().SetUint64(paramX)
|
||||
x.Neg(x)
|
||||
lhs := new(G1).Mul(generator, x)
|
||||
rhs := new(G1).MulByX(generator)
|
||||
require.Equal(t, 1, lhs.Equal(rhs))
|
||||
|
||||
pt := new(G1).Generator()
|
||||
s := Bls12381FqNew().SetUint64(42)
|
||||
pt.Mul(pt, s)
|
||||
lhs.Mul(pt, x)
|
||||
rhs.MulByX(pt)
|
||||
require.Equal(t, 1, lhs.Equal(rhs))
|
||||
}
|
||||
|
||||
func TestG1ClearCofactor(t *testing.T) {
|
||||
// the generator (and the identity) are always on the curve,
|
||||
// even after clearing the cofactor
|
||||
generator := new(G1).Generator()
|
||||
generator.ClearCofactor(generator)
|
||||
require.Equal(t, 1, generator.IsOnCurve())
|
||||
id := new(G1).Identity()
|
||||
id.ClearCofactor(id)
|
||||
require.Equal(t, 1, id.IsOnCurve())
|
||||
|
||||
z := fp{
|
||||
0x3d2d1c670671394e,
|
||||
0x0ee3a800a2f7c1ca,
|
||||
0x270f4f21da2e5050,
|
||||
0xe02840a53f1be768,
|
||||
0x55debeb597512690,
|
||||
0x08bd25353dc8f791,
|
||||
}
|
||||
|
||||
point := G1{
|
||||
x: fp{
|
||||
0x48af5ff540c817f0,
|
||||
0xd73893acaf379d5a,
|
||||
0xe6c43584e18e023c,
|
||||
0x1eda39c30f188b3e,
|
||||
0xf618c6d3ccc0f8d8,
|
||||
0x0073542cd671e16c,
|
||||
},
|
||||
y: fp{
|
||||
0x57bf8be79461d0ba,
|
||||
0xfc61459cee3547c3,
|
||||
0x0d23567df1ef147b,
|
||||
0x0ee187bcce1d9b64,
|
||||
0xb0c8cfbe9dc8fdc1,
|
||||
0x1328661767ef368b,
|
||||
},
|
||||
z: *(&fp{}).Set(&z),
|
||||
}
|
||||
point.x.Mul(&point.x, &z)
|
||||
point.z.Square(&z)
|
||||
point.z.Mul(&point.z, &z)
|
||||
|
||||
require.Equal(t, 1, point.IsOnCurve())
|
||||
require.Equal(t, 0, point.InCorrectSubgroup())
|
||||
clearedPoint := new(G1).ClearCofactor(&point)
|
||||
require.Equal(t, 1, clearedPoint.IsOnCurve())
|
||||
require.Equal(t, 1, clearedPoint.InCorrectSubgroup())
|
||||
|
||||
// in BLS12-381 the cofactor in G1 can be
|
||||
// cleared multiplying by (1-x)
|
||||
hEff := Bls12381FqNew().SetOne()
|
||||
hEff.Add(hEff, Bls12381FqNew().SetUint64(paramX))
|
||||
point.Mul(&point, hEff)
|
||||
require.Equal(t, 1, clearedPoint.Equal(&point))
|
||||
}
|
||||
|
||||
func TestG1Hash(t *testing.T) {
|
||||
dst := []byte("QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_")
|
||||
tests := []struct {
|
||||
input, expected string
|
||||
}{
|
||||
{"", "052926add2207b76ca4fa57a8734416c8dc95e24501772c814278700eed6d1e4e8cf62d9c09db0fac349612b759e79a108ba738453bfed09cb546dbb0783dbb3a5f1f566ed67bb6be0e8c67e2e81a4cc68ee29813bb7994998f3eae0c9c6a265"},
|
||||
{"abc", "03567bc5ef9c690c2ab2ecdf6a96ef1c139cc0b2f284dca0a9a7943388a49a3aee664ba5379a7655d3c68900be2f69030b9c15f3fe6e5cf4211f346271d7b01c8f3b28be689c8429c85b67af215533311f0b8dfaaa154fa6b88176c229f2885d"},
|
||||
{"abcdef0123456789", "11e0b079dea29a68f0383ee94fed1b940995272407e3bb916bbf268c263ddd57a6a27200a784cbc248e84f357ce82d9803a87ae2caf14e8ee52e51fa2ed8eefe80f02457004ba4d486d6aa1f517c0889501dc7413753f9599b099ebcbbd2d709"},
|
||||
{"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", "15f68eaa693b95ccb85215dc65fa81038d69629f70aeee0d0f677cf22285e7bf58d7cb86eefe8f2e9bc3f8cb84fac4881807a1d50c29f430b8cafc4f8638dfeeadf51211e1602a5f184443076715f91bb90a48ba1e370edce6ae1062f5e6dd38"},
|
||||
{"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "082aabae8b7dedb0e78aeb619ad3bfd9277a2f77ba7fad20ef6aabdc6c31d19ba5a6d12283553294c1825c4b3ca2dcfe05b84ae5a942248eea39e1d91030458c40153f3b654ab7872d779ad1e942856a20c438e8d99bc8abfbf74729ce1f7ac8"},
|
||||
}
|
||||
|
||||
pt := new(G1).Identity()
|
||||
ept := new(G1).Identity()
|
||||
var b [WideFieldBytes]byte
|
||||
for _, tst := range tests {
|
||||
i := []byte(tst.input)
|
||||
e, _ := hex.DecodeString(tst.expected)
|
||||
copy(b[:], e)
|
||||
_, _ = ept.FromUncompressed(&b)
|
||||
pt.Hash(native.EllipticPointHasherSha256(), i, dst)
|
||||
require.Equal(t, 1, pt.Equal(ept))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSerialization(t *testing.T) {
|
||||
a := new(G1).Hash(native.EllipticPointHasherSha256(), []byte("a"), []byte("BLS12381G1_XMD:SHA-256_SSWU_RO_"))
|
||||
b := new(G1).Hash(native.EllipticPointHasherSha256(), []byte("b"), []byte("BLS12381G1_XMD:SHA-256_SSWU_RO_"))
|
||||
|
||||
aBytes := a.ToCompressed()
|
||||
bBytes := b.ToCompressed()
|
||||
|
||||
aa, err := new(G1).FromCompressed(&aBytes)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, a.Equal(aa))
|
||||
|
||||
bb, err := new(G1).FromCompressed(&bBytes)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, b.Equal(bb))
|
||||
|
||||
auBytes := a.ToUncompressed()
|
||||
buBytes := b.ToUncompressed()
|
||||
|
||||
_, err = aa.FromUncompressed(&auBytes)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, a.Equal(aa))
|
||||
|
||||
_, err = bb.FromUncompressed(&buBytes)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, b.Equal(bb))
|
||||
|
||||
bBytes = a.ToCompressed()
|
||||
a.Neg(a)
|
||||
aBytes = a.ToCompressed()
|
||||
_, err = aa.FromCompressed(&aBytes)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, a.Equal(aa))
|
||||
_, err = aa.FromCompressed(&bBytes)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, a.Equal(aa))
|
||||
require.Equal(t, 1, aa.Equal(a.Neg(a)))
|
||||
}
|
||||
|
||||
func TestSumOfProducts(t *testing.T) {
|
||||
var b [64]byte
|
||||
h0, _ := new(G1).Random(crand.Reader)
|
||||
_, _ = crand.Read(b[:])
|
||||
s := Bls12381FqNew().SetBytesWide(&b)
|
||||
_, _ = crand.Read(b[:])
|
||||
sTilde := Bls12381FqNew().SetBytesWide(&b)
|
||||
_, _ = crand.Read(b[:])
|
||||
c := Bls12381FqNew().SetBytesWide(&b)
|
||||
|
||||
lhs := new(G1).Mul(h0, s)
|
||||
rhs, _ := new(G1).SumOfProducts([]*G1{h0}, []*native.Field{s})
|
||||
require.Equal(t, 1, lhs.Equal(rhs))
|
||||
|
||||
u := new(G1).Mul(h0, s)
|
||||
uTilde := new(G1).Mul(h0, sTilde)
|
||||
sHat := Bls12381FqNew().Mul(c, s)
|
||||
sHat.Sub(sTilde, sHat)
|
||||
|
||||
rhs.Mul(u, c)
|
||||
rhs.Add(rhs, new(G1).Mul(h0, sHat))
|
||||
require.Equal(t, 1, uTilde.Equal(rhs))
|
||||
_, _ = rhs.SumOfProducts([]*G1{u, h0}, []*native.Field{c, sHat})
|
||||
require.Equal(t, 1, uTilde.Equal(rhs))
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,554 +0,0 @@
|
||||
package bls12381
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
)
|
||||
|
||||
func TestG2IsOnCurve(t *testing.T) {
|
||||
require.Equal(t, 1, new(G2).Identity().IsOnCurve())
|
||||
require.Equal(t, 1, new(G2).Generator().IsOnCurve())
|
||||
|
||||
z := fp2{
|
||||
A: fp{
|
||||
0xba7a_fa1f_9a6f_e250,
|
||||
0xfa0f_5b59_5eaf_e731,
|
||||
0x3bdc_4776_94c3_06e7,
|
||||
0x2149_be4b_3949_fa24,
|
||||
0x64aa_6e06_49b2_078c,
|
||||
0x12b1_08ac_3364_3c3e,
|
||||
},
|
||||
B: fp{
|
||||
0x1253_25df_3d35_b5a8,
|
||||
0xdc46_9ef5_555d_7fe3,
|
||||
0x02d7_16d2_4431_06a9,
|
||||
0x05a1_db59_a6ff_37d0,
|
||||
0x7cf7_784e_5300_bb8f,
|
||||
0x16a8_8922_c7a5_e844,
|
||||
},
|
||||
}
|
||||
|
||||
test := new(G2).Generator()
|
||||
test.x.Mul(&test.x, &z)
|
||||
test.y.Mul(&test.y, &z)
|
||||
test.z.Set(&z)
|
||||
|
||||
require.Equal(t, 1, test.IsOnCurve())
|
||||
|
||||
test.x.Set(&z)
|
||||
require.Equal(t, 0, test.IsOnCurve())
|
||||
}
|
||||
|
||||
func TestG2Equal(t *testing.T) {
|
||||
a := new(G2).Generator()
|
||||
b := new(G2).Identity()
|
||||
|
||||
require.Equal(t, 1, a.Equal(a))
|
||||
require.Equal(t, 0, a.Equal(b))
|
||||
require.Equal(t, 1, b.Equal(b))
|
||||
}
|
||||
|
||||
func TestG2ToAffine(t *testing.T) {
|
||||
a := new(G2).Generator()
|
||||
|
||||
z := fp2{
|
||||
A: fp{
|
||||
0xba7afa1f9a6fe250,
|
||||
0xfa0f5b595eafe731,
|
||||
0x3bdc477694c306e7,
|
||||
0x2149be4b3949fa24,
|
||||
0x64aa6e0649b2078c,
|
||||
0x12b108ac33643c3e,
|
||||
},
|
||||
B: fp{
|
||||
0x125325df3d35b5a8,
|
||||
0xdc469ef5555d7fe3,
|
||||
0x02d716d2443106a9,
|
||||
0x05a1db59a6ff37d0,
|
||||
0x7cf7784e5300bb8f,
|
||||
0x16a88922c7a5e844,
|
||||
},
|
||||
}
|
||||
|
||||
a.x.Mul(&a.x, &z)
|
||||
a.y.Mul(&a.y, &z)
|
||||
a.z.Set(&z)
|
||||
|
||||
require.Equal(t, 1, a.ToAffine(a).Equal(new(G2).Generator()))
|
||||
}
|
||||
|
||||
func TestG2Double(t *testing.T) {
|
||||
a := new(G2).Identity()
|
||||
require.Equal(t, 1, a.Double(a).IsIdentity())
|
||||
|
||||
a.Generator()
|
||||
a.Double(a)
|
||||
e := G2{
|
||||
x: fp2{
|
||||
A: fp{
|
||||
0xe9d9e2da9620f98b,
|
||||
0x54f1199346b97f36,
|
||||
0x3db3b820376bed27,
|
||||
0xcfdb31c9b0b64f4c,
|
||||
0x41d7c12786354493,
|
||||
0x05710794c255c064,
|
||||
},
|
||||
B: fp{
|
||||
0xd6c1d3ca6ea0d06e,
|
||||
0xda0cbd905595489f,
|
||||
0x4f5352d43479221d,
|
||||
0x8ade5d736f8c97e0,
|
||||
0x48cc8433925ef70e,
|
||||
0x08d7ea71ea91ef81,
|
||||
},
|
||||
},
|
||||
y: fp2{
|
||||
A: fp{
|
||||
0x15ba26eb4b0d186f,
|
||||
0x0d086d64b7e9e01e,
|
||||
0xc8b848dd652f4c78,
|
||||
0xeecf46a6123bae4f,
|
||||
0x255e8dd8b6dc812a,
|
||||
0x164142af21dcf93f,
|
||||
},
|
||||
B: fp{
|
||||
0xf9b4a1a895984db4,
|
||||
0xd417b114cccff748,
|
||||
0x6856301fc89f086e,
|
||||
0x41c777878931e3da,
|
||||
0x3556b155066a2105,
|
||||
0x00acf7d325cb89cf,
|
||||
},
|
||||
},
|
||||
z: *((&fp2{}).SetOne()),
|
||||
}
|
||||
require.Equal(t, 1, e.Equal(a))
|
||||
}
|
||||
|
||||
func TestG2Add(t *testing.T) {
|
||||
a := new(G2).Identity()
|
||||
b := new(G2).Identity()
|
||||
c := new(G2).Add(a, b)
|
||||
require.Equal(t, 1, c.IsIdentity())
|
||||
b.Generator()
|
||||
c.Add(a, b)
|
||||
require.Equal(t, 1, c.Equal(b))
|
||||
|
||||
a.Generator()
|
||||
a.Double(a)
|
||||
a.Double(a)
|
||||
b.Double(b)
|
||||
c.Add(a, b)
|
||||
|
||||
d := new(G2).Generator()
|
||||
e := new(G2).Generator()
|
||||
for i := 0; i < 5; i++ {
|
||||
e.Add(e, d)
|
||||
}
|
||||
require.Equal(t, 1, e.Equal(c))
|
||||
|
||||
// Degenerate case
|
||||
beta := fp2{
|
||||
A: fp{
|
||||
0xcd03c9e48671f071,
|
||||
0x5dab22461fcda5d2,
|
||||
0x587042afd3851b95,
|
||||
0x8eb60ebe01bacb9e,
|
||||
0x03f97d6e83d050d2,
|
||||
0x18f0206554638741,
|
||||
},
|
||||
B: fp{},
|
||||
}
|
||||
beta.Square(&beta)
|
||||
b.x.Mul(&a.x, &beta)
|
||||
b.y.Neg(&a.y)
|
||||
b.z.Set(&a.z)
|
||||
require.Equal(t, 1, b.IsOnCurve())
|
||||
|
||||
c.Add(a, b)
|
||||
|
||||
e.x.Set(&fp2{
|
||||
A: fp{
|
||||
0x705abc799ca773d3,
|
||||
0xfe132292c1d4bf08,
|
||||
0xf37ece3e07b2b466,
|
||||
0x887e1c43f447e301,
|
||||
0x1e0970d033bc77e8,
|
||||
0x1985c81e20a693f2,
|
||||
},
|
||||
B: fp{
|
||||
0x1d79b25db36ab924,
|
||||
0x23948e4d529639d3,
|
||||
0x471ba7fb0d006297,
|
||||
0x2c36d4b4465dc4c0,
|
||||
0x82bbc3cfec67f538,
|
||||
0x051d2728b67bf952,
|
||||
},
|
||||
})
|
||||
e.y.Set(&fp2{
|
||||
A: fp{
|
||||
0x41b1bbf6576c0abf,
|
||||
0xb6cc93713f7a0f9a,
|
||||
0x6b65b43e48f3f01f,
|
||||
0xfb7a4cfcaf81be4f,
|
||||
0x3e32dadc6ec22cb6,
|
||||
0x0bb0fc49d79807e3,
|
||||
},
|
||||
B: fp{
|
||||
0x7d1397788f5f2ddf,
|
||||
0xab2907144ff0d8e8,
|
||||
0x5b7573e0cdb91f92,
|
||||
0x4cb8932dd31daf28,
|
||||
0x62bbfac6db052a54,
|
||||
0x11f95c16d14c3bbe,
|
||||
},
|
||||
})
|
||||
e.z.SetOne()
|
||||
require.Equal(t, 1, e.Equal(c))
|
||||
}
|
||||
|
||||
func TestG2Neg(t *testing.T) {
|
||||
a := new(G2).Generator()
|
||||
b := new(G2).Neg(a)
|
||||
require.Equal(t, 1, new(G2).Add(a, b).IsIdentity())
|
||||
require.Equal(t, 1, new(G2).Sub(a, b.Neg(b)).IsIdentity())
|
||||
a.Identity()
|
||||
require.Equal(t, 1, a.Neg(a).IsIdentity())
|
||||
}
|
||||
|
||||
func TestG2Mul(t *testing.T) {
|
||||
g := new(G2).Generator()
|
||||
a := Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{
|
||||
0x2b56_8297_a56d_a71c,
|
||||
0xd8c3_9ecb_0ef3_75d1,
|
||||
0x435c_38da_67bf_bf96,
|
||||
0x8088_a050_26b6_59b2,
|
||||
})
|
||||
b := Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{
|
||||
0x785f_dd9b_26ef_8b85,
|
||||
0xc997_f258_3769_5c18,
|
||||
0x4c8d_bc39_e7b7_56c1,
|
||||
0x70d9_b6cc_6d87_df20,
|
||||
})
|
||||
c := Bls12381FqNew().Mul(a, b)
|
||||
|
||||
t1 := new(G2).Generator()
|
||||
t1.Mul(t1, a)
|
||||
t1.Mul(t1, b)
|
||||
require.Equal(t, 1, t1.Equal(g.Mul(g, c)))
|
||||
}
|
||||
|
||||
func TestG2InCorrectSubgroup(t *testing.T) {
|
||||
a := G2{
|
||||
x: fp2{
|
||||
A: fp{
|
||||
0x89f550c813db6431,
|
||||
0xa50be8c456cd8a1a,
|
||||
0xa45b374114cae851,
|
||||
0xbb6190f5bf7fff63,
|
||||
0x970ca02c3ba80bc7,
|
||||
0x02b85d24e840fbac,
|
||||
},
|
||||
B: fp{
|
||||
0x6888bc53d70716dc,
|
||||
0x3dea6b4117682d70,
|
||||
0xd8f5f930500ca354,
|
||||
0x6b5ecb6556f5c155,
|
||||
0xc96bef0434778ab0,
|
||||
0x05081505515006ad,
|
||||
},
|
||||
},
|
||||
y: fp2{
|
||||
A: fp{
|
||||
0x3cf1ea0d434b0f40,
|
||||
0x1a0dc610e603e333,
|
||||
0x7f89956160c72fa0,
|
||||
0x25ee03decf6431c5,
|
||||
0xeee8e206ec0fe137,
|
||||
0x097592b226dfef28,
|
||||
},
|
||||
B: fp{
|
||||
0x71e8bb5f29247367,
|
||||
0xa5fe049e211831ce,
|
||||
0x0ce6b354502a3896,
|
||||
0x93b012000997314e,
|
||||
0x6759f3b6aa5b42ac,
|
||||
0x156944c4dfe92bbb,
|
||||
},
|
||||
},
|
||||
z: *(&fp2{}).SetOne(),
|
||||
}
|
||||
require.Equal(t, 0, a.InCorrectSubgroup())
|
||||
|
||||
require.Equal(t, 1, new(G2).Identity().InCorrectSubgroup())
|
||||
require.Equal(t, 1, new(G2).Generator().InCorrectSubgroup())
|
||||
}
|
||||
|
||||
func TestG2MulByX(t *testing.T) {
|
||||
// multiplying by `x` a point in G2 is the same as multiplying by
|
||||
// the equivalent scalar.
|
||||
x := Bls12381FqNew().SetUint64(paramX)
|
||||
x.Neg(x)
|
||||
t1 := new(G2).Generator()
|
||||
t1.MulByX(t1)
|
||||
t2 := new(G2).Generator()
|
||||
t2.Mul(t2, x)
|
||||
require.Equal(t, 1, t1.Equal(t2))
|
||||
|
||||
point := new(G2).Generator()
|
||||
a := Bls12381FqNew().SetUint64(42)
|
||||
point.Mul(point, a)
|
||||
|
||||
t1.MulByX(point)
|
||||
t2.Mul(point, x)
|
||||
require.Equal(t, 1, t1.Equal(t2))
|
||||
}
|
||||
|
||||
func TestG2Psi(t *testing.T) {
|
||||
generator := new(G2).Generator()
|
||||
|
||||
z := fp2{
|
||||
A: fp{
|
||||
0x0ef2ddffab187c0a,
|
||||
0x2424522b7d5ecbfc,
|
||||
0xc6f341a3398054f4,
|
||||
0x5523ddf409502df0,
|
||||
0xd55c0b5a88e0dd97,
|
||||
0x066428d704923e52,
|
||||
},
|
||||
B: fp{
|
||||
0x538bbe0c95b4878d,
|
||||
0xad04a50379522881,
|
||||
0x6d5c05bf5c12fb64,
|
||||
0x4ce4a069a2d34787,
|
||||
0x59ea6c8d0dffaeaf,
|
||||
0x0d42a083a75bd6f3,
|
||||
},
|
||||
}
|
||||
|
||||
// `point` is a random point in the curve
|
||||
point := G2{
|
||||
x: fp2{
|
||||
A: fp{
|
||||
0xee4c8cb7c047eaf2,
|
||||
0x44ca22eee036b604,
|
||||
0x33b3affb2aefe101,
|
||||
0x15d3e45bbafaeb02,
|
||||
0x7bfc2154cd7419a4,
|
||||
0x0a2d0c2b756e5edc,
|
||||
},
|
||||
B: fp{
|
||||
0xfc224361029a8777,
|
||||
0x4cbf2baab8740924,
|
||||
0xc5008c6ec6592c89,
|
||||
0xecc2c57b472a9c2d,
|
||||
0x8613eafd9d81ffb1,
|
||||
0x10fe54daa2d3d495,
|
||||
},
|
||||
},
|
||||
y: fp2{
|
||||
A: fp{
|
||||
0x7de7edc43953b75c,
|
||||
0x58be1d2de35e87dc,
|
||||
0x5731d30b0e337b40,
|
||||
0xbe93b60cfeaae4c9,
|
||||
0x8b22c203764bedca,
|
||||
0x01616c8d1033b771,
|
||||
},
|
||||
B: fp{
|
||||
0xea126fe476b5733b,
|
||||
0x85cee68b5dae1652,
|
||||
0x98247779f7272b04,
|
||||
0xa649c8b468c6e808,
|
||||
0xb5b9a62dff0c4e45,
|
||||
0x1555b67fc7bbe73d,
|
||||
},
|
||||
},
|
||||
z: *(&fp2{}).Set(&z),
|
||||
}
|
||||
point.x.Mul(&point.x, &z)
|
||||
point.z.Square(&point.z)
|
||||
point.z.Mul(&point.z, &z)
|
||||
require.Equal(t, 1, point.IsOnCurve())
|
||||
|
||||
// psi2(P) = psi(psi(P))
|
||||
tv1 := new(G2).psi2(generator)
|
||||
tv2 := new(G2).psi(generator)
|
||||
tv2.psi(tv2)
|
||||
require.Equal(t, 1, tv1.Equal(tv2))
|
||||
|
||||
tv1.psi2(&point)
|
||||
tv2.psi(&point)
|
||||
tv2.psi(tv2)
|
||||
require.Equal(t, 1, tv1.Equal(tv2))
|
||||
|
||||
// psi(P) is a morphism
|
||||
tv1.Double(generator)
|
||||
tv1.psi(tv1)
|
||||
tv2.psi(generator)
|
||||
tv2.Double(tv2)
|
||||
require.Equal(t, 1, tv1.Equal(tv2))
|
||||
|
||||
tv1.psi(&point)
|
||||
tv2.psi(generator)
|
||||
tv1.Add(tv1, tv2)
|
||||
|
||||
tv2.Set(&point)
|
||||
tv3 := new(G2).Generator()
|
||||
tv2.Add(tv2, tv3)
|
||||
tv2.psi(tv2)
|
||||
require.Equal(t, 1, tv1.Equal(tv2))
|
||||
}
|
||||
|
||||
func TestG2ClearCofactor(t *testing.T) {
|
||||
z := fp2{
|
||||
A: fp{
|
||||
0x0ef2ddffab187c0a,
|
||||
0x2424522b7d5ecbfc,
|
||||
0xc6f341a3398054f4,
|
||||
0x5523ddf409502df0,
|
||||
0xd55c0b5a88e0dd97,
|
||||
0x066428d704923e52,
|
||||
},
|
||||
B: fp{
|
||||
0x538bbe0c95b4878d,
|
||||
0xad04a50379522881,
|
||||
0x6d5c05bf5c12fb64,
|
||||
0x4ce4a069a2d34787,
|
||||
0x59ea6c8d0dffaeaf,
|
||||
0x0d42a083a75bd6f3,
|
||||
},
|
||||
}
|
||||
|
||||
// `point` is a random point in the curve
|
||||
point := G2{
|
||||
x: fp2{
|
||||
A: fp{
|
||||
0xee4c8cb7c047eaf2,
|
||||
0x44ca22eee036b604,
|
||||
0x33b3affb2aefe101,
|
||||
0x15d3e45bbafaeb02,
|
||||
0x7bfc2154cd7419a4,
|
||||
0x0a2d0c2b756e5edc,
|
||||
},
|
||||
B: fp{
|
||||
0xfc224361029a8777,
|
||||
0x4cbf2baab8740924,
|
||||
0xc5008c6ec6592c89,
|
||||
0xecc2c57b472a9c2d,
|
||||
0x8613eafd9d81ffb1,
|
||||
0x10fe54daa2d3d495,
|
||||
},
|
||||
},
|
||||
y: fp2{
|
||||
A: fp{
|
||||
0x7de7edc43953b75c,
|
||||
0x58be1d2de35e87dc,
|
||||
0x5731d30b0e337b40,
|
||||
0xbe93b60cfeaae4c9,
|
||||
0x8b22c203764bedca,
|
||||
0x01616c8d1033b771,
|
||||
},
|
||||
B: fp{
|
||||
0xea126fe476b5733b,
|
||||
0x85cee68b5dae1652,
|
||||
0x98247779f7272b04,
|
||||
0xa649c8b468c6e808,
|
||||
0xb5b9a62dff0c4e45,
|
||||
0x1555b67fc7bbe73d,
|
||||
},
|
||||
},
|
||||
z: fp2{},
|
||||
}
|
||||
point.x.Mul(&point.x, &z)
|
||||
point.z.Square(&z)
|
||||
point.z.Mul(&point.z, &z)
|
||||
|
||||
require.Equal(t, 1, point.IsOnCurve())
|
||||
require.Equal(t, 0, point.InCorrectSubgroup())
|
||||
|
||||
clearedPoint := new(G2).ClearCofactor(&point)
|
||||
|
||||
require.Equal(t, 1, clearedPoint.IsOnCurve())
|
||||
require.Equal(t, 1, clearedPoint.InCorrectSubgroup())
|
||||
|
||||
// the generator (and the identity) are always on the curve,
|
||||
// even after clearing the cofactor
|
||||
generator := new(G2).Generator()
|
||||
generator.ClearCofactor(generator)
|
||||
require.Equal(t, 1, generator.InCorrectSubgroup())
|
||||
id := new(G2).Identity()
|
||||
id.ClearCofactor(id)
|
||||
require.Equal(t, 1, id.InCorrectSubgroup())
|
||||
|
||||
// test the effect on q-torsion points multiplying by h_eff modulo q
|
||||
// h_eff % q = 0x2b116900400069009a40200040001ffff
|
||||
hEffModq := [native.FieldBytes]byte{
|
||||
0xff, 0xff, 0x01, 0x00, 0x04, 0x00, 0x02, 0xa4, 0x09, 0x90, 0x06, 0x00, 0x04, 0x90, 0x16,
|
||||
0xb1, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
}
|
||||
generator.Generator()
|
||||
generator.multiply(generator, &hEffModq)
|
||||
point.Generator().ClearCofactor(&point)
|
||||
require.Equal(t, 1, point.Equal(generator))
|
||||
point.ClearCofactor(clearedPoint)
|
||||
require.Equal(t, 1, point.Equal(clearedPoint.multiply(clearedPoint, &hEffModq)))
|
||||
}
|
||||
|
||||
func TestG2Hash(t *testing.T) {
|
||||
dst := []byte("QUUX-V01-CS02-with-BLS12381G2_XMD:SHA-256_SSWU_RO_")
|
||||
|
||||
tests := []struct {
|
||||
input, expected string
|
||||
}{
|
||||
{"", "05cb8437535e20ecffaef7752baddf98034139c38452458baeefab379ba13dff5bf5dd71b72418717047f5b0f37da03d0141ebfbdca40eb85b87142e130ab689c673cf60f1a3e98d69335266f30d9b8d4ac44c1038e9dcdd5393faf5c41fb78a12424ac32561493f3fe3c260708a12b7c620e7be00099a974e259ddc7d1f6395c3c811cdd19f1e8dbf3e9ecfdcbab8d60503921d7f6a12805e72940b963c0cf3471c7b2a524950ca195d11062ee75ec076daf2d4bc358c4b190c0c98064fdd92"},
|
||||
{"abc", "139cddbccdc5e91b9623efd38c49f81a6f83f175e80b06fc374de9eb4b41dfe4ca3a230ed250fbe3a2acf73a41177fd802c2d18e033b960562aae3cab37a27ce00d80ccd5ba4b7fe0e7a210245129dbec7780ccc7954725f4168aff2787776e600aa65dae3c8d732d10ecd2c50f8a1baf3001578f71c694e03866e9f3d49ac1e1ce70dd94a733534f106d4cec0eddd161787327b68159716a37440985269cf584bcb1e621d3a7202be6ea05c4cfe244aeb197642555a0645fb87bf7466b2ba48"},
|
||||
{"abcdef0123456789", "190d119345b94fbd15497bcba94ecf7db2cbfd1e1fe7da034d26cbba169fb3968288b3fafb265f9ebd380512a71c3f2c121982811d2491fde9ba7ed31ef9ca474f0e1501297f68c298e9f4c0028add35aea8bb83d53c08cfc007c1e005723cd00bb5e7572275c567462d91807de765611490205a941a5a6af3b1691bfe596c31225d3aabdf15faff860cb4ef17c7c3be05571a0f8d3c08d094576981f4a3b8eda0a8e771fcdcc8ecceaf1356a6acf17574518acb506e435b639353c2e14827c8"},
|
||||
{"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", "0934aba516a52d8ae479939a91998299c76d39cc0c035cd18813bec433f587e2d7a4fef038260eef0cef4d02aae3eb9119a84dd7248a1066f737cc34502ee5555bd3c19f2ecdb3c7d9e24dc65d4e25e50d83f0f77105e955d78f4762d33c17da09bcccfa036b4847c9950780733633f13619994394c23ff0b32fa6b795844f4a0673e20282d07bc69641cee04f5e566214f81cd421617428bc3b9fe25afbb751d934a00493524bc4e065635b0555084dd54679df1536101b2c979c0152d09192"},
|
||||
{"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "11fca2ff525572795a801eed17eb12785887c7b63fb77a42be46ce4a34131d71f7a73e95fee3f812aea3de78b4d0156901a6ba2f9a11fa5598b2d8ace0fbe0a0eacb65deceb476fbbcb64fd24557c2f4b18ecfc5663e54ae16a84f5ab7f6253403a47f8e6d1763ba0cad63d6114c0accbef65707825a511b251a660a9b3994249ae4e63fac38b23da0c398689ee2ab520b6798718c8aed24bc19cb27f866f1c9effcdbf92397ad6448b5c9db90d2b9da6cbabf48adc1adf59a1a28344e79d57e"},
|
||||
}
|
||||
|
||||
pt := new(G2).Identity()
|
||||
ept := new(G2).Identity()
|
||||
var b [DoubleWideFieldBytes]byte
|
||||
for _, tst := range tests {
|
||||
i := []byte(tst.input)
|
||||
e, _ := hex.DecodeString(tst.expected)
|
||||
copy(b[:], e)
|
||||
_, _ = ept.FromUncompressed(&b)
|
||||
pt.Hash(native.EllipticPointHasherSha256(), i, dst)
|
||||
require.Equal(t, 1, pt.Equal(ept))
|
||||
}
|
||||
}
|
||||
|
||||
func TestG2SumOfProducts(t *testing.T) {
|
||||
var b [64]byte
|
||||
h0, _ := new(G2).Random(crand.Reader)
|
||||
_, _ = crand.Read(b[:])
|
||||
s := Bls12381FqNew().SetBytesWide(&b)
|
||||
_, _ = crand.Read(b[:])
|
||||
sTilde := Bls12381FqNew().SetBytesWide(&b)
|
||||
_, _ = crand.Read(b[:])
|
||||
c := Bls12381FqNew().SetBytesWide(&b)
|
||||
|
||||
lhs := new(G2).Mul(h0, s)
|
||||
rhs, _ := new(G2).SumOfProducts([]*G2{h0}, []*native.Field{s})
|
||||
require.Equal(t, 1, lhs.Equal(rhs))
|
||||
|
||||
u := new(G2).Mul(h0, s)
|
||||
uTilde := new(G2).Mul(h0, sTilde)
|
||||
sHat := Bls12381FqNew().Mul(c, s)
|
||||
sHat.Sub(sTilde, sHat)
|
||||
|
||||
rhs.Mul(u, c)
|
||||
rhs.Add(rhs, new(G2).Mul(h0, sHat))
|
||||
require.Equal(t, 1, uTilde.Equal(rhs))
|
||||
_, _ = rhs.SumOfProducts([]*G2{u, h0}, []*native.Field{c, sHat})
|
||||
require.Equal(t, 1, uTilde.Equal(rhs))
|
||||
}
|
@ -1,434 +0,0 @@
|
||||
package bls12381
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
"github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
// GtFieldBytes is the number of bytes needed to represent this field
|
||||
const GtFieldBytes = 576
|
||||
|
||||
// Gt is the target group
|
||||
type Gt fp12
|
||||
|
||||
// Random generates a random field element
|
||||
func (gt *Gt) Random(reader io.Reader) (*Gt, error) {
|
||||
_, err := (*fp12)(gt).Random(reader)
|
||||
return gt, err
|
||||
}
|
||||
|
||||
// FinalExponentiation performs a "final exponentiation" routine to convert the result
|
||||
// of a Miller loop into an element of `Gt` with help of efficient squaring
|
||||
// operation in the so-called `cyclotomic subgroup` of `Fq6` so that
|
||||
// it can be compared with other elements of `Gt`.
|
||||
func (gt *Gt) FinalExponentiation(a *Gt) *Gt {
|
||||
var t0, t1, t2, t3, t4, t5, t6, t fp12
|
||||
t0.FrobeniusMap((*fp12)(a))
|
||||
t0.FrobeniusMap(&t0)
|
||||
t0.FrobeniusMap(&t0)
|
||||
t0.FrobeniusMap(&t0)
|
||||
t0.FrobeniusMap(&t0)
|
||||
t0.FrobeniusMap(&t0)
|
||||
|
||||
// Shouldn't happen since we enforce `a` to be non-zero but just in case
|
||||
_, wasInverted := t1.Invert((*fp12)(a))
|
||||
t2.Mul(&t0, &t1)
|
||||
t1.Set(&t2)
|
||||
t2.FrobeniusMap(&t2)
|
||||
t2.FrobeniusMap(&t2)
|
||||
t2.Mul(&t2, &t1)
|
||||
t1.cyclotomicSquare(&t2)
|
||||
t1.Conjugate(&t1)
|
||||
|
||||
t3.cyclotomicExp(&t2)
|
||||
t4.cyclotomicSquare(&t3)
|
||||
t5.Mul(&t1, &t3)
|
||||
t1.cyclotomicExp(&t5)
|
||||
t0.cyclotomicExp(&t1)
|
||||
t6.cyclotomicExp(&t0)
|
||||
t6.Mul(&t6, &t4)
|
||||
t4.cyclotomicExp(&t6)
|
||||
t5.Conjugate(&t5)
|
||||
t4.Mul(&t4, &t5)
|
||||
t4.Mul(&t4, &t2)
|
||||
t5.Conjugate(&t2)
|
||||
t1.Mul(&t1, &t2)
|
||||
t1.FrobeniusMap(&t1)
|
||||
t1.FrobeniusMap(&t1)
|
||||
t1.FrobeniusMap(&t1)
|
||||
t6.Mul(&t6, &t5)
|
||||
t6.FrobeniusMap(&t6)
|
||||
t3.Mul(&t3, &t0)
|
||||
t3.FrobeniusMap(&t3)
|
||||
t3.FrobeniusMap(&t3)
|
||||
t3.Mul(&t3, &t1)
|
||||
t3.Mul(&t3, &t6)
|
||||
t.Mul(&t3, &t4)
|
||||
(*fp12)(gt).CMove((*fp12)(gt), &t, wasInverted)
|
||||
return gt
|
||||
}
|
||||
|
||||
// IsZero returns 1 if gt == 0, 0 otherwise
|
||||
func (gt *Gt) IsZero() int {
|
||||
return (*fp12)(gt).IsZero()
|
||||
}
|
||||
|
||||
// IsOne returns 1 if gt == 1, 0 otherwise
|
||||
func (gt *Gt) IsOne() int {
|
||||
return (*fp12)(gt).IsOne()
|
||||
}
|
||||
|
||||
// SetOne gt = one
|
||||
func (gt *Gt) SetOne() *Gt {
|
||||
(*fp12)(gt).SetOne()
|
||||
return gt
|
||||
}
|
||||
|
||||
// Set copies a into gt
|
||||
func (gt *Gt) Set(a *Gt) *Gt {
|
||||
gt.A.Set(&a.A)
|
||||
gt.B.Set(&a.B)
|
||||
return gt
|
||||
}
|
||||
|
||||
// Bytes returns the Gt field byte representation
|
||||
func (gt *Gt) Bytes() [GtFieldBytes]byte {
|
||||
var out [GtFieldBytes]byte
|
||||
t := gt.A.A.A.Bytes()
|
||||
copy(out[:FieldBytes], internal.ReverseScalarBytes(t[:]))
|
||||
t = gt.A.A.B.Bytes()
|
||||
copy(out[FieldBytes:2*FieldBytes], internal.ReverseScalarBytes(t[:]))
|
||||
t = gt.A.B.A.Bytes()
|
||||
copy(out[2*FieldBytes:3*FieldBytes], internal.ReverseScalarBytes(t[:]))
|
||||
t = gt.A.B.B.Bytes()
|
||||
copy(out[3*FieldBytes:4*FieldBytes], internal.ReverseScalarBytes(t[:]))
|
||||
t = gt.A.C.A.Bytes()
|
||||
copy(out[4*FieldBytes:5*FieldBytes], internal.ReverseScalarBytes(t[:]))
|
||||
t = gt.A.C.B.Bytes()
|
||||
copy(out[5*FieldBytes:6*FieldBytes], internal.ReverseScalarBytes(t[:]))
|
||||
t = gt.B.A.A.Bytes()
|
||||
copy(out[6*FieldBytes:7*FieldBytes], internal.ReverseScalarBytes(t[:]))
|
||||
t = gt.B.A.B.Bytes()
|
||||
copy(out[7*FieldBytes:8*FieldBytes], internal.ReverseScalarBytes(t[:]))
|
||||
t = gt.B.B.A.Bytes()
|
||||
copy(out[8*FieldBytes:9*FieldBytes], internal.ReverseScalarBytes(t[:]))
|
||||
t = gt.B.B.B.Bytes()
|
||||
copy(out[9*FieldBytes:10*FieldBytes], internal.ReverseScalarBytes(t[:]))
|
||||
t = gt.B.C.A.Bytes()
|
||||
copy(out[10*FieldBytes:11*FieldBytes], internal.ReverseScalarBytes(t[:]))
|
||||
t = gt.B.C.B.Bytes()
|
||||
copy(out[11*FieldBytes:12*FieldBytes], internal.ReverseScalarBytes(t[:]))
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// SetBytes attempts to convert a big-endian byte representation of
|
||||
// a scalar into a `Gt`, failing if the input is not canonical.
|
||||
func (gt *Gt) SetBytes(input *[GtFieldBytes]byte) (*Gt, int) {
|
||||
var t [FieldBytes]byte
|
||||
var valid [12]int
|
||||
copy(t[:], internal.ReverseScalarBytes(input[:FieldBytes]))
|
||||
_, valid[0] = gt.A.A.A.SetBytes(&t)
|
||||
copy(t[:], internal.ReverseScalarBytes(input[FieldBytes:2*FieldBytes]))
|
||||
_, valid[1] = gt.A.A.B.SetBytes(&t)
|
||||
copy(t[:], internal.ReverseScalarBytes(input[2*FieldBytes:3*FieldBytes]))
|
||||
_, valid[2] = gt.A.B.A.SetBytes(&t)
|
||||
copy(t[:], internal.ReverseScalarBytes(input[3*FieldBytes:4*FieldBytes]))
|
||||
_, valid[3] = gt.A.B.B.SetBytes(&t)
|
||||
copy(t[:], internal.ReverseScalarBytes(input[4*FieldBytes:5*FieldBytes]))
|
||||
_, valid[4] = gt.A.C.A.SetBytes(&t)
|
||||
copy(t[:], internal.ReverseScalarBytes(input[5*FieldBytes:6*FieldBytes]))
|
||||
_, valid[5] = gt.A.C.B.SetBytes(&t)
|
||||
copy(t[:], internal.ReverseScalarBytes(input[6*FieldBytes:7*FieldBytes]))
|
||||
_, valid[6] = gt.B.A.A.SetBytes(&t)
|
||||
copy(t[:], internal.ReverseScalarBytes(input[7*FieldBytes:8*FieldBytes]))
|
||||
_, valid[7] = gt.B.A.B.SetBytes(&t)
|
||||
copy(t[:], internal.ReverseScalarBytes(input[8*FieldBytes:9*FieldBytes]))
|
||||
_, valid[8] = gt.B.B.A.SetBytes(&t)
|
||||
copy(t[:], internal.ReverseScalarBytes(input[9*FieldBytes:10*FieldBytes]))
|
||||
_, valid[9] = gt.B.B.B.SetBytes(&t)
|
||||
copy(t[:], internal.ReverseScalarBytes(input[10*FieldBytes:11*FieldBytes]))
|
||||
_, valid[10] = gt.B.C.A.SetBytes(&t)
|
||||
copy(t[:], internal.ReverseScalarBytes(input[11*FieldBytes:12*FieldBytes]))
|
||||
_, valid[11] = gt.B.C.B.SetBytes(&t)
|
||||
|
||||
return gt, valid[0] & valid[1] &
|
||||
valid[2] & valid[3] &
|
||||
valid[4] & valid[5] &
|
||||
valid[6] & valid[7] &
|
||||
valid[8] & valid[9] &
|
||||
valid[10] & valid[11]
|
||||
}
|
||||
|
||||
// Equal returns 1 if gt == rhs, 0 otherwise
|
||||
func (gt *Gt) Equal(rhs *Gt) int {
|
||||
return (*fp12)(gt).Equal((*fp12)(rhs))
|
||||
}
|
||||
|
||||
// Generator returns the base point
|
||||
func (gt *Gt) Generator() *Gt {
|
||||
// pairing(&G1::generator(), &G2::generator())
|
||||
gt.Set((*Gt)(&fp12{
|
||||
A: fp6{
|
||||
A: fp2{
|
||||
A: fp{
|
||||
0x1972e433a01f85c5,
|
||||
0x97d32b76fd772538,
|
||||
0xc8ce546fc96bcdf9,
|
||||
0xcef63e7366d40614,
|
||||
0xa611342781843780,
|
||||
0x13f3448a3fc6d825,
|
||||
},
|
||||
B: fp{
|
||||
0xd26331b02e9d6995,
|
||||
0x9d68a482f7797e7d,
|
||||
0x9c9b29248d39ea92,
|
||||
0xf4801ca2e13107aa,
|
||||
0xa16c0732bdbcb066,
|
||||
0x083ca4afba360478,
|
||||
},
|
||||
},
|
||||
B: fp2{
|
||||
A: fp{
|
||||
0x59e261db0916b641,
|
||||
0x2716b6f4b23e960d,
|
||||
0xc8e55b10a0bd9c45,
|
||||
0x0bdb0bd99c4deda8,
|
||||
0x8cf89ebf57fdaac5,
|
||||
0x12d6b7929e777a5e,
|
||||
},
|
||||
B: fp{
|
||||
0x5fc85188b0e15f35,
|
||||
0x34a06e3a8f096365,
|
||||
0xdb3126a6e02ad62c,
|
||||
0xfc6f5aa97d9a990b,
|
||||
0xa12f55f5eb89c210,
|
||||
0x1723703a926f8889,
|
||||
},
|
||||
},
|
||||
C: fp2{
|
||||
A: fp{
|
||||
0x93588f2971828778,
|
||||
0x43f65b8611ab7585,
|
||||
0x3183aaf5ec279fdf,
|
||||
0xfa73d7e18ac99df6,
|
||||
0x64e176a6a64c99b0,
|
||||
0x179fa78c58388f1f,
|
||||
},
|
||||
B: fp{
|
||||
0x672a0a11ca2aef12,
|
||||
0x0d11b9b52aa3f16b,
|
||||
0xa44412d0699d056e,
|
||||
0xc01d0177221a5ba5,
|
||||
0x66e0cede6c735529,
|
||||
0x05f5a71e9fddc339,
|
||||
},
|
||||
},
|
||||
},
|
||||
B: fp6{
|
||||
A: fp2{
|
||||
A: fp{
|
||||
0xd30a88a1b062c679,
|
||||
0x5ac56a5d35fc8304,
|
||||
0xd0c834a6a81f290d,
|
||||
0xcd5430c2da3707c7,
|
||||
0xf0c27ff780500af0,
|
||||
0x09245da6e2d72eae,
|
||||
},
|
||||
B: fp{
|
||||
0x9f2e0676791b5156,
|
||||
0xe2d1c8234918fe13,
|
||||
0x4c9e459f3c561bf4,
|
||||
0xa3e85e53b9d3e3c1,
|
||||
0x820a121e21a70020,
|
||||
0x15af618341c59acc,
|
||||
},
|
||||
},
|
||||
B: fp2{
|
||||
A: fp{
|
||||
0x7c95658c24993ab1,
|
||||
0x73eb38721ca886b9,
|
||||
0x5256d749477434bc,
|
||||
0x8ba41902ea504a8b,
|
||||
0x04a3d3f80c86ce6d,
|
||||
0x18a64a87fb686eaa,
|
||||
},
|
||||
B: fp{
|
||||
0xbb83e71bb920cf26,
|
||||
0x2a5277ac92a73945,
|
||||
0xfc0ee59f94f046a0,
|
||||
0x7158cdf3786058f7,
|
||||
0x7cc1061b82f945f6,
|
||||
0x03f847aa9fdbe567,
|
||||
},
|
||||
},
|
||||
C: fp2{
|
||||
A: fp{
|
||||
0x8078dba56134e657,
|
||||
0x1cd7ec9a43998a6e,
|
||||
0xb1aa599a1a993766,
|
||||
0xc9a0f62f0842ee44,
|
||||
0x8e159be3b605dffa,
|
||||
0x0c86ba0d4af13fc2,
|
||||
},
|
||||
B: fp{
|
||||
0xe80ff2a06a52ffb1,
|
||||
0x7694ca48721a906c,
|
||||
0x7583183e03b08514,
|
||||
0xf567afdd40cee4e2,
|
||||
0x9a6d96d2e526a5fc,
|
||||
0x197e9f49861f2242,
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
return gt
|
||||
}
|
||||
|
||||
// Add adds this value to another value.
|
||||
func (gt *Gt) Add(arg1, arg2 *Gt) *Gt {
|
||||
(*fp12)(gt).Mul((*fp12)(arg1), (*fp12)(arg2))
|
||||
return gt
|
||||
}
|
||||
|
||||
// Double this value
|
||||
func (gt *Gt) Double(a *Gt) *Gt {
|
||||
(*fp12)(gt).Square((*fp12)(a))
|
||||
return gt
|
||||
}
|
||||
|
||||
// Sub subtracts the two values
|
||||
func (gt *Gt) Sub(arg1, arg2 *Gt) *Gt {
|
||||
var t fp12
|
||||
t.Conjugate((*fp12)(arg2))
|
||||
(*fp12)(gt).Mul((*fp12)(arg1), &t)
|
||||
return gt
|
||||
}
|
||||
|
||||
// Neg negates this value
|
||||
func (gt *Gt) Neg(a *Gt) *Gt {
|
||||
(*fp12)(gt).Conjugate((*fp12)(a))
|
||||
return gt
|
||||
}
|
||||
|
||||
// Mul multiplies this value by the input scalar
|
||||
func (gt *Gt) Mul(a *Gt, s *native.Field) *Gt {
|
||||
var f, p fp12
|
||||
f.Set((*fp12)(a))
|
||||
bytes := s.Bytes()
|
||||
|
||||
precomputed := [16]fp12{}
|
||||
precomputed[1].Set(&f)
|
||||
for i := 2; i < 16; i += 2 {
|
||||
precomputed[i].Square(&precomputed[i>>1])
|
||||
precomputed[i+1].Mul(&precomputed[i], &f)
|
||||
}
|
||||
for i := 0; i < 256; i += 4 {
|
||||
// Brouwer / windowing method. window size of 4.
|
||||
for j := 0; j < 4; j++ {
|
||||
p.Square(&p)
|
||||
}
|
||||
window := bytes[32-1-i>>3] >> (4 - i&0x04) & 0x0F
|
||||
p.Mul(&p, &precomputed[window])
|
||||
}
|
||||
(*fp12)(gt).Set(&p)
|
||||
return gt
|
||||
}
|
||||
|
||||
// Square this value
|
||||
func (gt *Gt) Square(a *Gt) *Gt {
|
||||
(*fp12)(gt).cyclotomicSquare((*fp12)(a))
|
||||
return gt
|
||||
}
|
||||
|
||||
// Invert this value
|
||||
func (gt *Gt) Invert(a *Gt) (*Gt, int) {
|
||||
_, wasInverted := (*fp12)(gt).Invert((*fp12)(a))
|
||||
return gt, wasInverted
|
||||
}
|
||||
|
||||
func fp4Square(a, b, arg1, arg2 *fp2) {
|
||||
var t0, t1, t2 fp2
|
||||
|
||||
t0.Square(arg1)
|
||||
t1.Square(arg2)
|
||||
t2.MulByNonResidue(&t1)
|
||||
a.Add(&t2, &t0)
|
||||
t2.Add(arg1, arg2)
|
||||
t2.Square(&t2)
|
||||
t2.Sub(&t2, &t0)
|
||||
b.Sub(&t2, &t1)
|
||||
}
|
||||
|
||||
func (f *fp12) cyclotomicSquare(a *fp12) *fp12 {
|
||||
// Adaptation of Algorithm 5.5.4, Guide to Pairing-Based Cryptography
|
||||
// Faster Squaring in the Cyclotomic Subgroup of Sixth Degree Extensions
|
||||
// https://eprint.iacr.org/2009/565.pdf
|
||||
var z0, z1, z2, z3, z4, z5, t0, t1, t2, t3 fp2
|
||||
z0.Set(&a.A.A)
|
||||
z4.Set(&a.A.B)
|
||||
z3.Set(&a.A.C)
|
||||
z2.Set(&a.B.A)
|
||||
z1.Set(&a.B.B)
|
||||
z5.Set(&a.B.C)
|
||||
|
||||
fp4Square(&t0, &t1, &z0, &z1)
|
||||
z0.Sub(&t0, &z0)
|
||||
z0.Double(&z0)
|
||||
z0.Add(&z0, &t0)
|
||||
|
||||
z1.Add(&t1, &z1)
|
||||
z1.Double(&z1)
|
||||
z1.Add(&z1, &t1)
|
||||
|
||||
fp4Square(&t0, &t1, &z2, &z3)
|
||||
fp4Square(&t2, &t3, &z4, &z5)
|
||||
|
||||
z4.Sub(&t0, &z4)
|
||||
z4.Double(&z4)
|
||||
z4.Add(&z4, &t0)
|
||||
|
||||
z5.Add(&z5, &t1)
|
||||
z5.Double(&z5)
|
||||
z5.Add(&z5, &t1)
|
||||
|
||||
t0.MulByNonResidue(&t3)
|
||||
z2.Add(&z2, &t0)
|
||||
z2.Double(&z2)
|
||||
z2.Add(&z2, &t0)
|
||||
|
||||
z3.Sub(&t2, &z3)
|
||||
z3.Double(&z3)
|
||||
z3.Add(&z3, &t2)
|
||||
|
||||
f.A.A.Set(&z0)
|
||||
f.A.B.Set(&z4)
|
||||
f.A.C.Set(&z3)
|
||||
|
||||
f.B.A.Set(&z2)
|
||||
f.B.B.Set(&z1)
|
||||
f.B.C.Set(&z5)
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *fp12) cyclotomicExp(a *fp12) *fp12 {
|
||||
var t fp12
|
||||
t.SetOne()
|
||||
foundOne := 0
|
||||
|
||||
for i := 63; i >= 0; i-- {
|
||||
b := int((paramX >> i) & 1)
|
||||
if foundOne == 1 {
|
||||
t.cyclotomicSquare(&t)
|
||||
} else {
|
||||
foundOne = b
|
||||
}
|
||||
if b == 1 {
|
||||
t.Mul(&t, a)
|
||||
}
|
||||
}
|
||||
f.Conjugate(&t)
|
||||
return f
|
||||
}
|
@ -1,254 +0,0 @@
|
||||
package bls12381
|
||||
|
||||
const coefficientsG2 = 68
|
||||
|
||||
type Engine struct {
|
||||
pairs []pair
|
||||
}
|
||||
|
||||
type pair struct {
|
||||
g1 G1
|
||||
g2 G2
|
||||
}
|
||||
|
||||
type g2Prepared struct {
|
||||
identity int
|
||||
coefficients []coefficients
|
||||
}
|
||||
|
||||
type coefficients struct {
|
||||
a, b, c fp2
|
||||
}
|
||||
|
||||
func (c *coefficients) CMove(arg1, arg2 *coefficients, choice int) *coefficients {
|
||||
c.a.CMove(&arg1.a, &arg2.a, choice)
|
||||
c.b.CMove(&arg1.b, &arg2.b, choice)
|
||||
c.c.CMove(&arg1.c, &arg2.c, choice)
|
||||
return c
|
||||
}
|
||||
|
||||
// AddPair adds a pair of points to be paired
|
||||
func (e *Engine) AddPair(g1 *G1, g2 *G2) *Engine {
|
||||
var p pair
|
||||
p.g1.ToAffine(g1)
|
||||
p.g2.ToAffine(g2)
|
||||
if p.g1.IsIdentity()|p.g2.IsIdentity() == 0 {
|
||||
e.pairs = append(e.pairs, p)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// AddPairInvG1 adds a pair of points to be paired. G1 point is negated
|
||||
func (e *Engine) AddPairInvG1(g1 *G1, g2 *G2) *Engine {
|
||||
var p G1
|
||||
p.Neg(g1)
|
||||
return e.AddPair(&p, g2)
|
||||
}
|
||||
|
||||
// AddPairInvG2 adds a pair of points to be paired. G2 point is negated
|
||||
func (e *Engine) AddPairInvG2(g1 *G1, g2 *G2) *Engine {
|
||||
var p G2
|
||||
p.Neg(g2)
|
||||
return e.AddPair(g1, &p)
|
||||
}
|
||||
|
||||
func (e *Engine) Reset() *Engine {
|
||||
e.pairs = []pair{}
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *Engine) Check() bool {
|
||||
return e.pairing().IsOne() == 1
|
||||
}
|
||||
|
||||
func (e *Engine) Result() *Gt {
|
||||
return e.pairing()
|
||||
}
|
||||
|
||||
func (e *Engine) pairing() *Gt {
|
||||
f := new(Gt).SetOne()
|
||||
if len(e.pairs) == 0 {
|
||||
return f
|
||||
}
|
||||
coeffs := e.computeCoeffs()
|
||||
e.millerLoop((*fp12)(f), coeffs)
|
||||
return f.FinalExponentiation(f)
|
||||
}
|
||||
|
||||
func (e *Engine) millerLoop(f *fp12, coeffs []g2Prepared) {
|
||||
newF := new(fp12).SetZero()
|
||||
found := 0
|
||||
cIdx := 0
|
||||
for i := 63; i >= 0; i-- {
|
||||
x := int(((paramX >> 1) >> i) & 1)
|
||||
if found == 0 {
|
||||
found |= x
|
||||
continue
|
||||
}
|
||||
|
||||
// doubling
|
||||
for j, terms := range coeffs {
|
||||
identity := e.pairs[j].g1.IsIdentity() | terms.identity
|
||||
newF.Set(f)
|
||||
ell(newF, terms.coefficients[cIdx], &e.pairs[j].g1)
|
||||
f.CMove(newF, f, identity)
|
||||
}
|
||||
cIdx++
|
||||
|
||||
if x == 1 {
|
||||
// adding
|
||||
for j, terms := range coeffs {
|
||||
identity := e.pairs[j].g1.IsIdentity() | terms.identity
|
||||
newF.Set(f)
|
||||
ell(newF, terms.coefficients[cIdx], &e.pairs[j].g1)
|
||||
f.CMove(newF, f, identity)
|
||||
}
|
||||
cIdx++
|
||||
}
|
||||
f.Square(f)
|
||||
}
|
||||
for j, terms := range coeffs {
|
||||
identity := e.pairs[j].g1.IsIdentity() | terms.identity
|
||||
newF.Set(f)
|
||||
ell(newF, terms.coefficients[cIdx], &e.pairs[j].g1)
|
||||
f.CMove(newF, f, identity)
|
||||
}
|
||||
f.Conjugate(f)
|
||||
}
|
||||
|
||||
func (e *Engine) computeCoeffs() []g2Prepared {
|
||||
coeffs := make([]g2Prepared, len(e.pairs))
|
||||
for i, p := range e.pairs {
|
||||
identity := p.g2.IsIdentity()
|
||||
q := new(G2).Generator()
|
||||
q.CMove(&p.g2, q, identity)
|
||||
c := new(G2).Set(q)
|
||||
cfs := make([]coefficients, coefficientsG2)
|
||||
found := 0
|
||||
k := 0
|
||||
|
||||
for j := 63; j >= 0; j-- {
|
||||
x := int(((paramX >> 1) >> j) & 1)
|
||||
if found == 0 {
|
||||
found |= x
|
||||
continue
|
||||
}
|
||||
cfs[k] = doublingStep(c)
|
||||
k++
|
||||
|
||||
if x == 1 {
|
||||
cfs[k] = additionStep(c, q)
|
||||
k++
|
||||
}
|
||||
}
|
||||
cfs[k] = doublingStep(c)
|
||||
coeffs[i] = g2Prepared{
|
||||
coefficients: cfs, identity: identity,
|
||||
}
|
||||
}
|
||||
return coeffs
|
||||
}
|
||||
|
||||
func ell(f *fp12, coeffs coefficients, p *G1) {
|
||||
var x, y fp2
|
||||
x.A.Mul(&coeffs.a.A, &p.y)
|
||||
x.B.Mul(&coeffs.a.B, &p.y)
|
||||
y.A.Mul(&coeffs.b.A, &p.x)
|
||||
y.B.Mul(&coeffs.b.B, &p.x)
|
||||
f.MulByABD(f, &coeffs.c, &y, &x)
|
||||
}
|
||||
|
||||
func doublingStep(p *G2) coefficients {
|
||||
// Adaptation of Algorithm 26, https://eprint.iacr.org/2010/354.pdf
|
||||
var t0, t1, t2, t3, t4, t5, t6, zsqr fp2
|
||||
t0.Square(&p.x)
|
||||
t1.Square(&p.y)
|
||||
t2.Square(&t1)
|
||||
t3.Add(&t1, &p.x)
|
||||
t3.Square(&t3)
|
||||
t3.Sub(&t3, &t0)
|
||||
t3.Sub(&t3, &t2)
|
||||
t3.Double(&t3)
|
||||
t4.Double(&t0)
|
||||
t4.Add(&t4, &t0)
|
||||
t6.Add(&p.x, &t4)
|
||||
t5.Square(&t4)
|
||||
zsqr.Square(&p.z)
|
||||
p.x.Sub(&t5, &t3)
|
||||
p.x.Sub(&p.x, &t3)
|
||||
p.z.Add(&p.z, &p.y)
|
||||
p.z.Square(&p.z)
|
||||
p.z.Sub(&p.z, &t1)
|
||||
p.z.Sub(&p.z, &zsqr)
|
||||
p.y.Sub(&t3, &p.x)
|
||||
p.y.Mul(&p.y, &t4)
|
||||
t2.Double(&t2)
|
||||
t2.Double(&t2)
|
||||
t2.Double(&t2)
|
||||
p.y.Sub(&p.y, &t2)
|
||||
t3.Mul(&t4, &zsqr)
|
||||
t3.Double(&t3)
|
||||
t3.Neg(&t3)
|
||||
t6.Square(&t6)
|
||||
t6.Sub(&t6, &t0)
|
||||
t6.Sub(&t6, &t5)
|
||||
t1.Double(&t1)
|
||||
t1.Double(&t1)
|
||||
t6.Sub(&t6, &t1)
|
||||
t0.Mul(&p.z, &zsqr)
|
||||
t0.Double(&t0)
|
||||
|
||||
return coefficients{
|
||||
a: t0, b: t3, c: t6,
|
||||
}
|
||||
}
|
||||
|
||||
func additionStep(r, q *G2) coefficients {
|
||||
// Adaptation of Algorithm 27, https://eprint.iacr.org/2010/354.pdf
|
||||
var zsqr, ysqr fp2
|
||||
var t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10 fp2
|
||||
zsqr.Square(&r.z)
|
||||
ysqr.Square(&q.y)
|
||||
t0.Mul(&zsqr, &q.x)
|
||||
t1.Add(&q.y, &r.z)
|
||||
t1.Square(&t1)
|
||||
t1.Sub(&t1, &ysqr)
|
||||
t1.Sub(&t1, &zsqr)
|
||||
t1.Mul(&t1, &zsqr)
|
||||
t2.Sub(&t0, &r.x)
|
||||
t3.Square(&t2)
|
||||
t4.Double(&t3)
|
||||
t4.Double(&t4)
|
||||
t5.Mul(&t4, &t2)
|
||||
t6.Sub(&t1, &r.y)
|
||||
t6.Sub(&t6, &r.y)
|
||||
t9.Mul(&t6, &q.x)
|
||||
t7.Mul(&t4, &r.x)
|
||||
r.x.Square(&t6)
|
||||
r.x.Sub(&r.x, &t5)
|
||||
r.x.Sub(&r.x, &t7)
|
||||
r.x.Sub(&r.x, &t7)
|
||||
r.z.Add(&r.z, &t2)
|
||||
r.z.Square(&r.z)
|
||||
r.z.Sub(&r.z, &zsqr)
|
||||
r.z.Sub(&r.z, &t3)
|
||||
t10.Add(&q.y, &r.z)
|
||||
t8.Sub(&t7, &r.x)
|
||||
t8.Mul(&t8, &t6)
|
||||
t0.Mul(&r.y, &t5)
|
||||
t0.Double(&t0)
|
||||
r.y.Sub(&t8, &t0)
|
||||
t10.Square(&t10)
|
||||
t10.Sub(&t10, &ysqr)
|
||||
zsqr.Square(&r.z)
|
||||
t10.Sub(&t10, &zsqr)
|
||||
t9.Double(&t9)
|
||||
t9.Sub(&t9, &t10)
|
||||
t10.Double(&r.z)
|
||||
t6.Neg(&t6)
|
||||
t1.Double(&t6)
|
||||
|
||||
return coefficients{
|
||||
a: t10, b: t1, c: t9,
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
package bls12381
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
)
|
||||
|
||||
func TestSinglePairing(t *testing.T) {
|
||||
g := new(G1).Generator()
|
||||
h := new(G2).Generator()
|
||||
|
||||
e := new(Engine)
|
||||
e.AddPair(g, h)
|
||||
p := e.Result()
|
||||
p.Neg(p)
|
||||
|
||||
e.Reset()
|
||||
e.AddPairInvG2(g, h)
|
||||
q := e.Result()
|
||||
e.Reset()
|
||||
e.AddPairInvG1(g, h)
|
||||
r := e.Result()
|
||||
|
||||
require.Equal(t, 1, p.Equal(q))
|
||||
require.Equal(t, 1, q.Equal(r))
|
||||
}
|
||||
|
||||
func TestMultiPairing(t *testing.T) {
|
||||
const Tests = 10
|
||||
e1 := new(Engine)
|
||||
e2 := new(Engine)
|
||||
|
||||
g1s := make([]*G1, Tests)
|
||||
g2s := make([]*G2, Tests)
|
||||
sc := make([]*native.Field, Tests)
|
||||
res := make([]*Gt, Tests)
|
||||
expected := new(Gt).SetOne()
|
||||
|
||||
for i := 0; i < Tests; i++ {
|
||||
var bytes [64]byte
|
||||
g1s[i] = new(G1).Generator()
|
||||
g2s[i] = new(G2).Generator()
|
||||
sc[i] = Bls12381FqNew()
|
||||
_, _ = crand.Read(bytes[:])
|
||||
sc[i].SetBytesWide(&bytes)
|
||||
if i&1 == 0 {
|
||||
g1s[i].Mul(g1s[i], sc[i])
|
||||
} else {
|
||||
g2s[i].Mul(g2s[i], sc[i])
|
||||
}
|
||||
e1.AddPair(g1s[i], g2s[i])
|
||||
e2.AddPair(g1s[i], g2s[i])
|
||||
res[i] = e1.Result()
|
||||
e1.Reset()
|
||||
expected.Add(expected, res[i])
|
||||
}
|
||||
|
||||
actual := e2.Result()
|
||||
require.Equal(t, 1, expected.Equal(actual))
|
||||
}
|
@ -1,388 +0,0 @@
|
||||
package native
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
// FieldLimbs is the number of limbs needed to represent this field
|
||||
const FieldLimbs = 4
|
||||
|
||||
// FieldBytes is the number of bytes needed to represent this field
|
||||
const FieldBytes = 32
|
||||
|
||||
// WideFieldBytes is the number of bytes needed for safe conversion
|
||||
// to this field to avoid bias when reduced
|
||||
const WideFieldBytes = 64
|
||||
|
||||
// Field represents a field element
|
||||
type Field struct {
|
||||
// Value is the field elements value
|
||||
Value [FieldLimbs]uint64
|
||||
// Params are the field parameters
|
||||
Params *FieldParams
|
||||
// Arithmetic are the field methods
|
||||
Arithmetic FieldArithmetic
|
||||
}
|
||||
|
||||
// FieldParams are the field parameters
|
||||
type FieldParams struct {
|
||||
// R is 2^256 mod Modulus
|
||||
R [FieldLimbs]uint64
|
||||
// R2 is 2^512 mod Modulus
|
||||
R2 [FieldLimbs]uint64
|
||||
// R3 is 2^768 mod Modulus
|
||||
R3 [FieldLimbs]uint64
|
||||
// Modulus of the field
|
||||
Modulus [FieldLimbs]uint64
|
||||
// Modulus as big.Int
|
||||
BiModulus *big.Int
|
||||
}
|
||||
|
||||
// FieldArithmetic are the methods that can be done on a field
|
||||
type FieldArithmetic interface {
|
||||
// ToMontgomery converts this field to montgomery form
|
||||
ToMontgomery(out, arg *[FieldLimbs]uint64)
|
||||
// FromMontgomery converts this field from montgomery form
|
||||
FromMontgomery(out, arg *[FieldLimbs]uint64)
|
||||
// Neg performs modular negation
|
||||
Neg(out, arg *[FieldLimbs]uint64)
|
||||
// Square performs modular square
|
||||
Square(out, arg *[FieldLimbs]uint64)
|
||||
// Mul performs modular multiplication
|
||||
Mul(out, arg1, arg2 *[FieldLimbs]uint64)
|
||||
// Add performs modular addition
|
||||
Add(out, arg1, arg2 *[FieldLimbs]uint64)
|
||||
// Sub performs modular subtraction
|
||||
Sub(out, arg1, arg2 *[FieldLimbs]uint64)
|
||||
// Sqrt performs modular square root
|
||||
Sqrt(wasSquare *int, out, arg *[FieldLimbs]uint64)
|
||||
// Invert performs modular inverse
|
||||
Invert(wasInverted *int, out, arg *[FieldLimbs]uint64)
|
||||
// FromBytes converts a little endian byte array into a field element
|
||||
FromBytes(out *[FieldLimbs]uint64, arg *[FieldBytes]byte)
|
||||
// ToBytes converts a field element to a little endian byte array
|
||||
ToBytes(out *[FieldBytes]byte, arg *[FieldLimbs]uint64)
|
||||
// Selectznz performs conditional select.
|
||||
// selects arg1 if choice == 0 and arg2 if choice == 1
|
||||
Selectznz(out, arg1, arg2 *[FieldLimbs]uint64, choice int)
|
||||
}
|
||||
|
||||
// Cmp returns -1 if f < rhs
|
||||
// 0 if f == rhs
|
||||
// 1 if f > rhs
|
||||
func (f *Field) Cmp(rhs *Field) int {
|
||||
return cmpHelper(&f.Value, &rhs.Value)
|
||||
}
|
||||
|
||||
// cmpHelper returns -1 if lhs < rhs
|
||||
// -1 if lhs == rhs
|
||||
// 1 if lhs > rhs
|
||||
// Public only for convenience for some internal implementations
|
||||
func cmpHelper(lhs, rhs *[FieldLimbs]uint64) int {
|
||||
gt := uint64(0)
|
||||
lt := uint64(0)
|
||||
for i := 3; i >= 0; i-- {
|
||||
// convert to two 64-bit numbers where
|
||||
// the leading bits are zeros and hold no meaning
|
||||
// so rhs - fp actually means gt
|
||||
// and fp - rhs actually means lt.
|
||||
rhsH := rhs[i] >> 32
|
||||
rhsL := rhs[i] & 0xffffffff
|
||||
lhsH := lhs[i] >> 32
|
||||
lhsL := lhs[i] & 0xffffffff
|
||||
|
||||
// Check the leading bit
|
||||
// if negative then fp > rhs
|
||||
// if positive then fp < rhs
|
||||
gt |= (rhsH - lhsH) >> 32 & 1 &^ lt
|
||||
lt |= (lhsH - rhsH) >> 32 & 1 &^ gt
|
||||
gt |= (rhsL - lhsL) >> 32 & 1 &^ lt
|
||||
lt |= (lhsL - rhsL) >> 32 & 1 &^ gt
|
||||
}
|
||||
// Make the result -1 for <, 0 for =, 1 for >
|
||||
return int(gt) - int(lt)
|
||||
}
|
||||
|
||||
// Equal returns 1 if f == rhs, 0 otherwise
|
||||
func (f *Field) Equal(rhs *Field) int {
|
||||
return equalHelper(&f.Value, &rhs.Value)
|
||||
}
|
||||
|
||||
func equalHelper(lhs, rhs *[FieldLimbs]uint64) int {
|
||||
t := lhs[0] ^ rhs[0]
|
||||
t |= lhs[1] ^ rhs[1]
|
||||
t |= lhs[2] ^ rhs[2]
|
||||
t |= lhs[3] ^ rhs[3]
|
||||
return int(((int64(t) | int64(-t)) >> 63) + 1)
|
||||
}
|
||||
|
||||
// IsZero returns 1 if f == 0, 0 otherwise
|
||||
func (f *Field) IsZero() int {
|
||||
t := f.Value[0]
|
||||
t |= f.Value[1]
|
||||
t |= f.Value[2]
|
||||
t |= f.Value[3]
|
||||
return int(((int64(t) | int64(-t)) >> 63) + 1)
|
||||
}
|
||||
|
||||
// IsNonZero returns 1 if f != 0, 0 otherwise
|
||||
func (f *Field) IsNonZero() int {
|
||||
t := f.Value[0]
|
||||
t |= f.Value[1]
|
||||
t |= f.Value[2]
|
||||
t |= f.Value[3]
|
||||
return int(-((int64(t) | int64(-t)) >> 63))
|
||||
}
|
||||
|
||||
// IsOne returns 1 if f == 1, 0 otherwise
|
||||
func (f *Field) IsOne() int {
|
||||
return equalHelper(&f.Value, &f.Params.R)
|
||||
}
|
||||
|
||||
// Set f = rhs
|
||||
func (f *Field) Set(rhs *Field) *Field {
|
||||
f.Value[0] = rhs.Value[0]
|
||||
f.Value[1] = rhs.Value[1]
|
||||
f.Value[2] = rhs.Value[2]
|
||||
f.Value[3] = rhs.Value[3]
|
||||
f.Params = rhs.Params
|
||||
f.Arithmetic = rhs.Arithmetic
|
||||
return f
|
||||
}
|
||||
|
||||
// SetUint64 f = rhs
|
||||
func (f *Field) SetUint64(rhs uint64) *Field {
|
||||
t := &[FieldLimbs]uint64{rhs, 0, 0, 0}
|
||||
f.Arithmetic.ToMontgomery(&f.Value, t)
|
||||
return f
|
||||
}
|
||||
|
||||
// SetOne f = r
|
||||
func (f *Field) SetOne() *Field {
|
||||
f.Value[0] = f.Params.R[0]
|
||||
f.Value[1] = f.Params.R[1]
|
||||
f.Value[2] = f.Params.R[2]
|
||||
f.Value[3] = f.Params.R[3]
|
||||
return f
|
||||
}
|
||||
|
||||
// SetZero f = 0
|
||||
func (f *Field) SetZero() *Field {
|
||||
f.Value[0] = 0
|
||||
f.Value[1] = 0
|
||||
f.Value[2] = 0
|
||||
f.Value[3] = 0
|
||||
return f
|
||||
}
|
||||
|
||||
// SetBytesWide takes 64 bytes as input and treats them as a 512-bit number.
|
||||
// Attributed to https://github.com/zcash/pasta_curves/blob/main/src/fields/Fp.rs#L255
|
||||
// We reduce an arbitrary 512-bit number by decomposing it into two 256-bit digits
|
||||
// with the higher bits multiplied by 2^256. Thus, we perform two reductions
|
||||
//
|
||||
// 1. the lower bits are multiplied by r^2, as normal
|
||||
// 2. the upper bits are multiplied by r^2 * 2^256 = r^3
|
||||
//
|
||||
// and computing their sum in the field. It remains to see that arbitrary 256-bit
|
||||
// numbers can be placed into Montgomery form safely using the reduction. The
|
||||
// reduction works so long as the product is less than r=2^256 multiplied by
|
||||
// the modulus. This holds because for any `c` smaller than the modulus, we have
|
||||
// that (2^256 - 1)*c is an acceptable product for the reduction. Therefore, the
|
||||
// reduction always works so long as `c` is in the field; in this case it is either the
|
||||
// constant `r2` or `r3`.
|
||||
func (f *Field) SetBytesWide(input *[WideFieldBytes]byte) *Field {
|
||||
d0 := [FieldLimbs]uint64{
|
||||
binary.LittleEndian.Uint64(input[:8]),
|
||||
binary.LittleEndian.Uint64(input[8:16]),
|
||||
binary.LittleEndian.Uint64(input[16:24]),
|
||||
binary.LittleEndian.Uint64(input[24:32]),
|
||||
}
|
||||
d1 := [FieldLimbs]uint64{
|
||||
binary.LittleEndian.Uint64(input[32:40]),
|
||||
binary.LittleEndian.Uint64(input[40:48]),
|
||||
binary.LittleEndian.Uint64(input[48:56]),
|
||||
binary.LittleEndian.Uint64(input[56:64]),
|
||||
}
|
||||
// f.Arithmetic.ToMontgomery(&d0, &d0)
|
||||
// f.Arithmetic.Mul(&d1, &d1, &f.Params.R2)
|
||||
// f.Arithmetic.Add(&f.Value, &d0, &d0)
|
||||
// Convert to Montgomery form
|
||||
tv1 := &[FieldLimbs]uint64{}
|
||||
tv2 := &[FieldLimbs]uint64{}
|
||||
// d0*r2 + d1*r3
|
||||
f.Arithmetic.Mul(tv1, &d0, &f.Params.R2)
|
||||
f.Arithmetic.Mul(tv2, &d1, &f.Params.R3)
|
||||
f.Arithmetic.Add(&f.Value, tv1, tv2)
|
||||
return f
|
||||
}
|
||||
|
||||
// SetBytes attempts to convert a little endian byte representation
|
||||
// of a scalar into a `Fp`, failing if input is not canonical
|
||||
func (f *Field) SetBytes(input *[FieldBytes]byte) (*Field, error) {
|
||||
d0 := [FieldLimbs]uint64{0, 0, 0, 0}
|
||||
f.Arithmetic.FromBytes(&d0, input)
|
||||
|
||||
if cmpHelper(&d0, &f.Params.Modulus) != -1 {
|
||||
return nil, fmt.Errorf("invalid byte sequence")
|
||||
}
|
||||
return f.SetLimbs(&d0), nil
|
||||
}
|
||||
|
||||
// SetBigInt initializes an element from big.Int
|
||||
// The value is reduced by the modulus
|
||||
func (f *Field) SetBigInt(bi *big.Int) *Field {
|
||||
var buffer [FieldBytes]byte
|
||||
t := new(big.Int).Set(bi)
|
||||
t.Mod(t, f.Params.BiModulus)
|
||||
t.FillBytes(buffer[:])
|
||||
copy(buffer[:], internal.ReverseScalarBytes(buffer[:]))
|
||||
_, _ = f.SetBytes(&buffer)
|
||||
return f
|
||||
}
|
||||
|
||||
// SetRaw converts a raw array into a field element
|
||||
// Assumes input is already in montgomery form
|
||||
func (f *Field) SetRaw(input *[FieldLimbs]uint64) *Field {
|
||||
f.Value[0] = input[0]
|
||||
f.Value[1] = input[1]
|
||||
f.Value[2] = input[2]
|
||||
f.Value[3] = input[3]
|
||||
return f
|
||||
}
|
||||
|
||||
// SetLimbs converts an array into a field element
|
||||
// by converting to montgomery form
|
||||
func (f *Field) SetLimbs(input *[FieldLimbs]uint64) *Field {
|
||||
f.Arithmetic.ToMontgomery(&f.Value, input)
|
||||
return f
|
||||
}
|
||||
|
||||
// Bytes converts this element into a byte representation
|
||||
// in little endian byte order
|
||||
func (f *Field) Bytes() [FieldBytes]byte {
|
||||
var output [FieldBytes]byte
|
||||
tv := &[FieldLimbs]uint64{}
|
||||
f.Arithmetic.FromMontgomery(tv, &f.Value)
|
||||
f.Arithmetic.ToBytes(&output, tv)
|
||||
return output
|
||||
}
|
||||
|
||||
// BigInt converts this element into the big.Int struct
|
||||
func (f *Field) BigInt() *big.Int {
|
||||
buffer := f.Bytes()
|
||||
return new(big.Int).SetBytes(internal.ReverseScalarBytes(buffer[:]))
|
||||
}
|
||||
|
||||
// Raw converts this element into the a [FieldLimbs]uint64
|
||||
func (f *Field) Raw() [FieldLimbs]uint64 {
|
||||
res := &[FieldLimbs]uint64{}
|
||||
f.Arithmetic.FromMontgomery(res, &f.Value)
|
||||
return *res
|
||||
}
|
||||
|
||||
// Double this element
|
||||
func (f *Field) Double(a *Field) *Field {
|
||||
f.Arithmetic.Add(&f.Value, &a.Value, &a.Value)
|
||||
return f
|
||||
}
|
||||
|
||||
// Square this element
|
||||
func (f *Field) Square(a *Field) *Field {
|
||||
f.Arithmetic.Square(&f.Value, &a.Value)
|
||||
return f
|
||||
}
|
||||
|
||||
// Sqrt this element, if it exists. If true, then value
|
||||
// is a square root. If false, value is a QNR
|
||||
func (f *Field) Sqrt(a *Field) (*Field, bool) {
|
||||
wasSquare := 0
|
||||
f.Arithmetic.Sqrt(&wasSquare, &f.Value, &a.Value)
|
||||
return f, wasSquare == 1
|
||||
}
|
||||
|
||||
// Invert this element i.e. compute the multiplicative inverse
|
||||
// return false, zero if this element is zero.
|
||||
func (f *Field) Invert(a *Field) (*Field, bool) {
|
||||
wasInverted := 0
|
||||
f.Arithmetic.Invert(&wasInverted, &f.Value, &a.Value)
|
||||
return f, wasInverted == 1
|
||||
}
|
||||
|
||||
// Mul returns the result from multiplying this element by rhs
|
||||
func (f *Field) Mul(lhs, rhs *Field) *Field {
|
||||
f.Arithmetic.Mul(&f.Value, &lhs.Value, &rhs.Value)
|
||||
return f
|
||||
}
|
||||
|
||||
// Sub returns the result from subtracting rhs from this element
|
||||
func (f *Field) Sub(lhs, rhs *Field) *Field {
|
||||
f.Arithmetic.Sub(&f.Value, &lhs.Value, &rhs.Value)
|
||||
return f
|
||||
}
|
||||
|
||||
// Add returns the result from adding rhs to this element
|
||||
func (f *Field) Add(lhs, rhs *Field) *Field {
|
||||
f.Arithmetic.Add(&f.Value, &lhs.Value, &rhs.Value)
|
||||
return f
|
||||
}
|
||||
|
||||
// Neg returns negation of this element
|
||||
func (f *Field) Neg(input *Field) *Field {
|
||||
f.Arithmetic.Neg(&f.Value, &input.Value)
|
||||
return f
|
||||
}
|
||||
|
||||
// Exp raises base^exp
|
||||
func (f *Field) Exp(base, exp *Field) *Field {
|
||||
e := [FieldLimbs]uint64{}
|
||||
f.Arithmetic.FromMontgomery(&e, &exp.Value)
|
||||
Pow(&f.Value, &base.Value, &e, f.Params, f.Arithmetic)
|
||||
return f
|
||||
}
|
||||
|
||||
// CMove sets f = lhs if choice == 0 and f = rhs if choice == 1
|
||||
func (f *Field) CMove(lhs, rhs *Field, choice int) *Field {
|
||||
f.Arithmetic.Selectznz(&f.Value, &lhs.Value, &rhs.Value, choice)
|
||||
return f
|
||||
}
|
||||
|
||||
// Pow raises base^exp. The result is written to out.
|
||||
// Public only for convenience for some internal implementations
|
||||
func Pow(out, base, exp *[FieldLimbs]uint64, params *FieldParams, arithmetic FieldArithmetic) {
|
||||
res := [FieldLimbs]uint64{params.R[0], params.R[1], params.R[2], params.R[3]}
|
||||
tmp := [FieldLimbs]uint64{}
|
||||
|
||||
for i := len(exp) - 1; i >= 0; i-- {
|
||||
for j := 63; j >= 0; j-- {
|
||||
arithmetic.Square(&res, &res)
|
||||
arithmetic.Mul(&tmp, &res, base)
|
||||
arithmetic.Selectznz(&res, &res, &tmp, int(exp[i]>>j)&1)
|
||||
}
|
||||
}
|
||||
out[0] = res[0]
|
||||
out[1] = res[1]
|
||||
out[2] = res[2]
|
||||
out[3] = res[3]
|
||||
}
|
||||
|
||||
// Pow2k raises arg to the power `2^k`. This result is written to out.
|
||||
// Public only for convenience for some internal implementations
|
||||
func Pow2k(out, arg *[FieldLimbs]uint64, k int, arithmetic FieldArithmetic) {
|
||||
var t [FieldLimbs]uint64
|
||||
t[0] = arg[0]
|
||||
t[1] = arg[1]
|
||||
t[2] = arg[2]
|
||||
t[3] = arg[3]
|
||||
for i := 0; i < k; i++ {
|
||||
arithmetic.Square(&t, &t)
|
||||
}
|
||||
|
||||
out[0] = t[0]
|
||||
out[1] = t[1]
|
||||
out[2] = t[2]
|
||||
out[3] = t[3]
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
package native
|
||||
|
||||
import (
|
||||
"hash"
|
||||
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
// OversizeDstSalt is the salt used to hash a dst over MaxDstLen
|
||||
var OversizeDstSalt = []byte("H2C-OVERSIZE-DST-")
|
||||
|
||||
// MaxDstLen the max size for dst in hash to curve
|
||||
const MaxDstLen = 255
|
||||
|
||||
func getDomainXmd(h hash.Hash, domain []byte) []byte {
|
||||
var out []byte
|
||||
if len(domain) > MaxDstLen {
|
||||
h.Reset()
|
||||
_, _ = h.Write(OversizeDstSalt)
|
||||
_, _ = h.Write(domain)
|
||||
out = h.Sum(nil)
|
||||
} else {
|
||||
out = domain
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func getDomainXof(h sha3.ShakeHash, domain []byte) []byte {
|
||||
var out []byte
|
||||
if len(domain) > MaxDstLen {
|
||||
h.Reset()
|
||||
_, _ = h.Write(OversizeDstSalt)
|
||||
_, _ = h.Write(domain)
|
||||
var tv [64]byte
|
||||
_, _ = h.Read(tv[:])
|
||||
out = tv[:]
|
||||
} else {
|
||||
out = domain
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// ExpandMsgXmd expands the msg with the domain to output a byte array
|
||||
// with outLen in size using a fixed size hash.
|
||||
// See https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-13#section-5.4.1
|
||||
func ExpandMsgXmd(h *EllipticPointHasher, msg, domain []byte, outLen int) []byte {
|
||||
domain = getDomainXmd(h.xmd, domain)
|
||||
domainLen := byte(len(domain))
|
||||
h.xmd.Reset()
|
||||
// DST_prime = DST || I2OSP(len(DST), 1)
|
||||
// b_0 = H(Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime)
|
||||
_, _ = h.xmd.Write(make([]byte, h.xmd.BlockSize()))
|
||||
_, _ = h.xmd.Write(msg)
|
||||
_, _ = h.xmd.Write([]byte{uint8(outLen >> 8), uint8(outLen)})
|
||||
_, _ = h.xmd.Write([]byte{0})
|
||||
_, _ = h.xmd.Write(domain)
|
||||
_, _ = h.xmd.Write([]byte{domainLen})
|
||||
b0 := h.xmd.Sum(nil)
|
||||
|
||||
// b_1 = H(b_0 || I2OSP(1, 1) || DST_prime)
|
||||
h.xmd.Reset()
|
||||
_, _ = h.xmd.Write(b0)
|
||||
_, _ = h.xmd.Write([]byte{1})
|
||||
_, _ = h.xmd.Write(domain)
|
||||
_, _ = h.xmd.Write([]byte{domainLen})
|
||||
b1 := h.xmd.Sum(nil)
|
||||
|
||||
// b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime)
|
||||
ell := (outLen + h.xmd.Size() - 1) / h.xmd.Size()
|
||||
bi := b1
|
||||
out := make([]byte, outLen)
|
||||
for i := 1; i < ell; i++ {
|
||||
h.xmd.Reset()
|
||||
// b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime)
|
||||
tmp := make([]byte, h.xmd.Size())
|
||||
for j := 0; j < h.xmd.Size(); j++ {
|
||||
tmp[j] = b0[j] ^ bi[j]
|
||||
}
|
||||
_, _ = h.xmd.Write(tmp)
|
||||
_, _ = h.xmd.Write([]byte{1 + uint8(i)})
|
||||
_, _ = h.xmd.Write(domain)
|
||||
_, _ = h.xmd.Write([]byte{domainLen})
|
||||
|
||||
// b_1 || ... || b_(ell - 1)
|
||||
copy(out[(i-1)*h.xmd.Size():i*h.xmd.Size()], bi[:])
|
||||
bi = h.xmd.Sum(nil)
|
||||
}
|
||||
// b_ell
|
||||
copy(out[(ell-1)*h.xmd.Size():], bi[:])
|
||||
return out[:outLen]
|
||||
}
|
||||
|
||||
// ExpandMsgXof expands the msg with the domain to output a byte array
|
||||
// with outLen in size using a xof hash
|
||||
// See https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-13#section-5.4.2
|
||||
func ExpandMsgXof(h *EllipticPointHasher, msg, domain []byte, outLen int) []byte {
|
||||
domain = getDomainXof(h.xof, domain)
|
||||
domainLen := byte(len(domain))
|
||||
h.xof.Reset()
|
||||
_, _ = h.xof.Write(msg)
|
||||
_, _ = h.xof.Write([]byte{uint8(outLen >> 8), uint8(outLen)})
|
||||
_, _ = h.xof.Write(domain)
|
||||
_, _ = h.xof.Write([]byte{domainLen})
|
||||
out := make([]byte, outLen)
|
||||
_, _ = h.xof.Read(out)
|
||||
return out
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
package native
|
||||
|
||||
// IsogenyParams are the parameters needed to map from an isogeny to the main curve
|
||||
type IsogenyParams struct {
|
||||
XNum [][FieldLimbs]uint64
|
||||
XDen [][FieldLimbs]uint64
|
||||
YNum [][FieldLimbs]uint64
|
||||
YDen [][FieldLimbs]uint64
|
||||
}
|
||||
|
||||
// Map from the isogeny curve to the main curve using the parameters
|
||||
func (p *IsogenyParams) Map(xIn, yIn *Field) (x, y *Field) {
|
||||
var xNum, xDen, yNum, yDen, tv [FieldLimbs]uint64
|
||||
var wasInverted int
|
||||
|
||||
xnumL := len(p.XNum)
|
||||
xdenL := len(p.XDen)
|
||||
ynumL := len(p.YNum)
|
||||
ydenL := len(p.YDen)
|
||||
|
||||
degree := 0
|
||||
for _, i := range []int{xnumL, xdenL, ynumL, ydenL} {
|
||||
if degree < i {
|
||||
degree = i
|
||||
}
|
||||
}
|
||||
|
||||
xs := make([][FieldLimbs]uint64, degree)
|
||||
xs[0] = xIn.Params.R // x[0] = x^0
|
||||
xs[1] = xIn.Value // x[1] = x^1
|
||||
xIn.Arithmetic.Square(&xs[2], &xIn.Value) // x[2] = x^2
|
||||
for i := 3; i < degree; i++ {
|
||||
// x[i] = x^i
|
||||
xIn.Arithmetic.Mul(&xs[i], &xs[i-1], &xIn.Value)
|
||||
}
|
||||
|
||||
computeIsoK(&xNum, &xs, &p.XNum, xIn.Arithmetic)
|
||||
computeIsoK(&xDen, &xs, &p.XDen, xIn.Arithmetic)
|
||||
computeIsoK(&yNum, &xs, &p.YNum, xIn.Arithmetic)
|
||||
computeIsoK(&yDen, &xs, &p.YDen, xIn.Arithmetic)
|
||||
|
||||
xIn.Arithmetic.Invert(&wasInverted, &xDen, &xDen)
|
||||
x = new(Field).Set(xIn)
|
||||
xIn.Arithmetic.Mul(&tv, &xNum, &xDen)
|
||||
xIn.Arithmetic.Selectznz(&x.Value, &x.Value, &tv, wasInverted)
|
||||
|
||||
yIn.Arithmetic.Invert(&wasInverted, &yDen, &yDen)
|
||||
y = new(Field).Set(yIn)
|
||||
yIn.Arithmetic.Mul(&tv, &yNum, &yDen)
|
||||
yIn.Arithmetic.Selectznz(&y.Value, &y.Value, &tv, wasInverted)
|
||||
yIn.Arithmetic.Mul(&y.Value, &y.Value, &yIn.Value)
|
||||
return
|
||||
}
|
||||
|
||||
func computeIsoK(out *[FieldLimbs]uint64, xxs, k *[][FieldLimbs]uint64, f FieldArithmetic) {
|
||||
var tv [FieldLimbs]uint64
|
||||
|
||||
for i := range *k {
|
||||
f.Mul(&tv, &(*xxs)[i], &(*k)[i])
|
||||
f.Add(out, out, &tv)
|
||||
}
|
||||
}
|
@ -1,175 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package fp
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"sync"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
)
|
||||
|
||||
var (
|
||||
k256FpInitonce sync.Once
|
||||
k256FpParams native.FieldParams
|
||||
)
|
||||
|
||||
func K256FpNew() *native.Field {
|
||||
return &native.Field{
|
||||
Value: [native.FieldLimbs]uint64{},
|
||||
Params: getK256FpParams(),
|
||||
Arithmetic: k256FpArithmetic{},
|
||||
}
|
||||
}
|
||||
|
||||
func k256FpParamsInit() {
|
||||
k256FpParams = native.FieldParams{
|
||||
R: [native.FieldLimbs]uint64{0x00000001000003d1, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
|
||||
R2: [native.FieldLimbs]uint64{0x000007a2000e90a1, 0x0000000000000001, 0x0000000000000000, 0x0000000000000000},
|
||||
R3: [native.FieldLimbs]uint64{0x002bb1e33795f671, 0x0000000100000b73, 0x0000000000000000, 0x0000000000000000},
|
||||
Modulus: [native.FieldLimbs]uint64{0xfffffffefffffc2f, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff},
|
||||
BiModulus: new(big.Int).SetBytes([]byte{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func getK256FpParams() *native.FieldParams {
|
||||
k256FpInitonce.Do(k256FpParamsInit)
|
||||
return &k256FpParams
|
||||
}
|
||||
|
||||
// k256FpArithmetic is a struct with all the methods needed for working
|
||||
// in mod p
|
||||
type k256FpArithmetic struct{}
|
||||
|
||||
// ToMontgomery converts this field to montgomery form
|
||||
func (f k256FpArithmetic) ToMontgomery(out, arg *[native.FieldLimbs]uint64) {
|
||||
ToMontgomery((*MontgomeryDomainFieldElement)(out), (*NonMontgomeryDomainFieldElement)(arg))
|
||||
}
|
||||
|
||||
// FromMontgomery converts this field from montgomery form
|
||||
func (f k256FpArithmetic) FromMontgomery(out, arg *[native.FieldLimbs]uint64) {
|
||||
FromMontgomery((*NonMontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg))
|
||||
}
|
||||
|
||||
// Neg performs modular negation
|
||||
func (f k256FpArithmetic) Neg(out, arg *[native.FieldLimbs]uint64) {
|
||||
Opp((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg))
|
||||
}
|
||||
|
||||
// Square performs modular square
|
||||
func (f k256FpArithmetic) Square(out, arg *[native.FieldLimbs]uint64) {
|
||||
Square((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg))
|
||||
}
|
||||
|
||||
// Mul performs modular multiplication
|
||||
func (f k256FpArithmetic) Mul(out, arg1, arg2 *[native.FieldLimbs]uint64) {
|
||||
Mul((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2))
|
||||
}
|
||||
|
||||
// Add performs modular addition
|
||||
func (f k256FpArithmetic) Add(out, arg1, arg2 *[native.FieldLimbs]uint64) {
|
||||
Add((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2))
|
||||
}
|
||||
|
||||
// Sub performs modular subtraction
|
||||
func (f k256FpArithmetic) Sub(out, arg1, arg2 *[native.FieldLimbs]uint64) {
|
||||
Sub((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2))
|
||||
}
|
||||
|
||||
// Sqrt performs modular square root
|
||||
func (f k256FpArithmetic) Sqrt(wasSquare *int, out, arg *[native.FieldLimbs]uint64) {
|
||||
// p is congruent to 3 mod 4 we can compute
|
||||
// sqrt using elem^(p+1)/4 mod p
|
||||
// 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff0c
|
||||
var s, t [native.FieldLimbs]uint64
|
||||
params := getK256FpParams()
|
||||
native.Pow(&s, arg, &[native.FieldLimbs]uint64{
|
||||
0xffffffffbfffff0c,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0x3fffffffffffffff,
|
||||
}, params, f)
|
||||
f.Square(&t, &s)
|
||||
tv1 := &native.Field{Value: t, Params: params, Arithmetic: f}
|
||||
tv2 := &native.Field{Value: *arg, Params: params, Arithmetic: f}
|
||||
*wasSquare = tv1.Equal(tv2)
|
||||
f.Selectznz(out, out, &s, *wasSquare)
|
||||
}
|
||||
|
||||
// Invert performs modular inverse
|
||||
func (f k256FpArithmetic) Invert(wasInverted *int, out, arg *[native.FieldLimbs]uint64) {
|
||||
// The binary representation of (p - 2) has 5 groups of 1s, with lengths in
|
||||
// { 1, 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each group:
|
||||
// [1], [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]
|
||||
var s, x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223 [native.FieldLimbs]uint64
|
||||
|
||||
native.Pow2k(&x2, arg, 1, f)
|
||||
f.Mul(&x2, &x2, arg)
|
||||
|
||||
native.Pow2k(&x3, &x2, 1, f)
|
||||
f.Mul(&x3, &x3, arg)
|
||||
|
||||
native.Pow2k(&x6, &x3, 3, f)
|
||||
f.Mul(&x6, &x6, &x3)
|
||||
|
||||
native.Pow2k(&x9, &x6, 3, f)
|
||||
f.Mul(&x9, &x9, &x3)
|
||||
|
||||
native.Pow2k(&x11, &x9, 2, f)
|
||||
f.Mul(&x11, &x11, &x2)
|
||||
|
||||
native.Pow2k(&x22, &x11, 11, f)
|
||||
f.Mul(&x22, &x22, &x11)
|
||||
|
||||
native.Pow2k(&x44, &x22, 22, f)
|
||||
f.Mul(&x44, &x44, &x22)
|
||||
|
||||
native.Pow2k(&x88, &x44, 44, f)
|
||||
f.Mul(&x88, &x88, &x44)
|
||||
|
||||
native.Pow2k(&x176, &x88, 88, f)
|
||||
f.Mul(&x176, &x176, &x88)
|
||||
|
||||
native.Pow2k(&x220, &x176, 44, f)
|
||||
f.Mul(&x220, &x220, &x44)
|
||||
|
||||
native.Pow2k(&x223, &x220, 3, f)
|
||||
f.Mul(&x223, &x223, &x3)
|
||||
|
||||
// Use sliding window over the group
|
||||
native.Pow2k(&s, &x223, 23, f)
|
||||
f.Mul(&s, &s, &x22)
|
||||
native.Pow2k(&s, &s, 5, f)
|
||||
f.Mul(&s, &s, arg)
|
||||
native.Pow2k(&s, &s, 3, f)
|
||||
f.Mul(&s, &s, &x2)
|
||||
native.Pow2k(&s, &s, 2, f)
|
||||
f.Mul(&s, &s, arg)
|
||||
|
||||
tv := &native.Field{Value: *arg, Params: getK256FpParams(), Arithmetic: f}
|
||||
|
||||
*wasInverted = tv.IsNonZero()
|
||||
f.Selectznz(out, out, &s, *wasInverted)
|
||||
}
|
||||
|
||||
// FromBytes converts a little endian byte array into a field element
|
||||
func (f k256FpArithmetic) FromBytes(out *[native.FieldLimbs]uint64, arg *[native.FieldBytes]byte) {
|
||||
FromBytes(out, arg)
|
||||
}
|
||||
|
||||
// ToBytes converts a field element to a little endian byte array
|
||||
func (f k256FpArithmetic) ToBytes(out *[native.FieldBytes]byte, arg *[native.FieldLimbs]uint64) {
|
||||
ToBytes(out, arg)
|
||||
}
|
||||
|
||||
// Selectznz performs conditional select.
|
||||
// selects arg1 if choice == 0 and arg2 if choice == 1
|
||||
func (f k256FpArithmetic) Selectznz(out, arg1, arg2 *[native.FieldLimbs]uint64, choice int) {
|
||||
Selectznz(out, uint1(choice), arg1, arg2)
|
||||
}
|
@ -1,328 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package fp
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
"github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
func TestFpSetOne(t *testing.T) {
|
||||
fp := K256FpNew().SetOne()
|
||||
require.NotNil(t, fp)
|
||||
require.Equal(t, fp.Value, getK256FpParams().R)
|
||||
}
|
||||
|
||||
func TestFpSetUint64(t *testing.T) {
|
||||
act := K256FpNew().SetUint64(1 << 60)
|
||||
require.NotNil(t, act)
|
||||
// Remember it will be in montgomery form
|
||||
require.Equal(t, act.Value[0], uint64(0x1000000000000000))
|
||||
}
|
||||
|
||||
func TestFpAdd(t *testing.T) {
|
||||
lhs := K256FpNew().SetOne()
|
||||
rhs := K256FpNew().SetOne()
|
||||
exp := K256FpNew().SetUint64(2)
|
||||
res := K256FpNew().Add(lhs, rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, res.Equal(exp), 1)
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint64() >> 2
|
||||
r := rand.Uint64() >> 2
|
||||
e := l + r
|
||||
lhs.SetUint64(l)
|
||||
rhs.SetUint64(r)
|
||||
exp.SetUint64(e)
|
||||
|
||||
a := K256FpNew().Add(lhs, rhs)
|
||||
require.NotNil(t, a)
|
||||
require.Equal(t, exp, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpSub(t *testing.T) {
|
||||
lhs := K256FpNew().SetOne()
|
||||
rhs := K256FpNew().SetOne()
|
||||
exp := K256FpNew().SetZero()
|
||||
res := K256FpNew().Sub(lhs, rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, 1, res.Equal(exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint64() >> 2
|
||||
r := rand.Uint64() >> 2
|
||||
if l < r {
|
||||
l, r = r, l
|
||||
}
|
||||
e := l - r
|
||||
lhs.SetUint64(l)
|
||||
rhs.SetUint64(r)
|
||||
exp.SetUint64(e)
|
||||
|
||||
a := K256FpNew().Sub(lhs, rhs)
|
||||
require.NotNil(t, a)
|
||||
require.Equal(t, exp, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpMul(t *testing.T) {
|
||||
lhs := K256FpNew().SetOne()
|
||||
rhs := K256FpNew().SetOne()
|
||||
exp := K256FpNew().SetOne()
|
||||
res := K256FpNew().Mul(lhs, rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, 1, res.Equal(exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint32()
|
||||
r := rand.Uint32()
|
||||
e := uint64(l) * uint64(r)
|
||||
lhs.SetUint64(uint64(l))
|
||||
rhs.SetUint64(uint64(r))
|
||||
exp.SetUint64(e)
|
||||
|
||||
a := K256FpNew().Mul(lhs, rhs)
|
||||
require.NotNil(t, a)
|
||||
require.Equal(t, exp, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpDouble(t *testing.T) {
|
||||
a := K256FpNew().SetUint64(2)
|
||||
e := K256FpNew().SetUint64(4)
|
||||
require.Equal(t, e, K256FpNew().Double(a))
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
tv := rand.Uint32()
|
||||
ttv := uint64(tv) * 2
|
||||
a = K256FpNew().SetUint64(uint64(tv))
|
||||
e = K256FpNew().SetUint64(ttv)
|
||||
require.Equal(t, e, K256FpNew().Double(a))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpSquare(t *testing.T) {
|
||||
a := K256FpNew().SetUint64(4)
|
||||
e := K256FpNew().SetUint64(16)
|
||||
require.Equal(t, e, a.Square(a))
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
j := rand.Uint32()
|
||||
exp := uint64(j) * uint64(j)
|
||||
e.SetUint64(exp)
|
||||
a.SetUint64(uint64(j))
|
||||
require.Equal(t, e, a.Square(a))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpNeg(t *testing.T) {
|
||||
a := K256FpNew().SetOne()
|
||||
a.Neg(a)
|
||||
e := K256FpNew().SetRaw(&[native.FieldLimbs]uint64{0xfffffffdfffff85e, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff})
|
||||
require.Equal(t, e, a)
|
||||
}
|
||||
|
||||
func TestFpExp(t *testing.T) {
|
||||
e := K256FpNew().SetUint64(8)
|
||||
a := K256FpNew().SetUint64(2)
|
||||
by := K256FpNew().SetUint64(3)
|
||||
require.Equal(t, e, a.Exp(a, by))
|
||||
}
|
||||
|
||||
func TestFpSqrt(t *testing.T) {
|
||||
t1 := K256FpNew().SetUint64(2)
|
||||
t2 := K256FpNew().Neg(t1)
|
||||
t3 := K256FpNew().Square(t1)
|
||||
_, wasSquare := t3.Sqrt(t3)
|
||||
require.True(t, wasSquare)
|
||||
require.Equal(t, 1, t1.Equal(t3)|t2.Equal(t3))
|
||||
t1.SetUint64(5)
|
||||
_, wasSquare = K256FpNew().Sqrt(t1)
|
||||
require.False(t, wasSquare)
|
||||
}
|
||||
|
||||
func TestFpInvert(t *testing.T) {
|
||||
twoInv := K256FpNew().SetLimbs(&[native.FieldLimbs]uint64{
|
||||
0xffffffff7ffffe18,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0x7fffffffffffffff,
|
||||
})
|
||||
two := K256FpNew().SetUint64(2)
|
||||
a, inverted := K256FpNew().Invert(two)
|
||||
require.True(t, inverted)
|
||||
require.Equal(t, a, twoInv)
|
||||
|
||||
seven := K256FpNew().SetUint64(7)
|
||||
sevenInv := K256FpNew().SetRaw(&[native.FieldLimbs]uint64{0xdb6db6dab6db6afd, 0x6db6db6db6db6db6, 0xb6db6db6db6db6db, 0xdb6db6db6db6db6d})
|
||||
a, inverted = K256FpNew().Invert(seven)
|
||||
require.True(t, inverted)
|
||||
require.Equal(t, a, sevenInv)
|
||||
|
||||
lhs := K256FpNew().SetUint64(9)
|
||||
rhs := K256FpNew().SetUint64(3)
|
||||
rhsInv, inverted := K256FpNew().Invert(rhs)
|
||||
require.True(t, inverted)
|
||||
require.Equal(t, rhs, K256FpNew().Mul(lhs, rhsInv))
|
||||
|
||||
rhs.SetZero()
|
||||
_, inverted = K256FpNew().Invert(rhs)
|
||||
require.False(t, inverted)
|
||||
}
|
||||
|
||||
func TestFpCMove(t *testing.T) {
|
||||
t1 := K256FpNew().SetUint64(5)
|
||||
t2 := K256FpNew().SetUint64(10)
|
||||
require.Equal(t, t1, K256FpNew().CMove(t1, t2, 0))
|
||||
require.Equal(t, t2, K256FpNew().CMove(t1, t2, 1))
|
||||
}
|
||||
|
||||
func TestFpBytes(t *testing.T) {
|
||||
t1 := K256FpNew().SetUint64(99)
|
||||
seq := t1.Bytes()
|
||||
t2, err := K256FpNew().SetBytes(&seq)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, t1, t2)
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
t1.SetUint64(rand.Uint64())
|
||||
seq = t1.Bytes()
|
||||
_, err = t2.SetBytes(&seq)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, t1, t2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpCmp(t *testing.T) {
|
||||
tests := []struct {
|
||||
a *native.Field
|
||||
b *native.Field
|
||||
e int
|
||||
}{
|
||||
{
|
||||
a: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{2731658267414164836, 14655288906067898431, 6537465423330262322, 8306191141697566219}),
|
||||
b: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{6472764012681988529, 10848812988401906064, 2961825807536828898, 4282183981941645679}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{8023004109510539223, 4652004072850285717, 1877219145646046927, 383214385093921911}),
|
||||
b: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{10099384440823804262, 16139476942229308465, 8636966320777393798, 5435928725024696785}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{3741840066202388211, 12165774400417314871, 16619312580230515379, 16195032234110087705}),
|
||||
b: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{3905865991286066744, 543690822309071825, 17963103015950210055, 3745476720756119742}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{16660853697936147788, 7799793619412111108, 13515141085171033220, 2641079731236069032}),
|
||||
b: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{17790588295388238399, 571847801379669440, 14537208974498222469, 12792570372087452754}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{3912839285384959186, 2701177075110484070, 6453856448115499033, 6475797457962597458}),
|
||||
b: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{1282566391665688512, 13503640416992806563, 2962240104675990153, 3374904770947067689}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{5716631803409360103, 7859567470082614154, 12747956220853330146, 18434584096087315020}),
|
||||
b: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{16317076441459028418, 12854146980376319601, 2258436689269031143, 9531877130792223752}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{17955191469941083403, 10350326247207200880, 17263512235150705075, 12700328451238078022}),
|
||||
b: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{6767595547459644695, 7146403825494928147, 12269344038346710612, 9122477829383225603}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{17099388671847024438, 6426264987820696548, 10641143464957227405, 7709745403700754098}),
|
||||
b: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{10799154372990268556, 17178492485719929374, 5705777922258988797, 8051037767683567782}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{4567139260680454325, 1629385880182139061, 16607020832317899145, 1261011562621553200}),
|
||||
b: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{13487234491304534488, 17872642955936089265, 17651026784972590233, 9468934643333871559}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{18071070103467571798, 11787850505799426140, 10631355976141928593, 4867785203635092610}),
|
||||
b: K256FpNew().SetRaw(&[native.FieldLimbs]uint64{12596443599426461624, 10176122686151524591, 17075755296887483439, 6726169532695070719}),
|
||||
e: -1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
require.Equal(t, test.e, test.a.Cmp(test.b))
|
||||
require.Equal(t, -test.e, test.b.Cmp(test.a))
|
||||
require.Equal(t, 0, test.a.Cmp(test.a))
|
||||
require.Equal(t, 0, test.b.Cmp(test.b))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpBigInt(t *testing.T) {
|
||||
t1 := K256FpNew().SetBigInt(big.NewInt(9999))
|
||||
t2 := K256FpNew().SetBigInt(t1.BigInt())
|
||||
require.Equal(t, t1, t2)
|
||||
|
||||
e := K256FpNew().SetRaw(&[native.FieldLimbs]uint64{0xc6c6c6c63939371d, 0xc6c6c6c6c6c6c6c6, 0x8d8d8dd28485081d, 0x8484848484848484})
|
||||
b := new(big.Int).SetBytes([]byte{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9})
|
||||
t1.SetBigInt(b)
|
||||
require.Equal(t, e, t1)
|
||||
e.Value[0] = 0x39393938c6c6c512
|
||||
e.Value[1] = 0x3939393939393939
|
||||
e.Value[2] = 0x7272722d7b7af7e2
|
||||
e.Value[3] = 0x7b7b7b7b7b7b7b7b
|
||||
b.Neg(b)
|
||||
t1.SetBigInt(b)
|
||||
require.Equal(t, e, t1)
|
||||
}
|
||||
|
||||
func TestFpSetBytesWide(t *testing.T) {
|
||||
e := K256FpNew().SetRaw(&[native.FieldLimbs]uint64{0x6aa784623e2d641e, 0x7c40617d755bae27, 0x206b7be66ed7b71b, 0x6d1e4fc581e19dc2})
|
||||
|
||||
a := K256FpNew().SetBytesWide(&[64]byte{
|
||||
0x69, 0x23, 0x5a, 0x0b, 0xce, 0x0c, 0xa8, 0x64,
|
||||
0x3c, 0x78, 0xbc, 0x01, 0x05, 0xef, 0xf2, 0x84,
|
||||
0xde, 0xbb, 0x6b, 0xc8, 0x63, 0x5e, 0x6e, 0x69,
|
||||
0x62, 0xcc, 0xc6, 0x2d, 0xf5, 0x72, 0x40, 0x92,
|
||||
0x28, 0x11, 0xd6, 0xc8, 0x07, 0xa5, 0x88, 0x82,
|
||||
0xfe, 0xe3, 0x97, 0xf6, 0x1e, 0xfb, 0x2e, 0x3b,
|
||||
0x27, 0x5f, 0x85, 0x06, 0x8d, 0x99, 0xa4, 0x75,
|
||||
0xc0, 0x2c, 0x71, 0x69, 0x9e, 0x58, 0xea, 0x52,
|
||||
})
|
||||
require.Equal(t, e, a)
|
||||
}
|
||||
|
||||
func TestFpSetBytesWideBigInt(t *testing.T) {
|
||||
params := getK256FpParams()
|
||||
var tv2 [64]byte
|
||||
for i := 0; i < 25; i++ {
|
||||
_, _ = crand.Read(tv2[:])
|
||||
e := new(big.Int).SetBytes(tv2[:])
|
||||
e.Mod(e, params.BiModulus)
|
||||
|
||||
tv := internal.ReverseScalarBytes(tv2[:])
|
||||
copy(tv2[:], tv)
|
||||
a := K256FpNew().SetBytesWide(&tv2)
|
||||
require.Equal(t, 0, e.Cmp(a.BigInt()))
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,287 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package fq
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"sync"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
)
|
||||
|
||||
var (
|
||||
k256FqInitonce sync.Once
|
||||
k256FqParams native.FieldParams
|
||||
)
|
||||
|
||||
func K256FqNew() *native.Field {
|
||||
return &native.Field{
|
||||
Value: [native.FieldLimbs]uint64{},
|
||||
Params: getK256FqParams(),
|
||||
Arithmetic: k256FqArithmetic{},
|
||||
}
|
||||
}
|
||||
|
||||
func k256FqParamsInit() {
|
||||
k256FqParams = native.FieldParams{
|
||||
R: [native.FieldLimbs]uint64{0x402da1732fc9bebf, 0x4551231950b75fc4, 0x0000000000000001, 0x0000000000000000},
|
||||
R2: [native.FieldLimbs]uint64{0x896cf21467d7d140, 0x741496c20e7cf878, 0xe697f5e45bcd07c6, 0x9d671cd581c69bc5},
|
||||
R3: [native.FieldLimbs]uint64{0x7bc0cfe0e9ff41ed, 0x0017648444d4322c, 0xb1b31347f1d0b2da, 0x555d800c18ef116d},
|
||||
Modulus: [native.FieldLimbs]uint64{0xbfd25e8cd0364141, 0xbaaedce6af48a03b, 0xfffffffffffffffe, 0xffffffffffffffff},
|
||||
BiModulus: new(big.Int).SetBytes([]byte{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func getK256FqParams() *native.FieldParams {
|
||||
k256FqInitonce.Do(k256FqParamsInit)
|
||||
return &k256FqParams
|
||||
}
|
||||
|
||||
// k256FqArithmetic is a struct with all the methods needed for working
|
||||
// in mod q
|
||||
type k256FqArithmetic struct{}
|
||||
|
||||
// ToMontgomery converts this field to montgomery form
|
||||
func (f k256FqArithmetic) ToMontgomery(out, arg *[native.FieldLimbs]uint64) {
|
||||
ToMontgomery((*MontgomeryDomainFieldElement)(out), (*NonMontgomeryDomainFieldElement)(arg))
|
||||
}
|
||||
|
||||
// FromMontgomery converts this field from montgomery form
|
||||
func (f k256FqArithmetic) FromMontgomery(out, arg *[native.FieldLimbs]uint64) {
|
||||
FromMontgomery((*NonMontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg))
|
||||
}
|
||||
|
||||
// Neg performs modular negation
|
||||
func (f k256FqArithmetic) Neg(out, arg *[native.FieldLimbs]uint64) {
|
||||
Opp((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg))
|
||||
}
|
||||
|
||||
// Square performs modular square
|
||||
func (f k256FqArithmetic) Square(out, arg *[native.FieldLimbs]uint64) {
|
||||
Square((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg))
|
||||
}
|
||||
|
||||
// Mul performs modular multiplication
|
||||
func (f k256FqArithmetic) Mul(out, arg1, arg2 *[native.FieldLimbs]uint64) {
|
||||
Mul((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2))
|
||||
}
|
||||
|
||||
// Add performs modular addition
|
||||
func (f k256FqArithmetic) Add(out, arg1, arg2 *[native.FieldLimbs]uint64) {
|
||||
Add((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2))
|
||||
}
|
||||
|
||||
// Sub performs modular subtraction
|
||||
func (f k256FqArithmetic) Sub(out, arg1, arg2 *[native.FieldLimbs]uint64) {
|
||||
Sub((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2))
|
||||
}
|
||||
|
||||
// Sqrt performs modular square root
|
||||
func (f k256FqArithmetic) Sqrt(wasSquare *int, out, arg *[native.FieldLimbs]uint64) {
|
||||
// See sqrt_ts_ct at
|
||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-I.4
|
||||
// c1 := 6
|
||||
// c2 := (q - 1) / (2^c1)
|
||||
// c2 := [4]uint64{
|
||||
// 0xeeff497a3340d905,
|
||||
// 0xfaeabb739abd2280,
|
||||
// 0xffffffffffffffff,
|
||||
// 0x03ffffffffffffff,
|
||||
//}
|
||||
// c3 := (c2 - 1) / 2
|
||||
c3 := [native.FieldLimbs]uint64{
|
||||
0x777fa4bd19a06c82,
|
||||
0xfd755db9cd5e9140,
|
||||
0xffffffffffffffff,
|
||||
0x01ffffffffffffff,
|
||||
}
|
||||
// c4 := generator
|
||||
// c5 := new(Fq).pow(generator, c2)
|
||||
c5 := [native.FieldLimbs]uint64{0x944cf2a220910e04, 0x815c829c780589f4, 0x55980b07bc222113, 0xc702b0d248825b36}
|
||||
var z, t, b, c, tv [native.FieldLimbs]uint64
|
||||
|
||||
native.Pow(&z, arg, &c3, getK256FqParams(), f)
|
||||
Square((*MontgomeryDomainFieldElement)(&t), (*MontgomeryDomainFieldElement)(&z))
|
||||
Mul((*MontgomeryDomainFieldElement)(&t), (*MontgomeryDomainFieldElement)(&t), (*MontgomeryDomainFieldElement)(arg))
|
||||
Mul((*MontgomeryDomainFieldElement)(&z), (*MontgomeryDomainFieldElement)(&z), (*MontgomeryDomainFieldElement)(arg))
|
||||
|
||||
copy(b[:], t[:])
|
||||
copy(c[:], c5[:])
|
||||
|
||||
for i := s; i >= 2; i-- {
|
||||
for j := 1; j <= i-2; j++ {
|
||||
Square((*MontgomeryDomainFieldElement)(&b), (*MontgomeryDomainFieldElement)(&b))
|
||||
}
|
||||
// if b == 1 flag = 0 else flag = 1
|
||||
flag := -(&native.Field{
|
||||
Value: b,
|
||||
Params: getK256FqParams(),
|
||||
Arithmetic: f,
|
||||
}).IsOne() + 1
|
||||
Mul((*MontgomeryDomainFieldElement)(&tv), (*MontgomeryDomainFieldElement)(&z), (*MontgomeryDomainFieldElement)(&c))
|
||||
Selectznz(&z, uint1(flag), &z, &tv)
|
||||
Square((*MontgomeryDomainFieldElement)(&c), (*MontgomeryDomainFieldElement)(&c))
|
||||
Mul((*MontgomeryDomainFieldElement)(&tv), (*MontgomeryDomainFieldElement)(&t), (*MontgomeryDomainFieldElement)(&c))
|
||||
Selectznz(&t, uint1(flag), &t, &tv)
|
||||
copy(b[:], t[:])
|
||||
}
|
||||
Square((*MontgomeryDomainFieldElement)(&c), (*MontgomeryDomainFieldElement)(&z))
|
||||
*wasSquare = (&native.Field{
|
||||
Value: c,
|
||||
Params: getK256FqParams(),
|
||||
Arithmetic: f,
|
||||
}).Equal(&native.Field{
|
||||
Value: *arg,
|
||||
Params: getK256FqParams(),
|
||||
Arithmetic: f,
|
||||
})
|
||||
Selectznz(out, uint1(*wasSquare), out, &z)
|
||||
}
|
||||
|
||||
// Invert performs modular inverse
|
||||
func (f k256FqArithmetic) Invert(wasInverted *int, out, arg *[native.FieldLimbs]uint64) {
|
||||
// Using an addition chain from
|
||||
// https://briansmith.org/ecc-inversion-addition-chains-01#secp256k1_scalar_inversion
|
||||
var x1, x10, x11, x101, x111, x1001, x1011, x1101 [native.FieldLimbs]uint64
|
||||
var x6, x8, x14, x28, x56, tmp [native.FieldLimbs]uint64
|
||||
|
||||
copy(x1[:], arg[:])
|
||||
native.Pow2k(&x10, arg, 1, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&x11), (*MontgomeryDomainFieldElement)(&x10), (*MontgomeryDomainFieldElement)(&x1))
|
||||
Mul((*MontgomeryDomainFieldElement)(&x101), (*MontgomeryDomainFieldElement)(&x10), (*MontgomeryDomainFieldElement)(&x11))
|
||||
Mul((*MontgomeryDomainFieldElement)(&x111), (*MontgomeryDomainFieldElement)(&x10), (*MontgomeryDomainFieldElement)(&x101))
|
||||
Mul((*MontgomeryDomainFieldElement)(&x1001), (*MontgomeryDomainFieldElement)(&x10), (*MontgomeryDomainFieldElement)(&x111))
|
||||
Mul((*MontgomeryDomainFieldElement)(&x1011), (*MontgomeryDomainFieldElement)(&x10), (*MontgomeryDomainFieldElement)(&x1001))
|
||||
Mul((*MontgomeryDomainFieldElement)(&x1101), (*MontgomeryDomainFieldElement)(&x10), (*MontgomeryDomainFieldElement)(&x1011))
|
||||
|
||||
native.Pow2k(&x6, &x1101, 2, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&x6), (*MontgomeryDomainFieldElement)(&x6), (*MontgomeryDomainFieldElement)(&x1011))
|
||||
|
||||
native.Pow2k(&x8, &x6, 2, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&x8), (*MontgomeryDomainFieldElement)(&x8), (*MontgomeryDomainFieldElement)(&x11))
|
||||
|
||||
native.Pow2k(&x14, &x8, 6, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&x14), (*MontgomeryDomainFieldElement)(&x14), (*MontgomeryDomainFieldElement)(&x6))
|
||||
|
||||
native.Pow2k(&x28, &x14, 14, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&x28), (*MontgomeryDomainFieldElement)(&x28), (*MontgomeryDomainFieldElement)(&x14))
|
||||
|
||||
native.Pow2k(&x56, &x28, 28, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&x56), (*MontgomeryDomainFieldElement)(&x56), (*MontgomeryDomainFieldElement)(&x28))
|
||||
|
||||
native.Pow2k(&tmp, &x56, 56, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x56))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 14, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x14))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 3, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 4, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 4, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 5, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1011))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 4, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1011))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 4, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 5, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 6, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1101))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 4, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 3, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 5, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1001))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 6, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 10, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 4, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 9, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x8))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 5, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1001))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 6, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1011))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 4, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1101))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 5, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x11))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 6, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1101))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 10, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1101))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 4, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1001))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 6, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 8, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x6))
|
||||
|
||||
*wasInverted = (&native.Field{
|
||||
Value: *arg,
|
||||
Params: getK256FqParams(),
|
||||
Arithmetic: f,
|
||||
}).IsNonZero()
|
||||
Selectznz(out, uint1(*wasInverted), out, &tmp)
|
||||
}
|
||||
|
||||
// FromBytes converts a little endian byte array into a field element
|
||||
func (f k256FqArithmetic) FromBytes(out *[native.FieldLimbs]uint64, arg *[native.FieldBytes]byte) {
|
||||
FromBytes(out, arg)
|
||||
}
|
||||
|
||||
// ToBytes converts a field element to a little endian byte array
|
||||
func (f k256FqArithmetic) ToBytes(out *[native.FieldBytes]byte, arg *[native.FieldLimbs]uint64) {
|
||||
ToBytes(out, arg)
|
||||
}
|
||||
|
||||
// Selectznz performs conditional select.
|
||||
// selects arg1 if choice == 0 and arg2 if choice == 1
|
||||
func (f k256FqArithmetic) Selectznz(out, arg1, arg2 *[native.FieldLimbs]uint64, choice int) {
|
||||
Selectznz(out, uint1(choice), arg1, arg2)
|
||||
}
|
||||
|
||||
// generator = 7 mod q is a generator of the `q - 1` order multiplicative
|
||||
// subgroup, or in other words a primitive element of the field.
|
||||
// generator^t where t * 2^s + 1 = q
|
||||
var generator = &[native.FieldLimbs]uint64{0xc13f6a264e843739, 0xe537f5b135039e5d, 0x0000000000000008, 0x0000000000000000}
|
||||
|
||||
// s satisfies the equation 2^s * t = q - 1 with t odd.
|
||||
var s = 6
|
@ -1,328 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package fq
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
"github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
func TestFqSetOne(t *testing.T) {
|
||||
fq := K256FqNew().SetOne()
|
||||
require.NotNil(t, fq)
|
||||
require.Equal(t, fq.Value, getK256FqParams().R)
|
||||
}
|
||||
|
||||
func TestFqSetUint64(t *testing.T) {
|
||||
act := K256FqNew().SetUint64(1 << 60)
|
||||
require.NotNil(t, act)
|
||||
// Remember it will be in montgomery form
|
||||
require.Equal(t, act.Value[0], uint64(0xF000000000000000))
|
||||
}
|
||||
|
||||
func TestFqAdd(t *testing.T) {
|
||||
lhs := K256FqNew().SetOne()
|
||||
rhs := K256FqNew().SetOne()
|
||||
exp := K256FqNew().SetUint64(2)
|
||||
res := K256FqNew().Add(lhs, rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, 1, res.Equal(exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint64() >> 2
|
||||
r := rand.Uint64() >> 2
|
||||
e := l + r
|
||||
lhs.SetUint64(l)
|
||||
rhs.SetUint64(r)
|
||||
exp.SetUint64(e)
|
||||
|
||||
a := K256FqNew().Add(lhs, rhs)
|
||||
require.NotNil(t, a)
|
||||
require.Equal(t, exp, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqSub(t *testing.T) {
|
||||
lhs := K256FqNew().SetOne()
|
||||
rhs := K256FqNew().SetOne()
|
||||
exp := K256FqNew().SetZero()
|
||||
res := K256FqNew().Sub(lhs, rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, 1, res.Equal(exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint64() >> 2
|
||||
r := rand.Uint64() >> 2
|
||||
if l < r {
|
||||
l, r = r, l
|
||||
}
|
||||
e := l - r
|
||||
lhs.SetUint64(l)
|
||||
rhs.SetUint64(r)
|
||||
exp.SetUint64(e)
|
||||
|
||||
a := K256FqNew().Sub(lhs, rhs)
|
||||
require.NotNil(t, a)
|
||||
require.Equal(t, exp, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqMul(t *testing.T) {
|
||||
lhs := K256FqNew().SetOne()
|
||||
rhs := K256FqNew().SetOne()
|
||||
exp := K256FqNew().SetOne()
|
||||
res := K256FqNew().Mul(lhs, rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, 1, res.Equal(exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint32()
|
||||
r := rand.Uint32()
|
||||
e := uint64(l) * uint64(r)
|
||||
lhs.SetUint64(uint64(l))
|
||||
rhs.SetUint64(uint64(r))
|
||||
exp.SetUint64(e)
|
||||
|
||||
a := K256FqNew().Mul(lhs, rhs)
|
||||
require.NotNil(t, a)
|
||||
require.Equal(t, exp, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqDouble(t *testing.T) {
|
||||
a := K256FqNew().SetUint64(2)
|
||||
e := K256FqNew().SetUint64(4)
|
||||
require.Equal(t, e, K256FqNew().Double(a))
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
tv := rand.Uint32()
|
||||
ttv := uint64(tv) * 2
|
||||
a = K256FqNew().SetUint64(uint64(tv))
|
||||
e = K256FqNew().SetUint64(ttv)
|
||||
require.Equal(t, e, K256FqNew().Double(a))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqSquare(t *testing.T) {
|
||||
a := K256FqNew().SetUint64(4)
|
||||
e := K256FqNew().SetUint64(16)
|
||||
require.Equal(t, e, a.Square(a))
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
j := rand.Uint32()
|
||||
exp := uint64(j) * uint64(j)
|
||||
e.SetUint64(exp)
|
||||
a.SetUint64(uint64(j))
|
||||
require.Equal(t, e, a.Square(a))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqNeg(t *testing.T) {
|
||||
g := K256FqNew().SetRaw(generator)
|
||||
a := K256FqNew().SetOne()
|
||||
a.Neg(a)
|
||||
e := K256FqNew().SetRaw(&[native.FieldLimbs]uint64{0x7fa4bd19a06c8282, 0x755db9cd5e914077, 0xfffffffffffffffd, 0xffffffffffffffff})
|
||||
require.Equal(t, e, a)
|
||||
a.Neg(g)
|
||||
e = K256FqNew().SetRaw(&[native.FieldLimbs]uint64{0xfe92f46681b20a08, 0xd576e7357a4501dd, 0xfffffffffffffff5, 0xffffffffffffffff})
|
||||
require.Equal(t, e, a)
|
||||
}
|
||||
|
||||
func TestFqExp(t *testing.T) {
|
||||
e := K256FqNew().SetUint64(8)
|
||||
a := K256FqNew().SetUint64(2)
|
||||
by := K256FqNew().SetUint64(3)
|
||||
require.Equal(t, e, a.Exp(a, by))
|
||||
}
|
||||
|
||||
func TestFqSqrt(t *testing.T) {
|
||||
t1 := K256FqNew().SetUint64(2)
|
||||
t2 := K256FqNew().Neg(t1)
|
||||
t3 := K256FqNew().Square(t1)
|
||||
_, wasSquare := t3.Sqrt(t3)
|
||||
|
||||
require.True(t, wasSquare)
|
||||
require.Equal(t, 1, t1.Equal(t3)|t2.Equal(t3))
|
||||
t1.SetUint64(5)
|
||||
_, wasSquare = K256FqNew().Sqrt(t1)
|
||||
require.False(t, wasSquare)
|
||||
}
|
||||
|
||||
func TestFqInvert(t *testing.T) {
|
||||
twoInv := K256FqNew().SetLimbs(&[native.FieldLimbs]uint64{0xdfe92f46681b20a1, 0x5d576e7357a4501d, 0xffffffffffffffff, 0x7fffffffffffffff})
|
||||
two := K256FqNew().SetUint64(2)
|
||||
a, inverted := K256FqNew().Invert(two)
|
||||
require.True(t, inverted)
|
||||
require.Equal(t, a, twoInv)
|
||||
|
||||
rootOfUnity := K256FqNew().SetLimbs(&[native.FieldLimbs]uint64{0x8619a9e760c01d0c, 0xa883c4fba37998df, 0x45607580b6eabd98, 0xf252b002544b2f99})
|
||||
rootOfUnityInv := K256FqNew().SetRaw(&[native.FieldLimbs]uint64{0x7d99f8e21447e314, 0x5b60c477e7728d4c, 0xd78befc191f58654, 0x6897e5ff7824360f})
|
||||
a, inverted = K256FqNew().Invert(rootOfUnity)
|
||||
require.True(t, inverted)
|
||||
require.Equal(t, a, rootOfUnityInv)
|
||||
|
||||
lhs := K256FqNew().SetUint64(9)
|
||||
rhs := K256FqNew().SetUint64(3)
|
||||
rhsInv, inverted := K256FqNew().Invert(rhs)
|
||||
require.True(t, inverted)
|
||||
require.Equal(t, rhs, K256FqNew().Mul(lhs, rhsInv))
|
||||
|
||||
rhs.SetZero()
|
||||
_, inverted = K256FqNew().Invert(rhs)
|
||||
require.False(t, inverted)
|
||||
}
|
||||
|
||||
func TestFqCMove(t *testing.T) {
|
||||
t1 := K256FqNew().SetUint64(5)
|
||||
t2 := K256FqNew().SetUint64(10)
|
||||
require.Equal(t, t1, K256FqNew().CMove(t1, t2, 0))
|
||||
require.Equal(t, t2, K256FqNew().CMove(t1, t2, 1))
|
||||
}
|
||||
|
||||
func TestFqBytes(t *testing.T) {
|
||||
t1 := K256FqNew().SetUint64(99)
|
||||
seq := t1.Bytes()
|
||||
t2, err := K256FqNew().SetBytes(&seq)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, t1, t2)
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
t1.SetUint64(rand.Uint64())
|
||||
seq = t1.Bytes()
|
||||
_, err = t2.SetBytes(&seq)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, t1, t2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqCmp(t *testing.T) {
|
||||
tests := []struct {
|
||||
a *native.Field
|
||||
b *native.Field
|
||||
e int
|
||||
}{
|
||||
{
|
||||
a: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{2731658267414164836, 14655288906067898431, 6537465423330262322, 8306191141697566219}),
|
||||
b: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{6472764012681988529, 10848812988401906064, 2961825807536828898, 4282183981941645679}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{8023004109510539223, 4652004072850285717, 1877219145646046927, 383214385093921911}),
|
||||
b: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{10099384440823804262, 16139476942229308465, 8636966320777393798, 5435928725024696785}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{3741840066202388211, 12165774400417314871, 16619312580230515379, 16195032234110087705}),
|
||||
b: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{3905865991286066744, 543690822309071825, 17963103015950210055, 3745476720756119742}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{16660853697936147788, 7799793619412111108, 13515141085171033220, 2641079731236069032}),
|
||||
b: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{17790588295388238399, 571847801379669440, 14537208974498222469, 12792570372087452754}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{3912839285384959186, 2701177075110484070, 6453856448115499033, 6475797457962597458}),
|
||||
b: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{1282566391665688512, 13503640416992806563, 2962240104675990153, 3374904770947067689}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{5716631803409360103, 7859567470082614154, 12747956220853330146, 18434584096087315020}),
|
||||
b: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{16317076441459028418, 12854146980376319601, 2258436689269031143, 9531877130792223752}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{17955191469941083403, 10350326247207200880, 17263512235150705075, 12700328451238078022}),
|
||||
b: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{6767595547459644695, 7146403825494928147, 12269344038346710612, 9122477829383225603}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{17099388671847024438, 6426264987820696548, 10641143464957227405, 7709745403700754098}),
|
||||
b: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{10799154372990268556, 17178492485719929374, 5705777922258988797, 8051037767683567782}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{4567139260680454325, 1629385880182139061, 16607020832317899145, 1261011562621553200}),
|
||||
b: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{13487234491304534488, 17872642955936089265, 17651026784972590233, 9468934643333871559}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{18071070103467571798, 11787850505799426140, 10631355976141928593, 4867785203635092610}),
|
||||
b: K256FqNew().SetRaw(&[native.FieldLimbs]uint64{12596443599426461624, 10176122686151524591, 17075755296887483439, 6726169532695070719}),
|
||||
e: -1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
require.Equal(t, test.e, test.a.Cmp(test.b))
|
||||
require.Equal(t, -test.e, test.b.Cmp(test.a))
|
||||
require.Equal(t, 0, test.a.Cmp(test.a))
|
||||
require.Equal(t, 0, test.b.Cmp(test.b))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqBigInt(t *testing.T) {
|
||||
t1 := K256FqNew().SetBigInt(big.NewInt(9999))
|
||||
t2 := K256FqNew().SetBigInt(t1.BigInt())
|
||||
require.Equal(t, t1, t2)
|
||||
|
||||
e := K256FqNew().SetRaw(&[native.FieldLimbs]uint64{0xa764d3f6f152f222, 0x3b5dc8aacb9297b7, 0xb015fa9d2b3efdc6, 0x567360cef000f24a})
|
||||
b := new(big.Int).SetBytes([]byte{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9})
|
||||
t1.SetBigInt(b)
|
||||
require.Equal(t, e, t1)
|
||||
e.Value[0] = 0x186d8a95dee34f1f
|
||||
e.Value[1] = 0x7f51143be3b60884
|
||||
e.Value[2] = 0x4fea0562d4c10238
|
||||
e.Value[3] = 0xa98c9f310fff0db5
|
||||
b.Neg(b)
|
||||
t1.SetBigInt(b)
|
||||
require.Equal(t, e, t1)
|
||||
}
|
||||
|
||||
func TestFqSetBytesWide(t *testing.T) {
|
||||
e := K256FqNew().SetRaw(&[native.FieldLimbs]uint64{0x70620a92b4f2eb7a, 0xd04588eb9c228a3a, 0xccb71ae40a10491c, 0x61cf39d70a8b33b7})
|
||||
|
||||
a := K256FqNew().SetBytesWide(&[64]byte{
|
||||
0x69, 0x23, 0x5a, 0x0b, 0xce, 0x0c, 0xa8, 0x64,
|
||||
0x3c, 0x78, 0xbc, 0x01, 0x05, 0xef, 0xf2, 0x84,
|
||||
0xde, 0xbb, 0x6b, 0xc8, 0x63, 0x5e, 0x6e, 0x69,
|
||||
0x62, 0xcc, 0xc6, 0x2d, 0xf5, 0x72, 0x40, 0x92,
|
||||
0x28, 0x11, 0xd6, 0xc8, 0x07, 0xa5, 0x88, 0x82,
|
||||
0xfe, 0xe3, 0x97, 0xf6, 0x1e, 0xfb, 0x2e, 0x3b,
|
||||
0x27, 0x5f, 0x85, 0x06, 0x8d, 0x99, 0xa4, 0x75,
|
||||
0xc0, 0x2c, 0x71, 0x69, 0x9e, 0x58, 0xea, 0x52,
|
||||
})
|
||||
require.Equal(t, e, a)
|
||||
}
|
||||
|
||||
func TestFpSetBytesWideBigInt(t *testing.T) {
|
||||
params := getK256FqParams()
|
||||
var tv2 [64]byte
|
||||
for i := 0; i < 25; i++ {
|
||||
_, _ = crand.Read(tv2[:])
|
||||
e := new(big.Int).SetBytes(tv2[:])
|
||||
e.Mod(e, params.BiModulus)
|
||||
|
||||
tv := internal.ReverseScalarBytes(tv2[:])
|
||||
copy(tv2[:], tv)
|
||||
a := K256FqNew().SetBytesWide(&tv2)
|
||||
require.Equal(t, 0, e.Cmp(a.BigInt()))
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,446 +0,0 @@
|
||||
package k256
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
"github.com/onsonr/hway/crypto/core/curves/native/k256/fp"
|
||||
"github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
var (
|
||||
k256PointInitonce sync.Once
|
||||
k256PointParams native.EllipticPointParams
|
||||
k256PointSswuInitOnce sync.Once
|
||||
k256PointSswuParams native.SswuParams
|
||||
k256PointIsogenyInitOnce sync.Once
|
||||
k256PointIsogenyParams native.IsogenyParams
|
||||
)
|
||||
|
||||
func K256PointNew() *native.EllipticPoint {
|
||||
return &native.EllipticPoint{
|
||||
X: fp.K256FpNew(),
|
||||
Y: fp.K256FpNew(),
|
||||
Z: fp.K256FpNew(),
|
||||
Params: getK256PointParams(),
|
||||
Arithmetic: &k256PointArithmetic{},
|
||||
}
|
||||
}
|
||||
|
||||
func k256PointParamsInit() {
|
||||
k256PointParams = native.EllipticPointParams{
|
||||
A: fp.K256FpNew(),
|
||||
B: fp.K256FpNew().SetUint64(7),
|
||||
Gx: fp.K256FpNew().SetLimbs(&[native.FieldLimbs]uint64{
|
||||
0x59f2815b16f81798,
|
||||
0x029bfcdb2dce28d9,
|
||||
0x55a06295ce870b07,
|
||||
0x79be667ef9dcbbac,
|
||||
}),
|
||||
Gy: fp.K256FpNew().SetLimbs(&[native.FieldLimbs]uint64{
|
||||
0x9c47d08ffb10d4b8,
|
||||
0xfd17b448a6855419,
|
||||
0x5da4fbfc0e1108a8,
|
||||
0x483ada7726a3c465,
|
||||
}),
|
||||
BitSize: 256,
|
||||
Name: "secp256k1",
|
||||
}
|
||||
}
|
||||
|
||||
func getK256PointParams() *native.EllipticPointParams {
|
||||
k256PointInitonce.Do(k256PointParamsInit)
|
||||
return &k256PointParams
|
||||
}
|
||||
|
||||
func getK256PointSswuParams() *native.SswuParams {
|
||||
k256PointSswuInitOnce.Do(k256PointSswuParamsInit)
|
||||
return &k256PointSswuParams
|
||||
}
|
||||
|
||||
func k256PointSswuParamsInit() {
|
||||
// Taken from https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-8.7
|
||||
//params := btcec.S256().Params()
|
||||
//
|
||||
//// c1 = (q - 3) / 4
|
||||
//c1 := new(big.Int).Set(params.P)
|
||||
//c1.Sub(c1, big.NewInt(3))
|
||||
//c1.Rsh(c1, 2)
|
||||
//
|
||||
//a, _ := new(big.Int).SetString("3f8731abdd661adca08a5558f0f5d272e953d363cb6f0e5d405447c01a444533", 16)
|
||||
//b := big.NewInt(1771)
|
||||
//z := big.NewInt(-11)
|
||||
//z.Mod(z, params.P)
|
||||
//// sqrt(-z^3)
|
||||
//zTmp := new(big.Int).Exp(z, big.NewInt(3), nil)
|
||||
//zTmp = zTmp.Neg(zTmp)
|
||||
//zTmp.Mod(zTmp, params.P)
|
||||
//c2 := new(big.Int).ModSqrt(zTmp, params.P)
|
||||
//
|
||||
//var tBytes [32]byte
|
||||
//c1.FillBytes(tBytes[:])
|
||||
//newC1 := [native.FieldLimbs]uint64{
|
||||
// binary.BigEndian.Uint64(tBytes[24:32]),
|
||||
// binary.BigEndian.Uint64(tBytes[16:24]),
|
||||
// binary.BigEndian.Uint64(tBytes[8:16]),
|
||||
// binary.BigEndian.Uint64(tBytes[:8]),
|
||||
//}
|
||||
//fp.K256FpNew().Arithmetic.ToMontgomery(&newC1, &newC1)
|
||||
//c2.FillBytes(tBytes[:])
|
||||
//newC2 := [native.FieldLimbs]uint64{
|
||||
// binary.BigEndian.Uint64(tBytes[24:32]),
|
||||
// binary.BigEndian.Uint64(tBytes[16:24]),
|
||||
// binary.BigEndian.Uint64(tBytes[8:16]),
|
||||
// binary.BigEndian.Uint64(tBytes[:8]),
|
||||
//}
|
||||
//fp.K256FpNew().Arithmetic.ToMontgomery(&newC2, &newC2)
|
||||
//a.FillBytes(tBytes[:])
|
||||
//newA := [native.FieldLimbs]uint64{
|
||||
// binary.BigEndian.Uint64(tBytes[24:32]),
|
||||
// binary.BigEndian.Uint64(tBytes[16:24]),
|
||||
// binary.BigEndian.Uint64(tBytes[8:16]),
|
||||
// binary.BigEndian.Uint64(tBytes[:8]),
|
||||
//}
|
||||
//fp.K256FpNew().Arithmetic.ToMontgomery(&newA, &newA)
|
||||
//b.FillBytes(tBytes[:])
|
||||
//newB := [native.FieldLimbs]uint64{
|
||||
// binary.BigEndian.Uint64(tBytes[24:32]),
|
||||
// binary.BigEndian.Uint64(tBytes[16:24]),
|
||||
// binary.BigEndian.Uint64(tBytes[8:16]),
|
||||
// binary.BigEndian.Uint64(tBytes[:8]),
|
||||
//}
|
||||
//fp.K256FpNew().Arithmetic.ToMontgomery(&newB, &newB)
|
||||
//z.FillBytes(tBytes[:])
|
||||
//newZ := [native.FieldLimbs]uint64{
|
||||
// binary.BigEndian.Uint64(tBytes[24:32]),
|
||||
// binary.BigEndian.Uint64(tBytes[16:24]),
|
||||
// binary.BigEndian.Uint64(tBytes[8:16]),
|
||||
// binary.BigEndian.Uint64(tBytes[:8]),
|
||||
//}
|
||||
//fp.K256FpNew().Arithmetic.ToMontgomery(&newZ, &newZ)
|
||||
|
||||
k256PointSswuParams = native.SswuParams{
|
||||
// (q -3) // 4
|
||||
C1: [native.FieldLimbs]uint64{0xffffffffbfffff0b, 0xffffffffffffffff, 0xffffffffffffffff, 0x3fffffffffffffff},
|
||||
// sqrt(-z^3)
|
||||
C2: [native.FieldLimbs]uint64{0x5b57ba53a30d1520, 0x908f7cef34a762eb, 0x190b0ffe068460c8, 0x98a9828e8f00ff62},
|
||||
// 0x3f8731abdd661adca08a5558f0f5d272e953d363cb6f0e5d405447c01a444533
|
||||
A: [native.FieldLimbs]uint64{0xdb714ce7b18444a1, 0x4458ce38a32a19a2, 0xa0e58ae2837bfbf0, 0x505aabc49336d959},
|
||||
// 1771
|
||||
B: [native.FieldLimbs]uint64{0x000006eb001a66db, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
|
||||
// -11
|
||||
Z: [native.FieldLimbs]uint64{0xfffffff3ffffd234, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff},
|
||||
}
|
||||
}
|
||||
|
||||
func k256PointIsogenyInit() {
|
||||
k256PointIsogenyParams = native.IsogenyParams{
|
||||
XNum: [][native.FieldLimbs]uint64{
|
||||
{
|
||||
0x0000003b1c72a8b4,
|
||||
0x0000000000000000,
|
||||
0x0000000000000000,
|
||||
0x0000000000000000,
|
||||
},
|
||||
{
|
||||
0xd5bd51a17b2edf46,
|
||||
0x2cc06f7c86b86bcd,
|
||||
0x50b37e74f3294a00,
|
||||
0xeb32314a9da73679,
|
||||
},
|
||||
{
|
||||
0x48c18b1b0d2191bd,
|
||||
0x5a3f74c29bfccce3,
|
||||
0xbe55a02e5e8bd357,
|
||||
0x09bf218d11fff905,
|
||||
},
|
||||
{
|
||||
0x000000001c71c789,
|
||||
0x0000000000000000,
|
||||
0x0000000000000000,
|
||||
0x0000000000000000,
|
||||
},
|
||||
},
|
||||
XDen: [][native.FieldLimbs]uint64{
|
||||
{
|
||||
0x8af79c1ffdf1e7fa,
|
||||
0xb84bc22235735eb5,
|
||||
0x82ee5655a55ace04,
|
||||
0xce4b32dea0a2becb,
|
||||
},
|
||||
{
|
||||
0x8ecde3f3762e1fa5,
|
||||
0x2c3b1ad77be333fd,
|
||||
0xb102a1a152ea6e12,
|
||||
0x57b82df5a1ffc133,
|
||||
},
|
||||
{
|
||||
0x00000001000003d1,
|
||||
0x0000000000000000,
|
||||
0x0000000000000000,
|
||||
0x0000000000000000,
|
||||
},
|
||||
},
|
||||
YNum: [][native.FieldLimbs]uint64{
|
||||
{
|
||||
0xffffffce425e12c3,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
},
|
||||
{
|
||||
0xba60d5fd6e56922e,
|
||||
0x4ec198c898a435f2,
|
||||
0x27e77a577b9764ab,
|
||||
0xb3b80a1197651d12,
|
||||
},
|
||||
{
|
||||
0xa460c58d0690c6f6,
|
||||
0xad1fba614dfe6671,
|
||||
0xdf2ad0172f45e9ab,
|
||||
0x84df90c688fffc82,
|
||||
},
|
||||
{
|
||||
0x00000000097b4283,
|
||||
0x0000000000000000,
|
||||
0x0000000000000000,
|
||||
0x0000000000000000,
|
||||
},
|
||||
},
|
||||
YDen: [][native.FieldLimbs]uint64{
|
||||
{
|
||||
0xfffffd0afff4b6fb,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
},
|
||||
{
|
||||
0xa0e6d461f9d5bf90,
|
||||
0x28e34666a05a1c20,
|
||||
0x88cb0300f0106a0e,
|
||||
0x6ae1989be1e83c62,
|
||||
},
|
||||
{
|
||||
0x5634d5edb1453160,
|
||||
0x4258a84339d4cdfc,
|
||||
0x8983f271fc5fa51b,
|
||||
0x039444f072ffa1cd,
|
||||
},
|
||||
{
|
||||
0x00000001000003d1,
|
||||
0x0000000000000000,
|
||||
0x0000000000000000,
|
||||
0x0000000000000000,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getK256PointIsogenyParams() *native.IsogenyParams {
|
||||
k256PointIsogenyInitOnce.Do(k256PointIsogenyInit)
|
||||
return &k256PointIsogenyParams
|
||||
}
|
||||
|
||||
type k256PointArithmetic struct{}
|
||||
|
||||
func (k k256PointArithmetic) Hash(out *native.EllipticPoint, hash *native.EllipticPointHasher, msg, dst []byte) error {
|
||||
var u []byte
|
||||
sswuParams := getK256PointSswuParams()
|
||||
isoParams := getK256PointIsogenyParams()
|
||||
|
||||
switch hash.Type() {
|
||||
case native.XMD:
|
||||
u = native.ExpandMsgXmd(hash, msg, dst, 96)
|
||||
case native.XOF:
|
||||
u = native.ExpandMsgXof(hash, msg, dst, 96)
|
||||
}
|
||||
var buf [64]byte
|
||||
copy(buf[:48], internal.ReverseScalarBytes(u[:48]))
|
||||
u0 := fp.K256FpNew().SetBytesWide(&buf)
|
||||
copy(buf[:48], internal.ReverseScalarBytes(u[48:]))
|
||||
u1 := fp.K256FpNew().SetBytesWide(&buf)
|
||||
|
||||
r0x, r0y := sswuParams.Osswu3mod4(u0)
|
||||
r1x, r1y := sswuParams.Osswu3mod4(u1)
|
||||
q0x, q0y := isoParams.Map(r0x, r0y)
|
||||
q1x, q1y := isoParams.Map(r1x, r1y)
|
||||
out.X = q0x
|
||||
out.Y = q0y
|
||||
out.Z.SetOne()
|
||||
tv := &native.EllipticPoint{
|
||||
X: q1x,
|
||||
Y: q1y,
|
||||
Z: fp.K256FpNew().SetOne(),
|
||||
}
|
||||
k.Add(out, out, tv)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k k256PointArithmetic) Double(out, arg *native.EllipticPoint) {
|
||||
// Addition formula from Renes-Costello-Batina 2015
|
||||
// (https://eprint.iacr.org/2015/1060 Algorithm 9)
|
||||
var yy, zz, xy2, bzz, bzz3, bzz9 [native.FieldLimbs]uint64
|
||||
var yyMBzz9, yyPBzz3, yyzz, yyzz8, t [native.FieldLimbs]uint64
|
||||
var x, y, z [native.FieldLimbs]uint64
|
||||
f := arg.X.Arithmetic
|
||||
|
||||
f.Square(&yy, &arg.Y.Value)
|
||||
f.Square(&zz, &arg.Z.Value)
|
||||
f.Mul(&xy2, &arg.X.Value, &arg.Y.Value)
|
||||
f.Add(&xy2, &xy2, &xy2)
|
||||
f.Mul(&bzz, &zz, &arg.Params.B.Value)
|
||||
f.Add(&bzz3, &bzz, &bzz)
|
||||
f.Add(&bzz3, &bzz3, &bzz)
|
||||
f.Add(&bzz9, &bzz3, &bzz3)
|
||||
f.Add(&bzz9, &bzz9, &bzz3)
|
||||
f.Neg(&yyMBzz9, &bzz9)
|
||||
f.Add(&yyMBzz9, &yyMBzz9, &yy)
|
||||
f.Add(&yyPBzz3, &yy, &bzz3)
|
||||
f.Mul(&yyzz, &yy, &zz)
|
||||
f.Add(&yyzz8, &yyzz, &yyzz)
|
||||
f.Add(&yyzz8, &yyzz8, &yyzz8)
|
||||
f.Add(&yyzz8, &yyzz8, &yyzz8)
|
||||
f.Add(&t, &yyzz8, &yyzz8)
|
||||
f.Add(&t, &t, &yyzz8)
|
||||
f.Mul(&t, &t, &arg.Params.B.Value)
|
||||
|
||||
f.Mul(&x, &xy2, &yyMBzz9)
|
||||
|
||||
f.Mul(&y, &yyMBzz9, &yyPBzz3)
|
||||
f.Add(&y, &y, &t)
|
||||
|
||||
f.Mul(&z, &yy, &arg.Y.Value)
|
||||
f.Mul(&z, &z, &arg.Z.Value)
|
||||
f.Add(&z, &z, &z)
|
||||
f.Add(&z, &z, &z)
|
||||
f.Add(&z, &z, &z)
|
||||
|
||||
out.X.Value = x
|
||||
out.Y.Value = y
|
||||
out.Z.Value = z
|
||||
}
|
||||
|
||||
func (k k256PointArithmetic) Add(out, arg1, arg2 *native.EllipticPoint) {
|
||||
// Addition formula from Renes-Costello-Batina 2015
|
||||
// (https://eprint.iacr.org/2015/1060 Algorithm 7).
|
||||
var xx, yy, zz, nXxYy, nYyZz, nXxZz [native.FieldLimbs]uint64
|
||||
var tv1, tv2, xyPairs, yzPairs, xzPairs [native.FieldLimbs]uint64
|
||||
var bzz, bzz3, yyMBzz3, yyPBzz3, byz [native.FieldLimbs]uint64
|
||||
var byz3, xx3, bxx9, x, y, z [native.FieldLimbs]uint64
|
||||
f := arg1.X.Arithmetic
|
||||
|
||||
f.Mul(&xx, &arg1.X.Value, &arg2.X.Value)
|
||||
f.Mul(&yy, &arg1.Y.Value, &arg2.Y.Value)
|
||||
f.Mul(&zz, &arg1.Z.Value, &arg2.Z.Value)
|
||||
|
||||
f.Add(&nXxYy, &xx, &yy)
|
||||
f.Neg(&nXxYy, &nXxYy)
|
||||
|
||||
f.Add(&nYyZz, &yy, &zz)
|
||||
f.Neg(&nYyZz, &nYyZz)
|
||||
|
||||
f.Add(&nXxZz, &xx, &zz)
|
||||
f.Neg(&nXxZz, &nXxZz)
|
||||
|
||||
f.Add(&tv1, &arg1.X.Value, &arg1.Y.Value)
|
||||
f.Add(&tv2, &arg2.X.Value, &arg2.Y.Value)
|
||||
f.Mul(&xyPairs, &tv1, &tv2)
|
||||
f.Add(&xyPairs, &xyPairs, &nXxYy)
|
||||
|
||||
f.Add(&tv1, &arg1.Y.Value, &arg1.Z.Value)
|
||||
f.Add(&tv2, &arg2.Y.Value, &arg2.Z.Value)
|
||||
f.Mul(&yzPairs, &tv1, &tv2)
|
||||
f.Add(&yzPairs, &yzPairs, &nYyZz)
|
||||
|
||||
f.Add(&tv1, &arg1.X.Value, &arg1.Z.Value)
|
||||
f.Add(&tv2, &arg2.X.Value, &arg2.Z.Value)
|
||||
f.Mul(&xzPairs, &tv1, &tv2)
|
||||
f.Add(&xzPairs, &xzPairs, &nXxZz)
|
||||
|
||||
f.Mul(&bzz, &zz, &arg1.Params.B.Value)
|
||||
f.Add(&bzz3, &bzz, &bzz)
|
||||
f.Add(&bzz3, &bzz3, &bzz)
|
||||
|
||||
f.Neg(&yyMBzz3, &bzz3)
|
||||
f.Add(&yyMBzz3, &yyMBzz3, &yy)
|
||||
|
||||
f.Add(&yyPBzz3, &yy, &bzz3)
|
||||
|
||||
f.Mul(&byz, &yzPairs, &arg1.Params.B.Value)
|
||||
f.Add(&byz3, &byz, &byz)
|
||||
f.Add(&byz3, &byz3, &byz)
|
||||
|
||||
f.Add(&xx3, &xx, &xx)
|
||||
f.Add(&xx3, &xx3, &xx)
|
||||
|
||||
f.Add(&bxx9, &xx3, &xx3)
|
||||
f.Add(&bxx9, &bxx9, &xx3)
|
||||
f.Mul(&bxx9, &bxx9, &arg1.Params.B.Value)
|
||||
|
||||
f.Mul(&tv1, &xyPairs, &yyMBzz3)
|
||||
f.Mul(&tv2, &byz3, &xzPairs)
|
||||
f.Neg(&tv2, &tv2)
|
||||
f.Add(&x, &tv1, &tv2)
|
||||
|
||||
f.Mul(&tv1, &yyPBzz3, &yyMBzz3)
|
||||
f.Mul(&tv2, &bxx9, &xzPairs)
|
||||
f.Add(&y, &tv1, &tv2)
|
||||
|
||||
f.Mul(&tv1, &yzPairs, &yyPBzz3)
|
||||
f.Mul(&tv2, &xx3, &xyPairs)
|
||||
f.Add(&z, &tv1, &tv2)
|
||||
|
||||
e1 := arg1.Z.IsZero()
|
||||
e2 := arg2.Z.IsZero()
|
||||
|
||||
// If arg1 is identity set it to arg2
|
||||
f.Selectznz(&z, &z, &arg2.Z.Value, e1)
|
||||
f.Selectznz(&y, &y, &arg2.Y.Value, e1)
|
||||
f.Selectznz(&x, &x, &arg2.X.Value, e1)
|
||||
// If arg2 is identity set it to arg1
|
||||
f.Selectznz(&z, &z, &arg1.Z.Value, e2)
|
||||
f.Selectznz(&y, &y, &arg1.Y.Value, e2)
|
||||
f.Selectznz(&x, &x, &arg1.X.Value, e2)
|
||||
|
||||
out.X.Value = x
|
||||
out.Y.Value = y
|
||||
out.Z.Value = z
|
||||
}
|
||||
|
||||
func (k k256PointArithmetic) IsOnCurve(arg *native.EllipticPoint) bool {
|
||||
affine := K256PointNew()
|
||||
k.ToAffine(affine, arg)
|
||||
lhs := fp.K256FpNew().Square(affine.Y)
|
||||
rhs := fp.K256FpNew()
|
||||
k.RhsEq(rhs, affine.X)
|
||||
return lhs.Equal(rhs) == 1
|
||||
}
|
||||
|
||||
func (k k256PointArithmetic) ToAffine(out, arg *native.EllipticPoint) {
|
||||
var wasInverted int
|
||||
var zero, x, y, z [native.FieldLimbs]uint64
|
||||
f := arg.X.Arithmetic
|
||||
|
||||
f.Invert(&wasInverted, &z, &arg.Z.Value)
|
||||
f.Mul(&x, &arg.X.Value, &z)
|
||||
f.Mul(&y, &arg.Y.Value, &z)
|
||||
|
||||
out.Z.SetOne()
|
||||
// If point at infinity this does nothing
|
||||
f.Selectznz(&x, &zero, &x, wasInverted)
|
||||
f.Selectznz(&y, &zero, &y, wasInverted)
|
||||
f.Selectznz(&z, &zero, &out.Z.Value, wasInverted)
|
||||
|
||||
out.X.Value = x
|
||||
out.Y.Value = y
|
||||
out.Z.Value = z
|
||||
out.Params = arg.Params
|
||||
out.Arithmetic = arg.Arithmetic
|
||||
}
|
||||
|
||||
func (k k256PointArithmetic) RhsEq(out, x *native.Field) {
|
||||
// Elliptic curve equation for secp256k1 is: y^2 = x^3 + 7
|
||||
out.Square(x)
|
||||
out.Mul(out, x)
|
||||
out.Add(out, getK256PointParams().B)
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package k256_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
"github.com/onsonr/hway/crypto/core/curves/native/k256"
|
||||
)
|
||||
|
||||
func TestK256PointArithmetic_Hash(t *testing.T) {
|
||||
var b [32]byte
|
||||
sc, err := k256.K256PointNew().Hash(b[:], native.EllipticPointHasherSha256())
|
||||
|
||||
require.NoError(t, err)
|
||||
require.True(t, !sc.IsIdentity())
|
||||
require.True(t, sc.IsOnCurve())
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
package native
|
||||
|
||||
// SswuParams for computing the Simplified SWU mapping
|
||||
// for hash to curve implementations
|
||||
type SswuParams struct {
|
||||
C1, C2, A, B, Z [FieldLimbs]uint64
|
||||
}
|
||||
|
||||
// Osswu3mod4 computes the simplified map optmized for 3 mod 4 primes
|
||||
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-11#appendix-G.2.1
|
||||
func (p *SswuParams) Osswu3mod4(u *Field) (x, y *Field) {
|
||||
var tv1, tv2, tv3, tv4, xd, x1n, x2n, gxd, gx1, aNeg, zA, y1, y2 [FieldLimbs]uint64
|
||||
var wasInverted int
|
||||
u.Arithmetic.Mul(&tv1, &u.Value, &u.Value) // tv1 = u^2
|
||||
u.Arithmetic.Mul(&tv3, &p.Z, &tv1) // tv3 = z * tv1
|
||||
u.Arithmetic.Square(&tv2, &tv3) // tv2 = tv3^2
|
||||
u.Arithmetic.Add(&xd, &tv2, &tv3) // xd = tv2 + tv3
|
||||
u.Arithmetic.Add(&x1n, &u.Params.R, &xd) // x1n = (xd + 1)
|
||||
u.Arithmetic.Mul(&x1n, &x1n, &p.B) // x1n * B
|
||||
u.Arithmetic.Neg(&aNeg, &p.A)
|
||||
u.Arithmetic.Mul(&xd, &xd, &aNeg) // xd = -A * xd
|
||||
|
||||
xdIsZero := (&Field{
|
||||
Value: xd,
|
||||
}).IsZero()
|
||||
u.Arithmetic.Mul(&zA, &p.Z, &p.A)
|
||||
u.Arithmetic.Selectznz(&xd, &xd, &zA, xdIsZero) // xd = z * A if xd == 0
|
||||
|
||||
u.Arithmetic.Square(&tv2, &xd) // tv2 = xd^2
|
||||
u.Arithmetic.Mul(&gxd, &tv2, &xd) // gxd = tv2 * xd
|
||||
u.Arithmetic.Mul(&tv2, &tv2, &p.A) // tv2 = A * tv2
|
||||
|
||||
u.Arithmetic.Square(&gx1, &x1n) // gx1 = x1n^2
|
||||
u.Arithmetic.Add(&gx1, &gx1, &tv2) // gx1 = gx1 + tv2
|
||||
u.Arithmetic.Mul(&gx1, &gx1, &x1n) // gx1 = gx1 * x1n
|
||||
u.Arithmetic.Mul(&tv2, &gxd, &p.B) // tv2 = B * gxd
|
||||
u.Arithmetic.Add(&gx1, &gx1, &tv2) // gx1 = gx1 + tv2
|
||||
|
||||
u.Arithmetic.Square(&tv4, &gxd) // tv4 = gxd^2
|
||||
u.Arithmetic.Mul(&tv2, &gx1, &gxd) // tv2 = gx1 * gxd
|
||||
u.Arithmetic.Mul(&tv4, &tv4, &tv2) // tv4 = tv4 * tv2
|
||||
|
||||
Pow(&y1, &tv4, &p.C1, u.Params, u.Arithmetic) // y1 = tv4^C1
|
||||
u.Arithmetic.Mul(&y1, &y1, &tv2) //y1 = y1 * tv2
|
||||
u.Arithmetic.Mul(&x2n, &tv3, &x1n) // x2n = tv3 * x1n
|
||||
|
||||
u.Arithmetic.Mul(&y2, &y1, &p.C2) // y2 = y1 * c2
|
||||
u.Arithmetic.Mul(&y2, &y2, &tv1) // y2 = y2 * tv1
|
||||
u.Arithmetic.Mul(&y2, &y2, &u.Value) // y2 = y2 * u
|
||||
|
||||
u.Arithmetic.Square(&tv2, &y1) // tv2 = y1^2
|
||||
u.Arithmetic.Mul(&tv2, &tv2, &gxd) // tv2 = tv2 * gxd
|
||||
|
||||
e2 := (&Field{Value: tv2}).Equal(&Field{Value: gx1})
|
||||
|
||||
x = new(Field).Set(u)
|
||||
y = new(Field).Set(u)
|
||||
|
||||
// If e2, x = x1, else x = x2
|
||||
u.Arithmetic.Selectznz(&x.Value, &x2n, &x1n, e2)
|
||||
|
||||
// xn / xd
|
||||
u.Arithmetic.Invert(&wasInverted, &tv1, &xd)
|
||||
u.Arithmetic.Mul(&tv1, &x.Value, &tv1)
|
||||
u.Arithmetic.Selectznz(&x.Value, &x.Value, &tv1, wasInverted)
|
||||
|
||||
// If e2, y = y1, else y = y2
|
||||
u.Arithmetic.Selectznz(&y.Value, &y2, &y1, e2)
|
||||
|
||||
uBytes := u.Bytes()
|
||||
yBytes := y.Bytes()
|
||||
|
||||
usign := uBytes[0] & 1
|
||||
ysign := yBytes[0] & 1
|
||||
|
||||
// Fix sign of y
|
||||
if usign != ysign {
|
||||
y.Neg(y)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
@ -1,172 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package fp
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"sync"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
)
|
||||
|
||||
var (
|
||||
p256FpInitonce sync.Once
|
||||
p256FpParams native.FieldParams
|
||||
)
|
||||
|
||||
func P256FpNew() *native.Field {
|
||||
return &native.Field{
|
||||
Value: [native.FieldLimbs]uint64{},
|
||||
Params: getP256FpParams(),
|
||||
Arithmetic: p256FpArithmetic{},
|
||||
}
|
||||
}
|
||||
|
||||
func p256FpParamsInit() {
|
||||
// See FIPS 186-3, section D.2.3
|
||||
p256FpParams = native.FieldParams{
|
||||
R: [native.FieldLimbs]uint64{0x0000000000000001, 0xffffffff00000000, 0xffffffffffffffff, 0x00000000fffffffe},
|
||||
R2: [native.FieldLimbs]uint64{0x0000000000000003, 0xfffffffbffffffff, 0xfffffffffffffffe, 0x00000004fffffffd},
|
||||
R3: [native.FieldLimbs]uint64{0xfffffffd0000000a, 0xffffffedfffffff7, 0x00000005fffffffc, 0x0000001800000001},
|
||||
Modulus: [native.FieldLimbs]uint64{0xffffffffffffffff, 0x00000000ffffffff, 0x0000000000000000, 0xffffffff00000001},
|
||||
BiModulus: new(big.Int).SetBytes([]byte{
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func getP256FpParams() *native.FieldParams {
|
||||
p256FpInitonce.Do(p256FpParamsInit)
|
||||
return &p256FpParams
|
||||
}
|
||||
|
||||
// p256FpArithmetic is a struct with all the methods needed for working
|
||||
// in mod q
|
||||
type p256FpArithmetic struct{}
|
||||
|
||||
// ToMontgomery converts this field to montgomery form
|
||||
func (f p256FpArithmetic) ToMontgomery(out, arg *[native.FieldLimbs]uint64) {
|
||||
ToMontgomery((*MontgomeryDomainFieldElement)(out), (*NonMontgomeryDomainFieldElement)(arg))
|
||||
}
|
||||
|
||||
// FromMontgomery converts this field from montgomery form
|
||||
func (f p256FpArithmetic) FromMontgomery(out, arg *[native.FieldLimbs]uint64) {
|
||||
FromMontgomery((*NonMontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg))
|
||||
}
|
||||
|
||||
// Neg performs modular negation
|
||||
func (f p256FpArithmetic) Neg(out, arg *[native.FieldLimbs]uint64) {
|
||||
Opp((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg))
|
||||
}
|
||||
|
||||
// Square performs modular square
|
||||
func (f p256FpArithmetic) Square(out, arg *[native.FieldLimbs]uint64) {
|
||||
Square((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg))
|
||||
}
|
||||
|
||||
// Mul performs modular multiplication
|
||||
func (f p256FpArithmetic) Mul(out, arg1, arg2 *[native.FieldLimbs]uint64) {
|
||||
Mul((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2))
|
||||
}
|
||||
|
||||
// Add performs modular addition
|
||||
func (f p256FpArithmetic) Add(out, arg1, arg2 *[native.FieldLimbs]uint64) {
|
||||
Add((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2))
|
||||
}
|
||||
|
||||
// Sub performs modular subtraction
|
||||
func (f p256FpArithmetic) Sub(out, arg1, arg2 *[native.FieldLimbs]uint64) {
|
||||
Sub((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2))
|
||||
}
|
||||
|
||||
// Sqrt performs modular square root
|
||||
func (f p256FpArithmetic) Sqrt(wasSquare *int, out, arg *[native.FieldLimbs]uint64) {
|
||||
// Use p = 3 mod 4 by Euler's criterion means
|
||||
// arg^((p+1)/4 mod p
|
||||
var t, c [native.FieldLimbs]uint64
|
||||
c1 := [native.FieldLimbs]uint64{
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_4000_0000,
|
||||
0x4000_0000_0000_0000,
|
||||
0x3fff_ffff_c000_0000,
|
||||
}
|
||||
native.Pow(&t, arg, &c1, getP256FpParams(), f)
|
||||
Square((*MontgomeryDomainFieldElement)(&c), (*MontgomeryDomainFieldElement)(&t))
|
||||
*wasSquare = (&native.Field{Value: c, Params: getP256FpParams(), Arithmetic: f}).Equal(&native.Field{
|
||||
Value: *arg, Params: getP256FpParams(), Arithmetic: f,
|
||||
})
|
||||
Selectznz(out, uint1(*wasSquare), out, &t)
|
||||
}
|
||||
|
||||
// Invert performs modular inverse
|
||||
func (f p256FpArithmetic) Invert(wasInverted *int, out, arg *[native.FieldLimbs]uint64) {
|
||||
// Fermat's Little Theorem
|
||||
// a ^ (p - 2) mod p
|
||||
//
|
||||
// The exponent pattern (from high to low) is:
|
||||
// - 32 bits of value 1
|
||||
// - 31 bits of value 0
|
||||
// - 1 bit of value 1
|
||||
// - 96 bits of value 0
|
||||
// - 94 bits of value 1
|
||||
// - 1 bit of value 0
|
||||
// - 1 bit of value 1
|
||||
// To speed up the square-and-multiply algorithm, precompute a^(2^31-1).
|
||||
//
|
||||
// Courtesy of Thomas Pornin
|
||||
//
|
||||
var t, r [native.FieldLimbs]uint64
|
||||
copy(t[:], arg[:])
|
||||
|
||||
for i := 0; i < 30; i++ {
|
||||
f.Square(&t, &t)
|
||||
f.Mul(&t, &t, arg)
|
||||
}
|
||||
copy(r[:], t[:])
|
||||
for i := 224; i >= 0; i-- {
|
||||
f.Square(&r, &r)
|
||||
switch i {
|
||||
case 0:
|
||||
fallthrough
|
||||
case 2:
|
||||
fallthrough
|
||||
case 192:
|
||||
fallthrough
|
||||
case 224:
|
||||
f.Mul(&r, &r, arg)
|
||||
case 3:
|
||||
fallthrough
|
||||
case 34:
|
||||
fallthrough
|
||||
case 65:
|
||||
f.Mul(&r, &r, &t)
|
||||
}
|
||||
}
|
||||
|
||||
*wasInverted = (&native.Field{
|
||||
Value: *arg,
|
||||
Params: getP256FpParams(),
|
||||
Arithmetic: f,
|
||||
}).IsNonZero()
|
||||
Selectznz(out, uint1(*wasInverted), out, &r)
|
||||
}
|
||||
|
||||
// FromBytes converts a little endian byte array into a field element
|
||||
func (f p256FpArithmetic) FromBytes(out *[native.FieldLimbs]uint64, arg *[native.FieldBytes]byte) {
|
||||
FromBytes(out, arg)
|
||||
}
|
||||
|
||||
// ToBytes converts a field element to a little endian byte array
|
||||
func (f p256FpArithmetic) ToBytes(out *[native.FieldBytes]byte, arg *[native.FieldLimbs]uint64) {
|
||||
ToBytes(out, arg)
|
||||
}
|
||||
|
||||
// Selectznz performs conditional select.
|
||||
// selects arg1 if choice == 0 and arg2 if choice == 1
|
||||
func (f p256FpArithmetic) Selectznz(out, arg1, arg2 *[native.FieldLimbs]uint64, choice int) {
|
||||
Selectznz(out, uint1(choice), arg1, arg2)
|
||||
}
|
@ -1,328 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package fp
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
"github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
func TestFpSetOne(t *testing.T) {
|
||||
fq := P256FpNew().SetOne()
|
||||
require.NotNil(t, fq)
|
||||
require.Equal(t, fq.Value, getP256FpParams().R)
|
||||
}
|
||||
|
||||
func TestFpSetUint64(t *testing.T) {
|
||||
act := P256FpNew().SetUint64(1 << 60)
|
||||
require.NotNil(t, act)
|
||||
// Remember it will be in montgomery form
|
||||
require.Equal(t, act.Value[0], uint64(0x100000000fffffff))
|
||||
}
|
||||
|
||||
func TestFpAdd(t *testing.T) {
|
||||
lhs := P256FpNew().SetOne()
|
||||
rhs := P256FpNew().SetOne()
|
||||
exp := P256FpNew().SetUint64(2)
|
||||
res := P256FpNew().Add(lhs, rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, 1, res.Equal(exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint64() >> 2
|
||||
r := rand.Uint64() >> 2
|
||||
e := l + r
|
||||
lhs.SetUint64(l)
|
||||
rhs.SetUint64(r)
|
||||
exp.SetUint64(e)
|
||||
|
||||
a := P256FpNew().Add(lhs, rhs)
|
||||
require.NotNil(t, a)
|
||||
require.Equal(t, exp, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpSub(t *testing.T) {
|
||||
lhs := P256FpNew().SetOne()
|
||||
rhs := P256FpNew().SetOne()
|
||||
exp := P256FpNew().SetZero()
|
||||
res := P256FpNew().Sub(lhs, rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, 1, res.Equal(exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint64() >> 2
|
||||
r := rand.Uint64() >> 2
|
||||
if l < r {
|
||||
l, r = r, l
|
||||
}
|
||||
e := l - r
|
||||
lhs.SetUint64(l)
|
||||
rhs.SetUint64(r)
|
||||
exp.SetUint64(e)
|
||||
|
||||
a := P256FpNew().Sub(lhs, rhs)
|
||||
require.NotNil(t, a)
|
||||
require.Equal(t, exp, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpMul(t *testing.T) {
|
||||
lhs := P256FpNew().SetOne()
|
||||
rhs := P256FpNew().SetOne()
|
||||
exp := P256FpNew().SetOne()
|
||||
res := P256FpNew().Mul(lhs, rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, 1, res.Equal(exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint32()
|
||||
r := rand.Uint32()
|
||||
e := uint64(l) * uint64(r)
|
||||
lhs.SetUint64(uint64(l))
|
||||
rhs.SetUint64(uint64(r))
|
||||
exp.SetUint64(e)
|
||||
|
||||
a := P256FpNew().Mul(lhs, rhs)
|
||||
require.NotNil(t, a)
|
||||
require.Equal(t, exp, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpDouble(t *testing.T) {
|
||||
a := P256FpNew().SetUint64(2)
|
||||
e := P256FpNew().SetUint64(4)
|
||||
require.Equal(t, e, P256FpNew().Double(a))
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
tv := rand.Uint32()
|
||||
ttv := uint64(tv) * 2
|
||||
a = P256FpNew().SetUint64(uint64(tv))
|
||||
e = P256FpNew().SetUint64(ttv)
|
||||
require.Equal(t, e, P256FpNew().Double(a))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpSquare(t *testing.T) {
|
||||
a := P256FpNew().SetUint64(4)
|
||||
e := P256FpNew().SetUint64(16)
|
||||
require.Equal(t, e, a.Square(a))
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
j := rand.Uint32()
|
||||
exp := uint64(j) * uint64(j)
|
||||
e.SetUint64(exp)
|
||||
a.SetUint64(uint64(j))
|
||||
require.Equal(t, e, a.Square(a))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpNeg(t *testing.T) {
|
||||
g := P256FpNew().SetUint64(7)
|
||||
a := P256FpNew().SetOne()
|
||||
a.Neg(a)
|
||||
e := P256FpNew().SetRaw(&[native.FieldLimbs]uint64{0xfffffffffffffffe, 0x00000001ffffffff, 0x0000000000000000, 0xfffffffe00000002})
|
||||
require.Equal(t, e, a)
|
||||
a.Neg(g)
|
||||
e = P256FpNew().SetRaw(&[native.FieldLimbs]uint64{0xfffffffffffffff8, 0x00000007ffffffff, 0x0000000000000000, 0xfffffff800000008})
|
||||
require.Equal(t, e, a)
|
||||
}
|
||||
|
||||
func TestFpExp(t *testing.T) {
|
||||
e := P256FpNew().SetUint64(8)
|
||||
a := P256FpNew().SetUint64(2)
|
||||
by := P256FpNew().SetUint64(3)
|
||||
require.Equal(t, e, a.Exp(a, by))
|
||||
}
|
||||
|
||||
func TestFpSqrt(t *testing.T) {
|
||||
t1 := P256FpNew().SetUint64(2)
|
||||
t2 := P256FpNew().Neg(t1)
|
||||
t3 := P256FpNew().Square(t1)
|
||||
_, wasSquare := t3.Sqrt(t3)
|
||||
|
||||
require.True(t, wasSquare)
|
||||
require.Equal(t, 1, t1.Equal(t3)|t2.Equal(t3))
|
||||
t1.SetUint64(3)
|
||||
_, wasSquare = P256FpNew().Sqrt(t1)
|
||||
require.False(t, wasSquare)
|
||||
}
|
||||
|
||||
func TestFpInvert(t *testing.T) {
|
||||
twoInv := P256FpNew().SetRaw(&[native.FieldLimbs]uint64{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x8000000000000000})
|
||||
two := P256FpNew().SetUint64(2)
|
||||
a, inverted := P256FpNew().Invert(two)
|
||||
require.True(t, inverted)
|
||||
require.Equal(t, a, twoInv)
|
||||
|
||||
rootOfUnity := P256FpNew().SetLimbs(&[native.FieldLimbs]uint64{0x8619a9e760c01d0c, 0xa883c4fba37998df, 0x45607580b6eabd98, 0xf252b002544b2f99})
|
||||
rootOfUnityInv := P256FpNew().SetRaw(&[native.FieldLimbs]uint64{0x2609d8ab477f96d1, 0x6e5f128fb20a0f24, 0xe4d636874d99643b, 0x376080cc1f2a3735})
|
||||
a, inverted = P256FpNew().Invert(rootOfUnity)
|
||||
require.True(t, inverted)
|
||||
require.Equal(t, a, rootOfUnityInv)
|
||||
|
||||
lhs := P256FpNew().SetUint64(9)
|
||||
rhs := P256FpNew().SetUint64(3)
|
||||
rhsInv, inverted := P256FpNew().Invert(rhs)
|
||||
require.True(t, inverted)
|
||||
require.Equal(t, rhs, P256FpNew().Mul(lhs, rhsInv))
|
||||
|
||||
rhs.SetZero()
|
||||
_, inverted = P256FpNew().Invert(rhs)
|
||||
require.False(t, inverted)
|
||||
}
|
||||
|
||||
func TestFpCMove(t *testing.T) {
|
||||
t1 := P256FpNew().SetUint64(5)
|
||||
t2 := P256FpNew().SetUint64(10)
|
||||
require.Equal(t, t1, P256FpNew().CMove(t1, t2, 0))
|
||||
require.Equal(t, t2, P256FpNew().CMove(t1, t2, 1))
|
||||
}
|
||||
|
||||
func TestFpBytes(t *testing.T) {
|
||||
t1 := P256FpNew().SetUint64(99)
|
||||
seq := t1.Bytes()
|
||||
t2, err := P256FpNew().SetBytes(&seq)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, t1, t2)
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
t1.SetUint64(rand.Uint64())
|
||||
seq = t1.Bytes()
|
||||
_, err = t2.SetBytes(&seq)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, t1, t2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpCmp(t *testing.T) {
|
||||
tests := []struct {
|
||||
a *native.Field
|
||||
b *native.Field
|
||||
e int
|
||||
}{
|
||||
{
|
||||
a: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{2731658267414164836, 14655288906067898431, 6537465423330262322, 8306191141697566219}),
|
||||
b: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{6472764012681988529, 10848812988401906064, 2961825807536828898, 4282183981941645679}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{8023004109510539223, 4652004072850285717, 1877219145646046927, 383214385093921911}),
|
||||
b: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{10099384440823804262, 16139476942229308465, 8636966320777393798, 5435928725024696785}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{3741840066202388211, 12165774400417314871, 16619312580230515379, 16195032234110087705}),
|
||||
b: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{3905865991286066744, 543690822309071825, 17963103015950210055, 3745476720756119742}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{16660853697936147788, 7799793619412111108, 13515141085171033220, 2641079731236069032}),
|
||||
b: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{17790588295388238399, 571847801379669440, 14537208974498222469, 12792570372087452754}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{3912839285384959186, 2701177075110484070, 6453856448115499033, 6475797457962597458}),
|
||||
b: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{1282566391665688512, 13503640416992806563, 2962240104675990153, 3374904770947067689}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{5716631803409360103, 7859567470082614154, 12747956220853330146, 18434584096087315020}),
|
||||
b: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{16317076441459028418, 12854146980376319601, 2258436689269031143, 9531877130792223752}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{17955191469941083403, 10350326247207200880, 17263512235150705075, 12700328451238078022}),
|
||||
b: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{6767595547459644695, 7146403825494928147, 12269344038346710612, 9122477829383225603}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{17099388671847024438, 6426264987820696548, 10641143464957227405, 7709745403700754098}),
|
||||
b: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{10799154372990268556, 17178492485719929374, 5705777922258988797, 8051037767683567782}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{4567139260680454325, 1629385880182139061, 16607020832317899145, 1261011562621553200}),
|
||||
b: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{13487234491304534488, 17872642955936089265, 17651026784972590233, 9468934643333871559}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{18071070103467571798, 11787850505799426140, 10631355976141928593, 4867785203635092610}),
|
||||
b: P256FpNew().SetRaw(&[native.FieldLimbs]uint64{12596443599426461624, 10176122686151524591, 17075755296887483439, 6726169532695070719}),
|
||||
e: -1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
require.Equal(t, test.e, test.a.Cmp(test.b))
|
||||
require.Equal(t, -test.e, test.b.Cmp(test.a))
|
||||
require.Equal(t, 0, test.a.Cmp(test.a))
|
||||
require.Equal(t, 0, test.b.Cmp(test.b))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpBigInt(t *testing.T) {
|
||||
t1 := P256FpNew().SetBigInt(big.NewInt(9999))
|
||||
t2 := P256FpNew().SetBigInt(t1.BigInt())
|
||||
require.Equal(t, t1, t2)
|
||||
|
||||
e := P256FpNew().SetRaw(&[native.FieldLimbs]uint64{0x515151513f3f3f3e, 0xc9c9c9cb36363636, 0xb7b7b7b79c9c9c9c, 0xfffffffeaeaeaeaf})
|
||||
b := new(big.Int).SetBytes([]byte{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9})
|
||||
t1.SetBigInt(b)
|
||||
require.Equal(t, e, t1)
|
||||
e.Value[0] = 0xaeaeaeaec0c0c0c1
|
||||
e.Value[1] = 0x36363635c9c9c9c9
|
||||
e.Value[2] = 0x4848484863636363
|
||||
e.Value[3] = 0x0000000051515151
|
||||
b.Neg(b)
|
||||
t1.SetBigInt(b)
|
||||
require.Equal(t, e, t1)
|
||||
}
|
||||
|
||||
func TestFpSetBytesWide(t *testing.T) {
|
||||
e := P256FpNew().SetRaw(&[native.FieldLimbs]uint64{0xccdefd48c77805bc, 0xe935dc2db86364d6, 0xca8ee6e5870a020e, 0x4c94bf4467f3b5bf})
|
||||
|
||||
a := P256FpNew().SetBytesWide(&[64]byte{
|
||||
0x69, 0x23, 0x5a, 0x0b, 0xce, 0x0c, 0xa8, 0x64,
|
||||
0x3c, 0x78, 0xbc, 0x01, 0x05, 0xef, 0xf2, 0x84,
|
||||
0xde, 0xbb, 0x6b, 0xc8, 0x63, 0x5e, 0x6e, 0x69,
|
||||
0x62, 0xcc, 0xc6, 0x2d, 0xf5, 0x72, 0x40, 0x92,
|
||||
0x28, 0x11, 0xd6, 0xc8, 0x07, 0xa5, 0x88, 0x82,
|
||||
0xfe, 0xe3, 0x97, 0xf6, 0x1e, 0xfb, 0x2e, 0x3b,
|
||||
0x27, 0x5f, 0x85, 0x06, 0x8d, 0x99, 0xa4, 0x75,
|
||||
0xc0, 0x2c, 0x71, 0x69, 0x9e, 0x58, 0xea, 0x52,
|
||||
})
|
||||
require.Equal(t, e, a)
|
||||
}
|
||||
|
||||
func TestFpSetBytesWideBigInt(t *testing.T) {
|
||||
params := getP256FpParams()
|
||||
var tv2 [64]byte
|
||||
for i := 0; i < 25; i++ {
|
||||
_, _ = crand.Read(tv2[:])
|
||||
e := new(big.Int).SetBytes(tv2[:])
|
||||
e.Mod(e, params.BiModulus)
|
||||
|
||||
tv := internal.ReverseScalarBytes(tv2[:])
|
||||
copy(tv2[:], tv)
|
||||
a := P256FpNew().SetBytesWide(&tv2)
|
||||
require.Equal(t, 0, e.Cmp(a.BigInt()))
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,295 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package fq
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"sync"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
)
|
||||
|
||||
var (
|
||||
p256FqInitonce sync.Once
|
||||
p256FqParams native.FieldParams
|
||||
)
|
||||
|
||||
func P256FqNew() *native.Field {
|
||||
return &native.Field{
|
||||
Value: [native.FieldLimbs]uint64{},
|
||||
Params: getP256FqParams(),
|
||||
Arithmetic: p256FqArithmetic{},
|
||||
}
|
||||
}
|
||||
|
||||
func p256FqParamsInit() {
|
||||
// See FIPS 186-3, section D.2.3
|
||||
p256FqParams = native.FieldParams{
|
||||
R: [native.FieldLimbs]uint64{0x0c46353d039cdaaf, 0x4319055258e8617b, 0x0000000000000000, 0x00000000ffffffff},
|
||||
R2: [native.FieldLimbs]uint64{0x83244c95be79eea2, 0x4699799c49bd6fa6, 0x2845b2392b6bec59, 0x66e12d94f3d95620},
|
||||
R3: [native.FieldLimbs]uint64{0xac8ebec90b65a624, 0x111f28ae0c0555c9, 0x2543b9246ba5e93f, 0x503a54e76407be65},
|
||||
Modulus: [native.FieldLimbs]uint64{0xf3b9cac2fc632551, 0xbce6faada7179e84, 0xffffffffffffffff, 0xffffffff00000000},
|
||||
BiModulus: new(big.Int).SetBytes([]byte{
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func getP256FqParams() *native.FieldParams {
|
||||
p256FqInitonce.Do(p256FqParamsInit)
|
||||
return &p256FqParams
|
||||
}
|
||||
|
||||
// p256FqArithmetic is a struct with all the methods needed for working
|
||||
// in mod q
|
||||
type p256FqArithmetic struct{}
|
||||
|
||||
// ToMontgomery converts this field to montgomery form
|
||||
func (f p256FqArithmetic) ToMontgomery(out, arg *[native.FieldLimbs]uint64) {
|
||||
ToMontgomery((*MontgomeryDomainFieldElement)(out), (*NonMontgomeryDomainFieldElement)(arg))
|
||||
}
|
||||
|
||||
// FromMontgomery converts this field from montgomery form
|
||||
func (f p256FqArithmetic) FromMontgomery(out, arg *[native.FieldLimbs]uint64) {
|
||||
FromMontgomery((*NonMontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg))
|
||||
}
|
||||
|
||||
// Neg performs modular negation
|
||||
func (f p256FqArithmetic) Neg(out, arg *[native.FieldLimbs]uint64) {
|
||||
Opp((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg))
|
||||
}
|
||||
|
||||
// Square performs modular square
|
||||
func (f p256FqArithmetic) Square(out, arg *[native.FieldLimbs]uint64) {
|
||||
Square((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg))
|
||||
}
|
||||
|
||||
// Mul performs modular multiplication
|
||||
func (f p256FqArithmetic) Mul(out, arg1, arg2 *[native.FieldLimbs]uint64) {
|
||||
Mul((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2))
|
||||
}
|
||||
|
||||
// Add performs modular addition
|
||||
func (f p256FqArithmetic) Add(out, arg1, arg2 *[native.FieldLimbs]uint64) {
|
||||
Add((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2))
|
||||
}
|
||||
|
||||
// Sub performs modular subtraction
|
||||
func (f p256FqArithmetic) Sub(out, arg1, arg2 *[native.FieldLimbs]uint64) {
|
||||
Sub((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2))
|
||||
}
|
||||
|
||||
// Sqrt performs modular square root
|
||||
func (f p256FqArithmetic) Sqrt(wasSquare *int, out, arg *[native.FieldLimbs]uint64) {
|
||||
// See sqrt_ts_ct at
|
||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-I.4
|
||||
// c1 := s
|
||||
// c2 := (q - 1) / (2^c1)
|
||||
// c2 := [4]uint64{
|
||||
// 0x4f3b9cac2fc63255,
|
||||
// 0xfbce6faada7179e8,
|
||||
// 0x0fffffffffffffff,
|
||||
// 0x0ffffffff0000000,
|
||||
// }
|
||||
// c3 := (c2 - 1) / 2
|
||||
c3 := [native.FieldLimbs]uint64{
|
||||
0x279dce5617e3192a,
|
||||
0xfde737d56d38bcf4,
|
||||
0x07ffffffffffffff,
|
||||
0x07fffffff8000000,
|
||||
}
|
||||
// c4 := generator
|
||||
// c5 := new(Fq).pow(generator, c2)
|
||||
c5 := [native.FieldLimbs]uint64{0x1015708f7e368fe1, 0x31c6c5456ecc4511, 0x5281fe8998a19ea1, 0x0279089e10c63fe8}
|
||||
var z, t, b, c, tv [native.FieldLimbs]uint64
|
||||
|
||||
native.Pow(&z, arg, &c3, getP256FqParams(), f)
|
||||
Square((*MontgomeryDomainFieldElement)(&t), (*MontgomeryDomainFieldElement)(&z))
|
||||
Mul((*MontgomeryDomainFieldElement)(&t), (*MontgomeryDomainFieldElement)(&t), (*MontgomeryDomainFieldElement)(arg))
|
||||
Mul((*MontgomeryDomainFieldElement)(&z), (*MontgomeryDomainFieldElement)(&z), (*MontgomeryDomainFieldElement)(arg))
|
||||
|
||||
copy(b[:], t[:])
|
||||
copy(c[:], c5[:])
|
||||
|
||||
for i := s; i >= 2; i-- {
|
||||
for j := 1; j <= i-2; j++ {
|
||||
Square((*MontgomeryDomainFieldElement)(&b), (*MontgomeryDomainFieldElement)(&b))
|
||||
}
|
||||
// if b == 1 flag = 0 else flag = 1
|
||||
flag := -(&native.Field{
|
||||
Value: b,
|
||||
Params: getP256FqParams(),
|
||||
Arithmetic: f,
|
||||
}).IsOne() + 1
|
||||
Mul((*MontgomeryDomainFieldElement)(&tv), (*MontgomeryDomainFieldElement)(&z), (*MontgomeryDomainFieldElement)(&c))
|
||||
Selectznz(&z, uint1(flag), &z, &tv)
|
||||
Square((*MontgomeryDomainFieldElement)(&c), (*MontgomeryDomainFieldElement)(&c))
|
||||
Mul((*MontgomeryDomainFieldElement)(&tv), (*MontgomeryDomainFieldElement)(&t), (*MontgomeryDomainFieldElement)(&c))
|
||||
Selectznz(&t, uint1(flag), &t, &tv)
|
||||
copy(b[:], t[:])
|
||||
}
|
||||
Square((*MontgomeryDomainFieldElement)(&c), (*MontgomeryDomainFieldElement)(&z))
|
||||
*wasSquare = (&native.Field{
|
||||
Value: c,
|
||||
Params: getP256FqParams(),
|
||||
Arithmetic: f,
|
||||
}).Equal(&native.Field{
|
||||
Value: *arg,
|
||||
Params: getP256FqParams(),
|
||||
Arithmetic: f,
|
||||
})
|
||||
Selectznz(out, uint1(*wasSquare), out, &z)
|
||||
}
|
||||
|
||||
// Invert performs modular inverse
|
||||
func (f p256FqArithmetic) Invert(wasInverted *int, out, arg *[native.FieldLimbs]uint64) {
|
||||
// Using an addition chain from
|
||||
// https://briansmith.org/ecc-inversion-addition-chains-01#p256_field_inversion
|
||||
var x1, x10, x11, x101, x111, x1010, x1111, x10101, x101010, x101111 [native.FieldLimbs]uint64
|
||||
var x6, x8, x16, x32, tmp [native.FieldLimbs]uint64
|
||||
|
||||
copy(x1[:], arg[:])
|
||||
native.Pow2k(&x10, arg, 1, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&x11), (*MontgomeryDomainFieldElement)(&x10), (*MontgomeryDomainFieldElement)(&x1))
|
||||
Mul((*MontgomeryDomainFieldElement)(&x101), (*MontgomeryDomainFieldElement)(&x10), (*MontgomeryDomainFieldElement)(&x11))
|
||||
Mul((*MontgomeryDomainFieldElement)(&x111), (*MontgomeryDomainFieldElement)(&x10), (*MontgomeryDomainFieldElement)(&x101))
|
||||
native.Pow2k(&x1010, &x101, 1, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&x1111), (*MontgomeryDomainFieldElement)(&x101), (*MontgomeryDomainFieldElement)(&x1010))
|
||||
native.Pow2k(&x10101, &x1010, 1, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&x10101), (*MontgomeryDomainFieldElement)(&x10101), (*MontgomeryDomainFieldElement)(&x1))
|
||||
native.Pow2k(&x101010, &x10101, 1, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&x101111), (*MontgomeryDomainFieldElement)(&x101), (*MontgomeryDomainFieldElement)(&x101010))
|
||||
|
||||
Mul((*MontgomeryDomainFieldElement)(&x6), (*MontgomeryDomainFieldElement)(&x10101), (*MontgomeryDomainFieldElement)(&x101010))
|
||||
|
||||
native.Pow2k(&x8, &x6, 2, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&x8), (*MontgomeryDomainFieldElement)(&x8), (*MontgomeryDomainFieldElement)(&x11))
|
||||
|
||||
native.Pow2k(&x16, &x8, 8, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&x16), (*MontgomeryDomainFieldElement)(&x16), (*MontgomeryDomainFieldElement)(&x8))
|
||||
|
||||
native.Pow2k(&x32, &x16, 16, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&x32), (*MontgomeryDomainFieldElement)(&x32), (*MontgomeryDomainFieldElement)(&x16))
|
||||
|
||||
native.Pow2k(&tmp, &x32, 64, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x32))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 32, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x32))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 6, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101111))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 5, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 4, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x11))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 5, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1111))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 5, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x10101))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 4, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 3, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 3, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 5, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 9, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101111))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 6, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1111))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 2, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 5, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 6, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1111))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 5, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 4, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 5, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 5, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 3, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x11))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 10, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101111))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 2, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x11))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 5, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x11))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 5, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x11))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 3, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 7, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x10101))
|
||||
|
||||
native.Pow2k(&tmp, &tmp, 6, f)
|
||||
Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1111))
|
||||
|
||||
*wasInverted = (&native.Field{
|
||||
Value: *arg,
|
||||
Params: getP256FqParams(),
|
||||
Arithmetic: f,
|
||||
}).IsNonZero()
|
||||
Selectznz(out, uint1(*wasInverted), out, &tmp)
|
||||
}
|
||||
|
||||
// FromBytes converts a little endian byte array into a field element
|
||||
func (f p256FqArithmetic) FromBytes(out *[native.FieldLimbs]uint64, arg *[native.FieldBytes]byte) {
|
||||
FromBytes(out, arg)
|
||||
}
|
||||
|
||||
// ToBytes converts a field element to a little endian byte array
|
||||
func (f p256FqArithmetic) ToBytes(out *[native.FieldBytes]byte, arg *[native.FieldLimbs]uint64) {
|
||||
ToBytes(out, arg)
|
||||
}
|
||||
|
||||
// Selectznz performs conditional select.
|
||||
// selects arg1 if choice == 0 and arg2 if choice == 1
|
||||
func (f p256FqArithmetic) Selectznz(out, arg1, arg2 *[native.FieldLimbs]uint64, choice int) {
|
||||
Selectznz(out, uint1(choice), arg1, arg2)
|
||||
}
|
||||
|
||||
// generator = 7 mod q is a generator of the `q - 1` order multiplicative
|
||||
// subgroup, or in other words a primitive element of the field.
|
||||
// generator^t where t * 2^s + 1 = q
|
||||
var generator = &[native.FieldLimbs]uint64{0x55eb74ab1949fac9, 0xd5af25406e5aaa5d, 0x0000000000000001, 0x00000006fffffff9}
|
||||
|
||||
// s satisfies the equation 2^s * t = q - 1 with t odd.
|
||||
var s = 4
|
||||
|
||||
// rootOfUnity
|
||||
var rootOfUnity = &[native.FieldLimbs]uint64{0x0592d7fbb41e6602, 0x1546cad004378daf, 0xba807ace842a3dfc, 0xffc97f062a770992}
|
@ -1,328 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package fq
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
"github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
func TestFqSetOne(t *testing.T) {
|
||||
fq := P256FqNew().SetOne()
|
||||
require.NotNil(t, fq)
|
||||
require.Equal(t, fq.Value, getP256FqParams().R)
|
||||
}
|
||||
|
||||
func TestFqSetUint64(t *testing.T) {
|
||||
act := P256FqNew().SetUint64(1 << 60)
|
||||
require.NotNil(t, act)
|
||||
// Remember it will be in montgomery form
|
||||
require.Equal(t, act.Value[0], uint64(0xb3f3986dec632551))
|
||||
}
|
||||
|
||||
func TestFqAdd(t *testing.T) {
|
||||
lhs := P256FqNew().SetOne()
|
||||
rhs := P256FqNew().SetOne()
|
||||
exp := P256FqNew().SetUint64(2)
|
||||
res := P256FqNew().Add(lhs, rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, 1, res.Equal(exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint64() >> 2
|
||||
r := rand.Uint64() >> 2
|
||||
e := l + r
|
||||
lhs.SetUint64(l)
|
||||
rhs.SetUint64(r)
|
||||
exp.SetUint64(e)
|
||||
|
||||
a := P256FqNew().Add(lhs, rhs)
|
||||
require.NotNil(t, a)
|
||||
require.Equal(t, exp, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqSub(t *testing.T) {
|
||||
lhs := P256FqNew().SetOne()
|
||||
rhs := P256FqNew().SetOne()
|
||||
exp := P256FqNew().SetZero()
|
||||
res := P256FqNew().Sub(lhs, rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, 1, res.Equal(exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint64() >> 2
|
||||
r := rand.Uint64() >> 2
|
||||
if l < r {
|
||||
l, r = r, l
|
||||
}
|
||||
e := l - r
|
||||
lhs.SetUint64(l)
|
||||
rhs.SetUint64(r)
|
||||
exp.SetUint64(e)
|
||||
|
||||
a := P256FqNew().Sub(lhs, rhs)
|
||||
require.NotNil(t, a)
|
||||
require.Equal(t, exp, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqMul(t *testing.T) {
|
||||
lhs := P256FqNew().SetOne()
|
||||
rhs := P256FqNew().SetOne()
|
||||
exp := P256FqNew().SetOne()
|
||||
res := P256FqNew().Mul(lhs, rhs)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, 1, res.Equal(exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint32()
|
||||
r := rand.Uint32()
|
||||
e := uint64(l) * uint64(r)
|
||||
lhs.SetUint64(uint64(l))
|
||||
rhs.SetUint64(uint64(r))
|
||||
exp.SetUint64(e)
|
||||
|
||||
a := P256FqNew().Mul(lhs, rhs)
|
||||
require.NotNil(t, a)
|
||||
require.Equal(t, exp, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqDouble(t *testing.T) {
|
||||
a := P256FqNew().SetUint64(2)
|
||||
e := P256FqNew().SetUint64(4)
|
||||
require.Equal(t, e, P256FqNew().Double(a))
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
tv := rand.Uint32()
|
||||
ttv := uint64(tv) * 2
|
||||
a = P256FqNew().SetUint64(uint64(tv))
|
||||
e = P256FqNew().SetUint64(ttv)
|
||||
require.Equal(t, e, P256FqNew().Double(a))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqSquare(t *testing.T) {
|
||||
a := P256FqNew().SetUint64(4)
|
||||
e := P256FqNew().SetUint64(16)
|
||||
require.Equal(t, e, a.Square(a))
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
j := rand.Uint32()
|
||||
exp := uint64(j) * uint64(j)
|
||||
e.SetUint64(exp)
|
||||
a.SetUint64(uint64(j))
|
||||
require.Equal(t, e, a.Square(a))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqNeg(t *testing.T) {
|
||||
g := P256FqNew().SetRaw(generator)
|
||||
a := P256FqNew().SetOne()
|
||||
a.Neg(a)
|
||||
e := P256FqNew().SetRaw(&[native.FieldLimbs]uint64{0xe7739585f8c64aa2, 0x79cdf55b4e2f3d09, 0xffffffffffffffff, 0xfffffffe00000001})
|
||||
require.Equal(t, e, a)
|
||||
a.Neg(g)
|
||||
e = P256FqNew().SetRaw(&[native.FieldLimbs]uint64{0x9dce5617e3192a88, 0xe737d56d38bcf427, 0xfffffffffffffffd, 0xfffffff800000007})
|
||||
require.Equal(t, e, a)
|
||||
}
|
||||
|
||||
func TestFqExp(t *testing.T) {
|
||||
e := P256FqNew().SetUint64(8)
|
||||
a := P256FqNew().SetUint64(2)
|
||||
by := P256FqNew().SetUint64(3)
|
||||
require.Equal(t, e, a.Exp(a, by))
|
||||
}
|
||||
|
||||
func TestFqSqrt(t *testing.T) {
|
||||
t1 := P256FqNew().SetUint64(2)
|
||||
t2 := P256FqNew().Neg(t1)
|
||||
t3 := P256FqNew().Square(t1)
|
||||
_, wasSquare := t3.Sqrt(t3)
|
||||
|
||||
require.True(t, wasSquare)
|
||||
require.Equal(t, 1, t1.Equal(t3)|t2.Equal(t3))
|
||||
t1.SetUint64(7)
|
||||
_, wasSquare = t3.Sqrt(t1)
|
||||
require.False(t, wasSquare)
|
||||
}
|
||||
|
||||
func TestFqInvert(t *testing.T) {
|
||||
twoInv := P256FqNew().SetRaw(&[native.FieldLimbs]uint64{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x8000000000000000})
|
||||
two := P256FqNew().SetUint64(2)
|
||||
a, inverted := P256FqNew().Invert(two)
|
||||
require.True(t, inverted)
|
||||
require.Equal(t, a, twoInv)
|
||||
|
||||
rootOfUnityInv := P256FqNew().SetRaw(&[native.FieldLimbs]uint64{0xcfbf53b9618acf96, 0xf17e5c39df7bd05b, 0xc7acb1f83e3ad9ad, 0x4659a42b394ff7df})
|
||||
rootOU := P256FqNew().SetRaw(rootOfUnity)
|
||||
a, inverted = P256FqNew().Invert(rootOU)
|
||||
require.True(t, inverted)
|
||||
require.Equal(t, a, rootOfUnityInv)
|
||||
|
||||
lhs := P256FqNew().SetUint64(9)
|
||||
rhs := P256FqNew().SetUint64(3)
|
||||
rhsInv, inverted := P256FqNew().Invert(rhs)
|
||||
require.True(t, inverted)
|
||||
require.Equal(t, rhs, P256FqNew().Mul(lhs, rhsInv))
|
||||
|
||||
rhs.SetZero()
|
||||
_, inverted = P256FqNew().Invert(rhs)
|
||||
require.False(t, inverted)
|
||||
}
|
||||
|
||||
func TestFqCMove(t *testing.T) {
|
||||
t1 := P256FqNew().SetUint64(5)
|
||||
t2 := P256FqNew().SetUint64(10)
|
||||
require.Equal(t, t1, P256FqNew().CMove(t1, t2, 0))
|
||||
require.Equal(t, t2, P256FqNew().CMove(t1, t2, 1))
|
||||
}
|
||||
|
||||
func TestFqBytes(t *testing.T) {
|
||||
t1 := P256FqNew().SetUint64(99)
|
||||
seq := t1.Bytes()
|
||||
t2, err := P256FqNew().SetBytes(&seq)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, t1, t2)
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
t1.SetUint64(rand.Uint64())
|
||||
seq = t1.Bytes()
|
||||
_, err = t2.SetBytes(&seq)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, t1, t2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqCmp(t *testing.T) {
|
||||
tests := []struct {
|
||||
a *native.Field
|
||||
b *native.Field
|
||||
e int
|
||||
}{
|
||||
{
|
||||
a: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{2731658267414164836, 14655288906067898431, 6537465423330262322, 8306191141697566219}),
|
||||
b: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{6472764012681988529, 10848812988401906064, 2961825807536828898, 4282183981941645679}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{8023004109510539223, 4652004072850285717, 1877219145646046927, 383214385093921911}),
|
||||
b: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{10099384440823804262, 16139476942229308465, 8636966320777393798, 5435928725024696785}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{3741840066202388211, 12165774400417314871, 16619312580230515379, 16195032234110087705}),
|
||||
b: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{3905865991286066744, 543690822309071825, 17963103015950210055, 3745476720756119742}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{16660853697936147788, 7799793619412111108, 13515141085171033220, 2641079731236069032}),
|
||||
b: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{17790588295388238399, 571847801379669440, 14537208974498222469, 12792570372087452754}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{3912839285384959186, 2701177075110484070, 6453856448115499033, 6475797457962597458}),
|
||||
b: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{1282566391665688512, 13503640416992806563, 2962240104675990153, 3374904770947067689}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{5716631803409360103, 7859567470082614154, 12747956220853330146, 18434584096087315020}),
|
||||
b: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{16317076441459028418, 12854146980376319601, 2258436689269031143, 9531877130792223752}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{17955191469941083403, 10350326247207200880, 17263512235150705075, 12700328451238078022}),
|
||||
b: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{6767595547459644695, 7146403825494928147, 12269344038346710612, 9122477829383225603}),
|
||||
e: 1,
|
||||
},
|
||||
{
|
||||
a: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{17099388671847024438, 6426264987820696548, 10641143464957227405, 7709745403700754098}),
|
||||
b: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{10799154372990268556, 17178492485719929374, 5705777922258988797, 8051037767683567782}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{4567139260680454325, 1629385880182139061, 16607020832317899145, 1261011562621553200}),
|
||||
b: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{13487234491304534488, 17872642955936089265, 17651026784972590233, 9468934643333871559}),
|
||||
e: -1,
|
||||
},
|
||||
{
|
||||
a: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{18071070103467571798, 11787850505799426140, 10631355976141928593, 4867785203635092610}),
|
||||
b: P256FqNew().SetRaw(&[native.FieldLimbs]uint64{12596443599426461624, 10176122686151524591, 17075755296887483439, 6726169532695070719}),
|
||||
e: -1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
require.Equal(t, test.e, test.a.Cmp(test.b))
|
||||
require.Equal(t, -test.e, test.b.Cmp(test.a))
|
||||
require.Equal(t, 0, test.a.Cmp(test.a))
|
||||
require.Equal(t, 0, test.b.Cmp(test.b))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFqBigInt(t *testing.T) {
|
||||
t1 := P256FqNew().SetBigInt(big.NewInt(9999))
|
||||
t2 := P256FqNew().SetBigInt(t1.BigInt())
|
||||
require.Equal(t, t1, t2)
|
||||
|
||||
e := P256FqNew().SetRaw(&[native.FieldLimbs]uint64{0x21dcaaadf1cb6aa0, 0x568de5f5990a98d7, 0x354f43b0d837fac5, 0x3e02532cb23f481a})
|
||||
b := new(big.Int).SetBytes([]byte{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9})
|
||||
t1.SetBigInt(b)
|
||||
require.Equal(t, e, t1)
|
||||
e.Value[0] = 0xd1dd20150a97bab1
|
||||
e.Value[1] = 0x665914b80e0d05ad
|
||||
e.Value[2] = 0xcab0bc4f27c8053a
|
||||
e.Value[3] = 0xc1fdacd24dc0b7e6
|
||||
b.Neg(b)
|
||||
t1.SetBigInt(b)
|
||||
require.Equal(t, e, t1)
|
||||
}
|
||||
|
||||
func TestFqSetBytesWide(t *testing.T) {
|
||||
e := P256FqNew().SetRaw(&[native.FieldLimbs]uint64{0xe2b8d4b0e576c8fa, 0x9d2b215f85d3bdf7, 0xf6070a872442640c, 0xcf15d1e49c990b88})
|
||||
|
||||
a := P256FqNew().SetBytesWide(&[64]byte{
|
||||
0x69, 0x23, 0x5a, 0x0b, 0xce, 0x0c, 0xa8, 0x64,
|
||||
0x3c, 0x78, 0xbc, 0x01, 0x05, 0xef, 0xf2, 0x84,
|
||||
0xde, 0xbb, 0x6b, 0xc8, 0x63, 0x5e, 0x6e, 0x69,
|
||||
0x62, 0xcc, 0xc6, 0x2d, 0xf5, 0x72, 0x40, 0x92,
|
||||
0x28, 0x11, 0xd6, 0xc8, 0x07, 0xa5, 0x88, 0x82,
|
||||
0xfe, 0xe3, 0x97, 0xf6, 0x1e, 0xfb, 0x2e, 0x3b,
|
||||
0x27, 0x5f, 0x85, 0x06, 0x8d, 0x99, 0xa4, 0x75,
|
||||
0xc0, 0x2c, 0x71, 0x69, 0x9e, 0x58, 0xea, 0x52,
|
||||
})
|
||||
require.Equal(t, e, a)
|
||||
}
|
||||
|
||||
func TestFpSetBytesWideBigInt(t *testing.T) {
|
||||
params := getP256FqParams()
|
||||
var tv2 [64]byte
|
||||
for i := 0; i < 25; i++ {
|
||||
_, _ = crand.Read(tv2[:])
|
||||
e := new(big.Int).SetBytes(tv2[:])
|
||||
e.Mod(e, params.BiModulus)
|
||||
|
||||
tv := internal.ReverseScalarBytes(tv2[:])
|
||||
copy(tv2[:], tv)
|
||||
a := P256FqNew().SetBytesWide(&tv2)
|
||||
require.Equal(t, 0, e.Cmp(a.BigInt()))
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,317 +0,0 @@
|
||||
package p256
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
"github.com/onsonr/hway/crypto/core/curves/native/p256/fp"
|
||||
"github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
var (
|
||||
p256PointInitonce sync.Once
|
||||
p256PointParams native.EllipticPointParams
|
||||
p256PointSswuInitOnce sync.Once
|
||||
p256PointSswuParams native.SswuParams
|
||||
)
|
||||
|
||||
func P256PointNew() *native.EllipticPoint {
|
||||
return &native.EllipticPoint{
|
||||
X: fp.P256FpNew(),
|
||||
Y: fp.P256FpNew(),
|
||||
Z: fp.P256FpNew(),
|
||||
Params: getP256PointParams(),
|
||||
Arithmetic: &p256PointArithmetic{},
|
||||
}
|
||||
}
|
||||
|
||||
func p256PointParamsInit() {
|
||||
// How these values were derived
|
||||
// left for informational purposes
|
||||
// params := elliptic.P256().Params()
|
||||
// a := big.NewInt(-3)
|
||||
// a.Mod(a, params.P)
|
||||
// capA := fp.P256FpNew().SetBigInt(a)
|
||||
// capB := fp.P256FpNew().SetBigInt(params.B)
|
||||
// gx := fp.P256FpNew().SetBigInt(params.Gx)
|
||||
// gy := fp.P256FpNew().SetBigInt(params.Gy)
|
||||
|
||||
p256PointParams = native.EllipticPointParams{
|
||||
A: fp.P256FpNew().SetRaw(&[native.FieldLimbs]uint64{0xfffffffffffffffc, 0x00000003ffffffff, 0x0000000000000000, 0xfffffffc00000004}),
|
||||
B: fp.P256FpNew().SetRaw(&[native.FieldLimbs]uint64{0xd89cdf6229c4bddf, 0xacf005cd78843090, 0xe5a220abf7212ed6, 0xdc30061d04874834}),
|
||||
Gx: fp.P256FpNew().SetRaw(&[native.FieldLimbs]uint64{0x79e730d418a9143c, 0x75ba95fc5fedb601, 0x79fb732b77622510, 0x18905f76a53755c6}),
|
||||
Gy: fp.P256FpNew().SetRaw(&[native.FieldLimbs]uint64{0xddf25357ce95560a, 0x8b4ab8e4ba19e45c, 0xd2e88688dd21f325, 0x8571ff1825885d85}),
|
||||
BitSize: 256,
|
||||
Name: "P256",
|
||||
}
|
||||
}
|
||||
|
||||
func getP256PointParams() *native.EllipticPointParams {
|
||||
p256PointInitonce.Do(p256PointParamsInit)
|
||||
return &p256PointParams
|
||||
}
|
||||
|
||||
func getP256PointSswuParams() *native.SswuParams {
|
||||
p256PointSswuInitOnce.Do(p256PointSswuParamsInit)
|
||||
return &p256PointSswuParams
|
||||
}
|
||||
|
||||
func p256PointSswuParamsInit() {
|
||||
// How these values were derived
|
||||
// left for informational purposes
|
||||
//params := elliptic.P256().Params()
|
||||
//
|
||||
//// c1 = (q - 3) / 4
|
||||
//c1 := new(big.Int).Set(params.P)
|
||||
//c1.Sub(c1, big.NewInt(3))
|
||||
//c1.Rsh(c1, 2)
|
||||
//
|
||||
//a := big.NewInt(-3)
|
||||
//a.Mod(a, params.P)
|
||||
//b := new(big.Int).Set(params.B)
|
||||
//z := big.NewInt(-10)
|
||||
//z.Mod(z, params.P)
|
||||
//// sqrt(-Z^3)
|
||||
//zTmp := new(big.Int).Exp(z, big.NewInt(3), nil)
|
||||
//zTmp = zTmp.Neg(zTmp)
|
||||
//zTmp.Mod(zTmp, params.P)
|
||||
//c2 := new(big.Int).ModSqrt(zTmp, params.P)
|
||||
//
|
||||
//var capC1Bytes [32]byte
|
||||
//c1.FillBytes(capC1Bytes[:])
|
||||
//capC1 := fp.P256FpNew().SetRaw(&[native.FieldLimbs]uint64{
|
||||
// binary.BigEndian.Uint64(capC1Bytes[24:]),
|
||||
// binary.BigEndian.Uint64(capC1Bytes[16:24]),
|
||||
// binary.BigEndian.Uint64(capC1Bytes[8:16]),
|
||||
// binary.BigEndian.Uint64(capC1Bytes[:8]),
|
||||
//})
|
||||
//capC2 := fp.P256FpNew().SetBigInt(c2)
|
||||
//capA := fp.P256FpNew().SetBigInt(a)
|
||||
//capB := fp.P256FpNew().SetBigInt(b)
|
||||
//capZ := fp.P256FpNew().SetBigInt(z)
|
||||
|
||||
p256PointSswuParams = native.SswuParams{
|
||||
C1: [native.FieldLimbs]uint64{0xffffffffffffffff, 0x000000003fffffff, 0x4000000000000000, 0x3fffffffc0000000},
|
||||
C2: [native.FieldLimbs]uint64{0x53e43951f64fdbe7, 0xb2806c63966a1a66, 0x1ac5d59c3298bf50, 0xa3323851ba997e27},
|
||||
A: [native.FieldLimbs]uint64{0xfffffffffffffffc, 0x00000003ffffffff, 0x0000000000000000, 0xfffffffc00000004},
|
||||
B: [native.FieldLimbs]uint64{0xd89cdf6229c4bddf, 0xacf005cd78843090, 0xe5a220abf7212ed6, 0xdc30061d04874834},
|
||||
Z: [native.FieldLimbs]uint64{0xfffffffffffffff5, 0x0000000affffffff, 0x0000000000000000, 0xfffffff50000000b},
|
||||
}
|
||||
}
|
||||
|
||||
type p256PointArithmetic struct{}
|
||||
|
||||
func (k p256PointArithmetic) Hash(out *native.EllipticPoint, hash *native.EllipticPointHasher, msg, dst []byte) error {
|
||||
var u []byte
|
||||
sswuParams := getP256PointSswuParams()
|
||||
|
||||
switch hash.Type() {
|
||||
case native.XMD:
|
||||
u = native.ExpandMsgXmd(hash, msg, dst, 96)
|
||||
case native.XOF:
|
||||
u = native.ExpandMsgXof(hash, msg, dst, 96)
|
||||
}
|
||||
var buf [64]byte
|
||||
copy(buf[:48], internal.ReverseScalarBytes(u[:48]))
|
||||
u0 := fp.P256FpNew().SetBytesWide(&buf)
|
||||
copy(buf[:48], internal.ReverseScalarBytes(u[48:]))
|
||||
u1 := fp.P256FpNew().SetBytesWide(&buf)
|
||||
|
||||
q0x, q0y := sswuParams.Osswu3mod4(u0)
|
||||
q1x, q1y := sswuParams.Osswu3mod4(u1)
|
||||
out.X = q0x
|
||||
out.Y = q0y
|
||||
out.Z.SetOne()
|
||||
tv := &native.EllipticPoint{
|
||||
X: q1x,
|
||||
Y: q1y,
|
||||
Z: fp.P256FpNew().SetOne(),
|
||||
}
|
||||
k.Add(out, out, tv)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k p256PointArithmetic) Double(out, arg *native.EllipticPoint) {
|
||||
// Addition formula from Renes-Costello-Batina 2015
|
||||
// (https://eprint.iacr.org/2015/1060 Algorithm 6)
|
||||
var xx, yy, zz, xy2, yz2, xz2, bzz, bzz3 [native.FieldLimbs]uint64
|
||||
var yyMBzz3, yyPBzz3, yFrag, xFrag, zz3 [native.FieldLimbs]uint64
|
||||
var bxz2, bxz6, xx3Mzz3, x, y, z [native.FieldLimbs]uint64
|
||||
b := getP256PointParams().B.Value
|
||||
f := arg.X.Arithmetic
|
||||
|
||||
f.Square(&xx, &arg.X.Value)
|
||||
f.Square(&yy, &arg.Y.Value)
|
||||
f.Square(&zz, &arg.Z.Value)
|
||||
|
||||
f.Mul(&xy2, &arg.X.Value, &arg.Y.Value)
|
||||
f.Add(&xy2, &xy2, &xy2)
|
||||
|
||||
f.Mul(&yz2, &arg.Y.Value, &arg.Z.Value)
|
||||
f.Add(&yz2, &yz2, &yz2)
|
||||
|
||||
f.Mul(&xz2, &arg.X.Value, &arg.Z.Value)
|
||||
f.Add(&xz2, &xz2, &xz2)
|
||||
|
||||
f.Mul(&bzz, &b, &zz)
|
||||
f.Sub(&bzz, &bzz, &xz2)
|
||||
|
||||
f.Add(&bzz3, &bzz, &bzz)
|
||||
f.Add(&bzz3, &bzz3, &bzz)
|
||||
|
||||
f.Sub(&yyMBzz3, &yy, &bzz3)
|
||||
f.Add(&yyPBzz3, &yy, &bzz3)
|
||||
f.Mul(&yFrag, &yyPBzz3, &yyMBzz3)
|
||||
f.Mul(&xFrag, &yyMBzz3, &xy2)
|
||||
|
||||
f.Add(&zz3, &zz, &zz)
|
||||
f.Add(&zz3, &zz3, &zz)
|
||||
|
||||
f.Mul(&bxz2, &b, &xz2)
|
||||
f.Sub(&bxz2, &bxz2, &zz3)
|
||||
f.Sub(&bxz2, &bxz2, &xx)
|
||||
|
||||
f.Add(&bxz6, &bxz2, &bxz2)
|
||||
f.Add(&bxz6, &bxz6, &bxz2)
|
||||
|
||||
f.Add(&xx3Mzz3, &xx, &xx)
|
||||
f.Add(&xx3Mzz3, &xx3Mzz3, &xx)
|
||||
f.Sub(&xx3Mzz3, &xx3Mzz3, &zz3)
|
||||
|
||||
f.Mul(&x, &bxz6, &yz2)
|
||||
f.Sub(&x, &xFrag, &x)
|
||||
|
||||
f.Mul(&y, &xx3Mzz3, &bxz6)
|
||||
f.Add(&y, &yFrag, &y)
|
||||
|
||||
f.Mul(&z, &yz2, &yy)
|
||||
f.Add(&z, &z, &z)
|
||||
f.Add(&z, &z, &z)
|
||||
|
||||
out.X.Value = x
|
||||
out.Y.Value = y
|
||||
out.Z.Value = z
|
||||
}
|
||||
|
||||
func (k p256PointArithmetic) Add(out, arg1, arg2 *native.EllipticPoint) {
|
||||
// Addition formula from Renes-Costello-Batina 2015
|
||||
// (https://eprint.iacr.org/2015/1060 Algorithm 4).
|
||||
var xx, yy, zz, zz3, bxz, bxz3 [native.FieldLimbs]uint64
|
||||
var tv1, xyPairs, yzPairs, xzPairs [native.FieldLimbs]uint64
|
||||
var bzz, bzz3, yyMBzz3, yyPBzz3 [native.FieldLimbs]uint64
|
||||
var xx3Mzz3, x, y, z [native.FieldLimbs]uint64
|
||||
f := arg1.X.Arithmetic
|
||||
b := getP256PointParams().B.Value
|
||||
|
||||
f.Mul(&xx, &arg1.X.Value, &arg2.X.Value)
|
||||
f.Mul(&yy, &arg1.Y.Value, &arg2.Y.Value)
|
||||
f.Mul(&zz, &arg1.Z.Value, &arg2.Z.Value)
|
||||
|
||||
f.Add(&tv1, &arg2.X.Value, &arg2.Y.Value)
|
||||
f.Add(&xyPairs, &arg1.X.Value, &arg1.Y.Value)
|
||||
f.Mul(&xyPairs, &xyPairs, &tv1)
|
||||
f.Sub(&xyPairs, &xyPairs, &xx)
|
||||
f.Sub(&xyPairs, &xyPairs, &yy)
|
||||
|
||||
f.Add(&tv1, &arg2.Y.Value, &arg2.Z.Value)
|
||||
f.Add(&yzPairs, &arg1.Y.Value, &arg1.Z.Value)
|
||||
f.Mul(&yzPairs, &yzPairs, &tv1)
|
||||
f.Sub(&yzPairs, &yzPairs, &yy)
|
||||
f.Sub(&yzPairs, &yzPairs, &zz)
|
||||
|
||||
f.Add(&tv1, &arg2.X.Value, &arg2.Z.Value)
|
||||
f.Add(&xzPairs, &arg1.X.Value, &arg1.Z.Value)
|
||||
f.Mul(&xzPairs, &xzPairs, &tv1)
|
||||
f.Sub(&xzPairs, &xzPairs, &xx)
|
||||
f.Sub(&xzPairs, &xzPairs, &zz)
|
||||
|
||||
f.Mul(&bzz, &b, &zz)
|
||||
f.Sub(&bzz, &xzPairs, &bzz)
|
||||
|
||||
f.Add(&bzz3, &bzz, &bzz)
|
||||
f.Add(&bzz3, &bzz3, &bzz)
|
||||
|
||||
f.Sub(&yyMBzz3, &yy, &bzz3)
|
||||
f.Add(&yyPBzz3, &yy, &bzz3)
|
||||
|
||||
f.Add(&zz3, &zz, &zz)
|
||||
f.Add(&zz3, &zz3, &zz)
|
||||
|
||||
f.Mul(&bxz, &b, &xzPairs)
|
||||
f.Sub(&bxz, &bxz, &zz3)
|
||||
f.Sub(&bxz, &bxz, &xx)
|
||||
|
||||
f.Add(&bxz3, &bxz, &bxz)
|
||||
f.Add(&bxz3, &bxz3, &bxz)
|
||||
|
||||
f.Add(&xx3Mzz3, &xx, &xx)
|
||||
f.Add(&xx3Mzz3, &xx3Mzz3, &xx)
|
||||
f.Sub(&xx3Mzz3, &xx3Mzz3, &zz3)
|
||||
|
||||
f.Mul(&tv1, &yzPairs, &bxz3)
|
||||
f.Mul(&x, &yyPBzz3, &xyPairs)
|
||||
f.Sub(&x, &x, &tv1)
|
||||
|
||||
f.Mul(&tv1, &xx3Mzz3, &bxz3)
|
||||
f.Mul(&y, &yyPBzz3, &yyMBzz3)
|
||||
f.Add(&y, &y, &tv1)
|
||||
|
||||
f.Mul(&tv1, &xyPairs, &xx3Mzz3)
|
||||
f.Mul(&z, &yyMBzz3, &yzPairs)
|
||||
f.Add(&z, &z, &tv1)
|
||||
|
||||
e1 := arg1.Z.IsZero()
|
||||
e2 := arg2.Z.IsZero()
|
||||
|
||||
// If arg1 is identity set it to arg2
|
||||
f.Selectznz(&z, &z, &arg2.Z.Value, e1)
|
||||
f.Selectznz(&y, &y, &arg2.Y.Value, e1)
|
||||
f.Selectznz(&x, &x, &arg2.X.Value, e1)
|
||||
// If arg2 is identity set it to arg1
|
||||
f.Selectznz(&z, &z, &arg1.Z.Value, e2)
|
||||
f.Selectznz(&y, &y, &arg1.Y.Value, e2)
|
||||
f.Selectznz(&x, &x, &arg1.X.Value, e2)
|
||||
|
||||
out.X.Value = x
|
||||
out.Y.Value = y
|
||||
out.Z.Value = z
|
||||
}
|
||||
|
||||
func (k p256PointArithmetic) IsOnCurve(arg *native.EllipticPoint) bool {
|
||||
affine := P256PointNew()
|
||||
k.ToAffine(affine, arg)
|
||||
lhs := fp.P256FpNew().Square(affine.Y)
|
||||
rhs := fp.P256FpNew()
|
||||
k.RhsEq(rhs, affine.X)
|
||||
return lhs.Equal(rhs) == 1
|
||||
}
|
||||
|
||||
func (k p256PointArithmetic) ToAffine(out, arg *native.EllipticPoint) {
|
||||
var wasInverted int
|
||||
var zero, x, y, z [native.FieldLimbs]uint64
|
||||
f := arg.X.Arithmetic
|
||||
|
||||
f.Invert(&wasInverted, &z, &arg.Z.Value)
|
||||
f.Mul(&x, &arg.X.Value, &z)
|
||||
f.Mul(&y, &arg.Y.Value, &z)
|
||||
|
||||
out.Z.SetOne()
|
||||
// If point at infinity this does nothing
|
||||
f.Selectznz(&x, &zero, &x, wasInverted)
|
||||
f.Selectznz(&y, &zero, &y, wasInverted)
|
||||
f.Selectznz(&z, &zero, &out.Z.Value, wasInverted)
|
||||
|
||||
out.X.Value = x
|
||||
out.Y.Value = y
|
||||
out.Z.Value = z
|
||||
out.Params = arg.Params
|
||||
out.Arithmetic = arg.Arithmetic
|
||||
}
|
||||
|
||||
func (k p256PointArithmetic) RhsEq(out, x *native.Field) {
|
||||
// Elliptic curve equation for p256 is: y^2 = x^3 ax + b
|
||||
out.Square(x)
|
||||
out.Mul(out, x)
|
||||
out.Add(out, getP256PointParams().B)
|
||||
out.Add(out, fp.P256FpNew().Mul(getP256PointParams().A, x))
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
package p256_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/hway/crypto/core/curves"
|
||||
"github.com/onsonr/hway/crypto/core/curves/native"
|
||||
"github.com/onsonr/hway/crypto/core/curves/native/p256"
|
||||
"github.com/onsonr/hway/crypto/core/curves/native/p256/fp"
|
||||
)
|
||||
|
||||
func TestP256PointArithmetic_Double(t *testing.T) {
|
||||
g := p256.P256PointNew().Generator()
|
||||
pt1 := p256.P256PointNew().Double(g)
|
||||
pt2 := p256.P256PointNew().Add(g, g)
|
||||
pt3 := p256.P256PointNew().Mul(g, fp.P256FpNew().SetUint64(2))
|
||||
|
||||
e1 := pt1.Equal(pt2)
|
||||
e2 := pt1.Equal(pt3)
|
||||
e3 := pt2.Equal(pt3)
|
||||
require.Equal(t, 1, e1)
|
||||
require.Equal(t, 1, e2)
|
||||
require.Equal(t, 1, e3)
|
||||
}
|
||||
|
||||
func TestP256PointArithmetic_Hash(t *testing.T) {
|
||||
var b [32]byte
|
||||
sc, err := p256.P256PointNew().Hash(b[:], native.EllipticPointHasherSha256())
|
||||
sc1 := curves.P256().NewIdentityPoint().Hash(b[:])
|
||||
fmt.Printf("%v\n", sc1)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.True(t, !sc.IsIdentity())
|
||||
require.True(t, sc.IsOnCurve())
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
---
|
||||
aliases: [README]
|
||||
tags: []
|
||||
title: README
|
||||
linter-yaml-title-alias: README
|
||||
date created: Wednesday, April 17th 2024, 4:11:40 pm
|
||||
date modified: Thursday, April 18th 2024, 8:19:25 am
|
||||
---
|
||||
|
||||
## Pallas and Pasta Curve
|
@ -1,369 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package fp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
type Fp fiat_pasta_fp_montgomery_domain_field_element
|
||||
|
||||
// r = 2^256 mod p
|
||||
var r = &Fp{0x34786d38fffffffd, 0x992c350be41914ad, 0xffffffffffffffff, 0x3fffffffffffffff}
|
||||
|
||||
// r2 = 2^512 mod p
|
||||
var r2 = &Fp{0x8c78ecb30000000f, 0xd7d30dbd8b0de0e7, 0x7797a99bc3c95d18, 0x096d41af7b9cb714}
|
||||
|
||||
// r3 = 2^768 mod p
|
||||
var r3 = &Fp{0xf185a5993a9e10f9, 0xf6a68f3b6ac5b1d1, 0xdf8d1014353fd42c, 0x2ae309222d2d9910}
|
||||
|
||||
// generator = 5 mod p is a generator of the `p - 1` order multiplicative
|
||||
// subgroup, or in other words a primitive element of the field.
|
||||
var generator = &Fp{0xa1a55e68ffffffed, 0x74c2a54b4f4982f3, 0xfffffffffffffffd, 0x3fffffffffffffff}
|
||||
|
||||
var s = 32
|
||||
|
||||
// modulus representation
|
||||
// p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
|
||||
var modulus = &Fp{0x992d30ed00000001, 0x224698fc094cf91b, 0x0000000000000000, 0x4000000000000000}
|
||||
|
||||
var biModulus = new(big.Int).SetBytes([]byte{
|
||||
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x22, 0x46, 0x98, 0xfc, 0x09, 0x4c, 0xf9, 0x1b,
|
||||
0x99, 0x2d, 0x30, 0xed, 0x00, 0x00, 0x00, 0x01,
|
||||
})
|
||||
|
||||
// Cmp returns -1 if fp < rhs
|
||||
// 0 if fp == rhs
|
||||
// 1 if fp > rhs
|
||||
func (fp *Fp) Cmp(rhs *Fp) int {
|
||||
gt := 0
|
||||
lt := 0
|
||||
for i := len(fp) - 1; i >= 0; i-- {
|
||||
gt |= int((rhs[i]-fp[i])>>63) &^ lt
|
||||
lt |= int((fp[i]-rhs[i])>>63) &^ gt
|
||||
}
|
||||
return gt - lt
|
||||
}
|
||||
|
||||
// Equal returns true if fp == rhs
|
||||
func (fp *Fp) Equal(rhs *Fp) bool {
|
||||
t := fp[0] ^ rhs[0]
|
||||
t |= fp[1] ^ rhs[1]
|
||||
t |= fp[2] ^ rhs[2]
|
||||
t |= fp[3] ^ rhs[3]
|
||||
return t == 0
|
||||
}
|
||||
|
||||
// IsZero returns true if fp == 0
|
||||
func (fp *Fp) IsZero() bool {
|
||||
t := fp[0]
|
||||
t |= fp[1]
|
||||
t |= fp[2]
|
||||
t |= fp[3]
|
||||
return t == 0
|
||||
}
|
||||
|
||||
// IsOne returns true if fp == R
|
||||
func (fp *Fp) IsOne() bool {
|
||||
return fp.Equal(r)
|
||||
}
|
||||
|
||||
func (fp *Fp) IsOdd() bool {
|
||||
tv := new(fiat_pasta_fp_non_montgomery_domain_field_element)
|
||||
fiat_pasta_fp_from_montgomery(tv, (*fiat_pasta_fp_montgomery_domain_field_element)(fp))
|
||||
return tv[0]&0x01 == 0x01
|
||||
}
|
||||
|
||||
// Set fp == rhs
|
||||
func (fp *Fp) Set(rhs *Fp) *Fp {
|
||||
fp[0] = rhs[0]
|
||||
fp[1] = rhs[1]
|
||||
fp[2] = rhs[2]
|
||||
fp[3] = rhs[3]
|
||||
return fp
|
||||
}
|
||||
|
||||
// SetUint64 sets fp == rhs
|
||||
func (fp *Fp) SetUint64(rhs uint64) *Fp {
|
||||
r := &fiat_pasta_fp_non_montgomery_domain_field_element{rhs, 0, 0, 0}
|
||||
fiat_pasta_fp_to_montgomery((*fiat_pasta_fp_montgomery_domain_field_element)(fp), r)
|
||||
return fp
|
||||
}
|
||||
|
||||
func (fp *Fp) SetBool(rhs bool) *Fp {
|
||||
if rhs {
|
||||
fp.SetOne()
|
||||
} else {
|
||||
fp.SetZero()
|
||||
}
|
||||
return fp
|
||||
}
|
||||
|
||||
// SetOne fp == R
|
||||
func (fp *Fp) SetOne() *Fp {
|
||||
return fp.Set(r)
|
||||
}
|
||||
|
||||
// SetZero fp == 0
|
||||
func (fp *Fp) SetZero() *Fp {
|
||||
fp[0] = 0
|
||||
fp[1] = 0
|
||||
fp[2] = 0
|
||||
fp[3] = 0
|
||||
return fp
|
||||
}
|
||||
|
||||
// SetBytesWide takes 64 bytes as input and treats them as a 512-bit number.
|
||||
// Attributed to https://github.com/zcash/pasta_curves/blob/main/src/fields/fp.rs#L255
|
||||
// We reduce an arbitrary 512-bit number by decomposing it into two 256-bit digits
|
||||
// with the higher bits multiplied by 2^256. Thus, we perform two reductions
|
||||
//
|
||||
// 1. the lower bits are multiplied by R^2, as normal
|
||||
// 2. the upper bits are multiplied by R^2 * 2^256 = R^3
|
||||
//
|
||||
// and computing their sum in the field. It remains to see that arbitrary 256-bit
|
||||
// numbers can be placed into Montgomery form safely using the reduction. The
|
||||
// reduction works so long as the product is less than R=2^256 multiplied by
|
||||
// the modulus. This holds because for any `c` smaller than the modulus, we have
|
||||
// that (2^256 - 1)*c is an acceptable product for the reduction. Therefore, the
|
||||
// reduction always works so long as `c` is in the field; in this case it is either the
|
||||
// constant `r2` or `r3`.
|
||||
func (fp *Fp) SetBytesWide(input *[64]byte) *Fp {
|
||||
d0 := fiat_pasta_fp_montgomery_domain_field_element{
|
||||
binary.LittleEndian.Uint64(input[:8]),
|
||||
binary.LittleEndian.Uint64(input[8:16]),
|
||||
binary.LittleEndian.Uint64(input[16:24]),
|
||||
binary.LittleEndian.Uint64(input[24:32]),
|
||||
}
|
||||
d1 := fiat_pasta_fp_montgomery_domain_field_element{
|
||||
binary.LittleEndian.Uint64(input[32:40]),
|
||||
binary.LittleEndian.Uint64(input[40:48]),
|
||||
binary.LittleEndian.Uint64(input[48:56]),
|
||||
binary.LittleEndian.Uint64(input[56:64]),
|
||||
}
|
||||
// Convert to Montgomery form
|
||||
tv1 := new(fiat_pasta_fp_montgomery_domain_field_element)
|
||||
tv2 := new(fiat_pasta_fp_montgomery_domain_field_element)
|
||||
// d0 * r2 + d1 * r3
|
||||
fiat_pasta_fp_mul(tv1, &d0, (*fiat_pasta_fp_montgomery_domain_field_element)(r2))
|
||||
fiat_pasta_fp_mul(tv2, &d1, (*fiat_pasta_fp_montgomery_domain_field_element)(r3))
|
||||
fiat_pasta_fp_add((*fiat_pasta_fp_montgomery_domain_field_element)(fp), tv1, tv2)
|
||||
return fp
|
||||
}
|
||||
|
||||
// SetBytes attempts to convert a little endian byte representation
|
||||
// of a scalar into a `Fp`, failing if input is not canonical
|
||||
func (fp *Fp) SetBytes(input *[32]byte) (*Fp, error) {
|
||||
d0 := &Fp{
|
||||
binary.LittleEndian.Uint64(input[:8]),
|
||||
binary.LittleEndian.Uint64(input[8:16]),
|
||||
binary.LittleEndian.Uint64(input[16:24]),
|
||||
binary.LittleEndian.Uint64(input[24:32]),
|
||||
}
|
||||
if d0.Cmp(modulus) != -1 {
|
||||
return nil, fmt.Errorf("invalid byte sequence")
|
||||
}
|
||||
fiat_pasta_fp_from_bytes((*[4]uint64)(fp), input)
|
||||
fiat_pasta_fp_to_montgomery((*fiat_pasta_fp_montgomery_domain_field_element)(fp), (*fiat_pasta_fp_non_montgomery_domain_field_element)(fp))
|
||||
return fp, nil
|
||||
}
|
||||
|
||||
// SetBigInt initializes an element from big.Int
|
||||
// The value is reduced by the modulus
|
||||
func (fp *Fp) SetBigInt(bi *big.Int) *Fp {
|
||||
var buffer [32]byte
|
||||
r := new(big.Int).Set(bi)
|
||||
r.Mod(r, biModulus)
|
||||
r.FillBytes(buffer[:])
|
||||
copy(buffer[:], internal.ReverseScalarBytes(buffer[:]))
|
||||
_, _ = fp.SetBytes(&buffer)
|
||||
return fp
|
||||
}
|
||||
|
||||
// SetRaw converts a raw array into a field element
|
||||
func (fp *Fp) SetRaw(array *[4]uint64) *Fp {
|
||||
fiat_pasta_fp_to_montgomery((*fiat_pasta_fp_montgomery_domain_field_element)(fp), (*fiat_pasta_fp_non_montgomery_domain_field_element)(array))
|
||||
return fp
|
||||
}
|
||||
|
||||
// Bytes converts this element into a byte representation
|
||||
// in little endian byte order
|
||||
func (fp *Fp) Bytes() [32]byte {
|
||||
var output [32]byte
|
||||
tv := new(fiat_pasta_fp_non_montgomery_domain_field_element)
|
||||
fiat_pasta_fp_from_montgomery(tv, (*fiat_pasta_fp_montgomery_domain_field_element)(fp))
|
||||
fiat_pasta_fp_to_bytes(&output, (*[4]uint64)(tv))
|
||||
return output
|
||||
}
|
||||
|
||||
// BigInt converts this element into the big.Int struct
|
||||
func (fp *Fp) BigInt() *big.Int {
|
||||
buffer := fp.Bytes()
|
||||
return new(big.Int).SetBytes(internal.ReverseScalarBytes(buffer[:]))
|
||||
}
|
||||
|
||||
// Double this element
|
||||
func (fp *Fp) Double(elem *Fp) *Fp {
|
||||
delem := (*fiat_pasta_fp_montgomery_domain_field_element)(elem)
|
||||
fiat_pasta_fp_add((*fiat_pasta_fp_montgomery_domain_field_element)(fp), delem, delem)
|
||||
return fp
|
||||
}
|
||||
|
||||
// Square this element
|
||||
func (fp *Fp) Square(elem *Fp) *Fp {
|
||||
delem := (*fiat_pasta_fp_montgomery_domain_field_element)(elem)
|
||||
fiat_pasta_fp_square((*fiat_pasta_fp_montgomery_domain_field_element)(fp), delem)
|
||||
return fp
|
||||
}
|
||||
|
||||
// Sqrt this element, if it exists. If true, then value
|
||||
// is a square root. If false, value is a QNR
|
||||
func (fp *Fp) Sqrt(elem *Fp) (*Fp, bool) {
|
||||
return fp.tonelliShanks(elem)
|
||||
}
|
||||
|
||||
// See sqrt_ts_ct at
|
||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-I.4
|
||||
func (fp *Fp) tonelliShanks(elem *Fp) (*Fp, bool) {
|
||||
// c1 := 32
|
||||
// c2 := (q - 1) / (2^c1)
|
||||
// c2 := [4]uint64{
|
||||
// 0x094cf91b992d30ed,
|
||||
// 0x00000000224698fc,
|
||||
// 0x0000000000000000,
|
||||
// 0x0000000040000000,
|
||||
// }
|
||||
// c3 := (c2 - 1) / 2
|
||||
c3 := [4]uint64{
|
||||
0x04a67c8dcc969876,
|
||||
0x0000000011234c7e,
|
||||
0x0000000000000000,
|
||||
0x0000000020000000,
|
||||
}
|
||||
// c4 := generator
|
||||
// c5 := new(Fp).pow(&generator, c2)
|
||||
c5 := &Fp{
|
||||
0xa28db849bad6dbf0,
|
||||
0x9083cd03d3b539df,
|
||||
0xfba6b9ca9dc8448e,
|
||||
0x3ec928747b89c6da,
|
||||
}
|
||||
|
||||
z := new(Fp).pow(elem, c3)
|
||||
t := new(Fp).Square(z)
|
||||
t.Mul(t, elem)
|
||||
|
||||
z.Mul(z, elem)
|
||||
|
||||
b := new(Fp).Set(t)
|
||||
c := new(Fp).Set(c5)
|
||||
flags := map[bool]int{
|
||||
true: 1,
|
||||
false: 0,
|
||||
}
|
||||
|
||||
for i := s; i >= 2; i-- {
|
||||
for j := 1; j <= i-2; j++ {
|
||||
b.Square(b)
|
||||
}
|
||||
z.CMove(z, new(Fp).Mul(z, c), flags[!b.IsOne()])
|
||||
c.Square(c)
|
||||
t.CMove(t, new(Fp).Mul(t, c), flags[!b.IsOne()])
|
||||
b.Set(t)
|
||||
}
|
||||
wasSquare := c.Square(z).Equal(elem)
|
||||
return fp.Set(z), wasSquare
|
||||
}
|
||||
|
||||
// Invert this element i.e. compute the multiplicative inverse
|
||||
// return false, zero if this element is zero
|
||||
func (fp *Fp) Invert(elem *Fp) (*Fp, bool) {
|
||||
// computes elem^(p - 2) mod p
|
||||
exp := [4]uint64{
|
||||
0x992d30ecffffffff,
|
||||
0x224698fc094cf91b,
|
||||
0x0000000000000000,
|
||||
0x4000000000000000,
|
||||
}
|
||||
return fp.pow(elem, exp), !elem.IsZero()
|
||||
}
|
||||
|
||||
// Mul returns the result from multiplying this element by rhs
|
||||
func (fp *Fp) Mul(lhs, rhs *Fp) *Fp {
|
||||
dlhs := (*fiat_pasta_fp_montgomery_domain_field_element)(lhs)
|
||||
drhs := (*fiat_pasta_fp_montgomery_domain_field_element)(rhs)
|
||||
fiat_pasta_fp_mul((*fiat_pasta_fp_montgomery_domain_field_element)(fp), dlhs, drhs)
|
||||
return fp
|
||||
}
|
||||
|
||||
// Sub returns the result from subtracting rhs from this element
|
||||
func (fp *Fp) Sub(lhs, rhs *Fp) *Fp {
|
||||
dlhs := (*fiat_pasta_fp_montgomery_domain_field_element)(lhs)
|
||||
drhs := (*fiat_pasta_fp_montgomery_domain_field_element)(rhs)
|
||||
fiat_pasta_fp_sub((*fiat_pasta_fp_montgomery_domain_field_element)(fp), dlhs, drhs)
|
||||
return fp
|
||||
}
|
||||
|
||||
// Add returns the result from adding rhs to this element
|
||||
func (fp *Fp) Add(lhs, rhs *Fp) *Fp {
|
||||
dlhs := (*fiat_pasta_fp_montgomery_domain_field_element)(lhs)
|
||||
drhs := (*fiat_pasta_fp_montgomery_domain_field_element)(rhs)
|
||||
fiat_pasta_fp_add((*fiat_pasta_fp_montgomery_domain_field_element)(fp), dlhs, drhs)
|
||||
return fp
|
||||
}
|
||||
|
||||
// Neg returns negation of this element
|
||||
func (fp *Fp) Neg(elem *Fp) *Fp {
|
||||
delem := (*fiat_pasta_fp_montgomery_domain_field_element)(elem)
|
||||
fiat_pasta_fp_opp((*fiat_pasta_fp_montgomery_domain_field_element)(fp), delem)
|
||||
return fp
|
||||
}
|
||||
|
||||
// Exp exponentiates this element by exp
|
||||
func (fp *Fp) Exp(base, exp *Fp) *Fp {
|
||||
// convert exponent to integer form
|
||||
tv := &fiat_pasta_fp_non_montgomery_domain_field_element{}
|
||||
fiat_pasta_fp_from_montgomery(tv, (*fiat_pasta_fp_montgomery_domain_field_element)(exp))
|
||||
|
||||
e := (*[4]uint64)(tv)
|
||||
return fp.pow(base, *e)
|
||||
}
|
||||
|
||||
func (fp *Fp) pow(base *Fp, exp [4]uint64) *Fp {
|
||||
res := new(Fp).SetOne()
|
||||
tmp := new(Fp)
|
||||
|
||||
for i := len(exp) - 1; i >= 0; i-- {
|
||||
for j := 63; j >= 0; j-- {
|
||||
res.Square(res)
|
||||
tmp.Mul(res, base)
|
||||
res.CMove(res, tmp, int(exp[i]>>j)&1)
|
||||
}
|
||||
}
|
||||
return fp.Set(res)
|
||||
}
|
||||
|
||||
// CMove selects lhs if choice == 0 and rhs if choice == 1
|
||||
func (fp *Fp) CMove(lhs, rhs *Fp, choice int) *Fp {
|
||||
dlhs := (*[4]uint64)(lhs)
|
||||
drhs := (*[4]uint64)(rhs)
|
||||
fiat_pasta_fp_selectznz((*[4]uint64)(fp), fiat_pasta_fp_uint1(choice), dlhs, drhs)
|
||||
return fp
|
||||
}
|
||||
|
||||
// ToRaw converts this element into the a [4]uint64
|
||||
func (fp *Fp) ToRaw() [4]uint64 {
|
||||
res := &fiat_pasta_fp_non_montgomery_domain_field_element{}
|
||||
fiat_pasta_fp_from_montgomery(res, (*fiat_pasta_fp_montgomery_domain_field_element)(fp))
|
||||
return *(*[4]uint64)(res)
|
||||
}
|
@ -1,249 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package fp
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFpSetOne(t *testing.T) {
|
||||
fp := new(Fp).SetOne()
|
||||
require.NotNil(t, fp)
|
||||
require.True(t, fp.Equal(r))
|
||||
}
|
||||
|
||||
func TestFpSetUint64(t *testing.T) {
|
||||
act := new(Fp).SetUint64(1 << 60)
|
||||
require.NotNil(t, act)
|
||||
// Remember it will be in montgomery form
|
||||
require.Equal(t, int(act[0]), 0x592d30ed00000001)
|
||||
}
|
||||
|
||||
func TestFpAdd(t *testing.T) {
|
||||
lhs := new(Fp).SetOne()
|
||||
rhs := new(Fp).SetOne()
|
||||
exp := new(Fp).SetUint64(2)
|
||||
res := new(Fp).Add(lhs, rhs)
|
||||
require.NotNil(t, res)
|
||||
require.True(t, res.Equal(exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint64() >> 2
|
||||
r := rand.Uint64() >> 2
|
||||
e := l + r
|
||||
lhs.SetUint64(l)
|
||||
rhs.SetUint64(r)
|
||||
exp.SetUint64(e)
|
||||
|
||||
a := new(Fp).Add(lhs, rhs)
|
||||
require.NotNil(t, a)
|
||||
require.Equal(t, exp, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpSub(t *testing.T) {
|
||||
lhs := new(Fp).SetOne()
|
||||
rhs := new(Fp).SetOne()
|
||||
exp := new(Fp).SetZero()
|
||||
res := new(Fp).Sub(lhs, rhs)
|
||||
require.NotNil(t, res)
|
||||
require.True(t, res.Equal(exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint64() >> 2
|
||||
r := rand.Uint64() >> 2
|
||||
if l < r {
|
||||
l, r = r, l
|
||||
}
|
||||
e := l - r
|
||||
lhs.SetUint64(l)
|
||||
rhs.SetUint64(r)
|
||||
exp.SetUint64(e)
|
||||
|
||||
a := new(Fp).Sub(lhs, rhs)
|
||||
require.NotNil(t, a)
|
||||
require.Equal(t, exp, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpMul(t *testing.T) {
|
||||
lhs := new(Fp).SetOne()
|
||||
rhs := new(Fp).SetOne()
|
||||
exp := new(Fp).SetOne()
|
||||
res := new(Fp).Mul(lhs, rhs)
|
||||
require.NotNil(t, res)
|
||||
require.True(t, res.Equal(exp))
|
||||
|
||||
// Fuzz test
|
||||
for i := 0; i < 25; i++ {
|
||||
// Divide by 4 to prevent overflow false errors
|
||||
l := rand.Uint32()
|
||||
r := rand.Uint32()
|
||||
e := uint64(l) * uint64(r)
|
||||
lhs.SetUint64(uint64(l))
|
||||
rhs.SetUint64(uint64(r))
|
||||
exp.SetUint64(e)
|
||||
|
||||
a := new(Fp).Mul(lhs, rhs)
|
||||
require.NotNil(t, a)
|
||||
require.Equal(t, exp, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpDouble(t *testing.T) {
|
||||
a := new(Fp).SetUint64(2)
|
||||
e := new(Fp).SetUint64(4)
|
||||
require.Equal(t, e, new(Fp).Double(a))
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
tv := rand.Uint32()
|
||||
ttv := uint64(tv) * 2
|
||||
a = new(Fp).SetUint64(uint64(tv))
|
||||
e = new(Fp).SetUint64(ttv)
|
||||
require.Equal(t, e, new(Fp).Double(a))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpSquare(t *testing.T) {
|
||||
a := new(Fp).SetUint64(4)
|
||||
e := new(Fp).SetUint64(16)
|
||||
require.Equal(t, e, a.Square(a))
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
j := rand.Uint32()
|
||||
exp := uint64(j) * uint64(j)
|
||||
e.SetUint64(exp)
|
||||
a.SetUint64(uint64(j))
|
||||
require.Equal(t, e, a.Square(a))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpNeg(t *testing.T) {
|
||||
a := new(Fp).SetOne()
|
||||
a.Neg(a)
|
||||
e := &Fp{7256640077462241284, 9879318615658062958, 0, 0}
|
||||
require.Equal(t, e, a)
|
||||
a.Neg(generator)
|
||||
e = &Fp{0xf787d28400000014, 0xad83f3b0ba037627, 0x2, 0x0}
|
||||
require.Equal(t, e, a)
|
||||
}
|
||||
|
||||
func TestFpExp(t *testing.T) {
|
||||
e := new(Fp).SetUint64(8)
|
||||
a := new(Fp).SetUint64(2)
|
||||
by := new(Fp).SetUint64(3)
|
||||
require.Equal(t, e, a.Exp(a, by))
|
||||
}
|
||||
|
||||
func TestFpSqrt(t *testing.T) {
|
||||
t1 := new(Fp).SetUint64(2)
|
||||
t2 := new(Fp).Neg(t1)
|
||||
t3 := new(Fp).Square(t1)
|
||||
_, wasSquare := t3.Sqrt(t3)
|
||||
require.True(t, wasSquare)
|
||||
require.True(t, t1.Equal(t3) || t2.Equal(t3))
|
||||
t1.SetUint64(5)
|
||||
_, wasSquare = new(Fp).Sqrt(t1)
|
||||
require.False(t, wasSquare)
|
||||
}
|
||||
|
||||
func TestFpInvert(t *testing.T) {
|
||||
twoInv := &Fp{0xcc96987680000001, 0x11234c7e04a67c8d, 0x0000000000000000, 0x2000000000000000}
|
||||
fiat_pasta_fp_to_montgomery((*fiat_pasta_fp_montgomery_domain_field_element)(twoInv), (*fiat_pasta_fp_non_montgomery_domain_field_element)(twoInv))
|
||||
two := new(Fp).SetUint64(2)
|
||||
a, inverted := new(Fp).Invert(two)
|
||||
require.True(t, inverted)
|
||||
require.Equal(t, a, twoInv)
|
||||
|
||||
rootOfUnity := &Fp{0xbdad6fabd87ea32f, 0xea322bf2b7bb7584, 0x362120830561f81a, 0x2bce74deac30ebda}
|
||||
fiat_pasta_fp_to_montgomery((*fiat_pasta_fp_montgomery_domain_field_element)(rootOfUnity), (*fiat_pasta_fp_non_montgomery_domain_field_element)(rootOfUnity))
|
||||
rootOfUnityInv := &Fp{0xf0b87c7db2ce91f6, 0x84a0a1d8859f066f, 0xb4ed8e647196dad1, 0x2cd5282c53116b5c}
|
||||
fiat_pasta_fp_to_montgomery((*fiat_pasta_fp_montgomery_domain_field_element)(rootOfUnityInv), (*fiat_pasta_fp_non_montgomery_domain_field_element)(rootOfUnityInv))
|
||||
a, inverted = new(Fp).Invert(rootOfUnity)
|
||||
require.True(t, inverted)
|
||||
require.Equal(t, a, rootOfUnityInv)
|
||||
|
||||
lhs := new(Fp).SetUint64(9)
|
||||
rhs := new(Fp).SetUint64(3)
|
||||
rhsInv, inverted := new(Fp).Invert(rhs)
|
||||
require.True(t, inverted)
|
||||
require.Equal(t, rhs, new(Fp).Mul(lhs, rhsInv))
|
||||
|
||||
rhs.SetZero()
|
||||
_, inverted = new(Fp).Invert(rhs)
|
||||
require.False(t, inverted)
|
||||
}
|
||||
|
||||
func TestFpCMove(t *testing.T) {
|
||||
t1 := new(Fp).SetUint64(5)
|
||||
t2 := new(Fp).SetUint64(10)
|
||||
require.Equal(t, t1, new(Fp).CMove(t1, t2, 0))
|
||||
require.Equal(t, t2, new(Fp).CMove(t1, t2, 1))
|
||||
}
|
||||
|
||||
func TestFpBytes(t *testing.T) {
|
||||
t1 := new(Fp).SetUint64(99)
|
||||
seq := t1.Bytes()
|
||||
t2, err := new(Fp).SetBytes(&seq)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, t1, t2)
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
t1.SetUint64(rand.Uint64())
|
||||
seq = t1.Bytes()
|
||||
_, err = t2.SetBytes(&seq)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, t1, t2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFpBigInt(t *testing.T) {
|
||||
t1 := new(Fp).SetBigInt(big.NewInt(9999))
|
||||
t2 := new(Fp).SetBigInt(t1.BigInt())
|
||||
require.Equal(t, t1, t2)
|
||||
|
||||
e := &Fp{0x8c6bc70550c87761, 0xce2c6c48e7063731, 0xf1275fd1e4607cd6, 0x3e6762e63501edbd}
|
||||
b := new(big.Int).SetBytes([]byte{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9})
|
||||
t1.SetBigInt(b)
|
||||
require.Equal(t, e, t1)
|
||||
e[0] = 0xcc169e7af3788a0
|
||||
e[1] = 0x541a2cb32246c1ea
|
||||
e[2] = 0xed8a02e1b9f8329
|
||||
e[3] = 0x1989d19cafe1242
|
||||
b.Neg(b)
|
||||
t1.SetBigInt(b)
|
||||
require.Equal(t, e, t1)
|
||||
}
|
||||
|
||||
func TestFpSetBool(t *testing.T) {
|
||||
require.Equal(t, new(Fp).SetOne(), new(Fp).SetBool(true))
|
||||
require.Equal(t, new(Fp).SetZero(), new(Fp).SetBool(false))
|
||||
}
|
||||
|
||||
func TestFpSetBytesWide(t *testing.T) {
|
||||
e := &Fp{0x3daec14d565241d9, 0x0b7af45b6073944b, 0xea5b8bd611a5bd4c, 0x150160330625db3d}
|
||||
fiat_pasta_fp_to_montgomery((*fiat_pasta_fp_montgomery_domain_field_element)(e), (*fiat_pasta_fp_non_montgomery_domain_field_element)(e))
|
||||
a := new(Fp).SetBytesWide(&[64]byte{
|
||||
0xa1, 0x78, 0x76, 0x29, 0x41, 0x56, 0x15, 0xee,
|
||||
0x65, 0xbe, 0xfd, 0xdb, 0x6b, 0x15, 0x3e, 0xd8,
|
||||
0xb5, 0xa0, 0x8b, 0xc6, 0x34, 0xd8, 0xcc, 0xd9,
|
||||
0x58, 0x27, 0x27, 0x12, 0xe3, 0xed, 0x08, 0xf5,
|
||||
0x89, 0x8e, 0x22, 0xf8, 0xcb, 0xf7, 0x8d, 0x03,
|
||||
0x41, 0x4b, 0xc7, 0xa3, 0xe4, 0xa1, 0x05, 0x35,
|
||||
0xb3, 0x2d, 0xb8, 0x5e, 0x77, 0x6f, 0xa4, 0xbf,
|
||||
0x1d, 0x47, 0x2f, 0x26, 0x7e, 0xe2, 0xeb, 0x26,
|
||||
})
|
||||
require.Equal(t, e, a)
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,363 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package fq
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/onsonr/hway/crypto/internal"
|
||||
)
|
||||
|
||||
type Fq fiat_pasta_fq_montgomery_domain_field_element
|
||||
|
||||
// r = 2^256 mod p
|
||||
var r = &Fq{0x5b2b3e9cfffffffd, 0x992c350be3420567, 0xffffffffffffffff, 0x3fffffffffffffff}
|
||||
|
||||
// r2 = 2^512 mod p
|
||||
var r2 = &Fq{0xfc9678ff0000000f, 0x67bb433d891a16e3, 0x7fae231004ccf590, 0x096d41af7ccfdaa9}
|
||||
|
||||
// r3 = 2^768 mod p
|
||||
var r3 = &Fq{0x008b421c249dae4c, 0xe13bda50dba41326, 0x88fececb8e15cb63, 0x07dd97a06e6792c8}
|
||||
|
||||
// generator = 5 mod p is a generator of the `p - 1` order multiplicative
|
||||
// subgroup, or in other words a primitive element of the field.
|
||||
var generator = &Fq{0x96bc8c8cffffffed, 0x74c2a54b49f7778e, 0xfffffffffffffffd, 0x3fffffffffffffff}
|
||||
|
||||
var s = 32
|
||||
|
||||
// modulus representation
|
||||
// p = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
|
||||
var modulus = &Fq{0x8c46eb2100000001, 0x224698fc0994a8dd, 0x0000000000000000, 0x4000000000000000}
|
||||
|
||||
var BiModulus = new(big.Int).SetBytes([]byte{
|
||||
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x22, 0x46, 0x98, 0xfc, 0x09, 0x94, 0xa8, 0xdd,
|
||||
0x8c, 0x46, 0xeb, 0x21, 0x00, 0x00, 0x00, 0x01,
|
||||
})
|
||||
|
||||
// Cmp returns -1 if fp < rhs
|
||||
// 0 if fp == rhs
|
||||
// 1 if fp > rhs
|
||||
func (fq *Fq) Cmp(rhs *Fq) int {
|
||||
gt := 0
|
||||
lt := 0
|
||||
for i := len(fq) - 1; i >= 0; i-- {
|
||||
gt |= int((rhs[i]-fq[i])>>63) &^ lt
|
||||
lt |= int((fq[i]-rhs[i])>>63) &^ gt
|
||||
}
|
||||
return gt - lt
|
||||
}
|
||||
|
||||
// Equal returns true if fp == rhs
|
||||
func (fq *Fq) Equal(rhs *Fq) bool {
|
||||
t := fq[0] ^ rhs[0]
|
||||
t |= fq[1] ^ rhs[1]
|
||||
t |= fq[2] ^ rhs[2]
|
||||
t |= fq[3] ^ rhs[3]
|
||||
return t == 0
|
||||
}
|
||||
|
||||
// IsZero returns true if fp == 0
|
||||
func (fq *Fq) IsZero() bool {
|
||||
t := fq[0]
|
||||
t |= fq[1]
|
||||
t |= fq[2]
|
||||
t |= fq[3]
|
||||
return t == 0
|
||||
}
|
||||
|
||||
// IsOne returns true if fp == r
|
||||
func (fq *Fq) IsOne() bool {
|
||||
return fq.Equal(r)
|
||||
}
|
||||
|
||||
// Set fp == rhs
|
||||
func (fq *Fq) Set(rhs *Fq) *Fq {
|
||||
fq[0] = rhs[0]
|
||||
fq[1] = rhs[1]
|
||||
fq[2] = rhs[2]
|
||||
fq[3] = rhs[3]
|
||||
return fq
|
||||
}
|
||||
|
||||
// SetUint64 sets fp == rhs
|
||||
func (fq *Fq) SetUint64(rhs uint64) *Fq {
|
||||
r := &fiat_pasta_fq_non_montgomery_domain_field_element{rhs, 0, 0, 0}
|
||||
fiat_pasta_fq_to_montgomery((*fiat_pasta_fq_montgomery_domain_field_element)(fq), r)
|
||||
return fq
|
||||
}
|
||||
|
||||
func (fq *Fq) SetBool(rhs bool) *Fq {
|
||||
if rhs {
|
||||
fq.SetOne()
|
||||
} else {
|
||||
fq.SetZero()
|
||||
}
|
||||
return fq
|
||||
}
|
||||
|
||||
// SetOne fp == r
|
||||
func (fq *Fq) SetOne() *Fq {
|
||||
return fq.Set(r)
|
||||
}
|
||||
|
||||
// SetZero fp == 0
|
||||
func (fq *Fq) SetZero() *Fq {
|
||||
fq[0] = 0
|
||||
fq[1] = 0
|
||||
fq[2] = 0
|
||||
fq[3] = 0
|
||||
return fq
|
||||
}
|
||||
|
||||
// SetBytesWide takes 64 bytes as input and treats them as a 512-bit number.
|
||||
// Attributed to https://github.com/zcash/pasta_curves/blob/main/src/fields/fq.rs#L255
|
||||
// We reduce an arbitrary 512-bit number by decomposing it into two 256-bit digits
|
||||
// with the higher bits multiplied by 2^256. Thus, we perform two reductions
|
||||
//
|
||||
// 1. the lower bits are multiplied by r^2, as normal
|
||||
// 2. the upper bits are multiplied by r^2 * 2^256 = r^3
|
||||
//
|
||||
// and computing their sum in the field. It remains to see that arbitrary 256-bit
|
||||
// numbers can be placed into Montgomery form safely using the reduction. The
|
||||
// reduction works so long as the product is less than r=2^256 multiplied by
|
||||
// the modulus. This holds because for any `c` smaller than the modulus, we have
|
||||
// that (2^256 - 1)*c is an acceptable product for the reduction. Therefore, the
|
||||
// reduction always works so long as `c` is in the field; in this case it is either the
|
||||
// constant `r2` or `r3`.
|
||||
func (fq *Fq) SetBytesWide(input *[64]byte) *Fq {
|
||||
d0 := fiat_pasta_fq_montgomery_domain_field_element{
|
||||
binary.LittleEndian.Uint64(input[:8]),
|
||||
binary.LittleEndian.Uint64(input[8:16]),
|
||||
binary.LittleEndian.Uint64(input[16:24]),
|
||||
binary.LittleEndian.Uint64(input[24:32]),
|
||||
}
|
||||
d1 := fiat_pasta_fq_montgomery_domain_field_element{
|
||||
binary.LittleEndian.Uint64(input[32:40]),
|
||||
binary.LittleEndian.Uint64(input[40:48]),
|
||||
binary.LittleEndian.Uint64(input[48:56]),
|
||||
binary.LittleEndian.Uint64(input[56:64]),
|
||||
}
|
||||
// Convert to Montgomery form
|
||||
tv1 := &fiat_pasta_fq_montgomery_domain_field_element{}
|
||||
tv2 := &fiat_pasta_fq_montgomery_domain_field_element{}
|
||||
// d0 * r2 + d1 * r3
|
||||
fiat_pasta_fq_mul(tv1, &d0, (*fiat_pasta_fq_montgomery_domain_field_element)(r2))
|
||||
fiat_pasta_fq_mul(tv2, &d1, (*fiat_pasta_fq_montgomery_domain_field_element)(r3))
|
||||
fiat_pasta_fq_add((*fiat_pasta_fq_montgomery_domain_field_element)(fq), tv1, tv2)
|
||||
return fq
|
||||
}
|
||||
|
||||
// SetBytes attempts to convert a little endian byte representation
|
||||
// of a scalar into a `Fq`, failing if input is not canonical
|
||||
func (fq *Fq) SetBytes(input *[32]byte) (*Fq, error) {
|
||||
d0 := &Fq{
|
||||
binary.LittleEndian.Uint64(input[:8]),
|
||||
binary.LittleEndian.Uint64(input[8:16]),
|
||||
binary.LittleEndian.Uint64(input[16:24]),
|
||||
binary.LittleEndian.Uint64(input[24:32]),
|
||||
}
|
||||
if d0.Cmp(modulus) != -1 {
|
||||
return nil, fmt.Errorf("invalid byte sequence")
|
||||
}
|
||||
fiat_pasta_fq_from_bytes((*[4]uint64)(fq), input)
|
||||
fiat_pasta_fq_to_montgomery((*fiat_pasta_fq_montgomery_domain_field_element)(fq), (*fiat_pasta_fq_non_montgomery_domain_field_element)(fq))
|
||||
return fq, nil
|
||||
}
|
||||
|
||||
// SetBigInt initializes an element from big.Int
|
||||
// The value is reduced by the modulus
|
||||
func (fq *Fq) SetBigInt(bi *big.Int) *Fq {
|
||||
var buffer [32]byte
|
||||
r := new(big.Int).Set(bi)
|
||||
r.Mod(r, BiModulus)
|
||||
r.FillBytes(buffer[:])
|
||||
copy(buffer[:], internal.ReverseScalarBytes(buffer[:]))
|
||||
_, _ = fq.SetBytes(&buffer)
|
||||
return fq
|
||||
}
|
||||
|
||||
// SetRaw converts a raw array into a field element
|
||||
func (fq *Fq) SetRaw(array *[4]uint64) *Fq {
|
||||
fiat_pasta_fq_to_montgomery((*fiat_pasta_fq_montgomery_domain_field_element)(fq), (*fiat_pasta_fq_non_montgomery_domain_field_element)(array))
|
||||
return fq
|
||||
}
|
||||
|
||||
// Bytes converts this element into a byte representation
|
||||
// in little endian byte order
|
||||
func (fq *Fq) Bytes() [32]byte {
|
||||
var output [32]byte
|
||||
tv := &fiat_pasta_fq_non_montgomery_domain_field_element{}
|
||||
fiat_pasta_fq_from_montgomery(tv, (*fiat_pasta_fq_montgomery_domain_field_element)(fq))
|
||||
fiat_pasta_fq_to_bytes(&output, (*[4]uint64)(tv))
|
||||
return output
|
||||
}
|
||||
|
||||
// BigInt converts this element into the big.Int struct
|
||||
func (fq *Fq) BigInt() *big.Int {
|
||||
buffer := fq.Bytes()
|
||||
return new(big.Int).SetBytes(internal.ReverseScalarBytes(buffer[:]))
|
||||
}
|
||||
|
||||
// Double this element
|
||||
func (fq *Fq) Double(elem *Fq) *Fq {
|
||||
delem := (*fiat_pasta_fq_montgomery_domain_field_element)(elem)
|
||||
fiat_pasta_fq_add((*fiat_pasta_fq_montgomery_domain_field_element)(fq), delem, delem)
|
||||
return fq
|
||||
}
|
||||
|
||||
// Square this element
|
||||
func (fq *Fq) Square(elem *Fq) *Fq {
|
||||
delem := (*fiat_pasta_fq_montgomery_domain_field_element)(elem)
|
||||
fiat_pasta_fq_square((*fiat_pasta_fq_montgomery_domain_field_element)(fq), delem)
|
||||
return fq
|
||||
}
|
||||
|
||||
// Sqrt this element, if it exists. If true, then value
|
||||
// is a square root. If false, value is a QNR
|
||||
func (fq *Fq) Sqrt(elem *Fq) (*Fq, bool) {
|
||||
return fq.tonelliShanks(elem)
|
||||
}
|
||||
|
||||
// See sqrt_ts_ct at
|
||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-I.4
|
||||
func (fq *Fq) tonelliShanks(elem *Fq) (*Fq, bool) {
|
||||
// c1 := 32
|
||||
// c2 := (q - 1) / (2^c1)
|
||||
//c2 := [4]uint64{
|
||||
// 0x0994a8dd8c46eb21,
|
||||
// 0x00000000224698fc,
|
||||
// 0x0000000000000000,
|
||||
// 0x0000000040000000,
|
||||
//}
|
||||
// c3 := (c2 - 1) / 2
|
||||
c3 := [4]uint64{
|
||||
0x04ca546ec6237590,
|
||||
0x0000000011234c7e,
|
||||
0x0000000000000000,
|
||||
0x0000000020000000,
|
||||
}
|
||||
// c4 := generator
|
||||
// c5 := new(Fq).pow(&generator, c2)
|
||||
c5 := &Fq{
|
||||
0x218077428c9942de,
|
||||
0xcc49578921b60494,
|
||||
0xac2e5d27b2efbee2,
|
||||
0xb79fa897f2db056,
|
||||
}
|
||||
|
||||
z := new(Fq).pow(elem, c3)
|
||||
t := new(Fq).Square(z)
|
||||
t.Mul(t, elem)
|
||||
|
||||
z.Mul(z, elem)
|
||||
|
||||
b := new(Fq).Set(t)
|
||||
c := new(Fq).Set(c5)
|
||||
flags := map[bool]int{
|
||||
true: 1,
|
||||
false: 0,
|
||||
}
|
||||
|
||||
for i := s; i >= 2; i-- {
|
||||
for j := 1; j <= i-2; j++ {
|
||||
b.Square(b)
|
||||
}
|
||||
z.CMove(z, new(Fq).Mul(z, c), flags[!b.IsOne()])
|
||||
c.Square(c)
|
||||
t.CMove(t, new(Fq).Mul(t, c), flags[!b.IsOne()])
|
||||
b.Set(t)
|
||||
}
|
||||
wasSquare := c.Square(z).Equal(elem)
|
||||
return fq.Set(z), wasSquare
|
||||
}
|
||||
|
||||
// Invert this element i.e. compute the multiplicative inverse
|
||||
// return false, zero if this element is zero
|
||||
func (fq *Fq) Invert(elem *Fq) (*Fq, bool) {
|
||||
// computes elem^(p - 2) mod p
|
||||
exp := [4]uint64{
|
||||
0x8c46eb20ffffffff,
|
||||
0x224698fc0994a8dd,
|
||||
0x0000000000000000,
|
||||
0x4000000000000000,
|
||||
}
|
||||
return fq.pow(elem, exp), !elem.IsZero()
|
||||
}
|
||||
|
||||
// Mul returns the result from multiplying this element by rhs
|
||||
func (fq *Fq) Mul(lhs, rhs *Fq) *Fq {
|
||||
dlhs := (*fiat_pasta_fq_montgomery_domain_field_element)(lhs)
|
||||
drhs := (*fiat_pasta_fq_montgomery_domain_field_element)(rhs)
|
||||
fiat_pasta_fq_mul((*fiat_pasta_fq_montgomery_domain_field_element)(fq), dlhs, drhs)
|
||||
return fq
|
||||
}
|
||||
|
||||
// Sub returns the result from subtracting rhs from this element
|
||||
func (fq *Fq) Sub(lhs, rhs *Fq) *Fq {
|
||||
dlhs := (*fiat_pasta_fq_montgomery_domain_field_element)(lhs)
|
||||
drhs := (*fiat_pasta_fq_montgomery_domain_field_element)(rhs)
|
||||
fiat_pasta_fq_sub((*fiat_pasta_fq_montgomery_domain_field_element)(fq), dlhs, drhs)
|
||||
return fq
|
||||
}
|
||||
|
||||
// Add returns the result from adding rhs to this element
|
||||
func (fq *Fq) Add(lhs, rhs *Fq) *Fq {
|
||||
dlhs := (*fiat_pasta_fq_montgomery_domain_field_element)(lhs)
|
||||
drhs := (*fiat_pasta_fq_montgomery_domain_field_element)(rhs)
|
||||
fiat_pasta_fq_add((*fiat_pasta_fq_montgomery_domain_field_element)(fq), dlhs, drhs)
|
||||
return fq
|
||||
}
|
||||
|
||||
// Neg returns negation of this element
|
||||
func (fq *Fq) Neg(elem *Fq) *Fq {
|
||||
delem := (*fiat_pasta_fq_montgomery_domain_field_element)(elem)
|
||||
fiat_pasta_fq_opp((*fiat_pasta_fq_montgomery_domain_field_element)(fq), delem)
|
||||
return fq
|
||||
}
|
||||
|
||||
// Exp exponentiates this element by exp
|
||||
func (fq *Fq) Exp(base, exp *Fq) *Fq {
|
||||
// convert exponent to integer form
|
||||
tv := &fiat_pasta_fq_non_montgomery_domain_field_element{}
|
||||
fiat_pasta_fq_from_montgomery(tv, (*fiat_pasta_fq_montgomery_domain_field_element)(exp))
|
||||
|
||||
e := (*[4]uint64)(tv)
|
||||
return fq.pow(base, *e)
|
||||
}
|
||||
|
||||
func (fq *Fq) pow(base *Fq, exp [4]uint64) *Fq {
|
||||
res := new(Fq).SetOne()
|
||||
tmp := new(Fq)
|
||||
|
||||
for i := len(exp) - 1; i >= 0; i-- {
|
||||
for j := 63; j >= 0; j-- {
|
||||
res.Square(res)
|
||||
tmp.Mul(res, base)
|
||||
res.CMove(res, tmp, int(exp[i]>>j)&1)
|
||||
}
|
||||
}
|
||||
return fq.Set(res)
|
||||
}
|
||||
|
||||
// CMove selects lhs if choice == 0 and rhs if choice == 1
|
||||
func (fq *Fq) CMove(lhs, rhs *Fq, choice int) *Fq {
|
||||
dlhs := (*[4]uint64)(lhs)
|
||||
drhs := (*[4]uint64)(rhs)
|
||||
fiat_pasta_fq_selectznz((*[4]uint64)(fq), fiat_pasta_fq_uint1(choice), dlhs, drhs)
|
||||
return fq
|
||||
}
|
||||
|
||||
// ToRaw converts this element into the a [4]uint64
|
||||
func (fq *Fq) ToRaw() [4]uint64 {
|
||||
res := &fiat_pasta_fq_non_montgomery_domain_field_element{}
|
||||
fiat_pasta_fq_from_montgomery(res, (*fiat_pasta_fq_montgomery_domain_field_element)(fq))
|
||||
return *(*[4]uint64)(res)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user