@@ -29,6 +29,8 @@ public class LogicsigSignature {
29
29
@ JsonIgnore
30
30
private static final byte [] LOGIC_PREFIX = ("Program" ).getBytes (StandardCharsets .UTF_8 );
31
31
@ JsonIgnore
32
+ private static final byte [] MULTISIG_PROGRAM_PREFIX = ("MsigProgram" ).getBytes (StandardCharsets .UTF_8 );
33
+ @ JsonIgnore
32
34
private static final String SIGN_ALGO = "EdDSA" ;
33
35
34
36
@ JsonProperty ("l" )
@@ -39,6 +41,8 @@ public class LogicsigSignature {
39
41
public Signature sig ;
40
42
@ JsonProperty ("msig" )
41
43
public MultisigSignature msig ;
44
+ @ JsonProperty ("lmsig" )
45
+ public MultisigSignature lmsig ;
42
46
43
47
44
48
private static boolean isAsciiPrintable (final byte symbol ) {
@@ -98,7 +102,8 @@ public LogicsigSignature(
98
102
@ JsonProperty ("l" ) byte [] logic ,
99
103
@ JsonProperty ("arg" ) List <byte []> args ,
100
104
@ JsonProperty ("sig" ) byte [] sig ,
101
- @ JsonProperty ("msig" ) MultisigSignature msig
105
+ @ JsonProperty ("msig" ) MultisigSignature msig ,
106
+ @ JsonProperty ("lmsig" ) MultisigSignature lmsig
102
107
) {
103
108
this .logic = Objects .requireNonNull (logic , "program must not be null" );
104
109
this .args = args ;
@@ -107,6 +112,7 @@ public LogicsigSignature(
107
112
108
113
if (sig != null ) this .sig = new Signature (sig );
109
114
this .msig = msig ;
115
+ this .lmsig = lmsig ;
110
116
}
111
117
112
118
/**
@@ -123,7 +129,7 @@ public LogicsigSignature(byte[] logicsig) {
123
129
* @param args
124
130
*/
125
131
public LogicsigSignature (byte [] logicsig , List <byte []> args ) {
126
- this (logicsig , args , null , null );
132
+ this (logicsig , args , null , null , null );
127
133
}
128
134
129
135
/**
@@ -134,6 +140,19 @@ public LogicsigSignature() {
134
140
this .args = null ;
135
141
}
136
142
143
+ /**
144
+ * Returns the number of signatures (sig, msig, lmsig) on this LogicSig.
145
+ * At most one of these should be present.
146
+ * @return the number of signature types present
147
+ */
148
+ public int sigCount () {
149
+ int count = 0 ;
150
+ if (this .sig != null ) count ++;
151
+ if (this .msig != null ) count ++;
152
+ if (this .lmsig != null ) count ++;
153
+ return count ;
154
+ }
155
+
137
156
/**
138
157
* Calculate escrow address from logic sig program
139
158
* NOTE: THIS RETURNS AN ESCROW ACCOUNT OF A LOGIC-SIG (FROM LOGIC ITSELF),
@@ -157,6 +176,21 @@ public byte[] bytesToSign() {
157
176
return prefixedEncoded ;
158
177
}
159
178
179
+ /**
180
+ * Return prefixed program with multisig address as byte array that is ready to use with multisig
181
+ * signatures on delegated logicsig programs
182
+ * @param multisigAddress the multisig address to include in signed data
183
+ * @return byte[]
184
+ */
185
+ public byte [] bytesToSignMultisig (Address multisigAddress ) {
186
+ byte [] addressBytes = multisigAddress .getBytes ();
187
+ byte [] prefixedEncoded = new byte [this .logic .length + MULTISIG_PROGRAM_PREFIX .length + addressBytes .length ];
188
+ System .arraycopy (MULTISIG_PROGRAM_PREFIX , 0 , prefixedEncoded , 0 , MULTISIG_PROGRAM_PREFIX .length );
189
+ System .arraycopy (addressBytes , 0 , prefixedEncoded , MULTISIG_PROGRAM_PREFIX .length , addressBytes .length );
190
+ System .arraycopy (this .logic , 0 , prefixedEncoded , MULTISIG_PROGRAM_PREFIX .length + addressBytes .length , this .logic .length );
191
+ return prefixedEncoded ;
192
+ }
193
+
160
194
/**
161
195
* Perform signature verification against the sender address
162
196
* @param singleSigner only used in the case of a delegated LogicSig whose delegating account
@@ -168,7 +202,8 @@ public boolean verify(Address singleSigner) throws NoSuchAlgorithmException {
168
202
return false ;
169
203
}
170
204
171
- if (this .sig != null && this .msig != null ) {
205
+ // At most one signature type should be present
206
+ if (sigCount () > 1 ) {
172
207
return false ;
173
208
}
174
209
@@ -191,6 +226,11 @@ public boolean verify(Address singleSigner) throws NoSuchAlgorithmException {
191
226
}
192
227
}
193
228
229
+ if (this .lmsig != null ) {
230
+ Address multisigAddr = this .lmsig .convertToMultisigAddress ().toAddress ();
231
+ return this .lmsig .verify (this .bytesToSignMultisig (multisigAddr ));
232
+ }
233
+
194
234
if (this .msig != null )
195
235
return this .msig .verify (this .bytesToSign ());
196
236
@@ -221,6 +261,9 @@ public boolean equals(Object obj) {
221
261
if (!LogicsigSignature .nullCheck (this .sig , actual .sig )) return false ;
222
262
if (this .sig != null && !this .sig .equals (actual .sig )) return false ;
223
263
264
+ if (!LogicsigSignature .nullCheck (this .lmsig , actual .lmsig )) return false ;
265
+ if (this .lmsig != null && !this .lmsig .equals (actual .lmsig )) return false ;
266
+
224
267
if (!LogicsigSignature .nullCheck (this .msig , actual .msig )) return false ;
225
268
return this .msig == null || this .msig .equals (actual .msig );
226
269
} else {
0 commit comments